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