/**************************************************************
 * 
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 * 
 *************************************************************/



// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sw.hxx"
#include "hintids.hxx"

//#define TEST_DELAYED_RESIZE

#ifdef TEST_DELAYED_RESIZE
#include <vcl/sound.hxx>
#endif
#include <vcl/wrkwin.hxx>
#include <vcl/svapp.hxx>
#include <sot/storage.hxx>
#include <fmtornt.hxx>
#include <fmtfsize.hxx>
#include <frmfmt.hxx>
#include <docary.hxx>
#include "ndtxt.hxx"
#include "doc.hxx"
#include "swtable.hxx"
#include "rootfrm.hxx"
#include "docsh.hxx"
#include "flyfrm.hxx"
#include "poolfmt.hxx"
#include "viewsh.hxx"
#include "tabfrm.hxx"
#include "viewopt.hxx"
#include "htmltbl.hxx"
#include "ndindex.hxx"
#include "switerator.hxx"

using namespace ::com::sun::star;


#define COLFUZZY 20
#define MAX_TABWIDTH (USHRT_MAX - 2001)


class SwHTMLTableLayoutConstraints
{
	sal_uInt16 nRow;					// Start-Zeile
	sal_uInt16 nCol;					// Start-Spalte
	sal_uInt16 nColSpan;				// COLSPAN der Zelle

	SwHTMLTableLayoutConstraints *pNext;		// die naechste Bedingung

	sal_uLong nMinNoAlign, nMaxNoAlign;	// Zwischenergebnisse AL-Pass 1

public:

	SwHTMLTableLayoutConstraints( sal_uLong nMin, sal_uLong nMax, sal_uInt16 nRow,
								sal_uInt16 nCol, sal_uInt16 nColSp );
	~SwHTMLTableLayoutConstraints();

	sal_uLong GetMinNoAlign() const { return nMinNoAlign; }
	sal_uLong GetMaxNoAlign() const { return nMaxNoAlign; }

	SwHTMLTableLayoutConstraints *InsertNext( SwHTMLTableLayoutConstraints *pNxt );
	SwHTMLTableLayoutConstraints* GetNext() const { return pNext; }

	sal_uInt16 GetRow() const { return nRow; }

	sal_uInt16 GetColSpan() const { return nColSpan; }
	sal_uInt16 GetColumn() const { return nCol; }
};

/*  */

SwHTMLTableLayoutCnts::SwHTMLTableLayoutCnts( const SwStartNode *pSttNd,
										  SwHTMLTableLayout* pTab,
										  sal_Bool bNoBrTag,
										  SwHTMLTableLayoutCnts* pNxt ) :
	pNext( pNxt ), pBox( 0 ), pTable( pTab ), pStartNode( pSttNd ),
	nPass1Done( 0 ), nWidthSet( 0 ), bNoBreakTag( bNoBrTag )
{}

SwHTMLTableLayoutCnts::~SwHTMLTableLayoutCnts()
{
	delete pNext;
	delete pTable;
}

const SwStartNode *SwHTMLTableLayoutCnts::GetStartNode() const
{
	return pBox ? pBox->GetSttNd() : pStartNode;
}


/*  */

SwHTMLTableLayoutCell::SwHTMLTableLayoutCell( SwHTMLTableLayoutCnts *pCnts,
										  sal_uInt16 nRSpan, sal_uInt16 nCSpan,
										  sal_uInt16 nWidth, sal_Bool bPrcWidth,
										  sal_Bool bNWrapOpt ) :
	pContents( pCnts ),
	nRowSpan( nRSpan ), nColSpan( nCSpan ),
	nWidthOption( nWidth ), bPrcWidthOption( bPrcWidth ),
	bNoWrapOption( bNWrapOpt )
{}

SwHTMLTableLayoutCell::~SwHTMLTableLayoutCell()
{
	if( nRowSpan==1 && nColSpan==1 )
	{
		delete pContents;
	}
}

/*  */

SwHTMLTableLayoutColumn::SwHTMLTableLayoutColumn( sal_uInt16 nWidth,
												  sal_Bool bRelWidth,
												  sal_Bool bLBorder ) :
	nMinNoAlign(MINLAY), nMaxNoAlign(MINLAY), nAbsMinNoAlign(MINLAY),
	nMin(0), nMax(0),
	nAbsColWidth(0), nRelColWidth(0),
	nWidthOption( nWidth ), bRelWidthOption( bRelWidth ),
	bLeftBorder( bLBorder )
{}


/*  */

SwHTMLTableLayoutConstraints::SwHTMLTableLayoutConstraints(
	sal_uLong nMin, sal_uLong nMax,	sal_uInt16 nRw,	sal_uInt16 nColumn, sal_uInt16 nColSp ):
	nRow( nRw ), nCol( nColumn ), nColSpan( nColSp ),
	pNext( 0 ),
	nMinNoAlign( nMin ), nMaxNoAlign( nMax )
{}

SwHTMLTableLayoutConstraints::~SwHTMLTableLayoutConstraints()
{
	delete pNext;
}

SwHTMLTableLayoutConstraints *SwHTMLTableLayoutConstraints::InsertNext(
	SwHTMLTableLayoutConstraints *pNxt )
{
	SwHTMLTableLayoutConstraints *pPrev = 0;
	SwHTMLTableLayoutConstraints *pConstr = this;
	while( pConstr )
	{
		if( pConstr->GetRow() > pNxt->GetRow() ||
			pConstr->GetColumn() > pNxt->GetColumn() )
			break;
		pPrev = pConstr;
		pConstr = pConstr->GetNext();
	}

	if( pPrev )
	{
		pNxt->pNext = pPrev->GetNext();
		pPrev->pNext = pNxt;
		pConstr = this;
	}
	else
	{
		pNxt->pNext = this;
		pConstr = pNxt;
	}

	return pConstr;
}

/*  */

typedef SwHTMLTableLayoutColumn *SwHTMLTableLayoutColumnPtr;
typedef SwHTMLTableLayoutCell *SwHTMLTableLayoutCellPtr;

SwHTMLTableLayout::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 ) :
	aColumns( new SwHTMLTableLayoutColumnPtr[nCls] ),
	aCells( new SwHTMLTableLayoutCellPtr[nRws*nCls] ),
	pSwTable( pSwTbl ), pLeftFillerBox( 0 ), pRightFillerBox( 0 ),
	nMin( 0 ), nMax( 0 ),
	nRows( nRws ), nCols( nCls ),
	nLeftMargin( nLMargin ), nRightMargin( nRMargin ),
	nInhAbsLeftSpace( 0 ), nInhAbsRightSpace( 0 ),
	nRelLeftFill( 0 ), nRelRightFill( 0 ),
	nRelTabWidth( 0 ), nWidthOption( nWdth ),
	nCellPadding( nCellPad ), nCellSpacing( nCellSp ), nBorder( nBorderOpt ),
	nLeftBorderWidth( nLeftBWidth ), nRightBorderWidth( nRightBWidth ),
	nInhLeftBorderWidth( nInhLeftBWidth ),
	nInhRightBorderWidth( nInhRightBWidth ),
	nBorderWidth( nBWidth ),
	nDelayedResizeAbsAvail( 0 ), nLastResizeAbsAvail( 0 ),
	nPass1Done( 0 ), nWidthSet( 0 ), eTableAdjust( eAdjust ),
	bColsOption( bColsOpt ), bColTags( bColTgs ),
	bPrcWidthOption( bPrcWdth ), bUseRelWidth( sal_False ),
	bMustResize( sal_True ), bExportable( sal_True ), bBordersChanged( sal_False ),
	bMustNotResize( sal_False ), bMustNotRecalc( sal_False )
{
	aResizeTimer.SetTimeoutHdl( STATIC_LINK( this, SwHTMLTableLayout,
											 DelayedResize_Impl ) );
}

SwHTMLTableLayout::~SwHTMLTableLayout()
{
	sal_uInt16 i;

	for( i = 0; i < nCols; i++ )
		delete aColumns[i];
	delete[] aColumns;

	sal_uInt16 nCount = nRows*nCols;
	for( i=0; i<nCount; i++ )
		delete aCells[i];
	delete[] aCells;
}

// Die Breiten der Umrandung werden zunaechst wie in Netscape berechnet:
// Aussere Umrandung: BORDER + CELLSPACING + CELLPADDING
// Innere Umrandung: CELLSPACING + CELLPADDING
// Allerdings wird die Breite der Umrandung im SW trotzdem beachtet, wenn
// bSwBorders gesetzt ist, damit nicht faellschlich umgebrochen wird.
// MIB 27.6.97: Dabei muss auch der Abstand zum Inhalt berueckichtigt werden,
// und zwar auch dann, wenn wenn nur die gegenueberliegende Seite
// eine Umrandung hat.
sal_uInt16 SwHTMLTableLayout::GetLeftCellSpace( sal_uInt16 nCol, sal_uInt16 nColSpan,
											sal_Bool bSwBorders ) const
{
	sal_uInt16 nSpace = nCellSpacing + nCellPadding;

	if( nCol == 0 )
	{
		nSpace = nSpace + nBorder;

		if( bSwBorders && nSpace < nLeftBorderWidth )
			nSpace = nLeftBorderWidth;
	}
	else if( bSwBorders )
	{
		if( GetColumn(nCol)->HasLeftBorder() )
		{
			if( nSpace < nBorderWidth )
				nSpace = nBorderWidth;
		}
		else if( nCol+nColSpan == nCols && nRightBorderWidth &&
				 nSpace < MIN_BORDER_DIST )
		{
			ASSERT( !nCellPadding, "GetLeftCellSpace: CELLPADDING!=0" );
			// Wenn die Gegenueberliegende Seite umrandet ist muessen
			// wir zumindest den minimalen Abstand zum Inhalt
			// beruecksichtigen. (Koennte man zusaetzlich auch an
			// nCellPadding festmachen.)
			nSpace = MIN_BORDER_DIST;
		}
	}

	return nSpace;
}

sal_uInt16 SwHTMLTableLayout::GetRightCellSpace( sal_uInt16 nCol, sal_uInt16 nColSpan,
											 sal_Bool bSwBorders ) const
{
	sal_uInt16 nSpace = nCellPadding;

	if( nCol+nColSpan == nCols )
	{
		nSpace += nBorder + nCellSpacing;
		if( bSwBorders && nSpace < nRightBorderWidth )
			nSpace = nRightBorderWidth;
	}
	else if( bSwBorders && GetColumn(nCol)->HasLeftBorder() &&
			 nSpace < MIN_BORDER_DIST )
	{
		ASSERT( !nCellPadding, "GetRightCellSpace: CELLPADDING!=0" );
		// Wenn die Gegenueberliegende Seite umrandet ist muessen
		// wir zumindest den minimalen Abstand zum Inhalt
		// beruecksichtigen. (Koennte man zusaetzlich auch an
		// nCellPadding festmachen.)
		nSpace = MIN_BORDER_DIST;
	}

	return nSpace;
}

void SwHTMLTableLayout::AddBorderWidth( sal_uLong &rMin, sal_uLong &rMax,
										sal_uLong &rAbsMin,
										sal_uInt16 nCol, sal_uInt16 nColSpan,
										sal_Bool bSwBorders ) const
{
	sal_uLong nAdd = GetLeftCellSpace( nCol, nColSpan, bSwBorders ) +
				 GetRightCellSpace( nCol, nColSpan, bSwBorders );

	rMin += nAdd;
	rMax += nAdd;
	rAbsMin += nAdd;
}

void SwHTMLTableLayout::SetBoxWidth( SwTableBox *pBox, sal_uInt16 nCol,
							 sal_uInt16 nColSpan ) const
{
	SwFrmFmt *pFrmFmt = pBox->GetFrmFmt();

	// die Breite der Box berechnen
	SwTwips nFrmWidth = 0;
	while( nColSpan-- )
		nFrmWidth += GetColumn( nCol++ )->GetRelColWidth();

	// und neu setzen

    pFrmFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nFrmWidth, 0 ));
}

void SwHTMLTableLayout::GetAvail( sal_uInt16 nCol, sal_uInt16 nColSpan,
								  sal_uInt16& rAbsAvail, sal_uInt16& rRelAvail ) const
{
	rAbsAvail = 0;
	rRelAvail = 0;
	for( sal_uInt16 i=nCol; i<nCol+nColSpan;i++ )
	{
		const SwHTMLTableLayoutColumn *pColumn = GetColumn(i);
		rAbsAvail = rAbsAvail + pColumn->GetAbsColWidth();
		rRelAvail = rRelAvail + pColumn->GetRelColWidth();
	}
}

sal_uInt16 SwHTMLTableLayout::GetBrowseWidthByVisArea( const SwDoc& rDoc )
{
	ViewShell *pVSh = 0;
	rDoc.GetEditShell( &pVSh );
	if( pVSh )
	{
		return (sal_uInt16)pVSh->GetBrowseWidth();
	}

	return 0;
}

sal_uInt16 SwHTMLTableLayout::GetBrowseWidth( const SwDoc& rDoc )
{
	// Wenn ein Layout da ist, koennen wir die Breite dort herholen.
	const SwRootFrm *pRootFrm = rDoc.GetCurrentLayout();	//swmod 080218
	if( pRootFrm )
	{
		const SwFrm *pPageFrm = pRootFrm->GetLower();
		if( pPageFrm )
			return (sal_uInt16)pPageFrm->Prt().Width();
	}

    // --> OD 2010-05-12 #i91658#
    // Assertion removed which state that no browse width is available.
    // Investigation reveals that all calls can handle the case that no browse
    // width is provided.
    return GetBrowseWidthByVisArea( rDoc );
    // <--
}

sal_uInt16 SwHTMLTableLayout::GetBrowseWidthByTabFrm(
	const SwTabFrm& rTabFrm ) const
{
	SwTwips nWidth = 0;

	const SwFrm *pUpper = rTabFrm.GetUpper();
	if( MayBeInFlyFrame() && pUpper->IsFlyFrm() &&
        ((const SwFlyFrm *)pUpper)->GetAnchorFrm() )
	{
		// Wenn die Tabelle in einem selbst angelegten Rahmen steht, dann ist
		// die Breite Ankers und nicht die Breite Rahmens von Bedeutung.
		// Bei Absatz-gebundenen Rahmen werden Absatz-Einzuege nicht beachtet.
        const SwFrm *pAnchor = ((const SwFlyFrm *)pUpper)->GetAnchorFrm();
		if( pAnchor->IsTxtFrm() )
			nWidth = pAnchor->Frm().Width();
		else
			nWidth = pAnchor->Prt().Width();
	}
	else
	{
		nWidth = pUpper->Prt().Width();
	}

	SwTwips nUpperDummy = 0;
	long nRightOffset = 0,
		 nLeftOffset  = 0;
	rTabFrm.CalcFlyOffsets( nUpperDummy, nLeftOffset, nRightOffset );
	nWidth -= (nLeftOffset + nRightOffset);

	return nWidth < USHRT_MAX ? static_cast<sal_uInt16>(nWidth) : USHRT_MAX;
}

sal_uInt16 SwHTMLTableLayout::GetBrowseWidthByTable( const SwDoc& rDoc ) const
{
	sal_uInt16 nBrowseWidth = 0;
	SwTabFrm* pFrm = SwIterator<SwTabFrm,SwFmt>::FirstElement( *pSwTable->GetFrmFmt() );
	if( pFrm )
	{
		nBrowseWidth = GetBrowseWidthByTabFrm( *pFrm );
	}
	else
	{
		nBrowseWidth = SwHTMLTableLayout::GetBrowseWidth( rDoc );
	}

	return nBrowseWidth;
}

const SwStartNode *SwHTMLTableLayout::GetAnyBoxStartNode() const
{
	const SwStartNode *pBoxSttNd;

	const SwTableBox* pBox = pSwTable->GetTabLines()[0]->GetTabBoxes()[0];
	while( 0 == (pBoxSttNd = pBox->GetSttNd()) )
	{
		ASSERT( pBox->GetTabLines().Count() > 0,
				"Box ohne Start-Node und Lines" );
		ASSERT( pBox->GetTabLines()[0]->GetTabBoxes().Count() > 0,
				"Line ohne Boxen" );
		pBox = pBox->GetTabLines()[0]->GetTabBoxes()[0];
	}

	return pBoxSttNd;
}

SwFrmFmt *SwHTMLTableLayout::FindFlyFrmFmt() const
{
	const SwTableNode *pTblNd = GetAnyBoxStartNode()->FindTableNode();
	ASSERT( pTblNd, "Kein Table-Node?" );
	return pTblNd->GetFlyFmt();
}

static void lcl_GetMinMaxSize( sal_uLong& rMinNoAlignCnts, sal_uLong& rMaxNoAlignCnts,
						sal_uLong& rAbsMinNoAlignCnts,
#ifdef FIX41370
						sal_Bool& rHR,
#endif
						SwTxtNode *pTxtNd, sal_uLong nIdx, sal_Bool bNoBreak )
{
	pTxtNd->GetMinMaxSize( nIdx, rMinNoAlignCnts, rMaxNoAlignCnts,
						   rAbsMinNoAlignCnts );
	ASSERT( rAbsMinNoAlignCnts <= rMinNoAlignCnts,
			"GetMinMaxSize: absmin > min" );
	ASSERT( rMinNoAlignCnts <= rMaxNoAlignCnts,
			"GetMinMaxSize: max > min" );

	//Bei einen <PRE>-Absatz entspricht die maximale Breite der
	// minimalen breite
	const SwFmtColl *pColl = &pTxtNd->GetAnyFmtColl();
	while( pColl && !pColl->IsDefault() &&
			(USER_FMT & pColl->GetPoolFmtId()) )
	{
		pColl = (const SwFmtColl *)pColl->DerivedFrom();
	}

	// <NOBR> in der gesamten Zelle bezieht sich auf Text, aber nicht
	// auf Tabellen. Netscape beruecksichtigt dies nur fuer Grafiken.
	if( (pColl && RES_POOLCOLL_HTML_PRE==pColl->GetPoolFmtId()) || bNoBreak )
	{
		rMinNoAlignCnts = rMaxNoAlignCnts;
		rAbsMinNoAlignCnts = rMaxNoAlignCnts;
	}
#ifdef FIX41370
	else if( pColl && RES_POOLCOLL_HTML_HR==pColl->GetPoolFmtId() )
	{
        rHR |= !pTxtNd->HasSwAttrSet() ||
				SFX_ITEM_SET != pTxtNd->GetpSwAttrSet()
									  ->GetItemState( RES_LR_SPACE, sal_False );
	}
#endif
}

