From ed5640d8b587fbcfed7dd7967f3de04b37a76f26 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 11:06:44 +0200 Subject: Adding upstream version 4:7.4.7. Signed-off-by: Daniel Baumann --- sw/source/core/doc/htmltbl.cxx | 1772 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1772 insertions(+) create mode 100644 sw/source/core/doc/htmltbl.cxx (limited to 'sw/source/core/doc/htmltbl.cxx') diff --git a/sw/source/core/doc/htmltbl.cxx b/sw/source/core/doc/htmltbl.cxx new file mode 100644 index 000000000..19f8e3305 --- /dev/null +++ b/sw/source/core/doc/htmltbl.cxx @@ -0,0 +1,1772 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef DBG_UTIL +#include +#endif + +using namespace ::com::sun::star; + +#define COLFUZZY 20 +#define MAX_TABWIDTH (USHRT_MAX - 2001) + +namespace { + +class SwHTMLTableLayoutConstraints +{ + sal_uInt16 m_nRow; // start row + sal_uInt16 m_nCol; // start column + sal_uInt16 m_nColSpan; // the column's COLSPAN + + std::unique_ptr m_pNext; // the next constraint + + sal_uLong m_nMinNoAlign, m_nMaxNoAlign; // provisional result of AL-Pass 1 + +public: + SwHTMLTableLayoutConstraints( sal_uLong nMin, sal_uLong nMax, sal_uInt16 nRow, + sal_uInt16 nCol, sal_uInt16 nColSp ); + + sal_uLong GetMinNoAlign() const { return m_nMinNoAlign; } + sal_uLong GetMaxNoAlign() const { return m_nMaxNoAlign; } + + SwHTMLTableLayoutConstraints *InsertNext( SwHTMLTableLayoutConstraints *pNxt ); + SwHTMLTableLayoutConstraints* GetNext() const { return m_pNext.get(); } + + sal_uInt16 GetColSpan() const { return m_nColSpan; } + sal_uInt16 GetColumn() const { return m_nCol; } +}; + +} + +SwHTMLTableLayoutCnts::SwHTMLTableLayoutCnts(const SwStartNode *pSttNd, + std::shared_ptr const& rTab, + bool bNoBrTag, + std::shared_ptr const& rNxt ) : + m_xNext( rNxt ), m_pBox( nullptr ), m_xTable( rTab ), m_pStartNode( pSttNd ), + m_nPass1Done( 0 ), m_nWidthSet( 0 ), m_bNoBreakTag( bNoBrTag ) +{} + +const SwStartNode *SwHTMLTableLayoutCnts::GetStartNode() const +{ + return m_pBox ? m_pBox->GetSttNd() : m_pStartNode; +} + +SwHTMLTableLayoutCell::SwHTMLTableLayoutCell(std::shared_ptr const& rCnts, + sal_uInt16 nRSpan, sal_uInt16 nCSpan, + sal_uInt16 nWidth, bool bPercentWidth, + bool bNWrapOpt ) : + m_xContents(rCnts), + m_nRowSpan( nRSpan ), m_nColSpan( nCSpan ), + m_nWidthOption( nWidth ), m_bPercentWidthOption( bPercentWidth ), + m_bNoWrapOption( bNWrapOpt ) +{} + +SwHTMLTableLayoutColumn::SwHTMLTableLayoutColumn( sal_uInt16 nWidth, + bool bRelWidth, + bool bLBorder ) : + m_nMinNoAlign(MINLAY), m_nMaxNoAlign(MINLAY), m_nAbsMinNoAlign(MINLAY), + m_nMin(0), m_nMax(0), + m_nAbsColWidth(0), m_nRelColWidth(0), + m_nWidthOption( nWidth ), m_bRelWidthOption( bRelWidth ), + m_bLeftBorder( bLBorder ) +{} + +SwHTMLTableLayoutConstraints::SwHTMLTableLayoutConstraints(sal_uLong nMin, sal_uLong nMax, + sal_uInt16 nRw, sal_uInt16 nColumn, + sal_uInt16 nColSp) + : m_nRow(nRw) + , m_nCol(nColumn) + , m_nColSpan(nColSp) + , m_nMinNoAlign(nMin) + , m_nMaxNoAlign(nMax) +{} + +SwHTMLTableLayoutConstraints *SwHTMLTableLayoutConstraints::InsertNext( + SwHTMLTableLayoutConstraints *pNxt ) +{ + SwHTMLTableLayoutConstraints *pPrev = nullptr; + SwHTMLTableLayoutConstraints *pConstr = this; + while( pConstr ) + { + if (pConstr->m_nRow > pNxt->m_nRow || pConstr->GetColumn() > pNxt->GetColumn()) + break; + pPrev = pConstr; + pConstr = pConstr->GetNext(); + } + + if( pPrev ) + { + pNxt->m_pNext = std::move(pPrev->m_pNext); + pPrev->m_pNext.reset(pNxt); + pConstr = this; + } + else + { + pNxt->m_pNext.reset(this); + pConstr = pNxt; + } + + return pConstr; +} + +SwHTMLTableLayout::SwHTMLTableLayout( const SwTable * pTable, + sal_uInt16 nRws, sal_uInt16 nCls, + bool bColsOpt, bool bColTgs, + sal_uInt16 nWdth, bool bPercentWdth, + 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 ) + : m_aResizeTimer("SwHTMLTableLayout m_aResizeTimer") + , m_aColumns( nCls ) + , m_aCells( static_cast(nRws)*nCls ) + , m_pSwTable( pTable ) + , m_nMin( 0 ) + , m_nMax( 0 ) + , m_nRows( nRws ) + , m_nCols( nCls ) + , m_nLeftMargin( nLMargin ) + , m_nRightMargin( nRMargin ) + , m_nInhAbsLeftSpace( 0 ) + , m_nInhAbsRightSpace( 0 ) + , m_nRelLeftFill( 0 ) + , m_nRelRightFill( 0 ) + , m_nRelTabWidth( 0 ) + , m_nWidthOption( nWdth ) + , m_nCellPadding( nCellPad ) + , m_nCellSpacing( nCellSp ) + , m_nBorder( nBorderOpt ) + , m_nLeftBorderWidth( nLeftBWidth ) + , m_nRightBorderWidth( nRightBWidth ) + , m_nInhLeftBorderWidth( 0 ) + , m_nInhRightBorderWidth( 0 ) + , m_nBorderWidth( nBWidth ) + , m_nDelayedResizeAbsAvail( 0 ) + , m_nLastResizeAbsAvail( 0 ) + , m_nPass1Done( 0 ) + , m_nWidthSet( 0 ) + , m_eTableAdjust( eAdjust ) + , m_bColsOption( bColsOpt ) + , m_bColTags( bColTgs ) + , m_bPercentWidthOption( bPercentWdth ) + , m_bUseRelWidth( false ) + , m_bMustResize( true ) + , m_bExportable( true ) + , m_bBordersChanged( false ) + , m_bMayBeInFlyFrame( false ) + , m_bDelayedResizeRecalc( false) + , m_bMustNotResize( false ) + , m_bMustNotRecalc( false ) +{ + m_aResizeTimer.SetInvokeHandler( LINK( this, SwHTMLTableLayout, + DelayedResize_Impl ) ); +} + +SwHTMLTableLayout::~SwHTMLTableLayout() +{ +} + +/// The border widths are calculated like in Netscape: +/// Outer border: BORDER + CELLSPACING + CELLPADDING +/// Inner border: CELLSPACING + CELLPADDING +/// However, we respect the border widths in SW if bSwBorders is set, +/// so that we don't wrap wrongly. +/// We also need to respect the distance to the content. Even if +/// only the opposite side has a border. +sal_uInt16 SwHTMLTableLayout::GetLeftCellSpace( sal_uInt16 nCol, sal_uInt16 nColSpan, + bool bSwBorders ) const +{ + sal_uInt16 nSpace = m_nCellSpacing + m_nCellPadding; + + if( nCol == 0 ) + { + nSpace = nSpace + m_nBorder; + + if( bSwBorders && nSpace < m_nLeftBorderWidth ) + nSpace = m_nLeftBorderWidth; + } + else if( bSwBorders ) + { + if( GetColumn(nCol)->HasLeftBorder() ) + { + if( nSpace < m_nBorderWidth ) + nSpace = m_nBorderWidth; + } + else if( nCol+nColSpan == m_nCols && m_nRightBorderWidth && + nSpace < MIN_BORDER_DIST ) + { + OSL_ENSURE( !m_nCellPadding, "GetLeftCellSpace: CELLPADDING!=0" ); + // If the opposite side has a border we need to respect at + // least the minimum distance to the content. + // Additionally, we could also use nCellPadding for this. + nSpace = MIN_BORDER_DIST; + } + } + + return nSpace; +} + +sal_uInt16 SwHTMLTableLayout::GetRightCellSpace( sal_uInt16 nCol, sal_uInt16 nColSpan, + bool bSwBorders ) const +{ + sal_uInt16 nSpace = m_nCellPadding; + + if( nCol+nColSpan == m_nCols ) + { + nSpace += m_nBorder + m_nCellSpacing; + if( bSwBorders && nSpace < m_nRightBorderWidth ) + nSpace = m_nRightBorderWidth; + } + else if( bSwBorders && GetColumn(nCol)->HasLeftBorder() && + nSpace < MIN_BORDER_DIST ) + { + OSL_ENSURE( !m_nCellPadding, "GetRightCellSpace: CELLPADDING!=0" ); + // If the opposite side has a border we need to respect at + // least the minimum distance to the content. + // Additionally, we could also use nCellPadding for this. + nSpace = MIN_BORDER_DIST; + } + + return nSpace; +} + +void SwHTMLTableLayout::AddBorderWidth( sal_uLong &rMin, sal_uLong &rMax, + sal_uLong &rAbsMin, + sal_uInt16 nCol, sal_uInt16 nColSpan, + 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 +{ + SwFrameFormat *pFrameFormat = pBox->GetFrameFormat(); + + // calculate the box's width + SwTwips nFrameWidth = 0; + while( nColSpan-- ) + nFrameWidth += GetColumn( nCol++ )->GetRelColWidth(); + + // and reset + pFrameFormat->SetFormatAttr( SwFormatFrameSize( SwFrameSize::Variable, nFrameWidth, 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; iGetAbsColWidth(); + rRelAvail = rRelAvail + pColumn->GetRelColWidth(); + } +} + +sal_uInt16 SwHTMLTableLayout::GetBrowseWidthByVisArea( const SwDoc& rDoc ) +{ + SwViewShell const *pVSh = rDoc.getIDocumentLayoutAccess().GetCurrentViewShell(); + if( pVSh ) + { + return o3tl::narrowing(pVSh->GetBrowseWidth()); + } + + return 0; +} + +sal_uInt16 SwHTMLTableLayout::GetBrowseWidth( const SwDoc& rDoc ) +{ + // If we have a layout, we can get the width from there. + const SwRootFrame *pRootFrame = rDoc.getIDocumentLayoutAccess().GetCurrentLayout(); + if( pRootFrame ) + { + const SwFrame *pPageFrame = pRootFrame->GetLower(); + if( pPageFrame ) + return o3tl::narrowing(pPageFrame->getFramePrintArea().Width()); + } + + // #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::GetBrowseWidthByTabFrame( + const SwTabFrame& rTabFrame ) const +{ + SwTwips nWidth = 0; + + const SwFrame *pUpper = rTabFrame.GetUpper(); + if( MayBeInFlyFrame() && pUpper->IsFlyFrame() && + static_cast(pUpper)->GetAnchorFrame() ) + { + // If the table is located within a self-created frame, the anchor's + // width is relevant not the frame's width. + // For paragraph-bound frames we don't respect paragraph indents. + const SwFrame *pAnchor = static_cast(pUpper)->GetAnchorFrame(); + if( pAnchor->IsTextFrame() ) + nWidth = pAnchor->getFrameArea().Width(); + else + nWidth = pAnchor->getFramePrintArea().Width(); + } + else + { + nWidth = pUpper->getFramePrintArea().Width(); + } + + SwTwips nUpperDummy = 0; + tools::Long nRightOffset = 0, + nLeftOffset = 0; + rTabFrame.CalcFlyOffsets(nUpperDummy, nLeftOffset, nRightOffset, nullptr); + nWidth -= (nLeftOffset + nRightOffset); + + return o3tl::narrowing(std::min(nWidth, SwTwips(SAL_MAX_UINT16))); +} + +sal_uInt16 SwHTMLTableLayout::GetBrowseWidthByTable( const SwDoc& rDoc ) const +{ + sal_uInt16 nBrowseWidth = 0; + SwTabFrame* pFrame = SwIterator( *m_pSwTable->GetFrameFormat() ).First(); + if( pFrame ) + { + nBrowseWidth = GetBrowseWidthByTabFrame( *pFrame ); + } + else + { + nBrowseWidth = SwHTMLTableLayout::GetBrowseWidth( rDoc ); + } + + return nBrowseWidth; +} + +const SwStartNode *SwHTMLTableLayout::GetAnyBoxStartNode() const +{ + const SwStartNode *pBoxSttNd; + + const SwTableBox* pBox = m_pSwTable->GetTabLines()[0]->GetTabBoxes()[0]; + while( nullptr == (pBoxSttNd = pBox->GetSttNd()) ) + { + OSL_ENSURE( !pBox->GetTabLines().empty(), + "Box without start node and lines" ); + OSL_ENSURE( !pBox->GetTabLines().front()->GetTabBoxes().empty(), + "Line without boxes" ); + pBox = pBox->GetTabLines().front()->GetTabBoxes().front(); + } + + return pBoxSttNd; +} + +SwFrameFormat *SwHTMLTableLayout::FindFlyFrameFormat() const +{ + const SwTableNode *pTableNd = GetAnyBoxStartNode()->FindTableNode(); + OSL_ENSURE( pTableNd, "No Table-Node?" ); + return pTableNd->GetFlyFormat(); +} + +static void lcl_GetMinMaxSize( sal_uLong& rMinNoAlignCnts, sal_uLong& rMaxNoAlignCnts, + sal_uLong& rAbsMinNoAlignCnts, + SwTextNode const *pTextNd, SwNodeOffset nIdx, bool bNoBreak ) +{ + pTextNd->GetMinMaxSize( nIdx, rMinNoAlignCnts, rMaxNoAlignCnts, + rAbsMinNoAlignCnts ); + OSL_ENSURE( rAbsMinNoAlignCnts <= rMinNoAlignCnts, + "GetMinMaxSize: absmin > min" ); + OSL_ENSURE( rMinNoAlignCnts <= rMaxNoAlignCnts, + "GetMinMaxSize: max > min" ); + + // The maximal width for a
 paragraph is the minimal width
+    const SwFormatColl *pColl = &pTextNd->GetAnyFormatColl();
+    while( pColl && !pColl->IsDefault() &&
+            (USER_FMT & pColl->GetPoolFormatId()) )
+    {
+        pColl = static_cast(pColl->DerivedFrom());
+    }
+
+    //  in the whole cell apply to text but not to tables.
+    // Netscape only considers this for graphics.
+    if( (pColl && RES_POOLCOLL_HTML_PRE==pColl->GetPoolFormatId()) || bNoBreak )
+    {
+        rMinNoAlignCnts = rMaxNoAlignCnts;
+        rAbsMinNoAlignCnts = rMaxNoAlignCnts;
+    }
+}
+
+void SwHTMLTableLayout::AutoLayoutPass1()
+{
+    m_nPass1Done++;
+
+    m_nMin = m_nMax = 0; // clear pass1 info
+
+    bool bFixRelWidths = false;
+    sal_uInt16 i;
+
+    std::unique_ptr xConstraints;
+
+    for( i=0; iClearPass1Info( !HasColTags() );
+        sal_uInt16 nMinColSpan = USHRT_MAX; // Column count to which the calculated width refers to
+        sal_uInt16 nColSkip = USHRT_MAX;    // How many columns need to be skipped
+
+        for( sal_uInt16 j=0; jGetContents().get();
+
+            // We need to examine all rows in order to
+            // get the column that should be calculated next.
+            sal_uInt16 nColSpan = pCell->GetColSpan();
+            if( nColSpan < nColSkip )
+                nColSkip = nColSpan;
+
+            if( !pCnts || !pCnts->IsPass1Done(m_nPass1Done) )
+            {
+                // The cell is empty or it's content was not edited
+                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;
+
+                while( pCnts )
+                {
+                    const SwStartNode *pSttNd = pCnts->GetStartNode();
+                    if( pSttNd )
+                    {
+                        const SwDoc& rDoc = pSttNd->GetDoc();
+                        SwNodeOffset nIdx = pSttNd->GetIndex();
+                        while (!rDoc.GetNodes()[nIdx]->IsEndNode())
+                        {
+                            SwTextNode *pTextNd = (rDoc.GetNodes()[nIdx])->GetTextNode();
+                            if( pTextNd )
+                            {
+                                sal_uLong nMinNoAlignCnts = 0;
+                                sal_uLong nMaxNoAlignCnts = 0;
+                                sal_uLong nAbsMinNoAlignCnts = 0;
+
+                                lcl_GetMinMaxSize( nMinNoAlignCnts,
+                                                   nMaxNoAlignCnts,
+                                                   nAbsMinNoAlignCnts,
+                                                   pTextNd, nIdx,
+                                                   pCnts->HasNoBreakTag() );
+
+                                if( nMinNoAlignCnts > nMinNoAlignCell )
+                                    nMinNoAlignCell = nMinNoAlignCnts;
+                                if( nMaxNoAlignCnts > nMaxNoAlignCell )
+                                    nMaxNoAlignCell = nMaxNoAlignCnts;
+                                if( nAbsMinNoAlignCnts > nAbsMinNoAlignCell )
+                                    nAbsMinNoAlignCell = nAbsMinNoAlignCnts;
+                            }
+                            else
+                            {
+                                SwTableNode *pTabNd = (rDoc.GetNodes()[nIdx])->GetTableNode();
+                                if( pTabNd )
+                                {
+                                    SwHTMLTableLayout *pChild = pTabNd->GetTable().GetHTMLTableLayout();
+                                    if( pChild )
+                                    {
+                                        pChild->AutoLayoutPass1();
+                                        sal_uLong nMaxTableCnts = pChild->m_nMax;
+                                        sal_uLong nAbsMinTableCnts = pChild->m_nMin;
+
+                                        // A fixed table width is taken over as minimum and
+                                        // maximum at the same time
+                                        if( !pChild->m_bPercentWidthOption && pChild->m_nWidthOption )
+                                        {
+                                            sal_uLong nTabWidth = pChild->m_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 if (SwHTMLTableLayout *pChild = pCnts->GetTable())
+                    {
+                        OSL_ENSURE( false, "Sub tables in HTML import?" );
+                        pChild->AutoLayoutPass1();
+                        sal_uLong nMaxTableCnts = pChild->m_nMax;
+                        sal_uLong nAbsMinTableCnts = pChild->m_nMin;
+
+                        // A fixed table width is taken over as minimum and
+                        // maximum at the same time
+                        if( !pChild->m_bPercentWidthOption && pChild->m_nWidthOption )
+                        {
+                            sal_uLong nTabWidth = pChild->m_nWidthOption;
+                            if( nTabWidth >= nAbsMinTableCnts  )
+                            {
+                                nMaxTableCnts = nTabWidth;
+                                nAbsMinTableCnts = nTabWidth;
+                            }
+                            else
+                            {
+                                nMaxTableCnts = nAbsMinTableCnts;
+                            }
+                        }
+
+                        if( nMaxTableCnts > nMaxTableCell )
+                            nMaxTableCell = nMaxTableCnts;
+                        if( nAbsMinTableCnts > nAbsMinTableCell )
+                            nAbsMinTableCell = nAbsMinTableCnts;
+                    }
+                    pCnts->SetPass1Done( m_nPass1Done );
+                    pCnts = pCnts->GetNext().get();
+                }
+
+// This code previously came after AddBorderWidth
+                // If a table's width is wider in a cell than what we've calculated
+                // for the other content we need to use the table's width.
+                if( nMaxTableCell > nMaxNoAlignCell )
+                    nMaxNoAlignCell = nMaxTableCell;
+                if( nAbsMinTableCell > nAbsMinNoAlignCell )
+                {
+                    nAbsMinNoAlignCell = nAbsMinTableCell;
+                    if( nMinNoAlignCell < nAbsMinNoAlignCell )
+                        nMinNoAlignCell = nAbsMinNoAlignCell;
+                    if( nMaxNoAlignCell < nMinNoAlignCell )
+                        nMaxNoAlignCell = nMinNoAlignCell;
+                }
+// This code previously came after AddBorderWidth
+
+                bool bRelWidth = pCell->IsPercentWidthOption();
+                sal_uInt16 nWidth = pCell->GetWidthOption();
+
+                // A NOWRAP option applies to text and tables, but is
+                // not applied for fixed cell width.
+                // Instead, the stated cell width behaves like a minimal
+                // width.
+                if( pCell->HasNoWrapOption() )
+                {
+                    if( nWidth==0 || bRelWidth )
+                    {
+                        nMinNoAlignCell = nMaxNoAlignCell;
+                        nAbsMinNoAlignCell = nMaxNoAlignCell;
+                    }
+                    else
+                    {
+                        if( nWidth>nMinNoAlignCell )
+                            nMinNoAlignCell = nWidth;
+                        if( nWidth>nAbsMinNoAlignCell )
+                            nAbsMinNoAlignCell = nWidth;
+                    }
+                }
+
+                // Respect minimum width for content
+                if( nMinNoAlignCell < MINLAY )
+                    nMinNoAlignCell = MINLAY;
+                if( nMaxNoAlignCell < MINLAY )
+                    nMaxNoAlignCell = MINLAY;
+                if( nAbsMinNoAlignCell < MINLAY )
+                    nAbsMinNoAlignCell = MINLAY;
+
+                // Respect the border and distance to the content
+                AddBorderWidth( nMinNoAlignCell, nMaxNoAlignCell,
+                                nAbsMinNoAlignCell, i, nColSpan );
+
+                if( 1==nColSpan )
+                {
+                    // take over the values directly
+                    pColumn->MergeMinMaxNoAlign( nMinNoAlignCell,
+                                                 nMaxNoAlignCell,
+                                                 nAbsMinNoAlignCell );
+
+                    // the widest WIDTH wins
+                    if( !HasColTags() )
+                        pColumn->MergeCellWidthOption( nWidth, bRelWidth );
+                }
+                else
+                {
+                    // Process the data line by line from left to right at the end
+
+                    // When which values is taken over will be explained further down.
+                    if( !HasColTags() && nWidth && !bRelWidth )
+                    {
+                        sal_uLong nAbsWidth = nWidth, nDummy = 0, nDummy2 = 0;
+                        AddBorderWidth( nAbsWidth, nDummy, nDummy2,
+                                        i, nColSpan, 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 (xConstraints)
+                    {
+                        SwHTMLTableLayoutConstraints* pConstraints = xConstraints->InsertNext(pConstr);
+                        xConstraints.release();
+                        xConstraints.reset(pConstraints);
+                    }
+                    else
+                        xConstraints.reset(pConstr);
+                }
+            }
+        }
+
+        OSL_ENSURE( nMinColSpan>0 && nColSkip>0 && nColSkip <= nMinColSpan,
+                "Layout pass 1: Columns are being forgotten!" );
+        OSL_ENSURE( nMinColSpan!=USHRT_MAX,
+                "Layout pass 1: unnecessary pass through the loop or a bug" );
+
+        if( 1==nMinColSpan )
+        {
+            // There are cells with COLSPAN 1 and therefore also useful
+            // values in pColumn
+
+            // Take over values according to the following table (Netscape 4.0 pv 3):
+
+            // WIDTH:           no COLS         COLS
+
+            // none             min = min       min = absmin
+            //                  max = max       max = max
+
+            // >= min           min = min       min = width
+            //                  max = width     max = width
+
+            // >= absmin        min = width(*)  min = width
+            //                  max = width     max = width
+
+            // < absmin         min = absmin    min = absmin
+            //                  max = absmin    max = absmin
+
+            // (*) Netscape uses the minimum width without a break before
+            //     the last graphic here. We don't have that (yet?),
+            //     so we leave it set to width.
+
+            if( pColumn->GetWidthOption() && !pColumn->IsRelWidthOption() )
+            {
+                // Take over absolute widths as minimal and maximal widths.
+                sal_uLong nAbsWidth = pColumn->GetWidthOption();
+                sal_uLong nDummy = 0, nDummy2 = 0;
+                AddBorderWidth( nAbsWidth, nDummy, nDummy2, i, 1, 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 )
+        {
+            // Can be anything != 0, because it is altered by the constraints.
+            pColumn->SetMinMax( MINLAY, MINLAY );
+
+            // the next columns need not to be processed
+            i += (nColSkip-1);
+        }
+
+        m_nMin += pColumn->GetMin();
+        m_nMax += pColumn->GetMax();
+        if (pColumn->IsRelWidthOption()) bFixRelWidths = true;
+    }
+
+    // Now process the constraints
+    SwHTMLTableLayoutConstraints *pConstr = xConstraints.get();
+    while( pConstr )
+    {
+        // At first we need to process the width in the same way
+        // as the column widths
+        sal_uInt16 nCol = pConstr->GetColumn();
+        sal_uInt16 nColSpan = pConstr->GetColSpan();
+        sal_uLong nConstrMin = pConstr->GetMinNoAlign();
+        sal_uLong nConstrMax = pConstr->GetMaxNoAlign();
+
+        // We get the hitherto width of the spanned columns
+        sal_uLong nColsMin = 0;
+        sal_uLong nColsMax = 0;
+        for( sal_uInt16 j=nCol; jGetMin();
+            nColsMax += pColumn->GetMax();
+        }
+
+        if( nColsMin nColsMax )
+            {
+                // Proportional according to the minimum widths
+                sal_uInt16 nEndCol = nCol+nColSpan;
+                sal_uLong nDiff = nMinD;
+                for( sal_uInt16 ic=nCol; icGetMin();
+                    sal_uLong nColMax = pColumn->GetMax();
+
+                    m_nMin -= nColMin;
+                    sal_uLong nAdd;
+                    if (ic < nEndCol-1)
+                    {
+                        if (nColsMin == 0)
+                            throw o3tl::divide_by_zero();
+                        nAdd = (nColMin * nMinD) / nColsMin;
+                    }
+                    else
+                    {
+                        nAdd = nDiff;
+                    }
+                    nColMin += nAdd;
+                    m_nMin += nColMin;
+                    OSL_ENSURE( nDiff >= nAdd, "Ooops: nDiff is not correct anymore" );
+                    nDiff -= nAdd;
+
+                    if( nColMax < nColMin )
+                    {
+                        m_nMax -= nColMax;
+                        nColsMax -= nColMax;
+                        nColMax = nColMin;
+                        m_nMax += nColMax;
+                        nColsMax += nColMax;
+                    }
+
+                    pColumn->SetMinMax( nColMin, nColMax );
+                }
+            }
+            else
+            {
+                // Proportional according to the difference of max and min
+                for( sal_uInt16 ic=nCol; icGetMax()-pColumn->GetMin();
+                    if( nMinD < nDiff )
+                        nDiff = nMinD;
+
+                    pColumn->AddToMin( nDiff );
+
+                    OSL_ENSURE( pColumn->GetMax() >= pColumn->GetMin(),
+                            "Why is the Column suddenly too narrow?" );
+
+                    m_nMin += nDiff;
+                    nMinD -= nDiff;
+                }
+            }
+        }
+
+        if( !HasColTags() && nColsMaxGetMax();
+
+                pColumn->AddToMax( (pColumn->GetMax() * nMaxD) / nColsMax );
+
+                m_nMax += pColumn->GetMax();
+            }
+        }
+
+        pConstr = pConstr->GetNext();
+    }
+
+    if( !bFixRelWidths )
+        return;
+
+    if( HasColTags() )
+    {
+        // To adapt the relative widths, in a first step we multiply the
+        // minimum width of all affected cells with the relative width
+        // of the column.
+        // Thus, the width ratio among the columns is correct.
+
+        // Furthermore, a factor is calculated that says by how much the
+        // cell has gotten wider than the minimum width.
+
+        // In the second step the calculated widths are divided by this
+        // factor.  Thereby a cell's width is preserved and serves as a
+        // basis for the other cells.
+        // We only change the maximum widths here!
+
+        sal_uLong nAbsMin = 0;  // absolute minimum width of all widths with relative width
+        sal_uLong nRel = 0;     // sum of all relative widths of all columns
+        for( i=0; iIsRelWidthOption() && pColumn->GetWidthOption() )
+            {
+                nAbsMin += pColumn->GetMin();
+                nRel += pColumn->GetWidthOption();
+            }
+        }
+
+        sal_uLong nQuot = ULONG_MAX;
+        for( i=0; iIsRelWidthOption() )
+            {
+                m_nMax -= pColumn->GetMax();
+                if( pColumn->GetWidthOption() && pColumn->GetMin() )
+                {
+                    pColumn->SetMax( nAbsMin * pColumn->GetWidthOption() );
+                    sal_uLong nColQuot = pColumn->GetMax() / pColumn->GetMin();
+                    if( nColQuotIsRelWidthOption() )
+            {
+                if( pColumn->GetWidthOption() )
+                    pColumn->SetMax( pColumn->GetMax() / nQuot );
+                else
+                    pColumn->SetMax( pColumn->GetMin() );
+                OSL_ENSURE( pColumn->GetMax() >= pColumn->GetMin(),
+                        "Maximum column width is lower than the minimum column width" );
+                m_nMax += pColumn->GetMax();
+            }
+        }
+    }
+    else
+    {
+        sal_uInt16 nRel = 0;        // sum of the relative widths of all columns
+        sal_uInt16 nRelCols = 0;    // count of the columns with a relative setting
+        sal_uLong nRelMax = 0;      // fraction of the maximum of this column
+        for( i=0; i 100%" );
+            SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
+            if( pColumn->IsRelWidthOption() && pColumn->GetWidthOption() )
+            {
+                // Make sure that the relative widths don't go above 100%
+                sal_uInt16 nColWidth = pColumn->GetWidthOption();
+                if( nRel+nColWidth > 100 )
+                {
+                    nColWidth = 100 - nRel;
+                    pColumn->SetWidthOption( nColWidth );
+                }
+                nRelMax += pColumn->GetMax();
+                nRel = nRel + nColWidth;
+                nRelCols++;
+            }
+            else if( !pColumn->GetMin() )
+            {
+                // The column is empty (so it was solely created by
+                // COLSPAN) and therefore must not be assigned a % width.
+                nRelCols++;
+            }
+        }
+
+        // If there are percentages left we distribute them to the columns
+        // that don't have a width setting. Like in Netscape we distribute
+        // the remaining percentages according to the ratio of the maximum
+        // width of the affected columns.
+        // For the maximum widths we also take the fixed-width columns
+        // into account.  Is that correct?
+        sal_uLong nFixMax = 0;
+        if( nRel < 100 && nRelCols < m_nCols )
+        {
+            nFixMax = m_nMax - nRelMax;
+            SAL_WARN_IF(!nFixMax, "sw.core", "bad fixed width max");
+        }
+        if (nFixMax)
+        {
+            sal_uInt16 nRelLeft = 100 - nRel;
+            for( i=0; iIsRelWidthOption() &&
+                    !pColumn->GetWidthOption() &&
+                    pColumn->GetMin() )
+                {
+                    // the next column gets the rest
+                    sal_uInt16 nColWidth =
+                        o3tl::narrowing((pColumn->GetMax() * nRelLeft) / nFixMax);
+                    pColumn->SetWidthOption( nColWidth );
+                }
+            }
+        }
+
+        // adjust the maximum widths now accordingly
+        sal_uLong nQuotMax = ULONG_MAX;
+        sal_uLong nOldMax = m_nMax;
+        m_nMax = 0;
+        for( i=0; iIsRelWidthOption() && pColumn->GetWidthOption() )
+            {
+                sal_uLong nNewMax;
+                sal_uLong nColQuotMax;
+                if( !m_nWidthOption )
+                {
+                    nNewMax = nOldMax * pColumn->GetWidthOption();
+                    nColQuotMax = nNewMax / pColumn->GetMax();
+                }
+                else
+                {
+                    nNewMax = m_nMin * pColumn->GetWidthOption();
+                    nColQuotMax = nNewMax / pColumn->GetMin();
+                }
+                pColumn->SetMax( nNewMax );
+                if( nColQuotMax < nQuotMax )
+                    nQuotMax = nColQuotMax;
+            }
+            else if( HasColsOption() || m_nWidthOption ||
+                     (pColumn->IsRelWidthOption() &&
+                      !pColumn->GetWidthOption()) )
+                pColumn->SetMax( pColumn->GetMin() );
+        }
+        // and divide by the quotient
+        SAL_WARN_IF(!nQuotMax, "sw.core", "Where did the relative columns go?");
+        for (i = 0; i < m_nCols; ++i)
+        {
+            SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
+            if (pColumn->IsRelWidthOption() && pColumn->GetWidthOption() && nQuotMax)
+            {
+                pColumn->SetMax( pColumn->GetMax() / nQuotMax );
+                OSL_ENSURE( pColumn->GetMax() >= pColumn->GetMin(),
+                        "Minimum width is one column bigger than maximum" );
+                if( pColumn->GetMax() < pColumn->GetMin() )
+                    pColumn->SetMax( pColumn->GetMin() );
+            }
+            m_nMax += pColumn->GetMax();
+        }
+    }
+}
+
+//TODO: provide documentation
+/**
+
+    @param nAbsAvail available space in TWIPS.
+    @param nRelAvail available space related to USHRT_MAX or 0
+    @param nAbsSpace fraction of nAbsAvail, which is reserved by the surrounding
+                     cell for the border and the distance to the paragraph.
+*/
+void SwHTMLTableLayout::AutoLayoutPass2( sal_uInt16 nAbsAvail, sal_uInt16 nRelAvail,
+                                         sal_uInt16 nAbsLeftSpace,
+                                         sal_uInt16 nAbsRightSpace,
+                                         sal_uInt16 nParentInhAbsSpace )
+{
+    // For a start we do a lot of plausibility tests
+
+    // An absolute width always has to be passed
+    OSL_ENSURE( nAbsAvail, "AutoLayout pass 2: No absolute width given" );
+
+    // A relative width must only be passed for tables within tables (?)
+    OSL_ENSURE( IsTopTable() == (nRelAvail==0),
+            "AutoLayout pass 2: Relative width at table in table or the other way around" );
+
+    // The table's minimum width must not be bigger than its maximum width
+    OSL_ENSURE( m_nMin<=m_nMax, "AutoLayout pass 2: nMin > nMax" );
+
+    // Remember the available width for which the table was calculated.
+    // This is a good place as we pass by here for the initial calculation
+    // of the table in the parser and for each Resize_ call.
+    m_nLastResizeAbsAvail = nAbsAvail;
+
+    // Step 1: The available space is readjusted for the left/right border,
+    // possibly existing filler cells and distances.
+
+    // Distance to the content and border
+    sal_uInt16 nAbsLeftFill = 0, nAbsRightFill = 0;
+    if( !IsTopTable() &&
+        GetMin() + nAbsLeftSpace + nAbsRightSpace <= nAbsAvail )
+    {
+        nAbsLeftFill = nAbsLeftSpace;
+        nAbsRightFill = nAbsRightSpace;
+    }
+
+    // Left and right distance
+    if( m_nLeftMargin || m_nRightMargin )
+    {
+        if( IsTopTable() )
+        {
+            // For the top table we always respect the borders, because we
+            // never go below the table's minimum width.
+            nAbsAvail -= (m_nLeftMargin + m_nRightMargin);
+        }
+        else if( GetMin() + m_nLeftMargin + m_nRightMargin <= nAbsAvail )
+        {
+            // Else, we only respect the borders if there's space available
+            // for them (nMin has already been calculated!)
+            nAbsLeftFill = nAbsLeftFill + m_nLeftMargin;
+            nAbsRightFill = nAbsRightFill + m_nRightMargin;
+        }
+    }
+
+    // Read just the available space
+    m_nRelLeftFill = 0;
+    m_nRelRightFill = 0;
+    if( !IsTopTable() && (nAbsLeftFill>0 || nAbsRightFill) )
+    {
+        sal_uLong nAbsLeftFillL = nAbsLeftFill, nAbsRightFillL = nAbsRightFill;
+
+        m_nRelLeftFill = o3tl::narrowing((nAbsLeftFillL * nRelAvail) / nAbsAvail);
+        m_nRelRightFill = o3tl::narrowing((nAbsRightFillL * nRelAvail) / nAbsAvail);
+
+        nAbsAvail -= (nAbsLeftFill + nAbsRightFill);
+        if( nRelAvail )
+            nRelAvail -= (m_nRelLeftFill + m_nRelRightFill);
+    }
+
+    // Step 2: Calculate the absolute table width.
+    sal_uInt16 nAbsTabWidth = 0;
+    m_bUseRelWidth = false;
+    if( m_nWidthOption )
+    {
+        if( m_bPercentWidthOption )
+        {
+            OSL_ENSURE( m_nWidthOption<=100, "Percentage value too high" );
+            if( m_nWidthOption > 100 )
+                m_nWidthOption = 100;
+
+            // The absolute width is equal to the given percentage of
+            // the available width.
+            // Top tables only get a relative width if the available space
+            // is *strictly larger* than the minimum width.
+
+            // CAUTION: We need the "strictly larger" because changing from a
+            // relative width to an absolute width by resizing would lead
+            // to an infinite loop.
+
+            // Because we do not call resize for tables in frames if the
+            // frame has a non-relative width, we cannot play such games.
+
+            // Let's play such games now anyway. We had a graphic in a 1% wide
+            // table and it didn't fit in of course.
+            nAbsTabWidth = o3tl::narrowing( (static_cast(nAbsAvail) * m_nWidthOption) / 100 );
+            if( IsTopTable() &&
+                ( /*MayBeInFlyFrame() ||*/ static_cast(nAbsTabWidth) > m_nMin ) )
+            {
+                nRelAvail = USHRT_MAX;
+                m_bUseRelWidth = true;
+            }
+        }
+        else
+        {
+            nAbsTabWidth = m_nWidthOption;
+            if( nAbsTabWidth > MAX_TABWIDTH )
+                nAbsTabWidth = MAX_TABWIDTH;
+
+            // Tables within tables must never get wider than the available
+            // space.
+            if( !IsTopTable() && nAbsTabWidth > nAbsAvail )
+                nAbsTabWidth = nAbsAvail;
+        }
+    }
+
+    OSL_ENSURE( IsTopTable() || nAbsTabWidth<=nAbsAvail,
+            "AutoLayout pass 2: nAbsTabWidth > nAbsAvail for table in table" );
+    OSL_ENSURE( !nRelAvail || nAbsTabWidth<=nAbsAvail,
+            "AutoLayout pass 2: nAbsTabWidth > nAbsAvail for relative width" );
+
+    // Catch for the two asserts above (we never know!)
+    if( (!IsTopTable() || nRelAvail>0) && nAbsTabWidth>nAbsAvail )
+        nAbsTabWidth = nAbsAvail;
+
+    // Step 3: Identify the column width and, if applicable, the absolute
+    // and relative table widths.
+    if( (!IsTopTable() && m_nMin > static_cast(nAbsAvail)) ||
+        m_nMin > MAX_TABWIDTH )
+    {
+        // If
+        // - an inner table's minimum is larger than the available space, or
+        // - a top table's minimum is larger than USHORT_MAX the table
+        // has to be adapted to the available space or USHORT_MAX.
+        // We preserve the widths' ratio amongst themselves, however.
+
+        nAbsTabWidth = IsTopTable() ? MAX_TABWIDTH : nAbsAvail;
+        m_nRelTabWidth = (nRelAvail ? nRelAvail : nAbsTabWidth );
+
+        // First of all, we check whether we can fit the layout constrains,
+        // which are: Every cell's width excluding the borders must be at least
+        // MINLAY:
+
+        sal_uLong nRealMin = 0;
+        for( sal_uInt16 i=0; i= nAbsTabWidth) || (nRealMin >= m_nMin) )
+        {
+            // "Rien ne va plus": 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; iGetMin();
+                if( nColMin <= USHRT_MAX )
+                {
+                    pColumn->SetAbsColWidth(
+                        o3tl::narrowing((nColMin * nAbsTabWidth) / m_nMin) );
+                    pColumn->SetRelColWidth(
+                        o3tl::narrowing((nColMin * m_nRelTabWidth) / m_nMin) );
+                }
+                else
+                {
+                    double nColMinD = nColMin;
+                    pColumn->SetAbsColWidth(
+                        o3tl::narrowing((nColMinD * nAbsTabWidth) / m_nMin) );
+                    pColumn->SetRelColWidth(
+                        o3tl::narrowing((nColMinD * m_nRelTabWidth) / m_nMin) );
+                }
+
+                nAbs = nAbs + pColumn->GetAbsColWidth();
+                nRel = nRel + pColumn->GetRelColWidth();
+            }
+            pColumn = GetColumn( m_nCols-1 );
+            pColumn->SetAbsColWidth( nAbsTabWidth - nAbs );
+            pColumn->SetRelColWidth( m_nRelTabWidth - nRel );
+        }
+        else
+        {
+            sal_uLong nDistAbs = nAbsTabWidth - nRealMin;
+            sal_uLong nDistRel = m_nRelTabWidth - nRealMin;
+            sal_uLong nDistMin = m_nMin - nRealMin;
+            sal_uInt16 nAbs = 0, nRel = 0;
+            SwHTMLTableLayoutColumn *pColumn;
+            for( sal_uInt16 i=0; iGetMin();
+                sal_uLong nRealColMin = MINLAY, nDummy1 = 0, nDummy2 = 0;
+                AddBorderWidth( nRealColMin, nDummy1, nDummy2, i, 1 );
+
+                if( nColMin <= USHRT_MAX )
+                {
+                    pColumn->SetAbsColWidth(
+                        o3tl::narrowing((((nColMin-nRealColMin) * nDistAbs) / nDistMin) + nRealColMin) );
+                    pColumn->SetRelColWidth(
+                        o3tl::narrowing((((nColMin-nRealColMin) * nDistRel) / nDistMin) + nRealColMin) );
+                }
+                else
+                {
+                    double nColMinD = nColMin;
+                    pColumn->SetAbsColWidth(
+                        o3tl::narrowing((((nColMinD-nRealColMin) * nDistAbs) / nDistMin) + nRealColMin) );
+                    pColumn->SetRelColWidth(
+                        o3tl::narrowing((((nColMinD-nRealColMin) * nDistRel) / nDistMin) + nRealColMin) );
+                }
+
+                nAbs = nAbs + pColumn->GetAbsColWidth();
+                nRel = nRel + pColumn->GetRelColWidth();
+            }
+            pColumn = GetColumn( m_nCols-1 );
+            pColumn->SetAbsColWidth( nAbsTabWidth - nAbs );
+            pColumn->SetRelColWidth( m_nRelTabWidth - nRel );
+        }
+    }
+    else if( m_nMax <= static_cast(nAbsTabWidth ? nAbsTabWidth : nAbsAvail) )
+    {
+        // If
+        // - the table has a fixed width and the table's maximum is
+        //   smaller, or
+        //- the maximum is smaller than the available space,
+        // we can take over the maximum as it is. Respectively
+        // the table can only be adapted to the fixed width by
+        // respecting the maximum.
+
+        // No fixed width, use the maximum.
+        if( !nAbsTabWidth )
+            nAbsTabWidth = o3tl::narrowing(m_nMax);
+
+        // A top table may also get wider then the available space.
+        if( nAbsTabWidth > nAbsAvail )
+        {
+            OSL_ENSURE( IsTopTable(),
+                    "Table in table should get wider than the surrounding cell." );
+            nAbsAvail = nAbsTabWidth;
+        }
+
+        // Only use the relative widths' fraction, that is used for the
+        // absolute width.
+        sal_uLong nAbsTabWidthL = nAbsTabWidth;
+        if (nRelAvail)
+        {
+            if (nAbsAvail == 0)
+                throw o3tl::divide_by_zero();
+            m_nRelTabWidth = o3tl::narrowing((nAbsTabWidthL * nRelAvail) / nAbsAvail);
+        }
+        else
+            m_nRelTabWidth = nAbsTabWidth;
+
+        // Are there columns width a percentage setting and some without one?
+        sal_uLong nFixMax = m_nMax;
+        for( sal_uInt16 i=0; iIsRelWidthOption() && pColumn->GetWidthOption()>0 )
+                nFixMax -= pColumn->GetMax();
+        }
+
+        if( nFixMax > 0 && nFixMax < m_nMax )
+        {
+            // Yes, distribute the to-be-distributed space only to the
+            // columns with a percentage setting.
+
+            // In this case (and in this case only) there are columns
+            // that exactly keep their maximum width, that is they neither
+            // get smaller nor wider. When calculating the absolute width
+            // from the relative width we can get rounding errors.
+            // To correct this, we first make the fixed widths compensate for
+            // this error. We then fix the relative widths the same way.
+
+            sal_uInt16 nAbs = 0, nRel = 0;
+            sal_uInt16 nFixedCols = 0;
+            sal_uInt16 i;
+
+            for( i = 0; i < m_nCols; i++ )
+            {
+                SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
+                if( !pColumn->IsRelWidthOption() || !pColumn->GetWidthOption() )
+                {
+                    // The column keeps its width.
+                    nFixedCols++;
+                    sal_uLong nColMax = pColumn->GetMax();
+                    pColumn->SetAbsColWidth( o3tl::narrowing(nColMax) );
+
+                    sal_uLong nRelColWidth =
+                        (nColMax * m_nRelTabWidth) / nAbsTabWidth;
+                    sal_uLong nChkWidth =
+                        (nRelColWidth * nAbsTabWidth) / m_nRelTabWidth;
+                    if( nChkWidth < nColMax )
+                        nRelColWidth++;
+                    else if( nChkWidth > nColMax )
+                        nRelColWidth--;
+                    pColumn->SetRelColWidth( o3tl::narrowing(nRelColWidth) );
+
+                    nAbs = nAbs + o3tl::narrowing(nColMax);
+                    nRel = nRel + o3tl::narrowing(nRelColWidth);
+                }
+            }
+
+            // The to-be-distributed percentage of the maximum, the
+            // relative and absolute widths. Here, nFixMax corresponds
+            // to nAbs, so that we could've called it nAbs.
+            // The code is, however, more readable like that.
+            OSL_ENSURE( nFixMax == nAbs, "Two loops, two sums?" );
+            sal_uLong nDistMax = m_nMax - nFixMax;
+            sal_uInt16 nDistAbsTabWidth = nAbsTabWidth - nAbs;
+            sal_uInt16 nDistRelTabWidth = m_nRelTabWidth - nRel;
+
+            for( i=0; iIsRelWidthOption() && pColumn->GetWidthOption() > 0 )
+                {
+                    // The column gets proportionately wider.
+                    nFixedCols++;
+                    if( nFixedCols == m_nCols )
+                    {
+                        pColumn->SetAbsColWidth( nAbsTabWidth-nAbs );
+                        pColumn->SetRelColWidth( m_nRelTabWidth-nRel );
+                    }
+                    else
+                    {
+                        sal_uLong nColMax = pColumn->GetMax();
+                        pColumn->SetAbsColWidth(
+                            o3tl::narrowing((nColMax * nDistAbsTabWidth) / nDistMax) );
+                        pColumn->SetRelColWidth(
+                            o3tl::narrowing((nColMax * nDistRelTabWidth) / nDistMax) );
+                    }
+                    nAbs = nAbs + pColumn->GetAbsColWidth();
+                    nRel = nRel + pColumn->GetRelColWidth();
+                }
+            }
+            OSL_ENSURE( m_nCols==nFixedCols, "Missed a column!" );
+        }
+        else if (m_nCols > 0)
+        {
+            if (m_nMax == 0)
+                throw o3tl::divide_by_zero();
+            // No. So distribute the space regularly among all columns.
+            for (sal_uInt16 i=0; i < m_nCols; ++i)
+            {
+                sal_uLong nColMax = GetColumn( i )->GetMax();
+                GetColumn( i )->SetAbsColWidth(
+                    o3tl::narrowing((nColMax * nAbsTabWidth) / m_nMax) );
+                GetColumn( i )->SetRelColWidth(
+                    o3tl::narrowing((nColMax * m_nRelTabWidth) / m_nMax) );
+            }
+        }
+    }
+    else
+    {
+        // Proportionately distribute the space that extends over the minimum
+        // width among the columns.
+        if( !nAbsTabWidth )
+            nAbsTabWidth = nAbsAvail;
+        if( nAbsTabWidth < m_nMin )
+            nAbsTabWidth = o3tl::narrowing(m_nMin);
+
+        if( nAbsTabWidth > nAbsAvail )
+        {
+            OSL_ENSURE( IsTopTable(),
+                    "A nested table should become wider than the available space." );
+            nAbsAvail = nAbsTabWidth;
+        }
+
+        sal_uLong nAbsTabWidthL = nAbsTabWidth;
+        if (nRelAvail)
+        {
+            if (nAbsAvail == 0)
+                throw o3tl::divide_by_zero();
+            m_nRelTabWidth = o3tl::narrowing((nAbsTabWidthL * nRelAvail) / nAbsAvail);
+        }
+        else
+            m_nRelTabWidth = nAbsTabWidth;
+        double nW = nAbsTabWidth - m_nMin;
+        double nD = (m_nMax==m_nMin ? 1 : m_nMax-m_nMin);
+        sal_uInt16 nAbs = 0, nRel = 0;
+        for( sal_uInt16 i=0; iGetMax() - GetColumn( i )->GetMin();
+            sal_uLong nAbsColWidth = GetColumn( i )->GetMin() + static_cast((nd*nW)/nD);
+            sal_uLong nRelColWidth = nRelAvail
+                                    ? (nAbsColWidth * m_nRelTabWidth) / nAbsTabWidth
+                                    : nAbsColWidth;
+
+            GetColumn( i )->SetAbsColWidth( o3tl::narrowing(nAbsColWidth) );
+            GetColumn( i )->SetRelColWidth( o3tl::narrowing(nRelColWidth) );
+            nAbs = nAbs + o3tl::narrowing(nAbsColWidth);
+            nRel = nRel + o3tl::narrowing(nRelColWidth);
+        }
+        GetColumn( m_nCols-1 )->SetAbsColWidth( nAbsTabWidth - nAbs );
+        GetColumn( m_nCols-1 )->SetRelColWidth( m_nRelTabWidth - nRel );
+
+    }
+
+    // Step 4: For nested tables we can have balancing cells on the
+    // left or right. Here we calculate their width.
+    m_nInhAbsLeftSpace = 0;
+    m_nInhAbsRightSpace = 0;
+    if( IsTopTable() ||
+        !(m_nRelLeftFill>0 || m_nRelRightFill>0 || nAbsTabWidth(nAbsAvail-nAbsTabWidth);
+    sal_uInt16 nRelDist = o3tl::narrowing(nRelAvail-m_nRelTabWidth);
+    sal_uInt16 nParentInhAbsLeftSpace = 0, nParentInhAbsRightSpace = 0;
+
+    // Calculate the size and position of the additional cells.
+    switch( m_eTableAdjust )
+    {
+    case SvxAdjust::Right:
+        nAbsLeftFill = nAbsLeftFill + nAbsDist;
+        m_nRelLeftFill = m_nRelLeftFill + nRelDist;
+        nParentInhAbsLeftSpace = nParentInhAbsSpace;
+        break;
+    case SvxAdjust::Center:
+        {
+            sal_uInt16 nAbsLeftDist = nAbsDist / 2;
+            nAbsLeftFill = nAbsLeftFill + nAbsLeftDist;
+            nAbsRightFill += nAbsDist - nAbsLeftDist;
+            sal_uInt16 nRelLeftDist = nRelDist / 2;
+            m_nRelLeftFill = m_nRelLeftFill + nRelLeftDist;
+            m_nRelRightFill += nRelDist - nRelLeftDist;
+            nParentInhAbsLeftSpace = nParentInhAbsSpace / 2;
+            nParentInhAbsRightSpace = nParentInhAbsSpace -
+                                      nParentInhAbsLeftSpace;
+        }
+        break;
+    case SvxAdjust::Left:
+    default:
+        nAbsRightFill = nAbsRightFill + nAbsDist;
+        m_nRelRightFill = m_nRelRightFill + nRelDist;
+        nParentInhAbsRightSpace = nParentInhAbsSpace;
+        break;
+    }
+
+    // Filler widths are added to the outer columns, if there are no boxes
+    // for them after the first pass (nWidth>0) or their width would become
+    // too small or if there are COL tags and the filler width corresponds
+    // to the border width.
+    // In the last case we probably exported the table ourselves.
+    if( m_nRelLeftFill &&
+        ( m_nWidthSet>0 || nAbsLeftFillSetAbsColWidth( pColumn->GetAbsColWidth()+nAbsLeftFill );
+        pColumn->SetRelColWidth( pColumn->GetRelColWidth()+m_nRelLeftFill );
+        m_nRelLeftFill = 0;
+        m_nInhAbsLeftSpace = nAbsLeftSpace + nParentInhAbsLeftSpace;
+    }
+    if( m_nRelRightFill &&
+        ( m_nWidthSet>0 || nAbsRightFillSetAbsColWidth( pColumn->GetAbsColWidth()+nAbsRightFill );
+        pColumn->SetRelColWidth( pColumn->GetRelColWidth()+m_nRelRightFill );
+        m_nRelRightFill = 0;
+        m_nInhAbsRightSpace = nAbsRightSpace + nParentInhAbsRightSpace;
+    }
+}
+
+static void lcl_ResizeLine( const SwTableLine* pLine, SwTwips *pWidth );
+
+static void lcl_ResizeBox( const SwTableBox* pBox, SwTwips* pWidth )
+{
+    if( !pBox->GetSttNd() )
+    {
+        SwTwips nWidth = 0;
+        for( const SwTableLine *pLine : pBox->GetTabLines() )
+            lcl_ResizeLine( pLine, &nWidth );
+        pBox->GetFrameFormat()->SetFormatAttr( SwFormatFrameSize( SwFrameSize::Variable, nWidth, 0 ));
+        *pWidth = *pWidth + nWidth;
+    }
+    else
+    {
+        *pWidth = *pWidth + pBox->GetFrameFormat()->GetFrameSize().GetSize().Width();
+    }
+}
+
+static void lcl_ResizeLine( const SwTableLine* pLine, SwTwips *pWidth )
+{
+    SwTwips nOldWidth = *pWidth;
+    *pWidth = 0;
+    for( const SwTableBox* pBox : pLine->GetTabBoxes() )
+        lcl_ResizeBox(pBox, pWidth );
+
+    SAL_WARN_IF( nOldWidth && std::abs(*pWidth-nOldWidth) >= COLFUZZY, "sw.core",
+                 "A box's rows have all a different length" );
+}
+
+void SwHTMLTableLayout::SetWidths( bool bCallPass2, sal_uInt16 nAbsAvail,
+                                   sal_uInt16 nRelAvail, sal_uInt16 nAbsLeftSpace,
+                                   sal_uInt16 nAbsRightSpace,
+                                   sal_uInt16 nParentInhAbsSpace )
+{
+    // SetWidth must have been passed through once more for every cell in the
+    // end.
+    m_nWidthSet++;
+
+    // Step 0: If necessary, we call the layout algorithm of Pass2.
+    if( bCallPass2 )
+        AutoLayoutPass2( nAbsAvail, nRelAvail, nAbsLeftSpace, nAbsRightSpace,
+                         nParentInhAbsSpace );
+
+    // Step 1: Set the new width in all content boxes.
+    // Because the boxes don't know anything about the HTML table structure,
+    // we iterate over the HTML table structure.
+    // For tables in tables in tables we call SetWidth recursively.
+    for( sal_uInt16 i=0; iGetContents().get();
+            while( pContents && !pContents->IsWidthSet(m_nWidthSet) )
+            {
+                SwTableBox *pBox = pContents->GetTableBox();
+                if( pBox )
+                {
+                    SetBoxWidth( pBox, j, pCell->GetColSpan() );
+                }
+                else if (SwHTMLTableLayout *pTable = pContents->GetTable())
+                {
+                    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 );
+                    }
+                    pTable->SetWidths( bCallPass2, nAbs, nRel,
+                                                    nLSpace, nRSpace,
+                                                    nInhSpace );
+                }
+
+                pContents->SetWidthSet( m_nWidthSet );
+                pContents = pContents->GetNext().get();
+            }
+        }
+    }
+
+    // Step 2: If we have a top table, we adapt the formats of the
+    // non-content-boxes. Because they are not known in the HTML table
+    // due to garbage collection there, we need the iterate over the
+    // whole table.
+    // We also adapt the table frame format. For nested tables we set the
+    // filler cell's width instead.
+    if( !IsTopTable() )
+        return;
+
+    SwTwips nCalcTabWidth = 0;
+    for( const SwTableLine *pLine : m_pSwTable->GetTabLines() )
+        lcl_ResizeLine( pLine, &nCalcTabWidth );
+    SAL_WARN_IF( std::abs( m_nRelTabWidth-nCalcTabWidth ) >= COLFUZZY, "sw.core",
+                 "Table width is not equal to the row width" );
+
+    // Lock the table format when altering it, or else the box formats
+    // are altered again.
+    // Also, we need to preserve a percent setting if it exists.
+    SwFrameFormat *pFrameFormat = m_pSwTable->GetFrameFormat();
+    const_cast(m_pSwTable)->LockModify();
+    SwFormatFrameSize aFrameSize( pFrameFormat->GetFrameSize() );
+    aFrameSize.SetWidth( m_nRelTabWidth );
+    bool bRel = m_bUseRelWidth &&
+                text::HoriOrientation::FULL!=pFrameFormat->GetHoriOrient().GetHoriOrient();
+    aFrameSize.SetWidthPercent( static_cast(bRel ? m_nWidthOption : 0) );
+    pFrameFormat->SetFormatAttr( aFrameSize );
+    const_cast(m_pSwTable)->UnlockModify();
+
+    // If the table is located in a frame, we also need to adapt the
+    // frame's width.
+    if( MayBeInFlyFrame() )
+    {
+        SwFrameFormat *pFlyFrameFormat = FindFlyFrameFormat();
+        if( pFlyFrameFormat )
+        {
+            SwFormatFrameSize aFlyFrameSize( SwFrameSize::Variable, m_nRelTabWidth, MINLAY );
+
+            if( m_bUseRelWidth )
+            {
+                // For percentage settings we set the width to the minimum.
+                aFlyFrameSize.SetWidth(  m_nMin > USHRT_MAX ? USHRT_MAX
+                                                        : m_nMin );
+                aFlyFrameSize.SetWidthPercent( static_cast(m_nWidthOption) );
+            }
+            pFlyFrameFormat->SetFormatAttr( aFlyFrameSize );
+        }
+    }
+
+#ifdef DBG_UTIL
+    {
+        // check if the tables have correct widths
+        SwTwips nSize = m_pSwTable->GetFrameFormat()->GetFrameSize().GetWidth();
+        const SwTableLines& rLines = m_pSwTable->GetTabLines();
+        for (size_t n = 0; n < rLines.size(); ++n)
+        {
+            CheckBoxWidth( *rLines[ n ], nSize );
+        }
+    }
+#endif
+}
+
+void SwHTMLTableLayout::Resize_( sal_uInt16 nAbsAvail, bool bRecalc )
+{
+    // If bRecalc is set, the table's content changed.
+    // We need to execute pass 1 again.
+    if( bRecalc )
+        AutoLayoutPass1();
+
+    SwRootFrame *pRoot = GetDoc().getIDocumentLayoutAccess().GetCurrentViewShell()->GetLayout();
+    if ( pRoot && pRoot->IsCallbackActionEnabled() )
+        pRoot->StartAllAction();
+
+    // Else we can set the widths, in which we have to run Pass 2 in each case.
+    SetWidths( true, nAbsAvail );
+
+    if ( pRoot && pRoot->IsCallbackActionEnabled() )
+        pRoot->EndAllAction( true );    //True per VirDev (browsing is calmer)
+}
+
+IMPL_LINK_NOARG( SwHTMLTableLayout, DelayedResize_Impl, Timer*, void )
+{
+    m_aResizeTimer.Stop();
+    Resize_( m_nDelayedResizeAbsAvail, m_bDelayedResizeRecalc );
+}
+
+bool SwHTMLTableLayout::Resize( sal_uInt16 nAbsAvail, bool bRecalc,
+                                bool bForce, sal_uLong nDelay )
+{
+    if( 0 == nAbsAvail )
+        return false;
+    OSL_ENSURE( IsTopTable(), "Resize must only be called for top tables!" );
+
+    // May the table be resized at all? Or is it forced?
+    if( m_bMustNotResize && !bForce )
+        return false;
+
+    // May the table be recalculated? Or is it forced?
+    if( m_bMustNotRecalc && !bForce )
+        bRecalc = false;
+
+    const SwDoc& rDoc = GetDoc();
+
+    // If there is a layout, the root frame's size instead of the
+    // VisArea's size was potentially passed.
+    // If we're not in a frame we need to calculate the table for the VisArea,
+    // because switching from relative to absolute wouldn't work.
+    if( rDoc.getIDocumentLayoutAccess().GetCurrentViewShell() && rDoc.getIDocumentLayoutAccess().GetCurrentViewShell()->GetViewOptions()->getBrowseMode() )
+    {
+        const sal_uInt16 nVisAreaWidth = GetBrowseWidthByVisArea( rDoc );
+        if( nVisAreaWidth < nAbsAvail && !FindFlyFrameFormat() )
+            nAbsAvail = nVisAreaWidth;
+    }
+
+    if( nDelay==0 && m_aResizeTimer.IsActive() )
+    {
+        m_nDelayedResizeAbsAvail = nAbsAvail;
+        return false;
+    }
+
+    // Optimisation:
+    // If the minimum or maximum should not be recalculated and
+    // - the table's width never needs to be recalculated, or
+    // - the table was already calculated for the passed width, or
+    // - the available space is less or equal to the minimum width
+    //   and the table already has the minimum width, or
+    // - the available space is larger than the maximum width and
+    //   the table already has the maximum width
+    // nothing will happen to the table.
+    if( !bRecalc && ( !m_bMustResize ||
+                      (m_nLastResizeAbsAvail==nAbsAvail) ||
+                      (nAbsAvail<=m_nMin && m_nRelTabWidth==m_nMin) ||
+                      (!m_bPercentWidthOption && nAbsAvail>=m_nMax && m_nRelTabWidth==m_nMax) ) )
+        return false;
+
+    if( nDelay==HTMLTABLE_RESIZE_NOW )
+    {
+        if( m_aResizeTimer.IsActive() )
+            m_aResizeTimer.Stop();
+        Resize_( nAbsAvail, bRecalc );
+    }
+    else if( nDelay > 0 )
+    {
+        m_nDelayedResizeAbsAvail = nAbsAvail;
+        m_bDelayedResizeRecalc = bRecalc;
+        m_aResizeTimer.SetTimeout( nDelay );
+        m_aResizeTimer.Start();
+    }
+    else
+    {
+        Resize_( nAbsAvail, bRecalc );
+    }
+
+    return true;
+}
+
+void SwHTMLTableLayout::BordersChanged( sal_uInt16 nAbsAvail )
+{
+    m_bBordersChanged = true;
+
+    Resize( nAbsAvail, true/*bRecalc*/ );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
-- 
cgit v1.2.3