xref: /aoo4110/main/sw/source/core/doc/htmltbl.cxx (revision b1cdbd2c)
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