void SwHTMLTableLayout::AutoLayoutPass1()
{
	nPass1Done++;

	ClearPass1Info();

	sal_Bool bFixRelWidths = sal_False;
	sal_uInt16 i;

	SwHTMLTableLayoutConstraints *pConstraints = 0;

	for( i=0; i<nCols; i++ )
	{
		SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
		pColumn->ClearPass1Info( !HasColTags() );
		sal_uInt16 nMinColSpan = USHRT_MAX; // Spaltenzahl, auf die sich dir
										// berechnete Breite bezieht
		sal_uInt16 nColSkip = USHRT_MAX;	// Wie viele Spalten muessen
										// uebersprungen werden

		for( sal_uInt16 j=0; j<nRows; j++ )
		{
			SwHTMLTableLayoutCell *pCell = GetCell(j,i);
			SwHTMLTableLayoutCnts *pCnts = pCell->GetContents();

			// fix #31488#: Zum Ermitteln der naechsten zu berechnenden
			// Spalte muessen alle Zeilen herangezogen werden
			sal_uInt16 nColSpan = pCell->GetColSpan();
			if( nColSpan < nColSkip )
				nColSkip = nColSpan;

			if( !pCnts || (pCnts && !pCnts->IsPass1Done(nPass1Done)) )
			{
				// die Zelle ist leer oder ihr Inhalt wurde nich nicht
				// bearbeitet
				if( nColSpan < nMinColSpan )
					nMinColSpan = nColSpan;

				sal_uLong nMinNoAlignCell = 0;
				sal_uLong nMaxNoAlignCell = 0;
				sal_uLong nAbsMinNoAlignCell = 0;
				sal_uLong nMaxTableCell = 0;
				sal_uLong nAbsMinTableCell = 0;
#ifdef FIX41370
				sal_Bool bHR = sal_False;
#endif

				while( pCnts )
				{
					const SwStartNode *pSttNd = pCnts->GetStartNode();
					if( pSttNd )
					{
						const SwDoc *pDoc = pSttNd->GetDoc();
						sal_uLong nIdx = pSttNd->GetIndex();
						while( !(pDoc->GetNodes()[nIdx])->IsEndNode() )
						{
							SwTxtNode *pTxtNd = (pDoc->GetNodes()[nIdx])->GetTxtNode();
							if( pTxtNd )
							{
                                sal_uLong nMinNoAlignCnts = 0;
                                sal_uLong nMaxNoAlignCnts = 0;
                                sal_uLong nAbsMinNoAlignCnts = 0;

								lcl_GetMinMaxSize( nMinNoAlignCnts,
												   nMaxNoAlignCnts,
												   nAbsMinNoAlignCnts,
#ifdef FIX41370
												   bHR,
#endif
												   pTxtNd, nIdx,
												   pCnts->HasNoBreakTag() );

								if( nMinNoAlignCnts > nMinNoAlignCell )
									nMinNoAlignCell = nMinNoAlignCnts;
								if( nMaxNoAlignCnts > nMaxNoAlignCell )
									nMaxNoAlignCell = nMaxNoAlignCnts;
								if( nAbsMinNoAlignCnts > nAbsMinNoAlignCell )
									nAbsMinNoAlignCell = nAbsMinNoAlignCnts;
							}
							else
							{
								SwTableNode *pTabNd = (pDoc->GetNodes()[nIdx])->GetTableNode();
								if( pTabNd )
								{
									SwHTMLTableLayout *pChild = pTabNd->GetTable().GetHTMLTableLayout();
									if( pChild )
									{
										pChild->AutoLayoutPass1();
										sal_uLong nMaxTableCnts = pChild->nMax;
										sal_uLong nAbsMinTableCnts = pChild->nMin;

										// Eine feste Tabellen-Breite wird als Minimum
										// und Maximum gleichzeitig uebernommen
										if( !pChild->bPrcWidthOption && pChild->nWidthOption )
										{
											sal_uLong nTabWidth = pChild->nWidthOption;
											if( nTabWidth >= nAbsMinTableCnts  )
											{
												nMaxTableCnts = nTabWidth;
												nAbsMinTableCnts = nTabWidth;
											}
											else
											{
												nMaxTableCnts = nAbsMinTableCnts;
											}
										}

										if( nMaxTableCnts > nMaxTableCell )
											nMaxTableCell = nMaxTableCnts;
										if( nAbsMinTableCnts > nAbsMinTableCell )
											nAbsMinTableCell = nAbsMinTableCnts;
									}
									nIdx = pTabNd->EndOfSectionNode()->GetIndex();
								}
							}
							nIdx++;
						}
					}
					else
					{
						ASSERT( sal_False, "Sub tables in HTML import?" )
						SwHTMLTableLayout *pChild = pCnts->GetTable();
						pChild->AutoLayoutPass1();
						sal_uLong nMaxTableCnts = pChild->nMax;
						sal_uLong nAbsMinTableCnts = pChild->nMin;

						// Eine feste Tabellen-Breite wird als Minimum
						// und Maximum gleichzeitig uebernommen
						if( !pChild->bPrcWidthOption && pChild->nWidthOption )
						{
							sal_uLong nTabWidth = pChild->nWidthOption;
							if( nTabWidth >= nAbsMinTableCnts  )
							{
								nMaxTableCnts = nTabWidth;
								nAbsMinTableCnts = nTabWidth;
							}
							else
							{
								nMaxTableCnts = nAbsMinTableCnts;
							}
						}

						if( nMaxTableCnts > nMaxTableCell )
							nMaxTableCell = nMaxTableCnts;
						if( nAbsMinTableCnts > nAbsMinTableCell )
							nAbsMinTableCell = nAbsMinTableCnts;
					}
					pCnts->SetPass1Done( nPass1Done );
					pCnts = pCnts->GetNext();
				}

// War frueher hinter AddBorderWidth
				// Wenn die Breite einer Tabelle in der Zelle breiter ist als
				// das, was wir fuer sonstigen Inhalt berechnet haben, mussen
				// wir die Breite der Tabelle nutzen
				if( nMaxTableCell > nMaxNoAlignCell )
					nMaxNoAlignCell = nMaxTableCell;
				if( nAbsMinTableCell > nAbsMinNoAlignCell )
				{
					nAbsMinNoAlignCell = nAbsMinTableCell;
					if( nMinNoAlignCell < nAbsMinNoAlignCell )
						nMinNoAlignCell = nAbsMinNoAlignCell;
					if( nMaxNoAlignCell < nMinNoAlignCell )
						nMaxNoAlignCell = nMinNoAlignCell;
				}
// War frueher hinter AddBorderWidth

				sal_Bool bRelWidth = pCell->IsPrcWidthOption();
				sal_uInt16 nWidth = pCell->GetWidthOption();

				// Eine NOWRAP-Option bezieht sich auf Text und auf
				// Tabellen, wird aber bei fester Zellenbreite
				// nicht uebernommen. Stattdessen wirkt die angegebene
				// Zellenbreite wie eine Mindestbreite.
				if( pCell->HasNoWrapOption() )
				{
					if( nWidth==0 || bRelWidth )
					{
						nMinNoAlignCell = nMaxNoAlignCell;
						nAbsMinNoAlignCell = nMaxNoAlignCell;
					}
					else
					{
						if( nWidth>nMinNoAlignCell )
							nMinNoAlignCell = nWidth;
						if( nWidth>nAbsMinNoAlignCell )
							nAbsMinNoAlignCell = nWidth;
					}
				}
#ifdef FIX41370
				else if( bHR && nWidth>0 && !bRelWidth )
				{
					// Ein kleiner Hack, um einen Bug in Netscape 4.0
					// nachzubilden (siehe #41370#). Wenn eine Zelle eine
					// fixe Breite besitzt und gleichzeitig ein HR, wird
					// sie nie schmaler als die angegebene Breite.
					// (Genaugenomen scheint die Zelle nie schmaler zu werden
					// als die HR-Linie, denn wenn man fuer die Linie eine
					// Breite angibt, die breiter ist als die der Zelle, dann
					// wird die Zelle so breit wie die Linie. Das bekommen wir
					// natuerlich nicht hin.)
					if( nWidth>nMinNoAlignCell )
						nMinNoAlignCell = nWidth;
					if( nWidth>nAbsMinNoAlignCell )
						nAbsMinNoAlignCell = nWidth;
				}
#endif

				// Mindestbreite fuer Inhalt einhalten
				if( nMinNoAlignCell < MINLAY )
					nMinNoAlignCell = MINLAY;
				if( nMaxNoAlignCell < MINLAY )
					nMaxNoAlignCell = MINLAY;
				if( nAbsMinNoAlignCell < MINLAY )
					nAbsMinNoAlignCell = MINLAY;

				// Umrandung und Abstand zum Inhalt beachten.
				AddBorderWidth( nMinNoAlignCell, nMaxNoAlignCell,
								nAbsMinNoAlignCell, i, nColSpan );

				if( 1==nColSpan )
				{
					// die Werte direkt uebernehmen
					pColumn->MergeMinMaxNoAlign( nMinNoAlignCell,
												 nMaxNoAlignCell,
												 nAbsMinNoAlignCell );

					// bei den WIDTH angaben gewinnt die breiteste
					if( !HasColTags() )
						pColumn->MergeCellWidthOption( nWidth, bRelWidth );
				}
				else
				{
					// die Angaben erst am Ende, und zwar zeilenweise von
					// links nach rechts bearbeiten

					// Wann welche Werte wie uebernommen werden ist weiter
					// unten erklaert.
					if( !HasColTags() && nWidth && !bRelWidth )
					{
						sal_uLong nAbsWidth = nWidth, nDummy = 0, nDummy2 = 0;
						AddBorderWidth( nAbsWidth, nDummy, nDummy2,
										i, nColSpan, sal_False );

						if( nAbsWidth >= nMinNoAlignCell )
						{
							nMaxNoAlignCell = nAbsWidth;
							if( HasColsOption() )
								nMinNoAlignCell = nAbsWidth;
						}
						else if( nAbsWidth >= nAbsMinNoAlignCell )
						{
							nMaxNoAlignCell = nAbsWidth;
							nMinNoAlignCell = nAbsWidth;
						}
						else
						{
							nMaxNoAlignCell = nAbsMinNoAlignCell;
							nMinNoAlignCell = nAbsMinNoAlignCell;
						}
					}
					else if( HasColsOption() || HasColTags() )
						nMinNoAlignCell = nAbsMinNoAlignCell;

					SwHTMLTableLayoutConstraints *pConstr =
						new SwHTMLTableLayoutConstraints( nMinNoAlignCell,
							nMaxNoAlignCell, j, i, nColSpan );
					if( pConstraints )
						pConstraints = pConstraints->InsertNext( pConstr );
					else
						pConstraints = pConstr;
				}
			}
		}

		ASSERT( nMinColSpan>0 && nColSkip>0 && nColSkip <= nMinColSpan,
				"Layout Pass 1: Da werden Spalten vergessen!" );
		ASSERT( nMinColSpan!=USHRT_MAX,
				"Layout Pass 1: unnoetiger Schleifendurchlauf oder Bug" );

		if( 1==nMinColSpan )
		{
			// es gibt Zellen mit COLSPAN 1 und demnach auch sinnvolle
			// Werte in pColumn

			// Werte anhand folgender Tabelle (Netscape 4.0 pv 3) uebernehmen:
			//
			// WIDTH:			kein COLS		COLS
			//
			// keine			min = min		min = absmin
			//					max = max		max = max
			//
			// >= min			min = min  		min = width
			//					max = width		max = width
			//
			// >= absmin		min = wdith(*)	min = width
			//					max = width		max = width
			//
			// < absmin			min = absmin	min = absmin
			//					max = absmin	max = absmin
			//
			// (*) Netscape benutzt hier die Mindestbreite ohne einen
			//     Umbruch vor der letzten Grafik. Haben wir (noch?) nicht,
			//     also belassen wir es bei width.^

			if( pColumn->GetWidthOption() && !pColumn->IsRelWidthOption() )
			{
				// absolute Breiten als Minimal- und Maximalbreite
				// uebernehmen.
				sal_uLong nAbsWidth = pColumn->GetWidthOption();
				sal_uLong nDummy = 0, nDummy2 = 0;
				AddBorderWidth( nAbsWidth, nDummy, nDummy2, i, 1, sal_False );

				if( nAbsWidth >= pColumn->GetMinNoAlign() )
				{
					pColumn->SetMinMax( HasColsOption() ? nAbsWidth
												   : pColumn->GetMinNoAlign(),
										nAbsWidth );
				}
				else if( nAbsWidth >= pColumn->GetAbsMinNoAlign() )
				{
					pColumn->SetMinMax( nAbsWidth, nAbsWidth );
				}
				else
				{
					pColumn->SetMinMax( pColumn->GetAbsMinNoAlign(),
										pColumn->GetAbsMinNoAlign() );
				}
			}
			else
			{
				pColumn->SetMinMax( HasColsOption() ? pColumn->GetAbsMinNoAlign()
											   : pColumn->GetMinNoAlign(),
									pColumn->GetMaxNoAlign() );
			}
		}
		else if( USHRT_MAX!=nMinColSpan )
		{
			// kann irgendwas !=0 sein, weil es durch die Constraints
			// angepasst wird.
			pColumn->SetMinMax( MINLAY, MINLAY );

			// die naechsten Spalten muessen nicht bearbeitet werden
			i += (nColSkip-1);
		}

		nMin += pColumn->GetMin();
		nMax += pColumn->GetMax();
		bFixRelWidths |= pColumn->IsRelWidthOption();
	}

	// jetzt noch die Constrains verarbeiten
	SwHTMLTableLayoutConstraints *pConstr = pConstraints;
	while( pConstr )
	{
		// Erstmal muss die Breite analog zu den den Spaltenbreiten
		// aufbereitet werden
		sal_uInt16 nCol = pConstr->GetColumn();
		sal_uInt16 nColSpan = pConstr->GetColSpan();
		sal_uLong nConstrMin = pConstr->GetMinNoAlign();
		sal_uLong nConstrMax = pConstr->GetMaxNoAlign();

		// jetzt holen wir uns die bisherige Breite der ueberspannten
		// Spalten
		sal_uLong nColsMin = 0;
		sal_uLong nColsMax = 0;
		for( sal_uInt16 j=nCol; j<nCol+nColSpan; j++ )
		{
			SwHTMLTableLayoutColumn *pColumn = GetColumn( j );
			nColsMin += pColumn->GetMin();
			nColsMax += pColumn->GetMax();
		}

		if( nColsMin<nConstrMin )
		{
			// den Minimalwert anteilig auf die Spalten verteilen
			sal_uLong nMinD = nConstrMin-nColsMin;

			if( nConstrMin > nColsMax )
			{
				// Anteilig anhand der Mindestbreiten
				sal_uInt16 nEndCol = nCol+nColSpan;
				sal_uLong nDiff = nMinD;
				for( sal_uInt16 ic=nCol; ic<nEndCol; ic++ )
				{
					SwHTMLTableLayoutColumn *pColumn = GetColumn( ic );

					sal_uLong nColMin = pColumn->GetMin();
					sal_uLong nColMax = pColumn->GetMax();

					nMin -= nColMin;
					sal_uLong nAdd = ic<nEndCol-1 ? (nColMin * nMinD) / nColsMin
											 : nDiff;
					nColMin += nAdd;
					nMin += nColMin;
					ASSERT( nDiff >= nAdd, "Ooops: nDiff stimmt nicht mehr" );
					nDiff -= nAdd;

					if( nColMax < nColMin )
					{
						nMax -= nColMax;
						nColsMax -= nColMax;
						nColMax = nColMin;
						nMax += nColMax;
						nColsMax += nColMax;
					}

					pColumn->SetMinMax( nColMin, nColMax );
				}
			}
			else
			{
				// Anteilig anhand der Differenz zwischen Max und Min
				for( sal_uInt16 ic=nCol; ic<nCol+nColSpan; ic++ )
				{
					SwHTMLTableLayoutColumn *pColumn = GetColumn( ic );

					sal_uLong nDiff = pColumn->GetMax()-pColumn->GetMin();
					if( nMinD < nDiff )
						nDiff = nMinD;

					pColumn->AddToMin( nDiff );

					ASSERT( pColumn->GetMax() >= pColumn->GetMin(),
							"Wieso ist die SPalte auf einmal zu schmal?" )

					nMin += nDiff;
					nMinD -= nDiff;
				}
			}
		}

		if( !HasColTags() && nColsMax<nConstrMax )
		{
			sal_uLong nMaxD = nConstrMax-nColsMax;

			for( sal_uInt16 ic=nCol; ic<nCol+nColSpan; ic++ )
			{
				SwHTMLTableLayoutColumn *pColumn = GetColumn( ic );

				nMax -= pColumn->GetMax();

				pColumn->AddToMax( (pColumn->GetMax() * nMaxD) / nColsMax );

				nMax += pColumn->GetMax();
			}
		}

		pConstr = pConstr->GetNext();
	}


	if( bFixRelWidths )
	{
		if( HasColTags() )
		{
			// Zum Anpassen der relativen Breiten werden im 1. Schritt die
			// Minmalbreiten aller anzupassenden Zellen jeweils mit der
			// relativen Breite einer Spalte multipliziert. Dadurch stimmen
			// dann die Breitenverhaeltnisse der Spalten untereinander.
			// Ausserdem wird der Faktor berechnet, um den die Zelle dadurch
			// breiter gworden ist als die Minmalbreite.
			// Im 2. Schritt werden dann die berechneten Breiten durch diesen
			// Faktor geteilt. Dadurch bleibt die Breite (nimd.) einer Zelle
			// erhalten und dient als Ausgangsbasis fuer die andern Breiten.
			// Es werden auch hier nur die Maximalbreiten beeinflusst!

			sal_uLong nAbsMin = 0;	// absolte Min-Breite alter Spalten mit
								// relativer Breite
			sal_uLong nRel = 0;		// Summe der relativen Breiten aller Spalten
			for( i=0; i<nCols; i++ )
			{
				SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
				if( pColumn->IsRelWidthOption() && pColumn->GetWidthOption() )
				{
					nAbsMin += pColumn->GetMin();
					nRel += pColumn->GetWidthOption();
				}
			}

			sal_uLong nQuot = ULONG_MAX;
			for( i=0; i<nCols; i++ )
			{
				SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
				if( pColumn->IsRelWidthOption() )
				{
					nMax -= pColumn->GetMax();
					if( pColumn->GetWidthOption() && pColumn->GetMin() )
					{
						pColumn->SetMax( nAbsMin * pColumn->GetWidthOption() );
						sal_uLong nColQuot = pColumn->GetMax() / pColumn->GetMin();
						if( nColQuot<nQuot )
							nQuot = nColQuot;
					}
				}
			}
			ASSERT( 0==nRel || nQuot!=ULONG_MAX,
					"Wo sind die relativen Spalten geblieben?" );
			for( i=0; i<nCols; i++ )
			{
				SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
				if( pColumn->IsRelWidthOption() )
				{
					if( pColumn->GetWidthOption() )
						pColumn->SetMax( pColumn->GetMax() / nQuot );
					else
						pColumn->SetMax( pColumn->GetMin() );
					ASSERT( pColumn->GetMax() >= pColumn->GetMin(),
							"Maximale Spaltenbreite kleiner als Minimale" );
					nMax += pColumn->GetMax();
				}
			}
		}
		else
		{
			sal_uInt16 nRel = 0;		// Summe der relativen Breiten aller Spalten
			sal_uInt16 nRelCols = 0;	// Anzahl Spalten mit relativer Angabe
			sal_uLong nRelMax = 0;		// Anteil am Maximum dieser Spalten
			for( i=0; i<nCols; i++ )
			{
				ASSERT( nRel<=100, "relative Breite aller Spalten>100%" );
				SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
				if( pColumn->IsRelWidthOption() && pColumn->GetWidthOption() )
				{
					// Sicherstellen, dass die relativen breiten nicht
					// ueber 100% landen
					sal_uInt16 nColWidth = pColumn->GetWidthOption();
					if( nRel+nColWidth > 100 )
					{
						nColWidth = 100 - nRel;
						pColumn->SetWidthOption( nColWidth, sal_True, sal_False );
					}
					nRelMax += pColumn->GetMax();
					nRel = nRel + nColWidth;
					nRelCols++;
				}
				else if( !pColumn->GetMin() )
				{
					// Die Spalte ist leer (wurde also auschliesslich
					// durch COLSPAN erzeugt) und darf deshalb auch
					// keine %-Breite zugewiesen bekommen.
					nRelCols++;
				}
			}

			// Eventuell noch vorhandene Prozente werden auf die Spalten ohne
			// eine Breiten-Angabe verteilt. Wie in Netscape werden die
			// verbleibenden Prozente enstprechend der Verhaeltnisse
			// der Maximalbreiten der in Frage kommenden Spalten
			// untereinander verteilt.
			// ??? Wie beruecksichtigen bei den Maximalbreiten auch Spalten
			// mit fester Breite. Ist das richtig???
			if( nRel < 100 && nRelCols < nCols )
			{
				sal_uInt16 nRelLeft = 100 - nRel;
				sal_uLong nFixMax = nMax - nRelMax;
				for( i=0; i<nCols; i++ )
				{
					SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
					if( !pColumn->IsRelWidthOption() &&
						!pColumn->GetWidthOption() &&
						pColumn->GetMin() )
					{
						// den Rest bekommt die naechste Spalte
						sal_uInt16 nColWidth =
							(sal_uInt16)((pColumn->GetMax() * nRelLeft) / nFixMax);
						pColumn->SetWidthOption( nColWidth, sal_True, sal_False );
					}
				}
			}

			// nun die Maximalbreiten entsprechend anpassen
			sal_uLong nQuotMax = ULONG_MAX;
			sal_uLong nOldMax = nMax;
			nMax = 0;
			for( i=0; i<nCols; i++ )
			{
				// Spalten mit %-Angaben werden enstprechend angepasst.
				// Spalten, die
				// - keine %-Angabe besitzen und in einer Tabelle mit COLS
				//   oder WIDTH vorkommen, oder
				// - als Breite 0% angegeben haben erhalten die Minimalbreite
				SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
				if( pColumn->IsRelWidthOption() && pColumn->GetWidthOption() )
				{
					sal_uLong nNewMax;
					sal_uLong nColQuotMax;
					if( !nWidthOption )
					{
						nNewMax = nOldMax * pColumn->GetWidthOption();
						nColQuotMax = nNewMax / pColumn->GetMax();
					}
					else
					{
						nNewMax = nMin * pColumn->GetWidthOption();
						nColQuotMax = nNewMax / pColumn->GetMin();
					}
					pColumn->SetMax( nNewMax );
					if( nColQuotMax < nQuotMax )
						nQuotMax = nColQuotMax;
				}
				else if( HasColsOption() || nWidthOption ||
						 (pColumn->IsRelWidthOption() &&
						  !pColumn->GetWidthOption()) )
					pColumn->SetMax( pColumn->GetMin() );
			}
			// und durch den Quotienten teilen
			ASSERT( nQuotMax!=ULONG_MAX, "Wo sind die relativen Spalten geblieben?" );
			for( i=0; i<nCols; i++ )
			{
				SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
				if( pColumn->IsRelWidthOption() && pColumn->GetWidthOption() )
				{
					if( pColumn->GetWidthOption() )
					{
						pColumn->SetMax( pColumn->GetMax() / nQuotMax );
						ASSERT( pColumn->GetMax() >= pColumn->GetMin(),
								"Minimalbreite ein Spalte Groesser Maximum" );
						if( pColumn->GetMax() < pColumn->GetMin() )
							pColumn->SetMax( pColumn->GetMin() );
					}
				}
				nMax += pColumn->GetMax();
			}
		}
	}

	delete pConstraints;
}

// nAbsAvail ist der verfuegbare Platz in TWIPS.
// nRelAvail ist der auf USHRT_MAX bezogene verfuegbare Platz oder 0
// nAbsSpace ist der Anteil von nAbsAvail, der durch der umgebende Zelle
//           fur die Umrandung und den Abstand zum Inhalt reserviert ist.
void SwHTMLTableLayout::AutoLayoutPass2( sal_uInt16 nAbsAvail, sal_uInt16 nRelAvail,
										 sal_uInt16 nAbsLeftSpace,
										 sal_uInt16 nAbsRightSpace,
										 sal_uInt16 nParentInhAbsSpace )
{
	// Erstmal fuehren wie jede Menge Plausibilaets-Test durch

	// Eine abolute zur Verfuegung stehende Breite muss immer uebergeben
	// werden.
	ASSERT( nAbsAvail, "AutoLayout Pass 2: Keine absolute Breite gegeben" );

	// Eine realtive zur Verfuegung stehende Breite darf nur und muss fuer
	// Tabellen in Tabellen uebergeben
	ASSERT( IsTopTable() == (nRelAvail==0),
			"AutoLayout Pass 2: Rel. Breite bei Tab in Tab oder umgekehrt" );

	// Die Minimalbreite der Tabelle darf natuerlich nie groesser sein
	// als das die Maximalbreite.
	ASSERT( nMin<=nMax, "AutoLayout Pass2: nMin > nMax" );

	// Die verfuegbare Breite, fuer die die Tabelle berechnet wurde, merken.
	// (Dies ist ein guter Ort, denn hier kommer wir bei der Erstberechnung
	// der Tabelle aus dem Parser und bei jedem _Resize-Aufruf vorbei.)
	nLastResizeAbsAvail = nAbsAvail;

	// Schritt 1: Der verfuegbar Platz wird an linke/rechte Raender,
	// vorhandene Filler-Zellen und Abstande angepasst

	// Abstand zum Inhalt und Unrandung
	sal_uInt16 nAbsLeftFill = 0, nAbsRightFill = 0;
	if( !IsTopTable() &&
		GetMin() + nAbsLeftSpace + nAbsRightSpace <= nAbsAvail )
	{
		nAbsLeftFill = nAbsLeftSpace;
		nAbsRightFill = nAbsRightSpace;
	}

	// Linker und rechter Abstand
	if( nLeftMargin || nRightMargin )
	{
		if( IsTopTable() )
		{
			// fuer die Top-Table beruecksichtigen wir die Raender immer,
			// den die Minimalbreite der Tabelle wird hier nie unterschritten
			nAbsAvail -= (nLeftMargin + nRightMargin);
		}
		else if( GetMin() + nLeftMargin + nRightMargin <= nAbsAvail )
		{
			// sonst beruecksichtigen wir die Raender nur, wenn auch Platz
			// fuer sie da ist (nMin ist hier bereits berechnet!)
			nAbsLeftFill = nAbsLeftFill + nLeftMargin;
			nAbsRightFill = nAbsRightFill + nRightMargin;
		}
	}

	// Filler-Zellen
	if( !IsTopTable() )
	{
		if( pLeftFillerBox && nAbsLeftFill<MINLAY+nInhLeftBorderWidth )
			nAbsLeftFill = MINLAY+nInhLeftBorderWidth;
		if( pRightFillerBox && nAbsRightFill<MINLAY+nInhRightBorderWidth )
			nAbsRightFill = MINLAY+nInhRightBorderWidth;
	}

	// Anpassen des verfuegbaren Platzes.
	nRelLeftFill = 0;
	nRelRightFill = 0;
	if( !IsTopTable() && (nAbsLeftFill>0 || nAbsRightFill) )
	{
		sal_uLong nAbsLeftFillL = nAbsLeftFill, nAbsRightFillL = nAbsRightFill;

		nRelLeftFill = (sal_uInt16)((nAbsLeftFillL * nRelAvail) / nAbsAvail);
		nRelRightFill = (sal_uInt16)((nAbsRightFillL * nRelAvail) / nAbsAvail);

		nAbsAvail -= (nAbsLeftFill + nAbsRightFill);
		if( nRelAvail )
			nRelAvail -= (nRelLeftFill + nRelRightFill);
	}


	// Schritt 2: Die absolute Tabellenbreite wird berechnet.
	sal_uInt16 nAbsTabWidth = 0;
	bUseRelWidth = sal_False;
	if( nWidthOption )
	{
		if( bPrcWidthOption )
		{
			ASSERT( nWidthOption<=100, "Prozentangabe zu gross" );
			if( nWidthOption > 100 )
				nWidthOption = 100;

			// Die absolute Breite entspricht den angegeben Prozent der
			// zur Verfuegung stehenden Breite.
			// Top-Tabellen bekommen nur eine relative Breite, wenn der
			// verfuegbare Platz *echt groesser* ist als die Minimalbreite.
			// ACHTUNG: Das "echte groesser" ist noetig, weil der Wechsel
			// von einer relativen Breite zu einer absoluten Breite durch
			// Resize sonst zu einer Endlosschleife fuehrt.
			// Weil bei Tabellen in Rahmen kein Resize aufgerufen wird,
			// wenn der Rahmen eine nicht-relative Breite besitzt, koennen
			// wir da solche Spielchen nicht spielen
			// MIB 19.2.98: Wegen fix #47394# spielen wir solche Spielchen
			// jetzt doch. Dort war eine Grafik in einer 1%-breiten
			// Tabelle und hat da natuerlich nicht hineingepasst.
			nAbsTabWidth = (sal_uInt16)( ((sal_uLong)nAbsAvail * nWidthOption) / 100 );
			if( IsTopTable() &&
				( /*MayBeInFlyFrame() ||*/ (sal_uLong)nAbsTabWidth > nMin ) )
			{
				nRelAvail = USHRT_MAX;
				bUseRelWidth = sal_True;
			}
		}
		else
		{
			nAbsTabWidth = nWidthOption;
			if( nAbsTabWidth > MAX_TABWIDTH )
				nAbsTabWidth = MAX_TABWIDTH;

			// Tabellen in Tabellen duerfen niemals breiter werden als der
			// verfuegbare Platz.
			if( !IsTopTable() && nAbsTabWidth > nAbsAvail )
				nAbsTabWidth = nAbsAvail;
		}
	}

	ASSERT( IsTopTable() || nAbsTabWidth<=nAbsAvail,
			"AutoLayout Pass2: nAbsTabWidth > nAbsAvail fuer Tab in Tab" );
	ASSERT( !nRelAvail || nAbsTabWidth<=nAbsAvail,
			"AutoLayout Pass2: nAbsTabWidth > nAbsAvail fuer relative Breite" );

	// Catch fuer die beiden Asserts von oben (man weiss ja nie!)
	if( (!IsTopTable() || nRelAvail>0) && nAbsTabWidth>nAbsAvail )
		nAbsTabWidth = nAbsAvail;


	// Schritt 3: Bestimmen der Spaltenbreiten und ggf. auch der
	// absoluten und relativen Tabellenbreiten.
	if( (!IsTopTable() && nMin > (sal_uLong)nAbsAvail) ||
		nMin > MAX_TABWIDTH )
	{
		// Wenn
		// - das Minumum einer inneren Tabelle groesser ist als der
		//   verfuegbare Platz, oder
		// - das Minumum einer Top-Table groesser ist als USHRT_MAX
		// muss die Tabelle an den verfuegbaren Platz bzw. USHRT_MAX
		// abgepasst werden. Dabei bleiben die Verhaeltnisse der Breiten
		// untereinander erhalten.

		nAbsTabWidth = IsTopTable() ? MAX_TABWIDTH : nAbsAvail;
		nRelTabWidth = (nRelAvail ? nRelAvail : nAbsTabWidth );

		// First of all, we check wether we can fit the layout constrains,
		// that are: Every cell's width excluding the borders must be at least
		// MINLAY:

		sal_uLong nRealMin = 0;
		for( sal_uInt16 i=0; i<nCols; i++ )
		{
			sal_uLong nRealColMin = MINLAY, nDummy1, nDummy2;
			AddBorderWidth( nRealColMin, nDummy1, nDummy2, i, 1 );
			nRealMin += nRealColMin;
		}
		if( (nRealMin >= nAbsTabWidth) || (nRealMin >= nMin) )
		{
			// "Nichts geht mehr". We cannot get the minimum column widths
			// the layout wants to have.

			sal_uInt16 nAbs = 0, nRel = 0;
			SwHTMLTableLayoutColumn *pColumn;
			for( sal_uInt16 i=0; i<nCols-1; i++ )
			{
				pColumn = GetColumn( i );
				sal_uLong nColMin = pColumn->GetMin();
				if( nColMin <= USHRT_MAX )
				{
					pColumn->SetAbsColWidth(
						(sal_uInt16)((nColMin * nAbsTabWidth) / nMin) );
					pColumn->SetRelColWidth(
						(sal_uInt16)((nColMin * nRelTabWidth) / nMin) );
				}
				else
				{
					double nColMinD = nColMin;
					pColumn->SetAbsColWidth(
						(sal_uInt16)((nColMinD * nAbsTabWidth) / nMin) );
					pColumn->SetRelColWidth(
						(sal_uInt16)((nColMinD * nRelTabWidth) / nMin) );
				}

				nAbs = nAbs + (sal_uInt16)pColumn->GetAbsColWidth();
				nRel = nRel + (sal_uInt16)pColumn->GetRelColWidth();
			}
			pColumn = GetColumn( nCols-1 );
			pColumn->SetAbsColWidth( nAbsTabWidth - nAbs );
			pColumn->SetRelColWidth( nRelTabWidth - nRel );
		}
		else
		{
			sal_uLong nDistAbs = nAbsTabWidth - nRealMin;
			sal_uLong nDistRel = nRelTabWidth - nRealMin;
			sal_uLong nDistMin = nMin - nRealMin;
			sal_uInt16 nAbs = 0, nRel = 0;
			SwHTMLTableLayoutColumn *pColumn;
			for( sal_uInt16 i=0; i<nCols-1; i++ )
			{
				pColumn = GetColumn( i );
				sal_uLong nColMin = pColumn->GetMin();
				sal_uLong nRealColMin = MINLAY, nDummy1, nDummy2;
				AddBorderWidth( nRealColMin, nDummy1, nDummy2, i, 1 );

				if( nColMin <= USHRT_MAX )
				{
					pColumn->SetAbsColWidth(
						(sal_uInt16)((((nColMin-nRealColMin) * nDistAbs) / nDistMin) + nRealColMin) );
					pColumn->SetRelColWidth(
						(sal_uInt16)((((nColMin-nRealColMin) * nDistRel) / nDistMin) + nRealColMin) );
				}
				else
				{
					double nColMinD = nColMin;
					pColumn->SetAbsColWidth(
						(sal_uInt16)((((nColMinD-nRealColMin) * nDistAbs) / nDistMin) + nRealColMin) );
					pColumn->SetRelColWidth(
						(sal_uInt16)((((nColMinD-nRealColMin) * nDistRel) / nDistMin) + nRealColMin) );
				}

				nAbs = nAbs + (sal_uInt16)pColumn->GetAbsColWidth();
				nRel = nRel + (sal_uInt16)pColumn->GetRelColWidth();
			}
			pColumn = GetColumn( nCols-1 );
			pColumn->SetAbsColWidth( nAbsTabWidth - nAbs );
			pColumn->SetRelColWidth( nRelTabWidth - nRel );
		}
	}
	else if( nMax <= (sal_uLong)(nAbsTabWidth ? nAbsTabWidth : nAbsAvail) )
	{
		// Wenn
		// - die Tabelle eine fixe Breite besitzt und das Maximum der
		//   Tabelle kleiner ist, oder
		// - das Maximum kleiner ist als der verfuegbare Platz
		// kann das Maximum direkt uebernommen werden bzw. die Tabelle nur
		// unter Beruecksichtigung des Maxumums an die fixe Breite
		// angepasst werden.

		// Keine fixe Breite, dann das Maximum nehmen.
		if( !nAbsTabWidth )
			nAbsTabWidth = (sal_uInt16)nMax;

		// Eine Top-Table darf auch beriter werden als der verfuegbare Platz.
		if( nAbsTabWidth > nAbsAvail )
		{
			ASSERT( IsTopTable(),
					"Tabelle in Tabelle soll breiter werden als umgebende Zelle" );
			nAbsAvail = nAbsTabWidth;
		}

		// Nur den Anteil der relativen Breite verwenden, der auch fuer
		// die absolute Breite verwendet wuerde.
		sal_uLong nAbsTabWidthL = nAbsTabWidth;
		nRelTabWidth =
			( nRelAvail ? (sal_uInt16)((nAbsTabWidthL * nRelAvail) / nAbsAvail)
						: nAbsTabWidth );

		// Gibt es Spalten mit und Spalten ohne %-Angabe?
		sal_uLong nFixMax = nMax;
		for( sal_uInt16 i=0; i<nCols; i++ )
		{
			const SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
			if( pColumn->IsRelWidthOption() && pColumn->GetWidthOption()>0 )
				nFixMax -= pColumn->GetMax();
		}

		if( nFixMax > 0 && nFixMax < nMax )
		{
			// ja, dann den zu verteilenden Platz nur auf die Spalten
			// mit %-Angabe verteilen.

			// In diesem (und nur in diesem) Fall gibt es Spalten,
			// die ihre Maximalbreite genau einhalten, also weder
			// schmaler noch breiter werden. Beim zurueckrechnen der
			// absoluten Breite aus der relativen Breite kann es
			// zu Rundungsfehlern kommen (bug #45598#). Um die auszugeleichen
			// werden zuerst die fixen Breiten entsprechend korrigiert
			// eingestellt und erst danach die relativen.

			sal_uInt16 nAbs = 0, nRel = 0;
			sal_uInt16 nFixedCols = 0;
			sal_uInt16 i;

			for( i = 0; i < nCols; i++ )
			{
				SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
				if( !pColumn->IsRelWidthOption() || !pColumn->GetWidthOption() )
				{
					// Die Spalte behaelt ihre Breite bei.
					nFixedCols++;
					sal_uLong nColMax = pColumn->GetMax();
					pColumn->SetAbsColWidth( (sal_uInt16)nColMax );

					sal_uLong nRelColWidth =
						(nColMax * nRelTabWidth) / nAbsTabWidth;
					sal_uLong nChkWidth =
						(nRelColWidth * nAbsTabWidth) / nRelTabWidth;
					if( nChkWidth < nColMax )
						nRelColWidth++;
					else if( nChkWidth > nColMax )
						nRelColWidth--;
					pColumn->SetRelColWidth( (sal_uInt16)nRelColWidth );

					nAbs = nAbs + (sal_uInt16)nColMax;
					nRel = nRel + (sal_uInt16)nRelColWidth;
				}
			}

			// Zu verteilende Anteile des Maximums und der relativen und
			// absoluten Breiten. nFixMax entspricht an dieser Stelle
			// nAbs, so dass man gleich nFixMax haette nehmen koennen.
			// Der Code ist so aber verstaendlicher.
			ASSERT( nFixMax == nAbs, "Zwei Schleifen, zwei Summen?" )
			sal_uLong nDistMax = nMax - nFixMax;
			sal_uInt16 nDistAbsTabWidth = nAbsTabWidth - nAbs;
			sal_uInt16 nDistRelTabWidth = nRelTabWidth - nRel;

			for( i=0; i<nCols; i++ )
			{
				SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
				if( pColumn->IsRelWidthOption() && pColumn->GetWidthOption() > 0 )
				{
					// Die Spalte wird anteilig breiter.
					nFixedCols++;
					if( nFixedCols == nCols )
					{
						pColumn->SetAbsColWidth( nAbsTabWidth-nAbs );
						pColumn->SetRelColWidth( nRelTabWidth-nRel );
					}
					else
					{
						sal_uLong nColMax = pColumn->GetMax();
						pColumn->SetAbsColWidth(
							(sal_uInt16)((nColMax * nDistAbsTabWidth) / nDistMax) );
						pColumn->SetRelColWidth(
							(sal_uInt16)((nColMax * nDistRelTabWidth) / nDistMax) );
					}
					nAbs = nAbs + pColumn->GetAbsColWidth();
					nRel = nRel + pColumn->GetRelColWidth();
				}
			}
			ASSERT( nCols==nFixedCols, "Spalte vergessen!" );
		}
		else
		{
			// nein, dann den zu verteilenden Platz auf alle Spalten
			// gleichmaessig vertilen.
			for( sal_uInt16 i=0; i<nCols; i++ )
			{
				sal_uLong nColMax = GetColumn( i )->GetMax();
				GetColumn( i )->SetAbsColWidth(
					(sal_uInt16)((nColMax * nAbsTabWidth) / nMax) );
				GetColumn( i )->SetRelColWidth(
					(sal_uInt16)((nColMax * nRelTabWidth) / nMax) );
			}
		}
	}
	else
	{
		// den ueber die Minimalbreite herausgehenden Platz entsprechend
		// den einzelnen Spalten anteilig zuschlagen
		if( !nAbsTabWidth )
			nAbsTabWidth = nAbsAvail;
		if( nAbsTabWidth < nMin )
			nAbsTabWidth = (sal_uInt16)nMin;

		if( nAbsTabWidth > nAbsAvail )
		{
			ASSERT( IsTopTable(),
					"Tabelle in Tabelle soll breiter werden als Platz da ist" );
			nAbsAvail = nAbsTabWidth;
		}

		sal_uLong nAbsTabWidthL = nAbsTabWidth;
		nRelTabWidth =
			( nRelAvail ? (sal_uInt16)((nAbsTabWidthL * nRelAvail) / nAbsAvail)
						: nAbsTabWidth );
		double nW = nAbsTabWidth - nMin;
		double nD = (nMax==nMin ? 1 : nMax-nMin);
		sal_uInt16 nAbs = 0, nRel = 0;
		for( sal_uInt16 i=0; i<nCols-1; i++ )
		{
			double nd = GetColumn( i )->GetMax() - GetColumn( i )->GetMin();
			sal_uLong nAbsColWidth = GetColumn( i )->GetMin() + (sal_uLong)((nd*nW)/nD);
			sal_uLong nRelColWidth = nRelAvail
									? (nAbsColWidth * nRelTabWidth) / nAbsTabWidth
									: nAbsColWidth;

			GetColumn( i )->SetAbsColWidth( (sal_uInt16)nAbsColWidth );
			GetColumn( i )->SetRelColWidth( (sal_uInt16)nRelColWidth );
			nAbs = nAbs + (sal_uInt16)nAbsColWidth;
			nRel = nRel + (sal_uInt16)nRelColWidth;
		}
		GetColumn( nCols-1 )->SetAbsColWidth( nAbsTabWidth - nAbs );
		GetColumn( nCols-1 )->SetRelColWidth( nRelTabWidth - nRel );

	}

	// Schritt 4: Fuer Tabellen in Tabellen kann es links und/oder rechts
	// noch Ausgleichzellen geben. Deren Breite wird jetzt berechnet.
	nInhAbsLeftSpace = 0;
	nInhAbsRightSpace = 0;
	if( !IsTopTable() && (nRelLeftFill>0 || nRelRightFill>0 ||
						  nAbsTabWidth<nAbsAvail) )
	{
		// Die Breite von zusaetzlichen Zellen zur Ausrichtung der
		// inneren Tabelle bestimmen
		sal_uInt16 nAbsDist = (sal_uInt16)(nAbsAvail-nAbsTabWidth);
		sal_uInt16 nRelDist = (sal_uInt16)(nRelAvail-nRelTabWidth);
		sal_uInt16 nParentInhAbsLeftSpace = 0, nParentInhAbsRightSpace = 0;

		// Groesse und Position der zusaetzlichen Zellen bestimmen
		switch( eTableAdjust )
		{
		case SVX_ADJUST_RIGHT:
			nAbsLeftFill = nAbsLeftFill + nAbsDist;
			nRelLeftFill = nRelLeftFill + nRelDist;
			nParentInhAbsLeftSpace = nParentInhAbsSpace;
			break;
		case SVX_ADJUST_CENTER:
			{
				sal_uInt16 nAbsLeftDist = nAbsDist / 2;
				nAbsLeftFill = nAbsLeftFill + nAbsLeftDist;
				nAbsRightFill += nAbsDist - nAbsLeftDist;
				sal_uInt16 nRelLeftDist = nRelDist / 2;
				nRelLeftFill = nRelLeftFill + nRelLeftDist;
				nRelRightFill += nRelDist - nRelLeftDist;
				nParentInhAbsLeftSpace = nParentInhAbsSpace / 2;
				nParentInhAbsRightSpace = nParentInhAbsSpace -
										  nParentInhAbsLeftSpace;
			}
			break;
		case SVX_ADJUST_LEFT:
		default:
			nAbsRightFill = nAbsRightFill + nAbsDist;
			nRelRightFill = nRelRightFill + nRelDist;
			nParentInhAbsRightSpace = nParentInhAbsSpace;
			break;
		}

		ASSERT( !pLeftFillerBox || nRelLeftFill>0,
				"Fuer linke Filler-Box ist keine Breite da!" );
		ASSERT( !pRightFillerBox || nRelRightFill>0,
				"Fuer rechte Filler-Box ist keine Breite da!" );

		// Filler-Breiten werden auf die ausseren Spalten geschlagen, wenn
		// es nach dem ersten Durchlauf keine Boxen fuer sie gibt (nWidth>0)
		// oder ihre Breite zu klein wuerde oder wenn es COL-Tags gibt und
		// die Filler-Breite der Umrandung-Breite entspricht (dann haben wir
		// die Tabelle wahrscheinlich selbst exportiert)
		if( nRelLeftFill && !pLeftFillerBox &&
			( nWidthSet>0 || nAbsLeftFill<MINLAY+nInhLeftBorderWidth ||
			  (HasColTags() && nAbsLeftFill < nAbsLeftSpace+nParentInhAbsLeftSpace+20) ) )
//			(nAbsLeftFill<MINLAY || nAbsLeftFill<=nAbsLeftSpace) )
		{
			SwHTMLTableLayoutColumn *pColumn = GetColumn( 0 );
			pColumn->SetAbsColWidth( pColumn->GetAbsColWidth()+nAbsLeftFill );
			pColumn->SetRelColWidth( pColumn->GetRelColWidth()+nRelLeftFill );
			nRelLeftFill = 0;
			nInhAbsLeftSpace = nAbsLeftSpace + nParentInhAbsLeftSpace;
		}
		if( nRelRightFill && !pRightFillerBox &&
			( nWidthSet>0 || nAbsRightFill<MINLAY+nInhRightBorderWidth ||
			  (HasColTags() && nAbsRightFill < nAbsRightSpace+nParentInhAbsRightSpace+20) ) )
//			(nAbsRightFill<MINLAY || nAbsRightFill<=nAbsRightSpace) )
		{
			SwHTMLTableLayoutColumn *pColumn = GetColumn( nCols-1 );
			pColumn->SetAbsColWidth( pColumn->GetAbsColWidth()+nAbsRightFill );
			pColumn->SetRelColWidth( pColumn->GetRelColWidth()+nRelRightFill );
			nRelRightFill = 0;
			nInhAbsRightSpace = nAbsRightSpace + nParentInhAbsRightSpace;
		}
	}
}

static sal_Bool lcl_ResizeLine( const SwTableLine*& rpLine, void* pPara );

static sal_Bool lcl_ResizeBox( const SwTableBox*& rpBox, void* pPara )
{
	sal_uInt16 *pWidth = (sal_uInt16 *)pPara;

	if( !rpBox->GetSttNd() )
	{
		sal_uInt16 nWidth = 0;
		((SwTableBox *)rpBox)->GetTabLines().ForEach( &lcl_ResizeLine, &nWidth );
        rpBox->GetFrmFmt()->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nWidth, 0 ));
		*pWidth	= *pWidth + nWidth;
	}
	else
	{
		*pWidth = *pWidth + (sal_uInt16)rpBox->GetFrmFmt()->GetFrmSize().GetSize().Width();
	}

	return sal_True;
}

static sal_Bool lcl_ResizeLine( const SwTableLine*& rpLine, void* pPara )
{
	sal_uInt16 *pWidth = (sal_uInt16 *)pPara;
#ifdef DBG_UTIL
	sal_uInt16 nOldWidth = *pWidth;
#endif
	*pWidth = 0;
	((SwTableLine *)rpLine)->GetTabBoxes().ForEach( &lcl_ResizeBox, pWidth );

#ifdef DBG_UTIL
	ASSERT( !nOldWidth || Abs(*pWidth-nOldWidth) < COLFUZZY,
			"Zeilen einer Box sind unterschiedlich lang" );
#endif

	return sal_True;
}

void SwHTMLTableLayout::SetWidths( sal_Bool bCallPass2, sal_uInt16 nAbsAvail,
								   sal_uInt16 nRelAvail, sal_uInt16 nAbsLeftSpace,
								   sal_uInt16 nAbsRightSpace,
								   sal_uInt16 nParentInhAbsSpace )
{
	// SetWidth muss am Ende einmal mehr fuer jede Zelle durchlaufen
	// worden sein.
	nWidthSet++;

	// Schritt 0: Wenn noetig, wird hier noch der Pass2 des Layout-Alogithmus
	// aufgerufen.
	if( bCallPass2 )
		AutoLayoutPass2( nAbsAvail, nRelAvail, nAbsLeftSpace, nAbsRightSpace,
						 nParentInhAbsSpace );

	// Schritt 1: Setzten der neuen Breite an allen Content-Boxen.
	// Da die Boxen nichts von der HTML-Tabellen-Struktur wissen, wird
	// ueber die HTML-Tabellen-Struktur iteriert. Fuer Tabellen in Tabellen
	// in Tabellen wird rekursiv SetWidth aufgerufen.
	for( sal_uInt16 i=0; i<nRows; i++ )
	{
		for( sal_uInt16 j=0; j<nCols; j++ )
		{
			SwHTMLTableLayoutCell *pCell = GetCell( i, j );

			SwHTMLTableLayoutCnts* pCntnts = pCell->GetContents();
			while( pCntnts && !pCntnts->IsWidthSet(nWidthSet) )
			{
				SwTableBox *pBox = pCntnts->GetTableBox();
				if( pBox )
				{
					SetBoxWidth( pBox, j, pCell->GetColSpan() );
				}
				else
				{
					sal_uInt16 nAbs = 0, nRel = 0, nLSpace = 0, nRSpace = 0,
						   nInhSpace = 0;
					if( bCallPass2 )
					{
						sal_uInt16 nColSpan = pCell->GetColSpan();
						GetAvail( j, nColSpan, nAbs, nRel );
						nLSpace = GetLeftCellSpace( j, nColSpan );
						nRSpace = GetRightCellSpace( j, nColSpan );
						nInhSpace = GetInhCellSpace( j, nColSpan );
					}
					pCntnts->GetTable()->SetWidths( bCallPass2, nAbs, nRel,
													nLSpace, nRSpace,
													nInhSpace );
				}

				pCntnts->SetWidthSet( nWidthSet );
				pCntnts = pCntnts->GetNext();
			}
		}
	}

	// Schritt 2: Wenn eine Top-Tabelle vorliegt, werden jetzt die Formate
	// der Nicht-Content-Boxen angepasst. Da diese aufgrund der
	// Garbage-Collection in der HTML-Tabelle nicht bekannt sind, muessen
	// wir hier ueber die Tabelle iterieren. Bei der Gelegenheit wird auch
	// das Tabellen-Frameformat angepasst. Fuer Tabellen in Tabellen werden
	// stattdessen die Breiten der Filler-Zellen gesetzt.
	if( IsTopTable() )
	{
		sal_uInt16 nCalcTabWidth = 0;
		((SwTable *)pSwTable)->GetTabLines().ForEach( &lcl_ResizeLine,
													  &nCalcTabWidth );
		ASSERT( Abs( nRelTabWidth-nCalcTabWidth ) < COLFUZZY,
				"Tabellebreite stimmt nicht mit Zeilenbreite ueberein." );

		// Beim Anpassen des Tabellen-Formats dieses locken, weil sonst
		// die Boxformate erneut angepasst werden. Ausserdem muss eine
		// evtl. vorhandene %-Angabe in jedem Fall erhalten bleiben.
		SwFrmFmt *pFrmFmt = pSwTable->GetFrmFmt();
		((SwTable *)pSwTable)->LockModify();
		SwFmtFrmSize aFrmSize( pFrmFmt->GetFrmSize() );
		aFrmSize.SetWidth( nRelTabWidth );
		sal_Bool bRel = bUseRelWidth &&
                    text::HoriOrientation::FULL!=pFrmFmt->GetHoriOrient().GetHoriOrient();
		aFrmSize.SetWidthPercent( (sal_uInt8)(bRel ? nWidthOption : 0) );
        pFrmFmt->SetFmtAttr( aFrmSize );
		((SwTable *)pSwTable)->UnlockModify();

		// Wenn die Tabelle in einem Rahmen steht, muss auch noch dessen
		// breite angepasst werden.
		if( MayBeInFlyFrame() )
		{
			SwFrmFmt *pFlyFrmFmt = FindFlyFrmFmt();
			if( pFlyFrmFmt )
			{
				SwFmtFrmSize aFlyFrmSize( ATT_VAR_SIZE, nRelTabWidth, MINLAY );

				if( bUseRelWidth )
				{
					// Bei %-Angaben wird die Breite auf das Minimum gesetzt.
					aFlyFrmSize.SetWidth(  nMin > USHRT_MAX	? USHRT_MAX
															: nMin );
					aFlyFrmSize.SetWidthPercent( (sal_uInt8)nWidthOption );
				}
                pFlyFrmFmt->SetFmtAttr( aFlyFrmSize );
			}
		}

#ifdef DBG_UTIL
		{
			// steht im tblrwcl.cxx
			extern void _CheckBoxWidth( const SwTableLine&, SwTwips );

			// checke doch mal ob die Tabellen korrekte Breiten haben
			SwTwips nSize = pSwTable->GetFrmFmt()->GetFrmSize().GetWidth();
			const SwTableLines& rLines = pSwTable->GetTabLines();
			for( sal_uInt16 n = 0; n < rLines.Count(); ++n  )
				_CheckBoxWidth( *rLines[ n ], nSize );
		}
#endif

	}
	else
	{
		if( pLeftFillerBox )
		{
            pLeftFillerBox->GetFrmFmt()->SetFmtAttr(
				SwFmtFrmSize( ATT_VAR_SIZE, nRelLeftFill, 0 ));
		}
		if( pRightFillerBox )
		{
            pRightFillerBox->GetFrmFmt()->SetFmtAttr(
				SwFmtFrmSize( ATT_VAR_SIZE, nRelRightFill, 0 ));
		}
	}
}

void SwHTMLTableLayout::_Resize( sal_uInt16 nAbsAvail, sal_Bool bRecalc )
{
	// Wenn bRecalc gestzt ist, hat sich am Inhalt der Tabelle etwas
	// geaendert. Es muss dann der erste Pass noch einmal durchgefuehrt
	// werden.
	if( bRecalc )
		AutoLayoutPass1();

	SwRootFrm *pRoot = (SwRootFrm*)GetDoc()->GetCurrentViewShell()->GetLayout();
	if ( pRoot && pRoot->IsCallbackActionEnabled() )
		pRoot->StartAllAction();	//swmod 071108//swmod 071225

	// Sonst koennen die Breiten gesetzt werden, wobei zuvor aber jewils
	// noch der Pass 2 laufen muss.
	SetWidths( sal_True, nAbsAvail );

	if ( pRoot && pRoot->IsCallbackActionEnabled() )
		pRoot->EndAllAction( sal_True );	//True per VirDev (Browsen ruhiger)	//swmod 071108//swmod 071225
}

IMPL_STATIC_LINK( SwHTMLTableLayout, DelayedResize_Impl, void*, EMPTYARG )
{
#ifdef TEST_DELAYED_RESIZE
	Sound::Beep( SOUND_WARNING );
#endif
	pThis->aResizeTimer.Stop();
	pThis->_Resize( pThis->nDelayedResizeAbsAvail,
					pThis->bDelayedResizeRecalc );

	return 0;
}


