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