LCOV - code coverage report
Current view: top level - sw/source/core/doc - htmltbl.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 287 762 37.7 %
Date: 2014-11-03 Functions: 25 41 61.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : #include "hintids.hxx"
      21             : 
      22             : #include <vcl/wrkwin.hxx>
      23             : #include <vcl/svapp.hxx>
      24             : #include <sot/storage.hxx>
      25             : #include <fmtornt.hxx>
      26             : #include <fmtfsize.hxx>
      27             : #include <frmfmt.hxx>
      28             : #include <docary.hxx>
      29             : #include "ndtxt.hxx"
      30             : #include "doc.hxx"
      31             : #include <IDocumentLayoutAccess.hxx>
      32             : #include "swtable.hxx"
      33             : #include "rootfrm.hxx"
      34             : #include "docsh.hxx"
      35             : #include "flyfrm.hxx"
      36             : #include "poolfmt.hxx"
      37             : #include "viewsh.hxx"
      38             : #include "tabfrm.hxx"
      39             : #include "viewopt.hxx"
      40             : #include "htmltbl.hxx"
      41             : #include "ndindex.hxx"
      42             : #include "switerator.hxx"
      43             : #include <o3tl/numeric.hxx>
      44             : #include <boost/foreach.hpp>
      45             : #ifdef DBG_UTIL
      46             : #include "tblrwcl.hxx"
      47             : #endif
      48             : 
      49             : using namespace ::com::sun::star;
      50             : 
      51             : #define COLFUZZY 20
      52             : #define MAX_TABWIDTH (USHRT_MAX - 2001)
      53             : 
      54             : class SwHTMLTableLayoutConstraints
      55             : {
      56             :     sal_uInt16 nRow;                    // start row
      57             :     sal_uInt16 nCol;                    // start column
      58             :     sal_uInt16 nColSpan;                // the column's COLSPAN
      59             : 
      60             :     SwHTMLTableLayoutConstraints *pNext;        // the next constraint
      61             : 
      62             :     sal_uLong nMinNoAlign, nMaxNoAlign; // provisional result of AL-Pass 1
      63             : 
      64             : public:
      65             :     SwHTMLTableLayoutConstraints( sal_uLong nMin, sal_uLong nMax, sal_uInt16 nRow,
      66             :                                 sal_uInt16 nCol, sal_uInt16 nColSp );
      67             :     ~SwHTMLTableLayoutConstraints();
      68             : 
      69           0 :     sal_uLong GetMinNoAlign() const { return nMinNoAlign; }
      70           0 :     sal_uLong GetMaxNoAlign() const { return nMaxNoAlign; }
      71             : 
      72             :     SwHTMLTableLayoutConstraints *InsertNext( SwHTMLTableLayoutConstraints *pNxt );
      73           0 :     SwHTMLTableLayoutConstraints* GetNext() const { return pNext; }
      74             : 
      75           0 :     sal_uInt16 GetRow() const { return nRow; }
      76             : 
      77           0 :     sal_uInt16 GetColSpan() const { return nColSpan; }
      78           0 :     sal_uInt16 GetColumn() const { return nCol; }
      79             : };
      80             : 
      81         520 : SwHTMLTableLayoutCnts::SwHTMLTableLayoutCnts( const SwStartNode *pSttNd,
      82             :                                           SwHTMLTableLayout* pTab,
      83             :                                           bool bNoBrTag,
      84             :                                           SwHTMLTableLayoutCnts* pNxt ) :
      85             :     pNext( pNxt ), pBox( 0 ), pTable( pTab ), pStartNode( pSttNd ),
      86         520 :     nPass1Done( 0 ), nWidthSet( 0 ), bNoBreakTag( bNoBrTag )
      87         520 : {}
      88             : 
      89         520 : SwHTMLTableLayoutCnts::~SwHTMLTableLayoutCnts()
      90             : {
      91         520 :     delete pNext;
      92         520 :     delete pTable;
      93         520 : }
      94             : 
      95        1040 : const SwStartNode *SwHTMLTableLayoutCnts::GetStartNode() const
      96             : {
      97        1040 :     return pBox ? pBox->GetSttNd() : pStartNode;
      98             : }
      99             : 
     100         520 : SwHTMLTableLayoutCell::SwHTMLTableLayoutCell( SwHTMLTableLayoutCnts *pCnts,
     101             :                                           sal_uInt16 nRSpan, sal_uInt16 nCSpan,
     102             :                                           sal_uInt16 nWidth, bool bPrcWidth,
     103             :                                           bool bNWrapOpt ) :
     104             :     pContents( pCnts ),
     105             :     nRowSpan( nRSpan ), nColSpan( nCSpan ),
     106             :     nWidthOption( nWidth ), bPrcWidthOption( bPrcWidth ),
     107         520 :     bNoWrapOption( bNWrapOpt )
     108         520 : {}
     109             : 
     110         520 : SwHTMLTableLayoutCell::~SwHTMLTableLayoutCell()
     111             : {
     112         520 :     if( nRowSpan==1 && nColSpan==1 )
     113             :     {
     114         520 :         delete pContents;
     115             :     }
     116         520 : }
     117             : 
     118          10 : SwHTMLTableLayoutColumn::SwHTMLTableLayoutColumn( sal_uInt16 nWidth,
     119             :                                                   bool bRelWidth,
     120             :                                                   bool bLBorder ) :
     121             :     nMinNoAlign(MINLAY), nMaxNoAlign(MINLAY), nAbsMinNoAlign(MINLAY),
     122             :     nMin(0), nMax(0),
     123             :     nAbsColWidth(0), nRelColWidth(0),
     124             :     nWidthOption( nWidth ), bRelWidthOption( bRelWidth ),
     125          10 :     bLeftBorder( bLBorder )
     126          10 : {}
     127             : 
     128           0 : SwHTMLTableLayoutConstraints::SwHTMLTableLayoutConstraints(
     129             :     sal_uLong nMin, sal_uLong nMax, sal_uInt16 nRw, sal_uInt16 nColumn, sal_uInt16 nColSp ):
     130             :     nRow( nRw ), nCol( nColumn ), nColSpan( nColSp ),
     131             :     pNext( 0 ),
     132           0 :     nMinNoAlign( nMin ), nMaxNoAlign( nMax )
     133           0 : {}
     134             : 
     135           0 : SwHTMLTableLayoutConstraints::~SwHTMLTableLayoutConstraints()
     136             : {
     137           0 :     delete pNext;
     138           0 : }
     139             : 
     140           0 : SwHTMLTableLayoutConstraints *SwHTMLTableLayoutConstraints::InsertNext(
     141             :     SwHTMLTableLayoutConstraints *pNxt )
     142             : {
     143           0 :     SwHTMLTableLayoutConstraints *pPrev = 0;
     144           0 :     SwHTMLTableLayoutConstraints *pConstr = this;
     145           0 :     while( pConstr )
     146             :     {
     147           0 :         if( pConstr->GetRow() > pNxt->GetRow() ||
     148           0 :             pConstr->GetColumn() > pNxt->GetColumn() )
     149           0 :             break;
     150           0 :         pPrev = pConstr;
     151           0 :         pConstr = pConstr->GetNext();
     152             :     }
     153             : 
     154           0 :     if( pPrev )
     155             :     {
     156           0 :         pNxt->pNext = pPrev->GetNext();
     157           0 :         pPrev->pNext = pNxt;
     158           0 :         pConstr = this;
     159             :     }
     160             :     else
     161             :     {
     162           0 :         pNxt->pNext = this;
     163           0 :         pConstr = pNxt;
     164             :     }
     165             : 
     166           0 :     return pConstr;
     167             : }
     168             : 
     169             : typedef SwHTMLTableLayoutColumn *SwHTMLTableLayoutColumnPtr;
     170             : typedef SwHTMLTableLayoutCell *SwHTMLTableLayoutCellPtr;
     171             : 
     172           2 : SwHTMLTableLayout::SwHTMLTableLayout( const SwTable * pSwTbl,
     173             :                                       sal_uInt16 nRws, sal_uInt16 nCls,
     174             :                                       bool bColsOpt, bool bColTgs,
     175             :                                       sal_uInt16 nWdth, bool bPrcWdth,
     176             :                                       sal_uInt16 nBorderOpt, sal_uInt16 nCellPad,
     177             :                                       sal_uInt16 nCellSp, SvxAdjust eAdjust,
     178             :                                       sal_uInt16 nLMargin, sal_uInt16 nRMargin,
     179             :                                       sal_uInt16 nBWidth, sal_uInt16 nLeftBWidth,
     180             :                                       sal_uInt16 nRightBWidth,
     181             :                                       sal_uInt16 nInhLeftBWidth,
     182             :                                       sal_uInt16 nInhRightBWidth )
     183           2 :     : aColumns( new SwHTMLTableLayoutColumnPtr[nCls] )
     184           2 :     , aCells( new SwHTMLTableLayoutCellPtr[static_cast<size_t>(nRws)*nCls] )
     185             :     , pSwTable( pSwTbl )
     186             :     , pLeftFillerBox( 0 )
     187             :     , pRightFillerBox( 0 )
     188             :     , nMin( 0 )
     189             :     , nMax( 0 )
     190             :     , nRows( nRws )
     191             :     , nCols( nCls )
     192             :     , nLeftMargin( nLMargin )
     193             :     , nRightMargin( nRMargin )
     194             :     , nInhAbsLeftSpace( 0 )
     195             :     , nInhAbsRightSpace( 0 )
     196             :     , nRelLeftFill( 0 )
     197             :     , nRelRightFill( 0 )
     198             :     , nRelTabWidth( 0 )
     199             :     , nWidthOption( nWdth )
     200             :     , nCellPadding( nCellPad )
     201             :     , nCellSpacing( nCellSp )
     202             :     , nBorder( nBorderOpt )
     203             :     , nLeftBorderWidth( nLeftBWidth )
     204             :     , nRightBorderWidth( nRightBWidth )
     205             :     , nInhLeftBorderWidth( nInhLeftBWidth )
     206             :     , nInhRightBorderWidth( nInhRightBWidth )
     207             :     , nBorderWidth( nBWidth )
     208             :     , nDelayedResizeAbsAvail( 0 )
     209             :     , nLastResizeAbsAvail( 0 )
     210             :     , nPass1Done( 0 )
     211             :     , nWidthSet( 0 )
     212             :     , eTableAdjust( eAdjust )
     213             :     , bColsOption( bColsOpt )
     214             :     , bColTags( bColTgs )
     215             :     , bPrcWidthOption( bPrcWdth )
     216             :     , bUseRelWidth( false )
     217             :     , bMustResize( true )
     218             :     , bExportable( true )
     219             :     , bBordersChanged( false )
     220             :     , bMayBeInFlyFrame( false )
     221             :     , bDelayedResizeRecalc( false)
     222             :     , bMustNotResize( false )
     223           6 :     , bMustNotRecalc( false )
     224             : {
     225             :     aResizeTimer.SetTimeoutHdl( STATIC_LINK( this, SwHTMLTableLayout,
     226           2 :                                              DelayedResize_Impl ) );
     227           2 : }
     228             : 
     229           4 : SwHTMLTableLayout::~SwHTMLTableLayout()
     230             : {
     231             :     sal_uInt16 i;
     232             : 
     233          12 :     for( i = 0; i < nCols; i++ )
     234          10 :         delete aColumns[i];
     235           2 :     delete[] aColumns;
     236             : 
     237           2 :     sal_uInt16 nCount = nRows*nCols;
     238         522 :     for( i=0; i<nCount; i++ )
     239         520 :         delete aCells[i];
     240           2 :     delete[] aCells;
     241           2 : }
     242             : 
     243             : /// The border widths are calculated like in Netscape:
     244             : /// Outer border: BORDER + CELLSPACING + CELLPADDING
     245             : /// Inner border: CELLSPACING + CELLPADDING
     246             : /// However, we respect the border widths in SW if bSwBorders is set,
     247             : /// so that we don't wrap wrongly.
     248             : /// We also need to respect the distance to the content. Even if
     249             : /// only the opposite side has a border.
     250         520 : sal_uInt16 SwHTMLTableLayout::GetLeftCellSpace( sal_uInt16 nCol, sal_uInt16 nColSpan,
     251             :                                             bool bSwBorders ) const
     252             : {
     253         520 :     sal_uInt16 nSpace = nCellSpacing + nCellPadding;
     254             : 
     255         520 :     if( nCol == 0 )
     256             :     {
     257         104 :         nSpace = nSpace + nBorder;
     258             : 
     259         104 :         if( bSwBorders && nSpace < nLeftBorderWidth )
     260           0 :             nSpace = nLeftBorderWidth;
     261             :     }
     262         416 :     else if( bSwBorders )
     263             :     {
     264         416 :         if( GetColumn(nCol)->HasLeftBorder() )
     265             :         {
     266           0 :             if( nSpace < nBorderWidth )
     267           0 :                 nSpace = nBorderWidth;
     268             :         }
     269         416 :         else if( nCol+nColSpan == nCols && nRightBorderWidth &&
     270             :                  nSpace < MIN_BORDER_DIST )
     271             :         {
     272             :             OSL_ENSURE( !nCellPadding, "GetLeftCellSpace: CELLPADDING!=0" );
     273             :             // If the opposite side has a border we need to respect at
     274             :             // least the minimum distance to the content.
     275             :             // Additionally, we could also use nCellPadding for this.
     276           0 :             nSpace = MIN_BORDER_DIST;
     277             :         }
     278             :     }
     279             : 
     280         520 :     return nSpace;
     281             : }
     282             : 
     283         520 : sal_uInt16 SwHTMLTableLayout::GetRightCellSpace( sal_uInt16 nCol, sal_uInt16 nColSpan,
     284             :                                              bool bSwBorders ) const
     285             : {
     286         520 :     sal_uInt16 nSpace = nCellPadding;
     287             : 
     288         520 :     if( nCol+nColSpan == nCols )
     289             :     {
     290         104 :         nSpace += nBorder + nCellSpacing;
     291         104 :         if( bSwBorders && nSpace < nRightBorderWidth )
     292           0 :             nSpace = nRightBorderWidth;
     293             :     }
     294         416 :     else if( bSwBorders && GetColumn(nCol)->HasLeftBorder() &&
     295             :              nSpace < MIN_BORDER_DIST )
     296             :     {
     297             :         OSL_ENSURE( !nCellPadding, "GetRightCellSpace: CELLPADDING!=0" );
     298             :         // If the opposite side has a border we need to respect at
     299             :         // least the minimum distance to the content.
     300             :         // Additionally, we could also use nCellPadding for this.
     301           0 :         nSpace = MIN_BORDER_DIST;
     302             :     }
     303             : 
     304         520 :     return nSpace;
     305             : }
     306             : 
     307         520 : void SwHTMLTableLayout::AddBorderWidth( sal_uLong &rMin, sal_uLong &rMax,
     308             :                                         sal_uLong &rAbsMin,
     309             :                                         sal_uInt16 nCol, sal_uInt16 nColSpan,
     310             :                                         bool bSwBorders ) const
     311             : {
     312        1040 :     sal_uLong nAdd = GetLeftCellSpace( nCol, nColSpan, bSwBorders ) +
     313        1040 :                  GetRightCellSpace( nCol, nColSpan, bSwBorders );
     314             : 
     315         520 :     rMin += nAdd;
     316         520 :     rMax += nAdd;
     317         520 :     rAbsMin += nAdd;
     318         520 : }
     319             : 
     320         520 : void SwHTMLTableLayout::SetBoxWidth( SwTableBox *pBox, sal_uInt16 nCol,
     321             :                              sal_uInt16 nColSpan ) const
     322             : {
     323         520 :     SwFrmFmt *pFrmFmt = pBox->GetFrmFmt();
     324             : 
     325             :     // calculate the box's width
     326         520 :     SwTwips nFrmWidth = 0;
     327        1560 :     while( nColSpan-- )
     328         520 :         nFrmWidth += GetColumn( nCol++ )->GetRelColWidth();
     329             : 
     330             :     // and reset
     331         520 :     pFrmFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nFrmWidth, 0 ));
     332         520 : }
     333             : 
     334           0 : void SwHTMLTableLayout::GetAvail( sal_uInt16 nCol, sal_uInt16 nColSpan,
     335             :                                   sal_uInt16& rAbsAvail, sal_uInt16& rRelAvail ) const
     336             : {
     337           0 :     rAbsAvail = 0;
     338           0 :     rRelAvail = 0;
     339           0 :     for( sal_uInt16 i=nCol; i<nCol+nColSpan;i++ )
     340             :     {
     341           0 :         const SwHTMLTableLayoutColumn *pColumn = GetColumn(i);
     342           0 :         rAbsAvail = rAbsAvail + pColumn->GetAbsColWidth();
     343           0 :         rRelAvail = rRelAvail + pColumn->GetRelColWidth();
     344             :     }
     345           0 : }
     346             : 
     347           2 : sal_uInt16 SwHTMLTableLayout::GetBrowseWidthByVisArea( const SwDoc& rDoc )
     348             : {
     349           2 :     SwViewShell const *pVSh = rDoc.getIDocumentLayoutAccess().GetCurrentViewShell();
     350           2 :     if( pVSh )
     351             :     {
     352           0 :         return (sal_uInt16)pVSh->GetBrowseWidth();
     353             :     }
     354             : 
     355           2 :     return 0;
     356             : }
     357             : 
     358           2 : sal_uInt16 SwHTMLTableLayout::GetBrowseWidth( const SwDoc& rDoc )
     359             : {
     360             :     // If we have a layout, we can get the width from there.
     361           2 :     const SwRootFrm *pRootFrm = rDoc.getIDocumentLayoutAccess().GetCurrentLayout();
     362           2 :     if( pRootFrm )
     363             :     {
     364           0 :         const SwFrm *pPageFrm = pRootFrm->GetLower();
     365           0 :         if( pPageFrm )
     366           0 :             return (sal_uInt16)pPageFrm->Prt().Width();
     367             :     }
     368             : 
     369             :     // #i91658#
     370             :     // Assertion removed which state that no browse width is available.
     371             :     // Investigation reveals that all calls can handle the case that no browse
     372             :     // width is provided.
     373           2 :     return GetBrowseWidthByVisArea( rDoc );
     374             : }
     375             : 
     376         104 : sal_uInt16 SwHTMLTableLayout::GetBrowseWidthByTabFrm(
     377             :     const SwTabFrm& rTabFrm ) const
     378             : {
     379         104 :     SwTwips nWidth = 0;
     380             : 
     381         104 :     const SwFrm *pUpper = rTabFrm.GetUpper();
     382         104 :     if( MayBeInFlyFrame() && pUpper->IsFlyFrm() &&
     383           0 :         ((const SwFlyFrm *)pUpper)->GetAnchorFrm() )
     384             :     {
     385             :         // If the table is located within a self-created frame, the anchor's
     386             :         // width is relevant not the frame's width.
     387             :         // For paragraph-bound frames we don't respect paragraph indents.
     388           0 :         const SwFrm *pAnchor = ((const SwFlyFrm *)pUpper)->GetAnchorFrm();
     389           0 :         if( pAnchor->IsTxtFrm() )
     390           0 :             nWidth = pAnchor->Frm().Width();
     391             :         else
     392           0 :             nWidth = pAnchor->Prt().Width();
     393             :     }
     394             :     else
     395             :     {
     396         104 :         nWidth = pUpper->Prt().Width();
     397             :     }
     398             : 
     399         104 :     SwTwips nUpperDummy = 0;
     400         104 :     long nRightOffset = 0,
     401         104 :          nLeftOffset  = 0;
     402         104 :     rTabFrm.CalcFlyOffsets( nUpperDummy, nLeftOffset, nRightOffset );
     403         104 :     nWidth -= (nLeftOffset + nRightOffset);
     404             : 
     405         104 :     return nWidth < USHRT_MAX ? static_cast<sal_uInt16>(nWidth) : USHRT_MAX;
     406             : }
     407             : 
     408           0 : sal_uInt16 SwHTMLTableLayout::GetBrowseWidthByTable( const SwDoc& rDoc ) const
     409             : {
     410           0 :     sal_uInt16 nBrowseWidth = 0;
     411           0 :     SwTabFrm* pFrm = SwIterator<SwTabFrm,SwFmt>::FirstElement( *pSwTable->GetFrmFmt() );
     412           0 :     if( pFrm )
     413             :     {
     414           0 :         nBrowseWidth = GetBrowseWidthByTabFrm( *pFrm );
     415             :     }
     416             :     else
     417             :     {
     418           0 :         nBrowseWidth = SwHTMLTableLayout::GetBrowseWidth( rDoc );
     419             :     }
     420             : 
     421           0 :     return nBrowseWidth;
     422             : }
     423             : 
     424         104 : const SwStartNode *SwHTMLTableLayout::GetAnyBoxStartNode() const
     425             : {
     426             :     const SwStartNode *pBoxSttNd;
     427             : 
     428         104 :     const SwTableBox* pBox = pSwTable->GetTabLines()[0]->GetTabBoxes()[0];
     429         208 :     while( 0 == (pBoxSttNd = pBox->GetSttNd()) )
     430             :     {
     431             :         OSL_ENSURE( pBox->GetTabLines().size() > 0,
     432             :                 "Box without start node and lines" );
     433             :         OSL_ENSURE( pBox->GetTabLines().front()->GetTabBoxes().size() > 0,
     434             :                 "Line without boxes" );
     435           0 :         pBox = pBox->GetTabLines().front()->GetTabBoxes().front();
     436             :     }
     437             : 
     438         104 :     return pBoxSttNd;
     439             : }
     440             : 
     441           0 : SwFrmFmt *SwHTMLTableLayout::FindFlyFrmFmt() const
     442             : {
     443           0 :     const SwTableNode *pTblNd = GetAnyBoxStartNode()->FindTableNode();
     444             :     OSL_ENSURE( pTblNd, "Kein Table-Node?" );
     445           0 :     return pTblNd->GetFlyFmt();
     446             : }
     447             : 
     448         522 : static void lcl_GetMinMaxSize( sal_uLong& rMinNoAlignCnts, sal_uLong& rMaxNoAlignCnts,
     449             :                         sal_uLong& rAbsMinNoAlignCnts,
     450             :                         SwTxtNode *pTxtNd, sal_uLong nIdx, bool bNoBreak )
     451             : {
     452             :     pTxtNd->GetMinMaxSize( nIdx, rMinNoAlignCnts, rMaxNoAlignCnts,
     453         522 :                            rAbsMinNoAlignCnts );
     454             :     OSL_ENSURE( rAbsMinNoAlignCnts <= rMinNoAlignCnts,
     455             :             "GetMinMaxSize: absmin > min" );
     456             :     OSL_ENSURE( rMinNoAlignCnts <= rMaxNoAlignCnts,
     457             :             "GetMinMaxSize: max > min" );
     458             : 
     459             :     // The maximal width for a <PRE> paragraph is the minimal width
     460         522 :     const SwFmtColl *pColl = &pTxtNd->GetAnyFmtColl();
     461        1566 :     while( pColl && !pColl->IsDefault() &&
     462         522 :             (USER_FMT & pColl->GetPoolFmtId()) )
     463             :     {
     464           0 :         pColl = (const SwFmtColl *)pColl->DerivedFrom();
     465             :     }
     466             : 
     467             :     // <NOBR> in the whole cell apply to text but not to tables.
     468             :     // Netscape only considers this for graphics.
     469         522 :     if( (pColl && RES_POOLCOLL_HTML_PRE==pColl->GetPoolFmtId()) || bNoBreak )
     470             :     {
     471           0 :         rMinNoAlignCnts = rMaxNoAlignCnts;
     472           0 :         rAbsMinNoAlignCnts = rMaxNoAlignCnts;
     473             :     }
     474         522 : }
     475             : 
     476           2 : void SwHTMLTableLayout::AutoLayoutPass1()
     477             : {
     478           2 :     nPass1Done++;
     479             : 
     480           2 :     ClearPass1Info();
     481             : 
     482           2 :     bool bFixRelWidths = false;
     483             :     sal_uInt16 i;
     484             : 
     485           2 :     SwHTMLTableLayoutConstraints *pConstraints = 0;
     486             : 
     487          12 :     for( i=0; i<nCols; i++ )
     488             :     {
     489          10 :         SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
     490          10 :         pColumn->ClearPass1Info( !HasColTags() );
     491          10 :         sal_uInt16 nMinColSpan = USHRT_MAX; // Column count to which the calculated width refers to
     492          10 :         sal_uInt16 nColSkip = USHRT_MAX;    // How many columns need to be skipped
     493             : 
     494         530 :         for( sal_uInt16 j=0; j<nRows; j++ )
     495             :         {
     496         520 :             SwHTMLTableLayoutCell *pCell = GetCell(j,i);
     497         520 :             SwHTMLTableLayoutCnts *pCnts = pCell->GetContents();
     498             : 
     499             :             // We need to examine all rows in order to
     500             :             // get the column that should be calculated next.
     501         520 :             sal_uInt16 nColSpan = pCell->GetColSpan();
     502         520 :             if( nColSpan < nColSkip )
     503          10 :                 nColSkip = nColSpan;
     504             : 
     505         520 :             if( !pCnts || (pCnts && !pCnts->IsPass1Done(nPass1Done)) )
     506             :             {
     507             :                 // The cell is empty or it's content was not edited
     508         520 :                 if( nColSpan < nMinColSpan )
     509          10 :                     nMinColSpan = nColSpan;
     510             : 
     511         520 :                 sal_uLong nMinNoAlignCell = 0;
     512         520 :                 sal_uLong nMaxNoAlignCell = 0;
     513         520 :                 sal_uLong nAbsMinNoAlignCell = 0;
     514         520 :                 sal_uLong nMaxTableCell = 0;
     515         520 :                 sal_uLong nAbsMinTableCell = 0;
     516             : 
     517        1560 :                 while( pCnts )
     518             :                 {
     519         520 :                     const SwStartNode *pSttNd = pCnts->GetStartNode();
     520         520 :                     if( pSttNd )
     521             :                     {
     522         520 :                         const SwDoc *pDoc = pSttNd->GetDoc();
     523         520 :                         sal_uLong nIdx = pSttNd->GetIndex();
     524        2082 :                         while( !(pDoc->GetNodes()[nIdx])->IsEndNode() )
     525             :                         {
     526        1042 :                             SwTxtNode *pTxtNd = (pDoc->GetNodes()[nIdx])->GetTxtNode();
     527        1042 :                             if( pTxtNd )
     528             :                             {
     529         522 :                                 sal_uLong nMinNoAlignCnts = 0;
     530         522 :                                 sal_uLong nMaxNoAlignCnts = 0;
     531         522 :                                 sal_uLong nAbsMinNoAlignCnts = 0;
     532             : 
     533             :                                 lcl_GetMinMaxSize( nMinNoAlignCnts,
     534             :                                                    nMaxNoAlignCnts,
     535             :                                                    nAbsMinNoAlignCnts,
     536             :                                                    pTxtNd, nIdx,
     537         522 :                                                    pCnts->HasNoBreakTag() );
     538             : 
     539         522 :                                 if( nMinNoAlignCnts > nMinNoAlignCell )
     540          10 :                                     nMinNoAlignCell = nMinNoAlignCnts;
     541         522 :                                 if( nMaxNoAlignCnts > nMaxNoAlignCell )
     542          10 :                                     nMaxNoAlignCell = nMaxNoAlignCnts;
     543         522 :                                 if( nAbsMinNoAlignCnts > nAbsMinNoAlignCell )
     544          10 :                                     nAbsMinNoAlignCell = nAbsMinNoAlignCnts;
     545             :                             }
     546             :                             else
     547             :                             {
     548         520 :                                 SwTableNode *pTabNd = (pDoc->GetNodes()[nIdx])->GetTableNode();
     549         520 :                                 if( pTabNd )
     550             :                                 {
     551           0 :                                     SwHTMLTableLayout *pChild = pTabNd->GetTable().GetHTMLTableLayout();
     552           0 :                                     if( pChild )
     553             :                                     {
     554           0 :                                         pChild->AutoLayoutPass1();
     555           0 :                                         sal_uLong nMaxTableCnts = pChild->nMax;
     556           0 :                                         sal_uLong nAbsMinTableCnts = pChild->nMin;
     557             : 
     558             :                                         // A fixed table width is taken over as minimum and
     559             :                                         // maximum at the same time
     560           0 :                                         if( !pChild->bPrcWidthOption && pChild->nWidthOption )
     561             :                                         {
     562           0 :                                             sal_uLong nTabWidth = pChild->nWidthOption;
     563           0 :                                             if( nTabWidth >= nAbsMinTableCnts  )
     564             :                                             {
     565           0 :                                                 nMaxTableCnts = nTabWidth;
     566           0 :                                                 nAbsMinTableCnts = nTabWidth;
     567             :                                             }
     568             :                                             else
     569             :                                             {
     570           0 :                                                 nMaxTableCnts = nAbsMinTableCnts;
     571             :                                             }
     572             :                                         }
     573             : 
     574           0 :                                         if( nMaxTableCnts > nMaxTableCell )
     575           0 :                                             nMaxTableCell = nMaxTableCnts;
     576           0 :                                         if( nAbsMinTableCnts > nAbsMinTableCell )
     577           0 :                                             nAbsMinTableCell = nAbsMinTableCnts;
     578             :                                     }
     579           0 :                                     nIdx = pTabNd->EndOfSectionNode()->GetIndex();
     580             :                                 }
     581             :                             }
     582        1042 :                             nIdx++;
     583             :                         }
     584             :                     }
     585             :                     else
     586             :                     {
     587             :                         OSL_ENSURE( false, "Sub tables in HTML import?" );
     588           0 :                         SwHTMLTableLayout *pChild = pCnts->GetTable();
     589           0 :                         pChild->AutoLayoutPass1();
     590           0 :                         sal_uLong nMaxTableCnts = pChild->nMax;
     591           0 :                         sal_uLong nAbsMinTableCnts = pChild->nMin;
     592             : 
     593             :                         // A fixed table width is taken over as minimum and
     594             :                         // maximum at the same time
     595           0 :                         if( !pChild->bPrcWidthOption && pChild->nWidthOption )
     596             :                         {
     597           0 :                             sal_uLong nTabWidth = pChild->nWidthOption;
     598           0 :                             if( nTabWidth >= nAbsMinTableCnts  )
     599             :                             {
     600           0 :                                 nMaxTableCnts = nTabWidth;
     601           0 :                                 nAbsMinTableCnts = nTabWidth;
     602             :                             }
     603             :                             else
     604             :                             {
     605           0 :                                 nMaxTableCnts = nAbsMinTableCnts;
     606             :                             }
     607             :                         }
     608             : 
     609           0 :                         if( nMaxTableCnts > nMaxTableCell )
     610           0 :                             nMaxTableCell = nMaxTableCnts;
     611           0 :                         if( nAbsMinTableCnts > nAbsMinTableCell )
     612           0 :                             nAbsMinTableCell = nAbsMinTableCnts;
     613             :                     }
     614         520 :                     pCnts->SetPass1Done( nPass1Done );
     615         520 :                     pCnts = pCnts->GetNext();
     616             :                 }
     617             : 
     618             : // This code previously came after AddBorderWidth
     619             :                 // If a table's width is wider in a cell than what we've calculated
     620             :                 // for the other content we need to use the table's width.
     621         520 :                 if( nMaxTableCell > nMaxNoAlignCell )
     622           0 :                     nMaxNoAlignCell = nMaxTableCell;
     623         520 :                 if( nAbsMinTableCell > nAbsMinNoAlignCell )
     624             :                 {
     625           0 :                     nAbsMinNoAlignCell = nAbsMinTableCell;
     626           0 :                     if( nMinNoAlignCell < nAbsMinNoAlignCell )
     627           0 :                         nMinNoAlignCell = nAbsMinNoAlignCell;
     628           0 :                     if( nMaxNoAlignCell < nMinNoAlignCell )
     629           0 :                         nMaxNoAlignCell = nMinNoAlignCell;
     630             :                 }
     631             : // This code previously came after AddBorderWidth
     632             : 
     633         520 :                 bool bRelWidth = pCell->IsPrcWidthOption();
     634         520 :                 sal_uInt16 nWidth = pCell->GetWidthOption();
     635             : 
     636             :                 // A NOWRAP option applies to text and tables, but is
     637             :                 // not applied for fixed cell width.
     638             :                 // Instead, the stated cell width behaves like a minimal
     639             :                 // width.
     640         520 :                 if( pCell->HasNoWrapOption() )
     641             :                 {
     642           0 :                     if( nWidth==0 || bRelWidth )
     643             :                     {
     644           0 :                         nMinNoAlignCell = nMaxNoAlignCell;
     645           0 :                         nAbsMinNoAlignCell = nMaxNoAlignCell;
     646             :                     }
     647             :                     else
     648             :                     {
     649           0 :                         if( nWidth>nMinNoAlignCell )
     650           0 :                             nMinNoAlignCell = nWidth;
     651           0 :                         if( nWidth>nAbsMinNoAlignCell )
     652           0 :                             nAbsMinNoAlignCell = nWidth;
     653             :                     }
     654             :                 }
     655             : 
     656             :                 // Respect minimum width for content
     657         520 :                 if( nMinNoAlignCell < MINLAY )
     658         510 :                     nMinNoAlignCell = MINLAY;
     659         520 :                 if( nMaxNoAlignCell < MINLAY )
     660         510 :                     nMaxNoAlignCell = MINLAY;
     661         520 :                 if( nAbsMinNoAlignCell < MINLAY )
     662         510 :                     nAbsMinNoAlignCell = MINLAY;
     663             : 
     664             :                 // Respect the border and distance to the content
     665             :                 AddBorderWidth( nMinNoAlignCell, nMaxNoAlignCell,
     666         520 :                                 nAbsMinNoAlignCell, i, nColSpan );
     667             : 
     668         520 :                 if( 1==nColSpan )
     669             :                 {
     670             :                     // take over the values directly
     671             :                     pColumn->MergeMinMaxNoAlign( nMinNoAlignCell,
     672             :                                                  nMaxNoAlignCell,
     673         520 :                                                  nAbsMinNoAlignCell );
     674             : 
     675             :                     // the widest WIDTH wins
     676         520 :                     if( !HasColTags() )
     677           0 :                         pColumn->MergeCellWidthOption( nWidth, bRelWidth );
     678             :                 }
     679             :                 else
     680             :                 {
     681             :                     // Process the data line by line from left to right at the end
     682             : 
     683             :                     // When which values is taken over will be explained further down.
     684           0 :                     if( !HasColTags() && nWidth && !bRelWidth )
     685             :                     {
     686           0 :                         sal_uLong nAbsWidth = nWidth, nDummy = 0, nDummy2 = 0;
     687             :                         AddBorderWidth( nAbsWidth, nDummy, nDummy2,
     688           0 :                                         i, nColSpan, false );
     689             : 
     690           0 :                         if( nAbsWidth >= nMinNoAlignCell )
     691             :                         {
     692           0 :                             nMaxNoAlignCell = nAbsWidth;
     693           0 :                             if( HasColsOption() )
     694           0 :                                 nMinNoAlignCell = nAbsWidth;
     695             :                         }
     696           0 :                         else if( nAbsWidth >= nAbsMinNoAlignCell )
     697             :                         {
     698           0 :                             nMaxNoAlignCell = nAbsWidth;
     699           0 :                             nMinNoAlignCell = nAbsWidth;
     700             :                         }
     701             :                         else
     702             :                         {
     703           0 :                             nMaxNoAlignCell = nAbsMinNoAlignCell;
     704           0 :                             nMinNoAlignCell = nAbsMinNoAlignCell;
     705             :                         }
     706             :                     }
     707           0 :                     else if( HasColsOption() || HasColTags() )
     708           0 :                         nMinNoAlignCell = nAbsMinNoAlignCell;
     709             : 
     710             :                     SwHTMLTableLayoutConstraints *pConstr =
     711             :                         new SwHTMLTableLayoutConstraints( nMinNoAlignCell,
     712           0 :                             nMaxNoAlignCell, j, i, nColSpan );
     713           0 :                     if( pConstraints )
     714           0 :                         pConstraints = pConstraints->InsertNext( pConstr );
     715             :                     else
     716           0 :                         pConstraints = pConstr;
     717             :                 }
     718             :             }
     719             :         }
     720             : 
     721             :         OSL_ENSURE( nMinColSpan>0 && nColSkip>0 && nColSkip <= nMinColSpan,
     722             :                 "Layout pass 1: Columns are being forgotten!" );
     723             :         OSL_ENSURE( nMinColSpan!=USHRT_MAX,
     724             :                 "Layout pass 1: unnecessary pass through the loop or a bug" );
     725             : 
     726          10 :         if( 1==nMinColSpan )
     727             :         {
     728             :             // There are cells with COLSPAN 1 and therefore also useful
     729             :             // values in pColumn
     730             : 
     731             :             // Take over values according to the following table (Netscape 4.0 pv 3):
     732             : 
     733             :             // WIDTH:           no COLS         COLS
     734             : 
     735             :             // none             min = min       min = absmin
     736             :             //                  max = max       max = max
     737             : 
     738             :             // >= min           min = min       min = width
     739             :             //                  max = width     max = width
     740             : 
     741             :             // >= absmin        min = wdith(*)  min = width
     742             :             //                  max = width     max = width
     743             : 
     744             :             // < absmin         min = absmin    min = absmin
     745             :             //                  max = absmin    max = absmin
     746             : 
     747             :             // (*) Netscape uses the minimum width without a break before
     748             :             //     the last graphic here. We don't have that (yet?),
     749             :             //     so we leave it set to width.
     750             : 
     751          10 :             if( pColumn->GetWidthOption() && !pColumn->IsRelWidthOption() )
     752             :             {
     753             :                 // Take over absolute widths as minimal and maximal widths.
     754           0 :                 sal_uLong nAbsWidth = pColumn->GetWidthOption();
     755           0 :                 sal_uLong nDummy = 0, nDummy2 = 0;
     756           0 :                 AddBorderWidth( nAbsWidth, nDummy, nDummy2, i, 1, false );
     757             : 
     758           0 :                 if( nAbsWidth >= pColumn->GetMinNoAlign() )
     759             :                 {
     760           0 :                     pColumn->SetMinMax( HasColsOption() ? nAbsWidth
     761             :                                                    : pColumn->GetMinNoAlign(),
     762           0 :                                         nAbsWidth );
     763             :                 }
     764           0 :                 else if( nAbsWidth >= pColumn->GetAbsMinNoAlign() )
     765             :                 {
     766           0 :                     pColumn->SetMinMax( nAbsWidth, nAbsWidth );
     767             :                 }
     768             :                 else
     769             :                 {
     770             :                     pColumn->SetMinMax( pColumn->GetAbsMinNoAlign(),
     771           0 :                                         pColumn->GetAbsMinNoAlign() );
     772             :                 }
     773             :             }
     774             :             else
     775             :             {
     776          10 :                 pColumn->SetMinMax( HasColsOption() ? pColumn->GetAbsMinNoAlign()
     777             :                                                : pColumn->GetMinNoAlign(),
     778          20 :                                     pColumn->GetMaxNoAlign() );
     779             :             }
     780             :         }
     781           0 :         else if( USHRT_MAX!=nMinColSpan )
     782             :         {
     783             :             // Can be anything != 0, because it is altered by the constraints.
     784           0 :             pColumn->SetMinMax( MINLAY, MINLAY );
     785             : 
     786             :             // the next columns need not to be processed
     787           0 :             i += (nColSkip-1);
     788             :         }
     789             : 
     790          10 :         nMin += pColumn->GetMin();
     791          10 :         nMax += pColumn->GetMax();
     792          10 :         if (pColumn->IsRelWidthOption()) bFixRelWidths = true;
     793             :     }
     794             : 
     795             :     // Now process the constraints
     796           2 :     SwHTMLTableLayoutConstraints *pConstr = pConstraints;
     797           4 :     while( pConstr )
     798             :     {
     799             :         // At first we need to process the width in the same way
     800             :         // as the column widths
     801           0 :         sal_uInt16 nCol = pConstr->GetColumn();
     802           0 :         sal_uInt16 nColSpan = pConstr->GetColSpan();
     803           0 :         sal_uLong nConstrMin = pConstr->GetMinNoAlign();
     804           0 :         sal_uLong nConstrMax = pConstr->GetMaxNoAlign();
     805             : 
     806             :         // We get the hitherto width of the spanned columns
     807           0 :         sal_uLong nColsMin = 0;
     808           0 :         sal_uLong nColsMax = 0;
     809           0 :         for( sal_uInt16 j=nCol; j<nCol+nColSpan; j++ )
     810             :         {
     811           0 :             SwHTMLTableLayoutColumn *pColumn = GetColumn( j );
     812           0 :             nColsMin += pColumn->GetMin();
     813           0 :             nColsMax += pColumn->GetMax();
     814             :         }
     815             : 
     816           0 :         if( nColsMin<nConstrMin )
     817             :         {
     818             :             // Proportionately distribute the minimum value to the columns
     819           0 :             sal_uLong nMinD = nConstrMin-nColsMin;
     820             : 
     821           0 :             if( nConstrMin > nColsMax )
     822             :             {
     823             :                 // Proportional according to the minimum widths
     824           0 :                 sal_uInt16 nEndCol = nCol+nColSpan;
     825           0 :                 sal_uLong nDiff = nMinD;
     826           0 :                 for( sal_uInt16 ic=nCol; ic<nEndCol; ic++ )
     827             :                 {
     828           0 :                     SwHTMLTableLayoutColumn *pColumn = GetColumn( ic );
     829             : 
     830           0 :                     sal_uLong nColMin = pColumn->GetMin();
     831           0 :                     sal_uLong nColMax = pColumn->GetMax();
     832             : 
     833           0 :                     nMin -= nColMin;
     834           0 :                     sal_uLong nAdd = ic<nEndCol-1 ? (nColMin * nMinD) / nColsMin
     835           0 :                                              : nDiff;
     836           0 :                     nColMin += nAdd;
     837           0 :                     nMin += nColMin;
     838             :                     OSL_ENSURE( nDiff >= nAdd, "Ooops: nDiff is not correct anymore" );
     839           0 :                     nDiff -= nAdd;
     840             : 
     841           0 :                     if( nColMax < nColMin )
     842             :                     {
     843           0 :                         nMax -= nColMax;
     844           0 :                         nColsMax -= nColMax;
     845           0 :                         nColMax = nColMin;
     846           0 :                         nMax += nColMax;
     847           0 :                         nColsMax += nColMax;
     848             :                     }
     849             : 
     850           0 :                     pColumn->SetMinMax( nColMin, nColMax );
     851             :                 }
     852             :             }
     853             :             else
     854             :             {
     855             :                 // Proportional according to the difference of max and min
     856           0 :                 for( sal_uInt16 ic=nCol; ic<nCol+nColSpan; ic++ )
     857             :                 {
     858           0 :                     SwHTMLTableLayoutColumn *pColumn = GetColumn( ic );
     859             : 
     860           0 :                     sal_uLong nDiff = pColumn->GetMax()-pColumn->GetMin();
     861           0 :                     if( nMinD < nDiff )
     862           0 :                         nDiff = nMinD;
     863             : 
     864           0 :                     pColumn->AddToMin( nDiff );
     865             : 
     866             :                     OSL_ENSURE( pColumn->GetMax() >= pColumn->GetMin(),
     867             :                             "Why is the Column suddenly too narrow?" );
     868             : 
     869           0 :                     nMin += nDiff;
     870           0 :                     nMinD -= nDiff;
     871             :                 }
     872             :             }
     873             :         }
     874             : 
     875           0 :         if( !HasColTags() && nColsMax<nConstrMax )
     876             :         {
     877           0 :             sal_uLong nMaxD = nConstrMax-nColsMax;
     878             : 
     879           0 :             for( sal_uInt16 ic=nCol; ic<nCol+nColSpan; ic++ )
     880             :             {
     881           0 :                 SwHTMLTableLayoutColumn *pColumn = GetColumn( ic );
     882             : 
     883           0 :                 nMax -= pColumn->GetMax();
     884             : 
     885           0 :                 pColumn->AddToMax( (pColumn->GetMax() * nMaxD) / nColsMax );
     886             : 
     887           0 :                 nMax += pColumn->GetMax();
     888             :             }
     889             :         }
     890             : 
     891           0 :         pConstr = pConstr->GetNext();
     892             :     }
     893             : 
     894           2 :     if( bFixRelWidths )
     895             :     {
     896           2 :         if( HasColTags() )
     897             :         {
     898             :             // To adapt the relative widths, in a first step we multiply the
     899             :             // minimum width of all affected cells with the relative width
     900             :             // of the column.
     901             :             // Thus, the width ratio among the columns is correct.
     902             : 
     903             :             // Furthermore, a factor is calculated that says by how much the
     904             :             // cell has gotten wider than the minimum width.
     905             : 
     906             :             // In the second step the calculated widths are divided by this
     907             :             // factor.  Thereby a cell's width is preserved and serves as a
     908             :             // basis for the other cells.
     909             :             // We only change the maximum widths here!
     910             : 
     911           2 :             sal_uLong nAbsMin = 0;  // absolute minimum width of all widths with relative width
     912           2 :             sal_uLong nRel = 0;     // sum of all relative widths of all columns
     913          12 :             for( i=0; i<nCols; i++ )
     914             :             {
     915          10 :                 SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
     916          10 :                 if( pColumn->IsRelWidthOption() && pColumn->GetWidthOption() )
     917             :                 {
     918          10 :                     nAbsMin += pColumn->GetMin();
     919          10 :                     nRel += pColumn->GetWidthOption();
     920             :                 }
     921             :             }
     922             : 
     923           2 :             sal_uLong nQuot = ULONG_MAX;
     924          12 :             for( i=0; i<nCols; i++ )
     925             :             {
     926          10 :                 SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
     927          10 :                 if( pColumn->IsRelWidthOption() )
     928             :                 {
     929          10 :                     nMax -= pColumn->GetMax();
     930          10 :                     if( pColumn->GetWidthOption() && pColumn->GetMin() )
     931             :                     {
     932          10 :                         pColumn->SetMax( nAbsMin * pColumn->GetWidthOption() );
     933          10 :                         sal_uLong nColQuot = pColumn->GetMax() / pColumn->GetMin();
     934          10 :                         if( nColQuot<nQuot )
     935           4 :                             nQuot = nColQuot;
     936             :                     }
     937             :                 }
     938             :             }
     939             :             OSL_ENSURE( 0==nRel || nQuot!=ULONG_MAX,
     940             :                     "Where did the relative columns go?" );
     941          12 :             for( i=0; i<nCols; i++ )
     942             :             {
     943          10 :                 SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
     944          10 :                 if( pColumn->IsRelWidthOption() )
     945             :                 {
     946          10 :                     if( pColumn->GetWidthOption() )
     947          10 :                         pColumn->SetMax( pColumn->GetMax() / nQuot );
     948             :                     else
     949           0 :                         pColumn->SetMax( pColumn->GetMin() );
     950             :                     OSL_ENSURE( pColumn->GetMax() >= pColumn->GetMin(),
     951             :                             "Maximum column width is lower than the minimum column width" );
     952          10 :                     nMax += pColumn->GetMax();
     953             :                 }
     954             :             }
     955             :         }
     956             :         else
     957             :         {
     958           0 :             sal_uInt16 nRel = 0;        // sum of the relative widths of all columns
     959           0 :             sal_uInt16 nRelCols = 0;    // count of the columns with a relative setting
     960           0 :             sal_uLong nRelMax = 0;      // fraction of the maximum of this column
     961           0 :             for( i=0; i<nCols; i++ )
     962             :             {
     963             :                 OSL_ENSURE( nRel<=100, "relative width of all columns > 100%" );
     964           0 :                 SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
     965           0 :                 if( pColumn->IsRelWidthOption() && pColumn->GetWidthOption() )
     966             :                 {
     967             :                     // Make sure that the relative widths don't go above 100%
     968           0 :                     sal_uInt16 nColWidth = pColumn->GetWidthOption();
     969           0 :                     if( nRel+nColWidth > 100 )
     970             :                     {
     971           0 :                         nColWidth = 100 - nRel;
     972           0 :                         pColumn->SetWidthOption( nColWidth, true, false );
     973             :                     }
     974           0 :                     nRelMax += pColumn->GetMax();
     975           0 :                     nRel = nRel + nColWidth;
     976           0 :                     nRelCols++;
     977             :                 }
     978           0 :                 else if( !pColumn->GetMin() )
     979             :                 {
     980             :                     // The column is empty (so it was solely created by
     981             :                     // COLSPAN) and therefore must not be assigned a % width.
     982           0 :                     nRelCols++;
     983             :                 }
     984             :             }
     985             : 
     986             :             // If there are percentages left we distribute them to the columns
     987             :             // that don't have a width setting. Like in Netscape we distribute
     988             :             // the remaining percentages according to the ratio of the maximum
     989             :             // width of the affected columns.
     990             :             // For the maximum widths we also take the fixed-width columns
     991             :             // into account.  Is that correct?
     992           0 :             if( nRel < 100 && nRelCols < nCols )
     993             :             {
     994           0 :                 sal_uInt16 nRelLeft = 100 - nRel;
     995           0 :                 sal_uLong nFixMax = nMax - nRelMax;
     996           0 :                 for( i=0; i<nCols; i++ )
     997             :                 {
     998           0 :                     SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
     999           0 :                     if( !pColumn->IsRelWidthOption() &&
    1000           0 :                         !pColumn->GetWidthOption() &&
    1001           0 :                         pColumn->GetMin() )
    1002             :                     {
    1003             :                         // the next column gets the rest
    1004             :                         sal_uInt16 nColWidth =
    1005           0 :                             (sal_uInt16)((pColumn->GetMax() * nRelLeft) / nFixMax);
    1006           0 :                         pColumn->SetWidthOption( nColWidth, true, false );
    1007             :                     }
    1008             :                 }
    1009             :             }
    1010             : 
    1011             :             // adjust the maximum widths now accordingly
    1012           0 :             sal_uLong nQuotMax = ULONG_MAX;
    1013           0 :             sal_uLong nOldMax = nMax;
    1014           0 :             nMax = 0;
    1015           0 :             for( i=0; i<nCols; i++ )
    1016             :             {
    1017             :                 // Columns with a % setting are adapted accordingly.
    1018             :                 // Columns, that
    1019             :                 // - do not have a % setting and are located within a tables
    1020             :                 // with COLS and WIDTH, or
    1021             :                 // - their width is 0%
    1022             :                 // get set to the minimum width.
    1023           0 :                 SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
    1024           0 :                 if( pColumn->IsRelWidthOption() && pColumn->GetWidthOption() )
    1025             :                 {
    1026             :                     sal_uLong nNewMax;
    1027             :                     sal_uLong nColQuotMax;
    1028           0 :                     if( !nWidthOption )
    1029             :                     {
    1030           0 :                         nNewMax = nOldMax * pColumn->GetWidthOption();
    1031           0 :                         nColQuotMax = nNewMax / pColumn->GetMax();
    1032             :                     }
    1033             :                     else
    1034             :                     {
    1035           0 :                         nNewMax = nMin * pColumn->GetWidthOption();
    1036           0 :                         nColQuotMax = nNewMax / pColumn->GetMin();
    1037             :                     }
    1038           0 :                     pColumn->SetMax( nNewMax );
    1039           0 :                     if( nColQuotMax < nQuotMax )
    1040           0 :                         nQuotMax = nColQuotMax;
    1041             :                 }
    1042           0 :                 else if( HasColsOption() || nWidthOption ||
    1043           0 :                          (pColumn->IsRelWidthOption() &&
    1044           0 :                           !pColumn->GetWidthOption()) )
    1045           0 :                     pColumn->SetMax( pColumn->GetMin() );
    1046             :             }
    1047             :             // and divide by the quotient
    1048             :             OSL_ENSURE( nQuotMax!=ULONG_MAX, "Where did the relative columns go?" );
    1049           0 :             for( i=0; i<nCols; i++ )
    1050             :             {
    1051           0 :                 SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
    1052           0 :                 if( pColumn->IsRelWidthOption() && pColumn->GetWidthOption() )
    1053             :                 {
    1054           0 :                     if( pColumn->GetWidthOption() )
    1055             :                     {
    1056           0 :                         pColumn->SetMax( pColumn->GetMax() / nQuotMax );
    1057             :                         OSL_ENSURE( pColumn->GetMax() >= pColumn->GetMin(),
    1058             :                                 "Minimum width is one column bigger than maximum" );
    1059           0 :                         if( pColumn->GetMax() < pColumn->GetMin() )
    1060           0 :                             pColumn->SetMax( pColumn->GetMin() );
    1061             :                     }
    1062             :                 }
    1063           0 :                 nMax += pColumn->GetMax();
    1064             :             }
    1065             :         }
    1066             :     }
    1067             : 
    1068           2 :     delete pConstraints;
    1069           2 : }
    1070             : 
    1071             : //TODO: provide documentation
    1072             : /**
    1073             : 
    1074             :     @param nAbsAvail available space in TWIPS.
    1075             :     @param nRelAvail available space related to USHRT_MAX or 0
    1076             :     @param nAbsSpace fraction of nAbsAvail, which is reserved by the surrounding
    1077             :                      cell for the border and the distance to the paragraph.
    1078             : */
    1079           2 : void SwHTMLTableLayout::AutoLayoutPass2( sal_uInt16 nAbsAvail, sal_uInt16 nRelAvail,
    1080             :                                          sal_uInt16 nAbsLeftSpace,
    1081             :                                          sal_uInt16 nAbsRightSpace,
    1082             :                                          sal_uInt16 nParentInhAbsSpace )
    1083             : {
    1084             :     // For a start we do a lot of plausability tests
    1085             : 
    1086             :     // An absolute width always has to be passed
    1087             :     OSL_ENSURE( nAbsAvail, "AutoLayout pass 2: No absolute width given" );
    1088             : 
    1089             :     // A relative width must only be passed for tables within tables (?)
    1090             :     OSL_ENSURE( IsTopTable() == (nRelAvail==0),
    1091             :             "AutoLayout pass 2: Relative width at table in table or the other way around" );
    1092             : 
    1093             :     // The table's minimum width must not be bigger than its maximum width
    1094             :     OSL_ENSURE( nMin<=nMax, "AutoLayout pass 2: nMin > nMax" );
    1095             : 
    1096             :     // Remember the available width for which the table was calculated.
    1097             :     // This is a good place as we pass by here for the initial calculation
    1098             :     // of the table in the parser and for each _Resize call.
    1099           2 :     nLastResizeAbsAvail = nAbsAvail;
    1100             : 
    1101             :     // Step 1: The available space is readjusted for the left/right border,
    1102             :     // possibly existing filler cells and distances.
    1103             : 
    1104             :     // Distance to the content and border
    1105           2 :     sal_uInt16 nAbsLeftFill = 0, nAbsRightFill = 0;
    1106           2 :     if( !IsTopTable() &&
    1107           0 :         GetMin() + nAbsLeftSpace + nAbsRightSpace <= nAbsAvail )
    1108             :     {
    1109           0 :         nAbsLeftFill = nAbsLeftSpace;
    1110           0 :         nAbsRightFill = nAbsRightSpace;
    1111             :     }
    1112             : 
    1113             :     // Left and right distance
    1114           2 :     if( nLeftMargin || nRightMargin )
    1115             :     {
    1116           0 :         if( IsTopTable() )
    1117             :         {
    1118             :             // For the top table we always respect the borders, because we
    1119             :             // never go below the table's minimum width.
    1120           0 :             nAbsAvail -= (nLeftMargin + nRightMargin);
    1121             :         }
    1122           0 :         else if( GetMin() + nLeftMargin + nRightMargin <= nAbsAvail )
    1123             :         {
    1124             :             // Else, we only respect the borders if there's space available
    1125             :             // for them (nMin has already been calculated!)
    1126           0 :             nAbsLeftFill = nAbsLeftFill + nLeftMargin;
    1127           0 :             nAbsRightFill = nAbsRightFill + nRightMargin;
    1128             :         }
    1129             :     }
    1130             : 
    1131             :     // Filler cells
    1132           2 :     if( !IsTopTable() )
    1133             :     {
    1134           0 :         if( pLeftFillerBox && nAbsLeftFill<MINLAY+nInhLeftBorderWidth )
    1135           0 :             nAbsLeftFill = MINLAY+nInhLeftBorderWidth;
    1136           0 :         if( pRightFillerBox && nAbsRightFill<MINLAY+nInhRightBorderWidth )
    1137           0 :             nAbsRightFill = MINLAY+nInhRightBorderWidth;
    1138             :     }
    1139             : 
    1140             :     // Read just the available space
    1141           2 :     nRelLeftFill = 0;
    1142           2 :     nRelRightFill = 0;
    1143           2 :     if( !IsTopTable() && (nAbsLeftFill>0 || nAbsRightFill) )
    1144             :     {
    1145           0 :         sal_uLong nAbsLeftFillL = nAbsLeftFill, nAbsRightFillL = nAbsRightFill;
    1146             : 
    1147           0 :         nRelLeftFill = (sal_uInt16)((nAbsLeftFillL * nRelAvail) / nAbsAvail);
    1148           0 :         nRelRightFill = (sal_uInt16)((nAbsRightFillL * nRelAvail) / nAbsAvail);
    1149             : 
    1150           0 :         nAbsAvail -= (nAbsLeftFill + nAbsRightFill);
    1151           0 :         if( nRelAvail )
    1152           0 :             nRelAvail -= (nRelLeftFill + nRelRightFill);
    1153             :     }
    1154             : 
    1155             :     // Step 2: Calculate the absolute table width.
    1156           2 :     sal_uInt16 nAbsTabWidth = 0;
    1157           2 :     bUseRelWidth = false;
    1158           2 :     if( nWidthOption )
    1159             :     {
    1160           2 :         if( bPrcWidthOption )
    1161             :         {
    1162             :             OSL_ENSURE( nWidthOption<=100, "Percentage value too high" );
    1163           2 :             if( nWidthOption > 100 )
    1164           0 :                 nWidthOption = 100;
    1165             : 
    1166             :             // The absolute width is equal to the given percentage of
    1167             :             // the available width.
    1168             :             // Top tables only get a relative width if the available space
    1169             :             // is *strictly larger* than the minimum width.
    1170             : 
    1171             :             // CAUTION: We need the "strictly larger" because changing from a
    1172             :             // relative width to an absolute width by resizing would lead
    1173             :             // to an infinite loop.
    1174             : 
    1175             :             // Because we do not call resize for tables in frames if the
    1176             :             // frame has a non-relative width, we cannot play such games.
    1177             : 
    1178             :             // Let's play such games now anyway. We had a graphic in a 1% wide
    1179             :             // table and it didn't fit in of course.
    1180           2 :             nAbsTabWidth = (sal_uInt16)( ((sal_uLong)nAbsAvail * nWidthOption) / 100 );
    1181           4 :             if( IsTopTable() &&
    1182           2 :                 ( /*MayBeInFlyFrame() ||*/ (sal_uLong)nAbsTabWidth > nMin ) )
    1183             :             {
    1184           2 :                 nRelAvail = USHRT_MAX;
    1185           2 :                 bUseRelWidth = true;
    1186             :             }
    1187             :         }
    1188             :         else
    1189             :         {
    1190           0 :             nAbsTabWidth = nWidthOption;
    1191           0 :             if( nAbsTabWidth > MAX_TABWIDTH )
    1192           0 :                 nAbsTabWidth = MAX_TABWIDTH;
    1193             : 
    1194             :             // Tables within tables must never get wider than the available
    1195             :             // space.
    1196           0 :             if( !IsTopTable() && nAbsTabWidth > nAbsAvail )
    1197           0 :                 nAbsTabWidth = nAbsAvail;
    1198             :         }
    1199             :     }
    1200             : 
    1201             :     OSL_ENSURE( IsTopTable() || nAbsTabWidth<=nAbsAvail,
    1202             :             "AutoLayout pass 2: nAbsTabWidth > nAbsAvail for table in table" );
    1203             :     OSL_ENSURE( !nRelAvail || nAbsTabWidth<=nAbsAvail,
    1204             :             "AutoLayout pass 2: nAbsTabWidth > nAbsAvail for relative width" );
    1205             : 
    1206             :     // Catch for the two asserts above (we never know!)
    1207           2 :     if( (!IsTopTable() || nRelAvail>0) && nAbsTabWidth>nAbsAvail )
    1208           0 :         nAbsTabWidth = nAbsAvail;
    1209             : 
    1210             :     // Step 3: Identify the column width and, if applicable, the absolute
    1211             :     // and relative table widths.
    1212           4 :     if( (!IsTopTable() && nMin > (sal_uLong)nAbsAvail) ||
    1213           2 :         nMin > MAX_TABWIDTH )
    1214             :     {
    1215             :         // If
    1216             :         // - a inner table's minimum is larger than the available space, or
    1217             :         // - a top table's minimum is larger than USHORT_MAX the table
    1218             :         // has to be adapted to the available space or USHORT_MAX.
    1219             :         // We preserve the widths' ratio amongst themselves, however.
    1220             : 
    1221           0 :         nAbsTabWidth = IsTopTable() ? MAX_TABWIDTH : nAbsAvail;
    1222           0 :         nRelTabWidth = (nRelAvail ? nRelAvail : nAbsTabWidth );
    1223             : 
    1224             :         // First of all, we check whether we can fit the layout constrains,
    1225             :         // which are: Every cell's width excluding the borders must be at least
    1226             :         // MINLAY:
    1227             : 
    1228           0 :         sal_uLong nRealMin = 0;
    1229           0 :         for( sal_uInt16 i=0; i<nCols; i++ )
    1230             :         {
    1231           0 :             sal_uLong nRealColMin = MINLAY, nDummy1 = 0, nDummy2 = 0;
    1232           0 :             AddBorderWidth( nRealColMin, nDummy1, nDummy2, i, 1 );
    1233           0 :             nRealMin += nRealColMin;
    1234             :         }
    1235           0 :         if( (nRealMin >= nAbsTabWidth) || (nRealMin >= nMin) )
    1236             :         {
    1237             :             // "Rien ne va plus": we cannot get the minimum column widths
    1238             :             // the layout wants to have.
    1239             : 
    1240           0 :             sal_uInt16 nAbs = 0, nRel = 0;
    1241             :             SwHTMLTableLayoutColumn *pColumn;
    1242           0 :             for( sal_uInt16 i=0; i<nCols-1; i++ )
    1243             :             {
    1244           0 :                 pColumn = GetColumn( i );
    1245           0 :                 sal_uLong nColMin = pColumn->GetMin();
    1246           0 :                 if( nColMin <= USHRT_MAX )
    1247             :                 {
    1248             :                     pColumn->SetAbsColWidth(
    1249           0 :                         (sal_uInt16)((nColMin * nAbsTabWidth) / nMin) );
    1250             :                     pColumn->SetRelColWidth(
    1251           0 :                         (sal_uInt16)((nColMin * nRelTabWidth) / nMin) );
    1252             :                 }
    1253             :                 else
    1254             :                 {
    1255           0 :                     double nColMinD = nColMin;
    1256             :                     pColumn->SetAbsColWidth(
    1257           0 :                         (sal_uInt16)((nColMinD * nAbsTabWidth) / nMin) );
    1258             :                     pColumn->SetRelColWidth(
    1259           0 :                         (sal_uInt16)((nColMinD * nRelTabWidth) / nMin) );
    1260             :                 }
    1261             : 
    1262           0 :                 nAbs = nAbs + (sal_uInt16)pColumn->GetAbsColWidth();
    1263           0 :                 nRel = nRel + (sal_uInt16)pColumn->GetRelColWidth();
    1264             :             }
    1265           0 :             pColumn = GetColumn( nCols-1 );
    1266           0 :             pColumn->SetAbsColWidth( nAbsTabWidth - nAbs );
    1267           0 :             pColumn->SetRelColWidth( nRelTabWidth - nRel );
    1268             :         }
    1269             :         else
    1270             :         {
    1271           0 :             sal_uLong nDistAbs = nAbsTabWidth - nRealMin;
    1272           0 :             sal_uLong nDistRel = nRelTabWidth - nRealMin;
    1273           0 :             sal_uLong nDistMin = nMin - nRealMin;
    1274           0 :             sal_uInt16 nAbs = 0, nRel = 0;
    1275             :             SwHTMLTableLayoutColumn *pColumn;
    1276           0 :             for( sal_uInt16 i=0; i<nCols-1; i++ )
    1277             :             {
    1278           0 :                 pColumn = GetColumn( i );
    1279           0 :                 sal_uLong nColMin = pColumn->GetMin();
    1280           0 :                 sal_uLong nRealColMin = MINLAY, nDummy1 = 0, nDummy2 = 0;
    1281           0 :                 AddBorderWidth( nRealColMin, nDummy1, nDummy2, i, 1 );
    1282             : 
    1283           0 :                 if( nColMin <= USHRT_MAX )
    1284             :                 {
    1285             :                     pColumn->SetAbsColWidth(
    1286           0 :                         (sal_uInt16)((((nColMin-nRealColMin) * nDistAbs) / nDistMin) + nRealColMin) );
    1287             :                     pColumn->SetRelColWidth(
    1288           0 :                         (sal_uInt16)((((nColMin-nRealColMin) * nDistRel) / nDistMin) + nRealColMin) );
    1289             :                 }
    1290             :                 else
    1291             :                 {
    1292           0 :                     double nColMinD = nColMin;
    1293             :                     pColumn->SetAbsColWidth(
    1294           0 :                         (sal_uInt16)((((nColMinD-nRealColMin) * nDistAbs) / nDistMin) + nRealColMin) );
    1295             :                     pColumn->SetRelColWidth(
    1296           0 :                         (sal_uInt16)((((nColMinD-nRealColMin) * nDistRel) / nDistMin) + nRealColMin) );
    1297             :                 }
    1298             : 
    1299           0 :                 nAbs = nAbs + (sal_uInt16)pColumn->GetAbsColWidth();
    1300           0 :                 nRel = nRel + (sal_uInt16)pColumn->GetRelColWidth();
    1301             :             }
    1302           0 :             pColumn = GetColumn( nCols-1 );
    1303           0 :             pColumn->SetAbsColWidth( nAbsTabWidth - nAbs );
    1304           0 :             pColumn->SetRelColWidth( nRelTabWidth - nRel );
    1305             :         }
    1306             :     }
    1307           2 :     else if( nMax <= (sal_uLong)(nAbsTabWidth ? nAbsTabWidth : nAbsAvail) )
    1308             :     {
    1309             :         // If
    1310             :         // - the table has a fixed width and the table's maximum is
    1311             :         //   smaller, or
    1312             :         //- the maximum is smaller than the available space,
    1313             :         // we can take over the maximum as it is. Respectively
    1314             :         // the table can only be adapted to the fixed width by
    1315             :         // respecting the maximum.
    1316             : 
    1317             :         // No fixed width, use the maximum.
    1318           2 :         if( !nAbsTabWidth )
    1319           0 :             nAbsTabWidth = (sal_uInt16)nMax;
    1320             : 
    1321             :         // A top table may also get wider then the available space.
    1322           2 :         if( nAbsTabWidth > nAbsAvail )
    1323             :         {
    1324             :             OSL_ENSURE( IsTopTable(),
    1325             :                     "Table in table should get wider than the surrounding cell." );
    1326           0 :             nAbsAvail = nAbsTabWidth;
    1327             :         }
    1328             : 
    1329             :         // Only use the relative widths' fraction, that is used for the
    1330             :         // absolute width.
    1331           2 :         sal_uLong nAbsTabWidthL = nAbsTabWidth;
    1332           2 :         if (nRelAvail)
    1333             :         {
    1334           2 :             if (nAbsAvail == 0)
    1335           0 :                 throw o3tl::divide_by_zero();
    1336           2 :             nRelTabWidth = (sal_uInt16)((nAbsTabWidthL * nRelAvail) / nAbsAvail);
    1337             :         }
    1338             :         else
    1339           0 :             nRelTabWidth = nAbsTabWidth;
    1340             : 
    1341             :         // Are there columns width a percentage setting and some without one?
    1342           2 :         sal_uLong nFixMax = nMax;
    1343          12 :         for( sal_uInt16 i=0; i<nCols; i++ )
    1344             :         {
    1345          10 :             const SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
    1346          10 :             if( pColumn->IsRelWidthOption() && pColumn->GetWidthOption()>0 )
    1347          10 :                 nFixMax -= pColumn->GetMax();
    1348             :         }
    1349             : 
    1350           2 :         if( nFixMax > 0 && nFixMax < nMax )
    1351             :         {
    1352             :             // Yes, distribute the to-be-distributed space only to the
    1353             :             // columns with a percentage setting.
    1354             : 
    1355             :             // In this case (and in this case only) there are columns
    1356             :             // that exactly keep their maximum width, that is they neither
    1357             :             // get smaller nor wider. When calculating the absolute width
    1358             :             // from the relative width we can get rounding errors.
    1359             :             // To correct this, we first make the fixed widths compensate for
    1360             :             // this error. We then fix the relative widths the same way.
    1361             : 
    1362           0 :             sal_uInt16 nAbs = 0, nRel = 0;
    1363           0 :             sal_uInt16 nFixedCols = 0;
    1364             :             sal_uInt16 i;
    1365             : 
    1366           0 :             for( i = 0; i < nCols; i++ )
    1367             :             {
    1368           0 :                 SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
    1369           0 :                 if( !pColumn->IsRelWidthOption() || !pColumn->GetWidthOption() )
    1370             :                 {
    1371             :                     // The column keeps its width.
    1372           0 :                     nFixedCols++;
    1373           0 :                     sal_uLong nColMax = pColumn->GetMax();
    1374           0 :                     pColumn->SetAbsColWidth( (sal_uInt16)nColMax );
    1375             : 
    1376             :                     sal_uLong nRelColWidth =
    1377           0 :                         (nColMax * nRelTabWidth) / nAbsTabWidth;
    1378             :                     sal_uLong nChkWidth =
    1379           0 :                         (nRelColWidth * nAbsTabWidth) / nRelTabWidth;
    1380           0 :                     if( nChkWidth < nColMax )
    1381           0 :                         nRelColWidth++;
    1382           0 :                     else if( nChkWidth > nColMax )
    1383           0 :                         nRelColWidth--;
    1384           0 :                     pColumn->SetRelColWidth( (sal_uInt16)nRelColWidth );
    1385             : 
    1386           0 :                     nAbs = nAbs + (sal_uInt16)nColMax;
    1387           0 :                     nRel = nRel + (sal_uInt16)nRelColWidth;
    1388             :                 }
    1389             :             }
    1390             : 
    1391             :             // The to-be-distributed percentage of the maximum, the
    1392             :             // relative and absolute widths. Here, nFixMax corresponds
    1393             :             // to nAbs, so that we could've called it nAbs.
    1394             :             // The code is, however, more readable like that.
    1395             :             OSL_ENSURE( nFixMax == nAbs, "Two loops, two sums?" );
    1396           0 :             sal_uLong nDistMax = nMax - nFixMax;
    1397           0 :             sal_uInt16 nDistAbsTabWidth = nAbsTabWidth - nAbs;
    1398           0 :             sal_uInt16 nDistRelTabWidth = nRelTabWidth - nRel;
    1399             : 
    1400           0 :             for( i=0; i<nCols; i++ )
    1401             :             {
    1402           0 :                 SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
    1403           0 :                 if( pColumn->IsRelWidthOption() && pColumn->GetWidthOption() > 0 )
    1404             :                 {
    1405             :                     // The column gets proportionately wider.
    1406           0 :                     nFixedCols++;
    1407           0 :                     if( nFixedCols == nCols )
    1408             :                     {
    1409           0 :                         pColumn->SetAbsColWidth( nAbsTabWidth-nAbs );
    1410           0 :                         pColumn->SetRelColWidth( nRelTabWidth-nRel );
    1411             :                     }
    1412             :                     else
    1413             :                     {
    1414           0 :                         sal_uLong nColMax = pColumn->GetMax();
    1415             :                         pColumn->SetAbsColWidth(
    1416           0 :                             (sal_uInt16)((nColMax * nDistAbsTabWidth) / nDistMax) );
    1417             :                         pColumn->SetRelColWidth(
    1418           0 :                             (sal_uInt16)((nColMax * nDistRelTabWidth) / nDistMax) );
    1419             :                     }
    1420           0 :                     nAbs = nAbs + pColumn->GetAbsColWidth();
    1421           0 :                     nRel = nRel + pColumn->GetRelColWidth();
    1422             :                 }
    1423             :             }
    1424           0 :             OSL_ENSURE( nCols==nFixedCols, "Missed a column!" );
    1425             :         }
    1426           2 :         else if (nCols > 0)
    1427             :         {
    1428           2 :             if (nMax == 0)
    1429           0 :                 throw o3tl::divide_by_zero();
    1430             :             // No. So distribute the space regularly among all columns.
    1431          12 :             for (sal_uInt16 i=0; i < nCols; ++i)
    1432             :             {
    1433          10 :                 sal_uLong nColMax = GetColumn( i )->GetMax();
    1434             :                 GetColumn( i )->SetAbsColWidth(
    1435          10 :                     (sal_uInt16)((nColMax * nAbsTabWidth) / nMax) );
    1436             :                 GetColumn( i )->SetRelColWidth(
    1437          10 :                     (sal_uInt16)((nColMax * nRelTabWidth) / nMax) );
    1438             :             }
    1439             :         }
    1440             :     }
    1441             :     else
    1442             :     {
    1443             :         // Proportionately distribute the space that extends over the minimum
    1444             :         // width among the columns.
    1445           0 :         if( !nAbsTabWidth )
    1446           0 :             nAbsTabWidth = nAbsAvail;
    1447           0 :         if( nAbsTabWidth < nMin )
    1448           0 :             nAbsTabWidth = (sal_uInt16)nMin;
    1449             : 
    1450           0 :         if( nAbsTabWidth > nAbsAvail )
    1451             :         {
    1452             :             OSL_ENSURE( IsTopTable(),
    1453             :                     "A nested table should become wider than the available space." );
    1454           0 :             nAbsAvail = nAbsTabWidth;
    1455             :         }
    1456             : 
    1457           0 :         sal_uLong nAbsTabWidthL = nAbsTabWidth;
    1458           0 :         if (nRelAvail)
    1459             :         {
    1460           0 :             if (nAbsAvail == 0)
    1461           0 :                 throw o3tl::divide_by_zero();
    1462           0 :             nRelTabWidth = (sal_uInt16)((nAbsTabWidthL * nRelAvail) / nAbsAvail);
    1463             :         }
    1464             :         else
    1465           0 :             nRelTabWidth = nAbsTabWidth;
    1466           0 :         double nW = nAbsTabWidth - nMin;
    1467           0 :         double nD = (nMax==nMin ? 1 : nMax-nMin);
    1468           0 :         sal_uInt16 nAbs = 0, nRel = 0;
    1469           0 :         for( sal_uInt16 i=0; i<nCols-1; i++ )
    1470             :         {
    1471           0 :             double nd = GetColumn( i )->GetMax() - GetColumn( i )->GetMin();
    1472           0 :             sal_uLong nAbsColWidth = GetColumn( i )->GetMin() + (sal_uLong)((nd*nW)/nD);
    1473             :             sal_uLong nRelColWidth = nRelAvail
    1474           0 :                                     ? (nAbsColWidth * nRelTabWidth) / nAbsTabWidth
    1475           0 :                                     : nAbsColWidth;
    1476             : 
    1477           0 :             GetColumn( i )->SetAbsColWidth( (sal_uInt16)nAbsColWidth );
    1478           0 :             GetColumn( i )->SetRelColWidth( (sal_uInt16)nRelColWidth );
    1479           0 :             nAbs = nAbs + (sal_uInt16)nAbsColWidth;
    1480           0 :             nRel = nRel + (sal_uInt16)nRelColWidth;
    1481             :         }
    1482           0 :         GetColumn( nCols-1 )->SetAbsColWidth( nAbsTabWidth - nAbs );
    1483           0 :         GetColumn( nCols-1 )->SetRelColWidth( nRelTabWidth - nRel );
    1484             : 
    1485             :     }
    1486             : 
    1487             :     // Step 4: For nested tables we can have balancing cells on the
    1488             :     // left or right. Here we calculate their width.
    1489           2 :     nInhAbsLeftSpace = 0;
    1490           2 :     nInhAbsRightSpace = 0;
    1491           2 :     if( !IsTopTable() && (nRelLeftFill>0 || nRelRightFill>0 ||
    1492             :                           nAbsTabWidth<nAbsAvail) )
    1493             :     {
    1494             :         // Calculate the width of additional cells we use for
    1495             :         // aligning inner tables.
    1496           0 :         sal_uInt16 nAbsDist = (sal_uInt16)(nAbsAvail-nAbsTabWidth);
    1497           0 :         sal_uInt16 nRelDist = (sal_uInt16)(nRelAvail-nRelTabWidth);
    1498           0 :         sal_uInt16 nParentInhAbsLeftSpace = 0, nParentInhAbsRightSpace = 0;
    1499             : 
    1500             :         // Calculate the size and position of the additional cells.
    1501           0 :         switch( eTableAdjust )
    1502             :         {
    1503             :         case SVX_ADJUST_RIGHT:
    1504           0 :             nAbsLeftFill = nAbsLeftFill + nAbsDist;
    1505           0 :             nRelLeftFill = nRelLeftFill + nRelDist;
    1506           0 :             nParentInhAbsLeftSpace = nParentInhAbsSpace;
    1507           0 :             break;
    1508             :         case SVX_ADJUST_CENTER:
    1509             :             {
    1510           0 :                 sal_uInt16 nAbsLeftDist = nAbsDist / 2;
    1511           0 :                 nAbsLeftFill = nAbsLeftFill + nAbsLeftDist;
    1512           0 :                 nAbsRightFill += nAbsDist - nAbsLeftDist;
    1513           0 :                 sal_uInt16 nRelLeftDist = nRelDist / 2;
    1514           0 :                 nRelLeftFill = nRelLeftFill + nRelLeftDist;
    1515           0 :                 nRelRightFill += nRelDist - nRelLeftDist;
    1516           0 :                 nParentInhAbsLeftSpace = nParentInhAbsSpace / 2;
    1517             :                 nParentInhAbsRightSpace = nParentInhAbsSpace -
    1518           0 :                                           nParentInhAbsLeftSpace;
    1519             :             }
    1520           0 :             break;
    1521             :         case SVX_ADJUST_LEFT:
    1522             :         default:
    1523           0 :             nAbsRightFill = nAbsRightFill + nAbsDist;
    1524           0 :             nRelRightFill = nRelRightFill + nRelDist;
    1525           0 :             nParentInhAbsRightSpace = nParentInhAbsSpace;
    1526           0 :             break;
    1527             :         }
    1528             : 
    1529             :         OSL_ENSURE( !pLeftFillerBox || nRelLeftFill>0,
    1530             :                 "We don't have a width for the left filler box!" );
    1531             :         OSL_ENSURE( !pRightFillerBox || nRelRightFill>0,
    1532             :                 "We don't have a width for the right filler box!" );
    1533             : 
    1534             :         // Filler widths are added to the outer columns, if there are no boxes
    1535             :         // for them after the first pass (nWidth>0) or their width would become
    1536             :         // too small or if there are COL tags and the filler width corresponds
    1537             :         // to the border width.
    1538             :         // In the last case we probably exported the table ourselves.
    1539           0 :         if( nRelLeftFill && !pLeftFillerBox &&
    1540           0 :             ( nWidthSet>0 || nAbsLeftFill<MINLAY+nInhLeftBorderWidth ||
    1541           0 :               (HasColTags() && nAbsLeftFill < nAbsLeftSpace+nParentInhAbsLeftSpace+20) ) )
    1542             :         {
    1543           0 :             SwHTMLTableLayoutColumn *pColumn = GetColumn( 0 );
    1544           0 :             pColumn->SetAbsColWidth( pColumn->GetAbsColWidth()+nAbsLeftFill );
    1545           0 :             pColumn->SetRelColWidth( pColumn->GetRelColWidth()+nRelLeftFill );
    1546           0 :             nRelLeftFill = 0;
    1547           0 :             nInhAbsLeftSpace = nAbsLeftSpace + nParentInhAbsLeftSpace;
    1548             :         }
    1549           0 :         if( nRelRightFill && !pRightFillerBox &&
    1550           0 :             ( nWidthSet>0 || nAbsRightFill<MINLAY+nInhRightBorderWidth ||
    1551           0 :               (HasColTags() && nAbsRightFill < nAbsRightSpace+nParentInhAbsRightSpace+20) ) )
    1552             :         {
    1553           0 :             SwHTMLTableLayoutColumn *pColumn = GetColumn( nCols-1 );
    1554           0 :             pColumn->SetAbsColWidth( pColumn->GetAbsColWidth()+nAbsRightFill );
    1555           0 :             pColumn->SetRelColWidth( pColumn->GetRelColWidth()+nRelRightFill );
    1556           0 :             nRelRightFill = 0;
    1557           0 :             nInhAbsRightSpace = nAbsRightSpace + nParentInhAbsRightSpace;
    1558             :         }
    1559             :     }
    1560           2 : }
    1561             : 
    1562             : static void lcl_ResizeLine( const SwTableLine* pLine, sal_uInt16 *pWidth );
    1563             : 
    1564         520 : static void lcl_ResizeBox( const SwTableBox* pBox, sal_uInt16* pWidth )
    1565             : {
    1566         520 :     if( !pBox->GetSttNd() )
    1567             :     {
    1568           0 :         sal_uInt16 nWidth = 0;
    1569           0 :         BOOST_FOREACH( const SwTableLine *pLine, pBox->GetTabLines() )
    1570           0 :             lcl_ResizeLine( pLine, &nWidth );
    1571           0 :         pBox->GetFrmFmt()->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nWidth, 0 ));
    1572           0 :         *pWidth = *pWidth + nWidth;
    1573             :     }
    1574             :     else
    1575             :     {
    1576         520 :         *pWidth = *pWidth + (sal_uInt16)pBox->GetFrmFmt()->GetFrmSize().GetSize().Width();
    1577             :     }
    1578         520 : }
    1579             : 
    1580         104 : static void lcl_ResizeLine( const SwTableLine* pLine, sal_uInt16 *pWidth )
    1581             : {
    1582         104 :     sal_uInt16 nOldWidth = *pWidth;
    1583         104 :     *pWidth = 0;
    1584         624 :     BOOST_FOREACH( const SwTableBox* pBox, pLine->GetTabBoxes() )
    1585         520 :         lcl_ResizeBox(pBox, pWidth );
    1586             : 
    1587             :     SAL_WARN_IF( nOldWidth && std::abs(*pWidth-nOldWidth) >= COLFUZZY, "sw.core",
    1588             :                  "A box's rows have all a different length" );
    1589         104 : }
    1590             : 
    1591           2 : void SwHTMLTableLayout::SetWidths( bool bCallPass2, sal_uInt16 nAbsAvail,
    1592             :                                    sal_uInt16 nRelAvail, sal_uInt16 nAbsLeftSpace,
    1593             :                                    sal_uInt16 nAbsRightSpace,
    1594             :                                    sal_uInt16 nParentInhAbsSpace )
    1595             : {
    1596             :     // SetWidth must have been passed through once more for every cell in the
    1597             :     // end.
    1598           2 :     nWidthSet++;
    1599             : 
    1600             :     // Step 0: If necessary, we call the layout algorithm of Pass2.
    1601           2 :     if( bCallPass2 )
    1602             :         AutoLayoutPass2( nAbsAvail, nRelAvail, nAbsLeftSpace, nAbsRightSpace,
    1603           0 :                          nParentInhAbsSpace );
    1604             : 
    1605             :     // Step 1: Set the new width in all content boxes.
    1606             :     // Because the boxes don't know anything about the HTML table structure,
    1607             :     // we iterate over the HTML table structure.
    1608             :     // For tables in tables in tables we call SetWidth recursively.
    1609         106 :     for( sal_uInt16 i=0; i<nRows; i++ )
    1610             :     {
    1611         624 :         for( sal_uInt16 j=0; j<nCols; j++ )
    1612             :         {
    1613         520 :             SwHTMLTableLayoutCell *pCell = GetCell( i, j );
    1614             : 
    1615         520 :             SwHTMLTableLayoutCnts* pCntnts = pCell->GetContents();
    1616        1560 :             while( pCntnts && !pCntnts->IsWidthSet(nWidthSet) )
    1617             :             {
    1618         520 :                 SwTableBox *pBox = pCntnts->GetTableBox();
    1619         520 :                 if( pBox )
    1620             :                 {
    1621         520 :                     SetBoxWidth( pBox, j, pCell->GetColSpan() );
    1622             :                 }
    1623             :                 else
    1624             :                 {
    1625           0 :                     sal_uInt16 nAbs = 0, nRel = 0, nLSpace = 0, nRSpace = 0,
    1626           0 :                            nInhSpace = 0;
    1627           0 :                     if( bCallPass2 )
    1628             :                     {
    1629           0 :                         sal_uInt16 nColSpan = pCell->GetColSpan();
    1630           0 :                         GetAvail( j, nColSpan, nAbs, nRel );
    1631           0 :                         nLSpace = GetLeftCellSpace( j, nColSpan );
    1632           0 :                         nRSpace = GetRightCellSpace( j, nColSpan );
    1633           0 :                         nInhSpace = GetInhCellSpace( j, nColSpan );
    1634             :                     }
    1635             :                     pCntnts->GetTable()->SetWidths( bCallPass2, nAbs, nRel,
    1636             :                                                     nLSpace, nRSpace,
    1637           0 :                                                     nInhSpace );
    1638             :                 }
    1639             : 
    1640         520 :                 pCntnts->SetWidthSet( nWidthSet );
    1641         520 :                 pCntnts = pCntnts->GetNext();
    1642             :             }
    1643             :         }
    1644             :     }
    1645             : 
    1646             :     // Step 2: If we have a top table, we adapt the formats of the
    1647             :     // non-content-boxes. Because they are not known in the HTML table
    1648             :     // due to garbage collection there, we need the iterate over the
    1649             :     // whole table.
    1650             :     // We also adapt the table frame format. For nested tables we set the
    1651             :     // filler cell's width instead.
    1652           2 :     if( IsTopTable() )
    1653             :     {
    1654           2 :         sal_uInt16 nCalcTabWidth = 0;
    1655         106 :         BOOST_FOREACH( const SwTableLine *pLine, pSwTable->GetTabLines() )
    1656         104 :             lcl_ResizeLine( pLine, &nCalcTabWidth );
    1657             :         SAL_WARN_IF( std::abs( nRelTabWidth-nCalcTabWidth ) >= COLFUZZY, "sw.core",
    1658             :                      "Table width is not equal to the row width" );
    1659             : 
    1660             :         // Lock the table format when altering it, or else the box formats
    1661             :         // are altered again.
    1662             :         // Also, we need to preserve a percent setting if it exists.
    1663           2 :         SwFrmFmt *pFrmFmt = pSwTable->GetFrmFmt();
    1664           2 :         ((SwTable *)pSwTable)->LockModify();
    1665           2 :         SwFmtFrmSize aFrmSize( pFrmFmt->GetFrmSize() );
    1666           2 :         aFrmSize.SetWidth( nRelTabWidth );
    1667           4 :         bool bRel = bUseRelWidth &&
    1668           4 :                     text::HoriOrientation::FULL!=pFrmFmt->GetHoriOrient().GetHoriOrient();
    1669           2 :         aFrmSize.SetWidthPercent( (sal_uInt8)(bRel ? nWidthOption : 0) );
    1670           2 :         pFrmFmt->SetFmtAttr( aFrmSize );
    1671           2 :         ((SwTable *)pSwTable)->UnlockModify();
    1672             : 
    1673             :         // If the table is located in a frame, we also need to adapt the
    1674             :         // frame's width.
    1675           2 :         if( MayBeInFlyFrame() )
    1676             :         {
    1677           0 :             SwFrmFmt *pFlyFrmFmt = FindFlyFrmFmt();
    1678           0 :             if( pFlyFrmFmt )
    1679             :             {
    1680           0 :                 SwFmtFrmSize aFlyFrmSize( ATT_VAR_SIZE, nRelTabWidth, MINLAY );
    1681             : 
    1682           0 :                 if( bUseRelWidth )
    1683             :                 {
    1684             :                     // For percentage settings we set the width to the minimum.
    1685             :                     aFlyFrmSize.SetWidth(  nMin > USHRT_MAX ? USHRT_MAX
    1686           0 :                                                             : nMin );
    1687           0 :                     aFlyFrmSize.SetWidthPercent( (sal_uInt8)nWidthOption );
    1688             :                 }
    1689           0 :                 pFlyFrmFmt->SetFmtAttr( aFlyFrmSize );
    1690             :             }
    1691           2 :         }
    1692             : 
    1693             : #ifdef DBG_UTIL
    1694             :         {
    1695             :             // check if the tables have correct widths
    1696             :             SwTwips nSize = pSwTable->GetFrmFmt()->GetFrmSize().GetWidth();
    1697             :             const SwTableLines& rLines = pSwTable->GetTabLines();
    1698             :             for (size_t n = 0; n < rLines.size(); ++n)
    1699             :             {
    1700             :                 _CheckBoxWidth( *rLines[ n ], nSize );
    1701             :             }
    1702             :         }
    1703             : #endif
    1704             : 
    1705             :     }
    1706             :     else
    1707             :     {
    1708           0 :         if( pLeftFillerBox )
    1709             :         {
    1710           0 :             pLeftFillerBox->GetFrmFmt()->SetFmtAttr(
    1711           0 :                 SwFmtFrmSize( ATT_VAR_SIZE, nRelLeftFill, 0 ));
    1712             :         }
    1713           0 :         if( pRightFillerBox )
    1714             :         {
    1715           0 :             pRightFillerBox->GetFrmFmt()->SetFmtAttr(
    1716           0 :                 SwFmtFrmSize( ATT_VAR_SIZE, nRelRightFill, 0 ));
    1717             :         }
    1718             :     }
    1719           2 : }
    1720             : 
    1721           0 : void SwHTMLTableLayout::_Resize( sal_uInt16 nAbsAvail, bool bRecalc )
    1722             : {
    1723             :     // If bRecalc is set, the table's content changed.
    1724             :     // We need to execute pass 1 again.
    1725           0 :     if( bRecalc )
    1726           0 :         AutoLayoutPass1();
    1727             : 
    1728           0 :     SwRootFrm *pRoot = (SwRootFrm*)GetDoc()->getIDocumentLayoutAccess().GetCurrentViewShell()->GetLayout();
    1729           0 :     if ( pRoot && pRoot->IsCallbackActionEnabled() )
    1730           0 :         pRoot->StartAllAction();
    1731             : 
    1732             :     // Else we can set the widths, in which we have to run Pass 2 in each case.
    1733           0 :     SetWidths( true, nAbsAvail );
    1734             : 
    1735           0 :     if ( pRoot && pRoot->IsCallbackActionEnabled() )
    1736           0 :         pRoot->EndAllAction( true );    //True per VirDev (browsing is calmer)
    1737           0 : }
    1738             : 
    1739           0 : IMPL_STATIC_LINK( SwHTMLTableLayout, DelayedResize_Impl, void*, EMPTYARG )
    1740             : {
    1741           0 :     pThis->aResizeTimer.Stop();
    1742             :     pThis->_Resize( pThis->nDelayedResizeAbsAvail,
    1743           0 :                     pThis->bDelayedResizeRecalc );
    1744             : 
    1745           0 :     return 0;
    1746             : }
    1747             : 
    1748         104 : bool SwHTMLTableLayout::Resize( sal_uInt16 nAbsAvail, bool bRecalc,
    1749             :                                 bool bForce, sal_uLong nDelay )
    1750             : {
    1751         104 :     if( 0 == nAbsAvail )
    1752           0 :         return false;
    1753             :     OSL_ENSURE( IsTopTable(), "Resize must only be called for top tables!" );
    1754             : 
    1755             :     // May the table be resized at all? Or is it forced?
    1756         104 :     if( bMustNotResize && !bForce )
    1757           0 :         return false;
    1758             : 
    1759             :     // May the table be recalculated? Or is it forced?
    1760         104 :     if( bMustNotRecalc && !bForce )
    1761           0 :         bRecalc = false;
    1762             : 
    1763         104 :     const SwDoc *pDoc = GetDoc();
    1764             : 
    1765             :     // If there is a layout, the root frame's size instead of the
    1766             :     // VisArea's size was potentially passed.
    1767             :     // If we're not in a frame we need to calculate the table for the VisArea,
    1768             :     // because switching from relative to absolute wouldn't work.
    1769         104 :     if( pDoc->getIDocumentLayoutAccess().GetCurrentViewShell() && pDoc->getIDocumentLayoutAccess().GetCurrentViewShell()->GetViewOptions()->getBrowseMode() )
    1770             :     {
    1771           0 :         const sal_uInt16 nVisAreaWidth = GetBrowseWidthByVisArea( *pDoc );
    1772           0 :         if( nVisAreaWidth < nAbsAvail && !FindFlyFrmFmt() )
    1773           0 :             nAbsAvail = nVisAreaWidth;
    1774             :     }
    1775             : 
    1776         104 :     if( nDelay==0 && aResizeTimer.IsActive() )
    1777             :     {
    1778             :         // If there is an asynchronous resize left to process when we call
    1779             :         // a synchronous resize, we only take over the new values.
    1780           0 :         bRecalc |= bDelayedResizeRecalc;
    1781           0 :         nDelayedResizeAbsAvail = nAbsAvail;
    1782           0 :         return false;
    1783             :     }
    1784             : 
    1785             :     // Optimisation:
    1786             :     // If the minimums or maximums should not be recalculated and
    1787             :     // - the table's width never needs to be recalculated, or
    1788             :     // - the table was already calculated for the passed width, or
    1789             :     // - the available space is less or equal to the minimum width
    1790             :     //   and the table already has the minimum width, or
    1791             :     // - the available space is larger than the maximum width and
    1792             :     //   the table already has the maximum width
    1793             :     // nothing will happen to the table.
    1794         208 :     if( !bRecalc && ( !bMustResize ||
    1795         104 :                       (nLastResizeAbsAvail==nAbsAvail) ||
    1796           0 :                       (nAbsAvail<=nMin && nRelTabWidth==nMin) ||
    1797           0 :                       (!bPrcWidthOption && nAbsAvail>=nMax && nRelTabWidth==nMax) ) )
    1798         104 :         return false;
    1799             : 
    1800           0 :     if( nDelay==HTMLTABLE_RESIZE_NOW )
    1801             :     {
    1802           0 :         if( aResizeTimer.IsActive() )
    1803           0 :             aResizeTimer.Stop();
    1804           0 :         _Resize( nAbsAvail, bRecalc );
    1805             :     }
    1806           0 :     else if( nDelay > 0 )
    1807             :     {
    1808           0 :         nDelayedResizeAbsAvail = nAbsAvail;
    1809           0 :         bDelayedResizeRecalc = bRecalc;
    1810           0 :         aResizeTimer.SetTimeout( nDelay );
    1811           0 :         aResizeTimer.Start();
    1812             :     }
    1813             :     else
    1814             :     {
    1815           0 :         _Resize( nAbsAvail, bRecalc );
    1816             :     }
    1817             : 
    1818           0 :     return true;
    1819             : }
    1820             : 
    1821           0 : void SwHTMLTableLayout::BordersChanged( sal_uInt16 nAbsAvail, bool bRecalc )
    1822             : {
    1823           0 :     bBordersChanged = true;
    1824             : 
    1825           0 :     Resize( nAbsAvail, bRecalc );
    1826         270 : }
    1827             : 
    1828             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10