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