Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/LibreOffice/sw/source/core/doc/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 68 kB image not shown  

Quelle  htmltbl.cxx   Sprache: C

 
/* -*- 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 <sal/config.h>
#include <sal/log.hxx>

#include <algorithm>
#include <memory>

#include <fmtornt.hxx>
#include <fmtfsize.hxx>
#include <frmfmt.hxx>
#include <ndtxt.hxx>
#include <doc.hxx>
#include <IDocumentLayoutAccess.hxx>
#include <swtable.hxx>
#include <rootfrm.hxx>
#include <flyfrm.hxx>
#include <poolfmt.hxx>
#include <utility>
#include <viewsh.hxx>
#include <tabfrm.hxx>
#include <viewopt.hxx>
#include <htmltbl.hxx>
#include <calbck.hxx>
#include <o3tl/numeric.hxx>
#include <osl/diagnose.h>
#ifdef DBG_UTIL
#include <tblrwcl.hxx>
#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<SwHTMLTableLayoutConstraints> 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<SwHTMLTableLayout> xTab,
                                             bool bNoBrTag,
                                             std::shared_ptr<SwHTMLTableLayoutCnts> xNxt ) :
    m_xNext( std::move(xNxt) ), m_pBox( nullptr ), m_xTable( std::move(xTab) ), 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<SwHTMLTableLayoutCnts> xCnts,
                                          sal_uInt16 nRSpan, sal_uInt16 nCSpan,
                                          sal_uInt16 nWidth, bool bPercentWidth,
                                          bool bNWrapOpt ) :
    m_xContents(std::move(xCnts)),
    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<size_t>(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; i<nCol+nColSpan;i++ )
    {
        const SwHTMLTableLayoutColumn *pColumn = GetColumn(i);
        rAbsAvail = rAbsAvail + pColumn->GetAbsColWidth();
        rRelAvail = rRelAvail + pColumn->GetRelColWidth();
    }
}

sal_uInt16 SwHTMLTableLayout::GetBrowseWidthByVisArea( const SwDoc& rDoc )
{
    SwViewShell const *pVSh = rDoc.getIDocumentLayoutAccess().GetCurrentViewShell();
    if( pVSh )
    {
        return o3tl::narrowing<sal_uInt16>(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<sal_uInt16>(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<const SwFlyFrame *>(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<const SwFlyFrame *>(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<sal_uInt16>(std::min(nWidth, SwTwips(SAL_MAX_UINT16)));
}

sal_uInt16 SwHTMLTableLayout::GetBrowseWidthByTable( const SwDoc& rDoc ) const
{
    sal_uInt16 nBrowseWidth = 0;
    SwTabFrame* pFrame = SwIterator<SwTabFrame,SwFormat>( *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();
    assert(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 <PRE> paragraph is the minimal width
    const SwFormatColl *pColl = &pTextNd->GetAnyFormatColl();
    while( pColl && !pColl->IsDefault() &&
            (USER_FMT & pColl->GetPoolFormatId()) )
    {
        pColl = static_cast<const SwFormatColl *>(pColl->DerivedFrom());
    }

    // <NOBR> 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<SwHTMLTableLayoutConstraints> xConstraints;

    for( i=0; i<m_nCols; i++ )
    {
        SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
        pColumn->ClearPass1Info( !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; j<m_nRows; j++ )
        {
            SwHTMLTableLayoutCell *pCell = GetCell(j,i);
            SwHTMLTableLayoutCnts *pCnts = pCell->GetContents().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);
                        // coverity[leaked_storage] - ownership transferred to pConstraints chain
                        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; j<nCol+nColSpan; j++ )
        {
            SwHTMLTableLayoutColumn *pColumn = GetColumn( j );
            nColsMin += pColumn->GetMin();
            nColsMax += pColumn->GetMax();
        }

        if( nColsMin<nConstrMin )
        {
            // Proportionately distribute the minimum value to the columns
            sal_uLong nMinD = nConstrMin-nColsMin;

            if( nConstrMin > nColsMax )
            {
                // Proportional according to the minimum widths
                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();

                    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; ic<nCol+nColSpan; ic++ )
                {
                    SwHTMLTableLayoutColumn *pColumn = GetColumn( ic );

                    sal_uLong nDiff = pColumn->GetMax()-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() && nColsMax<nConstrMax )
        {
            sal_uLong nMaxD = nConstrMax-nColsMax;

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

                m_nMax -= pColumn->GetMax();

                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; i<m_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<m_nCols; i++ )
        {
            SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
            if( pColumn->IsRelWidthOption() )
            {
                m_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;
                }
            }
        }
        OSL_ENSURE( 0==nRel || nQuot!=ULONG_MAX,
                "Where did the relative columns go?" );
        for( i=0; i<m_nCols; i++ )
        {
            SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
            if( pColumn->IsRelWidthOption() )
            {
                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<m_nCols; i++ )
        {
            OSL_ENSURE( nRel<=100, "relative width of all columns > 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; i<m_nCols; i++ )
            {
                SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
                if( !pColumn->IsRelWidthOption() &&
                    !pColumn->GetWidthOption() &&
                    pColumn->GetMin() )
                {
                    // the next column gets the rest
                    sal_uInt16 nColWidth =
                        o3tl::narrowing<sal_uInt16>((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; i<m_nCols; i++ )
        {
            // Columns with a % setting are adapted accordingly.
            // Columns, that
            // - do not have a % setting and are located within a tables
            // with COLS and WIDTH, or
            // - their width is 0%
            // get set to the minimum width.
            SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
            if( pColumn->IsRelWidthOption() && 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<sal_uInt16>((nAbsLeftFillL * nRelAvail) / nAbsAvail);
        m_nRelRightFill = o3tl::narrowing<sal_uInt16>((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<sal_uInt16>( (static_cast<sal_uLong>(nAbsAvail) * m_nWidthOption) / 100 );
            if( IsTopTable() &&
                ( /*MayBeInFlyFrame() ||*/ static_cast<sal_uLong>(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<sal_uLong>(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<m_nCols; i++ )
        {
            sal_uLong nRealColMin = MINLAY, nDummy1 = 0, nDummy2 = 0;
            AddBorderWidth( nRealColMin, nDummy1, nDummy2, i, 1 );
            nRealMin += nRealColMin;
        }
        if( (nRealMin >= 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; i<m_nCols-1; i++ )
            {
                pColumn = GetColumn( i );
                sal_uLong nColMin = pColumn->GetMin();
                if( nColMin <= USHRT_MAX )
                {
                    pColumn->SetAbsColWidth(
                        o3tl::narrowing<sal_uInt16>((nColMin * nAbsTabWidth) / m_nMin) );
                    pColumn->SetRelColWidth(
                        o3tl::narrowing<sal_uInt16>((nColMin * m_nRelTabWidth) / m_nMin) );
                }
                else
                {
                    double nColMinD = nColMin;
                    pColumn->SetAbsColWidth(
                        o3tl::narrowing<sal_uInt16>((nColMinD * nAbsTabWidth) / m_nMin) );
                    pColumn->SetRelColWidth(
                        o3tl::narrowing<sal_uInt16>((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; i<m_nCols-1; i++ )
            {
                pColumn = GetColumn( i );
                sal_uLong nColMin = pColumn->GetMin();
                sal_uLong nRealColMin = MINLAY, nDummy1 = 0, nDummy2 = 0;
                AddBorderWidth( nRealColMin, nDummy1, nDummy2, i, 1 );

                if( nColMin <= USHRT_MAX )
                {
                    pColumn->SetAbsColWidth(
                        o3tl::narrowing<sal_uInt16>((((nColMin-nRealColMin) * nDistAbs) / nDistMin) + nRealColMin) );
                    pColumn->SetRelColWidth(
                        o3tl::narrowing<sal_uInt16>((((nColMin-nRealColMin) * nDistRel) / nDistMin) + nRealColMin) );
                }
                else
                {
                    double nColMinD = nColMin;
                    pColumn->SetAbsColWidth(
                        o3tl::narrowing<sal_uInt16>((((nColMinD-nRealColMin) * nDistAbs) / nDistMin) + nRealColMin) );
                    pColumn->SetRelColWidth(
                        o3tl::narrowing<sal_uInt16>((((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<sal_uLong>(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<sal_uInt16>(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<sal_uInt16>((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; i<m_nCols; i++ )
        {
            const SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
            if( pColumn->IsRelWidthOption() && 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<sal_uInt16>(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<sal_uInt16>(nRelColWidth) );

                    nAbs = nAbs + o3tl::narrowing<sal_uInt16>(nColMax);
                    nRel = nRel + o3tl::narrowing<sal_uInt16>(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; i<m_nCols; i++ )
            {
                SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
                if( pColumn->IsRelWidthOption() && 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<sal_uInt16>((nColMax * nDistAbsTabWidth) / nDistMax) );
                        pColumn->SetRelColWidth(
                            o3tl::narrowing<sal_uInt16>((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<sal_uInt16>((nColMax * nAbsTabWidth) / m_nMax) );
                GetColumn( i )->SetRelColWidth(
                    o3tl::narrowing<sal_uInt16>((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<sal_uInt16>(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<sal_uInt16>((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; i<m_nCols-1; i++ )
        {
            double nd = GetColumn( i )->GetMax() - GetColumn( i )->GetMin();
            sal_uLong nAbsColWidth = GetColumn( i )->GetMin() + static_cast<sal_uLong>((nd*nW)/nD);
            sal_uLong nRelColWidth = nRelAvail
                                    ? (nAbsColWidth * m_nRelTabWidth) / nAbsTabWidth
                                    : nAbsColWidth;

            GetColumn( i )->SetAbsColWidth( o3tl::narrowing<sal_uInt16>(nAbsColWidth) );
            GetColumn( i )->SetRelColWidth( o3tl::narrowing<sal_uInt16>(nRelColWidth) );
            nAbs = nAbs + o3tl::narrowing<sal_uInt16>(nAbsColWidth);
            nRel = nRel + o3tl::narrowing<sal_uInt16>(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) )
        return;

    // Calculate the width of additional cells we use for
    // aligning inner tables.
    sal_uInt16 nAbsDist = o3tl::narrowing<sal_uInt16>(nAbsAvail-nAbsTabWidth);
    sal_uInt16 nRelDist = o3tl::narrowing<sal_uInt16>(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 || nAbsLeftFill<MINLAY+m_nInhLeftBorderWidth ||
          (HasColTags() && nAbsLeftFill < nAbsLeftSpace+nParentInhAbsLeftSpace+20) ) )
    {
        SwHTMLTableLayoutColumn *pColumn = GetColumn( 0 );
        pColumn->SetAbsColWidth( pColumn->GetAbsColWidth()+nAbsLeftFill );
        pColumn->SetRelColWidth( pColumn->GetRelColWidth()+m_nRelLeftFill );
        m_nRelLeftFill = 0;
        m_nInhAbsLeftSpace = nAbsLeftSpace + nParentInhAbsLeftSpace;
    }
    if( m_nRelRightFill &&
        ( m_nWidthSet>0 || nAbsRightFill<MINLAY+m_nInhRightBorderWidth ||
          (HasColTags() && nAbsRightFill < nAbsRightSpace+nParentInhAbsRightSpace+20) ) )
    {
        SwHTMLTableLayoutColumn *pColumn = GetColumn( m_nCols-1 );
        pColumn->SetAbsColWidth( 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;
        forconst 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;
    forconst 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; i<m_nRows; i++ )
    {
        for( sal_uInt16 j=0; j<m_nCols; j++ )
        {
            SwHTMLTableLayoutCell *pCell = GetCell( i, j );

            SwHTMLTableLayoutCnts* pContents = pCell->GetContents().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;
    forconst 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<SwTable *>(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<sal_uInt8>(bRel ? m_nWidthOption : 0) );
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=90 H=92 G=90

¤ Dauer der Verarbeitung: 0.24 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.