1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <hintids.hxx>
22 #include <comphelper/flagguard.hxx>
24 #include <vcl/svapp.hxx>
25 #include <editeng/boxitem.hxx>
26 #include <editeng/brushitem.hxx>
27 #include <editeng/adjustitem.hxx>
28 #include <editeng/fhgtitem.hxx>
29 #include <editeng/ulspitem.hxx>
30 #include <editeng/lrspitem.hxx>
31 #include <editeng/formatbreakitem.hxx>
32 #include <editeng/spltitem.hxx>
33 #include <unotools/configmgr.hxx>
34 #include <svtools/htmltokn.h>
35 #include <svtools/htmlkywd.hxx>
36 #include <svl/numformat.hxx>
37 #include <svl/urihelper.hxx>
38 #include <svx/sdrobjectuser.hxx>
39 #include <sal/log.hxx>
40 #include <osl/diagnose.h>
42 #include <dcontact.hxx>
43 #include <fmtornt.hxx>
45 #include <fmtfsize.hxx>
46 #include <fmtsrnd.hxx>
47 #include <fmtpdsc.hxx>
48 #include <fmtcntnt.hxx>
49 #include <fmtanchr.hxx>
50 #include <fmtlsplt.hxx>
54 #include <IDocumentLayoutAccess.hxx>
55 #include <IDocumentMarkAccess.hxx>
57 #include <shellio.hxx>
58 #include <poolfmt.hxx>
59 #include <swtable.hxx>
60 #include <cellatr.hxx>
61 #include <htmltbl.hxx>
62 #include <swtblfmt.hxx>
63 #include "htmlnum.hxx"
67 #include <itabenum.hxx>
68 #include <tblafmt.hxx>
69 #include <SwStyleNameMapper.hxx>
70 #include <frameformats.hxx>
72 #define NETSCAPE_DFLT_BORDER 1
73 #define NETSCAPE_DFLT_CELLSPACING 2
75 using ::editeng::SvxBorderLine
;
76 using namespace ::com::sun::star
;
78 HTMLOptionEnum
<sal_Int16
> const aHTMLTableVAlignTable
[] =
80 { OOO_STRING_SVTOOLS_HTML_VA_top
, text::VertOrientation::NONE
},
81 { OOO_STRING_SVTOOLS_HTML_VA_middle
, text::VertOrientation::CENTER
},
82 { OOO_STRING_SVTOOLS_HTML_VA_bottom
, text::VertOrientation::BOTTOM
},
90 struct HTMLTableOptions
95 sal_uInt16 nCellPadding
;
96 sal_uInt16 nCellSpacing
;
103 HTMLTableFrame eFrame
;
104 HTMLTableRules eRules
;
106 bool bPercentWidth
: 1;
107 bool bTableAdjust
: 1;
113 OUString aBGImage
, aStyle
, aId
, aClass
, aDir
;
115 HTMLTableOptions( const HTMLOptions
& rOptions
, SvxAdjust eParentAdjust
);
118 class HTMLTableContext
120 SwHTMLNumRuleInfo m_aNumRuleInfo
; // Numbering valid before the table
122 SwTableNode
*m_pTableNd
; // table node
123 SwFrameFormat
*m_pFrameFormat
; // the Fly frame::Frame, containing the table
124 std::unique_ptr
<SwPosition
> m_pPos
; // position behind the table
126 size_t m_nContextStAttrMin
;
127 size_t m_nContextStMin
;
129 bool m_bRestartPRE
: 1;
130 bool m_bRestartXMP
: 1;
131 bool m_bRestartListing
: 1;
133 HTMLTableContext(const HTMLTableContext
&) = delete;
134 HTMLTableContext
& operator=(const HTMLTableContext
&) = delete;
138 std::shared_ptr
<HTMLAttrTable
> m_xAttrTab
; // attributes
140 HTMLTableContext( SwPosition
*pPs
, size_t nCntxtStMin
,
141 size_t nCntxtStAttrMin
) :
142 m_pTableNd( nullptr ),
143 m_pFrameFormat( nullptr ),
145 m_nContextStAttrMin( nCntxtStAttrMin
),
146 m_nContextStMin( nCntxtStMin
),
147 m_bRestartPRE( false ),
148 m_bRestartXMP( false ),
149 m_bRestartListing( false ),
150 m_xAttrTab(std::make_shared
<HTMLAttrTable
>())
152 memset(m_xAttrTab
.get(), 0, sizeof(HTMLAttrTable
));
155 void SetNumInfo( const SwHTMLNumRuleInfo
& rInf
) { m_aNumRuleInfo
.Set(rInf
); }
156 const SwHTMLNumRuleInfo
& GetNumInfo() const { return m_aNumRuleInfo
; };
158 void SavePREListingXMP( SwHTMLParser
& rParser
);
159 void RestorePREListingXMP( SwHTMLParser
& rParser
);
161 SwPosition
*GetPos() const { return m_pPos
.get(); }
163 void SetTableNode( SwTableNode
*pNd
) { m_pTableNd
= pNd
; }
164 SwTableNode
*GetTableNode() const { return m_pTableNd
; }
166 void SetFrameFormat( SwFrameFormat
*pFormat
) { m_pFrameFormat
= pFormat
; }
167 SwFrameFormat
*GetFrameFormat() const { return m_pFrameFormat
; }
169 size_t GetContextStMin() const { return m_nContextStMin
; }
170 size_t GetContextStAttrMin() const { return m_nContextStAttrMin
; }
175 // Cell content is a linked list with SwStartNodes and
180 std::unique_ptr
<HTMLTableCnts
> m_pNext
; // next content
182 // Only one of the next two pointers must be set!
183 const SwStartNode
*m_pStartNode
; // a paragraph
184 std::shared_ptr
<HTMLTable
> m_xTable
; // a table
186 std::shared_ptr
<SwHTMLTableLayoutCnts
> m_xLayoutInfo
;
194 explicit HTMLTableCnts(const SwStartNode
* pStNd
);
195 explicit HTMLTableCnts(std::shared_ptr
<HTMLTable
> xTab
);
197 ~HTMLTableCnts(); // only allowed in ~HTMLTableCell
199 // Determine SwStartNode and HTMLTable respectively
200 const SwStartNode
*GetStartNode() const { return m_pStartNode
; }
201 const std::shared_ptr
<HTMLTable
>& GetTable() const { return m_xTable
; }
202 std::shared_ptr
<HTMLTable
>& GetTable() { return m_xTable
; }
204 // Add a new node at the end of the list
205 void Add( std::unique_ptr
<HTMLTableCnts
> pNewCnts
);
207 // Determine next node
208 const HTMLTableCnts
*Next() const { return m_pNext
.get(); }
209 HTMLTableCnts
*Next() { return m_pNext
.get(); }
211 inline void SetTableBox( SwTableBox
*pBox
);
213 void SetNoBreak() { m_bNoBreak
= true; }
215 const std::shared_ptr
<SwHTMLTableLayoutCnts
>& CreateLayoutInfo();
220 // Cell of a HTML table
223 std::shared_ptr
<HTMLTableCnts
> m_xContents
; // cell content
224 std::shared_ptr
<SvxBrushItem
> m_xBGBrush
; // cell background
225 std::shared_ptr
<SvxBoxItem
> m_xBoxItem
;
228 sal_uInt32 m_nNumFormat
;
229 sal_uInt16 m_nRowSpan
; // cell ROWSPAN
230 sal_uInt16 m_nColSpan
; // cell COLSPAN
231 sal_uInt16 m_nWidth
; // cell WIDTH
232 sal_Int16 m_eVertOrient
; // vertical alignment of the cell
233 bool m_bProtected
: 1; // cell must not filled
234 bool m_bRelWidth
: 1; // nWidth is given in %
235 bool m_bHasNumFormat
: 1;
236 bool m_bHasValue
: 1;
242 HTMLTableCell(); // new cells always empty
244 // Fill a not empty cell
245 void Set( std::shared_ptr
<HTMLTableCnts
> const& rCnts
, sal_uInt16 nRSpan
, sal_uInt16 nCSpan
,
246 sal_Int16 eVertOri
, std::shared_ptr
<SvxBrushItem
> const& rBGBrush
,
247 std::shared_ptr
<SvxBoxItem
> const& rBoxItem
,
248 bool bHasNumFormat
, sal_uInt32 nNumFormat
,
249 bool bHasValue
, double nValue
, bool bNoWrap
, bool bCovered
);
251 // Protect an empty 1x1 cell
254 // Set/Get cell content
255 void SetContents(std::shared_ptr
<HTMLTableCnts
> const& rCnts
) { m_xContents
= rCnts
; }
256 const std::shared_ptr
<HTMLTableCnts
>& GetContents() const { return m_xContents
; }
258 // Set/Get cell ROWSPAN/COLSPAN
259 void SetRowSpan( sal_uInt16 nRSpan
) { m_nRowSpan
= nRSpan
; }
260 sal_uInt16
GetRowSpan() const { return m_nRowSpan
; }
262 void SetColSpan( sal_uInt16 nCSpan
) { m_nColSpan
= nCSpan
; }
263 sal_uInt16
GetColSpan() const { return m_nColSpan
; }
265 inline void SetWidth( sal_uInt16 nWidth
, bool bRelWidth
);
267 const std::shared_ptr
<SvxBrushItem
>& GetBGBrush() const { return m_xBGBrush
; }
268 const std::shared_ptr
<SvxBoxItem
>& GetBoxItem() const { return m_xBoxItem
; }
270 inline bool GetNumFormat( sal_uInt32
& rNumFormat
) const;
271 inline bool GetValue( double& rValue
) const;
273 sal_Int16
GetVertOri() const { return m_eVertOrient
; }
275 // Is the cell filled or protected ?
276 bool IsUsed() const { return m_xContents
|| m_bProtected
; }
278 std::unique_ptr
<SwHTMLTableLayoutCell
> CreateLayoutInfo();
280 bool IsCovered() const { return mbCovered
; }
288 // Row of a HTML table
291 std::vector
<HTMLTableCell
> m_aCells
; ///< cells of the row
292 std::unique_ptr
<SvxBrushItem
> m_xBGBrush
; // background of cell from STYLE
295 sal_uInt16 m_nHeight
; // options of <TR>/<TD>
296 sal_uInt16 m_nEmptyRows
; // number of empty rows are following
297 sal_Int16 m_eVertOri
;
298 bool m_bIsEndOfGroup
: 1;
299 bool m_bBottomBorder
: 1; // Is there a line after the row?
303 explicit HTMLTableRow( sal_uInt16 nCells
); // cells of the row are empty
305 void SetBottomBorder(bool bIn
) { m_bBottomBorder
= bIn
; }
306 bool GetBottomBorder() const { return m_bBottomBorder
; }
308 inline void SetHeight( sal_uInt16 nHeight
);
309 sal_uInt16
GetHeight() const { return m_nHeight
; }
311 const HTMLTableCell
& GetCell(sal_uInt16 nCell
) const;
312 HTMLTableCell
& GetCell(sal_uInt16 nCell
)
314 return const_cast<HTMLTableCell
&>(const_cast<const HTMLTableRow
&>(*this).GetCell(nCell
));
317 void SetAdjust( SvxAdjust eAdj
) { m_eAdjust
= eAdj
; }
318 SvxAdjust
GetAdjust() const { return m_eAdjust
; }
320 void SetVertOri( sal_Int16 eV
) { m_eVertOri
= eV
; }
321 sal_Int16
GetVertOri() const { return m_eVertOri
; }
323 void SetBGBrush(std::unique_ptr
<SvxBrushItem
>& rBrush
) { m_xBGBrush
= std::move(rBrush
); }
324 const std::unique_ptr
<SvxBrushItem
>& GetBGBrush() const { return m_xBGBrush
; }
326 void SetEndOfGroup() { m_bIsEndOfGroup
= true; }
327 bool IsEndOfGroup() const { return m_bIsEndOfGroup
; }
329 void IncEmptyRows() { m_nEmptyRows
++; }
330 sal_uInt16
GetEmptyRows() const { return m_nEmptyRows
; }
332 // Expand row by adding empty cells
333 void Expand( sal_uInt16 nCells
, bool bOneCell
=false );
335 // Shrink row by deleting empty cells
336 void Shrink( sal_uInt16 nCells
);
339 // Column of a HTML table
340 class HTMLTableColumn
342 bool m_bIsEndOfGroup
;
344 sal_uInt16 m_nWidth
; // options of <COL>
348 sal_Int16 m_eVertOri
;
350 SwFrameFormat
*m_aFrameFormats
[6];
352 static inline sal_uInt16
GetFrameFormatIdx( bool bBorderLine
,
353 sal_Int16 eVertOri
);
357 bool m_bLeftBorder
; // is there a line before the column
361 inline void SetWidth( sal_uInt16 nWidth
, bool bRelWidth
);
363 void SetAdjust( SvxAdjust eAdj
) { m_eAdjust
= eAdj
; }
364 SvxAdjust
GetAdjust() const { return m_eAdjust
; }
366 void SetVertOri( sal_Int16 eV
) { m_eVertOri
= eV
; }
367 sal_Int16
GetVertOri() const { return m_eVertOri
; }
369 void SetEndOfGroup() { m_bIsEndOfGroup
= true; }
370 bool IsEndOfGroup() const { return m_bIsEndOfGroup
; }
372 inline void SetFrameFormat( SwFrameFormat
*pFormat
, bool bBorderLine
,
373 sal_Int16 eVertOri
);
374 inline SwFrameFormat
*GetFrameFormat( bool bBorderLine
,
375 sal_Int16 eVertOri
) const;
377 std::unique_ptr
<SwHTMLTableLayoutColumn
> CreateLayoutInfo();
383 typedef std::vector
<SdrObject
*> SdrObjects
;
385 class HTMLTable
: public sdr::ObjectUser
392 std::optional
<SdrObjects
> m_xResizeDrawObjects
;// SDR objects
393 std::optional
<std::vector
<sal_uInt16
>> m_xDrawObjectPercentWidths
; // column of draw object and its rel. width
395 std::vector
<HTMLTableRow
> m_aRows
; ///< table rows
396 std::vector
<HTMLTableColumn
> m_aColumns
; ///< table columns
398 sal_uInt16 m_nRows
; // number of rows
399 sal_uInt16 m_nCols
; // number of columns
400 sal_uInt16 m_nFilledColumns
; // number of filled columns
402 sal_uInt16 m_nCurrentRow
; // current Row
403 sal_uInt16 m_nCurrentColumn
; // current Column
405 sal_uInt16 m_nLeftMargin
; // Space to the left margin (from paragraph edge)
406 sal_uInt16 m_nRightMargin
; // Space to the right margin (from paragraph edge)
408 sal_uInt16 m_nCellPadding
; // Space from border to Text
409 sal_uInt16 m_nCellSpacing
; // Space between two cells
410 sal_uInt16 m_nHSpace
;
411 sal_uInt16 m_nVSpace
;
413 sal_uInt16 m_nBoxes
; // number of boxes in the table
415 const SwStartNode
*m_pPrevStartNode
; // the Table-Node or the Start-Node of the section before
416 const SwTable
*m_pSwTable
; // SW-Table (only on Top-Level)
418 std::unique_ptr
<SwTableBox
> m_xBox1
; // TableBox, generated when the Top-Level-Table was build
420 SwTableBoxFormat
*m_pBoxFormat
; // frame::Frame-Format from SwTableBox
421 SwTableLineFormat
*m_pLineFormat
; // frame::Frame-Format from SwTableLine
422 SwTableLineFormat
*m_pLineFrameFormatNoHeight
;
423 std::unique_ptr
<SvxBrushItem
> m_xBackgroundBrush
; // background of the table
424 std::unique_ptr
<SvxBrushItem
> m_xInheritedBackgroundBrush
; // "inherited" background of the table
425 const SwStartNode
*m_pCaptionStartNode
; // Start-Node of the table-caption
426 //lines for the border
427 SvxBorderLine m_aTopBorderLine
;
428 SvxBorderLine m_aBottomBorderLine
;
429 SvxBorderLine m_aLeftBorderLine
;
430 SvxBorderLine m_aRightBorderLine
;
431 SvxBorderLine m_aBorderLine
;
432 SvxBorderLine m_aInheritedLeftBorderLine
;
433 SvxBorderLine m_aInheritedRightBorderLine
;
434 bool m_bTopBorder
; // is there a line on the top of the table
435 bool m_bRightBorder
; // is there a line on the top right of the table
436 bool m_bTopAllowed
; // is it allowed to set the border?
437 bool m_bRightAllowed
;
438 bool m_bFillerTopBorder
; // gets the left/right filler-cell a border on the
439 bool m_bFillerBottomBorder
; // top or in the bottom
440 bool m_bInheritedLeftBorder
;
441 bool m_bInheritedRightBorder
;
442 bool m_bBordersSet
; // the border is set already
444 bool m_bTableAdjustOfTag
; // comes nTableAdjust from <TABLE>?
445 sal_uInt32 m_nHeadlineRepeat
; // repeating rows
446 bool m_bIsParentHead
;
447 bool m_bHasParentSection
;
450 bool m_bColSpec
; // where there COL(GROUP)-elements?
451 bool m_bPercentWidth
; // width is declared in %
453 SwHTMLParser
*m_pParser
; // the current parser
454 std::unique_ptr
<HTMLTableCnts
> m_xParentContents
;
456 std::unique_ptr
<HTMLTableContext
> m_pContext
; // the context of the table
458 std::shared_ptr
<SwHTMLTableLayout
> m_xLayoutInfo
;
460 // the following parameters are from the <TABLE>-Tag
461 sal_uInt16 m_nWidth
; // width of the table
462 sal_uInt16 m_nHeight
; // absolute height of the table
463 SvxAdjust m_eTableAdjust
; // drawing::Alignment of the table
464 sal_Int16 m_eVertOrientation
; // Default vertical direction of the cells
465 sal_uInt16 m_nBorder
; // width of the external border
466 HTMLTableFrame m_eFrame
; // frame around the table
467 HTMLTableRules m_eRules
; // frame in the table
468 bool m_bTopCaption
; // Caption of the table
470 void InitCtor(const HTMLTableOptions
& rOptions
);
472 // Correction of the Row-Spans for all cells above the chosen cell and the cell itself for the indicated content. The chosen cell gets the Row-Span 1
473 void FixRowSpan( sal_uInt16 nRow
, sal_uInt16 nCol
, const HTMLTableCnts
*pCnts
);
475 // Protects the chosen cell and the cells among
476 void ProtectRowSpan( sal_uInt16 nRow
, sal_uInt16 nCol
, sal_uInt16 nRowSpan
);
478 // Looking for the SwStartNodes of the box ahead
479 // If nRow==nCell==USHRT_MAX, return the last Start-Node of the table.
480 const SwStartNode
* GetPrevBoxStartNode( sal_uInt16 nRow
, sal_uInt16 nCell
) const;
482 sal_uInt16
GetTopCellSpace( sal_uInt16 nRow
) const;
483 sal_uInt16
GetBottomCellSpace( sal_uInt16 nRow
, sal_uInt16 nRowSpan
) const;
485 // Conforming of the frame::Frame-Format of the box
486 void FixFrameFormat( SwTableBox
*pBox
, sal_uInt16 nRow
, sal_uInt16 nCol
,
487 sal_uInt16 nRowSpan
, sal_uInt16 nColSpan
,
488 bool bFirstPara
=true, bool bLastPara
=true ) const;
490 // Create a table with the content (lines/boxes)
491 void MakeTable_( SwTableBox
*pUpper
);
493 // Generate a new SwTableBox, which contains a SwStartNode
494 SwTableBox
*NewTableBox( const SwStartNode
*pStNd
,
495 SwTableLine
*pUpper
) const;
497 // Generate a SwTableLine from the cells of the rectangle
498 // (nTopRow/nLeftCol) inclusive to (nBottomRow/nRightRow) exclusive
499 SwTableLine
*MakeTableLine( SwTableBox
*pUpper
,
500 sal_uInt16 nTopRow
, sal_uInt16 nLeftCol
,
501 sal_uInt16 nBottomRow
, sal_uInt16 nRightCol
);
503 // Generate a SwTableBox from the content of the cell
504 SwTableBox
*MakeTableBox( SwTableLine
*pUpper
,
505 HTMLTableCnts
*pCnts
,
506 sal_uInt16 nTopRow
, sal_uInt16 nLeftCol
,
507 sal_uInt16 nBootomRow
, sal_uInt16 nRightCol
);
509 // Autolayout-Algorithm
511 // Setting the border with the help of guidelines of the Parent-Table
512 void InheritBorders( const HTMLTable
*pParent
,
513 sal_uInt16 nRow
, sal_uInt16 nCol
,
515 bool bFirstPara
, bool bLastPara
);
517 // Inherit the left and the right border of the surrounding table
518 void InheritVertBorders( const HTMLTable
*pParent
,
519 sal_uInt16 nCol
, sal_uInt16 nColSpan
);
521 // Set the border with the help of the information from the user
524 // is the border already set?
525 bool BordersSet() const { return m_bBordersSet
; }
527 const std::unique_ptr
<SvxBrushItem
>& GetBGBrush() const { return m_xBackgroundBrush
; }
528 const std::unique_ptr
<SvxBrushItem
>& GetInhBGBrush() const { return m_xInheritedBackgroundBrush
; }
530 sal_uInt16
GetBorderWidth( const SvxBorderLine
& rBLine
,
531 bool bWithDistance
=false ) const;
533 virtual void ObjectInDestruction(const SdrObject
& rObject
) override
;
537 bool m_bFirstCell
; // is there a cell created already?
539 HTMLTable(SwHTMLParser
* pPars
,
540 bool bParHead
, bool bHasParentSec
,
542 const HTMLTableOptions
& rOptions
);
544 virtual ~HTMLTable();
546 // Identifying of a cell
547 const HTMLTableCell
& GetCell(sal_uInt16 nRow
, sal_uInt16 nCell
) const;
548 HTMLTableCell
& GetCell(sal_uInt16 nRow
, sal_uInt16 nCell
)
550 return const_cast<HTMLTableCell
&>(const_cast<const HTMLTable
&>(*this).GetCell(nRow
, nCell
));
553 // set/determine caption
554 inline void SetCaption( const SwStartNode
*pStNd
, bool bTop
);
555 const SwStartNode
*GetCaptionStartNode() const { return m_pCaptionStartNode
; }
556 bool IsTopCaption() const { return m_bTopCaption
; }
558 SvxAdjust
GetTableAdjust( bool bAny
) const
560 return (m_bTableAdjustOfTag
|| bAny
) ? m_eTableAdjust
: SvxAdjust::End
;
563 sal_uInt16
GetHSpace() const { return m_nHSpace
; }
564 sal_uInt16
GetVSpace() const { return m_nVSpace
; }
566 // get inherited drawing::Alignment of rows and column
567 SvxAdjust
GetInheritedAdjust() const;
568 sal_Int16
GetInheritedVertOri() const;
570 // Insert a cell on the current position
571 void InsertCell( std::shared_ptr
<HTMLTableCnts
> const& rCnts
, sal_uInt16 nRowSpan
, sal_uInt16 nColSpan
,
572 sal_uInt16 nWidth
, bool bRelWidth
, sal_uInt16 nHeight
,
573 sal_Int16 eVertOri
, std::shared_ptr
<SvxBrushItem
> const& rBGBrushItem
,
574 std::shared_ptr
<SvxBoxItem
> const& rBoxItem
,
575 bool bHasNumFormat
, sal_uInt32 nNumFormat
,
576 bool bHasValue
, double nValue
, bool bNoWrap
);
578 // announce the start/end of a new row
579 void OpenRow(SvxAdjust eAdjust
, sal_Int16 eVertOri
, std::unique_ptr
<SvxBrushItem
>& rBGBrush
);
580 void CloseRow( bool bEmpty
);
582 // announce the end of a new section
583 inline void CloseSection( bool bHead
);
585 // announce the end of a column-group
586 inline void CloseColGroup( sal_uInt16 nSpan
, sal_uInt16 nWidth
, bool bRelWidth
,
587 SvxAdjust eAdjust
, sal_Int16 eVertOri
);
589 // insert a new column
590 void InsertCol( sal_uInt16 nSpan
, sal_uInt16 nWidth
, bool bRelWidth
,
591 SvxAdjust eAdjust
, sal_Int16 eVertOri
);
593 // End a table definition (needs to be called for every table)
596 // Construct a SwTable (including child tables)
597 void MakeTable( SwTableBox
*pUpper
, sal_uInt16 nAbsAvail
,
598 sal_uInt16 nRelAvail
=0, sal_uInt16 nAbsLeftSpace
=0,
599 sal_uInt16 nAbsRightSpace
=0, sal_uInt16 nInhAbsSpace
=0 );
601 bool IsNewDoc() const { return m_pParser
->IsNewDoc(); }
603 void SetHasParentSection( bool bSet
) { m_bHasParentSection
= bSet
; }
604 bool HasParentSection() const { return m_bHasParentSection
; }
606 void SetParentContents(std::unique_ptr
<HTMLTableCnts
> pCnts
) { m_xParentContents
= std::move(pCnts
); }
607 std::unique_ptr
<HTMLTableCnts
>& GetParentContents() { return m_xParentContents
; }
609 void MakeParentContents();
611 bool HasToFly() const { return m_bHasToFly
; }
613 void SetTable( const SwStartNode
*pStNd
, std::unique_ptr
<HTMLTableContext
> pCntxt
,
614 sal_uInt16 nLeft
, sal_uInt16 nRight
,
615 const SwTable
*pSwTab
=nullptr, bool bFrcFrame
=false );
617 HTMLTableContext
*GetContext() const { return m_pContext
.get(); }
619 const std::shared_ptr
<SwHTMLTableLayout
>& CreateLayoutInfo();
621 bool HasColTags() const { return m_bColSpec
; }
623 sal_uInt16
IncGrfsThatResize() { return m_pSwTable
? const_cast<SwTable
*>(m_pSwTable
)->IncGrfsThatResize() : 0; }
625 void RegisterDrawObject( SdrObject
*pObj
, sal_uInt8 nPercentWidth
);
627 const SwTable
*GetSwTable() const { return m_pSwTable
; }
629 void SetBGBrush(const SvxBrushItem
& rBrush
) { m_xBackgroundBrush
.reset(new SvxBrushItem(rBrush
)); }
631 const OUString
& GetId() const { return m_aId
; }
632 const OUString
& GetClass() const { return m_aClass
; }
633 const OUString
& GetStyle() const { return m_aStyle
; }
634 const OUString
& GetDirection() const { return m_aDir
; }
636 void IncBoxCount() { m_nBoxes
++; }
637 bool IsOverflowing() const { return m_nBoxes
> 64000; }
640 void HTMLTableCnts::InitCtor()
643 m_xLayoutInfo
.reset();
647 HTMLTableCnts::HTMLTableCnts(const SwStartNode
* pStNd
)
648 : m_pStartNode(pStNd
)
653 HTMLTableCnts::HTMLTableCnts(std::shared_ptr
<HTMLTable
> xTab
)
654 : m_pStartNode(nullptr)
655 , m_xTable(std::move(xTab
))
660 HTMLTableCnts::~HTMLTableCnts()
662 m_xTable
.reset(); // we don't need the tables anymore
666 void HTMLTableCnts::Add( std::unique_ptr
<HTMLTableCnts
> pNewCnts
)
668 HTMLTableCnts
*pCnts
= this;
670 while( pCnts
->m_pNext
)
671 pCnts
= pCnts
->m_pNext
.get();
673 pCnts
->m_pNext
= std::move(pNewCnts
);
676 inline void HTMLTableCnts::SetTableBox( SwTableBox
*pBox
)
678 OSL_ENSURE(m_xLayoutInfo
, "There is no layout info");
680 m_xLayoutInfo
->SetTableBox(pBox
);
683 const std::shared_ptr
<SwHTMLTableLayoutCnts
>& HTMLTableCnts::CreateLayoutInfo()
687 std::shared_ptr
<SwHTMLTableLayoutCnts
> xNextInfo
;
689 xNextInfo
= m_pNext
->CreateLayoutInfo();
690 std::shared_ptr
<SwHTMLTableLayout
> xTableInfo
;
692 xTableInfo
= m_xTable
->CreateLayoutInfo();
693 m_xLayoutInfo
= std::make_shared
<SwHTMLTableLayoutCnts
>(m_pStartNode
, xTableInfo
, m_bNoBreak
, xNextInfo
);
696 return m_xLayoutInfo
;
699 HTMLTableCell::HTMLTableCell():
705 m_eVertOrient( text::VertOrientation::NONE
),
707 m_bRelWidth( false ),
708 m_bHasNumFormat(false),
714 void HTMLTableCell::Set( std::shared_ptr
<HTMLTableCnts
> const& rCnts
, sal_uInt16 nRSpan
, sal_uInt16 nCSpan
,
715 sal_Int16 eVert
, std::shared_ptr
<SvxBrushItem
> const& rBrush
,
716 std::shared_ptr
<SvxBoxItem
> const& rBoxItem
,
717 bool bHasNF
, sal_uInt32 nNF
, bool bHasV
, double nVal
,
718 bool bNWrap
, bool bCovered
)
723 m_bProtected
= false;
724 m_eVertOrient
= eVert
;
726 m_xBoxItem
= rBoxItem
;
728 m_bHasNumFormat
= bHasNF
;
734 mbCovered
= bCovered
;
737 inline void HTMLTableCell::SetWidth( sal_uInt16 nWdth
, bool bRelWdth
)
740 m_bRelWidth
= bRelWdth
;
743 void HTMLTableCell::SetProtected()
745 // The content of this cell doesn't have to be anchored anywhere else,
746 // since they're not gonna be deleted
750 // Copy background color
752 m_xBGBrush
= std::make_shared
<SvxBrushItem
>(*m_xBGBrush
);
759 inline bool HTMLTableCell::GetNumFormat( sal_uInt32
& rNumFormat
) const
761 rNumFormat
= m_nNumFormat
;
762 return m_bHasNumFormat
;
765 inline bool HTMLTableCell::GetValue( double& rValue
) const
771 std::unique_ptr
<SwHTMLTableLayoutCell
> HTMLTableCell::CreateLayoutInfo()
773 std::shared_ptr
<SwHTMLTableLayoutCnts
> xCntInfo
;
775 xCntInfo
= m_xContents
->CreateLayoutInfo();
776 return std::unique_ptr
<SwHTMLTableLayoutCell
>(new SwHTMLTableLayoutCell(xCntInfo
, m_nRowSpan
, m_nColSpan
, m_nWidth
,
777 m_bRelWidth
, m_bNoWrap
));
780 HTMLTableRow::HTMLTableRow(sal_uInt16
const nCells
)
782 , m_eAdjust(SvxAdjust::End
)
785 , m_eVertOri(text::VertOrientation::TOP
)
786 , m_bIsEndOfGroup(false)
787 , m_bBottomBorder(false)
789 assert(nCells
== m_aCells
.size() &&
790 "wrong Cell count in new HTML table row");
793 inline void HTMLTableRow::SetHeight( sal_uInt16 nHght
)
795 if( nHght
> m_nHeight
)
799 const HTMLTableCell
& HTMLTableRow::GetCell(sal_uInt16 nCell
) const
801 OSL_ENSURE( nCell
< m_aCells
.size(),
802 "invalid cell index in HTML table row" );
803 return m_aCells
.at(nCell
);
806 void HTMLTableRow::Expand( sal_uInt16 nCells
, bool bOneCell
)
808 // This row will be filled with a single cell if bOneCell is set.
809 // This will only work for rows that don't allow adding cells!
811 sal_uInt16 nColSpan
= nCells
- m_aCells
.size();
812 for (sal_uInt16 i
= m_aCells
.size(); i
< nCells
; ++i
)
814 m_aCells
.emplace_back();
816 m_aCells
.back().SetColSpan(nColSpan
);
820 OSL_ENSURE(nCells
== m_aCells
.size(),
821 "wrong Cell count in expanded HTML table row");
824 void HTMLTableRow::Shrink( sal_uInt16 nCells
)
826 OSL_ENSURE(nCells
< m_aCells
.size(), "number of cells too large");
828 #if OSL_DEBUG_LEVEL > 0
829 sal_uInt16
const nEnd
= m_aCells
.size();
831 // The colspan of empty cells at the end has to be fixed to the new
836 HTMLTableCell
& rCell
= m_aCells
[--i
];
837 if (!rCell
.GetContents())
839 #if OSL_DEBUG_LEVEL > 0
840 OSL_ENSURE( rCell
.GetColSpan() == nEnd
- i
,
841 "invalid col span for empty cell at row end" );
843 rCell
.SetColSpan( nCells
-i
);
848 #if OSL_DEBUG_LEVEL > 0
849 for( i
=nCells
; i
<nEnd
; i
++ )
851 HTMLTableCell
& rCell
= m_aCells
[i
];
852 OSL_ENSURE( rCell
.GetRowSpan() == 1,
853 "RowSpan of to be deleted cell is wrong" );
854 OSL_ENSURE( rCell
.GetColSpan() == nEnd
- i
,
855 "ColSpan of to be deleted cell is wrong" );
856 OSL_ENSURE( !rCell
.GetContents(), "To be deleted cell has content" );
860 m_aCells
.erase(m_aCells
.begin() + nCells
, m_aCells
.end());
863 HTMLTableColumn::HTMLTableColumn():
864 m_bIsEndOfGroup(false),
865 m_nWidth(0), m_bRelWidth(false),
866 m_eAdjust(SvxAdjust::End
), m_eVertOri(text::VertOrientation::TOP
),
869 for(SwFrameFormat
* & rp
: m_aFrameFormats
)
873 inline void HTMLTableColumn::SetWidth( sal_uInt16 nWdth
, bool bRelWdth
)
875 if( m_bRelWidth
==bRelWdth
)
877 if( nWdth
> m_nWidth
)
882 m_bRelWidth
= bRelWdth
;
885 inline std::unique_ptr
<SwHTMLTableLayoutColumn
> HTMLTableColumn::CreateLayoutInfo()
887 return std::unique_ptr
<SwHTMLTableLayoutColumn
>(new SwHTMLTableLayoutColumn( m_nWidth
, m_bRelWidth
, m_bLeftBorder
));
890 inline sal_uInt16
HTMLTableColumn::GetFrameFormatIdx( bool bBorderLine
,
891 sal_Int16 eVertOrient
)
893 OSL_ENSURE( text::VertOrientation::TOP
!= eVertOrient
, "Top is not allowed" );
894 sal_uInt16 n
= bBorderLine
? 3 : 0;
895 switch( eVertOrient
)
897 case text::VertOrientation::CENTER
: n
+=1; break;
898 case text::VertOrientation::BOTTOM
: n
+=2; break;
905 inline void HTMLTableColumn::SetFrameFormat( SwFrameFormat
*pFormat
, bool bBorderLine
,
906 sal_Int16 eVertOrient
)
908 m_aFrameFormats
[GetFrameFormatIdx(bBorderLine
,eVertOrient
)] = pFormat
;
911 inline SwFrameFormat
*HTMLTableColumn::GetFrameFormat( bool bBorderLine
,
912 sal_Int16 eVertOrient
) const
914 return m_aFrameFormats
[GetFrameFormatIdx(bBorderLine
,eVertOrient
)];
917 void HTMLTable::InitCtor(const HTMLTableOptions
& rOptions
)
920 m_nCurrentRow
= 0; m_nCurrentColumn
= 0;
922 m_pBoxFormat
= nullptr; m_pLineFormat
= nullptr;
923 m_pLineFrameFormatNoHeight
= nullptr;
924 m_xInheritedBackgroundBrush
.reset();
926 m_pPrevStartNode
= nullptr;
927 m_pSwTable
= nullptr;
929 m_bTopBorder
= false; m_bRightBorder
= false;
930 m_bTopAllowed
= true; m_bRightAllowed
= true;
931 m_bFillerTopBorder
= false; m_bFillerBottomBorder
= false;
932 m_bInheritedLeftBorder
= false; m_bInheritedRightBorder
= false;
933 m_bBordersSet
= false;
934 m_bForceFrame
= false;
935 m_nHeadlineRepeat
= 0;
940 const Color
& rBorderColor
= rOptions
.aBorderColor
;
942 tools::Long nBorderOpt
= static_cast<tools::Long
>(rOptions
.nBorder
);
943 tools::Long nPWidth
= nBorderOpt
==USHRT_MAX
? NETSCAPE_DFLT_BORDER
945 tools::Long nPHeight
= nBorderOpt
==USHRT_MAX
? 0 : nBorderOpt
;
946 SvxCSS1Parser::PixelToTwip( nPWidth
, nPHeight
);
948 // nBorder tells the width of the border as it's used in the width calculation of NetScape
949 // If pOption->nBorder == USHRT_MAX, there wasn't a BORDER option given
950 // Nonetheless, a 1 pixel wide border will be used for width calculation
951 m_nBorder
= o3tl::narrowing
<sal_uInt16
>(nPWidth
);
952 if( nBorderOpt
==USHRT_MAX
)
955 if ( rOptions
.nCellSpacing
!= 0 )
957 m_aTopBorderLine
.SetBorderLineStyle(SvxBorderLineStyle::DOUBLE
);
959 m_aTopBorderLine
.SetWidth( nPHeight
);
960 m_aTopBorderLine
.SetColor( rBorderColor
);
961 m_aBottomBorderLine
= m_aTopBorderLine
;
963 if( nPWidth
== nPHeight
)
965 m_aLeftBorderLine
= m_aTopBorderLine
;
969 if ( rOptions
.nCellSpacing
!= 0 )
971 m_aLeftBorderLine
.SetBorderLineStyle(SvxBorderLineStyle::DOUBLE
);
973 m_aLeftBorderLine
.SetWidth( nPWidth
);
974 m_aLeftBorderLine
.SetColor( rBorderColor
);
976 m_aRightBorderLine
= m_aLeftBorderLine
;
978 if( rOptions
.nCellSpacing
!= 0 )
979 m_aBorderLine
.SetBorderLineStyle(SvxBorderLineStyle::DOUBLE
);
980 m_aBorderLine
.SetWidth(SvxBorderLineWidth::Hairline
);
981 m_aBorderLine
.SetColor( rBorderColor
);
985 if( m_nCellPadding
==USHRT_MAX
)
986 m_nCellPadding
= MIN_BORDER_DIST
; // default
989 m_nCellPadding
= SwHTMLParser::ToTwips( m_nCellPadding
);
990 if( m_nCellPadding
<MIN_BORDER_DIST
)
991 m_nCellPadding
= MIN_BORDER_DIST
;
996 if( m_nCellSpacing
==USHRT_MAX
)
997 m_nCellSpacing
= NETSCAPE_DFLT_CELLSPACING
;
998 m_nCellSpacing
= SwHTMLParser::ToTwips( m_nCellSpacing
);
1001 nPWidth
= rOptions
.nHSpace
;
1002 nPHeight
= rOptions
.nVSpace
;
1003 SvxCSS1Parser::PixelToTwip( nPWidth
, nPHeight
);
1004 m_nHSpace
= o3tl::narrowing
<sal_uInt16
>(nPWidth
);
1005 m_nVSpace
= o3tl::narrowing
<sal_uInt16
>(nPHeight
);
1009 m_xBackgroundBrush
.reset(m_pParser
->CreateBrushItem(
1010 rOptions
.bBGColor
? &(rOptions
.aBGColor
) : nullptr,
1011 rOptions
.aBGImage
, OUString(), OUString(), OUString()));
1013 m_pContext
= nullptr;
1014 m_xParentContents
.reset();
1016 m_aId
= rOptions
.aId
;
1017 m_aClass
= rOptions
.aClass
;
1018 m_aStyle
= rOptions
.aStyle
;
1019 m_aDir
= rOptions
.aDir
;
1022 HTMLTable::HTMLTable(SwHTMLParser
* pPars
,
1024 bool bHasParentSec
, bool bHasToFlw
,
1025 const HTMLTableOptions
& rOptions
) :
1026 m_aColumns(rOptions
.nCols
),
1027 m_nCols(rOptions
.nCols
),
1028 m_nFilledColumns( 0 ),
1029 m_nCellPadding(rOptions
.nCellPadding
),
1030 m_nCellSpacing(rOptions
.nCellSpacing
),
1032 m_pCaptionStartNode( nullptr ),
1033 m_bTableAdjustOfTag( rOptions
.bTableAdjust
),
1034 m_bIsParentHead( bParHead
),
1035 m_bHasParentSection( bHasParentSec
),
1036 m_bHasToFly( bHasToFlw
),
1037 m_bFixedCols( rOptions
.nCols
>0 ),
1038 m_bPercentWidth( rOptions
.bPercentWidth
),
1040 m_nWidth( rOptions
.nWidth
),
1041 m_nHeight( rOptions
.nHeight
),
1042 m_eTableAdjust( rOptions
.eAdjust
),
1043 m_eVertOrientation( rOptions
.eVertOri
),
1044 m_eFrame( rOptions
.eFrame
),
1045 m_eRules( rOptions
.eRules
),
1046 m_bTopCaption( false ),
1050 m_pParser
->RegisterHTMLTable(this);
1053 void SwHTMLParser::DeregisterHTMLTable(HTMLTable
* pOld
)
1056 m_aOrphanedTableBoxes
.emplace_back(std::move(pOld
->m_xBox1
));
1057 m_aTables
.erase(std::remove(m_aTables
.begin(), m_aTables
.end(), pOld
));
1060 SwDoc
* SwHTMLParser::GetDoc() const
1062 return m_xDoc
.get();
1065 bool SwHTMLParser::IsReqIF() const
1070 // if any m_xResizeDrawObjects members are deleted during parse, remove them
1071 // from m_xResizeDrawObjects and m_xDrawObjectPercentWidths
1072 void HTMLTable::ObjectInDestruction(const SdrObject
& rObject
)
1074 auto it
= std::find(m_xResizeDrawObjects
->begin(), m_xResizeDrawObjects
->end(), &rObject
);
1075 assert(it
!= m_xResizeDrawObjects
->end());
1076 auto nIndex
= std::distance(m_xResizeDrawObjects
->begin(), it
);
1077 m_xResizeDrawObjects
->erase(it
);
1078 auto otherit
= m_xDrawObjectPercentWidths
->begin() + nIndex
* 3;
1079 m_xDrawObjectPercentWidths
->erase(otherit
, otherit
+ 3);
1082 HTMLTable::~HTMLTable()
1084 m_pParser
->DeregisterHTMLTable(this);
1086 if (m_xResizeDrawObjects
)
1088 size_t nCount
= m_xResizeDrawObjects
->size();
1089 for (size_t i
= 0; i
< nCount
; ++i
)
1091 SdrObject
*pObj
= (*m_xResizeDrawObjects
)[i
];
1092 pObj
->RemoveObjectUser(*this);
1094 m_xResizeDrawObjects
.reset();
1097 m_xDrawObjectPercentWidths
.reset();
1101 // pLayoutInfo has either already been deleted or is now owned by SwTable
1104 const std::shared_ptr
<SwHTMLTableLayout
>& HTMLTable::CreateLayoutInfo()
1106 sal_uInt16 nW
= m_bPercentWidth
? m_nWidth
: SwHTMLParser::ToTwips( m_nWidth
);
1108 sal_uInt16 nBorderWidth
= GetBorderWidth( m_aBorderLine
, true );
1109 sal_uInt16 nLeftBorderWidth
=
1110 m_aColumns
[0].m_bLeftBorder
? GetBorderWidth(m_aLeftBorderLine
, true) : 0;
1111 sal_uInt16 nRightBorderWidth
=
1112 m_bRightBorder
? GetBorderWidth( m_aRightBorderLine
, true ) : 0;
1114 m_xLayoutInfo
= std::make_shared
<SwHTMLTableLayout
>(
1116 m_nRows
, m_nCols
, m_bFixedCols
, m_bColSpec
,
1117 nW
, m_bPercentWidth
, m_nBorder
, m_nCellPadding
,
1118 m_nCellSpacing
, m_eTableAdjust
,
1119 m_nLeftMargin
, m_nRightMargin
,
1120 nBorderWidth
, nLeftBorderWidth
, nRightBorderWidth
);
1122 bool bExportable
= true;
1124 for( i
=0; i
<m_nRows
; i
++ )
1126 HTMLTableRow
& rRow
= m_aRows
[i
];
1127 for( sal_uInt16 j
=0; j
<m_nCols
; j
++ )
1129 m_xLayoutInfo
->SetCell(rRow
.GetCell(j
).CreateLayoutInfo(), i
, j
);
1130 SwHTMLTableLayoutCell
* pLayoutCell
= m_xLayoutInfo
->GetCell(i
, j
);
1134 const std::shared_ptr
<SwHTMLTableLayoutCnts
>& rLayoutCnts
=
1135 pLayoutCell
->GetContents();
1136 bExportable
= !rLayoutCnts
||
1137 (rLayoutCnts
->GetStartNode() && !rLayoutCnts
->GetNext());
1142 m_xLayoutInfo
->SetExportable( bExportable
);
1144 for( i
=0; i
<m_nCols
; i
++ )
1145 m_xLayoutInfo
->SetColumn(m_aColumns
[i
].CreateLayoutInfo(), i
);
1147 return m_xLayoutInfo
;
1150 inline void HTMLTable::SetCaption( const SwStartNode
*pStNd
, bool bTop
)
1152 m_pCaptionStartNode
= pStNd
;
1153 m_bTopCaption
= bTop
;
1156 void HTMLTable::FixRowSpan( sal_uInt16 nRow
, sal_uInt16 nCol
,
1157 const HTMLTableCnts
*pCnts
)
1159 sal_uInt16 nRowSpan
=1;
1162 HTMLTableCell
& rCell
= GetCell(nRow
, nCol
);
1163 if (rCell
.GetContents().get() != pCnts
)
1165 rCell
.SetRowSpan(nRowSpan
);
1167 m_xLayoutInfo
->GetCell(nRow
,nCol
)->SetRowSpan(nRowSpan
);
1174 void HTMLTable::ProtectRowSpan( sal_uInt16 nRow
, sal_uInt16 nCol
, sal_uInt16 nRowSpan
)
1176 for( sal_uInt16 i
=0; i
<nRowSpan
; i
++ )
1178 GetCell(nRow
+i
,nCol
).SetProtected();
1180 m_xLayoutInfo
->GetCell(nRow
+i
,nCol
)->SetProtected();
1184 // Search the SwStartNode of the last used predecessor box
1185 const SwStartNode
* HTMLTable::GetPrevBoxStartNode( sal_uInt16 nRow
, sal_uInt16 nCol
) const
1187 const HTMLTableCnts
*pPrevCnts
= nullptr;
1191 // always the predecessor cell
1193 pPrevCnts
= GetCell(0, nCol
- 1).GetContents().get();
1195 return m_pPrevStartNode
;
1197 else if( USHRT_MAX
==nRow
&& USHRT_MAX
==nCol
)
1198 // contents of preceding cell
1199 pPrevCnts
= GetCell(m_nRows
- 1, m_nCols
- 1).GetContents().get();
1203 const HTMLTableRow
& rPrevRow
= m_aRows
[nRow
-1];
1205 // maybe a cell in the current row
1210 if( 1 == rPrevRow
.GetCell(i
).GetRowSpan() )
1212 pPrevCnts
= GetCell(nRow
, i
).GetContents().get();
1217 // otherwise the last filled cell of the row before
1221 while( !pPrevCnts
&& i
)
1224 pPrevCnts
= rPrevRow
.GetCell(i
).GetContents().get();
1228 OSL_ENSURE( pPrevCnts
, "No previous filled cell found" );
1231 pPrevCnts
= GetCell(0, 0).GetContents().get();
1233 return m_pPrevStartNode
;
1236 while( pPrevCnts
->Next() )
1237 pPrevCnts
= pPrevCnts
->Next();
1239 const SwStartNode
* pRet
= pPrevCnts
->GetStartNode();
1242 HTMLTable
* pTable
= pPrevCnts
->GetTable().get();
1245 return pTable
->GetPrevBoxStartNode(USHRT_MAX
, USHRT_MAX
);
1248 sal_uInt16
HTMLTable::GetTopCellSpace( sal_uInt16 nRow
) const
1250 sal_uInt16 nSpace
= m_nCellPadding
;
1254 nSpace
+= m_nBorder
+ m_nCellSpacing
;
1260 sal_uInt16
HTMLTable::GetBottomCellSpace( sal_uInt16 nRow
, sal_uInt16 nRowSpan
) const
1262 sal_uInt16 nSpace
= m_nCellSpacing
+ m_nCellPadding
;
1264 if( nRow
+nRowSpan
== m_nRows
)
1266 nSpace
= nSpace
+ m_nBorder
;
1272 void HTMLTable::FixFrameFormat( SwTableBox
*pBox
,
1273 sal_uInt16 nRow
, sal_uInt16 nCol
,
1274 sal_uInt16 nRowSpan
, sal_uInt16 nColSpan
,
1275 bool bFirstPara
, bool bLastPara
) const
1277 SwFrameFormat
*pFrameFormat
= nullptr; // frame::Frame format
1278 sal_Int16 eVOri
= text::VertOrientation::NONE
;
1279 const SvxBrushItem
*pBGBrushItem
= nullptr; // background
1280 std::shared_ptr
<SvxBoxItem
> pBoxItem
;
1281 bool bTopLine
= false, bBottomLine
= false, bLastBottomLine
= false;
1282 bool bReUsable
= false; // Format reusable?
1283 sal_uInt16 nEmptyRows
= 0;
1284 bool bHasNumFormat
= false;
1285 bool bHasValue
= false;
1286 sal_uInt32 nNumFormat
= 0;
1287 double nValue
= 0.0;
1289 const HTMLTableColumn
& rColumn
= m_aColumns
[nCol
];
1291 if( pBox
->GetSttNd() )
1293 // Determine background color/graphic
1294 const HTMLTableCell
& rCell
= GetCell(nRow
, nCol
);
1295 pBoxItem
= rCell
.GetBoxItem();
1296 pBGBrushItem
= rCell
.GetBGBrush().get();
1299 // If a cell spans multiple rows, a background to that row should be copied to the cell.
1302 pBGBrushItem
= m_aRows
[nRow
].GetBGBrush().get();
1306 bTopLine
= 0==nRow
&& m_bTopBorder
&& bFirstPara
;
1307 if (m_aRows
[nRow
+nRowSpan
-1].GetBottomBorder() && bLastPara
)
1309 nEmptyRows
= m_aRows
[nRow
+nRowSpan
-1].GetEmptyRows();
1310 if( nRow
+nRowSpan
== m_nRows
)
1311 bLastBottomLine
= true;
1316 eVOri
= rCell
.GetVertOri();
1317 bHasNumFormat
= rCell
.GetNumFormat( nNumFormat
);
1319 bHasValue
= rCell
.GetValue( nValue
);
1321 if( nColSpan
==1 && !bTopLine
&& !bLastBottomLine
&& !nEmptyRows
&&
1322 !pBGBrushItem
&& !bHasNumFormat
&& !pBoxItem
)
1324 pFrameFormat
= rColumn
.GetFrameFormat( bBottomLine
, eVOri
);
1325 bReUsable
= !pFrameFormat
;
1331 pFrameFormat
= pBox
->ClaimFrameFormat();
1333 // calculate width of the box
1334 SwTwips nFrameWidth
= static_cast<SwTwips
>(m_xLayoutInfo
->GetColumn(nCol
)
1335 ->GetRelColWidth());
1336 for( sal_uInt16 i
=1; i
<nColSpan
; i
++ )
1337 nFrameWidth
+= static_cast<SwTwips
>(m_xLayoutInfo
->GetColumn(nCol
+i
)
1338 ->GetRelColWidth());
1340 // Only set the border on edit boxes.
1341 // On setting the upper and lower border, keep in mind if
1342 // it's the first or the last paragraph of the cell
1343 if( pBox
->GetSttNd() )
1345 bool bSet
= (m_nCellPadding
> 0);
1347 SvxBoxItem
aBoxItem( RES_BOX
);
1348 tools::Long nInnerFrameWidth
= nFrameWidth
;
1352 aBoxItem
.SetLine( &m_aTopBorderLine
, SvxBoxItemLine::TOP
);
1355 if( bLastBottomLine
)
1357 aBoxItem
.SetLine( &m_aBottomBorderLine
, SvxBoxItemLine::BOTTOM
);
1360 else if( bBottomLine
)
1362 if( nEmptyRows
&& !m_aBorderLine
.GetInWidth() )
1364 // For now, empty rows can only be emulated by thick lines, if it's a single line
1365 SvxBorderLine
aThickBorderLine( m_aBorderLine
);
1367 sal_uInt16 nBorderWidth
= m_aBorderLine
.GetOutWidth();
1368 nBorderWidth
*= (nEmptyRows
+ 1);
1369 aThickBorderLine
.SetBorderLineStyle(SvxBorderLineStyle::SOLID
);
1370 aThickBorderLine
.SetWidth( nBorderWidth
);
1371 aBoxItem
.SetLine( &aThickBorderLine
, SvxBoxItemLine::BOTTOM
);
1375 aBoxItem
.SetLine( &m_aBorderLine
, SvxBoxItemLine::BOTTOM
);
1379 if (m_aColumns
[nCol
].m_bLeftBorder
)
1381 const SvxBorderLine
& rBorderLine
=
1382 0==nCol
? m_aLeftBorderLine
: m_aBorderLine
;
1383 aBoxItem
.SetLine( &rBorderLine
, SvxBoxItemLine::LEFT
);
1384 nInnerFrameWidth
-= GetBorderWidth( rBorderLine
);
1387 if( m_bRightBorder
)
1389 aBoxItem
.SetLine( &m_aRightBorderLine
, SvxBoxItemLine::RIGHT
);
1390 nInnerFrameWidth
-= GetBorderWidth( m_aRightBorderLine
);
1396 pFrameFormat
->SetFormatAttr( *pBoxItem
);
1400 // BorderDist is not part of a cell with fixed width
1401 sal_uInt16 nBDist
= static_cast< sal_uInt16
>(
1402 (2*m_nCellPadding
<= nInnerFrameWidth
) ? m_nCellPadding
1403 : (nInnerFrameWidth
/ 2) );
1404 // We only set the item if there's a border or a border distance
1405 // If the latter is missing, there's gonna be a border and we'll have to set the distance
1406 aBoxItem
.SetAllDistances(nBDist
? nBDist
: MIN_BORDER_DIST
);
1407 pFrameFormat
->SetFormatAttr( aBoxItem
);
1410 pFrameFormat
->ResetFormatAttr( RES_BOX
);
1414 pFrameFormat
->SetFormatAttr( *pBGBrushItem
);
1417 pFrameFormat
->ResetFormatAttr( RES_BACKGROUND
);
1419 // Only set format if there's a value or the box is empty
1420 if( bHasNumFormat
&& (bHasValue
|| pBox
->IsEmpty()) )
1422 bool bLock
= pFrameFormat
->GetDoc()->GetNumberFormatter()
1423 ->IsTextFormat( nNumFormat
);
1424 SfxItemSetFixed
<RES_BOXATR_FORMAT
, RES_BOXATR_VALUE
>
1425 aItemSet( *pFrameFormat
->GetAttrSet().GetPool() );
1426 SvxAdjust eAdjust
= SvxAdjust::End
;
1427 SwContentNode
*pCNd
= nullptr;
1430 const SwStartNode
*pSttNd
= pBox
->GetSttNd();
1431 pCNd
= pSttNd
->GetNodes()[pSttNd
->GetIndex()+1]
1433 const SvxAdjustItem
*pItem
;
1434 if( pCNd
&& pCNd
->HasSwAttrSet() &&
1435 (pItem
= pCNd
->GetpSwAttrSet()->GetItemIfSet(
1436 RES_PARATR_ADJUST
, false )) )
1438 eAdjust
= pItem
->GetAdjust();
1441 aItemSet
.Put( SwTableBoxNumFormat(nNumFormat
) );
1443 aItemSet
.Put( SwTableBoxValue(nValue
) );
1446 pFrameFormat
->LockModify();
1447 pFrameFormat
->SetFormatAttr( aItemSet
);
1449 pFrameFormat
->UnlockModify();
1450 else if( pCNd
&& SvxAdjust::End
!= eAdjust
)
1452 SvxAdjustItem
aAdjItem( eAdjust
, RES_PARATR_ADJUST
);
1453 pCNd
->SetAttr( aAdjItem
);
1457 pFrameFormat
->ResetFormatAttr( RES_BOXATR_FORMAT
);
1459 OSL_ENSURE( eVOri
!= text::VertOrientation::TOP
, "text::VertOrientation::TOP is not allowed!" );
1460 if( text::VertOrientation::NONE
!= eVOri
)
1462 pFrameFormat
->SetFormatAttr( SwFormatVertOrient( 0, eVOri
) );
1465 pFrameFormat
->ResetFormatAttr( RES_VERT_ORIENT
);
1468 const_cast<HTMLTableColumn
&>(rColumn
).SetFrameFormat(pFrameFormat
, bBottomLine
, eVOri
);
1472 pFrameFormat
->ResetFormatAttr( RES_BOX
);
1473 pFrameFormat
->ResetFormatAttr( RES_BACKGROUND
);
1474 pFrameFormat
->ResetFormatAttr( RES_VERT_ORIENT
);
1475 pFrameFormat
->ResetFormatAttr( RES_BOXATR_FORMAT
);
1478 if (m_pParser
->IsReqIF())
1480 // ReqIF case, cells would have no formatting. Apply the default
1481 // table autoformat on them, so imported and UI-created tables look
1483 SwTableAutoFormatTable
& rTable
= m_pParser
->GetDoc()->GetTableStyles();
1484 SwTableAutoFormat
* pTableFormat
= rTable
.FindAutoFormat(
1485 SwStyleNameMapper::GetUIName(RES_POOLTABLESTYLE_DEFAULT
, OUString()));
1488 sal_uInt8 nPos
= SwTableAutoFormat::CountPos(nCol
, m_nCols
, nRow
, m_nRows
);
1489 const SfxItemSet
& rAttrSet
= pFrameFormat
->GetAttrSet();
1490 std::unique_ptr
<SvxBoxItem
> pOldBoxItem
;
1491 if (const SvxBoxItem
* pBoxItem2
= rAttrSet
.GetItemIfSet(RES_BOX
))
1492 pOldBoxItem
.reset(pBoxItem2
->Clone());
1493 pTableFormat
->UpdateToSet(nPos
, m_nRows
==1, m_nCols
==1,
1494 const_cast<SfxItemSet
&>(rAttrSet
),
1495 SwTableAutoFormatUpdateFlags::Box
,
1496 pFrameFormat
->GetDoc()->GetNumberFormatter());
1499 // There was an old item, so it's guaranteed that there's a new item
1500 const SvxBoxItem
* pBoxItem2(rAttrSet
.GetItem(RES_BOX
));
1501 if (*pBoxItem2
!= *pOldBoxItem
)
1503 std::unique_ptr
<SvxBoxItem
> pNewBoxItem(pBoxItem2
->Clone());
1504 // Restore the box elements that could have been already set
1505 for (auto eLine
: { SvxBoxItemLine::TOP
, SvxBoxItemLine::BOTTOM
,
1506 SvxBoxItemLine::LEFT
, SvxBoxItemLine::RIGHT
})
1508 if (auto pLine
= pOldBoxItem
->GetLine(eLine
))
1509 pNewBoxItem
->SetLine(pLine
, eLine
);
1510 if (auto nDistance
= pOldBoxItem
->GetDistance(eLine
, true))
1511 pNewBoxItem
->SetDistance(nDistance
, eLine
);
1514 pFrameFormat
->SetFormatAttr(*pNewBoxItem
);
1522 OSL_ENSURE( pBox
->GetSttNd() ||
1523 SfxItemState::SET
!=pFrameFormat
->GetAttrSet().GetItemState(
1524 RES_VERT_ORIENT
, false ),
1525 "Box without content has vertical orientation" );
1526 pBox
->ChgFrameFormat( static_cast<SwTableBoxFormat
*>(pFrameFormat
) );
1531 SwTableBox
*HTMLTable::NewTableBox( const SwStartNode
*pStNd
,
1532 SwTableLine
*pUpper
) const
1536 if (m_xBox1
&& m_xBox1
->GetSttNd() == pStNd
)
1538 // If the StartNode is the StartNode of the initially created box, we take that box
1539 pBox
= const_cast<HTMLTable
*>(this)->m_xBox1
.release();
1540 pBox
->SetUpper(pUpper
);
1543 pBox
= new SwTableBox( m_pBoxFormat
, *pStNd
, pUpper
);
1548 static void ResetLineFrameFormatAttrs( SwFrameFormat
*pFrameFormat
)
1550 pFrameFormat
->ResetFormatAttr( RES_FRM_SIZE
);
1551 pFrameFormat
->ResetFormatAttr( RES_BACKGROUND
);
1552 OSL_ENSURE( SfxItemState::SET
!=pFrameFormat
->GetAttrSet().GetItemState(
1553 RES_VERT_ORIENT
, false ),
1554 "Cell has vertical orientation" );
1557 // !!! could be simplified
1558 SwTableLine
*HTMLTable::MakeTableLine( SwTableBox
*pUpper
,
1559 sal_uInt16 nTopRow
, sal_uInt16 nLeftCol
,
1560 sal_uInt16 nBottomRow
, sal_uInt16 nRightCol
)
1563 if (!pUpper
&& 0 == nTopRow
)
1564 pLine
= (m_pSwTable
->GetTabLines())[0];
1566 pLine
= new SwTableLine( m_pLineFrameFormatNoHeight
? m_pLineFrameFormatNoHeight
1570 const HTMLTableRow
& rTopRow
= m_aRows
[nTopRow
];
1571 sal_uInt16 nRowHeight
= rTopRow
.GetHeight();
1572 const SvxBrushItem
*pBGBrushItem
= nullptr;
1573 if (nTopRow
> 0 || nBottomRow
< m_nRows
)
1575 // It doesn't make sense to set a color on a line,
1576 // if it's the outermost and simultaneously sole line of a table in a table
1577 pBGBrushItem
= rTopRow
.GetBGBrush().get();
1579 if( nTopRow
==nBottomRow
-1 && (nRowHeight
|| pBGBrushItem
) )
1581 SwTableLineFormat
*pFrameFormat
= static_cast<SwTableLineFormat
*>(pLine
->ClaimFrameFormat());
1582 ResetLineFrameFormatAttrs( pFrameFormat
);
1586 // set table height. Since it's a minimum height it can be calculated like in Netscape,
1587 // so without considering the actual border width
1588 nRowHeight
+= GetTopCellSpace( nTopRow
) +
1589 GetBottomCellSpace( nTopRow
, 1 );
1591 pFrameFormat
->SetFormatAttr( SwFormatFrameSize( SwFrameSize::Minimum
, 0, nRowHeight
) );
1596 pFrameFormat
->SetFormatAttr( *pBGBrushItem
);
1600 else if( !m_pLineFrameFormatNoHeight
)
1602 // else, we'll have to remove the height from the attribute and remember the format
1603 m_pLineFrameFormatNoHeight
= static_cast<SwTableLineFormat
*>(pLine
->ClaimFrameFormat());
1605 ResetLineFrameFormatAttrs( m_pLineFrameFormatNoHeight
);
1608 SwTableBoxes
& rBoxes
= pLine
->GetTabBoxes();
1610 sal_uInt16 nStartCol
= nLeftCol
;
1611 while( nStartCol
<nRightCol
)
1613 sal_uInt16 nCol
= nStartCol
;
1614 sal_uInt16 nSplitCol
= nRightCol
;
1615 bool bSplitted
= false;
1618 OSL_ENSURE( nCol
< nRightCol
, "Gone too far" );
1620 HTMLTableCell
& rCell
= GetCell(nTopRow
,nCol
);
1621 const bool bSplit
= 1 == rCell
.GetColSpan();
1623 OSL_ENSURE((nCol
!= nRightCol
-1) || bSplit
, "Split-Flag wrong");
1626 SwTableBox
* pBox
= nullptr;
1627 HTMLTableCell
& rCell2
= GetCell(nTopRow
, nStartCol
);
1628 if (rCell2
.GetColSpan() == (nCol
+1-nStartCol
))
1630 // The HTML tables represent a box. So we need to split behind that box
1631 nSplitCol
= nCol
+ 1;
1633 sal_Int32 nBoxRowSpan
= rCell2
.GetRowSpan();
1634 if (!rCell2
.GetContents() || rCell2
.IsCovered())
1636 if (rCell2
.IsCovered())
1637 nBoxRowSpan
= -1 * nBoxRowSpan
;
1639 const SwStartNode
* pPrevStartNd
=
1640 GetPrevBoxStartNode( nTopRow
, nStartCol
);
1641 auto xCnts
= std::make_shared
<HTMLTableCnts
>(
1642 m_pParser
->InsertTableSection(pPrevStartNd
));
1643 const std::shared_ptr
<SwHTMLTableLayoutCnts
> xCntsLayoutInfo
=
1644 xCnts
->CreateLayoutInfo();
1646 rCell2
.SetContents(xCnts
);
1647 SwHTMLTableLayoutCell
*pCurrCell
= m_xLayoutInfo
->GetCell(nTopRow
, nStartCol
);
1648 pCurrCell
->SetContents(xCntsLayoutInfo
);
1649 if( nBoxRowSpan
< 0 )
1650 pCurrCell
->SetRowSpan( 0 );
1652 // check COLSPAN if needed
1653 for( sal_uInt16 j
=nStartCol
+1; j
<nSplitCol
; j
++ )
1655 GetCell(nTopRow
, j
).SetContents(xCnts
);
1656 m_xLayoutInfo
->GetCell(nTopRow
, j
)
1657 ->SetContents(xCntsLayoutInfo
);
1661 pBox
= MakeTableBox(pLine
, rCell2
.GetContents().get(),
1663 nBottomRow
, nSplitCol
);
1665 if (1 != nBoxRowSpan
&& pBox
)
1666 pBox
->setRowSpan( nBoxRowSpan
);
1671 OSL_ENSURE( pBox
, "Colspan trouble" );
1674 rBoxes
.push_back( pBox
);
1678 nStartCol
= nSplitCol
;
1684 SwTableBox
*HTMLTable::MakeTableBox( SwTableLine
*pUpper
,
1685 HTMLTableCnts
*pCnts
,
1686 sal_uInt16 nTopRow
, sal_uInt16 nLeftCol
,
1687 sal_uInt16 nBottomRow
, sal_uInt16 nRightCol
)
1690 sal_uInt16 nColSpan
= nRightCol
- nLeftCol
;
1691 sal_uInt16 nRowSpan
= nBottomRow
- nTopRow
;
1693 if( !pCnts
->Next() )
1695 // just one content section
1696 if( pCnts
->GetStartNode() )
1698 // ... that's not a table
1699 pBox
= NewTableBox( pCnts
->GetStartNode(), pUpper
);
1700 pCnts
->SetTableBox( pBox
);
1702 else if (HTMLTable
* pTable
= pCnts
->GetTable().get())
1704 pTable
->InheritVertBorders( this, nLeftCol
,
1705 nRightCol
-nLeftCol
);
1706 // ... that's a table. We'll build a new box and put the rows of the table
1707 // in the rows of the box
1708 pBox
= new SwTableBox( m_pBoxFormat
, 0, pUpper
);
1709 sal_uInt16 nAbs
, nRel
;
1710 m_xLayoutInfo
->GetAvail( nLeftCol
, nColSpan
, nAbs
, nRel
);
1711 sal_uInt16 nLSpace
= m_xLayoutInfo
->GetLeftCellSpace( nLeftCol
, nColSpan
);
1712 sal_uInt16 nRSpace
= m_xLayoutInfo
->GetRightCellSpace( nLeftCol
, nColSpan
);
1713 sal_uInt16 nInhSpace
= m_xLayoutInfo
->GetInhCellSpace( nLeftCol
, nColSpan
);
1714 pCnts
->GetTable()->MakeTable( pBox
, nAbs
, nRel
, nLSpace
, nRSpace
,
1724 // multiple content sections: we'll build a box with rows
1725 pBox
= new SwTableBox( m_pBoxFormat
, 0, pUpper
);
1726 SwTableLines
& rLines
= pBox
->GetTabLines();
1727 bool bFirstPara
= true;
1731 if( pCnts
->GetStartNode() )
1733 // normal paragraphs are gonna be boxes in a row
1734 SwTableLine
*pLine
=
1735 new SwTableLine( m_pLineFrameFormatNoHeight
? m_pLineFrameFormatNoHeight
1736 : m_pLineFormat
, 0, pBox
);
1737 if( !m_pLineFrameFormatNoHeight
)
1739 // If there's no line format without height yet, we can use that one
1740 m_pLineFrameFormatNoHeight
= static_cast<SwTableLineFormat
*>(pLine
->ClaimFrameFormat());
1742 ResetLineFrameFormatAttrs( m_pLineFrameFormatNoHeight
);
1745 SwTableBox
* pCntBox
= NewTableBox( pCnts
->GetStartNode(),
1747 pCnts
->SetTableBox( pCntBox
);
1748 FixFrameFormat( pCntBox
, nTopRow
, nLeftCol
, nRowSpan
, nColSpan
,
1749 bFirstPara
, nullptr==pCnts
->Next() );
1750 pLine
->GetTabBoxes().push_back( pCntBox
);
1752 rLines
.push_back( pLine
);
1756 pCnts
->GetTable()->InheritVertBorders( this, nLeftCol
,
1757 nRightCol
-nLeftCol
);
1758 // Tables are entered directly
1759 sal_uInt16 nAbs
, nRel
;
1760 m_xLayoutInfo
->GetAvail( nLeftCol
, nColSpan
, nAbs
, nRel
);
1761 sal_uInt16 nLSpace
= m_xLayoutInfo
->GetLeftCellSpace( nLeftCol
,
1763 sal_uInt16 nRSpace
= m_xLayoutInfo
->GetRightCellSpace( nLeftCol
,
1765 sal_uInt16 nInhSpace
= m_xLayoutInfo
->GetInhCellSpace( nLeftCol
, nColSpan
);
1766 pCnts
->GetTable()->MakeTable( pBox
, nAbs
, nRel
, nLSpace
,
1767 nRSpace
, nInhSpace
);
1770 pCnts
= pCnts
->Next();
1775 FixFrameFormat( pBox
, nTopRow
, nLeftCol
, nRowSpan
, nColSpan
);
1780 void HTMLTable::InheritBorders( const HTMLTable
*pParent
,
1781 sal_uInt16 nRow
, sal_uInt16 nCol
,
1782 sal_uInt16 nRowSpan
,
1783 bool bFirstPara
, bool bLastPara
)
1785 OSL_ENSURE( m_nRows
>0 && m_nCols
>0 && m_nCurrentRow
==m_nRows
,
1786 "Was CloseTable not called?" );
1788 // The child table needs a border, if the surrounding cell has a margin on that side.
1789 // The upper/lower border is only set if the table is the first/last paragraph in that cell
1790 // It can't be determined if a border for that table is needed or possible for the left or right side,
1791 // since that's depending on if filler cells are gonna be added. We'll only collect info for now
1793 if( 0==nRow
&& pParent
->m_bTopBorder
&& bFirstPara
)
1795 m_bTopBorder
= true;
1796 m_bFillerTopBorder
= true; // fillers get a border too
1797 m_aTopBorderLine
= pParent
->m_aTopBorderLine
;
1799 if (pParent
->m_aRows
[nRow
+nRowSpan
-1].GetBottomBorder() && bLastPara
)
1801 m_aRows
[m_nRows
-1].SetBottomBorder(true);
1802 m_bFillerBottomBorder
= true; // fillers get a border too
1803 m_aBottomBorderLine
=
1804 nRow
+nRowSpan
==pParent
->m_nRows
? pParent
->m_aBottomBorderLine
1805 : pParent
->m_aBorderLine
;
1808 // The child table mustn't get an upper or lower border, if that's already done by the surrounding table
1809 // It can get an upper border if the table is not the first paragraph in that cell
1810 m_bTopAllowed
= ( !bFirstPara
|| (pParent
->m_bTopAllowed
&&
1811 (0==nRow
|| !pParent
->m_aRows
[nRow
-1].GetBottomBorder())) );
1813 // The child table has to inherit the color of the cell it's contained in, if it doesn't have one
1814 const SvxBrushItem
*pInhBG
= pParent
->GetCell(nRow
, nCol
).GetBGBrush().get();
1815 if( !pInhBG
&& pParent
!= this &&
1816 pParent
->GetCell(nRow
,nCol
).GetRowSpan() == pParent
->m_nRows
)
1818 // the whole surrounding table is a table in a table and consists only of a single line
1819 // that's gonna be GC-ed (correctly). That's why the background of that line is copied.
1820 pInhBG
= pParent
->m_aRows
[nRow
].GetBGBrush().get();
1822 pInhBG
= pParent
->GetBGBrush().get();
1824 pInhBG
= pParent
->GetInhBGBrush().get();
1827 m_xInheritedBackgroundBrush
.reset(new SvxBrushItem(*pInhBG
));
1830 void HTMLTable::InheritVertBorders( const HTMLTable
*pParent
,
1831 sal_uInt16 nCol
, sal_uInt16 nColSpan
)
1833 sal_uInt16 nInhLeftBorderWidth
= 0;
1834 sal_uInt16 nInhRightBorderWidth
= 0;
1836 if( nCol
+nColSpan
==pParent
->m_nCols
&& pParent
->m_bRightBorder
)
1838 m_bInheritedRightBorder
= true; // just remember for now
1839 m_aInheritedRightBorderLine
= pParent
->m_aRightBorderLine
;
1840 nInhRightBorderWidth
=
1841 GetBorderWidth( m_aInheritedRightBorderLine
, true ) + MIN_BORDER_DIST
;
1844 if (pParent
->m_aColumns
[nCol
].m_bLeftBorder
)
1846 m_bInheritedLeftBorder
= true; // just remember for now
1847 m_aInheritedLeftBorderLine
= 0==nCol
? pParent
->m_aLeftBorderLine
1848 : pParent
->m_aBorderLine
;
1849 nInhLeftBorderWidth
=
1850 GetBorderWidth( m_aInheritedLeftBorderLine
, true ) + MIN_BORDER_DIST
;
1853 if( !m_bInheritedLeftBorder
&& (m_bFillerTopBorder
|| m_bFillerBottomBorder
) )
1854 nInhLeftBorderWidth
= 2 * MIN_BORDER_DIST
;
1855 if( !m_bInheritedRightBorder
&& (m_bFillerTopBorder
|| m_bFillerBottomBorder
) )
1856 nInhRightBorderWidth
= 2 * MIN_BORDER_DIST
;
1857 m_xLayoutInfo
->SetInhBorderWidths( nInhLeftBorderWidth
,
1858 nInhRightBorderWidth
);
1860 m_bRightAllowed
= ( pParent
->m_bRightAllowed
&&
1861 (nCol
+nColSpan
==pParent
->m_nCols
||
1862 !pParent
->m_aColumns
[nCol
+nColSpan
].m_bLeftBorder
) );
1865 void HTMLTable::SetBorders()
1868 for( i
=1; i
<m_nCols
; i
++ )
1869 if( HTMLTableRules::All
==m_eRules
|| HTMLTableRules::Cols
==m_eRules
||
1870 ((HTMLTableRules::Rows
==m_eRules
|| HTMLTableRules::Groups
==m_eRules
) &&
1871 m_aColumns
[i
-1].IsEndOfGroup()))
1873 m_aColumns
[i
].m_bLeftBorder
= true;
1876 for( i
=0; i
<m_nRows
-1; i
++ )
1877 if( HTMLTableRules::All
==m_eRules
|| HTMLTableRules::Rows
==m_eRules
||
1878 ((HTMLTableRules::Cols
==m_eRules
|| HTMLTableRules::Groups
==m_eRules
) &&
1879 m_aRows
[i
].IsEndOfGroup()))
1881 m_aRows
[i
].SetBottomBorder(true);
1884 if( m_bTopAllowed
&& (HTMLTableFrame::Above
==m_eFrame
|| HTMLTableFrame::HSides
==m_eFrame
||
1885 HTMLTableFrame::Box
==m_eFrame
) )
1886 m_bTopBorder
= true;
1887 if( HTMLTableFrame::Below
==m_eFrame
|| HTMLTableFrame::HSides
==m_eFrame
||
1888 HTMLTableFrame::Box
==m_eFrame
)
1890 m_aRows
[m_nRows
-1].SetBottomBorder(true);
1892 if( HTMLTableFrame::RHS
==m_eFrame
|| HTMLTableFrame::VSides
==m_eFrame
||
1893 HTMLTableFrame::Box
==m_eFrame
)
1894 m_bRightBorder
= true;
1895 if( HTMLTableFrame::LHS
==m_eFrame
|| HTMLTableFrame::VSides
==m_eFrame
|| HTMLTableFrame::Box
==m_eFrame
)
1897 m_aColumns
[0].m_bLeftBorder
= true;
1900 for( i
=0; i
<m_nRows
; i
++ )
1902 HTMLTableRow
& rRow
= m_aRows
[i
];
1903 for (sal_uInt16 j
=0; j
<m_nCols
; ++j
)
1905 HTMLTableCell
& rCell
= rRow
.GetCell(j
);
1906 if (rCell
.GetContents())
1908 HTMLTableCnts
*pCnts
= rCell
.GetContents().get();
1909 bool bFirstPara
= true;
1912 HTMLTable
*pTable
= pCnts
->GetTable().get();
1913 if( pTable
&& !pTable
->BordersSet() )
1915 pTable
->InheritBorders(this, i
, j
,
1918 nullptr==pCnts
->Next());
1919 pTable
->SetBorders();
1922 pCnts
= pCnts
->Next();
1928 m_bBordersSet
= true;
1931 sal_uInt16
HTMLTable::GetBorderWidth( const SvxBorderLine
& rBLine
,
1932 bool bWithDistance
) const
1934 sal_uInt16 nBorderWidth
= rBLine
.GetWidth();
1937 if( m_nCellPadding
)
1938 nBorderWidth
= nBorderWidth
+ m_nCellPadding
;
1939 else if( nBorderWidth
)
1940 nBorderWidth
= nBorderWidth
+ MIN_BORDER_DIST
;
1943 return nBorderWidth
;
1946 const HTMLTableCell
& HTMLTable::GetCell(sal_uInt16 nRow
, sal_uInt16 nCell
) const
1948 OSL_ENSURE(nRow
< m_aRows
.size(), "invalid row index in HTML table");
1949 return m_aRows
[nRow
].GetCell(nCell
);
1952 SvxAdjust
HTMLTable::GetInheritedAdjust() const
1954 SvxAdjust eAdjust
= (m_nCurrentColumn
<m_nCols
? m_aColumns
[m_nCurrentColumn
].GetAdjust()
1956 if( SvxAdjust::End
==eAdjust
)
1957 eAdjust
= m_aRows
[m_nCurrentRow
].GetAdjust();
1962 sal_Int16
HTMLTable::GetInheritedVertOri() const
1964 // text::VertOrientation::TOP is default!
1965 sal_Int16 eVOri
= m_aRows
[m_nCurrentRow
].GetVertOri();
1966 if( text::VertOrientation::TOP
==eVOri
&& m_nCurrentColumn
<m_nCols
)
1967 eVOri
= m_aColumns
[m_nCurrentColumn
].GetVertOri();
1968 if( text::VertOrientation::TOP
==eVOri
)
1969 eVOri
= m_eVertOrientation
;
1971 OSL_ENSURE( m_eVertOrientation
!= text::VertOrientation::TOP
, "text::VertOrientation::TOP is not allowed!" );
1975 void HTMLTable::InsertCell( std::shared_ptr
<HTMLTableCnts
> const& rCnts
,
1976 sal_uInt16 nRowSpan
, sal_uInt16 nColSpan
,
1977 sal_uInt16 nCellWidth
, bool bRelWidth
, sal_uInt16 nCellHeight
,
1978 sal_Int16 eVertOrient
, std::shared_ptr
<SvxBrushItem
> const& rBGBrushItem
,
1979 std::shared_ptr
<SvxBoxItem
> const& rBoxItem
,
1980 bool bHasNumFormat
, sal_uInt32 nNumFormat
,
1981 bool bHasValue
, double nValue
, bool bNoWrap
)
1983 if( !nRowSpan
|| static_cast<sal_uInt32
>(m_nCurrentRow
) + nRowSpan
> USHRT_MAX
)
1986 if( !nColSpan
|| static_cast<sal_uInt32
>(m_nCurrentColumn
) + nColSpan
> USHRT_MAX
)
1989 sal_uInt16 nColsReq
= m_nCurrentColumn
+ nColSpan
;
1990 sal_uInt16 nRowsReq
= m_nCurrentRow
+ nRowSpan
;
1993 // if we need more columns than we currently have, we need to add cells for all rows
1994 if( m_nCols
< nColsReq
)
1996 m_aColumns
.resize(nColsReq
);
1997 for( i
=0; i
<m_nRows
; i
++ )
1998 m_aRows
[i
].Expand( nColsReq
, i
<m_nCurrentRow
);
2000 OSL_ENSURE(m_aColumns
.size() == m_nCols
,
2001 "wrong number of columns after expanding");
2003 if( nColsReq
> m_nFilledColumns
)
2004 m_nFilledColumns
= nColsReq
;
2006 // if we need more rows than we currently have, we need to add cells
2007 if( m_nRows
< nRowsReq
)
2009 for( i
=m_nRows
; i
<nRowsReq
; i
++ )
2010 m_aRows
.emplace_back(m_nCols
);
2012 OSL_ENSURE(m_nRows
== m_aRows
.size(), "wrong number of rows in Insert");
2015 // Check if we have an overlap and could remove that
2016 sal_uInt16 nSpanedCols
= 0;
2017 if( m_nCurrentRow
>0 )
2019 HTMLTableRow
& rCurRow
= m_aRows
[m_nCurrentRow
];
2020 for( i
=m_nCurrentColumn
; i
<nColsReq
; i
++ )
2022 HTMLTableCell
& rCell
= rCurRow
.GetCell(i
);
2023 if (rCell
.GetContents())
2025 // A cell from a row further above overlaps this one.
2026 // Content and colors are coming from that cell and can be overwritten
2027 // or deleted (content) or copied (color) by ProtectRowSpan
2028 nSpanedCols
= i
+ rCell
.GetColSpan();
2029 FixRowSpan( m_nCurrentRow
-1, i
, rCell
.GetContents().get() );
2030 if (rCell
.GetRowSpan() > nRowSpan
)
2031 ProtectRowSpan( nRowsReq
, i
,
2032 rCell
.GetRowSpan()-nRowSpan
);
2035 for( i
=nColsReq
; i
<nSpanedCols
; i
++ )
2037 // These contents are anchored in the row above in any case
2038 HTMLTableCell
& rCell
= rCurRow
.GetCell(i
);
2039 FixRowSpan( m_nCurrentRow
-1, i
, rCell
.GetContents().get() );
2040 ProtectRowSpan( m_nCurrentRow
, i
, rCell
.GetRowSpan() );
2045 for( i
=nColSpan
; i
>0; i
-- )
2047 for( j
=nRowSpan
; j
>0; j
-- )
2049 const bool bCovered
= i
!= nColSpan
|| j
!= nRowSpan
;
2050 GetCell( nRowsReq
-j
, nColsReq
-i
)
2051 .Set( rCnts
, j
, i
, eVertOrient
, rBGBrushItem
, rBoxItem
,
2052 bHasNumFormat
, nNumFormat
, bHasValue
, nValue
, bNoWrap
, bCovered
);
2056 Size
aTwipSz( bRelWidth
? 0 : nCellWidth
, nCellHeight
);
2057 if( aTwipSz
.Width() || aTwipSz
.Height() )
2059 aTwipSz
= o3tl::convert(aTwipSz
, o3tl::Length::px
, o3tl::Length::twip
);
2062 // Only set width on the first cell!
2065 sal_uInt16 nTmp
= bRelWidth
? nCellWidth
: o3tl::narrowing
<sal_uInt16
>(aTwipSz
.Width());
2066 GetCell( m_nCurrentRow
, m_nCurrentColumn
).SetWidth( nTmp
, bRelWidth
);
2070 if( nCellHeight
&& 1==nRowSpan
)
2072 m_aRows
[m_nCurrentRow
].SetHeight(o3tl::narrowing
<sal_uInt16
>(aTwipSz
.Height()));
2075 // Set the column counter behind the new cells
2076 m_nCurrentColumn
= nColsReq
;
2077 if( nSpanedCols
> m_nCurrentColumn
)
2078 m_nCurrentColumn
= nSpanedCols
;
2080 // and search for the next free cell
2081 while( m_nCurrentColumn
<m_nCols
&& GetCell(m_nCurrentRow
,m_nCurrentColumn
).IsUsed() )
2085 inline void HTMLTable::CloseSection( bool bHead
)
2087 // Close the preceding sections if there's already a row
2088 OSL_ENSURE( m_nCurrentRow
<=m_nRows
, "invalid current row" );
2089 if( m_nCurrentRow
>0 && m_nCurrentRow
<=m_nRows
)
2090 m_aRows
[m_nCurrentRow
-1].SetEndOfGroup();
2092 m_nHeadlineRepeat
= m_nCurrentRow
;
2095 void HTMLTable::OpenRow(SvxAdjust eAdjust
, sal_Int16 eVertOrient
,
2096 std::unique_ptr
<SvxBrushItem
>& rBGBrushItem
)
2098 sal_uInt16 nRowsReq
= m_nCurrentRow
+1;
2100 // create the next row if it's not there already
2101 if( m_nRows
<nRowsReq
)
2103 for( sal_uInt16 i
=m_nRows
; i
<nRowsReq
; i
++ )
2104 m_aRows
.emplace_back(m_nCols
);
2106 OSL_ENSURE( m_nRows
== m_aRows
.size(),
2107 "Row number in OpenRow is wrong" );
2110 HTMLTableRow
& rCurRow
= m_aRows
[m_nCurrentRow
];
2111 rCurRow
.SetAdjust(eAdjust
);
2112 rCurRow
.SetVertOri(eVertOrient
);
2114 m_aRows
[m_nCurrentRow
].SetBGBrush(rBGBrushItem
);
2116 // reset the column counter
2119 // and search for the next free cell
2120 while( m_nCurrentColumn
<m_nCols
&& GetCell(m_nCurrentRow
,m_nCurrentColumn
).IsUsed() )
2124 void HTMLTable::CloseRow( bool bEmpty
)
2126 OSL_ENSURE( m_nCurrentRow
<m_nRows
, "current row after table end" );
2128 // empty cells just get a slightly thicker lower border!
2131 if( m_nCurrentRow
> 0 )
2132 m_aRows
[m_nCurrentRow
-1].IncEmptyRows();
2136 HTMLTableRow
& rRow
= m_aRows
[m_nCurrentRow
];
2138 // modify the COLSPAN of all empty cells at the row end in a way, that they're forming a single cell
2139 // that can be done here (and not earlier) since there's no more cells in that row
2140 sal_uInt16 i
=m_nCols
;
2143 HTMLTableCell
& rCell
= rRow
.GetCell(--i
);
2144 if (!rCell
.GetContents())
2146 sal_uInt16 nColSpan
= m_nCols
-i
;
2148 rCell
.SetColSpan(nColSpan
);
2157 inline void HTMLTable::CloseColGroup( sal_uInt16 nSpan
, sal_uInt16 _nWidth
,
2158 bool bRelWidth
, SvxAdjust eAdjust
,
2159 sal_Int16 eVertOrient
)
2162 InsertCol( nSpan
, _nWidth
, bRelWidth
, eAdjust
, eVertOrient
);
2164 OSL_ENSURE( m_nCurrentColumn
<=m_nCols
, "invalid column" );
2165 if( m_nCurrentColumn
>0 && m_nCurrentColumn
<=m_nCols
)
2166 m_aColumns
[m_nCurrentColumn
-1].SetEndOfGroup();
2169 void HTMLTable::InsertCol( sal_uInt16 nSpan
, sal_uInt16 nColWidth
, bool bRelWidth
,
2170 SvxAdjust eAdjust
, sal_Int16 eVertOrient
)
2172 // #i35143# - no columns, if rows already exist.
2181 sal_uInt16 nColsReq
= m_nCurrentColumn
+ nSpan
;
2183 if( m_nCols
< nColsReq
)
2185 m_aColumns
.resize(nColsReq
);
2189 sal_uInt16
nTwipWidth(bRelWidth
? 0 : o3tl::convert(nColWidth
, o3tl::Length::px
, o3tl::Length::twip
));
2191 for( i
=m_nCurrentColumn
; i
<nColsReq
; i
++ )
2193 HTMLTableColumn
& rCol
= m_aColumns
[i
];
2194 sal_uInt16 nTmp
= bRelWidth
? nColWidth
: o3tl::narrowing
<sal_uInt16
>(nTwipWidth
);
2195 rCol
.SetWidth( nTmp
, bRelWidth
);
2196 rCol
.SetAdjust( eAdjust
);
2197 rCol
.SetVertOri( eVertOrient
);
2202 m_nCurrentColumn
= nColsReq
;
2205 void HTMLTable::CloseTable()
2209 // The number of table rows is only dependent on the <TR> elements (i.e. nCurRow).
2210 // Rows that are spanned via ROWSPAN behind nCurRow need to be deleted
2211 // and we need to adjust the ROWSPAN in the rows above
2212 if( m_nRows
>m_nCurrentRow
)
2214 HTMLTableRow
& rPrevRow
= m_aRows
[m_nCurrentRow
-1];
2215 for( i
=0; i
<m_nCols
; i
++ )
2217 HTMLTableCell
& rCell
= rPrevRow
.GetCell(i
);
2218 if (rCell
.GetRowSpan() > 1)
2220 FixRowSpan(m_nCurrentRow
-1, i
, rCell
.GetContents().get());
2221 ProtectRowSpan(m_nCurrentRow
, i
, m_aRows
[m_nCurrentRow
].GetCell(i
).GetRowSpan());
2224 for( i
=m_nRows
-1; i
>=m_nCurrentRow
; i
-- )
2225 m_aRows
.erase(m_aRows
.begin() + i
);
2226 m_nRows
= m_nCurrentRow
;
2229 // if the table has no column, we need to add one
2232 m_aColumns
.resize(1);
2233 for( i
=0; i
<m_nRows
; i
++ )
2234 m_aRows
[i
].Expand(1);
2236 m_nFilledColumns
= 1;
2239 // if the table has no row, we need to add one
2242 m_aRows
.emplace_back(m_nCols
);
2247 if( m_nFilledColumns
< m_nCols
)
2249 m_aColumns
.erase(m_aColumns
.begin() + m_nFilledColumns
, m_aColumns
.begin() + m_nCols
);
2250 for( i
=0; i
<m_nRows
; i
++ )
2251 m_aRows
[i
].Shrink( m_nFilledColumns
);
2252 m_nCols
= m_nFilledColumns
;
2256 void HTMLTable::MakeTable_( SwTableBox
*pBox
)
2258 SwTableLines
& rLines
= (pBox
? pBox
->GetTabLines()
2259 : const_cast<SwTable
*>(m_pSwTable
)->GetTabLines() );
2261 for( sal_uInt16 i
=0; i
<m_nRows
; i
++ )
2263 SwTableLine
*pLine
= MakeTableLine( pBox
, i
, 0, i
+1, m_nCols
);
2265 rLines
.push_back( pLine
);
2269 /* How are tables aligned?
2271 first row: without paragraph indents
2272 second row: with paragraph indents
2274 ALIGN= LEFT RIGHT CENTER -
2275 -------------------------------------------------------------------------
2276 xxx for tables with WIDTH=nn% the percentage value is important:
2277 xxx nn = 100 text::HoriOrientation::FULL text::HoriOrientation::FULL text::HoriOrientation::FULL text::HoriOrientation::FULL %
2278 xxx text::HoriOrientation::NONE text::HoriOrientation::NONE text::HoriOrientation::NONE % text::HoriOrientation::NONE %
2279 xxx nn < 100 frame F frame F text::HoriOrientation::CENTER % text::HoriOrientation::LEFT %
2280 xxx frame F frame F text::HoriOrientation::CENTER % text::HoriOrientation::NONE %
2282 for tables with WIDTH=nn% the percentage value is important:
2283 nn = 100 text::HoriOrientation::LEFT text::HoriOrientation::RIGHT text::HoriOrientation::CENTER % text::HoriOrientation::LEFT %
2284 text::HoriOrientation::LEFT_AND text::HoriOrientation::RIGHT text::HoriOrientation::CENTER % text::HoriOrientation::LEFT_AND %
2285 nn < 100 frame F frame F text::HoriOrientation::CENTER % text::HoriOrientation::LEFT %
2286 frame F frame F text::HoriOrientation::CENTER % text::HoriOrientation::NONE %
2288 otherwise the calculated width w
2289 w = avail* text::HoriOrientation::LEFT text::HoriOrientation::RIGHT text::HoriOrientation::CENTER text::HoriOrientation::LEFT
2290 HORI_LEDT_AND text::HoriOrientation::RIGHT text::HoriOrientation::CENTER text::HoriOrientation::LEFT_AND
2291 w < avail frame L frame L text::HoriOrientation::CENTER text::HoriOrientation::LEFT
2292 frame L frame L text::HoriOrientation::CENTER text::HoriOrientation::NONE
2294 xxx *) if for the table no size was specified, always
2295 xxx text::HoriOrientation::FULL is taken
2299 void HTMLTable::MakeTable( SwTableBox
*pBox
, sal_uInt16 nAbsAvail
,
2300 sal_uInt16 nRelAvail
, sal_uInt16 nAbsLeftSpace
,
2301 sal_uInt16 nAbsRightSpace
, sal_uInt16 nInhAbsSpace
)
2303 OSL_ENSURE( m_nRows
>0 && m_nCols
>0 && m_nCurrentRow
==m_nRows
,
2304 "Was CloseTable not called?" );
2306 OSL_ENSURE(m_xLayoutInfo
== nullptr, "Table already has layout info");
2308 // Calculate borders of the table and all contained tables
2311 // Step 1: needed layout structures are created (including tables in tables)
2314 if (!utl::ConfigManager::IsFuzzing()) // skip slow path for fuzzing
2316 // Step 2: the minimal and maximal column width is calculated
2317 // (including tables in tables). Since we don't have boxes yet,
2318 // we'll work on the start nodes
2319 m_xLayoutInfo
->AutoLayoutPass1();
2321 // Step 3: the actual column widths of this table are calculated (not tables in tables)
2322 // We need this now to decide if we need filler cells
2323 // (Pass1 was needed because of this as well)
2324 m_xLayoutInfo
->AutoLayoutPass2( nAbsAvail
, nRelAvail
, nAbsLeftSpace
,
2325 nAbsRightSpace
, nInhAbsSpace
);
2328 // Set adjustment for the top table
2332 // The table should go in a text frame and it's narrower than the
2333 // available space and not 100% wide. So it gets a border
2334 eHoriOri
= m_bPercentWidth
? text::HoriOrientation::FULL
: text::HoriOrientation::LEFT
;
2336 else switch (m_eTableAdjust
)
2338 // The table either fits the page but shouldn't get a text frame,
2339 // or it's wider than the page so it doesn't need a text frame
2341 case SvxAdjust::Right
:
2342 // Don't be considerate of the right margin in right-adjusted tables
2343 eHoriOri
= text::HoriOrientation::RIGHT
;
2345 case SvxAdjust::Center
:
2346 // Centred tables are not considerate of margins
2347 eHoriOri
= text::HoriOrientation::CENTER
;
2349 case SvxAdjust::Left
:
2351 // left-adjusted tables are only considerate of the left margin
2352 eHoriOri
= m_nLeftMargin
? text::HoriOrientation::LEFT_AND_WIDTH
: text::HoriOrientation::LEFT
;
2358 SAL_WARN("sw.html", "no table");
2362 // get the table format and adapt it
2363 SwFrameFormat
*pFrameFormat
= m_pSwTable
->GetFrameFormat();
2364 pFrameFormat
->SetFormatAttr( SwFormatHoriOrient(0, eHoriOri
) );
2365 if (text::HoriOrientation::LEFT_AND_WIDTH
== eHoriOri
)
2367 OSL_ENSURE( m_nLeftMargin
|| m_nRightMargin
,
2368 "There are still leftovers from relative margins" );
2370 // The right margin will be ignored anyway.
2371 SvxLRSpaceItem
aLRItem( m_pSwTable
->GetFrameFormat()->GetLRSpace() );
2372 aLRItem
.SetLeft( m_nLeftMargin
);
2373 aLRItem
.SetRight( m_nRightMargin
);
2374 pFrameFormat
->SetFormatAttr( aLRItem
);
2377 if (m_bPercentWidth
&& text::HoriOrientation::FULL
!= eHoriOri
)
2379 pFrameFormat
->LockModify();
2380 SwFormatFrameSize
aFrameSize( pFrameFormat
->GetFrameSize() );
2381 aFrameSize
.SetWidthPercent( static_cast<sal_uInt8
>(m_nWidth
) );
2382 pFrameFormat
->SetFormatAttr( aFrameSize
);
2383 pFrameFormat
->UnlockModify();
2386 // get the default line and box format
2387 // remember the first box and unlist it from the first row
2388 SwTableLine
*pLine1
= (m_pSwTable
->GetTabLines())[0];
2389 m_xBox1
.reset((pLine1
->GetTabBoxes())[0]);
2390 pLine1
->GetTabBoxes().erase(pLine1
->GetTabBoxes().begin());
2392 m_pLineFormat
= static_cast<SwTableLineFormat
*>(pLine1
->GetFrameFormat());
2393 m_pBoxFormat
= static_cast<SwTableBoxFormat
*>(m_xBox1
->GetFrameFormat());
2397 // Finally, we'll do a garbage collection for the top level table
2399 if( 1==m_nRows
&& m_nHeight
&& 1==m_pSwTable
->GetTabLines().size() )
2401 // Set height of a one-row table as the minimum width of the row
2402 // Was originally a fixed height, but that made problems
2403 // and is not Netscape 4.0 compliant
2404 m_nHeight
= SwHTMLParser::ToTwips( m_nHeight
);
2405 if( m_nHeight
< MINLAY
)
2408 (m_pSwTable
->GetTabLines())[0]->ClaimFrameFormat();
2409 (m_pSwTable
->GetTabLines())[0]->GetFrameFormat()
2410 ->SetFormatAttr( SwFormatFrameSize( SwFrameSize::Minimum
, 0, m_nHeight
) );
2414 m_pSwTable
->GetFrameFormat()->SetFormatAttr( *GetBGBrush() );
2416 const_cast<SwTable
*>(m_pSwTable
)->SetRowsToRepeat( static_cast< sal_uInt16
>(m_nHeadlineRepeat
) );
2417 const_cast<SwTable
*>(m_pSwTable
)->GCLines();
2419 bool bIsInFlyFrame
= m_pContext
&& m_pContext
->GetFrameFormat();
2420 if( bIsInFlyFrame
&& !m_nWidth
)
2422 SvxAdjust eAdjust
= GetTableAdjust(false);
2423 if (eAdjust
!= SvxAdjust::Left
&&
2424 eAdjust
!= SvxAdjust::Right
)
2426 // If a table with a width attribute isn't flowed around left or right
2427 // we'll stack it with a border of 100% width, so its size will
2428 // be adapted. That text frame mustn't be modified
2429 OSL_ENSURE( HasToFly(), "Why is the table in a frame?" );
2430 sal_uInt32 nMin
= m_xLayoutInfo
->GetMin();
2431 if( nMin
> USHRT_MAX
)
2433 SwFormatFrameSize
aFlyFrameSize( SwFrameSize::Variable
, static_cast<SwTwips
>(nMin
), MINLAY
);
2434 aFlyFrameSize
.SetWidthPercent( 100 );
2435 m_pContext
->GetFrameFormat()->SetFormatAttr( aFlyFrameSize
);
2436 bIsInFlyFrame
= false;
2440 // left or right adjusted table without width mustn't be adjusted in width
2441 // as they would only shrink but never grow
2442 m_xLayoutInfo
->SetMustNotRecalc( true );
2443 if( m_pContext
->GetFrameFormat()->GetAnchor().GetAnchorNode()
2446 sal_uInt32 nMax
= m_xLayoutInfo
->GetMax();
2447 if( nMax
> USHRT_MAX
)
2449 SwFormatFrameSize
aFlyFrameSize( SwFrameSize::Variable
, static_cast<SwTwips
>(nMax
), MINLAY
);
2450 m_pContext
->GetFrameFormat()->SetFormatAttr( aFlyFrameSize
);
2451 bIsInFlyFrame
= false;
2455 m_xLayoutInfo
->SetMustNotResize( true );
2459 m_xLayoutInfo
->SetMayBeInFlyFrame( bIsInFlyFrame
);
2461 // Only tables with relative width or without width should be modified
2462 m_xLayoutInfo
->SetMustResize( m_bPercentWidth
|| !m_nWidth
);
2464 if (!pLine1
->GetTabBoxes().empty())
2465 m_xLayoutInfo
->SetWidths();
2467 SAL_WARN("sw.html", "no table box");
2469 const_cast<SwTable
*>(m_pSwTable
)->SetHTMLTableLayout(m_xLayoutInfo
);
2471 if( !m_xResizeDrawObjects
)
2474 sal_uInt16 nCount
= m_xResizeDrawObjects
->size();
2475 for( sal_uInt16 i
=0; i
<nCount
; i
++ )
2477 SdrObject
*pObj
= (*m_xResizeDrawObjects
)[i
];
2478 sal_uInt16 nRow
= (*m_xDrawObjectPercentWidths
)[3*i
];
2479 sal_uInt16 nCol
= (*m_xDrawObjectPercentWidths
)[3*i
+1];
2480 sal_uInt8 nPercentWidth
= static_cast<sal_uInt8
>((*m_xDrawObjectPercentWidths
)[3*i
+2]);
2482 SwHTMLTableLayoutCell
*pLayoutCell
=
2483 m_xLayoutInfo
->GetCell( nRow
, nCol
);
2484 sal_uInt16 nColSpan
= pLayoutCell
->GetColSpan();
2486 sal_uInt16 nWidth2
, nDummy
;
2487 m_xLayoutInfo
->GetAvail( nCol
, nColSpan
, nWidth2
, nDummy
);
2488 nWidth2
= static_cast< sal_uInt16
>((static_cast<tools::Long
>(m_nWidth
) * nPercentWidth
) / 100);
2490 SwHTMLParser::ResizeDrawObject( pObj
, nWidth2
);
2495 void HTMLTable::SetTable( const SwStartNode
*pStNd
, std::unique_ptr
<HTMLTableContext
> pCntxt
,
2496 sal_uInt16 nLeft
, sal_uInt16 nRight
,
2497 const SwTable
*pSwTab
, bool bFrcFrame
)
2499 m_pPrevStartNode
= pStNd
;
2500 m_pSwTable
= pSwTab
;
2501 m_pContext
= std::move(pCntxt
);
2503 m_nLeftMargin
= nLeft
;
2504 m_nRightMargin
= nRight
;
2506 m_bForceFrame
= bFrcFrame
;
2509 void HTMLTable::RegisterDrawObject( SdrObject
*pObj
, sal_uInt8 nPercentWidth
)
2511 if( !m_xResizeDrawObjects
)
2512 m_xResizeDrawObjects
.emplace();
2513 m_xResizeDrawObjects
->push_back( pObj
);
2514 pObj
->AddObjectUser(*this);
2516 if( !m_xDrawObjectPercentWidths
)
2517 m_xDrawObjectPercentWidths
.emplace();
2518 m_xDrawObjectPercentWidths
->push_back( m_nCurrentRow
);
2519 m_xDrawObjectPercentWidths
->push_back( m_nCurrentColumn
);
2520 m_xDrawObjectPercentWidths
->push_back( o3tl::narrowing
<sal_uInt16
>(nPercentWidth
) );
2523 void HTMLTable::MakeParentContents()
2525 if( !GetContext() && !HasParentSection() )
2528 m_pParser
->InsertTableContents( m_bIsParentHead
) );
2530 SetHasParentSection( true );
2534 void HTMLTableContext::SavePREListingXMP( SwHTMLParser
& rParser
)
2536 m_bRestartPRE
= rParser
.IsReadPRE();
2537 m_bRestartXMP
= rParser
.IsReadXMP();
2538 m_bRestartListing
= rParser
.IsReadListing();
2539 rParser
.FinishPREListingXMP();
2542 void HTMLTableContext::RestorePREListingXMP( SwHTMLParser
& rParser
)
2544 rParser
.FinishPREListingXMP();
2552 if( m_bRestartListing
)
2553 rParser
.StartListing();
2556 const SwStartNode
*SwHTMLParser::InsertTableSection
2557 ( const SwStartNode
*pPrevStNd
)
2559 OSL_ENSURE( pPrevStNd
, "Start-Node is NULL" );
2561 m_pCSS1Parser
->SetTDTagStyles();
2562 SwTextFormatColl
*pColl
= m_pCSS1Parser
->GetTextCollFromPool( RES_POOLCOLL_TABLE
);
2564 const SwStartNode
*pStNd
;
2565 if (m_xTable
->m_bFirstCell
)
2567 SwNode
*const pNd
= & m_pPam
->GetPoint()->GetNode();
2568 pNd
->GetTextNode()->ChgFormatColl( pColl
);
2569 pStNd
= pNd
->FindTableBoxStartNode();
2570 m_xTable
->m_bFirstCell
= false;
2575 if( pPrevStNd
->IsTableNode() )
2578 pNd
= pPrevStNd
->EndOfSectionNode();
2579 SwNodeIndex
nIdx( *pNd
, 1 );
2580 pStNd
= m_xDoc
->GetNodes().MakeTextSection( nIdx
.GetNode(), SwTableBoxStartNode
,
2582 m_xTable
->IncBoxCount();
2586 eState
= SvParserState::Error
;
2590 //Added defaults to CJK and CTL
2591 SwContentNode
*pCNd
= m_xDoc
->GetNodes()[pStNd
->GetIndex()+1] ->GetContentNode();
2592 SvxFontHeightItem
aFontHeight( 40, 100, RES_CHRATR_FONTSIZE
);
2593 pCNd
->SetAttr( aFontHeight
);
2594 SvxFontHeightItem
aFontHeightCJK( 40, 100, RES_CHRATR_CJK_FONTSIZE
);
2595 pCNd
->SetAttr( aFontHeightCJK
);
2596 SvxFontHeightItem
aFontHeightCTL( 40, 100, RES_CHRATR_CTL_FONTSIZE
);
2597 pCNd
->SetAttr( aFontHeightCTL
);
2602 const SwStartNode
*SwHTMLParser::InsertTableSection( sal_uInt16 nPoolId
)
2606 case RES_POOLCOLL_TABLE_HDLN
:
2607 m_pCSS1Parser
->SetTHTagStyles();
2609 case RES_POOLCOLL_TABLE
:
2610 m_pCSS1Parser
->SetTDTagStyles();
2614 SwTextFormatColl
*pColl
= m_pCSS1Parser
->GetTextCollFromPool( nPoolId
);
2616 SwNode
*const pNd
= & m_pPam
->GetPoint()->GetNode();
2617 const SwStartNode
*pStNd
;
2618 if (m_xTable
->m_bFirstCell
)
2620 SwTextNode
* pTextNd
= pNd
->GetTextNode();
2623 eState
= SvParserState::Error
;
2626 pTextNd
->ChgFormatColl(pColl
);
2627 m_xTable
->m_bFirstCell
= false;
2628 pStNd
= pNd
->FindTableBoxStartNode();
2632 SwTableNode
*pTableNd
= pNd
->FindTableNode();
2635 eState
= SvParserState::Error
;
2638 if( pTableNd
->GetTable().GetHTMLTableLayout() )
2639 { // if there is already a HTMTableLayout, this table is already finished
2640 // and we have to look for the right table in the environment
2641 SwTableNode
*pOutTable
= pTableNd
;
2643 pTableNd
= pOutTable
;
2644 pOutTable
= pOutTable
->StartOfSectionNode()->FindTableNode();
2645 } while( pOutTable
&& pTableNd
->GetTable().GetHTMLTableLayout() );
2647 pStNd
= m_xDoc
->GetNodes().MakeTextSection( *pTableNd
->EndOfSectionNode(), SwTableBoxStartNode
,
2650 m_pPam
->GetPoint()->Assign( pStNd
->GetIndex() + 1 );
2651 m_xTable
->IncBoxCount();
2656 eState
= SvParserState::Error
;
2662 SwStartNode
*SwHTMLParser::InsertTempTableCaptionSection()
2664 SwTextFormatColl
*pColl
= m_pCSS1Parser
->GetTextCollFromPool( RES_POOLCOLL_TEXT
);
2665 SwStartNode
*pStNd
= m_xDoc
->GetNodes().MakeTextSection( m_xDoc
->GetNodes().GetEndOfExtras(),
2666 SwNormalStartNode
, pColl
);
2668 m_pPam
->GetPoint()->Assign( pStNd
->GetIndex() + 1);
2673 sal_Int32
SwHTMLParser::StripTrailingLF()
2675 sal_Int32 nStripped
= 0;
2679 // One <br> is exactly one line-break in the ReqIF case.
2683 const sal_Int32 nLen
= m_pPam
->GetPoint()->GetContentIndex();
2686 SwTextNode
* pTextNd
= m_pPam
->GetPoint()->GetNode().GetTextNode();
2687 // careful, when comments aren't ignored!!!
2690 sal_Int32 nPos
= nLen
;
2691 sal_Int32 nLFCount
= 0;
2692 while (nPos
&& ('\x0a' == pTextNd
->GetText()[--nPos
]))
2699 // On Netscape, a paragraph end matches 2 LFs
2700 // (1 is just a newline, 2 creates a blank line)
2701 // We already have this space with the lower paragraph gap
2702 // If there's a paragraph after the <BR>, we take the maximum
2703 // of the gap that results from the <BR> and <P>
2704 // That's why we need to delete 2 respectively all if less than 2
2708 nPos
= nLen
- nLFCount
;
2709 SwContentIndex
nIdx( pTextNd
, nPos
);
2710 pTextNd
->EraseText( nIdx
, nLFCount
);
2711 nStripped
= nLFCount
;
2719 SvxBrushItem
* SwHTMLParser::CreateBrushItem( const Color
*pColor
,
2720 const OUString
& rImageURL
,
2721 const OUString
& rStyle
,
2722 const OUString
& rId
,
2723 const OUString
& rClass
)
2725 SvxBrushItem
*pBrushItem
= nullptr;
2727 if( !rStyle
.isEmpty() || !rId
.isEmpty() || !rClass
.isEmpty() )
2729 SfxItemSetFixed
<RES_BACKGROUND
, RES_BACKGROUND
> aItemSet( m_xDoc
->GetAttrPool() );
2730 SvxCSS1PropertyInfo aPropInfo
;
2732 if( !rClass
.isEmpty() )
2734 OUString
aClass( rClass
);
2735 SwCSS1Parser::GetScriptFromClass( aClass
);
2736 const SvxCSS1MapEntry
*pClass
= m_pCSS1Parser
->GetClass( aClass
);
2738 aItemSet
.Put( pClass
->GetItemSet() );
2741 if( !rId
.isEmpty() )
2743 const SvxCSS1MapEntry
*pId
= m_pCSS1Parser
->GetId( rId
);
2745 aItemSet
.Put( pId
->GetItemSet() );
2748 m_pCSS1Parser
->ParseStyleOption( rStyle
, aItemSet
, aPropInfo
);
2749 if( const SvxBrushItem
*pItem
= aItemSet
.GetItemIfSet( RES_BACKGROUND
, false ) )
2751 pBrushItem
= new SvxBrushItem( *pItem
);
2755 if( !pBrushItem
&& (pColor
|| !rImageURL
.isEmpty()) )
2757 pBrushItem
= new SvxBrushItem(RES_BACKGROUND
);
2760 pBrushItem
->SetColor(*pColor
);
2762 if( !rImageURL
.isEmpty() )
2764 pBrushItem
->SetGraphicLink( URIHelper::SmartRel2Abs( INetURLObject(m_sBaseURL
), rImageURL
, Link
<OUString
*, bool>(), false) );
2765 pBrushItem
->SetGraphicPos( GPOS_TILED
);
2772 class SectionSaveStruct
: public SwPendingData
2774 sal_uInt16 m_nBaseFontStMinSave
, m_nFontStMinSave
, m_nFontStHeadStartSave
;
2775 sal_uInt16 m_nDefListDeepSave
;
2776 size_t m_nContextStMinSave
;
2777 size_t m_nContextStAttrMinSave
;
2781 std::shared_ptr
<HTMLTable
> m_xTable
;
2783 explicit SectionSaveStruct( SwHTMLParser
& rParser
);
2785 #if OSL_DEBUG_LEVEL > 0
2786 size_t GetContextStAttrMin() const { return m_nContextStAttrMinSave
; }
2788 void Restore( SwHTMLParser
& rParser
);
2791 SectionSaveStruct::SectionSaveStruct( SwHTMLParser
& rParser
) :
2792 m_nBaseFontStMinSave(rParser
.m_nBaseFontStMin
),
2793 m_nFontStMinSave(rParser
.m_nFontStMin
),
2794 m_nFontStHeadStartSave(rParser
.m_nFontStHeadStart
),
2795 m_nDefListDeepSave(rParser
.m_nDefListDeep
),
2796 m_nContextStMinSave(rParser
.m_nContextStMin
),
2797 m_nContextStAttrMinSave(rParser
.m_nContextStAttrMin
)
2799 // Freeze font stacks
2800 rParser
.m_nBaseFontStMin
= rParser
.m_aBaseFontStack
.size();
2802 rParser
.m_nFontStMin
= rParser
.m_aFontStack
.size();
2804 // Freeze context stack
2805 rParser
.m_nContextStMin
= rParser
.m_aContexts
.size();
2806 rParser
.m_nContextStAttrMin
= rParser
.m_nContextStMin
;
2808 // And remember a few counters
2809 rParser
.m_nDefListDeep
= 0;
2812 void SectionSaveStruct::Restore( SwHTMLParser
& rParser
)
2814 // Unfreeze font stacks
2815 sal_uInt16 nMin
= rParser
.m_nBaseFontStMin
;
2816 if( rParser
.m_aBaseFontStack
.size() > nMin
)
2817 rParser
.m_aBaseFontStack
.erase( rParser
.m_aBaseFontStack
.begin() + nMin
,
2818 rParser
.m_aBaseFontStack
.end() );
2819 rParser
.m_nBaseFontStMin
= m_nBaseFontStMinSave
;
2821 nMin
= rParser
.m_nFontStMin
;
2822 if( rParser
.m_aFontStack
.size() > nMin
)
2823 rParser
.m_aFontStack
.erase( rParser
.m_aFontStack
.begin() + nMin
,
2824 rParser
.m_aFontStack
.end() );
2825 rParser
.m_nFontStMin
= m_nFontStMinSave
;
2826 rParser
.m_nFontStHeadStart
= m_nFontStHeadStartSave
;
2828 OSL_ENSURE( rParser
.m_aContexts
.size() == rParser
.m_nContextStMin
&&
2829 rParser
.m_aContexts
.size() == rParser
.m_nContextStAttrMin
,
2830 "The Context Stack was not cleaned up" );
2831 rParser
.m_nContextStMin
= m_nContextStMinSave
;
2832 rParser
.m_nContextStAttrMin
= m_nContextStAttrMinSave
;
2834 // Reconstruct a few counters
2835 rParser
.m_nDefListDeep
= m_nDefListDeepSave
;
2837 // Reset a few flags
2838 rParser
.m_bNoParSpace
= false;
2839 rParser
.m_nOpenParaToken
= HtmlTokenId::NONE
;
2841 rParser
.m_aParaAttrs
.clear();
2844 class CellSaveStruct
: public SectionSaveStruct
2846 OUString m_aStyle
, m_aId
, m_aClass
;
2847 OUString m_aBGImage
;
2849 std::shared_ptr
<SvxBoxItem
> m_xBoxItem
;
2851 std::shared_ptr
<HTMLTableCnts
> m_xCnts
; // List of all contents
2852 HTMLTableCnts
* m_pCurrCnts
; // current content or 0
2853 std::optional
<SwNodeIndex
> m_oNoBreakEndNodeIndex
; // Paragraph index of a <NOBR>
2857 sal_uInt32 m_nNumFormat
;
2859 sal_uInt16 m_nRowSpan
, m_nColSpan
, m_nWidth
, m_nHeight
;
2860 sal_Int32 m_nNoBreakEndContentPos
; // Character index of a <NOBR>
2862 sal_Int16 m_eVertOri
;
2865 bool m_bPercentWidth
: 1;
2866 bool m_bHasNumFormat
: 1;
2867 bool m_bHasValue
: 1;
2868 bool m_bBGColor
: 1;
2869 bool m_bNoWrap
: 1; // NOWRAP option
2870 bool m_bNoBreak
: 1; // NOBREAK tag
2874 CellSaveStruct( SwHTMLParser
& rParser
, HTMLTable
const *pCurTable
, bool bHd
,
2877 void AddContents( std::unique_ptr
<HTMLTableCnts
> pNewCnts
);
2878 bool HasFirstContents() const { return bool(m_xCnts
); }
2880 void ClearIsInSection() { m_pCurrCnts
= nullptr; }
2881 bool IsInSection() const { return m_pCurrCnts
!=nullptr; }
2883 void InsertCell( SwHTMLParser
& rParser
, HTMLTable
*pCurTable
);
2885 bool IsHeaderCell() const { return m_bHead
; }
2887 void StartNoBreak( const SwPosition
& rPos
);
2888 void EndNoBreak( const SwPosition
& rPos
);
2889 void CheckNoBreak( const SwPosition
& rPos
);
2892 CellSaveStruct::CellSaveStruct( SwHTMLParser
& rParser
, HTMLTable
const *pCurTable
,
2893 bool bHd
, bool bReadOpt
) :
2894 SectionSaveStruct( rParser
),
2895 m_pCurrCnts( nullptr ),
2902 m_nNoBreakEndContentPos( 0 ),
2903 m_eVertOri( pCurTable
->GetInheritedVertOri() ),
2905 m_bPercentWidth( false ),
2906 m_bHasNumFormat( false ),
2907 m_bHasValue( false ),
2908 m_bBGColor( false ),
2912 OUString aNumFormat
, aValue
, aDir
, aLang
;
2913 SvxAdjust
eAdjust( pCurTable
->GetInheritedAdjust() );
2917 const HTMLOptions
& rOptions
= rParser
.GetOptions();
2918 for (size_t i
= rOptions
.size(); i
; )
2920 const HTMLOption
& rOption
= rOptions
[--i
];
2921 switch( rOption
.GetToken() )
2923 case HtmlOptionId::ID
:
2924 m_aId
= rOption
.GetString();
2926 case HtmlOptionId::COLSPAN
:
2927 m_nColSpan
= o3tl::narrowing
<sal_uInt16
>(rOption
.GetNumber());
2928 if (m_nColSpan
> 256)
2930 SAL_INFO("sw.html", "ignoring huge COLSPAN " << m_nColSpan
);
2934 case HtmlOptionId::ROWSPAN
:
2935 m_nRowSpan
= o3tl::narrowing
<sal_uInt16
>(rOption
.GetNumber());
2936 if (m_nRowSpan
> 8192 || (m_nRowSpan
> 256 && utl::ConfigManager::IsFuzzing()))
2938 SAL_INFO("sw.html", "ignoring huge ROWSPAN " << m_nRowSpan
);
2942 case HtmlOptionId::ALIGN
:
2943 eAdjust
= rOption
.GetEnum( aHTMLPAlignTable
, eAdjust
);
2945 case HtmlOptionId::VALIGN
:
2946 m_eVertOri
= rOption
.GetEnum( aHTMLTableVAlignTable
, m_eVertOri
);
2948 case HtmlOptionId::WIDTH
:
2949 m_nWidth
= o3tl::narrowing
<sal_uInt16
>(rOption
.GetNumber()); // Just for Netscape
2950 m_bPercentWidth
= (rOption
.GetString().indexOf('%') != -1);
2951 if( m_bPercentWidth
&& m_nWidth
>100 )
2954 case HtmlOptionId::HEIGHT
:
2955 m_nHeight
= o3tl::narrowing
<sal_uInt16
>(rOption
.GetNumber()); // Just for Netscape
2956 if( rOption
.GetString().indexOf('%') != -1)
2957 m_nHeight
= 0; // don't consider % attributes
2959 case HtmlOptionId::BGCOLOR
:
2960 // Ignore empty BGCOLOR on <TABLE>, <TR> and <TD>/<TH> like Netscape
2961 // *really* not on other tags
2962 if( !rOption
.GetString().isEmpty() )
2964 rOption
.GetColor( m_aBGColor
);
2968 case HtmlOptionId::BACKGROUND
:
2969 m_aBGImage
= rOption
.GetString();
2971 case HtmlOptionId::STYLE
:
2972 m_aStyle
= rOption
.GetString();
2974 case HtmlOptionId::CLASS
:
2975 m_aClass
= rOption
.GetString();
2977 case HtmlOptionId::LANG
:
2978 aLang
= rOption
.GetString();
2980 case HtmlOptionId::DIR:
2981 aDir
= rOption
.GetString();
2983 case HtmlOptionId::SDNUM
:
2984 aNumFormat
= rOption
.GetString();
2985 m_bHasNumFormat
= true;
2987 case HtmlOptionId::SDVAL
:
2989 aValue
= rOption
.GetString();
2991 case HtmlOptionId::NOWRAP
:
2998 if( !m_aId
.isEmpty() )
2999 rParser
.InsertBookmark( m_aId
);
3002 if( m_bHasNumFormat
)
3005 m_nValue
= SfxHTMLParser::GetTableDataOptionsValNum(
3006 m_nNumFormat
, eLang
, aValue
, aNumFormat
,
3007 *rParser
.m_xDoc
->GetNumberFormatter() );
3010 // Create a new context but don't anchor the drawing::Alignment attribute there,
3011 // since there's no section yet
3016 nToken
= HtmlTokenId::TABLEHEADER_ON
;
3017 nColl
= RES_POOLCOLL_TABLE_HDLN
;
3021 nToken
= HtmlTokenId::TABLEDATA_ON
;
3022 nColl
= RES_POOLCOLL_TABLE
;
3024 std::unique_ptr
<HTMLAttrContext
> xCntxt(new HTMLAttrContext(nToken
, nColl
, OUString(), true));
3025 if( SvxAdjust::End
!= eAdjust
)
3026 rParser
.InsertAttr(&rParser
.m_xAttrTab
->pAdjust
, SvxAdjustItem(eAdjust
, RES_PARATR_ADJUST
),
3029 if( SwHTMLParser::HasStyleOptions( m_aStyle
, m_aId
, m_aClass
, &aLang
, &aDir
) )
3031 SfxItemSet
aItemSet( rParser
.m_xDoc
->GetAttrPool(),
3032 rParser
.m_pCSS1Parser
->GetWhichMap() );
3033 SvxCSS1PropertyInfo aPropInfo
;
3035 if( rParser
.ParseStyleOptions( m_aStyle
, m_aId
, m_aClass
, aItemSet
,
3036 aPropInfo
, &aLang
, &aDir
) )
3038 if (SvxBoxItem
const* pItem
= aItemSet
.GetItemIfSet(RES_BOX
, false))
3039 { // fdo#41796: steal box item to set it in FixFrameFormat later!
3040 m_xBoxItem
.reset(pItem
->Clone());
3041 aItemSet
.ClearItem(RES_BOX
);
3043 rParser
.InsertAttrs(aItemSet
, aPropInfo
, xCntxt
.get());
3047 rParser
.SplitPREListingXMP(xCntxt
.get());
3049 rParser
.PushContext(xCntxt
);
3052 void CellSaveStruct::AddContents( std::unique_ptr
<HTMLTableCnts
> pNewCnts
)
3054 m_pCurrCnts
= pNewCnts
.get();
3057 m_xCnts
->Add( std::move(pNewCnts
) );
3059 m_xCnts
= std::move(pNewCnts
);
3062 void CellSaveStruct::InsertCell( SwHTMLParser
& rParser
,
3063 HTMLTable
*pCurTable
)
3065 #if OSL_DEBUG_LEVEL > 0
3066 // The attributes need to have been removed when tidying up the context stack,
3067 // Otherwise something's wrong. Let's check that...
3069 // MIB 8.1.98: When attributes were opened outside of a cell,
3070 // they're still in the attribute table and will only be deleted at the end
3071 // through the CleanContext calls in BuildTable. We don't check that there
3072 // so that we get no assert [violations, by translator]
3073 // We can see this on nContextStAttrMin: the remembered value of nContextStAttrMinSave
3074 // is the value that nContextStAttrMin had at the start of the table. And the
3075 // current value of nContextStAttrMin corresponds to the number of contexts
3076 // we found at the start of the cell. If the values differ, contexts
3077 // were created and we don't check anything.
3079 if( rParser
.m_nContextStAttrMin
== GetContextStAttrMin() )
3081 HTMLAttr
** pTable
= reinterpret_cast<HTMLAttr
**>(rParser
.m_xAttrTab
.get());
3083 for( auto nCnt
= sizeof( HTMLAttrTable
) / sizeof( HTMLAttr
* );
3086 OSL_ENSURE( !*pTable
, "The attribute table isn't empty" );
3091 // we need to add the cell on the current position
3092 std::shared_ptr
<SvxBrushItem
> xBrushItem(
3093 rParser
.CreateBrushItem(m_bBGColor
? &m_aBGColor
: nullptr, m_aBGImage
,
3094 m_aStyle
, m_aId
, m_aClass
));
3095 pCurTable
->InsertCell( m_xCnts
, m_nRowSpan
, m_nColSpan
, m_nWidth
,
3096 m_bPercentWidth
, m_nHeight
, m_eVertOri
, xBrushItem
, m_xBoxItem
,
3097 m_bHasNumFormat
, m_nNumFormat
, m_bHasValue
, m_nValue
,
3102 void CellSaveStruct::StartNoBreak( const SwPosition
& rPos
)
3105 (!rPos
.GetContentIndex() && m_pCurrCnts
== m_xCnts
.get() &&
3106 m_xCnts
->GetStartNode() &&
3107 m_xCnts
->GetStartNode()->GetIndex() + 1 ==
3108 rPos
.GetNodeIndex()) )
3114 void CellSaveStruct::EndNoBreak( const SwPosition
& rPos
)
3118 m_oNoBreakEndNodeIndex
.emplace( rPos
.GetNode() );
3119 m_nNoBreakEndContentPos
= rPos
.GetContentIndex();
3124 void CellSaveStruct::CheckNoBreak( const SwPosition
& rPos
)
3126 if (!(m_xCnts
&& m_pCurrCnts
== m_xCnts
.get()))
3131 // <NOBR> wasn't closed
3132 m_xCnts
->SetNoBreak();
3134 else if( m_oNoBreakEndNodeIndex
&&
3135 m_oNoBreakEndNodeIndex
->GetIndex() == rPos
.GetNodeIndex() )
3137 if( m_nNoBreakEndContentPos
== rPos
.GetContentIndex() )
3139 // <NOBR> was closed immediately before the cell end
3140 m_xCnts
->SetNoBreak();
3142 else if( m_nNoBreakEndContentPos
+ 1 == rPos
.GetContentIndex() )
3144 SwTextNode
const*const pTextNd(rPos
.GetNode().GetTextNode());
3147 sal_Unicode
const cLast
=
3148 pTextNd
->GetText()[m_nNoBreakEndContentPos
];
3149 if( ' '==cLast
|| '\x0a'==cLast
)
3151 // There's just a blank or a newline between the <NOBR> and the cell end
3152 m_xCnts
->SetNoBreak();
3159 std::unique_ptr
<HTMLTableCnts
> SwHTMLParser::InsertTableContents(
3162 // create a new section, the PaM is gonna be there
3163 const SwStartNode
*pStNd
=
3164 InsertTableSection( static_cast< sal_uInt16
>(bHead
? RES_POOLCOLL_TABLE_HDLN
3165 : RES_POOLCOLL_TABLE
) );
3167 if( GetNumInfo().GetNumRule() )
3169 // Set the first paragraph to non-enumerated
3170 sal_uInt8 nLvl
= GetNumInfo().GetLevel();
3175 // Reset attributation start
3176 const SwNode
& rSttPara
= m_pPam
->GetPoint()->GetNode();
3177 sal_Int32 nSttCnt
= m_pPam
->GetPoint()->GetContentIndex();
3179 HTMLAttr
** pHTMLAttributes
= reinterpret_cast<HTMLAttr
**>(m_xAttrTab
.get());
3180 for (sal_uInt16 nCnt
= sizeof(HTMLAttrTable
) / sizeof(HTMLAttr
*); nCnt
--; ++pHTMLAttributes
)
3182 HTMLAttr
*pAttr
= *pHTMLAttributes
;
3185 OSL_ENSURE( !pAttr
->GetPrev(), "Attribute has previous list" );
3186 pAttr
->m_nStartPara
= rSttPara
;
3187 pAttr
->m_nEndPara
= rSttPara
;
3188 pAttr
->m_nStartContent
= nSttCnt
;
3189 pAttr
->m_nEndContent
= nSttCnt
;
3191 pAttr
= pAttr
->GetNext();
3195 return std::make_unique
<HTMLTableCnts
>( pStNd
);
3198 sal_uInt16
SwHTMLParser::IncGrfsThatResizeTable()
3200 return m_xTable
? m_xTable
->IncGrfsThatResize() : 0;
3203 void SwHTMLParser::RegisterDrawObjectToTable( HTMLTable
*pCurTable
,
3204 SdrObject
*pObj
, sal_uInt8 nPercentWidth
)
3206 pCurTable
->RegisterDrawObject( pObj
, nPercentWidth
);
3209 void SwHTMLParser::BuildTableCell( HTMLTable
*pCurTable
, bool bReadOptions
,
3212 if( !IsParserWorking() && m_vPendingStack
.empty() )
3215 ::comphelper::FlagRestorationGuard
g(m_isInTableStructure
, false);
3216 std::unique_ptr
<CellSaveStruct
> xSaveStruct
;
3218 HtmlTokenId nToken
= HtmlTokenId::NONE
;
3219 bool bPending
= false;
3220 if( !m_vPendingStack
.empty() )
3222 xSaveStruct
.reset(static_cast<CellSaveStruct
*>(m_vPendingStack
.back().pData
.release()));
3224 m_vPendingStack
.pop_back();
3225 nToken
= !m_vPendingStack
.empty() ? m_vPendingStack
.back().nToken
: GetSaveToken();
3226 bPending
= SvParserState::Error
== eState
&& !m_vPendingStack
.empty();
3228 SaveState( nToken
);
3232 // <TH> resp. <TD> were already read
3233 if (m_xTable
->IsOverflowing())
3235 SaveState( HtmlTokenId::NONE
);
3239 if( !pCurTable
->GetContext() )
3241 bool bTopTable
= m_xTable
.get() == pCurTable
;
3243 // the table has no content yet, this means the actual table needs
3244 // to be created first
3247 RES_PARATR_SPLIT
, RES_PARATR_SPLIT
,
3248 RES_PAGEDESC
, RES_PAGEDESC
,
3249 RES_BREAK
, RES_BREAK
,
3250 RES_BACKGROUND
, RES_BACKGROUND
,
3252 RES_LAYOUT_SPLIT
, RES_LAYOUT_SPLIT
,
3253 RES_FRAMEDIR
, RES_FRAMEDIR
3254 > aItemSet( m_xDoc
->GetAttrPool() );
3255 SvxCSS1PropertyInfo aPropInfo
;
3257 bool bStyleParsed
= ParseStyleOptions( pCurTable
->GetStyle(),
3259 pCurTable
->GetClass(),
3260 aItemSet
, aPropInfo
,
3261 nullptr, &pCurTable
->GetDirection() );
3264 if( const SvxBrushItem
* pItem
= aItemSet
.GetItemIfSet(
3265 RES_BACKGROUND
, false ) )
3267 pCurTable
->SetBGBrush( *pItem
);
3268 aItemSet
.ClearItem( RES_BACKGROUND
);
3270 if( const SvxFormatSplitItem
* pSplitItem
= aItemSet
.GetItemIfSet(
3271 RES_PARATR_SPLIT
, false ) )
3274 SwFormatLayoutSplit( pSplitItem
->GetValue() ) );
3275 aItemSet
.ClearItem( RES_PARATR_SPLIT
);
3279 sal_uInt16 nLeftSpace
= 0;
3280 sal_uInt16 nRightSpace
= 0;
3282 GetMarginsFromContextWithNumberBullet( nLeftSpace
, nRightSpace
, nIndent
);
3284 // save the current position we'll get back to some time
3285 SwPosition
*pSavePos
= nullptr;
3286 bool bForceFrame
= false;
3287 bool bAppended
= false;
3288 bool bParentLFStripped
= false;
3291 SvxAdjust eTableAdjust
= m_xTable
->GetTableAdjust(false);
3293 // If the table is left or right adjusted or should be in a text frame,
3295 bForceFrame
= eTableAdjust
== SvxAdjust::Left
||
3296 eTableAdjust
== SvxAdjust::Right
||
3297 pCurTable
->HasToFly();
3299 // The table either shouldn't get in a text frame and isn't in one
3300 // (it gets simulated through cells),
3301 // or there's already content at that position
3302 OSL_ENSURE( !bForceFrame
|| pCurTable
->HasParentSection(),
3303 "table in frame has no parent!" );
3305 bool bAppend
= false;
3308 // If the table gets in a border, we only need to open a new
3309 //paragraph if the paragraph has text frames that don't fly
3310 bAppend
= HasCurrentParaFlys(true);
3314 // Otherwise, we need to open a new paragraph if the paragraph
3315 // is empty or contains text frames or bookmarks
3317 m_pPam
->GetPoint()->GetContentIndex() ||
3318 HasCurrentParaFlys() ||
3319 HasCurrentParaBookmarks();
3323 if( !m_pPam
->GetPoint()->GetContentIndex() )
3325 //Set default to CJK and CTL
3326 m_xDoc
->SetTextFormatColl( *m_pPam
,
3327 m_pCSS1Parser
->GetTextCollFromPool(RES_POOLCOLL_STANDARD
) );
3328 SvxFontHeightItem
aFontHeight( 40, 100, RES_CHRATR_FONTSIZE
);
3331 new HTMLAttr( *m_pPam
->GetPoint(), aFontHeight
, nullptr, std::shared_ptr
<HTMLAttrTable
>() );
3332 m_aSetAttrTab
.push_back( pTmp
);
3334 SvxFontHeightItem
aFontHeightCJK( 40, 100, RES_CHRATR_CJK_FONTSIZE
);
3336 new HTMLAttr( *m_pPam
->GetPoint(), aFontHeightCJK
, nullptr, std::shared_ptr
<HTMLAttrTable
>() );
3337 m_aSetAttrTab
.push_back( pTmp
);
3339 SvxFontHeightItem
aFontHeightCTL( 40, 100, RES_CHRATR_CTL_FONTSIZE
);
3341 new HTMLAttr( *m_pPam
->GetPoint(), aFontHeightCTL
, nullptr, std::shared_ptr
<HTMLAttrTable
>() );
3342 m_aSetAttrTab
.push_back( pTmp
);
3344 pTmp
= new HTMLAttr( *m_pPam
->GetPoint(),
3345 SvxULSpaceItem( 0, 0, RES_UL_SPACE
), nullptr, std::shared_ptr
<HTMLAttrTable
>() );
3346 m_aSetAttrTab
.push_front( pTmp
); // Position 0, since
3347 // something can be set by
3348 // the table end before
3350 AppendTextNode( AM_NOSPACE
);
3353 else if( !m_aParaAttrs
.empty() )
3357 // The paragraph will be moved right behind the table.
3358 // That's why we remove all hard attributes of that paragraph
3360 for(HTMLAttr
* i
: m_aParaAttrs
)
3364 m_aParaAttrs
.clear();
3367 pSavePos
= new SwPosition( *m_pPam
->GetPoint() );
3369 else if( pCurTable
->HasParentSection() )
3371 bParentLFStripped
= StripTrailingLF() > 0;
3373 // Close paragraph resp. headers
3374 m_nOpenParaToken
= HtmlTokenId::NONE
;
3375 m_nFontStHeadStart
= m_nFontStMin
;
3377 // The hard attributes on that paragraph are never gonna be invalid anymore
3378 m_aParaAttrs
.clear();
3381 // create a table context
3382 std::unique_ptr
<HTMLTableContext
> pTCntxt(
3383 new HTMLTableContext( pSavePos
, m_nContextStMin
,
3384 m_nContextStAttrMin
) );
3386 // end all open attributes and open them again behind the table
3387 std::optional
<std::deque
<std::unique_ptr
<HTMLAttr
>>> pPostIts
;
3388 if( !bForceFrame
&& (bTopTable
|| pCurTable
->HasParentSection()) )
3390 SplitAttrTab(pTCntxt
->m_xAttrTab
, bTopTable
);
3391 // If we reuse an already existing paragraph, we can't add
3392 // PostIts since the paragraph gets behind that table.
3393 // They're gonna be moved into the first paragraph of the table
3394 // If we have tables in tables, we also can't add PostIts to a
3395 // still empty paragraph, since it's not gonna be deleted that way
3396 if( (bTopTable
&& !bAppended
) ||
3397 (!bTopTable
&& !bParentLFStripped
&&
3398 !m_pPam
->GetPoint()->GetContentIndex()) )
3400 SetAttr( bTopTable
, bTopTable
, pPostIts
? &*pPostIts
: nullptr );
3404 SaveAttrTab(pTCntxt
->m_xAttrTab
);
3405 if( bTopTable
&& !bAppended
)
3408 SetAttr( true, true, &*pPostIts
);
3411 m_bNoParSpace
= false;
3413 // Save current numbering and turn it off
3414 pTCntxt
->SetNumInfo( GetNumInfo() );
3415 GetNumInfo().Clear();
3416 pTCntxt
->SavePREListingXMP( *this );
3422 // the table should be put in a text frame
3424 SfxItemSetFixed
<RES_FRMATR_BEGIN
, RES_FRMATR_END
-1>
3425 aFrameSet( m_xDoc
->GetAttrPool() );
3426 if( !pCurTable
->IsNewDoc() )
3427 Reader::ResetFrameFormatAttrs( aFrameSet
);
3429 css::text::WrapTextMode eSurround
= css::text::WrapTextMode_NONE
;
3432 switch( pCurTable
->GetTableAdjust(true) )
3434 case SvxAdjust::Right
:
3435 eHori
= text::HoriOrientation::RIGHT
;
3436 eSurround
= css::text::WrapTextMode_LEFT
;
3438 case SvxAdjust::Center
:
3439 eHori
= text::HoriOrientation::CENTER
;
3441 case SvxAdjust::Left
:
3442 eSurround
= css::text::WrapTextMode_RIGHT
;
3445 eHori
= text::HoriOrientation::LEFT
;
3448 SetAnchorAndAdjustment( text::VertOrientation::NONE
, eHori
, aFrameSet
,
3450 aFrameSet
.Put( SwFormatSurround(eSurround
) );
3452 constexpr tools::Long constTwips_100mm
= o3tl::convert(tools::Long(100), o3tl::Length::mm
, o3tl::Length::twip
);
3454 SwFormatFrameSize
aFrameSize( SwFrameSize::Variable
, constTwips_100mm
, MINLAY
);
3455 aFrameSize
.SetWidthPercent( 100 );
3456 aFrameSet
.Put( aFrameSize
);
3458 sal_uInt16 nSpace
= pCurTable
->GetHSpace();
3460 aFrameSet
.Put( SvxLRSpaceItem(nSpace
, nSpace
, 0, RES_LR_SPACE
) );
3461 nSpace
= pCurTable
->GetVSpace();
3463 aFrameSet
.Put( SvxULSpaceItem(nSpace
,nSpace
, RES_UL_SPACE
) );
3465 RndStdIds eAnchorId
= aFrameSet
.
3468 SwFrameFormat
*pFrameFormat
= m_xDoc
->MakeFlySection(
3469 eAnchorId
, m_pPam
->GetPoint(), &aFrameSet
);
3471 pTCntxt
->SetFrameFormat( pFrameFormat
);
3472 const SwFormatContent
& rFlyContent
= pFrameFormat
->GetContent();
3473 m_pPam
->GetPoint()->Assign( *rFlyContent
.GetContentIdx() );
3474 m_xDoc
->GetNodes().GoNext( m_pPam
->GetPoint() );
3477 // create a SwTable with a box and set the PaM to the content of
3478 // the box section (the adjustment parameter is a dummy for now
3479 // and will be corrected later)
3480 OSL_ENSURE( !m_pPam
->GetPoint()->GetContentIndex(),
3481 "The paragraph after the table is not empty!" );
3482 const SwTable
* pSwTable
= m_xDoc
->InsertTable(
3483 SwInsertTableOptions( SwInsertTableFlags::HeadlineNoBorder
, 1 ),
3484 *m_pPam
->GetPoint(), 1, 1, text::HoriOrientation::LEFT
);
3485 SwFrameFormat
*pFrameFormat
= pSwTable
? pSwTable
->GetFrameFormat() : nullptr;
3489 SwNodeIndex
aDstIdx( m_pPam
->GetPoint()->GetNode() );
3490 m_pPam
->Move( fnMoveBackward
);
3491 m_xDoc
->GetNodes().Delete( aDstIdx
);
3495 if (bStyleParsed
&& pFrameFormat
)
3497 m_pCSS1Parser
->SetFormatBreak( aItemSet
, aPropInfo
);
3498 pFrameFormat
->SetFormatAttr( aItemSet
);
3500 m_pPam
->Move( fnMoveBackward
);
3503 SwNode
const*const pNd
= & m_pPam
->GetPoint()->GetNode();
3504 SwTextNode
*const pOldTextNd
= (!bAppended
&& !bForceFrame
) ?
3505 pSavePos
->GetNode().GetTextNode() : nullptr;
3507 if (pFrameFormat
&& pOldTextNd
)
3509 const SwFormatPageDesc
* pPageDescItem
= pOldTextNd
->GetSwAttrSet()
3510 .GetItemIfSet( RES_PAGEDESC
, false );
3511 if( pPageDescItem
&& pPageDescItem
->GetPageDesc() )
3513 pFrameFormat
->SetFormatAttr( *pPageDescItem
);
3514 pOldTextNd
->ResetAttr( RES_PAGEDESC
);
3517 if( const SvxFormatBreakItem
* pBreakItem
= pOldTextNd
->GetSwAttrSet()
3518 .GetItemIfSet( RES_BREAK
) )
3520 switch( pBreakItem
->GetBreak() )
3522 case SvxBreak::PageBefore
:
3523 case SvxBreak::PageAfter
:
3524 case SvxBreak::PageBoth
:
3525 pFrameFormat
->SetFormatAttr( *pBreakItem
);
3526 pOldTextNd
->ResetAttr( RES_BREAK
);
3534 if( !bAppended
&& pPostIts
)
3536 // set still-existing PostIts to the first paragraph of the table
3537 InsertAttrs( std::move(*pPostIts
) );
3541 pTCntxt
->SetTableNode( const_cast<SwTableNode
*>(pNd
->FindTableNode()) );
3543 auto pTableNode
= pTCntxt
->GetTableNode();
3544 pCurTable
->SetTable( pTableNode
, std::move(pTCntxt
),
3545 nLeftSpace
, nRightSpace
,
3546 pSwTable
, bForceFrame
);
3548 OSL_ENSURE( !pPostIts
, "unused PostIts" );
3552 // still open sections need to be deleted
3553 if( EndSections( bParentLFStripped
) )
3554 bParentLFStripped
= false;
3556 if( pCurTable
->HasParentSection() )
3558 // after that, we remove a possibly redundant empty paragraph,
3559 // but only if it was empty before we stripped the LFs
3560 if( !bParentLFStripped
)
3561 StripTrailingPara();
3565 // move still existing PostIts to the end of the current paragraph
3566 InsertAttrs( std::move(*pPostIts
) );
3571 SwNode
const*const pNd
= & m_pPam
->GetPoint()->GetNode();
3572 const SwStartNode
*pStNd
= (m_xTable
->m_bFirstCell
? pNd
->FindTableNode()
3573 : pNd
->FindTableBoxStartNode() );
3575 pCurTable
->SetTable( pStNd
, std::move(pTCntxt
), nLeftSpace
, nRightSpace
);
3578 // Freeze the context stack, since there could be attributes set
3579 // outside of cells. Can't happen earlier, since there may be
3580 // searches in the stack
3581 m_nContextStMin
= m_aContexts
.size();
3582 m_nContextStAttrMin
= m_nContextStMin
;
3585 xSaveStruct
.reset(new CellSaveStruct(*this, pCurTable
, bHead
, bReadOptions
));
3587 // If the first GetNextToken() doesn't succeed (pending input), must re-read from the beginning.
3588 SaveState( HtmlTokenId::NONE
);
3591 if( nToken
== HtmlTokenId::NONE
)
3592 nToken
= GetNextToken(); // Token after <TABLE>
3595 while( (IsParserWorking() && !bDone
) || bPending
)
3597 SaveState( nToken
);
3599 nToken
= FilterToken( nToken
);
3601 OSL_ENSURE( !m_vPendingStack
.empty() || !m_bCallNextToken
|| xSaveStruct
->IsInSection(),
3602 "Where is the section??" );
3603 if( m_vPendingStack
.empty() && m_bCallNextToken
&& xSaveStruct
->IsInSection() )
3605 // Call NextToken directly (e.g. ignore the content of floating frames or applets)
3606 NextToken( nToken
);
3608 else switch( nToken
)
3610 case HtmlTokenId::TABLEHEADER_ON
:
3611 case HtmlTokenId::TABLEDATA_ON
:
3612 case HtmlTokenId::TABLEROW_ON
:
3613 case HtmlTokenId::TABLEROW_OFF
:
3614 case HtmlTokenId::THEAD_ON
:
3615 case HtmlTokenId::THEAD_OFF
:
3616 case HtmlTokenId::TFOOT_ON
:
3617 case HtmlTokenId::TFOOT_OFF
:
3618 case HtmlTokenId::TBODY_ON
:
3619 case HtmlTokenId::TBODY_OFF
:
3620 case HtmlTokenId::TABLE_OFF
:
3623 case HtmlTokenId::TABLEHEADER_OFF
:
3624 case HtmlTokenId::TABLEDATA_OFF
:
3627 case HtmlTokenId::TABLE_ON
:
3629 bool bHasToFly
= false;
3630 SvxAdjust eTabAdjust
= SvxAdjust::End
;
3631 if( m_vPendingStack
.empty() )
3633 // only if we create a new table, but not if we're still
3634 // reading in the table after a Pending
3635 xSaveStruct
->m_xTable
= m_xTable
;
3637 // HACK: create a section for a table that goes in a text frame
3638 if( !xSaveStruct
->IsInSection() )
3640 // The loop needs to be forward, since the
3641 // first option always wins
3642 bool bNeedsSection
= false;
3643 const HTMLOptions
& rHTMLOptions
= GetOptions();
3644 for (const auto & rOption
: rHTMLOptions
)
3646 if( HtmlOptionId::ALIGN
==rOption
.GetToken() )
3648 SvxAdjust eAdjust
= rOption
.GetEnum( aHTMLPAlignTable
, SvxAdjust::End
);
3649 bNeedsSection
= SvxAdjust::Left
== eAdjust
||
3650 SvxAdjust::Right
== eAdjust
;
3656 xSaveStruct
->AddContents(
3657 InsertTableContents(bHead
) );
3662 // If Flys are anchored in the current paragraph,
3663 // the table needs to get in a text frame
3664 bHasToFly
= HasCurrentParaFlys(false,true);
3667 // There could be a section in the cell
3668 eTabAdjust
= m_xAttrTab
->pAdjust
3669 ? static_cast<const SvxAdjustItem
&>(m_xAttrTab
->pAdjust
->GetItem()).
3674 std::shared_ptr
<HTMLTable
> xSubTable
= BuildTable(eTabAdjust
,
3676 xSaveStruct
->IsInSection(),
3678 if( SvParserState::Pending
!= GetStatus() )
3680 // Only if the table is really complete
3683 OSL_ENSURE( xSubTable
->GetTableAdjust(false)!= SvxAdjust::Left
&&
3684 xSubTable
->GetTableAdjust(false)!= SvxAdjust::Right
,
3685 "left or right aligned tables belong in frames" );
3687 auto& rParentContents
= xSubTable
->GetParentContents();
3688 if (rParentContents
)
3690 OSL_ENSURE( !xSaveStruct
->IsInSection(),
3691 "Where is the section" );
3693 // If there's no table coming, we have a section
3694 xSaveStruct
->AddContents(std::move(rParentContents
));
3697 const SwStartNode
*pCapStNd
=
3698 xSubTable
->GetCaptionStartNode();
3700 if (xSubTable
->GetContext())
3702 OSL_ENSURE( !xSubTable
->GetContext()->GetFrameFormat(),
3705 if( pCapStNd
&& xSubTable
->IsTopCaption() )
3707 xSaveStruct
->AddContents(
3708 std::make_unique
<HTMLTableCnts
>(pCapStNd
) );
3711 xSaveStruct
->AddContents(
3712 std::make_unique
<HTMLTableCnts
>(xSubTable
) );
3714 if( pCapStNd
&& !xSubTable
->IsTopCaption() )
3716 xSaveStruct
->AddContents(
3717 std::make_unique
<HTMLTableCnts
>(pCapStNd
) );
3720 // We don't have a section anymore
3721 xSaveStruct
->ClearIsInSection();
3725 // Since we can't delete this section (it might
3726 // belong to the first box), we'll add it
3727 xSaveStruct
->AddContents(
3728 std::make_unique
<HTMLTableCnts
>(pCapStNd
) );
3730 // We don't have a section anymore
3731 xSaveStruct
->ClearIsInSection();
3735 m_xTable
= xSaveStruct
->m_xTable
;
3740 case HtmlTokenId::NOBR_ON
:
3741 // HACK for MS: Is the <NOBR> at the start of the cell?
3742 xSaveStruct
->StartNoBreak( *m_pPam
->GetPoint() );
3745 case HtmlTokenId::NOBR_OFF
:
3746 xSaveStruct
->EndNoBreak( *m_pPam
->GetPoint() );
3749 case HtmlTokenId::COMMENT
:
3750 // Spaces are not gonna be deleted with comment fields,
3751 // and we don't want a new cell for a comment
3752 NextToken( nToken
);
3755 case HtmlTokenId::MARQUEE_ON
:
3756 if( !xSaveStruct
->IsInSection() )
3758 // create a new section, the PaM is gonna be there
3759 xSaveStruct
->AddContents(
3760 InsertTableContents( bHead
) );
3762 m_bCallNextToken
= true;
3763 NewMarquee( pCurTable
);
3766 case HtmlTokenId::TEXTTOKEN
:
3767 // Don't add a section for an empty string
3768 if( !xSaveStruct
->IsInSection() && 1==aToken
.getLength() &&
3773 if( !xSaveStruct
->IsInSection() )
3775 // add a new section, the PaM's gonna be there
3776 xSaveStruct
->AddContents(
3777 InsertTableContents( bHead
) );
3780 if( IsParserWorking() || bPending
)
3781 NextToken( nToken
);
3785 OSL_ENSURE( !bPending
|| m_vPendingStack
.empty(),
3786 "SwHTMLParser::BuildTableCell: There is a PendStack again" );
3788 if( IsParserWorking() )
3789 SaveState( HtmlTokenId::NONE
);
3792 nToken
= GetNextToken();
3795 if( SvParserState::Pending
== GetStatus() )
3797 m_vPendingStack
.emplace_back( bHead
? HtmlTokenId::TABLEHEADER_ON
3798 : HtmlTokenId::TABLEDATA_ON
);
3799 m_vPendingStack
.back().pData
= std::move(xSaveStruct
);
3804 // If the content of the cell was empty, we need to create an empty content
3805 // We also create an empty content if the cell ended with a table and had no
3806 // COL tags. Otherwise, it was probably exported by us and we don't
3807 // want to have an additional paragraph
3808 if( !xSaveStruct
->HasFirstContents() ||
3809 (!xSaveStruct
->IsInSection() && !pCurTable
->HasColTags()) )
3811 OSL_ENSURE( xSaveStruct
->HasFirstContents() ||
3812 !xSaveStruct
->IsInSection(),
3813 "Section or not, that is the question here" );
3814 const SwStartNode
*pStNd
=
3815 InsertTableSection( static_cast< sal_uInt16
>(xSaveStruct
->IsHeaderCell()
3816 ? RES_POOLCOLL_TABLE_HDLN
3817 : RES_POOLCOLL_TABLE
));
3820 eState
= SvParserState::Error
;
3823 const SwEndNode
*pEndNd
= pStNd
->EndOfSectionNode();
3824 SwContentNode
*pCNd
= m_xDoc
->GetNodes()[pEndNd
->GetIndex()-1] ->GetContentNode();
3826 eState
= SvParserState::Error
;
3829 //Added defaults to CJK and CTL
3830 SvxFontHeightItem
aFontHeight( 40, 100, RES_CHRATR_FONTSIZE
);
3831 pCNd
->SetAttr( aFontHeight
);
3832 SvxFontHeightItem
aFontHeightCJK( 40, 100, RES_CHRATR_CJK_FONTSIZE
);
3833 pCNd
->SetAttr( aFontHeightCJK
);
3834 SvxFontHeightItem
aFontHeightCTL( 40, 100, RES_CHRATR_CTL_FONTSIZE
);
3835 pCNd
->SetAttr( aFontHeightCTL
);
3839 xSaveStruct
->AddContents( std::make_unique
<HTMLTableCnts
>(pStNd
) );
3840 xSaveStruct
->ClearIsInSection();
3843 if( xSaveStruct
->IsInSection() )
3845 xSaveStruct
->CheckNoBreak( *m_pPam
->GetPoint() );
3847 // End all open contexts. We'll take AttrMin because nContextStMin might
3848 // have been modified. Since it's gonna be restored by EndContext, it's okay
3849 while( m_aContexts
.size() > m_nContextStAttrMin
+1 )
3851 std::unique_ptr
<HTMLAttrContext
> xCntxt(PopContext());
3852 EndContext(xCntxt
.get());
3855 // Remove LFs at the paragraph end
3856 if (StripTrailingLF() == 0 && !m_pPam
->GetPoint()->GetContentIndex())
3858 HTMLTableContext
* pTableContext
= m_xTable
? m_xTable
->GetContext() : nullptr;
3859 SwPosition
* pSavedPos
= pTableContext
? pTableContext
->GetPos() : nullptr;
3860 const bool bDeleteSafe
= !pSavedPos
|| pSavedPos
->GetNode() != m_pPam
->GetPoint()->GetNode();
3862 StripTrailingPara();
3865 // If there was an adjustment set for the cell, we need to close it
3866 std::unique_ptr
<HTMLAttrContext
> xCntxt(PopContext());
3868 EndContext(xCntxt
.get());
3872 // Close all still open contexts
3873 while( m_aContexts
.size() > m_nContextStAttrMin
)
3875 std::unique_ptr
<HTMLAttrContext
> xCntxt(PopContext());
3878 ClearContext(xCntxt
.get());
3882 // end an enumeration
3883 GetNumInfo().Clear();
3887 xSaveStruct
->InsertCell( *this, pCurTable
);
3889 // we're probably before a <TH>, <TD>, <TR> or </TABLE>
3890 xSaveStruct
.reset();
3895 class RowSaveStruct
: public SwPendingData
3903 eAdjust( SvxAdjust::End
), eVertOri( text::VertOrientation::TOP
), bHasCells( false )
3909 void SwHTMLParser::BuildTableRow( HTMLTable
*pCurTable
, bool bReadOptions
,
3910 SvxAdjust eGrpAdjust
,
3911 sal_Int16 eGrpVertOri
)
3913 // <TR> was already read
3915 if( !IsParserWorking() && m_vPendingStack
.empty() )
3918 HtmlTokenId nToken
= HtmlTokenId::NONE
;
3919 std::unique_ptr
<RowSaveStruct
> xSaveStruct
;
3921 bool bPending
= false;
3922 if( !m_vPendingStack
.empty() )
3924 xSaveStruct
.reset(static_cast<RowSaveStruct
*>(m_vPendingStack
.back().pData
.release()));
3926 m_vPendingStack
.pop_back();
3927 nToken
= !m_vPendingStack
.empty() ? m_vPendingStack
.back().nToken
: GetSaveToken();
3928 bPending
= SvParserState::Error
== eState
&& !m_vPendingStack
.empty();
3930 SaveState( nToken
);
3934 SvxAdjust eAdjust
= eGrpAdjust
;
3935 sal_Int16 eVertOri
= eGrpVertOri
;
3937 OUString aBGImage
, aStyle
, aId
, aClass
;
3938 bool bBGColor
= false;
3939 xSaveStruct
.reset(new RowSaveStruct
);
3943 const HTMLOptions
& rHTMLOptions
= GetOptions();
3944 for (size_t i
= rHTMLOptions
.size(); i
; )
3946 const HTMLOption
& rOption
= rHTMLOptions
[--i
];
3947 switch( rOption
.GetToken() )
3949 case HtmlOptionId::ID
:
3950 aId
= rOption
.GetString();
3952 case HtmlOptionId::ALIGN
:
3953 eAdjust
= rOption
.GetEnum( aHTMLPAlignTable
, eAdjust
);
3955 case HtmlOptionId::VALIGN
:
3956 eVertOri
= rOption
.GetEnum( aHTMLTableVAlignTable
, eVertOri
);
3958 case HtmlOptionId::BGCOLOR
:
3959 // Ignore empty BGCOLOR on <TABLE>, <TR> and <TD>/>TH> like Netscape
3960 // *really* not on other tags
3961 if( !rOption
.GetString().isEmpty() )
3963 rOption
.GetColor( aBGColor
);
3967 case HtmlOptionId::BACKGROUND
:
3968 aBGImage
= rOption
.GetString();
3970 case HtmlOptionId::STYLE
:
3971 aStyle
= rOption
.GetString();
3973 case HtmlOptionId::CLASS
:
3974 aClass
= rOption
.GetString();
3981 if( !aId
.isEmpty() )
3982 InsertBookmark( aId
);
3984 std::unique_ptr
<SvxBrushItem
> xBrushItem(
3985 CreateBrushItem( bBGColor
? &aBGColor
: nullptr, aBGImage
, aStyle
,
3987 pCurTable
->OpenRow(eAdjust
, eVertOri
, xBrushItem
);
3988 // If the first GetNextToken() doesn't succeed (pending input), must re-read from the beginning.
3989 SaveState( HtmlTokenId::NONE
);
3992 if( nToken
== HtmlTokenId::NONE
)
3993 nToken
= GetNextToken();
3996 while( (IsParserWorking() && !bDone
) || bPending
)
3998 SaveState( nToken
);
4000 nToken
= FilterToken( nToken
);
4002 OSL_ENSURE( !m_vPendingStack
.empty() || !m_bCallNextToken
||
4003 pCurTable
->GetContext() || pCurTable
->HasParentSection(),
4004 "Where is the section??" );
4005 if( m_vPendingStack
.empty() && m_bCallNextToken
&&
4006 (pCurTable
->GetContext() || pCurTable
->HasParentSection()) )
4008 /// Call NextToken directly (e.g. ignore the content of floating frames or applets)
4009 NextToken( nToken
);
4011 else switch( nToken
)
4013 case HtmlTokenId::TABLE_ON
:
4014 if( !pCurTable
->GetContext() )
4021 case HtmlTokenId::TABLEROW_ON
:
4022 case HtmlTokenId::THEAD_ON
:
4023 case HtmlTokenId::THEAD_OFF
:
4024 case HtmlTokenId::TBODY_ON
:
4025 case HtmlTokenId::TBODY_OFF
:
4026 case HtmlTokenId::TFOOT_ON
:
4027 case HtmlTokenId::TFOOT_OFF
:
4028 case HtmlTokenId::TABLE_OFF
:
4031 case HtmlTokenId::TABLEROW_OFF
:
4034 case HtmlTokenId::TABLEHEADER_ON
:
4035 case HtmlTokenId::TABLEDATA_ON
:
4036 BuildTableCell( pCurTable
, true, HtmlTokenId::TABLEHEADER_ON
==nToken
);
4037 if( SvParserState::Pending
!= GetStatus() )
4039 xSaveStruct
->bHasCells
= true;
4040 bDone
= m_xTable
->IsOverflowing();
4043 case HtmlTokenId::CAPTION_ON
:
4044 BuildTableCaption( pCurTable
);
4045 bDone
= m_xTable
->IsOverflowing();
4047 case HtmlTokenId::CAPTION_OFF
:
4048 case HtmlTokenId::TABLEHEADER_OFF
:
4049 case HtmlTokenId::TABLEDATA_OFF
:
4050 case HtmlTokenId::COLGROUP_ON
:
4051 case HtmlTokenId::COLGROUP_OFF
:
4052 case HtmlTokenId::COL_ON
:
4053 case HtmlTokenId::COL_OFF
:
4054 // Where no cell started, there can't be a cell ending
4055 // all the other tokens are bogus anyway and only break the table
4057 case HtmlTokenId::MULTICOL_ON
:
4058 // we can't add columned text frames here
4060 case HtmlTokenId::FORM_ON
:
4061 NewForm( false ); // don't create a new paragraph
4063 case HtmlTokenId::FORM_OFF
:
4064 EndForm( false ); // don't create a new paragraph
4066 case HtmlTokenId::COMMENT
:
4067 NextToken( nToken
);
4069 case HtmlTokenId::MAP_ON
:
4070 // an image map doesn't add anything, so we can parse it without a cell
4071 NextToken( nToken
);
4073 case HtmlTokenId::TEXTTOKEN
:
4074 if( (pCurTable
->GetContext() ||
4075 !pCurTable
->HasParentSection()) &&
4076 1==aToken
.getLength() && ' '==aToken
[0] )
4080 pCurTable
->MakeParentContents();
4081 NextToken( nToken
);
4085 OSL_ENSURE( !bPending
|| m_vPendingStack
.empty(),
4086 "SwHTMLParser::BuildTableRow: There is a PendStack again" );
4088 if( IsParserWorking() )
4089 SaveState( HtmlTokenId::NONE
);
4092 nToken
= GetNextToken();
4095 if( SvParserState::Pending
== GetStatus() )
4097 m_vPendingStack
.emplace_back( HtmlTokenId::TABLEROW_ON
);
4098 m_vPendingStack
.back().pData
= std::move(xSaveStruct
);
4102 pCurTable
->CloseRow(!xSaveStruct
->bHasCells
);
4103 xSaveStruct
.reset();
4106 // we're probably before <TR> or </TABLE>
4109 void SwHTMLParser::BuildTableSection( HTMLTable
*pCurTable
,
4113 // <THEAD>, <TBODY> resp. <TFOOT> were read already
4114 if( !IsParserWorking() && m_vPendingStack
.empty() )
4117 HtmlTokenId nToken
= HtmlTokenId::NONE
;
4118 bool bPending
= false;
4119 std::unique_ptr
<RowSaveStruct
> xSaveStruct
;
4121 if( !m_vPendingStack
.empty() )
4123 xSaveStruct
.reset(static_cast<RowSaveStruct
*>(m_vPendingStack
.back().pData
.release()));
4125 m_vPendingStack
.pop_back();
4126 nToken
= !m_vPendingStack
.empty() ? m_vPendingStack
.back().nToken
: GetSaveToken();
4127 bPending
= SvParserState::Error
== eState
&& !m_vPendingStack
.empty();
4129 SaveState( nToken
);
4133 xSaveStruct
.reset(new RowSaveStruct
);
4137 const HTMLOptions
& rHTMLOptions
= GetOptions();
4138 for (size_t i
= rHTMLOptions
.size(); i
; )
4140 const HTMLOption
& rOption
= rHTMLOptions
[--i
];
4141 switch( rOption
.GetToken() )
4143 case HtmlOptionId::ID
:
4144 InsertBookmark( rOption
.GetString() );
4146 case HtmlOptionId::ALIGN
:
4147 xSaveStruct
->eAdjust
=
4148 rOption
.GetEnum( aHTMLPAlignTable
, xSaveStruct
->eAdjust
);
4150 case HtmlOptionId::VALIGN
:
4151 xSaveStruct
->eVertOri
=
4152 rOption
.GetEnum( aHTMLTableVAlignTable
,
4153 xSaveStruct
->eVertOri
);
4160 // If the first GetNextToken() doesn't succeed (pending input), must re-read from the beginning.
4161 SaveState( HtmlTokenId::NONE
);
4164 if( nToken
== HtmlTokenId::NONE
)
4165 nToken
= GetNextToken();
4168 while( (IsParserWorking() && !bDone
) || bPending
)
4170 SaveState( nToken
);
4172 nToken
= FilterToken( nToken
);
4174 OSL_ENSURE( !m_vPendingStack
.empty() || !m_bCallNextToken
||
4175 pCurTable
->GetContext() || pCurTable
->HasParentSection(),
4176 "Where is the section?" );
4177 if( m_vPendingStack
.empty() && m_bCallNextToken
&&
4178 (pCurTable
->GetContext() || pCurTable
->HasParentSection()) )
4180 // Call NextToken directly (e.g. ignore the content of floating frames or applets)
4181 NextToken( nToken
);
4183 else switch( nToken
)
4185 case HtmlTokenId::TABLE_ON
:
4186 if( !pCurTable
->GetContext() )
4193 case HtmlTokenId::THEAD_ON
:
4194 case HtmlTokenId::TFOOT_ON
:
4195 case HtmlTokenId::TBODY_ON
:
4196 case HtmlTokenId::TABLE_OFF
:
4199 case HtmlTokenId::THEAD_OFF
:
4200 case HtmlTokenId::TBODY_OFF
:
4201 case HtmlTokenId::TFOOT_OFF
:
4204 case HtmlTokenId::CAPTION_ON
:
4205 BuildTableCaption( pCurTable
);
4206 bDone
= m_xTable
->IsOverflowing();
4208 case HtmlTokenId::CAPTION_OFF
:
4210 case HtmlTokenId::TABLEHEADER_ON
:
4211 case HtmlTokenId::TABLEDATA_ON
:
4213 BuildTableRow( pCurTable
, false, xSaveStruct
->eAdjust
,
4214 xSaveStruct
->eVertOri
);
4215 bDone
= m_xTable
->IsOverflowing();
4217 case HtmlTokenId::TABLEROW_ON
:
4218 BuildTableRow( pCurTable
, true, xSaveStruct
->eAdjust
,
4219 xSaveStruct
->eVertOri
);
4220 bDone
= m_xTable
->IsOverflowing();
4222 case HtmlTokenId::MULTICOL_ON
:
4223 // we can't add columned text frames here
4225 case HtmlTokenId::FORM_ON
:
4226 NewForm( false ); // don't create a new paragraph
4228 case HtmlTokenId::FORM_OFF
:
4229 EndForm( false ); // don't create a new paragraph
4231 case HtmlTokenId::TEXTTOKEN
:
4232 // blank strings may be a series of CR+LF and no text
4233 if( (pCurTable
->GetContext() ||
4234 !pCurTable
->HasParentSection()) &&
4235 1==aToken
.getLength() && ' ' == aToken
[0] )
4239 pCurTable
->MakeParentContents();
4240 NextToken( nToken
);
4243 OSL_ENSURE( !bPending
|| m_vPendingStack
.empty(),
4244 "SwHTMLParser::BuildTableSection: There is a PendStack again" );
4246 if( IsParserWorking() )
4247 SaveState( HtmlTokenId::NONE
);
4250 nToken
= GetNextToken();
4253 if( SvParserState::Pending
== GetStatus() )
4255 m_vPendingStack
.emplace_back( bHead
? HtmlTokenId::THEAD_ON
4256 : HtmlTokenId::TBODY_ON
);
4257 m_vPendingStack
.back().pData
= std::move(xSaveStruct
);
4261 pCurTable
->CloseSection( bHead
);
4262 xSaveStruct
.reset();
4265 // now we stand (perhaps) in front of <TBODY>,... or </TABLE>
4270 struct TableColGrpSaveStruct
: public SwPendingData
4272 sal_uInt16 nColGrpSpan
;
4273 sal_uInt16 nColGrpWidth
;
4274 bool bRelColGrpWidth
;
4275 SvxAdjust eColGrpAdjust
;
4276 sal_Int16 eColGrpVertOri
;
4278 inline TableColGrpSaveStruct();
4280 inline void CloseColGroup( HTMLTable
*pTable
);
4285 inline TableColGrpSaveStruct::TableColGrpSaveStruct() :
4286 nColGrpSpan( 1 ), nColGrpWidth( 0 ),
4287 bRelColGrpWidth( false ), eColGrpAdjust( SvxAdjust::End
),
4288 eColGrpVertOri( text::VertOrientation::TOP
)
4291 inline void TableColGrpSaveStruct::CloseColGroup( HTMLTable
*pTable
)
4293 pTable
->CloseColGroup( nColGrpSpan
, nColGrpWidth
,
4294 bRelColGrpWidth
, eColGrpAdjust
, eColGrpVertOri
);
4297 void SwHTMLParser::BuildTableColGroup( HTMLTable
*pCurTable
,
4300 // <COLGROUP> was read already if bReadOptions is set
4302 if( !IsParserWorking() && m_vPendingStack
.empty() )
4305 HtmlTokenId nToken
= HtmlTokenId::NONE
;
4306 bool bPending
= false;
4307 std::unique_ptr
<TableColGrpSaveStruct
> pSaveStruct
;
4309 if( !m_vPendingStack
.empty() )
4311 pSaveStruct
.reset(static_cast<TableColGrpSaveStruct
*>(m_vPendingStack
.back().pData
.release()));
4314 m_vPendingStack
.pop_back();
4315 nToken
= !m_vPendingStack
.empty() ? m_vPendingStack
.back().nToken
: GetSaveToken();
4316 bPending
= SvParserState::Error
== eState
&& !m_vPendingStack
.empty();
4318 SaveState( nToken
);
4323 pSaveStruct
.reset(new TableColGrpSaveStruct
);
4326 const HTMLOptions
& rColGrpOptions
= GetOptions();
4327 for (size_t i
= rColGrpOptions
.size(); i
; )
4329 const HTMLOption
& rOption
= rColGrpOptions
[--i
];
4330 switch( rOption
.GetToken() )
4332 case HtmlOptionId::ID
:
4333 InsertBookmark( rOption
.GetString() );
4335 case HtmlOptionId::SPAN
:
4336 pSaveStruct
->nColGrpSpan
= o3tl::narrowing
<sal_uInt16
>(rOption
.GetNumber());
4337 if (pSaveStruct
->nColGrpSpan
> 256)
4339 SAL_INFO("sw.html", "ignoring huge SPAN " << pSaveStruct
->nColGrpSpan
);
4340 pSaveStruct
->nColGrpSpan
= 1;
4343 case HtmlOptionId::WIDTH
:
4344 pSaveStruct
->nColGrpWidth
= o3tl::narrowing
<sal_uInt16
>(rOption
.GetNumber());
4345 pSaveStruct
->bRelColGrpWidth
=
4346 (rOption
.GetString().indexOf('*') != -1);
4348 case HtmlOptionId::ALIGN
:
4349 pSaveStruct
->eColGrpAdjust
=
4350 rOption
.GetEnum( aHTMLPAlignTable
, pSaveStruct
->eColGrpAdjust
);
4352 case HtmlOptionId::VALIGN
:
4353 pSaveStruct
->eColGrpVertOri
=
4354 rOption
.GetEnum( aHTMLTableVAlignTable
,
4355 pSaveStruct
->eColGrpVertOri
);
4361 // If the first GetNextToken() doesn't succeed (pending input), must re-read from the beginning.
4362 SaveState( HtmlTokenId::NONE
);
4365 if( nToken
== HtmlTokenId::NONE
)
4366 nToken
= GetNextToken(); // naechstes Token
4369 while( (IsParserWorking() && !bDone
) || bPending
)
4371 SaveState( nToken
);
4373 nToken
= FilterToken( nToken
);
4375 OSL_ENSURE( !m_vPendingStack
.empty() || !m_bCallNextToken
||
4376 pCurTable
->GetContext() || pCurTable
->HasParentSection(),
4377 "Where is the section?" );
4378 if( m_vPendingStack
.empty() && m_bCallNextToken
&&
4379 (pCurTable
->GetContext() || pCurTable
->HasParentSection()) )
4381 // Call NextToken directly (e.g. ignore the content of floating frames or applets)
4382 NextToken( nToken
);
4384 else switch( nToken
)
4386 case HtmlTokenId::TABLE_ON
:
4387 if( !pCurTable
->GetContext() )
4394 case HtmlTokenId::COLGROUP_ON
:
4395 case HtmlTokenId::THEAD_ON
:
4396 case HtmlTokenId::TFOOT_ON
:
4397 case HtmlTokenId::TBODY_ON
:
4398 case HtmlTokenId::TABLEROW_ON
:
4399 case HtmlTokenId::TABLE_OFF
:
4402 case HtmlTokenId::COLGROUP_OFF
:
4405 case HtmlTokenId::COL_ON
:
4407 sal_uInt16 nColSpan
= 1;
4408 sal_uInt16 nColWidth
= pSaveStruct
->nColGrpWidth
;
4409 bool bRelColWidth
= pSaveStruct
->bRelColGrpWidth
;
4410 SvxAdjust eColAdjust
= pSaveStruct
->eColGrpAdjust
;
4411 sal_Int16 eColVertOri
= pSaveStruct
->eColGrpVertOri
;
4413 const HTMLOptions
& rColOptions
= GetOptions();
4414 for (size_t i
= rColOptions
.size(); i
; )
4416 const HTMLOption
& rOption
= rColOptions
[--i
];
4417 switch( rOption
.GetToken() )
4419 case HtmlOptionId::ID
:
4420 InsertBookmark( rOption
.GetString() );
4422 case HtmlOptionId::SPAN
:
4423 nColSpan
= o3tl::narrowing
<sal_uInt16
>(rOption
.GetNumber());
4426 SAL_INFO("sw.html", "ignoring huge SPAN " << nColSpan
);
4430 case HtmlOptionId::WIDTH
:
4431 nColWidth
= o3tl::narrowing
<sal_uInt16
>(rOption
.GetNumber());
4433 (rOption
.GetString().indexOf('*') != -1);
4435 case HtmlOptionId::ALIGN
:
4436 eColAdjust
= rOption
.GetEnum( aHTMLPAlignTable
, eColAdjust
);
4438 case HtmlOptionId::VALIGN
:
4440 rOption
.GetEnum( aHTMLTableVAlignTable
, eColVertOri
);
4445 pCurTable
->InsertCol( nColSpan
, nColWidth
, bRelColWidth
,
4446 eColAdjust
, eColVertOri
);
4448 // the attributes in <COLGRP> should be ignored, if there are <COL> elements
4449 pSaveStruct
->nColGrpSpan
= 0;
4452 case HtmlTokenId::COL_OFF
:
4454 case HtmlTokenId::MULTICOL_ON
:
4455 // we can't add columned text frames here
4457 case HtmlTokenId::TEXTTOKEN
:
4458 if( (pCurTable
->GetContext() ||
4459 !pCurTable
->HasParentSection()) &&
4460 1==aToken
.getLength() && ' '==aToken
[0] )
4464 pCurTable
->MakeParentContents();
4465 NextToken( nToken
);
4468 OSL_ENSURE( !bPending
|| m_vPendingStack
.empty(),
4469 "SwHTMLParser::BuildTableColGrp: There is a PendStack again" );
4471 if( IsParserWorking() )
4472 SaveState( HtmlTokenId::NONE
);
4475 nToken
= GetNextToken();
4478 if( SvParserState::Pending
== GetStatus() )
4480 m_vPendingStack
.emplace_back( HtmlTokenId::COL_ON
);
4481 m_vPendingStack
.back().pData
= std::move(pSaveStruct
);
4485 pSaveStruct
->CloseColGroup( pCurTable
);
4489 class CaptionSaveStruct
: public SectionSaveStruct
4491 SwPosition m_aSavePos
;
4492 SwHTMLNumRuleInfo m_aNumRuleInfo
; // valid numbering
4496 std::shared_ptr
<HTMLAttrTable
> m_xAttrTab
; // attributes
4498 CaptionSaveStruct( SwHTMLParser
& rParser
, SwPosition aPos
) :
4499 SectionSaveStruct( rParser
), m_aSavePos(std::move( aPos
)),
4500 m_xAttrTab(std::make_shared
<HTMLAttrTable
>())
4502 rParser
.SaveAttrTab(m_xAttrTab
);
4504 // The current numbering was remembered and just needs to be closed
4505 m_aNumRuleInfo
.Set( rParser
.GetNumInfo() );
4506 rParser
.GetNumInfo().Clear();
4509 const SwPosition
& GetPos() const { return m_aSavePos
; }
4511 void RestoreAll( SwHTMLParser
& rParser
)
4513 // Recover the old stack
4516 // Recover the old attribute tables
4517 rParser
.RestoreAttrTab(m_xAttrTab
);
4519 // Re-open the old numbering
4520 rParser
.GetNumInfo().Set( m_aNumRuleInfo
);
4524 void SwHTMLParser::BuildTableCaption( HTMLTable
*pCurTable
)
4526 // <CAPTION> was read already
4528 if( !IsParserWorking() && m_vPendingStack
.empty() )
4531 HtmlTokenId nToken
= HtmlTokenId::NONE
;
4532 std::unique_ptr
<CaptionSaveStruct
> xSaveStruct
;
4534 if( !m_vPendingStack
.empty() )
4536 xSaveStruct
.reset(static_cast<CaptionSaveStruct
*>(m_vPendingStack
.back().pData
.release()));
4538 m_vPendingStack
.pop_back();
4539 nToken
= !m_vPendingStack
.empty() ? m_vPendingStack
.back().nToken
: GetSaveToken();
4540 OSL_ENSURE( m_vPendingStack
.empty(), "Where does a PendStack coming from?" );
4542 SaveState( nToken
);
4546 if (m_xTable
->IsOverflowing())
4548 SaveState( HtmlTokenId::NONE
);
4553 const HTMLOptions
& rHTMLOptions
= GetOptions();
4554 for ( size_t i
= rHTMLOptions
.size(); i
; )
4556 const HTMLOption
& rOption
= rHTMLOptions
[--i
];
4557 if( HtmlOptionId::ALIGN
== rOption
.GetToken() )
4559 if (rOption
.GetString().equalsIgnoreAsciiCase(
4560 OOO_STRING_SVTOOLS_HTML_VA_bottom
))
4567 // Remember old PaM position
4568 xSaveStruct
.reset(new CaptionSaveStruct(*this, *m_pPam
->GetPoint()));
4570 // Add a text section in the icon section as a container for the header
4571 // and set the PaM there
4572 const SwStartNode
*pStNd
;
4573 if (m_xTable
.get() == pCurTable
)
4574 pStNd
= InsertTempTableCaptionSection();
4576 pStNd
= InsertTableSection( RES_POOLCOLL_TEXT
);
4578 std::unique_ptr
<HTMLAttrContext
> xCntxt(new HTMLAttrContext(HtmlTokenId::CAPTION_ON
));
4580 // Table headers are always centered
4581 NewAttr(m_xAttrTab
, &m_xAttrTab
->pAdjust
, SvxAdjustItem(SvxAdjust::Center
, RES_PARATR_ADJUST
));
4583 HTMLAttrs
&rAttrs
= xCntxt
->GetAttrs();
4584 rAttrs
.push_back( m_xAttrTab
->pAdjust
);
4586 PushContext(xCntxt
);
4588 // Remember the start node of the section at the table
4589 pCurTable
->SetCaption( pStNd
, bTop
);
4591 // If the first GetNextToken() doesn't succeed (pending input), must re-read from the beginning.
4592 SaveState( HtmlTokenId::NONE
);
4595 if( nToken
== HtmlTokenId::NONE
)
4596 nToken
= GetNextToken();
4598 // </CAPTION> is needed according to DTD
4600 while( IsParserWorking() && !bDone
)
4602 SaveState( nToken
);
4604 nToken
= FilterToken( nToken
);
4608 case HtmlTokenId::TABLE_ON
:
4609 if( m_vPendingStack
.empty() )
4611 xSaveStruct
->m_xTable
= m_xTable
;
4612 bool bHasToFly
= xSaveStruct
->m_xTable
.get() != pCurTable
;
4613 BuildTable( pCurTable
->GetTableAdjust( true ),
4614 false, true, bHasToFly
);
4618 BuildTable( SvxAdjust::End
);
4620 if( SvParserState::Pending
!= GetStatus() )
4622 m_xTable
= xSaveStruct
->m_xTable
;
4625 case HtmlTokenId::TABLE_OFF
:
4626 case HtmlTokenId::COLGROUP_ON
:
4627 case HtmlTokenId::THEAD_ON
:
4628 case HtmlTokenId::TFOOT_ON
:
4629 case HtmlTokenId::TBODY_ON
:
4630 case HtmlTokenId::TABLEROW_ON
:
4635 case HtmlTokenId::CAPTION_OFF
:
4639 if( !m_vPendingStack
.empty() )
4641 m_vPendingStack
.pop_back();
4642 OSL_ENSURE( m_vPendingStack
.empty(), "Further it can't go!" );
4645 if( IsParserWorking() )
4646 NextToken( nToken
);
4650 if( IsParserWorking() )
4651 SaveState( HtmlTokenId::NONE
);
4654 nToken
= GetNextToken();
4657 if( SvParserState::Pending
==GetStatus() )
4659 m_vPendingStack
.emplace_back( HtmlTokenId::CAPTION_ON
);
4660 m_vPendingStack
.back().pData
= std::move(xSaveStruct
);
4664 // end all still open contexts
4665 while( m_aContexts
.size() > m_nContextStAttrMin
+1 )
4667 std::unique_ptr
<HTMLAttrContext
> xCntxt(PopContext());
4668 EndContext(xCntxt
.get());
4671 bool bLFStripped
= StripTrailingLF() > 0;
4673 if (m_xTable
.get() == pCurTable
)
4675 // On moving the caption later, the last paragraph isn't moved as well.
4676 // That means, there has to be an empty paragraph at the end of the section
4677 if( m_pPam
->GetPoint()->GetContentIndex() || bLFStripped
)
4678 AppendTextNode( AM_NOSPACE
);
4682 // Strip LFs at the end of the paragraph
4683 if( !m_pPam
->GetPoint()->GetContentIndex() && !bLFStripped
)
4684 StripTrailingPara();
4687 // If there's an adjustment for the cell, we need to close it
4688 std::unique_ptr
<HTMLAttrContext
> xCntxt(PopContext());
4691 EndContext(xCntxt
.get());
4697 // Recover stack and attribute table
4698 xSaveStruct
->RestoreAll(*this);
4701 *m_pPam
->GetPoint() = xSaveStruct
->GetPos();
4706 class TableSaveStruct
: public SwPendingData
4709 std::shared_ptr
<HTMLTable
> m_xCurrentTable
;
4711 explicit TableSaveStruct(std::shared_ptr
<HTMLTable
> xCurTable
)
4712 : m_xCurrentTable(std::move(xCurTable
))
4716 // Initiate creation of the table and put the table in a text frame if
4717 // needed. If it returns true, we need to insert a paragraph.
4718 void MakeTable( sal_uInt16 nWidth
, SwPosition
& rPos
, SwDoc
*pDoc
);
4723 void TableSaveStruct::MakeTable( sal_uInt16 nWidth
, SwPosition
& rPos
, SwDoc
*pDoc
)
4725 m_xCurrentTable
->MakeTable(nullptr, nWidth
);
4727 HTMLTableContext
*pTCntxt
= m_xCurrentTable
->GetContext();
4728 OSL_ENSURE( pTCntxt
, "Where is the table context" );
4730 SwTableNode
*pTableNd
= pTCntxt
->GetTableNode();
4731 OSL_ENSURE( pTableNd
, "Where is the table node" );
4733 if( pDoc
->getIDocumentLayoutAccess().GetCurrentViewShell() && pTableNd
)
4735 // If there's already a layout, the BoxFrames need to be regenerated at this table
4737 if( pTCntxt
->GetFrameFormat() )
4739 pTCntxt
->GetFrameFormat()->DelFrames();
4740 pTableNd
->DelFrames();
4741 pTCntxt
->GetFrameFormat()->MakeFrames();
4745 pTableNd
->DelFrames();
4746 SwNodeIndex
aIdx( *pTableNd
->EndOfSectionNode(), 1 );
4747 OSL_ENSURE( aIdx
.GetIndex() <= pTCntxt
->GetPos()->GetNodeIndex(),
4748 "unexpected node for table layout" );
4749 pTableNd
->MakeOwnFrames();
4753 rPos
= *pTCntxt
->GetPos();
4756 HTMLTableOptions::HTMLTableOptions( const HTMLOptions
& rOptions
,
4757 SvxAdjust eParentAdjust
) :
4759 nWidth( 0 ), nHeight( 0 ),
4760 nCellPadding( USHRT_MAX
), nCellSpacing( USHRT_MAX
),
4761 nBorder( USHRT_MAX
),
4762 nHSpace( 0 ), nVSpace( 0 ),
4763 eAdjust( eParentAdjust
), eVertOri( text::VertOrientation::CENTER
),
4764 eFrame( HTMLTableFrame::Void
), eRules( HTMLTableRules::NONE
),
4765 bPercentWidth( false ),
4766 bTableAdjust( false ),
4768 aBorderColor( COL_GRAY
)
4770 bool bBorderColor
= false;
4771 bool bHasFrame
= false, bHasRules
= false;
4773 for (size_t i
= rOptions
.size(); i
; )
4775 const HTMLOption
& rOption
= rOptions
[--i
];
4776 switch( rOption
.GetToken() )
4778 case HtmlOptionId::ID
:
4779 aId
= rOption
.GetString();
4781 case HtmlOptionId::COLS
:
4782 nCols
= o3tl::narrowing
<sal_uInt16
>(rOption
.GetNumber());
4784 case HtmlOptionId::WIDTH
:
4785 nWidth
= o3tl::narrowing
<sal_uInt16
>(rOption
.GetNumber());
4786 bPercentWidth
= (rOption
.GetString().indexOf('%') != -1);
4787 if( bPercentWidth
&& nWidth
>100 )
4790 case HtmlOptionId::HEIGHT
:
4791 nHeight
= o3tl::narrowing
<sal_uInt16
>(rOption
.GetNumber());
4792 if( rOption
.GetString().indexOf('%') != -1 )
4793 nHeight
= 0; // don't use % attributes
4795 case HtmlOptionId::CELLPADDING
:
4796 nCellPadding
= o3tl::narrowing
<sal_uInt16
>(rOption
.GetNumber());
4798 case HtmlOptionId::CELLSPACING
:
4799 nCellSpacing
= o3tl::narrowing
<sal_uInt16
>(rOption
.GetNumber());
4801 case HtmlOptionId::ALIGN
:
4803 if( rOption
.GetEnum( eAdjust
, aHTMLPAlignTable
) )
4805 bTableAdjust
= true;
4809 case HtmlOptionId::VALIGN
:
4810 eVertOri
= rOption
.GetEnum( aHTMLTableVAlignTable
, eVertOri
);
4812 case HtmlOptionId::BORDER
:
4813 // Handle BORDER and BORDER=BORDER like BORDER=1
4814 if (!rOption
.GetString().isEmpty() &&
4815 !rOption
.GetString().equalsIgnoreAsciiCase(
4816 OOO_STRING_SVTOOLS_HTML_O_border
))
4818 nBorder
= o3tl::narrowing
<sal_uInt16
>(rOption
.GetNumber());
4824 eFrame
= ( nBorder
? HTMLTableFrame::Box
: HTMLTableFrame::Void
);
4826 eRules
= ( nBorder
? HTMLTableRules::All
: HTMLTableRules::NONE
);
4828 case HtmlOptionId::FRAME
:
4829 eFrame
= rOption
.GetTableFrame();
4832 case HtmlOptionId::RULES
:
4833 eRules
= rOption
.GetTableRules();
4836 case HtmlOptionId::BGCOLOR
:
4837 // Ignore empty BGCOLOR on <TABLE>, <TR> and <TD>/<TH> like Netscape
4838 // *really* not on other tags
4839 if( !rOption
.GetString().isEmpty() )
4841 rOption
.GetColor( aBGColor
);
4845 case HtmlOptionId::BACKGROUND
:
4846 aBGImage
= rOption
.GetString();
4848 case HtmlOptionId::BORDERCOLOR
:
4849 rOption
.GetColor( aBorderColor
);
4850 bBorderColor
= true;
4852 case HtmlOptionId::BORDERCOLORDARK
:
4854 rOption
.GetColor( aBorderColor
);
4856 case HtmlOptionId::STYLE
:
4857 aStyle
= rOption
.GetString();
4859 case HtmlOptionId::CLASS
:
4860 aClass
= rOption
.GetString();
4862 case HtmlOptionId::DIR:
4863 aDir
= rOption
.GetString();
4865 case HtmlOptionId::HSPACE
:
4866 nHSpace
= o3tl::narrowing
<sal_uInt16
>(rOption
.GetNumber());
4868 case HtmlOptionId::VSPACE
:
4869 nVSpace
= o3tl::narrowing
<sal_uInt16
>(rOption
.GetNumber());
4875 if( nCols
&& !nWidth
)
4878 bPercentWidth
= true;
4881 // If BORDER=0 or no BORDER given, then there shouldn't be a border
4882 if( 0==nBorder
|| USHRT_MAX
==nBorder
)
4884 eFrame
= HTMLTableFrame::Void
;
4885 eRules
= HTMLTableRules::NONE
;
4889 void SwHTMLParser::DeleteSection(SwStartNode
* pSttNd
)
4891 //if section to be deleted contains a pending m_pMarquee, it will be deleted
4892 //so clear m_pMarquee pointer if that's the case
4893 SwFrameFormat
* pObjectFormat
= m_pMarquee
? ::FindFrameFormat(m_pMarquee
.get()) : nullptr;
4894 FrameDeleteWatch
aWatch(pObjectFormat
);
4896 m_xDoc
->getIDocumentContentOperations().DeleteSection(pSttNd
);
4900 if (aWatch
.WasDeleted())
4901 m_pMarquee
= nullptr;
4903 aWatch
.EndListeningAll();
4907 std::shared_ptr
<HTMLTable
> SwHTMLParser::BuildTable(SvxAdjust eParentAdjust
,
4909 bool bHasParentSection
,
4912 TableDepthGuard
aGuard(*this);
4913 if (aGuard
.TooDeep())
4914 eState
= SvParserState::Error
;
4916 if (!IsParserWorking() && m_vPendingStack
.empty())
4917 return std::shared_ptr
<HTMLTable
>();
4919 ::comphelper::FlagRestorationGuard
g(m_isInTableStructure
, true);
4920 HtmlTokenId nToken
= HtmlTokenId::NONE
;
4921 bool bPending
= false;
4922 std::unique_ptr
<TableSaveStruct
> xSaveStruct
;
4924 if( !m_vPendingStack
.empty() )
4926 xSaveStruct
.reset(static_cast<TableSaveStruct
*>(m_vPendingStack
.back().pData
.release()));
4928 m_vPendingStack
.pop_back();
4929 nToken
= !m_vPendingStack
.empty() ? m_vPendingStack
.back().nToken
: GetSaveToken();
4930 bPending
= SvParserState::Error
== eState
&& !m_vPendingStack
.empty();
4932 SaveState( nToken
);
4938 // Parse CSS on the table.
4940 const HTMLOptions
& rHTMLOptions
= GetOptions();
4941 for (size_t i
= rHTMLOptions
.size(); i
;)
4943 const HTMLOption
& rOption
= rHTMLOptions
[--i
];
4944 if (rOption
.GetToken() == HtmlOptionId::STYLE
)
4946 aStyle
= rOption
.GetString();
4949 if (!aStyle
.isEmpty())
4952 SfxItemSet
aItemSet(m_xDoc
->GetAttrPool(), m_pCSS1Parser
->GetWhichMap());
4953 SvxCSS1PropertyInfo aPropInfo
;
4954 if (ParseStyleOptions(aStyle
, /*aId=*/OUString(), /*aClass=*/OUString(), aItemSet
,
4957 if (aPropInfo
.m_eLeftMarginType
== SVX_CSS1_LTYPE_AUTO
4958 && aPropInfo
.m_eRightMarginType
== SVX_CSS1_LTYPE_AUTO
)
4960 // Both left & right is set to auto: that's our center.
4961 eParentAdjust
= SvxAdjust::Center
;
4966 HTMLTableOptions
aTableOptions(GetOptions(), eParentAdjust
);
4968 if (!aTableOptions
.aId
.isEmpty())
4969 InsertBookmark(aTableOptions
.aId
);
4971 std::shared_ptr
<HTMLTable
> xCurTable(std::make_shared
<HTMLTable
>(this,
4976 m_xTable
= xCurTable
;
4978 xSaveStruct
.reset(new TableSaveStruct(xCurTable
));
4980 // Is pending on the first GetNextToken, needs to be re-read on each construction
4981 SaveState( HtmlTokenId::NONE
);
4984 std::shared_ptr
<HTMLTable
> xCurTable
= xSaveStruct
->m_xCurrentTable
;
4986 // </TABLE> is needed according to DTD
4987 if( nToken
== HtmlTokenId::NONE
)
4988 nToken
= GetNextToken();
4991 while( (IsParserWorking() && !bDone
) || bPending
)
4993 SaveState( nToken
);
4995 nToken
= FilterToken( nToken
);
4997 OSL_ENSURE( !m_vPendingStack
.empty() || !m_bCallNextToken
||
4998 xCurTable
->GetContext() || xCurTable
->HasParentSection(),
4999 "Where is the section?" );
5000 if( m_vPendingStack
.empty() && m_bCallNextToken
&&
5001 (xCurTable
->GetContext() || xCurTable
->HasParentSection()) )
5003 /// Call NextToken directly (e.g. ignore the content of floating frames or applets)
5004 NextToken( nToken
);
5006 else switch( nToken
)
5008 case HtmlTokenId::TABLE_ON
:
5009 if( !xCurTable
->GetContext() )
5011 // If there's no table added, read the next table'
5017 case HtmlTokenId::TABLE_OFF
:
5020 case HtmlTokenId::CAPTION_ON
:
5021 BuildTableCaption(xCurTable
.get());
5022 bDone
= m_xTable
->IsOverflowing();
5024 case HtmlTokenId::COL_ON
:
5026 BuildTableColGroup(xCurTable
.get(), false);
5028 case HtmlTokenId::COLGROUP_ON
:
5029 BuildTableColGroup(xCurTable
.get(), true);
5031 case HtmlTokenId::TABLEROW_ON
:
5032 case HtmlTokenId::TABLEHEADER_ON
:
5033 case HtmlTokenId::TABLEDATA_ON
:
5035 BuildTableSection(xCurTable
.get(), false, false);
5036 bDone
= m_xTable
->IsOverflowing();
5038 case HtmlTokenId::THEAD_ON
:
5039 case HtmlTokenId::TFOOT_ON
:
5040 case HtmlTokenId::TBODY_ON
:
5041 BuildTableSection(xCurTable
.get(), true, HtmlTokenId::THEAD_ON
==nToken
);
5042 bDone
= m_xTable
->IsOverflowing();
5044 case HtmlTokenId::MULTICOL_ON
:
5045 // we can't add columned text frames here
5047 case HtmlTokenId::FORM_ON
:
5048 NewForm( false ); // don't add a new paragraph
5050 case HtmlTokenId::FORM_OFF
:
5051 EndForm( false ); // don't add a new paragraph
5053 case HtmlTokenId::TEXTTOKEN
:
5054 // blank strings may be a series of CR+LF and no text
5055 if( (xCurTable
->GetContext() ||
5056 !xCurTable
->HasParentSection()) &&
5057 1==aToken
.getLength() && ' '==aToken
[0] )
5061 xCurTable
->MakeParentContents();
5062 NextToken( nToken
);
5066 OSL_ENSURE( !bPending
|| m_vPendingStack
.empty(),
5067 "SwHTMLParser::BuildTable: There is a PendStack again" );
5069 if( IsParserWorking() )
5070 SaveState( HtmlTokenId::NONE
);
5073 nToken
= GetNextToken();
5076 if( SvParserState::Pending
== GetStatus() )
5078 m_vPendingStack
.emplace_back( HtmlTokenId::TABLE_ON
);
5079 m_vPendingStack
.back().pData
= std::move(xSaveStruct
);
5080 return std::shared_ptr
<HTMLTable
>();
5083 HTMLTableContext
*pTCntxt
= xCurTable
->GetContext();
5087 // Modify table structure
5088 xCurTable
->CloseTable();
5090 // end contexts that began out of cells. Needs to exist before (!) we move the table,
5091 // since the current one doesn't exist anymore afterwards
5092 while( m_aContexts
.size() > m_nContextStAttrMin
)
5094 std::unique_ptr
<HTMLAttrContext
> xCntxt(PopContext());
5097 ClearContext(xCntxt
.get());
5100 m_nContextStMin
= pTCntxt
->GetContextStMin();
5101 m_nContextStAttrMin
= pTCntxt
->GetContextStAttrMin();
5103 if (m_xTable
== xCurTable
)
5105 // Set table caption
5106 const SwStartNode
*pCapStNd
= m_xTable
->GetCaptionStartNode();
5109 // The last paragraph of the section is never part of the copy.
5110 // That's why the section needs to contain at least two paragraphs
5112 if( pCapStNd
->EndOfSectionIndex() - pCapStNd
->GetIndex() > SwNodeOffset(2) )
5114 // Don't copy start node and the last paragraph
5115 SwNodeRange
aSrcRg( *pCapStNd
, SwNodeOffset(1),
5116 *pCapStNd
->EndOfSectionNode(), SwNodeOffset(-1) );
5118 bool bTop
= m_xTable
->IsTopCaption();
5119 SwStartNode
*pTableStNd
= pTCntxt
->GetTableNode();
5121 OSL_ENSURE( pTableStNd
, "Where is the table node" );
5122 OSL_ENSURE( pTableStNd
== m_pPam
->GetPointNode().FindTableNode(),
5123 "Are we in the wrong table?" );
5131 pNd
= pTableStNd
->EndOfSectionNode();
5132 SwNodeIndex
aDstIdx( *pNd
, bTop
? 0 : 1 );
5134 m_xDoc
->getIDocumentContentOperations().MoveNodeRange( aSrcRg
, aDstIdx
.GetNode(),
5135 SwMoveFlags::DEFAULT
);
5137 // If the caption was added before the table, a page style on that table
5138 // needs to be moved to the first paragraph of the header.
5139 // Additionally, all remembered indices that point to the table node
5143 MovePageDescAttrs( pTableStNd
, aSrcRg
.aStart
.GetIndex(),
5149 // The section isn't needed anymore
5151 m_pPam
->DeleteMark();
5152 DeleteSection(const_cast<SwStartNode
*>(pCapStNd
));
5153 m_xTable
->SetCaption( nullptr, false );
5157 sal_uInt16 nBrowseWidth
= o3tl::narrowing
<sal_uInt16
>(GetCurrentBrowseWidth());
5158 xSaveStruct
->MakeTable(nBrowseWidth
, *m_pPam
->GetPoint(), m_xDoc
.get());
5161 GetNumInfo().Set( pTCntxt
->GetNumInfo() );
5162 pTCntxt
->RestorePREListingXMP( *this );
5163 RestoreAttrTab(pTCntxt
->m_xAttrTab
);
5165 if (m_xTable
== xCurTable
)
5167 // Set upper paragraph spacing
5168 m_bUpperSpace
= true;
5171 SwTableNode
* pTableNode
= pTCntxt
->GetTableNode();
5172 size_t nTableBoxSize
= pTableNode
? pTableNode
->GetTable().GetTabSortBoxes().size() : 0;
5173 m_nParaCnt
= m_nParaCnt
- std::min(m_nParaCnt
, nTableBoxSize
);
5175 // Jump to a table if needed
5176 if( JumpToMarks::Table
== m_eJumpTo
&& m_xTable
->GetSwTable() &&
5177 m_xTable
->GetSwTable()->GetFrameFormat()->GetName() == m_sJmpMark
)
5179 m_bChkJumpMark
= true;
5180 m_eJumpTo
= JumpToMarks::NONE
;
5183 // If the import was canceled, don't call Show again here since
5184 // the SwViewShell was already deleted
5185 // That's not enough. Even in the ACCEPTING_STATE, a Show mustn't be called
5186 // because otherwise the parser's gonna be destroyed on the reschedule,
5187 // if there's still a DataAvailable link coming. So: only in the WORKING state
5188 if( !m_nParaCnt
&& SvParserState::Working
== GetStatus() )
5192 else if (m_xTable
== xCurTable
)
5194 // There was no table read
5196 // We maybe need to delete a read caption
5197 const SwStartNode
*pCapStNd
= xCurTable
->GetCaptionStartNode();
5201 m_pPam
->DeleteMark();
5202 DeleteSection(const_cast<SwStartNode
*>(pCapStNd
));
5203 xCurTable
->SetCaption( nullptr, false );
5207 if (m_xTable
== xCurTable
)
5209 xSaveStruct
->m_xCurrentTable
.reset();
5213 std::shared_ptr
<HTMLTable
> xRetTable
= xSaveStruct
->m_xCurrentTable
;
5214 xSaveStruct
.reset();
5219 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */