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