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