1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sw.hxx"
26 #include <hintids.hxx>
27 #include <tools/debug.hxx>
28 #include <editeng/boxitem.hxx>
29 #include <editeng/brshitem.hxx>
30 #include <tools/fract.hxx>
31 #include <wrtswtbl.hxx>
32 #include <swtable.hxx>
33 #include <frmfmt.hxx>
34 #include <fmtfsize.hxx>
35 #include <fmtornt.hxx>
36 #include <frmatr.hxx>
37 #include <htmltbl.hxx>
38 
39 using namespace ::com::sun::star;
40 
SV_IMPL_PTRARR(SwWriteTableCells,SwWriteTableCellPtr)41 SV_IMPL_PTRARR( SwWriteTableCells, SwWriteTableCellPtr )
42 SV_IMPL_OP_PTRARR_SORT( SwWriteTableRows, SwWriteTableRowPtr )
43 SV_IMPL_OP_PTRARR_SORT( SwWriteTableCols, SwWriteTableColPtr )
44 
45 //-----------------------------------------------------------------------
46 
47 sal_Int16 SwWriteTableCell::GetVertOri() const
48 {
49     sal_Int16 eCellVertOri = text::VertOrientation::TOP;
50 	if( pBox->GetSttNd() )
51 	{
52 		const SfxItemSet& rItemSet = pBox->GetFrmFmt()->GetAttrSet();
53 		const SfxPoolItem *pItem;
54 		if(	SFX_ITEM_SET == rItemSet.GetItemState( RES_VERT_ORIENT, sal_False, &pItem ) )
55 		{
56             sal_Int16 eBoxVertOri =
57 				((const SwFmtVertOrient *)pItem)->GetVertOrient();
58             if( text::VertOrientation::CENTER==eBoxVertOri || text::VertOrientation::BOTTOM==eBoxVertOri)
59 				eCellVertOri = eBoxVertOri;
60 		}
61 	}
62 
63 	return eCellVertOri;
64 }
65 
66 //-----------------------------------------------------------------------
67 
SwWriteTableRow(long nPosition,sal_Bool bUseLayoutHeights)68 SwWriteTableRow::SwWriteTableRow( long nPosition, sal_Bool bUseLayoutHeights )
69 	: pBackground(0), nPos(nPosition), mbUseLayoutHeights(bUseLayoutHeights),
70 	nTopBorder(USHRT_MAX), nBottomBorder(USHRT_MAX), bTopBorder(true),
71 	bBottomBorder(true)
72 {
73 }
74 
AddCell(const SwTableBox * pBox,sal_uInt16 nRow,sal_uInt16 nCol,sal_uInt16 nRowSpan,sal_uInt16 nColSpan,long nHeight,const SvxBrushItem * pBackgroundBrush)75 SwWriteTableCell *SwWriteTableRow::AddCell( const SwTableBox *pBox,
76 								sal_uInt16 nRow, sal_uInt16 nCol,
77 								sal_uInt16 nRowSpan, sal_uInt16 nColSpan,
78 								long nHeight,
79 								const SvxBrushItem *pBackgroundBrush )
80 {
81 	SwWriteTableCell *pCell =
82 		new SwWriteTableCell( pBox, nRow, nCol, nRowSpan, nColSpan,
83 								nHeight, pBackgroundBrush );
84 	aCells.Insert( pCell, aCells.Count() );
85 
86 	return pCell;
87 }
88 
89 //-----------------------------------------------------------------------
90 
SwWriteTableCol(sal_uInt32 nPosition)91 SwWriteTableCol::SwWriteTableCol(sal_uInt32 nPosition)
92 	: nPos(nPosition), nWidthOpt(0), bRelWidthOpt(false), bOutWidth(true),
93 	bLeftBorder(true), bRightBorder(true)
94 {
95 }
96 
97 //-----------------------------------------------------------------------
98 
GetBoxWidth(const SwTableBox * pBox)99 sal_uInt32 SwWriteTable::GetBoxWidth( const SwTableBox *pBox )
100 {
101 	const SwFrmFmt *pFmt = pBox->GetFrmFmt();
102 	const SwFmtFrmSize& aFrmSize=
103         (const SwFmtFrmSize&)pFmt->GetFmtAttr( RES_FRM_SIZE );
104 
105 	return sal::static_int_cast<sal_uInt32>(aFrmSize.GetSize().Width());
106 }
107 
GetLineHeight(const SwTableLine * pLine)108 long SwWriteTable::GetLineHeight( const SwTableLine *pLine )
109 {
110 #ifdef DBG_UTIL
111 	sal_Bool bOldGetLineHeightCalled = bGetLineHeightCalled;
112 	bGetLineHeightCalled = sal_True;
113 #endif
114 
115 	long nHeight = 0;
116 	if( bUseLayoutHeights )
117 	{
118 		// Erstmal versuchen wir die Hoehe ueber das Layout zu bekommen
119         bool bLayoutAvailable = false;
120         nHeight = pLine->GetTableLineHeight(bLayoutAvailable);
121 		if( nHeight > 0 )
122 			return nHeight;
123 
124 		// Wenn kein Layout gefunden wurde, gehen wir von festen Hoehen aus.
125         // --> FME 2007-3-26 #i60390# in some cases we still want to continue
126         // to use the layout heights even if one of the rows has a height of 0
127         // ('hidden' rows)
128         // <--
129 		bUseLayoutHeights = bLayoutAvailable; /*sal_False;*/
130 
131 #ifdef DBG_UTIL
132 		ASSERT( bLayoutAvailable || !bOldGetLineHeightCalled, "Layout ungueltig?" );
133 #endif
134 	}
135 
136 	const SwTableBoxes& rBoxes = pLine->GetTabBoxes();
137 	sal_uInt16 nBoxes = rBoxes.Count();
138 
139 	for( sal_uInt16 nBox=0; nBox<nBoxes; nBox++ )
140 	{
141 		const SwTableBox* pBox = rBoxes[nBox];
142 		if( pBox->GetSttNd() )
143 		{
144 			if( nHeight < ROW_DFLT_HEIGHT )
145 				nHeight = ROW_DFLT_HEIGHT;
146 		}
147 		else
148 		{
149 			long nTmp = 0;
150 			const SwTableLines &rLines = pBox->GetTabLines();
151 			for( sal_uInt16 nLine=0; nLine<rLines.Count(); nLine++ )
152 			{
153 				nTmp += GetLineHeight( rLines[nLine] );
154 			}
155 			if( nHeight < nTmp )
156 				nHeight = nTmp;
157 		}
158 	}
159 
160 	return nHeight;
161 }
162 
GetLineHeight(const SwTableBox * pBox) const163 long SwWriteTable::GetLineHeight( const SwTableBox *pBox ) const
164 {
165 	const SwTableLine *pLine = pBox->GetUpper();
166 
167 	if( !pLine )
168 		return 0;
169 
170 	const SwFrmFmt *pLineFrmFmt = pLine->GetFrmFmt();
171 	const SfxPoolItem* pItem;
172 	const SfxItemSet& rItemSet = pLineFrmFmt->GetAttrSet();
173 
174 	long nHeight = 0;
175 	if( SFX_ITEM_SET == rItemSet.GetItemState( RES_FRM_SIZE, sal_True, &pItem ))
176 		nHeight = ((SwFmtFrmSize*)pItem)->GetHeight();
177 
178 	return nHeight;
179 }
180 
GetLineBrush(const SwTableBox * pBox,SwWriteTableRow * pRow)181 const SvxBrushItem *SwWriteTable::GetLineBrush( const SwTableBox *pBox,
182 												  SwWriteTableRow *pRow )
183 {
184 	const SwTableLine *pLine = pBox->GetUpper();
185 
186 	while( pLine )
187 	{
188 		const SwFrmFmt *pLineFrmFmt = pLine->GetFrmFmt();
189 		const SfxPoolItem* pItem;
190 		const SfxItemSet& rItemSet = pLineFrmFmt->GetAttrSet();
191 
192 		if( SFX_ITEM_SET == rItemSet.GetItemState( RES_BACKGROUND, sal_False,
193 												   &pItem ) )
194 		{
195 			if( !pLine->GetUpper() )
196 			{
197 				if( !pRow->GetBackground() )
198 					pRow->SetBackground( (const SvxBrushItem *)pItem );
199 				pItem = 0;
200 			}
201 
202 			return (const SvxBrushItem *)pItem;
203 		}
204 
205 		pBox = pLine->GetUpper();
206 		pLine = pBox ? pBox->GetUpper() : 0;
207 	}
208 
209 	return 0;
210 }
211 
212 
MergeBorders(const SvxBorderLine * pBorderLine,sal_Bool bTable)213 void SwWriteTable::MergeBorders( const SvxBorderLine* pBorderLine,
214 								   sal_Bool bTable )
215 {
216 	if( (sal_uInt32)-1 == nBorderColor )
217 	{
218 		Color aGrayColor( COL_GRAY );
219 		if( !pBorderLine->GetColor().IsRGBEqual( aGrayColor ) )
220 			nBorderColor = pBorderLine->GetColor().GetColor();
221 	}
222 
223 	if( !bCollectBorderWidth )
224 		return;
225 
226 	sal_uInt16 nOutWidth = pBorderLine->GetOutWidth();
227 	if( bTable )
228 	{
229 		if( nOutWidth && (!nBorder || nOutWidth < nBorder) )
230 			nBorder = nOutWidth;
231 	}
232 	else
233 	{
234 		if( nOutWidth && (!nInnerBorder || nOutWidth < nInnerBorder) )
235 			nInnerBorder = nOutWidth;
236 	}
237 
238 	sal_uInt16 nDist = pBorderLine->GetInWidth() ? pBorderLine->GetDistance()
239 												: 0;
240 	if( nDist && (!nCellSpacing || nDist < nCellSpacing) )
241 		nCellSpacing = nDist;
242 }
243 
244 
MergeBoxBorders(const SwTableBox * pBox,sal_uInt16 nRow,sal_uInt16 nCol,sal_uInt16 nRowSpan,sal_uInt16 nColSpan,sal_uInt16 & rTopBorder,sal_uInt16 & rBottomBorder)245 sal_uInt16 SwWriteTable::MergeBoxBorders( const SwTableBox *pBox,
246 										sal_uInt16 nRow, sal_uInt16 nCol,
247 										sal_uInt16 nRowSpan, sal_uInt16 nColSpan,
248 										sal_uInt16& rTopBorder,
249 										sal_uInt16 &rBottomBorder )
250 {
251 	sal_uInt16 nBorderMask = 0;
252 
253 	const SwFrmFmt *pFrmFmt = pBox->GetFrmFmt();
254     const SvxBoxItem& rBoxItem = (const SvxBoxItem&)pFrmFmt->GetFmtAttr( RES_BOX );
255 
256 	if( rBoxItem.GetTop() )
257 	{
258 		nBorderMask |= 1;
259 		MergeBorders( rBoxItem.GetTop(), nRow==0 );
260 		rTopBorder = rBoxItem.GetTop()->GetOutWidth();
261 	}
262 
263 	if( rBoxItem.GetLeft() )
264 	{
265 		nBorderMask |= 4;
266 		MergeBorders( rBoxItem.GetLeft(), nCol==0 );
267 	}
268 
269 	if( rBoxItem.GetBottom() )
270 	{
271 		nBorderMask |= 2;
272 		MergeBorders( rBoxItem.GetBottom(), nRow+nRowSpan==aRows.Count() );
273 		rBottomBorder = rBoxItem.GetBottom()->GetOutWidth();
274 	}
275 
276 	if( rBoxItem.GetRight() )
277 	{
278 		nBorderMask |= 8;
279 		MergeBorders( rBoxItem.GetRight(), nCol+nColSpan==aCols.Count() );
280 	}
281 
282 	// If any distance is set, the smallest one is used. This holds for
283 	// the four distance of a box as well as for the distances of different
284 	// boxes.
285 	if( bCollectBorderWidth )
286 	{
287 		sal_uInt16 nDist = rBoxItem.GetDistance( BOX_LINE_TOP );
288 		if( nDist && (!nCellPadding || nDist < nCellPadding) )
289 			nCellPadding = nDist;
290 		nDist = rBoxItem.GetDistance( BOX_LINE_BOTTOM );
291 		if( nDist && (!nCellPadding || nDist < nCellPadding) )
292 			nCellPadding = nDist;
293 		nDist = rBoxItem.GetDistance( BOX_LINE_LEFT );
294 		if( nDist && (!nCellPadding || nDist < nCellPadding) )
295 			nCellPadding = nDist;
296 		nDist = rBoxItem.GetDistance( BOX_LINE_RIGHT );
297 		if( nDist && (!nCellPadding || nDist < nCellPadding) )
298 			nCellPadding = nDist;
299 	}
300 
301 	return nBorderMask;
302 }
303 
304 
GetRawWidth(sal_uInt16 nCol,sal_uInt16 nColSpan) const305 sal_uInt32  SwWriteTable::GetRawWidth( sal_uInt16 nCol, sal_uInt16 nColSpan ) const
306 {
307     sal_uInt32 nWidth = aCols[nCol+nColSpan-1]->GetPos();
308 	if( nCol > 0 )
309         nWidth = nWidth - aCols[nCol-1]->GetPos();
310 
311 	return nWidth;
312 }
313 
GetLeftSpace(sal_uInt16 nCol) const314 sal_uInt16 SwWriteTable::GetLeftSpace( sal_uInt16 nCol ) const
315 {
316 	sal_uInt16 nSpace = nCellPadding + nCellSpacing;
317 
318 	// In der ersten Spalte auch noch die Liniendicke abziehen
319 	if( nCol==0 )
320 	{
321         nSpace = nSpace + nLeftSub;
322 
323 		const SwWriteTableCol *pCol = aCols[nCol];
324 		if( pCol->HasLeftBorder() )
325             nSpace = nSpace + nBorder;
326 	}
327 
328 	return nSpace;
329 }
330 
GetRightSpace(sal_uInt16 nCol,sal_uInt16 nColSpan) const331 sal_uInt16 SwWriteTable::GetRightSpace( sal_uInt16 nCol, sal_uInt16 nColSpan ) const
332 {
333 	sal_uInt16 nSpace = nCellPadding;
334 
335 	// In der letzten Spalte noch einmal zusaetzlich CELLSPACING und
336 	// und die Liniendicke abziehen
337 	if( nCol+nColSpan==aCols.Count() )
338 	{
339 		nSpace += (nCellSpacing + nRightSub);
340 
341 		const SwWriteTableCol *pCol = aCols[nCol+nColSpan-1];
342 		if( pCol->HasRightBorder() )
343             nSpace = nSpace + nBorder;
344 	}
345 
346 	return nSpace;
347 }
348 
GetAbsWidth(sal_uInt16 nCol,sal_uInt16 nColSpan) const349 sal_uInt16 SwWriteTable::GetAbsWidth( sal_uInt16 nCol, sal_uInt16 nColSpan ) const
350 {
351     sal_uInt32 nWidth = GetRawWidth( nCol, nColSpan );
352 	if( nBaseWidth != nTabWidth )
353 	{
354 		nWidth *= nTabWidth;
355 		nWidth /= nBaseWidth;
356 	}
357 
358 	nWidth -= GetLeftSpace( nCol ) + GetRightSpace( nCol, nColSpan );
359 
360 	ASSERT( nWidth > 0, "Spaltenbreite <= 0. OK?" );
361 	return nWidth > 0 ? (sal_uInt16)nWidth : 0;
362 }
363 
GetRelWidth(sal_uInt16 nCol,sal_uInt16 nColSpan) const364 sal_uInt16 SwWriteTable::GetRelWidth( sal_uInt16 nCol, sal_uInt16 nColSpan ) const
365 {
366 	long nWidth = GetRawWidth( nCol, nColSpan );
367 
368 	return (sal_uInt16)(long)Fraction( nWidth*256 + GetBaseWidth()/2,
369 								   GetBaseWidth() );
370 }
371 
GetPrcWidth(sal_uInt16 nCol,sal_uInt16 nColSpan) const372 sal_uInt16 SwWriteTable::GetPrcWidth( sal_uInt16 nCol, sal_uInt16 nColSpan ) const
373 {
374 	long nWidth = GetRawWidth( nCol, nColSpan );
375 
376 	// sieht komisch aus, ist aber nichts anderes als
377 	//  [(100 * nWidth) + .5] ohne Rundungsfehler
378 	return (sal_uInt16)(long)Fraction( nWidth*100 + GetBaseWidth()/2,
379 								   GetBaseWidth() );
380 }
381 
GetAbsHeight(long nRawHeight,sal_uInt16 nRow,sal_uInt16 nRowSpan) const382 long SwWriteTable::GetAbsHeight( long nRawHeight, sal_uInt16 nRow,
383 								   sal_uInt16 nRowSpan ) const
384 {
385 	nRawHeight -= (2*nCellPadding + nCellSpacing);
386 
387 	// In der ersten Zeile noch einmal zusaetzlich CELLSPACING und
388 	// und die Liniendicke abziehen
389 	const SwWriteTableRow *pRow = 0;
390 	if( nRow==0 )
391 	{
392 		nRawHeight -= nCellSpacing;
393 		pRow = aRows[nRow];
394 		if( pRow->HasTopBorder() )
395 			nRawHeight -= nBorder;
396 	}
397 
398 	// In der letzten Zeile noch die Liniendicke abziehen
399 	if( nRow+nRowSpan==aRows.Count() )
400 	{
401 		if( !pRow || nRowSpan > 1 )
402 			pRow = aRows[nRow+nRowSpan-1];
403 		if( pRow->HasBottomBorder() )
404 			nRawHeight -= nBorder;
405 	}
406 
407 	ASSERT( nRawHeight > 0, "Zeilenheohe <= 0. OK?" );
408 	return nRawHeight > 0 ? nRawHeight : 0;
409 }
410 
ShouldExpandSub(const SwTableBox * pBox,sal_Bool,sal_uInt16 nDepth) const411 sal_Bool SwWriteTable::ShouldExpandSub(const SwTableBox *pBox, sal_Bool /*bExpandedBefore*/,
412 	sal_uInt16 nDepth) const
413 {
414 	return !pBox->GetSttNd() && nDepth > 0;
415 }
416 
CollectTableRowsCols(long nStartRPos,sal_uInt32 nStartCPos,long nParentLineHeight,sal_uInt32 nParentLineWidth,const SwTableLines & rLines,sal_uInt16 nDepth)417 void SwWriteTable::CollectTableRowsCols( long nStartRPos,
418 										   sal_uInt32 nStartCPos,
419 										   long nParentLineHeight,
420 										   sal_uInt32 nParentLineWidth,
421 										   const SwTableLines& rLines,
422 										   sal_uInt16 nDepth )
423 {
424 	sal_Bool bSubExpanded = sal_False;
425 	sal_uInt16 nLines = rLines.Count();
426 
427 #ifdef DBG_UTIL
428     sal_uInt32 nEndCPos = 0;
429 #endif
430 
431 	long nRPos = nStartRPos;
432 	for( sal_uInt16 nLine = 0; nLine < nLines; nLine++ )
433 	{
434 		/*const*/ SwTableLine *pLine = rLines[nLine];
435 
436 		long nOldRPos = nRPos;
437 
438 		if( nLine < nLines-1 || nParentLineHeight==0  )
439 		{
440             long nLineHeight = GetLineHeight( pLine );
441 			nRPos += nLineHeight;
442             if( nParentLineHeight && nStartRPos + nParentLineHeight <= nRPos )
443             {
444                 /* If you have corrupt line height information, e.g. breaking rows in complex table
445                 layout, you may run into this robust code.
446                 It's not allowed that subrows leaves their parentrow. If this would happen the line
447                 height of subrow is reduced to a part of the remaining height */
448                 ASSERT( sal_False, "Corrupt line height I" );
449                 nRPos -= nLineHeight;
450                 nLineHeight = nStartRPos + nParentLineHeight - nRPos; // remaining parent height
451                 nLineHeight /= nLines - nLine; // divided through the number of remaining sub rows
452                 nRPos += nLineHeight;
453             }
454 			SwWriteTableRow *pRow = new SwWriteTableRow( nRPos, bUseLayoutHeights);
455 			sal_uInt16 nRow;
456 			if( aRows.Seek_Entry( pRow, &nRow ) )
457 				delete pRow;
458 			else
459 				aRows.Insert( pRow );
460 		}
461 		else
462 		{
463 #ifdef DBG_UTIL
464 			long nCheckPos = nRPos + GetLineHeight( pLine );
465 #endif
466 			nRPos = nStartRPos + nParentLineHeight;
467 #ifdef DBG_UTIL
468 			SwWriteTableRow aRow( nStartRPos + nParentLineHeight, bUseLayoutHeights );
469 			ASSERT( aRows.Seek_Entry(&aRow),
470 					"Parent-Zeile nicht gefunden" );
471             SwWriteTableRow aRowCheckPos(nCheckPos,bUseLayoutHeights);
472             SwWriteTableRow aRowRPos(nRPos,bUseLayoutHeights);
473 			ASSERT( !bUseLayoutHeights ||
474                     aRowCheckPos == aRowRPos,
475 					"Hoehe der Zeilen stimmt nicht mit Parent ueberein" );
476 #endif
477 		}
478 
479 		// Fuer alle Boxen der Zeile ggf. eine Spalte einfuegen
480 		const SwTableBoxes& rBoxes = pLine->GetTabBoxes();
481 		sal_uInt16 nBoxes = rBoxes.Count();
482 
483 		sal_uInt32 nCPos = nStartCPos;
484 		for( sal_uInt16 nBox=0; nBox<nBoxes; nBox++ )
485 		{
486 			const SwTableBox *pBox = rBoxes[nBox];
487 
488 			sal_uInt32 nOldCPos = nCPos;
489 
490 			if( nBox < nBoxes-1 || (nParentLineWidth==0 && nLine==0)  )
491 			{
492                 nCPos = nCPos + GetBoxWidth( pBox );
493 				SwWriteTableCol *pCol = new SwWriteTableCol( nCPos );
494 
495 				sal_uInt16 nCol;
496 				if( aCols.Seek_Entry( pCol, &nCol ) )
497 					delete pCol;
498 				else
499 					aCols.Insert( pCol );
500 
501 				if( nBox==nBoxes-1 )
502 				{
503 					ASSERT( nLine==0 && nParentLineWidth==0,
504 							"Jetzt wird die Parent-Breite plattgemacht!" );
505 					nParentLineWidth = nCPos-nStartCPos;
506 				}
507 			}
508 			else
509 			{
510 #ifdef DBG_UTIL
511                 sal_uInt32 nCheckPos = nCPos + GetBoxWidth( pBox );
512 				if( !nEndCPos )
513 				{
514 					nEndCPos = nCheckPos;
515 				}
516 				else
517 				{
518 					ASSERT( SwWriteTableCol(nCheckPos) ==
519 												SwWriteTableCol(nEndCPos),
520 					"Zelle enthaelt unterschiedlich breite Zeilen" );
521 				}
522 #endif
523 				nCPos = nStartCPos + nParentLineWidth;
524 #ifdef DBG_UTIL
525 				SwWriteTableCol aCol( nStartCPos + nParentLineWidth );
526 				ASSERT( aCols.Seek_Entry(&aCol),
527 						"Parent-Zelle nicht gefunden" );
528 				ASSERT( SwWriteTableCol(nCheckPos) ==
529 											SwWriteTableCol(nCPos),
530 						"Breite der Zellen stimmt nicht mit Parent ueberein" );
531 #endif
532 			}
533 
534 			if( ShouldExpandSub( pBox, bSubExpanded, nDepth ) )
535 			{
536 				CollectTableRowsCols( nOldRPos, nOldCPos,
537 										nRPos - nOldRPos,
538 										nCPos - nOldCPos,
539 										pBox->GetTabLines(),
540 										nDepth-1 );
541 				bSubExpanded = sal_True;
542 			}
543 		}
544 	}
545 }
546 
547 
FillTableRowsCols(long nStartRPos,sal_uInt16 nStartRow,sal_uInt32 nStartCPos,sal_uInt16 nStartCol,long nParentLineHeight,sal_uInt32 nParentLineWidth,const SwTableLines & rLines,const SvxBrushItem * pParentBrush,sal_uInt16 nDepth,sal_uInt16 nNumOfHeaderRows)548 void SwWriteTable::FillTableRowsCols( long nStartRPos, sal_uInt16 nStartRow,
549 										sal_uInt32 nStartCPos, sal_uInt16 nStartCol,
550 										long nParentLineHeight,
551 										sal_uInt32 nParentLineWidth,
552 										const SwTableLines& rLines,
553 										const SvxBrushItem* pParentBrush,
554 										sal_uInt16 nDepth,
555 										sal_uInt16 nNumOfHeaderRows )
556 {
557 	sal_uInt16 nLines = rLines.Count();
558 	sal_Bool bSubExpanded = sal_False;
559 
560 	// Festlegen der Umrandung
561 	long nRPos = nStartRPos;
562 	sal_uInt16 nRow = nStartRow;
563 
564 	for( sal_uInt16 nLine = 0; nLine < nLines; nLine++ )
565 	{
566 		const SwTableLine *pLine = rLines[nLine];
567 
568 		// Position der letzten ueberdeckten Zeile ermitteln
569 		long nOldRPos = nRPos;
570 		if( nLine < nLines-1 || nParentLineHeight==0 )
571         {
572             long nLineHeight = GetLineHeight( pLine );
573 			nRPos += nLineHeight;
574             if( nParentLineHeight && nStartRPos + nParentLineHeight <= nRPos )
575             {
576                 /* See comment in CollectTableRowCols */
577                 ASSERT( sal_False, "Corrupt line height II" );
578                 nRPos -= nLineHeight;
579                 nLineHeight = nStartRPos + nParentLineHeight - nRPos; // remaining parent height
580                 nLineHeight /= nLines - nLine; // divided through the number of remaining sub rows
581                 nRPos += nLineHeight;
582             }
583         }
584 		else
585 			nRPos = nStartRPos + nParentLineHeight;
586 
587 		// Und ihren Index
588 		sal_uInt16 nOldRow = nRow;
589 		SwWriteTableRow aRow( nRPos,bUseLayoutHeights );
590 #ifdef DBG_UTIL
591 		sal_Bool bFound =
592 #endif
593 			aRows.Seek_Entry( &aRow, &nRow );
594 		ASSERT( bFound, "Wo ist die Zeile geblieben?" );
595 
596         ASSERT( nOldRow <= nRow, "Don't look back!" );
597         if( nOldRow > nRow )
598         {
599             nOldRow = nRow;
600             if( nOldRow )
601                 --nOldRow;
602         }
603 
604 
605 		SwWriteTableRow *pRow = aRows[nOldRow];
606 		SwWriteTableRow *pEndRow = aRows[nRow];
607 //		if( nLine==0 && nParentLineHeight==0 )
608 		if( nLine+1==nNumOfHeaderRows && nParentLineHeight==0 )
609 			nHeadEndRow = nRow;
610 
611 		const SwTableBoxes& rBoxes = pLine->GetTabBoxes();
612 
613 		const SwFrmFmt *pLineFrmFmt = pLine->GetFrmFmt();
614 		const SfxPoolItem* pItem;
615 		const SfxItemSet& rItemSet = pLineFrmFmt->GetAttrSet();
616 
617 		long nHeight = 0;
618 		if( SFX_ITEM_SET == rItemSet.GetItemState( RES_FRM_SIZE, sal_True, &pItem ))
619 			nHeight = ((SwFmtFrmSize*)pItem)->GetHeight();
620 
621 
622 		const SvxBrushItem *pBrushItem, *pLineBrush = pParentBrush;
623 		if( SFX_ITEM_SET == rItemSet.GetItemState( RES_BACKGROUND, sal_False,
624 												   &pItem ) )
625 		{
626 			pLineBrush = (const SvxBrushItem *)pItem;
627 
628 			// Wenn die Zeile die gesamte Tabelle umspannt, koennen
629 			// Wir den Hintergrund an der Zeile ausgeben. Sonst muessen
630 			// wir in an den Zelle ausgeben.
631 			sal_Bool bOutAtRow = !nParentLineWidth;
632 			if( !bOutAtRow && nStartCPos==0 )
633 			{
634 				sal_uInt16 nEndCol;
635 				SwWriteTableCol aCol( nParentLineWidth );
636 				bOutAtRow = aCols.Seek_Entry(&aCol,&nEndCol) &&
637 							nEndCol == aCols.Count()-1;
638 			}
639 			if( bOutAtRow )
640 			{
641 				pRow->SetBackground( pLineBrush );
642 				pBrushItem = 0;
643 			}
644 			else
645 				pBrushItem = pLineBrush;
646 		}
647 		else
648 		{
649 			pRow->SetBackground( pLineBrush );
650 			pBrushItem = 0;
651 		}
652 
653 		sal_uInt16 nBoxes = rBoxes.Count();
654 		sal_uInt32 nCPos = nStartCPos;
655 		sal_uInt16 nCol = nStartCol;
656 
657 		for( sal_uInt16 nBox=0; nBox<nBoxes; nBox++ )
658 		{
659 			const SwTableBox *pBox = rBoxes[nBox];
660 
661 			// Position der letzten ueberdeckten Spalte ermitteln
662 			sal_uInt32 nOldCPos = nCPos;
663 			if( nBox < nBoxes-1 || (nParentLineWidth==0 && nLine==0) )
664 			{
665                 nCPos = nCPos + GetBoxWidth( pBox );
666 				if( nBox==nBoxes-1 )
667 					nParentLineWidth = nCPos - nStartCPos;
668 			}
669 			else
670 				nCPos = nStartCPos + nParentLineWidth;
671 
672 			// Und ihren Index
673 			sal_uInt16 nOldCol = nCol;
674 			SwWriteTableCol aCol( nCPos );
675 #ifdef DBG_UTIL
676 			sal_Bool bFound2 =
677 #endif
678 				aCols.Seek_Entry( &aCol, &nCol );
679 			ASSERT( bFound2, "Wo ist die Spalte geblieben?" );
680 
681 			if( !ShouldExpandSub( pBox, bSubExpanded, nDepth ) )
682 			{
683 				sal_uInt16 nRowSpan = nRow - nOldRow + 1;
684 
685                 // The new table model may have true row span attributes
686                 const long nAttrRowSpan = pBox->getRowSpan();
687                 if ( 1 < nAttrRowSpan )
688                     nRowSpan = (sal_uInt16)nAttrRowSpan;
689                 else if ( nAttrRowSpan < 1 )
690                     nRowSpan = 0;
691 
692 				sal_uInt16 nColSpan = nCol - nOldCol + 1;
693 				pRow->AddCell( pBox, nOldRow, nOldCol,
694 							   nRowSpan, nColSpan, nHeight,
695 							   pBrushItem );
696 				nHeight = 0; // Die Hoehe braucht nur einmal geschieben werden
697 
698 				if( pBox->GetSttNd() )
699 				{
700 					sal_uInt16 nTopBorder = USHRT_MAX, nBottomBorder = USHRT_MAX;
701 					sal_uInt16 nBorderMask = MergeBoxBorders(pBox, nOldRow, nOldCol,
702 						nRowSpan, nColSpan, nTopBorder, nBottomBorder);
703 
704 					// #i30094# add a sanity check here to ensure that
705 					// we don't access an invalid aCols[] as &nCol
706 					// above can be changed.
707 					if (!(nBorderMask & 4) && nOldCol < aCols.Count())
708 					{
709 						SwWriteTableCol *pCol = aCols[nOldCol];
710 						ASSERT(pCol, "No TableCol found, panic!");
711 						if (pCol)
712 							pCol->bLeftBorder = sal_False;
713 					}
714 
715 					if (!(nBorderMask & 8))
716 					{
717 						SwWriteTableCol *pCol = aCols[nCol];
718 						ASSERT(pCol, "No TableCol found, panic!");
719 						if (pCol)
720 							pCol->bRightBorder = sal_False;
721 					}
722 
723 					if (!(nBorderMask & 1))
724 						pRow->bTopBorder = sal_False;
725 					else if (!pRow->nTopBorder || nTopBorder < pRow->nTopBorder)
726 						pRow->nTopBorder = nTopBorder;
727 
728 					if (!(nBorderMask & 2))
729 						pEndRow->bBottomBorder = sal_False;
730 					else if (
731 								!pEndRow->nBottomBorder ||
732 								nBottomBorder < pEndRow->nBottomBorder
733 							)
734 					{
735 						pEndRow->nBottomBorder = nBottomBorder;
736 					}
737 				}
738 //				MIB: 13.12.2000: Why should a cell that contains a subtable
739 //				not have borders? Moreover, switching them, off switches off
740 //				the fill border lines between the columns and rows. (#74222#)
741 //				else
742 //				{
743 //					aCols[nOldCol]->bLeftBorder = sal_False;
744 //					aCols[nCol]->bRightBorder = sal_False;
745 //					pRow->bTopBorder = sal_False;
746 //					pEndRow->bBottomBorder = sal_False;
747 //				}
748 			}
749 			else
750 			{
751 				FillTableRowsCols( nOldRPos, nOldRow, nOldCPos, nOldCol,
752 									nRPos-nOldRPos, nCPos-nOldCPos,
753 									pBox->GetTabLines(),
754 									pLineBrush, nDepth-1,
755 									nNumOfHeaderRows );
756 				bSubExpanded = sal_True;
757 			}
758 
759 			nCol++; // Die naechste Zelle faengt in der nachten Spalte an
760 		}
761 
762 		nRow++;
763 	}
764 }
765 
SwWriteTable(const SwTableLines & rLines,long nWidth,sal_uInt32 nBWidth,sal_Bool bRel,sal_uInt16 nMaxDepth,sal_uInt16 nLSub,sal_uInt16 nRSub,sal_uInt32 nNumOfRowsToRepeat)766 SwWriteTable::SwWriteTable(const SwTableLines& rLines, long nWidth,
767     sal_uInt32 nBWidth, sal_Bool bRel, sal_uInt16 nMaxDepth, sal_uInt16 nLSub, sal_uInt16 nRSub, sal_uInt32 nNumOfRowsToRepeat)
768 	: nBorderColor((sal_uInt32)-1), nCellSpacing(0), nCellPadding(0), nBorder(0),
769 	nInnerBorder(0), nBaseWidth(nBWidth), nHeadEndRow(USHRT_MAX),
770 	 nLeftSub(nLSub), nRightSub(nRSub), nTabWidth(nWidth), bRelWidths(bRel),
771 	bUseLayoutHeights(true),
772 #ifdef DBG_UTIL
773 	bGetLineHeightCalled(false),
774 #endif
775 	bColsOption(false), bColTags(true), bLayoutExport(false),
776 	bCollectBorderWidth(true)
777 {
778     sal_uInt32 nParentWidth = nBaseWidth + nLeftSub + nRightSub;
779 
780 	// Erstmal die Tabellen-Struktur festlegen. Hinter der Tabelle ist in
781 	// jedem Fall eine Spalte zu Ende
782 	SwWriteTableCol *pCol = new SwWriteTableCol( nParentWidth );
783 	aCols.Insert( pCol );
784 	CollectTableRowsCols( 0, 0, 0, nParentWidth, rLines, nMaxDepth - 1 );
785 
786 	// Und jetzt mit leben fuellen
787     FillTableRowsCols( 0, 0, 0, 0, 0, nParentWidth, rLines, 0, nMaxDepth - 1, static_cast< sal_uInt16 >(nNumOfRowsToRepeat) );
788 
789 	// Einige Twip-Werte an Pixel-Grenzen anpassen
790 	if( !nBorder )
791 		nBorder = nInnerBorder;
792 }
793 
SwWriteTable(const SwHTMLTableLayout * pLayoutInfo)794 SwWriteTable::SwWriteTable( const SwHTMLTableLayout *pLayoutInfo )
795 	: nBorderColor((sal_uInt32)-1), nCellSpacing(0), nCellPadding(0), nBorder(0),
796 	nInnerBorder(0), nBaseWidth(pLayoutInfo->GetWidthOption()), nHeadEndRow(0),
797 	nLeftSub(0), nRightSub(0), nTabWidth(pLayoutInfo->GetWidthOption()),
798 	bRelWidths(pLayoutInfo->HasPrcWidthOption()), bUseLayoutHeights(false),
799 #ifdef DBG_UTIL
800 	bGetLineHeightCalled(false),
801 #endif
802 	bColsOption(pLayoutInfo->HasColsOption()),
803 	bColTags(pLayoutInfo->HasColTags()), bLayoutExport(true),
804 	bCollectBorderWidth(pLayoutInfo->HaveBordersChanged())
805 {
806 	if( !bCollectBorderWidth )
807 	{
808 		nBorder = pLayoutInfo->GetBorder();
809 		nCellPadding = pLayoutInfo->GetCellPadding();
810 		nCellSpacing = pLayoutInfo->GetCellSpacing();
811 	}
812 
813 	sal_uInt16 nRow, nCol;
814 	sal_uInt16 nCols = pLayoutInfo->GetColCount();
815 	sal_uInt16 nRows = pLayoutInfo->GetRowCount();
816 
817 	// Erstmal die Tabellen-Struktur festlegen.
818 	for( nCol=0; nCol<nCols; nCol++ )
819 	{
820 		SwWriteTableCol *pCol =
821 			new SwWriteTableCol( (nCol+1)*COL_DFLT_WIDTH );
822 
823 		if( bColTags )
824 		{
825 			const SwHTMLTableLayoutColumn *pLayoutCol =
826 				pLayoutInfo->GetColumn( nCol );
827 			pCol->SetWidthOpt( pLayoutCol->GetWidthOption(),
828 							   pLayoutCol->IsRelWidthOption() );
829 		}
830 
831 		aCols.Insert( pCol );
832 	}
833 
834 	for( nRow=0; nRow<nRows; nRow++ )
835 	{
836 		SwWriteTableRow *pRow =
837 			new SwWriteTableRow( (nRow+1)*ROW_DFLT_HEIGHT, bUseLayoutHeights );
838 		pRow->nTopBorder = 0;
839 		pRow->nBottomBorder = 0;
840 		aRows.Insert( pRow );
841 	}
842 
843 	// Und jetzt mit leben fuellen
844 	for( nRow=0; nRow<nRows; nRow++ )
845 	{
846 		SwWriteTableRow *pRow = aRows[nRow];
847 
848 		sal_Bool bHeightExported = sal_False;
849 		for( nCol=0; nCol<nCols; nCol++ )
850 		{
851 			const SwHTMLTableLayoutCell *pLayoutCell =
852 				pLayoutInfo->GetCell( nRow, nCol );
853 
854 			const SwHTMLTableLayoutCnts *pLayoutCnts =
855 				pLayoutCell->GetContents();
856 
857 			// Beginnt die Zelle eigentlich eine Zeile weiter oben oder
858 			// weiter vorne?
859 			if( ( nRow>0 && pLayoutCnts == pLayoutInfo->GetCell(nRow-1,nCol)
860 													  ->GetContents() ) ||
861 				( nCol>0 && pLayoutCnts == pLayoutInfo->GetCell(nRow,nCol-1)
862 													  ->GetContents() ) )
863 			{
864 				continue;
865 			}
866 
867 			sal_uInt16 nRowSpan = pLayoutCell->GetRowSpan();
868 			sal_uInt16 nColSpan = pLayoutCell->GetColSpan();
869 			const SwTableBox *pBox = pLayoutCnts->GetTableBox();
870 			ASSERT( pBox,
871 					"Tabelle in Tabelle kann nicht ueber Layout exportiert werden" );
872 
873 			long nHeight = bHeightExported ? 0 : GetLineHeight( pBox );
874 			const SvxBrushItem *pBrushItem = GetLineBrush( pBox, pRow );
875 
876 			SwWriteTableCell *pCell =
877 				pRow->AddCell( pBox, nRow, nCol, nRowSpan, nColSpan,
878 							   nHeight, pBrushItem );
879 			pCell->SetWidthOpt( pLayoutCell->GetWidthOption(),
880 								pLayoutCell->IsPrcWidthOption() );
881 
882 			sal_uInt16 nTopBorder = USHRT_MAX, nBottomBorder = USHRT_MAX;
883 			sal_uInt16 nBorderMask =
884 			MergeBoxBorders( pBox, nRow, nCol, nRowSpan, nColSpan,
885 								nTopBorder, nBottomBorder );
886 
887 			SwWriteTableCol *pCol = aCols[nCol];
888 			if( !(nBorderMask & 4) )
889 				pCol->bLeftBorder = sal_False;
890 
891 			pCol = aCols[nCol+nColSpan-1];
892 			if( !(nBorderMask & 8) )
893 				pCol->bRightBorder = sal_False;
894 
895 			if( !(nBorderMask & 1) )
896 				pRow->bTopBorder = sal_False;
897 
898 			SwWriteTableRow *pEndRow = aRows[nRow+nRowSpan-1];
899 			if( !(nBorderMask & 2) )
900 				pEndRow->bBottomBorder = sal_False;
901 
902 			// Die Hoehe braucht nur einmal geschieben werden
903 			if( nHeight )
904 				bHeightExported = sal_True;
905 		}
906 	}
907 
908 	// Einige Twip-Werte an Pixel-Grenzen anpassen
909 	if( bCollectBorderWidth && !nBorder )
910 		nBorder = nInnerBorder;
911 }
912 
~SwWriteTable()913 SwWriteTable::~SwWriteTable()
914 {
915 }
916