Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / sw / source / filter / writer / wrtswtbl.cxx
blob1c4e43e35c8fae289d15f05add0a204726f24def
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
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>
35 using ::editeng::SvxBorderLine;
36 using namespace ::com::sun::star;
38 sal_Int16 SwWriteTableCell::GetVertOri() const
40 sal_Int16 eCellVertOri = text::VertOrientation::TOP;
41 if( m_pBox->GetSttNd() )
43 const SfxItemSet& rItemSet = m_pBox->GetFrameFormat()->GetAttrSet();
44 if( const SwFormatVertOrient *pItem = rItemSet.GetItemIfSet( RES_VERT_ORIENT, false ) )
46 sal_Int16 eBoxVertOri = pItem->GetVertOrient();
47 if( text::VertOrientation::CENTER==eBoxVertOri || text::VertOrientation::BOTTOM==eBoxVertOri)
48 eCellVertOri = eBoxVertOri;
52 return eCellVertOri;
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)
62 SwWriteTableCell *SwWriteTableRow::AddCell( const SwTableBox *pBox,
63 sal_uInt16 nRow, sal_uInt16 nCol,
64 sal_uInt16 nRowSpan, sal_uInt16 nColSpan,
65 tools::Long nHeight,
66 const SvxBrushItem *pBackgroundBrush )
68 SwWriteTableCell *pCell =
69 new SwWriteTableCell( pBox, nRow, nCol, nRowSpan, nColSpan,
70 nHeight, pBackgroundBrush );
71 m_Cells.push_back(std::unique_ptr<SwWriteTableCell>(pCell));
73 return pCell;
76 SwWriteTableCol::SwWriteTableCol(sal_uInt32 nPosition)
77 : m_nPos(nPosition), m_nWidthOpt(0), m_bRelWidthOpt(false),
78 m_bLeftBorder(true), m_bRightBorder(true)
82 sal_uInt32 SwWriteTable::GetBoxWidth( const SwTableBox *pBox )
84 const SwFrameFormat *pFormat = pBox->GetFrameFormat();
85 const SwFormatFrameSize& aFrameSize=
86 pFormat->GetFormatAttr( RES_FRM_SIZE );
88 return sal::static_int_cast<sal_uInt32>(aFrameSize.GetSize().Width());
91 tools::Long SwWriteTable::GetLineHeight( const SwTableLine *pLine )
93 #ifdef DBG_UTIL
94 bool bOldGetLineHeightCalled = m_bGetLineHeightCalled;
95 m_bGetLineHeightCalled = true;
96 #endif
98 tools::Long nHeight = 0;
99 if( m_bUseLayoutHeights )
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;
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;
113 #ifdef DBG_UTIL
114 SAL_WARN_IF( !bLayoutAvailable && bOldGetLineHeightCalled, "sw", "Layout invalid?" );
115 #endif
118 const SwTableBoxes& rBoxes = pLine->GetTabBoxes();
119 for( auto pBox : rBoxes )
121 if( pBox->GetSttNd() )
123 if( nHeight < ROW_DFLT_HEIGHT )
124 nHeight = ROW_DFLT_HEIGHT;
126 else
128 tools::Long nTmp = 0;
129 const SwTableLines &rLines = pBox->GetTabLines();
130 for( size_t nLine=0; nLine<rLines.size(); nLine++ )
132 nTmp += GetLineHeight( rLines[nLine] );
134 if( nHeight < nTmp )
135 nHeight = nTmp;
139 return nHeight;
142 tools::Long SwWriteTable::GetLineHeight( const SwTableBox *pBox )
144 const SwTableLine *pLine = pBox->GetUpper();
146 if( !pLine )
147 return 0;
149 const SwFrameFormat *pLineFrameFormat = pLine->GetFrameFormat();
150 const SfxItemSet& rItemSet = pLineFrameFormat->GetAttrSet();
152 tools::Long nHeight = 0;
153 if( const SwFormatFrameSize* pItem = rItemSet.GetItemIfSet( RES_FRM_SIZE ) )
154 nHeight = pItem->GetHeight();
156 return nHeight;
159 const SvxBrushItem *SwWriteTable::GetLineBrush( const SwTableBox *pBox,
160 SwWriteTableRow *pRow )
162 const SwTableLine *pLine = pBox->GetUpper();
164 while( pLine )
166 const SwFrameFormat *pLineFrameFormat = pLine->GetFrameFormat();
167 const SfxItemSet& rItemSet = pLineFrameFormat->GetAttrSet();
169 if( const SvxBrushItem* pItem = rItemSet.GetItemIfSet( RES_BACKGROUND, false ) )
171 if( !pLine->GetUpper() )
173 if( !pRow->GetBackground() )
174 pRow->SetBackground( pItem );
175 pItem = nullptr;
178 return pItem;
181 pBox = pLine->GetUpper();
182 pLine = pBox ? pBox->GetUpper() : nullptr;
185 return nullptr;
188 void SwWriteTable::MergeBorders( const SvxBorderLine* pBorderLine,
189 bool bTable )
191 if( Color(ColorTransparency, 0xffffffff) == m_nBorderColor )
193 if( !pBorderLine->GetColor().IsRGBEqual( COL_GRAY ) )
194 m_nBorderColor = pBorderLine->GetColor();
197 if( !m_bCollectBorderWidth )
198 return;
200 const sal_uInt16 nOutWidth = pBorderLine->GetOutWidth();
201 if( bTable )
203 if( nOutWidth && (!m_nBorder || nOutWidth < m_nBorder) )
204 m_nBorder = nOutWidth;
206 else
208 if( nOutWidth && (!m_nInnerBorder || nOutWidth < m_nInnerBorder) )
209 m_nInnerBorder = nOutWidth;
212 const sal_uInt16 nDist = pBorderLine->GetInWidth() ? pBorderLine->GetDistance()
213 : 0;
214 if( nDist && (!m_nCellSpacing || nDist < m_nCellSpacing) )
215 m_nCellSpacing = nDist;
218 sal_uInt16 SwWriteTable::MergeBoxBorders( const SwTableBox *pBox,
219 size_t const nRow, size_t const nCol,
220 sal_uInt16 nRowSpan, sal_uInt16 nColSpan,
221 sal_uInt16& rTopBorder,
222 sal_uInt16 &rBottomBorder )
224 sal_uInt16 nBorderMask = 0;
226 const SwFrameFormat *pFrameFormat = pBox->GetFrameFormat();
227 const SvxBoxItem& rBoxItem = pFrameFormat->GetFormatAttr( RES_BOX );
229 if( rBoxItem.GetTop() )
231 nBorderMask |= 1;
232 MergeBorders( rBoxItem.GetTop(), nRow==0 );
233 rTopBorder = rBoxItem.GetTop()->GetOutWidth();
236 if( rBoxItem.GetLeft() )
238 nBorderMask |= 4;
239 MergeBorders( rBoxItem.GetLeft(), nCol==0 );
242 if( rBoxItem.GetBottom() )
244 nBorderMask |= 2;
245 MergeBorders( rBoxItem.GetBottom(), nRow+nRowSpan==m_aRows.size() );
246 rBottomBorder = rBoxItem.GetBottom()->GetOutWidth();
249 if( rBoxItem.GetRight() )
251 nBorderMask |= 8;
252 MergeBorders( rBoxItem.GetRight(), nCol+nColSpan==m_aCols.size() );
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.
258 if( m_bCollectBorderWidth )
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;
274 return nBorderMask;
277 sal_uInt32 SwWriteTable::GetRawWidth( sal_uInt16 nCol, sal_uInt16 nColSpan ) const
279 sal_uInt32 nWidth = m_aCols[nCol+nColSpan-1]->GetPos();
280 if( nCol > 0 )
281 nWidth = nWidth - m_aCols[nCol-1]->GetPos();
283 return nWidth;
286 sal_uInt16 SwWriteTable::GetLeftSpace( sal_uInt16 nCol ) const
288 sal_uInt16 nSpace = m_nCellPadding + m_nCellSpacing;
290 // Additional subtract the line thickness in the first column.
291 if( nCol==0 )
293 nSpace = nSpace + m_nLeftSub;
295 const SwWriteTableCol *pCol = m_aCols[nCol].get();
296 if( pCol->HasLeftBorder() )
297 nSpace = nSpace + m_nBorder;
300 return nSpace;
303 sal_uInt16
304 SwWriteTable::GetRightSpace(size_t const nCol, sal_uInt16 nColSpan) const
306 sal_uInt16 nSpace = m_nCellPadding;
308 // Additional subtract in the last column CELLSPACING and
309 // line thickness once again.
310 if( nCol+nColSpan==m_aCols.size() )
312 nSpace += (m_nCellSpacing + m_nRightSub);
314 const SwWriteTableCol *pCol = m_aCols[nCol+nColSpan-1].get();
315 if( pCol->HasRightBorder() )
316 nSpace = nSpace + m_nBorder;
319 return nSpace;
322 sal_uInt16 SwWriteTable::GetAbsWidth( sal_uInt16 nCol, sal_uInt16 nColSpan ) const
324 sal_uInt32 nWidth = GetRawWidth( nCol, nColSpan );
325 if( m_nBaseWidth != m_nTabWidth )
327 nWidth *= m_nTabWidth;
328 nWidth /= m_nBaseWidth;
331 nWidth -= GetLeftSpace( nCol ) + GetRightSpace( nCol, nColSpan );
333 OSL_ENSURE( nWidth > 0, "Column Width <= 0. OK?" );
334 return nWidth > 0 ? o3tl::narrowing<sal_uInt16>(nWidth) : 0;
337 sal_uInt16 SwWriteTable::GetRelWidth( sal_uInt16 nCol, sal_uInt16 nColSpan ) const
339 tools::Long nWidth = GetRawWidth( nCol, nColSpan );
341 return o3tl::narrowing<sal_uInt16>(static_cast<tools::Long>(Fraction( nWidth*256 + GetBaseWidth()/2,
342 GetBaseWidth() )));
345 sal_uInt16 SwWriteTable::GetPercentWidth( sal_uInt16 nCol, sal_uInt16 nColSpan ) const
347 tools::Long nWidth = GetRawWidth( nCol, nColSpan );
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() )));
355 tools::Long SwWriteTable::GetAbsHeight(tools::Long nRawHeight, size_t const nRow,
356 sal_uInt16 nRowSpan ) const
358 nRawHeight -= (2*m_nCellPadding + m_nCellSpacing);
360 // Additional subtract in the first column CELLSPACING and
361 // line thickness once again.
362 const SwWriteTableRow *pRow = nullptr;
363 if( nRow==0 )
365 nRawHeight -= m_nCellSpacing;
366 pRow = m_aRows[nRow].get();
367 if( pRow->HasTopBorder() )
368 nRawHeight -= m_nBorder;
371 // Subtract the line thickness in the last column
372 if( nRow+nRowSpan==m_aRows.size() )
374 if( !pRow || nRowSpan > 1 )
375 pRow = m_aRows[nRow+nRowSpan-1].get();
376 if( pRow->HasBottomBorder() )
377 nRawHeight -= m_nBorder;
380 OSL_ENSURE( nRawHeight > 0, "Row Height <= 0. OK?" );
381 return std::max<tools::Long>(nRawHeight, 0);
384 bool SwWriteTable::ShouldExpandSub(const SwTableBox *pBox, bool /*bExpandedBefore*/,
385 sal_uInt16 nDepth) const
387 return !pBox->GetSttNd() && nDepth > 0;
390 // FIXME: the degree of coupling between this method and
391 // FillTableRowsCols which is called immediately afterwards
392 // is -extremely- unpleasant and potentially problematic.
394 void SwWriteTable::CollectTableRowsCols( tools::Long nStartRPos,
395 sal_uInt32 nStartCPos,
396 tools::Long nParentLineHeight,
397 sal_uInt32 nParentLineWidth,
398 const SwTableLines& rLines,
399 sal_uInt16 nDepth )
401 bool bSubExpanded = false;
402 const SwTableLines::size_type nLines = rLines.size();
404 #if OSL_DEBUG_LEVEL > 0
405 sal_uInt32 nEndCPos = 0;
406 #endif
408 tools::Long nRPos = nStartRPos;
409 for( SwTableLines::size_type nLine = 0; nLine < nLines; ++nLine )
411 /*const*/ SwTableLine *pLine = rLines[nLine];
413 tools::Long nOldRPos = nRPos;
415 if( nLine < nLines-1 || nParentLineHeight==0 )
417 tools::Long nLineHeight = GetLineHeight( pLine );
418 nRPos += nLineHeight;
419 if( nParentLineHeight && nStartRPos + nParentLineHeight <= nRPos )
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;
431 std::unique_ptr<SwWriteTableRow> pRow(new SwWriteTableRow( nRPos, m_bUseLayoutHeights));
432 m_aRows.insert( std::move(pRow) );
434 else
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
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();
457 sal_uInt32 nCPos = nStartCPos;
458 for( SwTableBoxes::size_type nBox=0; nBox<nBoxes; ++nBox )
460 const SwTableBox *pBox = rBoxes[nBox];
462 sal_uInt32 nOldCPos = nCPos;
464 if( nBox < nBoxes-1 || (nParentLineWidth==0 && nLine==0) )
466 nCPos = nCPos + GetBoxWidth( pBox );
467 std::unique_ptr<SwWriteTableCol> pCol(new SwWriteTableCol( nCPos ));
469 m_aCols.insert( std::move(pCol) );
471 if( nBox==nBoxes-1 )
473 OSL_ENSURE( nLine==0 && nParentLineWidth==0,
474 "Now the parent width will be flattened!" );
475 nParentLineWidth = nCPos-nStartCPos;
478 else
480 #if OSL_DEBUG_LEVEL > 0
481 sal_uInt32 nCheckPos = nCPos + GetBoxWidth( pBox );
482 if( !nEndCPos )
484 nEndCPos = nCheckPos;
486 else
488 OSL_ENSURE( SwWriteTableCol(nCheckPos) ==
489 SwWriteTableCol(nEndCPos),
490 "Cell includes rows of different widths" );
492 #endif
493 nCPos = nStartCPos + nParentLineWidth;
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
505 if( ShouldExpandSub( pBox, bSubExpanded, nDepth ) )
507 CollectTableRowsCols( nOldRPos, nOldCPos,
508 nRPos - nOldRPos,
509 nCPos - nOldCPos,
510 pBox->GetTabLines(),
511 nDepth-1 );
512 bSubExpanded = true;
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 )
527 const SwTableLines::size_type nLines = rLines.size();
528 bool bSubExpanded = false;
530 // Specifying the border
531 tools::Long nRPos = nStartRPos;
532 sal_uInt16 nRow = nStartRow;
534 for( SwTableLines::size_type nLine = 0; nLine < nLines; ++nLine )
536 const SwTableLine *pLine = rLines[nLine];
538 // Determine the position of the last covered row
539 tools::Long nOldRPos = nRPos;
540 if( nLine < nLines-1 || nParentLineHeight==0 )
542 tools::Long nLineHeight = GetLineHeight( pLine );
543 nRPos += nLineHeight;
544 if( nParentLineHeight && nStartRPos + nParentLineHeight <= nRPos )
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;
554 else
555 nRPos = nStartRPos + nParentLineHeight;
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; });
564 // coupled methods out of sync ...
565 assert( it2 != m_aRows.end() );
566 nRow = it2 - m_aRows.begin();
568 OSL_ENSURE( nOldRow <= nRow, "Don't look back!" );
569 if( nOldRow > nRow )
571 nOldRow = nRow;
572 if( nOldRow )
573 --nOldRow;
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;
581 const SwTableBoxes& rBoxes = pLine->GetTabBoxes();
583 const SwFrameFormat *pLineFrameFormat = pLine->GetFrameFormat();
584 const SfxItemSet& rItemSet = pLineFrameFormat->GetAttrSet();
586 tools::Long nHeight = 0;
587 if( const SwFormatFrameSize* pFrameSizeItem = rItemSet.GetItemIfSet( RES_FRM_SIZE ))
588 nHeight = pFrameSizeItem->GetHeight();
590 const SvxBrushItem *pBrushItem, *pLineBrush = pParentBrush;
591 if( const SvxBrushItem* pTmpBrush = rItemSet.GetItemIfSet( RES_BACKGROUND, false ) )
593 pLineBrush = pTmpBrush;
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 )
601 SwWriteTableCol aCol( nParentLineWidth );
602 bOutAtRow = m_aCols.find( &aCol ) == (m_aCols.end() - 1);
604 if( bOutAtRow )
606 pRow->SetBackground( pLineBrush );
607 pBrushItem = nullptr;
609 else
610 pBrushItem = pLineBrush;
612 else
614 pRow->SetBackground( pLineBrush );
615 pBrushItem = nullptr;
618 const SwTableBoxes::size_type nBoxes = rBoxes.size();
619 sal_uInt32 nCPos = nStartCPos;
620 sal_uInt16 nCol = nStartCol;
622 for( SwTableBoxes::size_type nBox=0; nBox<nBoxes; ++nBox )
624 const SwTableBox *pBox = rBoxes[nBox];
626 // Determine the position of the last covered column
627 sal_uInt32 nOldCPos = nCPos;
628 if( nBox < nBoxes-1 || (nParentLineWidth==0 && nLine==0) )
630 nCPos = nCPos + GetBoxWidth( pBox );
631 if( nBox==nBoxes-1 )
632 nParentLineWidth = nCPos - nStartCPos;
634 else
635 nCPos = nStartCPos + nParentLineWidth;
637 // And their index
638 sal_uInt16 nOldCol = nCol;
639 SwWriteTableCol aSrchCol( nCPos );
640 SwWriteTableCols::const_iterator it = m_aCols.find( &aSrchCol );
641 OSL_ENSURE( it != m_aCols.end(), "missing column" );
642 if(it != m_aCols.end())
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();
648 if( !ShouldExpandSub( pBox, bSubExpanded, nDepth ) )
650 sal_uInt16 nRowSpan = nRow - nOldRow + 1;
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;
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
666 if( pBox->GetSttNd() )
668 sal_uInt16 nTopBorder = USHRT_MAX, nBottomBorder = USHRT_MAX;
669 sal_uInt16 nBorderMask = MergeBoxBorders(pBox, nOldRow, nOldCol,
670 nRowSpan, nColSpan, nTopBorder, nBottomBorder);
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())
677 SwWriteTableCol *pCol = m_aCols[nOldCol].get();
678 OSL_ENSURE(pCol, "No TableCol found, panic!");
679 if (pCol)
680 pCol->m_bLeftBorder = false;
683 if (!(nBorderMask & 8))
685 SwWriteTableCol *pCol = m_aCols[nCol].get();
686 OSL_ENSURE(pCol, "No TableCol found, panic!");
687 if (pCol)
688 pCol->m_bRightBorder = false;
691 if (!(nBorderMask & 1))
692 pRow->m_bTopBorder = false;
693 else if (!pRow->m_nTopBorder || nTopBorder < pRow->m_nTopBorder)
694 pRow->m_nTopBorder = nTopBorder;
696 if (!(nBorderMask & 2))
697 pEndRow->m_bBottomBorder = false;
698 else if (
699 !pEndRow->m_nBottomBorder ||
700 nBottomBorder < pEndRow->m_nBottomBorder
703 pEndRow->m_nBottomBorder = nBottomBorder;
707 else
709 FillTableRowsCols( nOldRPos, nOldRow, nOldCPos, nOldCol,
710 nRPos-nOldRPos, nCPos-nOldCPos,
711 pBox->GetTabLines(),
712 pLineBrush, nDepth-1,
713 nNumOfHeaderRows );
714 bSubExpanded = true;
717 nCol++; // The next cell begins in the next column
720 nRow++;
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)
736 sal_uInt32 nParentWidth = m_nBaseWidth + m_nLeftSub + m_nRightSub;
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 );
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) );
753 // Adjust some Twip values to pixel boundaries
754 if( !m_nBorder )
755 m_nBorder = m_nInnerBorder;
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())
769 if( !m_bCollectBorderWidth )
771 m_nBorder = pLayoutInfo->GetBorder();
772 m_nCellPadding = pLayoutInfo->GetCellPadding();
773 m_nCellSpacing = pLayoutInfo->GetCellSpacing();
776 const sal_uInt16 nCols = pLayoutInfo->GetColCount();
777 const sal_uInt16 nRows = pLayoutInfo->GetRowCount();
779 // First set the table structure.
780 for( sal_uInt16 nCol=0; nCol<nCols; ++nCol )
782 std::unique_ptr<SwWriteTableCol> pCol(
783 new SwWriteTableCol( (nCol+1)*COL_DFLT_WIDTH ));
785 if( m_bColTags )
787 const SwHTMLTableLayoutColumn *pLayoutCol =
788 pLayoutInfo->GetColumn( nCol );
789 pCol->SetWidthOpt( pLayoutCol->GetWidthOption(),
790 pLayoutCol->IsRelWidthOption() );
793 m_aCols.insert( std::move(pCol) );
796 for( sal_uInt16 nRow=0; nRow<nRows; ++nRow )
798 std::unique_ptr<SwWriteTableRow> pRow(
799 new SwWriteTableRow( (nRow+1)*ROW_DFLT_HEIGHT, m_bUseLayoutHeights ));
800 pRow->m_nTopBorder = 0;
801 pRow->m_nBottomBorder = 0;
802 m_aRows.insert( std::move(pRow) );
805 // And now fill with life
806 for( sal_uInt16 nRow=0; nRow<nRows; ++nRow )
808 SwWriteTableRow *pRow = m_aRows[nRow].get();
810 bool bHeightExported = false;
811 for( sal_uInt16 nCol=0; nCol<nCols; nCol++ )
813 const SwHTMLTableLayoutCell *pLayoutCell =
814 pLayoutInfo->GetCell( nRow, nCol );
816 const SwHTMLTableLayoutCnts *pLayoutCnts =
817 pLayoutCell->GetContents().get();
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() ) )
825 continue;
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" );
834 tools::Long nHeight = bHeightExported ? 0 : GetLineHeight( pBox );
835 const SvxBrushItem *pBrushItem = GetLineBrush( pBox, pRow );
837 SwWriteTableCell *pCell =
838 pRow->AddCell( pBox, nRow, nCol, nRowSpan, nColSpan,
839 nHeight, pBrushItem );
840 pCell->SetWidthOpt( pLayoutCell->GetWidthOption(),
841 pLayoutCell->IsPercentWidthOption() );
843 sal_uInt16 nTopBorder = USHRT_MAX, nBottomBorder = USHRT_MAX;
844 sal_uInt16 nBorderMask =
845 MergeBoxBorders( pBox, nRow, nCol, nRowSpan, nColSpan,
846 nTopBorder, nBottomBorder );
848 SwWriteTableCol *pCol = m_aCols[nCol].get();
849 if( !(nBorderMask & 4) )
850 pCol->m_bLeftBorder = false;
852 pCol = m_aCols[nCol+nColSpan-1].get();
853 if( !(nBorderMask & 8) )
854 pCol->m_bRightBorder = false;
856 if( !(nBorderMask & 1) )
857 pRow->m_bTopBorder = false;
859 SwWriteTableRow *pEndRow = m_aRows[nRow+nRowSpan-1].get();
860 if( !(nBorderMask & 2) )
861 pEndRow->m_bBottomBorder = false;
863 // The height requires only to be written once
864 if( nHeight )
865 bHeightExported = true;
869 // Adjust some Twip values to pixel boundaries
870 if( m_bCollectBorderWidth && !m_nBorder )
871 m_nBorder = m_nInnerBorder;
874 SwWriteTable::~SwWriteTable()
878 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */