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