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>
23 #include <vcl/svapp.hxx>
24 #include <editeng/boxitem.hxx>
25 #include <editeng/brushitem.hxx>
26 #include <editeng/adjustitem.hxx>
27 #include <editeng/fhgtitem.hxx>
28 #include <editeng/ulspitem.hxx>
29 #include <editeng/lrspitem.hxx>
30 #include <editeng/formatbreakitem.hxx>
31 #include <editeng/spltitem.hxx>
32 #include <unotools/configmgr.hxx>
33 #include <svtools/htmltokn.h>
34 #include <svtools/htmlkywd.hxx>
35 #include <svl/urihelper.hxx>
36 #include <sal/log.hxx>
37 #include <osl/diagnose.h>
39 #include <dcontact.hxx>
40 #include <fmtornt.hxx>
42 #include <fmtfsize.hxx>
43 #include <fmtsrnd.hxx>
44 #include <fmtpdsc.hxx>
45 #include <fmtcntnt.hxx>
46 #include <fmtanchr.hxx>
47 #include <fmtlsplt.hxx>
51 #include <IDocumentLayoutAccess.hxx>
52 #include <IDocumentMarkAccess.hxx>
54 #include <shellio.hxx>
55 #include <poolfmt.hxx>
56 #include <swtable.hxx>
57 #include <cellatr.hxx>
58 #include <htmltbl.hxx>
59 #include <swtblfmt.hxx>
60 #include "htmlnum.hxx"
64 #include <itabenum.hxx>
65 #include <tblafmt.hxx>
66 #include <SwStyleNameMapper.hxx>
67 #include <frameformats.hxx>
69 #define NETSCAPE_DFLT_BORDER 1
70 #define NETSCAPE_DFLT_CELLSPACING 2
72 using ::editeng::SvxBorderLine
;
73 using namespace ::com::sun::star
;
75 HTMLOptionEnum
<sal_Int16
> const aHTMLTableVAlignTable
[] =
77 { OOO_STRING_SVTOOLS_HTML_VA_top
, text::VertOrientation::NONE
},
78 { OOO_STRING_SVTOOLS_HTML_VA_middle
, text::VertOrientation::CENTER
},
79 { OOO_STRING_SVTOOLS_HTML_VA_bottom
, text::VertOrientation::BOTTOM
},
87 struct HTMLTableOptions
92 sal_uInt16 nCellPadding
;
93 sal_uInt16 nCellSpacing
;
100 HTMLTableFrame eFrame
;
101 HTMLTableRules eRules
;
103 bool bPercentWidth
: 1;
104 bool bTableAdjust
: 1;
110 OUString aBGImage
, aStyle
, aId
, aClass
, aDir
;
112 HTMLTableOptions( const HTMLOptions
& rOptions
, SvxAdjust eParentAdjust
);
115 class HTMLTableContext
117 SwHTMLNumRuleInfo m_aNumRuleInfo
; // Numbering valid before the table
119 SwTableNode
*m_pTableNd
; // table node
120 SwFrameFormat
*m_pFrameFormat
; // the Fly frame::Frame, containing the table
121 std::unique_ptr
<SwPosition
> m_pPos
; // position behind the table
123 size_t m_nContextStAttrMin
;
124 size_t m_nContextStMin
;
126 bool m_bRestartPRE
: 1;
127 bool m_bRestartXMP
: 1;
128 bool m_bRestartListing
: 1;
130 HTMLTableContext(const HTMLTableContext
&) = delete;
131 HTMLTableContext
& operator=(const HTMLTableContext
&) = delete;
135 std::shared_ptr
<HTMLAttrTable
> m_xAttrTab
; // attributes
137 HTMLTableContext( SwPosition
*pPs
, size_t nCntxtStMin
,
138 size_t nCntxtStAttrMin
) :
139 m_pTableNd( nullptr ),
140 m_pFrameFormat( nullptr ),
142 m_nContextStAttrMin( nCntxtStAttrMin
),
143 m_nContextStMin( nCntxtStMin
),
144 m_bRestartPRE( false ),
145 m_bRestartXMP( false ),
146 m_bRestartListing( false ),
147 m_xAttrTab(std::make_shared
<HTMLAttrTable
>())
149 memset(m_xAttrTab
.get(), 0, sizeof(HTMLAttrTable
));
152 void SetNumInfo( const SwHTMLNumRuleInfo
& rInf
) { m_aNumRuleInfo
.Set(rInf
); }
153 const SwHTMLNumRuleInfo
& GetNumInfo() const { return m_aNumRuleInfo
; };
155 void SavePREListingXMP( SwHTMLParser
& rParser
);
156 void RestorePREListingXMP( SwHTMLParser
& rParser
);
158 SwPosition
*GetPos() const { return m_pPos
.get(); }
160 void SetTableNode( SwTableNode
*pNd
) { m_pTableNd
= pNd
; }
161 SwTableNode
*GetTableNode() const { return m_pTableNd
; }
163 void SetFrameFormat( SwFrameFormat
*pFormat
) { m_pFrameFormat
= pFormat
; }
164 SwFrameFormat
*GetFrameFormat() const { return m_pFrameFormat
; }
166 size_t GetContextStMin() const { return m_nContextStMin
; }
167 size_t GetContextStAttrMin() const { return m_nContextStAttrMin
; }
172 // Cell content is a linked list with SwStartNodes and
177 std::unique_ptr
<HTMLTableCnts
> m_pNext
; // next content
179 // Only one of the next two pointers must be set!
180 const SwStartNode
*m_pStartNode
; // a paragraph
181 std::shared_ptr
<HTMLTable
> m_xTable
; // a table
183 std::shared_ptr
<SwHTMLTableLayoutCnts
> m_xLayoutInfo
;
191 explicit HTMLTableCnts(const SwStartNode
* pStNd
);
192 explicit HTMLTableCnts(const std::shared_ptr
<HTMLTable
>& rTab
);
194 ~HTMLTableCnts(); // only allowed in ~HTMLTableCell
196 // Determine SwStartNode and HTMLTable respectively
197 const SwStartNode
*GetStartNode() const { return m_pStartNode
; }
198 const std::shared_ptr
<HTMLTable
>& GetTable() const { return m_xTable
; }
199 std::shared_ptr
<HTMLTable
>& GetTable() { return m_xTable
; }
201 // Add a new node at the end of the list
202 void Add( std::unique_ptr
<HTMLTableCnts
> pNewCnts
);
204 // Determine next node
205 const HTMLTableCnts
*Next() const { return m_pNext
.get(); }
206 HTMLTableCnts
*Next() { return m_pNext
.get(); }
208 inline void SetTableBox( SwTableBox
*pBox
);
210 void SetNoBreak() { m_bNoBreak
= true; }
212 const std::shared_ptr
<SwHTMLTableLayoutCnts
>& CreateLayoutInfo();
217 // Cell of a HTML table
220 std::shared_ptr
<HTMLTableCnts
> m_xContents
; // cell content
221 std::shared_ptr
<SvxBrushItem
> m_xBGBrush
; // cell background
222 std::shared_ptr
<SvxBoxItem
> m_xBoxItem
;
225 sal_uInt32 m_nNumFormat
;
226 sal_uInt16 m_nRowSpan
; // cell ROWSPAN
227 sal_uInt16 m_nColSpan
; // cell COLSPAN
228 sal_uInt16 m_nWidth
; // cell WIDTH
229 sal_Int16 m_eVertOrient
; // vertical alignment of the cell
230 bool m_bProtected
: 1; // cell must not filled
231 bool m_bRelWidth
: 1; // nWidth is given in %
232 bool m_bHasNumFormat
: 1;
233 bool m_bHasValue
: 1;
239 HTMLTableCell(); // new cells always empty
241 // Fill a not empty cell
242 void Set( std::shared_ptr
<HTMLTableCnts
> const& rCnts
, sal_uInt16 nRSpan
, sal_uInt16 nCSpan
,
243 sal_Int16 eVertOri
, std::shared_ptr
<SvxBrushItem
> const& rBGBrush
,
244 std::shared_ptr
<SvxBoxItem
> const& rBoxItem
,
245 bool bHasNumFormat
, sal_uInt32 nNumFormat
,
246 bool bHasValue
, double nValue
, bool bNoWrap
, bool bCovered
);
248 // Protect an empty 1x1 cell
251 // Set/Get cell content
252 void SetContents(std::shared_ptr
<HTMLTableCnts
> const& rCnts
) { m_xContents
= rCnts
; }
253 const std::shared_ptr
<HTMLTableCnts
>& GetContents() const { return m_xContents
; }
255 // Set/Get cell ROWSPAN/COLSPAN
256 void SetRowSpan( sal_uInt16 nRSpan
) { m_nRowSpan
= nRSpan
; }
257 sal_uInt16
GetRowSpan() const { return m_nRowSpan
; }
259 void SetColSpan( sal_uInt16 nCSpan
) { m_nColSpan
= nCSpan
; }
260 sal_uInt16
GetColSpan() const { return m_nColSpan
; }
262 inline void SetWidth( sal_uInt16 nWidth
, bool bRelWidth
);
264 const std::shared_ptr
<SvxBrushItem
>& GetBGBrush() const { return m_xBGBrush
; }
265 const std::shared_ptr
<SvxBoxItem
>& GetBoxItem() const { return m_xBoxItem
; }
267 inline bool GetNumFormat( sal_uInt32
& rNumFormat
) const;
268 inline bool GetValue( double& rValue
) const;
270 sal_Int16
GetVertOri() const { return m_eVertOrient
; }
272 // Is the cell filled or protected ?
273 bool IsUsed() const { return m_xContents
|| m_bProtected
; }
275 std::unique_ptr
<SwHTMLTableLayoutCell
> CreateLayoutInfo();
277 bool IsCovered() const { return mbCovered
; }
285 // Row of a HTML table
288 std::vector
<HTMLTableCell
> m_aCells
; ///< cells of the row
289 std::unique_ptr
<SvxBrushItem
> m_xBGBrush
; // background of cell from STYLE
292 sal_uInt16 m_nHeight
; // options of <TR>/<TD>
293 sal_uInt16 m_nEmptyRows
; // number of empty rows are following
294 sal_Int16 m_eVertOri
;
295 bool m_bIsEndOfGroup
: 1;
296 bool m_bBottomBorder
: 1; // Is there a line after the row?
300 explicit HTMLTableRow( sal_uInt16 nCells
); // cells of the row are empty
302 void SetBottomBorder(bool bIn
) { m_bBottomBorder
= bIn
; }
303 bool GetBottomBorder() const { return m_bBottomBorder
; }
305 inline void SetHeight( sal_uInt16 nHeight
);
306 sal_uInt16
GetHeight() const { return m_nHeight
; }
308 const HTMLTableCell
& GetCell(sal_uInt16 nCell
) const;
309 HTMLTableCell
& GetCell(sal_uInt16 nCell
)
311 return const_cast<HTMLTableCell
&>(const_cast<const HTMLTableRow
&>(*this).GetCell(nCell
));
314 void SetAdjust( SvxAdjust eAdj
) { m_eAdjust
= eAdj
; }
315 SvxAdjust
GetAdjust() const { return m_eAdjust
; }
317 void SetVertOri( sal_Int16 eV
) { m_eVertOri
= eV
; }
318 sal_Int16
GetVertOri() const { return m_eVertOri
; }
320 void SetBGBrush(std::unique_ptr
<SvxBrushItem
>& rBrush
) { m_xBGBrush
= std::move(rBrush
); }
321 const std::unique_ptr
<SvxBrushItem
>& GetBGBrush() const { return m_xBGBrush
; }
323 void SetEndOfGroup() { m_bIsEndOfGroup
= true; }
324 bool IsEndOfGroup() const { return m_bIsEndOfGroup
; }
326 void IncEmptyRows() { m_nEmptyRows
++; }
327 sal_uInt16
GetEmptyRows() const { return m_nEmptyRows
; }
329 // Expand row by adding empty cells
330 void Expand( sal_uInt16 nCells
, bool bOneCell
=false );
332 // Shrink row by deleting empty cells
333 void Shrink( sal_uInt16 nCells
);
336 // Column of a HTML table
337 class HTMLTableColumn
339 bool m_bIsEndOfGroup
;
341 sal_uInt16 m_nWidth
; // options of <COL>
345 sal_Int16 m_eVertOri
;
347 SwFrameFormat
*m_aFrameFormats
[6];
349 static inline sal_uInt16
GetFrameFormatIdx( bool bBorderLine
,
350 sal_Int16 eVertOri
);
354 bool m_bLeftBorder
; // is there a line before the column
358 inline void SetWidth( sal_uInt16 nWidth
, bool bRelWidth
);
360 void SetAdjust( SvxAdjust eAdj
) { m_eAdjust
= eAdj
; }
361 SvxAdjust
GetAdjust() const { return m_eAdjust
; }
363 void SetVertOri( sal_Int16 eV
) { m_eVertOri
= eV
; }
364 sal_Int16
GetVertOri() const { return m_eVertOri
; }
366 void SetEndOfGroup() { m_bIsEndOfGroup
= true; }
367 bool IsEndOfGroup() const { return m_bIsEndOfGroup
; }
369 inline void SetFrameFormat( SwFrameFormat
*pFormat
, bool bBorderLine
,
370 sal_Int16 eVertOri
);
371 inline SwFrameFormat
*GetFrameFormat( bool bBorderLine
,
372 sal_Int16 eVertOri
) const;
374 std::unique_ptr
<SwHTMLTableLayoutColumn
> CreateLayoutInfo();
380 typedef std::vector
<SdrObject
*> SdrObjects
;
389 std::optional
<SdrObjects
> m_xResizeDrawObjects
;// SDR objects
390 std::optional
<std::vector
<sal_uInt16
>> m_xDrawObjectPercentWidths
; // column of draw object and its rel. width
392 std::vector
<HTMLTableRow
> m_aRows
; ///< table rows
393 std::vector
<HTMLTableColumn
> m_aColumns
; ///< table columns
395 sal_uInt16 m_nRows
; // number of rows
396 sal_uInt16 m_nCols
; // number of columns
397 sal_uInt16 m_nFilledColumns
; // number of filled columns
399 sal_uInt16 m_nCurrentRow
; // current Row
400 sal_uInt16 m_nCurrentColumn
; // current Column
402 sal_uInt16 m_nLeftMargin
; // Space to the left margin (from paragraph edge)
403 sal_uInt16 m_nRightMargin
; // Space to the right margin (from paragraph edge)
405 sal_uInt16 m_nCellPadding
; // Space from border to Text
406 sal_uInt16 m_nCellSpacing
; // Space between two cells
407 sal_uInt16 m_nHSpace
;
408 sal_uInt16 m_nVSpace
;
410 sal_uInt16 m_nBoxes
; // number of boxes in the table
412 const SwStartNode
*m_pPrevStartNode
; // the Table-Node or the Start-Node of the section before
413 const SwTable
*m_pSwTable
; // SW-Table (only on Top-Level)
415 std::unique_ptr
<SwTableBox
> m_xBox1
; // TableBox, generated when the Top-Level-Table was build
417 SwTableBoxFormat
*m_pBoxFormat
; // frame::Frame-Format from SwTableBox
418 SwTableLineFormat
*m_pLineFormat
; // frame::Frame-Format from SwTableLine
419 SwTableLineFormat
*m_pLineFrameFormatNoHeight
;
420 std::unique_ptr
<SvxBrushItem
> m_xBackgroundBrush
; // background of the table
421 std::unique_ptr
<SvxBrushItem
> m_xInheritedBackgroundBrush
; // "inherited" background of the table
422 const SwStartNode
*m_pCaptionStartNode
; // Start-Node of the table-caption
423 //lines for the border
424 SvxBorderLine m_aTopBorderLine
;
425 SvxBorderLine m_aBottomBorderLine
;
426 SvxBorderLine m_aLeftBorderLine
;
427 SvxBorderLine m_aRightBorderLine
;
428 SvxBorderLine m_aBorderLine
;
429 SvxBorderLine m_aInheritedLeftBorderLine
;
430 SvxBorderLine m_aInheritedRightBorderLine
;
431 bool m_bTopBorder
; // is there a line on the top of the table
432 bool m_bRightBorder
; // is there a line on the top right of the table
433 bool m_bTopAllowed
; // is it allowed to set the border?
434 bool m_bRightAllowed
;
435 bool m_bFillerTopBorder
; // gets the left/right filler-cell a border on the
436 bool m_bFillerBottomBorder
; // top or in the bottom
437 bool m_bInheritedLeftBorder
;
438 bool m_bInheritedRightBorder
;
439 bool m_bBordersSet
; // the border is set already
441 bool m_bTableAdjustOfTag
; // comes nTableAdjust from <TABLE>?
442 sal_uInt32 m_nHeadlineRepeat
; // repeating rows
443 bool m_bIsParentHead
;
444 bool m_bHasParentSection
;
447 bool m_bColSpec
; // where there COL(GROUP)-elements?
448 bool m_bPercentWidth
; // width is declared in %
450 SwHTMLParser
*m_pParser
; // the current parser
451 std::unique_ptr
<HTMLTableCnts
> m_xParentContents
;
453 std::unique_ptr
<HTMLTableContext
> m_pContext
; // the context of the table
455 std::shared_ptr
<SwHTMLTableLayout
> m_xLayoutInfo
;
457 // the following parameters are from the <TABLE>-Tag
458 sal_uInt16 m_nWidth
; // width of the table
459 sal_uInt16 m_nHeight
; // absolute height of the table
460 SvxAdjust m_eTableAdjust
; // drawing::Alignment of the table
461 sal_Int16 m_eVertOrientation
; // Default vertical direction of the cells
462 sal_uInt16 m_nBorder
; // width of the external border
463 HTMLTableFrame m_eFrame
; // frame around the table
464 HTMLTableRules m_eRules
; // frame in the table
465 bool m_bTopCaption
; // Caption of the table
467 void InitCtor(const HTMLTableOptions
& rOptions
);
469 // 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
470 void FixRowSpan( sal_uInt16 nRow
, sal_uInt16 nCol
, const HTMLTableCnts
*pCnts
);
472 // Protects the chosen cell and the cells among
473 void ProtectRowSpan( sal_uInt16 nRow
, sal_uInt16 nCol
, sal_uInt16 nRowSpan
);
475 // Looking for the SwStartNodes of the box ahead
476 // If nRow==nCell==USHRT_MAX, return the last Start-Node of the table.
477 const SwStartNode
* GetPrevBoxStartNode( sal_uInt16 nRow
, sal_uInt16 nCell
) const;
479 sal_uInt16
GetTopCellSpace( sal_uInt16 nRow
) const;
480 sal_uInt16
GetBottomCellSpace( sal_uInt16 nRow
, sal_uInt16 nRowSpan
) const;
482 // Conforming of the frame::Frame-Format of the box
483 void FixFrameFormat( SwTableBox
*pBox
, sal_uInt16 nRow
, sal_uInt16 nCol
,
484 sal_uInt16 nRowSpan
, sal_uInt16 nColSpan
,
485 bool bFirstPara
=true, bool bLastPara
=true ) const;
487 // Create a table with the content (lines/boxes)
488 void MakeTable_( SwTableBox
*pUpper
);
490 // Generate a new SwTableBox, which contains a SwStartNode
491 SwTableBox
*NewTableBox( const SwStartNode
*pStNd
,
492 SwTableLine
*pUpper
) const;
494 // Generate a SwTableLine from the cells of the rectangle
495 // (nTopRow/nLeftCol) inclusive to (nBottomRow/nRightRow) exclusive
496 SwTableLine
*MakeTableLine( SwTableBox
*pUpper
,
497 sal_uInt16 nTopRow
, sal_uInt16 nLeftCol
,
498 sal_uInt16 nBottomRow
, sal_uInt16 nRightCol
);
500 // Generate a SwTableBox from the content of the cell
501 SwTableBox
*MakeTableBox( SwTableLine
*pUpper
,
502 HTMLTableCnts
*pCnts
,
503 sal_uInt16 nTopRow
, sal_uInt16 nLeftCol
,
504 sal_uInt16 nBootomRow
, sal_uInt16 nRightCol
);
506 // Autolayout-Algorithm
508 // Setting the border with the help of guidelines of the Parent-Table
509 void InheritBorders( const HTMLTable
*pParent
,
510 sal_uInt16 nRow
, sal_uInt16 nCol
,
512 bool bFirstPara
, bool bLastPara
);
514 // Inherit the left and the right border of the surrounding table
515 void InheritVertBorders( const HTMLTable
*pParent
,
516 sal_uInt16 nCol
, sal_uInt16 nColSpan
);
518 // Set the border with the help of the information from the user
521 // is the border already set?
522 bool BordersSet() const { return m_bBordersSet
; }
524 const std::unique_ptr
<SvxBrushItem
>& GetBGBrush() const { return m_xBackgroundBrush
; }
525 const std::unique_ptr
<SvxBrushItem
>& GetInhBGBrush() const { return m_xInheritedBackgroundBrush
; }
527 sal_uInt16
GetBorderWidth( const SvxBorderLine
& rBLine
,
528 bool bWithDistance
=false ) const;
532 bool m_bFirstCell
; // is there a cell created already?
534 HTMLTable(SwHTMLParser
* pPars
,
535 bool bParHead
, bool bHasParentSec
,
537 const HTMLTableOptions
& rOptions
);
541 // Identifying of a cell
542 const HTMLTableCell
& GetCell(sal_uInt16 nRow
, sal_uInt16 nCell
) const;
543 HTMLTableCell
& GetCell(sal_uInt16 nRow
, sal_uInt16 nCell
)
545 return const_cast<HTMLTableCell
&>(const_cast<const HTMLTable
&>(*this).GetCell(nRow
, nCell
));
548 // set/determine caption
549 inline void SetCaption( const SwStartNode
*pStNd
, bool bTop
);
550 const SwStartNode
*GetCaptionStartNode() const { return m_pCaptionStartNode
; }
551 bool IsTopCaption() const { return m_bTopCaption
; }
553 SvxAdjust
GetTableAdjust( bool bAny
) const
555 return (m_bTableAdjustOfTag
|| bAny
) ? m_eTableAdjust
: SvxAdjust::End
;
558 sal_uInt16
GetHSpace() const { return m_nHSpace
; }
559 sal_uInt16
GetVSpace() const { return m_nVSpace
; }
561 // get inherited drawing::Alignment of rows and column
562 SvxAdjust
GetInheritedAdjust() const;
563 sal_Int16
GetInheritedVertOri() const;
565 // Insert a cell on the current position
566 void InsertCell( std::shared_ptr
<HTMLTableCnts
> const& rCnts
, sal_uInt16 nRowSpan
, sal_uInt16 nColSpan
,
567 sal_uInt16 nWidth
, bool bRelWidth
, sal_uInt16 nHeight
,
568 sal_Int16 eVertOri
, std::shared_ptr
<SvxBrushItem
> const& rBGBrushItem
,
569 std::shared_ptr
<SvxBoxItem
> const& rBoxItem
,
570 bool bHasNumFormat
, sal_uInt32 nNumFormat
,
571 bool bHasValue
, double nValue
, bool bNoWrap
);
573 // announce the start/end of a new row
574 void OpenRow(SvxAdjust eAdjust
, sal_Int16 eVertOri
, std::unique_ptr
<SvxBrushItem
>& rBGBrush
);
575 void CloseRow( bool bEmpty
);
577 // announce the end of a new section
578 inline void CloseSection( bool bHead
);
580 // announce the end of a column-group
581 inline void CloseColGroup( sal_uInt16 nSpan
, sal_uInt16 nWidth
, bool bRelWidth
,
582 SvxAdjust eAdjust
, sal_Int16 eVertOri
);
584 // insert a new column
585 void InsertCol( sal_uInt16 nSpan
, sal_uInt16 nWidth
, bool bRelWidth
,
586 SvxAdjust eAdjust
, sal_Int16 eVertOri
);
588 // End a table definition (needs to be called for every table)
591 // Construct a SwTable (including child tables)
592 void MakeTable( SwTableBox
*pUpper
, sal_uInt16 nAbsAvail
,
593 sal_uInt16 nRelAvail
=0, sal_uInt16 nAbsLeftSpace
=0,
594 sal_uInt16 nAbsRightSpace
=0, sal_uInt16 nInhAbsSpace
=0 );
596 bool IsNewDoc() const { return m_pParser
->IsNewDoc(); }
598 void SetHasParentSection( bool bSet
) { m_bHasParentSection
= bSet
; }
599 bool HasParentSection() const { return m_bHasParentSection
; }
601 void SetParentContents(std::unique_ptr
<HTMLTableCnts
> pCnts
) { m_xParentContents
= std::move(pCnts
); }
602 std::unique_ptr
<HTMLTableCnts
>& GetParentContents() { return m_xParentContents
; }
604 void MakeParentContents();
606 bool HasToFly() const { return m_bHasToFly
; }
608 void SetTable( const SwStartNode
*pStNd
, std::unique_ptr
<HTMLTableContext
> pCntxt
,
609 sal_uInt16 nLeft
, sal_uInt16 nRight
,
610 const SwTable
*pSwTab
=nullptr, bool bFrcFrame
=false );
612 HTMLTableContext
*GetContext() const { return m_pContext
.get(); }
614 const std::shared_ptr
<SwHTMLTableLayout
>& CreateLayoutInfo();
616 bool HasColTags() const { return m_bColSpec
; }
618 sal_uInt16
IncGrfsThatResize() { return m_pSwTable
? const_cast<SwTable
*>(m_pSwTable
)->IncGrfsThatResize() : 0; }
620 void RegisterDrawObject( SdrObject
*pObj
, sal_uInt8 nPercentWidth
);
622 const SwTable
*GetSwTable() const { return m_pSwTable
; }
624 void SetBGBrush(const SvxBrushItem
& rBrush
) { m_xBackgroundBrush
.reset(new SvxBrushItem(rBrush
)); }
626 const OUString
& GetId() const { return m_aId
; }
627 const OUString
& GetClass() const { return m_aClass
; }
628 const OUString
& GetStyle() const { return m_aStyle
; }
629 const OUString
& GetDirection() const { return m_aDir
; }
631 void IncBoxCount() { m_nBoxes
++; }
632 bool IsOverflowing() const { return m_nBoxes
> 64000; }
634 bool PendingDrawObjectsInPaM(SwPaM
& rPam
) const;
637 void HTMLTableCnts::InitCtor()
640 m_xLayoutInfo
.reset();
644 HTMLTableCnts::HTMLTableCnts(const SwStartNode
* pStNd
)
645 : m_pStartNode(pStNd
)
650 HTMLTableCnts::HTMLTableCnts(const std::shared_ptr
<HTMLTable
>& rTab
)
651 : m_pStartNode(nullptr)
657 HTMLTableCnts::~HTMLTableCnts()
659 m_xTable
.reset(); // we don't need the tables anymore
663 void HTMLTableCnts::Add( std::unique_ptr
<HTMLTableCnts
> pNewCnts
)
665 HTMLTableCnts
*pCnts
= this;
667 while( pCnts
->m_pNext
)
668 pCnts
= pCnts
->m_pNext
.get();
670 pCnts
->m_pNext
= std::move(pNewCnts
);
673 inline void HTMLTableCnts::SetTableBox( SwTableBox
*pBox
)
675 OSL_ENSURE(m_xLayoutInfo
, "There is no layout info");
677 m_xLayoutInfo
->SetTableBox(pBox
);
680 const std::shared_ptr
<SwHTMLTableLayoutCnts
>& HTMLTableCnts::CreateLayoutInfo()
684 std::shared_ptr
<SwHTMLTableLayoutCnts
> xNextInfo
;
686 xNextInfo
= m_pNext
->CreateLayoutInfo();
687 std::shared_ptr
<SwHTMLTableLayout
> xTableInfo
;
689 xTableInfo
= m_xTable
->CreateLayoutInfo();
690 m_xLayoutInfo
= std::make_shared
<SwHTMLTableLayoutCnts
>(m_pStartNode
, xTableInfo
, m_bNoBreak
, xNextInfo
);
693 return m_xLayoutInfo
;
696 HTMLTableCell::HTMLTableCell():
702 m_eVertOrient( text::VertOrientation::NONE
),
704 m_bRelWidth( false ),
705 m_bHasNumFormat(false),
711 void HTMLTableCell::Set( std::shared_ptr
<HTMLTableCnts
> const& rCnts
, sal_uInt16 nRSpan
, sal_uInt16 nCSpan
,
712 sal_Int16 eVert
, std::shared_ptr
<SvxBrushItem
> const& rBrush
,
713 std::shared_ptr
<SvxBoxItem
> const& rBoxItem
,
714 bool bHasNF
, sal_uInt32 nNF
, bool bHasV
, double nVal
,
715 bool bNWrap
, bool bCovered
)
720 m_bProtected
= false;
721 m_eVertOrient
= eVert
;
723 m_xBoxItem
= rBoxItem
;
725 m_bHasNumFormat
= bHasNF
;
731 mbCovered
= bCovered
;
734 inline void HTMLTableCell::SetWidth( sal_uInt16 nWdth
, bool bRelWdth
)
737 m_bRelWidth
= bRelWdth
;
740 void HTMLTableCell::SetProtected()
742 // The content of this cell doesn't have to be anchored anywhere else,
743 // since they're not gonna be deleted
747 // Copy background color
749 m_xBGBrush
= std::make_shared
<SvxBrushItem
>(*m_xBGBrush
);
756 inline bool HTMLTableCell::GetNumFormat( sal_uInt32
& rNumFormat
) const
758 rNumFormat
= m_nNumFormat
;
759 return m_bHasNumFormat
;
762 inline bool HTMLTableCell::GetValue( double& rValue
) const
768 std::unique_ptr
<SwHTMLTableLayoutCell
> HTMLTableCell::CreateLayoutInfo()
770 std::shared_ptr
<SwHTMLTableLayoutCnts
> xCntInfo
;
772 xCntInfo
= m_xContents
->CreateLayoutInfo();
773 return std::unique_ptr
<SwHTMLTableLayoutCell
>(new SwHTMLTableLayoutCell(xCntInfo
, m_nRowSpan
, m_nColSpan
, m_nWidth
,
774 m_bRelWidth
, m_bNoWrap
));
777 HTMLTableRow::HTMLTableRow(sal_uInt16
const nCells
)
779 , m_eAdjust(SvxAdjust::End
)
782 , m_eVertOri(text::VertOrientation::TOP
)
783 , m_bIsEndOfGroup(false)
784 , m_bBottomBorder(false)
786 assert(nCells
== m_aCells
.size() &&
787 "wrong Cell count in new HTML table row");
790 inline void HTMLTableRow::SetHeight( sal_uInt16 nHght
)
792 if( nHght
> m_nHeight
)
796 const HTMLTableCell
& HTMLTableRow::GetCell(sal_uInt16 nCell
) const
798 OSL_ENSURE( nCell
< m_aCells
.size(),
799 "invalid cell index in HTML table row" );
800 return m_aCells
.at(nCell
);
803 void HTMLTableRow::Expand( sal_uInt16 nCells
, bool bOneCell
)
805 // This row will be filled with a single cell if bOneCell is set.
806 // This will only work for rows that don't allow adding cells!
808 sal_uInt16 nColSpan
= nCells
- m_aCells
.size();
809 for (sal_uInt16 i
= m_aCells
.size(); i
< nCells
; ++i
)
811 m_aCells
.emplace_back();
813 m_aCells
.back().SetColSpan(nColSpan
);
817 OSL_ENSURE(nCells
== m_aCells
.size(),
818 "wrong Cell count in expanded HTML table row");
821 void HTMLTableRow::Shrink( sal_uInt16 nCells
)
823 OSL_ENSURE(nCells
< m_aCells
.size(), "number of cells too large");
825 #if OSL_DEBUG_LEVEL > 0
826 sal_uInt16
const nEnd
= m_aCells
.size();
828 // The colspan of empty cells at the end has to be fixed to the new
833 HTMLTableCell
& rCell
= m_aCells
[--i
];
834 if (!rCell
.GetContents())
836 #if OSL_DEBUG_LEVEL > 0
837 OSL_ENSURE( rCell
.GetColSpan() == nEnd
- i
,
838 "invalid col span for empty cell at row end" );
840 rCell
.SetColSpan( nCells
-i
);
845 #if OSL_DEBUG_LEVEL > 0
846 for( i
=nCells
; i
<nEnd
; i
++ )
848 HTMLTableCell
& rCell
= m_aCells
[i
];
849 OSL_ENSURE( rCell
.GetRowSpan() == 1,
850 "RowSpan of to be deleted cell is wrong" );
851 OSL_ENSURE( rCell
.GetColSpan() == nEnd
- i
,
852 "ColSpan of to be deleted cell is wrong" );
853 OSL_ENSURE( !rCell
.GetContents(), "To be deleted cell has content" );
857 m_aCells
.erase(m_aCells
.begin() + nCells
, m_aCells
.end());
860 HTMLTableColumn::HTMLTableColumn():
861 m_bIsEndOfGroup(false),
862 m_nWidth(0), m_bRelWidth(false),
863 m_eAdjust(SvxAdjust::End
), m_eVertOri(text::VertOrientation::TOP
),
866 for(SwFrameFormat
* & rp
: m_aFrameFormats
)
870 inline void HTMLTableColumn::SetWidth( sal_uInt16 nWdth
, bool bRelWdth
)
872 if( m_bRelWidth
==bRelWdth
)
874 if( nWdth
> m_nWidth
)
879 m_bRelWidth
= bRelWdth
;
882 inline std::unique_ptr
<SwHTMLTableLayoutColumn
> HTMLTableColumn::CreateLayoutInfo()
884 return std::unique_ptr
<SwHTMLTableLayoutColumn
>(new SwHTMLTableLayoutColumn( m_nWidth
, m_bRelWidth
, m_bLeftBorder
));
887 inline sal_uInt16
HTMLTableColumn::GetFrameFormatIdx( bool bBorderLine
,
888 sal_Int16 eVertOrient
)
890 OSL_ENSURE( text::VertOrientation::TOP
!= eVertOrient
, "Top is not allowed" );
891 sal_uInt16 n
= bBorderLine
? 3 : 0;
892 switch( eVertOrient
)
894 case text::VertOrientation::CENTER
: n
+=1; break;
895 case text::VertOrientation::BOTTOM
: n
+=2; break;
902 inline void HTMLTableColumn::SetFrameFormat( SwFrameFormat
*pFormat
, bool bBorderLine
,
903 sal_Int16 eVertOrient
)
905 m_aFrameFormats
[GetFrameFormatIdx(bBorderLine
,eVertOrient
)] = pFormat
;
908 inline SwFrameFormat
*HTMLTableColumn::GetFrameFormat( bool bBorderLine
,
909 sal_Int16 eVertOrient
) const
911 return m_aFrameFormats
[GetFrameFormatIdx(bBorderLine
,eVertOrient
)];
914 void HTMLTable::InitCtor(const HTMLTableOptions
& rOptions
)
917 m_nCurrentRow
= 0; m_nCurrentColumn
= 0;
919 m_pBoxFormat
= nullptr; m_pLineFormat
= nullptr;
920 m_pLineFrameFormatNoHeight
= nullptr;
921 m_xInheritedBackgroundBrush
.reset();
923 m_pPrevStartNode
= nullptr;
924 m_pSwTable
= nullptr;
926 m_bTopBorder
= false; m_bRightBorder
= false;
927 m_bTopAllowed
= true; m_bRightAllowed
= true;
928 m_bFillerTopBorder
= false; m_bFillerBottomBorder
= false;
929 m_bInheritedLeftBorder
= false; m_bInheritedRightBorder
= false;
930 m_bBordersSet
= false;
931 m_bForceFrame
= false;
932 m_nHeadlineRepeat
= 0;
937 const Color
& rBorderColor
= rOptions
.aBorderColor
;
939 tools::Long nBorderOpt
= static_cast<tools::Long
>(rOptions
.nBorder
);
940 tools::Long nPWidth
= nBorderOpt
==USHRT_MAX
? NETSCAPE_DFLT_BORDER
942 tools::Long nPHeight
= nBorderOpt
==USHRT_MAX
? 0 : nBorderOpt
;
943 SvxCSS1Parser::PixelToTwip( nPWidth
, nPHeight
);
945 // nBorder tells the width of the border as it's used in the width calculation of NetScape
946 // If pOption->nBorder == USHRT_MAX, there wasn't a BORDER option given
947 // Nonetheless, a 1 pixel wide border will be used for width calculation
948 m_nBorder
= o3tl::narrowing
<sal_uInt16
>(nPWidth
);
949 if( nBorderOpt
==USHRT_MAX
)
952 if ( rOptions
.nCellSpacing
!= 0 )
954 m_aTopBorderLine
.SetBorderLineStyle(SvxBorderLineStyle::DOUBLE
);
956 m_aTopBorderLine
.SetWidth( nPHeight
);
957 m_aTopBorderLine
.SetColor( rBorderColor
);
958 m_aBottomBorderLine
= m_aTopBorderLine
;
960 if( nPWidth
== nPHeight
)
962 m_aLeftBorderLine
= m_aTopBorderLine
;
966 if ( rOptions
.nCellSpacing
!= 0 )
968 m_aLeftBorderLine
.SetBorderLineStyle(SvxBorderLineStyle::DOUBLE
);
970 m_aLeftBorderLine
.SetWidth( nPWidth
);
971 m_aLeftBorderLine
.SetColor( rBorderColor
);
973 m_aRightBorderLine
= m_aLeftBorderLine
;
975 if( rOptions
.nCellSpacing
!= 0 )
977 m_aBorderLine
.SetBorderLineStyle(SvxBorderLineStyle::DOUBLE
);
978 m_aBorderLine
.SetWidth( DEF_LINE_WIDTH_0
);
982 m_aBorderLine
.SetWidth( DEF_LINE_WIDTH_0
);
984 m_aBorderLine
.SetColor( rBorderColor
);
988 if( m_nCellPadding
==USHRT_MAX
)
989 m_nCellPadding
= MIN_BORDER_DIST
; // default
992 m_nCellPadding
= SwHTMLParser::ToTwips( m_nCellPadding
);
993 if( m_nCellPadding
<MIN_BORDER_DIST
)
994 m_nCellPadding
= MIN_BORDER_DIST
;
999 if( m_nCellSpacing
==USHRT_MAX
)
1000 m_nCellSpacing
= NETSCAPE_DFLT_CELLSPACING
;
1001 m_nCellSpacing
= SwHTMLParser::ToTwips( m_nCellSpacing
);
1004 nPWidth
= rOptions
.nHSpace
;
1005 nPHeight
= rOptions
.nVSpace
;
1006 SvxCSS1Parser::PixelToTwip( nPWidth
, nPHeight
);
1007 m_nHSpace
= o3tl::narrowing
<sal_uInt16
>(nPWidth
);
1008 m_nVSpace
= o3tl::narrowing
<sal_uInt16
>(nPHeight
);
1012 m_xBackgroundBrush
.reset(m_pParser
->CreateBrushItem(
1013 rOptions
.bBGColor
? &(rOptions
.aBGColor
) : nullptr,
1014 rOptions
.aBGImage
, OUString(), OUString(), OUString()));
1016 m_pContext
= nullptr;
1017 m_xParentContents
.reset();
1019 m_aId
= rOptions
.aId
;
1020 m_aClass
= rOptions
.aClass
;
1021 m_aStyle
= rOptions
.aStyle
;
1022 m_aDir
= rOptions
.aDir
;
1025 HTMLTable::HTMLTable(SwHTMLParser
* pPars
,
1027 bool bHasParentSec
, bool bHasToFlw
,
1028 const HTMLTableOptions
& rOptions
) :
1029 m_aColumns(rOptions
.nCols
),
1030 m_nCols(rOptions
.nCols
),
1031 m_nFilledColumns( 0 ),
1032 m_nCellPadding(rOptions
.nCellPadding
),
1033 m_nCellSpacing(rOptions
.nCellSpacing
),
1035 m_pCaptionStartNode( nullptr ),
1036 m_bTableAdjustOfTag( rOptions
.bTableAdjust
),
1037 m_bIsParentHead( bParHead
),
1038 m_bHasParentSection( bHasParentSec
),
1039 m_bHasToFly( bHasToFlw
),
1040 m_bFixedCols( rOptions
.nCols
>0 ),
1041 m_bPercentWidth( rOptions
.bPercentWidth
),
1043 m_nWidth( rOptions
.nWidth
),
1044 m_nHeight( rOptions
.nHeight
),
1045 m_eTableAdjust( rOptions
.eAdjust
),
1046 m_eVertOrientation( rOptions
.eVertOri
),
1047 m_eFrame( rOptions
.eFrame
),
1048 m_eRules( rOptions
.eRules
),
1049 m_bTopCaption( false ),
1053 m_pParser
->RegisterHTMLTable(this);
1056 void SwHTMLParser::DeregisterHTMLTable(HTMLTable
* pOld
)
1059 m_aOrphanedTableBoxes
.emplace_back(std::move(pOld
->m_xBox1
));
1060 m_aTables
.erase(std::remove(m_aTables
.begin(), m_aTables
.end(), pOld
));
1063 SwDoc
* SwHTMLParser::GetDoc() const
1065 return m_xDoc
.get();
1068 bool SwHTMLParser::IsReqIF() const
1073 HTMLTable::~HTMLTable()
1075 m_pParser
->DeregisterHTMLTable(this);
1077 m_xResizeDrawObjects
.reset();
1078 m_xDrawObjectPercentWidths
.reset();
1082 // pLayoutInfo has either already been deleted or is now owned by SwTable
1085 const std::shared_ptr
<SwHTMLTableLayout
>& HTMLTable::CreateLayoutInfo()
1087 sal_uInt16 nW
= m_bPercentWidth
? m_nWidth
: SwHTMLParser::ToTwips( m_nWidth
);
1089 sal_uInt16 nBorderWidth
= GetBorderWidth( m_aBorderLine
, true );
1090 sal_uInt16 nLeftBorderWidth
=
1091 m_aColumns
[0].m_bLeftBorder
? GetBorderWidth(m_aLeftBorderLine
, true) : 0;
1092 sal_uInt16 nRightBorderWidth
=
1093 m_bRightBorder
? GetBorderWidth( m_aRightBorderLine
, true ) : 0;
1095 m_xLayoutInfo
= std::make_shared
<SwHTMLTableLayout
>(
1097 m_nRows
, m_nCols
, m_bFixedCols
, m_bColSpec
,
1098 nW
, m_bPercentWidth
, m_nBorder
, m_nCellPadding
,
1099 m_nCellSpacing
, m_eTableAdjust
,
1100 m_nLeftMargin
, m_nRightMargin
,
1101 nBorderWidth
, nLeftBorderWidth
, nRightBorderWidth
);
1103 bool bExportable
= true;
1105 for( i
=0; i
<m_nRows
; i
++ )
1107 HTMLTableRow
& rRow
= m_aRows
[i
];
1108 for( sal_uInt16 j
=0; j
<m_nCols
; j
++ )
1110 m_xLayoutInfo
->SetCell(rRow
.GetCell(j
).CreateLayoutInfo(), i
, j
);
1111 SwHTMLTableLayoutCell
* pLayoutCell
= m_xLayoutInfo
->GetCell(i
, j
);
1115 const std::shared_ptr
<SwHTMLTableLayoutCnts
>& rLayoutCnts
=
1116 pLayoutCell
->GetContents();
1117 bExportable
= !rLayoutCnts
||
1118 (rLayoutCnts
->GetStartNode() && !rLayoutCnts
->GetNext());
1123 m_xLayoutInfo
->SetExportable( bExportable
);
1125 for( i
=0; i
<m_nCols
; i
++ )
1126 m_xLayoutInfo
->SetColumn(m_aColumns
[i
].CreateLayoutInfo(), i
);
1128 return m_xLayoutInfo
;
1131 inline void HTMLTable::SetCaption( const SwStartNode
*pStNd
, bool bTop
)
1133 m_pCaptionStartNode
= pStNd
;
1134 m_bTopCaption
= bTop
;
1137 void HTMLTable::FixRowSpan( sal_uInt16 nRow
, sal_uInt16 nCol
,
1138 const HTMLTableCnts
*pCnts
)
1140 sal_uInt16 nRowSpan
=1;
1143 HTMLTableCell
& rCell
= GetCell(nRow
, nCol
);
1144 if (rCell
.GetContents().get() != pCnts
)
1146 rCell
.SetRowSpan(nRowSpan
);
1148 m_xLayoutInfo
->GetCell(nRow
,nCol
)->SetRowSpan(nRowSpan
);
1155 void HTMLTable::ProtectRowSpan( sal_uInt16 nRow
, sal_uInt16 nCol
, sal_uInt16 nRowSpan
)
1157 for( sal_uInt16 i
=0; i
<nRowSpan
; i
++ )
1159 GetCell(nRow
+i
,nCol
).SetProtected();
1161 m_xLayoutInfo
->GetCell(nRow
+i
,nCol
)->SetProtected();
1165 // Search the SwStartNode of the last used predecessor box
1166 const SwStartNode
* HTMLTable::GetPrevBoxStartNode( sal_uInt16 nRow
, sal_uInt16 nCol
) const
1168 const HTMLTableCnts
*pPrevCnts
= nullptr;
1172 // always the predecessor cell
1174 pPrevCnts
= GetCell(0, nCol
- 1).GetContents().get();
1176 return m_pPrevStartNode
;
1178 else if( USHRT_MAX
==nRow
&& USHRT_MAX
==nCol
)
1179 // contents of preceding cell
1180 pPrevCnts
= GetCell(m_nRows
- 1, m_nCols
- 1).GetContents().get();
1184 const HTMLTableRow
& rPrevRow
= m_aRows
[nRow
-1];
1186 // maybe a cell in the current row
1191 if( 1 == rPrevRow
.GetCell(i
).GetRowSpan() )
1193 pPrevCnts
= GetCell(nRow
, i
).GetContents().get();
1198 // otherwise the last filled cell of the row before
1202 while( !pPrevCnts
&& i
)
1205 pPrevCnts
= rPrevRow
.GetCell(i
).GetContents().get();
1209 OSL_ENSURE( pPrevCnts
, "No previous filled cell found" );
1212 pPrevCnts
= GetCell(0, 0).GetContents().get();
1214 return m_pPrevStartNode
;
1217 while( pPrevCnts
->Next() )
1218 pPrevCnts
= pPrevCnts
->Next();
1220 const SwStartNode
* pRet
= pPrevCnts
->GetStartNode();
1223 HTMLTable
* pTable
= pPrevCnts
->GetTable().get();
1226 return pTable
->GetPrevBoxStartNode(USHRT_MAX
, USHRT_MAX
);
1229 sal_uInt16
HTMLTable::GetTopCellSpace( sal_uInt16 nRow
) const
1231 sal_uInt16 nSpace
= m_nCellPadding
;
1235 nSpace
+= m_nBorder
+ m_nCellSpacing
;
1241 sal_uInt16
HTMLTable::GetBottomCellSpace( sal_uInt16 nRow
, sal_uInt16 nRowSpan
) const
1243 sal_uInt16 nSpace
= m_nCellSpacing
+ m_nCellPadding
;
1245 if( nRow
+nRowSpan
== m_nRows
)
1247 nSpace
= nSpace
+ m_nBorder
;
1253 void HTMLTable::FixFrameFormat( SwTableBox
*pBox
,
1254 sal_uInt16 nRow
, sal_uInt16 nCol
,
1255 sal_uInt16 nRowSpan
, sal_uInt16 nColSpan
,
1256 bool bFirstPara
, bool bLastPara
) const
1258 SwFrameFormat
*pFrameFormat
= nullptr; // frame::Frame format
1259 sal_Int16 eVOri
= text::VertOrientation::NONE
;
1260 const SvxBrushItem
*pBGBrushItem
= nullptr; // background
1261 std::shared_ptr
<SvxBoxItem
> pBoxItem
;
1262 bool bTopLine
= false, bBottomLine
= false, bLastBottomLine
= false;
1263 bool bReUsable
= false; // Format reusable?
1264 sal_uInt16 nEmptyRows
= 0;
1265 bool bHasNumFormat
= false;
1266 bool bHasValue
= false;
1267 sal_uInt32 nNumFormat
= 0;
1268 double nValue
= 0.0;
1270 const HTMLTableColumn
& rColumn
= m_aColumns
[nCol
];
1272 if( pBox
->GetSttNd() )
1274 // Determine background color/graphic
1275 const HTMLTableCell
& rCell
= GetCell(nRow
, nCol
);
1276 pBoxItem
= rCell
.GetBoxItem();
1277 pBGBrushItem
= rCell
.GetBGBrush().get();
1280 // If a cell spans multiple rows, a background to that row should be copied to the cell.
1283 pBGBrushItem
= m_aRows
[nRow
].GetBGBrush().get();
1287 bTopLine
= 0==nRow
&& m_bTopBorder
&& bFirstPara
;
1288 if (m_aRows
[nRow
+nRowSpan
-1].GetBottomBorder() && bLastPara
)
1290 nEmptyRows
= m_aRows
[nRow
+nRowSpan
-1].GetEmptyRows();
1291 if( nRow
+nRowSpan
== m_nRows
)
1292 bLastBottomLine
= true;
1297 eVOri
= rCell
.GetVertOri();
1298 bHasNumFormat
= rCell
.GetNumFormat( nNumFormat
);
1300 bHasValue
= rCell
.GetValue( nValue
);
1302 if( nColSpan
==1 && !bTopLine
&& !bLastBottomLine
&& !nEmptyRows
&&
1303 !pBGBrushItem
&& !bHasNumFormat
&& !pBoxItem
)
1305 pFrameFormat
= rColumn
.GetFrameFormat( bBottomLine
, eVOri
);
1306 bReUsable
= !pFrameFormat
;
1312 pFrameFormat
= pBox
->ClaimFrameFormat();
1314 // calculate width of the box
1315 SwTwips nFrameWidth
= static_cast<SwTwips
>(m_xLayoutInfo
->GetColumn(nCol
)
1316 ->GetRelColWidth());
1317 for( sal_uInt16 i
=1; i
<nColSpan
; i
++ )
1318 nFrameWidth
+= static_cast<SwTwips
>(m_xLayoutInfo
->GetColumn(nCol
+i
)
1319 ->GetRelColWidth());
1321 // Only set the border on edit boxes.
1322 // On setting the upper and lower border, keep in mind if
1323 // it's the first or the last paragraph of the cell
1324 if( pBox
->GetSttNd() )
1326 bool bSet
= (m_nCellPadding
> 0);
1328 SvxBoxItem
aBoxItem( RES_BOX
);
1329 tools::Long nInnerFrameWidth
= nFrameWidth
;
1333 aBoxItem
.SetLine( &m_aTopBorderLine
, SvxBoxItemLine::TOP
);
1336 if( bLastBottomLine
)
1338 aBoxItem
.SetLine( &m_aBottomBorderLine
, SvxBoxItemLine::BOTTOM
);
1341 else if( bBottomLine
)
1343 if( nEmptyRows
&& !m_aBorderLine
.GetInWidth() )
1345 // For now, empty rows can only be emulated by thick lines, if it's a single line
1346 SvxBorderLine
aThickBorderLine( m_aBorderLine
);
1348 sal_uInt16 nBorderWidth
= m_aBorderLine
.GetOutWidth();
1349 nBorderWidth
*= (nEmptyRows
+ 1);
1350 aThickBorderLine
.SetBorderLineStyle(SvxBorderLineStyle::SOLID
);
1351 aThickBorderLine
.SetWidth( nBorderWidth
);
1352 aBoxItem
.SetLine( &aThickBorderLine
, SvxBoxItemLine::BOTTOM
);
1356 aBoxItem
.SetLine( &m_aBorderLine
, SvxBoxItemLine::BOTTOM
);
1360 if (m_aColumns
[nCol
].m_bLeftBorder
)
1362 const SvxBorderLine
& rBorderLine
=
1363 0==nCol
? m_aLeftBorderLine
: m_aBorderLine
;
1364 aBoxItem
.SetLine( &rBorderLine
, SvxBoxItemLine::LEFT
);
1365 nInnerFrameWidth
-= GetBorderWidth( rBorderLine
);
1368 if( m_bRightBorder
)
1370 aBoxItem
.SetLine( &m_aRightBorderLine
, SvxBoxItemLine::RIGHT
);
1371 nInnerFrameWidth
-= GetBorderWidth( m_aRightBorderLine
);
1377 pFrameFormat
->SetFormatAttr( *pBoxItem
);
1381 // BorderDist is not part of a cell with fixed width
1382 sal_uInt16 nBDist
= static_cast< sal_uInt16
>(
1383 (2*m_nCellPadding
<= nInnerFrameWidth
) ? m_nCellPadding
1384 : (nInnerFrameWidth
/ 2) );
1385 // We only set the item if there's a border or a border distance
1386 // If the latter is missing, there's gonna be a border and we'll have to set the distance
1387 aBoxItem
.SetAllDistances(nBDist
? nBDist
: MIN_BORDER_DIST
);
1388 pFrameFormat
->SetFormatAttr( aBoxItem
);
1391 pFrameFormat
->ResetFormatAttr( RES_BOX
);
1395 pFrameFormat
->SetFormatAttr( *pBGBrushItem
);
1398 pFrameFormat
->ResetFormatAttr( RES_BACKGROUND
);
1400 // Only set format if there's a value or the box is empty
1401 if( bHasNumFormat
&& (bHasValue
|| pBox
->IsEmpty()) )
1403 bool bLock
= pFrameFormat
->GetDoc()->GetNumberFormatter()
1404 ->IsTextFormat( nNumFormat
);
1405 SfxItemSet
aItemSet( *pFrameFormat
->GetAttrSet().GetPool(),
1406 svl::Items
<RES_BOXATR_FORMAT
, RES_BOXATR_VALUE
>{} );
1407 SvxAdjust eAdjust
= SvxAdjust::End
;
1408 SwContentNode
*pCNd
= nullptr;
1411 const SwStartNode
*pSttNd
= pBox
->GetSttNd();
1412 pCNd
= pSttNd
->GetNodes()[pSttNd
->GetIndex()+1]
1414 const SfxPoolItem
*pItem
;
1415 if( pCNd
&& pCNd
->HasSwAttrSet() &&
1416 SfxItemState::SET
==pCNd
->GetpSwAttrSet()->GetItemState(
1417 RES_PARATR_ADJUST
, false, &pItem
) )
1419 eAdjust
= static_cast<const SvxAdjustItem
*>(pItem
)
1423 aItemSet
.Put( SwTableBoxNumFormat(nNumFormat
) );
1425 aItemSet
.Put( SwTableBoxValue(nValue
) );
1428 pFrameFormat
->LockModify();
1429 pFrameFormat
->SetFormatAttr( aItemSet
);
1431 pFrameFormat
->UnlockModify();
1432 else if( pCNd
&& SvxAdjust::End
!= eAdjust
)
1434 SvxAdjustItem
aAdjItem( eAdjust
, RES_PARATR_ADJUST
);
1435 pCNd
->SetAttr( aAdjItem
);
1439 pFrameFormat
->ResetFormatAttr( RES_BOXATR_FORMAT
);
1441 OSL_ENSURE( eVOri
!= text::VertOrientation::TOP
, "text::VertOrientation::TOP is not allowed!" );
1442 if( text::VertOrientation::NONE
!= eVOri
)
1444 pFrameFormat
->SetFormatAttr( SwFormatVertOrient( 0, eVOri
) );
1447 pFrameFormat
->ResetFormatAttr( RES_VERT_ORIENT
);
1450 const_cast<HTMLTableColumn
&>(rColumn
).SetFrameFormat(pFrameFormat
, bBottomLine
, eVOri
);
1454 pFrameFormat
->ResetFormatAttr( RES_BOX
);
1455 pFrameFormat
->ResetFormatAttr( RES_BACKGROUND
);
1456 pFrameFormat
->ResetFormatAttr( RES_VERT_ORIENT
);
1457 pFrameFormat
->ResetFormatAttr( RES_BOXATR_FORMAT
);
1460 if (m_pParser
->IsReqIF())
1462 // ReqIF case, cells would have no formatting. Apply the default
1463 // table autoformat on them, so imported and UI-created tables look
1465 SwTableAutoFormatTable
& rTable
= m_pParser
->GetDoc()->GetTableStyles();
1466 SwTableAutoFormat
* pTableFormat
= rTable
.FindAutoFormat(
1467 SwStyleNameMapper::GetUIName(RES_POOLTABLESTYLE_DEFAULT
, OUString()));
1470 sal_uInt8 nPos
= SwTableAutoFormat::CountPos(nCol
, m_nCols
, nRow
, m_nRows
);
1471 pTableFormat
->UpdateToSet(nPos
, m_nRows
==1, m_nCols
==1,
1472 const_cast<SfxItemSet
&>(static_cast<SfxItemSet
const&>(
1473 pFrameFormat
->GetAttrSet())),
1474 SwTableAutoFormatUpdateFlags::Box
,
1475 pFrameFormat
->GetDoc()->GetNumberFormatter());
1481 OSL_ENSURE( pBox
->GetSttNd() ||
1482 SfxItemState::SET
!=pFrameFormat
->GetAttrSet().GetItemState(
1483 RES_VERT_ORIENT
, false ),
1484 "Box without content has vertical orientation" );
1485 pBox
->ChgFrameFormat( static_cast<SwTableBoxFormat
*>(pFrameFormat
) );
1490 SwTableBox
*HTMLTable::NewTableBox( const SwStartNode
*pStNd
,
1491 SwTableLine
*pUpper
) const
1495 if (m_xBox1
&& m_xBox1
->GetSttNd() == pStNd
)
1497 // If the StartNode is the StartNode of the initially created box, we take that box
1498 pBox
= const_cast<HTMLTable
*>(this)->m_xBox1
.release();
1499 pBox
->SetUpper(pUpper
);
1502 pBox
= new SwTableBox( m_pBoxFormat
, *pStNd
, pUpper
);
1507 static void ResetLineFrameFormatAttrs( SwFrameFormat
*pFrameFormat
)
1509 pFrameFormat
->ResetFormatAttr( RES_FRM_SIZE
);
1510 pFrameFormat
->ResetFormatAttr( RES_BACKGROUND
);
1511 OSL_ENSURE( SfxItemState::SET
!=pFrameFormat
->GetAttrSet().GetItemState(
1512 RES_VERT_ORIENT
, false ),
1513 "Cell has vertical orientation" );
1516 // !!! could be simplified
1517 SwTableLine
*HTMLTable::MakeTableLine( SwTableBox
*pUpper
,
1518 sal_uInt16 nTopRow
, sal_uInt16 nLeftCol
,
1519 sal_uInt16 nBottomRow
, sal_uInt16 nRightCol
)
1522 if (!pUpper
&& 0 == nTopRow
)
1523 pLine
= (m_pSwTable
->GetTabLines())[0];
1525 pLine
= new SwTableLine( m_pLineFrameFormatNoHeight
? m_pLineFrameFormatNoHeight
1529 const HTMLTableRow
& rTopRow
= m_aRows
[nTopRow
];
1530 sal_uInt16 nRowHeight
= rTopRow
.GetHeight();
1531 const SvxBrushItem
*pBGBrushItem
= nullptr;
1532 if (nTopRow
> 0 || nBottomRow
< m_nRows
)
1534 // It doesn't make sense to set a color on a line,
1535 // if it's the outermost and simultaneously sole line of a table in a table
1536 pBGBrushItem
= rTopRow
.GetBGBrush().get();
1538 if( nTopRow
==nBottomRow
-1 && (nRowHeight
|| pBGBrushItem
) )
1540 SwTableLineFormat
*pFrameFormat
= static_cast<SwTableLineFormat
*>(pLine
->ClaimFrameFormat());
1541 ResetLineFrameFormatAttrs( pFrameFormat
);
1545 // set table height. Since it's a minimum height it can be calculated like in Netscape,
1546 // so without considering the actual border width
1547 nRowHeight
+= GetTopCellSpace( nTopRow
) +
1548 GetBottomCellSpace( nTopRow
, 1 );
1550 pFrameFormat
->SetFormatAttr( SwFormatFrameSize( SwFrameSize::Minimum
, 0, nRowHeight
) );
1555 pFrameFormat
->SetFormatAttr( *pBGBrushItem
);
1559 else if( !m_pLineFrameFormatNoHeight
)
1561 // else, we'll have to remove the height from the attribute and remember the format
1562 m_pLineFrameFormatNoHeight
= static_cast<SwTableLineFormat
*>(pLine
->ClaimFrameFormat());
1564 ResetLineFrameFormatAttrs( m_pLineFrameFormatNoHeight
);
1567 SwTableBoxes
& rBoxes
= pLine
->GetTabBoxes();
1569 sal_uInt16 nStartCol
= nLeftCol
;
1570 while( nStartCol
<nRightCol
)
1572 sal_uInt16 nCol
= nStartCol
;
1573 sal_uInt16 nSplitCol
= nRightCol
;
1574 bool bSplitted
= false;
1577 OSL_ENSURE( nCol
< nRightCol
, "Gone too far" );
1579 HTMLTableCell
& rCell
= GetCell(nTopRow
,nCol
);
1580 const bool bSplit
= 1 == rCell
.GetColSpan();
1582 OSL_ENSURE((nCol
!= nRightCol
-1) || bSplit
, "Split-Flag wrong");
1585 SwTableBox
* pBox
= nullptr;
1586 HTMLTableCell
& rCell2
= GetCell(nTopRow
, nStartCol
);
1587 if (rCell2
.GetColSpan() == (nCol
+1-nStartCol
))
1589 // The HTML tables represent a box. So we need to split behind that box
1590 nSplitCol
= nCol
+ 1;
1592 sal_Int32 nBoxRowSpan
= rCell2
.GetRowSpan();
1593 if (!rCell2
.GetContents() || rCell2
.IsCovered())
1595 if (rCell2
.IsCovered())
1596 nBoxRowSpan
= -1 * nBoxRowSpan
;
1598 const SwStartNode
* pPrevStartNd
=
1599 GetPrevBoxStartNode( nTopRow
, nStartCol
);
1600 auto xCnts
= std::make_shared
<HTMLTableCnts
>(
1601 m_pParser
->InsertTableSection(pPrevStartNd
));
1602 const std::shared_ptr
<SwHTMLTableLayoutCnts
> xCntsLayoutInfo
=
1603 xCnts
->CreateLayoutInfo();
1605 rCell2
.SetContents(xCnts
);
1606 SwHTMLTableLayoutCell
*pCurrCell
= m_xLayoutInfo
->GetCell(nTopRow
, nStartCol
);
1607 pCurrCell
->SetContents(xCntsLayoutInfo
);
1608 if( nBoxRowSpan
< 0 )
1609 pCurrCell
->SetRowSpan( 0 );
1611 // check COLSPAN if needed
1612 for( sal_uInt16 j
=nStartCol
+1; j
<nSplitCol
; j
++ )
1614 GetCell(nTopRow
, j
).SetContents(xCnts
);
1615 m_xLayoutInfo
->GetCell(nTopRow
, j
)
1616 ->SetContents(xCntsLayoutInfo
);
1620 pBox
= MakeTableBox(pLine
, rCell2
.GetContents().get(),
1622 nBottomRow
, nSplitCol
);
1624 if (1 != nBoxRowSpan
&& pBox
)
1625 pBox
->setRowSpan( nBoxRowSpan
);
1630 OSL_ENSURE( pBox
, "Colspan trouble" );
1633 rBoxes
.push_back( pBox
);
1637 nStartCol
= nSplitCol
;
1643 SwTableBox
*HTMLTable::MakeTableBox( SwTableLine
*pUpper
,
1644 HTMLTableCnts
*pCnts
,
1645 sal_uInt16 nTopRow
, sal_uInt16 nLeftCol
,
1646 sal_uInt16 nBottomRow
, sal_uInt16 nRightCol
)
1649 sal_uInt16 nColSpan
= nRightCol
- nLeftCol
;
1650 sal_uInt16 nRowSpan
= nBottomRow
- nTopRow
;
1652 if( !pCnts
->Next() )
1654 // just one content section
1655 if( pCnts
->GetStartNode() )
1657 // ... that's not a table
1658 pBox
= NewTableBox( pCnts
->GetStartNode(), pUpper
);
1659 pCnts
->SetTableBox( pBox
);
1661 else if (HTMLTable
* pTable
= pCnts
->GetTable().get())
1663 pTable
->InheritVertBorders( this, nLeftCol
,
1664 nRightCol
-nLeftCol
);
1665 // ... that's a table. We'll build a new box and put the rows of the table
1666 // in the rows of the box
1667 pBox
= new SwTableBox( m_pBoxFormat
, 0, pUpper
);
1668 sal_uInt16 nAbs
, nRel
;
1669 m_xLayoutInfo
->GetAvail( nLeftCol
, nColSpan
, nAbs
, nRel
);
1670 sal_uInt16 nLSpace
= m_xLayoutInfo
->GetLeftCellSpace( nLeftCol
, nColSpan
);
1671 sal_uInt16 nRSpace
= m_xLayoutInfo
->GetRightCellSpace( nLeftCol
, nColSpan
);
1672 sal_uInt16 nInhSpace
= m_xLayoutInfo
->GetInhCellSpace( nLeftCol
, nColSpan
);
1673 pCnts
->GetTable()->MakeTable( pBox
, nAbs
, nRel
, nLSpace
, nRSpace
,
1683 // multiple content sections: we'll build a box with rows
1684 pBox
= new SwTableBox( m_pBoxFormat
, 0, pUpper
);
1685 SwTableLines
& rLines
= pBox
->GetTabLines();
1686 bool bFirstPara
= true;
1690 if( pCnts
->GetStartNode() )
1692 // normal paragraphs are gonna be boxes in a row
1693 SwTableLine
*pLine
=
1694 new SwTableLine( m_pLineFrameFormatNoHeight
? m_pLineFrameFormatNoHeight
1695 : m_pLineFormat
, 0, pBox
);
1696 if( !m_pLineFrameFormatNoHeight
)
1698 // If there's no line format without height yet, we can use that one
1699 m_pLineFrameFormatNoHeight
= static_cast<SwTableLineFormat
*>(pLine
->ClaimFrameFormat());
1701 ResetLineFrameFormatAttrs( m_pLineFrameFormatNoHeight
);
1704 SwTableBox
* pCntBox
= NewTableBox( pCnts
->GetStartNode(),
1706 pCnts
->SetTableBox( pCntBox
);
1707 FixFrameFormat( pCntBox
, nTopRow
, nLeftCol
, nRowSpan
, nColSpan
,
1708 bFirstPara
, nullptr==pCnts
->Next() );
1709 pLine
->GetTabBoxes().push_back( pCntBox
);
1711 rLines
.push_back( pLine
);
1715 pCnts
->GetTable()->InheritVertBorders( this, nLeftCol
,
1716 nRightCol
-nLeftCol
);
1717 // Tables are entered directly
1718 sal_uInt16 nAbs
, nRel
;
1719 m_xLayoutInfo
->GetAvail( nLeftCol
, nColSpan
, nAbs
, nRel
);
1720 sal_uInt16 nLSpace
= m_xLayoutInfo
->GetLeftCellSpace( nLeftCol
,
1722 sal_uInt16 nRSpace
= m_xLayoutInfo
->GetRightCellSpace( nLeftCol
,
1724 sal_uInt16 nInhSpace
= m_xLayoutInfo
->GetInhCellSpace( nLeftCol
, nColSpan
);
1725 pCnts
->GetTable()->MakeTable( pBox
, nAbs
, nRel
, nLSpace
,
1726 nRSpace
, nInhSpace
);
1729 pCnts
= pCnts
->Next();
1734 FixFrameFormat( pBox
, nTopRow
, nLeftCol
, nRowSpan
, nColSpan
);
1739 void HTMLTable::InheritBorders( const HTMLTable
*pParent
,
1740 sal_uInt16 nRow
, sal_uInt16 nCol
,
1741 sal_uInt16 nRowSpan
,
1742 bool bFirstPara
, bool bLastPara
)
1744 OSL_ENSURE( m_nRows
>0 && m_nCols
>0 && m_nCurrentRow
==m_nRows
,
1745 "Was CloseTable not called?" );
1747 // The child table needs a border, if the surrounding cell has a margin on that side.
1748 // The upper/lower border is only set if the table is the first/last paragraph in that cell
1749 // It can't be determined if a border for that table is needed or possible for the left or right side,
1750 // since that's depending on if filler cells are gonna be added. We'll only collect info for now
1752 if( 0==nRow
&& pParent
->m_bTopBorder
&& bFirstPara
)
1754 m_bTopBorder
= true;
1755 m_bFillerTopBorder
= true; // fillers get a border too
1756 m_aTopBorderLine
= pParent
->m_aTopBorderLine
;
1758 if (pParent
->m_aRows
[nRow
+nRowSpan
-1].GetBottomBorder() && bLastPara
)
1760 m_aRows
[m_nRows
-1].SetBottomBorder(true);
1761 m_bFillerBottomBorder
= true; // fillers get a border too
1762 m_aBottomBorderLine
=
1763 nRow
+nRowSpan
==pParent
->m_nRows
? pParent
->m_aBottomBorderLine
1764 : pParent
->m_aBorderLine
;
1767 // The child table mustn't get an upper or lower border, if that's already done by the surrounding table
1768 // It can get an upper border if the table is not the first paragraph in that cell
1769 m_bTopAllowed
= ( !bFirstPara
|| (pParent
->m_bTopAllowed
&&
1770 (0==nRow
|| !pParent
->m_aRows
[nRow
-1].GetBottomBorder())) );
1772 // The child table has to inherit the color of the cell it's contained in, if it doesn't have one
1773 const SvxBrushItem
*pInhBG
= pParent
->GetCell(nRow
, nCol
).GetBGBrush().get();
1774 if( !pInhBG
&& pParent
!= this &&
1775 pParent
->GetCell(nRow
,nCol
).GetRowSpan() == pParent
->m_nRows
)
1777 // the whole surrounding table is a table in a table and consists only of a single line
1778 // that's gonna be GC-ed (correctly). That's why the background of that line is copied.
1779 pInhBG
= pParent
->m_aRows
[nRow
].GetBGBrush().get();
1781 pInhBG
= pParent
->GetBGBrush().get();
1783 pInhBG
= pParent
->GetInhBGBrush().get();
1786 m_xInheritedBackgroundBrush
.reset(new SvxBrushItem(*pInhBG
));
1789 void HTMLTable::InheritVertBorders( const HTMLTable
*pParent
,
1790 sal_uInt16 nCol
, sal_uInt16 nColSpan
)
1792 sal_uInt16 nInhLeftBorderWidth
= 0;
1793 sal_uInt16 nInhRightBorderWidth
= 0;
1795 if( nCol
+nColSpan
==pParent
->m_nCols
&& pParent
->m_bRightBorder
)
1797 m_bInheritedRightBorder
= true; // just remember for now
1798 m_aInheritedRightBorderLine
= pParent
->m_aRightBorderLine
;
1799 nInhRightBorderWidth
=
1800 GetBorderWidth( m_aInheritedRightBorderLine
, true ) + MIN_BORDER_DIST
;
1803 if (pParent
->m_aColumns
[nCol
].m_bLeftBorder
)
1805 m_bInheritedLeftBorder
= true; // just remember for now
1806 m_aInheritedLeftBorderLine
= 0==nCol
? pParent
->m_aLeftBorderLine
1807 : pParent
->m_aBorderLine
;
1808 nInhLeftBorderWidth
=
1809 GetBorderWidth( m_aInheritedLeftBorderLine
, true ) + MIN_BORDER_DIST
;
1812 if( !m_bInheritedLeftBorder
&& (m_bFillerTopBorder
|| m_bFillerBottomBorder
) )
1813 nInhLeftBorderWidth
= 2 * MIN_BORDER_DIST
;
1814 if( !m_bInheritedRightBorder
&& (m_bFillerTopBorder
|| m_bFillerBottomBorder
) )
1815 nInhRightBorderWidth
= 2 * MIN_BORDER_DIST
;
1816 m_xLayoutInfo
->SetInhBorderWidths( nInhLeftBorderWidth
,
1817 nInhRightBorderWidth
);
1819 m_bRightAllowed
= ( pParent
->m_bRightAllowed
&&
1820 (nCol
+nColSpan
==pParent
->m_nCols
||
1821 !pParent
->m_aColumns
[nCol
+nColSpan
].m_bLeftBorder
) );
1824 void HTMLTable::SetBorders()
1827 for( i
=1; i
<m_nCols
; i
++ )
1828 if( HTMLTableRules::All
==m_eRules
|| HTMLTableRules::Cols
==m_eRules
||
1829 ((HTMLTableRules::Rows
==m_eRules
|| HTMLTableRules::Groups
==m_eRules
) &&
1830 m_aColumns
[i
-1].IsEndOfGroup()))
1832 m_aColumns
[i
].m_bLeftBorder
= true;
1835 for( i
=0; i
<m_nRows
-1; i
++ )
1836 if( HTMLTableRules::All
==m_eRules
|| HTMLTableRules::Rows
==m_eRules
||
1837 ((HTMLTableRules::Cols
==m_eRules
|| HTMLTableRules::Groups
==m_eRules
) &&
1838 m_aRows
[i
].IsEndOfGroup()))
1840 m_aRows
[i
].SetBottomBorder(true);
1843 if( m_bTopAllowed
&& (HTMLTableFrame::Above
==m_eFrame
|| HTMLTableFrame::HSides
==m_eFrame
||
1844 HTMLTableFrame::Box
==m_eFrame
) )
1845 m_bTopBorder
= true;
1846 if( HTMLTableFrame::Below
==m_eFrame
|| HTMLTableFrame::HSides
==m_eFrame
||
1847 HTMLTableFrame::Box
==m_eFrame
)
1849 m_aRows
[m_nRows
-1].SetBottomBorder(true);
1851 if( HTMLTableFrame::RHS
==m_eFrame
|| HTMLTableFrame::VSides
==m_eFrame
||
1852 HTMLTableFrame::Box
==m_eFrame
)
1853 m_bRightBorder
= true;
1854 if( HTMLTableFrame::LHS
==m_eFrame
|| HTMLTableFrame::VSides
==m_eFrame
|| HTMLTableFrame::Box
==m_eFrame
)
1856 m_aColumns
[0].m_bLeftBorder
= true;
1859 for( i
=0; i
<m_nRows
; i
++ )
1861 HTMLTableRow
& rRow
= m_aRows
[i
];
1862 for (sal_uInt16 j
=0; j
<m_nCols
; ++j
)
1864 HTMLTableCell
& rCell
= rRow
.GetCell(j
);
1865 if (rCell
.GetContents())
1867 HTMLTableCnts
*pCnts
= rCell
.GetContents().get();
1868 bool bFirstPara
= true;
1871 HTMLTable
*pTable
= pCnts
->GetTable().get();
1872 if( pTable
&& !pTable
->BordersSet() )
1874 pTable
->InheritBorders(this, i
, j
,
1877 nullptr==pCnts
->Next());
1878 pTable
->SetBorders();
1881 pCnts
= pCnts
->Next();
1887 m_bBordersSet
= true;
1890 sal_uInt16
HTMLTable::GetBorderWidth( const SvxBorderLine
& rBLine
,
1891 bool bWithDistance
) const
1893 sal_uInt16 nBorderWidth
= rBLine
.GetWidth();
1896 if( m_nCellPadding
)
1897 nBorderWidth
= nBorderWidth
+ m_nCellPadding
;
1898 else if( nBorderWidth
)
1899 nBorderWidth
= nBorderWidth
+ MIN_BORDER_DIST
;
1902 return nBorderWidth
;
1905 const HTMLTableCell
& HTMLTable::GetCell(sal_uInt16 nRow
, sal_uInt16 nCell
) const
1907 OSL_ENSURE(nRow
< m_aRows
.size(), "invalid row index in HTML table");
1908 return m_aRows
[nRow
].GetCell(nCell
);
1911 SvxAdjust
HTMLTable::GetInheritedAdjust() const
1913 SvxAdjust eAdjust
= (m_nCurrentColumn
<m_nCols
? m_aColumns
[m_nCurrentColumn
].GetAdjust()
1915 if( SvxAdjust::End
==eAdjust
)
1916 eAdjust
= m_aRows
[m_nCurrentRow
].GetAdjust();
1921 sal_Int16
HTMLTable::GetInheritedVertOri() const
1923 // text::VertOrientation::TOP is default!
1924 sal_Int16 eVOri
= m_aRows
[m_nCurrentRow
].GetVertOri();
1925 if( text::VertOrientation::TOP
==eVOri
&& m_nCurrentColumn
<m_nCols
)
1926 eVOri
= m_aColumns
[m_nCurrentColumn
].GetVertOri();
1927 if( text::VertOrientation::TOP
==eVOri
)
1928 eVOri
= m_eVertOrientation
;
1930 OSL_ENSURE( m_eVertOrientation
!= text::VertOrientation::TOP
, "text::VertOrientation::TOP is not allowed!" );
1934 void HTMLTable::InsertCell( std::shared_ptr
<HTMLTableCnts
> const& rCnts
,
1935 sal_uInt16 nRowSpan
, sal_uInt16 nColSpan
,
1936 sal_uInt16 nCellWidth
, bool bRelWidth
, sal_uInt16 nCellHeight
,
1937 sal_Int16 eVertOrient
, std::shared_ptr
<SvxBrushItem
> const& rBGBrushItem
,
1938 std::shared_ptr
<SvxBoxItem
> const& rBoxItem
,
1939 bool bHasNumFormat
, sal_uInt32 nNumFormat
,
1940 bool bHasValue
, double nValue
, bool bNoWrap
)
1942 if( !nRowSpan
|| static_cast<sal_uInt32
>(m_nCurrentRow
) + nRowSpan
> USHRT_MAX
)
1945 if( !nColSpan
|| static_cast<sal_uInt32
>(m_nCurrentColumn
) + nColSpan
> USHRT_MAX
)
1948 sal_uInt16 nColsReq
= m_nCurrentColumn
+ nColSpan
;
1949 sal_uInt16 nRowsReq
= m_nCurrentRow
+ nRowSpan
;
1952 // if we need more columns than we currently have, we need to add cells for all rows
1953 if( m_nCols
< nColsReq
)
1955 m_aColumns
.resize(nColsReq
);
1956 for( i
=0; i
<m_nRows
; i
++ )
1957 m_aRows
[i
].Expand( nColsReq
, i
<m_nCurrentRow
);
1959 OSL_ENSURE(m_aColumns
.size() == m_nCols
,
1960 "wrong number of columns after expanding");
1962 if( nColsReq
> m_nFilledColumns
)
1963 m_nFilledColumns
= nColsReq
;
1965 // if we need more rows than we currently have, we need to add cells
1966 if( m_nRows
< nRowsReq
)
1968 for( i
=m_nRows
; i
<nRowsReq
; i
++ )
1969 m_aRows
.emplace_back(m_nCols
);
1971 OSL_ENSURE(m_nRows
== m_aRows
.size(), "wrong number of rows in Insert");
1974 // Check if we have an overlap and could remove that
1975 sal_uInt16 nSpanedCols
= 0;
1976 if( m_nCurrentRow
>0 )
1978 HTMLTableRow
& rCurRow
= m_aRows
[m_nCurrentRow
];
1979 for( i
=m_nCurrentColumn
; i
<nColsReq
; i
++ )
1981 HTMLTableCell
& rCell
= rCurRow
.GetCell(i
);
1982 if (rCell
.GetContents())
1984 // A cell from a row further above overlaps this one.
1985 // Content and colors are coming from that cell and can be overwritten
1986 // or deleted (content) or copied (color) by ProtectRowSpan
1987 nSpanedCols
= i
+ rCell
.GetColSpan();
1988 FixRowSpan( m_nCurrentRow
-1, i
, rCell
.GetContents().get() );
1989 if (rCell
.GetRowSpan() > nRowSpan
)
1990 ProtectRowSpan( nRowsReq
, i
,
1991 rCell
.GetRowSpan()-nRowSpan
);
1994 for( i
=nColsReq
; i
<nSpanedCols
; i
++ )
1996 // These contents are anchored in the row above in any case
1997 HTMLTableCell
& rCell
= rCurRow
.GetCell(i
);
1998 FixRowSpan( m_nCurrentRow
-1, i
, rCell
.GetContents().get() );
1999 ProtectRowSpan( m_nCurrentRow
, i
, rCell
.GetRowSpan() );
2004 for( i
=nColSpan
; i
>0; i
-- )
2006 for( j
=nRowSpan
; j
>0; j
-- )
2008 const bool bCovered
= i
!= nColSpan
|| j
!= nRowSpan
;
2009 GetCell( nRowsReq
-j
, nColsReq
-i
)
2010 .Set( rCnts
, j
, i
, eVertOrient
, rBGBrushItem
, rBoxItem
,
2011 bHasNumFormat
, nNumFormat
, bHasValue
, nValue
, bNoWrap
, bCovered
);
2015 Size
aTwipSz( bRelWidth
? 0 : nCellWidth
, nCellHeight
);
2016 if( (aTwipSz
.Width() || aTwipSz
.Height()) && Application::GetDefaultDevice() )
2018 aTwipSz
= Application::GetDefaultDevice()
2019 ->PixelToLogic( aTwipSz
, MapMode( MapUnit::MapTwip
) );
2022 // Only set width on the first cell!
2025 sal_uInt16 nTmp
= bRelWidth
? nCellWidth
: o3tl::narrowing
<sal_uInt16
>(aTwipSz
.Width());
2026 GetCell( m_nCurrentRow
, m_nCurrentColumn
).SetWidth( nTmp
, bRelWidth
);
2030 if( nCellHeight
&& 1==nRowSpan
)
2032 m_aRows
[m_nCurrentRow
].SetHeight(o3tl::narrowing
<sal_uInt16
>(aTwipSz
.Height()));
2035 // Set the column counter behind the new cells
2036 m_nCurrentColumn
= nColsReq
;
2037 if( nSpanedCols
> m_nCurrentColumn
)
2038 m_nCurrentColumn
= nSpanedCols
;
2040 // and search for the next free cell
2041 while( m_nCurrentColumn
<m_nCols
&& GetCell(m_nCurrentRow
,m_nCurrentColumn
).IsUsed() )
2045 inline void HTMLTable::CloseSection( bool bHead
)
2047 // Close the preceding sections if there's already a row
2048 OSL_ENSURE( m_nCurrentRow
<=m_nRows
, "invalid current row" );
2049 if( m_nCurrentRow
>0 && m_nCurrentRow
<=m_nRows
)
2050 m_aRows
[m_nCurrentRow
-1].SetEndOfGroup();
2052 m_nHeadlineRepeat
= m_nCurrentRow
;
2055 void HTMLTable::OpenRow(SvxAdjust eAdjust
, sal_Int16 eVertOrient
,
2056 std::unique_ptr
<SvxBrushItem
>& rBGBrushItem
)
2058 sal_uInt16 nRowsReq
= m_nCurrentRow
+1;
2060 // create the next row if it's not there already
2061 if( m_nRows
<nRowsReq
)
2063 for( sal_uInt16 i
=m_nRows
; i
<nRowsReq
; i
++ )
2064 m_aRows
.emplace_back(m_nCols
);
2066 OSL_ENSURE( m_nRows
== m_aRows
.size(),
2067 "Row number in OpenRow is wrong" );
2070 HTMLTableRow
& rCurRow
= m_aRows
[m_nCurrentRow
];
2071 rCurRow
.SetAdjust(eAdjust
);
2072 rCurRow
.SetVertOri(eVertOrient
);
2074 m_aRows
[m_nCurrentRow
].SetBGBrush(rBGBrushItem
);
2076 // reset the column counter
2079 // and search for the next free cell
2080 while( m_nCurrentColumn
<m_nCols
&& GetCell(m_nCurrentRow
,m_nCurrentColumn
).IsUsed() )
2084 void HTMLTable::CloseRow( bool bEmpty
)
2086 OSL_ENSURE( m_nCurrentRow
<m_nRows
, "current row after table end" );
2088 // empty cells just get a slightly thicker lower border!
2091 if( m_nCurrentRow
> 0 )
2092 m_aRows
[m_nCurrentRow
-1].IncEmptyRows();
2096 HTMLTableRow
& rRow
= m_aRows
[m_nCurrentRow
];
2098 // modify the COLSPAN of all empty cells at the row end in a way, that they're forming a single cell
2099 // that can be done here (and not earlier) since there's no more cells in that row
2100 sal_uInt16 i
=m_nCols
;
2103 HTMLTableCell
& rCell
= rRow
.GetCell(--i
);
2104 if (!rCell
.GetContents())
2106 sal_uInt16 nColSpan
= m_nCols
-i
;
2108 rCell
.SetColSpan(nColSpan
);
2117 inline void HTMLTable::CloseColGroup( sal_uInt16 nSpan
, sal_uInt16 _nWidth
,
2118 bool bRelWidth
, SvxAdjust eAdjust
,
2119 sal_Int16 eVertOrient
)
2122 InsertCol( nSpan
, _nWidth
, bRelWidth
, eAdjust
, eVertOrient
);
2124 OSL_ENSURE( m_nCurrentColumn
<=m_nCols
, "invalid column" );
2125 if( m_nCurrentColumn
>0 && m_nCurrentColumn
<=m_nCols
)
2126 m_aColumns
[m_nCurrentColumn
-1].SetEndOfGroup();
2129 void HTMLTable::InsertCol( sal_uInt16 nSpan
, sal_uInt16 nColWidth
, bool bRelWidth
,
2130 SvxAdjust eAdjust
, sal_Int16 eVertOrient
)
2132 // #i35143# - no columns, if rows already exist.
2141 sal_uInt16 nColsReq
= m_nCurrentColumn
+ nSpan
;
2143 if( m_nCols
< nColsReq
)
2145 m_aColumns
.resize(nColsReq
);
2149 Size
aTwipSz( bRelWidth
? 0 : nColWidth
, 0 );
2150 if( aTwipSz
.Width() && Application::GetDefaultDevice() )
2152 aTwipSz
= Application::GetDefaultDevice()
2153 ->PixelToLogic( aTwipSz
, MapMode( MapUnit::MapTwip
) );
2156 for( i
=m_nCurrentColumn
; i
<nColsReq
; i
++ )
2158 HTMLTableColumn
& rCol
= m_aColumns
[i
];
2159 sal_uInt16 nTmp
= bRelWidth
? nColWidth
: o3tl::narrowing
<sal_uInt16
>(aTwipSz
.Width());
2160 rCol
.SetWidth( nTmp
, bRelWidth
);
2161 rCol
.SetAdjust( eAdjust
);
2162 rCol
.SetVertOri( eVertOrient
);
2167 m_nCurrentColumn
= nColsReq
;
2170 void HTMLTable::CloseTable()
2174 // The number of table rows is only dependent on the <TR> elements (i.e. nCurRow).
2175 // Rows that are spanned via ROWSPAN behind nCurRow need to be deleted
2176 // and we need to adjust the ROWSPAN in the rows above
2177 if( m_nRows
>m_nCurrentRow
)
2179 HTMLTableRow
& rPrevRow
= m_aRows
[m_nCurrentRow
-1];
2180 for( i
=0; i
<m_nCols
; i
++ )
2182 HTMLTableCell
& rCell
= rPrevRow
.GetCell(i
);
2183 if (rCell
.GetRowSpan() > 1)
2185 FixRowSpan(m_nCurrentRow
-1, i
, rCell
.GetContents().get());
2186 ProtectRowSpan(m_nCurrentRow
, i
, m_aRows
[m_nCurrentRow
].GetCell(i
).GetRowSpan());
2189 for( i
=m_nRows
-1; i
>=m_nCurrentRow
; i
-- )
2190 m_aRows
.erase(m_aRows
.begin() + i
);
2191 m_nRows
= m_nCurrentRow
;
2194 // if the table has no column, we need to add one
2197 m_aColumns
.resize(1);
2198 for( i
=0; i
<m_nRows
; i
++ )
2199 m_aRows
[i
].Expand(1);
2201 m_nFilledColumns
= 1;
2204 // if the table has no row, we need to add one
2207 m_aRows
.emplace_back(m_nCols
);
2212 if( m_nFilledColumns
< m_nCols
)
2214 m_aColumns
.erase(m_aColumns
.begin() + m_nFilledColumns
, m_aColumns
.begin() + m_nCols
);
2215 for( i
=0; i
<m_nRows
; i
++ )
2216 m_aRows
[i
].Shrink( m_nFilledColumns
);
2217 m_nCols
= m_nFilledColumns
;
2221 void HTMLTable::MakeTable_( SwTableBox
*pBox
)
2223 SwTableLines
& rLines
= (pBox
? pBox
->GetTabLines()
2224 : const_cast<SwTable
*>(m_pSwTable
)->GetTabLines() );
2226 for( sal_uInt16 i
=0; i
<m_nRows
; i
++ )
2228 SwTableLine
*pLine
= MakeTableLine( pBox
, i
, 0, i
+1, m_nCols
);
2230 rLines
.push_back( pLine
);
2234 /* How are tables aligned?
2236 first row: without paragraph indents
2237 second row: with paragraph indents
2239 ALIGN= LEFT RIGHT CENTER -
2240 -------------------------------------------------------------------------
2241 xxx for tables with WIDTH=nn% the percentage value is important:
2242 xxx nn = 100 text::HoriOrientation::FULL text::HoriOrientation::FULL text::HoriOrientation::FULL text::HoriOrientation::FULL %
2243 xxx text::HoriOrientation::NONE text::HoriOrientation::NONE text::HoriOrientation::NONE % text::HoriOrientation::NONE %
2244 xxx nn < 100 frame F frame F text::HoriOrientation::CENTER % text::HoriOrientation::LEFT %
2245 xxx frame F frame F text::HoriOrientation::CENTER % text::HoriOrientation::NONE %
2247 for tables with WIDTH=nn% the percentage value is important:
2248 nn = 100 text::HoriOrientation::LEFT text::HoriOrientation::RIGHT text::HoriOrientation::CENTER % text::HoriOrientation::LEFT %
2249 text::HoriOrientation::LEFT_AND text::HoriOrientation::RIGHT text::HoriOrientation::CENTER % text::HoriOrientation::LEFT_AND %
2250 nn < 100 frame F frame F text::HoriOrientation::CENTER % text::HoriOrientation::LEFT %
2251 frame F frame F text::HoriOrientation::CENTER % text::HoriOrientation::NONE %
2253 otherwise the calculated width w
2254 w = avail* text::HoriOrientation::LEFT text::HoriOrientation::RIGHT text::HoriOrientation::CENTER text::HoriOrientation::LEFT
2255 HORI_LEDT_AND text::HoriOrientation::RIGHT text::HoriOrientation::CENTER text::HoriOrientation::LEFT_AND
2256 w < avail frame L frame L text::HoriOrientation::CENTER text::HoriOrientation::LEFT
2257 frame L frame L text::HoriOrientation::CENTER text::HoriOrientation::NONE
2259 xxx *) if for the table no size was specified, always
2260 xxx text::HoriOrientation::FULL is taken
2264 void HTMLTable::MakeTable( SwTableBox
*pBox
, sal_uInt16 nAbsAvail
,
2265 sal_uInt16 nRelAvail
, sal_uInt16 nAbsLeftSpace
,
2266 sal_uInt16 nAbsRightSpace
, sal_uInt16 nInhAbsSpace
)
2268 OSL_ENSURE( m_nRows
>0 && m_nCols
>0 && m_nCurrentRow
==m_nRows
,
2269 "Was CloseTable not called?" );
2271 OSL_ENSURE(m_xLayoutInfo
== nullptr, "Table already has layout info");
2273 // Calculate borders of the table and all contained tables
2276 // Step 1: needed layout structures are created (including tables in tables)
2279 if (!utl::ConfigManager::IsFuzzing()) // skip slow path for fuzzing
2281 // Step 2: the minimal and maximal column width is calculated
2282 // (including tables in tables). Since we don't have boxes yet,
2283 // we'll work on the start nodes
2284 m_xLayoutInfo
->AutoLayoutPass1();
2286 // Step 3: the actual column widths of this table are calculated (not tables in tables)
2287 // We need this now to decide if we need filler cells
2288 // (Pass1 was needed because of this as well)
2289 m_xLayoutInfo
->AutoLayoutPass2( nAbsAvail
, nRelAvail
, nAbsLeftSpace
,
2290 nAbsRightSpace
, nInhAbsSpace
);
2293 // Set adjustment for the top table
2297 // The table should go in a text frame and it's narrower than the
2298 // available space and not 100% wide. So it gets a border
2299 eHoriOri
= m_bPercentWidth
? text::HoriOrientation::FULL
: text::HoriOrientation::LEFT
;
2301 else switch (m_eTableAdjust
)
2303 // The table either fits the page but shouldn't get a text frame,
2304 // or it's wider than the page so it doesn't need a text frame
2306 case SvxAdjust::Right
:
2307 // Don't be considerate of the right margin in right-adjusted tables
2308 eHoriOri
= text::HoriOrientation::RIGHT
;
2310 case SvxAdjust::Center
:
2311 // Centred tables are not considerate of margins
2312 eHoriOri
= text::HoriOrientation::CENTER
;
2314 case SvxAdjust::Left
:
2316 // left-adjusted tables are only considerate of the left margin
2317 eHoriOri
= m_nLeftMargin
? text::HoriOrientation::LEFT_AND_WIDTH
: text::HoriOrientation::LEFT
;
2323 SAL_WARN("sw.html", "no table");
2327 // get the table format and adapt it
2328 SwFrameFormat
*pFrameFormat
= m_pSwTable
->GetFrameFormat();
2329 pFrameFormat
->SetFormatAttr( SwFormatHoriOrient(0, eHoriOri
) );
2330 if (text::HoriOrientation::LEFT_AND_WIDTH
== eHoriOri
)
2332 OSL_ENSURE( m_nLeftMargin
|| m_nRightMargin
,
2333 "There are still leftovers from relative margins" );
2335 // The right margin will be ignored anyway.
2336 SvxLRSpaceItem
aLRItem( m_pSwTable
->GetFrameFormat()->GetLRSpace() );
2337 aLRItem
.SetLeft( m_nLeftMargin
);
2338 aLRItem
.SetRight( m_nRightMargin
);
2339 pFrameFormat
->SetFormatAttr( aLRItem
);
2342 if (m_bPercentWidth
&& text::HoriOrientation::FULL
!= eHoriOri
)
2344 pFrameFormat
->LockModify();
2345 SwFormatFrameSize
aFrameSize( pFrameFormat
->GetFrameSize() );
2346 aFrameSize
.SetWidthPercent( static_cast<sal_uInt8
>(m_nWidth
) );
2347 pFrameFormat
->SetFormatAttr( aFrameSize
);
2348 pFrameFormat
->UnlockModify();
2351 // get the default line and box format
2352 // remember the first box and unlist it from the first row
2353 SwTableLine
*pLine1
= (m_pSwTable
->GetTabLines())[0];
2354 m_xBox1
.reset((pLine1
->GetTabBoxes())[0]);
2355 pLine1
->GetTabBoxes().erase(pLine1
->GetTabBoxes().begin());
2357 m_pLineFormat
= static_cast<SwTableLineFormat
*>(pLine1
->GetFrameFormat());
2358 m_pBoxFormat
= static_cast<SwTableBoxFormat
*>(m_xBox1
->GetFrameFormat());
2362 // Finally, we'll do a garbage collection for the top level table
2364 if( 1==m_nRows
&& m_nHeight
&& 1==m_pSwTable
->GetTabLines().size() )
2366 // Set height of a one-row table as the minimum width of the row
2367 // Was originally a fixed height, but that made problems
2368 // and is not Netscape 4.0 compliant
2369 m_nHeight
= SwHTMLParser::ToTwips( m_nHeight
);
2370 if( m_nHeight
< MINLAY
)
2373 (m_pSwTable
->GetTabLines())[0]->ClaimFrameFormat();
2374 (m_pSwTable
->GetTabLines())[0]->GetFrameFormat()
2375 ->SetFormatAttr( SwFormatFrameSize( SwFrameSize::Minimum
, 0, m_nHeight
) );
2379 m_pSwTable
->GetFrameFormat()->SetFormatAttr( *GetBGBrush() );
2381 const_cast<SwTable
*>(m_pSwTable
)->SetRowsToRepeat( static_cast< sal_uInt16
>(m_nHeadlineRepeat
) );
2382 const_cast<SwTable
*>(m_pSwTable
)->GCLines();
2384 bool bIsInFlyFrame
= m_pContext
&& m_pContext
->GetFrameFormat();
2385 if( bIsInFlyFrame
&& !m_nWidth
)
2387 SvxAdjust eAdjust
= GetTableAdjust(false);
2388 if (eAdjust
!= SvxAdjust::Left
&&
2389 eAdjust
!= SvxAdjust::Right
)
2391 // If a table with a width attribute isn't flowed around left or right
2392 // we'll stack it with a border of 100% width, so its size will
2393 // be adapted. That text frame mustn't be modified
2394 OSL_ENSURE( HasToFly(), "Why is the table in a frame?" );
2395 sal_uInt32 nMin
= m_xLayoutInfo
->GetMin();
2396 if( nMin
> USHRT_MAX
)
2398 SwFormatFrameSize
aFlyFrameSize( SwFrameSize::Variable
, static_cast<SwTwips
>(nMin
), MINLAY
);
2399 aFlyFrameSize
.SetWidthPercent( 100 );
2400 m_pContext
->GetFrameFormat()->SetFormatAttr( aFlyFrameSize
);
2401 bIsInFlyFrame
= false;
2405 // left or right adjusted table without width mustn't be adjusted in width
2406 // as they would only shrink but never grow
2407 m_xLayoutInfo
->SetMustNotRecalc( true );
2408 if( m_pContext
->GetFrameFormat()->GetAnchor().GetContentAnchor()
2409 ->nNode
.GetNode().FindTableNode() )
2411 sal_uInt32 nMax
= m_xLayoutInfo
->GetMax();
2412 if( nMax
> USHRT_MAX
)
2414 SwFormatFrameSize
aFlyFrameSize( SwFrameSize::Variable
, static_cast<SwTwips
>(nMax
), MINLAY
);
2415 m_pContext
->GetFrameFormat()->SetFormatAttr( aFlyFrameSize
);
2416 bIsInFlyFrame
= false;
2420 m_xLayoutInfo
->SetMustNotResize( true );
2424 m_xLayoutInfo
->SetMayBeInFlyFrame( bIsInFlyFrame
);
2426 // Only tables with relative width or without width should be modified
2427 m_xLayoutInfo
->SetMustResize( m_bPercentWidth
|| !m_nWidth
);
2429 if (!pLine1
->GetTabBoxes().empty())
2430 m_xLayoutInfo
->SetWidths();
2432 SAL_WARN("sw.html", "no table box");
2434 const_cast<SwTable
*>(m_pSwTable
)->SetHTMLTableLayout(m_xLayoutInfo
);
2436 if( !m_xResizeDrawObjects
)
2439 sal_uInt16 nCount
= m_xResizeDrawObjects
->size();
2440 for( sal_uInt16 i
=0; i
<nCount
; i
++ )
2442 SdrObject
*pObj
= (*m_xResizeDrawObjects
)[i
];
2443 sal_uInt16 nRow
= (*m_xDrawObjectPercentWidths
)[3*i
];
2444 sal_uInt16 nCol
= (*m_xDrawObjectPercentWidths
)[3*i
+1];
2445 sal_uInt8 nPercentWidth
= static_cast<sal_uInt8
>((*m_xDrawObjectPercentWidths
)[3*i
+2]);
2447 SwHTMLTableLayoutCell
*pLayoutCell
=
2448 m_xLayoutInfo
->GetCell( nRow
, nCol
);
2449 sal_uInt16 nColSpan
= pLayoutCell
->GetColSpan();
2451 sal_uInt16 nWidth2
, nDummy
;
2452 m_xLayoutInfo
->GetAvail( nCol
, nColSpan
, nWidth2
, nDummy
);
2453 nWidth2
= static_cast< sal_uInt16
>((static_cast<tools::Long
>(m_nWidth
) * nPercentWidth
) / 100);
2455 SwHTMLParser::ResizeDrawObject( pObj
, nWidth2
);
2460 void HTMLTable::SetTable( const SwStartNode
*pStNd
, std::unique_ptr
<HTMLTableContext
> pCntxt
,
2461 sal_uInt16 nLeft
, sal_uInt16 nRight
,
2462 const SwTable
*pSwTab
, bool bFrcFrame
)
2464 m_pPrevStartNode
= pStNd
;
2465 m_pSwTable
= pSwTab
;
2466 m_pContext
= std::move(pCntxt
);
2468 m_nLeftMargin
= nLeft
;
2469 m_nRightMargin
= nRight
;
2471 m_bForceFrame
= bFrcFrame
;
2474 void HTMLTable::RegisterDrawObject( SdrObject
*pObj
, sal_uInt8 nPercentWidth
)
2476 if( !m_xResizeDrawObjects
)
2477 m_xResizeDrawObjects
.emplace();
2478 m_xResizeDrawObjects
->push_back( pObj
);
2480 if( !m_xDrawObjectPercentWidths
)
2481 m_xDrawObjectPercentWidths
.emplace();
2482 m_xDrawObjectPercentWidths
->push_back( m_nCurrentRow
);
2483 m_xDrawObjectPercentWidths
->push_back( m_nCurrentColumn
);
2484 m_xDrawObjectPercentWidths
->push_back( o3tl::narrowing
<sal_uInt16
>(nPercentWidth
) );
2487 void HTMLTable::MakeParentContents()
2489 if( !GetContext() && !HasParentSection() )
2492 m_pParser
->InsertTableContents( m_bIsParentHead
) );
2494 SetHasParentSection( true );
2498 void HTMLTableContext::SavePREListingXMP( SwHTMLParser
& rParser
)
2500 m_bRestartPRE
= rParser
.IsReadPRE();
2501 m_bRestartXMP
= rParser
.IsReadXMP();
2502 m_bRestartListing
= rParser
.IsReadListing();
2503 rParser
.FinishPREListingXMP();
2506 void HTMLTableContext::RestorePREListingXMP( SwHTMLParser
& rParser
)
2508 rParser
.FinishPREListingXMP();
2516 if( m_bRestartListing
)
2517 rParser
.StartListing();
2520 const SwStartNode
*SwHTMLParser::InsertTableSection
2521 ( const SwStartNode
*pPrevStNd
)
2523 OSL_ENSURE( pPrevStNd
, "Start-Node is NULL" );
2525 m_pCSS1Parser
->SetTDTagStyles();
2526 SwTextFormatColl
*pColl
= m_pCSS1Parser
->GetTextCollFromPool( RES_POOLCOLL_TABLE
);
2528 const SwStartNode
*pStNd
;
2529 if (m_xTable
->m_bFirstCell
)
2531 SwNode
*const pNd
= & m_pPam
->GetPoint()->nNode
.GetNode();
2532 pNd
->GetTextNode()->ChgFormatColl( pColl
);
2533 pStNd
= pNd
->FindTableBoxStartNode();
2534 m_xTable
->m_bFirstCell
= false;
2539 if( pPrevStNd
->IsTableNode() )
2542 pNd
= pPrevStNd
->EndOfSectionNode();
2543 SwNodeIndex
nIdx( *pNd
, 1 );
2544 pStNd
= m_xDoc
->GetNodes().MakeTextSection( nIdx
, SwTableBoxStartNode
,
2546 m_xTable
->IncBoxCount();
2550 eState
= SvParserState::Error
;
2554 //Added defaults to CJK and CTL
2555 SwContentNode
*pCNd
= m_xDoc
->GetNodes()[pStNd
->GetIndex()+1] ->GetContentNode();
2556 SvxFontHeightItem
aFontHeight( 40, 100, RES_CHRATR_FONTSIZE
);
2557 pCNd
->SetAttr( aFontHeight
);
2558 SvxFontHeightItem
aFontHeightCJK( 40, 100, RES_CHRATR_CJK_FONTSIZE
);
2559 pCNd
->SetAttr( aFontHeightCJK
);
2560 SvxFontHeightItem
aFontHeightCTL( 40, 100, RES_CHRATR_CTL_FONTSIZE
);
2561 pCNd
->SetAttr( aFontHeightCTL
);
2566 const SwStartNode
*SwHTMLParser::InsertTableSection( sal_uInt16 nPoolId
)
2570 case RES_POOLCOLL_TABLE_HDLN
:
2571 m_pCSS1Parser
->SetTHTagStyles();
2573 case RES_POOLCOLL_TABLE
:
2574 m_pCSS1Parser
->SetTDTagStyles();
2578 SwTextFormatColl
*pColl
= m_pCSS1Parser
->GetTextCollFromPool( nPoolId
);
2580 SwNode
*const pNd
= & m_pPam
->GetPoint()->nNode
.GetNode();
2581 const SwStartNode
*pStNd
;
2582 if (m_xTable
->m_bFirstCell
)
2584 SwTextNode
* pTextNd
= pNd
->GetTextNode();
2587 eState
= SvParserState::Error
;
2590 pTextNd
->ChgFormatColl(pColl
);
2591 m_xTable
->m_bFirstCell
= false;
2592 pStNd
= pNd
->FindTableBoxStartNode();
2596 SwTableNode
*pTableNd
= pNd
->FindTableNode();
2599 eState
= SvParserState::Error
;
2602 if( pTableNd
->GetTable().GetHTMLTableLayout() )
2603 { // if there is already a HTMTableLayout, this table is already finished
2604 // and we have to look for the right table in the environment
2605 SwTableNode
*pOutTable
= pTableNd
;
2607 pTableNd
= pOutTable
;
2608 pOutTable
= pOutTable
->StartOfSectionNode()->FindTableNode();
2609 } while( pOutTable
&& pTableNd
->GetTable().GetHTMLTableLayout() );
2611 SwNodeIndex
aIdx( *pTableNd
->EndOfSectionNode() );
2612 pStNd
= m_xDoc
->GetNodes().MakeTextSection( aIdx
, SwTableBoxStartNode
,
2615 m_pPam
->GetPoint()->nNode
= pStNd
->GetIndex() + 1;
2616 SwTextNode
*pTextNd
= m_pPam
->GetPoint()->nNode
.GetNode().GetTextNode();
2617 m_pPam
->GetPoint()->nContent
.Assign( pTextNd
, 0 );
2618 m_xTable
->IncBoxCount();
2623 eState
= SvParserState::Error
;
2629 SwStartNode
*SwHTMLParser::InsertTempTableCaptionSection()
2631 SwTextFormatColl
*pColl
= m_pCSS1Parser
->GetTextCollFromPool( RES_POOLCOLL_TEXT
);
2632 SwNodeIndex
& rIdx
= m_pPam
->GetPoint()->nNode
;
2633 rIdx
= m_xDoc
->GetNodes().GetEndOfExtras();
2634 SwStartNode
*pStNd
= m_xDoc
->GetNodes().MakeTextSection( rIdx
,
2635 SwNormalStartNode
, pColl
);
2637 rIdx
= pStNd
->GetIndex() + 1;
2638 m_pPam
->GetPoint()->nContent
.Assign( rIdx
.GetNode().GetTextNode(), 0 );
2643 sal_Int32
SwHTMLParser::StripTrailingLF()
2645 sal_Int32 nStripped
= 0;
2647 const sal_Int32 nLen
= m_pPam
->GetPoint()->nContent
.GetIndex();
2650 SwTextNode
* pTextNd
= m_pPam
->GetPoint()->nNode
.GetNode().GetTextNode();
2651 // careful, when comments aren't ignored!!!
2654 sal_Int32 nPos
= nLen
;
2655 sal_Int32 nLFCount
= 0;
2656 while (nPos
&& ('\x0a' == pTextNd
->GetText()[--nPos
]))
2663 // On Netscape, a paragraph end matches 2 LFs
2664 // (1 is just a newline, 2 creates a blank line)
2665 // We already have this space with the lower paragraph gap
2666 // If there's a paragraph after the <BR>, we take the maximum
2667 // of the gap that results from the <BR> and <P>
2668 // That's why we need to delete 2 respectively all if less than 2
2672 nPos
= nLen
- nLFCount
;
2673 SwIndex
nIdx( pTextNd
, nPos
);
2674 pTextNd
->EraseText( nIdx
, nLFCount
);
2675 nStripped
= nLFCount
;
2683 SvxBrushItem
* SwHTMLParser::CreateBrushItem( const Color
*pColor
,
2684 const OUString
& rImageURL
,
2685 const OUString
& rStyle
,
2686 const OUString
& rId
,
2687 const OUString
& rClass
)
2689 SvxBrushItem
*pBrushItem
= nullptr;
2691 if( !rStyle
.isEmpty() || !rId
.isEmpty() || !rClass
.isEmpty() )
2693 SfxItemSet
aItemSet( m_xDoc
->GetAttrPool(), svl::Items
<RES_BACKGROUND
,
2694 RES_BACKGROUND
>{} );
2695 SvxCSS1PropertyInfo aPropInfo
;
2697 if( !rClass
.isEmpty() )
2699 OUString
aClass( rClass
);
2700 SwCSS1Parser::GetScriptFromClass( aClass
);
2701 const SvxCSS1MapEntry
*pClass
= m_pCSS1Parser
->GetClass( aClass
);
2703 aItemSet
.Put( pClass
->GetItemSet() );
2706 if( !rId
.isEmpty() )
2708 const SvxCSS1MapEntry
*pId
= m_pCSS1Parser
->GetId( rId
);
2710 aItemSet
.Put( pId
->GetItemSet() );
2713 m_pCSS1Parser
->ParseStyleOption( rStyle
, aItemSet
, aPropInfo
);
2714 const SfxPoolItem
*pItem
= nullptr;
2715 if( SfxItemState::SET
== aItemSet
.GetItemState( RES_BACKGROUND
, false,
2718 pBrushItem
= new SvxBrushItem( *static_cast<const SvxBrushItem
*>(pItem
) );
2722 if( !pBrushItem
&& (pColor
|| !rImageURL
.isEmpty()) )
2724 pBrushItem
= new SvxBrushItem(RES_BACKGROUND
);
2727 pBrushItem
->SetColor(*pColor
);
2729 if( !rImageURL
.isEmpty() )
2731 pBrushItem
->SetGraphicLink( URIHelper::SmartRel2Abs( INetURLObject(m_sBaseURL
), rImageURL
, Link
<OUString
*, bool>(), false) );
2732 pBrushItem
->SetGraphicPos( GPOS_TILED
);
2739 class SectionSaveStruct
: public SwPendingData
2741 sal_uInt16 m_nBaseFontStMinSave
, m_nFontStMinSave
, m_nFontStHeadStartSave
;
2742 sal_uInt16 m_nDefListDeepSave
;
2743 size_t m_nContextStMinSave
;
2744 size_t m_nContextStAttrMinSave
;
2748 std::shared_ptr
<HTMLTable
> m_xTable
;
2750 explicit SectionSaveStruct( SwHTMLParser
& rParser
);
2752 #if OSL_DEBUG_LEVEL > 0
2753 size_t GetContextStAttrMin() const { return m_nContextStAttrMinSave
; }
2755 void Restore( SwHTMLParser
& rParser
);
2758 SectionSaveStruct::SectionSaveStruct( SwHTMLParser
& rParser
) :
2759 m_nBaseFontStMinSave(rParser
.m_nBaseFontStMin
),
2760 m_nFontStMinSave(rParser
.m_nFontStMin
),
2761 m_nFontStHeadStartSave(rParser
.m_nFontStHeadStart
),
2762 m_nDefListDeepSave(rParser
.m_nDefListDeep
),
2763 m_nContextStMinSave(rParser
.m_nContextStMin
),
2764 m_nContextStAttrMinSave(rParser
.m_nContextStAttrMin
)
2766 // Freeze font stacks
2767 rParser
.m_nBaseFontStMin
= rParser
.m_aBaseFontStack
.size();
2769 rParser
.m_nFontStMin
= rParser
.m_aFontStack
.size();
2771 // Freeze context stack
2772 rParser
.m_nContextStMin
= rParser
.m_aContexts
.size();
2773 rParser
.m_nContextStAttrMin
= rParser
.m_nContextStMin
;
2775 // And remember a few counters
2776 rParser
.m_nDefListDeep
= 0;
2779 void SectionSaveStruct::Restore( SwHTMLParser
& rParser
)
2781 // Unfreeze font stacks
2782 sal_uInt16 nMin
= rParser
.m_nBaseFontStMin
;
2783 if( rParser
.m_aBaseFontStack
.size() > nMin
)
2784 rParser
.m_aBaseFontStack
.erase( rParser
.m_aBaseFontStack
.begin() + nMin
,
2785 rParser
.m_aBaseFontStack
.end() );
2786 rParser
.m_nBaseFontStMin
= m_nBaseFontStMinSave
;
2788 nMin
= rParser
.m_nFontStMin
;
2789 if( rParser
.m_aFontStack
.size() > nMin
)
2790 rParser
.m_aFontStack
.erase( rParser
.m_aFontStack
.begin() + nMin
,
2791 rParser
.m_aFontStack
.end() );
2792 rParser
.m_nFontStMin
= m_nFontStMinSave
;
2793 rParser
.m_nFontStHeadStart
= m_nFontStHeadStartSave
;
2795 OSL_ENSURE( rParser
.m_aContexts
.size() == rParser
.m_nContextStMin
&&
2796 rParser
.m_aContexts
.size() == rParser
.m_nContextStAttrMin
,
2797 "The Context Stack was not cleaned up" );
2798 rParser
.m_nContextStMin
= m_nContextStMinSave
;
2799 rParser
.m_nContextStAttrMin
= m_nContextStAttrMinSave
;
2801 // Reconstruct a few counters
2802 rParser
.m_nDefListDeep
= m_nDefListDeepSave
;
2804 // Reset a few flags
2805 rParser
.m_bNoParSpace
= false;
2806 rParser
.m_nOpenParaToken
= HtmlTokenId::NONE
;
2808 rParser
.m_aParaAttrs
.clear();
2811 class CellSaveStruct
: public SectionSaveStruct
2813 OUString m_aStyle
, m_aId
, m_aClass
;
2814 OUString m_aBGImage
;
2816 std::shared_ptr
<SvxBoxItem
> m_xBoxItem
;
2818 std::shared_ptr
<HTMLTableCnts
> m_xCnts
; // List of all contents
2819 HTMLTableCnts
* m_pCurrCnts
; // current content or 0
2820 std::unique_ptr
<SwNodeIndex
> m_pNoBreakEndNodeIndex
; // Paragraph index of a <NOBR>
2824 sal_uInt32 m_nNumFormat
;
2826 sal_uInt16 m_nRowSpan
, m_nColSpan
, m_nWidth
, m_nHeight
;
2827 sal_Int32 m_nNoBreakEndContentPos
; // Character index of a <NOBR>
2829 sal_Int16 m_eVertOri
;
2832 bool m_bPercentWidth
: 1;
2833 bool m_bHasNumFormat
: 1;
2834 bool m_bHasValue
: 1;
2835 bool m_bBGColor
: 1;
2836 bool m_bNoWrap
: 1; // NOWRAP option
2837 bool m_bNoBreak
: 1; // NOBREAK tag
2841 CellSaveStruct( SwHTMLParser
& rParser
, HTMLTable
const *pCurTable
, bool bHd
,
2844 void AddContents( std::unique_ptr
<HTMLTableCnts
> pNewCnts
);
2845 bool HasFirstContents() const { return bool(m_xCnts
); }
2847 void ClearIsInSection() { m_pCurrCnts
= nullptr; }
2848 bool IsInSection() const { return m_pCurrCnts
!=nullptr; }
2850 void InsertCell( SwHTMLParser
& rParser
, HTMLTable
*pCurTable
);
2852 bool IsHeaderCell() const { return m_bHead
; }
2854 void StartNoBreak( const SwPosition
& rPos
);
2855 void EndNoBreak( const SwPosition
& rPos
);
2856 void CheckNoBreak( const SwPosition
& rPos
);
2859 CellSaveStruct::CellSaveStruct( SwHTMLParser
& rParser
, HTMLTable
const *pCurTable
,
2860 bool bHd
, bool bReadOpt
) :
2861 SectionSaveStruct( rParser
),
2862 m_pCurrCnts( nullptr ),
2869 m_nNoBreakEndContentPos( 0 ),
2870 m_eVertOri( pCurTable
->GetInheritedVertOri() ),
2872 m_bPercentWidth( false ),
2873 m_bHasNumFormat( false ),
2874 m_bHasValue( false ),
2875 m_bBGColor( false ),
2879 OUString aNumFormat
, aValue
, aDir
, aLang
;
2880 SvxAdjust
eAdjust( pCurTable
->GetInheritedAdjust() );
2884 const HTMLOptions
& rOptions
= rParser
.GetOptions();
2885 for (size_t i
= rOptions
.size(); i
; )
2887 const HTMLOption
& rOption
= rOptions
[--i
];
2888 switch( rOption
.GetToken() )
2890 case HtmlOptionId::ID
:
2891 m_aId
= rOption
.GetString();
2893 case HtmlOptionId::COLSPAN
:
2894 m_nColSpan
= o3tl::narrowing
<sal_uInt16
>(rOption
.GetNumber());
2895 if (m_nColSpan
> 256)
2897 SAL_INFO("sw.html", "ignoring huge COLSPAN " << m_nColSpan
);
2901 case HtmlOptionId::ROWSPAN
:
2902 m_nRowSpan
= o3tl::narrowing
<sal_uInt16
>(rOption
.GetNumber());
2903 if (m_nRowSpan
> 8192 || (m_nRowSpan
> 256 && utl::ConfigManager::IsFuzzing()))
2905 SAL_INFO("sw.html", "ignoring huge ROWSPAN " << m_nRowSpan
);
2909 case HtmlOptionId::ALIGN
:
2910 eAdjust
= rOption
.GetEnum( aHTMLPAlignTable
, eAdjust
);
2912 case HtmlOptionId::VALIGN
:
2913 m_eVertOri
= rOption
.GetEnum( aHTMLTableVAlignTable
, m_eVertOri
);
2915 case HtmlOptionId::WIDTH
:
2916 m_nWidth
= o3tl::narrowing
<sal_uInt16
>(rOption
.GetNumber()); // Just for Netscape
2917 m_bPercentWidth
= (rOption
.GetString().indexOf('%') != -1);
2918 if( m_bPercentWidth
&& m_nWidth
>100 )
2921 case HtmlOptionId::HEIGHT
:
2922 m_nHeight
= o3tl::narrowing
<sal_uInt16
>(rOption
.GetNumber()); // Just for Netscape
2923 if( rOption
.GetString().indexOf('%') != -1)
2924 m_nHeight
= 0; // don't consider % attributes
2926 case HtmlOptionId::BGCOLOR
:
2927 // Ignore empty BGCOLOR on <TABLE>, <TR> and <TD>/<TH> like Netscape
2928 // *really* not on other tags
2929 if( !rOption
.GetString().isEmpty() )
2931 rOption
.GetColor( m_aBGColor
);
2935 case HtmlOptionId::BACKGROUND
:
2936 m_aBGImage
= rOption
.GetString();
2938 case HtmlOptionId::STYLE
:
2939 m_aStyle
= rOption
.GetString();
2941 case HtmlOptionId::CLASS
:
2942 m_aClass
= rOption
.GetString();
2944 case HtmlOptionId::LANG
:
2945 aLang
= rOption
.GetString();
2947 case HtmlOptionId::DIR:
2948 aDir
= rOption
.GetString();
2950 case HtmlOptionId::SDNUM
:
2951 aNumFormat
= rOption
.GetString();
2952 m_bHasNumFormat
= true;
2954 case HtmlOptionId::SDVAL
:
2956 aValue
= rOption
.GetString();
2958 case HtmlOptionId::NOWRAP
:
2965 if( !m_aId
.isEmpty() )
2966 rParser
.InsertBookmark( m_aId
);
2969 if( m_bHasNumFormat
)
2972 m_nValue
= SfxHTMLParser::GetTableDataOptionsValNum(
2973 m_nNumFormat
, eLang
, aValue
, aNumFormat
,
2974 *rParser
.m_xDoc
->GetNumberFormatter() );
2977 // Create a new context but don't anchor the drawing::Alignment attribute there,
2978 // since there's no section yet
2983 nToken
= HtmlTokenId::TABLEHEADER_ON
;
2984 nColl
= RES_POOLCOLL_TABLE_HDLN
;
2988 nToken
= HtmlTokenId::TABLEDATA_ON
;
2989 nColl
= RES_POOLCOLL_TABLE
;
2991 std::unique_ptr
<HTMLAttrContext
> xCntxt(new HTMLAttrContext(nToken
, nColl
, OUString(), true));
2992 if( SvxAdjust::End
!= eAdjust
)
2993 rParser
.InsertAttr(&rParser
.m_xAttrTab
->pAdjust
, SvxAdjustItem(eAdjust
, RES_PARATR_ADJUST
),
2996 if( SwHTMLParser::HasStyleOptions( m_aStyle
, m_aId
, m_aClass
, &aLang
, &aDir
) )
2998 SfxItemSet
aItemSet( rParser
.m_xDoc
->GetAttrPool(),
2999 rParser
.m_pCSS1Parser
->GetWhichMap() );
3000 SvxCSS1PropertyInfo aPropInfo
;
3002 if( rParser
.ParseStyleOptions( m_aStyle
, m_aId
, m_aClass
, aItemSet
,
3003 aPropInfo
, &aLang
, &aDir
) )
3005 SfxPoolItem
const* pItem
;
3006 if (SfxItemState::SET
== aItemSet
.GetItemState(RES_BOX
, false, &pItem
))
3007 { // fdo#41796: steal box item to set it in FixFrameFormat later!
3008 m_xBoxItem
.reset(dynamic_cast<SvxBoxItem
*>(pItem
->Clone()));
3009 aItemSet
.ClearItem(RES_BOX
);
3011 rParser
.InsertAttrs(aItemSet
, aPropInfo
, xCntxt
.get());
3015 rParser
.SplitPREListingXMP(xCntxt
.get());
3017 rParser
.PushContext(xCntxt
);
3020 void CellSaveStruct::AddContents( std::unique_ptr
<HTMLTableCnts
> pNewCnts
)
3022 m_pCurrCnts
= pNewCnts
.get();
3025 m_xCnts
->Add( std::move(pNewCnts
) );
3027 m_xCnts
= std::move(pNewCnts
);
3030 void CellSaveStruct::InsertCell( SwHTMLParser
& rParser
,
3031 HTMLTable
*pCurTable
)
3033 #if OSL_DEBUG_LEVEL > 0
3034 // The attributes need to have been removed when tidying up the context stack,
3035 // Otherwise something's wrong. Let's check that...
3037 // MIB 8.1.98: When attributes were opened outside of a cell,
3038 // they're still in the attribute table and will only be deleted at the end
3039 // through the CleanContext calls in BuildTable. We don't check that there
3040 // so that we get no assert [violations, by translator]
3041 // We can see this on nContextStAttrMin: the remembered value of nContextStAttrMinSave
3042 // is the value that nContextStAttrMin had at the start of the table. And the
3043 // current value of nContextStAttrMin corresponds to the number of contexts
3044 // we found at the start of the cell. If the values differ, contexts
3045 // were created and we don't check anything.
3047 if( rParser
.m_nContextStAttrMin
== GetContextStAttrMin() )
3049 HTMLAttr
** pTable
= reinterpret_cast<HTMLAttr
**>(rParser
.m_xAttrTab
.get());
3051 for( auto nCnt
= sizeof( HTMLAttrTable
) / sizeof( HTMLAttr
* );
3054 OSL_ENSURE( !*pTable
, "The attribute table isn't empty" );
3059 // we need to add the cell on the current position
3060 std::shared_ptr
<SvxBrushItem
> xBrushItem(
3061 rParser
.CreateBrushItem(m_bBGColor
? &m_aBGColor
: nullptr, m_aBGImage
,
3062 m_aStyle
, m_aId
, m_aClass
));
3063 pCurTable
->InsertCell( m_xCnts
, m_nRowSpan
, m_nColSpan
, m_nWidth
,
3064 m_bPercentWidth
, m_nHeight
, m_eVertOri
, xBrushItem
, m_xBoxItem
,
3065 m_bHasNumFormat
, m_nNumFormat
, m_bHasValue
, m_nValue
,
3070 void CellSaveStruct::StartNoBreak( const SwPosition
& rPos
)
3073 (!rPos
.nContent
.GetIndex() && m_pCurrCnts
== m_xCnts
.get() &&
3074 m_xCnts
->GetStartNode() &&
3075 m_xCnts
->GetStartNode()->GetIndex() + 1 ==
3076 rPos
.nNode
.GetIndex()) )
3082 void CellSaveStruct::EndNoBreak( const SwPosition
& rPos
)
3086 m_pNoBreakEndNodeIndex
.reset( new SwNodeIndex( rPos
.nNode
) );
3087 m_nNoBreakEndContentPos
= rPos
.nContent
.GetIndex();
3092 void CellSaveStruct::CheckNoBreak( const SwPosition
& rPos
)
3094 if (!(m_xCnts
&& m_pCurrCnts
== m_xCnts
.get()))
3099 // <NOBR> wasn't closed
3100 m_xCnts
->SetNoBreak();
3102 else if( m_pNoBreakEndNodeIndex
&&
3103 m_pNoBreakEndNodeIndex
->GetIndex() == rPos
.nNode
.GetIndex() )
3105 if( m_nNoBreakEndContentPos
== rPos
.nContent
.GetIndex() )
3107 // <NOBR> was closed immediately before the cell end
3108 m_xCnts
->SetNoBreak();
3110 else if( m_nNoBreakEndContentPos
+ 1 == rPos
.nContent
.GetIndex() )
3112 SwTextNode
const*const pTextNd(rPos
.nNode
.GetNode().GetTextNode());
3115 sal_Unicode
const cLast
=
3116 pTextNd
->GetText()[m_nNoBreakEndContentPos
];
3117 if( ' '==cLast
|| '\x0a'==cLast
)
3119 // There's just a blank or a newline between the <NOBR> and the cell end
3120 m_xCnts
->SetNoBreak();
3127 std::unique_ptr
<HTMLTableCnts
> SwHTMLParser::InsertTableContents(
3130 // create a new section, the PaM is gonna be there
3131 const SwStartNode
*pStNd
=
3132 InsertTableSection( static_cast< sal_uInt16
>(bHead
? RES_POOLCOLL_TABLE_HDLN
3133 : RES_POOLCOLL_TABLE
) );
3135 if( GetNumInfo().GetNumRule() )
3137 // Set the first paragraph to non-enumerated
3138 sal_uInt8 nLvl
= GetNumInfo().GetLevel();
3143 // Reset attributation start
3144 const SwNodeIndex
& rSttPara
= m_pPam
->GetPoint()->nNode
;
3145 sal_Int32 nSttCnt
= m_pPam
->GetPoint()->nContent
.GetIndex();
3147 HTMLAttr
** pHTMLAttributes
= reinterpret_cast<HTMLAttr
**>(m_xAttrTab
.get());
3148 for (sal_uInt16 nCnt
= sizeof(HTMLAttrTable
) / sizeof(HTMLAttr
*); nCnt
--; ++pHTMLAttributes
)
3150 HTMLAttr
*pAttr
= *pHTMLAttributes
;
3153 OSL_ENSURE( !pAttr
->GetPrev(), "Attribute has previous list" );
3154 pAttr
->m_nStartPara
= rSttPara
;
3155 pAttr
->m_nEndPara
= rSttPara
;
3156 pAttr
->m_nStartContent
= nSttCnt
;
3157 pAttr
->m_nEndContent
= nSttCnt
;
3159 pAttr
= pAttr
->GetNext();
3163 return std::make_unique
<HTMLTableCnts
>( pStNd
);
3166 sal_uInt16
SwHTMLParser::IncGrfsThatResizeTable()
3168 return m_xTable
? m_xTable
->IncGrfsThatResize() : 0;
3171 void SwHTMLParser::RegisterDrawObjectToTable( HTMLTable
*pCurTable
,
3172 SdrObject
*pObj
, sal_uInt8 nPercentWidth
)
3174 pCurTable
->RegisterDrawObject( pObj
, nPercentWidth
);
3177 void SwHTMLParser::BuildTableCell( HTMLTable
*pCurTable
, bool bReadOptions
,
3180 if( !IsParserWorking() && m_vPendingStack
.empty() )
3183 ::comphelper::FlagRestorationGuard
g(m_isInTableStructure
, false);
3184 std::unique_ptr
<CellSaveStruct
> xSaveStruct
;
3186 HtmlTokenId nToken
= HtmlTokenId::NONE
;
3187 bool bPending
= false;
3188 if( !m_vPendingStack
.empty() )
3190 xSaveStruct
.reset(static_cast<CellSaveStruct
*>(m_vPendingStack
.back().pData
.release()));
3192 m_vPendingStack
.pop_back();
3193 nToken
= !m_vPendingStack
.empty() ? m_vPendingStack
.back().nToken
: GetSaveToken();
3194 bPending
= SvParserState::Error
== eState
&& !m_vPendingStack
.empty();
3196 SaveState( nToken
);
3200 // <TH> resp. <TD> were already read
3201 if (m_xTable
->IsOverflowing())
3203 SaveState( HtmlTokenId::NONE
);
3207 if( !pCurTable
->GetContext() )
3209 bool bTopTable
= m_xTable
.get() == pCurTable
;
3211 // the table has no content yet, this means the actual table needs
3212 // to be created first
3214 static sal_uInt16 aWhichIds
[] =
3216 RES_PARATR_SPLIT
, RES_PARATR_SPLIT
,
3217 RES_PAGEDESC
, RES_PAGEDESC
,
3218 RES_BREAK
, RES_BREAK
,
3219 RES_BACKGROUND
, RES_BACKGROUND
,
3221 RES_LAYOUT_SPLIT
, RES_LAYOUT_SPLIT
,
3222 RES_FRAMEDIR
, RES_FRAMEDIR
,
3226 SfxItemSet
aItemSet( m_xDoc
->GetAttrPool(), aWhichIds
);
3227 SvxCSS1PropertyInfo aPropInfo
;
3229 bool bStyleParsed
= ParseStyleOptions( pCurTable
->GetStyle(),
3231 pCurTable
->GetClass(),
3232 aItemSet
, aPropInfo
,
3233 nullptr, &pCurTable
->GetDirection() );
3234 const SfxPoolItem
*pItem
= nullptr;
3237 if( SfxItemState::SET
== aItemSet
.GetItemState(
3238 RES_BACKGROUND
, false, &pItem
) )
3240 pCurTable
->SetBGBrush( *static_cast<const SvxBrushItem
*>(pItem
) );
3241 aItemSet
.ClearItem( RES_BACKGROUND
);
3243 if( SfxItemState::SET
== aItemSet
.GetItemState(
3244 RES_PARATR_SPLIT
, false, &pItem
) )
3247 SwFormatLayoutSplit( static_cast<const SvxFormatSplitItem
*>(pItem
)
3249 aItemSet
.ClearItem( RES_PARATR_SPLIT
);
3253 sal_uInt16 nLeftSpace
= 0;
3254 sal_uInt16 nRightSpace
= 0;
3256 GetMarginsFromContextWithNumberBullet( nLeftSpace
, nRightSpace
, nIndent
);
3258 // save the current position we'll get back to some time
3259 SwPosition
*pSavePos
= nullptr;
3260 bool bForceFrame
= false;
3261 bool bAppended
= false;
3262 bool bParentLFStripped
= false;
3265 SvxAdjust eTableAdjust
= m_xTable
->GetTableAdjust(false);
3267 // If the table is left or right adjusted or should be in a text frame,
3269 bForceFrame
= eTableAdjust
== SvxAdjust::Left
||
3270 eTableAdjust
== SvxAdjust::Right
||
3271 pCurTable
->HasToFly();
3273 // The table either shouldn't get in a text frame and isn't in one
3274 // (it gets simulated through cells),
3275 // or there's already content at that position
3276 OSL_ENSURE( !bForceFrame
|| pCurTable
->HasParentSection(),
3277 "table in frame has no parent!" );
3279 bool bAppend
= false;
3282 // If the table gets in a border, we only need to open a new
3283 //paragraph if the paragraph has text frames that don't fly
3284 bAppend
= HasCurrentParaFlys(true);
3288 // Otherwise, we need to open a new paragraph if the paragraph
3289 // is empty or contains text frames or bookmarks
3291 m_pPam
->GetPoint()->nContent
.GetIndex() ||
3292 HasCurrentParaFlys() ||
3293 HasCurrentParaBookmarks();
3297 if( !m_pPam
->GetPoint()->nContent
.GetIndex() )
3299 //Set default to CJK and CTL
3300 m_xDoc
->SetTextFormatColl( *m_pPam
,
3301 m_pCSS1Parser
->GetTextCollFromPool(RES_POOLCOLL_STANDARD
) );
3302 SvxFontHeightItem
aFontHeight( 40, 100, RES_CHRATR_FONTSIZE
);
3305 new HTMLAttr( *m_pPam
->GetPoint(), aFontHeight
, nullptr, std::shared_ptr
<HTMLAttrTable
>() );
3306 m_aSetAttrTab
.push_back( pTmp
);
3308 SvxFontHeightItem
aFontHeightCJK( 40, 100, RES_CHRATR_CJK_FONTSIZE
);
3310 new HTMLAttr( *m_pPam
->GetPoint(), aFontHeightCJK
, nullptr, std::shared_ptr
<HTMLAttrTable
>() );
3311 m_aSetAttrTab
.push_back( pTmp
);
3313 SvxFontHeightItem
aFontHeightCTL( 40, 100, RES_CHRATR_CTL_FONTSIZE
);
3315 new HTMLAttr( *m_pPam
->GetPoint(), aFontHeightCTL
, nullptr, std::shared_ptr
<HTMLAttrTable
>() );
3316 m_aSetAttrTab
.push_back( pTmp
);
3318 pTmp
= new HTMLAttr( *m_pPam
->GetPoint(),
3319 SvxULSpaceItem( 0, 0, RES_UL_SPACE
), nullptr, std::shared_ptr
<HTMLAttrTable
>() );
3320 m_aSetAttrTab
.push_front( pTmp
); // Position 0, since
3321 // something can be set by
3322 // the table end before
3324 AppendTextNode( AM_NOSPACE
);
3327 else if( !m_aParaAttrs
.empty() )
3331 // The paragraph will be moved right behind the table.
3332 // That's why we remove all hard attributes of that paragraph
3334 for(HTMLAttr
* i
: m_aParaAttrs
)
3338 m_aParaAttrs
.clear();
3341 pSavePos
= new SwPosition( *m_pPam
->GetPoint() );
3343 else if( pCurTable
->HasParentSection() )
3345 bParentLFStripped
= StripTrailingLF() > 0;
3347 // Close paragraph resp. headers
3348 m_nOpenParaToken
= HtmlTokenId::NONE
;
3349 m_nFontStHeadStart
= m_nFontStMin
;
3351 // The hard attributes on that paragraph are never gonna be invalid anymore
3352 m_aParaAttrs
.clear();
3355 // create a table context
3356 std::unique_ptr
<HTMLTableContext
> pTCntxt(
3357 new HTMLTableContext( pSavePos
, m_nContextStMin
,
3358 m_nContextStAttrMin
) );
3360 // end all open attributes and open them again behind the table
3361 std::optional
<std::deque
<std::unique_ptr
<HTMLAttr
>>> pPostIts
;
3362 if( !bForceFrame
&& (bTopTable
|| pCurTable
->HasParentSection()) )
3364 SplitAttrTab(pTCntxt
->m_xAttrTab
, bTopTable
);
3365 // If we reuse an already existing paragraph, we can't add
3366 // PostIts since the paragraph gets behind that table.
3367 // They're gonna be moved into the first paragraph of the table
3368 // If we have tables in tables, we also can't add PostIts to a
3369 // still empty paragraph, since it's not gonna be deleted that way
3370 if( (bTopTable
&& !bAppended
) ||
3371 (!bTopTable
&& !bParentLFStripped
&&
3372 !m_pPam
->GetPoint()->nContent
.GetIndex()) )
3374 SetAttr( bTopTable
, bTopTable
, pPostIts
? &*pPostIts
: nullptr );
3378 SaveAttrTab(pTCntxt
->m_xAttrTab
);
3379 if( bTopTable
&& !bAppended
)
3382 SetAttr( true, true, &*pPostIts
);
3385 m_bNoParSpace
= false;
3387 // Save current numbering and turn it off
3388 pTCntxt
->SetNumInfo( GetNumInfo() );
3389 GetNumInfo().Clear();
3390 pTCntxt
->SavePREListingXMP( *this );
3396 // the table should be put in a text frame
3398 SfxItemSet
aFrameSet( m_xDoc
->GetAttrPool(),
3399 svl::Items
<RES_FRMATR_BEGIN
, RES_FRMATR_END
-1>{} );
3400 if( !pCurTable
->IsNewDoc() )
3401 Reader::ResetFrameFormatAttrs( aFrameSet
);
3403 css::text::WrapTextMode eSurround
= css::text::WrapTextMode_NONE
;
3406 switch( pCurTable
->GetTableAdjust(true) )
3408 case SvxAdjust::Right
:
3409 eHori
= text::HoriOrientation::RIGHT
;
3410 eSurround
= css::text::WrapTextMode_LEFT
;
3412 case SvxAdjust::Center
:
3413 eHori
= text::HoriOrientation::CENTER
;
3415 case SvxAdjust::Left
:
3416 eSurround
= css::text::WrapTextMode_RIGHT
;
3419 eHori
= text::HoriOrientation::LEFT
;
3422 SetAnchorAndAdjustment( text::VertOrientation::NONE
, eHori
, aFrameSet
,
3424 aFrameSet
.Put( SwFormatSurround(eSurround
) );
3426 SwFormatFrameSize
aFrameSize( SwFrameSize::Variable
, 20*MM50
, MINLAY
);
3427 aFrameSize
.SetWidthPercent( 100 );
3428 aFrameSet
.Put( aFrameSize
);
3430 sal_uInt16 nSpace
= pCurTable
->GetHSpace();
3432 aFrameSet
.Put( SvxLRSpaceItem(nSpace
,nSpace
, 0, 0, RES_LR_SPACE
) );
3433 nSpace
= pCurTable
->GetVSpace();
3435 aFrameSet
.Put( SvxULSpaceItem(nSpace
,nSpace
, RES_UL_SPACE
) );
3437 RndStdIds eAnchorId
= aFrameSet
.
3440 SwFrameFormat
*pFrameFormat
= m_xDoc
->MakeFlySection(
3441 eAnchorId
, m_pPam
->GetPoint(), &aFrameSet
);
3443 pTCntxt
->SetFrameFormat( pFrameFormat
);
3444 const SwFormatContent
& rFlyContent
= pFrameFormat
->GetContent();
3445 m_pPam
->GetPoint()->nNode
= *rFlyContent
.GetContentIdx();
3446 SwContentNode
*pCNd
=
3447 m_xDoc
->GetNodes().GoNext( &(m_pPam
->GetPoint()->nNode
) );
3448 m_pPam
->GetPoint()->nContent
.Assign( pCNd
, 0 );
3452 // create a SwTable with a box and set the PaM to the content of
3453 // the box section (the adjustment parameter is a dummy for now
3454 // and will be corrected later)
3455 OSL_ENSURE( !m_pPam
->GetPoint()->nContent
.GetIndex(),
3456 "The paragraph after the table is not empty!" );
3457 const SwTable
* pSwTable
= m_xDoc
->InsertTable(
3458 SwInsertTableOptions( SwInsertTableFlags::HeadlineNoBorder
, 1 ),
3459 *m_pPam
->GetPoint(), 1, 1, text::HoriOrientation::LEFT
);
3460 SwFrameFormat
*pFrameFormat
= pSwTable
? pSwTable
->GetFrameFormat() : nullptr;
3464 SwNodeIndex
aDstIdx( m_pPam
->GetPoint()->nNode
);
3465 m_pPam
->Move( fnMoveBackward
);
3466 m_xDoc
->GetNodes().Delete( aDstIdx
);
3470 if (bStyleParsed
&& pFrameFormat
)
3472 m_pCSS1Parser
->SetFormatBreak( aItemSet
, aPropInfo
);
3473 pFrameFormat
->SetFormatAttr( aItemSet
);
3475 m_pPam
->Move( fnMoveBackward
);
3478 SwNode
const*const pNd
= & m_pPam
->GetPoint()->nNode
.GetNode();
3479 SwTextNode
*const pOldTextNd
= (!bAppended
&& !bForceFrame
) ?
3480 pSavePos
->nNode
.GetNode().GetTextNode() : nullptr;
3482 if (pFrameFormat
&& pOldTextNd
)
3484 const SfxPoolItem
* pItem2
;
3485 if( SfxItemState::SET
== pOldTextNd
->GetSwAttrSet()
3486 .GetItemState( RES_PAGEDESC
, false, &pItem2
) &&
3487 static_cast<const SwFormatPageDesc
*>(pItem2
)->GetPageDesc() )
3489 pFrameFormat
->SetFormatAttr( *pItem2
);
3490 pOldTextNd
->ResetAttr( RES_PAGEDESC
);
3492 if( SfxItemState::SET
== pOldTextNd
->GetSwAttrSet()
3493 .GetItemState( RES_BREAK
, true, &pItem2
) )
3495 switch( static_cast<const SvxFormatBreakItem
*>(pItem2
)->GetBreak() )
3497 case SvxBreak::PageBefore
:
3498 case SvxBreak::PageAfter
:
3499 case SvxBreak::PageBoth
:
3500 pFrameFormat
->SetFormatAttr( *pItem2
);
3501 pOldTextNd
->ResetAttr( RES_BREAK
);
3509 if( !bAppended
&& pPostIts
)
3511 // set still-existing PostIts to the first paragraph of the table
3512 InsertAttrs( std::move(*pPostIts
) );
3516 pTCntxt
->SetTableNode( const_cast<SwTableNode
*>(pNd
->FindTableNode()) );
3518 auto pTableNode
= pTCntxt
->GetTableNode();
3519 pCurTable
->SetTable( pTableNode
, std::move(pTCntxt
),
3520 nLeftSpace
, nRightSpace
,
3521 pSwTable
, bForceFrame
);
3523 OSL_ENSURE( !pPostIts
, "unused PostIts" );
3527 // still open sections need to be deleted
3528 if( EndSections( bParentLFStripped
) )
3529 bParentLFStripped
= false;
3531 if( pCurTable
->HasParentSection() )
3533 // after that, we remove a possibly redundant empty paragraph,
3534 // but only if it was empty before we stripped the LFs
3535 if( !bParentLFStripped
)
3536 StripTrailingPara();
3540 // move still existing PostIts to the end of the current paragraph
3541 InsertAttrs( std::move(*pPostIts
) );
3546 SwNode
const*const pNd
= & m_pPam
->GetPoint()->nNode
.GetNode();
3547 const SwStartNode
*pStNd
= (m_xTable
->m_bFirstCell
? pNd
->FindTableNode()
3548 : pNd
->FindTableBoxStartNode() );
3550 pCurTable
->SetTable( pStNd
, std::move(pTCntxt
), nLeftSpace
, nRightSpace
);
3553 // Freeze the context stack, since there could be attributes set
3554 // outside of cells. Can't happen earlier, since there may be
3555 // searches in the stack
3556 m_nContextStMin
= m_aContexts
.size();
3557 m_nContextStAttrMin
= m_nContextStMin
;
3560 xSaveStruct
.reset(new CellSaveStruct(*this, pCurTable
, bHead
, bReadOptions
));
3562 // If the first GetNextToken() doesn't succeed (pending input), must re-read from the beginning.
3563 SaveState( HtmlTokenId::NONE
);
3566 if( nToken
== HtmlTokenId::NONE
)
3567 nToken
= GetNextToken(); // Token after <TABLE>
3570 while( (IsParserWorking() && !bDone
) || bPending
)
3572 SaveState( nToken
);
3574 nToken
= FilterToken( nToken
);
3576 OSL_ENSURE( !m_vPendingStack
.empty() || !m_bCallNextToken
|| xSaveStruct
->IsInSection(),
3577 "Where is the section??" );
3578 if( m_vPendingStack
.empty() && m_bCallNextToken
&& xSaveStruct
->IsInSection() )
3580 // Call NextToken directly (e.g. ignore the content of floating frames or applets)
3581 NextToken( nToken
);
3583 else switch( nToken
)
3585 case HtmlTokenId::TABLEHEADER_ON
:
3586 case HtmlTokenId::TABLEDATA_ON
:
3587 case HtmlTokenId::TABLEROW_ON
:
3588 case HtmlTokenId::TABLEROW_OFF
:
3589 case HtmlTokenId::THEAD_ON
:
3590 case HtmlTokenId::THEAD_OFF
:
3591 case HtmlTokenId::TFOOT_ON
:
3592 case HtmlTokenId::TFOOT_OFF
:
3593 case HtmlTokenId::TBODY_ON
:
3594 case HtmlTokenId::TBODY_OFF
:
3595 case HtmlTokenId::TABLE_OFF
:
3598 case HtmlTokenId::TABLEHEADER_OFF
:
3599 case HtmlTokenId::TABLEDATA_OFF
:
3602 case HtmlTokenId::TABLE_ON
:
3604 bool bHasToFly
= false;
3605 SvxAdjust eTabAdjust
= SvxAdjust::End
;
3606 if( m_vPendingStack
.empty() )
3608 // only if we create a new table, but not if we're still
3609 // reading in the table after a Pending
3610 xSaveStruct
->m_xTable
= m_xTable
;
3612 // HACK: create a section for a table that goes in a text frame
3613 if( !xSaveStruct
->IsInSection() )
3615 // The loop needs to be forward, since the
3616 // first option always wins
3617 bool bNeedsSection
= false;
3618 const HTMLOptions
& rHTMLOptions
= GetOptions();
3619 for (const auto & rOption
: rHTMLOptions
)
3621 if( HtmlOptionId::ALIGN
==rOption
.GetToken() )
3623 SvxAdjust eAdjust
= rOption
.GetEnum( aHTMLPAlignTable
, SvxAdjust::End
);
3624 bNeedsSection
= SvxAdjust::Left
== eAdjust
||
3625 SvxAdjust::Right
== eAdjust
;
3631 xSaveStruct
->AddContents(
3632 InsertTableContents(bHead
) );
3637 // If Flys are anchored in the current paragraph,
3638 // the table needs to get in a text frame
3639 bHasToFly
= HasCurrentParaFlys(false,true);
3642 // There could be a section in the cell
3643 eTabAdjust
= m_xAttrTab
->pAdjust
3644 ? static_cast<const SvxAdjustItem
&>(m_xAttrTab
->pAdjust
->GetItem()).
3649 std::shared_ptr
<HTMLTable
> xSubTable
= BuildTable(eTabAdjust
,
3651 xSaveStruct
->IsInSection(),
3653 if( SvParserState::Pending
!= GetStatus() )
3655 // Only if the table is really complete
3658 OSL_ENSURE( xSubTable
->GetTableAdjust(false)!= SvxAdjust::Left
&&
3659 xSubTable
->GetTableAdjust(false)!= SvxAdjust::Right
,
3660 "left or right aligned tables belong in frames" );
3662 auto& rParentContents
= xSubTable
->GetParentContents();
3663 if (rParentContents
)
3665 OSL_ENSURE( !xSaveStruct
->IsInSection(),
3666 "Where is the section" );
3668 // If there's no table coming, we have a section
3669 xSaveStruct
->AddContents(std::move(rParentContents
));
3672 const SwStartNode
*pCapStNd
=
3673 xSubTable
->GetCaptionStartNode();
3675 if (xSubTable
->GetContext())
3677 OSL_ENSURE( !xSubTable
->GetContext()->GetFrameFormat(),
3680 if( pCapStNd
&& xSubTable
->IsTopCaption() )
3682 xSaveStruct
->AddContents(
3683 std::make_unique
<HTMLTableCnts
>(pCapStNd
) );
3686 xSaveStruct
->AddContents(
3687 std::make_unique
<HTMLTableCnts
>(xSubTable
) );
3689 if( pCapStNd
&& !xSubTable
->IsTopCaption() )
3691 xSaveStruct
->AddContents(
3692 std::make_unique
<HTMLTableCnts
>(pCapStNd
) );
3695 // We don't have a section anymore
3696 xSaveStruct
->ClearIsInSection();
3700 // Since we can't delete this section (it might
3701 // belong to the first box), we'll add it
3702 xSaveStruct
->AddContents(
3703 std::make_unique
<HTMLTableCnts
>(pCapStNd
) );
3705 // We don't have a section anymore
3706 xSaveStruct
->ClearIsInSection();
3710 m_xTable
= xSaveStruct
->m_xTable
;
3715 case HtmlTokenId::NOBR_ON
:
3716 // HACK for MS: Is the <NOBR> at the start of the cell?
3717 xSaveStruct
->StartNoBreak( *m_pPam
->GetPoint() );
3720 case HtmlTokenId::NOBR_OFF
:
3721 xSaveStruct
->EndNoBreak( *m_pPam
->GetPoint() );
3724 case HtmlTokenId::COMMENT
:
3725 // Spaces are not gonna be deleted with comment fields,
3726 // and we don't want a new cell for a comment
3727 NextToken( nToken
);
3730 case HtmlTokenId::MARQUEE_ON
:
3731 if( !xSaveStruct
->IsInSection() )
3733 // create a new section, the PaM is gonna be there
3734 xSaveStruct
->AddContents(
3735 InsertTableContents( bHead
) );
3737 m_bCallNextToken
= true;
3738 NewMarquee( pCurTable
);
3741 case HtmlTokenId::TEXTTOKEN
:
3742 // Don't add a section for an empty string
3743 if( !xSaveStruct
->IsInSection() && 1==aToken
.getLength() &&
3748 if( !xSaveStruct
->IsInSection() )
3750 // add a new section, the PaM's gonna be there
3751 xSaveStruct
->AddContents(
3752 InsertTableContents( bHead
) );
3755 if( IsParserWorking() || bPending
)
3756 NextToken( nToken
);
3760 OSL_ENSURE( !bPending
|| m_vPendingStack
.empty(),
3761 "SwHTMLParser::BuildTableCell: There is a PendStack again" );
3763 if( IsParserWorking() )
3764 SaveState( HtmlTokenId::NONE
);
3767 nToken
= GetNextToken();
3770 if( SvParserState::Pending
== GetStatus() )
3772 m_vPendingStack
.emplace_back( bHead
? HtmlTokenId::TABLEHEADER_ON
3773 : HtmlTokenId::TABLEDATA_ON
);
3774 m_vPendingStack
.back().pData
= std::move(xSaveStruct
);
3779 // If the content of the cell was empty, we need to create an empty content
3780 // We also create an empty content if the cell ended with a table and had no
3781 // COL tags. Otherwise, it was probably exported by us and we don't
3782 // want to have an additional paragraph
3783 if( !xSaveStruct
->HasFirstContents() ||
3784 (!xSaveStruct
->IsInSection() && !pCurTable
->HasColTags()) )
3786 OSL_ENSURE( xSaveStruct
->HasFirstContents() ||
3787 !xSaveStruct
->IsInSection(),
3788 "Section or not, that is the question here" );
3789 const SwStartNode
*pStNd
=
3790 InsertTableSection( static_cast< sal_uInt16
>(xSaveStruct
->IsHeaderCell()
3791 ? RES_POOLCOLL_TABLE_HDLN
3792 : RES_POOLCOLL_TABLE
));
3795 eState
= SvParserState::Error
;
3798 const SwEndNode
*pEndNd
= pStNd
->EndOfSectionNode();
3799 SwContentNode
*pCNd
= m_xDoc
->GetNodes()[pEndNd
->GetIndex()-1] ->GetContentNode();
3801 eState
= SvParserState::Error
;
3804 //Added defaults to CJK and CTL
3805 SvxFontHeightItem
aFontHeight( 40, 100, RES_CHRATR_FONTSIZE
);
3806 pCNd
->SetAttr( aFontHeight
);
3807 SvxFontHeightItem
aFontHeightCJK( 40, 100, RES_CHRATR_CJK_FONTSIZE
);
3808 pCNd
->SetAttr( aFontHeightCJK
);
3809 SvxFontHeightItem
aFontHeightCTL( 40, 100, RES_CHRATR_CTL_FONTSIZE
);
3810 pCNd
->SetAttr( aFontHeightCTL
);
3814 xSaveStruct
->AddContents( std::make_unique
<HTMLTableCnts
>(pStNd
) );
3815 xSaveStruct
->ClearIsInSection();
3818 if( xSaveStruct
->IsInSection() )
3820 xSaveStruct
->CheckNoBreak( *m_pPam
->GetPoint() );
3822 // End all open contexts. We'll take AttrMin because nContextStMin might
3823 // have been modified. Since it's gonna be restored by EndContext, it's okay
3824 while( m_aContexts
.size() > m_nContextStAttrMin
+1 )
3826 std::unique_ptr
<HTMLAttrContext
> xCntxt(PopContext());
3827 EndContext(xCntxt
.get());
3830 // Remove LFs at the paragraph end
3831 if (StripTrailingLF() == 0 && !m_pPam
->GetPoint()->nContent
.GetIndex())
3833 HTMLTableContext
* pTableContext
= m_xTable
? m_xTable
->GetContext() : nullptr;
3834 SwPosition
* pSavedPos
= pTableContext
? pTableContext
->GetPos() : nullptr;
3835 const bool bDeleteSafe
= !pSavedPos
|| pSavedPos
->nNode
!= m_pPam
->GetPoint()->nNode
;
3837 StripTrailingPara();
3840 // If there was an adjustment set for the cell, we need to close it
3841 std::unique_ptr
<HTMLAttrContext
> xCntxt(PopContext());
3843 EndContext(xCntxt
.get());
3847 // Close all still open contexts
3848 while( m_aContexts
.size() > m_nContextStAttrMin
)
3850 std::unique_ptr
<HTMLAttrContext
> xCntxt(PopContext());
3853 ClearContext(xCntxt
.get());
3857 // end an enumeration
3858 GetNumInfo().Clear();
3862 xSaveStruct
->InsertCell( *this, pCurTable
);
3864 // we're probably before a <TH>, <TD>, <TR> or </TABLE>
3865 xSaveStruct
.reset();
3870 class RowSaveStruct
: public SwPendingData
3878 eAdjust( SvxAdjust::End
), eVertOri( text::VertOrientation::TOP
), bHasCells( false )
3884 void SwHTMLParser::BuildTableRow( HTMLTable
*pCurTable
, bool bReadOptions
,
3885 SvxAdjust eGrpAdjust
,
3886 sal_Int16 eGrpVertOri
)
3888 // <TR> was already read
3890 if( !IsParserWorking() && m_vPendingStack
.empty() )
3893 HtmlTokenId nToken
= HtmlTokenId::NONE
;
3894 std::unique_ptr
<RowSaveStruct
> xSaveStruct
;
3896 bool bPending
= false;
3897 if( !m_vPendingStack
.empty() )
3899 xSaveStruct
.reset(static_cast<RowSaveStruct
*>(m_vPendingStack
.back().pData
.release()));
3901 m_vPendingStack
.pop_back();
3902 nToken
= !m_vPendingStack
.empty() ? m_vPendingStack
.back().nToken
: GetSaveToken();
3903 bPending
= SvParserState::Error
== eState
&& !m_vPendingStack
.empty();
3905 SaveState( nToken
);
3909 SvxAdjust eAdjust
= eGrpAdjust
;
3910 sal_Int16 eVertOri
= eGrpVertOri
;
3912 OUString aBGImage
, aStyle
, aId
, aClass
;
3913 bool bBGColor
= false;
3914 xSaveStruct
.reset(new RowSaveStruct
);
3918 const HTMLOptions
& rHTMLOptions
= GetOptions();
3919 for (size_t i
= rHTMLOptions
.size(); i
; )
3921 const HTMLOption
& rOption
= rHTMLOptions
[--i
];
3922 switch( rOption
.GetToken() )
3924 case HtmlOptionId::ID
:
3925 aId
= rOption
.GetString();
3927 case HtmlOptionId::ALIGN
:
3928 eAdjust
= rOption
.GetEnum( aHTMLPAlignTable
, eAdjust
);
3930 case HtmlOptionId::VALIGN
:
3931 eVertOri
= rOption
.GetEnum( aHTMLTableVAlignTable
, eVertOri
);
3933 case HtmlOptionId::BGCOLOR
:
3934 // Ignore empty BGCOLOR on <TABLE>, <TR> and <TD>/>TH> like Netscape
3935 // *really* not on other tags
3936 if( !rOption
.GetString().isEmpty() )
3938 rOption
.GetColor( aBGColor
);
3942 case HtmlOptionId::BACKGROUND
:
3943 aBGImage
= rOption
.GetString();
3945 case HtmlOptionId::STYLE
:
3946 aStyle
= rOption
.GetString();
3948 case HtmlOptionId::CLASS
:
3949 aClass
= rOption
.GetString();
3956 if( !aId
.isEmpty() )
3957 InsertBookmark( aId
);
3959 std::unique_ptr
<SvxBrushItem
> xBrushItem(
3960 CreateBrushItem( bBGColor
? &aBGColor
: nullptr, aBGImage
, aStyle
,
3962 pCurTable
->OpenRow(eAdjust
, eVertOri
, xBrushItem
);
3963 // If the first GetNextToken() doesn't succeed (pending input), must re-read from the beginning.
3964 SaveState( HtmlTokenId::NONE
);
3967 if( nToken
== HtmlTokenId::NONE
)
3968 nToken
= GetNextToken();
3971 while( (IsParserWorking() && !bDone
) || bPending
)
3973 SaveState( nToken
);
3975 nToken
= FilterToken( nToken
);
3977 OSL_ENSURE( !m_vPendingStack
.empty() || !m_bCallNextToken
||
3978 pCurTable
->GetContext() || pCurTable
->HasParentSection(),
3979 "Where is the section??" );
3980 if( m_vPendingStack
.empty() && m_bCallNextToken
&&
3981 (pCurTable
->GetContext() || pCurTable
->HasParentSection()) )
3983 /// Call NextToken directly (e.g. ignore the content of floating frames or applets)
3984 NextToken( nToken
);
3986 else switch( nToken
)
3988 case HtmlTokenId::TABLE_ON
:
3989 if( !pCurTable
->GetContext() )
3996 case HtmlTokenId::TABLEROW_ON
:
3997 case HtmlTokenId::THEAD_ON
:
3998 case HtmlTokenId::THEAD_OFF
:
3999 case HtmlTokenId::TBODY_ON
:
4000 case HtmlTokenId::TBODY_OFF
:
4001 case HtmlTokenId::TFOOT_ON
:
4002 case HtmlTokenId::TFOOT_OFF
:
4003 case HtmlTokenId::TABLE_OFF
:
4006 case HtmlTokenId::TABLEROW_OFF
:
4009 case HtmlTokenId::TABLEHEADER_ON
:
4010 case HtmlTokenId::TABLEDATA_ON
:
4011 BuildTableCell( pCurTable
, true, HtmlTokenId::TABLEHEADER_ON
==nToken
);
4012 if( SvParserState::Pending
!= GetStatus() )
4014 xSaveStruct
->bHasCells
= true;
4015 bDone
= m_xTable
->IsOverflowing();
4018 case HtmlTokenId::CAPTION_ON
:
4019 BuildTableCaption( pCurTable
);
4020 bDone
= m_xTable
->IsOverflowing();
4022 case HtmlTokenId::CAPTION_OFF
:
4023 case HtmlTokenId::TABLEHEADER_OFF
:
4024 case HtmlTokenId::TABLEDATA_OFF
:
4025 case HtmlTokenId::COLGROUP_ON
:
4026 case HtmlTokenId::COLGROUP_OFF
:
4027 case HtmlTokenId::COL_ON
:
4028 case HtmlTokenId::COL_OFF
:
4029 // Where no cell started, there can't be a cell ending
4030 // all the other tokens are bogus anyway and only break the table
4032 case HtmlTokenId::MULTICOL_ON
:
4033 // we can't add columned text frames here
4035 case HtmlTokenId::FORM_ON
:
4036 NewForm( false ); // don't create a new paragraph
4038 case HtmlTokenId::FORM_OFF
:
4039 EndForm( false ); // don't create a new paragraph
4041 case HtmlTokenId::COMMENT
:
4042 NextToken( nToken
);
4044 case HtmlTokenId::MAP_ON
:
4045 // an image map doesn't add anything, so we can parse it without a cell
4046 NextToken( nToken
);
4048 case HtmlTokenId::TEXTTOKEN
:
4049 if( (pCurTable
->GetContext() ||
4050 !pCurTable
->HasParentSection()) &&
4051 1==aToken
.getLength() && ' '==aToken
[0] )
4055 pCurTable
->MakeParentContents();
4056 NextToken( nToken
);
4060 OSL_ENSURE( !bPending
|| m_vPendingStack
.empty(),
4061 "SwHTMLParser::BuildTableRow: There is a PendStack again" );
4063 if( IsParserWorking() )
4064 SaveState( HtmlTokenId::NONE
);
4067 nToken
= GetNextToken();
4070 if( SvParserState::Pending
== GetStatus() )
4072 m_vPendingStack
.emplace_back( HtmlTokenId::TABLEROW_ON
);
4073 m_vPendingStack
.back().pData
= std::move(xSaveStruct
);
4077 pCurTable
->CloseRow(!xSaveStruct
->bHasCells
);
4078 xSaveStruct
.reset();
4081 // we're probably before <TR> or </TABLE>
4084 void SwHTMLParser::BuildTableSection( HTMLTable
*pCurTable
,
4088 // <THEAD>, <TBODY> resp. <TFOOT> were read already
4089 if( !IsParserWorking() && m_vPendingStack
.empty() )
4092 HtmlTokenId nToken
= HtmlTokenId::NONE
;
4093 bool bPending
= false;
4094 std::unique_ptr
<RowSaveStruct
> xSaveStruct
;
4096 if( !m_vPendingStack
.empty() )
4098 xSaveStruct
.reset(static_cast<RowSaveStruct
*>(m_vPendingStack
.back().pData
.release()));
4100 m_vPendingStack
.pop_back();
4101 nToken
= !m_vPendingStack
.empty() ? m_vPendingStack
.back().nToken
: GetSaveToken();
4102 bPending
= SvParserState::Error
== eState
&& !m_vPendingStack
.empty();
4104 SaveState( nToken
);
4108 xSaveStruct
.reset(new RowSaveStruct
);
4112 const HTMLOptions
& rHTMLOptions
= GetOptions();
4113 for (size_t i
= rHTMLOptions
.size(); i
; )
4115 const HTMLOption
& rOption
= rHTMLOptions
[--i
];
4116 switch( rOption
.GetToken() )
4118 case HtmlOptionId::ID
:
4119 InsertBookmark( rOption
.GetString() );
4121 case HtmlOptionId::ALIGN
:
4122 xSaveStruct
->eAdjust
=
4123 rOption
.GetEnum( aHTMLPAlignTable
, xSaveStruct
->eAdjust
);
4125 case HtmlOptionId::VALIGN
:
4126 xSaveStruct
->eVertOri
=
4127 rOption
.GetEnum( aHTMLTableVAlignTable
,
4128 xSaveStruct
->eVertOri
);
4135 // If the first GetNextToken() doesn't succeed (pending input), must re-read from the beginning.
4136 SaveState( HtmlTokenId::NONE
);
4139 if( nToken
== HtmlTokenId::NONE
)
4140 nToken
= GetNextToken();
4143 while( (IsParserWorking() && !bDone
) || bPending
)
4145 SaveState( nToken
);
4147 nToken
= FilterToken( nToken
);
4149 OSL_ENSURE( !m_vPendingStack
.empty() || !m_bCallNextToken
||
4150 pCurTable
->GetContext() || pCurTable
->HasParentSection(),
4151 "Where is the section?" );
4152 if( m_vPendingStack
.empty() && m_bCallNextToken
&&
4153 (pCurTable
->GetContext() || pCurTable
->HasParentSection()) )
4155 // Call NextToken directly (e.g. ignore the content of floating frames or applets)
4156 NextToken( nToken
);
4158 else switch( nToken
)
4160 case HtmlTokenId::TABLE_ON
:
4161 if( !pCurTable
->GetContext() )
4168 case HtmlTokenId::THEAD_ON
:
4169 case HtmlTokenId::TFOOT_ON
:
4170 case HtmlTokenId::TBODY_ON
:
4171 case HtmlTokenId::TABLE_OFF
:
4174 case HtmlTokenId::THEAD_OFF
:
4175 case HtmlTokenId::TBODY_OFF
:
4176 case HtmlTokenId::TFOOT_OFF
:
4179 case HtmlTokenId::CAPTION_ON
:
4180 BuildTableCaption( pCurTable
);
4181 bDone
= m_xTable
->IsOverflowing();
4183 case HtmlTokenId::CAPTION_OFF
:
4185 case HtmlTokenId::TABLEHEADER_ON
:
4186 case HtmlTokenId::TABLEDATA_ON
:
4188 BuildTableRow( pCurTable
, false, xSaveStruct
->eAdjust
,
4189 xSaveStruct
->eVertOri
);
4190 bDone
= m_xTable
->IsOverflowing();
4192 case HtmlTokenId::TABLEROW_ON
:
4193 BuildTableRow( pCurTable
, true, xSaveStruct
->eAdjust
,
4194 xSaveStruct
->eVertOri
);
4195 bDone
= m_xTable
->IsOverflowing();
4197 case HtmlTokenId::MULTICOL_ON
:
4198 // we can't add columned text frames here
4200 case HtmlTokenId::FORM_ON
:
4201 NewForm( false ); // don't create a new paragraph
4203 case HtmlTokenId::FORM_OFF
:
4204 EndForm( false ); // don't create a new paragraph
4206 case HtmlTokenId::TEXTTOKEN
:
4207 // blank strings may be a series of CR+LF and no text
4208 if( (pCurTable
->GetContext() ||
4209 !pCurTable
->HasParentSection()) &&
4210 1==aToken
.getLength() && ' ' == aToken
[0] )
4214 pCurTable
->MakeParentContents();
4215 NextToken( nToken
);
4218 OSL_ENSURE( !bPending
|| m_vPendingStack
.empty(),
4219 "SwHTMLParser::BuildTableSection: There is a PendStack again" );
4221 if( IsParserWorking() )
4222 SaveState( HtmlTokenId::NONE
);
4225 nToken
= GetNextToken();
4228 if( SvParserState::Pending
== GetStatus() )
4230 m_vPendingStack
.emplace_back( bHead
? HtmlTokenId::THEAD_ON
4231 : HtmlTokenId::TBODY_ON
);
4232 m_vPendingStack
.back().pData
= std::move(xSaveStruct
);
4236 pCurTable
->CloseSection( bHead
);
4237 xSaveStruct
.reset();
4240 // now we stand (perhaps) in front of <TBODY>,... or </TABLE>
4245 struct TableColGrpSaveStruct
: public SwPendingData
4247 sal_uInt16 nColGrpSpan
;
4248 sal_uInt16 nColGrpWidth
;
4249 bool bRelColGrpWidth
;
4250 SvxAdjust eColGrpAdjust
;
4251 sal_Int16 eColGrpVertOri
;
4253 inline TableColGrpSaveStruct();
4255 inline void CloseColGroup( HTMLTable
*pTable
);
4260 inline TableColGrpSaveStruct::TableColGrpSaveStruct() :
4261 nColGrpSpan( 1 ), nColGrpWidth( 0 ),
4262 bRelColGrpWidth( false ), eColGrpAdjust( SvxAdjust::End
),
4263 eColGrpVertOri( text::VertOrientation::TOP
)
4266 inline void TableColGrpSaveStruct::CloseColGroup( HTMLTable
*pTable
)
4268 pTable
->CloseColGroup( nColGrpSpan
, nColGrpWidth
,
4269 bRelColGrpWidth
, eColGrpAdjust
, eColGrpVertOri
);
4272 void SwHTMLParser::BuildTableColGroup( HTMLTable
*pCurTable
,
4275 // <COLGROUP> was read already if bReadOptions is set
4277 if( !IsParserWorking() && m_vPendingStack
.empty() )
4280 HtmlTokenId nToken
= HtmlTokenId::NONE
;
4281 bool bPending
= false;
4282 std::unique_ptr
<TableColGrpSaveStruct
> pSaveStruct
;
4284 if( !m_vPendingStack
.empty() )
4286 pSaveStruct
.reset(static_cast<TableColGrpSaveStruct
*>(m_vPendingStack
.back().pData
.release()));
4289 m_vPendingStack
.pop_back();
4290 nToken
= !m_vPendingStack
.empty() ? m_vPendingStack
.back().nToken
: GetSaveToken();
4291 bPending
= SvParserState::Error
== eState
&& !m_vPendingStack
.empty();
4293 SaveState( nToken
);
4298 pSaveStruct
.reset(new TableColGrpSaveStruct
);
4301 const HTMLOptions
& rColGrpOptions
= GetOptions();
4302 for (size_t i
= rColGrpOptions
.size(); i
; )
4304 const HTMLOption
& rOption
= rColGrpOptions
[--i
];
4305 switch( rOption
.GetToken() )
4307 case HtmlOptionId::ID
:
4308 InsertBookmark( rOption
.GetString() );
4310 case HtmlOptionId::SPAN
:
4311 pSaveStruct
->nColGrpSpan
= o3tl::narrowing
<sal_uInt16
>(rOption
.GetNumber());
4312 if (pSaveStruct
->nColGrpSpan
> 256)
4314 SAL_INFO("sw.html", "ignoring huge SPAN " << pSaveStruct
->nColGrpSpan
);
4315 pSaveStruct
->nColGrpSpan
= 1;
4318 case HtmlOptionId::WIDTH
:
4319 pSaveStruct
->nColGrpWidth
= o3tl::narrowing
<sal_uInt16
>(rOption
.GetNumber());
4320 pSaveStruct
->bRelColGrpWidth
=
4321 (rOption
.GetString().indexOf('*') != -1);
4323 case HtmlOptionId::ALIGN
:
4324 pSaveStruct
->eColGrpAdjust
=
4325 rOption
.GetEnum( aHTMLPAlignTable
, pSaveStruct
->eColGrpAdjust
);
4327 case HtmlOptionId::VALIGN
:
4328 pSaveStruct
->eColGrpVertOri
=
4329 rOption
.GetEnum( aHTMLTableVAlignTable
,
4330 pSaveStruct
->eColGrpVertOri
);
4336 // If the first GetNextToken() doesn't succeed (pending input), must re-read from the beginning.
4337 SaveState( HtmlTokenId::NONE
);
4340 if( nToken
== HtmlTokenId::NONE
)
4341 nToken
= GetNextToken(); // naechstes Token
4344 while( (IsParserWorking() && !bDone
) || bPending
)
4346 SaveState( nToken
);
4348 nToken
= FilterToken( nToken
);
4350 OSL_ENSURE( !m_vPendingStack
.empty() || !m_bCallNextToken
||
4351 pCurTable
->GetContext() || pCurTable
->HasParentSection(),
4352 "Where is the section?" );
4353 if( m_vPendingStack
.empty() && m_bCallNextToken
&&
4354 (pCurTable
->GetContext() || pCurTable
->HasParentSection()) )
4356 // Call NextToken directly (e.g. ignore the content of floating frames or applets)
4357 NextToken( nToken
);
4359 else switch( nToken
)
4361 case HtmlTokenId::TABLE_ON
:
4362 if( !pCurTable
->GetContext() )
4369 case HtmlTokenId::COLGROUP_ON
:
4370 case HtmlTokenId::THEAD_ON
:
4371 case HtmlTokenId::TFOOT_ON
:
4372 case HtmlTokenId::TBODY_ON
:
4373 case HtmlTokenId::TABLEROW_ON
:
4374 case HtmlTokenId::TABLE_OFF
:
4377 case HtmlTokenId::COLGROUP_OFF
:
4380 case HtmlTokenId::COL_ON
:
4382 sal_uInt16 nColSpan
= 1;
4383 sal_uInt16 nColWidth
= pSaveStruct
->nColGrpWidth
;
4384 bool bRelColWidth
= pSaveStruct
->bRelColGrpWidth
;
4385 SvxAdjust eColAdjust
= pSaveStruct
->eColGrpAdjust
;
4386 sal_Int16 eColVertOri
= pSaveStruct
->eColGrpVertOri
;
4388 const HTMLOptions
& rColOptions
= GetOptions();
4389 for (size_t i
= rColOptions
.size(); i
; )
4391 const HTMLOption
& rOption
= rColOptions
[--i
];
4392 switch( rOption
.GetToken() )
4394 case HtmlOptionId::ID
:
4395 InsertBookmark( rOption
.GetString() );
4397 case HtmlOptionId::SPAN
:
4398 nColSpan
= o3tl::narrowing
<sal_uInt16
>(rOption
.GetNumber());
4401 SAL_INFO("sw.html", "ignoring huge SPAN " << nColSpan
);
4405 case HtmlOptionId::WIDTH
:
4406 nColWidth
= o3tl::narrowing
<sal_uInt16
>(rOption
.GetNumber());
4408 (rOption
.GetString().indexOf('*') != -1);
4410 case HtmlOptionId::ALIGN
:
4411 eColAdjust
= rOption
.GetEnum( aHTMLPAlignTable
, eColAdjust
);
4413 case HtmlOptionId::VALIGN
:
4415 rOption
.GetEnum( aHTMLTableVAlignTable
, eColVertOri
);
4420 pCurTable
->InsertCol( nColSpan
, nColWidth
, bRelColWidth
,
4421 eColAdjust
, eColVertOri
);
4423 // the attributes in <COLGRP> should be ignored, if there are <COL> elements
4424 pSaveStruct
->nColGrpSpan
= 0;
4427 case HtmlTokenId::COL_OFF
:
4429 case HtmlTokenId::MULTICOL_ON
:
4430 // we can't add columned text frames here
4432 case HtmlTokenId::TEXTTOKEN
:
4433 if( (pCurTable
->GetContext() ||
4434 !pCurTable
->HasParentSection()) &&
4435 1==aToken
.getLength() && ' '==aToken
[0] )
4439 pCurTable
->MakeParentContents();
4440 NextToken( nToken
);
4443 OSL_ENSURE( !bPending
|| m_vPendingStack
.empty(),
4444 "SwHTMLParser::BuildTableColGrp: There is a PendStack again" );
4446 if( IsParserWorking() )
4447 SaveState( HtmlTokenId::NONE
);
4450 nToken
= GetNextToken();
4453 if( SvParserState::Pending
== GetStatus() )
4455 m_vPendingStack
.emplace_back( HtmlTokenId::COL_ON
);
4456 m_vPendingStack
.back().pData
= std::move(pSaveStruct
);
4460 pSaveStruct
->CloseColGroup( pCurTable
);
4464 class CaptionSaveStruct
: public SectionSaveStruct
4466 SwPosition m_aSavePos
;
4467 SwHTMLNumRuleInfo m_aNumRuleInfo
; // valid numbering
4471 std::shared_ptr
<HTMLAttrTable
> m_xAttrTab
; // attributes
4473 CaptionSaveStruct( SwHTMLParser
& rParser
, const SwPosition
& rPos
) :
4474 SectionSaveStruct( rParser
), m_aSavePos( rPos
),
4475 m_xAttrTab(std::make_shared
<HTMLAttrTable
>())
4477 rParser
.SaveAttrTab(m_xAttrTab
);
4479 // The current numbering was remembered and just needs to be closed
4480 m_aNumRuleInfo
.Set( rParser
.GetNumInfo() );
4481 rParser
.GetNumInfo().Clear();
4484 const SwPosition
& GetPos() const { return m_aSavePos
; }
4486 void RestoreAll( SwHTMLParser
& rParser
)
4488 // Recover the old stack
4491 // Recover the old attribute tables
4492 rParser
.RestoreAttrTab(m_xAttrTab
);
4494 // Re-open the old numbering
4495 rParser
.GetNumInfo().Set( m_aNumRuleInfo
);
4499 void SwHTMLParser::BuildTableCaption( HTMLTable
*pCurTable
)
4501 // <CAPTION> was read already
4503 if( !IsParserWorking() && m_vPendingStack
.empty() )
4506 HtmlTokenId nToken
= HtmlTokenId::NONE
;
4507 std::unique_ptr
<CaptionSaveStruct
> xSaveStruct
;
4509 if( !m_vPendingStack
.empty() )
4511 xSaveStruct
.reset(static_cast<CaptionSaveStruct
*>(m_vPendingStack
.back().pData
.release()));
4513 m_vPendingStack
.pop_back();
4514 nToken
= !m_vPendingStack
.empty() ? m_vPendingStack
.back().nToken
: GetSaveToken();
4515 OSL_ENSURE( m_vPendingStack
.empty(), "Where does a PendStack coming from?" );
4517 SaveState( nToken
);
4521 if (m_xTable
->IsOverflowing())
4523 SaveState( HtmlTokenId::NONE
);
4528 const HTMLOptions
& rHTMLOptions
= GetOptions();
4529 for ( size_t i
= rHTMLOptions
.size(); i
; )
4531 const HTMLOption
& rOption
= rHTMLOptions
[--i
];
4532 if( HtmlOptionId::ALIGN
== rOption
.GetToken() )
4534 if (rOption
.GetString().equalsIgnoreAsciiCase(
4535 OOO_STRING_SVTOOLS_HTML_VA_bottom
))
4542 // Remember old PaM position
4543 xSaveStruct
.reset(new CaptionSaveStruct(*this, *m_pPam
->GetPoint()));
4545 // Add a text section in the icon section as a container for the header
4546 // and set the PaM there
4547 const SwStartNode
*pStNd
;
4548 if (m_xTable
.get() == pCurTable
)
4549 pStNd
= InsertTempTableCaptionSection();
4551 pStNd
= InsertTableSection( RES_POOLCOLL_TEXT
);
4553 std::unique_ptr
<HTMLAttrContext
> xCntxt(new HTMLAttrContext(HtmlTokenId::CAPTION_ON
));
4555 // Table headers are always centered
4556 NewAttr(m_xAttrTab
, &m_xAttrTab
->pAdjust
, SvxAdjustItem(SvxAdjust::Center
, RES_PARATR_ADJUST
));
4558 HTMLAttrs
&rAttrs
= xCntxt
->GetAttrs();
4559 rAttrs
.push_back( m_xAttrTab
->pAdjust
);
4561 PushContext(xCntxt
);
4563 // Remember the start node of the section at the table
4564 pCurTable
->SetCaption( pStNd
, bTop
);
4566 // If the first GetNextToken() doesn't succeed (pending input), must re-read from the beginning.
4567 SaveState( HtmlTokenId::NONE
);
4570 if( nToken
== HtmlTokenId::NONE
)
4571 nToken
= GetNextToken();
4573 // </CAPTION> is needed according to DTD
4575 while( IsParserWorking() && !bDone
)
4577 SaveState( nToken
);
4579 nToken
= FilterToken( nToken
);
4583 case HtmlTokenId::TABLE_ON
:
4584 if( m_vPendingStack
.empty() )
4586 xSaveStruct
->m_xTable
= m_xTable
;
4587 bool bHasToFly
= xSaveStruct
->m_xTable
.get() != pCurTable
;
4588 BuildTable( pCurTable
->GetTableAdjust( true ),
4589 false, true, bHasToFly
);
4593 BuildTable( SvxAdjust::End
);
4595 if( SvParserState::Pending
!= GetStatus() )
4597 m_xTable
= xSaveStruct
->m_xTable
;
4600 case HtmlTokenId::TABLE_OFF
:
4601 case HtmlTokenId::COLGROUP_ON
:
4602 case HtmlTokenId::THEAD_ON
:
4603 case HtmlTokenId::TFOOT_ON
:
4604 case HtmlTokenId::TBODY_ON
:
4605 case HtmlTokenId::TABLEROW_ON
:
4610 case HtmlTokenId::CAPTION_OFF
:
4614 if( !m_vPendingStack
.empty() )
4616 m_vPendingStack
.pop_back();
4617 OSL_ENSURE( m_vPendingStack
.empty(), "Further it can't go!" );
4620 if( IsParserWorking() )
4621 NextToken( nToken
);
4625 if( IsParserWorking() )
4626 SaveState( HtmlTokenId::NONE
);
4629 nToken
= GetNextToken();
4632 if( SvParserState::Pending
==GetStatus() )
4634 m_vPendingStack
.emplace_back( HtmlTokenId::CAPTION_ON
);
4635 m_vPendingStack
.back().pData
= std::move(xSaveStruct
);
4639 // end all still open contexts
4640 while( m_aContexts
.size() > m_nContextStAttrMin
+1 )
4642 std::unique_ptr
<HTMLAttrContext
> xCntxt(PopContext());
4643 EndContext(xCntxt
.get());
4646 bool bLFStripped
= StripTrailingLF() > 0;
4648 if (m_xTable
.get() == pCurTable
)
4650 // On moving the caption later, the last paragraph isn't moved as well.
4651 // That means, there has to be an empty paragraph at the end of the section
4652 if( m_pPam
->GetPoint()->nContent
.GetIndex() || bLFStripped
)
4653 AppendTextNode( AM_NOSPACE
);
4657 // Strip LFs at the end of the paragraph
4658 if( !m_pPam
->GetPoint()->nContent
.GetIndex() && !bLFStripped
)
4659 StripTrailingPara();
4662 // If there's an adjustment for the cell, we need to close it
4663 std::unique_ptr
<HTMLAttrContext
> xCntxt(PopContext());
4666 EndContext(xCntxt
.get());
4672 // Recover stack and attribute table
4673 xSaveStruct
->RestoreAll(*this);
4676 *m_pPam
->GetPoint() = xSaveStruct
->GetPos();
4681 class TableSaveStruct
: public SwPendingData
4684 std::shared_ptr
<HTMLTable
> m_xCurrentTable
;
4686 explicit TableSaveStruct(const std::shared_ptr
<HTMLTable
>& rCurTable
)
4687 : m_xCurrentTable(rCurTable
)
4691 // Initiate creation of the table and put the table in a text frame if
4692 // needed. If it returns true, we need to insert a paragraph.
4693 void MakeTable( sal_uInt16 nWidth
, SwPosition
& rPos
, SwDoc
*pDoc
);
4698 void TableSaveStruct::MakeTable( sal_uInt16 nWidth
, SwPosition
& rPos
, SwDoc
*pDoc
)
4700 m_xCurrentTable
->MakeTable(nullptr, nWidth
);
4702 HTMLTableContext
*pTCntxt
= m_xCurrentTable
->GetContext();
4703 OSL_ENSURE( pTCntxt
, "Where is the table context" );
4705 SwTableNode
*pTableNd
= pTCntxt
->GetTableNode();
4706 OSL_ENSURE( pTableNd
, "Where is the table node" );
4708 if( pDoc
->getIDocumentLayoutAccess().GetCurrentViewShell() && pTableNd
)
4710 // If there's already a layout, the BoxFrames need to be regenerated at this table
4712 if( pTCntxt
->GetFrameFormat() )
4714 pTCntxt
->GetFrameFormat()->DelFrames();
4715 pTableNd
->DelFrames();
4716 pTCntxt
->GetFrameFormat()->MakeFrames();
4720 pTableNd
->DelFrames();
4721 SwNodeIndex
aIdx( *pTableNd
->EndOfSectionNode(), 1 );
4722 OSL_ENSURE( aIdx
.GetIndex() <= pTCntxt
->GetPos()->nNode
.GetIndex(),
4723 "unexpected node for table layout" );
4724 pTableNd
->MakeOwnFrames(&aIdx
);
4728 rPos
= *pTCntxt
->GetPos();
4731 HTMLTableOptions::HTMLTableOptions( const HTMLOptions
& rOptions
,
4732 SvxAdjust eParentAdjust
) :
4734 nWidth( 0 ), nHeight( 0 ),
4735 nCellPadding( USHRT_MAX
), nCellSpacing( USHRT_MAX
),
4736 nBorder( USHRT_MAX
),
4737 nHSpace( 0 ), nVSpace( 0 ),
4738 eAdjust( eParentAdjust
), eVertOri( text::VertOrientation::CENTER
),
4739 eFrame( HTMLTableFrame::Void
), eRules( HTMLTableRules::NONE
),
4740 bPercentWidth( false ),
4741 bTableAdjust( false ),
4743 aBorderColor( COL_GRAY
)
4745 bool bBorderColor
= false;
4746 bool bHasFrame
= false, bHasRules
= false;
4748 for (size_t i
= rOptions
.size(); i
; )
4750 const HTMLOption
& rOption
= rOptions
[--i
];
4751 switch( rOption
.GetToken() )
4753 case HtmlOptionId::ID
:
4754 aId
= rOption
.GetString();
4756 case HtmlOptionId::COLS
:
4757 nCols
= o3tl::narrowing
<sal_uInt16
>(rOption
.GetNumber());
4759 case HtmlOptionId::WIDTH
:
4760 nWidth
= o3tl::narrowing
<sal_uInt16
>(rOption
.GetNumber());
4761 bPercentWidth
= (rOption
.GetString().indexOf('%') != -1);
4762 if( bPercentWidth
&& nWidth
>100 )
4765 case HtmlOptionId::HEIGHT
:
4766 nHeight
= o3tl::narrowing
<sal_uInt16
>(rOption
.GetNumber());
4767 if( rOption
.GetString().indexOf('%') != -1 )
4768 nHeight
= 0; // don't use % attributes
4770 case HtmlOptionId::CELLPADDING
:
4771 nCellPadding
= o3tl::narrowing
<sal_uInt16
>(rOption
.GetNumber());
4773 case HtmlOptionId::CELLSPACING
:
4774 nCellSpacing
= o3tl::narrowing
<sal_uInt16
>(rOption
.GetNumber());
4776 case HtmlOptionId::ALIGN
:
4778 if( rOption
.GetEnum( eAdjust
, aHTMLPAlignTable
) )
4780 bTableAdjust
= true;
4784 case HtmlOptionId::VALIGN
:
4785 eVertOri
= rOption
.GetEnum( aHTMLTableVAlignTable
, eVertOri
);
4787 case HtmlOptionId::BORDER
:
4788 // Handle BORDER and BORDER=BORDER like BORDER=1
4789 if (!rOption
.GetString().isEmpty() &&
4790 !rOption
.GetString().equalsIgnoreAsciiCase(
4791 OOO_STRING_SVTOOLS_HTML_O_border
))
4793 nBorder
= o3tl::narrowing
<sal_uInt16
>(rOption
.GetNumber());
4799 eFrame
= ( nBorder
? HTMLTableFrame::Box
: HTMLTableFrame::Void
);
4801 eRules
= ( nBorder
? HTMLTableRules::All
: HTMLTableRules::NONE
);
4803 case HtmlOptionId::FRAME
:
4804 eFrame
= rOption
.GetTableFrame();
4807 case HtmlOptionId::RULES
:
4808 eRules
= rOption
.GetTableRules();
4811 case HtmlOptionId::BGCOLOR
:
4812 // Ignore empty BGCOLOR on <TABLE>, <TR> and <TD>/<TH> like Netscape
4813 // *really* not on other tags
4814 if( !rOption
.GetString().isEmpty() )
4816 rOption
.GetColor( aBGColor
);
4820 case HtmlOptionId::BACKGROUND
:
4821 aBGImage
= rOption
.GetString();
4823 case HtmlOptionId::BORDERCOLOR
:
4824 rOption
.GetColor( aBorderColor
);
4825 bBorderColor
= true;
4827 case HtmlOptionId::BORDERCOLORDARK
:
4829 rOption
.GetColor( aBorderColor
);
4831 case HtmlOptionId::STYLE
:
4832 aStyle
= rOption
.GetString();
4834 case HtmlOptionId::CLASS
:
4835 aClass
= rOption
.GetString();
4837 case HtmlOptionId::DIR:
4838 aDir
= rOption
.GetString();
4840 case HtmlOptionId::HSPACE
:
4841 nHSpace
= o3tl::narrowing
<sal_uInt16
>(rOption
.GetNumber());
4843 case HtmlOptionId::VSPACE
:
4844 nVSpace
= o3tl::narrowing
<sal_uInt16
>(rOption
.GetNumber());
4850 if( nCols
&& !nWidth
)
4853 bPercentWidth
= true;
4856 // If BORDER=0 or no BORDER given, then there shouldn't be a border
4857 if( 0==nBorder
|| USHRT_MAX
==nBorder
)
4859 eFrame
= HTMLTableFrame::Void
;
4860 eRules
= HTMLTableRules::NONE
;
4869 SwNodeIndex maStart
;
4872 explicit IndexInRange(const SwNodeIndex
& rStart
, const SwNodeIndex
& rEnd
)
4877 bool operator()(const SwHTMLTextFootnote
& rTextFootnote
) const
4879 const SwNodeIndex
aTextIdx(rTextFootnote
.pTextFootnote
->GetTextNode());
4880 return aTextIdx
>= maStart
&& aTextIdx
<= maEnd
;
4885 void SwHTMLParser::ClearFootnotesMarksInRange(const SwNodeIndex
& rMkNdIdx
, const SwNodeIndex
& rPtNdIdx
)
4887 //similarly for footnotes
4888 if (m_pFootEndNoteImpl
)
4890 m_pFootEndNoteImpl
->aTextFootnotes
.erase(std::remove_if(m_pFootEndNoteImpl
->aTextFootnotes
.begin(),
4891 m_pFootEndNoteImpl
->aTextFootnotes
.end(), IndexInRange(rMkNdIdx
, rPtNdIdx
)), m_pFootEndNoteImpl
->aTextFootnotes
.end());
4892 if (m_pFootEndNoteImpl
->aTextFootnotes
.empty())
4894 m_pFootEndNoteImpl
.reset();
4898 //follow DelFlyInRange pattern here
4899 assert(rMkNdIdx
.GetIndex() <= rPtNdIdx
.GetIndex());
4901 SwDoc
& rDoc
= rMkNdIdx
.GetNode().GetDoc();
4903 //ofz#9733 drop bookmarks in this range
4904 IDocumentMarkAccess
* const pMarkAccess
= rDoc
.getIDocumentMarkAccess();
4905 pMarkAccess
->deleteMarks(rMkNdIdx
, SwNodeIndex(rPtNdIdx
, 1), nullptr, nullptr, nullptr);
4907 SwFrameFormats
& rTable
= *rDoc
.GetSpzFrameFormats();
4908 for ( auto i
= rTable
.size(); i
; )
4910 SwFrameFormat
*pFormat
= rTable
[--i
];
4911 const SwFormatAnchor
&rAnch
= pFormat
->GetAnchor();
4912 SwPosition
const*const pAPos
= rAnch
.GetContentAnchor();
4914 ((rAnch
.GetAnchorId() == RndStdIds::FLY_AT_PARA
) ||
4915 (rAnch
.GetAnchorId() == RndStdIds::FLY_AT_CHAR
)) &&
4916 ( rMkNdIdx
< pAPos
->nNode
&& pAPos
->nNode
<= rPtNdIdx
))
4918 if( rPtNdIdx
!= pAPos
->nNode
)
4920 // If the Fly is deleted, all Flys in its content have to be deleted too.
4921 const SwFormatContent
&rContent
= pFormat
->GetContent();
4922 // But only fly formats own their content, not draw formats.
4923 if (rContent
.GetContentIdx() && pFormat
->Which() == RES_FLYFRMFMT
)
4925 ClearFootnotesMarksInRange(*rContent
.GetContentIdx(),
4926 SwNodeIndex(*rContent
.GetContentIdx()->GetNode().EndOfSectionNode()));
4933 void SwHTMLParser::DeleteSection(SwStartNode
* pSttNd
)
4935 //if section to be deleted contains a pending m_pMarquee, it will be deleted
4936 //so clear m_pMarquee pointer if that's the case
4937 SwFrameFormat
* pObjectFormat
= m_pMarquee
? ::FindFrameFormat(m_pMarquee
) : nullptr;
4938 FrameDeleteWatch
aWatch(pObjectFormat
);
4940 //similarly for footnotes
4941 SwNodeIndex
aSttIdx(*pSttNd
), aEndIdx(*pSttNd
->EndOfSectionNode());
4942 ClearFootnotesMarksInRange(aSttIdx
, aEndIdx
);
4944 m_xDoc
->getIDocumentContentOperations().DeleteSection(pSttNd
);
4948 if (aWatch
.WasDeleted())
4949 m_pMarquee
= nullptr;
4951 aWatch
.EndListeningAll();
4955 std::shared_ptr
<HTMLTable
> SwHTMLParser::BuildTable(SvxAdjust eParentAdjust
,
4957 bool bHasParentSection
,
4960 TableDepthGuard
aGuard(*this);
4961 if (aGuard
.TooDeep())
4962 eState
= SvParserState::Error
;
4964 if (!IsParserWorking() && m_vPendingStack
.empty())
4965 return std::shared_ptr
<HTMLTable
>();
4967 ::comphelper::FlagRestorationGuard
g(m_isInTableStructure
, true);
4968 HtmlTokenId nToken
= HtmlTokenId::NONE
;
4969 bool bPending
= false;
4970 std::unique_ptr
<TableSaveStruct
> xSaveStruct
;
4972 if( !m_vPendingStack
.empty() )
4974 xSaveStruct
.reset(static_cast<TableSaveStruct
*>(m_vPendingStack
.back().pData
.release()));
4976 m_vPendingStack
.pop_back();
4977 nToken
= !m_vPendingStack
.empty() ? m_vPendingStack
.back().nToken
: GetSaveToken();
4978 bPending
= SvParserState::Error
== eState
&& !m_vPendingStack
.empty();
4980 SaveState( nToken
);
4985 HTMLTableOptions
aTableOptions(GetOptions(), eParentAdjust
);
4987 if (!aTableOptions
.aId
.isEmpty())
4988 InsertBookmark(aTableOptions
.aId
);
4990 std::shared_ptr
<HTMLTable
> xCurTable(std::make_shared
<HTMLTable
>(this,
4995 m_xTable
= xCurTable
;
4997 xSaveStruct
.reset(new TableSaveStruct(xCurTable
));
4999 // Is pending on the first GetNextToken, needs to be re-read on each construction
5000 SaveState( HtmlTokenId::NONE
);
5003 std::shared_ptr
<HTMLTable
> xCurTable
= xSaveStruct
->m_xCurrentTable
;
5005 // </TABLE> is needed according to DTD
5006 if( nToken
== HtmlTokenId::NONE
)
5007 nToken
= GetNextToken();
5010 while( (IsParserWorking() && !bDone
) || bPending
)
5012 SaveState( nToken
);
5014 nToken
= FilterToken( nToken
);
5016 OSL_ENSURE( !m_vPendingStack
.empty() || !m_bCallNextToken
||
5017 xCurTable
->GetContext() || xCurTable
->HasParentSection(),
5018 "Where is the section?" );
5019 if( m_vPendingStack
.empty() && m_bCallNextToken
&&
5020 (xCurTable
->GetContext() || xCurTable
->HasParentSection()) )
5022 /// Call NextToken directly (e.g. ignore the content of floating frames or applets)
5023 NextToken( nToken
);
5025 else switch( nToken
)
5027 case HtmlTokenId::TABLE_ON
:
5028 if( !xCurTable
->GetContext() )
5030 // If there's no table added, read the next table'
5036 case HtmlTokenId::TABLE_OFF
:
5039 case HtmlTokenId::CAPTION_ON
:
5040 BuildTableCaption(xCurTable
.get());
5041 bDone
= m_xTable
->IsOverflowing();
5043 case HtmlTokenId::COL_ON
:
5045 BuildTableColGroup(xCurTable
.get(), false);
5047 case HtmlTokenId::COLGROUP_ON
:
5048 BuildTableColGroup(xCurTable
.get(), true);
5050 case HtmlTokenId::TABLEROW_ON
:
5051 case HtmlTokenId::TABLEHEADER_ON
:
5052 case HtmlTokenId::TABLEDATA_ON
:
5054 BuildTableSection(xCurTable
.get(), false, false);
5055 bDone
= m_xTable
->IsOverflowing();
5057 case HtmlTokenId::THEAD_ON
:
5058 case HtmlTokenId::TFOOT_ON
:
5059 case HtmlTokenId::TBODY_ON
:
5060 BuildTableSection(xCurTable
.get(), true, HtmlTokenId::THEAD_ON
==nToken
);
5061 bDone
= m_xTable
->IsOverflowing();
5063 case HtmlTokenId::MULTICOL_ON
:
5064 // we can't add columned text frames here
5066 case HtmlTokenId::FORM_ON
:
5067 NewForm( false ); // don't add a new paragraph
5069 case HtmlTokenId::FORM_OFF
:
5070 EndForm( false ); // don't add a new paragraph
5072 case HtmlTokenId::TEXTTOKEN
:
5073 // blank strings may be a series of CR+LF and no text
5074 if( (xCurTable
->GetContext() ||
5075 !xCurTable
->HasParentSection()) &&
5076 1==aToken
.getLength() && ' '==aToken
[0] )
5080 xCurTable
->MakeParentContents();
5081 NextToken( nToken
);
5085 OSL_ENSURE( !bPending
|| m_vPendingStack
.empty(),
5086 "SwHTMLParser::BuildTable: There is a PendStack again" );
5088 if( IsParserWorking() )
5089 SaveState( HtmlTokenId::NONE
);
5092 nToken
= GetNextToken();
5095 if( SvParserState::Pending
== GetStatus() )
5097 m_vPendingStack
.emplace_back( HtmlTokenId::TABLE_ON
);
5098 m_vPendingStack
.back().pData
= std::move(xSaveStruct
);
5099 return std::shared_ptr
<HTMLTable
>();
5102 HTMLTableContext
*pTCntxt
= xCurTable
->GetContext();
5106 // Modify table structure
5107 xCurTable
->CloseTable();
5109 // end contexts that began out of cells. Needs to exist before (!) we move the table,
5110 // since the current one doesn't exist anymore afterwards
5111 while( m_aContexts
.size() > m_nContextStAttrMin
)
5113 std::unique_ptr
<HTMLAttrContext
> xCntxt(PopContext());
5116 ClearContext(xCntxt
.get());
5119 m_nContextStMin
= pTCntxt
->GetContextStMin();
5120 m_nContextStAttrMin
= pTCntxt
->GetContextStAttrMin();
5122 if (m_xTable
== xCurTable
)
5124 // Set table caption
5125 const SwStartNode
*pCapStNd
= m_xTable
->GetCaptionStartNode();
5128 // The last paragraph of the section is never part of the copy.
5129 // That's why the section needs to contain at least two paragraphs
5131 if( pCapStNd
->EndOfSectionIndex() - pCapStNd
->GetIndex() > 2 )
5133 // Don't copy start node and the last paragraph
5134 SwNodeRange
aSrcRg( *pCapStNd
, 1,
5135 *pCapStNd
->EndOfSectionNode(), -1 );
5137 bool bTop
= m_xTable
->IsTopCaption();
5138 SwStartNode
*pTableStNd
= pTCntxt
->GetTableNode();
5140 OSL_ENSURE( pTableStNd
, "Where is the table node" );
5141 OSL_ENSURE( pTableStNd
==m_pPam
->GetNode().FindTableNode(),
5142 "Are we in the wrong table?" );
5148 pNd
= pTableStNd
->EndOfSectionNode();
5149 SwNodeIndex
aDstIdx( *pNd
, bTop
? 0 : 1 );
5151 m_xDoc
->getIDocumentContentOperations().MoveNodeRange( aSrcRg
, aDstIdx
,
5152 SwMoveFlags::DEFAULT
);
5154 // If the caption was added before the table, a page style on that table
5155 // needs to be moved to the first paragraph of the header.
5156 // Additionally, all remembered indices that point to the table node
5160 MovePageDescAttrs( pTableStNd
, aSrcRg
.aStart
.GetIndex(),
5165 // The section isn't needed anymore
5167 m_pPam
->DeleteMark();
5168 DeleteSection(const_cast<SwStartNode
*>(pCapStNd
));
5169 m_xTable
->SetCaption( nullptr, false );
5173 sal_uInt16 nBrowseWidth
= o3tl::narrowing
<sal_uInt16
>(GetCurrentBrowseWidth());
5174 xSaveStruct
->MakeTable(nBrowseWidth
, *m_pPam
->GetPoint(), m_xDoc
.get());
5177 GetNumInfo().Set( pTCntxt
->GetNumInfo() );
5178 pTCntxt
->RestorePREListingXMP( *this );
5179 RestoreAttrTab(pTCntxt
->m_xAttrTab
);
5181 if (m_xTable
== xCurTable
)
5183 // Set upper paragraph spacing
5184 m_bUpperSpace
= true;
5187 SwTableNode
* pTableNode
= pTCntxt
->GetTableNode();
5188 size_t nTableBoxSize
= pTableNode
? pTableNode
->GetTable().GetTabSortBoxes().size() : 0;
5189 m_nParaCnt
= m_nParaCnt
- std::min(m_nParaCnt
, nTableBoxSize
);
5191 // Jump to a table if needed
5192 if( JumpToMarks::Table
== m_eJumpTo
&& m_xTable
->GetSwTable() &&
5193 m_xTable
->GetSwTable()->GetFrameFormat()->GetName() == m_sJmpMark
)
5195 m_bChkJumpMark
= true;
5196 m_eJumpTo
= JumpToMarks::NONE
;
5199 // If the import was canceled, don't call Show again here since
5200 // the SwViewShell was already deleted
5201 // That's not enough. Even in the ACCEPTING_STATE, a Show mustn't be called
5202 // because otherwise the parser's gonna be destroyed on the reschedule,
5203 // if there's still a DataAvailable link coming. So: only in the WORKING state
5204 if( !m_nParaCnt
&& SvParserState::Working
== GetStatus() )
5208 else if (m_xTable
== xCurTable
)
5210 // There was no table read
5212 // We maybe need to delete a read caption
5213 const SwStartNode
*pCapStNd
= xCurTable
->GetCaptionStartNode();
5217 m_pPam
->DeleteMark();
5218 DeleteSection(const_cast<SwStartNode
*>(pCapStNd
));
5219 xCurTable
->SetCaption( nullptr, false );
5223 if (m_xTable
== xCurTable
)
5225 xSaveStruct
->m_xCurrentTable
.reset();
5229 std::shared_ptr
<HTMLTable
> xRetTable
= xSaveStruct
->m_xCurrentTable
;
5230 xSaveStruct
.reset();
5235 bool HTMLTable::PendingDrawObjectsInPaM(SwPaM
& rPam
) const
5237 if (!m_xResizeDrawObjects
)
5242 sal_uInt16 nCount
= m_xResizeDrawObjects
->size();
5243 for (sal_uInt16 i
= 0; i
< nCount
&& !bRet
; ++i
)
5245 SdrObject
*pObj
= (*m_xResizeDrawObjects
)[i
];
5246 SwFrameFormat
* pObjectFormat
= ::FindFrameFormat(pObj
);
5249 const SwFormatAnchor
& rAnch
= pObjectFormat
->GetAnchor();
5250 if (const SwPosition
* pPos
= rAnch
.GetContentAnchor())
5252 SwNodeIndex
aObjNodeIndex(pPos
->nNode
);
5253 bRet
= (aObjNodeIndex
>= rPam
.Start()->nNode
&& aObjNodeIndex
<= rPam
.End()->nNode
);
5260 bool SwHTMLParser::PendingObjectsInPaM(SwPaM
& rPam
) const
5263 for (const auto& a
: m_aTables
)
5265 bRet
= a
->PendingDrawObjectsInPaM(rPam
);
5268 const SwTable
*pTable
= a
->GetSwTable();
5271 const SwTableNode
* pTableNode
= pTable
->GetTableNode();
5274 SwNodeIndex
aTableNodeIndex(*pTableNode
);
5275 bRet
= (aTableNodeIndex
>= rPam
.Start()->nNode
&& aTableNodeIndex
<= rPam
.End()->nNode
);
5282 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */