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