xref: /trunk/main/sw/source/core/doc/htmltbl.cxx (revision e883eadd19c750cfe26756b7f3a4200f3e440102) !
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 
28 //#define TEST_DELAYED_RESIZE
29 
30 #ifdef TEST_DELAYED_RESIZE
31 #include <vcl/sound.hxx>
32 #endif
33 #include <vcl/wrkwin.hxx>
34 #include <vcl/svapp.hxx>
35 #include <sot/storage.hxx>
36 #include <fmtornt.hxx>
37 #include <fmtfsize.hxx>
38 #include <frmfmt.hxx>
39 #include <docary.hxx>
40 #include "ndtxt.hxx"
41 #include "doc.hxx"
42 #include "swtable.hxx"
43 #include "rootfrm.hxx"
44 #include "docsh.hxx"
45 #include "flyfrm.hxx"
46 #include "poolfmt.hxx"
47 #include "viewsh.hxx"
48 #include "tabfrm.hxx"
49 #include "viewopt.hxx"
50 #include "htmltbl.hxx"
51 #include "ndindex.hxx"
52 #include "switerator.hxx"
53 
54 using namespace ::com::sun::star;
55 
56 
57 #define COLFUZZY 20
58 #define MAX_TABWIDTH (USHRT_MAX - 2001)
59 
60 
61 class SwHTMLTableLayoutConstraints
62 {
63     sal_uInt16 nRow;                    // Start-Zeile
64     sal_uInt16 nCol;                    // Start-Spalte
65     sal_uInt16 nColSpan;                // COLSPAN der Zelle
66 
67     SwHTMLTableLayoutConstraints *pNext;        // die naechste Bedingung
68 
69     sal_uLong nMinNoAlign, nMaxNoAlign; // Zwischenergebnisse AL-Pass 1
70 
71 public:
72 
73     SwHTMLTableLayoutConstraints( sal_uLong nMin, sal_uLong nMax, sal_uInt16 nRow,
74                                 sal_uInt16 nCol, sal_uInt16 nColSp );
75     ~SwHTMLTableLayoutConstraints();
76 
77     sal_uLong GetMinNoAlign() const { return nMinNoAlign; }
78     sal_uLong GetMaxNoAlign() const { return nMaxNoAlign; }
79 
80     SwHTMLTableLayoutConstraints *InsertNext( SwHTMLTableLayoutConstraints *pNxt );
81     SwHTMLTableLayoutConstraints* GetNext() const { return pNext; }
82 
83     sal_uInt16 GetRow() const { return nRow; }
84 
85     sal_uInt16 GetColSpan() const { return nColSpan; }
86     sal_uInt16 GetColumn() const { return nCol; }
87 };
88 
89 /*  */
90 
91 SwHTMLTableLayoutCnts::SwHTMLTableLayoutCnts( const SwStartNode *pSttNd,
92                                           SwHTMLTableLayout* pTab,
93                                           sal_Bool bNoBrTag,
94                                           SwHTMLTableLayoutCnts* pNxt ) :
95     pNext( pNxt ), pBox( 0 ), pTable( pTab ), pStartNode( pSttNd ),
96     nPass1Done( 0 ), nWidthSet( 0 ), bNoBreakTag( bNoBrTag )
97 {}
98 
99 SwHTMLTableLayoutCnts::~SwHTMLTableLayoutCnts()
100 {
101     delete pNext;
102     delete pTable;
103 }
104 
105 const SwStartNode *SwHTMLTableLayoutCnts::GetStartNode() const
106 {
107     return pBox ? pBox->GetSttNd() : pStartNode;
108 }
109 
110 
111 /*
112  */
113 
114 SwHTMLTableLayoutCell::SwHTMLTableLayoutCell( SwHTMLTableLayoutCnts *pCnts,
115                                           sal_uInt16 nRSpan, sal_uInt16 nCSpan,
116                                           sal_uInt16 nWidth, sal_Bool bPrcWidth,
117                                           sal_Bool bNWrapOpt ) :
118     pContents( pCnts ),
119     nRowSpan( nRSpan ), nColSpan( nCSpan ),
120     nWidthOption( nWidth ), bPrcWidthOption( bPrcWidth ),
121     bNoWrapOption( bNWrapOpt )
122 {}
123 
124 SwHTMLTableLayoutCell::~SwHTMLTableLayoutCell()
125 {
126     if( nRowSpan==1 && nColSpan==1 )
127     {
128         delete pContents;
129     }
130 }
131 
132 /*
133  */
134 
135 SwHTMLTableLayoutColumn::SwHTMLTableLayoutColumn( sal_uInt16 nWidth,
136                                                   sal_Bool bRelWidth,
137                                                   sal_Bool bLBorder ) :
138     nMinNoAlign(MINLAY), nMaxNoAlign(MINLAY), nAbsMinNoAlign(MINLAY),
139     nMin(0), nMax(0),
140     nAbsColWidth(0), nRelColWidth(0),
141     nWidthOption( nWidth ), bRelWidthOption( bRelWidth ),
142     bLeftBorder( bLBorder )
143 {}
144 
145 
146 /*
147  */
148 
149 SwHTMLTableLayoutConstraints::SwHTMLTableLayoutConstraints(
150     sal_uLong nMin, sal_uLong nMax, sal_uInt16 nRw, sal_uInt16 nColumn, sal_uInt16 nColSp ):
151     nRow( nRw ), nCol( nColumn ), nColSpan( nColSp ),
152     pNext( 0 ),
153     nMinNoAlign( nMin ), nMaxNoAlign( nMax )
154 {}
155 
156 SwHTMLTableLayoutConstraints::~SwHTMLTableLayoutConstraints()
157 {
158     delete pNext;
159 }
160 
161 SwHTMLTableLayoutConstraints *SwHTMLTableLayoutConstraints::InsertNext(
162     SwHTMLTableLayoutConstraints *pNxt )
163 {
164     SwHTMLTableLayoutConstraints *pPrev = 0;
165     SwHTMLTableLayoutConstraints *pConstr = this;
166     while( pConstr )
167     {
168         if( pConstr->GetRow() > pNxt->GetRow() ||
169             pConstr->GetColumn() > pNxt->GetColumn() )
170             break;
171         pPrev = pConstr;
172         pConstr = pConstr->GetNext();
173     }
174 
175     if( pPrev )
176     {
177         pNxt->pNext = pPrev->GetNext();
178         pPrev->pNext = pNxt;
179         pConstr = this;
180     }
181     else
182     {
183         pNxt->pNext = this;
184         pConstr = pNxt;
185     }
186 
187     return pConstr;
188 }
189 
190 /*
191  */
192 
193 typedef SwHTMLTableLayoutColumn *SwHTMLTableLayoutColumnPtr;
194 typedef SwHTMLTableLayoutCell *SwHTMLTableLayoutCellPtr;
195 
196 SwHTMLTableLayout::SwHTMLTableLayout(
197                         const SwTable * pSwTbl,
198                         sal_uInt16 nRws, sal_uInt16 nCls, sal_Bool bColsOpt, sal_Bool bColTgs,
199                         sal_uInt16 nWdth, sal_Bool bPrcWdth, sal_uInt16 nBorderOpt,
200                         sal_uInt16 nCellPad, sal_uInt16 nCellSp, SvxAdjust eAdjust,
201                         sal_uInt16 nLMargin, sal_uInt16 nRMargin,
202                         sal_uInt16 nBWidth, sal_uInt16 nLeftBWidth,
203                         sal_uInt16 nRightBWidth,
204                         sal_uInt16 nInhLeftBWidth, sal_uInt16 nInhRightBWidth ) :
205     aColumns( new SwHTMLTableLayoutColumnPtr[nCls] ),
206     aCells( new SwHTMLTableLayoutCellPtr[nRws*nCls] ),
207     pSwTable( pSwTbl ), pLeftFillerBox( 0 ), pRightFillerBox( 0 ),
208     nMin( 0 ), nMax( 0 ),
209     nRows( nRws ), nCols( nCls ),
210     nLeftMargin( nLMargin ), nRightMargin( nRMargin ),
211     nInhAbsLeftSpace( 0 ), nInhAbsRightSpace( 0 ),
212     nRelLeftFill( 0 ), nRelRightFill( 0 ),
213     nRelTabWidth( 0 ), nWidthOption( nWdth ),
214     nCellPadding( nCellPad ), nCellSpacing( nCellSp ), nBorder( nBorderOpt ),
215     nLeftBorderWidth( nLeftBWidth ), nRightBorderWidth( nRightBWidth ),
216     nInhLeftBorderWidth( nInhLeftBWidth ),
217     nInhRightBorderWidth( nInhRightBWidth ),
218     nBorderWidth( nBWidth ),
219     nDelayedResizeAbsAvail( 0 ), nLastResizeAbsAvail( 0 ),
220     nPass1Done( 0 ), nWidthSet( 0 ), eTableAdjust( eAdjust ),
221     bColsOption( bColsOpt ), bColTags( bColTgs ),
222     bPrcWidthOption( bPrcWdth ), bUseRelWidth( sal_False ),
223     bMustResize( sal_True ), bExportable( sal_True ), bBordersChanged( sal_False ),
224     bMustNotResize( sal_False ), bMustNotRecalc( sal_False )
225 {
226     aResizeTimer.SetTimeoutHdl( STATIC_LINK( this, SwHTMLTableLayout,
227                                              DelayedResize_Impl ) );
228 }
229 
230 SwHTMLTableLayout::~SwHTMLTableLayout()
231 {
232     sal_uInt16 i;
233 
234     for( i = 0; i < nCols; i++ )
235         delete aColumns[i];
236     delete[] aColumns;
237 
238     sal_uInt16 nCount = nRows*nCols;
239     for( i=0; i<nCount; i++ )
240         delete aCells[i];
241     delete[] aCells;
242 }
243 
244 // Die Breiten der Umrandung werden zunaechst wie in Netscape berechnet:
245 // Aeussere Umrandung: BORDER + CELLSPACING + CELLPADDING
246 // Innere Umrandung: CELLSPACING + CELLPADDING
247 // Allerdings wird die Breite der Umrandung im SW trotzdem beachtet, wenn
248 // bSwBorders gesetzt ist, damit nicht faellschlich umgebrochen wird.
249 // MIB 27.6.97: Dabei muss auch der Abstand zum Inhalt beruecksichtigt werden,
250 // und zwar auch dann, wenn wenn nur die gegenueberliegende Seite
251 // eine Umrandung hat.
252 sal_uInt16 SwHTMLTableLayout::GetLeftCellSpace( sal_uInt16 nCol, sal_uInt16 nColSpan,
253                                             sal_Bool bSwBorders ) const
254 {
255     sal_uInt16 nSpace = nCellSpacing + nCellPadding;
256 
257     if( nCol == 0 )
258     {
259         nSpace = nSpace + nBorder;
260 
261         if( bSwBorders && nSpace < nLeftBorderWidth )
262             nSpace = nLeftBorderWidth;
263     }
264     else if( bSwBorders )
265     {
266         if( GetColumn(nCol)->HasLeftBorder() )
267         {
268             if( nSpace < nBorderWidth )
269                 nSpace = nBorderWidth;
270         }
271         else if( nCol+nColSpan == nCols && nRightBorderWidth &&
272                  nSpace < MIN_BORDER_DIST )
273         {
274             ASSERT( !nCellPadding, "GetLeftCellSpace: CELLPADDING!=0" );
275             // Wenn die Gegenueberliegende Seite umrandet ist muessen
276             // wir zumindest den minimalen Abstand zum Inhalt
277             // beruecksichtigen. (Koennte man zusaetzlich auch an
278             // nCellPadding festmachen.)
279             nSpace = MIN_BORDER_DIST;
280         }
281     }
282 
283     return nSpace;
284 }
285 
286 sal_uInt16 SwHTMLTableLayout::GetRightCellSpace( sal_uInt16 nCol, sal_uInt16 nColSpan,
287                                              sal_Bool bSwBorders ) const
288 {
289     sal_uInt16 nSpace = nCellPadding;
290 
291     if( nCol+nColSpan == nCols )
292     {
293         nSpace += nBorder + nCellSpacing;
294         if( bSwBorders && nSpace < nRightBorderWidth )
295             nSpace = nRightBorderWidth;
296     }
297     else if( bSwBorders && GetColumn(nCol)->HasLeftBorder() &&
298              nSpace < MIN_BORDER_DIST )
299     {
300         ASSERT( !nCellPadding, "GetRightCellSpace: CELLPADDING!=0" );
301         // Wenn die Gegenueberliegende Seite umrandet ist muessen
302         // wir zumindest den minimalen Abstand zum Inhalt
303         // beruecksichtigen. (Koennte man zusaetzlich auch an
304         // nCellPadding festmachen.)
305         nSpace = MIN_BORDER_DIST;
306     }
307 
308     return nSpace;
309 }
310 
311 void SwHTMLTableLayout::AddBorderWidth( sal_uLong &rMin, sal_uLong &rMax,
312                                         sal_uLong &rAbsMin,
313                                         sal_uInt16 nCol, sal_uInt16 nColSpan,
314                                         sal_Bool bSwBorders ) const
315 {
316     sal_uLong nAdd = GetLeftCellSpace( nCol, nColSpan, bSwBorders ) +
317                  GetRightCellSpace( nCol, nColSpan, bSwBorders );
318 
319     rMin += nAdd;
320     rMax += nAdd;
321     rAbsMin += nAdd;
322 }
323 
324 void SwHTMLTableLayout::SetBoxWidth( SwTableBox *pBox, sal_uInt16 nCol,
325                              sal_uInt16 nColSpan ) const
326 {
327     SwFrmFmt *pFrmFmt = pBox->GetFrmFmt();
328 
329     // die Breite der Box berechnen
330     SwTwips nFrmWidth = 0;
331     while( nColSpan-- )
332         nFrmWidth += GetColumn( nCol++ )->GetRelColWidth();
333 
334     // und neu setzen
335 
336     pFrmFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nFrmWidth, 0 ));
337 }
338 
339 void SwHTMLTableLayout::GetAvail( sal_uInt16 nCol, sal_uInt16 nColSpan,
340                                   sal_uInt16& rAbsAvail, sal_uInt16& rRelAvail ) const
341 {
342     rAbsAvail = 0;
343     rRelAvail = 0;
344     for( sal_uInt16 i=nCol; i<nCol+nColSpan;i++ )
345     {
346         const SwHTMLTableLayoutColumn *pColumn = GetColumn(i);
347         rAbsAvail = rAbsAvail + pColumn->GetAbsColWidth();
348         rRelAvail = rRelAvail + pColumn->GetRelColWidth();
349     }
350 }
351 
352 sal_uInt16 SwHTMLTableLayout::GetBrowseWidthByVisArea( const SwDoc& rDoc )
353 {
354     ViewShell *pVSh = 0;
355     rDoc.GetEditShell( &pVSh );
356     if( pVSh )
357     {
358         return (sal_uInt16)pVSh->GetBrowseWidth();
359     }
360 
361     return 0;
362 }
363 
364 sal_uInt16 SwHTMLTableLayout::GetBrowseWidth( const SwDoc& rDoc )
365 {
366     // Wenn ein Layout da ist, koennen wir die Breite dort herholen.
367     const SwRootFrm *pRootFrm = rDoc.GetCurrentLayout();    //swmod 080218
368     if( pRootFrm )
369     {
370         const SwFrm *pPageFrm = pRootFrm->GetLower();
371         if( pPageFrm )
372             return (sal_uInt16)pPageFrm->Prt().Width();
373     }
374 
375     // --> OD 2010-05-12 #i91658#
376     // Assertion removed which state that no browse width is available.
377     // Investigation reveals that all calls can handle the case that no browse
378     // width is provided.
379     return GetBrowseWidthByVisArea( rDoc );
380     // <--
381 }
382 
383 sal_uInt16 SwHTMLTableLayout::GetBrowseWidthByTabFrm(
384     const SwTabFrm& rTabFrm ) const
385 {
386     SwTwips nWidth = 0;
387 
388     const SwFrm *pUpper = rTabFrm.GetUpper();
389     if( MayBeInFlyFrame() && pUpper->IsFlyFrm() &&
390         ((const SwFlyFrm *)pUpper)->GetAnchorFrm() )
391     {
392         // Wenn die Tabelle in einem selbst angelegten Rahmen steht, dann ist
393         // die Breite Ankers und nicht die Breite Rahmens von Bedeutung.
394         // Bei Absatz-gebundenen Rahmen werden Absatz-Einzuege nicht beachtet.
395         const SwFrm *pAnchor = ((const SwFlyFrm *)pUpper)->GetAnchorFrm();
396         if( pAnchor->IsTxtFrm() )
397             nWidth = pAnchor->Frm().Width();
398         else
399             nWidth = pAnchor->Prt().Width();
400     }
401     else
402     {
403         nWidth = pUpper->Prt().Width();
404     }
405 
406     SwTwips nUpperDummy = 0;
407     long nRightOffset = 0,
408          nLeftOffset  = 0;
409     rTabFrm.CalcFlyOffsets( nUpperDummy, nLeftOffset, nRightOffset );
410     nWidth -= (nLeftOffset + nRightOffset);
411 
412     return nWidth < USHRT_MAX ? static_cast<sal_uInt16>(nWidth) : USHRT_MAX;
413 }
414 
415 sal_uInt16 SwHTMLTableLayout::GetBrowseWidthByTable( const SwDoc& rDoc ) const
416 {
417     sal_uInt16 nBrowseWidth = 0;
418     SwTabFrm* pFrm = SwIterator<SwTabFrm,SwFmt>::FirstElement( *pSwTable->GetFrmFmt() );
419     if( pFrm )
420     {
421         nBrowseWidth = GetBrowseWidthByTabFrm( *pFrm );
422     }
423     else
424     {
425         nBrowseWidth = SwHTMLTableLayout::GetBrowseWidth( rDoc );
426     }
427 
428     return nBrowseWidth;
429 }
430 
431 const SwStartNode *SwHTMLTableLayout::GetAnyBoxStartNode() const
432 {
433     const SwStartNode *pBoxSttNd;
434 
435     const SwTableBox* pBox = pSwTable->GetTabLines()[0]->GetTabBoxes()[0];
436     while( 0 == (pBoxSttNd = pBox->GetSttNd()) )
437     {
438         ASSERT( pBox->GetTabLines().Count() > 0,
439                 "Box ohne Start-Node und Lines" );
440         ASSERT( pBox->GetTabLines()[0]->GetTabBoxes().Count() > 0,
441                 "Line ohne Boxen" );
442         pBox = pBox->GetTabLines()[0]->GetTabBoxes()[0];
443     }
444 
445     return pBoxSttNd;
446 }
447 
448 SwFrmFmt *SwHTMLTableLayout::FindFlyFrmFmt() const
449 {
450     const SwTableNode *pTblNd = GetAnyBoxStartNode()->FindTableNode();
451     ASSERT( pTblNd, "Kein Table-Node?" );
452     return pTblNd->GetFlyFmt();
453 }
454 
455 static void lcl_GetMinMaxSize( sal_uLong& rMinNoAlignCnts, sal_uLong& rMaxNoAlignCnts,
456                         sal_uLong& rAbsMinNoAlignCnts,
457 #ifdef FIX41370
458                         sal_Bool& rHR,
459 #endif
460                         SwTxtNode *pTxtNd, sal_uLong nIdx, sal_Bool bNoBreak )
461 {
462     pTxtNd->GetMinMaxSize( nIdx, rMinNoAlignCnts, rMaxNoAlignCnts,
463                            rAbsMinNoAlignCnts );
464     ASSERT( rAbsMinNoAlignCnts <= rMinNoAlignCnts,
465             "GetMinMaxSize: absmin > min" );
466     ASSERT( rMinNoAlignCnts <= rMaxNoAlignCnts,
467             "GetMinMaxSize: max > min" );
468 
469     // Bei einen <PRE>-Absatz entspricht die maximale Breite der
470     // minimalen breite
471     const SwFmtColl *pColl = &pTxtNd->GetAnyFmtColl();
472     while( pColl && !pColl->IsDefault() &&
473             (USER_FMT & pColl->GetPoolFmtId()) )
474     {
475         pColl = (const SwFmtColl *)pColl->DerivedFrom();
476     }
477 
478     // <NOBR> in der gesamten Zelle bezieht sich auf Text, aber nicht
479     // auf Tabellen. Netscape beruecksichtigt dies nur fuer Grafiken.
480     if( (pColl && RES_POOLCOLL_HTML_PRE==pColl->GetPoolFmtId()) || bNoBreak )
481     {
482         rMinNoAlignCnts = rMaxNoAlignCnts;
483         rAbsMinNoAlignCnts = rMaxNoAlignCnts;
484     }
485 #ifdef FIX41370
486     else if( pColl && RES_POOLCOLL_HTML_HR==pColl->GetPoolFmtId() )
487     {
488         rHR |= !pTxtNd->HasSwAttrSet() ||
489                 SFX_ITEM_SET != pTxtNd->GetpSwAttrSet()
490                                       ->GetItemState( RES_LR_SPACE, sal_False );
491     }
492 #endif
493 }
494 
495 void SwHTMLTableLayout::AutoLayoutPass1()
496 {
497     nPass1Done++;
498 
499     ClearPass1Info();
500 
501     sal_Bool bFixRelWidths = sal_False;
502     sal_uInt16 i;
503 
504     SwHTMLTableLayoutConstraints *pConstraints = 0;
505 
506     for( i=0; i<nCols; i++ )
507     {
508         SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
509         pColumn->ClearPass1Info( !HasColTags() );
510         sal_uInt16 nMinColSpan = USHRT_MAX; // Spaltenzahl, auf die sich dir
511                                         // berechnete Breite bezieht
512         sal_uInt16 nColSkip = USHRT_MAX;    // Wie viele Spalten muessen
513                                         // uebersprungen werden
514 
515         for( sal_uInt16 j=0; j<nRows; j++ )
516         {
517             SwHTMLTableLayoutCell *pCell = GetCell(j,i);
518             SwHTMLTableLayoutCnts *pCnts = pCell->GetContents();
519 
520             // fix #31488#: Zum Ermitteln der naechsten zu berechnenden
521             // Spalte muessen alle Zeilen herangezogen werden
522             sal_uInt16 nColSpan = pCell->GetColSpan();
523             if( nColSpan < nColSkip )
524                 nColSkip = nColSpan;
525 
526             if( !pCnts || (pCnts && !pCnts->IsPass1Done(nPass1Done)) )
527             {
528                 // die Zelle ist leer oder ihr Inhalt wurde noch nicht
529                 // bearbeitet
530                 if( nColSpan < nMinColSpan )
531                     nMinColSpan = nColSpan;
532 
533                 sal_uLong nMinNoAlignCell = 0;
534                 sal_uLong nMaxNoAlignCell = 0;
535                 sal_uLong nAbsMinNoAlignCell = 0;
536                 sal_uLong nMaxTableCell = 0;
537                 sal_uLong nAbsMinTableCell = 0;
538 #ifdef FIX41370
539                 sal_Bool bHR = sal_False;
540 #endif
541 
542                 while( pCnts )
543                 {
544                     const SwStartNode *pSttNd = pCnts->GetStartNode();
545                     if( pSttNd )
546                     {
547                         const SwDoc *pDoc = pSttNd->GetDoc();
548                         sal_uLong nIdx = pSttNd->GetIndex();
549                         while( !(pDoc->GetNodes()[nIdx])->IsEndNode() )
550                         {
551                             SwTxtNode *pTxtNd = (pDoc->GetNodes()[nIdx])->GetTxtNode();
552                             if( pTxtNd )
553                             {
554                                 sal_uLong nMinNoAlignCnts = 0;
555                                 sal_uLong nMaxNoAlignCnts = 0;
556                                 sal_uLong nAbsMinNoAlignCnts = 0;
557 
558                                 lcl_GetMinMaxSize( nMinNoAlignCnts,
559                                                    nMaxNoAlignCnts,
560                                                    nAbsMinNoAlignCnts,
561 #ifdef FIX41370
562                                                    bHR,
563 #endif
564                                                    pTxtNd, nIdx,
565                                                    pCnts->HasNoBreakTag() );
566 
567                                 if( nMinNoAlignCnts > nMinNoAlignCell )
568                                     nMinNoAlignCell = nMinNoAlignCnts;
569                                 if( nMaxNoAlignCnts > nMaxNoAlignCell )
570                                     nMaxNoAlignCell = nMaxNoAlignCnts;
571                                 if( nAbsMinNoAlignCnts > nAbsMinNoAlignCell )
572                                     nAbsMinNoAlignCell = nAbsMinNoAlignCnts;
573                             }
574                             else
575                             {
576                                 SwTableNode *pTabNd = (pDoc->GetNodes()[nIdx])->GetTableNode();
577                                 if( pTabNd )
578                                 {
579                                     SwHTMLTableLayout *pChild = pTabNd->GetTable().GetHTMLTableLayout();
580                                     if( pChild )
581                                     {
582                                         pChild->AutoLayoutPass1();
583                                         sal_uLong nMaxTableCnts = pChild->nMax;
584                                         sal_uLong nAbsMinTableCnts = pChild->nMin;
585 
586                                         // Eine feste Tabellen-Breite wird als Minimum
587                                         // und Maximum gleichzeitig uebernommen
588                                         if( !pChild->bPrcWidthOption && pChild->nWidthOption )
589                                         {
590                                             sal_uLong nTabWidth = pChild->nWidthOption;
591                                             if( nTabWidth >= nAbsMinTableCnts  )
592                                             {
593                                                 nMaxTableCnts = nTabWidth;
594                                                 nAbsMinTableCnts = nTabWidth;
595                                             }
596                                             else
597                                             {
598                                                 nMaxTableCnts = nAbsMinTableCnts;
599                                             }
600                                         }
601 
602                                         if( nMaxTableCnts > nMaxTableCell )
603                                             nMaxTableCell = nMaxTableCnts;
604                                         if( nAbsMinTableCnts > nAbsMinTableCell )
605                                             nAbsMinTableCell = nAbsMinTableCnts;
606                                     }
607                                     nIdx = pTabNd->EndOfSectionNode()->GetIndex();
608                                 }
609                             }
610                             nIdx++;
611                         }
612                     }
613                     else
614                     {
615                         ASSERT( sal_False, "Sub tables in HTML import?" )
616                         SwHTMLTableLayout *pChild = pCnts->GetTable();
617                         pChild->AutoLayoutPass1();
618                         sal_uLong nMaxTableCnts = pChild->nMax;
619                         sal_uLong nAbsMinTableCnts = pChild->nMin;
620 
621                         // Eine feste Tabellen-Breite wird als Minimum
622                         // und Maximum gleichzeitig uebernommen
623                         if( !pChild->bPrcWidthOption && pChild->nWidthOption )
624                         {
625                             sal_uLong nTabWidth = pChild->nWidthOption;
626                             if( nTabWidth >= nAbsMinTableCnts  )
627                             {
628                                 nMaxTableCnts = nTabWidth;
629                                 nAbsMinTableCnts = nTabWidth;
630                             }
631                             else
632                             {
633                                 nMaxTableCnts = nAbsMinTableCnts;
634                             }
635                         }
636 
637                         if( nMaxTableCnts > nMaxTableCell )
638                             nMaxTableCell = nMaxTableCnts;
639                         if( nAbsMinTableCnts > nAbsMinTableCell )
640                             nAbsMinTableCell = nAbsMinTableCnts;
641                     }
642                     pCnts->SetPass1Done( nPass1Done );
643                     pCnts = pCnts->GetNext();
644                 }
645 
646 // War frueher hinter AddBorderWidth
647                 // Wenn die Breite einer Tabelle in der Zelle breiter ist als
648                 // das, was wir fuer sonstigen Inhalt berechnet haben, muessen
649                 // wir die Breite der Tabelle nutzen
650                 if( nMaxTableCell > nMaxNoAlignCell )
651                     nMaxNoAlignCell = nMaxTableCell;
652                 if( nAbsMinTableCell > nAbsMinNoAlignCell )
653                 {
654                     nAbsMinNoAlignCell = nAbsMinTableCell;
655                     if( nMinNoAlignCell < nAbsMinNoAlignCell )
656                         nMinNoAlignCell = nAbsMinNoAlignCell;
657                     if( nMaxNoAlignCell < nMinNoAlignCell )
658                         nMaxNoAlignCell = nMinNoAlignCell;
659                 }
660 // War frueher hinter AddBorderWidth
661 
662                 sal_Bool bRelWidth = pCell->IsPrcWidthOption();
663                 sal_uInt16 nWidth = pCell->GetWidthOption();
664 
665                 // Eine NOWRAP-Option bezieht sich auf Text und auf
666                 // Tabellen, wird aber bei fester Zellenbreite
667                 // nicht uebernommen. Stattdessen wirkt die angegebene
668                 // Zellenbreite wie eine Mindestbreite.
669                 if( pCell->HasNoWrapOption() )
670                 {
671                     if( nWidth==0 || bRelWidth )
672                     {
673                         nMinNoAlignCell = nMaxNoAlignCell;
674                         nAbsMinNoAlignCell = nMaxNoAlignCell;
675                     }
676                     else
677                     {
678                         if( nWidth>nMinNoAlignCell )
679                             nMinNoAlignCell = nWidth;
680                         if( nWidth>nAbsMinNoAlignCell )
681                             nAbsMinNoAlignCell = nWidth;
682                     }
683                 }
684 #ifdef FIX41370
685                 else if( bHR && nWidth>0 && !bRelWidth )
686                 {
687                     // Ein kleiner Hack, um einen Bug in Netscape 4.0
688                     // nachzubilden (siehe #41370#). Wenn eine Zelle eine
689                     // fixe Breite besitzt und gleichzeitig ein HR, wird
690                     // sie nie schmaler als die angegebene Breite.
691                     // (Genaugenomen scheint die Zelle nie schmaler zu werden
692                     // als die HR-Linie, denn wenn man fuer die Linie eine
693                     // Breite angibt, die breiter ist als die der Zelle, dann
694                     // wird die Zelle so breit wie die Linie. Das bekommen wir
695                     // natuerlich nicht hin.)
696                     if( nWidth>nMinNoAlignCell )
697                         nMinNoAlignCell = nWidth;
698                     if( nWidth>nAbsMinNoAlignCell )
699                         nAbsMinNoAlignCell = nWidth;
700                 }
701 #endif
702 
703                 // Mindestbreite fuer Inhalt einhalten
704                 if( nMinNoAlignCell < MINLAY )
705                     nMinNoAlignCell = MINLAY;
706                 if( nMaxNoAlignCell < MINLAY )
707                     nMaxNoAlignCell = MINLAY;
708                 if( nAbsMinNoAlignCell < MINLAY )
709                     nAbsMinNoAlignCell = MINLAY;
710 
711                 // Umrandung und Abstand zum Inhalt beachten.
712                 AddBorderWidth( nMinNoAlignCell, nMaxNoAlignCell,
713                                 nAbsMinNoAlignCell, i, nColSpan );
714 
715                 if( 1==nColSpan )
716                 {
717                     // die Werte direkt uebernehmen
718                     pColumn->MergeMinMaxNoAlign( nMinNoAlignCell,
719                                                  nMaxNoAlignCell,
720                                                  nAbsMinNoAlignCell );
721 
722                     // bei den WIDTH angaben gewinnt die breiteste
723                     if( !HasColTags() )
724                         pColumn->MergeCellWidthOption( nWidth, bRelWidth );
725                 }
726                 else
727                 {
728                     // die Angaben erst am Ende, und zwar zeilenweise von
729                     // links nach rechts bearbeiten
730 
731                     // Wann welche Werte wie uebernommen werden ist weiter
732                     // unten erklaert.
733                     if( !HasColTags() && nWidth && !bRelWidth )
734                     {
735                         sal_uLong nAbsWidth = nWidth, nDummy = 0, nDummy2 = 0;
736                         AddBorderWidth( nAbsWidth, nDummy, nDummy2,
737                                         i, nColSpan, sal_False );
738 
739                         if( nAbsWidth >= nMinNoAlignCell )
740                         {
741                             nMaxNoAlignCell = nAbsWidth;
742                             if( HasColsOption() )
743                                 nMinNoAlignCell = nAbsWidth;
744                         }
745                         else if( nAbsWidth >= nAbsMinNoAlignCell )
746                         {
747                             nMaxNoAlignCell = nAbsWidth;
748                             nMinNoAlignCell = nAbsWidth;
749                         }
750                         else
751                         {
752                             nMaxNoAlignCell = nAbsMinNoAlignCell;
753                             nMinNoAlignCell = nAbsMinNoAlignCell;
754                         }
755                     }
756                     else if( HasColsOption() || HasColTags() )
757                         nMinNoAlignCell = nAbsMinNoAlignCell;
758 
759                     SwHTMLTableLayoutConstraints *pConstr =
760                         new SwHTMLTableLayoutConstraints( nMinNoAlignCell,
761                             nMaxNoAlignCell, j, i, nColSpan );
762                     if( pConstraints )
763                         pConstraints = pConstraints->InsertNext( pConstr );
764                     else
765                         pConstraints = pConstr;
766                 }
767             }
768         }
769 
770         ASSERT( nMinColSpan>0 && nColSkip>0 && nColSkip <= nMinColSpan,
771                 "Layout Pass 1: Da werden Spalten vergessen!" );
772         ASSERT( nMinColSpan!=USHRT_MAX,
773                 "Layout Pass 1: unnoetiger Schleifendurchlauf oder Bug" );
774 
775         if( 1==nMinColSpan )
776         {
777             // es gibt Zellen mit COLSPAN 1 und demnach auch sinnvolle
778             // Werte in pColumn
779 
780             // Werte anhand folgender Tabelle (Netscape 4.0 pv 3) uebernehmen:
781             //
782             // WIDTH:           kein COLS       COLS
783             //
784             // keine            min = min       min = absmin
785             //                  max = max       max = max
786             //
787             // >= min           min = min       min = width
788             //                  max = width     max = width
789             //
790             // >= absmin        min = wdith(*)  min = width
791             //                  max = width     max = width
792             //
793             // < absmin         min = absmin    min = absmin
794             //                  max = absmin    max = absmin
795             //
796             // (*) Netscape benutzt hier die Mindestbreite ohne einen
797             //     Umbruch vor der letzten Grafik. Haben wir (noch?) nicht,
798             //     also belassen wir es bei width.^
799 
800             if( pColumn->GetWidthOption() && !pColumn->IsRelWidthOption() )
801             {
802                 // absolute Breiten als Minimal- und Maximalbreite
803                 // uebernehmen.
804                 sal_uLong nAbsWidth = pColumn->GetWidthOption();
805                 sal_uLong nDummy = 0, nDummy2 = 0;
806                 AddBorderWidth( nAbsWidth, nDummy, nDummy2, i, 1, sal_False );
807 
808                 if( nAbsWidth >= pColumn->GetMinNoAlign() )
809                 {
810                     pColumn->SetMinMax( HasColsOption() ? nAbsWidth
811                                                    : pColumn->GetMinNoAlign(),
812                                         nAbsWidth );
813                 }
814                 else if( nAbsWidth >= pColumn->GetAbsMinNoAlign() )
815                 {
816                     pColumn->SetMinMax( nAbsWidth, nAbsWidth );
817                 }
818                 else
819                 {
820                     pColumn->SetMinMax( pColumn->GetAbsMinNoAlign(),
821                                         pColumn->GetAbsMinNoAlign() );
822                 }
823             }
824             else
825             {
826                 pColumn->SetMinMax( HasColsOption() ? pColumn->GetAbsMinNoAlign()
827                                                : pColumn->GetMinNoAlign(),
828                                     pColumn->GetMaxNoAlign() );
829             }
830         }
831         else if( USHRT_MAX!=nMinColSpan )
832         {
833             // kann irgendwas !=0 sein, weil es durch die Constraints
834             // angepasst wird.
835             pColumn->SetMinMax( MINLAY, MINLAY );
836 
837             // die naechsten Spalten muessen nicht bearbeitet werden
838             i += (nColSkip-1);
839         }
840 
841         nMin += pColumn->GetMin();
842         nMax += pColumn->GetMax();
843         bFixRelWidths |= pColumn->IsRelWidthOption();
844     }
845 
846     // jetzt noch die Constrains verarbeiten
847     SwHTMLTableLayoutConstraints *pConstr = pConstraints;
848     while( pConstr )
849     {
850         // Erstmal muss die Breite analog zu den den Spaltenbreiten
851         // aufbereitet werden
852         sal_uInt16 nCol = pConstr->GetColumn();
853         sal_uInt16 nColSpan = pConstr->GetColSpan();
854         sal_uLong nConstrMin = pConstr->GetMinNoAlign();
855         sal_uLong nConstrMax = pConstr->GetMaxNoAlign();
856 
857         // jetzt holen wir uns die bisherige Breite der ueberspannten
858         // Spalten
859         sal_uLong nColsMin = 0;
860         sal_uLong nColsMax = 0;
861         for( sal_uInt16 j=nCol; j<nCol+nColSpan; j++ )
862         {
863             SwHTMLTableLayoutColumn *pColumn = GetColumn( j );
864             nColsMin += pColumn->GetMin();
865             nColsMax += pColumn->GetMax();
866         }
867 
868         if( nColsMin<nConstrMin )
869         {
870             // den Minimalwert anteilig auf die Spalten verteilen
871             sal_uLong nMinD = nConstrMin-nColsMin;
872 
873             if( nConstrMin > nColsMax )
874             {
875                 // Anteilig anhand der Mindestbreiten
876                 sal_uInt16 nEndCol = nCol+nColSpan;
877                 sal_uLong nDiff = nMinD;
878                 for( sal_uInt16 ic=nCol; ic<nEndCol; ic++ )
879                 {
880                     SwHTMLTableLayoutColumn *pColumn = GetColumn( ic );
881 
882                     sal_uLong nColMin = pColumn->GetMin();
883                     sal_uLong nColMax = pColumn->GetMax();
884 
885                     nMin -= nColMin;
886                     sal_uLong nAdd = ic<nEndCol-1 ? (nColMin * nMinD) / nColsMin
887                                              : nDiff;
888                     nColMin += nAdd;
889                     nMin += nColMin;
890                     ASSERT( nDiff >= nAdd, "Ooops: nDiff stimmt nicht mehr" );
891                     nDiff -= nAdd;
892 
893                     if( nColMax < nColMin )
894                     {
895                         nMax -= nColMax;
896                         nColsMax -= nColMax;
897                         nColMax = nColMin;
898                         nMax += nColMax;
899                         nColsMax += nColMax;
900                     }
901 
902                     pColumn->SetMinMax( nColMin, nColMax );
903                 }
904             }
905             else
906             {
907                 // Anteilig anhand der Differenz zwischen Max und Min
908                 for( sal_uInt16 ic=nCol; ic<nCol+nColSpan; ic++ )
909                 {
910                     SwHTMLTableLayoutColumn *pColumn = GetColumn( ic );
911 
912                     sal_uLong nDiff = pColumn->GetMax()-pColumn->GetMin();
913                     if( nMinD < nDiff )
914                         nDiff = nMinD;
915 
916                     pColumn->AddToMin( nDiff );
917 
918                     ASSERT( pColumn->GetMax() >= pColumn->GetMin(),
919                             "Wieso ist die SPalte auf einmal zu schmal?" )
920 
921                     nMin += nDiff;
922                     nMinD -= nDiff;
923                 }
924             }
925         }
926 
927         if( !HasColTags() && nColsMax<nConstrMax )
928         {
929             sal_uLong nMaxD = nConstrMax-nColsMax;
930 
931             for( sal_uInt16 ic=nCol; ic<nCol+nColSpan; ic++ )
932             {
933                 SwHTMLTableLayoutColumn *pColumn = GetColumn( ic );
934 
935                 nMax -= pColumn->GetMax();
936 
937                 pColumn->AddToMax( (pColumn->GetMax() * nMaxD) / nColsMax );
938 
939                 nMax += pColumn->GetMax();
940             }
941         }
942 
943         pConstr = pConstr->GetNext();
944     }
945 
946 
947     if( bFixRelWidths )
948     {
949         if( HasColTags() )
950         {
951             // Zum Anpassen der relativen Breiten werden im 1. Schritt die
952             // Minimalbreiten aller anzupassenden Zellen jeweils mit der
953             // relativen Breite einer Spalte multipliziert. Dadurch stimmen
954             // dann die Breitenverhaeltnisse der Spalten untereinander.
955             // Ausserdem wird der Faktor berechnet, um den die Zelle dadurch
956             // breiter geworden ist als die Minimalbreite.
957             // Im 2. Schritt werden dann die berechneten Breiten durch diesen
958             // Faktor geteilt. Dadurch bleibt die Breite (mind.) einer Zelle
959             // erhalten und dient als Ausgangsbasis fuer die andern Breiten.
960             // Es werden auch hier nur die Maximalbreiten beeinflusst!
961 
962             sal_uLong nAbsMin = 0;  // absolute Min-Breite alter Spalten mit
963                                 // relativer Breite
964             sal_uLong nRel = 0;     // Summe der relativen Breiten aller Spalten
965             for( i=0; i<nCols; i++ )
966             {
967                 SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
968                 if( pColumn->IsRelWidthOption() && pColumn->GetWidthOption() )
969                 {
970                     nAbsMin += pColumn->GetMin();
971                     nRel += pColumn->GetWidthOption();
972                 }
973             }
974 
975             sal_uLong nQuot = ULONG_MAX;
976             for( i=0; i<nCols; i++ )
977             {
978                 SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
979                 if( pColumn->IsRelWidthOption() )
980                 {
981                     nMax -= pColumn->GetMax();
982                     if( pColumn->GetWidthOption() && pColumn->GetMin() )
983                     {
984                         pColumn->SetMax( nAbsMin * pColumn->GetWidthOption() );
985                         sal_uLong nColQuot = pColumn->GetMax() / pColumn->GetMin();
986                         if( nColQuot<nQuot )
987                             nQuot = nColQuot;
988                     }
989                 }
990             }
991             ASSERT( 0==nRel || nQuot!=ULONG_MAX,
992                     "Wo sind die relativen Spalten geblieben?" );
993             for( i=0; i<nCols; i++ )
994             {
995                 SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
996                 if( pColumn->IsRelWidthOption() )
997                 {
998                     if( pColumn->GetWidthOption() )
999                         pColumn->SetMax( pColumn->GetMax() / nQuot );
1000                     else
1001                         pColumn->SetMax( pColumn->GetMin() );
1002                     ASSERT( pColumn->GetMax() >= pColumn->GetMin(),
1003                             "Maximale Spaltenbreite kleiner als Minimale" );
1004                     nMax += pColumn->GetMax();
1005                 }
1006             }
1007         }
1008         else
1009         {
1010             sal_uInt16 nRel = 0;        // Summe der relativen Breiten aller Spalten
1011             sal_uInt16 nRelCols = 0;    // Anzahl Spalten mit relativer Angabe
1012             sal_uLong nRelMax = 0;      // Anteil am Maximum dieser Spalten
1013             for( i=0; i<nCols; i++ )
1014             {
1015                 ASSERT( nRel<=100, "relative Breite aller Spalten>100%" );
1016                 SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
1017                 if( pColumn->IsRelWidthOption() && pColumn->GetWidthOption() )
1018                 {
1019                     // Sicherstellen, dass die relativen breiten nicht
1020                     // ueber 100% landen
1021                     sal_uInt16 nColWidth = pColumn->GetWidthOption();
1022                     if( nRel+nColWidth > 100 )
1023                     {
1024                         nColWidth = 100 - nRel;
1025                         pColumn->SetWidthOption( nColWidth, sal_True, sal_False );
1026                     }
1027                     nRelMax += pColumn->GetMax();
1028                     nRel = nRel + nColWidth;
1029                     nRelCols++;
1030                 }
1031                 else if( !pColumn->GetMin() )
1032                 {
1033                     // Die Spalte ist leer (wurde also ausschliesslich
1034                     // durch COLSPAN erzeugt) und darf deshalb auch
1035                     // keine %-Breite zugewiesen bekommen.
1036                     nRelCols++;
1037                 }
1038             }
1039 
1040             // Eventuell noch vorhandene Prozente werden auf die Spalten ohne
1041             // eine Breiten-Angabe verteilt. Wie in Netscape werden die
1042             // verbleibenden Prozente entsprechend der Verhaeltnisse
1043             // der Maximalbreiten der in Frage kommenden Spalten
1044             // untereinander verteilt.
1045             // ??? Wie beruecksichtigen bei den Maximalbreiten auch Spalten
1046             // mit fester Breite. Ist das richtig???
1047             if( nRel < 100 && nRelCols < nCols )
1048             {
1049                 sal_uInt16 nRelLeft = 100 - nRel;
1050                 sal_uLong nFixMax = nMax - nRelMax;
1051                 for( i=0; i<nCols; i++ )
1052                 {
1053                     SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
1054                     if( !pColumn->IsRelWidthOption() &&
1055                         !pColumn->GetWidthOption() &&
1056                         pColumn->GetMin() )
1057                     {
1058                         // den Rest bekommt die naechste Spalte
1059                         sal_uInt16 nColWidth =
1060                             (sal_uInt16)((pColumn->GetMax() * nRelLeft) / nFixMax);
1061                         pColumn->SetWidthOption( nColWidth, sal_True, sal_False );
1062                     }
1063                 }
1064             }
1065 
1066             // nun die Maximalbreiten entsprechend anpassen
1067             sal_uLong nQuotMax = ULONG_MAX;
1068             sal_uLong nOldMax = nMax;
1069             nMax = 0;
1070             for( i=0; i<nCols; i++ )
1071             {
1072                 // Spalten mit %-Angaben werden entsprechend angepasst.
1073                 // Spalten, die
1074                 // - keine %-Angabe besitzen und in einer Tabelle mit COLS
1075                 //   oder WIDTH vorkommen, oder
1076                 // - als Breite 0% angegeben haben erhalten die Minimalbreite
1077                 SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
1078                 if( pColumn->IsRelWidthOption() && pColumn->GetWidthOption() )
1079                 {
1080                     sal_uLong nNewMax;
1081                     sal_uLong nColQuotMax;
1082                     if( !nWidthOption )
1083                     {
1084                         nNewMax = nOldMax * pColumn->GetWidthOption();
1085                         nColQuotMax = nNewMax / pColumn->GetMax();
1086                     }
1087                     else
1088                     {
1089                         nNewMax = nMin * pColumn->GetWidthOption();
1090                         nColQuotMax = nNewMax / pColumn->GetMin();
1091                     }
1092                     pColumn->SetMax( nNewMax );
1093                     if( nColQuotMax < nQuotMax )
1094                         nQuotMax = nColQuotMax;
1095                 }
1096                 else if( HasColsOption() || nWidthOption ||
1097                          (pColumn->IsRelWidthOption() &&
1098                           !pColumn->GetWidthOption()) )
1099                     pColumn->SetMax( pColumn->GetMin() );
1100             }
1101             // und durch den Quotienten teilen
1102             ASSERT( nQuotMax!=ULONG_MAX, "Wo sind die relativen Spalten geblieben?" );
1103             for( i=0; i<nCols; i++ )
1104             {
1105                 SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
1106                 if( pColumn->IsRelWidthOption() && pColumn->GetWidthOption() )
1107                 {
1108                     if( pColumn->GetWidthOption() )
1109                     {
1110                         pColumn->SetMax( pColumn->GetMax() / nQuotMax );
1111                         ASSERT( pColumn->GetMax() >= pColumn->GetMin(),
1112                                 "Minimalbreite ein Spalte Groesser Maximum" );
1113                         if( pColumn->GetMax() < pColumn->GetMin() )
1114                             pColumn->SetMax( pColumn->GetMin() );
1115                     }
1116                 }
1117                 nMax += pColumn->GetMax();
1118             }
1119         }
1120     }
1121 
1122     delete pConstraints;
1123 }
1124 
1125 // nAbsAvail ist der verfuegbare Platz in TWIPS.
1126 // nRelAvail ist der auf USHRT_MAX bezogene verfuegbare Platz oder 0
1127 // nAbsSpace ist der Anteil von nAbsAvail, der durch der umgebende Zelle
1128 //           fur die Umrandung und den Abstand zum Inhalt reserviert ist.
1129 void SwHTMLTableLayout::AutoLayoutPass2( sal_uInt16 nAbsAvail, sal_uInt16 nRelAvail,
1130                                          sal_uInt16 nAbsLeftSpace,
1131                                          sal_uInt16 nAbsRightSpace,
1132                                          sal_uInt16 nParentInhAbsSpace )
1133 {
1134     // Erstmal fuehren wie jede Menge Plausibilitaets-Test durch
1135 
1136     // Eine absolute zur Verfuegung stehende Breite muss immer uebergeben
1137     // werden.
1138     ASSERT( nAbsAvail, "AutoLayout Pass 2: Keine absolute Breite gegeben" );
1139 
1140     // Eine realtive zur Verfuegung stehende Breite darf nur und muss fuer
1141     // Tabellen in Tabellen uebergeben
1142     ASSERT( IsTopTable() == (nRelAvail==0),
1143             "AutoLayout Pass 2: Rel. Breite bei Tab in Tab oder umgekehrt" );
1144 
1145     // Die Minimalbreite der Tabelle darf natuerlich nie groesser sein
1146     // als das die Maximalbreite.
1147     ASSERT( nMin<=nMax, "AutoLayout Pass2: nMin > nMax" );
1148 
1149     // Die verfuegbare Breite, fuer die die Tabelle berechnet wurde, merken.
1150     // (Dies ist ein guter Ort, denn hier kommen wir bei der Erstberechnung
1151     // der Tabelle aus dem Parser und bei jedem _Resize-Aufruf vorbei.)
1152     nLastResizeAbsAvail = nAbsAvail;
1153 
1154     // Schritt 1: Der verfuegbare Platz wird an linke/rechte Raender,
1155     // vorhandene Filler-Zellen und Abstaende angepasst
1156 
1157     // Abstand zum Inhalt und Unrandung
1158     sal_uInt16 nAbsLeftFill = 0, nAbsRightFill = 0;
1159     if( !IsTopTable() &&
1160         GetMin() + nAbsLeftSpace + nAbsRightSpace <= nAbsAvail )
1161     {
1162         nAbsLeftFill = nAbsLeftSpace;
1163         nAbsRightFill = nAbsRightSpace;
1164     }
1165 
1166     // Linker und rechter Abstand
1167     if( nLeftMargin || nRightMargin )
1168     {
1169         if( IsTopTable() )
1170         {
1171             // fuer die Top-Table beruecksichtigen wir die Raender immer,
1172             // den die Minimalbreite der Tabelle wird hier nie unterschritten
1173             nAbsAvail -= (nLeftMargin + nRightMargin);
1174         }
1175         else if( GetMin() + nLeftMargin + nRightMargin <= nAbsAvail )
1176         {
1177             // sonst beruecksichtigen wir die Raender nur, wenn auch Platz
1178             // fuer sie da ist (nMin ist hier bereits berechnet!)
1179             nAbsLeftFill = nAbsLeftFill + nLeftMargin;
1180             nAbsRightFill = nAbsRightFill + nRightMargin;
1181         }
1182     }
1183 
1184     // Filler-Zellen
1185     if( !IsTopTable() )
1186     {
1187         if( pLeftFillerBox && nAbsLeftFill<MINLAY+nInhLeftBorderWidth )
1188             nAbsLeftFill = MINLAY+nInhLeftBorderWidth;
1189         if( pRightFillerBox && nAbsRightFill<MINLAY+nInhRightBorderWidth )
1190             nAbsRightFill = MINLAY+nInhRightBorderWidth;
1191     }
1192 
1193     // Anpassen des verfuegbaren Platzes.
1194     nRelLeftFill = 0;
1195     nRelRightFill = 0;
1196     if( !IsTopTable() && (nAbsLeftFill>0 || nAbsRightFill) )
1197     {
1198         sal_uLong nAbsLeftFillL = nAbsLeftFill, nAbsRightFillL = nAbsRightFill;
1199 
1200         nRelLeftFill = (sal_uInt16)((nAbsLeftFillL * nRelAvail) / nAbsAvail);
1201         nRelRightFill = (sal_uInt16)((nAbsRightFillL * nRelAvail) / nAbsAvail);
1202 
1203         nAbsAvail -= (nAbsLeftFill + nAbsRightFill);
1204         if( nRelAvail )
1205             nRelAvail -= (nRelLeftFill + nRelRightFill);
1206     }
1207 
1208 
1209     // Schritt 2: Die absolute Tabellenbreite wird berechnet.
1210     sal_uInt16 nAbsTabWidth = 0;
1211     bUseRelWidth = sal_False;
1212     if( nWidthOption )
1213     {
1214         if( bPrcWidthOption )
1215         {
1216             ASSERT( nWidthOption<=100, "Prozentangabe zu gross" );
1217             if( nWidthOption > 100 )
1218                 nWidthOption = 100;
1219 
1220             // Die absolute Breite entspricht den angegeben Prozent der
1221             // zur Verfuegung stehenden Breite.
1222             // Top-Tabellen bekommen nur eine relative Breite, wenn der
1223             // verfuegbare Platz *echt groesser* ist als die Minimalbreite.
1224             // ACHTUNG: Das "echte groesser" ist noetig, weil der Wechsel
1225             // von einer relativen Breite zu einer absoluten Breite durch
1226             // Resize sonst zu einer Endlosschleife fuehrt.
1227             // Weil bei Tabellen in Rahmen kein Resize aufgerufen wird,
1228             // wenn der Rahmen eine nicht-relative Breite besitzt, koennen
1229             // wir da solche Spielchen nicht spielen
1230             // MIB 19.2.98: Wegen fix #47394# spielen wir solche Spielchen
1231             // jetzt doch. Dort war eine Grafik in einer 1%-breiten
1232             // Tabelle und hat da natuerlich nicht hineingepasst.
1233             nAbsTabWidth = (sal_uInt16)( ((sal_uLong)nAbsAvail * nWidthOption) / 100 );
1234             if( IsTopTable() &&
1235                 ( /*MayBeInFlyFrame() ||*/ (sal_uLong)nAbsTabWidth > nMin ) )
1236             {
1237                 nRelAvail = USHRT_MAX;
1238                 bUseRelWidth = sal_True;
1239             }
1240         }
1241         else
1242         {
1243             nAbsTabWidth = nWidthOption;
1244             if( nAbsTabWidth > MAX_TABWIDTH )
1245                 nAbsTabWidth = MAX_TABWIDTH;
1246 
1247             // Tabellen in Tabellen duerfen niemals breiter werden als der
1248             // verfuegbare Platz.
1249             if( !IsTopTable() && nAbsTabWidth > nAbsAvail )
1250                 nAbsTabWidth = nAbsAvail;
1251         }
1252     }
1253 
1254     ASSERT( IsTopTable() || nAbsTabWidth<=nAbsAvail,
1255             "AutoLayout Pass2: nAbsTabWidth > nAbsAvail fuer Tab in Tab" );
1256     ASSERT( !nRelAvail || nAbsTabWidth<=nAbsAvail,
1257             "AutoLayout Pass2: nAbsTabWidth > nAbsAvail fuer relative Breite" );
1258 
1259     // Catch fuer die beiden Asserts von oben (man weiss ja nie!)
1260     if( (!IsTopTable() || nRelAvail>0) && nAbsTabWidth>nAbsAvail )
1261         nAbsTabWidth = nAbsAvail;
1262 
1263 
1264     // Schritt 3: Bestimmen der Spaltenbreiten und ggf. auch der
1265     // absoluten und relativen Tabellenbreiten.
1266     if( (!IsTopTable() && nMin > (sal_uLong)nAbsAvail) ||
1267         nMin > MAX_TABWIDTH )
1268     {
1269         // Wenn
1270         // - das Minimum einer inneren Tabelle groesser ist als der
1271         //   verfuegbare Platz, oder
1272         // - das Minimum einer Top-Table groesser ist als USHRT_MAX
1273         // muss die Tabelle an den verfuegbaren Platz bzw. USHRT_MAX
1274         // abgepasst werden. Dabei bleiben die Verhaeltnisse der Breiten
1275         // untereinander erhalten.
1276 
1277         nAbsTabWidth = IsTopTable() ? MAX_TABWIDTH : nAbsAvail;
1278         nRelTabWidth = (nRelAvail ? nRelAvail : nAbsTabWidth );
1279 
1280         // First of all, we check whether we can fit the layout constrains,
1281         // that are: Every cell's width excluding the borders must be at least
1282         // MINLAY:
1283 
1284         sal_uLong nRealMin = 0;
1285         for( sal_uInt16 i=0; i<nCols; i++ )
1286         {
1287             sal_uLong nRealColMin = MINLAY, nDummy1, nDummy2;
1288             AddBorderWidth( nRealColMin, nDummy1, nDummy2, i, 1 );
1289             nRealMin += nRealColMin;
1290         }
1291         if( (nRealMin >= nAbsTabWidth) || (nRealMin >= nMin) )
1292         {
1293             // "Nichts geht mehr". We cannot get the minimum column widths
1294             // the layout wants to have.
1295 
1296             sal_uInt16 nAbs = 0, nRel = 0;
1297             SwHTMLTableLayoutColumn *pColumn;
1298             for( sal_uInt16 i=0; i<nCols-1; i++ )
1299             {
1300                 pColumn = GetColumn( i );
1301                 sal_uLong nColMin = pColumn->GetMin();
1302                 if( nColMin <= USHRT_MAX )
1303                 {
1304                     pColumn->SetAbsColWidth(
1305                         (sal_uInt16)((nColMin * nAbsTabWidth) / nMin) );
1306                     pColumn->SetRelColWidth(
1307                         (sal_uInt16)((nColMin * nRelTabWidth) / nMin) );
1308                 }
1309                 else
1310                 {
1311                     double nColMinD = nColMin;
1312                     pColumn->SetAbsColWidth(
1313                         (sal_uInt16)((nColMinD * nAbsTabWidth) / nMin) );
1314                     pColumn->SetRelColWidth(
1315                         (sal_uInt16)((nColMinD * nRelTabWidth) / nMin) );
1316                 }
1317 
1318                 nAbs = nAbs + (sal_uInt16)pColumn->GetAbsColWidth();
1319                 nRel = nRel + (sal_uInt16)pColumn->GetRelColWidth();
1320             }
1321             pColumn = GetColumn( nCols-1 );
1322             pColumn->SetAbsColWidth( nAbsTabWidth - nAbs );
1323             pColumn->SetRelColWidth( nRelTabWidth - nRel );
1324         }
1325         else
1326         {
1327             sal_uLong nDistAbs = nAbsTabWidth - nRealMin;
1328             sal_uLong nDistRel = nRelTabWidth - nRealMin;
1329             sal_uLong nDistMin = nMin - nRealMin;
1330             sal_uInt16 nAbs = 0, nRel = 0;
1331             SwHTMLTableLayoutColumn *pColumn;
1332             for( sal_uInt16 i=0; i<nCols-1; i++ )
1333             {
1334                 pColumn = GetColumn( i );
1335                 sal_uLong nColMin = pColumn->GetMin();
1336                 sal_uLong nRealColMin = MINLAY, nDummy1, nDummy2;
1337                 AddBorderWidth( nRealColMin, nDummy1, nDummy2, i, 1 );
1338 
1339                 if( nColMin <= USHRT_MAX )
1340                 {
1341                     pColumn->SetAbsColWidth(
1342                         (sal_uInt16)((((nColMin-nRealColMin) * nDistAbs) / nDistMin) + nRealColMin) );
1343                     pColumn->SetRelColWidth(
1344                         (sal_uInt16)((((nColMin-nRealColMin) * nDistRel) / nDistMin) + nRealColMin) );
1345                 }
1346                 else
1347                 {
1348                     double nColMinD = nColMin;
1349                     pColumn->SetAbsColWidth(
1350                         (sal_uInt16)((((nColMinD-nRealColMin) * nDistAbs) / nDistMin) + nRealColMin) );
1351                     pColumn->SetRelColWidth(
1352                         (sal_uInt16)((((nColMinD-nRealColMin) * nDistRel) / nDistMin) + nRealColMin) );
1353                 }
1354 
1355                 nAbs = nAbs + (sal_uInt16)pColumn->GetAbsColWidth();
1356                 nRel = nRel + (sal_uInt16)pColumn->GetRelColWidth();
1357             }
1358             pColumn = GetColumn( nCols-1 );
1359             pColumn->SetAbsColWidth( nAbsTabWidth - nAbs );
1360             pColumn->SetRelColWidth( nRelTabWidth - nRel );
1361         }
1362     }
1363     else if( nMax <= (sal_uLong)(nAbsTabWidth ? nAbsTabWidth : nAbsAvail) )
1364     {
1365         // Wenn
1366         // - die Tabelle eine fixe Breite besitzt und das Maximum der
1367         //   Tabelle kleiner ist, oder
1368         // - das Maximum kleiner ist als der verfuegbare Platz
1369         // kann das Maximum direkt uebernommen werden bzw. die Tabelle nur
1370         // unter Beruecksichtigung des Maximums an die fixe Breite
1371         // angepasst werden.
1372 
1373         // Keine fixe Breite, dann das Maximum nehmen.
1374         if( !nAbsTabWidth )
1375             nAbsTabWidth = (sal_uInt16)nMax;
1376 
1377         // Eine Top-Table darf auch breiter werden als der verfuegbare Platz.
1378         if( nAbsTabWidth > nAbsAvail )
1379         {
1380             ASSERT( IsTopTable(),
1381                     "Tabelle in Tabelle soll breiter werden als umgebende Zelle" );
1382             nAbsAvail = nAbsTabWidth;
1383         }
1384 
1385         // Nur den Anteil der relativen Breite verwenden, der auch fuer
1386         // die absolute Breite verwendet wuerde.
1387         sal_uLong nAbsTabWidthL = nAbsTabWidth;
1388         nRelTabWidth =
1389             ( nRelAvail ? (sal_uInt16)((nAbsTabWidthL * nRelAvail) / nAbsAvail)
1390                         : nAbsTabWidth );
1391 
1392         // Gibt es Spalten mit und Spalten ohne %-Angabe?
1393         sal_uLong nFixMax = nMax;
1394         for( sal_uInt16 i=0; i<nCols; i++ )
1395         {
1396             const SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
1397             if( pColumn->IsRelWidthOption() && pColumn->GetWidthOption()>0 )
1398                 nFixMax -= pColumn->GetMax();
1399         }
1400 
1401         if( nFixMax > 0 && nFixMax < nMax )
1402         {
1403             // ja, dann den zu verteilenden Platz nur auf die Spalten
1404             // mit %-Angabe verteilen.
1405 
1406             // In diesem (und nur in diesem) Fall gibt es Spalten,
1407             // die ihre Maximalbreite genau einhalten, also weder
1408             // schmaler noch breiter werden. Beim zurueckrechnen der
1409             // absoluten Breite aus der relativen Breite kann es
1410             // zu Rundungsfehlern kommen (bug #45598#). Um die auszugleichen
1411             // werden zuerst die fixen Breiten entsprechend korrigiert
1412             // eingestellt und erst danach die relativen.
1413 
1414             sal_uInt16 nAbs = 0, nRel = 0;
1415             sal_uInt16 nFixedCols = 0;
1416             sal_uInt16 i;
1417 
1418             for( i = 0; i < nCols; i++ )
1419             {
1420                 SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
1421                 if( !pColumn->IsRelWidthOption() || !pColumn->GetWidthOption() )
1422                 {
1423                     // Die Spalte behaelt ihre Breite bei.
1424                     nFixedCols++;
1425                     sal_uLong nColMax = pColumn->GetMax();
1426                     pColumn->SetAbsColWidth( (sal_uInt16)nColMax );
1427 
1428                     sal_uLong nRelColWidth =
1429                         (nColMax * nRelTabWidth) / nAbsTabWidth;
1430                     sal_uLong nChkWidth =
1431                         (nRelColWidth * nAbsTabWidth) / nRelTabWidth;
1432                     if( nChkWidth < nColMax )
1433                         nRelColWidth++;
1434                     else if( nChkWidth > nColMax )
1435                         nRelColWidth--;
1436                     pColumn->SetRelColWidth( (sal_uInt16)nRelColWidth );
1437 
1438                     nAbs = nAbs + (sal_uInt16)nColMax;
1439                     nRel = nRel + (sal_uInt16)nRelColWidth;
1440                 }
1441             }
1442 
1443             // Zu verteilende Anteile des Maximums und der relativen und
1444             // absoluten Breiten. nFixMax entspricht an dieser Stelle
1445             // nAbs, so dass man gleich nFixMax haette nehmen koennen.
1446             // Der Code ist so aber verstaendlicher.
1447             ASSERT( nFixMax == nAbs, "Zwei Schleifen, zwei Summen?" )
1448             sal_uLong nDistMax = nMax - nFixMax;
1449             sal_uInt16 nDistAbsTabWidth = nAbsTabWidth - nAbs;
1450             sal_uInt16 nDistRelTabWidth = nRelTabWidth - nRel;
1451 
1452             for( i=0; i<nCols; i++ )
1453             {
1454                 SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
1455                 if( pColumn->IsRelWidthOption() && pColumn->GetWidthOption() > 0 )
1456                 {
1457                     // Die Spalte wird anteilig breiter.
1458                     nFixedCols++;
1459                     if( nFixedCols == nCols )
1460                     {
1461                         pColumn->SetAbsColWidth( nAbsTabWidth-nAbs );
1462                         pColumn->SetRelColWidth( nRelTabWidth-nRel );
1463                     }
1464                     else
1465                     {
1466                         sal_uLong nColMax = pColumn->GetMax();
1467                         pColumn->SetAbsColWidth(
1468                             (sal_uInt16)((nColMax * nDistAbsTabWidth) / nDistMax) );
1469                         pColumn->SetRelColWidth(
1470                             (sal_uInt16)((nColMax * nDistRelTabWidth) / nDistMax) );
1471                     }
1472                     nAbs = nAbs + pColumn->GetAbsColWidth();
1473                     nRel = nRel + pColumn->GetRelColWidth();
1474                 }
1475             }
1476             ASSERT( nCols==nFixedCols, "Spalte vergessen!" );
1477         }
1478         else
1479         {
1480             // nein, dann den zu verteilenden Platz auf alle Spalten
1481             // gleichmaessig verteilen.
1482             for( sal_uInt16 i=0; i<nCols; i++ )
1483             {
1484                 sal_uLong nColMax = GetColumn( i )->GetMax();
1485                 GetColumn( i )->SetAbsColWidth(
1486                     (sal_uInt16)((nColMax * nAbsTabWidth) / nMax) );
1487                 GetColumn( i )->SetRelColWidth(
1488                     (sal_uInt16)((nColMax * nRelTabWidth) / nMax) );
1489             }
1490         }
1491     }
1492     else
1493     {
1494         // den ueber die Minimalbreite herausgehenden Platz entsprechend
1495         // den einzelnen Spalten anteilig zuschlagen
1496         if( !nAbsTabWidth )
1497             nAbsTabWidth = nAbsAvail;
1498         if( nAbsTabWidth < nMin )
1499             nAbsTabWidth = (sal_uInt16)nMin;
1500 
1501         if( nAbsTabWidth > nAbsAvail )
1502         {
1503             ASSERT( IsTopTable(),
1504                     "Tabelle in Tabelle soll breiter werden als Platz da ist" );
1505             nAbsAvail = nAbsTabWidth;
1506         }
1507 
1508         sal_uLong nAbsTabWidthL = nAbsTabWidth;
1509         nRelTabWidth =
1510             ( nRelAvail ? (sal_uInt16)((nAbsTabWidthL * nRelAvail) / nAbsAvail)
1511                         : nAbsTabWidth );
1512         double nW = nAbsTabWidth - nMin;
1513         double nD = (nMax==nMin ? 1 : nMax-nMin);
1514         sal_uInt16 nAbs = 0, nRel = 0;
1515         for( sal_uInt16 i=0; i<nCols-1; i++ )
1516         {
1517             double nd = GetColumn( i )->GetMax() - GetColumn( i )->GetMin();
1518             sal_uLong nAbsColWidth = GetColumn( i )->GetMin() + (sal_uLong)((nd*nW)/nD);
1519             sal_uLong nRelColWidth = nRelAvail
1520                                     ? (nAbsColWidth * nRelTabWidth) / nAbsTabWidth
1521                                     : nAbsColWidth;
1522 
1523             GetColumn( i )->SetAbsColWidth( (sal_uInt16)nAbsColWidth );
1524             GetColumn( i )->SetRelColWidth( (sal_uInt16)nRelColWidth );
1525             nAbs = nAbs + (sal_uInt16)nAbsColWidth;
1526             nRel = nRel + (sal_uInt16)nRelColWidth;
1527         }
1528         GetColumn( nCols-1 )->SetAbsColWidth( nAbsTabWidth - nAbs );
1529         GetColumn( nCols-1 )->SetRelColWidth( nRelTabWidth - nRel );
1530 
1531     }
1532 
1533     // Schritt 4: Fuer Tabellen in Tabellen kann es links und/oder rechts
1534     // noch Ausgleichzellen geben. Deren Breite wird jetzt berechnet.
1535     nInhAbsLeftSpace = 0;
1536     nInhAbsRightSpace = 0;
1537     if( !IsTopTable() && (nRelLeftFill>0 || nRelRightFill>0 ||
1538                           nAbsTabWidth<nAbsAvail) )
1539     {
1540         // Die Breite von zusaetzlichen Zellen zur Ausrichtung der
1541         // inneren Tabelle bestimmen
1542         sal_uInt16 nAbsDist = (sal_uInt16)(nAbsAvail-nAbsTabWidth);
1543         sal_uInt16 nRelDist = (sal_uInt16)(nRelAvail-nRelTabWidth);
1544         sal_uInt16 nParentInhAbsLeftSpace = 0, nParentInhAbsRightSpace = 0;
1545 
1546         // Groesse und Position der zusaetzlichen Zellen bestimmen
1547         switch( eTableAdjust )
1548         {
1549         case SVX_ADJUST_RIGHT:
1550             nAbsLeftFill = nAbsLeftFill + nAbsDist;
1551             nRelLeftFill = nRelLeftFill + nRelDist;
1552             nParentInhAbsLeftSpace = nParentInhAbsSpace;
1553             break;
1554         case SVX_ADJUST_CENTER:
1555             {
1556                 sal_uInt16 nAbsLeftDist = nAbsDist / 2;
1557                 nAbsLeftFill = nAbsLeftFill + nAbsLeftDist;
1558                 nAbsRightFill += nAbsDist - nAbsLeftDist;
1559                 sal_uInt16 nRelLeftDist = nRelDist / 2;
1560                 nRelLeftFill = nRelLeftFill + nRelLeftDist;
1561                 nRelRightFill += nRelDist - nRelLeftDist;
1562                 nParentInhAbsLeftSpace = nParentInhAbsSpace / 2;
1563                 nParentInhAbsRightSpace = nParentInhAbsSpace -
1564                                           nParentInhAbsLeftSpace;
1565             }
1566             break;
1567         case SVX_ADJUST_LEFT:
1568         default:
1569             nAbsRightFill = nAbsRightFill + nAbsDist;
1570             nRelRightFill = nRelRightFill + nRelDist;
1571             nParentInhAbsRightSpace = nParentInhAbsSpace;
1572             break;
1573         }
1574 
1575         ASSERT( !pLeftFillerBox || nRelLeftFill>0,
1576                 "Fuer linke Filler-Box ist keine Breite da!" );
1577         ASSERT( !pRightFillerBox || nRelRightFill>0,
1578                 "Fuer rechte Filler-Box ist keine Breite da!" );
1579 
1580         // Filler-Breiten werden auf die aeusseren Spalten geschlagen, wenn
1581         // es nach dem ersten Durchlauf keine Boxen fuer sie gibt (nWidth>0)
1582         // oder ihre Breite zu klein wuerde oder wenn es COL-Tags gibt und
1583         // die Filler-Breite der Umrandung-Breite entspricht (dann haben wir
1584         // die Tabelle wahrscheinlich selbst exportiert)
1585         if( nRelLeftFill && !pLeftFillerBox &&
1586             ( nWidthSet>0 || nAbsLeftFill<MINLAY+nInhLeftBorderWidth ||
1587               (HasColTags() && nAbsLeftFill < nAbsLeftSpace+nParentInhAbsLeftSpace+20) ) )
1588 //          (nAbsLeftFill<MINLAY || nAbsLeftFill<=nAbsLeftSpace) )
1589         {
1590             SwHTMLTableLayoutColumn *pColumn = GetColumn( 0 );
1591             pColumn->SetAbsColWidth( pColumn->GetAbsColWidth()+nAbsLeftFill );
1592             pColumn->SetRelColWidth( pColumn->GetRelColWidth()+nRelLeftFill );
1593             nRelLeftFill = 0;
1594             nInhAbsLeftSpace = nAbsLeftSpace + nParentInhAbsLeftSpace;
1595         }
1596         if( nRelRightFill && !pRightFillerBox &&
1597             ( nWidthSet>0 || nAbsRightFill<MINLAY+nInhRightBorderWidth ||
1598               (HasColTags() && nAbsRightFill < nAbsRightSpace+nParentInhAbsRightSpace+20) ) )
1599 //          (nAbsRightFill<MINLAY || nAbsRightFill<=nAbsRightSpace) )
1600         {
1601             SwHTMLTableLayoutColumn *pColumn = GetColumn( nCols-1 );
1602             pColumn->SetAbsColWidth( pColumn->GetAbsColWidth()+nAbsRightFill );
1603             pColumn->SetRelColWidth( pColumn->GetRelColWidth()+nRelRightFill );
1604             nRelRightFill = 0;
1605             nInhAbsRightSpace = nAbsRightSpace + nParentInhAbsRightSpace;
1606         }
1607     }
1608 }
1609 
1610 static sal_Bool lcl_ResizeLine( const SwTableLine*& rpLine, void* pPara );
1611 
1612 static sal_Bool lcl_ResizeBox( const SwTableBox*& rpBox, void* pPara )
1613 {
1614     sal_uInt16 *pWidth = (sal_uInt16 *)pPara;
1615 
1616     if( !rpBox->GetSttNd() )
1617     {
1618         sal_uInt16 nWidth = 0;
1619         ((SwTableBox *)rpBox)->GetTabLines().ForEach( &lcl_ResizeLine, &nWidth );
1620         rpBox->GetFrmFmt()->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nWidth, 0 ));
1621         *pWidth = *pWidth + nWidth;
1622     }
1623     else
1624     {
1625         *pWidth = *pWidth + (sal_uInt16)rpBox->GetFrmFmt()->GetFrmSize().GetSize().Width();
1626     }
1627 
1628     return sal_True;
1629 }
1630 
1631 static sal_Bool lcl_ResizeLine( const SwTableLine*& rpLine, void* pPara )
1632 {
1633     sal_uInt16 *pWidth = (sal_uInt16 *)pPara;
1634 #ifdef DBG_UTIL
1635     sal_uInt16 nOldWidth = *pWidth;
1636 #endif
1637     *pWidth = 0;
1638     ((SwTableLine *)rpLine)->GetTabBoxes().ForEach( &lcl_ResizeBox, pWidth );
1639 
1640 #ifdef DBG_UTIL
1641     ASSERT( !nOldWidth || Abs(*pWidth-nOldWidth) < COLFUZZY,
1642             "Zeilen einer Box sind unterschiedlich lang" );
1643 #endif
1644 
1645     return sal_True;
1646 }
1647 
1648 void SwHTMLTableLayout::SetWidths( sal_Bool bCallPass2, sal_uInt16 nAbsAvail,
1649                                    sal_uInt16 nRelAvail, sal_uInt16 nAbsLeftSpace,
1650                                    sal_uInt16 nAbsRightSpace,
1651                                    sal_uInt16 nParentInhAbsSpace )
1652 {
1653     // SetWidth muss am Ende einmal mehr fuer jede Zelle durchlaufen
1654     // worden sein.
1655     nWidthSet++;
1656 
1657     // Schritt 0: Wenn noetig, wird hier noch der Pass2 des Layout-Algorithmus
1658     // aufgerufen.
1659     if( bCallPass2 )
1660         AutoLayoutPass2( nAbsAvail, nRelAvail, nAbsLeftSpace, nAbsRightSpace,
1661                          nParentInhAbsSpace );
1662 
1663     // Schritt 1: Setzten der neuen Breite an allen Content-Boxen.
1664     // Da die Boxen nichts von der HTML-Tabellen-Struktur wissen, wird
1665     // ueber die HTML-Tabellen-Struktur iteriert. Fuer Tabellen in Tabellen
1666     // in Tabellen wird rekursiv SetWidth aufgerufen.
1667     for( sal_uInt16 i=0; i<nRows; i++ )
1668     {
1669         for( sal_uInt16 j=0; j<nCols; j++ )
1670         {
1671             SwHTMLTableLayoutCell *pCell = GetCell( i, j );
1672 
1673             SwHTMLTableLayoutCnts* pCntnts = pCell->GetContents();
1674             while( pCntnts && !pCntnts->IsWidthSet(nWidthSet) )
1675             {
1676                 SwTableBox *pBox = pCntnts->GetTableBox();
1677                 if( pBox )
1678                 {
1679                     SetBoxWidth( pBox, j, pCell->GetColSpan() );
1680                 }
1681                 else
1682                 {
1683                     sal_uInt16 nAbs = 0, nRel = 0, nLSpace = 0, nRSpace = 0,
1684                            nInhSpace = 0;
1685                     if( bCallPass2 )
1686                     {
1687                         sal_uInt16 nColSpan = pCell->GetColSpan();
1688                         GetAvail( j, nColSpan, nAbs, nRel );
1689                         nLSpace = GetLeftCellSpace( j, nColSpan );
1690                         nRSpace = GetRightCellSpace( j, nColSpan );
1691                         nInhSpace = GetInhCellSpace( j, nColSpan );
1692                     }
1693                     pCntnts->GetTable()->SetWidths( bCallPass2, nAbs, nRel,
1694                                                     nLSpace, nRSpace,
1695                                                     nInhSpace );
1696                 }
1697 
1698                 pCntnts->SetWidthSet( nWidthSet );
1699                 pCntnts = pCntnts->GetNext();
1700             }
1701         }
1702     }
1703 
1704     // Schritt 2: Wenn eine Top-Tabelle vorliegt, werden jetzt die Formate
1705     // der Nicht-Content-Boxen angepasst. Da diese aufgrund der
1706     // Garbage-Collection in der HTML-Tabelle nicht bekannt sind, muessen
1707     // wir hier ueber die Tabelle iterieren. Bei der Gelegenheit wird auch
1708     // das Tabellen-Frameformat angepasst. Fuer Tabellen in Tabellen werden
1709     // stattdessen die Breiten der Filler-Zellen gesetzt.
1710     if( IsTopTable() )
1711     {
1712         sal_uInt16 nCalcTabWidth = 0;
1713         ((SwTable *)pSwTable)->GetTabLines().ForEach( &lcl_ResizeLine,
1714                                                       &nCalcTabWidth );
1715         ASSERT( Abs( nRelTabWidth-nCalcTabWidth ) < COLFUZZY,
1716                 "Tabellebreite stimmt nicht mit Zeilenbreite ueberein." );
1717 
1718         // Beim Anpassen des Tabellen-Formats dieses locken, weil sonst
1719         // die Boxformate erneut angepasst werden. Ausserdem muss eine
1720         // evtl. vorhandene %-Angabe in jedem Fall erhalten bleiben.
1721         SwFrmFmt *pFrmFmt = pSwTable->GetFrmFmt();
1722         ((SwTable *)pSwTable)->LockModify();
1723         SwFmtFrmSize aFrmSize( pFrmFmt->GetFrmSize() );
1724         aFrmSize.SetWidth( nRelTabWidth );
1725         sal_Bool bRel = bUseRelWidth &&
1726                     text::HoriOrientation::FULL!=pFrmFmt->GetHoriOrient().GetHoriOrient();
1727         aFrmSize.SetWidthPercent( (sal_uInt8)(bRel ? nWidthOption : 0) );
1728         pFrmFmt->SetFmtAttr( aFrmSize );
1729         ((SwTable *)pSwTable)->UnlockModify();
1730 
1731         // Wenn die Tabelle in einem Rahmen steht, muss auch noch dessen
1732         // Breite angepasst werden.
1733         if( MayBeInFlyFrame() )
1734         {
1735             SwFrmFmt *pFlyFrmFmt = FindFlyFrmFmt();
1736             if( pFlyFrmFmt )
1737             {
1738                 SwFmtFrmSize aFlyFrmSize( ATT_VAR_SIZE, nRelTabWidth, MINLAY );
1739 
1740                 if( bUseRelWidth )
1741                 {
1742                     // Bei %-Angaben wird die Breite auf das Minimum gesetzt.
1743                     aFlyFrmSize.SetWidth(  nMin > USHRT_MAX ? USHRT_MAX
1744                                                             : nMin );
1745                     aFlyFrmSize.SetWidthPercent( (sal_uInt8)nWidthOption );
1746                 }
1747                 pFlyFrmFmt->SetFmtAttr( aFlyFrmSize );
1748             }
1749         }
1750 
1751 #ifdef DBG_UTIL
1752         {
1753             // steht im tblrwcl.cxx
1754             extern void _CheckBoxWidth( const SwTableLine&, SwTwips );
1755 
1756             // checke doch mal ob die Tabellen korrekte Breiten haben
1757             SwTwips nSize = pSwTable->GetFrmFmt()->GetFrmSize().GetWidth();
1758             const SwTableLines& rLines = pSwTable->GetTabLines();
1759             for( sal_uInt16 n = 0; n < rLines.Count(); ++n  )
1760                 _CheckBoxWidth( *rLines[ n ], nSize );
1761         }
1762 #endif
1763 
1764     }
1765     else
1766     {
1767         if( pLeftFillerBox )
1768         {
1769             pLeftFillerBox->GetFrmFmt()->SetFmtAttr(
1770                 SwFmtFrmSize( ATT_VAR_SIZE, nRelLeftFill, 0 ));
1771         }
1772         if( pRightFillerBox )
1773         {
1774             pRightFillerBox->GetFrmFmt()->SetFmtAttr(
1775                 SwFmtFrmSize( ATT_VAR_SIZE, nRelRightFill, 0 ));
1776         }
1777     }
1778 }
1779 
1780 void SwHTMLTableLayout::_Resize( sal_uInt16 nAbsAvail, sal_Bool bRecalc )
1781 {
1782     // Wenn bRecalc gesetzt ist, hat sich am Inhalt der Tabelle etwas
1783     // geaendert. Es muss dann der erste Pass noch einmal durchgefuehrt
1784     // werden.
1785     if( bRecalc )
1786         AutoLayoutPass1();
1787 
1788     SwRootFrm *pRoot = (SwRootFrm*)GetDoc()->GetCurrentViewShell()->GetLayout();
1789     if ( pRoot && pRoot->IsCallbackActionEnabled() )
1790         pRoot->StartAllAction();    //swmod 071108//swmod 071225
1791 
1792     // Sonst koennen die Breiten gesetzt werden, wobei zuvor aber jeweils
1793     // noch der Pass 2 laufen muss.
1794     SetWidths( sal_True, nAbsAvail );
1795 
1796     if ( pRoot && pRoot->IsCallbackActionEnabled() )
1797         pRoot->EndAllAction( sal_True );    //True per VirDev (Browsen ruhiger) //swmod 071108//swmod 071225
1798 }
1799 
1800 IMPL_STATIC_LINK( SwHTMLTableLayout, DelayedResize_Impl, void*, EMPTYARG )
1801 {
1802 #ifdef TEST_DELAYED_RESIZE
1803     Sound::Beep( SOUND_WARNING );
1804 #endif
1805     pThis->aResizeTimer.Stop();
1806     pThis->_Resize( pThis->nDelayedResizeAbsAvail,
1807                     pThis->bDelayedResizeRecalc );
1808 
1809     return 0;
1810 }
1811 
1812 
1813 sal_Bool SwHTMLTableLayout::Resize( sal_uInt16 nAbsAvail, sal_Bool bRecalc,
1814                                 sal_Bool bForce, sal_uLong nDelay )
1815 {
1816     if( 0 == nAbsAvail )
1817         return sal_False;
1818     ASSERT( IsTopTable(), "Resize darf nur an Top-Tabellen aufgerufen werden" );
1819 
1820     // Darf die Tabelle ueberhaupt Resized werden oder soll sie es trotzdem?
1821     if( bMustNotResize && !bForce )
1822         return sal_False;
1823 
1824     // Darf ein Recalc der Tabelle durchgefuehrt werden?
1825     if( bMustNotRecalc && !bForce )
1826         bRecalc = sal_False;
1827 
1828     const SwDoc *pDoc = GetDoc();
1829 
1830     // Wenn es ein Layout gibt, wurde evtl. die Groesse der Root-Frames
1831     // und nicht die der VisArea uebergeben. Wenn wir nicht in einem Rahmen
1832     // stehen, muss die Tabelle allerdings fuer die VisArea berechnet werden,
1833     // weil sonst die Umschaltung von relativ nach absolut nicht funktioniert.
1834     if( pDoc->GetCurrentViewShell() && pDoc->GetCurrentViewShell()->GetViewOptions()->getBrowseMode() )
1835     {
1836         const sal_uInt16 nVisAreaWidth = GetBrowseWidthByVisArea( *pDoc );
1837         if( nVisAreaWidth < nAbsAvail && !FindFlyFrmFmt() )
1838             nAbsAvail = nVisAreaWidth;
1839     }
1840 
1841     if( nDelay==0 && aResizeTimer.IsActive() )
1842     {
1843         // Wenn beim Aufruf eines synchronen Resize noch ein asynchrones
1844         // Resize aussteht, dann werden nur die neuen Werte uebernommen.
1845 
1846         bRecalc |= bDelayedResizeRecalc;
1847         nDelayedResizeAbsAvail = nAbsAvail;
1848         return sal_False;
1849     }
1850 
1851     // Optimierung:
1852     // Wenn die Minima/Maxima nicht neu berechnet werden sollen und
1853     // - die Breite der Tabelle nie neu berechnet werden muss, oder
1854     // - die Tabelle schon fuer die uebergebene Breite berechnet wurde, oder
1855     // - der verfuegbare Platz kleiner oder gleich der Minimalbreite ist
1856     //   und die Tabelle bereits die Minimalbreite besitzt, oder
1857     // - der verfuegbare Platz groesser ist als die Maximalbreite und
1858     //   die Tabelle bereits die Maximalbreite besitzt
1859     //   wird sich an der Tabelle nichts aendern.
1860     if( !bRecalc && ( !bMustResize ||
1861                       (nLastResizeAbsAvail==nAbsAvail) ||
1862                       (nAbsAvail<=nMin && nRelTabWidth==nMin) ||
1863                       (!bPrcWidthOption && nAbsAvail>=nMax && nRelTabWidth==nMax) ) )
1864         return sal_False;
1865 
1866     if( nDelay==HTMLTABLE_RESIZE_NOW )
1867     {
1868         if( aResizeTimer.IsActive() )
1869             aResizeTimer.Stop();
1870         _Resize( nAbsAvail, bRecalc );
1871     }
1872     else if( nDelay > 0 )
1873     {
1874         nDelayedResizeAbsAvail = nAbsAvail;
1875         bDelayedResizeRecalc = bRecalc;
1876         aResizeTimer.SetTimeout( nDelay );
1877         aResizeTimer.Start();
1878 #ifdef TEST_DELAYED_RESIZE
1879         Sound::Beep( SOUND_DEFAULT );
1880 #endif
1881     }
1882     else
1883     {
1884         _Resize( nAbsAvail, bRecalc );
1885     }
1886 
1887     return sal_True;
1888 }
1889 
1890 void SwHTMLTableLayout::BordersChanged( sal_uInt16 nAbsAvail, sal_Bool bRecalc )
1891 {
1892     bBordersChanged = sal_True;
1893 
1894     Resize( nAbsAvail, bRecalc );
1895 }
1896