LibreOffice Module sw (master)  1
htmltab.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include <memory>
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>
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>
38 
39 #include <dcontact.hxx>
40 #include <fmtornt.hxx>
41 #include <frmfmt.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>
48 #include <frmatr.hxx>
49 #include <pam.hxx>
50 #include <doc.hxx>
52 #include <IDocumentMarkAccess.hxx>
53 #include <ndtxt.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"
61 #include "swhtml.hxx"
62 #include "swcss1.hxx"
63 #include <txtftn.hxx>
64 #include <itabenum.hxx>
65 #include <tblafmt.hxx>
66 #include <SwStyleNameMapper.hxx>
67 #include <frameformats.hxx>
68 
69 #define NETSCAPE_DFLT_BORDER 1
70 #define NETSCAPE_DFLT_CELLSPACING 2
71 
72 using ::editeng::SvxBorderLine;
73 using namespace ::com::sun::star;
74 
76 {
78  { OOO_STRING_SVTOOLS_HTML_VA_middle, text::VertOrientation::CENTER },
79  { OOO_STRING_SVTOOLS_HTML_VA_bottom, text::VertOrientation::BOTTOM },
80  { nullptr, 0 }
81 };
82 
83 // table tags options
84 
85 namespace {
86 
87 struct HTMLTableOptions
88 {
89  sal_uInt16 nCols;
90  sal_uInt16 nWidth;
91  sal_uInt16 nHeight;
92  sal_uInt16 nCellPadding;
93  sal_uInt16 nCellSpacing;
94  sal_uInt16 nBorder;
95  sal_uInt16 nHSpace;
96  sal_uInt16 nVSpace;
97 
98  SvxAdjust eAdjust;
99  sal_Int16 eVertOri;
100  HTMLTableFrame eFrame;
101  HTMLTableRules eRules;
102 
103  bool bPercentWidth : 1;
104  bool bTableAdjust : 1;
105  bool bBGColor : 1;
106 
107  Color aBorderColor;
108  Color aBGColor;
109 
110  OUString aBGImage, aStyle, aId, aClass, aDir;
111 
112  HTMLTableOptions( const HTMLOptions& rOptions, SvxAdjust eParentAdjust );
113 };
114 
115 class HTMLTableContext
116 {
117  SwHTMLNumRuleInfo aNumRuleInfo; // Numbering valid before the table
118 
119  SwTableNode *pTableNd; // table node
120  SwFrameFormat *pFrameFormat; // the Fly frame::Frame, containing the table
121  std::unique_ptr<SwPosition> pPos; // position behind the table
122 
123  size_t nContextStAttrMin;
124  size_t nContextStMin;
125 
126  bool bRestartPRE : 1;
127  bool bRestartXMP : 1;
128  bool bRestartListing : 1;
129 
130  HTMLTableContext(const HTMLTableContext&) = delete;
131  HTMLTableContext& operator=(const HTMLTableContext&) = delete;
132 
133 public:
134 
135  std::shared_ptr<HTMLAttrTable> xAttrTab; // attributes
136 
137  HTMLTableContext( SwPosition *pPs, size_t nCntxtStMin,
138  size_t nCntxtStAttrMin ) :
139  pTableNd( nullptr ),
140  pFrameFormat( nullptr ),
141  pPos( pPs ),
142  nContextStAttrMin( nCntxtStAttrMin ),
143  nContextStMin( nCntxtStMin ),
144  bRestartPRE( false ),
145  bRestartXMP( false ),
146  bRestartListing( false ),
147  xAttrTab(std::make_shared<HTMLAttrTable>())
148  {
149  memset(xAttrTab.get(), 0, sizeof(HTMLAttrTable));
150  }
151 
152  void SetNumInfo( const SwHTMLNumRuleInfo& rInf ) { aNumRuleInfo.Set(rInf); }
153  const SwHTMLNumRuleInfo& GetNumInfo() const { return aNumRuleInfo; };
154 
155  void SavePREListingXMP( SwHTMLParser& rParser );
156  void RestorePREListingXMP( SwHTMLParser& rParser );
157 
158  SwPosition *GetPos() const { return pPos.get(); }
159 
160  void SetTableNode( SwTableNode *pNd ) { pTableNd = pNd; }
161  SwTableNode *GetTableNode() const { return pTableNd; }
162 
163  void SetFrameFormat( SwFrameFormat *pFormat ) { pFrameFormat = pFormat; }
164  SwFrameFormat *GetFrameFormat() const { return pFrameFormat; }
165 
166  size_t GetContextStMin() const { return nContextStMin; }
167  size_t GetContextStAttrMin() const { return nContextStAttrMin; }
168 };
169 
170 }
171 
172 // Cell content is a linked list with SwStartNodes and
173 // HTMLTables.
174 
176 {
177  std::unique_ptr<HTMLTableCnts> m_pNext; // next content
178 
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
182 
183  std::shared_ptr<SwHTMLTableLayoutCnts> m_xLayoutInfo;
184 
186 
187  void InitCtor();
188 
189 public:
190 
191  explicit HTMLTableCnts(const SwStartNode* pStNd);
192  explicit HTMLTableCnts(const std::shared_ptr<HTMLTable>& rTab);
193 
194  ~HTMLTableCnts(); // only allowed in ~HTMLTableCell
195 
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; }
200 
201  // Add a new node at the end of the list
202  void Add( std::unique_ptr<HTMLTableCnts> pNewCnts );
203 
204  // Determine next node
205  const HTMLTableCnts *Next() const { return m_pNext.get(); }
206  HTMLTableCnts *Next() { return m_pNext.get(); }
207 
208  inline void SetTableBox( SwTableBox *pBox );
209 
210  void SetNoBreak() { m_bNoBreak = true; }
211 
212  const std::shared_ptr<SwHTMLTableLayoutCnts>& CreateLayoutInfo();
213 };
214 
215 namespace {
216 
217 // Cell of a HTML table
218 class HTMLTableCell
219 {
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;
223 
224  double m_nValue;
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;
234  bool m_bNoWrap : 1;
235  bool mbCovered : 1;
236 
237 public:
238 
239  HTMLTableCell(); // new cells always empty
240 
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 );
247 
248  // Protect an empty 1x1 cell
249  void SetProtected();
250 
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; }
254 
255  // Set/Get cell ROWSPAN/COLSPAN
256  void SetRowSpan( sal_uInt16 nRSpan ) { m_nRowSpan = nRSpan; }
257  sal_uInt16 GetRowSpan() const { return m_nRowSpan; }
258 
259  void SetColSpan( sal_uInt16 nCSpan ) { m_nColSpan = nCSpan; }
260  sal_uInt16 GetColSpan() const { return m_nColSpan; }
261 
262  inline void SetWidth( sal_uInt16 nWidth, bool bRelWidth );
263 
264  const std::shared_ptr<SvxBrushItem>& GetBGBrush() const { return m_xBGBrush; }
265  const std::shared_ptr<SvxBoxItem>& GetBoxItem() const { return m_xBoxItem; }
266 
267  inline bool GetNumFormat( sal_uInt32& rNumFormat ) const;
268  inline bool GetValue( double& rValue ) const;
269 
270  sal_Int16 GetVertOri() const { return m_eVertOrient; }
271 
272  // Is the cell filled or protected ?
273  bool IsUsed() const { return m_xContents || m_bProtected; }
274 
275  std::unique_ptr<SwHTMLTableLayoutCell> CreateLayoutInfo();
276 
277  bool IsCovered() const { return mbCovered; }
278 };
279 
280 }
281 
282 
283 namespace {
284 
285 // Row of a HTML table
286 class HTMLTableRow
287 {
288  std::vector<HTMLTableCell> m_aCells;
289  std::unique_ptr<SvxBrushItem> xBGBrush; // background of cell from STYLE
290 
291  SvxAdjust eAdjust;
292  sal_uInt16 nHeight; // options of <TR>/<TD>
293  sal_uInt16 nEmptyRows; // number of empty rows are following
294  sal_Int16 eVertOri;
295  bool bIsEndOfGroup : 1;
296  bool bBottomBorder : 1; // Is there a line after the row?
297 
298 public:
299 
300  explicit HTMLTableRow( sal_uInt16 nCells ); // cells of the row are empty
301 
302  void SetBottomBorder(bool bIn) { bBottomBorder = bIn; }
303  bool GetBottomBorder() const { return bBottomBorder; }
304 
305  inline void SetHeight( sal_uInt16 nHeight );
306  sal_uInt16 GetHeight() const { return nHeight; }
307 
308  const HTMLTableCell& GetCell(sal_uInt16 nCell) const;
309  HTMLTableCell& GetCell(sal_uInt16 nCell)
310  {
311  return const_cast<HTMLTableCell&>(const_cast<const HTMLTableRow&>(*this).GetCell(nCell));
312  }
313 
314  void SetAdjust( SvxAdjust eAdj ) { eAdjust = eAdj; }
315  SvxAdjust GetAdjust() const { return eAdjust; }
316 
317  void SetVertOri( sal_Int16 eV) { eVertOri = eV; }
318  sal_Int16 GetVertOri() const { return eVertOri; }
319 
320  void SetBGBrush(std::unique_ptr<SvxBrushItem>& rBrush ) { xBGBrush = std::move(rBrush); }
321  const std::unique_ptr<SvxBrushItem>& GetBGBrush() const { return xBGBrush; }
322 
323  void SetEndOfGroup() { bIsEndOfGroup = true; }
324  bool IsEndOfGroup() const { return bIsEndOfGroup; }
325 
326  void IncEmptyRows() { nEmptyRows++; }
327  sal_uInt16 GetEmptyRows() const { return nEmptyRows; }
328 
329  // Expand row by adding empty cells
330  void Expand( sal_uInt16 nCells, bool bOneCell=false );
331 
332  // Shrink row by deleting empty cells
333  void Shrink( sal_uInt16 nCells );
334 };
335 
336 // Column of a HTML table
337 class HTMLTableColumn
338 {
339  bool bIsEndOfGroup;
340 
341  sal_uInt16 nWidth; // options of <COL>
342  bool bRelWidth;
343 
344  SvxAdjust eAdjust;
345  sal_Int16 eVertOri;
346 
347  SwFrameFormat *aFrameFormats[6];
348 
349  static inline sal_uInt16 GetFrameFormatIdx( bool bBorderLine,
350  sal_Int16 eVertOri );
351 
352 public:
353 
354  bool bLeftBorder; // is there a line before the column
355 
356  HTMLTableColumn();
357 
358  inline void SetWidth( sal_uInt16 nWidth, bool bRelWidth);
359 
360  void SetAdjust( SvxAdjust eAdj ) { eAdjust = eAdj; }
361  SvxAdjust GetAdjust() const { return eAdjust; }
362 
363  void SetVertOri( sal_Int16 eV) { eVertOri = eV; }
364  sal_Int16 GetVertOri() const { return eVertOri; }
365 
366  void SetEndOfGroup() { bIsEndOfGroup = true; }
367  bool IsEndOfGroup() const { return bIsEndOfGroup; }
368 
369  inline void SetFrameFormat( SwFrameFormat *pFormat, bool bBorderLine,
370  sal_Int16 eVertOri );
371  inline SwFrameFormat *GetFrameFormat( bool bBorderLine,
372  sal_Int16 eVertOri ) const;
373 
374  std::unique_ptr<SwHTMLTableLayoutColumn> CreateLayoutInfo();
375 };
376 
377 }
378 
379 // HTML table
380 typedef std::vector<SdrObject *> SdrObjects;
381 
383 {
384  OUString m_aId;
385  OUString m_aStyle;
386  OUString m_aClass;
387  OUString m_aDir;
388 
389  std::unique_ptr<SdrObjects> m_pResizeDrawObjects;// SDR objects
390  std::unique_ptr<std::vector<sal_uInt16>> m_pDrawObjectPercentWidths; // column of draw object and its rel. width
391 
392  std::vector<HTMLTableRow> m_aRows;
393  std::vector<HTMLTableColumn> m_aColumns;
394 
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
398 
399  sal_uInt16 m_nCurrentRow; // current Row
400  sal_uInt16 m_nCurrentColumn; // current Column
401 
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)
404 
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;
409 
410  sal_uInt16 m_nBoxes; // number of boxes in the table
411 
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)
414 public:
415  std::unique_ptr<SwTableBox> m_xBox1; // TableBox, generated when the Top-Level-Table was build
416 private:
417  SwTableBoxFormat *m_pBoxFormat; // frame::Frame-Format from SwTableBox
418  SwTableLineFormat *m_pLineFormat; // frame::Frame-Format from SwTableLine
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;
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?
435  bool m_bFillerTopBorder; // gets the left/right filler-cell a border on the
436  bool m_bFillerBottomBorder; // top or in the bottom
439  bool m_bBordersSet; // the border is set already
441  bool m_bTableAdjustOfTag; // comes nTableAdjust from <TABLE>?
442  sal_uInt32 m_nHeadlineRepeat; // repeating rows
447  bool m_bColSpec; // where there COL(GROUP)-elements?
448  bool m_bPercentWidth; // width is declared in %
449 
450  SwHTMLParser *m_pParser; // the current parser
451  std::unique_ptr<HTMLTableCnts> m_xParentContents;
452 
453  std::unique_ptr<HTMLTableContext> m_pContext; // the context of the table
454 
455  std::shared_ptr<SwHTMLTableLayout> m_xLayoutInfo;
456 
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
466 
467  void InitCtor(const HTMLTableOptions& rOptions);
468 
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 );
471 
472  // Protects the chosen cell and the cells among
473  void ProtectRowSpan( sal_uInt16 nRow, sal_uInt16 nCol, sal_uInt16 nRowSpan );
474 
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;
478 
479  sal_uInt16 GetTopCellSpace( sal_uInt16 nRow ) const;
480  sal_uInt16 GetBottomCellSpace( sal_uInt16 nRow, sal_uInt16 nRowSpan ) const;
481 
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;
486 
487  // Create a table with the content (lines/boxes)
488  void MakeTable_( SwTableBox *pUpper );
489 
490  // Generate a new SwTableBox, which contains a SwStartNode
491  SwTableBox *NewTableBox( const SwStartNode *pStNd,
492  SwTableLine *pUpper ) const;
493 
494  // Generate a SwTableLine from the cells of the rectangle
495  // (nTopRow/nLeftCol) inclusive to (nBottomRow/nRightRow) exclusive
497  sal_uInt16 nTopRow, sal_uInt16 nLeftCol,
498  sal_uInt16 nBottomRow, sal_uInt16 nRightCol );
499 
500  // Generate a SwTableBox from the content of the cell
502  HTMLTableCnts *pCnts,
503  sal_uInt16 nTopRow, sal_uInt16 nLeftCol,
504  sal_uInt16 nBootomRow, sal_uInt16 nRightCol );
505 
506  // Autolayout-Algorithm
507 
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,
511  sal_uInt16 nRowSpan,
512  bool bFirstPara, bool bLastPara );
513 
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 );
517 
518  // Set the border with the help of the information from the user
519  void SetBorders();
520 
521  // is the border already set?
522  bool BordersSet() const { return m_bBordersSet; }
523 
524  const std::unique_ptr<SvxBrushItem>& GetBGBrush() const { return m_xBackgroundBrush; }
525  const std::unique_ptr<SvxBrushItem>& GetInhBGBrush() const { return m_xInheritedBackgroundBrush; }
526 
527  sal_uInt16 GetBorderWidth( const SvxBorderLine& rBLine,
528  bool bWithDistance=false ) const;
529 
530 public:
531 
532  bool m_bFirstCell; // is there a cell created already?
533 
534  HTMLTable(SwHTMLParser* pPars,
535  bool bParHead, bool bHasParentSec,
536  bool bHasToFly,
537  const HTMLTableOptions& rOptions);
538 
539  ~HTMLTable();
540 
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)
544  {
545  return const_cast<HTMLTableCell&>(const_cast<const HTMLTable&>(*this).GetCell(nRow, nCell));
546  }
547 
548  // set/determine caption
549  inline void SetCaption( const SwStartNode *pStNd, bool bTop );
551  bool IsTopCaption() const { return m_bTopCaption; }
552 
553  SvxAdjust GetTableAdjust( bool bAny ) const
554  {
555  return (m_bTableAdjustOfTag || bAny) ? m_eTableAdjust : SvxAdjust::End;
556  }
557 
558  sal_uInt16 GetHSpace() const { return m_nHSpace; }
559  sal_uInt16 GetVSpace() const { return m_nVSpace; }
560 
561  // get inherited drawing::Alignment of rows and column
563  sal_Int16 GetInheritedVertOri() const;
564 
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 );
572 
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 );
576 
577  // announce the end of a new section
578  inline void CloseSection( bool bHead );
579 
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 );
583 
584  // insert a new column
585  void InsertCol( sal_uInt16 nSpan, sal_uInt16 nWidth, bool bRelWidth,
586  SvxAdjust eAdjust, sal_Int16 eVertOri );
587 
588  // End a table definition (needs to be called for every table)
589  void CloseTable();
590 
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 );
595 
596  bool IsNewDoc() const { return m_pParser->IsNewDoc(); }
597 
598  void SetHasParentSection( bool bSet ) { m_bHasParentSection = bSet; }
599  bool HasParentSection() const { return m_bHasParentSection; }
600 
601  void SetParentContents(std::unique_ptr<HTMLTableCnts> pCnts) { m_xParentContents = std::move(pCnts); }
602  std::unique_ptr<HTMLTableCnts>& GetParentContents() { return m_xParentContents; }
603 
604  void MakeParentContents();
605 
606  bool HasToFly() const { return m_bHasToFly; }
607 
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 );
611 
612  HTMLTableContext *GetContext() const { return m_pContext.get(); }
613 
614  const std::shared_ptr<SwHTMLTableLayout>& CreateLayoutInfo();
615 
616  bool HasColTags() const { return m_bColSpec; }
617 
618  sal_uInt16 IncGrfsThatResize() { return m_pSwTable ? const_cast<SwTable *>(m_pSwTable)->IncGrfsThatResize() : 0; }
619 
620  void RegisterDrawObject( SdrObject *pObj, sal_uInt8 nPercentWidth );
621 
622  const SwTable *GetSwTable() const { return m_pSwTable; }
623 
624  void SetBGBrush(const SvxBrushItem& rBrush) { m_xBackgroundBrush.reset(new SvxBrushItem(rBrush)); }
625 
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; }
630 
631  void IncBoxCount() { m_nBoxes++; }
632  bool IsOverflowing() const { return m_nBoxes > 64000; }
633 
634  bool PendingDrawObjectsInPaM(SwPaM& rPam) const;
635 };
636 
638 {
639  m_pNext = nullptr;
640  m_xLayoutInfo.reset();
641  m_bNoBreak = false;
642 }
643 
645  : m_pStartNode(pStNd)
646 {
647  InitCtor();
648 }
649 
650 HTMLTableCnts::HTMLTableCnts(const std::shared_ptr<HTMLTable>& rTab)
651  : m_pStartNode(nullptr)
652  , m_xTable(rTab)
653 {
654  InitCtor();
655 }
656 
658 {
659  m_xTable.reset(); // we don't need the tables anymore
660  m_pNext.reset();
661 }
662 
663 void HTMLTableCnts::Add( std::unique_ptr<HTMLTableCnts> pNewCnts )
664 {
665  HTMLTableCnts *pCnts = this;
666 
667  while( pCnts->m_pNext )
668  pCnts = pCnts->m_pNext.get();
669 
670  pCnts->m_pNext = std::move(pNewCnts);
671 }
672 
674 {
675  OSL_ENSURE(m_xLayoutInfo, "There is no layout info");
676  if (m_xLayoutInfo)
677  m_xLayoutInfo->SetTableBox(pBox);
678 }
679 
680 const std::shared_ptr<SwHTMLTableLayoutCnts>& HTMLTableCnts::CreateLayoutInfo()
681 {
682  if (!m_xLayoutInfo)
683  {
684  std::shared_ptr<SwHTMLTableLayoutCnts> xNextInfo;
685  if (m_pNext)
686  xNextInfo = m_pNext->CreateLayoutInfo();
687  std::shared_ptr<SwHTMLTableLayout> xTableInfo;
688  if (m_xTable)
689  xTableInfo = m_xTable->CreateLayoutInfo();
690  m_xLayoutInfo = std::make_shared<SwHTMLTableLayoutCnts>(m_pStartNode, xTableInfo, m_bNoBreak, xNextInfo);
691  }
692 
693  return m_xLayoutInfo;
694 }
695 
696 HTMLTableCell::HTMLTableCell():
697  m_nValue(0),
698  m_nNumFormat(0),
699  m_nRowSpan(1),
700  m_nColSpan(1),
701  m_nWidth( 0 ),
702  m_eVertOrient( text::VertOrientation::NONE ),
703  m_bProtected(false),
704  m_bRelWidth( false ),
705  m_bHasNumFormat(false),
706  m_bHasValue(false),
707  m_bNoWrap(false),
708  mbCovered(false)
709 {}
710 
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 )
716 {
717  m_xContents = rCnts;
718  m_nRowSpan = nRSpan;
719  m_nColSpan = nCSpan;
720  m_bProtected = false;
721  m_eVertOrient = eVert;
722  m_xBGBrush = rBrush;
723  m_xBoxItem = rBoxItem;
724 
725  m_bHasNumFormat = bHasNF;
726  m_bHasValue = bHasV;
727  m_nNumFormat = nNF;
728  m_nValue = nVal;
729 
730  m_bNoWrap = bNWrap;
731  mbCovered = bCovered;
732 }
733 
734 inline void HTMLTableCell::SetWidth( sal_uInt16 nWdth, bool bRelWdth )
735 {
736  m_nWidth = nWdth;
737  m_bRelWidth = bRelWdth;
738 }
739 
740 void HTMLTableCell::SetProtected()
741 {
742  // The content of this cell doesn't have to be anchored anywhere else,
743  // since they're not gonna be deleted
744 
745  m_xContents.reset();
746 
747  // Copy background color
748  if (m_xBGBrush)
749  m_xBGBrush = std::make_shared<SvxBrushItem>(*m_xBGBrush);
750 
751  m_nRowSpan = 1;
752  m_nColSpan = 1;
753  m_bProtected = true;
754 }
755 
756 inline bool HTMLTableCell::GetNumFormat( sal_uInt32& rNumFormat ) const
757 {
758  rNumFormat = m_nNumFormat;
759  return m_bHasNumFormat;
760 }
761 
762 inline bool HTMLTableCell::GetValue( double& rValue ) const
763 {
764  rValue = m_nValue;
765  return m_bHasValue;
766 }
767 
768 std::unique_ptr<SwHTMLTableLayoutCell> HTMLTableCell::CreateLayoutInfo()
769 {
770  std::shared_ptr<SwHTMLTableLayoutCnts> xCntInfo;
771  if (m_xContents)
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));
775 }
776 
777 HTMLTableRow::HTMLTableRow(sal_uInt16 const nCells)
778  : m_aCells(nCells)
779  , eAdjust(SvxAdjust::End)
780  , nHeight(0)
781  , nEmptyRows(0)
782  , eVertOri(text::VertOrientation::TOP)
783  , bIsEndOfGroup(false)
784  , bBottomBorder(false)
785 {
786  assert(nCells == m_aCells.size() &&
787  "wrong Cell count in new HTML table row");
788 }
789 
790 inline void HTMLTableRow::SetHeight( sal_uInt16 nHght )
791 {
792  if( nHght > nHeight )
793  nHeight = nHght;
794 }
795 
796 const HTMLTableCell& HTMLTableRow::GetCell(sal_uInt16 nCell) const
797 {
798  OSL_ENSURE( nCell < m_aCells.size(),
799  "invalid cell index in HTML table row" );
800  return m_aCells.at(nCell);
801 }
802 
803 void HTMLTableRow::Expand( sal_uInt16 nCells, bool bOneCell )
804 {
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!
807 
808  sal_uInt16 nColSpan = nCells - m_aCells.size();
809  for (sal_uInt16 i = m_aCells.size(); i < nCells; ++i)
810  {
811  m_aCells.emplace_back();
812  if (bOneCell)
813  m_aCells.back().SetColSpan(nColSpan);
814  --nColSpan;
815  }
816 
817  OSL_ENSURE(nCells == m_aCells.size(),
818  "wrong Cell count in expanded HTML table row");
819 }
820 
821 void HTMLTableRow::Shrink( sal_uInt16 nCells )
822 {
823  OSL_ENSURE(nCells < m_aCells.size(), "number of cells too large");
824 
825 #if OSL_DEBUG_LEVEL > 0
826  sal_uInt16 const nEnd = m_aCells.size();
827 #endif
828  // The colspan of empty cells at the end has to be fixed to the new
829  // number of cells.
830  sal_uInt16 i=nCells;
831  while( i )
832  {
833  HTMLTableCell& rCell = m_aCells[--i];
834  if (!rCell.GetContents())
835  {
836 #if OSL_DEBUG_LEVEL > 0
837  OSL_ENSURE( rCell.GetColSpan() == nEnd - i,
838  "invalid col span for empty cell at row end" );
839 #endif
840  rCell.SetColSpan( nCells-i);
841  }
842  else
843  break;
844  }
845 #if OSL_DEBUG_LEVEL > 0
846  for( i=nCells; i<nEnd; i++ )
847  {
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" );
854  }
855 #endif
856 
857  m_aCells.erase(m_aCells.begin() + nCells, m_aCells.end());
858 }
859 
860 HTMLTableColumn::HTMLTableColumn():
861  bIsEndOfGroup(false),
862  nWidth(0), bRelWidth(false),
863  eAdjust(SvxAdjust::End), eVertOri(text::VertOrientation::TOP),
864  bLeftBorder(false)
865 {
866  for(SwFrameFormat* & rp : aFrameFormats)
867  rp = nullptr;
868 }
869 
870 inline void HTMLTableColumn::SetWidth( sal_uInt16 nWdth, bool bRelWdth )
871 {
872  if( bRelWidth==bRelWdth )
873  {
874  if( nWdth > nWidth )
875  nWidth = nWdth;
876  }
877  else
878  nWidth = nWdth;
879  bRelWidth = bRelWdth;
880 }
881 
882 inline std::unique_ptr<SwHTMLTableLayoutColumn> HTMLTableColumn::CreateLayoutInfo()
883 {
884  return std::unique_ptr<SwHTMLTableLayoutColumn>(new SwHTMLTableLayoutColumn( nWidth, bRelWidth, bLeftBorder ));
885 }
886 
887 inline sal_uInt16 HTMLTableColumn::GetFrameFormatIdx( bool bBorderLine,
888  sal_Int16 eVertOrient )
889 {
890  OSL_ENSURE( text::VertOrientation::TOP != eVertOrient, "Top is not allowed" );
891  sal_uInt16 n = bBorderLine ? 3 : 0;
892  switch( eVertOrient )
893  {
894  case text::VertOrientation::CENTER: n+=1; break;
895  case text::VertOrientation::BOTTOM: n+=2; break;
896  default:
897  ;
898  }
899  return n;
900 }
901 
902 inline void HTMLTableColumn::SetFrameFormat( SwFrameFormat *pFormat, bool bBorderLine,
903  sal_Int16 eVertOrient )
904 {
905  aFrameFormats[GetFrameFormatIdx(bBorderLine,eVertOrient)] = pFormat;
906 }
907 
908 inline SwFrameFormat *HTMLTableColumn::GetFrameFormat( bool bBorderLine,
909  sal_Int16 eVertOrient ) const
910 {
911  return aFrameFormats[GetFrameFormatIdx(bBorderLine,eVertOrient)];
912 }
913 
914 void HTMLTable::InitCtor(const HTMLTableOptions& rOptions)
915 {
916  m_nRows = 0;
918 
919  m_pBoxFormat = nullptr; m_pLineFormat = nullptr;
920  m_pLineFrameFormatNoHeight = nullptr;
922 
923  m_pPrevStartNode = nullptr;
924  m_pSwTable = nullptr;
925 
926  m_bTopBorder = false; m_bRightBorder = false;
927  m_bTopAllowed = true; m_bRightAllowed = true;
928  m_bFillerTopBorder = false; m_bFillerBottomBorder = false;
930  m_bBordersSet = false;
931  m_bForceFrame = false;
932  m_nHeadlineRepeat = 0;
933 
934  m_nLeftMargin = 0;
935  m_nRightMargin = 0;
936 
937  const Color& rBorderColor = rOptions.aBorderColor;
938 
939  tools::Long nBorderOpt = static_cast<tools::Long>(rOptions.nBorder);
940  tools::Long nPWidth = nBorderOpt==USHRT_MAX ? NETSCAPE_DFLT_BORDER
941  : nBorderOpt;
942  tools::Long nPHeight = nBorderOpt==USHRT_MAX ? 0 : nBorderOpt;
943  SvxCSS1Parser::PixelToTwip( nPWidth, nPHeight );
944 
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 = static_cast<sal_uInt16>(nPWidth);
949  if( nBorderOpt==USHRT_MAX )
950  nPWidth = 0;
951 
952  if ( rOptions.nCellSpacing != 0 )
953  {
954  m_aTopBorderLine.SetBorderLineStyle(SvxBorderLineStyle::DOUBLE);
955  }
956  m_aTopBorderLine.SetWidth( nPHeight );
957  m_aTopBorderLine.SetColor( rBorderColor );
959 
960  if( nPWidth == nPHeight )
961  {
963  }
964  else
965  {
966  if ( rOptions.nCellSpacing != 0 )
967  {
968  m_aLeftBorderLine.SetBorderLineStyle(SvxBorderLineStyle::DOUBLE);
969  }
970  m_aLeftBorderLine.SetWidth( nPWidth );
971  m_aLeftBorderLine.SetColor( rBorderColor );
972  }
974 
975  if( rOptions.nCellSpacing != 0 )
976  {
977  m_aBorderLine.SetBorderLineStyle(SvxBorderLineStyle::DOUBLE);
978  m_aBorderLine.SetWidth( DEF_LINE_WIDTH_0 );
979  }
980  else
981  {
982  m_aBorderLine.SetWidth( DEF_LINE_WIDTH_0 );
983  }
984  m_aBorderLine.SetColor( rBorderColor );
985 
986  if( m_nCellPadding )
987  {
989  m_nCellPadding = MIN_BORDER_DIST; // default
990  else
991  {
995  }
996  }
997  if( m_nCellSpacing )
998  {
1002  }
1003 
1004  nPWidth = rOptions.nHSpace;
1005  nPHeight = rOptions.nVSpace;
1006  SvxCSS1Parser::PixelToTwip( nPWidth, nPHeight );
1007  m_nHSpace = static_cast<sal_uInt16>(nPWidth);
1008  m_nVSpace = static_cast<sal_uInt16>(nPHeight);
1009 
1010  m_bColSpec = false;
1011 
1013  rOptions.bBGColor ? &(rOptions.aBGColor) : nullptr,
1014  rOptions.aBGImage, OUString(), OUString(), OUString()));
1015 
1016  m_pContext = nullptr;
1017  m_xParentContents.reset();
1018 
1019  m_aId = rOptions.aId;
1020  m_aClass = rOptions.aClass;
1021  m_aStyle = rOptions.aStyle;
1022  m_aDir = rOptions.aDir;
1023 }
1024 
1026  bool bParHead,
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),
1034  m_nBoxes( 1 ),
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 ),
1042  m_pParser( pPars ),
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 ),
1050  m_bFirstCell(true)
1051 {
1052  InitCtor(rOptions);
1054 }
1055 
1057 {
1058  if (pOld->m_xBox1)
1059  m_aOrphanedTableBoxes.emplace_back(std::move(pOld->m_xBox1));
1060  m_aTables.erase(std::remove(m_aTables.begin(), m_aTables.end(), pOld));
1061 }
1062 
1064 {
1065  return m_xDoc.get();
1066 }
1067 
1069 {
1070  return m_bReqIF;
1071 }
1072 
1074 {
1076 
1077  m_pResizeDrawObjects.reset();
1079 
1080  m_pContext.reset();
1081 
1082  // pLayoutInfo has either already been deleted or is now owned by SwTable
1083 }
1084 
1085 const std::shared_ptr<SwHTMLTableLayout>& HTMLTable::CreateLayoutInfo()
1086 {
1087  sal_uInt16 nW = m_bPercentWidth ? m_nWidth : SwHTMLParser::ToTwips( m_nWidth );
1088 
1089  sal_uInt16 nBorderWidth = GetBorderWidth( m_aBorderLine, true );
1090  sal_uInt16 nLeftBorderWidth =
1091  m_aColumns[0].bLeftBorder ? GetBorderWidth(m_aLeftBorderLine, true) : 0;
1092  sal_uInt16 nRightBorderWidth =
1094 
1095  m_xLayoutInfo = std::make_shared<SwHTMLTableLayout>(
1096  m_pSwTable,
1101  nBorderWidth, nLeftBorderWidth, nRightBorderWidth);
1102 
1103  bool bExportable = true;
1104  sal_uInt16 i;
1105  for( i=0; i<m_nRows; i++ )
1106  {
1107  HTMLTableRow& rRow = m_aRows[i];
1108  for( sal_uInt16 j=0; j<m_nCols; j++ )
1109  {
1110  m_xLayoutInfo->SetCell(rRow.GetCell(j).CreateLayoutInfo(), i, j);
1111  SwHTMLTableLayoutCell* pLayoutCell = m_xLayoutInfo->GetCell(i, j );
1112 
1113  if( bExportable )
1114  {
1115  const std::shared_ptr<SwHTMLTableLayoutCnts>& rLayoutCnts =
1116  pLayoutCell->GetContents();
1117  bExportable = !rLayoutCnts ||
1118  (rLayoutCnts->GetStartNode() && !rLayoutCnts->GetNext());
1119  }
1120  }
1121  }
1122 
1123  m_xLayoutInfo->SetExportable( bExportable );
1124 
1125  for( i=0; i<m_nCols; i++ )
1126  m_xLayoutInfo->SetColumn(m_aColumns[i].CreateLayoutInfo(), i);
1127 
1128  return m_xLayoutInfo;
1129 }
1130 
1131 inline void HTMLTable::SetCaption( const SwStartNode *pStNd, bool bTop )
1132 {
1133  m_pCaptionStartNode = pStNd;
1134  m_bTopCaption = bTop;
1135 }
1136 
1137 void HTMLTable::FixRowSpan( sal_uInt16 nRow, sal_uInt16 nCol,
1138  const HTMLTableCnts *pCnts )
1139 {
1140  sal_uInt16 nRowSpan=1;
1141  while (true)
1142  {
1143  HTMLTableCell& rCell = GetCell(nRow, nCol);
1144  if (rCell.GetContents().get() != pCnts)
1145  break;
1146  rCell.SetRowSpan(nRowSpan);
1147  if (m_xLayoutInfo)
1148  m_xLayoutInfo->GetCell(nRow,nCol)->SetRowSpan(nRowSpan);
1149 
1150  if( !nRow ) break;
1151  nRowSpan++; nRow--;
1152  }
1153 }
1154 
1155 void HTMLTable::ProtectRowSpan( sal_uInt16 nRow, sal_uInt16 nCol, sal_uInt16 nRowSpan )
1156 {
1157  for( sal_uInt16 i=0; i<nRowSpan; i++ )
1158  {
1159  GetCell(nRow+i,nCol).SetProtected();
1160  if (m_xLayoutInfo)
1161  m_xLayoutInfo->GetCell(nRow+i,nCol)->SetProtected();
1162  }
1163 }
1164 
1165 // Search the SwStartNode of the last used predecessor box
1166 const SwStartNode* HTMLTable::GetPrevBoxStartNode( sal_uInt16 nRow, sal_uInt16 nCol ) const
1167 {
1168  const HTMLTableCnts *pPrevCnts = nullptr;
1169 
1170  if( 0==nRow )
1171  {
1172  // always the predecessor cell
1173  if( nCol>0 )
1174  pPrevCnts = GetCell(0, nCol - 1).GetContents().get();
1175  else
1176  return m_pPrevStartNode;
1177  }
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();
1181  else
1182  {
1183  sal_uInt16 i;
1184  const HTMLTableRow& rPrevRow = m_aRows[nRow-1];
1185 
1186  // maybe a cell in the current row
1187  i = nCol;
1188  while( i )
1189  {
1190  i--;
1191  if( 1 == rPrevRow.GetCell(i).GetRowSpan() )
1192  {
1193  pPrevCnts = GetCell(nRow, i).GetContents().get();
1194  break;
1195  }
1196  }
1197 
1198  // otherwise the last filled cell of the row before
1199  if( !pPrevCnts )
1200  {
1201  i = m_nCols;
1202  while( !pPrevCnts && i )
1203  {
1204  i--;
1205  pPrevCnts = rPrevRow.GetCell(i).GetContents().get();
1206  }
1207  }
1208  }
1209  OSL_ENSURE( pPrevCnts, "No previous filled cell found" );
1210  if( !pPrevCnts )
1211  {
1212  pPrevCnts = GetCell(0, 0).GetContents().get();
1213  if( !pPrevCnts )
1214  return m_pPrevStartNode;
1215  }
1216 
1217  while( pPrevCnts->Next() )
1218  pPrevCnts = pPrevCnts->Next();
1219 
1220  const SwStartNode* pRet = pPrevCnts->GetStartNode();
1221  if (pRet)
1222  return pRet;
1223  HTMLTable* pTable = pPrevCnts->GetTable().get();
1224  if (!pTable)
1225  return nullptr;
1226  return pTable->GetPrevBoxStartNode(USHRT_MAX, USHRT_MAX);
1227 }
1228 
1229 static bool IsBoxEmpty( const SwTableBox *pBox )
1230 {
1231  const SwStartNode *pSttNd = pBox->GetSttNd();
1232  if( pSttNd &&
1233  pSttNd->GetIndex() + 2 == pSttNd->EndOfSectionIndex() )
1234  {
1235  const SwContentNode *pCNd =
1236  pSttNd->GetNodes()[pSttNd->GetIndex()+1]->GetContentNode();
1237  if( pCNd && !pCNd->Len() )
1238  return true;
1239  }
1240 
1241  return false;
1242 }
1243 
1244 sal_uInt16 HTMLTable::GetTopCellSpace( sal_uInt16 nRow ) const
1245 {
1246  sal_uInt16 nSpace = m_nCellPadding;
1247 
1248  if( nRow == 0 )
1249  {
1250  nSpace += m_nBorder + m_nCellSpacing;
1251  }
1252 
1253  return nSpace;
1254 }
1255 
1256 sal_uInt16 HTMLTable::GetBottomCellSpace( sal_uInt16 nRow, sal_uInt16 nRowSpan ) const
1257 {
1258  sal_uInt16 nSpace = m_nCellSpacing + m_nCellPadding;
1259 
1260  if( nRow+nRowSpan == m_nRows )
1261  {
1262  nSpace = nSpace + m_nBorder;
1263  }
1264 
1265  return nSpace;
1266 }
1267 
1269  sal_uInt16 nRow, sal_uInt16 nCol,
1270  sal_uInt16 nRowSpan, sal_uInt16 nColSpan,
1271  bool bFirstPara, bool bLastPara ) const
1272 {
1273  SwFrameFormat *pFrameFormat = nullptr; // frame::Frame format
1274  sal_Int16 eVOri = text::VertOrientation::NONE;
1275  const SvxBrushItem *pBGBrushItem = nullptr; // background
1276  std::shared_ptr<SvxBoxItem> pBoxItem;
1277  bool bTopLine = false, bBottomLine = false, bLastBottomLine = false;
1278  bool bReUsable = false; // Format reusable?
1279  sal_uInt16 nEmptyRows = 0;
1280  bool bHasNumFormat = false;
1281  bool bHasValue = false;
1282  sal_uInt32 nNumFormat = 0;
1283  double nValue = 0.0;
1284 
1285  const HTMLTableColumn& rColumn = m_aColumns[nCol];
1286 
1287  if( pBox->GetSttNd() )
1288  {
1289  // Determine background color/graphic
1290  const HTMLTableCell& rCell = GetCell(nRow, nCol);
1291  pBoxItem = rCell.GetBoxItem();
1292  pBGBrushItem = rCell.GetBGBrush().get();
1293  if( !pBGBrushItem )
1294  {
1295  // If a cell spans multiple rows, a background to that row should be copied to the cell.
1296  if (nRowSpan > 1)
1297  {
1298  pBGBrushItem = m_aRows[nRow].GetBGBrush().get();
1299  }
1300  }
1301 
1302  bTopLine = 0==nRow && m_bTopBorder && bFirstPara;
1303  if (m_aRows[nRow+nRowSpan-1].GetBottomBorder() && bLastPara)
1304  {
1305  nEmptyRows = m_aRows[nRow+nRowSpan-1].GetEmptyRows();
1306  if( nRow+nRowSpan == m_nRows )
1307  bLastBottomLine = true;
1308  else
1309  bBottomLine = true;
1310  }
1311 
1312  eVOri = rCell.GetVertOri();
1313  bHasNumFormat = rCell.GetNumFormat( nNumFormat );
1314  if( bHasNumFormat )
1315  bHasValue = rCell.GetValue( nValue );
1316 
1317  if( nColSpan==1 && !bTopLine && !bLastBottomLine && !nEmptyRows &&
1318  !pBGBrushItem && !bHasNumFormat && !pBoxItem)
1319  {
1320  pFrameFormat = rColumn.GetFrameFormat( bBottomLine, eVOri );
1321  bReUsable = !pFrameFormat;
1322  }
1323  }
1324 
1325  if( !pFrameFormat )
1326  {
1327  pFrameFormat = pBox->ClaimFrameFormat();
1328 
1329  // calculate width of the box
1330  SwTwips nFrameWidth = static_cast<SwTwips>(m_xLayoutInfo->GetColumn(nCol)
1331  ->GetRelColWidth());
1332  for( sal_uInt16 i=1; i<nColSpan; i++ )
1333  nFrameWidth += static_cast<SwTwips>(m_xLayoutInfo->GetColumn(nCol+i)
1334  ->GetRelColWidth());
1335 
1336  // Only set the border on edit boxes.
1337  // On setting the upper and lower border, keep in mind if
1338  // it's the first or the last paragraph of the cell
1339  if( pBox->GetSttNd() )
1340  {
1341  bool bSet = (m_nCellPadding > 0);
1342 
1343  SvxBoxItem aBoxItem( RES_BOX );
1344  tools::Long nInnerFrameWidth = nFrameWidth;
1345 
1346  if( bTopLine )
1347  {
1348  aBoxItem.SetLine( &m_aTopBorderLine, SvxBoxItemLine::TOP );
1349  bSet = true;
1350  }
1351  if( bLastBottomLine )
1352  {
1353  aBoxItem.SetLine( &m_aBottomBorderLine, SvxBoxItemLine::BOTTOM );
1354  bSet = true;
1355  }
1356  else if( bBottomLine )
1357  {
1358  if( nEmptyRows && !m_aBorderLine.GetInWidth() )
1359  {
1360  // For now, empty rows can only be emulated by thick lines, if it's a single line
1361  SvxBorderLine aThickBorderLine( m_aBorderLine );
1362 
1363  sal_uInt16 nBorderWidth = m_aBorderLine.GetOutWidth();
1364  nBorderWidth *= (nEmptyRows + 1);
1365  aThickBorderLine.SetBorderLineStyle(SvxBorderLineStyle::SOLID);
1366  aThickBorderLine.SetWidth( nBorderWidth );
1367  aBoxItem.SetLine( &aThickBorderLine, SvxBoxItemLine::BOTTOM );
1368  }
1369  else
1370  {
1371  aBoxItem.SetLine( &m_aBorderLine, SvxBoxItemLine::BOTTOM );
1372  }
1373  bSet = true;
1374  }
1375  if (m_aColumns[nCol].bLeftBorder)
1376  {
1377  const SvxBorderLine& rBorderLine =
1378  0==nCol ? m_aLeftBorderLine : m_aBorderLine;
1379  aBoxItem.SetLine( &rBorderLine, SvxBoxItemLine::LEFT );
1380  nInnerFrameWidth -= GetBorderWidth( rBorderLine );
1381  bSet = true;
1382  }
1383  if( m_bRightBorder )
1384  {
1385  aBoxItem.SetLine( &m_aRightBorderLine, SvxBoxItemLine::RIGHT );
1386  nInnerFrameWidth -= GetBorderWidth( m_aRightBorderLine );
1387  bSet = true;
1388  }
1389 
1390  if (pBoxItem)
1391  {
1392  pFrameFormat->SetFormatAttr( *pBoxItem );
1393  }
1394  else if (bSet)
1395  {
1396  // BorderDist is not part of a cell with fixed width
1397  sal_uInt16 nBDist = static_cast< sal_uInt16 >(
1398  (2*m_nCellPadding <= nInnerFrameWidth) ? m_nCellPadding
1399  : (nInnerFrameWidth / 2) );
1400  // We only set the item if there's a border or a border distance
1401  // If the latter is missing, there's gonna be a border and we'll have to set the distance
1402  aBoxItem.SetAllDistances(nBDist ? nBDist : MIN_BORDER_DIST);
1403  pFrameFormat->SetFormatAttr( aBoxItem );
1404  }
1405  else
1406  pFrameFormat->ResetFormatAttr( RES_BOX );
1407 
1408  if( pBGBrushItem )
1409  {
1410  pFrameFormat->SetFormatAttr( *pBGBrushItem );
1411  }
1412  else
1413  pFrameFormat->ResetFormatAttr( RES_BACKGROUND );
1414 
1415  // Only set format if there's a value or the box is empty
1416  if( bHasNumFormat && (bHasValue || IsBoxEmpty(pBox)) )
1417  {
1418  bool bLock = pFrameFormat->GetDoc()->GetNumberFormatter()
1419  ->IsTextFormat( nNumFormat );
1420  SfxItemSet aItemSet( *pFrameFormat->GetAttrSet().GetPool(),
1422  SvxAdjust eAdjust = SvxAdjust::End;
1423  SwContentNode *pCNd = nullptr;
1424  if( !bLock )
1425  {
1426  const SwStartNode *pSttNd = pBox->GetSttNd();
1427  pCNd = pSttNd->GetNodes()[pSttNd->GetIndex()+1]
1428  ->GetContentNode();
1429  const SfxPoolItem *pItem;
1430  if( pCNd && pCNd->HasSwAttrSet() &&
1431  SfxItemState::SET==pCNd->GetpSwAttrSet()->GetItemState(
1432  RES_PARATR_ADJUST, false, &pItem ) )
1433  {
1434  eAdjust = static_cast<const SvxAdjustItem *>(pItem)
1435  ->GetAdjust();
1436  }
1437  }
1438  aItemSet.Put( SwTableBoxNumFormat(nNumFormat) );
1439  if( bHasValue )
1440  aItemSet.Put( SwTableBoxValue(nValue) );
1441 
1442  if( bLock )
1443  pFrameFormat->LockModify();
1444  pFrameFormat->SetFormatAttr( aItemSet );
1445  if( bLock )
1446  pFrameFormat->UnlockModify();
1447  else if( pCNd && SvxAdjust::End != eAdjust )
1448  {
1449  SvxAdjustItem aAdjItem( eAdjust, RES_PARATR_ADJUST );
1450  pCNd->SetAttr( aAdjItem );
1451  }
1452  }
1453  else
1454  pFrameFormat->ResetFormatAttr( RES_BOXATR_FORMAT );
1455 
1456  OSL_ENSURE( eVOri != text::VertOrientation::TOP, "text::VertOrientation::TOP is not allowed!" );
1457  if( text::VertOrientation::NONE != eVOri )
1458  {
1459  pFrameFormat->SetFormatAttr( SwFormatVertOrient( 0, eVOri ) );
1460  }
1461  else
1462  pFrameFormat->ResetFormatAttr( RES_VERT_ORIENT );
1463 
1464  if( bReUsable )
1465  const_cast<HTMLTableColumn&>(rColumn).SetFrameFormat(pFrameFormat, bBottomLine, eVOri);
1466  }
1467  else
1468  {
1469  pFrameFormat->ResetFormatAttr( RES_BOX );
1470  pFrameFormat->ResetFormatAttr( RES_BACKGROUND );
1471  pFrameFormat->ResetFormatAttr( RES_VERT_ORIENT );
1472  pFrameFormat->ResetFormatAttr( RES_BOXATR_FORMAT );
1473  }
1474 
1475  if (m_pParser->IsReqIF())
1476  {
1477  // ReqIF case, cells would have no formatting. Apply the default
1478  // table autoformat on them, so imported and UI-created tables look
1479  // the same.
1481  SwTableAutoFormat* pTableFormat = rTable.FindAutoFormat(
1483  if (pTableFormat)
1484  {
1486  pTableFormat->UpdateToSet(nPos, m_nRows==1, m_nCols==1,
1487  const_cast<SfxItemSet&>(static_cast<SfxItemSet const&>(
1488  pFrameFormat->GetAttrSet())),
1490  pFrameFormat->GetDoc()->GetNumberFormatter());
1491  }
1492  }
1493  }
1494  else
1495  {
1496  OSL_ENSURE( pBox->GetSttNd() ||
1497  SfxItemState::SET!=pFrameFormat->GetAttrSet().GetItemState(
1498  RES_VERT_ORIENT, false ),
1499  "Box without content has vertical orientation" );
1500  pBox->ChgFrameFormat( static_cast<SwTableBoxFormat*>(pFrameFormat) );
1501  }
1502 
1503 }
1504 
1506  SwTableLine *pUpper ) const
1507 {
1508  SwTableBox *pBox;
1509 
1510  if (m_xBox1 && m_xBox1->GetSttNd() == pStNd)
1511  {
1512  // If the StartNode is the StartNode of the initially created box, we take that box
1513  pBox = const_cast<HTMLTable*>(this)->m_xBox1.release();
1514  pBox->SetUpper(pUpper);
1515  }
1516  else
1517  pBox = new SwTableBox( m_pBoxFormat, *pStNd, pUpper );
1518 
1519  return pBox;
1520 }
1521 
1522 static void ResetLineFrameFormatAttrs( SwFrameFormat *pFrameFormat )
1523 {
1524  pFrameFormat->ResetFormatAttr( RES_FRM_SIZE );
1525  pFrameFormat->ResetFormatAttr( RES_BACKGROUND );
1526  OSL_ENSURE( SfxItemState::SET!=pFrameFormat->GetAttrSet().GetItemState(
1527  RES_VERT_ORIENT, false ),
1528  "Cell has vertical orientation" );
1529 }
1530 
1531 // !!! could be simplified
1533  sal_uInt16 nTopRow, sal_uInt16 nLeftCol,
1534  sal_uInt16 nBottomRow, sal_uInt16 nRightCol )
1535 {
1536  SwTableLine *pLine;
1537  if (!pUpper && 0 == nTopRow)
1538  pLine = (m_pSwTable->GetTabLines())[0];
1539  else
1541  : m_pLineFormat,
1542  0, pUpper );
1543 
1544  const HTMLTableRow& rTopRow = m_aRows[nTopRow];
1545  sal_uInt16 nRowHeight = rTopRow.GetHeight();
1546  const SvxBrushItem *pBGBrushItem = nullptr;
1547  if (nTopRow > 0 || nBottomRow < m_nRows)
1548  {
1549  // It doesn't make sense to set a color on a line,
1550  // if it's the outermost and simultaneously sole line of a table in a table
1551  pBGBrushItem = rTopRow.GetBGBrush().get();
1552  }
1553  if( nTopRow==nBottomRow-1 && (nRowHeight || pBGBrushItem) )
1554  {
1555  SwTableLineFormat *pFrameFormat = static_cast<SwTableLineFormat*>(pLine->ClaimFrameFormat());
1556  ResetLineFrameFormatAttrs( pFrameFormat );
1557 
1558  if( nRowHeight )
1559  {
1560  // set table height. Since it's a minimum height it can be calculated like in Netscape,
1561  // so without considering the actual border width
1562  nRowHeight += GetTopCellSpace( nTopRow ) +
1563  GetBottomCellSpace( nTopRow, 1 );
1564 
1565  pFrameFormat->SetFormatAttr( SwFormatFrameSize( SwFrameSize::Minimum, 0, nRowHeight ) );
1566  }
1567 
1568  if( pBGBrushItem )
1569  {
1570  pFrameFormat->SetFormatAttr( *pBGBrushItem );
1571  }
1572 
1573  }
1574  else if( !m_pLineFrameFormatNoHeight )
1575  {
1576  // else, we'll have to remove the height from the attribute and remember the format
1578 
1580  }
1581 
1582  SwTableBoxes& rBoxes = pLine->GetTabBoxes();
1583 
1584  sal_uInt16 nStartCol = nLeftCol;
1585  while( nStartCol<nRightCol )
1586  {
1587  sal_uInt16 nCol = nStartCol;
1588  sal_uInt16 nSplitCol = nRightCol;
1589  bool bSplitted = false;
1590  while( !bSplitted )
1591  {
1592  OSL_ENSURE( nCol < nRightCol, "Gone too far" );
1593 
1594  HTMLTableCell& rCell = GetCell(nTopRow,nCol);
1595  const bool bSplit = 1 == rCell.GetColSpan();
1596 
1597  OSL_ENSURE((nCol != nRightCol-1) || bSplit, "Split-Flag wrong");
1598  if( bSplit )
1599  {
1600  SwTableBox* pBox = nullptr;
1601  HTMLTableCell& rCell2 = GetCell(nTopRow, nStartCol);
1602  if (rCell2.GetColSpan() == (nCol+1-nStartCol))
1603  {
1604  // The HTML tables represent a box. So we need to split behind that box
1605  nSplitCol = nCol + 1;
1606 
1607  sal_Int32 nBoxRowSpan = rCell2.GetRowSpan();
1608  if (!rCell2.GetContents() || rCell2.IsCovered())
1609  {
1610  if (rCell2.IsCovered())
1611  nBoxRowSpan = -1 * nBoxRowSpan;
1612 
1613  const SwStartNode* pPrevStartNd =
1614  GetPrevBoxStartNode( nTopRow, nStartCol );
1615  auto xCnts = std::make_shared<HTMLTableCnts>(
1616  m_pParser->InsertTableSection(pPrevStartNd));
1617  const std::shared_ptr<SwHTMLTableLayoutCnts> xCntsLayoutInfo =
1618  xCnts->CreateLayoutInfo();
1619 
1620  rCell2.SetContents(xCnts);
1621  SwHTMLTableLayoutCell *pCurrCell = m_xLayoutInfo->GetCell(nTopRow, nStartCol);
1622  pCurrCell->SetContents(xCntsLayoutInfo);
1623  if( nBoxRowSpan < 0 )
1624  pCurrCell->SetRowSpan( 0 );
1625 
1626  // check COLSPAN if needed
1627  for( sal_uInt16 j=nStartCol+1; j<nSplitCol; j++ )
1628  {
1629  GetCell(nTopRow, j).SetContents(xCnts);
1630  m_xLayoutInfo->GetCell(nTopRow, j)
1631  ->SetContents(xCntsLayoutInfo);
1632  }
1633  }
1634 
1635  pBox = MakeTableBox(pLine, rCell2.GetContents().get(),
1636  nTopRow, nStartCol,
1637  nBottomRow, nSplitCol);
1638 
1639  if (1 != nBoxRowSpan && pBox)
1640  pBox->setRowSpan( nBoxRowSpan );
1641 
1642  bSplitted = true;
1643  }
1644 
1645  OSL_ENSURE( pBox, "Colspan trouble" );
1646 
1647  if( pBox )
1648  rBoxes.push_back( pBox );
1649  }
1650  nCol++;
1651  }
1652  nStartCol = nSplitCol;
1653  }
1654 
1655  return pLine;
1656 }
1657 
1659  HTMLTableCnts *pCnts,
1660  sal_uInt16 nTopRow, sal_uInt16 nLeftCol,
1661  sal_uInt16 nBottomRow, sal_uInt16 nRightCol )
1662 {
1663  SwTableBox *pBox;
1664  sal_uInt16 nColSpan = nRightCol - nLeftCol;
1665  sal_uInt16 nRowSpan = nBottomRow - nTopRow;
1666 
1667  if( !pCnts->Next() )
1668  {
1669  // just one content section
1670  if( pCnts->GetStartNode() )
1671  {
1672  // ... that's not a table
1673  pBox = NewTableBox( pCnts->GetStartNode(), pUpper );
1674  pCnts->SetTableBox( pBox );
1675  }
1676  else if (HTMLTable* pTable = pCnts->GetTable().get())
1677  {
1678  pTable->InheritVertBorders( this, nLeftCol,
1679  nRightCol-nLeftCol );
1680  // ... that's a table. We'll build a new box and put the rows of the table
1681  // in the rows of the box
1682  pBox = new SwTableBox( m_pBoxFormat, 0, pUpper );
1683  sal_uInt16 nAbs, nRel;
1684  m_xLayoutInfo->GetAvail( nLeftCol, nColSpan, nAbs, nRel );
1685  sal_uInt16 nLSpace = m_xLayoutInfo->GetLeftCellSpace( nLeftCol, nColSpan );
1686  sal_uInt16 nRSpace = m_xLayoutInfo->GetRightCellSpace( nLeftCol, nColSpan );
1687  sal_uInt16 nInhSpace = m_xLayoutInfo->GetInhCellSpace( nLeftCol, nColSpan );
1688  pCnts->GetTable()->MakeTable( pBox, nAbs, nRel, nLSpace, nRSpace,
1689  nInhSpace );
1690  }
1691  else
1692  {
1693  return nullptr;
1694  }
1695  }
1696  else
1697  {
1698  // multiple content sections: we'll build a box with rows
1699  pBox = new SwTableBox( m_pBoxFormat, 0, pUpper );
1700  SwTableLines& rLines = pBox->GetTabLines();
1701  bool bFirstPara = true;
1702 
1703  while( pCnts )
1704  {
1705  if( pCnts->GetStartNode() )
1706  {
1707  // normal paragraphs are gonna be boxes in a row
1708  SwTableLine *pLine =
1710  : m_pLineFormat, 0, pBox );
1712  {
1713  // If there's no line format without height yet, we can use that one
1715 
1717  }
1718 
1719  SwTableBox* pCntBox = NewTableBox( pCnts->GetStartNode(),
1720  pLine );
1721  pCnts->SetTableBox( pCntBox );
1722  FixFrameFormat( pCntBox, nTopRow, nLeftCol, nRowSpan, nColSpan,
1723  bFirstPara, nullptr==pCnts->Next() );
1724  pLine->GetTabBoxes().push_back( pCntBox );
1725 
1726  rLines.push_back( pLine );
1727  }
1728  else
1729  {
1730  pCnts->GetTable()->InheritVertBorders( this, nLeftCol,
1731  nRightCol-nLeftCol );
1732  // Tables are entered directly
1733  sal_uInt16 nAbs, nRel;
1734  m_xLayoutInfo->GetAvail( nLeftCol, nColSpan, nAbs, nRel );
1735  sal_uInt16 nLSpace = m_xLayoutInfo->GetLeftCellSpace( nLeftCol,
1736  nColSpan );
1737  sal_uInt16 nRSpace = m_xLayoutInfo->GetRightCellSpace( nLeftCol,
1738  nColSpan );
1739  sal_uInt16 nInhSpace = m_xLayoutInfo->GetInhCellSpace( nLeftCol, nColSpan );
1740  pCnts->GetTable()->MakeTable( pBox, nAbs, nRel, nLSpace,
1741  nRSpace, nInhSpace );
1742  }
1743 
1744  pCnts = pCnts->Next();
1745  bFirstPara = false;
1746  }
1747  }
1748 
1749  FixFrameFormat( pBox, nTopRow, nLeftCol, nRowSpan, nColSpan );
1750 
1751  return pBox;
1752 }
1753 
1755  sal_uInt16 nRow, sal_uInt16 nCol,
1756  sal_uInt16 nRowSpan,
1757  bool bFirstPara, bool bLastPara )
1758 {
1759  OSL_ENSURE( m_nRows>0 && m_nCols>0 && m_nCurrentRow==m_nRows,
1760  "Was CloseTable not called?" );
1761 
1762  // The child table needs a border, if the surrounding cell has a margin on that side.
1763  // The upper/lower border is only set if the table is the first/last paragraph in that cell
1764  // It can't be determined if a border for that table is needed or possible for the left or right side,
1765  // since that's depending on if filler cells are gonna be added. We'll only collect info for now
1766 
1767  if( 0==nRow && pParent->m_bTopBorder && bFirstPara )
1768  {
1769  m_bTopBorder = true;
1770  m_bFillerTopBorder = true; // fillers get a border too
1772  }
1773  if (pParent->m_aRows[nRow+nRowSpan-1].GetBottomBorder() && bLastPara)
1774  {
1775  m_aRows[m_nRows-1].SetBottomBorder(true);
1776  m_bFillerBottomBorder = true; // fillers get a border too
1778  nRow+nRowSpan==pParent->m_nRows ? pParent->m_aBottomBorderLine
1779  : pParent->m_aBorderLine;
1780  }
1781 
1782  // The child table mustn't get an upper or lower border, if that's already done by the surrounding table
1783  // It can get an upper border if the table is not the first paragraph in that cell
1784  m_bTopAllowed = ( !bFirstPara || (pParent->m_bTopAllowed &&
1785  (0==nRow || !pParent->m_aRows[nRow-1].GetBottomBorder())) );
1786 
1787  // The child table has to inherit the color of the cell it's contained in, if it doesn't have one
1788  const SvxBrushItem *pInhBG = pParent->GetCell(nRow, nCol).GetBGBrush().get();
1789  if( !pInhBG && pParent != this &&
1790  pParent->GetCell(nRow,nCol).GetRowSpan() == pParent->m_nRows )
1791  {
1792  // the whole surrounding table is a table in a table and consists only of a single line
1793  // that's gonna be GC-ed (correctly). That's why the background of that line is copied.
1794  pInhBG = pParent->m_aRows[nRow].GetBGBrush().get();
1795  if( !pInhBG )
1796  pInhBG = pParent->GetBGBrush().get();
1797  if( !pInhBG )
1798  pInhBG = pParent->GetInhBGBrush().get();
1799  }
1800  if( pInhBG )
1801  m_xInheritedBackgroundBrush.reset(new SvxBrushItem(*pInhBG));
1802 }
1803 
1805  sal_uInt16 nCol, sal_uInt16 nColSpan )
1806 {
1807  sal_uInt16 nInhLeftBorderWidth = 0;
1808  sal_uInt16 nInhRightBorderWidth = 0;
1809 
1810  if( nCol+nColSpan==pParent->m_nCols && pParent->m_bRightBorder )
1811  {
1812  m_bInheritedRightBorder = true; // just remember for now
1814  nInhRightBorderWidth =
1816  }
1817 
1818  if (pParent->m_aColumns[nCol].bLeftBorder)
1819  {
1820  m_bInheritedLeftBorder = true; // just remember for now
1821  m_aInheritedLeftBorderLine = 0==nCol ? pParent->m_aLeftBorderLine
1822  : pParent->m_aBorderLine;
1823  nInhLeftBorderWidth =
1825  }
1826 
1828  nInhLeftBorderWidth = 2 * MIN_BORDER_DIST;
1830  nInhRightBorderWidth = 2 * MIN_BORDER_DIST;
1831  m_xLayoutInfo->SetInhBorderWidths( nInhLeftBorderWidth,
1832  nInhRightBorderWidth );
1833 
1834  m_bRightAllowed = ( pParent->m_bRightAllowed &&
1835  (nCol+nColSpan==pParent->m_nCols ||
1836  !pParent->m_aColumns[nCol+nColSpan].bLeftBorder) );
1837 }
1838 
1840 {
1841  sal_uInt16 i;
1842  for( i=1; i<m_nCols; i++ )
1843  if( HTMLTableRules::All==m_eRules || HTMLTableRules::Cols==m_eRules ||
1844  ((HTMLTableRules::Rows==m_eRules || HTMLTableRules::Groups==m_eRules) &&
1845  m_aColumns[i-1].IsEndOfGroup()))
1846  {
1847  m_aColumns[i].bLeftBorder = true;
1848  }
1849 
1850  for( i=0; i<m_nRows-1; i++ )
1851  if( HTMLTableRules::All==m_eRules || HTMLTableRules::Rows==m_eRules ||
1852  ((HTMLTableRules::Cols==m_eRules || HTMLTableRules::Groups==m_eRules) &&
1853  m_aRows[i].IsEndOfGroup()))
1854  {
1855  m_aRows[i].SetBottomBorder(true);
1856  }
1857 
1858  if( m_bTopAllowed && (HTMLTableFrame::Above==m_eFrame || HTMLTableFrame::HSides==m_eFrame ||
1859  HTMLTableFrame::Box==m_eFrame) )
1860  m_bTopBorder = true;
1861  if( HTMLTableFrame::Below==m_eFrame || HTMLTableFrame::HSides==m_eFrame ||
1862  HTMLTableFrame::Box==m_eFrame )
1863  {
1864  m_aRows[m_nRows-1].SetBottomBorder(true);
1865  }
1866  if( HTMLTableFrame::RHS==m_eFrame || HTMLTableFrame::VSides==m_eFrame ||
1867  HTMLTableFrame::Box==m_eFrame )
1868  m_bRightBorder = true;
1869  if( HTMLTableFrame::LHS==m_eFrame || HTMLTableFrame::VSides==m_eFrame || HTMLTableFrame::Box==m_eFrame )
1870  {
1871  m_aColumns[0].bLeftBorder = true;
1872  }
1873 
1874  for( i=0; i<m_nRows; i++ )
1875  {
1876  HTMLTableRow& rRow = m_aRows[i];
1877  for (sal_uInt16 j=0; j<m_nCols; ++j)
1878  {
1879  HTMLTableCell& rCell = rRow.GetCell(j);
1880  if (rCell.GetContents())
1881  {
1882  HTMLTableCnts *pCnts = rCell.GetContents().get();
1883  bool bFirstPara = true;
1884  while( pCnts )
1885  {
1886  HTMLTable *pTable = pCnts->GetTable().get();
1887  if( pTable && !pTable->BordersSet() )
1888  {
1889  pTable->InheritBorders(this, i, j,
1890  rCell.GetRowSpan(),
1891  bFirstPara,
1892  nullptr==pCnts->Next());
1893  pTable->SetBorders();
1894  }
1895  bFirstPara = false;
1896  pCnts = pCnts->Next();
1897  }
1898  }
1899  }
1900  }
1901 
1902  m_bBordersSet = true;
1903 }
1904 
1905 sal_uInt16 HTMLTable::GetBorderWidth( const SvxBorderLine& rBLine,
1906  bool bWithDistance ) const
1907 {
1908  sal_uInt16 nBorderWidth = rBLine.GetWidth();
1909  if( bWithDistance )
1910  {
1911  if( m_nCellPadding )
1912  nBorderWidth = nBorderWidth + m_nCellPadding;
1913  else if( nBorderWidth )
1914  nBorderWidth = nBorderWidth + MIN_BORDER_DIST;
1915  }
1916 
1917  return nBorderWidth;
1918 }
1919 
1920 const HTMLTableCell& HTMLTable::GetCell(sal_uInt16 nRow, sal_uInt16 nCell) const
1921 {
1922  OSL_ENSURE(nRow < m_aRows.size(), "invalid row index in HTML table");
1923  return m_aRows[nRow].GetCell(nCell);
1924 }
1925 
1927 {
1929  : SvxAdjust::End );
1930  if( SvxAdjust::End==eAdjust )
1931  eAdjust = m_aRows[m_nCurrentRow].GetAdjust();
1932 
1933  return eAdjust;
1934 }
1935 
1937 {
1938  // text::VertOrientation::TOP is default!
1939  sal_Int16 eVOri = m_aRows[m_nCurrentRow].GetVertOri();
1940  if( text::VertOrientation::TOP==eVOri && m_nCurrentColumn<m_nCols )
1941  eVOri = m_aColumns[m_nCurrentColumn].GetVertOri();
1942  if( text::VertOrientation::TOP==eVOri )
1943  eVOri = m_eVertOrientation;
1944 
1945  OSL_ENSURE( m_eVertOrientation != text::VertOrientation::TOP, "text::VertOrientation::TOP is not allowed!" );
1946  return eVOri;
1947 }
1948 
1949 void HTMLTable::InsertCell( std::shared_ptr<HTMLTableCnts> const& rCnts,
1950  sal_uInt16 nRowSpan, sal_uInt16 nColSpan,
1951  sal_uInt16 nCellWidth, bool bRelWidth, sal_uInt16 nCellHeight,
1952  sal_Int16 eVertOrient, std::shared_ptr<SvxBrushItem> const& rBGBrushItem,
1953  std::shared_ptr<SvxBoxItem> const& rBoxItem,
1954  bool bHasNumFormat, sal_uInt32 nNumFormat,
1955  bool bHasValue, double nValue, bool bNoWrap )
1956 {
1957  if( !nRowSpan || static_cast<sal_uInt32>(m_nCurrentRow) + nRowSpan > USHRT_MAX )
1958  nRowSpan = 1;
1959 
1960  if( !nColSpan || static_cast<sal_uInt32>(m_nCurrentColumn) + nColSpan > USHRT_MAX )
1961  nColSpan = 1;
1962 
1963  sal_uInt16 nColsReq = m_nCurrentColumn + nColSpan;
1964  sal_uInt16 nRowsReq = m_nCurrentRow + nRowSpan;
1965  sal_uInt16 i, j;
1966 
1967  // if we need more columns than we currently have, we need to add cells for all rows
1968  if( m_nCols < nColsReq )
1969  {
1970  m_aColumns.resize(nColsReq);
1971  for( i=0; i<m_nRows; i++ )
1972  m_aRows[i].Expand( nColsReq, i<m_nCurrentRow );
1973  m_nCols = nColsReq;
1974  OSL_ENSURE(m_aColumns.size() == m_nCols,
1975  "wrong number of columns after expanding");
1976  }
1977  if( nColsReq > m_nFilledColumns )
1978  m_nFilledColumns = nColsReq;
1979 
1980  // if we need more rows than we currently have, we need to add cells
1981  if( m_nRows < nRowsReq )
1982  {
1983  for( i=m_nRows; i<nRowsReq; i++ )
1984  m_aRows.emplace_back(m_nCols);
1985  m_nRows = nRowsReq;
1986  OSL_ENSURE(m_nRows == m_aRows.size(), "wrong number of rows in Insert");
1987  }
1988 
1989  // Check if we have an overlap and could remove that
1990  sal_uInt16 nSpanedCols = 0;
1991  if( m_nCurrentRow>0 )
1992  {
1993  HTMLTableRow& rCurRow = m_aRows[m_nCurrentRow];
1994  for( i=m_nCurrentColumn; i<nColsReq; i++ )
1995  {
1996  HTMLTableCell& rCell = rCurRow.GetCell(i);
1997  if (rCell.GetContents())
1998  {
1999  // A cell from a row further above overlaps this one.
2000  // Content and colors are coming from that cell and can be overwritten
2001  // or deleted (content) or copied (color) by ProtectRowSpan
2002  nSpanedCols = i + rCell.GetColSpan();
2003  FixRowSpan( m_nCurrentRow-1, i, rCell.GetContents().get() );
2004  if (rCell.GetRowSpan() > nRowSpan)
2005  ProtectRowSpan( nRowsReq, i,
2006  rCell.GetRowSpan()-nRowSpan );
2007  }
2008  }
2009  for( i=nColsReq; i<nSpanedCols; i++ )
2010  {
2011  // These contents are anchored in the row above in any case
2012  HTMLTableCell& rCell = rCurRow.GetCell(i);
2013  FixRowSpan( m_nCurrentRow-1, i, rCell.GetContents().get() );
2014  ProtectRowSpan( m_nCurrentRow, i, rCell.GetRowSpan() );
2015  }
2016  }
2017 
2018  // Fill the cells
2019  for( i=nColSpan; i>0; i-- )
2020  {
2021  for( j=nRowSpan; j>0; j-- )
2022  {
2023  const bool bCovered = i != nColSpan || j != nRowSpan;
2024  GetCell( nRowsReq-j, nColsReq-i )
2025  .Set( rCnts, j, i, eVertOrient, rBGBrushItem, rBoxItem,
2026  bHasNumFormat, nNumFormat, bHasValue, nValue, bNoWrap, bCovered );
2027  }
2028  }
2029 
2030  Size aTwipSz( bRelWidth ? 0 : nCellWidth, nCellHeight );
2031  if( (aTwipSz.Width() || aTwipSz.Height()) && Application::GetDefaultDevice() )
2032  {
2033  aTwipSz = Application::GetDefaultDevice()
2034  ->PixelToLogic( aTwipSz, MapMode( MapUnit::MapTwip ) );
2035  }
2036 
2037  // Only set width on the first cell!
2038  if( nCellWidth )
2039  {
2040  sal_uInt16 nTmp = bRelWidth ? nCellWidth : static_cast<sal_uInt16>(aTwipSz.Width());
2041  GetCell( m_nCurrentRow, m_nCurrentColumn ).SetWidth( nTmp, bRelWidth );
2042  }
2043 
2044  // Remember height
2045  if( nCellHeight && 1==nRowSpan )
2046  {
2047  m_aRows[m_nCurrentRow].SetHeight(static_cast<sal_uInt16>(aTwipSz.Height()));
2048  }
2049 
2050  // Set the column counter behind the new cells
2051  m_nCurrentColumn = nColsReq;
2052  if( nSpanedCols > m_nCurrentColumn )
2053  m_nCurrentColumn = nSpanedCols;
2054 
2055  // and search for the next free cell
2057  m_nCurrentColumn++;
2058 }
2059 
2060 inline void HTMLTable::CloseSection( bool bHead )
2061 {
2062  // Close the preceding sections if there's already a row
2063  OSL_ENSURE( m_nCurrentRow<=m_nRows, "invalid current row" );
2064  if( m_nCurrentRow>0 && m_nCurrentRow<=m_nRows )
2065  m_aRows[m_nCurrentRow-1].SetEndOfGroup();
2066  if( bHead )
2068 }
2069 
2070 void HTMLTable::OpenRow(SvxAdjust eAdjust, sal_Int16 eVertOrient,
2071  std::unique_ptr<SvxBrushItem>& rBGBrushItem)
2072 {
2073  sal_uInt16 nRowsReq = m_nCurrentRow+1;
2074 
2075  // create the next row if it's not there already
2076  if( m_nRows<nRowsReq )
2077  {
2078  for( sal_uInt16 i=m_nRows; i<nRowsReq; i++ )
2079  m_aRows.emplace_back(m_nCols);
2080  m_nRows = nRowsReq;
2081  OSL_ENSURE( m_nRows == m_aRows.size(),
2082  "Row number in OpenRow is wrong" );
2083  }
2084 
2085  HTMLTableRow& rCurRow = m_aRows[m_nCurrentRow];
2086  rCurRow.SetAdjust(eAdjust);
2087  rCurRow.SetVertOri(eVertOrient);
2088  if (rBGBrushItem)
2089  m_aRows[m_nCurrentRow].SetBGBrush(rBGBrushItem);
2090 
2091  // reset the column counter
2092  m_nCurrentColumn=0;
2093 
2094  // and search for the next free cell
2096  m_nCurrentColumn++;
2097 }
2098 
2099 void HTMLTable::CloseRow( bool bEmpty )
2100 {
2101  OSL_ENSURE( m_nCurrentRow<m_nRows, "current row after table end" );
2102 
2103  // empty cells just get a slightly thicker lower border!
2104  if( bEmpty )
2105  {
2106  if( m_nCurrentRow > 0 )
2107  m_aRows[m_nCurrentRow-1].IncEmptyRows();
2108  return;
2109  }
2110 
2111  HTMLTableRow& rRow = m_aRows[m_nCurrentRow];
2112 
2113  // modify the COLSPAN of all empty cells at the row end in a way, that they're forming a single cell
2114  // that can be done here (and not earlier) since there's no more cells in that row
2115  sal_uInt16 i=m_nCols;
2116  while( i )
2117  {
2118  HTMLTableCell& rCell = rRow.GetCell(--i);
2119  if (!rCell.GetContents())
2120  {
2121  sal_uInt16 nColSpan = m_nCols-i;
2122  if( nColSpan > 1 )
2123  rCell.SetColSpan(nColSpan);
2124  }
2125  else
2126  break;
2127  }
2128 
2129  m_nCurrentRow++;
2130 }
2131 
2132 inline void HTMLTable::CloseColGroup( sal_uInt16 nSpan, sal_uInt16 _nWidth,
2133  bool bRelWidth, SvxAdjust eAdjust,
2134  sal_Int16 eVertOrient )
2135 {
2136  if( nSpan )
2137  InsertCol( nSpan, _nWidth, bRelWidth, eAdjust, eVertOrient );
2138 
2139  OSL_ENSURE( m_nCurrentColumn<=m_nCols, "invalid column" );
2141  m_aColumns[m_nCurrentColumn-1].SetEndOfGroup();
2142 }
2143 
2144 void HTMLTable::InsertCol( sal_uInt16 nSpan, sal_uInt16 nColWidth, bool bRelWidth,
2145  SvxAdjust eAdjust, sal_Int16 eVertOrient )
2146 {
2147  // #i35143# - no columns, if rows already exist.
2148  if ( m_nRows > 0 )
2149  return;
2150 
2151  sal_uInt16 i;
2152 
2153  if( !nSpan )
2154  nSpan = 1;
2155 
2156  sal_uInt16 nColsReq = m_nCurrentColumn + nSpan;
2157 
2158  if( m_nCols < nColsReq )
2159  {
2160  m_aColumns.resize(nColsReq);
2161  m_nCols = nColsReq;
2162  }
2163 
2164  Size aTwipSz( bRelWidth ? 0 : nColWidth, 0 );
2165  if( aTwipSz.Width() && Application::GetDefaultDevice() )
2166  {
2167  aTwipSz = Application::GetDefaultDevice()
2168  ->PixelToLogic( aTwipSz, MapMode( MapUnit::MapTwip ) );
2169  }
2170 
2171  for( i=m_nCurrentColumn; i<nColsReq; i++ )
2172  {
2173  HTMLTableColumn& rCol = m_aColumns[i];
2174  sal_uInt16 nTmp = bRelWidth ? nColWidth : static_cast<sal_uInt16>(aTwipSz.Width());
2175  rCol.SetWidth( nTmp, bRelWidth );
2176  rCol.SetAdjust( eAdjust );
2177  rCol.SetVertOri( eVertOrient );
2178  }
2179 
2180  m_bColSpec = true;
2181 
2182  m_nCurrentColumn = nColsReq;
2183 }
2184 
2186 {
2187  sal_uInt16 i;
2188 
2189  // The number of table rows is only dependent on the <TR> elements (i.e. nCurRow).
2190  // Rows that are spanned via ROWSPAN behind nCurRow need to be deleted
2191  // and we need to adjust the ROWSPAN in the rows above
2192  if( m_nRows>m_nCurrentRow )
2193  {
2194  HTMLTableRow& rPrevRow = m_aRows[m_nCurrentRow-1];
2195  for( i=0; i<m_nCols; i++ )
2196  {
2197  HTMLTableCell& rCell = rPrevRow.GetCell(i);
2198  if (rCell.GetRowSpan() > 1)
2199  {
2200  FixRowSpan(m_nCurrentRow-1, i, rCell.GetContents().get());
2202  }
2203  }
2204  for( i=m_nRows-1; i>=m_nCurrentRow; i-- )
2205  m_aRows.erase(m_aRows.begin() + i);
2207  }
2208 
2209  // if the table has no column, we need to add one
2210  if( 0==m_nCols )
2211  {
2212  m_aColumns.resize(1);
2213  for( i=0; i<m_nRows; i++ )
2214  m_aRows[i].Expand(1);
2215  m_nCols = 1;
2216  m_nFilledColumns = 1;
2217  }
2218 
2219  // if the table has no row, we need to add one
2220  if( 0==m_nRows )
2221  {
2222  m_aRows.emplace_back(m_nCols);
2223  m_nRows = 1;
2224  m_nCurrentRow = 1;
2225  }
2226 
2227  if( m_nFilledColumns < m_nCols )
2228  {
2229  m_aColumns.erase(m_aColumns.begin() + m_nFilledColumns, m_aColumns.begin() + m_nCols);
2230  for( i=0; i<m_nRows; i++ )
2233  }
2234 }
2235 
2237 {
2238  SwTableLines& rLines = (pBox ? pBox->GetTabLines()
2239  : const_cast<SwTable *>(m_pSwTable)->GetTabLines() );
2240 
2241  for( sal_uInt16 i=0; i<m_nRows; i++ )
2242  {
2243  SwTableLine *pLine = MakeTableLine( pBox, i, 0, i+1, m_nCols );
2244  if( pBox || i > 0 )
2245  rLines.push_back( pLine );
2246  }
2247 }
2248 
2249 /* How are tables aligned?
2250 
2251 first row: without paragraph indents
2252 second row: with paragraph indents
2253 
2254 ALIGN= LEFT RIGHT CENTER -
2255 -------------------------------------------------------------------------
2256 xxx for tables with WIDTH=nn% the percentage value is important:
2257 xxx nn = 100 text::HoriOrientation::FULL text::HoriOrientation::FULL text::HoriOrientation::FULL text::HoriOrientation::FULL %
2258 xxx text::HoriOrientation::NONE text::HoriOrientation::NONE text::HoriOrientation::NONE % text::HoriOrientation::NONE %
2259 xxx nn < 100 frame F frame F text::HoriOrientation::CENTER % text::HoriOrientation::LEFT %
2260 xxx frame F frame F text::HoriOrientation::CENTER % text::HoriOrientation::NONE %
2261 
2262 for tables with WIDTH=nn% the percentage value is important:
2263 nn = 100 text::HoriOrientation::LEFT text::HoriOrientation::RIGHT text::HoriOrientation::CENTER % text::HoriOrientation::LEFT %
2264  text::HoriOrientation::LEFT_AND text::HoriOrientation::RIGHT text::HoriOrientation::CENTER % text::HoriOrientation::LEFT_AND %
2265 nn < 100 frame F frame F text::HoriOrientation::CENTER % text::HoriOrientation::LEFT %
2266  frame F frame F text::HoriOrientation::CENTER % text::HoriOrientation::NONE %
2267 
2268 otherwise the calculated width w
2269 w = avail* text::HoriOrientation::LEFT text::HoriOrientation::RIGHT text::HoriOrientation::CENTER text::HoriOrientation::LEFT
2270  HORI_LEDT_AND text::HoriOrientation::RIGHT text::HoriOrientation::CENTER text::HoriOrientation::LEFT_AND
2271 w < avail frame L frame L text::HoriOrientation::CENTER text::HoriOrientation::LEFT
2272  frame L frame L text::HoriOrientation::CENTER text::HoriOrientation::NONE
2273 
2274 xxx *) if for the table no size was specified, always
2275 xxx text::HoriOrientation::FULL is taken
2276 
2277 */
2278 
2279 void HTMLTable::MakeTable( SwTableBox *pBox, sal_uInt16 nAbsAvail,
2280  sal_uInt16 nRelAvail, sal_uInt16 nAbsLeftSpace,
2281  sal_uInt16 nAbsRightSpace, sal_uInt16 nInhAbsSpace )
2282 {
2283  OSL_ENSURE( m_nRows>0 && m_nCols>0 && m_nCurrentRow==m_nRows,
2284  "Was CloseTable not called?" );
2285 
2286  OSL_ENSURE(m_xLayoutInfo == nullptr, "Table already has layout info");
2287 
2288  // Calculate borders of the table and all contained tables
2289  SetBorders();
2290 
2291  // Step 1: needed layout structures are created (including tables in tables)
2292  CreateLayoutInfo();
2293 
2294  if (!utl::ConfigManager::IsFuzzing()) // skip slow path for fuzzing
2295  {
2296  // Step 2: the minimal and maximal column width is calculated
2297  // (including tables in tables). Since we don't have boxes yet,
2298  // we'll work on the start nodes
2299  m_xLayoutInfo->AutoLayoutPass1();
2300 
2301  // Step 3: the actual column widths of this table are calculated (not tables in tables)
2302  // We need this now to decide if we need filler cells
2303  // (Pass1 was needed because of this as well)
2304  m_xLayoutInfo->AutoLayoutPass2( nAbsAvail, nRelAvail, nAbsLeftSpace,
2305  nAbsRightSpace, nInhAbsSpace );
2306  }
2307 
2308  // Set adjustment for the top table
2309  sal_Int16 eHoriOri;
2310  if (m_bForceFrame)
2311  {
2312  // The table should go in a text frame and it's narrower than the
2313  // available space and not 100% wide. So it gets a border
2314  eHoriOri = m_bPercentWidth ? text::HoriOrientation::FULL : text::HoriOrientation::LEFT;
2315  }
2316  else switch (m_eTableAdjust)
2317  {
2318  // The table either fits the page but shouldn't get a text frame,
2319  // or it's wider than the page so it doesn't need a text frame
2320 
2321  case SvxAdjust::Right:
2322  // Don't be considerate of the right margin in right-adjusted tables
2323  eHoriOri = text::HoriOrientation::RIGHT;
2324  break;
2325  case SvxAdjust::Center:
2326  // Centred tables are not considerate of margins
2327  eHoriOri = text::HoriOrientation::CENTER;
2328  break;
2329  case SvxAdjust::Left:
2330  default:
2331  // left-adjusted tables are only considerate of the left margin
2332  eHoriOri = m_nLeftMargin ? text::HoriOrientation::LEFT_AND_WIDTH : text::HoriOrientation::LEFT;
2333  break;
2334  }
2335 
2336  if (!m_pSwTable)
2337  {
2338  SAL_WARN("sw.html", "no table");
2339  return;
2340  }
2341 
2342  // get the table format and adapt it
2343  SwFrameFormat *pFrameFormat = m_pSwTable->GetFrameFormat();
2344  pFrameFormat->SetFormatAttr( SwFormatHoriOrient(0, eHoriOri) );
2345  if (text::HoriOrientation::LEFT_AND_WIDTH == eHoriOri)
2346  {
2347  OSL_ENSURE( m_nLeftMargin || m_nRightMargin,
2348  "There are still leftovers from relative margins" );
2349 
2350  // The right margin will be ignored anyway.
2352  aLRItem.SetLeft( m_nLeftMargin );
2353  aLRItem.SetRight( m_nRightMargin );
2354  pFrameFormat->SetFormatAttr( aLRItem );
2355  }
2356 
2357  if (m_bPercentWidth && text::HoriOrientation::FULL != eHoriOri)
2358  {
2359  pFrameFormat->LockModify();
2360  SwFormatFrameSize aFrameSize( pFrameFormat->GetFrameSize() );
2361  aFrameSize.SetWidthPercent( static_cast<sal_uInt8>(m_nWidth) );
2362  pFrameFormat->SetFormatAttr( aFrameSize );
2363  pFrameFormat->UnlockModify();
2364  }
2365 
2366  // get the default line and box format
2367  // remember the first box and unlist it from the first row
2368  SwTableLine *pLine1 = (m_pSwTable->GetTabLines())[0];
2369  m_xBox1.reset((pLine1->GetTabBoxes())[0]);
2370  pLine1->GetTabBoxes().erase(pLine1->GetTabBoxes().begin());
2371 
2372  m_pLineFormat = static_cast<SwTableLineFormat*>(pLine1->GetFrameFormat());
2373  m_pBoxFormat = static_cast<SwTableBoxFormat*>(m_xBox1->GetFrameFormat());
2374 
2375  MakeTable_( pBox );
2376 
2377  // Finally, we'll do a garbage collection for the top level table
2378 
2379  if( 1==m_nRows && m_nHeight && 1==m_pSwTable->GetTabLines().size() )
2380  {
2381  // Set height of a one-row table as the minimum width of the row
2382  // Was originally a fixed height, but that made problems
2383  // and is not Netscape 4.0 compliant
2385  if( m_nHeight < MINLAY )
2386  m_nHeight = MINLAY;
2387 
2388  (m_pSwTable->GetTabLines())[0]->ClaimFrameFormat();
2389  (m_pSwTable->GetTabLines())[0]->GetFrameFormat()
2390  ->SetFormatAttr( SwFormatFrameSize( SwFrameSize::Minimum, 0, m_nHeight ) );
2391  }
2392 
2393  if( GetBGBrush() )
2395 
2396  const_cast<SwTable *>(m_pSwTable)->SetRowsToRepeat( static_cast< sal_uInt16 >(m_nHeadlineRepeat) );
2397  const_cast<SwTable *>(m_pSwTable)->GCLines();
2398 
2399  bool bIsInFlyFrame = m_pContext && m_pContext->GetFrameFormat();
2400  if( bIsInFlyFrame && !m_nWidth )
2401  {
2402  SvxAdjust eAdjust = GetTableAdjust(false);
2403  if (eAdjust != SvxAdjust::Left &&
2404  eAdjust != SvxAdjust::Right)
2405  {
2406  // If a table with a width attribute isn't flowed around left or right
2407  // we'll stack it with a border of 100% width, so its size will
2408  // be adapted. That text frame mustn't be modified
2409  OSL_ENSURE( HasToFly(), "Why is the table in a frame?" );
2410  sal_uInt32 nMin = m_xLayoutInfo->GetMin();
2411  if( nMin > USHRT_MAX )
2412  nMin = USHRT_MAX;
2413  SwFormatFrameSize aFlyFrameSize( SwFrameSize::Variable, static_cast<SwTwips>(nMin), MINLAY );
2414  aFlyFrameSize.SetWidthPercent( 100 );
2415  m_pContext->GetFrameFormat()->SetFormatAttr( aFlyFrameSize );
2416  bIsInFlyFrame = false;
2417  }
2418  else
2419  {
2420  // left or right adjusted table without width mustn't be adjusted in width
2421  // as they would only shrink but never grow
2422  m_xLayoutInfo->SetMustNotRecalc( true );
2423  if( m_pContext->GetFrameFormat()->GetAnchor().GetContentAnchor()
2424  ->nNode.GetNode().FindTableNode() )
2425  {
2426  sal_uInt32 nMax = m_xLayoutInfo->GetMax();
2427  if( nMax > USHRT_MAX )
2428  nMax = USHRT_MAX;
2429  SwFormatFrameSize aFlyFrameSize( SwFrameSize::Variable, static_cast<SwTwips>(nMax), MINLAY );
2430  m_pContext->GetFrameFormat()->SetFormatAttr( aFlyFrameSize );
2431  bIsInFlyFrame = false;
2432  }
2433  else
2434  {
2435  m_xLayoutInfo->SetMustNotResize( true );
2436  }
2437  }
2438  }
2439  m_xLayoutInfo->SetMayBeInFlyFrame( bIsInFlyFrame );
2440 
2441  // Only tables with relative width or without width should be modified
2442  m_xLayoutInfo->SetMustResize( m_bPercentWidth || !m_nWidth );
2443 
2444  if (!pLine1->GetTabBoxes().empty())
2445  m_xLayoutInfo->SetWidths();
2446  else
2447  SAL_WARN("sw.html", "no table box");
2448 
2449  const_cast<SwTable *>(m_pSwTable)->SetHTMLTableLayout(m_xLayoutInfo);
2450 
2451  if( !m_pResizeDrawObjects )
2452  return;
2453 
2454  sal_uInt16 nCount = m_pResizeDrawObjects->size();
2455  for( sal_uInt16 i=0; i<nCount; i++ )
2456  {
2457  SdrObject *pObj = (*m_pResizeDrawObjects)[i];
2458  sal_uInt16 nRow = (*m_pDrawObjectPercentWidths)[3*i];
2459  sal_uInt16 nCol = (*m_pDrawObjectPercentWidths)[3*i+1];
2460  sal_uInt8 nPercentWidth = static_cast<sal_uInt8>((*m_pDrawObjectPercentWidths)[3*i+2]);
2461 
2462  SwHTMLTableLayoutCell *pLayoutCell =
2463  m_xLayoutInfo->GetCell( nRow, nCol );
2464  sal_uInt16 nColSpan = pLayoutCell->GetColSpan();
2465 
2466  sal_uInt16 nWidth2, nDummy;
2467  m_xLayoutInfo->GetAvail( nCol, nColSpan, nWidth2, nDummy );
2468  nWidth2 = static_cast< sal_uInt16 >((static_cast<tools::Long>(m_nWidth) * nPercentWidth) / 100);
2469 
2470  SwHTMLParser::ResizeDrawObject( pObj, nWidth2 );
2471  }
2472 
2473 }
2474 
2475 void HTMLTable::SetTable( const SwStartNode *pStNd, std::unique_ptr<HTMLTableContext> pCntxt,
2476  sal_uInt16 nLeft, sal_uInt16 nRight,
2477  const SwTable *pSwTab, bool bFrcFrame )
2478 {
2479  m_pPrevStartNode = pStNd;
2480  m_pSwTable = pSwTab;
2481  m_pContext = std::move(pCntxt);
2482 
2483  m_nLeftMargin = nLeft;
2484  m_nRightMargin = nRight;
2485 
2486  m_bForceFrame = bFrcFrame;
2487 }
2488 
2490 {
2491  if( !m_pResizeDrawObjects )
2492  m_pResizeDrawObjects.reset(new SdrObjects);
2493  m_pResizeDrawObjects->push_back( pObj );
2494 
2496  m_pDrawObjectPercentWidths.reset(new std::vector<sal_uInt16>);
2499  m_pDrawObjectPercentWidths->push_back( static_cast<sal_uInt16>(nPercentWidth) );
2500 }
2501 
2503 {
2504  if( !GetContext() && !HasParentSection() )
2505  {
2508 
2509  SetHasParentSection( true );
2510  }
2511 }
2512 
2513 void HTMLTableContext::SavePREListingXMP( SwHTMLParser& rParser )
2514 {
2515  bRestartPRE = rParser.IsReadPRE();
2516  bRestartXMP = rParser.IsReadXMP();
2517  bRestartListing = rParser.IsReadListing();
2518  rParser.FinishPREListingXMP();
2519 }
2520 
2521 void HTMLTableContext::RestorePREListingXMP( SwHTMLParser& rParser )
2522 {
2523  rParser.FinishPREListingXMP();
2524 
2525  if( bRestartPRE )
2526  rParser.StartPRE();
2527 
2528  if( bRestartXMP )
2529  rParser.StartXMP();
2530 
2531  if( bRestartListing )
2532  rParser.StartListing();
2533 }
2534 
2536  ( const SwStartNode *pPrevStNd )
2537 {
2538  OSL_ENSURE( pPrevStNd, "Start-Node is NULL" );
2539 
2540  m_pCSS1Parser->SetTDTagStyles();
2541  SwTextFormatColl *pColl = m_pCSS1Parser->GetTextCollFromPool( RES_POOLCOLL_TABLE );
2542 
2543  const SwStartNode *pStNd;
2544  if (m_xTable->m_bFirstCell )
2545  {
2546  SwNode *const pNd = & m_pPam->GetPoint()->nNode.GetNode();
2547  pNd->GetTextNode()->ChgFormatColl( pColl );
2548  pStNd = pNd->FindTableBoxStartNode();
2549  m_xTable->m_bFirstCell = false;
2550  }
2551  else if (pPrevStNd)
2552  {
2553  const SwNode* pNd;
2554  if( pPrevStNd->IsTableNode() )
2555  pNd = pPrevStNd;
2556  else
2557  pNd = pPrevStNd->EndOfSectionNode();
2558  SwNodeIndex nIdx( *pNd, 1 );
2559  pStNd = m_xDoc->GetNodes().MakeTextSection( nIdx, SwTableBoxStartNode,
2560  pColl );
2561  m_xTable->IncBoxCount();
2562  }
2563  else
2564  {
2565  eState = SvParserState::Error;
2566  return nullptr;
2567  }
2568 
2569  //Added defaults to CJK and CTL
2570  SwContentNode *pCNd = m_xDoc->GetNodes()[pStNd->GetIndex()+1] ->GetContentNode();
2571  SvxFontHeightItem aFontHeight( 40, 100, RES_CHRATR_FONTSIZE );
2572  pCNd->SetAttr( aFontHeight );
2573  SvxFontHeightItem aFontHeightCJK( 40, 100, RES_CHRATR_CJK_FONTSIZE );
2574  pCNd->SetAttr( aFontHeightCJK );
2575  SvxFontHeightItem aFontHeightCTL( 40, 100, RES_CHRATR_CTL_FONTSIZE );
2576  pCNd->SetAttr( aFontHeightCTL );
2577 
2578  return pStNd;
2579 }
2580 
2581 const SwStartNode *SwHTMLParser::InsertTableSection( sal_uInt16 nPoolId )
2582 {
2583  switch( nPoolId )
2584  {
2586  m_pCSS1Parser->SetTHTagStyles();
2587  break;
2588  case RES_POOLCOLL_TABLE:
2589  m_pCSS1Parser->SetTDTagStyles();
2590  break;
2591  }
2592 
2593  SwTextFormatColl *pColl = m_pCSS1Parser->GetTextCollFromPool( nPoolId );
2594 
2595  SwNode *const pNd = & m_pPam->GetPoint()->nNode.GetNode();
2596  const SwStartNode *pStNd;
2597  if (m_xTable->m_bFirstCell)
2598  {
2599  SwTextNode* pTextNd = pNd->GetTextNode();
2600  if (!pTextNd)
2601  {
2602  eState = SvParserState::Error;
2603  return nullptr;
2604  }
2605  pTextNd->ChgFormatColl(pColl);
2606  m_xTable->m_bFirstCell = false;
2607  pStNd = pNd->FindTableBoxStartNode();
2608  }
2609  else
2610  {
2611  SwTableNode *pTableNd = pNd->FindTableNode();
2612  if (!pTableNd)
2613  {
2614  eState = SvParserState::Error;
2615  return nullptr;
2616  }
2617  if( pTableNd->GetTable().GetHTMLTableLayout() )
2618  { // if there is already a HTMTableLayout, this table is already finished
2619  // and we have to look for the right table in the environment
2620  SwTableNode *pOutTable = pTableNd;
2621  do {
2622  pTableNd = pOutTable;
2623  pOutTable = pOutTable->StartOfSectionNode()->FindTableNode();
2624  } while( pOutTable && pTableNd->GetTable().GetHTMLTableLayout() );
2625  }
2626  SwNodeIndex aIdx( *pTableNd->EndOfSectionNode() );
2627  pStNd = m_xDoc->GetNodes().MakeTextSection( aIdx, SwTableBoxStartNode,
2628  pColl );
2629 
2630  m_pPam->GetPoint()->nNode = pStNd->GetIndex() + 1;
2631  SwTextNode *pTextNd = m_pPam->GetPoint()->nNode.GetNode().GetTextNode();
2632  m_pPam->GetPoint()->nContent.Assign( pTextNd, 0 );
2633  m_xTable->IncBoxCount();
2634  }
2635 
2636  if (!pStNd)
2637  {
2638  eState = SvParserState::Error;
2639  }
2640 
2641  return pStNd;
2642 }
2643 
2645 {
2646  SwTextFormatColl *pColl = m_pCSS1Parser->GetTextCollFromPool( RES_POOLCOLL_TEXT );
2647  SwNodeIndex& rIdx = m_pPam->GetPoint()->nNode;
2648  rIdx = m_xDoc->GetNodes().GetEndOfExtras();
2649  SwStartNode *pStNd = m_xDoc->GetNodes().MakeTextSection( rIdx,
2650  SwNormalStartNode, pColl );
2651 
2652  rIdx = pStNd->GetIndex() + 1;
2653  m_pPam->GetPoint()->nContent.Assign( rIdx.GetNode().GetTextNode(), 0 );
2654 
2655  return pStNd;
2656 }
2657 
2659 {
2660  sal_Int32 nStripped = 0;
2661 
2662  const sal_Int32 nLen = m_pPam->GetPoint()->nContent.GetIndex();
2663  if( nLen )
2664  {
2665  SwTextNode* pTextNd = m_pPam->GetPoint()->nNode.GetNode().GetTextNode();
2666  // careful, when comments aren't ignored!!!
2667  if( pTextNd )
2668  {
2669  sal_Int32 nPos = nLen;
2670  sal_Int32 nLFCount = 0;
2671  while (nPos && ('\x0a' == pTextNd->GetText()[--nPos]))
2672  nLFCount++;
2673 
2674  if( nLFCount )
2675  {
2676  if( nLFCount > 2 )
2677  {
2678  // On Netscape, a paragraph end matches 2 LFs
2679  // (1 is just a newline, 2 creates a blank line)
2680  // We already have this space with the lower paragraph gap
2681  // If there's a paragraph after the <BR>, we take the maximum
2682  // of the gap that results from the <BR> and <P>
2683  // That's why we need to delete 2 respectively all if less than 2
2684  nLFCount = 2;
2685  }
2686 
2687  nPos = nLen - nLFCount;
2688  SwIndex nIdx( pTextNd, nPos );
2689  pTextNd->EraseText( nIdx, nLFCount );
2690  nStripped = nLFCount;
2691  }
2692  }
2693  }
2694 
2695  return nStripped;
2696 }
2697 
2699  const OUString& rImageURL,
2700  const OUString& rStyle,
2701  const OUString& rId,
2702  const OUString& rClass )
2703 {
2704  SvxBrushItem *pBrushItem = nullptr;
2705 
2706  if( !rStyle.isEmpty() || !rId.isEmpty() || !rClass.isEmpty() )
2707  {
2708  SfxItemSet aItemSet( m_xDoc->GetAttrPool(), svl::Items<RES_BACKGROUND,
2709  RES_BACKGROUND>{} );
2710  SvxCSS1PropertyInfo aPropInfo;
2711 
2712  if( !rClass.isEmpty() )
2713  {
2714  OUString aClass( rClass );
2716  const SvxCSS1MapEntry *pClass = m_pCSS1Parser->GetClass( aClass );
2717  if( pClass )
2718  aItemSet.Put( pClass->GetItemSet() );
2719  }
2720 
2721  if( !rId.isEmpty() )
2722  {
2723  const SvxCSS1MapEntry *pId = m_pCSS1Parser->GetId( rId );
2724  if( pId )
2725  aItemSet.Put( pId->GetItemSet() );
2726  }
2727 
2728  m_pCSS1Parser->ParseStyleOption( rStyle, aItemSet, aPropInfo );
2729  const SfxPoolItem *pItem = nullptr;
2730  if( SfxItemState::SET == aItemSet.GetItemState( RES_BACKGROUND, false,
2731  &pItem ) )
2732  {
2733  pBrushItem = new SvxBrushItem( *static_cast<const SvxBrushItem *>(pItem) );
2734  }
2735  }
2736 
2737  if( !pBrushItem && (pColor || !rImageURL.isEmpty()) )
2738  {
2739  pBrushItem = new SvxBrushItem(RES_BACKGROUND);
2740 
2741  if( pColor )
2742  pBrushItem->SetColor(*pColor);
2743 
2744  if( !rImageURL.isEmpty() )
2745  {
2747  pBrushItem->SetGraphicPos( GPOS_TILED );
2748  }
2749  }
2750 
2751  return pBrushItem;
2752 }
2753 
2755 {
2760 
2761 public:
2762 
2763  std::shared_ptr<HTMLTable> m_xTable;
2764 
2765  explicit SectionSaveStruct( SwHTMLParser& rParser );
2766 
2767 #if OSL_DEBUG_LEVEL > 0
2769 #endif
2770  void Restore( SwHTMLParser& rParser );
2771 };
2772 
2774  m_nBaseFontStMinSave(rParser.m_nBaseFontStMin),
2775  m_nFontStMinSave(rParser.m_nFontStMin),
2776  m_nFontStHeadStartSave(rParser.m_nFontStHeadStart),
2777  m_nDefListDeepSave(rParser.m_nDefListDeep),
2778  m_nContextStMinSave(rParser.m_nContextStMin),
2779  m_nContextStAttrMinSave(rParser.m_nContextStAttrMin)
2780 {
2781  // Freeze font stacks
2782  rParser.m_nBaseFontStMin = rParser.m_aBaseFontStack.size();
2783 
2784  rParser.m_nFontStMin = rParser.m_aFontStack.size();
2785 
2786  // Freeze context stack
2787  rParser.m_nContextStMin = rParser.m_aContexts.size();
2788  rParser.m_nContextStAttrMin = rParser.m_nContextStMin;
2789 
2790  // And remember a few counters
2791  rParser.m_nDefListDeep = 0;
2792 }
2793 
2795 {
2796  // Unfreeze font stacks
2797  sal_uInt16 nMin = rParser.m_nBaseFontStMin;
2798  if( rParser.m_aBaseFontStack.size() > nMin )
2799  rParser.m_aBaseFontStack.erase( rParser.m_aBaseFontStack.begin() + nMin,
2800  rParser.m_aBaseFontStack.end() );
2802 
2803  nMin = rParser.m_nFontStMin;
2804  if( rParser.m_aFontStack.size() > nMin )
2805  rParser.m_aFontStack.erase( rParser.m_aFontStack.begin() + nMin,
2806  rParser.m_aFontStack.end() );
2807  rParser.m_nFontStMin = m_nFontStMinSave;
2809 
2810  OSL_ENSURE( rParser.m_aContexts.size() == rParser.m_nContextStMin &&
2811  rParser.m_aContexts.size() == rParser.m_nContextStAttrMin,
2812  "The Context Stack was not cleaned up" );
2815 
2816  // Reconstruct a few counters
2818 
2819  // Reset a few flags
2820  rParser.m_bNoParSpace = false;
2821  rParser.m_nOpenParaToken = HtmlTokenId::NONE;
2822 
2823  rParser.m_aParaAttrs.clear();
2824 }
2825 
2827 {
2829  OUString m_aBGImage;
2831  std::shared_ptr<SvxBoxItem> m_xBoxItem;
2832 
2833  std::shared_ptr<HTMLTableCnts> m_xCnts; // List of all contents
2834  HTMLTableCnts* m_pCurrCnts; // current content or 0
2835  std::unique_ptr<SwNodeIndex> m_pNoBreakEndNodeIndex; // Paragraph index of a <NOBR>
2836 
2837  double m_nValue;
2838 
2839  sal_uInt32 m_nNumFormat;
2840 
2842  sal_Int32 m_nNoBreakEndContentPos; // Character index of a <NOBR>
2843 
2844  sal_Int16 m_eVertOri;
2845 
2846  bool m_bHead : 1;
2849  bool m_bHasValue : 1;
2850  bool m_bBGColor : 1;
2851  bool m_bNoWrap : 1; // NOWRAP option
2852  bool m_bNoBreak : 1; // NOBREAK tag
2853 
2854 public:
2855 
2856  CellSaveStruct( SwHTMLParser& rParser, HTMLTable const *pCurTable, bool bHd,
2857  bool bReadOpt );
2858 
2859  void AddContents( std::unique_ptr<HTMLTableCnts> pNewCnts );
2860  bool HasFirstContents() const { return bool(m_xCnts); }
2861 
2862  void ClearIsInSection() { m_pCurrCnts = nullptr; }
2863  bool IsInSection() const { return m_pCurrCnts!=nullptr; }
2864 
2865  void InsertCell( SwHTMLParser& rParser, HTMLTable *pCurTable );
2866 
2867  bool IsHeaderCell() const { return m_bHead; }
2868 
2869  void StartNoBreak( const SwPosition& rPos );
2870  void EndNoBreak( const SwPosition& rPos );
2871  void CheckNoBreak( const SwPosition& rPos );
2872 };
2873 
2875  bool bHd, bool bReadOpt ) :
2876  SectionSaveStruct( rParser ),
2877  m_pCurrCnts( nullptr ),
2878  m_nValue( 0.0 ),
2879  m_nNumFormat( 0 ),
2880  m_nRowSpan( 1 ),
2881  m_nColSpan( 1 ),
2882  m_nWidth( 0 ),
2883  m_nHeight( 0 ),
2884  m_nNoBreakEndContentPos( 0 ),
2885  m_eVertOri( pCurTable->GetInheritedVertOri() ),
2886  m_bHead( bHd ),
2887  m_bPercentWidth( false ),
2888  m_bHasNumFormat( false ),
2889  m_bHasValue( false ),
2890  m_bBGColor( false ),
2891  m_bNoWrap( false ),
2892  m_bNoBreak( false )
2893 {
2894  OUString aNumFormat, aValue, aDir, aLang;
2895  SvxAdjust eAdjust( pCurTable->GetInheritedAdjust() );
2896 
2897  if( bReadOpt )
2898  {
2899  const HTMLOptions& rOptions = rParser.GetOptions();
2900  for (size_t i = rOptions.size(); i; )
2901  {
2902  const HTMLOption& rOption = rOptions[--i];
2903  switch( rOption.GetToken() )
2904  {
2905  case HtmlOptionId::ID:
2906  m_aId = rOption.GetString();
2907  break;
2908  case HtmlOptionId::COLSPAN:
2909  m_nColSpan = static_cast<sal_uInt16>(rOption.GetNumber());
2910  if (m_nColSpan > 256)
2911  {
2912  SAL_INFO("sw.html", "ignoring huge COLSPAN " << m_nColSpan);
2913  m_nColSpan = 1;
2914  }
2915  break;
2916  case HtmlOptionId::ROWSPAN:
2917  m_nRowSpan = static_cast<sal_uInt16>(rOption.GetNumber());
2918  if (m_nRowSpan > 8192 || (m_nRowSpan > 256 && utl::ConfigManager::IsFuzzing()))
2919  {
2920  SAL_INFO("sw.html", "ignoring huge ROWSPAN " << m_nRowSpan);
2921  m_nRowSpan = 1;
2922  }
2923  break;
2924  case HtmlOptionId::ALIGN:
2925  eAdjust = rOption.GetEnum( aHTMLPAlignTable, eAdjust );
2926  break;
2927  case HtmlOptionId::VALIGN:
2928  m_eVertOri = rOption.GetEnum( aHTMLTableVAlignTable, m_eVertOri );
2929  break;
2930  case HtmlOptionId::WIDTH:
2931  m_nWidth = static_cast<sal_uInt16>(rOption.GetNumber()); // Just for Netscape
2932  m_bPercentWidth = (rOption.GetString().indexOf('%') != -1);
2933  if( m_bPercentWidth && m_nWidth>100 )
2934  m_nWidth = 100;
2935  break;
2936  case HtmlOptionId::HEIGHT:
2937  m_nHeight = static_cast<sal_uInt16>(rOption.GetNumber()); // Just for Netscape
2938  if( rOption.GetString().indexOf('%') != -1)
2939  m_nHeight = 0; // don't consider % attributes
2940  break;
2941  case HtmlOptionId::BGCOLOR:
2942  // Ignore empty BGCOLOR on <TABLE>, <TR> and <TD>/<TH> like Netscape
2943  // *really* not on other tags
2944  if( !rOption.GetString().isEmpty() )
2945  {
2946  rOption.GetColor( m_aBGColor );
2947  m_bBGColor = true;
2948  }
2949  break;
2950  case HtmlOptionId::BACKGROUND:
2951  m_aBGImage = rOption.GetString();
2952  break;
2953  case HtmlOptionId::STYLE:
2954  m_aStyle = rOption.GetString();
2955  break;
2956  case HtmlOptionId::CLASS:
2957  m_aClass = rOption.GetString();
2958  break;
2959  case HtmlOptionId::LANG:
2960  aLang = rOption.GetString();
2961  break;
2962  case HtmlOptionId::DIR:
2963  aDir = rOption.GetString();
2964  break;
2965  case HtmlOptionId::SDNUM:
2966  aNumFormat = rOption.GetString();
2967  m_bHasNumFormat = true;
2968  break;
2969  case HtmlOptionId::SDVAL:
2970  m_bHasValue = true;
2971  aValue = rOption.GetString();
2972  break;
2973  case HtmlOptionId::NOWRAP:
2974  m_bNoWrap = true;
2975  break;
2976  default: break;
2977  }
2978  }
2979 
2980  if( !m_aId.isEmpty() )
2981  rParser.InsertBookmark( m_aId );
2982  }
2983 
2984  if( m_bHasNumFormat )
2985  {
2986  LanguageType eLang;
2988  m_nNumFormat, eLang, aValue, aNumFormat,
2989  *rParser.m_xDoc->GetNumberFormatter() );
2990  }
2991 
2992  // Create a new context but don't anchor the drawing::Alignment attribute there,
2993  // since there's no section yet
2995  sal_uInt16 nColl;
2996  if( m_bHead )
2997  {
2998  nToken = HtmlTokenId::TABLEHEADER_ON;
2999  nColl = RES_POOLCOLL_TABLE_HDLN;
3000  }
3001  else
3002  {
3003  nToken = HtmlTokenId::TABLEDATA_ON;
3004  nColl = RES_POOLCOLL_TABLE;
3005  }
3006  std::unique_ptr<HTMLAttrContext> xCntxt(new HTMLAttrContext(nToken, nColl, OUString(), true));
3007  if( SvxAdjust::End != eAdjust )
3008  rParser.InsertAttr(&rParser.m_xAttrTab->pAdjust, SvxAdjustItem(eAdjust, RES_PARATR_ADJUST),
3009  xCntxt.get());
3010 
3011  if( SwHTMLParser::HasStyleOptions( m_aStyle, m_aId, m_aClass, &aLang, &aDir ) )
3012  {
3013  SfxItemSet aItemSet( rParser.m_xDoc->GetAttrPool(),
3014  rParser.m_pCSS1Parser->GetWhichMap() );
3015  SvxCSS1PropertyInfo aPropInfo;
3016 
3017  if( rParser.ParseStyleOptions( m_aStyle, m_aId, m_aClass, aItemSet,
3018  aPropInfo, &aLang, &aDir ) )
3019  {
3020  SfxPoolItem const* pItem;
3021  if (SfxItemState::SET == aItemSet.GetItemState(RES_BOX, false, &pItem))
3022  { // fdo#41796: steal box item to set it in FixFrameFormat later!
3023  m_xBoxItem.reset(dynamic_cast<SvxBoxItem *>(pItem->Clone()));
3024  aItemSet.ClearItem(RES_BOX);
3025  }
3026  rParser.InsertAttrs(aItemSet, aPropInfo, xCntxt.get());
3027  }
3028  }
3029 
3030  rParser.SplitPREListingXMP(xCntxt.get());
3031 
3032  rParser.PushContext(xCntxt);
3033 }
3034 
3035 void CellSaveStruct::AddContents( std::unique_ptr<HTMLTableCnts> pNewCnts )
3036 {
3037  m_pCurrCnts = pNewCnts.get();
3038 
3039  if (m_xCnts)
3040  m_xCnts->Add( std::move(pNewCnts) );
3041  else
3042  m_xCnts = std::move(pNewCnts);
3043 }
3044 
3046  HTMLTable *pCurTable )
3047 {
3048 #if OSL_DEBUG_LEVEL > 0
3049  // The attributes need to have been removed when tidying up the context stack,
3050  // Otherwise something's wrong. Let's check that...
3051 
3052  // MIB 8.1.98: When attributes were opened outside of a cell,
3053  // they're still in the attribute table and will only be deleted at the end
3054  // through the CleanContext calls in BuildTable. We don't check that there
3055  // so that we get no assert [violations, by translator]
3056  // We can see this on nContextStAttrMin: the remembered value of nContextStAttrMinSave
3057  // is the value that nContextStAttrMin had at the start of the table. And the
3058  // current value of nContextStAttrMin corresponds to the number of contexts
3059  // we found at the start of the cell. If the values differ, contexts
3060  // were created and we don't check anything.
3061 
3062  if( rParser.m_nContextStAttrMin == GetContextStAttrMin() )
3063  {
3064  HTMLAttr** pTable = reinterpret_cast<HTMLAttr**>(rParser.m_xAttrTab.get());
3065 
3066  for( auto nCnt = sizeof( HTMLAttrTable ) / sizeof( HTMLAttr* );
3067  nCnt--; ++pTable )
3068  {
3069  OSL_ENSURE( !*pTable, "The attribute table isn't empty" );
3070  }
3071  }
3072 #endif
3073 
3074  // we need to add the cell on the current position
3075  std::shared_ptr<SvxBrushItem> xBrushItem(
3076  rParser.CreateBrushItem(m_bBGColor ? &m_aBGColor : nullptr, m_aBGImage,
3077  m_aStyle, m_aId, m_aClass));
3081  m_bNoWrap );
3082  Restore( rParser );
3083 }
3084 
3086 {
3087  if( !m_xCnts ||
3088  (!rPos.nContent.GetIndex() && m_pCurrCnts == m_xCnts.get() &&
3089  m_xCnts->GetStartNode() &&
3090  m_xCnts->GetStartNode()->GetIndex() + 1 ==
3091  rPos.nNode.GetIndex()) )
3092  {
3093  m_bNoBreak = true;
3094  }
3095 }
3096 
3098 {
3099  if( m_bNoBreak )
3100  {
3101  m_pNoBreakEndNodeIndex.reset( new SwNodeIndex( rPos.nNode ) );
3103  m_bNoBreak = false;
3104  }
3105 }
3106 
3108 {
3109  if (!(m_xCnts && m_pCurrCnts == m_xCnts.get()))
3110  return;
3111 
3112  if( m_bNoBreak )
3113  {
3114  // <NOBR> wasn't closed
3115  m_xCnts->SetNoBreak();
3116  }
3117  else if( m_pNoBreakEndNodeIndex &&
3118  m_pNoBreakEndNodeIndex->GetIndex() == rPos.nNode.GetIndex() )
3119  {
3120  if( m_nNoBreakEndContentPos == rPos.nContent.GetIndex() )
3121  {
3122  // <NOBR> was closed immediately before the cell end
3123  m_xCnts->SetNoBreak();
3124  }
3125  else if( m_nNoBreakEndContentPos + 1 == rPos.nContent.GetIndex() )
3126  {
3127  SwTextNode const*const pTextNd(rPos.nNode.GetNode().GetTextNode());
3128  if( pTextNd )
3129  {
3130  sal_Unicode const cLast =
3131  pTextNd->GetText()[m_nNoBreakEndContentPos];
3132  if( ' '==cLast || '\x0a'==cLast )
3133  {
3134  // There's just a blank or a newline between the <NOBR> and the cell end
3135  m_xCnts->SetNoBreak();
3136  }
3137  }
3138  }
3139  }
3140 }
3141 
3142 std::unique_ptr<HTMLTableCnts> SwHTMLParser::InsertTableContents(
3143  bool bHead )
3144 {
3145  // create a new section, the PaM is gonna be there
3146  const SwStartNode *pStNd =
3147  InsertTableSection( static_cast< sal_uInt16 >(bHead ? RES_POOLCOLL_TABLE_HDLN
3148  : RES_POOLCOLL_TABLE) );
3149 
3150  if( GetNumInfo().GetNumRule() )
3151  {
3152  // Set the first paragraph to non-enumerated
3153  sal_uInt8 nLvl = GetNumInfo().GetLevel();
3154 
3155  SetNodeNum( nLvl );
3156  }
3157 
3158  // Reset attributation start
3159  const SwNodeIndex& rSttPara = m_pPam->GetPoint()->nNode;
3160  sal_Int32 nSttCnt = m_pPam->GetPoint()->nContent.GetIndex();
3161 
3162  HTMLAttr** pHTMLAttributes = reinterpret_cast<HTMLAttr**>(m_xAttrTab.get());
3163  for (sal_uInt16 nCnt = sizeof(HTMLAttrTable) / sizeof(HTMLAttr*); nCnt--; ++pHTMLAttributes)
3164  {
3165  HTMLAttr *pAttr = *pHTMLAttributes;
3166  while( pAttr )
3167  {
3168  OSL_ENSURE( !pAttr->GetPrev(), "Attribute has previous list" );
3169  pAttr->m_nStartPara = rSttPara;
3170  pAttr->m_nEndPara = rSttPara;
3171  pAttr->m_nStartContent = nSttCnt;
3172  pAttr->m_nEndContent = nSttCnt;
3173 
3174  pAttr = pAttr->GetNext();
3175  }
3176  }
3177 
3178  return std::make_unique<HTMLTableCnts>( pStNd );
3179 }
3180 
3182 {
3183  return m_xTable ? m_xTable->IncGrfsThatResize() : 0;
3184 }
3185 
3187  SdrObject *pObj, sal_uInt8 nPercentWidth )
3188 {
3189  pCurTable->RegisterDrawObject( pObj, nPercentWidth );
3190 }
3191 
3192 void SwHTMLParser::BuildTableCell( HTMLTable *pCurTable, bool bReadOptions,
3193  bool bHead )
3194 {
3195  if( !IsParserWorking() && m_vPendingStack.empty() )
3196  return;
3197 
3199  std::unique_ptr<CellSaveStruct> xSaveStruct;
3200 
3201  HtmlTokenId nToken = HtmlTokenId::NONE;
3202  bool bPending = false;
3203  if( !m_vPendingStack.empty() )
3204  {
3205  xSaveStruct.reset(static_cast<CellSaveStruct*>(m_vPendingStack.back().pData.release()));
3206 
3207  m_vPendingStack.pop_back();
3208  nToken = !m_vPendingStack.empty() ? m_vPendingStack.back().nToken : GetSaveToken();
3209  bPending = SvParserState::Error == eState && !m_vPendingStack.empty();
3210 
3211  SaveState( nToken );
3212  }
3213  else
3214  {
3215  // <TH> resp. <TD> were already read
3216  if (m_xTable->IsOverflowing())
3217  {
3218  SaveState( HtmlTokenId::NONE );
3219  return;
3220  }
3221 
3222  if( !pCurTable->GetContext() )
3223  {
3224  bool bTopTable = m_xTable.get() == pCurTable;
3225 
3226  // the table has no content yet, this means the actual table needs
3227  // to be created first
3228 
3229  static sal_uInt16 aWhichIds[] =
3230  {
3235  RES_KEEP, RES_KEEP,
3238  0
3239  };
3240 
3241  SfxItemSet aItemSet( m_xDoc->GetAttrPool(), aWhichIds );
3242  SvxCSS1PropertyInfo aPropInfo;
3243 
3244  bool bStyleParsed = ParseStyleOptions( pCurTable->GetStyle(),
3245  pCurTable->GetId(),
3246  pCurTable->GetClass(),
3247  aItemSet, aPropInfo,
3248  nullptr, &pCurTable->GetDirection() );
3249  const SfxPoolItem *pItem = nullptr;
3250  if( bStyleParsed )
3251  {
3252  if( SfxItemState::SET == aItemSet.GetItemState(
3253  RES_BACKGROUND, false, &pItem ) )
3254  {
3255  pCurTable->SetBGBrush( *static_cast<const SvxBrushItem *>(pItem) );
3256  aItemSet.ClearItem( RES_BACKGROUND );
3257  }
3258  if( SfxItemState::SET == aItemSet.GetItemState(
3259  RES_PARATR_SPLIT, false, &pItem ) )
3260  {
3261  aItemSet.Put(
3262  SwFormatLayoutSplit( static_cast<const SvxFormatSplitItem *>(pItem)
3263  ->GetValue() ) );
3264  aItemSet.ClearItem( RES_PARATR_SPLIT );
3265  }
3266  }
3267 
3268  sal_uInt16 nLeftSpace = 0;
3269  sal_uInt16 nRightSpace = 0;
3270  short nIndent;
3271  GetMarginsFromContextWithNumberBullet( nLeftSpace, nRightSpace, nIndent );
3272 
3273  // save the current position we'll get back to some time
3274  SwPosition *pSavePos = nullptr;
3275  bool bForceFrame = false;
3276  bool bAppended = false;
3277  bool bParentLFStripped = false;
3278  if( bTopTable )
3279  {
3280  SvxAdjust eTableAdjust = m_xTable->GetTableAdjust(false);
3281 
3282  // If the table is left or right adjusted or should be in a text frame,
3283  // it'll get one
3284  bForceFrame = eTableAdjust == SvxAdjust::Left ||
3285  eTableAdjust == SvxAdjust::Right ||
3286  pCurTable->HasToFly();
3287 
3288  // The table either shouldn't get in a text frame and isn't in one
3289  // (it gets simulated through cells),
3290  // or there's already content at that position
3291  OSL_ENSURE( !bForceFrame || pCurTable->HasParentSection(),
3292  "table in frame has no parent!" );
3293 
3294  bool bAppend = false;
3295  if( bForceFrame )
3296  {
3297  // If the table gets in a border, we only need to open a new
3298  //paragraph if the paragraph has text frames that don't fly
3299  bAppend = HasCurrentParaFlys(true);
3300  }
3301  else
3302  {
3303  // Otherwise, we need to open a new paragraph if the paragraph
3304  // is empty or contains text frames or bookmarks
3305  bAppend =
3306  m_pPam->GetPoint()->nContent.GetIndex() ||
3307  HasCurrentParaFlys() ||
3309  }
3310  if( bAppend )
3311  {
3312  if( !m_pPam->GetPoint()->nContent.GetIndex() )
3313  {
3314  //Set default to CJK and CTL
3315  m_xDoc->SetTextFormatColl( *m_pPam,
3316  m_pCSS1Parser->GetTextCollFromPool(RES_POOLCOLL_STANDARD) );
3317  SvxFontHeightItem aFontHeight( 40, 100, RES_CHRATR_FONTSIZE );
3318 
3319  HTMLAttr* pTmp =
3320  new HTMLAttr( *m_pPam->GetPoint(), aFontHeight, nullptr, std::shared_ptr<HTMLAttrTable>() );
3321  m_aSetAttrTab.push_back( pTmp );
3322 
3323  SvxFontHeightItem aFontHeightCJK( 40, 100, RES_CHRATR_CJK_FONTSIZE );
3324  pTmp =
3325  new HTMLAttr( *m_pPam->GetPoint(), aFontHeightCJK, nullptr, std::shared_ptr<HTMLAttrTable>() );
3326  m_aSetAttrTab.push_back( pTmp );
3327 
3328  SvxFontHeightItem aFontHeightCTL( 40, 100, RES_CHRATR_CTL_FONTSIZE );
3329  pTmp =
3330  new HTMLAttr( *m_pPam->GetPoint(), aFontHeightCTL, nullptr, std::shared_ptr<HTMLAttrTable>() );
3331  m_aSetAttrTab.push_back( pTmp );
3332 
3333  pTmp = new HTMLAttr( *m_pPam->GetPoint(),
3334  SvxULSpaceItem( 0, 0, RES_UL_SPACE ), nullptr, std::shared_ptr<HTMLAttrTable>() );
3335  m_aSetAttrTab.push_front( pTmp ); // Position 0, since
3336  // something can be set by
3337  // the table end before
3338  }
3340  bAppended = true;
3341  }
3342  else if( !m_aParaAttrs.empty() )
3343  {
3344  if( !bForceFrame )
3345  {
3346  // The paragraph will be moved right behind the table.
3347  // That's why we remove all hard attributes of that paragraph
3348 
3349  for(HTMLAttr* i : m_aParaAttrs)
3350  i->Invalidate();
3351  }
3352 
3353  m_aParaAttrs.clear();
3354  }
3355 
3356  pSavePos = new SwPosition( *m_pPam->GetPoint() );
3357  }
3358  else if( pCurTable->HasParentSection() )
3359  {
3360  bParentLFStripped = StripTrailingLF() > 0;
3361 
3362  // Close paragraph resp. headers
3363  m_nOpenParaToken = HtmlTokenId::NONE;
3365 
3366  // The hard attributes on that paragraph are never gonna be invalid anymore
3367  m_aParaAttrs.clear();
3368  }
3369 
3370  // create a table context
3371  std::unique_ptr<HTMLTableContext> pTCntxt(
3372  new HTMLTableContext( pSavePos, m_nContextStMin,
3373  m_nContextStAttrMin ) );
3374 
3375  // end all open attributes and open them again behind the table
3376  std::unique_ptr<std::deque<std::unique_ptr<HTMLAttr>>> pPostIts;
3377  if( !bForceFrame && (bTopTable || pCurTable->HasParentSection()) )
3378  {
3379  SplitAttrTab(pTCntxt->xAttrTab, bTopTable);
3380  // If we reuse an already existing paragraph, we can't add
3381  // PostIts since the paragraph gets behind that table.
3382  // They're gonna be moved into the first paragraph of the table
3383  // If we have tables in tables, we also can't add PostIts to a
3384  // still empty paragraph, since it's not gonna be deleted that way
3385  if( (bTopTable && !bAppended) ||
3386  (!bTopTable && !bParentLFStripped &&
3387  !m_pPam->GetPoint()->nContent.GetIndex()) )
3388  pPostIts.reset(new std::deque<std::unique_ptr<HTMLAttr>>);
3389  SetAttr( bTopTable, bTopTable, pPostIts.get() );
3390  }
3391  else
3392  {
3393  SaveAttrTab(pTCntxt->xAttrTab);
3394  if( bTopTable && !bAppended )
3395  {
3396  pPostIts.reset(new std::deque<std::unique_ptr<HTMLAttr>>);
3397  SetAttr( true, true, pPostIts.get() );
3398  }
3399  }
3400  m_bNoParSpace = false;
3401 
3402  // Save current numbering and turn it off
3403  pTCntxt->SetNumInfo( GetNumInfo() );
3404  GetNumInfo().Clear();
3405  pTCntxt->SavePREListingXMP( *this );
3406 
3407  if( bTopTable )
3408  {
3409  if( bForceFrame )
3410  {
3411  // the table should be put in a text frame
3412 
3413  SfxItemSet aFrameSet( m_xDoc->GetAttrPool(),
3415  if( !pCurTable->IsNewDoc() )
3416  Reader::ResetFrameFormatAttrs( aFrameSet );
3417 
3418  css::text::WrapTextMode eSurround = css::text::WrapTextMode_NONE;
3419  sal_Int16 eHori;
3420 
3421  switch( pCurTable->GetTableAdjust(true) )
3422  {
3423  case SvxAdjust::Right:
3424  eHori = text::HoriOrientation::RIGHT;
3425  eSurround = css::text::WrapTextMode_LEFT;
3426  break;
3427  case SvxAdjust::Center:
3428  eHori = text::HoriOrientation::CENTER;
3429  break;
3430  case SvxAdjust::Left:
3431  eSurround = css::text::WrapTextMode_RIGHT;
3432  [[fallthrough]];
3433  default:
3434  eHori = text::HoriOrientation::LEFT;
3435  break;
3436  }
3438  true );
3439  aFrameSet.Put( SwFormatSurround(eSurround) );
3440 
3442  aFrameSize.SetWidthPercent( 100 );
3443  aFrameSet.Put( aFrameSize );
3444 
3445  sal_uInt16 nSpace = pCurTable->GetHSpace();
3446  if( nSpace )
3447  aFrameSet.Put( SvxLRSpaceItem(nSpace,nSpace, 0, 0, RES_LR_SPACE) );
3448  nSpace = pCurTable->GetVSpace();
3449  if( nSpace )
3450  aFrameSet.Put( SvxULSpaceItem(nSpace,nSpace, RES_UL_SPACE) );
3451 
3452  RndStdIds eAnchorId = aFrameSet.
3453  Get( RES_ANCHOR ).
3454  GetAnchorId();
3455  SwFrameFormat *pFrameFormat = m_xDoc->MakeFlySection(
3456  eAnchorId, m_pPam->GetPoint(), &aFrameSet );
3457 
3458  pTCntxt->SetFrameFormat( pFrameFormat );
3459  const SwFormatContent& rFlyContent = pFrameFormat->GetContent();
3460  m_pPam->GetPoint()->nNode = *rFlyContent.GetContentIdx();
3461  SwContentNode *pCNd =
3462  m_xDoc->GetNodes().GoNext( &(m_pPam->GetPoint()->nNode) );
3463  m_pPam->GetPoint()->nContent.Assign( pCNd, 0 );
3464 
3465  }
3466 
3467  // create a SwTable with a box and set the PaM to the content of
3468  // the box section (the adjustment parameter is a dummy for now
3469  // and will be corrected later)
3470  OSL_ENSURE( !m_pPam->GetPoint()->nContent.GetIndex(),
3471  "The paragraph after the table is not empty!" );
3472  const SwTable* pSwTable = m_xDoc->InsertTable(
3474  *m_pPam->GetPoint(), 1, 1, text::HoriOrientation::LEFT );
3475  SwFrameFormat *pFrameFormat = pSwTable ? pSwTable->GetFrameFormat() : nullptr;
3476 
3477  if( bForceFrame )
3478  {
3479  SwNodeIndex aDstIdx( m_pPam->GetPoint()->nNode );
3481  m_xDoc->GetNodes().Delete( aDstIdx );
3482  }
3483  else
3484  {
3485  if (bStyleParsed && pFrameFormat)
3486  {
3487  m_pCSS1Parser->SetFormatBreak( aItemSet, aPropInfo );
3488  pFrameFormat->SetFormatAttr( aItemSet );
3489  }
3491  }
3492 
3493  SwNode const*const pNd = & m_pPam->GetPoint()->nNode.GetNode();
3494  SwTextNode *const pOldTextNd = (!bAppended && !bForceFrame) ?
3495  pSavePos->nNode.GetNode().GetTextNode() : nullptr;
3496 
3497  if (pFrameFormat && pOldTextNd)
3498  {
3499  const SfxPoolItem* pItem2;
3500  if( SfxItemState::SET == pOldTextNd->GetSwAttrSet()
3501  .GetItemState( RES_PAGEDESC, false, &pItem2 ) &&
3502  static_cast<const SwFormatPageDesc *>(pItem2)->GetPageDesc() )
3503  {
3504  pFrameFormat->SetFormatAttr( *pItem2 );
3505  pOldTextNd->ResetAttr( RES_PAGEDESC );
3506  }
3507  if( SfxItemState::SET == pOldTextNd->GetSwAttrSet()
3508  .GetItemState( RES_BREAK, true, &pItem2 ) )
3509  {
3510  switch( static_cast<const SvxFormatBreakItem *>(pItem2)->GetBreak() )
3511  {
3512  case SvxBreak::PageBefore:
3513  case SvxBreak::PageAfter:
3514  case SvxBreak::PageBoth:
3515  pFrameFormat->SetFormatAttr( *pItem2 );
3516  pOldTextNd->ResetAttr( RES_BREAK );
3517  break;
3518  default:
3519  break;
3520  }
3521  }
3522  }
3523 
3524  if( !bAppended && pPostIts )
3525  {
3526  // set still-existing PostIts to the first paragraph of the table
3527  InsertAttrs( std::move(*pPostIts) );
3528  pPostIts.reset();
3529  }
3530 
3531  pTCntxt->SetTableNode( const_cast<SwTableNode *>(pNd->FindTableNode()) );
3532 
3533  auto pTableNode = pTCntxt->GetTableNode();
3534  pCurTable->SetTable( pTableNode, std::move(pTCntxt),
3535  nLeftSpace, nRightSpace,
3536  pSwTable, bForceFrame );
3537 
3538  OSL_ENSURE( !pPostIts, "unused PostIts" );
3539  }
3540  else
3541  {
3542  // still open sections need to be deleted
3543  if( EndSections( bParentLFStripped ) )
3544  bParentLFStripped = false;
3545 
3546  if( pCurTable->HasParentSection() )
3547  {
3548  // after that, we remove a possibly redundant empty paragraph,
3549  // but only if it was empty before we stripped the LFs
3550  if( !bParentLFStripped )
3552 
3553  if( pPostIts )
3554  {
3555  // move still existing PostIts to the end of the current paragraph
3556  InsertAttrs( std::move(*pPostIts) );
3557  pPostIts.reset();
3558  }
3559  }
3560 
3561  SwNode const*const pNd = & m_pPam->GetPoint()->nNode.GetNode();
3562  const SwStartNode *pStNd = (m_xTable->m_bFirstCell ? pNd->FindTableNode()
3563  : pNd->FindTableBoxStartNode() );
3564 
3565  pCurTable->SetTable( pStNd, std::move(pTCntxt), nLeftSpace, nRightSpace );
3566  }
3567 
3568  // Freeze the context stack, since there could be attributes set
3569  // outside of cells. Can't happen earlier, since there may be
3570  // searches in the stack
3571  m_nContextStMin = m_aContexts.size();
3573  }
3574 
3575  xSaveStruct.reset(new CellSaveStruct(*this, pCurTable, bHead, bReadOptions));
3576 
3577  // If the first GetNextToken() doesn't succeed (pending input), must re-read from the beginning.
3578  SaveState( HtmlTokenId::NONE );
3579  }
3580 
3581  if( nToken == HtmlTokenId::NONE )
3582  nToken = GetNextToken(); // Token after <TABLE>
3583 
3584  bool bDone = false;
3585  while( (IsParserWorking() && !bDone) || bPending )
3586  {
3587  SaveState( nToken );
3588 
3589  nToken = FilterToken( nToken );
3590 
3591  OSL_ENSURE( !m_vPendingStack.empty() || !m_bCallNextToken || xSaveStruct->IsInSection(),
3592  "Where is the section??" );
3593  if( m_vPendingStack.empty() && m_bCallNextToken && xSaveStruct->IsInSection() )
3594  {
3595  // Call NextToken directly (e.g. ignore the content of floating frames or applets)
3596  NextToken( nToken );
3597  }
3598  else switch( nToken )
3599  {
3600  case HtmlTokenId::TABLEHEADER_ON:
3601  case HtmlTokenId::TABLEDATA_ON:
3602  case HtmlTokenId::TABLEROW_ON:
3603  case HtmlTokenId::TABLEROW_OFF:
3604  case HtmlTokenId::THEAD_ON:
3605  case HtmlTokenId::THEAD_OFF:
3606  case HtmlTokenId::TFOOT_ON:
3607  case HtmlTokenId::TFOOT_OFF:
3608  case HtmlTokenId::TBODY_ON:
3609  case HtmlTokenId::TBODY_OFF:
3610  case HtmlTokenId::TABLE_OFF:
3611  SkipToken();
3612  [[fallthrough]];
3613  case HtmlTokenId::TABLEHEADER_OFF:
3614  case HtmlTokenId::TABLEDATA_OFF:
3615  bDone = true;
3616  break;
3617  case HtmlTokenId::TABLE_ON:
3618  {
3619  bool bHasToFly = false;
3620  SvxAdjust eTabAdjust = SvxAdjust::End;
3621  if( m_vPendingStack.empty() )
3622  {
3623  // only if we create a new table, but not if we're still
3624  // reading in the table after a Pending
3625  xSaveStruct->m_xTable = m_xTable;
3626 
3627  // HACK: create a section for a table that goes in a text frame
3628  if( !xSaveStruct->IsInSection() )
3629  {
3630  // The loop needs to be forward, since the
3631  // first option always wins
3632  bool bNeedsSection = false;
3633  const HTMLOptions& rHTMLOptions = GetOptions();
3634  for (const auto & rOption : rHTMLOptions)
3635  {
3636  if( HtmlOptionId::ALIGN==rOption.GetToken() )
3637  {
3638  SvxAdjust eAdjust = rOption.GetEnum( aHTMLPAlignTable, SvxAdjust::End );
3639  bNeedsSection = SvxAdjust::Left == eAdjust ||
3640  SvxAdjust::Right == eAdjust;
3641  break;
3642  }
3643  }
3644  if( bNeedsSection )
3645  {
3646  xSaveStruct->AddContents(
3647  InsertTableContents(bHead ) );
3648  }
3649  }
3650  else
3651  {
3652  // If Flys are anchored in the current paragraph,
3653  // the table needs to get in a text frame
3654  bHasToFly = HasCurrentParaFlys(false,true);
3655  }
3656 
3657  // There could be a section in the cell
3658  eTabAdjust = m_xAttrTab->pAdjust
3659  ? static_cast<const SvxAdjustItem&>(m_xAttrTab->pAdjust->GetItem()).
3660  GetAdjust()
3661  : SvxAdjust::End;
3662  }
3663 
3664  std::shared_ptr<HTMLTable> xSubTable = BuildTable(eTabAdjust,
3665  bHead,
3666  xSaveStruct->IsInSection(),
3667  bHasToFly);
3668  if( SvParserState::Pending != GetStatus() )
3669  {
3670  // Only if the table is really complete
3671  if (xSubTable)
3672  {
3673  OSL_ENSURE( xSubTable->GetTableAdjust(false)!= SvxAdjust::Left &&
3674  xSubTable->GetTableAdjust(false)!= SvxAdjust::Right,
3675  "left or right aligned tables belong in frames" );
3676 
3677  auto& rParentContents = xSubTable->GetParentContents();
3678  if (rParentContents)
3679  {
3680  OSL_ENSURE( !xSaveStruct->IsInSection(),
3681  "Where is the section" );
3682 
3683  // If there's no table coming, we have a section
3684  xSaveStruct->AddContents(std::move(rParentContents));
3685  }
3686 
3687  const SwStartNode *pCapStNd =
3688  xSubTable->GetCaptionStartNode();
3689 
3690  if (xSubTable->GetContext())
3691  {
3692  OSL_ENSURE( !xSubTable->GetContext()->GetFrameFormat(),
3693  "table in frame" );
3694 
3695  if( pCapStNd && xSubTable->IsTopCaption() )
3696  {
3697  xSaveStruct->AddContents(
3698  std::make_unique<HTMLTableCnts>(pCapStNd) );
3699  }
3700 
3701  xSaveStruct->AddContents(
3702  std::make_unique<HTMLTableCnts>(xSubTable) );
3703 
3704  if( pCapStNd && !xSubTable->IsTopCaption() )
3705  {
3706  xSaveStruct->AddContents(
3707  std::make_unique<HTMLTableCnts>(pCapStNd) );
3708  }
3709 
3710  // We don't have a section anymore
3711  xSaveStruct->ClearIsInSection();
3712  }
3713  else if( pCapStNd )
3714  {
3715  // Since we can't delete this section (it might
3716  // belong to the first box), we'll add it
3717  xSaveStruct->AddContents(
3718  std::make_unique<HTMLTableCnts>(pCapStNd) );
3719 
3720  // We don't have a section anymore
3721  xSaveStruct->ClearIsInSection();
3722  }
3723  }
3724 
3725  m_xTable = xSaveStruct->m_xTable;
3726  }
3727  }
3728  break;
3729 
3730  case HtmlTokenId::NOBR_ON:
3731  // HACK for MS: Is the <NOBR> at the start of the cell?
3732  xSaveStruct->StartNoBreak( *m_pPam->GetPoint() );
3733  break;
3734 
3735  case HtmlTokenId::NOBR_OFF:
3736  xSaveStruct->EndNoBreak( *m_pPam->GetPoint() );
3737  break;
3738 
3739  case HtmlTokenId::COMMENT:
3740  // Spaces are not gonna be deleted with comment fields,
3741  // and we don't want a new cell for a comment
3742  NextToken( nToken );
3743  break;
3744 
3745  case HtmlTokenId::MARQUEE_ON:
3746  if( !xSaveStruct->IsInSection() )
3747  {
3748  // create a new section, the PaM is gonna be there
3749  xSaveStruct->AddContents(
3750  InsertTableContents( bHead ) );
3751  }
3752  m_bCallNextToken = true;
3753  NewMarquee( pCurTable );
3754  break;
3755 
3756  case HtmlTokenId::TEXTTOKEN:
3757  // Don't add a section for an empty string
3758  if( !xSaveStruct->IsInSection() && 1==aToken.getLength() &&
3759  ' '==aToken[0] )
3760  break;
3761  [[fallthrough]];
3762  default:
3763  if( !xSaveStruct->IsInSection() )
3764  {
3765  // add a new section, the PaM's gonna be there
3766  xSaveStruct->AddContents(
3767  InsertTableContents( bHead ) );
3768  }
3769 
3770  if( IsParserWorking() || bPending )
3771  NextToken( nToken );
3772  break;
3773  }
3774 
3775  OSL_ENSURE( !bPending || m_vPendingStack.empty(),
3776  "SwHTMLParser::BuildTableCell: There is a PendStack again" );
3777  bPending = false;
3778  if( IsParserWorking() )
3779  SaveState( HtmlTokenId::NONE );
3780 
3781  if( !bDone )
3782  nToken = GetNextToken();
3783  }
3784 
3785  if( SvParserState::Pending == GetStatus() )
3786  {
3787  m_vPendingStack.emplace_back( bHead ? HtmlTokenId::TABLEHEADER_ON
3788  : HtmlTokenId::TABLEDATA_ON );
3789  m_vPendingStack.back().pData = std::move(xSaveStruct);
3790 
3791  return;
3792  }
3793 
3794  // If the content of the cell was empty, we need to create an empty content
3795  // We also create an empty content if the cell ended with a table and had no
3796  // COL tags. Otherwise, it was probably exported by us and we don't
3797  // want to have an additional paragraph
3798  if( !xSaveStruct->HasFirstContents() ||
3799  (!xSaveStruct->IsInSection() && !pCurTable->HasColTags()) )
3800  {
3801  OSL_ENSURE( xSaveStruct->HasFirstContents() ||
3802  !xSaveStruct->IsInSection(),
3803  "Section or not, that is the question here" );
3804  const SwStartNode *pStNd =
3805  InsertTableSection( static_cast< sal_uInt16 >(xSaveStruct->IsHeaderCell()
3807  : RES_POOLCOLL_TABLE ));
3808 
3809  if (!pStNd)
3810  eState = SvParserState::Error;
3811  else
3812  {
3813  const SwEndNode *pEndNd = pStNd->EndOfSectionNode();
3814  SwContentNode *pCNd = m_xDoc->GetNodes()[pEndNd->GetIndex()-1] ->GetContentNode();
3815  if (!pCNd)
3816  eState = SvParserState::Error;
3817  else
3818  {
3819  //Added defaults to CJK and CTL
3820  SvxFontHeightItem aFontHeight( 40, 100, RES_CHRATR_FONTSIZE );
3821  pCNd->SetAttr( aFontHeight );
3822  SvxFontHeightItem aFontHeightCJK( 40, 100, RES_CHRATR_CJK_FONTSIZE );
3823  pCNd->SetAttr( aFontHeightCJK );
3824  SvxFontHeightItem aFontHeightCTL( 40, 100, RES_CHRATR_CTL_FONTSIZE );
3825  pCNd->SetAttr( aFontHeightCTL );
3826  }
3827  }
3828 
3829  xSaveStruct->AddContents( std::make_unique<HTMLTableCnts>(pStNd) );
3830  xSaveStruct->ClearIsInSection();
3831  }
3832 
3833  if( xSaveStruct->IsInSection() )
3834  {
3835  xSaveStruct->CheckNoBreak( *m_pPam->GetPoint() );
3836 
3837  // End all open contexts. We'll take AttrMin because nContextStMin might
3838  // have been modified. Since it's gonna be restored by EndContext, it's okay
3839  while( m_aContexts.size() > m_nContextStAttrMin+1 )
3840  {
3841  std::unique_ptr<HTMLAttrContext> xCntxt(PopContext());
3842  EndContext(xCntxt.get());
3843  }
3844 
3845  // Remove LFs at the paragraph end
3846  if (StripTrailingLF() == 0 && !m_pPam->GetPoint()->nContent.GetIndex())
3847  {
3848  HTMLTableContext* pTableContext = m_xTable ? m_xTable->GetContext() : nullptr;
3849  SwPosition* pSavedPos = pTableContext ? pTableContext->GetPos() : nullptr;
3850  const bool bDeleteSafe = !pSavedPos || pSavedPos->nNode != m_pPam->GetPoint()->nNode;
3851  if (bDeleteSafe)
3853  }
3854 
3855  // If there was an adjustment set for the cell, we need to close it
3856  std::unique_ptr<HTMLAttrContext> xCntxt(PopContext());
3857  if (xCntxt)
3858  EndContext(xCntxt.get());
3859  }
3860  else
3861  {
3862  // Close all still open contexts
3863  while( m_aContexts.size() > m_nContextStAttrMin )
3864  {
3865  std::unique_ptr<HTMLAttrContext> xCntxt(PopContext());
3866  if (!xCntxt)
3867  break;
3868  ClearContext(xCntxt.get());
3869  }
3870  }
3871 
3872  // end an enumeration
3873  GetNumInfo().Clear();
3874 
3875  SetAttr( false );
3876 
3877  xSaveStruct->InsertCell( *this, pCurTable );
3878 
3879  // we're probably before a <TH>, <TD>, <TR> or </TABLE>
3880  xSaveStruct.reset();
3881 }
3882 
3883 namespace {
3884 
3885 class RowSaveStruct : public SwPendingData
3886 {
3887 public:
3888  SvxAdjust eAdjust;
3889  sal_Int16 eVertOri;
3890  bool bHasCells;
3891 
3892  RowSaveStruct() :
3893  eAdjust( SvxAdjust::End ), eVertOri( text::VertOrientation::TOP ), bHasCells( false )
3894  {}
3895 };
3896 
3897 }
3898 
3899 void SwHTMLParser::BuildTableRow( HTMLTable *pCurTable, bool bReadOptions,
3900  SvxAdjust eGrpAdjust,
3901  sal_Int16 eGrpVertOri )
3902 {
3903  // <TR> was already read
3904 
3905  if( !IsParserWorking() && m_vPendingStack.empty() )
3906  return;
3907 
3908  HtmlTokenId nToken = HtmlTokenId::NONE;
3909  std::unique_ptr<RowSaveStruct> xSaveStruct;
3910 
3911  bool bPending = false;
3912  if( !m_vPendingStack.empty() )
3913  {
3914  xSaveStruct.reset(static_cast<RowSaveStruct*>(m_vPendingStack.back().pData.release()));
3915 
3916  m_vPendingStack.pop_back();
3917  nToken = !m_vPendingStack.empty() ? m_vPendingStack.back().nToken : GetSaveToken();
3918  bPending = SvParserState::Error == eState && !m_vPendingStack.empty();
3919 
3920  SaveState( nToken );
3921  }
3922  else
3923  {
3924  SvxAdjust eAdjust = eGrpAdjust;
3925  sal_Int16 eVertOri = eGrpVertOri;
3926  Color aBGColor;
3927  OUString aBGImage, aStyle, aId, aClass;
3928  bool bBGColor = false;
3929  xSaveStruct.reset(new RowSaveStruct);
3930 
3931  if( bReadOptions )
3932  {
3933  const HTMLOptions& rHTMLOptions = GetOptions();
3934  for (size_t i = rHTMLOptions.size(); i; )
3935  {
3936  const HTMLOption& rOption = rHTMLOptions[--i];
3937  switch( rOption.GetToken() )
3938  {
3939  case HtmlOptionId::ID:
3940  aId = rOption.GetString();
3941  break;
3942  case HtmlOptionId::ALIGN:
3943  eAdjust = rOption.GetEnum( aHTMLPAlignTable, eAdjust );
3944  break;
3945  case HtmlOptionId::VALIGN:
3946  eVertOri = rOption.GetEnum( aHTMLTableVAlignTable, eVertOri );
3947  break;
3948  case HtmlOptionId::BGCOLOR:
3949  // Ignore empty BGCOLOR on <TABLE>, <TR> and <TD>/>TH> like Netscape
3950  // *really* not on other tags
3951  if( !rOption.GetString().isEmpty() )
3952  {
3953  rOption.GetColor( aBGColor );
3954  bBGColor = true;
3955  }
3956  break;
3957  case HtmlOptionId::BACKGROUND:
3958  aBGImage = rOption.GetString();
3959  break;
3960  case HtmlOptionId::STYLE:
3961  aStyle = rOption.GetString();
3962  break;
3963  case HtmlOptionId::CLASS:
3964  aClass= rOption.GetString();
3965  break;
3966  default: break;
3967  }
3968  }
3969  }
3970 
3971  if( !aId.isEmpty() )
3972  InsertBookmark( aId );
3973 
3974  std::unique_ptr<SvxBrushItem> xBrushItem(
3975  CreateBrushItem( bBGColor ? &aBGColor : nullptr, aBGImage, aStyle,
3976  aId, aClass ));
3977  pCurTable->OpenRow(eAdjust, eVertOri, xBrushItem);
3978  // If the first GetNextToken() doesn't succeed (pending input), must re-read from the beginning.
3979  SaveState( HtmlTokenId::NONE );
3980  }
3981 
3982  if( nToken == HtmlTokenId::NONE )
3983  nToken = GetNextToken();
3984 
3985  bool bDone = false;
3986  while( (IsParserWorking() && !bDone) || bPending )
3987  {
3988  SaveState( nToken );
3989 
3990  nToken = FilterToken( nToken );
3991 
3992  OSL_ENSURE( !m_vPendingStack.empty() || !m_bCallNextToken ||
3993  pCurTable->GetContext() || pCurTable->HasParentSection(),
3994  "Where is the section??" );
3995  if( m_vPendingStack.empty() && m_bCallNextToken &&
3996  (pCurTable->GetContext() || pCurTable->HasParentSection()) )
3997  {
3999  NextToken( nToken );
4000  }
4001  else switch( nToken )
4002  {
4003  case HtmlTokenId::TABLE_ON:
4004  if( !pCurTable->GetContext() )
4005  {
4006  SkipToken();
4007  bDone = true;
4008  }
4009 
4010  break;
4011  case HtmlTokenId::TABLEROW_ON:
4012  case HtmlTokenId::THEAD_ON:
4013  case HtmlTokenId::THEAD_OFF:
4014  case HtmlTokenId::TBODY_ON:
4015  case HtmlTokenId::TBODY_OFF:
4016  case HtmlTokenId::TFOOT_ON:
4017  case HtmlTokenId::TFOOT_OFF:
4018  case HtmlTokenId::TABLE_OFF:
4019  SkipToken();
4020  [[fallthrough]];
4021  case HtmlTokenId::TABLEROW_OFF:
4022  bDone = true;
4023  break;
4024  case HtmlTokenId::TABLEHEADER_ON:
4025  case HtmlTokenId::TABLEDATA_ON:
4026  BuildTableCell( pCurTable, true, HtmlTokenId::TABLEHEADER_ON==nToken );
4027  if( SvParserState::Pending != GetStatus() )
4028  {
4029  xSaveStruct->bHasCells = true;
4030  bDone = m_xTable->IsOverflowing();
4031  }
4032  break;
4033  case HtmlTokenId::CAPTION_ON:
4034  BuildTableCaption( pCurTable );
4035  bDone = m_xTable->IsOverflowing();
4036  break;
4037  case HtmlTokenId::CAPTION_OFF:
4038  case HtmlTokenId::TABLEHEADER_OFF:
4039  case HtmlTokenId::TABLEDATA_OFF:
4040  case HtmlTokenId::COLGROUP_ON:
4041  case HtmlTokenId::COLGROUP_OFF:
4042  case HtmlTokenId::COL_ON:
4043  case HtmlTokenId::COL_OFF:
4044  // Where no cell started, there can't be a cell ending
4045  // all the other tokens are bogus anyway and only break the table
4046  break;
4047  case HtmlTokenId::MULTICOL_ON:
4048  // we can't add columned text frames here
4049  break;
4050  case HtmlTokenId::FORM_ON:
4051  NewForm( false ); // don't create a new paragraph
4052  break;
4053  case HtmlTokenId::FORM_OFF:
4054  EndForm( false ); // don't create a new paragraph
4055  break;
4056  case HtmlTokenId::COMMENT:
4057  NextToken( nToken );
4058  break;
4059  case HtmlTokenId::MAP_ON:
4060  // an image map doesn't add anything, so we can parse it without a cell
4061  NextToken( nToken );
4062  break;
4063  case HtmlTokenId::TEXTTOKEN:
4064  if( (pCurTable->GetContext() ||
4065  !pCurTable->HasParentSection()) &&
4066  1==aToken.getLength() && ' '==aToken[0] )
4067  break;
4068  [[fallthrough]];
4069  default:
4070  pCurTable->MakeParentContents();
4071  NextToken( nToken );
4072  break;
4073  }
4074 
4075  OSL_ENSURE( !bPending || m_vPendingStack.empty(),
4076  "SwHTMLParser::BuildTableRow: There is a PendStack again" );
4077  bPending = false;
4078  if( IsParserWorking() )
4079  SaveState( HtmlTokenId::NONE );
4080 
4081  if( !bDone )
4082  nToken = GetNextToken();
4083  }
4084 
4085  if( SvParserState::Pending == GetStatus() )
4086  {
4087  m_vPendingStack.emplace_back( HtmlTokenId::TABLEROW_ON );
4088  m_vPendingStack.back().pData = std::move(xSaveStruct);
4089  }
4090  else
4091  {
4092  pCurTable->CloseRow(!xSaveStruct->bHasCells);
4093  xSaveStruct.reset();
4094  }
4095 
4096  // we're probably before <TR> or </TABLE>
4097 }
4098 
4100  bool bReadOptions,
4101  bool bHead )
4102 {
4103  // <THEAD>, <TBODY> resp. <TFOOT> were read already
4104  if( !IsParserWorking() && m_vPendingStack.empty() )
4105  return;
4106 
4107  HtmlTokenId nToken = HtmlTokenId::NONE;
4108  bool bPending = false;
4109  std::unique_ptr<RowSaveStruct> xSaveStruct;
4110 
4111  if( !m_vPendingStack.empty() )
4112  {
4113  xSaveStruct.reset(static_cast<RowSaveStruct*>(m_vPendingStack.back().pData.release()));
4114 
4115  m_vPendingStack.pop_back();
4116  nToken = !m_vPendingStack.empty() ? m_vPendingStack.back().nToken : GetSaveToken();
4117  bPending = SvParserState::Error == eState && !m_vPendingStack.empty();
4118 
4119  SaveState( nToken );
4120  }
4121  else
4122  {
4123  xSaveStruct.reset(new RowSaveStruct);
4124 
4125  if( bReadOptions )
4126  {
4127  const HTMLOptions& rHTMLOptions = GetOptions();
4128  for (size_t i = rHTMLOptions.size(); i; )
4129  {
4130  const HTMLOption& rOption = rHTMLOptions[--i];
4131  switch( rOption.GetToken() )
4132  {
4133  case HtmlOptionId::ID:
4134  InsertBookmark( rOption.GetString() );
4135  break;
4136  case HtmlOptionId::ALIGN:
4137  xSaveStruct->eAdjust =
4138  rOption.GetEnum( aHTMLPAlignTable, xSaveStruct->eAdjust );
4139  break;
4140  case HtmlOptionId::VALIGN:
4141  xSaveStruct->eVertOri =
4142  rOption.GetEnum( aHTMLTableVAlignTable,
4143  xSaveStruct->eVertOri );
4144  break;
4145  default: break;
4146  }
4147  }
4148  }
4149 
4150  // If the first GetNextToken() doesn't succeed (pending input), must re-read from the beginning.
4151  SaveState( HtmlTokenId::NONE );
4152  }
4153 
4154  if( nToken == HtmlTokenId::NONE )
4155  nToken = GetNextToken();
4156 
4157  bool bDone = false;
4158  while( (IsParserWorking() && !bDone) || bPending )
4159  {
4160  SaveState( nToken );
4161 
4162  nToken = FilterToken( nToken );
4163 
4164  OSL_ENSURE( !m_vPendingStack.empty() || !m_bCallNextToken ||
4165  pCurTable->GetContext() || pCurTable->HasParentSection(),
4166  "Where is the section?" );
4167  if( m_vPendingStack.empty() && m_bCallNextToken &&
4168  (pCurTable->GetContext() || pCurTable->HasParentSection()) )
4169  {
4170  // Call NextToken directly (e.g. ignore the content of floating frames or applets)
4171  NextToken( nToken );
4172  }
4173  else switch( nToken )
4174  {
4175  case HtmlTokenId::TABLE_ON:
4176  if( !pCurTable->GetContext() )
4177  {
4178  SkipToken();
4179  bDone = true;
4180  }
4181 
4182  break;
4183  case HtmlTokenId::THEAD_ON:
4184  case HtmlTokenId::TFOOT_ON:
4185  case HtmlTokenId::TBODY_ON:
4186  case HtmlTokenId::TABLE_OFF:
4187  SkipToken();
4188  [[fallthrough]];
4189  case HtmlTokenId::THEAD_OFF:
4190  case HtmlTokenId::TBODY_OFF:
4191  case HtmlTokenId::TFOOT_OFF:
4192  bDone = true;
4193  break;
4194  case HtmlTokenId::CAPTION_ON:
4195  BuildTableCaption( pCurTable );
4196  bDone = m_xTable->IsOverflowing();
4197  break;
4198  case HtmlTokenId::CAPTION_OFF:
4199  break;
4200  case HtmlTokenId::TABLEHEADER_ON:
4201  case HtmlTokenId::TABLEDATA_ON:
4202  SkipToken();
4203  BuildTableRow( pCurTable, false, xSaveStruct->eAdjust,
4204  xSaveStruct->eVertOri );
4205  bDone = m_xTable->IsOverflowing();
4206  break;
4207  case HtmlTokenId::TABLEROW_ON:
4208  BuildTableRow( pCurTable, true, xSaveStruct->eAdjust,
4209  xSaveStruct->eVertOri );
4210  bDone = m_xTable->IsOverflowing();
4211  break;
4212  case HtmlTokenId::MULTICOL_ON:
4213  // we can't add columned text frames here
4214  break;
4215  case HtmlTokenId::FORM_ON:
4216  NewForm( false ); // don't create a new paragraph
4217  break;
4218  case HtmlTokenId::FORM_OFF:
4219  EndForm( false ); // don't create a new paragraph
4220  break;
4221  case HtmlTokenId::TEXTTOKEN:
4222  // blank strings may be a series of CR+LF and no text
4223  if( (pCurTable->GetContext() ||
4224  !pCurTable->HasParentSection()) &&
4225  1==aToken.getLength() && ' ' == aToken[0] )
4226  break;
4227  [[fallthrough]];
4228  default:
4229  pCurTable->MakeParentContents();
4230  NextToken( nToken );
4231  }
4232 
4233  OSL_ENSURE( !bPending || m_vPendingStack.empty(),
4234  "SwHTMLParser::BuildTableSection: There is a PendStack again" );
4235  bPending = false;
4236  if( IsParserWorking() )
4237  SaveState( HtmlTokenId::NONE );
4238 
4239  if( !bDone )
4240  nToken = GetNextToken();
4241  }
4242 
4243  if( SvParserState::Pending == GetStatus() )
4244  {
4245  m_vPendingStack.emplace_back( bHead ? HtmlTokenId::THEAD_ON
4246  : HtmlTokenId::TBODY_ON );
4247  m_vPendingStack.back().pData = std::move(xSaveStruct);
4248  }
4249  else
4250  {
4251  pCurTable->CloseSection( bHead );
4252  xSaveStruct.reset();
4253  }
4254 
4255  // now we stand (perhaps) in front of <TBODY>,... or </TABLE>
4256 }
4257 
4258 namespace {
4259 
4260 struct TableColGrpSaveStruct : public SwPendingData
4261 {
4262  sal_uInt16 nColGrpSpan;
4263  sal_uInt16 nColGrpWidth;
4264  bool bRelColGrpWidth;
4265  SvxAdjust eColGrpAdjust;
4266  sal_Int16 eColGrpVertOri;
4267 
4268  inline TableColGrpSaveStruct();
4269 
4270  inline void CloseColGroup( HTMLTable *pTable );
4271 };
4272 
4273 }
4274 
4275 inline TableColGrpSaveStruct::TableColGrpSaveStruct() :
4276  nColGrpSpan( 1 ), nColGrpWidth( 0 ),
4277  bRelColGrpWidth( false ), eColGrpAdjust( SvxAdjust::End ),
4278  eColGrpVertOri( text::VertOrientation::TOP )
4279 {}
4280 
4281 inline void TableColGrpSaveStruct::CloseColGroup( HTMLTable *pTable )
4282 {
4283  pTable->CloseColGroup( nColGrpSpan, nColGrpWidth,
4284  bRelColGrpWidth, eColGrpAdjust, eColGrpVertOri );
4285 }
4286 
4288  bool bReadOptions )
4289 {
4290  // <COLGROUP> was read already if bReadOptions is set
4291 
4292  if( !IsParserWorking() && m_vPendingStack.empty() )
4293  return;
4294 
4295  HtmlTokenId nToken = HtmlTokenId::NONE;
4296  bool bPending = false;
4297  std::unique_ptr<TableColGrpSaveStruct> pSaveStruct;
4298 
4299  if( !m_vPendingStack.empty() )
4300  {
4301  pSaveStruct.reset(static_cast<TableColGrpSaveStruct*>(m_vPendingStack.back().pData.release()));
4302 
4303 
4304  m_vPendingStack.pop_back();
4305  nToken = !m_vPendingStack.empty() ? m_vPendingStack.back().nToken : GetSaveToken();
4306  bPending = SvParserState::Error == eState && !m_vPendingStack.empty();
4307 
4308  SaveState( nToken );
4309  }
4310  else
4311  {
4312 
4313  pSaveStruct.reset(new TableColGrpSaveStruct);
4314  if( bReadOptions )
4315  {
4316  const HTMLOptions& rColGrpOptions = GetOptions();
4317  for (size_t i = rColGrpOptions.size(); i; )
4318  {
4319  const HTMLOption& rOption = rColGrpOptions[--i];
4320  switch( rOption.GetToken() )
4321  {
4322  case HtmlOptionId::ID:
4323  InsertBookmark( rOption.GetString() );
4324  break;
4325  case HtmlOptionId::SPAN:
4326  pSaveStruct->nColGrpSpan = static_cast<sal_uInt16>(rOption.GetNumber());
4327  if (pSaveStruct->nColGrpSpan > 256)
4328  {
4329  SAL_INFO("sw.html", "ignoring huge SPAN " << pSaveStruct->nColGrpSpan);
4330  pSaveStruct->nColGrpSpan = 1;
4331  }
4332  break;
4333  case HtmlOptionId::WIDTH:
4334  pSaveStruct->nColGrpWidth = static_cast<sal_uInt16>(rOption.GetNumber());
4335  pSaveStruct->bRelColGrpWidth =
4336  (rOption.GetString().indexOf('*') != -1);
4337  break;
4338  case HtmlOptionId::ALIGN:
4339  pSaveStruct->eColGrpAdjust =
4340  rOption.GetEnum( aHTMLPAlignTable, pSaveStruct->eColGrpAdjust );
4341  break;
4342  case HtmlOptionId::VALIGN:
4343  pSaveStruct->eColGrpVertOri =
4344  rOption.GetEnum( aHTMLTableVAlignTable,
4345  pSaveStruct->eColGrpVertOri );
4346  break;
4347  default: break;
4348  }
4349  }
4350  }
4351  // If the first GetNextToken() doesn't succeed (pending input), must re-read from the beginning.
4352  SaveState( HtmlTokenId::NONE );
4353  }
4354 
4355  if( nToken == HtmlTokenId::NONE )
4356  nToken = GetNextToken(); // naechstes Token
4357 
4358  bool bDone = false;
4359  while( (IsParserWorking() && !bDone) || bPending )
4360  {
4361  SaveState( nToken );
4362 
4363  nToken = FilterToken( nToken );
4364 
4365  OSL_ENSURE( !m_vPendingStack.empty() || !m_bCallNextToken ||
4366  pCurTable->GetContext() || pCurTable->HasParentSection(),
4367  "Where is the section?" );
4368  if( m_vPendingStack.empty() && m_bCallNextToken &&
4369  (pCurTable->GetContext() || pCurTable->HasParentSection()) )
4370  {
4371  // Call NextToken directly (e.g. ignore the content of floating frames or applets)
4372  NextToken( nToken );
4373  }
4374  else switch( nToken )
4375  {
4376  case HtmlTokenId::TABLE_ON:
4377  if( !pCurTable->GetContext() )
4378  {
4379  SkipToken();
4380  bDone = true;
4381  }
4382 
4383  break;
4384  case HtmlTokenId::COLGROUP_ON:
4385  case HtmlTokenId::THEAD_ON:
4386  case HtmlTokenId::TFOOT_ON:
4387  case HtmlTokenId::TBODY_ON:
4388  case HtmlTokenId::TABLEROW_ON:
4389  case HtmlTokenId::TABLE_OFF:
4390  SkipToken();
4391  [[fallthrough]];
4392  case HtmlTokenId::COLGROUP_OFF:
4393  bDone = true;
4394  break;
4395  case HtmlTokenId::COL_ON:
4396  {
4397  sal_uInt16 nColSpan = 1;
4398  sal_uInt16 nColWidth = pSaveStruct->nColGrpWidth;
4399  bool bRelColWidth = pSaveStruct->bRelColGrpWidth;
4400  SvxAdjust eColAdjust = pSaveStruct->eColGrpAdjust;
4401  sal_Int16 eColVertOri = pSaveStruct->eColGrpVertOri;
4402 
4403  const HTMLOptions& rColOptions = GetOptions();
4404  for (size_t i = rColOptions.size(); i; )
4405  {
4406  const HTMLOption& rOption = rColOptions[--i];
4407  switch( rOption.GetToken() )
4408  {
4409  case HtmlOptionId::ID:
4410  InsertBookmark( rOption.GetString() );
4411  break;
4412  case HtmlOptionId::SPAN:
4413  nColSpan = static_cast<sal_uInt16>(rOption.GetNumber());
4414  if (nColSpan > 256)
4415  {
4416  SAL_INFO("sw.html", "ignoring huge SPAN " << nColSpan);
4417  nColSpan = 1;
4418  }
4419  break;
4420  case HtmlOptionId::WIDTH:
4421  nColWidth = static_cast<sal_uInt16>(rOption.GetNumber());
4422  bRelColWidth =
4423  (rOption.GetString().indexOf('*') != -1);
4424  break;
4425  case HtmlOptionId::ALIGN:
4426  eColAdjust = rOption.GetEnum( aHTMLPAlignTable, eColAdjust );
4427  break;
4428  case HtmlOptionId::VALIGN:
4429  eColVertOri =
4430  rOption.GetEnum( aHTMLTableVAlignTable, eColVertOri );
4431  break;
4432  default: break;
4433  }
4434  }
4435  pCurTable->InsertCol( nColSpan, nColWidth, bRelColWidth,
4436  eColAdjust, eColVertOri );
4437 
4438  // the attributes in <COLGRP> should be ignored, if there are <COL> elements
4439  pSaveStruct->nColGrpSpan = 0;
4440  }
4441  break;
4442  case HtmlTokenId::COL_OFF:
4443  break; // Ignore
4444  case HtmlTokenId::MULTICOL_ON:
4445  // we can't add columned text frames here
4446  break;
4447  case HtmlTokenId::TEXTTOKEN:
4448  if( (pCurTable->GetContext() ||
4449  !pCurTable->HasParentSection()) &&
4450  1==aToken.getLength() && ' '==aToken[0] )
4451  break;
4452  [[fallthrough]];
4453  default:
4454  pCurTable->MakeParentContents();
4455  NextToken( nToken );
4456  }
4457 
4458  OSL_ENSURE( !bPending || m_vPendingStack.empty(),
4459  "SwHTMLParser::BuildTableColGrp: There is a PendStack again" );
4460  bPending = false;
4461  if( IsParserWorking() )
4462  SaveState( HtmlTokenId::NONE );
4463 
4464  if( !bDone )
4465  nToken = GetNextToken();
4466  }
4467 
4468  if( SvParserState::Pending == GetStatus() )
4469  {
4470  m_vPendingStack.emplace_back( HtmlTokenId::COL_ON );
4471  m_vPendingStack.back().pData = std::move(pSaveStruct);
4472  }
4473  else
4474  {
4475  pSaveStruct->CloseColGroup( pCurTable );
4476  }
4477 }
4478 
4480 {
4482  SwHTMLNumRuleInfo aNumRuleInfo; // valid numbering
4483 
4484 public:
4485 
4486  std::shared_ptr<HTMLAttrTable> xAttrTab; // attributes
4487 
4488  CaptionSaveStruct( SwHTMLParser& rParser, const SwPosition& rPos ) :
4489  SectionSaveStruct( rParser ), aSavePos( rPos ),
4490  xAttrTab(std::make_shared<HTMLAttrTable>())
4491  {
4492  rParser.SaveAttrTab(xAttrTab);
4493 
4494  // The current numbering was remembered and just needs to be closed
4495  aNumRuleInfo.Set( rParser.GetNumInfo() );
4496  rParser.GetNumInfo().Clear();
4497  }
4498 
4499  const SwPosition& GetPos() const { return aSavePos; }
4500 
4501  void RestoreAll( SwHTMLParser& rParser )
4502  {
4503  // Recover the old stack
4504  Restore( rParser );
4505 
4506  // Recover the old attribute tables
4507  rParser.RestoreAttrTab(xAttrTab);
4508 
4509  // Re-open the old numbering
4510  rParser.GetNumInfo().Set( aNumRuleInfo );
4511  }
4512 };
4513 
4515 {
4516  // <CAPTION> was read already
4517 
4518  if( !IsParserWorking() && m_vPendingStack.empty() )
4519  return;
4520 
4521  HtmlTokenId nToken = HtmlTokenId::NONE;
4522  std::unique_ptr<CaptionSaveStruct> xSaveStruct;
4523 
4524  if( !m_vPendingStack.empty() )
4525  {
4526  xSaveStruct.reset(static_cast<CaptionSaveStruct*>(m_vPendingStack.back().pData.release()));
4527 
4528  m_vPendingStack.pop_back();
4529  nToken = !m_vPendingStack.empty() ? m_vPendingStack.back().nToken : GetSaveToken();
4530  OSL_ENSURE( m_vPendingStack.empty(), "Where does a PendStack coming from?" );
4531 
4532  SaveState( nToken );
4533  }
4534  else
4535  {
4536  if (m_xTable->IsOverflowing())
4537  {
4538  SaveState( HtmlTokenId::NONE );
4539  return;
4540  }
4541 
4542  bool bTop = true;
4543  const HTMLOptions& rHTMLOptions = GetOptions();
4544  for ( size_t i = rHTMLOptions.size(); i; )
4545  {
4546  const HTMLOption& rOption = rHTMLOptions[--i];
4547  if( HtmlOptionId::ALIGN == rOption.GetToken() )
4548  {
4549  if (rOption.GetString().equalsIgnoreAsciiCase(
4551  {
4552  bTop = false;
4553  }
4554  }
4555  }
4556 
4557  // Remember old PaM position
4558  xSaveStruct.reset(new CaptionSaveStruct(*this, *m_pPam->GetPoint()));
4559 
4560  // Add a text section in the icon section as a container for the header
4561  // and set the PaM there
4562  const SwStartNode *pStNd;
4563  if (m_xTable.get() == pCurTable)
4565  else
4567 
4568  std::unique_ptr<HTMLAttrContext> xCntxt(new HTMLAttrContext(HtmlTokenId::CAPTION_ON));
4569 
4570  // Table headers are always centered
4571  NewAttr(m_xAttrTab, &m_xAttrTab->pAdjust, SvxAdjustItem(SvxAdjust::Center, RES_PARATR_ADJUST));
4572 
4573  HTMLAttrs &rAttrs = xCntxt->GetAttrs();
4574  rAttrs.push_back( m_xAttrTab->pAdjust );
4575 
4576  PushContext(xCntxt);
4577 
4578  // Remember the start node of the section at the table
4579  pCurTable->SetCaption( pStNd, bTop );
4580 
4581  // If the first GetNextToken() doesn't succeed (pending input), must re-read from the beginning.
4582  SaveState( HtmlTokenId::NONE );
4583  }
4584 
4585  if( nToken == HtmlTokenId::NONE )
4586  nToken = GetNextToken();
4587 
4588  // </CAPTION> is needed according to DTD
4589  bool bDone = false;
4590  while( IsParserWorking() && !bDone )
4591  {
4592  SaveState( nToken );
4593 
4594  nToken = FilterToken( nToken );
4595 
4596  switch( nToken )
4597  {
4598  case HtmlTokenId::TABLE_ON:
4599  if( m_vPendingStack.empty() )
4600  {
4601  xSaveStruct->m_xTable = m_xTable;
4602  bool bHasToFly = xSaveStruct->m_xTable.get() != pCurTable;
4603  BuildTable( pCurTable->GetTableAdjust( true ),
4604  false, true, bHasToFly );
4605  }
4606  else
4607  {
4608  BuildTable( SvxAdjust::End );
4609  }
4610  if( SvParserState::Pending != GetStatus() )
4611  {
4612  m_xTable = xSaveStruct->m_xTable;
4613  }
4614  break;
4615  case HtmlTokenId::TABLE_OFF:
4616  case HtmlTokenId::COLGROUP_ON:
4617  case HtmlTokenId::THEAD_ON:
4618  case HtmlTokenId::TFOOT_ON:
4619  case HtmlTokenId::TBODY_ON:
4620  case HtmlTokenId::TABLEROW_ON:
4621  SkipToken();
4622  bDone = true;
4623  break;
4624 
4625  case HtmlTokenId::CAPTION_OFF:
4626  bDone = true;
4627  break;
4628  default:
4629  if( !m_vPendingStack.empty() )
4630  {
4631  m_vPendingStack.pop_back();
4632  OSL_ENSURE( m_vPendingStack.empty(), "Further it can't go!" );
4633  }
4634 
4635  if( IsParserWorking() )
4636  NextToken( nToken );
4637  break;
4638  }
4639 
4640  if( IsParserWorking() )
4641  SaveState( HtmlTokenId::NONE );
4642 
4643  if( !bDone )
4644  nToken = GetNextToken();
4645  }
4646 
4647  if( SvParserState::Pending==GetStatus() )
4648  {
4649  m_vPendingStack.emplace_back( HtmlTokenId::CAPTION_ON );
4650  m_vPendingStack.back().pData = std::move(xSaveStruct);
4651  return;
4652  }
4653 
4654  // end all still open contexts
4655  while( m_aContexts.size() > m_nContextStAttrMin+1 )
4656  {
4657  std::unique_ptr<HTMLAttrContext> xCntxt(PopContext());
4658  EndContext(xCntxt.get());
4659  }
4660 
4661  bool bLFStripped = StripTrailingLF() > 0;
4662 
4663  if (m_xTable.get() == pCurTable)
4664  {
4665  // On moving the caption later, the last paragraph isn't moved as well.
4666  // That means, there has to be an empty paragraph at the end of the section
4667  if( m_pPam->GetPoint()->nContent.GetIndex() || bLFStripped )
4669  }
4670  else
4671  {
4672  // Strip LFs at the end of the paragraph
4673  if( !m_pPam->GetPoint()->nContent.GetIndex() && !bLFStripped )
4675  }
4676 
4677  // If there's an adjustment for the cell, we need to close it
4678  std::unique_ptr<HTMLAttrContext> xCntxt(PopContext());
4679  if (xCntxt)
4680  {
4681  EndContext(xCntxt.get());
4682  xCntxt.reset();
4683  }
4684 
4685  SetAttr( false );
4686 
4687  // Recover stack and attribute table
4688  xSaveStruct->RestoreAll(*this);
4689 
4690  // Recover PaM
4691  *m_pPam->GetPoint() = xSaveStruct->GetPos();
4692 }
4693 
4694 namespace {
4695 
4696 class TableSaveStruct : public SwPendingData
4697 {
4698 public:
4699  std::shared_ptr<HTMLTable> m_xCurrentTable;
4700 
4701  explicit TableSaveStruct(const std::shared_ptr<HTMLTable>& rCurTable)
4702  : m_xCurrentTable(rCurTable)
4703  {
4704  }
4705 
4706  // Initiate creation of the table and put the table in a text frame if
4707  // needed. If it returns true, we need to insert a paragraph.
4708  void MakeTable( sal_uInt16 nWidth, SwPosition& rPos, SwDoc *pDoc );
4709 };
4710 
4711 }
4712 
4713 void TableSaveStruct::MakeTable( sal_uInt16 nWidth, SwPosition& rPos, SwDoc *pDoc )
4714 {
4715  m_xCurrentTable->MakeTable(nullptr, nWidth);
4716 
4717  HTMLTableContext *pTCntxt = m_xCurrentTable->GetContext();
4718  OSL_ENSURE( pTCntxt, "Where is the table context" );
4719 
4720  SwTableNode *pTableNd = pTCntxt->GetTableNode();
4721  OSL_ENSURE( pTableNd, "Where is the table node" );
4722 
4723  if( pDoc->getIDocumentLayoutAccess().GetCurrentViewShell() && pTableNd )
4724  {
4725  // If there's already a layout, the BoxFrames need to be regenerated at this table
4726 
4727  if( pTCntxt->GetFrameFormat() )
4728  {
4729  pTCntxt->GetFrameFormat()->DelFrames();
4730  pTableNd->DelFrames();
4731  pTCntxt->GetFrameFormat()->MakeFrames();
4732  }
4733  else
4734  {
4735  pTableNd->DelFrames();
4736  SwNodeIndex aIdx( *pTableNd->EndOfSectionNode(), 1 );
4737  OSL_ENSURE( aIdx.GetIndex() <= pTCntxt->GetPos()->nNode.GetIndex(),
4738  "unexpected node for table layout" );
4739  pTableNd->MakeOwnFrames(&aIdx);
4740  }
4741  }
4742 
4743  rPos = *pTCntxt->GetPos();
4744 }
4745 
4746 HTMLTableOptions::HTMLTableOptions( const HTMLOptions& rOptions,
4747  SvxAdjust eParentAdjust ) :
4748  nCols( 0 ),
4749  nWidth( 0 ), nHeight( 0 ),
4750  nCellPadding( USHRT_MAX ), nCellSpacing( USHRT_MAX ),
4751  nBorder( USHRT_MAX ),
4752  nHSpace( 0 ), nVSpace( 0 ),
4753  eAdjust( eParentAdjust ), eVertOri( text::VertOrientation::CENTER ),
4754  eFrame( HTMLTableFrame::Void ), eRules( HTMLTableRules::NONE ),
4755  bPercentWidth( false ),
4756  bTableAdjust( false ),
4757  bBGColor( false ),
4758  aBorderColor( COL_GRAY )
4759 {
4760  bool bBorderColor = false;
4761  bool bHasFrame = false, bHasRules = false;
4762 
4763  for (size_t i = rOptions.size(); i; )
4764  {
4765  const HTMLOption& rOption = rOptions[--i];
4766  switch( rOption.GetToken() )
4767  {
4768  case HtmlOptionId::ID:
4769  aId = rOption.GetString();
4770  break;
4771  case HtmlOptionId::COLS:
4772  nCols = static_cast<sal_uInt16>(rOption.GetNumber());
4773  break;
4774  case HtmlOptionId::WIDTH:
4775  nWidth = static_cast<sal_uInt16>(rOption.GetNumber());
4776  bPercentWidth = (rOption.GetString().indexOf('%') != -1);
4777  if( bPercentWidth && nWidth>100 )
4778  nWidth = 100;
4779  break;
4780  case HtmlOptionId::HEIGHT:
4781  nHeight = static_cast<sal_uInt16>(rOption.GetNumber());
4782  if( rOption.GetString().indexOf('%') != -1 )
4783  nHeight = 0; // don't use % attributes
4784  break;
4785  case HtmlOptionId::CELLPADDING:
4786  nCellPadding = static_cast<sal_uInt16>(rOption.GetNumber());
4787  break;
4788  case HtmlOptionId::CELLSPACING:
4789  nCellSpacing = static_cast<sal_uInt16>(rOption.GetNumber());
4790  break;
4791  case HtmlOptionId::ALIGN:
4792  {
4793  if( rOption.GetEnum( eAdjust, aHTMLPAlignTable ) )
4794  {
4795  bTableAdjust = true;
4796  }
4797  }
4798  break;
4799  case HtmlOptionId::VALIGN:
4800  eVertOri = rOption.GetEnum( aHTMLTableVAlignTable, eVertOri );
4801  break;
4802  case HtmlOptionId::BORDER:
4803  // Handle BORDER and BORDER=BORDER like BORDER=1
4804  if (!rOption.GetString().isEmpty() &&
4805  !rOption.GetString().equalsIgnoreAsciiCase(
4806  OOO_STRING_SVTOOLS_HTML_O_border))
4807  {
4808  nBorder = static_cast<sal_uInt16>(rOption.GetNumber());
4809  }
4810  else
4811  nBorder = 1;
4812 
4813  if( !bHasFrame )
4814  eFrame = ( nBorder ? HTMLTableFrame::Box : HTMLTableFrame::Void );
4815  if( !bHasRules )
4816  eRules = ( nBorder ? HTMLTableRules::All : HTMLTableRules::NONE );
4817  break;
4818  case HtmlOptionId::FRAME:
4819  eFrame = rOption.GetTableFrame();
4820  bHasFrame = true;
4821  break;
4822  case HtmlOptionId::RULES:
4823  eRules = rOption.GetTableRules();
4824  bHasRules = true;
4825  break;
4826  case HtmlOptionId::BGCOLOR:
4827  // Ignore empty BGCOLOR on <TABLE>, <TR> and <TD>/<TH> like Netscape
4828  // *really* not on other tags
4829  if( !rOption.GetString().isEmpty() )
4830  {
4831  rOption.GetColor( aBGColor );
4832  bBGColor = true;
4833  }
4834  break;
4835  case HtmlOptionId::BACKGROUND:
4836  aBGImage = rOption.GetString();
4837  break;
4838  case HtmlOptionId::BORDERCOLOR:
4839  rOption.GetColor( aBorderColor );
4840  bBorderColor = true;
4841  break;
4842  case HtmlOptionId::BORDERCOLORDARK:
4843  if( !bBorderColor )
4844  rOption.GetColor( aBorderColor );
4845  break;
4846  case HtmlOptionId::STYLE:
4847  aStyle = rOption.GetString();
4848  break;
4849  case HtmlOptionId::CLASS:
4850  aClass = rOption.GetString();
4851  break;
4852  case HtmlOptionId::DIR:
4853  aDir = rOption.GetString();
4854  break;
4855  case HtmlOptionId::HSPACE:
4856  nHSpace = static_cast<sal_uInt16>(rOption.GetNumber());
4857  break;
4858  case HtmlOptionId::VSPACE:
4859  nVSpace = static_cast<sal_uInt16>(rOption.GetNumber());
4860  break;
4861  default: break;
4862  }
4863  }
4864 
4865  if( nCols && !nWidth )
4866  {
4867  nWidth = 100;
4868  bPercentWidth = true;
4869  }
4870 
4871  // If BORDER=0 or no BORDER given, then there shouldn't be a border
4872  if( 0==nBorder || USHRT_MAX==nBorder )
4873  {
4874  eFrame = HTMLTableFrame::Void;
4875  eRules = HTMLTableRules::NONE;
4876  }
4877 }
4878 
4879 namespace
4880 {
4881  class IndexInRange
4882  {
4883  private:
4886  public:
4887  explicit IndexInRange(const SwNodeIndex& rStart, const SwNodeIndex& rEnd)
4888  : maStart(rStart)
4889  , maEnd(rEnd)
4890  {
4891  }
4892  bool operator()(const SwHTMLTextFootnote& rTextFootnote) const
4893  {
4894  const SwNodeIndex aTextIdx(rTextFootnote.pTextFootnote->GetTextNode());
4895  return aTextIdx >= maStart && aTextIdx <= maEnd;
4896  }
4897  };
4898 }
4899 
4901 {
4902  //similarly for footnotes
4903  if (m_pFootEndNoteImpl)
4904  {
4905  m_pFootEndNoteImpl->aTextFootnotes.erase(std::remove_if(m_pFootEndNoteImpl->aTextFootnotes.begin(),
4906  m_pFootEndNoteImpl->aTextFootnotes.end(), IndexInRange(rMkNdIdx, rPtNdIdx)), m_pFootEndNoteImpl->aTextFootnotes.end());
4907  if (m_pFootEndNoteImpl->aTextFootnotes.empty())
4908  {
4909  m_pFootEndNoteImpl.reset();
4910  }
4911  }
4912 
4913  //follow DelFlyInRange pattern here
4914  assert(rMkNdIdx.GetIndex() <= rPtNdIdx.GetIndex());
4915 
4916  SwDoc& rDoc = rMkNdIdx.GetNode().GetDoc();
4917 
4918  //ofz#9733 drop bookmarks in this range
4919  IDocumentMarkAccess* const pMarkAccess = rDoc.getIDocumentMarkAccess();
4920  pMarkAccess->deleteMarks(rMkNdIdx, SwNodeIndex(rPtNdIdx, 1), nullptr, nullptr, nullptr);
4921 
4922  SwFrameFormats& rTable = *rDoc.GetSpzFrameFormats();
4923  for ( auto i = rTable.size(); i; )
4924  {
4925  SwFrameFormat *pFormat = rTable[--i];
4926  const SwFormatAnchor &rAnch = pFormat->GetAnchor();
4927  SwPosition const*const pAPos = rAnch.GetContentAnchor();
4928  if (pAPos &&
4929  ((rAnch.GetAnchorId() == RndStdIds::FLY_AT_PARA) ||
4930  (rAnch.GetAnchorId() == RndStdIds::FLY_AT_CHAR)) &&
4931  ( rMkNdIdx < pAPos->nNode && pAPos->nNode <= rPtNdIdx ))
4932  {
4933  if( rPtNdIdx != pAPos->nNode )
4934  {
4935  // If the Fly is deleted, all Flys in its content have to be deleted too.
4936  const SwFormatContent &rContent = pFormat->GetContent();
4937  // But only fly formats own their content, not draw formats.
4938  if (rContent.GetContentIdx() && pFormat->Which() == RES_FLYFRMFMT)
4939  {
4942  }
4943  }
4944  }
4945  }
4946 }
4947 
4949 {
4950  //if section to be deleted contains a pending m_pMarquee, it will be deleted
4951  //so clear m_pMarquee pointer if that's the case
4952  SwFrameFormat* pObjectFormat = m_pMarquee ? ::FindFrameFormat(m_pMarquee) : nullptr;
4953  FrameDeleteWatch aWatch(pObjectFormat);
4954 
4955  //similarly for footnotes
4956  SwNodeIndex aSttIdx(*pSttNd), aEndIdx(*pSttNd->EndOfSectionNode());
4957  ClearFootnotesMarksInRange(aSttIdx, aEndIdx);
4958 
4959  m_xDoc->getIDocumentContentOperations().DeleteSection(pSttNd);
4960 
4961  if (pObjectFormat)
4962  {
4963  if (aWatch.WasDeleted())
4964  m_pMarquee = nullptr;
4965  else
4966  aWatch.EndListeningAll();
4967  }
4968 }
4969 
4970 std::shared_ptr<HTMLTable> SwHTMLParser::BuildTable(SvxAdjust eParentAdjust,
4971  bool bIsParentHead,
4972  bool bHasParentSection,
4973  bool bHasToFly)
4974 {
4975  TableDepthGuard aGuard(*this);
4976  if (aGuard.TooDeep())
4977  eState = SvParserState::Error;
4978 
4979  if (!IsParserWorking() && m_vPendingStack.empty())
4980  return std::shared_ptr<HTMLTable>();
4981 
4983  HtmlTokenId nToken = HtmlTokenId::NONE;
4984  bool bPending = false;
4985  std::unique_ptr<TableSaveStruct> xSaveStruct;
4986 
4987  if( !m_vPendingStack.empty() )
4988  {
4989  xSaveStruct.reset(static_cast<TableSaveStruct*>(m_vPendingStack.back().pData.release()));
4990 
4991  m_vPendingStack.pop_back();
4992  nToken = !m_vPendingStack.empty() ? m_vPendingStack.back().nToken : GetSaveToken();
4993  bPending = SvParserState::Error == eState && !m_vPendingStack.empty();
4994 
4995  SaveState( nToken );
4996  }
4997  else
4998  {
4999  m_xTable.reset();
5000  HTMLTableOptions aTableOptions(GetOptions(), eParentAdjust);
5001 
5002  if (!aTableOptions.aId.isEmpty())
5003  InsertBookmark(aTableOptions.aId);
5004 
5005  std::shared_ptr<HTMLTable> xCurTable(std::make_shared<HTMLTable>(this,
5006  bIsParentHead,
5007  bHasParentSection,
5008  bHasToFly,
5009  aTableOptions));
5010  m_xTable = xCurTable;
5011 
5012  xSaveStruct.reset(new TableSaveStruct(xCurTable));
5013 
5014  // Is pending on the first GetNextToken, needs to be re-read on each construction
5015  SaveState( HtmlTokenId::NONE );
5016  }
5017 
5018  std::shared_ptr<HTMLTable> xCurTable = xSaveStruct->m_xCurrentTable;
5019 
5020  // </TABLE> is needed according to DTD
5021  if( nToken == HtmlTokenId::NONE )
5022  nToken = GetNextToken();
5023 
5024  bool bDone = false;
5025  while( (IsParserWorking() && !bDone) || bPending )
5026  {
5027  SaveState( nToken );
5028 
5029  nToken = FilterToken( nToken );
5030 
5031  OSL_ENSURE( !m_vPendingStack.empty() || !m_bCallNextToken ||
5032  xCurTable->GetContext() || xCurTable->HasParentSection(),
5033  "Where is the section?" );
5034  if( m_vPendingStack.empty() && m_bCallNextToken &&
5035  (xCurTable->GetContext() || xCurTable->HasParentSection()) )
5036  {
5038  NextToken( nToken );
5039  }
5040  else switch( nToken )
5041  {
5042  case HtmlTokenId::TABLE_ON:
5043  if( !xCurTable->GetContext() )
5044  {
5045  // If there's no table added, read the next table'
5046  SkipToken();
5047  bDone = true;
5048  }
5049 
5050  break;
5051  case HtmlTokenId::TABLE_OFF:
5052  bDone = true;
5053  break;
5054  case HtmlTokenId::CAPTION_ON:
5055  BuildTableCaption(xCurTable.get());
5056  bDone = m_xTable->IsOverflowing();
5057  break;
5058  case HtmlTokenId::COL_ON:
5059  SkipToken();
5060  BuildTableColGroup(xCurTable.get(), false);
5061  break;
5062  case HtmlTokenId::COLGROUP_ON:
5063  BuildTableColGroup(xCurTable.get(), true);
5064  break;
5065  case HtmlTokenId::TABLEROW_ON:
5066  case HtmlTokenId::TABLEHEADER_ON:
5067  case HtmlTokenId::TABLEDATA_ON:
5068  SkipToken();
5069  BuildTableSection(xCurTable.get(), false, false);
5070  bDone = m_xTable->IsOverflowing();
5071  break;
5072  case HtmlTokenId::THEAD_ON:
5073  case HtmlTokenId::TFOOT_ON:
5074  case HtmlTokenId::TBODY_ON:
5075  BuildTableSection(xCurTable.get(), true, HtmlTokenId::THEAD_ON==nToken);
5076  bDone = m_xTable->IsOverflowing();
5077  break;
5078  case HtmlTokenId::MULTICOL_ON:
5079  // we can't add columned text frames here
5080  break;
5081  case HtmlTokenId::FORM_ON:
5082  NewForm( false ); // don't add a new paragraph
5083  break;
5084  case HtmlTokenId::FORM_OFF:
5085  EndForm( false ); // don't add a new paragraph
5086  break;
5087  case HtmlTokenId::TEXTTOKEN:
5088  // blank strings may be a series of CR+LF and no text
5089  if( (xCurTable->GetContext() ||
5090  !xCurTable->HasParentSection()) &&
5091  1==aToken.getLength() && ' '==aToken[0] )
5092  break;
5093  [[fallthrough]];
5094  default:
5095  xCurTable->MakeParentContents();
5096  NextToken( nToken );
5097  break;
5098  }
5099 
5100  OSL_ENSURE( !bPending || m_vPendingStack.empty(),
5101  "SwHTMLParser::BuildTable: There is a PendStack again" );
5102  bPending = false;
5103  if( IsParserWorking() )
5104  SaveState( HtmlTokenId::NONE );
5105 
5106  if( !bDone )
5107  nToken = GetNextToken();
5108  }
5109 
5110  if( SvParserState::Pending == GetStatus() )
5111  {
5112  m_vPendingStack.emplace_back( HtmlTokenId::TABLE_ON );
5113  m_vPendingStack.back().pData = std::move(xSaveStruct);
5114  return std::shared_ptr<HTMLTable>();
5115  }
5116 
5117  HTMLTableContext *pTCntxt = xCurTable->GetContext();
5118  if( pTCntxt )
5119  {
5120 
5121  // Modify table structure
5122  xCurTable->CloseTable();
5123 
5124  // end contexts that began out of cells. Needs to exist before (!) we move the table,
5125  // since the current one doesn't exist anymore afterwards
5126  while( m_aContexts.size() > m_nContextStAttrMin )
5127  {
5128  std::unique_ptr<HTMLAttrContext> xCntxt(PopContext());
5129  if (!xCntxt)
5130  break;
5131  ClearContext(xCntxt.get());
5132  }
5133 
5134  m_nContextStMin = pTCntxt->GetContextStMin();
5135  m_nContextStAttrMin = pTCntxt->GetContextStAttrMin();
5136 
5137  if (m_xTable == xCurTable)
5138  {
5139  // Set table caption
5140  const SwStartNode *pCapStNd = m_xTable->GetCaptionStartNode();
5141  if( pCapStNd )
5142  {
5143  // The last paragraph of the section is never part of the copy.
5144  // That's why the section needs to contain at least two paragraphs
5145 
5146  if( pCapStNd->EndOfSectionIndex() - pCapStNd->GetIndex() > 2 )
5147  {
5148  // Don't copy start node and the last paragraph
5149  SwNodeRange aSrcRg( *pCapStNd, 1,
5150  *pCapStNd->EndOfSectionNode(), -1 );
5151 
5152  bool bTop = m_xTable->IsTopCaption();
5153  SwStartNode *pTableStNd = pTCntxt->GetTableNode();
5154 
5155  OSL_ENSURE( pTableStNd, "Where is the table node" );
5156  OSL_ENSURE( pTableStNd==m_pPam->GetNode().FindTableNode(),
5157  "Are we in the wrong table?" );
5158 
5159  SwNode* pNd;
5160  if( bTop )
5161  pNd = pTableStNd;
5162  else
5163  pNd = pTableStNd->EndOfSectionNode();
5164  SwNodeIndex aDstIdx( *pNd, bTop ? 0 : 1 );
5165 
5166  m_xDoc->getIDocumentContentOperations().MoveNodeRange( aSrcRg, aDstIdx,
5168 
5169  // If the caption was added before the table, a page style on that table
5170  // needs to be moved to the first paragraph of the header.
5171  // Additionally, all remembered indices that point to the table node
5172  // need to be moved
5173  if( bTop )
5174  {
5175  MovePageDescAttrs( pTableStNd, aSrcRg.aStart.GetIndex(),
5176  false );
5177  }
5178  }
5179 
5180  // The section isn't needed anymore
5181  m_pPam->SetMark();
5182  m_pPam->DeleteMark();
5183  DeleteSection(const_cast<SwStartNode*>(pCapStNd));
5184  m_xTable->SetCaption( nullptr, false );
5185  }
5186 
5187  // Process SwTable
5188  sal_uInt16 nBrowseWidth = static_cast<sal_uInt16>(GetCurrentBrowseWidth());
5189  xSaveStruct->MakeTable(nBrowseWidth, *m_pPam->GetPoint(), m_xDoc.get());
5190  }
5191 
5192  GetNumInfo().Set( pTCntxt->GetNumInfo() );
5193  pTCntxt->RestorePREListingXMP( *this );
5194  RestoreAttrTab(pTCntxt->xAttrTab);
5195 
5196  if (m_xTable == xCurTable)
5197  {
5198  // Set upper paragraph spacing
5199  m_bUpperSpace = true;
5200  SetTextCollAttrs();
5201 
5202  SwTableNode* pTableNode = pTCntxt->GetTableNode();
5203  size_t nTableBoxSize = pTableNode ? pTableNode->GetTable().GetTabSortBoxes().size() : 0;
5204  m_nParaCnt = m_nParaCnt - std::min(m_nParaCnt, nTableBoxSize);
5205 
5206  // Jump to a table if needed
5207  if( JumpToMarks::Table == m_eJumpTo && m_xTable->GetSwTable() &&
5208  m_xTable->GetSwTable()->GetFrameFormat()->GetName() == m_sJmpMark )
5209  {
5210  m_bChkJumpMark = true;
5212  }
5213 
5214  // If the import was canceled, don't call Show again here since
5215  // the SwViewShell was already deleted
5216  // That's not enough. Even in the ACCEPTING_STATE, a Show mustn't be called
5217  // because otherwise the parser's gonna be destroyed on the reschedule,
5218  // if there's still a DataAvailable link coming. So: only in the WORKING state
5219  if( !m_nParaCnt && SvParserState::Working == GetStatus() )
5220  Show();
5221  }
5222  }
5223  else if (m_xTable == xCurTable)
5224  {
5225  // There was no table read
5226 
5227  // We maybe need to delete a read caption
5228  const SwStartNode *pCapStNd = xCurTable->GetCaptionStartNode();
5229  if( pCapStNd )
5230  {
5231  m_pPam->SetMark();
5232  m_pPam->DeleteMark();
5233  DeleteSection(const_cast<SwStartNode*>(pCapStNd));
5234  xCurTable->SetCaption( nullptr, false );
5235  }
5236  }
5237 
5238  if (m_xTable == xCurTable)
5239  {
5240  xSaveStruct->m_xCurrentTable.reset();
5241  m_xTable.reset();
5242  }
5243 
5244  std::shared_ptr<HTMLTable> xRetTable = xSaveStruct->m_xCurrentTable;
5245  xSaveStruct.reset();
5246 
5247  return xRetTable;
5248 }
5249 
5251 {
5252  if (!m_pResizeDrawObjects)
5253  return false;
5254 
5255  bool bRet = false;
5256 
5257  sal_uInt16 nCount = m_pResizeDrawObjects->size();
5258  for (sal_uInt16 i = 0; i < nCount && !bRet; ++i)
5259  {
5260  SdrObject *pObj = (*m_pResizeDrawObjects)[i];
5261  SwFrameFormat* pObjectFormat = ::FindFrameFormat(pObj);
5262  if (!pObjectFormat)
5263  continue;
5264  const SwFormatAnchor& rAnch = pObjectFormat->GetAnchor();
5265  if (const SwPosition* pPos = rAnch.GetContentAnchor())
5266  {
5267  SwNodeIndex aObjNodeIndex(pPos->nNode);
5268  bRet = (aObjNodeIndex >= rPam.Start()->nNode && aObjNodeIndex <= rPam.End()->nNode);
5269  }
5270  }
5271 
5272  return bRet;
5273 }
5274 
5276 {
5277  bool bRet = false;
5278  for (const auto& a : m_aTables)
5279  {
5280  bRet = a->PendingDrawObjectsInPaM(rPam);
5281  if (bRet)
5282  break;
5283  const SwTable *pTable = a->GetSwTable();
5284  if (!pTable)
5285  continue;
5286  const SwTableNode* pTableNode = pTable->GetTableNode();
5287  if (!pTableNode)
5288  continue;
5289  SwNodeIndex aTableNodeIndex(*pTableNode);
5290  bRet = (aTableNodeIndex >= rPam.Start()->nNode && aTableNodeIndex <= rPam.End()->nNode);
5291  if (bRet)
5292  break;
5293  }
5294  return bRet;
5295 }
5296 
5297 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
sal_uInt16 IncGrfsThatResizeTable()
Definition: htmltab.cxx:3181
void SetNodeNum(sal_uInt8 nLevel)
std::vector< SwPending > m_vPendingStack
Definition: swhtml.hxx:390
void ClearIsInSection()
Definition: htmltab.cxx:2862
const SwEndNode * EndOfSectionNode() const
Definition: node.hxx:686
const SwStartNode * m_pStartNode
Definition: htmltab.cxx:180
sal_uInt8 GetLevel() const
Definition: htmlnum.hxx:110
Starts a section of nodes in the document model.
Definition: node.hxx:312
bool m_bTopAllowed
Definition: htmltab.cxx:433
SvxAdjust GetInheritedAdjust() const
Definition: htmltab.cxx:1926
const std::unique_ptr< SvxBrushItem > & GetBGBrush() const
Definition: htmltab.cxx:524
constexpr TypedWhichId< SvxFrameDirectionItem > RES_FRAMEDIR(120)
virtual sal_Int32 Len() const
Definition: node.cxx:1245
constexpr TypedWhichId< SwFormatPageDesc > RES_PAGEDESC(93)
void DeleteMark()
Definition: pam.hxx:177
bool HasColTags() const
Definition: htmltab.cxx:616
void SetAnchorAndAdjustment(sal_Int16 eVertOri, sal_Int16 eHoriOri, const SvxCSS1PropertyInfo &rPropInfo, SfxItemSet &rFrameSet)
Definition: htmlgrin.cxx:149
sal_uLong GetIndex() const
Definition: node.hxx:291
SwNode & GetNode(bool bPoint=true) const
Definition: pam.hxx:223
std::shared_ptr< SwHTMLTableLayout > m_xLayoutInfo
Definition: htmltab.cxx:455
SwTableLine * MakeTableLine(SwTableBox *pUpper, sal_uInt16 nTopRow, sal_uInt16 nLeftCol, sal_uInt16 nBottomRow, sal_uInt16 nRightCol)
Definition: htmltab.cxx:1532
EnumT GetEnum(const HTMLOptionEnum< EnumT > *pOptEnums, EnumT nDflt=static_cast< EnumT >(0)) const
void SplitPREListingXMP(HTMLAttrContext *pCntxt)
Definition: htmlctxt.cxx:751
void AddContents(std::unique_ptr< HTMLTableCnts > pNewCnts)
Definition: htmltab.cxx:3035
void DeleteSection(SwStartNode *pSttNd)
Definition: htmltab.cxx:4948
std::shared_ptr< HTMLAttrTable > xAttrTab
Definition: htmltab.cxx:4486
std::unique_ptr< HTMLTableCnts > m_pNext
Definition: htmltab.cxx:177
HtmlOptionId GetToken() const
static Css1ScriptFlags GetScriptFromClass(OUString &rClass, bool bSubClassOnly=true)
Definition: htmlcss1.cxx:554
Represents the style of a paragraph.
Definition: fmtcol.hxx:56
bool HasToFly() const
Definition: htmltab.cxx:606
void InsertCol(sal_uInt16 nSpan, sal_uInt16 nWidth, bool bRelWidth, SvxAdjust eAdjust, sal_Int16 eVertOri)
Definition: htmltab.cxx:2144
#define OOO_STRING_SVTOOLS_HTML_VA_bottom
Marks a position in the document model.
Definition: pam.hxx:35
void SetAttr(bool bChkEnd=true, bool bBeforeTable=false, std::deque< std::unique_ptr< HTMLAttr >> *pPostIts=nullptr)
Definition: swhtml.hxx:505
bool m_bRightBorder
Definition: htmltab.cxx:432
void EndForm(bool bAppend=true)
Definition: htmlform.cxx:1368
Pagedescriptor Client of SwPageDesc that is "described" by the attribute.
Definition: fmtpdsc.hxx:35
SvxBorderLine m_aLeftBorderLine
Definition: htmltab.cxx:426
std::vector< sal_uInt16 > m_aBaseFontStack
Definition: swhtml.hxx:370
HTMLAttrs m_aSetAttrTab
Definition: swhtml.hxx:376
sal_uInt16 m_nWidth
Definition: htmltab.cxx:458
std::unique_ptr< std::vector< sal_uInt16 > > m_pDrawObjectPercentWidths
Definition: htmltab.cxx:390
void DelFrames(SwRootFrame const *pLayout=nullptr)
Method deletes all views of document for the node.
Definition: ndtbl.cxx:2443
SdrObject * m_pMarquee
Definition: swhtml.hxx:400
constexpr TypedWhichId< SwTableBoxNumFormat > RES_BOXATR_FORMAT(RES_BOXATR_BEGIN)
void SetParentContents(std::unique_ptr< HTMLTableCnts > pCnts)
Definition: htmltab.cxx:601
bool m_bFirstCell
Definition: htmltab.cxx:532
SwHTMLNumRuleInfo aNumRuleInfo
Definition: htmltab.cxx:4482
const OUString & GetText() const
Definition: ndtxt.hxx:210
std::vector< sal_uInt16 > m_aFontStack
Definition: swhtml.hxx:372
SwStartNode * InsertTempTableCaptionSection()
Definition: htmltab.cxx:2644
std::string GetValue
SvxBorderLine m_aBottomBorderLine
Definition: htmltab.cxx:425
SvNumberFormatter * GetNumberFormatter(bool bCreate=true)
Definition: doc.hxx:1412
void Show()
Definition: swhtml.cxx:2535
bool IsHeaderCell() const
Definition: htmltab.cxx:2867
void UpdateToSet(const sal_uInt8 nPos, const bool bSingleRowTable, const bool bSingleColTable, SfxItemSet &rSet, SwTableAutoFormatUpdateFlags eFlags, SvNumberFormatter *) const
Definition: tblafmt.cxx:560
std::shared_ptr< HTMLTable > BuildTable(SvxAdjust eCellAdjust, bool bIsParentHead=false, bool bHasParentSection=true, bool bHasToFlow=false)
Definition: htmltab.cxx:4970
virtual SfxPoolItem * Clone(SfxItemPool *pPool=nullptr) const =0
constexpr TypedWhichId< SvxFormatKeepItem > RES_KEEP(110)
SwNodeIndex nNode
Definition: pam.hxx:37
constexpr TypedWhichId< SwFormatFrameSize > RES_FRM_SIZE(89)
std::unique_ptr< SwHTMLFootEndNote_Impl > m_pFootEndNoteImpl
Definition: swhtml.hxx:404
const std::shared_ptr< SwHTMLTableLayout > & CreateLayoutInfo()
Definition: htmltab.cxx:1085
void SaveAttrTab(std::shared_ptr< HTMLAttrTable > const &rNewAttrTab)
Definition: swhtml.cxx:3287
void ProtectRowSpan(sal_uInt16 nRow, sal_uInt16 nCol, sal_uInt16 nRowSpan)
Definition: htmltab.cxx:1155
OUString m_aClass
Definition: htmltab.cxx:2828
void InsertBookmark(const OUString &rName)
Definition: htmlgrin.cxx:1350
#define NETSCAPE_DFLT_BORDER
Definition: htmltab.cxx:69
bool m_bRightAllowed
Definition: htmltab.cxx:434
std::shared_ptr< HTMLTable > & GetTable()
Definition: htmltab.cxx:199
OUString m_aClass
Definition: htmltab.cxx:386
bool m_bFillerTopBorder
Definition: htmltab.cxx:435
void Set(const SwHTMLNumRuleInfo &rInf)
Definition: htmlnum.hxx:93
void InsertCell(std::shared_ptr< HTMLTableCnts > const &rCnts, sal_uInt16 nRowSpan, sal_uInt16 nColSpan, sal_uInt16 nWidth, bool bRelWidth, sal_uInt16 nHeight, sal_Int16 eVertOri, std::shared_ptr< SvxBrushItem > const &rBGBrushItem, std::shared_ptr< SvxBoxItem > const &rBoxItem, bool bHasNumFormat, sal_uInt32 nNumFormat, bool bHasValue, double nValue, bool bNoWrap)
Definition: htmltab.cxx:1949
const OUString & GetStyle() const
Definition: htmltab.cxx:628
void SetHasParentSection(bool bSet)
Definition: htmltab.cxx:598
long Long
sal_uInt16 GetVSpace() const
Definition: htmltab.cxx:559
constexpr TypedWhichId< SvxFontHeightItem > RES_CHRATR_FONTSIZE(8)
#define MINLAY
Definition: swtypes.hxx:66
HTMLAttr * GetNext() const
Definition: swhtml.hxx:175
const SwStartNode * InsertTableSection(const SwStartNode *pPrevStNd)
Definition: htmltab.cxx:2536
void NewAttr(const std::shared_ptr< HTMLAttrTable > &rAttrTab, HTMLAttr **ppAttr, const SfxPoolItem &rItem)
Definition: swhtml.cxx:3051
sal_Int64 n
Provides access to the marks of a document.
const OUString & GetString() const
sal_uInt16 m_nBaseFontStMin
Definition: swhtml.hxx:411
Definition: doc.hxx:187
constexpr sal_uInt16 RES_FRMATR_END(133)
sal_uInt16 m_nDefListDeepSave
Definition: htmltab.cxx:2757
SwFrameFormat * ClaimFrameFormat()
Definition: swtable.cxx:1466
JumpToMarks m_eJumpTo
Definition: swhtml.hxx:424
std::unique_ptr< HTMLTableCnts > InsertTableContents(bool bHead)
Definition: htmltab.cxx:3142
HTMLTableFrame
HTMLTableCnts * Next()
Definition: htmltab.cxx:206
bool IsOverflowing() const
Definition: htmltab.cxx:632
HTMLTableFrame m_eFrame
Definition: htmltab.cxx:463
bool m_bTableAdjustOfTag
Definition: htmltab.cxx:441
static bool IsBoxEmpty(const SwTableBox *pBox)
Definition: htmltab.cxx:1229
const OUString & GetClass() const
Definition: htmltab.cxx:627
bool IsTopCaption() const
Definition: htmltab.cxx:551
HTMLAttrContexts m_aContexts
Definition: swhtml.hxx:379
const std::shared_ptr< HTMLTable > & GetTable() const
Definition: htmltab.cxx:198
void FixFrameFormat(SwTableBox *pBox, sal_uInt16 nRow, sal_uInt16 nCol, sal_uInt16 nRowSpan, sal_uInt16 nColSpan, bool bFirstPara=true, bool bLastPara=true) const
Definition: htmltab.cxx:1268
constexpr TypedWhichId< SvxFormatBreakItem > RES_BREAK(94)
void push_back(SwTableLine *pLine)
Definition: swtable.hxx:91
SwTableLine is one table row in the document model.
Definition: swtable.hxx:351
bool m_bNoBreak
Definition: htmltab.cxx:185
SvxBorderLine m_aTopBorderLine
Definition: htmltab.cxx:424
SwNode & GetNode() const
Definition: ndindex.hxx:119
OUString aId
sal_uInt16 m_nBaseFontStMinSave
Definition: htmltab.cxx:2756
Content, content of frame (header, footer, fly).
Definition: fmtcntnt.hxx:31
void SetBGBrush(const SvxBrushItem &rBrush)
Definition: htmltab.cxx:624
SvxBorderLine m_aBorderLine
Definition: htmltab.cxx:428
std::shared_ptr< SwHTMLTableLayoutCnts > m_xLayoutInfo
Definition: htmltab.cxx:183
sal_Int32 StripTrailingLF()
Definition: htmltab.cxx:2658
sal_uInt16 m_nCurrentRow
Definition: htmltab.cxx:399
OUString m_sBaseURL
Definition: swhtml.hxx:357
SwPosition aSavePos
Definition: htmltab.cxx:4481
void NewForm(bool bAppend=true)
Definition: htmlform.cxx:1207
std::shared_ptr< T > make_shared(Args &&...args)
void SetTable(const SwStartNode *pStNd, std::unique_ptr< HTMLTableContext > pCntxt, sal_uInt16 nLeft, sal_uInt16 nRight, const SwTable *pSwTab=nullptr, bool bFrcFrame=false)
Definition: htmltab.cxx:2475
const SwStartNode * m_pCaptionStartNode
Definition: htmltab.cxx:422
void SplitAttrTab(const SwPosition &rNewPos)
Definition: htmlctxt.cxx:172
static void PixelToTwip(tools::Long &nWidth, tools::Long &nHeight)
Definition: svxcss1.cxx:873
#define MIN_BORDER_DIST
Definition: swtypes.hxx:74
bool m_isInTableStructure
Definition: swhtml.hxx:472
friend class CellSaveStruct
Definition: swhtml.hxx:348
static void RegisterDrawObjectToTable(HTMLTable *pCurTable, SdrObject *pObj, sal_uInt8 nWidth)
Definition: htmltab.cxx:3186
SwTableFormat * GetFrameFormat()
Definition: swtable.hxx:203
bool WasDeleted() const
Definition: fltshell.hxx:348
Value in Var-direction gives minimum (can be exceeded but not be less).
std::shared_ptr< HTMLTable > m_xTable
Definition: htmltab.cxx:2763
std::unique_ptr< SvxBrushItem > m_xInheritedBackgroundBrush
Definition: htmltab.cxx:421
size_type size() const
Definition: swtable.hxx:75
constexpr TypedWhichId< SwFlyFrameFormat > RES_FLYFRMFMT(156)
SwNodeIndex m_nStartPara
Definition: swhtml.hxx:133
Color m_aBGColor
Definition: htmltab.cxx:2830
constexpr TypedWhichId< SwFormatLayoutSplit > RES_LAYOUT_SPLIT(113)
const HTMLTableCnts * Next() const
Definition: htmltab.cxx:205
SvxBorderLine m_aRightBorderLine
Definition: