1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
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>
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
;
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),
62 SwWriteTableCell
*SwWriteTableRow::AddCell( const SwTableBox
*pBox
,
63 sal_uInt16 nRow
, sal_uInt16 nCol
,
64 sal_uInt16 nRowSpan
, sal_uInt16 nColSpan
,
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
));
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
)
94 bool bOldGetLineHeightCalled
= m_bGetLineHeightCalled
;
95 m_bGetLineHeightCalled
= true;
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
);
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
111 m_bUseLayoutHeights
= bLayoutAvailable
;
114 SAL_WARN_IF( !bLayoutAvailable
&& bOldGetLineHeightCalled
, "sw", "Layout invalid?" );
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
;
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
] );
142 tools::Long
SwWriteTable::GetLineHeight( const SwTableBox
*pBox
)
144 const SwTableLine
*pLine
= pBox
->GetUpper();
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();
159 const SvxBrushItem
*SwWriteTable::GetLineBrush( const SwTableBox
*pBox
,
160 SwWriteTableRow
*pRow
)
162 const SwTableLine
*pLine
= pBox
->GetUpper();
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
);
181 pBox
= pLine
->GetUpper();
182 pLine
= pBox
? pBox
->GetUpper() : nullptr;
188 void SwWriteTable::MergeBorders( const SvxBorderLine
* pBorderLine
,
191 if( Color(ColorTransparency
, 0xffffffff) == m_nBorderColor
)
193 if( !pBorderLine
->GetColor().IsRGBEqual( COL_GRAY
) )
194 m_nBorderColor
= pBorderLine
->GetColor();
197 if( !m_bCollectBorderWidth
)
200 const sal_uInt16 nOutWidth
= pBorderLine
->GetOutWidth();
203 if( nOutWidth
&& (!m_nBorder
|| nOutWidth
< m_nBorder
) )
204 m_nBorder
= nOutWidth
;
208 if( nOutWidth
&& (!m_nInnerBorder
|| nOutWidth
< m_nInnerBorder
) )
209 m_nInnerBorder
= nOutWidth
;
212 const sal_uInt16 nDist
= pBorderLine
->GetInWidth() ? pBorderLine
->GetDistance()
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() )
232 MergeBorders( rBoxItem
.GetTop(), nRow
==0 );
233 rTopBorder
= rBoxItem
.GetTop()->GetOutWidth();
236 if( rBoxItem
.GetLeft() )
239 MergeBorders( rBoxItem
.GetLeft(), nCol
==0 );
242 if( rBoxItem
.GetBottom() )
245 MergeBorders( rBoxItem
.GetBottom(), nRow
+nRowSpan
==m_aRows
.size() );
246 rBottomBorder
= rBoxItem
.GetBottom()->GetOutWidth();
249 if( rBoxItem
.GetRight() )
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
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
;
277 sal_uInt32
SwWriteTable::GetRawWidth( sal_uInt16 nCol
, sal_uInt16 nColSpan
) const
279 sal_uInt32 nWidth
= m_aCols
[nCol
+nColSpan
-1]->GetPos();
281 nWidth
= nWidth
- m_aCols
[nCol
-1]->GetPos();
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.
293 nSpace
= nSpace
+ m_nLeftSub
;
295 const SwWriteTableCol
*pCol
= m_aCols
[nCol
].get();
296 if( pCol
->HasLeftBorder() )
297 nSpace
= nSpace
+ m_nBorder
;
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
;
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,
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,
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;
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
,
401 bool bSubExpanded
= false;
402 const SwTableLines::size_type nLines
= rLines
.size();
404 #if OSL_DEBUG_LEVEL > 0
405 sal_uInt32 nEndCPos
= 0;
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
) );
436 #if OSL_DEBUG_LEVEL > 0
437 tools::Long nCheckPos
= nRPos
+ GetLineHeight( pLine
);
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" );
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
) );
473 OSL_ENSURE( nLine
==0 && nParentLineWidth
==0,
474 "Now the parent width will be flattened!" );
475 nParentLineWidth
= nCPos
-nStartCPos
;
480 #if OSL_DEBUG_LEVEL > 0
481 sal_uInt32 nCheckPos
= nCPos
+ GetBoxWidth( pBox
);
484 nEndCPos
= nCheckPos
;
488 OSL_ENSURE( SwWriteTableCol(nCheckPos
) ==
489 SwWriteTableCol(nEndCPos
),
490 "Cell includes rows of different widths" );
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" );
505 if( ShouldExpandSub( pBox
, bSubExpanded
, nDepth
) )
507 CollectTableRowsCols( nOldRPos
, nOldCPos
,
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
,
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
;
555 nRPos
= nStartRPos
+ nParentLineHeight
;
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!" );
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);
606 pRow
->SetBackground( pLineBrush
);
607 pBrushItem
= nullptr;
610 pBrushItem
= pLineBrush
;
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
);
632 nParentLineWidth
= nCPos
- nStartCPos
;
635 nCPos
= nStartCPos
+ nParentLineWidth
;
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 )
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
,
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!");
680 pCol
->m_bLeftBorder
= false;
683 if (!(nBorderMask
& 8))
685 SwWriteTableCol
*pCol
= m_aCols
[nCol
].get();
686 OSL_ENSURE(pCol
, "No TableCol found, panic!");
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;
699 !pEndRow
->m_nBottomBorder
||
700 nBottomBorder
< pEndRow
->m_nBottomBorder
703 pEndRow
->m_nBottomBorder
= nBottomBorder
;
709 FillTableRowsCols( nOldRPos
, nOldRow
, nOldCPos
, nOldCol
,
710 nRPos
-nOldRPos
, nCPos
-nOldCPos
,
712 pLineBrush
, nDepth
-1,
717 nCol
++; // The next cell begins in the next column
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),
731 m_bGetLineHeightCalled(false),
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
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),
764 m_bGetLineHeightCalled(false),
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
));
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() ) )
828 const sal_uInt16 nRowSpan
= pLayoutCell
->GetRowSpan();
829 const sal_uInt16 nColSpan
= pLayoutCell
->GetColSpan();
830 const SwTableBox
*pBox
= pLayoutCnts
->GetTableBox();
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
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: */