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