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