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: */
|