sal_Bool SwHTMLTableLayout::Resize( sal_uInt16 nAbsAvail, sal_Bool bRecalc,
								sal_Bool bForce, sal_uLong nDelay )
{
	if( 0 == nAbsAvail )
		return sal_False;
	ASSERT( IsTopTable(), "Resize darf nur an Top-Tabellen aufgerufen werden" );

	// Darf die Tabelle uberhaupt Resized werden oder soll sie es trotzdem?
	if( bMustNotResize && !bForce )
		return sal_False;

	// Darf ein Recalc der Tabelle durchgefuehrt werden?
	if( bMustNotRecalc && !bForce )
		bRecalc = sal_False;

	const SwDoc *pDoc = GetDoc();

	// Wenn es ein Layout gibt, wurde evtl. die Groesse der Root-Frames
	// und nicht die der VisArea uebergeben. Wenn wir nicht in einem Rahmen
	// stehen, muss die Tabelle allerdings fuer die VisArea berechnet werden,
	// weil sond die Umschaltung von relativ nach absolut nicht funktioniert.
    if( pDoc->GetCurrentViewShell() && pDoc->GetCurrentViewShell()->GetViewOptions()->getBrowseMode() )
	{
        const sal_uInt16 nVisAreaWidth = GetBrowseWidthByVisArea( *pDoc );
		if( nVisAreaWidth < nAbsAvail && !FindFlyFrmFmt() )
			nAbsAvail = nVisAreaWidth;
	}

	if( nDelay==0 && aResizeTimer.IsActive() )
	{
		// Wenn beim Aufruf eines synchronen Resize noch ein asynchrones
		// Resize aussteht, dann werden nur die neuen Werte uebernommen.

		bRecalc |= bDelayedResizeRecalc;
		nDelayedResizeAbsAvail = nAbsAvail;
		return sal_False;
	}

	// Optimierung:
	// Wenn die Minima/Maxima nicht neu berechnet werden sollen und
	// - die Breite der Tabelle nie neu berechnet werden muss, oder
	// - die Tabelle schon fuer die uebergebene Breite berechnet wurde, oder
	// - der verfuegbare Platz kleiner oder gleich der Minimalbreite ist
	//   und die Tabelle bereits die Minimalbreite besitzt, oder
	// - der verfuegbare Platz groesser ist als die Maximalbreite und
	//   die Tabelle bereits die Maximalbreite besitzt
	// wird sich an der Tabelle nichts aendern.
	if( !bRecalc && ( !bMustResize ||
					  (nLastResizeAbsAvail==nAbsAvail) ||
					  (nAbsAvail<=nMin && nRelTabWidth==nMin) ||
					  (!bPrcWidthOption && nAbsAvail>=nMax && nRelTabWidth==nMax) ) )
		return sal_False;

	if( nDelay==HTMLTABLE_RESIZE_NOW )
	{
		if( aResizeTimer.IsActive() )
			aResizeTimer.Stop();
		_Resize( nAbsAvail, bRecalc );
	}
	else if( nDelay > 0 )
	{
		nDelayedResizeAbsAvail = nAbsAvail;
		bDelayedResizeRecalc = bRecalc;
		aResizeTimer.SetTimeout( nDelay );
		aResizeTimer.Start();
#ifdef TEST_DELAYED_RESIZE
		Sound::Beep( SOUND_DEFAULT );
#endif
	}
	else
	{
		_Resize( nAbsAvail, bRecalc );
	}

	return sal_True;
}

void SwHTMLTableLayout::BordersChanged( sal_uInt16 nAbsAvail, sal_Bool bRecalc )
{
	bBordersChanged = sal_True;

	Resize( nAbsAvail, bRecalc );
}