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