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