xref: /AOO41X/main/sw/source/filter/writer/wrtswtbl.cxx (revision efeef26f81c84063fb0a91bde3856d4a51172d90)
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