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