LibreOffice Module sw (master)  1
wrtswtbl.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 <editeng/borderline.hxx>
23 #include <editeng/boxitem.hxx>
24 #include <editeng/brushitem.hxx>
25 #include <tools/fract.hxx>
26 #include <sal/log.hxx>
27 #include <osl/diagnose.h>
28 #include <wrtswtbl.hxx>
29 #include <swtable.hxx>
30 #include <frmfmt.hxx>
31 #include <fmtfsize.hxx>
32 #include <fmtornt.hxx>
33 #include <htmltbl.hxx>
34 
35 using ::editeng::SvxBorderLine;
36 using namespace ::com::sun::star;
37 
39 {
40  sal_Int16 eCellVertOri = text::VertOrientation::TOP;
41  if( m_pBox->GetSttNd() )
42  {
43  const SfxItemSet& rItemSet = m_pBox->GetFrameFormat()->GetAttrSet();
44  if( const SwFormatVertOrient *pItem = rItemSet.GetItemIfSet( RES_VERT_ORIENT, false ) )
45  {
46  sal_Int16 eBoxVertOri = pItem->GetVertOrient();
47  if( text::VertOrientation::CENTER==eBoxVertOri || text::VertOrientation::BOTTOM==eBoxVertOri)
48  eCellVertOri = eBoxVertOri;
49  }
50  }
51 
52  return eCellVertOri;
53 }
54 
55 SwWriteTableRow::SwWriteTableRow( tools::Long nPosition, bool bUseLayoutHeights )
56  : m_pBackground(nullptr), m_nPos(nPosition), mbUseLayoutHeights(bUseLayoutHeights),
57  m_nTopBorder(USHRT_MAX), m_nBottomBorder(USHRT_MAX), m_bTopBorder(true),
58  m_bBottomBorder(true)
59 {
60 }
61 
63  sal_uInt16 nRow, sal_uInt16 nCol,
64  sal_uInt16 nRowSpan, sal_uInt16 nColSpan,
65  tools::Long nHeight,
66  const SvxBrushItem *pBackgroundBrush )
67 {
68  SwWriteTableCell *pCell =
69  new SwWriteTableCell( pBox, nRow, nCol, nRowSpan, nColSpan,
70  nHeight, pBackgroundBrush );
71  m_Cells.push_back(std::unique_ptr<SwWriteTableCell>(pCell));
72 
73  return pCell;
74 }
75 
76 SwWriteTableCol::SwWriteTableCol(sal_uInt32 nPosition)
77  : m_nPos(nPosition), m_nWidthOpt(0), m_bRelWidthOpt(false),
78  m_bLeftBorder(true), m_bRightBorder(true)
79 {
80 }
81 
82 sal_uInt32 SwWriteTable::GetBoxWidth( const SwTableBox *pBox )
83 {
84  const SwFrameFormat *pFormat = pBox->GetFrameFormat();
85  const SwFormatFrameSize& aFrameSize=
86  pFormat->GetFormatAttr( RES_FRM_SIZE );
87 
88  return sal::static_int_cast<sal_uInt32>(aFrameSize.GetSize().Width());
89 }
90 
92 {
93 #ifdef DBG_UTIL
94  bool bOldGetLineHeightCalled = m_bGetLineHeightCalled;
96 #endif
97 
98  tools::Long nHeight = 0;
100  {
101  // At first we try to get the height of the layout.
102  bool bLayoutAvailable = false;
103  nHeight = pLine->GetTableLineHeight(bLayoutAvailable);
104  if( nHeight > 0 )
105  return nHeight;
106 
107  // If no layout is found, we assume that the heights are fixed.
108  // #i60390# - in some cases we still want to continue
109  // to use the layout heights even if one of the rows has a height of 0
110  // ('hidden' rows)
111  m_bUseLayoutHeights = bLayoutAvailable;
112 
113 #ifdef DBG_UTIL
114  SAL_WARN_IF( !bLayoutAvailable && bOldGetLineHeightCalled, "sw", "Layout invalid?" );
115 #endif
116  }
117 
118  const SwTableBoxes& rBoxes = pLine->GetTabBoxes();
119  for( auto pBox : rBoxes )
120  {
121  if( pBox->GetSttNd() )
122  {
123  if( nHeight < ROW_DFLT_HEIGHT )
124  nHeight = ROW_DFLT_HEIGHT;
125  }
126  else
127  {
128  tools::Long nTmp = 0;
129  const SwTableLines &rLines = pBox->GetTabLines();
130  for( size_t nLine=0; nLine<rLines.size(); nLine++ )
131  {
132  nTmp += GetLineHeight( rLines[nLine] );
133  }
134  if( nHeight < nTmp )
135  nHeight = nTmp;
136  }
137  }
138 
139  return nHeight;
140 }
141 
143 {
144  const SwTableLine *pLine = pBox->GetUpper();
145 
146  if( !pLine )
147  return 0;
148 
149  const SwFrameFormat *pLineFrameFormat = pLine->GetFrameFormat();
150  const SfxItemSet& rItemSet = pLineFrameFormat->GetAttrSet();
151 
152  tools::Long nHeight = 0;
153  if( const SwFormatFrameSize* pItem = rItemSet.GetItemIfSet( RES_FRM_SIZE ) )
154  nHeight = pItem->GetHeight();
155 
156  return nHeight;
157 }
158 
160  SwWriteTableRow *pRow )
161 {
162  const SwTableLine *pLine = pBox->GetUpper();
163 
164  while( pLine )
165  {
166  const SwFrameFormat *pLineFrameFormat = pLine->GetFrameFormat();
167  const SfxItemSet& rItemSet = pLineFrameFormat->GetAttrSet();
168 
169  if( const SvxBrushItem* pItem = rItemSet.GetItemIfSet( RES_BACKGROUND, false ) )
170  {
171  if( !pLine->GetUpper() )
172  {
173  if( !pRow->GetBackground() )
174  pRow->SetBackground( pItem );
175  pItem = nullptr;
176  }
177 
178  return pItem;
179  }
180 
181  pBox = pLine->GetUpper();
182  pLine = pBox ? pBox->GetUpper() : nullptr;
183  }
184 
185  return nullptr;
186 }
187 
188 void SwWriteTable::MergeBorders( const SvxBorderLine* pBorderLine,
189  bool bTable )
190 {
191  if( Color(ColorTransparency, 0xffffffff) == m_nBorderColor )
192  {
193  if( !pBorderLine->GetColor().IsRGBEqual( COL_GRAY ) )
194  m_nBorderColor = pBorderLine->GetColor();
195  }
196 
197  if( !m_bCollectBorderWidth )
198  return;
199 
200  const sal_uInt16 nOutWidth = pBorderLine->GetOutWidth();
201  if( bTable )
202  {
203  if( nOutWidth && (!m_nBorder || nOutWidth < m_nBorder) )
204  m_nBorder = nOutWidth;
205  }
206  else
207  {
208  if( nOutWidth && (!m_nInnerBorder || nOutWidth < m_nInnerBorder) )
209  m_nInnerBorder = nOutWidth;
210  }
211 
212  const sal_uInt16 nDist = pBorderLine->GetInWidth() ? pBorderLine->GetDistance()
213  : 0;
214  if( nDist && (!m_nCellSpacing || nDist < m_nCellSpacing) )
215  m_nCellSpacing = nDist;
216 }
217 
219  size_t const nRow, size_t const nCol,
220  sal_uInt16 nRowSpan, sal_uInt16 nColSpan,
221  sal_uInt16& rTopBorder,
222  sal_uInt16 &rBottomBorder )
223 {
224  sal_uInt16 nBorderMask = 0;
225 
226  const SwFrameFormat *pFrameFormat = pBox->GetFrameFormat();
227  const SvxBoxItem& rBoxItem = pFrameFormat->GetFormatAttr( RES_BOX );
228 
229  if( rBoxItem.GetTop() )
230  {
231  nBorderMask |= 1;
232  MergeBorders( rBoxItem.GetTop(), nRow==0 );
233  rTopBorder = rBoxItem.GetTop()->GetOutWidth();
234  }
235 
236  if( rBoxItem.GetLeft() )
237  {
238  nBorderMask |= 4;
239  MergeBorders( rBoxItem.GetLeft(), nCol==0 );
240  }
241 
242  if( rBoxItem.GetBottom() )
243  {
244  nBorderMask |= 2;
245  MergeBorders( rBoxItem.GetBottom(), nRow+nRowSpan==m_aRows.size() );
246  rBottomBorder = rBoxItem.GetBottom()->GetOutWidth();
247  }
248 
249  if( rBoxItem.GetRight() )
250  {
251  nBorderMask |= 8;
252  MergeBorders( rBoxItem.GetRight(), nCol+nColSpan==m_aCols.size() );
253  }
254 
255  // If any distance is set, the smallest one is used. This holds for
256  // the four distance of a box as well as for the distances of different
257  // boxes.
259  {
260  sal_uInt16 nDist = rBoxItem.GetDistance( SvxBoxItemLine::TOP );
261  if( nDist && (!m_nCellPadding || nDist < m_nCellPadding) )
262  m_nCellPadding = nDist;
263  nDist = rBoxItem.GetDistance( SvxBoxItemLine::BOTTOM );
264  if( nDist && (!m_nCellPadding || nDist < m_nCellPadding) )
265  m_nCellPadding = nDist;
266  nDist = rBoxItem.GetDistance( SvxBoxItemLine::LEFT );
267  if( nDist && (!m_nCellPadding || nDist < m_nCellPadding) )
268  m_nCellPadding = nDist;
269  nDist = rBoxItem.GetDistance( SvxBoxItemLine::RIGHT );
270  if( nDist && (!m_nCellPadding || nDist < m_nCellPadding) )
271  m_nCellPadding = nDist;
272  }
273 
274  return nBorderMask;
275 }
276 
277 sal_uInt32 SwWriteTable::GetRawWidth( sal_uInt16 nCol, sal_uInt16 nColSpan ) const
278 {
279  sal_uInt32 nWidth = m_aCols[nCol+nColSpan-1]->GetPos();
280  if( nCol > 0 )
281  nWidth = nWidth - m_aCols[nCol-1]->GetPos();
282 
283  return nWidth;
284 }
285 
286 sal_uInt16 SwWriteTable::GetLeftSpace( sal_uInt16 nCol ) const
287 {
288  sal_uInt16 nSpace = m_nCellPadding + m_nCellSpacing;
289 
290  // Additional subtract the line thickness in the first column.
291  if( nCol==0 )
292  {
293  nSpace = nSpace + m_nLeftSub;
294 
295  const SwWriteTableCol *pCol = m_aCols[nCol].get();
296  if( pCol->HasLeftBorder() )
297  nSpace = nSpace + m_nBorder;
298  }
299 
300  return nSpace;
301 }
302 
303 sal_uInt16
304 SwWriteTable::GetRightSpace(size_t const nCol, sal_uInt16 nColSpan) const
305 {
306  sal_uInt16 nSpace = m_nCellPadding;
307 
308  // Additional subtract in the last column CELLSPACING and
309  // line thickness once again.
310  if( nCol+nColSpan==m_aCols.size() )
311  {
312  nSpace += (m_nCellSpacing + m_nRightSub);
313 
314  const SwWriteTableCol *pCol = m_aCols[nCol+nColSpan-1].get();
315  if( pCol->HasRightBorder() )
316  nSpace = nSpace + m_nBorder;
317  }
318 
319  return nSpace;
320 }
321 
322 sal_uInt16 SwWriteTable::GetAbsWidth( sal_uInt16 nCol, sal_uInt16 nColSpan ) const
323 {
324  sal_uInt32 nWidth = GetRawWidth( nCol, nColSpan );
325  if( m_nBaseWidth != m_nTabWidth )
326  {
327  nWidth *= m_nTabWidth;
328  nWidth /= m_nBaseWidth;
329  }
330 
331  nWidth -= GetLeftSpace( nCol ) + GetRightSpace( nCol, nColSpan );
332 
333  OSL_ENSURE( nWidth > 0, "Column Width <= 0. OK?" );
334  return nWidth > 0 ? o3tl::narrowing<sal_uInt16>(nWidth) : 0;
335 }
336 
337 sal_uInt16 SwWriteTable::GetRelWidth( sal_uInt16 nCol, sal_uInt16 nColSpan ) const
338 {
339  tools::Long nWidth = GetRawWidth( nCol, nColSpan );
340 
341  return o3tl::narrowing<sal_uInt16>(static_cast<tools::Long>(Fraction( nWidth*256 + GetBaseWidth()/2,
342  GetBaseWidth() )));
343 }
344 
345 sal_uInt16 SwWriteTable::GetPercentWidth( sal_uInt16 nCol, sal_uInt16 nColSpan ) const
346 {
347  tools::Long nWidth = GetRawWidth( nCol, nColSpan );
348 
349  // Looks funny, but is nothing more than
350  // [(100 * nWidth) + .5] without rounding errors
351  return o3tl::narrowing<sal_uInt16>(static_cast<tools::Long>(Fraction( nWidth*100 + GetBaseWidth()/2,
352  GetBaseWidth() )));
353 }
354 
355 tools::Long SwWriteTable::GetAbsHeight(tools::Long nRawHeight, size_t const nRow,
356  sal_uInt16 nRowSpan ) const
357 {
358  nRawHeight -= (2*m_nCellPadding + m_nCellSpacing);
359 
360  // Additional subtract in the first column CELLSPACING and
361  // line thickness once again.
362  const SwWriteTableRow *pRow = nullptr;
363  if( nRow==0 )
364  {
365  nRawHeight -= m_nCellSpacing;
366  pRow = m_aRows[nRow].get();
367  if( pRow->HasTopBorder() )
368  nRawHeight -= m_nBorder;
369  }
370 
371  // Subtract the line thickness in the last column
372  if( nRow+nRowSpan==m_aRows.size() )
373  {
374  if( !pRow || nRowSpan > 1 )
375  pRow = m_aRows[nRow+nRowSpan-1].get();
376  if( pRow->HasBottomBorder() )
377  nRawHeight -= m_nBorder;
378  }
379 
380  OSL_ENSURE( nRawHeight > 0, "Row Height <= 0. OK?" );
381  return std::max<tools::Long>(nRawHeight, 0);
382 }
383 
384 bool SwWriteTable::ShouldExpandSub(const SwTableBox *pBox, bool /*bExpandedBefore*/,
385  sal_uInt16 nDepth) const
386 {
387  return !pBox->GetSttNd() && nDepth > 0;
388 }
389 
390 // FIXME: the degree of coupling between this method and
391 // FillTableRowsCols which is called immediately afterwards
392 // is -extremely- unpleasant and potentially problematic.
393 
395  sal_uInt32 nStartCPos,
396  tools::Long nParentLineHeight,
397  sal_uInt32 nParentLineWidth,
398  const SwTableLines& rLines,
399  sal_uInt16 nDepth )
400 {
401  bool bSubExpanded = false;
402  const SwTableLines::size_type nLines = rLines.size();
403 
404 #if OSL_DEBUG_LEVEL > 0
405  sal_uInt32 nEndCPos = 0;
406 #endif
407 
408  tools::Long nRPos = nStartRPos;
409  for( SwTableLines::size_type nLine = 0; nLine < nLines; ++nLine )
410  {
411  /*const*/ SwTableLine *pLine = rLines[nLine];
412 
413  tools::Long nOldRPos = nRPos;
414 
415  if( nLine < nLines-1 || nParentLineHeight==0 )
416  {
417  tools::Long nLineHeight = GetLineHeight( pLine );
418  nRPos += nLineHeight;
419  if( nParentLineHeight && nStartRPos + nParentLineHeight <= nRPos )
420  {
421  /* If you have corrupt line height information, e.g. breaking rows in complex table
422  layout, you may run into this robust code.
423  It's not allowed that subrows leaves their parentrow. If this would happen the line
424  height of subrow is reduced to a part of the remaining height */
425  OSL_FAIL( "Corrupt line height I" );
426  nRPos -= nLineHeight;
427  nLineHeight = nStartRPos + nParentLineHeight - nRPos; // remaining parent height
428  nLineHeight /= nLines - nLine; // divided through the number of remaining sub rows
429  nRPos += nLineHeight;
430  }
431  std::unique_ptr<SwWriteTableRow> pRow(new SwWriteTableRow( nRPos, m_bUseLayoutHeights));
432  m_aRows.insert( std::move(pRow) );
433  }
434  else
435  {
436 #if OSL_DEBUG_LEVEL > 0
437  tools::Long nCheckPos = nRPos + GetLineHeight( pLine );
438 #endif
439  nRPos = nStartRPos + nParentLineHeight;
440 #if OSL_DEBUG_LEVEL > 0
441  SwWriteTableRow aSrchRow( nRPos, m_bUseLayoutHeights );
442  OSL_ENSURE( std::find_if(m_aRows.begin(), m_aRows.end(),
443  [&](std::unique_ptr<SwWriteTableRow> const & p)
444  { return *p == aSrchRow; }) != m_aRows.end(), "Parent-Row not found" );
445  SwWriteTableRow aRowCheckPos(nCheckPos,m_bUseLayoutHeights);
446  SwWriteTableRow aRowRPos(nRPos,m_bUseLayoutHeights);
447  OSL_ENSURE( !m_bUseLayoutHeights ||
448  aRowCheckPos == aRowRPos,
449  "Height of the rows does not correspond with the parent" );
450 #endif
451  }
452 
453  // If necessary insert a column for all boxes of the row
454  const SwTableBoxes& rBoxes = pLine->GetTabBoxes();
455  const SwTableBoxes::size_type nBoxes = rBoxes.size();
456 
457  sal_uInt32 nCPos = nStartCPos;
458  for( SwTableBoxes::size_type nBox=0; nBox<nBoxes; ++nBox )
459  {
460  const SwTableBox *pBox = rBoxes[nBox];
461 
462  sal_uInt32 nOldCPos = nCPos;
463 
464  if( nBox < nBoxes-1 || (nParentLineWidth==0 && nLine==0) )
465  {
466  nCPos = nCPos + GetBoxWidth( pBox );
467  std::unique_ptr<SwWriteTableCol> pCol(new SwWriteTableCol( nCPos ));
468 
469  m_aCols.insert( std::move(pCol) );
470 
471  if( nBox==nBoxes-1 )
472  {
473  OSL_ENSURE( nLine==0 && nParentLineWidth==0,
474  "Now the parent width will be flattened!" );
475  nParentLineWidth = nCPos-nStartCPos;
476  }
477  }
478  else
479  {
480 #if OSL_DEBUG_LEVEL > 0
481  sal_uInt32 nCheckPos = nCPos + GetBoxWidth( pBox );
482  if( !nEndCPos )
483  {
484  nEndCPos = nCheckPos;
485  }
486  else
487  {
488  OSL_ENSURE( SwWriteTableCol(nCheckPos) ==
489  SwWriteTableCol(nEndCPos),
490  "Cell includes rows of different widths" );
491  }
492 #endif
493  nCPos = nStartCPos + nParentLineWidth;
494 
495 #if OSL_DEBUG_LEVEL > 0
496  SwWriteTableCol aSrchCol( nCPos );
497  OSL_ENSURE( m_aCols.find( &aSrchCol ) != m_aCols.end(),
498  "Parent-Cell not found" );
499  OSL_ENSURE( SwWriteTableCol(nCheckPos) ==
500  SwWriteTableCol(nCPos),
501  "Width of the cells does not correspond with the parent" );
502 #endif
503  }
504 
505  if( ShouldExpandSub( pBox, bSubExpanded, nDepth ) )
506  {
507  CollectTableRowsCols( nOldRPos, nOldCPos,
508  nRPos - nOldRPos,
509  nCPos - nOldCPos,
510  pBox->GetTabLines(),
511  nDepth-1 );
512  bSubExpanded = true;
513  }
514  }
515  }
516 }
517 
518 void SwWriteTable::FillTableRowsCols( tools::Long nStartRPos, sal_uInt16 nStartRow,
519  sal_uInt32 nStartCPos, sal_uInt16 nStartCol,
520  tools::Long nParentLineHeight,
521  sal_uInt32 nParentLineWidth,
522  const SwTableLines& rLines,
523  const SvxBrushItem* pParentBrush,
524  sal_uInt16 nDepth,
525  sal_uInt16 nNumOfHeaderRows )
526 {
527  const SwTableLines::size_type nLines = rLines.size();
528  bool bSubExpanded = false;
529 
530  // Specifying the border
531  tools::Long nRPos = nStartRPos;
532  sal_uInt16 nRow = nStartRow;
533 
534  for( SwTableLines::size_type nLine = 0; nLine < nLines; ++nLine )
535  {
536  const SwTableLine *pLine = rLines[nLine];
537 
538  // Determine the position of the last covered row
539  tools::Long nOldRPos = nRPos;
540  if( nLine < nLines-1 || nParentLineHeight==0 )
541  {
542  tools::Long nLineHeight = GetLineHeight( pLine );
543  nRPos += nLineHeight;
544  if( nParentLineHeight && nStartRPos + nParentLineHeight <= nRPos )
545  {
546  /* See comment in CollectTableRowCols */
547  OSL_FAIL( "Corrupt line height II" );
548  nRPos -= nLineHeight;
549  nLineHeight = nStartRPos + nParentLineHeight - nRPos; // remaining parent height
550  nLineHeight /= nLines - nLine; // divided through the number of remaining sub rows
551  nRPos += nLineHeight;
552  }
553  }
554  else
555  nRPos = nStartRPos + nParentLineHeight;
556 
557  // And their index
558  sal_uInt16 nOldRow = nRow;
559  SwWriteTableRow aSrchRow( nRPos,m_bUseLayoutHeights );
560  SwWriteTableRows::const_iterator it2 = std::find_if(m_aRows.begin(), m_aRows.end(),
561  [&](std::unique_ptr<SwWriteTableRow> const &p)
562  { return *p == aSrchRow; });
563 
564  // coupled methods out of sync ...
565  assert( it2 != m_aRows.end() );
566  nRow = it2 - m_aRows.begin();
567 
568  OSL_ENSURE( nOldRow <= nRow, "Don't look back!" );
569  if( nOldRow > nRow )
570  {
571  nOldRow = nRow;
572  if( nOldRow )
573  --nOldRow;
574  }
575 
576  SwWriteTableRow *pRow = m_aRows[nOldRow].get();
577  SwWriteTableRow *pEndRow = m_aRows[nRow].get();
578  if( nLine+1==nNumOfHeaderRows && nParentLineHeight==0 )
579  m_nHeadEndRow = nRow;
580 
581  const SwTableBoxes& rBoxes = pLine->GetTabBoxes();
582 
583  const SwFrameFormat *pLineFrameFormat = pLine->GetFrameFormat();
584  const SfxItemSet& rItemSet = pLineFrameFormat->GetAttrSet();
585 
586  tools::Long nHeight = 0;
587  if( const SwFormatFrameSize* pFrameSizeItem = rItemSet.GetItemIfSet( RES_FRM_SIZE ))
588  nHeight = pFrameSizeItem->GetHeight();
589 
590  const SvxBrushItem *pBrushItem, *pLineBrush = pParentBrush;
591  if( const SvxBrushItem* pTmpBrush = rItemSet.GetItemIfSet( RES_BACKGROUND, false ) )
592  {
593  pLineBrush = pTmpBrush;
594 
595  // If the row spans the entire table, we can
596  // print out the background to the row. Otherwise
597  // we have to print out into the cell.
598  bool bOutAtRow = !nParentLineWidth;
599  if( !bOutAtRow && nStartCPos==0 )
600  {
601  SwWriteTableCol aCol( nParentLineWidth );
602  bOutAtRow = m_aCols.find( &aCol ) == (m_aCols.end() - 1);
603  }
604  if( bOutAtRow )
605  {
606  pRow->SetBackground( pLineBrush );
607  pBrushItem = nullptr;
608  }
609  else
610  pBrushItem = pLineBrush;
611  }
612  else
613  {
614  pRow->SetBackground( pLineBrush );
615  pBrushItem = nullptr;
616  }
617 
618  const SwTableBoxes::size_type nBoxes = rBoxes.size();
619  sal_uInt32 nCPos = nStartCPos;
620  sal_uInt16 nCol = nStartCol;
621 
622  for( SwTableBoxes::size_type nBox=0; nBox<nBoxes; ++nBox )
623  {
624  const SwTableBox *pBox = rBoxes[nBox];
625 
626  // Determine the position of the last covered column
627  sal_uInt32 nOldCPos = nCPos;
628  if( nBox < nBoxes-1 || (nParentLineWidth==0 && nLine==0) )
629  {
630  nCPos = nCPos + GetBoxWidth( pBox );
631  if( nBox==nBoxes-1 )
632  nParentLineWidth = nCPos - nStartCPos;
633  }
634  else
635  nCPos = nStartCPos + nParentLineWidth;
636 
637  // And their index
638  sal_uInt16 nOldCol = nCol;
639  SwWriteTableCol aSrchCol( nCPos );
641  OSL_ENSURE( it != m_aCols.end(), "missing column" );
642  if(it != m_aCols.end())
643  {
644  // if find fails for some nCPos value then it used to set nCol value with size of aCols.
645  nCol = it - m_aCols.begin();
646  }
647 
648  if( !ShouldExpandSub( pBox, bSubExpanded, nDepth ) )
649  {
650  sal_uInt16 nRowSpan = nRow - nOldRow + 1;
651 
652  // The new table model may have true row span attributes
653  const sal_Int32 nAttrRowSpan = pBox->getRowSpan();
654  if ( 1 < nAttrRowSpan )
655  nRowSpan = o3tl::narrowing<sal_uInt16>(nAttrRowSpan);
656  else if ( nAttrRowSpan < 1 )
657  nRowSpan = 0;
658 
659  SAL_WARN_IF(nCol < nOldCol, "sw.filter", "unexpected " << nCol << " < " << nOldCol);
660  sal_uInt16 nColSpan = nCol >= nOldCol ? nCol - nOldCol + 1 : 1;
661  pRow->AddCell( pBox, nOldRow, nOldCol,
662  nRowSpan, nColSpan, nHeight,
663  pBrushItem );
664  nHeight = 0; // The height requires only to be written once
665 
666  if( pBox->GetSttNd() )
667  {
668  sal_uInt16 nTopBorder = USHRT_MAX, nBottomBorder = USHRT_MAX;
669  sal_uInt16 nBorderMask = MergeBoxBorders(pBox, nOldRow, nOldCol,
670  nRowSpan, nColSpan, nTopBorder, nBottomBorder);
671 
672  // #i30094# add a sanity check here to ensure that
673  // we don't access an invalid aCols[] as &nCol
674  // above can be changed.
675  if (!(nBorderMask & 4) && nOldCol < m_aCols.size())
676  {
677  SwWriteTableCol *pCol = m_aCols[nOldCol].get();
678  OSL_ENSURE(pCol, "No TableCol found, panic!");
679  if (pCol)
680  pCol->m_bLeftBorder = false;
681  }
682 
683  if (!(nBorderMask & 8))
684  {
685  SwWriteTableCol *pCol = m_aCols[nCol].get();
686  OSL_ENSURE(pCol, "No TableCol found, panic!");
687  if (pCol)
688  pCol->m_bRightBorder = false;
689  }
690 
691  if (!(nBorderMask & 1))
692  pRow->m_bTopBorder = false;
693  else if (!pRow->m_nTopBorder || nTopBorder < pRow->m_nTopBorder)
694  pRow->m_nTopBorder = nTopBorder;
695 
696  if (!(nBorderMask & 2))
697  pEndRow->m_bBottomBorder = false;
698  else if (
699  !pEndRow->m_nBottomBorder ||
700  nBottomBorder < pEndRow->m_nBottomBorder
701  )
702  {
703  pEndRow->m_nBottomBorder = nBottomBorder;
704  }
705  }
706  }
707  else
708  {
709  FillTableRowsCols( nOldRPos, nOldRow, nOldCPos, nOldCol,
710  nRPos-nOldRPos, nCPos-nOldCPos,
711  pBox->GetTabLines(),
712  pLineBrush, nDepth-1,
713  nNumOfHeaderRows );
714  bSubExpanded = true;
715  }
716 
717  nCol++; // The next cell begins in the next column
718  }
719 
720  nRow++;
721  }
722 }
723 
724 SwWriteTable::SwWriteTable(const SwTable* pTable, const SwTableLines& rLines, tools::Long nWidth,
725  sal_uInt32 nBWidth, bool bRel, sal_uInt16 nMaxDepth, sal_uInt16 nLSub, sal_uInt16 nRSub, sal_uInt32 nNumOfRowsToRepeat)
726  : m_pTable(pTable), m_nBorderColor(ColorTransparency, sal_uInt32(-1)), m_nCellSpacing(0), m_nCellPadding(0), m_nBorder(0),
727  m_nInnerBorder(0), m_nBaseWidth(nBWidth), m_nHeadEndRow(USHRT_MAX),
728  m_nLeftSub(nLSub), m_nRightSub(nRSub), m_nTabWidth(nWidth), m_bRelWidths(bRel),
729  m_bUseLayoutHeights(true),
730 #ifdef DBG_UTIL
731  m_bGetLineHeightCalled(false),
732 #endif
733  m_bColTags(true), m_bLayoutExport(false),
734  m_bCollectBorderWidth(true)
735 {
736  sal_uInt32 nParentWidth = m_nBaseWidth + m_nLeftSub + m_nRightSub;
737 
738  // First the table structure set. Behind the table is in each
739  // case the end of a column
740  std::unique_ptr<SwWriteTableCol> pCol(new SwWriteTableCol( nParentWidth ));
741  m_aCols.insert( std::move(pCol) );
742  m_bUseLayoutHeights = true;
743  CollectTableRowsCols( 0, 0, 0, nParentWidth, rLines, nMaxDepth - 1 );
744 
745  // FIXME: awfully GetLineHeight writes to this in its first call
746  // and proceeds to return a rather odd number fdo#62336, we have to
747  // behave identically since the code in FillTableRowsCols duplicates
748  // and is highly coupled to CollectTableRowsCols - sadly.
749  m_bUseLayoutHeights = true;
750  // And now fill with life
751  FillTableRowsCols( 0, 0, 0, 0, 0, nParentWidth, rLines, nullptr, nMaxDepth - 1, static_cast< sal_uInt16 >(nNumOfRowsToRepeat) );
752 
753  // Adjust some Twip values to pixel boundaries
754  if( !m_nBorder )
756 }
757 
758 SwWriteTable::SwWriteTable(const SwTable* pTable, const SwHTMLTableLayout *pLayoutInfo)
759  : m_pTable(pTable), m_nBorderColor(ColorTransparency, sal_uInt32(-1)), m_nCellSpacing(0), m_nCellPadding(0), m_nBorder(0),
760  m_nInnerBorder(0), m_nBaseWidth(pLayoutInfo->GetWidthOption()), m_nHeadEndRow(0),
761  m_nLeftSub(0), m_nRightSub(0), m_nTabWidth(pLayoutInfo->GetWidthOption()),
762  m_bRelWidths(pLayoutInfo->HasPercentWidthOption()), m_bUseLayoutHeights(false),
763 #ifdef DBG_UTIL
764  m_bGetLineHeightCalled(false),
765 #endif
766  m_bColTags(pLayoutInfo->HasColTags()), m_bLayoutExport(true),
767  m_bCollectBorderWidth(pLayoutInfo->HaveBordersChanged())
768 {
769  if( !m_bCollectBorderWidth )
770  {
771  m_nBorder = pLayoutInfo->GetBorder();
772  m_nCellPadding = pLayoutInfo->GetCellPadding();
773  m_nCellSpacing = pLayoutInfo->GetCellSpacing();
774  }
775 
776  const sal_uInt16 nCols = pLayoutInfo->GetColCount();
777  const sal_uInt16 nRows = pLayoutInfo->GetRowCount();
778 
779  // First set the table structure.
780  for( sal_uInt16 nCol=0; nCol<nCols; ++nCol )
781  {
782  std::unique_ptr<SwWriteTableCol> pCol(
783  new SwWriteTableCol( (nCol+1)*COL_DFLT_WIDTH ));
784 
785  if( m_bColTags )
786  {
787  const SwHTMLTableLayoutColumn *pLayoutCol =
788  pLayoutInfo->GetColumn( nCol );
789  pCol->SetWidthOpt( pLayoutCol->GetWidthOption(),
790  pLayoutCol->IsRelWidthOption() );
791  }
792 
793  m_aCols.insert( std::move(pCol) );
794  }
795 
796  for( sal_uInt16 nRow=0; nRow<nRows; ++nRow )
797  {
798  std::unique_ptr<SwWriteTableRow> pRow(
800  pRow->m_nTopBorder = 0;
801  pRow->m_nBottomBorder = 0;
802  m_aRows.insert( std::move(pRow) );
803  }
804 
805  // And now fill with life
806  for( sal_uInt16 nRow=0; nRow<nRows; ++nRow )
807  {
808  SwWriteTableRow *pRow = m_aRows[nRow].get();
809 
810  bool bHeightExported = false;
811  for( sal_uInt16 nCol=0; nCol<nCols; nCol++ )
812  {
813  const SwHTMLTableLayoutCell *pLayoutCell =
814  pLayoutInfo->GetCell( nRow, nCol );
815 
816  const SwHTMLTableLayoutCnts *pLayoutCnts =
817  pLayoutCell->GetContents().get();
818 
819  // The cell begins actually a row above or further forward?
820  if( ( nRow>0 && pLayoutCnts == pLayoutInfo->GetCell(nRow-1,nCol)
821  ->GetContents().get() ) ||
822  ( nCol>0 && pLayoutCnts == pLayoutInfo->GetCell(nRow,nCol-1)
823  ->GetContents().get() ) )
824  {
825  continue;
826  }
827 
828  const sal_uInt16 nRowSpan = pLayoutCell->GetRowSpan();
829  const sal_uInt16 nColSpan = pLayoutCell->GetColSpan();
830  const SwTableBox *pBox = pLayoutCnts->GetTableBox();
831  OSL_ENSURE( pBox,
832  "Table in Table can not be exported over layout" );
833 
834  tools::Long nHeight = bHeightExported ? 0 : GetLineHeight( pBox );
835  const SvxBrushItem *pBrushItem = GetLineBrush( pBox, pRow );
836 
837  SwWriteTableCell *pCell =
838  pRow->AddCell( pBox, nRow, nCol, nRowSpan, nColSpan,
839  nHeight, pBrushItem );
840  pCell->SetWidthOpt( pLayoutCell->GetWidthOption(),
841  pLayoutCell->IsPercentWidthOption() );
842 
843  sal_uInt16 nTopBorder = USHRT_MAX, nBottomBorder = USHRT_MAX;
844  sal_uInt16 nBorderMask =
845  MergeBoxBorders( pBox, nRow, nCol, nRowSpan, nColSpan,
846  nTopBorder, nBottomBorder );
847 
848  SwWriteTableCol *pCol = m_aCols[nCol].get();
849  if( !(nBorderMask & 4) )
850  pCol->m_bLeftBorder = false;
851 
852  pCol = m_aCols[nCol+nColSpan-1].get();
853  if( !(nBorderMask & 8) )
854  pCol->m_bRightBorder = false;
855 
856  if( !(nBorderMask & 1) )
857  pRow->m_bTopBorder = false;
858 
859  SwWriteTableRow *pEndRow = m_aRows[nRow+nRowSpan-1].get();
860  if( !(nBorderMask & 2) )
861  pEndRow->m_bBottomBorder = false;
862 
863  // The height requires only to be written once
864  if( nHeight )
865  bHeightExported = true;
866  }
867  }
868 
869  // Adjust some Twip values to pixel boundaries
872 }
873 
875 {
876 }
877 
878 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
std::vector< SwTableLine * >::size_type size_type
Definition: swtable.hxx:68
SwTwips GetTableLineHeight(bool &bLayoutAvailable) const
Definition: swtable.cxx:1526
sal_uInt16 GetCellPadding() const
Definition: htmltbl.hxx:325
void CollectTableRowsCols(tools::Long nStartRPos, sal_uInt32 nStartCPos, tools::Long nParentLineHeight, sal_uInt32 nParentLineWidth, const SwTableLines &rLines, sal_uInt16 nDepth)
Definition: wrtswtbl.cxx:394
bool HasRightBorder() const
Definition: wrtswtbl.hxx:176
virtual bool ShouldExpandSub(const SwTableBox *pBox, bool bExpandedBefore, sal_uInt16 nDepth) const
Definition: wrtswtbl.cxx:384
const T * GetItemIfSet(TypedWhichId< T > nWhich, bool bSrchInParent=true) const
size_t m_nPos
sal_uInt16 GetLeftSpace(sal_uInt16 nCol) const
Definition: wrtswtbl.cxx:286
void SetWidthOpt(sal_uInt16 nWidth, bool bPercent)
Definition: wrtswtbl.hxx:86
sal_uInt32 GetRawWidth(sal_uInt16 nCol, sal_uInt16 nColSpan) const
Definition: wrtswtbl.cxx:277
sal_uInt32 m_nTabWidth
Definition: wrtswtbl.hxx:236
sal_uInt16 m_nInnerBorder
Definition: wrtswtbl.hxx:228
constexpr TypedWhichId< SwFormatFrameSize > RES_FRM_SIZE(89)
long Long
SwTableBox * GetTableBox() const
Definition: htmltbl.hxx:65
sal_uInt16 GetDistance(SvxBoxItemLine nLine) const
static sal_uInt32 GetBoxWidth(const SwTableBox *pBox)
Definition: wrtswtbl.cxx:82
const_iterator find(const Value &x) const
SwTableLine is one table row in the document model.
Definition: swtable.hxx:357
sal_uInt16 GetBorder() const
Definition: htmltbl.hxx:327
sal_uInt16 m_nLeftSub
Definition: wrtswtbl.hxx:233
const editeng::SvxBorderLine * GetRight() const
sal_uInt16 GetRelWidth(sal_uInt16 nCol, sal_uInt16 nColSpan) const
Definition: wrtswtbl.cxx:337
size_type size() const
Definition: swtable.hxx:76
sal_uInt16 MergeBoxBorders(const SwTableBox *pBox, size_t nRow, size_t nCol, sal_uInt16 nRowSpan, sal_uInt16 nColSpan, sal_uInt16 &rTopBorder, sal_uInt16 &rBottomBorder)
Definition: wrtswtbl.cxx:218
sal_Int32 getRowSpan() const
Definition: swtable.cxx:77
constexpr tools::Long Width() const
constexpr TypedWhichId< SwFormatVertOrient > RES_VERT_ORIENT(102)
sal_uInt32 GetBaseWidth() const
Definition: wrtswtbl.hxx:272
bool HasTopBorder() const
Definition: wrtswtbl.hxx:132
sal_uInt16 GetColSpan() const
Definition: htmltbl.hxx:110
sal_uInt16 GetOutWidth() const
sal_uInt16 GetAbsWidth(sal_uInt16 nCol, sal_uInt16 nColSpan) const
Definition: wrtswtbl.cxx:322
sal_uInt16 m_nBottomBorder
Definition: wrtswtbl.hxx:113
sal_uInt16 GetRowCount() const
Definition: htmltbl.hxx:329
const SvxBrushItem * GetBackground() const
Definition: wrtswtbl.hxx:130
sal_uInt16 GetWidthOption() const
Definition: htmltbl.hxx:144
sal_uInt16 GetColCount() const
Definition: htmltbl.hxx:330
size_type size() const
sal_uInt16 GetPercentWidth(sal_uInt16 nCol, sal_uInt16 nColSpan) const
Definition: wrtswtbl.cxx:345
bool HasLeftBorder() const
Definition: wrtswtbl.hxx:174
sal_Int16 GetVertOri() const
Definition: wrtswtbl.cxx:38
sal_uInt16 m_nCellSpacing
Definition: wrtswtbl.hxx:224
sal_uInt16 m_nTopBorder
Definition: wrtswtbl.hxx:112
SwWriteTableCells m_Cells
all cells of the rows
Definition: wrtswtbl.hxx:99
const editeng::SvxBorderLine * GetTop() const
SwWriteTableCell * AddCell(const SwTableBox *pBox, sal_uInt16 nRow, sal_uInt16 nCol, sal_uInt16 nRowSpan, sal_uInt16 nColSpan, tools::Long nHeight, const SvxBrushItem *pBackground)
Definition: wrtswtbl.cxx:62
SwHTMLTableLayoutCell * GetCell(sal_uInt16 nRow, sal_uInt16 nCol) const
Definition: htmltbl.hxx:415
Style of a layout element.
Definition: frmfmt.hxx:59
bool IsPercentWidthOption() const
Definition: htmltbl.hxx:113
const editeng::SvxBorderLine * GetLeft() const
bool IsRelWidthOption() const
Definition: htmltbl.hxx:145
static const SvxBrushItem * GetLineBrush(const SwTableBox *pBox, SwWriteTableRow *pRow)
Definition: wrtswtbl.cxx:159
tools::Long GetAbsHeight(tools::Long nRawWidth, size_t nRow, sal_uInt16 nRowSpan) const
Definition: wrtswtbl.cxx:355
sal_uInt16 m_nCellPadding
Definition: wrtswtbl.hxx:225
const ::std::vector< Color > ImpSvNumberformatScan::StandardColor COL_GRAY
const SwTableBox * m_pBox
Definition: wrtswtbl.hxx:49
const std::shared_ptr< SwHTMLTableLayoutCnts > & GetContents() const
Definition: htmltbl.hxx:103
SwFrameFormat * GetFrameFormat()
Definition: swtable.hxx:380
SwFrameFormat * GetFrameFormat()
Definition: swtable.hxx:457
ColorTransparency
const_iterator end() const
void SetBackground(const SvxBrushItem *pBGround)
Definition: wrtswtbl.hxx:126
const SwFormatVertOrient & GetVertOrient(bool=true) const
Definition: fmtornt.hxx:101
SwTable is one table in the document model, containing rows (which contain cells).
Definition: swtable.hxx:112
SwTableLines & GetTabLines()
Definition: swtable.hxx:450
const_iterator begin() const
SwWriteTableCols m_aCols
Definition: wrtswtbl.hxx:219
bool m_bCollectBorderWidth
Definition: wrtswtbl.hxx:246
SwTableBoxes & GetTabBoxes()
Definition: swtable.hxx:368
std::vector< SwTableBox * > SwTableBoxes
Definition: swtable.hxx:105
const SwStartNode * GetSttNd() const
Definition: swtable.hxx:471
sal_uInt16 GetCellSpacing() const
Definition: htmltbl.hxx:326
constexpr TypedWhichId< SvxBrushItem > RES_BACKGROUND(105)
#define SAL_WARN_IF(condition, area, stream)
SwWriteTableRow(const SwWriteTableRow &)
SwWriteTableRows m_aRows
Definition: wrtswtbl.hxx:220
Color m_nBorderColor
Definition: wrtswtbl.hxx:222
SwWriteTableCol(sal_uInt32 nPosition)
Definition: wrtswtbl.cxx:76
#define ROW_DFLT_HEIGHT
Definition: wrtswtbl.hxx:45
void MergeBorders(const editeng::SvxBorderLine *pBorderLine, bool bTable)
Definition: wrtswtbl.cxx:188
bool m_bUseLayoutHeights
Definition: wrtswtbl.hxx:239
bool HasBottomBorder() const
Definition: wrtswtbl.hxx:133
void FillTableRowsCols(tools::Long nStartRPos, sal_uInt16 nStartRow, sal_uInt32 nStartCPos, sal_uInt16 nStartCol, tools::Long nParentLineHeight, sal_uInt32 nParentLineWidth, const SwTableLines &rLines, const SvxBrushItem *pLineBrush, sal_uInt16 nDepth, sal_uInt16 nNumOfHeaderRows)
Definition: wrtswtbl.cxx:518
sal_uInt16 GetRightSpace(size_t nCol, sal_uInt16 nColSpan) const
Definition: wrtswtbl.cxx:304
SwTableBox is one table cell in the document model.
Definition: swtable.hxx:418
void * p
const SfxPoolItem & GetFormatAttr(sal_uInt16 nWhich, bool bInParents=true) const
If bInParents is FALSE, search only in this format for attribute.
Definition: format.cxx:367
virtual ~SwWriteTable()
Definition: wrtswtbl.cxx:874
sal_uInt16 GetRowSpan() const
Definition: htmltbl.hxx:109
SvxBoxItem & rBoxItem
constexpr TypedWhichId< SvxBoxItem > RES_BOX(106)
sal_uInt16 m_nRightSub
Definition: wrtswtbl.hxx:234
SwTableBox * GetUpper()
Definition: swtable.hxx:376
tools::Long GetLineHeight(const SwTableLine *pLine)
Definition: wrtswtbl.cxx:91
bool m_bGetLineHeightCalled
Definition: wrtswtbl.hxx:241
const SwAttrSet & GetAttrSet() const
For querying the attribute array.
Definition: format.hxx:136
SwHTMLTableLayoutColumn * GetColumn(sal_uInt16 nCol) const
Definition: htmltbl.hxx:399
sal_uInt16 GetWidthOption() const
Definition: htmltbl.hxx:112
std::pair< const_iterator, bool > insert(Value &&x)
sal_uInt16 m_nBorder
Definition: wrtswtbl.hxx:227
SwTableLine * GetUpper()
Definition: swtable.hxx:453
bool m_bColTags
Definition: wrtswtbl.hxx:244
SwWriteTable(const SwTable *pTable, const SwTableLines &rLines, tools::Long nWidth, sal_uInt32 nBWidth, bool bRel, sal_uInt16 nMaxDepth=USHRT_MAX, sal_uInt16 nLeftSub=0, sal_uInt16 nRightSub=0, sal_uInt32 nNumOfRowsToRepeat=0)
Definition: wrtswtbl.cxx:724
const editeng::SvxBorderLine * GetBottom() const
sal_uInt16 m_nHeadEndRow
Definition: wrtswtbl.hxx:231
const Size & GetSize() const
std::vector< std::unique_ptr< SwWriteTableRow > >::const_iterator const_iterator
sal_uInt32 m_nBaseWidth
Definition: wrtswtbl.hxx:229
bool m_bBottomBorder
Definition: wrtswtbl.hxx:116
#define COL_DFLT_WIDTH
Definition: wrtswtbl.hxx:44
bool m_bDetectedRangeSegmentation false