Impress Remote 1.0.5, tag sdremote-1.0.5
[LibreOffice.git] / sw / source / core / doc / htmltbl.cxx
blob5f1a759f4ea761d3ee9a66b1a1cd3f47f4a3823c
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include "hintids.hxx"
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 "swtable.hxx"
32 #include "rootfrm.hxx"
33 #include "docsh.hxx"
34 #include "flyfrm.hxx"
35 #include "poolfmt.hxx"
36 #include "viewsh.hxx"
37 #include "tabfrm.hxx"
38 #include "viewopt.hxx"
39 #include "htmltbl.hxx"
40 #include "ndindex.hxx"
41 #include "switerator.hxx"
42 #include <boost/foreach.hpp>
44 using namespace ::com::sun::star;
47 #define COLFUZZY 20
48 #define MAX_TABWIDTH (USHRT_MAX - 2001)
51 class SwHTMLTableLayoutConstraints
53 sal_uInt16 nRow; // start row
54 sal_uInt16 nCol; // start column
55 sal_uInt16 nColSpan; // the column's COLSPAN
57 SwHTMLTableLayoutConstraints *pNext; // the next constraint
59 sal_uLong nMinNoAlign, nMaxNoAlign; // provisional result of AL-Pass 1
61 public:
63 SwHTMLTableLayoutConstraints( sal_uLong nMin, sal_uLong nMax, sal_uInt16 nRow,
64 sal_uInt16 nCol, sal_uInt16 nColSp );
65 ~SwHTMLTableLayoutConstraints();
67 sal_uLong GetMinNoAlign() const { return nMinNoAlign; }
68 sal_uLong GetMaxNoAlign() const { return nMaxNoAlign; }
70 SwHTMLTableLayoutConstraints *InsertNext( SwHTMLTableLayoutConstraints *pNxt );
71 SwHTMLTableLayoutConstraints* GetNext() const { return pNext; }
73 sal_uInt16 GetRow() const { return nRow; }
75 sal_uInt16 GetColSpan() const { return nColSpan; }
76 sal_uInt16 GetColumn() const { return nCol; }
80 SwHTMLTableLayoutCnts::SwHTMLTableLayoutCnts( const SwStartNode *pSttNd,
81 SwHTMLTableLayout* pTab,
82 bool bNoBrTag,
83 SwHTMLTableLayoutCnts* pNxt ) :
84 pNext( pNxt ), pBox( 0 ), pTable( pTab ), pStartNode( pSttNd ),
85 nPass1Done( 0 ), nWidthSet( 0 ), bNoBreakTag( bNoBrTag )
88 SwHTMLTableLayoutCnts::~SwHTMLTableLayoutCnts()
90 delete pNext;
91 delete pTable;
94 const SwStartNode *SwHTMLTableLayoutCnts::GetStartNode() const
96 return pBox ? pBox->GetSttNd() : pStartNode;
100 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 bNoWrapOption( bNWrapOpt )
110 SwHTMLTableLayoutCell::~SwHTMLTableLayoutCell()
112 if( nRowSpan==1 && nColSpan==1 )
114 delete pContents;
119 SwHTMLTableLayoutColumn::SwHTMLTableLayoutColumn( sal_uInt16 nWidth,
120 bool bRelWidth,
121 bool bLBorder ) :
122 nMinNoAlign(MINLAY), nMaxNoAlign(MINLAY), nAbsMinNoAlign(MINLAY),
123 nMin(0), nMax(0),
124 nAbsColWidth(0), nRelColWidth(0),
125 nWidthOption( nWidth ), bRelWidthOption( bRelWidth ),
126 bLeftBorder( bLBorder )
130 SwHTMLTableLayoutConstraints::SwHTMLTableLayoutConstraints(
131 sal_uLong nMin, sal_uLong nMax, sal_uInt16 nRw, sal_uInt16 nColumn, sal_uInt16 nColSp ):
132 nRow( nRw ), nCol( nColumn ), nColSpan( nColSp ),
133 pNext( 0 ),
134 nMinNoAlign( nMin ), nMaxNoAlign( nMax )
137 SwHTMLTableLayoutConstraints::~SwHTMLTableLayoutConstraints()
139 delete pNext;
142 SwHTMLTableLayoutConstraints *SwHTMLTableLayoutConstraints::InsertNext(
143 SwHTMLTableLayoutConstraints *pNxt )
145 SwHTMLTableLayoutConstraints *pPrev = 0;
146 SwHTMLTableLayoutConstraints *pConstr = this;
147 while( pConstr )
149 if( pConstr->GetRow() > pNxt->GetRow() ||
150 pConstr->GetColumn() > pNxt->GetColumn() )
151 break;
152 pPrev = pConstr;
153 pConstr = pConstr->GetNext();
156 if( pPrev )
158 pNxt->pNext = pPrev->GetNext();
159 pPrev->pNext = pNxt;
160 pConstr = this;
162 else
164 pNxt->pNext = this;
165 pConstr = pNxt;
168 return pConstr;
172 typedef SwHTMLTableLayoutColumn *SwHTMLTableLayoutColumnPtr;
173 typedef SwHTMLTableLayoutCell *SwHTMLTableLayoutCellPtr;
175 SwHTMLTableLayout::SwHTMLTableLayout(
176 const SwTable * pSwTbl,
177 sal_uInt16 nRws, sal_uInt16 nCls, bool bColsOpt, bool bColTgs,
178 sal_uInt16 nWdth, bool bPrcWdth, sal_uInt16 nBorderOpt,
179 sal_uInt16 nCellPad, sal_uInt16 nCellSp, SvxAdjust eAdjust,
180 sal_uInt16 nLMargin, sal_uInt16 nRMargin,
181 sal_uInt16 nBWidth, sal_uInt16 nLeftBWidth,
182 sal_uInt16 nRightBWidth,
183 sal_uInt16 nInhLeftBWidth, sal_uInt16 nInhRightBWidth ) :
184 aColumns( new SwHTMLTableLayoutColumnPtr[nCls] ),
185 aCells( new SwHTMLTableLayoutCellPtr[nRws*nCls] ),
186 pSwTable( pSwTbl ), pLeftFillerBox( 0 ), pRightFillerBox( 0 ),
187 nMin( 0 ), nMax( 0 ),
188 nRows( nRws ), nCols( nCls ),
189 nLeftMargin( nLMargin ), nRightMargin( nRMargin ),
190 nInhAbsLeftSpace( 0 ), nInhAbsRightSpace( 0 ),
191 nRelLeftFill( 0 ), nRelRightFill( 0 ),
192 nRelTabWidth( 0 ), nWidthOption( nWdth ),
193 nCellPadding( nCellPad ), nCellSpacing( nCellSp ), nBorder( nBorderOpt ),
194 nLeftBorderWidth( nLeftBWidth ), nRightBorderWidth( nRightBWidth ),
195 nInhLeftBorderWidth( nInhLeftBWidth ),
196 nInhRightBorderWidth( nInhRightBWidth ),
197 nBorderWidth( nBWidth ),
198 nDelayedResizeAbsAvail( 0 ), nLastResizeAbsAvail( 0 ),
199 nPass1Done( 0 ), nWidthSet( 0 ), eTableAdjust( eAdjust ),
200 bColsOption( bColsOpt ), bColTags( bColTgs ),
201 bPrcWidthOption( bPrcWdth ), bUseRelWidth( false ),
202 bMustResize( sal_True ), bExportable( sal_True ), bBordersChanged( sal_False ),
203 bMustNotResize( sal_False ), bMustNotRecalc( sal_False )
205 aResizeTimer.SetTimeoutHdl( STATIC_LINK( this, SwHTMLTableLayout,
206 DelayedResize_Impl ) );
209 SwHTMLTableLayout::~SwHTMLTableLayout()
211 sal_uInt16 i;
213 for( i = 0; i < nCols; i++ )
214 delete aColumns[i];
215 delete[] aColumns;
217 sal_uInt16 nCount = nRows*nCols;
218 for( i=0; i<nCount; i++ )
219 delete aCells[i];
220 delete[] aCells;
223 // The border width are calculated like in Netscape:
224 // Outer border: BORDER + CELLSPACING + CELLPADDING
225 // Inner border: CELLSPACING + CELLPADDING
226 // However, we respect the border width in SW if bSwBorders is set,
227 // so that we don't wrap wrongly.
228 // We also need to respect the distance to the content. Even if
229 // only the opposite side has a border.
230 sal_uInt16 SwHTMLTableLayout::GetLeftCellSpace( sal_uInt16 nCol, sal_uInt16 nColSpan,
231 sal_Bool bSwBorders ) const
233 sal_uInt16 nSpace = nCellSpacing + nCellPadding;
235 if( nCol == 0 )
237 nSpace = nSpace + nBorder;
239 if( bSwBorders && nSpace < nLeftBorderWidth )
240 nSpace = nLeftBorderWidth;
242 else if( bSwBorders )
244 if( GetColumn(nCol)->HasLeftBorder() )
246 if( nSpace < nBorderWidth )
247 nSpace = nBorderWidth;
249 else if( nCol+nColSpan == nCols && nRightBorderWidth &&
250 nSpace < MIN_BORDER_DIST )
252 OSL_ENSURE( !nCellPadding, "GetLeftCellSpace: CELLPADDING!=0" );
253 // If the opposite side has a border we need to respect at
254 // least the minimum distance to the content.
255 // Additionally, we could also use nCellPadding for this.
256 nSpace = MIN_BORDER_DIST;
260 return nSpace;
263 sal_uInt16 SwHTMLTableLayout::GetRightCellSpace( sal_uInt16 nCol, sal_uInt16 nColSpan,
264 sal_Bool bSwBorders ) const
266 sal_uInt16 nSpace = nCellPadding;
268 if( nCol+nColSpan == nCols )
270 nSpace += nBorder + nCellSpacing;
271 if( bSwBorders && nSpace < nRightBorderWidth )
272 nSpace = nRightBorderWidth;
274 else if( bSwBorders && GetColumn(nCol)->HasLeftBorder() &&
275 nSpace < MIN_BORDER_DIST )
277 OSL_ENSURE( !nCellPadding, "GetRightCellSpace: CELLPADDING!=0" );
278 // If the opposite side has a border we need to respect at
279 // least the minimum distance to the content.
280 // Additionally, we could also use nCellPadding for this.
281 nSpace = MIN_BORDER_DIST;
284 return nSpace;
287 void SwHTMLTableLayout::AddBorderWidth( sal_uLong &rMin, sal_uLong &rMax,
288 sal_uLong &rAbsMin,
289 sal_uInt16 nCol, sal_uInt16 nColSpan,
290 sal_Bool bSwBorders ) const
292 sal_uLong nAdd = GetLeftCellSpace( nCol, nColSpan, bSwBorders ) +
293 GetRightCellSpace( nCol, nColSpan, bSwBorders );
295 rMin += nAdd;
296 rMax += nAdd;
297 rAbsMin += nAdd;
300 void SwHTMLTableLayout::SetBoxWidth( SwTableBox *pBox, sal_uInt16 nCol,
301 sal_uInt16 nColSpan ) const
303 SwFrmFmt *pFrmFmt = pBox->GetFrmFmt();
305 // calculate the box's width
306 SwTwips nFrmWidth = 0;
307 while( nColSpan-- )
308 nFrmWidth += GetColumn( nCol++ )->GetRelColWidth();
310 // and reset
311 pFrmFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nFrmWidth, 0 ));
314 void SwHTMLTableLayout::GetAvail( sal_uInt16 nCol, sal_uInt16 nColSpan,
315 sal_uInt16& rAbsAvail, sal_uInt16& rRelAvail ) const
317 rAbsAvail = 0;
318 rRelAvail = 0;
319 for( sal_uInt16 i=nCol; i<nCol+nColSpan;i++ )
321 const SwHTMLTableLayoutColumn *pColumn = GetColumn(i);
322 rAbsAvail = rAbsAvail + pColumn->GetAbsColWidth();
323 rRelAvail = rRelAvail + pColumn->GetRelColWidth();
327 sal_uInt16 SwHTMLTableLayout::GetBrowseWidthByVisArea( const SwDoc& rDoc )
329 ViewShell *pVSh = 0;
330 rDoc.GetEditShell( &pVSh );
331 if( pVSh )
333 return (sal_uInt16)pVSh->GetBrowseWidth();
336 return 0;
339 sal_uInt16 SwHTMLTableLayout::GetBrowseWidth( const SwDoc& rDoc )
341 // If we have a layout, we can get the width from there.
342 const SwRootFrm *pRootFrm = rDoc.GetCurrentLayout(); //swmod 080218
343 if( pRootFrm )
345 const SwFrm *pPageFrm = pRootFrm->GetLower();
346 if( pPageFrm )
347 return (sal_uInt16)pPageFrm->Prt().Width();
350 // #i91658#
351 // Assertion removed which state that no browse width is available.
352 // Investigation reveals that all calls can handle the case that no browse
353 // width is provided.
354 return GetBrowseWidthByVisArea( rDoc );
357 sal_uInt16 SwHTMLTableLayout::GetBrowseWidthByTabFrm(
358 const SwTabFrm& rTabFrm ) const
360 SwTwips nWidth = 0;
362 const SwFrm *pUpper = rTabFrm.GetUpper();
363 if( MayBeInFlyFrame() && pUpper->IsFlyFrm() &&
364 ((const SwFlyFrm *)pUpper)->GetAnchorFrm() )
366 // If the table is located within a self-created frame, the anchor's
367 // width is relevant not the frame's width.
368 // For paragraph-bound frames we don't respect paragraph indents.
369 const SwFrm *pAnchor = ((const SwFlyFrm *)pUpper)->GetAnchorFrm();
370 if( pAnchor->IsTxtFrm() )
371 nWidth = pAnchor->Frm().Width();
372 else
373 nWidth = pAnchor->Prt().Width();
375 else
377 nWidth = pUpper->Prt().Width();
380 SwTwips nUpperDummy = 0;
381 long nRightOffset = 0,
382 nLeftOffset = 0;
383 rTabFrm.CalcFlyOffsets( nUpperDummy, nLeftOffset, nRightOffset );
384 nWidth -= (nLeftOffset + nRightOffset);
386 return nWidth < USHRT_MAX ? static_cast<sal_uInt16>(nWidth) : USHRT_MAX;
389 sal_uInt16 SwHTMLTableLayout::GetBrowseWidthByTable( const SwDoc& rDoc ) const
391 sal_uInt16 nBrowseWidth = 0;
392 SwTabFrm* pFrm = SwIterator<SwTabFrm,SwFmt>::FirstElement( *pSwTable->GetFrmFmt() );
393 if( pFrm )
395 nBrowseWidth = GetBrowseWidthByTabFrm( *pFrm );
397 else
399 nBrowseWidth = SwHTMLTableLayout::GetBrowseWidth( rDoc );
402 return nBrowseWidth;
405 const SwStartNode *SwHTMLTableLayout::GetAnyBoxStartNode() const
407 const SwStartNode *pBoxSttNd;
409 const SwTableBox* pBox = pSwTable->GetTabLines()[0]->GetTabBoxes()[0];
410 while( 0 == (pBoxSttNd = pBox->GetSttNd()) )
412 OSL_ENSURE( pBox->GetTabLines().size() > 0,
413 "Box without start node and lines" );
414 OSL_ENSURE( pBox->GetTabLines().front()->GetTabBoxes().size() > 0,
415 "Line without boxes" );
416 pBox = pBox->GetTabLines().front()->GetTabBoxes().front();
419 return pBoxSttNd;
422 SwFrmFmt *SwHTMLTableLayout::FindFlyFrmFmt() const
424 const SwTableNode *pTblNd = GetAnyBoxStartNode()->FindTableNode();
425 OSL_ENSURE( pTblNd, "Kein Table-Node?" );
426 return pTblNd->GetFlyFmt();
429 static void lcl_GetMinMaxSize( sal_uLong& rMinNoAlignCnts, sal_uLong& rMaxNoAlignCnts,
430 sal_uLong& rAbsMinNoAlignCnts,
431 SwTxtNode *pTxtNd, sal_uLong nIdx, bool bNoBreak )
433 pTxtNd->GetMinMaxSize( nIdx, rMinNoAlignCnts, rMaxNoAlignCnts,
434 rAbsMinNoAlignCnts );
435 OSL_ENSURE( rAbsMinNoAlignCnts <= rMinNoAlignCnts,
436 "GetMinMaxSize: absmin > min" );
437 OSL_ENSURE( rMinNoAlignCnts <= rMaxNoAlignCnts,
438 "GetMinMaxSize: max > min" );
440 // The maximal width for a <PRE> paragraph is the minimal width
441 const SwFmtColl *pColl = &pTxtNd->GetAnyFmtColl();
442 while( pColl && !pColl->IsDefault() &&
443 (USER_FMT & pColl->GetPoolFmtId()) )
445 pColl = (const SwFmtColl *)pColl->DerivedFrom();
448 // <NOBR> in the whole cell apply to text but not to tables.
449 // Netscape only considers this for graphics.
450 if( (pColl && RES_POOLCOLL_HTML_PRE==pColl->GetPoolFmtId()) || bNoBreak )
452 rMinNoAlignCnts = rMaxNoAlignCnts;
453 rAbsMinNoAlignCnts = rMaxNoAlignCnts;
457 void SwHTMLTableLayout::AutoLayoutPass1()
459 nPass1Done++;
461 ClearPass1Info();
463 bool bFixRelWidths = false;
464 sal_uInt16 i;
466 SwHTMLTableLayoutConstraints *pConstraints = 0;
468 for( i=0; i<nCols; i++ )
470 SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
471 pColumn->ClearPass1Info( !HasColTags() );
472 sal_uInt16 nMinColSpan = USHRT_MAX; // Column count to which the calculated width refers to
473 sal_uInt16 nColSkip = USHRT_MAX; // How many columns need to be skipped
475 for( sal_uInt16 j=0; j<nRows; j++ )
477 SwHTMLTableLayoutCell *pCell = GetCell(j,i);
478 SwHTMLTableLayoutCnts *pCnts = pCell->GetContents();
480 // We need to examine all rows in order to
481 // get the column that should be calculated next.
482 sal_uInt16 nColSpan = pCell->GetColSpan();
483 if( nColSpan < nColSkip )
484 nColSkip = nColSpan;
486 if( !pCnts || (pCnts && !pCnts->IsPass1Done(nPass1Done)) )
488 // The cell is empty or it's content was not edited
489 if( nColSpan < nMinColSpan )
490 nMinColSpan = nColSpan;
492 sal_uLong nMinNoAlignCell = 0;
493 sal_uLong nMaxNoAlignCell = 0;
494 sal_uLong nAbsMinNoAlignCell = 0;
495 sal_uLong nMaxTableCell = 0;
496 sal_uLong nAbsMinTableCell = 0;
498 while( pCnts )
500 const SwStartNode *pSttNd = pCnts->GetStartNode();
501 if( pSttNd )
503 const SwDoc *pDoc = pSttNd->GetDoc();
504 sal_uLong nIdx = pSttNd->GetIndex();
505 while( !(pDoc->GetNodes()[nIdx])->IsEndNode() )
507 SwTxtNode *pTxtNd = (pDoc->GetNodes()[nIdx])->GetTxtNode();
508 if( pTxtNd )
510 sal_uLong nMinNoAlignCnts = 0;
511 sal_uLong nMaxNoAlignCnts = 0;
512 sal_uLong nAbsMinNoAlignCnts = 0;
514 lcl_GetMinMaxSize( nMinNoAlignCnts,
515 nMaxNoAlignCnts,
516 nAbsMinNoAlignCnts,
517 pTxtNd, nIdx,
518 pCnts->HasNoBreakTag() );
520 if( nMinNoAlignCnts > nMinNoAlignCell )
521 nMinNoAlignCell = nMinNoAlignCnts;
522 if( nMaxNoAlignCnts > nMaxNoAlignCell )
523 nMaxNoAlignCell = nMaxNoAlignCnts;
524 if( nAbsMinNoAlignCnts > nAbsMinNoAlignCell )
525 nAbsMinNoAlignCell = nAbsMinNoAlignCnts;
527 else
529 SwTableNode *pTabNd = (pDoc->GetNodes()[nIdx])->GetTableNode();
530 if( pTabNd )
532 SwHTMLTableLayout *pChild = pTabNd->GetTable().GetHTMLTableLayout();
533 if( pChild )
535 pChild->AutoLayoutPass1();
536 sal_uLong nMaxTableCnts = pChild->nMax;
537 sal_uLong nAbsMinTableCnts = pChild->nMin;
539 // A fixed table width is taken over as minimum and
540 // maximum at the same time
541 if( !pChild->bPrcWidthOption && pChild->nWidthOption )
543 sal_uLong nTabWidth = pChild->nWidthOption;
544 if( nTabWidth >= nAbsMinTableCnts )
546 nMaxTableCnts = nTabWidth;
547 nAbsMinTableCnts = nTabWidth;
549 else
551 nMaxTableCnts = nAbsMinTableCnts;
555 if( nMaxTableCnts > nMaxTableCell )
556 nMaxTableCell = nMaxTableCnts;
557 if( nAbsMinTableCnts > nAbsMinTableCell )
558 nAbsMinTableCell = nAbsMinTableCnts;
560 nIdx = pTabNd->EndOfSectionNode()->GetIndex();
563 nIdx++;
566 else
568 OSL_ENSURE( !this, "Sub tables in HTML import?" );
569 SwHTMLTableLayout *pChild = pCnts->GetTable();
570 pChild->AutoLayoutPass1();
571 sal_uLong nMaxTableCnts = pChild->nMax;
572 sal_uLong nAbsMinTableCnts = pChild->nMin;
574 // A fixed table width is taken over as minimum and
575 // maximum at the same time
576 if( !pChild->bPrcWidthOption && pChild->nWidthOption )
578 sal_uLong nTabWidth = pChild->nWidthOption;
579 if( nTabWidth >= nAbsMinTableCnts )
581 nMaxTableCnts = nTabWidth;
582 nAbsMinTableCnts = nTabWidth;
584 else
586 nMaxTableCnts = nAbsMinTableCnts;
590 if( nMaxTableCnts > nMaxTableCell )
591 nMaxTableCell = nMaxTableCnts;
592 if( nAbsMinTableCnts > nAbsMinTableCell )
593 nAbsMinTableCell = nAbsMinTableCnts;
595 pCnts->SetPass1Done( nPass1Done );
596 pCnts = pCnts->GetNext();
599 // This code previously came after AddBorderWidth
600 // If a table's width is wider in a cell than what we've calculated
601 // for the other content we need to use the table's width.
602 if( nMaxTableCell > nMaxNoAlignCell )
603 nMaxNoAlignCell = nMaxTableCell;
604 if( nAbsMinTableCell > nAbsMinNoAlignCell )
606 nAbsMinNoAlignCell = nAbsMinTableCell;
607 if( nMinNoAlignCell < nAbsMinNoAlignCell )
608 nMinNoAlignCell = nAbsMinNoAlignCell;
609 if( nMaxNoAlignCell < nMinNoAlignCell )
610 nMaxNoAlignCell = nMinNoAlignCell;
612 // This code previously came after AddBorderWidth
614 sal_Bool bRelWidth = pCell->IsPrcWidthOption();
615 sal_uInt16 nWidth = pCell->GetWidthOption();
617 // A NOWRAP option applies to text and tables, but is
618 // not applied for fixed cell width.
619 // Instead, the stated cell width behaves like a minimal
620 // width.
621 if( pCell->HasNoWrapOption() )
623 if( nWidth==0 || bRelWidth )
625 nMinNoAlignCell = nMaxNoAlignCell;
626 nAbsMinNoAlignCell = nMaxNoAlignCell;
628 else
630 if( nWidth>nMinNoAlignCell )
631 nMinNoAlignCell = nWidth;
632 if( nWidth>nAbsMinNoAlignCell )
633 nAbsMinNoAlignCell = nWidth;
637 // Respect minimum width for content
638 if( nMinNoAlignCell < MINLAY )
639 nMinNoAlignCell = MINLAY;
640 if( nMaxNoAlignCell < MINLAY )
641 nMaxNoAlignCell = MINLAY;
642 if( nAbsMinNoAlignCell < MINLAY )
643 nAbsMinNoAlignCell = MINLAY;
645 // Respect the border and distance to the content
646 AddBorderWidth( nMinNoAlignCell, nMaxNoAlignCell,
647 nAbsMinNoAlignCell, i, nColSpan );
649 if( 1==nColSpan )
651 // take over the values directly
652 pColumn->MergeMinMaxNoAlign( nMinNoAlignCell,
653 nMaxNoAlignCell,
654 nAbsMinNoAlignCell );
656 // the widest WIDTH wins
657 if( !HasColTags() )
658 pColumn->MergeCellWidthOption( nWidth, bRelWidth );
660 else
662 // Process the data line by line from left to right at the end
664 // When which values is taken over will be explained further down.
665 if( !HasColTags() && nWidth && !bRelWidth )
667 sal_uLong nAbsWidth = nWidth, nDummy = 0, nDummy2 = 0;
668 AddBorderWidth( nAbsWidth, nDummy, nDummy2,
669 i, nColSpan, sal_False );
671 if( nAbsWidth >= nMinNoAlignCell )
673 nMaxNoAlignCell = nAbsWidth;
674 if( HasColsOption() )
675 nMinNoAlignCell = nAbsWidth;
677 else if( nAbsWidth >= nAbsMinNoAlignCell )
679 nMaxNoAlignCell = nAbsWidth;
680 nMinNoAlignCell = nAbsWidth;
682 else
684 nMaxNoAlignCell = nAbsMinNoAlignCell;
685 nMinNoAlignCell = nAbsMinNoAlignCell;
688 else if( HasColsOption() || HasColTags() )
689 nMinNoAlignCell = nAbsMinNoAlignCell;
691 SwHTMLTableLayoutConstraints *pConstr =
692 new SwHTMLTableLayoutConstraints( nMinNoAlignCell,
693 nMaxNoAlignCell, j, i, nColSpan );
694 if( pConstraints )
695 pConstraints = pConstraints->InsertNext( pConstr );
696 else
697 pConstraints = pConstr;
702 OSL_ENSURE( nMinColSpan>0 && nColSkip>0 && nColSkip <= nMinColSpan,
703 "Layout pass 1: Columns are being forgotten!" );
704 OSL_ENSURE( nMinColSpan!=USHRT_MAX,
705 "Layout pass 1: unnecessary pass through the loop or a bug" );
707 if( 1==nMinColSpan )
709 // There are cells with COLSPAN 1 and therefore also useful
710 // values in pColumn
712 // Take over values according to the following table (Netscape 4.0 pv 3):
714 // WIDTH: no COLS COLS
716 // none min = min min = absmin
717 // max = max max = max
719 // >= min min = min min = width
720 // max = width max = width
722 // >= absmin min = wdith(*) min = width
723 // max = width max = width
725 // < absmin min = absmin min = absmin
726 // max = absmin max = absmin
728 // (*) Netscape uses the minimum width without a break before
729 // the last graphic here. We don't have that (yet?),
730 // so we leave it set to width.
732 if( pColumn->GetWidthOption() && !pColumn->IsRelWidthOption() )
734 // Take over absolute widths as minimal and maximal widths.
735 sal_uLong nAbsWidth = pColumn->GetWidthOption();
736 sal_uLong nDummy = 0, nDummy2 = 0;
737 AddBorderWidth( nAbsWidth, nDummy, nDummy2, i, 1, sal_False );
739 if( nAbsWidth >= pColumn->GetMinNoAlign() )
741 pColumn->SetMinMax( HasColsOption() ? nAbsWidth
742 : pColumn->GetMinNoAlign(),
743 nAbsWidth );
745 else if( nAbsWidth >= pColumn->GetAbsMinNoAlign() )
747 pColumn->SetMinMax( nAbsWidth, nAbsWidth );
749 else
751 pColumn->SetMinMax( pColumn->GetAbsMinNoAlign(),
752 pColumn->GetAbsMinNoAlign() );
755 else
757 pColumn->SetMinMax( HasColsOption() ? pColumn->GetAbsMinNoAlign()
758 : pColumn->GetMinNoAlign(),
759 pColumn->GetMaxNoAlign() );
762 else if( USHRT_MAX!=nMinColSpan )
764 // Can be anything != 0, because it is altered by the constraints.
765 pColumn->SetMinMax( MINLAY, MINLAY );
767 // the next columns need not to be processed
768 i += (nColSkip-1);
771 nMin += pColumn->GetMin();
772 nMax += pColumn->GetMax();
773 if (pColumn->IsRelWidthOption()) bFixRelWidths = true;
776 // Now process the constraints
777 SwHTMLTableLayoutConstraints *pConstr = pConstraints;
778 while( pConstr )
780 // At first we need to process the width in the same way
781 // as the column widths
782 sal_uInt16 nCol = pConstr->GetColumn();
783 sal_uInt16 nColSpan = pConstr->GetColSpan();
784 sal_uLong nConstrMin = pConstr->GetMinNoAlign();
785 sal_uLong nConstrMax = pConstr->GetMaxNoAlign();
787 // We get the hitherto width of the spanned columns
788 sal_uLong nColsMin = 0;
789 sal_uLong nColsMax = 0;
790 for( sal_uInt16 j=nCol; j<nCol+nColSpan; j++ )
792 SwHTMLTableLayoutColumn *pColumn = GetColumn( j );
793 nColsMin += pColumn->GetMin();
794 nColsMax += pColumn->GetMax();
797 if( nColsMin<nConstrMin )
799 // Proportionately distribute the minimum value to the columns
800 sal_uLong nMinD = nConstrMin-nColsMin;
802 if( nConstrMin > nColsMax )
804 // Proportional according to the minimum widths
805 sal_uInt16 nEndCol = nCol+nColSpan;
806 sal_uLong nDiff = nMinD;
807 for( sal_uInt16 ic=nCol; ic<nEndCol; ic++ )
809 SwHTMLTableLayoutColumn *pColumn = GetColumn( ic );
811 sal_uLong nColMin = pColumn->GetMin();
812 sal_uLong nColMax = pColumn->GetMax();
814 nMin -= nColMin;
815 sal_uLong nAdd = ic<nEndCol-1 ? (nColMin * nMinD) / nColsMin
816 : nDiff;
817 nColMin += nAdd;
818 nMin += nColMin;
819 OSL_ENSURE( nDiff >= nAdd, "Ooops: nDiff is not correct anymore" );
820 nDiff -= nAdd;
822 if( nColMax < nColMin )
824 nMax -= nColMax;
825 nColsMax -= nColMax;
826 nColMax = nColMin;
827 nMax += nColMax;
828 nColsMax += nColMax;
831 pColumn->SetMinMax( nColMin, nColMax );
834 else
836 // Proportional according to the difference of max and min
837 for( sal_uInt16 ic=nCol; ic<nCol+nColSpan; ic++ )
839 SwHTMLTableLayoutColumn *pColumn = GetColumn( ic );
841 sal_uLong nDiff = pColumn->GetMax()-pColumn->GetMin();
842 if( nMinD < nDiff )
843 nDiff = nMinD;
845 pColumn->AddToMin( nDiff );
847 OSL_ENSURE( pColumn->GetMax() >= pColumn->GetMin(),
848 "Why is the Column suddenly too narrow?" );
850 nMin += nDiff;
851 nMinD -= nDiff;
856 if( !HasColTags() && nColsMax<nConstrMax )
858 sal_uLong nMaxD = nConstrMax-nColsMax;
860 for( sal_uInt16 ic=nCol; ic<nCol+nColSpan; ic++ )
862 SwHTMLTableLayoutColumn *pColumn = GetColumn( ic );
864 nMax -= pColumn->GetMax();
866 pColumn->AddToMax( (pColumn->GetMax() * nMaxD) / nColsMax );
868 nMax += pColumn->GetMax();
872 pConstr = pConstr->GetNext();
876 if( bFixRelWidths )
878 if( HasColTags() )
880 // To adapt the relative widths, in a first step we multiply the
881 // minimum width of all affected cells with the relative width
882 // of the column.
883 // Thus, the width ratio among the columns is correct.
885 // Furthermore, a factor is calculated that says by how much the
886 // cell has gotten wider than the minimum width.
888 // In the second step the calculated widths are divided by this
889 // factor. Thereby a cell's width is preserved and serves as a
890 // basis for the other cells.
891 // We only change the maximum widths here!
893 sal_uLong nAbsMin = 0; // absolute minimum width of all widths with relative width
894 sal_uLong nRel = 0; // sum of all relative widths of all columns
895 for( i=0; i<nCols; i++ )
897 SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
898 if( pColumn->IsRelWidthOption() && pColumn->GetWidthOption() )
900 nAbsMin += pColumn->GetMin();
901 nRel += pColumn->GetWidthOption();
905 sal_uLong nQuot = ULONG_MAX;
906 for( i=0; i<nCols; i++ )
908 SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
909 if( pColumn->IsRelWidthOption() )
911 nMax -= pColumn->GetMax();
912 if( pColumn->GetWidthOption() && pColumn->GetMin() )
914 pColumn->SetMax( nAbsMin * pColumn->GetWidthOption() );
915 sal_uLong nColQuot = pColumn->GetMax() / pColumn->GetMin();
916 if( nColQuot<nQuot )
917 nQuot = nColQuot;
921 OSL_ENSURE( 0==nRel || nQuot!=ULONG_MAX,
922 "Where did the relative columns go?" );
923 for( i=0; i<nCols; i++ )
925 SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
926 if( pColumn->IsRelWidthOption() )
928 if( pColumn->GetWidthOption() )
929 pColumn->SetMax( pColumn->GetMax() / nQuot );
930 else
931 pColumn->SetMax( pColumn->GetMin() );
932 OSL_ENSURE( pColumn->GetMax() >= pColumn->GetMin(),
933 "Maximum column width is lower than the minimum column width" );
934 nMax += pColumn->GetMax();
938 else
940 sal_uInt16 nRel = 0; // sum of the relative widths of all columns
941 sal_uInt16 nRelCols = 0; // count of the columns with a relative setting
942 sal_uLong nRelMax = 0; // fraction of the maximum of this column
943 for( i=0; i<nCols; i++ )
945 OSL_ENSURE( nRel<=100, "relative width of all columns > 100%" );
946 SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
947 if( pColumn->IsRelWidthOption() && pColumn->GetWidthOption() )
949 // Make sure that the relative widths don't go above 100%
950 sal_uInt16 nColWidth = pColumn->GetWidthOption();
951 if( nRel+nColWidth > 100 )
953 nColWidth = 100 - nRel;
954 pColumn->SetWidthOption( nColWidth, true, false );
956 nRelMax += pColumn->GetMax();
957 nRel = nRel + nColWidth;
958 nRelCols++;
960 else if( !pColumn->GetMin() )
962 // The column is empty (so it was solely created by
963 // COLSPAN) and therefore must not be assigned a % width.
964 nRelCols++;
968 // If there are percentages left we distribute them to the columns
969 // that don't have a width setting. Like in Netscape we distribute
970 // the remaining percentages according to the ratio of the maximum
971 // width of the affected columns.
972 // For the maximum widths we also take the fixed-width columns
973 // into account. Is that correct?
974 if( nRel < 100 && nRelCols < nCols )
976 sal_uInt16 nRelLeft = 100 - nRel;
977 sal_uLong nFixMax = nMax - nRelMax;
978 for( i=0; i<nCols; i++ )
980 SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
981 if( !pColumn->IsRelWidthOption() &&
982 !pColumn->GetWidthOption() &&
983 pColumn->GetMin() )
985 // the next column gets the rest
986 sal_uInt16 nColWidth =
987 (sal_uInt16)((pColumn->GetMax() * nRelLeft) / nFixMax);
988 pColumn->SetWidthOption( nColWidth, true, false );
993 // adjust the maximum widths now accordingly
994 sal_uLong nQuotMax = ULONG_MAX;
995 sal_uLong nOldMax = nMax;
996 nMax = 0;
997 for( i=0; i<nCols; i++ )
999 // Columns with a % setting are adapted accordingly.
1000 // Columns, that
1001 // - do not have a % setting and are located within a tables
1002 // with COLS and WIDTH, or
1003 // - their width is 0%
1004 // get set to the minimum width.
1005 SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
1006 if( pColumn->IsRelWidthOption() && pColumn->GetWidthOption() )
1008 sal_uLong nNewMax;
1009 sal_uLong nColQuotMax;
1010 if( !nWidthOption )
1012 nNewMax = nOldMax * pColumn->GetWidthOption();
1013 nColQuotMax = nNewMax / pColumn->GetMax();
1015 else
1017 nNewMax = nMin * pColumn->GetWidthOption();
1018 nColQuotMax = nNewMax / pColumn->GetMin();
1020 pColumn->SetMax( nNewMax );
1021 if( nColQuotMax < nQuotMax )
1022 nQuotMax = nColQuotMax;
1024 else if( HasColsOption() || nWidthOption ||
1025 (pColumn->IsRelWidthOption() &&
1026 !pColumn->GetWidthOption()) )
1027 pColumn->SetMax( pColumn->GetMin() );
1029 // and divide by the quotient
1030 OSL_ENSURE( nQuotMax!=ULONG_MAX, "Where did the relative columns go?" );
1031 for( i=0; i<nCols; i++ )
1033 SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
1034 if( pColumn->IsRelWidthOption() && pColumn->GetWidthOption() )
1036 if( pColumn->GetWidthOption() )
1038 pColumn->SetMax( pColumn->GetMax() / nQuotMax );
1039 OSL_ENSURE( pColumn->GetMax() >= pColumn->GetMin(),
1040 "Minimum width is one column bigger than maximum" );
1041 if( pColumn->GetMax() < pColumn->GetMin() )
1042 pColumn->SetMax( pColumn->GetMin() );
1045 nMax += pColumn->GetMax();
1050 delete pConstraints;
1053 // nAbsAvail is the available space in TWIPS.
1054 // nRelAvail is the available space related to USHRT_MAX or 0
1055 // nAbsSpace is the fraction of nAbsAvail, which is reserved by the surrounding
1056 // cell for the border and the distance to the paragraph.
1057 void SwHTMLTableLayout::AutoLayoutPass2( sal_uInt16 nAbsAvail, sal_uInt16 nRelAvail,
1058 sal_uInt16 nAbsLeftSpace,
1059 sal_uInt16 nAbsRightSpace,
1060 sal_uInt16 nParentInhAbsSpace )
1062 // For a start we do a lot of plausability tests
1064 // An absolute width always has to be passed
1065 OSL_ENSURE( nAbsAvail, "AutoLayout pass 2: No absolute width given" );
1067 // A relative width must only be passed for tables within tables (?)
1068 OSL_ENSURE( IsTopTable() == (nRelAvail==0),
1069 "AutoLayout pass 2: Relative width at table in table or the other way around" );
1071 // The table's minimum width must not be bigger than it's maximum width
1072 OSL_ENSURE( nMin<=nMax, "AutoLayout pass 2: nMin > nMax" );
1074 // Remember the available width for which the table was calculated.
1075 // This is a good place as we pass by here for the initial calculation
1076 // of the table in the parser and for each _Resize call.
1077 nLastResizeAbsAvail = nAbsAvail;
1079 // Step 1: The available space is readjusted for the left/right border,
1080 // possibly existing filler cells and distances.
1082 // Distance to the content and border
1083 sal_uInt16 nAbsLeftFill = 0, nAbsRightFill = 0;
1084 if( !IsTopTable() &&
1085 GetMin() + nAbsLeftSpace + nAbsRightSpace <= nAbsAvail )
1087 nAbsLeftFill = nAbsLeftSpace;
1088 nAbsRightFill = nAbsRightSpace;
1091 // Left and right distance
1092 if( nLeftMargin || nRightMargin )
1094 if( IsTopTable() )
1096 // For the top table we always respect the borders, because we
1097 // never go below the table's minimum width.
1098 nAbsAvail -= (nLeftMargin + nRightMargin);
1100 else if( GetMin() + nLeftMargin + nRightMargin <= nAbsAvail )
1102 // Else, we only respect the borders if there's space available
1103 // for them (nMin has already been calculated!)
1104 nAbsLeftFill = nAbsLeftFill + nLeftMargin;
1105 nAbsRightFill = nAbsRightFill + nRightMargin;
1109 // Filler cells
1110 if( !IsTopTable() )
1112 if( pLeftFillerBox && nAbsLeftFill<MINLAY+nInhLeftBorderWidth )
1113 nAbsLeftFill = MINLAY+nInhLeftBorderWidth;
1114 if( pRightFillerBox && nAbsRightFill<MINLAY+nInhRightBorderWidth )
1115 nAbsRightFill = MINLAY+nInhRightBorderWidth;
1118 // Read just the available space
1119 nRelLeftFill = 0;
1120 nRelRightFill = 0;
1121 if( !IsTopTable() && (nAbsLeftFill>0 || nAbsRightFill) )
1123 sal_uLong nAbsLeftFillL = nAbsLeftFill, nAbsRightFillL = nAbsRightFill;
1125 nRelLeftFill = (sal_uInt16)((nAbsLeftFillL * nRelAvail) / nAbsAvail);
1126 nRelRightFill = (sal_uInt16)((nAbsRightFillL * nRelAvail) / nAbsAvail);
1128 nAbsAvail -= (nAbsLeftFill + nAbsRightFill);
1129 if( nRelAvail )
1130 nRelAvail -= (nRelLeftFill + nRelRightFill);
1134 // Step 2: Calculate the absolute table width.
1135 sal_uInt16 nAbsTabWidth = 0;
1136 bUseRelWidth = false;
1137 if( nWidthOption )
1139 if( bPrcWidthOption )
1141 OSL_ENSURE( nWidthOption<=100, "Percentage value too high" );
1142 if( nWidthOption > 100 )
1143 nWidthOption = 100;
1145 // The absolute width is equal to the given percentage of
1146 // the available width.
1147 // Top tables only get a relative width if the available space
1148 // is *strictly larger* than the minimum width.
1150 // CAUTION: We need the "strictly larger" because changing from a
1151 // relative width to an absolute width by resizing would lead
1152 // to an infinite loop.
1154 // Because we do not call resize for tables in frames if the
1155 // frame has a non-relative width, we cannot play such games.
1157 // Let's play such games now anyway. We had a graphic in a 1% wide
1158 // table and it didn't fit in of course.
1159 nAbsTabWidth = (sal_uInt16)( ((sal_uLong)nAbsAvail * nWidthOption) / 100 );
1160 if( IsTopTable() &&
1161 ( /*MayBeInFlyFrame() ||*/ (sal_uLong)nAbsTabWidth > nMin ) )
1163 nRelAvail = USHRT_MAX;
1164 bUseRelWidth = true;
1167 else
1169 nAbsTabWidth = nWidthOption;
1170 if( nAbsTabWidth > MAX_TABWIDTH )
1171 nAbsTabWidth = MAX_TABWIDTH;
1173 // Tables within tables must never get wider than the available
1174 // space.
1175 if( !IsTopTable() && nAbsTabWidth > nAbsAvail )
1176 nAbsTabWidth = nAbsAvail;
1180 OSL_ENSURE( IsTopTable() || nAbsTabWidth<=nAbsAvail,
1181 "AutoLayout pass 2: nAbsTabWidth > nAbsAvail for table in table" );
1182 OSL_ENSURE( !nRelAvail || nAbsTabWidth<=nAbsAvail,
1183 "AutoLayout pass 2: nAbsTabWidth > nAbsAvail for relative width" );
1185 // Catch for the two asserts above (we never know!)
1186 if( (!IsTopTable() || nRelAvail>0) && nAbsTabWidth>nAbsAvail )
1187 nAbsTabWidth = nAbsAvail;
1190 // Step 3: Identify the column width and, if applicable, the absolute
1191 // and relative table widths.
1192 if( (!IsTopTable() && nMin > (sal_uLong)nAbsAvail) ||
1193 nMin > MAX_TABWIDTH )
1195 // If
1196 // - a inner table's minimum is larger than the available space, or
1197 // - a top table's minimum is larger than USHORT_MAX the table
1198 // has to be adapted to the available space or USHORT_MAX.
1199 // We preserve the widths' ratio amongst themselves, however.
1201 nAbsTabWidth = IsTopTable() ? MAX_TABWIDTH : nAbsAvail;
1202 nRelTabWidth = (nRelAvail ? nRelAvail : nAbsTabWidth );
1204 // First of all, we check whether we can fit the layout constrains,
1205 // which are: Every cell's width excluding the borders must be at least
1206 // MINLAY:
1208 sal_uLong nRealMin = 0;
1209 for( sal_uInt16 i=0; i<nCols; i++ )
1211 sal_uLong nRealColMin = MINLAY, nDummy1, nDummy2;
1212 AddBorderWidth( nRealColMin, nDummy1, nDummy2, i, 1 );
1213 nRealMin += nRealColMin;
1215 if( (nRealMin >= nAbsTabWidth) || (nRealMin >= nMin) )
1217 // "Rien ne va plus": we cannot get the minimum column widths
1218 // the layout wants to have.
1220 sal_uInt16 nAbs = 0, nRel = 0;
1221 SwHTMLTableLayoutColumn *pColumn;
1222 for( sal_uInt16 i=0; i<nCols-1; i++ )
1224 pColumn = GetColumn( i );
1225 sal_uLong nColMin = pColumn->GetMin();
1226 if( nColMin <= USHRT_MAX )
1228 pColumn->SetAbsColWidth(
1229 (sal_uInt16)((nColMin * nAbsTabWidth) / nMin) );
1230 pColumn->SetRelColWidth(
1231 (sal_uInt16)((nColMin * nRelTabWidth) / nMin) );
1233 else
1235 double nColMinD = nColMin;
1236 pColumn->SetAbsColWidth(
1237 (sal_uInt16)((nColMinD * nAbsTabWidth) / nMin) );
1238 pColumn->SetRelColWidth(
1239 (sal_uInt16)((nColMinD * nRelTabWidth) / nMin) );
1242 nAbs = nAbs + (sal_uInt16)pColumn->GetAbsColWidth();
1243 nRel = nRel + (sal_uInt16)pColumn->GetRelColWidth();
1245 pColumn = GetColumn( nCols-1 );
1246 pColumn->SetAbsColWidth( nAbsTabWidth - nAbs );
1247 pColumn->SetRelColWidth( nRelTabWidth - nRel );
1249 else
1251 sal_uLong nDistAbs = nAbsTabWidth - nRealMin;
1252 sal_uLong nDistRel = nRelTabWidth - nRealMin;
1253 sal_uLong nDistMin = nMin - nRealMin;
1254 sal_uInt16 nAbs = 0, nRel = 0;
1255 SwHTMLTableLayoutColumn *pColumn;
1256 for( sal_uInt16 i=0; i<nCols-1; i++ )
1258 pColumn = GetColumn( i );
1259 sal_uLong nColMin = pColumn->GetMin();
1260 sal_uLong nRealColMin = MINLAY, nDummy1, nDummy2;
1261 AddBorderWidth( nRealColMin, nDummy1, nDummy2, i, 1 );
1263 if( nColMin <= USHRT_MAX )
1265 pColumn->SetAbsColWidth(
1266 (sal_uInt16)((((nColMin-nRealColMin) * nDistAbs) / nDistMin) + nRealColMin) );
1267 pColumn->SetRelColWidth(
1268 (sal_uInt16)((((nColMin-nRealColMin) * nDistRel) / nDistMin) + nRealColMin) );
1270 else
1272 double nColMinD = nColMin;
1273 pColumn->SetAbsColWidth(
1274 (sal_uInt16)((((nColMinD-nRealColMin) * nDistAbs) / nDistMin) + nRealColMin) );
1275 pColumn->SetRelColWidth(
1276 (sal_uInt16)((((nColMinD-nRealColMin) * nDistRel) / nDistMin) + nRealColMin) );
1279 nAbs = nAbs + (sal_uInt16)pColumn->GetAbsColWidth();
1280 nRel = nRel + (sal_uInt16)pColumn->GetRelColWidth();
1282 pColumn = GetColumn( nCols-1 );
1283 pColumn->SetAbsColWidth( nAbsTabWidth - nAbs );
1284 pColumn->SetRelColWidth( nRelTabWidth - nRel );
1287 else if( nMax <= (sal_uLong)(nAbsTabWidth ? nAbsTabWidth : nAbsAvail) )
1289 // If
1290 // - the table has a fixed width and the table's maximum is
1291 // smaller, or
1292 //- the maximum is smaller than the available space,
1293 // we can take over the maximum as it is. Respectively
1294 // the table can only be adapted to the fixed width by
1295 // respecting the maximum.
1297 // No fixed width, use the maximum.
1298 if( !nAbsTabWidth )
1299 nAbsTabWidth = (sal_uInt16)nMax;
1301 // A top table may also get wider then the available space.
1302 if( nAbsTabWidth > nAbsAvail )
1304 OSL_ENSURE( IsTopTable(),
1305 "Table in table should get wider than the surrounding cell." );
1306 nAbsAvail = nAbsTabWidth;
1309 // Only use the relative widths' fraction, that is used for the
1310 // absolute width.
1311 sal_uLong nAbsTabWidthL = nAbsTabWidth;
1312 nRelTabWidth =
1313 ( nRelAvail ? (sal_uInt16)((nAbsTabWidthL * nRelAvail) / nAbsAvail)
1314 : nAbsTabWidth );
1316 // Are there columns width a percentage setting and some without one?
1317 sal_uLong nFixMax = nMax;
1318 for( sal_uInt16 i=0; i<nCols; i++ )
1320 const SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
1321 if( pColumn->IsRelWidthOption() && pColumn->GetWidthOption()>0 )
1322 nFixMax -= pColumn->GetMax();
1325 if( nFixMax > 0 && nFixMax < nMax )
1327 // Yes, distribute the to-be-distributed space only to the
1328 // columns with a percentage setting.
1330 // In this case (and in this case only) there are columns
1331 // that exactly keep their maximum width, that is they neither
1332 // get smaller nor wider. When calculating the absolute width
1333 // from the relative width we can get rounding errors.
1334 // To correct this, we first make the fixed widths compensate for
1335 // this error. We then fix the relative widths the same way.
1337 sal_uInt16 nAbs = 0, nRel = 0;
1338 sal_uInt16 nFixedCols = 0;
1339 sal_uInt16 i;
1341 for( i = 0; i < nCols; i++ )
1343 SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
1344 if( !pColumn->IsRelWidthOption() || !pColumn->GetWidthOption() )
1346 // The column keeps it's width.
1347 nFixedCols++;
1348 sal_uLong nColMax = pColumn->GetMax();
1349 pColumn->SetAbsColWidth( (sal_uInt16)nColMax );
1351 sal_uLong nRelColWidth =
1352 (nColMax * nRelTabWidth) / nAbsTabWidth;
1353 sal_uLong nChkWidth =
1354 (nRelColWidth * nAbsTabWidth) / nRelTabWidth;
1355 if( nChkWidth < nColMax )
1356 nRelColWidth++;
1357 else if( nChkWidth > nColMax )
1358 nRelColWidth--;
1359 pColumn->SetRelColWidth( (sal_uInt16)nRelColWidth );
1361 nAbs = nAbs + (sal_uInt16)nColMax;
1362 nRel = nRel + (sal_uInt16)nRelColWidth;
1366 // The to-be-distributed percentage of the maximum, the
1367 // relative and absolute widths. Here, nFixMax corresponds
1368 // to nAbs, so that we could've called it nAbs.
1369 // The code is, however, more readable like that.
1370 OSL_ENSURE( nFixMax == nAbs, "Two loops, two sums?" );
1371 sal_uLong nDistMax = nMax - nFixMax;
1372 sal_uInt16 nDistAbsTabWidth = nAbsTabWidth - nAbs;
1373 sal_uInt16 nDistRelTabWidth = nRelTabWidth - nRel;
1375 for( i=0; i<nCols; i++ )
1377 SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
1378 if( pColumn->IsRelWidthOption() && pColumn->GetWidthOption() > 0 )
1380 // The column gets proportionately wider.
1381 nFixedCols++;
1382 if( nFixedCols == nCols )
1384 pColumn->SetAbsColWidth( nAbsTabWidth-nAbs );
1385 pColumn->SetRelColWidth( nRelTabWidth-nRel );
1387 else
1389 sal_uLong nColMax = pColumn->GetMax();
1390 pColumn->SetAbsColWidth(
1391 (sal_uInt16)((nColMax * nDistAbsTabWidth) / nDistMax) );
1392 pColumn->SetRelColWidth(
1393 (sal_uInt16)((nColMax * nDistRelTabWidth) / nDistMax) );
1395 nAbs = nAbs + pColumn->GetAbsColWidth();
1396 nRel = nRel + pColumn->GetRelColWidth();
1399 OSL_ENSURE( nCols==nFixedCols, "Missed a column!" );
1401 else
1403 // No. So distribute the space regularily among all columns.
1404 for( sal_uInt16 i=0; i<nCols; i++ )
1406 sal_uLong nColMax = GetColumn( i )->GetMax();
1407 GetColumn( i )->SetAbsColWidth(
1408 (sal_uInt16)((nColMax * nAbsTabWidth) / nMax) );
1409 GetColumn( i )->SetRelColWidth(
1410 (sal_uInt16)((nColMax * nRelTabWidth) / nMax) );
1414 else
1416 // Proportionately distribute the space that extends over the minimum
1417 // width among the columns.
1418 if( !nAbsTabWidth )
1419 nAbsTabWidth = nAbsAvail;
1420 if( nAbsTabWidth < nMin )
1421 nAbsTabWidth = (sal_uInt16)nMin;
1423 if( nAbsTabWidth > nAbsAvail )
1425 OSL_ENSURE( IsTopTable(),
1426 "A nested table should become wider than the available space." );
1427 nAbsAvail = nAbsTabWidth;
1430 sal_uLong nAbsTabWidthL = nAbsTabWidth;
1431 nRelTabWidth =
1432 ( nRelAvail ? (sal_uInt16)((nAbsTabWidthL * nRelAvail) / nAbsAvail)
1433 : nAbsTabWidth );
1434 double nW = nAbsTabWidth - nMin;
1435 double nD = (nMax==nMin ? 1 : nMax-nMin);
1436 sal_uInt16 nAbs = 0, nRel = 0;
1437 for( sal_uInt16 i=0; i<nCols-1; i++ )
1439 double nd = GetColumn( i )->GetMax() - GetColumn( i )->GetMin();
1440 sal_uLong nAbsColWidth = GetColumn( i )->GetMin() + (sal_uLong)((nd*nW)/nD);
1441 sal_uLong nRelColWidth = nRelAvail
1442 ? (nAbsColWidth * nRelTabWidth) / nAbsTabWidth
1443 : nAbsColWidth;
1445 GetColumn( i )->SetAbsColWidth( (sal_uInt16)nAbsColWidth );
1446 GetColumn( i )->SetRelColWidth( (sal_uInt16)nRelColWidth );
1447 nAbs = nAbs + (sal_uInt16)nAbsColWidth;
1448 nRel = nRel + (sal_uInt16)nRelColWidth;
1450 GetColumn( nCols-1 )->SetAbsColWidth( nAbsTabWidth - nAbs );
1451 GetColumn( nCols-1 )->SetRelColWidth( nRelTabWidth - nRel );
1455 // Step 4: For nested tables we can have balancing cells on the
1456 // left or right. Here we calculate their width.
1457 nInhAbsLeftSpace = 0;
1458 nInhAbsRightSpace = 0;
1459 if( !IsTopTable() && (nRelLeftFill>0 || nRelRightFill>0 ||
1460 nAbsTabWidth<nAbsAvail) )
1462 // Calculate the width of additional cells we use for
1463 // aligning inner tables.
1464 sal_uInt16 nAbsDist = (sal_uInt16)(nAbsAvail-nAbsTabWidth);
1465 sal_uInt16 nRelDist = (sal_uInt16)(nRelAvail-nRelTabWidth);
1466 sal_uInt16 nParentInhAbsLeftSpace = 0, nParentInhAbsRightSpace = 0;
1468 // Calculate the size and position of the additional cells.
1469 switch( eTableAdjust )
1471 case SVX_ADJUST_RIGHT:
1472 nAbsLeftFill = nAbsLeftFill + nAbsDist;
1473 nRelLeftFill = nRelLeftFill + nRelDist;
1474 nParentInhAbsLeftSpace = nParentInhAbsSpace;
1475 break;
1476 case SVX_ADJUST_CENTER:
1478 sal_uInt16 nAbsLeftDist = nAbsDist / 2;
1479 nAbsLeftFill = nAbsLeftFill + nAbsLeftDist;
1480 nAbsRightFill += nAbsDist - nAbsLeftDist;
1481 sal_uInt16 nRelLeftDist = nRelDist / 2;
1482 nRelLeftFill = nRelLeftFill + nRelLeftDist;
1483 nRelRightFill += nRelDist - nRelLeftDist;
1484 nParentInhAbsLeftSpace = nParentInhAbsSpace / 2;
1485 nParentInhAbsRightSpace = nParentInhAbsSpace -
1486 nParentInhAbsLeftSpace;
1488 break;
1489 case SVX_ADJUST_LEFT:
1490 default:
1491 nAbsRightFill = nAbsRightFill + nAbsDist;
1492 nRelRightFill = nRelRightFill + nRelDist;
1493 nParentInhAbsRightSpace = nParentInhAbsSpace;
1494 break;
1497 OSL_ENSURE( !pLeftFillerBox || nRelLeftFill>0,
1498 "We don't have a width for the left filler box!" );
1499 OSL_ENSURE( !pRightFillerBox || nRelRightFill>0,
1500 "We don't have a width for the right filler box!" );
1502 // Filler widths are added to the outer columns, if there are no boxes
1503 // for them after the first pass (nWidth>0) or their width would become
1504 // too small or if there are COL tags and the filler width corresponds
1505 // to the border width.
1506 // In the last case we probably exported the table ourselves.
1507 if( nRelLeftFill && !pLeftFillerBox &&
1508 ( nWidthSet>0 || nAbsLeftFill<MINLAY+nInhLeftBorderWidth ||
1509 (HasColTags() && nAbsLeftFill < nAbsLeftSpace+nParentInhAbsLeftSpace+20) ) )
1511 SwHTMLTableLayoutColumn *pColumn = GetColumn( 0 );
1512 pColumn->SetAbsColWidth( pColumn->GetAbsColWidth()+nAbsLeftFill );
1513 pColumn->SetRelColWidth( pColumn->GetRelColWidth()+nRelLeftFill );
1514 nRelLeftFill = 0;
1515 nInhAbsLeftSpace = nAbsLeftSpace + nParentInhAbsLeftSpace;
1517 if( nRelRightFill && !pRightFillerBox &&
1518 ( nWidthSet>0 || nAbsRightFill<MINLAY+nInhRightBorderWidth ||
1519 (HasColTags() && nAbsRightFill < nAbsRightSpace+nParentInhAbsRightSpace+20) ) )
1521 SwHTMLTableLayoutColumn *pColumn = GetColumn( nCols-1 );
1522 pColumn->SetAbsColWidth( pColumn->GetAbsColWidth()+nAbsRightFill );
1523 pColumn->SetRelColWidth( pColumn->GetRelColWidth()+nRelRightFill );
1524 nRelRightFill = 0;
1525 nInhAbsRightSpace = nAbsRightSpace + nParentInhAbsRightSpace;
1530 static void lcl_ResizeLine( const SwTableLine* pLine, sal_uInt16 *pWidth );
1532 static void lcl_ResizeBox( const SwTableBox* pBox, sal_uInt16* pWidth )
1534 if( !pBox->GetSttNd() )
1536 sal_uInt16 nWidth = 0;
1537 BOOST_FOREACH( const SwTableLine *pLine, pBox->GetTabLines() )
1538 lcl_ResizeLine( pLine, &nWidth );
1539 pBox->GetFrmFmt()->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nWidth, 0 ));
1540 *pWidth = *pWidth + nWidth;
1542 else
1544 *pWidth = *pWidth + (sal_uInt16)pBox->GetFrmFmt()->GetFrmSize().GetSize().Width();
1548 static void lcl_ResizeLine( const SwTableLine* pLine, sal_uInt16 *pWidth )
1550 #if OSL_DEBUG_LEVEL > 0
1551 sal_uInt16 nOldWidth = *pWidth;
1552 #endif
1553 *pWidth = 0;
1554 BOOST_FOREACH( const SwTableBox* pBox, pLine->GetTabBoxes() )
1555 lcl_ResizeBox(pBox, pWidth );
1557 #if OSL_DEBUG_LEVEL > 0
1558 OSL_ENSURE( !nOldWidth || Abs(*pWidth-nOldWidth) < COLFUZZY,
1559 "A box's rows have all a different length." );
1560 #endif
1563 void SwHTMLTableLayout::SetWidths( sal_Bool bCallPass2, sal_uInt16 nAbsAvail,
1564 sal_uInt16 nRelAvail, sal_uInt16 nAbsLeftSpace,
1565 sal_uInt16 nAbsRightSpace,
1566 sal_uInt16 nParentInhAbsSpace )
1568 // SetWidth must have been passed through once more for every cell in the
1569 // end.
1570 nWidthSet++;
1572 // Step 0: If necessary, we call the layout algorithm of Pass2.
1573 if( bCallPass2 )
1574 AutoLayoutPass2( nAbsAvail, nRelAvail, nAbsLeftSpace, nAbsRightSpace,
1575 nParentInhAbsSpace );
1577 // Step 1: Set the new width in all content boxes.
1578 // Because the boxes don't know anything about the HTML table structure,
1579 // we iterate over the HTML table structure.
1580 // For tables in tables in tables we call SetWidth recursively.
1581 for( sal_uInt16 i=0; i<nRows; i++ )
1583 for( sal_uInt16 j=0; j<nCols; j++ )
1585 SwHTMLTableLayoutCell *pCell = GetCell( i, j );
1587 SwHTMLTableLayoutCnts* pCntnts = pCell->GetContents();
1588 while( pCntnts && !pCntnts->IsWidthSet(nWidthSet) )
1590 SwTableBox *pBox = pCntnts->GetTableBox();
1591 if( pBox )
1593 SetBoxWidth( pBox, j, pCell->GetColSpan() );
1595 else
1597 sal_uInt16 nAbs = 0, nRel = 0, nLSpace = 0, nRSpace = 0,
1598 nInhSpace = 0;
1599 if( bCallPass2 )
1601 sal_uInt16 nColSpan = pCell->GetColSpan();
1602 GetAvail( j, nColSpan, nAbs, nRel );
1603 nLSpace = GetLeftCellSpace( j, nColSpan );
1604 nRSpace = GetRightCellSpace( j, nColSpan );
1605 nInhSpace = GetInhCellSpace( j, nColSpan );
1607 pCntnts->GetTable()->SetWidths( bCallPass2, nAbs, nRel,
1608 nLSpace, nRSpace,
1609 nInhSpace );
1612 pCntnts->SetWidthSet( nWidthSet );
1613 pCntnts = pCntnts->GetNext();
1618 // Step 2: If we have a top table, we adapt the formats of the
1619 // non-content-boxes. Because they are not known in the HTML table
1620 // due to garbage collection there, we need the iterate over the
1621 // whole table.
1622 // We also adapt the table frame format. For nested tables we set the
1623 // filler cell's width instead.
1624 if( IsTopTable() )
1626 sal_uInt16 nCalcTabWidth = 0;
1627 BOOST_FOREACH( const SwTableLine *pLine, pSwTable->GetTabLines() )
1628 lcl_ResizeLine( pLine, &nCalcTabWidth );
1629 OSL_ENSURE( Abs( nRelTabWidth-nCalcTabWidth ) < COLFUZZY,
1630 "Table width is not equal to the row width." );
1632 // Lock the table format when altering it, or else the box formats
1633 // are altered again.
1634 // Also, we need to preserve a percent setting if it exists.
1635 SwFrmFmt *pFrmFmt = pSwTable->GetFrmFmt();
1636 ((SwTable *)pSwTable)->LockModify();
1637 SwFmtFrmSize aFrmSize( pFrmFmt->GetFrmSize() );
1638 aFrmSize.SetWidth( nRelTabWidth );
1639 bool bRel = bUseRelWidth &&
1640 text::HoriOrientation::FULL!=pFrmFmt->GetHoriOrient().GetHoriOrient();
1641 aFrmSize.SetWidthPercent( (sal_uInt8)(bRel ? nWidthOption : 0) );
1642 pFrmFmt->SetFmtAttr( aFrmSize );
1643 ((SwTable *)pSwTable)->UnlockModify();
1645 // If the table is located in a frame, we also need to adapt the
1646 // frame's width.
1647 if( MayBeInFlyFrame() )
1649 SwFrmFmt *pFlyFrmFmt = FindFlyFrmFmt();
1650 if( pFlyFrmFmt )
1652 SwFmtFrmSize aFlyFrmSize( ATT_VAR_SIZE, nRelTabWidth, MINLAY );
1654 if( bUseRelWidth )
1656 // For percentage settings we set the width to the minimum.
1657 aFlyFrmSize.SetWidth( nMin > USHRT_MAX ? USHRT_MAX
1658 : nMin );
1659 aFlyFrmSize.SetWidthPercent( (sal_uInt8)nWidthOption );
1661 pFlyFrmFmt->SetFmtAttr( aFlyFrmSize );
1665 #ifdef DBG_UTIL
1667 // is located in tblrwcl.cxx
1668 extern void _CheckBoxWidth( const SwTableLine&, SwTwips );
1670 // check if the tables have correct widths
1671 SwTwips nSize = pSwTable->GetFrmFmt()->GetFrmSize().GetWidth();
1672 const SwTableLines& rLines = pSwTable->GetTabLines();
1673 for (size_t n = 0; n < rLines.size(); ++n)
1675 _CheckBoxWidth( *rLines[ n ], nSize );
1678 #endif
1681 else
1683 if( pLeftFillerBox )
1685 pLeftFillerBox->GetFrmFmt()->SetFmtAttr(
1686 SwFmtFrmSize( ATT_VAR_SIZE, nRelLeftFill, 0 ));
1688 if( pRightFillerBox )
1690 pRightFillerBox->GetFrmFmt()->SetFmtAttr(
1691 SwFmtFrmSize( ATT_VAR_SIZE, nRelRightFill, 0 ));
1696 void SwHTMLTableLayout::_Resize( sal_uInt16 nAbsAvail, sal_Bool bRecalc )
1698 // If bRecalc is set, the table's content changed.
1699 // We need to execute pass 1 again.
1700 if( bRecalc )
1701 AutoLayoutPass1();
1703 SwRootFrm *pRoot = (SwRootFrm*)GetDoc()->GetCurrentViewShell()->GetLayout();
1704 if ( pRoot && pRoot->IsCallbackActionEnabled() )
1705 pRoot->StartAllAction(); //swmod 071108//swmod 071225
1707 // Else we can set the widths, in which we have to run Pass 2 in each case.
1708 SetWidths( sal_True, nAbsAvail );
1710 if ( pRoot && pRoot->IsCallbackActionEnabled() )
1711 pRoot->EndAllAction( sal_True ); //True per VirDev (browsing is calmer) //swmod 071108//swmod 071225
1714 IMPL_STATIC_LINK( SwHTMLTableLayout, DelayedResize_Impl, void*, EMPTYARG )
1716 pThis->aResizeTimer.Stop();
1717 pThis->_Resize( pThis->nDelayedResizeAbsAvail,
1718 pThis->bDelayedResizeRecalc );
1720 return 0;
1724 sal_Bool SwHTMLTableLayout::Resize( sal_uInt16 nAbsAvail, sal_Bool bRecalc,
1725 sal_Bool bForce, sal_uLong nDelay )
1727 if( 0 == nAbsAvail )
1728 return sal_False;
1729 OSL_ENSURE( IsTopTable(), "Resize must only be called for top tables!" );
1731 // May the table be resized at all? Or is it forced?
1732 if( bMustNotResize && !bForce )
1733 return sal_False;
1735 // May the table be recalculated? Or is it forced?
1736 if( bMustNotRecalc && !bForce )
1737 bRecalc = sal_False;
1739 const SwDoc *pDoc = GetDoc();
1741 // If there is a layout, the root frame's size instead of the
1742 // VisArea's size was potentially passed.
1743 // If we're not in a frame we need to calculate the table for the VisArea,
1744 // because switching from relative to absolute wouldn't work.
1745 if( pDoc->GetCurrentViewShell() && pDoc->GetCurrentViewShell()->GetViewOptions()->getBrowseMode() )
1747 const sal_uInt16 nVisAreaWidth = GetBrowseWidthByVisArea( *pDoc );
1748 if( nVisAreaWidth < nAbsAvail && !FindFlyFrmFmt() )
1749 nAbsAvail = nVisAreaWidth;
1752 if( nDelay==0 && aResizeTimer.IsActive() )
1754 // If there is an asynchronous resize left to process when we call
1755 // a synchronous resize, we only take over the new values.
1756 bRecalc |= bDelayedResizeRecalc;
1757 nDelayedResizeAbsAvail = nAbsAvail;
1758 return sal_False;
1761 // Optimisation:
1762 // If the minimums or maximums should not be recalculated and
1763 // - the table's width never needs to be recalculated, or
1764 // - the table was already calculated for the passed width, or
1765 // - the available space is less or equal to the minimum width
1766 // and the table already has the minimum width, or
1767 // - the available space is larger than the maximum width and
1768 // the table already has the maximum width
1769 // nothing will happen to the table.
1770 if( !bRecalc && ( !bMustResize ||
1771 (nLastResizeAbsAvail==nAbsAvail) ||
1772 (nAbsAvail<=nMin && nRelTabWidth==nMin) ||
1773 (!bPrcWidthOption && nAbsAvail>=nMax && nRelTabWidth==nMax) ) )
1774 return sal_False;
1776 if( nDelay==HTMLTABLE_RESIZE_NOW )
1778 if( aResizeTimer.IsActive() )
1779 aResizeTimer.Stop();
1780 _Resize( nAbsAvail, bRecalc );
1782 else if( nDelay > 0 )
1784 nDelayedResizeAbsAvail = nAbsAvail;
1785 bDelayedResizeRecalc = bRecalc;
1786 aResizeTimer.SetTimeout( nDelay );
1787 aResizeTimer.Start();
1789 else
1791 _Resize( nAbsAvail, bRecalc );
1794 return sal_True;
1797 void SwHTMLTableLayout::BordersChanged( sal_uInt16 nAbsAvail, sal_Bool bRecalc )
1799 bBordersChanged = sal_True;
1801 Resize( nAbsAvail, bRecalc );
1805 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */