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