1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <config_wasm_strip.h>
22 #include <pagefrm.hxx>
23 #include <rootfrm.hxx>
24 #include <IDocumentFieldsAccess.hxx>
25 #include <IDocumentRedlineAccess.hxx>
26 #include <viewimp.hxx>
28 #include <swtable.hxx>
29 #include <deletelistener.hxx>
30 #include <dflyobj.hxx>
31 #include <anchoreddrawobject.hxx>
32 #include <fmtanchr.hxx>
33 #include <viewopt.hxx>
35 #include <dbg_lay.hxx>
37 #include <svl/itemiter.hxx>
38 #include <editeng/keepitem.hxx>
39 #include <editeng/ulspitem.hxx>
40 #include <editeng/brushitem.hxx>
41 #include <editeng/boxitem.hxx>
42 #include <basegfx/range/b1drange.hxx>
43 #include <fmtlsplt.hxx>
44 #include <fmtrowsplt.hxx>
45 #include <fmtsrnd.hxx>
46 #include <fmtornt.hxx>
47 #include <fmtpdsc.hxx>
48 #include <fmtfsize.hxx>
49 #include <swtblfmt.hxx>
52 #include <cellfrm.hxx>
53 #include <flyfrms.hxx>
56 #include <notxtfrm.hxx>
57 #include <htmltbl.hxx>
58 #include <sectfrm.hxx>
59 #include <fmtfollowtextflow.hxx>
60 #include <sortedobjs.hxx>
61 #include <objectformatter.hxx>
62 #include <layouter.hxx>
64 #include <DocumentSettingManager.hxx>
65 #include <sal/log.hxx>
66 #include <osl/diagnose.h>
68 #include <frmtool.hxx>
70 #include <frameformats.hxx>
72 using namespace ::com::sun::star
;
74 SwTabFrame::SwTabFrame( SwTable
&rTab
, SwFrame
* pSib
)
75 : SwLayoutFrame( rTab
.GetFrameFormat(), pSib
)
76 , SwFlowFrame( static_cast<SwFrame
&>(*this) )
79 , m_bCalcLowers(false)
80 , m_bLowersFormatted(false)
81 , m_bLockBackMove(false)
82 , m_bWantBackMove(false)
83 , m_bResizeHTMLTable(false)
84 , m_bONECalcLowers(false)
85 , m_bHasFollowFlowLine(false)
86 , m_bIsRebuildLastLine(false)
87 , m_bRestrictTableGrowth(false)
88 , m_bRemoveFollowFlowLinePending(false)
89 , m_bConsiderObjsForMinCellHeight(true)
90 , m_bObjsDoesFit(true)
91 , m_bInRecalcLowerRow(false)
93 mbFixSize
= false; //Don't fall for import filter again.
94 mnFrameType
= SwFrameType::Tab
;
96 //Create the lines and insert them.
97 const SwTableLines
&rLines
= rTab
.GetTabLines();
98 SwFrame
*pTmpPrev
= nullptr;
99 bool bHiddenRedlines
= getRootFrame()->IsHideRedlines() &&
100 !GetFormat()->GetDoc()->getIDocumentRedlineAccess().GetRedlineTable().empty();
101 SwRedlineTable::size_type nRedlinePos
= 0;
102 for ( size_t i
= 0; i
< rLines
.size(); ++i
)
104 // skip lines deleted with track changes
105 if ( bHiddenRedlines
&& rLines
[i
]->IsDeleted(nRedlinePos
) )
108 SwRowFrame
*pNew
= new SwRowFrame( *rLines
[i
], this );
111 pNew
->InsertBehind( this, pTmpPrev
);
115 SwFrame::DestroyFrame(pNew
);
117 OSL_ENSURE( Lower() && Lower()->IsRowFrame(), "SwTabFrame::SwTabFrame: No rows." );
120 SwTabFrame::SwTabFrame( SwTabFrame
&rTab
)
121 : SwLayoutFrame( rTab
.GetFormat(), &rTab
)
122 , SwFlowFrame( static_cast<SwFrame
&>(*this) )
123 , m_pTable( rTab
.GetTable() )
125 , m_bCalcLowers(false)
126 , m_bLowersFormatted(false)
127 , m_bLockBackMove(false)
128 , m_bWantBackMove(false)
129 , m_bResizeHTMLTable(false)
130 , m_bONECalcLowers(false)
131 , m_bHasFollowFlowLine(false)
132 , m_bIsRebuildLastLine(false)
133 , m_bRestrictTableGrowth(false)
134 , m_bRemoveFollowFlowLinePending(false)
135 , m_bConsiderObjsForMinCellHeight(true)
136 , m_bObjsDoesFit(true)
137 , m_bInRecalcLowerRow(false)
139 mbFixSize
= false; //Don't fall for import filter again.
140 mnFrameType
= SwFrameType::Tab
;
142 SetFollow( rTab
.GetFollow() );
143 rTab
.SetFollow( this );
146 void SwTabFrame::DestroyImpl()
148 // There is some terrible code in fetab.cxx, that
149 // caches pointers to SwTabFrames.
150 ::ClearFEShellTabCols(*GetFormat()->GetDoc(), this);
152 SwLayoutFrame::DestroyImpl();
155 SwTabFrame::~SwTabFrame()
159 void SwTabFrame::JoinAndDelFollows()
161 SwTabFrame
*pFoll
= GetFollow();
162 if ( pFoll
->HasFollow() )
163 pFoll
->JoinAndDelFollows();
165 SetFollow( pFoll
->GetFollow() );
166 SwFrame::DestroyFrame(pFoll
);
169 void SwTabFrame::RegistFlys()
171 OSL_ENSURE( Lower() && Lower()->IsRowFrame(), "No rows." );
173 SwPageFrame
*pPage
= FindPageFrame();
176 SwRowFrame
*pRow
= static_cast<SwRowFrame
*>(Lower());
179 pRow
->RegistFlys( pPage
);
180 pRow
= static_cast<SwRowFrame
*>(pRow
->GetNext());
185 static void SwInvalidateAll( SwFrame
*pFrame
, tools::Long nBottom
);
186 static void lcl_RecalcRow( SwRowFrame
& rRow
, tools::Long nBottom
);
187 static bool lcl_ArrangeLowers( SwLayoutFrame
*pLay
, tools::Long lYStart
, bool bInva
);
188 // #i26945# - add parameter <_bOnlyRowsAndCells> to control
189 // that only row and cell frames are formatted.
190 static bool lcl_InnerCalcLayout( SwFrame
*pFrame
,
192 bool _bOnlyRowsAndCells
= false );
193 // OD 2004-02-18 #106629# - correct type of 1st parameter
194 // #i26945# - add parameter <_bConsiderObjs> in order to
195 // control, if floating screen objects have to be considered for the minimal
197 static SwTwips
lcl_CalcMinRowHeight( const SwRowFrame
*pRow
,
198 const bool _bConsiderObjs
);
199 static SwTwips
lcl_CalcTopAndBottomMargin( const SwLayoutFrame
&, const SwBorderAttrs
& );
201 static SwTwips
lcl_calcHeightOfRowBeforeThisFrame(const SwRowFrame
& rRow
);
203 static SwTwips
lcl_GetHeightOfRows( const SwFrame
* pStart
, tools::Long nCount
)
205 if ( !nCount
|| !pStart
)
209 SwRectFnSet
aRectFnSet(pStart
);
210 while ( pStart
&& nCount
> 0 )
212 nRet
+= aRectFnSet
.GetHeight(pStart
->getFrameArea());
213 pStart
= pStart
->GetNext();
220 // Local helper function to insert a new follow flow line
221 static SwRowFrame
* lcl_InsertNewFollowFlowLine( SwTabFrame
& rTab
, const SwFrame
& rTmpRow
, bool bRowSpanLine
)
223 OSL_ENSURE( rTmpRow
.IsRowFrame(), "No row frame to copy for FollowFlowLine" );
224 const SwRowFrame
& rRow
= static_cast<const SwRowFrame
&>(rTmpRow
);
226 rTab
.SetFollowFlowLine( true );
227 SwRowFrame
*pFollowFlowLine
= new SwRowFrame(*rRow
.GetTabLine(), &rTab
, false );
228 pFollowFlowLine
->SetRowSpanLine( bRowSpanLine
);
229 SwFrame
* pFirstRow
= rTab
.GetFollow()->GetFirstNonHeadlineRow();
230 pFollowFlowLine
->InsertBefore( rTab
.GetFollow(), pFirstRow
);
231 return pFollowFlowLine
;
234 // #i26945# - local helper function to invalidate all lower
235 // objects. By parameter <_bMoveObjsOutOfRange> it can be controlled, if
236 // additionally the objects are moved 'out of range'.
237 static void lcl_InvalidateLowerObjs( SwLayoutFrame
& _rLayoutFrame
,
238 const bool _bMoveObjsOutOfRange
= false,
239 SwPageFrame
* _pPageFrame
= nullptr )
241 // determine page frame, if needed
244 _pPageFrame
= _rLayoutFrame
.FindPageFrame();
245 OSL_ENSURE( _pPageFrame
,
246 "<lcl_InvalidateLowerObjs(..)> - missing page frame -> no move of lower objects out of range" );
253 // loop on lower frames
254 SwFrame
* pLowerFrame
= _rLayoutFrame
.Lower();
255 while ( pLowerFrame
)
257 if ( pLowerFrame
->IsLayoutFrame() )
259 ::lcl_InvalidateLowerObjs( *static_cast<SwLayoutFrame
*>(pLowerFrame
),
260 _bMoveObjsOutOfRange
, _pPageFrame
);
262 if ( pLowerFrame
->GetDrawObjs() )
264 for (size_t i
= 0, nCount
= pLowerFrame
->GetDrawObjs()->size(); i
< nCount
; ++i
)
266 SwAnchoredObject
* pAnchoredObj
= (*pLowerFrame
->GetDrawObjs())[i
];
268 // invalidate position of anchored object
269 pAnchoredObj
->SetTmpConsiderWrapInfluence( false );
270 pAnchoredObj
->SetConsiderForTextWrap( false );
271 pAnchoredObj
->UnlockPosition();
272 pAnchoredObj
->InvalidateObjPos();
274 SwFlyFrame
*pFly
= pAnchoredObj
->DynCastFlyFrame();
276 // move anchored object 'out of range'
277 if ( _bMoveObjsOutOfRange
)
279 // indicate, that positioning is progress to avoid
280 // modification of the anchored object resp. it's attributes
281 // due to the movement
282 SwObjPositioningInProgress
aObjPosInProgress( *pAnchoredObj
);
283 pAnchoredObj
->SetObjLeft( _pPageFrame
->getFrameArea().Right() );
284 // #115759# - reset character rectangle,
285 // top of line and relative position in order to assure,
286 // that anchored object is correctly positioned.
287 pAnchoredObj
->ClearCharRectAndTopOfLine();
288 pAnchoredObj
->SetCurrRelPos( Point( 0, 0 ) );
289 if ( pAnchoredObj
->GetFrameFormat().GetAnchor().GetAnchorId()
290 == RndStdIds::FLY_AS_CHAR
)
292 pAnchoredObj
->AnchorFrame()
293 ->Prepare( PrepareHint::FlyFrameAttributesChanged
,
294 &(pAnchoredObj
->GetFrameFormat()) );
296 if ( pFly
!= nullptr )
298 pFly
->GetVirtDrawObj()->SetBoundAndSnapRectsDirty();
299 pFly
->GetVirtDrawObj()->SetChanged();
303 // If anchored object is a fly frame, invalidate its lower objects
304 if ( pFly
!= nullptr )
306 ::lcl_InvalidateLowerObjs( *pFly
, _bMoveObjsOutOfRange
, _pPageFrame
);
310 pLowerFrame
= pLowerFrame
->GetNext();
314 // Local helper function to shrink all lowers of pRow to 0 height
315 static void lcl_ShrinkCellsAndAllContent( SwRowFrame
& rRow
)
317 SwCellFrame
* pCurrMasterCell
= static_cast<SwCellFrame
*>(rRow
.Lower());
318 SwRectFnSet
aRectFnSet(pCurrMasterCell
);
320 bool bAllCellsCollapsed
= true;
321 while ( pCurrMasterCell
)
324 SwCellFrame
& rToAdjust
= pCurrMasterCell
->GetTabBox()->getRowSpan() < 1 ?
325 const_cast<SwCellFrame
&>(pCurrMasterCell
->FindStartEndOfRowSpanCell( true )) :
329 // all lowers should have the correct position
330 lcl_ArrangeLowers( &rToAdjust
,
331 aRectFnSet
.GetPrtTop(rToAdjust
),
333 // TODO: Optimize number of frames which are set to 0 height
334 // we have to start with the last lower frame, otherwise
335 // the shrink will not shrink the current cell
336 SwFrame
* pTmp
= rToAdjust
.GetLastLower();
337 bool bAllLowersCollapsed
= true;
339 if ( pTmp
&& pTmp
->IsRowFrame() )
341 SwRowFrame
* pTmpRow
= static_cast<SwRowFrame
*>(pTmp
);
342 lcl_ShrinkCellsAndAllContent( *pTmpRow
);
346 // TODO: Optimize number of frames which are set to 0 height
349 // the frames have to be shrunk
350 if ( pTmp
->IsTabFrame() )
352 SwRowFrame
* pTmpRow
= static_cast<SwRowFrame
*>(static_cast<SwTabFrame
*>(pTmp
)->Lower());
353 bool bAllRowsCollapsed
= true;
357 lcl_ShrinkCellsAndAllContent( *pTmpRow
);
359 if (aRectFnSet
.GetHeight(pTmpRow
->getFrameArea()) > 0)
360 bAllRowsCollapsed
= false;
362 pTmpRow
= static_cast<SwRowFrame
*>(pTmpRow
->GetNext());
365 if (bAllRowsCollapsed
)
367 // All rows of this table have 0 height -> set height of the table itself as well.
368 SwFrameAreaDefinition::FrameAreaWriteAccess
aFrm(*pTmp
);
369 aRectFnSet
.SetHeight(aFrm
, 0);
371 SwFrameAreaDefinition::FramePrintAreaWriteAccess
aPrt(*pTmp
);
372 aRectFnSet
.SetTop(aPrt
, 0);
373 aRectFnSet
.SetHeight(aPrt
, 0);
376 bAllLowersCollapsed
= false;
380 pTmp
->Shrink(aRectFnSet
.GetHeight(pTmp
->getFrameArea()));
381 SwFrameAreaDefinition::FramePrintAreaWriteAccess
aPrt(*pTmp
);
382 aRectFnSet
.SetTop(aPrt
, 0);
383 aRectFnSet
.SetHeight(aPrt
, 0);
385 if (aRectFnSet
.GetHeight(pTmp
->getFrameArea()) > 0)
387 bAllLowersCollapsed
= false;
391 pTmp
= pTmp
->GetPrev();
394 // all lowers should have the correct position
395 lcl_ArrangeLowers( &rToAdjust
,
396 aRectFnSet
.GetPrtTop(rToAdjust
),
400 if (bAllLowersCollapsed
)
402 // All lower frame of this cell have 0 height -> set height of the cell itself as well.
403 SwFrameAreaDefinition::FrameAreaWriteAccess
aFrm(*pCurrMasterCell
);
404 aRectFnSet
.SetHeight(aFrm
, 0);
406 SwFrameAreaDefinition::FramePrintAreaWriteAccess
aPrt(*pCurrMasterCell
);
407 aRectFnSet
.SetTop(aPrt
, 0);
408 aRectFnSet
.SetHeight(aPrt
, 0);
411 bAllCellsCollapsed
= false;
413 pCurrMasterCell
= static_cast<SwCellFrame
*>(pCurrMasterCell
->GetNext());
416 if (bAllCellsCollapsed
)
418 // All cells have 0 height -> set height of row as well.
419 SwFrameAreaDefinition::FrameAreaWriteAccess
aFrm(rRow
);
420 aRectFnSet
.SetHeight(aFrm
, 0);
422 SwFrameAreaDefinition::FramePrintAreaWriteAccess
aPrt(rRow
);
423 aRectFnSet
.SetTop(aPrt
, 0);
424 aRectFnSet
.SetHeight(aPrt
, 0);
428 // Local helper function to move the content from rSourceLine to rDestLine
429 // The content is inserted behind the last content in the corresponding
430 // cell in rDestLine.
431 static void lcl_MoveRowContent( SwRowFrame
& rSourceLine
, SwRowFrame
& rDestLine
)
433 SwCellFrame
* pCurrDestCell
= static_cast<SwCellFrame
*>(rDestLine
.Lower());
434 SwCellFrame
* pCurrSourceCell
= static_cast<SwCellFrame
*>(rSourceLine
.Lower());
436 // Move content of follow cells into master cells
437 while ( pCurrSourceCell
)
439 if ( pCurrSourceCell
->Lower() && pCurrSourceCell
->Lower()->IsRowFrame() )
441 SwRowFrame
* pTmpSourceRow
= static_cast<SwRowFrame
*>(pCurrSourceCell
->Lower());
442 while ( pTmpSourceRow
)
444 // #125926# Attention! It is possible,
445 // that pTmpSourceRow->IsFollowFlowRow() but pTmpDestRow
446 // cannot be found. In this case, we have to move the complete
448 SwRowFrame
* pTmpDestRow
= static_cast<SwRowFrame
*>(pCurrDestCell
->Lower());
450 if ( pTmpSourceRow
->IsFollowFlowRow() && pTmpDestRow
)
452 // move content from follow flow row to pTmpDestRow:
453 while ( pTmpDestRow
->GetNext() )
454 pTmpDestRow
= static_cast<SwRowFrame
*>(pTmpDestRow
->GetNext());
456 assert(pTmpDestRow
->GetFollowRow() == pTmpSourceRow
);
458 lcl_MoveRowContent( *pTmpSourceRow
, *pTmpDestRow
);
459 pTmpDestRow
->SetFollowRow( pTmpSourceRow
->GetFollowRow() );
460 pTmpSourceRow
->RemoveFromLayout();
461 SwFrame::DestroyFrame(pTmpSourceRow
);
465 // move complete row:
466 pTmpSourceRow
->RemoveFromLayout();
467 pTmpSourceRow
->InsertBefore( pCurrDestCell
, nullptr );
470 pTmpSourceRow
= static_cast<SwRowFrame
*>(pCurrSourceCell
->Lower());
475 SwFrame
*pTmp
= ::SaveContent( pCurrSourceCell
);
479 SwCellFrame
* pDestCell
= pCurrDestCell
;
480 if ( pDestCell
->GetTabBox()->getRowSpan() < 1 )
481 pDestCell
= & const_cast<SwCellFrame
&>(pDestCell
->FindStartEndOfRowSpanCell( true ));
484 SwFrame
* pFrame
= pDestCell
->GetLastLower();
485 ::RestoreContent( pTmp
, pDestCell
, pFrame
);
488 pCurrDestCell
= static_cast<SwCellFrame
*>(pCurrDestCell
->GetNext());
489 pCurrSourceCell
= static_cast<SwCellFrame
*>(pCurrSourceCell
->GetNext());
493 // Local helper function to move all footnotes in rRowFrame from
494 // the footnote boss of rSource to the footnote boss of rDest.
495 static void lcl_MoveFootnotes( SwTabFrame
& rSource
, SwTabFrame
& rDest
, SwLayoutFrame
& rRowFrame
)
497 if ( !rSource
.GetFormat()->GetDoc()->GetFootnoteIdxs().empty() )
499 SwFootnoteBossFrame
* pOldBoss
= rSource
.FindFootnoteBossFrame( true );
500 SwFootnoteBossFrame
* pNewBoss
= rDest
.FindFootnoteBossFrame( true );
501 rRowFrame
.MoveLowerFootnotes( nullptr, pOldBoss
, pNewBoss
, true );
505 // Local helper function to handle nested table cells before the split process
506 static void lcl_PreprocessRowsInCells( SwTabFrame
& rTab
, SwRowFrame
& rLastLine
,
507 SwRowFrame
& rFollowFlowLine
, SwTwips nRemain
)
509 SwCellFrame
* pCurrLastLineCell
= static_cast<SwCellFrame
*>(rLastLine
.Lower());
510 SwCellFrame
* pCurrFollowFlowLineCell
= static_cast<SwCellFrame
*>(rFollowFlowLine
.Lower());
512 SwRectFnSet
aRectFnSet(pCurrLastLineCell
);
514 // Move content of follow cells into master cells
515 while ( pCurrLastLineCell
)
517 if ( pCurrLastLineCell
->Lower() && pCurrLastLineCell
->Lower()->IsRowFrame() )
519 SwTwips nTmpCut
= nRemain
;
520 SwRowFrame
* pTmpLastLineRow
= static_cast<SwRowFrame
*>(pCurrLastLineCell
->Lower());
523 SwTwips nCurrentHeight
=
524 lcl_CalcMinRowHeight( pTmpLastLineRow
,
525 rTab
.IsConsiderObjsForMinCellHeight() );
526 while ( pTmpLastLineRow
->GetNext() && nTmpCut
> nCurrentHeight
)
528 nTmpCut
-= nCurrentHeight
;
529 pTmpLastLineRow
= static_cast<SwRowFrame
*>(pTmpLastLineRow
->GetNext());
532 lcl_CalcMinRowHeight( pTmpLastLineRow
,
533 rTab
.IsConsiderObjsForMinCellHeight() );
536 // pTmpLastLineRow does not fit to the line or it is the last line
537 // Check if we can move pTmpLastLineRow to the follow table,
538 // or if we have to split the line:
539 bool bTableLayoutTooComplex
= false;
540 tools::Long nMinHeight
= 0;
542 // We have to take into account:
543 // 1. The fixed height of the row
544 // 2. The borders of the cells inside the row
545 // 3. The minimum height of the row
546 if ( pTmpLastLineRow
->HasFixSize() )
547 nMinHeight
= aRectFnSet
.GetHeight(pTmpLastLineRow
->getFrameArea());
551 const SwFormatFrameSize
&rSz
= pTmpLastLineRow
->GetFormat()->GetFrameSize();
552 if ( rSz
.GetHeightSizeType() == SwFrameSize::Minimum
)
553 nMinHeight
= rSz
.GetHeight() - lcl_calcHeightOfRowBeforeThisFrame(*pTmpLastLineRow
);
556 SwFrame
* pCell
= pTmpLastLineRow
->Lower();
559 if ( static_cast<SwCellFrame
*>(pCell
)->Lower() &&
560 static_cast<SwCellFrame
*>(pCell
)->Lower()->IsRowFrame() )
562 bTableLayoutTooComplex
= true;
566 SwBorderAttrAccess
aAccess( SwFrame::GetCache(), pCell
);
567 const SwBorderAttrs
&rAttrs
= *aAccess
.Get();
568 nMinHeight
= std::max( nMinHeight
, tools::Long(lcl_CalcTopAndBottomMargin( *static_cast<SwLayoutFrame
*>(pCell
), rAttrs
)) );
569 pCell
= pCell
->GetNext();
574 // The line completely fits into the master table.
575 // Nevertheless, we build a follow (otherwise painting problems
579 // The line has to be split, the minimum height still fits into
580 // the master table, and the table structure is not too complex.
581 if ( nTmpCut
> nCurrentHeight
||
582 ( pTmpLastLineRow
->IsRowSplitAllowed() &&
583 !bTableLayoutTooComplex
&& nMinHeight
< nTmpCut
) )
585 // The line has to be split:
586 SwRowFrame
* pNewRow
= new SwRowFrame( *pTmpLastLineRow
->GetTabLine(), &rTab
, false );
587 pNewRow
->SetFollowFlowRow( true );
588 pNewRow
->SetFollowRow( pTmpLastLineRow
->GetFollowRow() );
589 pTmpLastLineRow
->SetFollowRow( pNewRow
);
590 pNewRow
->InsertBehind( pCurrFollowFlowLineCell
, nullptr );
591 pTmpLastLineRow
= static_cast<SwRowFrame
*>(pTmpLastLineRow
->GetNext());
594 // The following lines have to be moved:
595 while ( pTmpLastLineRow
)
597 SwRowFrame
* pTmp
= static_cast<SwRowFrame
*>(pTmpLastLineRow
->GetNext());
598 lcl_MoveFootnotes( rTab
, *rTab
.GetFollow(), *pTmpLastLineRow
);
599 pTmpLastLineRow
->RemoveFromLayout();
600 pTmpLastLineRow
->InsertBefore( pCurrFollowFlowLineCell
, nullptr );
601 pTmpLastLineRow
->Shrink( aRectFnSet
.GetHeight(pTmpLastLineRow
->getFrameArea()) );
602 pCurrFollowFlowLineCell
->Grow( aRectFnSet
.GetHeight(pTmpLastLineRow
->getFrameArea()) );
603 pTmpLastLineRow
= pTmp
;
607 pCurrLastLineCell
= static_cast<SwCellFrame
*>(pCurrLastLineCell
->GetNext());
608 pCurrFollowFlowLineCell
= static_cast<SwCellFrame
*>(pCurrFollowFlowLineCell
->GetNext());
612 // Local helper function to handle nested table cells after the split process
613 static void lcl_PostprocessRowsInCells( SwTabFrame
& rTab
, SwRowFrame
& rLastLine
)
615 SwCellFrame
* pCurrMasterCell
= static_cast<SwCellFrame
*>(rLastLine
.Lower());
616 while ( pCurrMasterCell
)
618 if ( pCurrMasterCell
->Lower() &&
619 pCurrMasterCell
->Lower()->IsRowFrame() )
621 SwRowFrame
* pRowFrame
= static_cast<SwRowFrame
*>(pCurrMasterCell
->GetLastLower());
623 if ( nullptr != pRowFrame
->GetPrev() && !pRowFrame
->ContainsContent() )
625 OSL_ENSURE( pRowFrame
->GetFollowRow(), "Deleting row frame without follow" );
627 // The footnotes have to be moved:
628 lcl_MoveFootnotes( rTab
, *rTab
.GetFollow(), *pRowFrame
);
630 SwRowFrame
* pFollowRow
= pRowFrame
->GetFollowRow();
631 pRowFrame
->Paste( pFollowRow
->GetUpper(), pFollowRow
);
632 pRowFrame
->SetFollowRow( pFollowRow
->GetFollowRow() );
633 lcl_MoveRowContent( *pFollowRow
, *pRowFrame
);
635 SwFrame::DestroyFrame(pFollowRow
);
636 ::SwInvalidateAll( pCurrMasterCell
, LONG_MAX
);
640 pCurrMasterCell
= static_cast<SwCellFrame
*>(pCurrMasterCell
->GetNext());
644 // Local helper function to re-calculate the split line.
645 inline void TableSplitRecalcLock( SwFlowFrame
*pTab
) { pTab
->LockJoin(); }
646 inline void TableSplitRecalcUnlock( SwFlowFrame
*pTab
) { pTab
->UnlockJoin(); }
648 static bool lcl_RecalcSplitLine( SwRowFrame
& rLastLine
, SwRowFrame
& rFollowLine
,
649 SwTwips nRemainingSpaceForLastRow
, SwTwips nAlreadyFree
,
650 bool & rIsFootnoteGrowth
)
654 vcl::RenderContext
* pRenderContext
= rLastLine
.getRootFrame()->GetCurrShell()->GetOut();
655 SwTabFrame
& rTab
= static_cast<SwTabFrame
&>(*rLastLine
.GetUpper());
656 SwRectFnSet
aRectFnSet(rTab
.GetUpper());
657 SwTwips nCurLastLineHeight
= aRectFnSet
.GetHeight(rLastLine
.getFrameArea());
659 SwTwips
nFootnoteHeight(0);
660 if (SwFootnoteBossFrame
const*const pBoss
= rTab
.FindFootnoteBossFrame())
662 if (SwFootnoteContFrame
const*const pCont
= pBoss
->FindFootnoteCont())
664 for (SwFootnoteFrame
const* pFootnote
= static_cast<SwFootnoteFrame
const*>(pCont
->Lower());
665 pFootnote
!= nullptr;
666 pFootnote
= static_cast<SwFootnoteFrame
const*>(pFootnote
->GetNext()))
668 SwContentFrame
const*const pAnchor
= pFootnote
->GetRef();
669 SwTabFrame
const* pTab
= pAnchor
->FindTabFrame();
672 while (pTab
->GetUpper()->IsInTab())
674 pTab
= pTab
->GetUpper()->FindTabFrame();
676 // TODO currently do this only for top-level tables?
677 // otherwise would need to check rTab's follow and any upper table's follow?
680 nFootnoteHeight
+= aRectFnSet
.GetHeight(pFootnote
->getFrameArea());
687 // If there are nested cells in rLastLine, the recalculation of the last
688 // line needs some preprocessing.
689 lcl_PreprocessRowsInCells( rTab
, rLastLine
, rFollowLine
, nRemainingSpaceForLastRow
);
691 // Here the recalculation process starts:
692 rTab
.SetRebuildLastLine( true );
694 rTab
.SetDoesObjsFit( true );
696 // #i26945# - invalidate and move floating screen
697 // objects 'out of range'
698 ::lcl_InvalidateLowerObjs( rLastLine
, true );
700 // manipulate row and cell sizes
702 // #i26945# - Do *not* consider floating screen objects
703 // for the minimal cell height.
704 rTab
.SetConsiderObjsForMinCellHeight( false );
705 ::lcl_ShrinkCellsAndAllContent( rLastLine
);
706 rTab
.SetConsiderObjsForMinCellHeight( true );
708 // invalidate last line
709 ::SwInvalidateAll( &rLastLine
, LONG_MAX
);
711 // Shrink the table to account for the shrunk last row, as well as lower rows
712 // that had been moved to follow table in SwTabFrame::Split.
713 // It will grow later when last line will recalc its height.
714 rTab
.Shrink(nAlreadyFree
+ nCurLastLineHeight
- nRemainingSpaceForLastRow
+ 1);
716 // Lock this tab frame and its follow
717 bool bUnlockMaster
= false;
718 SwFlowFrame
* pFollow
= nullptr;
719 SwTabFrame
* pMaster
= rTab
.IsFollow() ? rTab
.FindMaster() : nullptr;
720 if ( pMaster
&& !pMaster
->IsJoinLocked() )
722 bUnlockMaster
= true;
723 ::TableSplitRecalcLock( pMaster
);
725 if ( !rTab
.GetFollow()->IsJoinLocked() )
727 pFollow
= rTab
.GetFollow();
728 ::TableSplitRecalcLock( pFollow
);
731 bool bInSplit
= rLastLine
.IsInSplit();
732 rLastLine
.SetInSplit();
734 // Do the recalculation
735 lcl_RecalcRow( rLastLine
, LONG_MAX
);
736 // #115759# - force a format of the last line in order to
737 // get the correct height.
738 rLastLine
.InvalidateSize();
739 rLastLine
.Calc(pRenderContext
);
741 rLastLine
.SetInSplit(bInSplit
);
743 // Unlock this tab frame and its follow
745 ::TableSplitRecalcUnlock( pFollow
);
747 ::TableSplitRecalcUnlock( pMaster
);
749 // If there are nested cells in rLastLine, the recalculation of the last
750 // line needs some postprocessing.
751 lcl_PostprocessRowsInCells( rTab
, rLastLine
);
753 // Do a couple of checks on the current situation.
755 // If we are not happy with the current situation we return false.
756 // This will start a new try to split the table, this time we do not
757 // try to split the table rows.
759 // 1. Check if table fits to its upper.
760 // #i26945# - include check, if objects fit
761 const SwTwips nDistanceToUpperPrtBottom
=
762 aRectFnSet
.BottomDist(rTab
.getFrameArea(), aRectFnSet
.GetPrtBottom(*rTab
.GetUpper()));
763 // tdf#125685 ignore footnotes that are anchored in follow-table of this
764 // table - if split is successful they move to the next page/column anyway
765 assert(rTab
.GetFollow() == rFollowLine
.GetUpper());
766 SwTwips
nFollowFootnotes(0);
767 // actually there should always be a boss frame, except if "this" isn't
768 // connected to a page yet; not sure if that can happen
769 if (SwFootnoteBossFrame
const*const pBoss
= rTab
.FindFootnoteBossFrame())
771 if (SwFootnoteContFrame
const*const pCont
= pBoss
->FindFootnoteCont())
773 for (SwFootnoteFrame
const* pFootnote
= static_cast<SwFootnoteFrame
const*>(pCont
->Lower());
774 pFootnote
!= nullptr;
775 pFootnote
= static_cast<SwFootnoteFrame
const*>(pFootnote
->GetNext()))
777 SwContentFrame
const*const pAnchor
= pFootnote
->GetRef();
778 SwTabFrame
const* pTab
= pAnchor
->FindTabFrame();
781 while (pTab
->GetUpper()->IsInTab())
783 pTab
= pTab
->GetUpper()->FindTabFrame();
785 // TODO currently do this only for top-level tables?
786 // otherwise would need to check rTab's follow and any upper table's follow?
787 if (pTab
== rTab
.GetFollow())
789 nFollowFootnotes
+= aRectFnSet
.GetHeight(pFootnote
->getFrameArea());
793 nFootnoteHeight
-= aRectFnSet
.GetHeight(pFootnote
->getFrameArea());
797 if (nFootnoteHeight
< 0)
798 { // tdf#156724 footnotes have grown, try to split again
799 rIsFootnoteGrowth
= true;
803 if (nDistanceToUpperPrtBottom
+ nFollowFootnotes
< 0 || !rTab
.DoesObjsFit())
806 // 2. Check if each cell in the last line has at least one content frame.
808 // Note: a FollowFlowRow may contains empty cells!
811 if ( !rLastLine
.IsInFollowFlowRow() )
813 SwCellFrame
* pCurrMasterCell
= static_cast<SwCellFrame
*>(rLastLine
.Lower());
814 while ( pCurrMasterCell
)
816 if ( !pCurrMasterCell
->ContainsContent() && pCurrMasterCell
->GetTabBox()->getRowSpan() >= 1 )
821 pCurrMasterCell
= static_cast<SwCellFrame
*>(pCurrMasterCell
->GetNext());
826 // 3. Check if last line does not contain any content:
829 if ( !rLastLine
.ContainsContent() )
835 // 4. Check if follow flow line does not contain content:
838 if ( !rFollowLine
.IsRowSpanLine() && !rFollowLine
.ContainsContent() )
846 // Everything looks fine. Splitting seems to be successful. We invalidate
847 // rFollowLine to force a new formatting.
848 ::SwInvalidateAll( &rFollowLine
, LONG_MAX
);
852 // Splitting the table row gave us an unexpected result.
853 // Everything has to be prepared for a second try to split
854 // the table, this time without splitting the row.
855 ::SwInvalidateAll( &rLastLine
, LONG_MAX
);
858 rTab
.SetRebuildLastLine( false );
860 rTab
.SetDoesObjsFit( true );
865 // Sets the correct height for all spanned cells
866 static void lcl_AdjustRowSpanCells( SwRowFrame
* pRow
)
868 SwRectFnSet
aRectFnSet(pRow
);
869 SwCellFrame
* pCellFrame
= static_cast<SwCellFrame
*>(pRow
->GetLower());
872 const tools::Long nLayoutRowSpan
= pCellFrame
->GetLayoutRowSpan();
873 if ( nLayoutRowSpan
> 1 )
875 // calculate height of cell:
876 const tools::Long nNewCellHeight
= lcl_GetHeightOfRows( pRow
, nLayoutRowSpan
);
877 const tools::Long nDiff
= nNewCellHeight
- aRectFnSet
.GetHeight(pCellFrame
->getFrameArea());
881 SwFrameAreaDefinition::FrameAreaWriteAccess
aFrm(*pCellFrame
);
882 aRectFnSet
.AddBottom(aFrm
, nDiff
);
886 pCellFrame
= static_cast<SwCellFrame
*>(pCellFrame
->GetNext());
890 // Returns the maximum layout row span of the row
891 // Looking for the next row that contains no covered cells:
892 static tools::Long
lcl_GetMaximumLayoutRowSpan( const SwRowFrame
& rRow
)
894 tools::Long nRet
= 1;
896 const SwRowFrame
* pCurrentRowFrame
= static_cast<const SwRowFrame
*>(rRow
.GetNext());
897 bool bNextRow
= false;
899 while ( pCurrentRowFrame
)
901 // if there is any covered cell, we proceed to the next row frame
902 const SwCellFrame
* pLower
= static_cast<const SwCellFrame
*>( pCurrentRowFrame
->Lower());
905 if ( pLower
->GetTabBox()->getRowSpan() < 0 )
911 pLower
= static_cast<const SwCellFrame
*>(pLower
->GetNext());
913 pCurrentRowFrame
= bNextRow
?
914 static_cast<const SwRowFrame
*>(pCurrentRowFrame
->GetNext() ) :
921 // Function to remove the FollowFlowLine of rTab.
922 // The content of the FollowFlowLine is moved to the associated line in the
924 bool SwTabFrame::RemoveFollowFlowLine()
926 // find FollowFlowLine
927 SwTabFrame
*pFoll
= GetFollow();
928 SwRowFrame
* pFollowFlowLine
= pFoll
? pFoll
->GetFirstNonHeadlineRow() : nullptr;
930 // find last row in master
931 SwFrame
* pLastLine
= GetLastLower();
933 OSL_ENSURE( HasFollowFlowLine() &&
935 pLastLine
, "There should be a flowline in the follow" );
937 // #140081# Make code robust.
938 if ( !pFollowFlowLine
|| !pLastLine
)
940 if (pFollowFlowLine
->IsDeleteForbidden())
942 SAL_WARN("sw.layout", "Cannot remove in-use Follow Flow Line");
946 // We have to reset the flag here, because lcl_MoveRowContent
947 // calls a GrowFrame(), which has a different behavior if
949 SetFollowFlowLine( false );
952 lcl_MoveRowContent( *pFollowFlowLine
, *static_cast<SwRowFrame
*>(pLastLine
) );
955 // If a row span follow flow line is removed, we want to move the whole span
957 tools::Long nRowsToMove
= lcl_GetMaximumLayoutRowSpan( *pFollowFlowLine
);
959 if ( nRowsToMove
> 1 )
961 SwRectFnSet
aRectFnSet(this);
962 SwFrame
* pRow
= pFollowFlowLine
->GetNext();
963 SwFrame
* pInsertBehind
= GetLastLower();
966 while ( pRow
&& nRowsToMove
-- > 1 )
968 SwFrame
* pNxt
= pRow
->GetNext();
969 nGrow
+= aRectFnSet
.GetHeight(pRow
->getFrameArea());
971 // The footnotes have to be moved:
972 lcl_MoveFootnotes( *GetFollow(), *this, static_cast<SwRowFrame
&>(*pRow
) );
974 pRow
->RemoveFromLayout();
975 pRow
->InsertBehind( this, pInsertBehind
);
976 pRow
->InvalidateAll_();
977 pRow
->CheckDirChange();
978 pInsertBehind
= pRow
;
982 SwFrame
* pFirstRow
= Lower();
985 lcl_AdjustRowSpanCells( static_cast<SwRowFrame
*>(pFirstRow
) );
986 pFirstRow
= pFirstRow
->GetNext();
990 GetFollow()->Shrink( nGrow
);
993 bool bJoin
= !pFollowFlowLine
->GetNext();
994 pFollowFlowLine
->Cut();
995 SwFrame::DestroyFrame(pFollowFlowLine
);
1000 // #i26945# - Floating screen objects are no longer searched.
1001 static bool lcl_FindSectionsInRow( const SwRowFrame
& rRow
)
1004 const SwCellFrame
* pLower
= static_cast<const SwCellFrame
*>(rRow
.Lower());
1007 if ( pLower
->IsVertical() != rRow
.IsVertical() )
1010 const SwFrame
* pTmpFrame
= pLower
->Lower();
1013 if ( pTmpFrame
->IsRowFrame() )
1015 bRet
= lcl_FindSectionsInRow( *static_cast<const SwRowFrame
*>(pTmpFrame
) );
1019 // #i26945# - search only for sections
1020 if (pTmpFrame
->IsSctFrame())
1024 if (!rRow
.IsInSct())
1026 // This row is not in a section.
1027 if (const SwFrame
* pSectionLower
= pTmpFrame
->GetLower())
1029 if (!pSectionLower
->IsColumnFrame())
1031 // Section has a single column only, try to
1035 for (const SwFrame
* pFrame
= pSectionLower
; pFrame
; pFrame
= pFrame
->GetNext())
1037 if (pFrame
->IsTabFrame())
1039 // Section contains a table, no split in that case.
1052 pTmpFrame
= pTmpFrame
->GetNext();
1055 pLower
= static_cast<const SwCellFrame
*>(pLower
->GetNext());
1060 bool SwTabFrame::Split(const SwTwips nCutPos
, bool bTryToSplit
,
1061 bool bTableRowKeep
, bool & rIsFootnoteGrowth
)
1065 SwRectFnSet
aRectFnSet(this);
1067 // #i26745# - format row and cell frames of table
1069 Lower()->InvalidatePos_();
1070 // #i43913# - correction
1071 // call method <lcl_InnerCalcLayout> with first lower.
1072 lcl_InnerCalcLayout( Lower(), LONG_MAX
, true );
1075 //In order to be able to compare the positions of the cells with CutPos,
1076 //they have to be calculated consecutively starting from the table.
1077 //They can definitely be invalid because of position changes of the table.
1078 SwRowFrame
*pRow
= static_cast<SwRowFrame
*>(Lower());
1082 const sal_uInt16 nRepeat
= GetTable()->GetRowsToRepeat();
1083 sal_uInt16 nRowCount
= 0; // pRow currently points to the first row
1085 SwTwips nRemainingSpaceForLastRow
=
1086 aRectFnSet
.YDiff(nCutPos
, aRectFnSet
.GetTop(getFrameArea()));
1087 nRemainingSpaceForLastRow
-= aRectFnSet
.GetTopMargin(*this);
1089 // Make pRow point to the line that does not fit anymore:
1090 while( pRow
->GetNext() &&
1091 nRemainingSpaceForLastRow
>= ( aRectFnSet
.GetHeight(pRow
->getFrameArea()) +
1092 (IsCollapsingBorders() ?
1093 pRow
->GetBottomLineSize() :
1096 if( bTryToSplit
|| !pRow
->IsRowSpanLine() ||
1097 0 != aRectFnSet
.GetHeight(pRow
->getFrameArea()) )
1099 nRemainingSpaceForLastRow
-= aRectFnSet
.GetHeight(pRow
->getFrameArea());
1100 pRow
= static_cast<SwRowFrame
*>(pRow
->GetNext());
1103 // bSplitRowAllowed: Row may be split according to its attributes.
1104 // bTryToSplit: Row will never be split if bTryToSplit = false.
1105 // This can either be passed as a parameter, indicating
1106 // that we are currently doing the second try to split the
1107 // table, or it will be set to false under certain
1108 // conditions that are not suitable for splitting
1110 bool bSplitRowAllowed
= true;
1111 if (!pRow
->IsRowSplitAllowed())
1113 // A row larger than the entire page ought to be allowed to split regardless of setting,
1114 // otherwise it has hidden content and that makes no sense
1115 if ( pRow
->getFrameArea().Height() > FindPageFrame()->getFramePrintArea().Height() )
1116 pRow
->SetForceRowSplitAllowed( true );
1118 bSplitRowAllowed
= false;
1121 // #i26945# - Floating screen objects no longer forbid
1122 // a splitting of the table row.
1123 // Special DoNotSplit case 1:
1124 // Search for sections inside pRow:
1125 if ( lcl_FindSectionsInRow( *pRow
) )
1127 bTryToSplit
= false;
1130 SwFlyFrame
* pFly
= FindFlyFrame();
1131 if (bSplitRowAllowed
&& pFly
&& pFly
->IsFlySplitAllowed())
1133 // The remaining size is less than the minimum row height, then don't even try to split the
1134 // row, just move it forward.
1135 const SwFormatFrameSize
& rRowSize
= pRow
->GetFormat()->GetFrameSize();
1136 if (rRowSize
.GetHeightSizeType() == SwFrameSize::Minimum
)
1138 SwTwips nMinHeight
= rRowSize
.GetHeight();
1139 if (nMinHeight
> nRemainingSpaceForLastRow
)
1141 bSplitRowAllowed
= false;
1143 if (!pRow
->GetPrev() && aRectFnSet
.GetHeight(pRow
->getFrameArea()) > nRemainingSpaceForLastRow
)
1145 // Split of pRow is not allowed, no previous row, the current row doesn't fit:
1146 // that's a failure, we'll have to move forward instead.
1154 // To avoid loops, we do some checks before actually trying to split
1155 // the row. Maybe we should keep the next row in this table.
1156 // Note: This is only done if we are at the beginning of our upper
1157 bool bKeepNextRow
= false;
1158 if ( nRowCount
< nRepeat
)
1160 // First case: One of the repeated headline does not fit to the page anymore.
1161 // tdf#88496 Disable repeated headline (like for #i44910#) to avoid loops and
1162 // to fix interoperability problems (very long tables only with headline)
1163 // tdf#150149 except in multi-column sections, where it's possible to enlarge
1164 // the height of the section frame instead of using this fallback
1165 OSL_ENSURE( !GetIndPrev(), "Table is supposed to be at beginning" );
1168 m_pTable
->SetRowsToRepeat(0);
1172 bKeepNextRow
= true;
1174 else if ( !GetIndPrev() && nRepeat
== nRowCount
)
1176 // Second case: The first non-headline row does not fit to the page.
1177 // If it is not allowed to be split, or it contains a sub-row that
1178 // is not allowed to be split, we keep the row in this table:
1179 if ( bTryToSplit
&& bSplitRowAllowed
)
1181 // Check if there are (first) rows inside this row,
1182 // which are not allowed to be split.
1183 SwCellFrame
* pLowerCell
= static_cast<SwCellFrame
*>(pRow
->Lower());
1184 while ( pLowerCell
)
1186 if ( pLowerCell
->Lower() && pLowerCell
->Lower()->IsRowFrame() )
1188 const SwRowFrame
* pLowerRow
= static_cast<SwRowFrame
*>(pLowerCell
->Lower());
1189 if ( !pLowerRow
->IsRowSplitAllowed() &&
1190 aRectFnSet
.GetHeight(pLowerRow
->getFrameArea()) > nRemainingSpaceForLastRow
)
1192 bKeepNextRow
= true;
1196 pLowerCell
= static_cast<SwCellFrame
*>(pLowerCell
->GetNext());
1200 bKeepNextRow
= true;
1203 // Better keep the next row in this table:
1206 pRow
= GetFirstNonHeadlineRow();
1207 if ( pRow
&& pRow
->IsRowSpanLine() && 0 == aRectFnSet
.GetHeight(pRow
->getFrameArea()) )
1208 pRow
= static_cast<SwRowFrame
*>(pRow
->GetNext());
1211 pRow
= static_cast<SwRowFrame
*>(pRow
->GetNext());
1216 // No more row to split or to move to follow table:
1220 // We try to split the row if
1221 // - the attributes of the row are set accordingly and
1222 // - we are allowed to do so
1223 // - it should not be kept with the next row
1224 bSplitRowAllowed
= bSplitRowAllowed
&& bTryToSplit
&&
1226 !pRow
->ShouldRowKeepWithNext() );
1228 // Adjust pRow according to the keep-with-next attribute:
1229 if ( !bSplitRowAllowed
&& bTableRowKeep
)
1231 SwRowFrame
* pTmpRow
= static_cast<SwRowFrame
*>(pRow
->GetPrev());
1232 SwRowFrame
* pOldRow
= pRow
;
1233 while ( pTmpRow
&& pTmpRow
->ShouldRowKeepWithNext() &&
1234 nRowCount
> nRepeat
)
1238 pTmpRow
= static_cast<SwRowFrame
*>(pTmpRow
->GetPrev());
1242 if ( nRowCount
== nRepeat
&& !GetIndPrev())
1248 // If we do not intend to split pRow, we check if we are
1249 // allowed to move pRow to a follow. Otherwise we return
1250 // false, indicating an error
1251 if ( !bSplitRowAllowed
)
1253 SwRowFrame
* pFirstNonHeadlineRow
= GetFirstNonHeadlineRow();
1254 if ( pRow
== pFirstNonHeadlineRow
)
1258 // Ignore row span lines
1259 SwRowFrame
* pTmpRow
= pFirstNonHeadlineRow
;
1260 while ( pTmpRow
&& pTmpRow
->IsRowSpanLine() )
1262 pTmpRow
= static_cast<SwRowFrame
*>(pTmpRow
->GetNext());
1264 if ( !pTmpRow
|| pRow
== pTmpRow
)
1270 // Build follow table if not already done:
1275 pFoll
= GetFollow();
1281 pFoll
= new SwTabFrame( *this );
1283 // We give the follow table an initial width.
1285 SwFrameAreaDefinition::FrameAreaWriteAccess
aFrm(*pFoll
);
1286 aRectFnSet
.AddWidth(aFrm
, aRectFnSet
.GetWidth(getFrameArea()));
1287 aRectFnSet
.SetLeft(aFrm
, aRectFnSet
.GetLeft(getFrameArea()));
1291 SwFrameAreaDefinition::FramePrintAreaWriteAccess
aPrt(*pFoll
);
1292 aRectFnSet
.AddWidth(aPrt
, aRectFnSet
.GetWidth(getFramePrintArea()));
1295 // Insert the new follow table
1296 pFoll
->InsertBehind( GetUpper(), this );
1298 // Repeat the headlines.
1299 auto& rLines
= GetTable()->GetTabLines();
1300 for ( nRowCount
= 0; nRowCount
< nRepeat
; ++nRowCount
)
1302 // Insert new headlines:
1303 SwRowFrame
* pHeadline
= new SwRowFrame(*rLines
[nRowCount
], this);
1305 sw::FlyCreationSuppressor aSuppressor
;
1306 pHeadline
->SetRepeatedHeadline(true);
1308 pHeadline
->InsertBefore( pFoll
, nullptr );
1310 SwPageFrame
*pPage
= pHeadline
->FindPageFrame();
1311 const sw::SpzFrameFormats
* pSpzs
= GetFormat()->GetDoc()->GetSpzFrameFormats();
1312 if( !pSpzs
->empty() )
1314 SwNodeOffset nIndex
;
1315 SwContentFrame
* pFrame
= pHeadline
->ContainsContent();
1318 // sw_redlinehide: the implementation of AppendObjs
1319 // takes care of iterating merged SwTextFrame
1320 nIndex
= pFrame
->IsTextFrame()
1321 ? static_cast<SwTextFrame
*>(pFrame
)->GetTextNodeFirst()->GetIndex()
1322 : static_cast<SwNoTextFrame
*>(pFrame
)->GetNode()->GetIndex();
1323 AppendObjs(pSpzs
, nIndex
, pFrame
, pPage
, GetFormat()->GetDoc());
1324 pFrame
= pFrame
->GetNextContentFrame();
1325 if( !pHeadline
->IsAnLower( pFrame
) )
1332 SwRowFrame
* pLastRow
= nullptr; // points to the last remaining line in master
1333 SwRowFrame
* pFollowRow
= nullptr; // points to either the follow flow line or the
1334 // first regular line in the follow
1336 if ( bSplitRowAllowed
)
1338 // If the row that does not fit anymore is allowed
1339 // to be split, the next row has to be moved to the follow table.
1341 pRow
= static_cast<SwRowFrame
*>(pRow
->GetNext());
1343 // new follow flow line for last row of master table
1344 pFollowRow
= lcl_InsertNewFollowFlowLine( *this, *pLastRow
, false );
1351 // check if we will break a row span by moving pFollowRow to the follow:
1352 // In this case we want to reformat the last line.
1353 const SwCellFrame
* pCellFrame
= static_cast<const SwCellFrame
*>(pFollowRow
->GetLower());
1354 while ( pCellFrame
)
1356 if ( pCellFrame
->GetTabBox()->getRowSpan() < 1 )
1358 pLastRow
= static_cast<SwRowFrame
*>(pRow
->GetPrev());
1362 pCellFrame
= static_cast<const SwCellFrame
*>(pCellFrame
->GetNext());
1365 // new follow flow line for last row of master table
1367 pFollowRow
= lcl_InsertNewFollowFlowLine( *this, *pLastRow
, true );
1370 SwTwips nShrink
= 0;
1372 //Optimization: There is no paste needed for the new Follow and the
1373 //optimized insert can be used (large numbers of rows luckily only occur in
1377 SwFrame
* pInsertBehind
= pFoll
->GetLastLower();
1381 SwFrame
* pNxt
= pRow
->GetNext();
1382 nShrink
+= aRectFnSet
.GetHeight(pRow
->getFrameArea());
1383 // The footnotes do not have to be moved, this is done in the
1384 // MoveFwd of the follow table!!!
1385 pRow
->RemoveFromLayout();
1386 pRow
->InsertBehind( pFoll
, pInsertBehind
);
1387 pRow
->InvalidateAll_();
1388 pInsertBehind
= pRow
;
1389 pRow
= static_cast<SwRowFrame
*>(pNxt
);
1394 SwFrame
* pPasteBefore
= HasFollowFlowLine() ?
1395 pFollowRow
->GetNext() :
1396 pFoll
->GetFirstNonHeadlineRow();
1400 SwFrame
* pNxt
= pRow
->GetNext();
1401 nShrink
+= aRectFnSet
.GetHeight(pRow
->getFrameArea());
1403 // The footnotes have to be moved:
1404 lcl_MoveFootnotes( *this, *GetFollow(), *pRow
);
1406 pRow
->RemoveFromLayout();
1407 pRow
->Paste( pFoll
, pPasteBefore
);
1409 pRow
->CheckDirChange();
1410 pRow
= static_cast<SwRowFrame
*>(pNxt
);
1418 // we rebuild the last line to assure that it will be fully formatted
1419 // we also don't shrink here, because we will be doing that in lcl_RecalcSplitLine
1421 // recalculate the split line
1422 bRet
= lcl_RecalcSplitLine(*pLastRow
, *pFollowRow
, nRemainingSpaceForLastRow
, nShrink
, rIsFootnoteGrowth
);
1424 // RecalcSplitLine did not work. In this case we conceal the split error:
1425 if (!bRet
&& !bSplitRowAllowed
)
1431 // check if each cell in the row span line has a good height
1432 if ( bRet
&& pFollowRow
->IsRowSpanLine() )
1433 lcl_AdjustRowSpanCells( pFollowRow
);
1441 bool CanDeleteFollow(SwTabFrame
*pFoll
)
1443 if (pFoll
->IsJoinLocked())
1446 if (pFoll
->IsDeleteForbidden())
1448 SAL_WARN("sw.layout", "Delete Forbidden");
1456 void SwTabFrame::Join()
1458 OSL_ENSURE( !HasFollowFlowLine(), "Joining follow flow line" );
1460 SwTabFrame
*pFoll
= GetFollow();
1462 if (!pFoll
|| !CanDeleteFollow(pFoll
))
1465 SwRectFnSet
aRectFnSet(this);
1466 pFoll
->Cut(); //Cut out first to avoid unnecessary notifications.
1468 SwFrame
*pRow
= pFoll
->GetFirstNonHeadlineRow(),
1471 SwFrame
* pPrv
= GetLastLower();
1473 SwTwips nHeight
= 0; //Total height of the inserted rows as return value.
1477 pNxt
= pRow
->GetNext();
1478 nHeight
+= aRectFnSet
.GetHeight(pRow
->getFrameArea());
1479 pRow
->RemoveFromLayout();
1480 pRow
->InvalidateAll_();
1481 pRow
->InsertBehind( this, pPrv
);
1482 pRow
->CheckDirChange();
1487 SetFollow( pFoll
->GetFollow() );
1488 SetFollowFlowLine( pFoll
->HasFollowFlowLine() );
1489 SwFrame::DestroyFrame(pFoll
);
1494 static void SwInvalidatePositions( SwFrame
*pFrame
, tools::Long nBottom
)
1496 // LONG_MAX == nBottom means we have to calculate all
1497 bool bAll
= LONG_MAX
== nBottom
;
1498 SwRectFnSet
aRectFnSet(pFrame
);
1500 { pFrame
->InvalidatePos_();
1501 pFrame
->InvalidateSize_();
1502 if( pFrame
->IsLayoutFrame() )
1504 if ( static_cast<SwLayoutFrame
*>(pFrame
)->Lower() )
1506 ::SwInvalidatePositions( static_cast<SwLayoutFrame
*>(pFrame
)->Lower(), nBottom
);
1508 ::lcl_InvalidateLowerObjs( *static_cast<SwLayoutFrame
*>(pFrame
) );
1512 pFrame
->Prepare( PrepareHint::AdjustSizeWithoutFormatting
);
1513 pFrame
= pFrame
->GetNext();
1516 aRectFnSet
.YDiff( aRectFnSet
.GetTop(pFrame
->getFrameArea()), nBottom
) < 0 ) );
1519 void SwInvalidateAll( SwFrame
*pFrame
, tools::Long nBottom
)
1521 // LONG_MAX == nBottom means we have to calculate all
1522 bool bAll
= LONG_MAX
== nBottom
;
1523 SwRectFnSet
aRectFnSet(pFrame
);
1526 pFrame
->InvalidatePos_();
1527 pFrame
->InvalidateSize_();
1528 pFrame
->InvalidatePrt_();
1529 if( pFrame
->IsLayoutFrame() )
1532 SwLayoutFrame
* pToInvalidate
= static_cast<SwLayoutFrame
*>(pFrame
);
1533 if (pFrame
->IsCellFrame())
1535 SwCellFrame
* pThisCell
= static_cast<SwCellFrame
*>(pFrame
);
1536 if ( pThisCell
->GetTabBox()->getRowSpan() < 1 )
1538 pToInvalidate
= & const_cast<SwCellFrame
&>(pThisCell
->FindStartEndOfRowSpanCell( true ));
1539 pToInvalidate
->InvalidatePos_();
1540 pToInvalidate
->InvalidateSize_();
1541 pToInvalidate
->InvalidatePrt_();
1544 if ( pToInvalidate
->Lower() )
1545 ::SwInvalidateAll( pToInvalidate
->Lower(), nBottom
);
1550 pFrame
= pFrame
->GetNext();
1553 aRectFnSet
.YDiff( aRectFnSet
.GetTop(pFrame
->getFrameArea()), nBottom
) < 0 ) );
1557 static void lcl_InvalidateAllLowersPrt( SwLayoutFrame
* pLayFrame
)
1559 pLayFrame
->InvalidatePrt_();
1560 pLayFrame
->InvalidateSize_();
1561 pLayFrame
->SetCompletePaint();
1563 SwFrame
* pFrame
= pLayFrame
->Lower();
1567 if ( pFrame
->IsLayoutFrame() )
1568 lcl_InvalidateAllLowersPrt( static_cast<SwLayoutFrame
*>(pFrame
) );
1571 pFrame
->InvalidatePrt_();
1572 pFrame
->InvalidateSize_();
1573 pFrame
->SetCompletePaint();
1576 pFrame
= pFrame
->GetNext();
1580 bool SwContentFrame::CalcLowers(SwLayoutFrame
& rLay
, SwLayoutFrame
const& rDontLeave
,
1581 tools::Long nBottom
, bool bSkipRowSpanCells
)
1583 vcl::RenderContext
* pRenderContext
= rLay
.getRootFrame()->GetCurrShell()->GetOut();
1584 // LONG_MAX == nBottom means we have to calculate all
1585 bool bAll
= LONG_MAX
== nBottom
;
1587 SwContentFrame
*pCnt
= rLay
.ContainsContent();
1588 SwRectFnSet
aRectFnSet(&rLay
);
1590 // FME 2007-08-30 #i81146# new loop control
1591 int nLoopControlRuns
= 0;
1592 const int nLoopControlMax
= 10;
1593 const sw::BroadcastingModify
* pLoopControlCond
= nullptr;
1595 while (pCnt
&& rDontLeave
.IsAnLower(pCnt
))
1597 // #115759# - check, if a format of content frame is
1598 // possible. Thus, 'copy' conditions, found at the beginning of
1599 // <SwContentFrame::MakeAll(..)>, and check these.
1600 const bool bFormatPossible
= !pCnt
->IsJoinLocked() &&
1601 ( !pCnt
->IsTextFrame() ||
1602 !static_cast<SwTextFrame
*>(pCnt
)->IsLocked() ) &&
1603 ( pCnt
->IsFollow() || !StackHack::IsLocked() );
1606 bool bSkipContent
= false;
1607 if ( bSkipRowSpanCells
&& pCnt
->IsInTab() )
1609 const SwFrame
* pCell
= pCnt
->GetUpper();
1610 while ( pCell
&& !pCell
->IsCellFrame() )
1611 pCell
= pCell
->GetUpper();
1612 if ( pCell
&& 1 != static_cast<const SwCellFrame
*>( pCell
)->GetLayoutRowSpan() )
1613 bSkipContent
= true;
1616 if ( bFormatPossible
&& !bSkipContent
)
1618 bRet
|= !pCnt
->isFrameAreaDefinitionValid();
1619 // #i26945# - no extra invalidation of floating
1620 // screen objects needed.
1621 // Thus, delete call of method <SwFrame::InvalidateObjs( true )>
1622 pCnt
->Calc(pRenderContext
);
1623 // #i46941# - frame has to be valid
1624 // Note: frame could be invalid after calling its format, if it's locked.
1625 OSL_ENSURE( !pCnt
->IsTextFrame() ||
1626 pCnt
->isFrameAreaDefinitionValid() ||
1627 static_cast<SwTextFrame
*>(pCnt
)->IsJoinLocked(),
1628 "<SwContentFrame::CalcLowers(..)> - text frame invalid and not locked." );
1629 if ( pCnt
->IsTextFrame() && pCnt
->isFrameAreaDefinitionValid() )
1631 // #i23129#, #i36347# - pass correct page frame to
1632 // the object formatter
1633 if ( !SwObjectFormatter::FormatObjsAtFrame( *pCnt
,
1634 *(pCnt
->FindPageFrame()) ) )
1636 SwTextNode
const*const pTextNode(
1637 static_cast<SwTextFrame
*>(pCnt
)->GetTextNodeFirst());
1638 if (pTextNode
== pLoopControlCond
)
1642 nLoopControlRuns
= 0;
1643 pLoopControlCond
= pTextNode
;
1646 if ( nLoopControlRuns
< nLoopControlMax
)
1648 // restart format with first content
1649 pCnt
= rLay
.ContainsContent();
1653 SAL_WARN("sw.layout", "LoopControl in SwContentFrame::CalcLowers");
1656 if (!rDontLeave
.IsAnLower(pCnt
)) // moved backward?
1658 pCnt
= rLay
.ContainsContent();
1659 continue; // avoid formatting new upper on different page
1661 pCnt
->GetUpper()->Calc(pRenderContext
);
1663 if( ! bAll
&& aRectFnSet
.YDiff(aRectFnSet
.GetTop(pCnt
->getFrameArea()), nBottom
) > 0 )
1665 pCnt
= pCnt
->GetNextContentFrame();
1670 // #i26945# - add parameter <_bOnlyRowsAndCells> to control
1671 // that only row and cell frames are formatted.
1672 static bool lcl_InnerCalcLayout( SwFrame
*pFrame
,
1673 tools::Long nBottom
,
1674 bool _bOnlyRowsAndCells
)
1676 vcl::RenderContext
* pRenderContext
= pFrame
->getRootFrame()->GetCurrShell() ? pFrame
->getRootFrame()->GetCurrShell()->GetOut() : nullptr;
1677 // LONG_MAX == nBottom means we have to calculate all
1678 bool bAll
= LONG_MAX
== nBottom
;
1680 const SwFrame
* pOldUp
= pFrame
->GetUpper();
1681 SwRectFnSet
aRectFnSet(pFrame
);
1684 // #i26945# - parameter <_bOnlyRowsAndCells> controls,
1685 // if only row and cell frames are formatted.
1686 if ( pFrame
->IsLayoutFrame() &&
1687 ( !_bOnlyRowsAndCells
|| pFrame
->IsRowFrame() || pFrame
->IsCellFrame() ) )
1689 SwFrameDeleteGuard
aDeleteGuard(pFrame
);
1691 // #130744# An invalid locked table frame will
1692 // not be calculated => It will not become valid =>
1693 // Loop in lcl_RecalcRow(). Therefore we do not consider them for bRet.
1694 bRet
|= !pFrame
->isFrameAreaDefinitionValid() && ( !pFrame
->IsTabFrame() || !static_cast<SwTabFrame
*>(pFrame
)->IsJoinLocked() );
1695 pFrame
->Calc(pRenderContext
);
1696 if( static_cast<SwLayoutFrame
*>(pFrame
)->Lower() )
1697 bRet
|= lcl_InnerCalcLayout( static_cast<SwLayoutFrame
*>(pFrame
)->Lower(), nBottom
);
1700 if (pFrame
->IsCellFrame())
1702 SwCellFrame
* pThisCell
= static_cast<SwCellFrame
*>(pFrame
);
1703 if ( pThisCell
->GetTabBox()->getRowSpan() < 1 )
1705 SwCellFrame
& rToCalc
= const_cast<SwCellFrame
&>(pThisCell
->FindStartEndOfRowSpanCell( true ));
1706 bRet
|= !rToCalc
.isFrameAreaDefinitionValid();
1707 rToCalc
.Calc(pRenderContext
);
1708 if ( rToCalc
.Lower() )
1709 bRet
|= lcl_InnerCalcLayout( rToCalc
.Lower(), nBottom
);
1713 pFrame
= pFrame
->GetNext();
1716 aRectFnSet
.YDiff(aRectFnSet
.GetTop(pFrame
->getFrameArea()), nBottom
) < 0 )
1717 && pFrame
->GetUpper() == pOldUp
);
1721 static void lcl_RecalcRow(SwRowFrame
& rRow
, tools::Long
const nBottom
)
1723 // FME 2007-08-30 #i81146# new loop control
1724 int nLoopControlRuns_1
= 0;
1725 sal_uInt16 nLoopControlStage_1
= 0;
1726 const int nLoopControlMax
= 10;
1731 // FME 2007-08-30 #i81146# new loop control
1732 int nLoopControlRuns_2
= 0;
1733 sal_uInt16 nLoopControlStage_2
= 0;
1735 while (lcl_InnerCalcLayout(&rRow
, nBottom
))
1737 if ( ++nLoopControlRuns_2
> nLoopControlMax
)
1739 SAL_WARN_IF(nLoopControlStage_2
== 0, "sw.layout", "LoopControl_2 in lcl_RecalcRow: Stage 1!");
1740 SAL_WARN_IF(nLoopControlStage_2
== 1, "sw.layout", "LoopControl_2 in lcl_RecalcRow: Stage 2!!");
1741 SAL_WARN_IF(nLoopControlStage_2
>= 2, "sw.layout", "LoopControl_2 in lcl_RecalcRow: Stage 3!!!");
1742 rRow
.ValidateThisAndAllLowers( nLoopControlStage_2
++ );
1743 nLoopControlRuns_2
= 0;
1744 if( nLoopControlStage_2
> 2 )
1753 SwFrameDeleteGuard
g(&rRow
);
1755 // #115759# - force another format of the
1756 // lowers, if at least one of it was invalid.
1757 bCheck
= SwContentFrame::CalcLowers(rRow
, *rRow
.GetUpper(), nBottom
, true);
1760 // First we calculate the cells with row span of < 1, afterwards
1761 // all cells with row span of > 1:
1762 for ( int i
= 0; i
< 2; ++i
)
1764 SwCellFrame
* pCellFrame
= static_cast<SwCellFrame
*>(rRow
.Lower());
1765 while ( pCellFrame
)
1767 const bool bCalc
= 0 == i
?
1768 pCellFrame
->GetLayoutRowSpan() < 1 :
1769 pCellFrame
->GetLayoutRowSpan() > 1;
1773 SwCellFrame
& rToRecalc
= 0 == i
?
1774 const_cast<SwCellFrame
&>(pCellFrame
->FindStartEndOfRowSpanCell( true )) :
1776 bCheck
|= SwContentFrame::CalcLowers(rToRecalc
, rToRecalc
, nBottom
, false);
1779 pCellFrame
= static_cast<SwCellFrame
*>(pCellFrame
->GetNext());
1785 if ( ++nLoopControlRuns_1
> nLoopControlMax
)
1787 SAL_WARN_IF(nLoopControlStage_1
== 0, "sw.layout", "LoopControl_1 in lcl_RecalcRow: Stage 1!");
1788 SAL_WARN_IF(nLoopControlStage_1
== 1, "sw.layout", "LoopControl_1 in lcl_RecalcRow: Stage 2!!");
1789 SAL_WARN_IF(nLoopControlStage_1
>= 2, "sw.layout", "LoopControl_1 in lcl_RecalcRow: Stage 3!!!");
1790 rRow
.ValidateThisAndAllLowers( nLoopControlStage_1
++ );
1791 nLoopControlRuns_1
= 0;
1792 if( nLoopControlStage_1
> 2 )
1803 static void lcl_RecalcTable( SwTabFrame
& rTab
,
1804 SwLayoutFrame
*pFirstRow
,
1805 SwLayNotify
&rNotify
)
1811 pFirstRow
= static_cast<SwLayoutFrame
*>(rTab
.Lower());
1812 rNotify
.SetLowersComplete( true );
1814 ::SwInvalidatePositions( pFirstRow
, LONG_MAX
);
1815 lcl_RecalcRow( *static_cast<SwRowFrame
*>(pFirstRow
), LONG_MAX
);
1819 // This is a new function to check the first condition whether
1820 // a tab frame may move backward. It replaces the formerly used
1821 // GetIndPrev(), which did not work correctly for #i5947#
1822 static bool lcl_NoPrev( const SwFrame
& rFrame
)
1825 // skip empty sections on investigation of direct previous frame.
1826 // use information, that at least one empty section is skipped in the following code.
1827 bool bSkippedDirectPrevEmptySection( false );
1828 if ( rFrame
.GetPrev() )
1830 const SwFrame
* pPrev( rFrame
.GetPrev() );
1832 pPrev
->IsSctFrame() &&
1833 !dynamic_cast<const SwSectionFrame
&>(*pPrev
).GetSection() )
1835 pPrev
= pPrev
->GetPrev();
1836 bSkippedDirectPrevEmptySection
= true;
1844 if ( ( !bSkippedDirectPrevEmptySection
&& !rFrame
.GetIndPrev() ) ||
1845 ( bSkippedDirectPrevEmptySection
&&
1846 ( !rFrame
.IsInSct() || !rFrame
.GetIndPrev_() ) ) )
1851 // I do not have a direct prev, but I have an indirect prev.
1852 // In section frames I have to check if I'm located inside
1853 // the first column:
1854 if ( rFrame
.IsInSct() )
1856 const SwFrame
* pSct
= rFrame
.GetUpper();
1857 if ( pSct
&& pSct
->IsColBodyFrame() &&
1858 pSct
->GetUpper()->GetUpper()->IsSctFrame() )
1860 const SwFrame
* pPrevCol
= rFrame
.GetUpper()->GetUpper()->GetPrev();
1862 // I'm not inside the first column and do not have a direct
1863 // prev. I can try to go backward.
1871 #define KEEPTAB ( !GetFollow() && !IsFollow() )
1873 // - helper method to find next content frame of
1874 // a table frame and format it to assure keep attribute.
1875 // method return true, if a next content frame is formatted.
1876 // Precondition: The given table frame hasn't a follow and isn't a follow.
1877 SwFrame
* sw_FormatNextContentForKeep( SwTabFrame
* pTabFrame
)
1879 vcl::RenderContext
* pRenderContext
= pTabFrame
->getRootFrame()->GetCurrShell()->GetOut();
1880 // find next content, table or section
1881 SwFrame
* pNxt
= pTabFrame
->FindNext();
1883 // skip empty sections
1884 while ( pNxt
&& pNxt
->IsSctFrame() &&
1885 !static_cast<SwSectionFrame
*>(pNxt
)->GetSection() )
1887 pNxt
= pNxt
->FindNext();
1890 // if found next frame is a section, get its first content.
1891 if ( pNxt
&& pNxt
->IsSctFrame() )
1893 pNxt
= static_cast<SwSectionFrame
*>(pNxt
)->ContainsAny();
1896 // format found next frame.
1897 // if table frame is inside another table, method <SwFrame::MakeAll()> is
1898 // called to avoid that the superior table frame is formatted.
1901 if ( pTabFrame
->GetUpper()->IsInTab() )
1902 pNxt
->MakeAll(pNxt
->getRootFrame()->GetCurrShell()->GetOut());
1904 pNxt
->Calc(pRenderContext
);
1911 bool AreAllRowsKeepWithNext( const SwRowFrame
* pFirstRowFrame
, const bool bCheckParents
= true )
1913 bool bRet
= pFirstRowFrame
!= nullptr &&
1914 pFirstRowFrame
->ShouldRowKeepWithNext( bCheckParents
);
1916 while ( bRet
&& pFirstRowFrame
->GetNext() != nullptr )
1918 pFirstRowFrame
= dynamic_cast<const SwRowFrame
*>(pFirstRowFrame
->GetNext());
1919 bRet
= pFirstRowFrame
!= nullptr &&
1920 pFirstRowFrame
->ShouldRowKeepWithNext( bCheckParents
);
1927 // extern because static can't be friend
1928 void FriendHackInvalidateRowFrame(SwFrameAreaDefinition
& rRowFrame
)
1930 // hilariously static_cast<SwTabFrame*>(GetLower()) would not require friend declaration, but it's UB...
1931 rRowFrame
.setFrameAreaPositionValid(false);
1934 static void InvalidateFramePositions(SwFrame
* pFrame
)
1938 if (pFrame
->IsLayoutFrame())
1940 InvalidateFramePositions(pFrame
->GetLower());
1942 else if (pFrame
->IsTextFrame())
1944 pFrame
->Prepare(PrepareHint::FramePositionChanged
);
1946 pFrame
= pFrame
->GetNext();
1950 void SwTabFrame::MakeAll(vcl::RenderContext
* pRenderContext
)
1952 if ( IsJoinLocked() || StackHack::IsLocked() || StackHack::Count() > 50 )
1957 SwTabFrame
* pFollowFrame
= GetFollow();
1958 OSL_ENSURE( !pFollowFrame
->IsJoinLocked() || !pFollowFrame
->IsRebuildLastLine(),
1959 "SwTabFrame::MakeAll for master while follow is in RebuildLastLine()" );
1960 if ( pFollowFrame
->IsJoinLocked() && pFollowFrame
->IsRebuildLastLine() )
1964 PROTOCOL_ENTER( this, PROT::MakeAll
, DbgAction::NONE
, nullptr )
1966 LockJoin(); //I don't want to be destroyed on the way.
1967 SwLayNotify
aNotify( this ); //does the notification in the DTor
1968 // If pos is invalid, we have to call a SetInvaKeep at aNotify.
1969 // Otherwise the keep attribute would not work in front of a table.
1970 const bool bOldValidPos
= isFrameAreaPositionValid();
1972 //If my neighbour is my Follow at the same time, I'll swallow it up.
1973 // OD 09.04.2003 #108698# - join all follows, which are placed on the
1974 // same page/column.
1975 // OD 29.04.2003 #109213# - join follow, only if join for the follow
1976 // is not locked. Otherwise, join will not be performed and this loop
1978 while ( GetNext() && GetNext() == GetFollow() &&
1979 CanDeleteFollow(GetFollow())
1982 if ( HasFollowFlowLine() )
1983 RemoveFollowFlowLine();
1987 // The bRemoveFollowFlowLinePending is set if the split attribute of the
1988 // last line is set:
1989 if ( IsRemoveFollowFlowLinePending() && HasFollowFlowLine() )
1991 if ( RemoveFollowFlowLine() )
1993 SetRemoveFollowFlowLinePending( false );
1996 if (m_bResizeHTMLTable
) //Optimized interplay with grow/shrink of the content
1998 m_bResizeHTMLTable
= false;
1999 SwHTMLTableLayout
*pLayout
= GetTable()->GetHTMLTableLayout();
2001 m_bCalcLowers
= pLayout
->Resize(
2002 pLayout
->GetBrowseWidthByTabFrame( *this ) );
2005 // as long as bMakePage is true, a new page can be created (exactly once)
2006 bool bMakePage
= true;
2007 // bMovedBwd gets set to true when the frame flows backwards
2008 bool bMovedBwd
= false;
2009 // as long as bMovedFwd is false, the Frame may flow backwards (until
2010 // it has been moved forward once)
2011 bool bMovedFwd
= false;
2012 // gets set to true when the Frame is split
2013 bool bSplit
= false;
2014 const bool bFootnotesInDoc
= !GetFormat()->GetDoc()->GetFootnoteIdxs().empty();
2015 const bool bFly
= IsInFly();
2017 std::optional
<SwBorderAttrAccess
> oAccess(std::in_place
, SwFrame::GetCache(), this);
2018 const SwBorderAttrs
*pAttrs
= oAccess
->Get();
2020 // All rows should keep together
2021 bool bDontSplit
= !IsFollow() &&
2022 ( !GetFormat()->GetLayoutSplit().GetValue() );
2024 // The number of repeated headlines
2025 const sal_uInt16 nRepeat
= GetTable()->GetRowsToRepeat();
2027 // This flag indicates that we are allowed to try to split the
2029 bool bTryToSplit
= true;
2031 // Indicates that two individual rows may keep together, based on the keep
2032 // attribute set at the first paragraph in the first cell.
2033 bool bTableRowKeep
= !bDontSplit
&& GetFormat()->GetDoc()->GetDocumentSettingManager().get(DocumentSettingId::TABLE_ROW_KEEP
);
2034 if (SwFlyFrame
* pFly
= FindFlyFrame())
2036 if (pFly
->IsFlySplitAllowed())
2038 // Ignore the above text node -> row inheritance for floating tables.
2039 bTableRowKeep
= false;
2041 else if (!pFly
->GetNextLink())
2043 // If the fly is not allowed to split and is not chained, then it makes no sense to
2049 // The Magic Move: Used for the table row keep feature.
2050 // If only the last row of the table wants to keep (implicitly by setting
2051 // keep for the first paragraph in the first cell), and this table does
2052 // not have a next, the last line will be cut. Loop prevention: Only
2054 // WHAT IS THIS??? It "magically" hides last line (paragraph) in a table,
2055 // if first is set to keep with next???
2056 bool bLastRowHasToMoveToFollow
= false;
2057 bool bLastRowMoveNoMoreTries
= false;
2059 const bool bLargeTable
= GetTable()->GetTabLines().size() > 64; //arbitrary value, virtually guaranteed to be larger than one page.
2060 const bool bEmulateTableKeep
= !bLargeTable
&& bTableRowKeep
2061 && !pAttrs
->GetAttrSet().GetKeep().GetValue()
2062 && AreAllRowsKeepWithNext(GetFirstNonHeadlineRow(), /*bCheckParents=*/false);
2063 // The beloved keep attribute
2064 const bool bKeep
= IsKeep(pAttrs
->GetAttrSet().GetKeep(), GetBreakItem(), bEmulateTableKeep
);
2066 // Join follow table, if this table is not allowed to split:
2069 while ( GetFollow() && !GetFollow()->IsJoinLocked() )
2071 if ( HasFollowFlowLine() )
2072 RemoveFollowFlowLine();
2077 // Join follow table, if this does not have enough (repeated) lines:
2080 if( GetFollow() && !GetFollow()->IsJoinLocked() &&
2081 nullptr == GetFirstNonHeadlineRow() )
2083 if ( HasFollowFlowLine() )
2084 RemoveFollowFlowLine();
2089 // Join follow table, if last row of this table should keep:
2090 if ( bTableRowKeep
&& GetFollow() && !GetFollow()->IsJoinLocked() )
2092 const SwRowFrame
* pTmpRow
= static_cast<const SwRowFrame
*>(GetLastLower());
2093 if ( pTmpRow
&& pTmpRow
->ShouldRowKeepWithNext() )
2095 if ( HasFollowFlowLine() )
2096 RemoveFollowFlowLine();
2101 // a new one is moved forwards immediately
2102 if ( !getFrameArea().Top() && IsFollow() )
2104 SwFrame
*pPre
= GetPrev();
2105 if ( pPre
&& pPre
->IsTabFrame() && static_cast<SwTabFrame
*>(pPre
)->GetFollow() == this)
2107 // don't make the effort to move fwd if its known
2108 // conditions that are known not to work
2109 if (IsInFootnote() && ForbiddenForFootnoteCntFwd())
2111 else if (!MoveFwd(bMakePage
, false))
2117 int nUnSplitted
= 5; // Just another loop control :-(
2118 int nThrowAwayValidLayoutLimit
= 5; // And another one :-(
2119 SwRectFnSet
aRectFnSet(this);
2120 while ( !isFrameAreaPositionValid() || !isFrameAreaSizeValid() || !isFramePrintAreaValid() )
2122 const bool bMoveable
= IsMoveable();
2124 !(bMovedFwd
&& bEmulateTableKeep
) )
2125 if ( CheckMoveFwd( bMakePage
, bKeep
&& KEEPTAB
, bEmulateTableKeep
) )
2128 m_bCalcLowers
= true;
2130 // reset <bSplit> after forward move to assure that follows
2131 // can be joined, if further space is available.
2135 Point
aOldPos( aRectFnSet
.GetPos(getFrameArea()) );
2138 if ( aOldPos
!= aRectFnSet
.GetPos(getFrameArea()) )
2140 if ( aOldPos
.Y() != aRectFnSet
.GetTop(getFrameArea()) )
2142 SwHTMLTableLayout
*pLayout
= GetTable()->GetHTMLTableLayout();
2146 m_bCalcLowers
|= pLayout
->Resize(
2147 pLayout
->GetBrowseWidthByTabFrame( *this ) );
2150 setFramePrintAreaValid(false);
2151 aNotify
.SetLowersComplete( false );
2154 if ( bKeep
|| (nullptr != (pPre
= FindPrev()) &&
2155 pPre
->GetAttrSet()->GetKeep().GetValue()) )
2157 m_bCalcLowers
= true;
2160 { // it's possible that the rows already have valid pos - but it is surely wrong if the table's pos changed!
2161 FriendHackInvalidateRowFrame(*GetLower());
2162 // invalidate text frames to get rid of their SwFlyPortions
2163 InvalidateFramePositions(GetLower());
2167 //We need to know the height of the first row, because the master needs
2168 //to be invalidated if it shrinks and then absorb the row if possible.
2169 tools::Long n1StLineHeight
= 0;
2172 SwFrame
* pFrame
= GetFirstNonHeadlineRow();
2174 n1StLineHeight
= aRectFnSet
.GetHeight(pFrame
->getFrameArea());
2177 if ( !isFrameAreaSizeValid() || !isFramePrintAreaValid() )
2179 const tools::Long nOldPrtWidth
= aRectFnSet
.GetWidth(getFramePrintArea());
2180 const tools::Long nOldFrameWidth
= aRectFnSet
.GetWidth(getFrameArea());
2181 const Point aOldPrtPos
= aRectFnSet
.GetPos(getFramePrintArea());
2185 oAccess
.emplace(SwFrame::GetCache(), this);
2186 pAttrs
= oAccess
->Get();
2188 Format( getRootFrame()->GetCurrShell()->GetOut(), pAttrs
);
2190 SwHTMLTableLayout
*pLayout
= GetTable()->GetHTMLTableLayout();
2192 (aRectFnSet
.GetWidth(getFramePrintArea()) != nOldPrtWidth
||
2193 aRectFnSet
.GetWidth(getFrameArea()) != nOldFrameWidth
) )
2196 m_bCalcLowers
|= pLayout
->Resize(
2197 pLayout
->GetBrowseWidthByTabFrame( *this ) );
2199 if ( aOldPrtPos
!= aRectFnSet
.GetPos(getFramePrintArea()) )
2200 aNotify
.SetLowersComplete( false );
2203 // If this is the first one in a chain, check if this can flow
2204 // backwards (if this is movable at all).
2205 // To prevent oscillations/loops, check that this has not just
2207 if ( !bMovedFwd
&& (bMoveable
|| bFly
) && lcl_NoPrev( *this ) )
2209 // for Follows notify Master.
2210 // only move Follow if it has to skip empty pages.
2213 // Only if the height of the first line got smaller.
2214 SwFrame
*pFrame
= GetFirstNonHeadlineRow();
2215 if( pFrame
&& n1StLineHeight
>aRectFnSet
.GetHeight(pFrame
->getFrameArea()) )
2217 SwTabFrame
*pMaster
= FindMaster();
2219 if ( ShouldBwdMoved( pMaster
->GetUpper(), bDummy
) )
2220 pMaster
->InvalidatePos();
2223 SwFootnoteBossFrame
*pOldBoss
= bFootnotesInDoc
? FindFootnoteBossFrame( true ) : nullptr;
2225 std::optional
<SfxDeleteListener
> oDeleteListener
;
2227 oDeleteListener
.emplace(*pOldBoss
);
2228 SwFrameDeleteGuard
g(this);
2229 if ( MoveBwd( bReformat
) )
2231 SAL_WARN_IF(oDeleteListener
&& oDeleteListener
->WasDeleted(), "sw.layout", "SwFootnoteBossFrame unexpectedly deleted");
2233 aRectFnSet
.Refresh(this);
2235 aNotify
.SetLowersComplete( false );
2236 if (bFootnotesInDoc
&& !oDeleteListener
->WasDeleted())
2237 MoveLowerFootnotes( nullptr, pOldBoss
, nullptr, true );
2238 if ( bReformat
|| bKeep
)
2240 tools::Long nOldTop
= aRectFnSet
.GetTop(getFrameArea());
2242 if( nOldTop
!= aRectFnSet
.GetTop(getFrameArea()) )
2244 SwHTMLTableLayout
*pHTMLLayout
=
2245 GetTable()->GetHTMLTableLayout();
2249 m_bCalcLowers
|= pHTMLLayout
->Resize(
2250 pHTMLLayout
->GetBrowseWidthByTabFrame( *this ) );
2253 setFramePrintAreaValid(false);
2257 oAccess
.emplace(SwFrame::GetCache(), this);
2258 pAttrs
= oAccess
->Get();
2260 Format( getRootFrame()->GetCurrShell()->GetOut(), pAttrs
);
2265 lcl_RecalcTable( *this, nullptr, aNotify
);
2267 m_bLowersFormatted
= true;
2268 if ( bKeep
&& KEEPTAB
)
2271 // Consider case that table is inside another table,
2272 // because it has to be avoided, that superior table
2274 // Thus, find next content, table or section
2275 // and, if a section is found, get its first
2277 if ( nullptr != sw_FormatNextContentForKeep( this ) && !GetNext() )
2279 setFrameAreaPositionValid(false);
2286 //Again an invalid value? - do it again...
2287 if ( !isFrameAreaPositionValid() || !isFrameAreaSizeValid() || !isFramePrintAreaValid() )
2290 // check, if calculation of table frame is ready.
2292 // Local variable <nDistanceToUpperPrtBottom>
2293 // Introduce local variable and init it with the distance from the
2294 // table frame bottom to the bottom of the upper printing area.
2295 // Note: negative values denotes the situation that table frame doesn't fit in its upper.
2296 SwTwips nDistanceToUpperPrtBottom
=
2297 aRectFnSet
.BottomDist(getFrameArea(), aRectFnSet
.GetPrtBottom(*GetUpper()));
2299 /// In online layout try to grow upper of table frame, if table frame doesn't fit in its upper.
2300 const SwViewShell
*pSh
= getRootFrame()->GetCurrShell();
2301 const bool bBrowseMode
= pSh
&& pSh
->GetViewOptions()->getBrowseMode();
2302 if ( nDistanceToUpperPrtBottom
< 0 && bBrowseMode
)
2304 if ( GetUpper()->Grow( -nDistanceToUpperPrtBottom
) )
2306 // upper is grown --> recalculate <nDistanceToUpperPrtBottom>
2307 nDistanceToUpperPrtBottom
= aRectFnSet
.BottomDist(getFrameArea(), aRectFnSet
.GetPrtBottom(*GetUpper()));
2311 if (GetFollow() && GetUpper()->IsFlyFrame())
2313 auto pUpper
= static_cast<SwFlyFrame
*>(GetUpper());
2314 if (pUpper
->IsFlySplitAllowed())
2316 // We have a follow tab frame that may be joined, and we're directly in a split fly.
2317 // See if the fly could grow.
2318 SwTwips nTest
= GetUpper()->Grow(LONG_MAX
, /*bTst=*/true);
2319 if (nTest
>= aRectFnSet
.GetHeight(GetFollow()->getFrameArea()))
2321 // We have space to join at least one follow tab frame.
2322 SwTwips nRequest
= 0;
2323 for (SwTabFrame
* pFollow
= GetFollow(); pFollow
; pFollow
= pFollow
->GetFollow())
2325 nRequest
+= aRectFnSet
.GetHeight(pFollow
->getFrameArea());
2327 // Try to grow the split fly to join all follows.
2328 pUpper
->Grow(nRequest
);
2329 // Determine what is space we actually got from the requested space.
2330 nDistanceToUpperPrtBottom
= aRectFnSet
.BottomDist(getFrameArea(), aRectFnSet
.GetPrtBottom(*pUpper
));
2335 // If there is still some space left in the upper, we check if we
2336 // can join some rows of the follow.
2337 // Setting bLastRowHasToMoveToFollow to true means we want to force
2338 // the table to be split! Only skip this if condition once.
2339 if( nDistanceToUpperPrtBottom
>= 0 && !bLastRowHasToMoveToFollow
)
2341 // If there is space left in the upper printing area, join as for trial
2342 // at least one further row of an existing follow.
2343 if ( !bSplit
&& GetFollow() )
2346 if (!(HasFollowFlowLine()
2347 && GetFollow()->GetFirstNonHeadlineRow()->IsDeleteForbidden())
2348 && GetFollow()->ShouldBwdMoved(GetUpper(), bDummy
))
2350 SwFrame
*pTmp
= GetUpper();
2351 SwTwips nDeadLine
= aRectFnSet
.GetPrtBottom(*pTmp
);
2353 nDeadLine
+= pTmp
->Grow( LONG_MAX
, true );
2354 bool bFits
= aRectFnSet
.BottomDist(getFrameArea(), nDeadLine
) > 0;
2355 if (!bFits
&& aRectFnSet
.GetHeight(GetFollow()->getFrameArea()) == 0)
2356 // The follow should move backwards, so allow the case
2357 // when the upper has no space, but the follow is
2359 bFits
= aRectFnSet
.BottomDist(getFrameArea(), nDeadLine
) >= 0;
2363 // The follow table's wants to move backwards, see if the first row has a
2364 // split fly anchored in it that would have more space than what we have:
2365 SwRowFrame
* pRow
= GetFollow()->GetFirstNonHeadlineRow();
2368 SwPageFrame
* pPage
= GetFollow()->FindPageFrame();
2369 SwSortedObjs
* pPageObjs
= pPage
->GetSortedObjs();
2372 bool bSplitFly
= false;
2373 for (size_t i
= 0; i
< pPageObjs
->size(); ++i
)
2375 SwAnchoredObject
* pAnchoredObj
= (*pPage
->GetSortedObjs())[i
];
2376 auto pFly
= pAnchoredObj
->DynCastFlyFrame();
2377 if (!pFly
|| !pFly
->IsFlySplitAllowed())
2382 SwFrame
* pFlyAnchor
= pFly
->FindAnchorCharFrame();
2383 if (!pFlyAnchor
|| !pRow
->IsAnLower(pFlyAnchor
))
2391 SwTwips nFollowFirstRowHeight
= aRectFnSet
.GetHeight(pRow
->getFrameArea());
2392 SwTwips nSpace
= aRectFnSet
.BottomDist(getFrameArea(), nDeadLine
);
2393 if (bSplitFly
&& nFollowFirstRowHeight
> 0 && nSpace
< nFollowFirstRowHeight
)
2395 // The row has at least one split fly and the row would not fit
2396 // to our remaining space, when also taking flys into account,
2397 // so that's not a fit.
2406 // First, we remove an existing follow flow line.
2407 if ( HasFollowFlowLine() )
2409 SwFrame
* pLastLine
= GetLastLower();
2410 RemoveFollowFlowLine();
2411 // invalidate and rebuild last row
2414 ::SwInvalidateAll( pLastLine
, LONG_MAX
);
2415 SetRebuildLastLine( true );
2416 lcl_RecalcRow(*static_cast<SwRowFrame
*>(pLastLine
), LONG_MAX
);
2417 SetRebuildLastLine( false );
2420 SwFrame
* pRow
= GetFollow()->GetFirstNonHeadlineRow();
2422 if ( !pRow
|| !pRow
->GetNext() )
2423 // The follow became empty and hence useless
2429 // If there is no follow flow line, we move the first
2430 // row in the follow table to the master table.
2431 SwRowFrame
*pRow
= GetFollow()->GetFirstNonHeadlineRow();
2433 // The follow became empty and hence useless
2440 const SwTwips nOld
= aRectFnSet
.GetHeight(getFrameArea());
2441 tools::Long nRowsToMove
= lcl_GetMaximumLayoutRowSpan( *pRow
);
2442 SwFrame
* pRowToMove
= pRow
;
2444 while ( pRowToMove
&& nRowsToMove
-- > 0 )
2446 const bool bMoveFootnotes
= bFootnotesInDoc
&& !GetFollow()->IsJoinLocked();
2448 SwFootnoteBossFrame
*pOldBoss
= nullptr;
2449 if ( bMoveFootnotes
)
2450 pOldBoss
= pRowToMove
->FindFootnoteBossFrame( true );
2452 SwFrame
* pNextRow
= pRowToMove
->GetNext();
2456 // The follow became empty and hence useless
2462 pRowToMove
->Paste( this );
2465 // Move the footnotes!
2466 if ( bMoveFootnotes
)
2467 if ( static_cast<SwLayoutFrame
*>(pRowToMove
)->MoveLowerFootnotes( nullptr, pOldBoss
, FindFootnoteBossFrame( true ), true ) )
2468 GetUpper()->Calc(pRenderContext
);
2470 pRowToMove
= pNextRow
;
2473 if ( nOld
!= aRectFnSet
.GetHeight(getFrameArea()) )
2474 lcl_RecalcTable( *this, static_cast<SwLayoutFrame
*>(pRow
), aNotify
);
2482 bool bFormat
= false;
2485 else if ( bTableRowKeep
&& !bLastRowMoveNoMoreTries
)
2487 // We only want to give the last row one chance to move
2488 // to the follow table. Set the flag as early as possible:
2489 bLastRowMoveNoMoreTries
= true;
2491 // The last line of the table has to be cut off if:
2492 // 1. The table does not want to keep with its next
2493 // 2. The compatibility option is set and the table is allowed to split
2494 // 3. We did not already cut off the last row
2495 // 4. There is not break after attribute set at the table
2496 // 5. There is no break before attribute set behind the table
2497 // 6. There is no section change behind the table (see IsKeep)
2498 // 7. The last table row wants to keep with its next.
2499 const SwRowFrame
* pLastRow
= static_cast<const SwRowFrame
*>(GetLastLower());
2504 oAccess
.emplace(SwFrame::GetCache(), this);
2505 pAttrs
= oAccess
->Get();
2507 if (IsKeep(pAttrs
->GetAttrSet().GetKeep(), GetBreakItem(), true)
2508 && pLastRow
->ShouldRowKeepWithNext())
2519 // Consider case that table is inside another table, because
2520 // it has to be avoided, that superior table is formatted.
2521 // Thus, find next content, table or section and, if a section
2522 // is found, get its first content.
2523 const SwFrame
* pTmpNxt
= sw_FormatNextContentForKeep( this );
2525 // The last row wants to keep with the frame behind the table.
2526 // Check if the next frame is on a different page and valid.
2527 // In this case we do a magic trick:
2528 if ( !bKeep
&& !GetNext() && pTmpNxt
&& pTmpNxt
->isFrameAreaDefinitionValid() )
2530 setFrameAreaPositionValid(false);
2531 bLastRowHasToMoveToFollow
= true;
2536 if ( isFrameAreaDefinitionValid() )
2540 lcl_RecalcTable( *this, nullptr, aNotify
);
2541 m_bLowersFormatted
= true;
2542 m_bCalcLowers
= false;
2544 else if (m_bONECalcLowers
)
2546 // tdf#147526 is a case of a macro which results in a null Lower() result
2547 if (SwRowFrame
* pLower
= static_cast<SwRowFrame
*>(Lower()))
2548 lcl_RecalcRow(*pLower
, LONG_MAX
);
2549 m_bONECalcLowers
= false;
2555 // I don't fit in the upper Frame anymore, therefore it's the
2556 // right moment to do some preferably constructive changes.
2558 // If I'm NOT allowed to leave the upper Frame, I've got a problem.
2559 // Following Arthur Dent, we do the only thing that you can do with
2560 // an unsolvable problem: We ignore it with all our power.
2563 if (m_bCalcLowers
&& isFrameAreaDefinitionValid())
2565 lcl_RecalcTable( *this, nullptr, aNotify
);
2566 m_bLowersFormatted
= true;
2567 m_bCalcLowers
= false;
2569 else if (m_bONECalcLowers
)
2571 lcl_RecalcRow(*static_cast<SwRowFrame
*>(Lower()), LONG_MAX
);
2572 m_bONECalcLowers
= false;
2575 // It does not make sense to cut off the last line if we are
2577 bLastRowHasToMoveToFollow
= false;
2582 if (m_bCalcLowers
&& isFrameAreaDefinitionValid())
2584 lcl_RecalcTable( *this, nullptr, aNotify
);
2585 m_bLowersFormatted
= true;
2586 m_bCalcLowers
= false;
2587 if( !isFrameAreaDefinitionValid() )
2591 // First try to split the table. Condition:
2592 // 1. We have at least one non headline row
2593 // 2. If this row wants to keep, we need an additional row
2594 // 3. The table is allowed to split or we do not have a pIndPrev:
2595 SwFrame
* pIndPrev
= GetIndPrev();
2597 SwFlyFrame
* pFly
= FindFlyFrame();
2598 if (!pIndPrev
&& pFly
&& pFly
->IsFlySplitAllowed())
2600 auto pFlyAtContent
= static_cast<SwFlyAtContentFrame
*>(pFly
);
2601 SwFrame
* pAnchor
= pFlyAtContent
->FindAnchorCharFrame();
2604 // If the anchor of the split has a previous frame, we're allowed to move forward.
2605 pIndPrev
= pAnchor
->GetIndPrev();
2609 const SwRowFrame
* pFirstNonHeadlineRow
= GetFirstNonHeadlineRow();
2610 // #i120016# if this row wants to keep, allow split in case that all rows want to keep with next,
2611 // the table can not move forward as it is the first one and a split is in general allowed.
2612 const bool bAllowSplitOfRow
= bTableRowKeep
&& !pIndPrev
&& AreAllRowsKeepWithNext(pFirstNonHeadlineRow
);
2613 // tdf91083 MSCompat: this extends bAllowSplitOfRow (and perhaps should just replace it).
2614 // If the kept-together items cannot move to a new page, a table split is in general allowed.
2615 const bool bEmulateTableKeepSplitAllowed
= bEmulateTableKeep
&& !IsKeepFwdMoveAllowed(/*IgnoreMyOwnKeepValue=*/true);
2617 if ( pFirstNonHeadlineRow
&& nUnSplitted
> 0 &&
2618 ( bEmulateTableKeepSplitAllowed
|| bAllowSplitOfRow
||
2619 ( ( !bTableRowKeep
|| pFirstNonHeadlineRow
->GetNext() ||
2620 !pFirstNonHeadlineRow
->ShouldRowKeepWithNext()
2621 ) && ( !bDontSplit
|| !pIndPrev
)
2625 // Special DoNotSplit cases:
2626 // We better avoid splitting of a row frame if we are inside a columned
2627 // section which has a height of 0, because this is not growable and thus
2628 // all kinds of unexpected things could happen.
2629 if ( IsInSct() && FindSctFrame()->Lower()->IsColumnFrame() &&
2630 0 == aRectFnSet
.GetHeight(GetUpper()->getFrameArea())
2633 bTryToSplit
= false;
2636 // 1. Try: bTryToSplit = true => Try to split the row.
2637 // 2. Try: bTryToSplit = false => Split the table between the rows.
2638 if ( pFirstNonHeadlineRow
->GetNext() || bTryToSplit
)
2640 SwTwips nDeadLine
= aRectFnSet
.GetPrtBottom(*GetUpper());
2641 bool bFlySplit
= false;
2642 if (GetUpper()->IsFlyFrame())
2644 // See if this is a split fly that can also grow.
2645 auto pUpperFly
= static_cast<SwFlyFrame
*>(GetUpper());
2646 bFlySplit
= pUpperFly
->IsFlySplitAllowed();
2648 if (bFlySplit
&& bTryToSplit
)
2650 // This is a split fly that wants to split the row itself. See if it's also
2651 // nested. If so, we'll want to know if the row split has rowspans.
2652 SwTextFrame
* pAnchorCharFrame
= pUpperFly
->FindAnchorCharFrame();
2653 if (pAnchorCharFrame
&& pAnchorCharFrame
->IsInFly())
2655 // Find the row we'll split.
2657 = aRectFnSet
.YDiff(nDeadLine
, aRectFnSet
.GetTop(getFrameArea()));
2658 nRemaining
-= aRectFnSet
.GetTopMargin(*this);
2659 const SwFrame
* pRow
= Lower();
2660 for (; pRow
->GetNext(); pRow
= pRow
->GetNext())
2662 if (nRemaining
< aRectFnSet
.GetHeight(pRow
->getFrameArea()))
2667 nRemaining
-= aRectFnSet
.GetHeight(pRow
->getFrameArea());
2669 // See if any cells have rowspans.
2670 for (const SwFrame
* pLower
= pRow
->GetLower(); pLower
;
2671 pLower
= pLower
->GetNext())
2673 auto pCellFrame
= static_cast<const SwCellFrame
*>(pLower
);
2674 if (pCellFrame
->GetTabBox()->getRowSpan() != 1)
2676 // The cell has a rowspan, don't split the row itself in this
2677 // case (but just move it forward, i.e. split between the rows).
2678 bTryToSplit
= false;
2685 if( IsInSct() || GetUpper()->IsInTab() || bFlySplit
)
2686 nDeadLine
= aRectFnSet
.YInc( nDeadLine
,
2687 GetUpper()->Grow( LONG_MAX
, true ) );
2690 SwFrameDeleteGuard
g(Lower()); // tdf#134965 prevent RemoveFollowFlowLine()
2691 SetInRecalcLowerRow( true );
2692 ::lcl_RecalcRow(*static_cast<SwRowFrame
*>(Lower()), nDeadLine
);
2693 SetInRecalcLowerRow( false );
2695 m_bLowersFormatted
= true;
2696 aNotify
.SetLowersComplete( true );
2698 // One more check if it's really necessary to split the table.
2699 // 1. The table either has to exceed the deadline or
2700 // 2. We explicitly want to cut off the last row.
2701 if( aRectFnSet
.BottomDist( getFrameArea(), nDeadLine
) > 0 && !bLastRowHasToMoveToFollow
)
2706 // Set to false again as early as possible.
2707 bLastRowHasToMoveToFollow
= false;
2710 // YaSC - Yet another special case:
2711 // If our upper is inside a table cell which is not allowed
2712 // to split, we do not try to split:
2713 if ( GetUpper()->IsInTab() )
2715 const SwFrame
* pTmpRow
= GetUpper();
2716 while ( pTmpRow
&& !pTmpRow
->IsRowFrame() )
2717 pTmpRow
= pTmpRow
->GetUpper();
2718 if ( pTmpRow
&& !static_cast<const SwRowFrame
*>(pTmpRow
)->IsRowSplitAllowed() )
2722 sal_uInt16 nMinNumOfLines
= nRepeat
;
2724 if ( bTableRowKeep
)
2726 const SwRowFrame
* pTmpRow
= GetFirstNonHeadlineRow();
2727 while ( pTmpRow
&& pTmpRow
->ShouldRowKeepWithNext() )
2730 pTmpRow
= static_cast<const SwRowFrame
*>(pTmpRow
->GetNext());
2737 const SwTwips nBreakLine
= aRectFnSet
.YInc(
2738 aRectFnSet
.GetTop(getFrameArea()),
2739 aRectFnSet
.GetTopMargin(*this) +
2740 lcl_GetHeightOfRows( GetLower(), nMinNumOfLines
) );
2742 // Some more checks if we want to call the split algorithm or not:
2743 // The repeating lines / keeping lines still fit into the upper or
2744 // if we do not have an (in)direct Prev, we split anyway.
2745 if( aRectFnSet
.YDiff(nDeadLine
, nBreakLine
) >=0
2746 || !pIndPrev
|| bEmulateTableKeepSplitAllowed
)
2748 aNotify
.SetLowersComplete( false );
2751 // An existing follow flow line has to be removed.
2752 if ( HasFollowFlowLine() )
2754 if (!nThrowAwayValidLayoutLimit
)
2756 const bool bInitialLoopEndCondition(isFrameAreaDefinitionValid());
2757 RemoveFollowFlowLine();
2758 const bool bFinalLoopEndCondition(isFrameAreaDefinitionValid());
2760 if (bInitialLoopEndCondition
&& !bFinalLoopEndCondition
)
2762 --nThrowAwayValidLayoutLimit
;
2767 bool isFootnoteGrowth(false);
2768 const bool bSplitError
= !Split(nDeadLine
, bTryToSplit
,
2769 (bTableRowKeep
&& !(bAllowSplitOfRow
|| bEmulateTableKeepSplitAllowed
)),
2772 // tdf#130639 don't start table on a new page after the fallback "switch off repeating header"
2773 if (bSplitError
&& nRepeat
> GetTable()->GetRowsToRepeat())
2775 setFrameAreaPositionValid(false);
2779 if (!bTryToSplit
&& !bSplitError
)
2784 // #i29771# Two tries to split the table
2785 // If an error occurred during splitting. We start a second
2786 // try, this time without splitting of table rows.
2787 if ( bSplitError
&& HasFollowFlowLine() )
2788 RemoveFollowFlowLine();
2790 // If splitting the table was successful or not,
2791 // we do not want to have 'empty' follow tables.
2792 if ( GetFollow() && !GetFollow()->GetFirstNonHeadlineRow() )
2795 // We want to restore the situation before the failed
2796 // split operation as good as possible. Therefore we
2797 // do some more calculations. Note: Restricting this
2798 // to nDeadLine may not be enough.
2799 if ( bSplitError
&& bTryToSplit
) // no restart if we did not try to split: i72847, i79426
2801 lcl_RecalcRow(*static_cast<SwRowFrame
*>(Lower()), LONG_MAX
);
2802 setFrameAreaPositionValid(false);
2803 // tdf#156724 if the table added footnotes, try to split *again*
2804 if (!isFootnoteGrowth
)
2806 bTryToSplit
= false;
2811 bTryToSplit
= !bSplitError
;
2813 //To avoid oscillations the Follow must become valid now
2817 // After a successful split assure that the first row
2818 // is invalid. When graphics are present, this isn't hold.
2819 // Note: defect i80924 could also be fixed, if it is
2820 // assured, that <SwLayNotify::bLowersComplete> is only
2821 // set, if all lower are valid *and* are correct laid out.
2822 if ( !bSplitError
&& GetFollow()->GetLower() )
2824 GetFollow()->GetLower()->InvalidatePos();
2826 SwRectFnSet
fnRectX(GetFollow());
2828 static sal_uInt8 nStack
= 0;
2829 if ( !StackHack::IsLocked() && nStack
< 4 )
2835 GetFollow()->MakeAll(pRenderContext
);
2837 GetFollow()->SetLowersFormatted(false);
2838 // #i43913# - lock follow table
2839 // to avoid its formatting during the format of
2841 const bool bOldJoinLock
= GetFollow()->IsJoinLocked();
2842 GetFollow()->LockJoin();
2843 ::lcl_RecalcRow(*static_cast<SwRowFrame
*>(GetFollow()->Lower()),
2844 fnRectX
.GetBottom(GetFollow()->GetUpper()->getFrameArea()) );
2846 // #i63632# Do not unlock the
2847 // follow if it wasn't locked before.
2848 if ( !bOldJoinLock
)
2849 GetFollow()->UnlockJoin();
2851 if ( !GetFollow()->GetFollow() )
2853 SwFrame
* pNxt
= static_cast<SwFrame
*>(GetFollow())->FindNext();
2856 // #i18103# - no formatting of found next
2857 // frame, if it's a follow section of the
2858 // 'ColLocked' section, the follow table is
2860 bool bCalcNxt
= true;
2861 if ( GetFollow()->IsInSct() && pNxt
->IsSctFrame() )
2863 SwSectionFrame
* pSct
= GetFollow()->FindSctFrame();
2864 if ( pSct
->IsColLocked() &&
2865 pSct
->GetFollow() == pNxt
)
2872 // tdf#119109 follow was just formatted,
2873 // don't do it again now
2874 FlowFrameJoinLockGuard
g(GetFollow());
2875 pNxt
->Calc(pRenderContext
);
2882 else if ( GetFollow() == GetNext() )
2883 GetFollow()->MoveFwd( true, false );
2890 // Set to false again as early as possible.
2891 bLastRowHasToMoveToFollow
= false;
2893 if( IsInSct() && bMovedFwd
&& bMakePage
&& GetUpper()->IsColBodyFrame() &&
2894 GetUpper()->GetUpper()->GetUpper()->IsSctFrame() &&
2895 ( GetUpper()->GetUpper()->GetPrev() || GetIndPrev() ) &&
2896 static_cast<SwSectionFrame
*>(GetUpper()->GetUpper()->GetUpper())->MoveAllowed(this) )
2901 // #i29771# Reset bTryToSplit flag on change of upper
2902 const SwFrame
* pOldUpper
= GetUpper();
2904 //Let's see if we find some place anywhere...
2907 bool bMoveAlways
= false;
2908 SwFrame
* pUpper
= GetUpper();
2909 if (pUpper
&& pUpper
->IsFlyFrame())
2911 auto pFlyFrame
= static_cast<SwFlyFrame
*>(pUpper
);
2912 if (pFlyFrame
->IsFlySplitAllowed())
2914 // If the anchor of the split has a previous frame, MoveFwd() is allowed to move
2919 // don't make the effort to move fwd if its known
2920 // conditions that are known not to work
2921 if (IsInFootnote() && ForbiddenForFootnoteCntFwd())
2923 else if (!MoveFwd(bMakePage
, false, bMoveAlways
))
2927 // #i29771# Reset bSplitError flag on change of upper
2928 if ( GetUpper() != pOldUpper
)
2934 aRectFnSet
.Refresh(this);
2935 m_bCalcLowers
= true;
2937 aNotify
.SetLowersComplete( false );
2940 // To avoid oscillations, master should not remain invalid
2941 SwTabFrame
*pTab
= FindMaster();
2942 if ( pTab
->GetUpper() )
2943 pTab
->GetUpper()->Calc(pRenderContext
);
2944 pTab
->Calc(pRenderContext
);
2945 pTab
->SetLowersFormatted( false );
2948 //If my neighbour is my Follow at the same time, I'll swallow it up.
2949 if ( ( GetNext() && GetNext() == GetFollow() ) || !GetLower() )
2951 if ( HasFollowFlowLine() )
2952 RemoveFollowFlowLine();
2956 else if (!GetNext() && !HasFollowFlowLine() && GetFollow()
2957 && (getFrameArea().Bottom() + GetFollow()->getFrameArea().Height())
2958 < GetUpper()->getFrameArea().Bottom())
2960 // We're the last lower of the upper, no split row and we have a follow. That follow
2961 // fits our upper, still. Prefer joining that follow in the next iteration, instead of
2962 // trying to split the current table.
2966 if ( bMovedBwd
&& GetUpper() )
2968 //During flowing back the upper was animated to do a full repaint,
2969 //we can now skip this after the whole flowing back and forth.
2970 GetUpper()->ResetCompletePaint();
2973 if (m_bCalcLowers
&& isFrameAreaDefinitionValid())
2975 // #i44910# - format of lower frames unnecessary
2976 // and can cause layout loops, if table doesn't fit and isn't
2977 // allowed to split.
2978 SwTwips nDistToUpperPrtBottom
=
2979 aRectFnSet
.BottomDist( getFrameArea(), aRectFnSet
.GetPrtBottom(*GetUpper()));
2981 if (GetUpper()->IsFlyFrame())
2983 SwFlyFrame
* pFlyFrame
= GetUpper()->FindFlyFrame();
2984 if (pFlyFrame
->IsFlySplitAllowed())
2986 SwTextFrame
* pAnchor
= pFlyFrame
->FindAnchorCharFrame();
2987 if (pAnchor
&& pAnchor
->HasFollow())
2989 // The split fly's anchor has a follow frame, we can move there & try to
2996 if ( nDistToUpperPrtBottom
>= 0 || bTryToSplit
)
2998 lcl_RecalcTable( *this, nullptr, aNotify
);
2999 m_bLowersFormatted
= true;
3000 m_bCalcLowers
= false;
3001 if (!isFramePrintAreaValid())
3002 m_pTable
->SetRowsToRepeat(1);
3004 #if OSL_DEBUG_LEVEL > 0
3007 OSL_FAIL( "debug assertion: <SwTabFrame::MakeAll()> - format of table lowers suppressed by fix i44910" );
3012 } //while ( !isFrameAreaPositionValid() || !isFrameAreaSizeValid() || !isFramePrintAreaValid() )
3014 //If my direct predecessor is my master now, it can destroy me during the
3015 //next best opportunity.
3018 SwFrame
*pPre
= GetPrev();
3019 if ( pPre
&& pPre
->IsTabFrame() && static_cast<SwTabFrame
*>(pPre
)->GetFollow() == this)
3020 pPre
->InvalidatePos();
3023 m_bCalcLowers
= m_bONECalcLowers
= false;
3026 if ( bMovedFwd
|| bMovedBwd
|| !bOldValidPos
)
3027 aNotify
.SetInvaKeep();
3030 static bool IsNextOnSamePage(SwPageFrame
const& rPage
,
3031 SwTabFrame
const& rTabFrame
, SwTextFrame
const& rAnchorFrame
)
3033 for (SwContentFrame
const* pContentFrame
= rTabFrame
.FindNextCnt();
3034 pContentFrame
&& pContentFrame
->FindPageFrame() == &rPage
;
3035 pContentFrame
= pContentFrame
->FindNextCnt())
3037 if (pContentFrame
== &rAnchorFrame
)
3045 /// Calculate the offsets arising because of FlyFrames
3046 bool SwTabFrame::CalcFlyOffsets( SwTwips
& rUpper
,
3047 tools::Long
& rLeftOffset
,
3048 tools::Long
& rRightOffset
,
3049 SwTwips
*const pSpaceBelowBottom
) const
3051 bool bInvalidatePrtArea
= false;
3052 const SwPageFrame
*pPage
= FindPageFrame();
3053 const SwFlyFrame
* pMyFly
= FindFlyFrame();
3055 // --> #108724# Page header/footer content doesn't have to wrap around
3056 // floating screen objects
3058 const IDocumentSettingAccess
& rIDSA
= GetFormat()->getIDocumentSettingAccess();
3059 const bool bWrapAllowed
= rIDSA
.get(DocumentSettingId::USE_FORMER_TEXT_WRAPPING
) ||
3060 ( !IsInFootnote() && nullptr == FindFooterOrHeader() );
3062 if (!bWrapAllowed
|| !pPage
->GetSortedObjs())
3063 return bInvalidatePrtArea
;
3065 SwRectFnSet
aRectFnSet(this);
3066 const bool bConsiderWrapOnObjPos
3067 = rIDSA
.get(DocumentSettingId::CONSIDER_WRAP_ON_OBJECT_POSITION
);
3068 tools::Long nPrtPos
= aRectFnSet
.GetTop(getFrameArea());
3069 nPrtPos
= aRectFnSet
.YInc(nPrtPos
, rUpper
);
3070 SwRect
aRect(getFrameArea());
3071 if (pSpaceBelowBottom
)
3073 // set to space below table frame
3074 aRectFnSet
.SetTopAndHeight(aRect
, aRectFnSet
.GetBottom(aRect
), *pSpaceBelowBottom
);
3078 tools::Long nYDiff
= aRectFnSet
.YDiff(aRectFnSet
.GetTop(getFramePrintArea()), rUpper
);
3080 aRectFnSet
.AddBottom(aRect
, -nYDiff
);
3083 bool bAddVerticalFlyOffsets
= rIDSA
.get(DocumentSettingId::ADD_VERTICAL_FLY_OFFSETS
);
3085 for (size_t i
= 0; i
< pPage
->GetSortedObjs()->size(); ++i
)
3087 SwAnchoredObject
* pAnchoredObj
= (*pPage
->GetSortedObjs())[i
];
3088 auto pFly
= pAnchoredObj
->DynCastFlyFrame();
3092 const SwRect aFlyRect
= pFly
->GetObjRectWithSpaces();
3093 // #i26945# - correction of conditions,
3094 // if Writer fly frame has to be considered:
3095 // - no need to check, if top of Writer fly frame differs
3096 // from FAR_AWAY, because it's also checked, if the Writer
3097 // fly frame rectangle overlaps with <aRect>
3098 // - no check, if bottom of anchor frame is prior the top of
3099 // the table, because Writer fly frames can be negative positioned.
3100 // - correct check, if the Writer fly frame is a lower of the
3101 // table, because table lines/rows can split and an at-character
3102 // anchored Writer fly frame could be positioned in the follow
3104 // - add condition, that an existing anchor character text frame
3105 // has to be on the same page as the table.
3106 // E.g., it could happen, that the fly frame is still registered
3107 // at the page frame, the table is on, but it's anchor character
3108 // text frame has already changed its page.
3109 const SwTextFrame
* pAnchorCharFrame
= pFly
->FindAnchorCharFrame();
3110 const SwFormatHoriOrient
& rHori
= pFly
->GetFormat()->GetHoriOrient();
3111 // TODO: why not just ignore HoriOrient?
3112 bool isHoriOrientShiftDown
=
3113 rHori
.GetHoriOrient() == text::HoriOrientation::NONE
3114 || rHori
.GetHoriOrient() == text::HoriOrientation::LEFT
;
3115 // Only consider invalid Writer fly frames if they'll be shifted down.
3116 bool bIgnoreFlyValidity
= bAddVerticalFlyOffsets
&& isHoriOrientShiftDown
;
3118 // #i46807# - do not consider invalid
3119 // Writer fly frames.
3120 (pFly
->isFrameAreaDefinitionValid() || bIgnoreFlyValidity
)
3121 // fly anchored at character or at paragraph
3122 && pFly
->IsFlyAtContentFrame()
3123 // fly overlaps with corresponding table rectangle
3124 && aFlyRect
.Overlaps(aRect
)
3125 // fly isn't lower of table and
3126 // anchor character frame of fly isn't lower of table
3127 && (pSpaceBelowBottom
// not if in ShouldBwdMoved
3128 || (!IsAnLower(pFly
) && (!pAnchorCharFrame
|| !IsAnLower(pAnchorCharFrame
))))
3129 // table isn't lower of fly
3130 && !pFly
->IsAnLower(this)
3131 // fly is lower of fly, the table is in
3132 // #123274# - correction
3133 // assure that fly isn't a lower of a fly, the table isn't in.
3134 // E.g., a table in the body doesn't wrap around a graphic,
3135 // which is inside a frame.
3136 && (!pMyFly
|| pMyFly
->IsAnLower(pFly
))
3137 && pMyFly
== pFly
->GetAnchorFrameContainingAnchPos()->FindFlyFrame()
3138 // anchor frame not on following page
3139 && pPage
->GetPhyPageNum() >= pFly
->GetAnchorFrame()->FindPageFrame()->GetPhyPageNum()
3140 // anchor character text frame on same page
3141 && (!pAnchorCharFrame
||
3142 pAnchorCharFrame
->FindPageFrame()->GetPhyPageNum() == pPage
->GetPhyPageNum());
3147 const SwFrame
* pFlyHeaderFooterFrame
= pFly
->GetAnchorFrame()->FindFooterOrHeader();
3148 const SwFrame
* pThisHeaderFooterFrame
= FindFooterOrHeader();
3149 if (pFlyHeaderFooterFrame
!= pThisHeaderFooterFrame
3150 // #148493# If bConsiderWrapOnObjPos is set,
3151 // we want to consider the fly if it is located in the header and
3152 // the table is located in the body:
3153 && (!bConsiderWrapOnObjPos
|| nullptr != pThisHeaderFooterFrame
3154 || !pFlyHeaderFooterFrame
->IsHeaderFrame()))
3159 text::WrapTextMode nSurround
= pFly
->GetFormat()->GetSurround().GetSurround();
3160 // If the frame format is a TextBox of a draw shape,
3161 // then use the surround of the original shape.
3162 bool bWrapThrough
= nSurround
== text::WrapTextMode_THROUGH
;
3163 SwTextBoxHelper::getShapeWrapThrough(pFly
->GetFormat(), bWrapThrough
);
3166 if (!bWrapThrough
&& nSurround
== text::WrapTextMode_THROUGH
)
3167 nSurround
= text::WrapTextMode_PARALLEL
;
3169 bool bShiftDown
= css::text::WrapTextMode_NONE
== nSurround
;
3170 if (!bShiftDown
&& bAddVerticalFlyOffsets
)
3172 if (nSurround
== text::WrapTextMode_PARALLEL
&& isHoriOrientShiftDown
)
3174 // We know that wrapping was requested and the table frame overlaps with
3175 // the fly frame. Check if the print area overlaps with the fly frame as
3176 // well (in case the table does not use all the available width).
3177 basegfx::B1DRange
aTabRange(
3178 aRectFnSet
.GetLeft(aRect
) + aRectFnSet
.GetLeft(getFramePrintArea()),
3179 aRectFnSet
.GetLeft(aRect
) + aRectFnSet
.GetLeft(getFramePrintArea())
3180 + aRectFnSet
.GetWidth(getFramePrintArea()));
3182 // Ignore spacing when determining the left/right edge of the fly, like
3184 const SwRect aFlyRectWithoutSpaces
= pFly
->GetObjRect();
3185 basegfx::B1DRange
aFlyRange(aRectFnSet
.GetLeft(aFlyRectWithoutSpaces
),
3186 aRectFnSet
.GetRight(aFlyRectWithoutSpaces
));
3188 // If it does, shift the table down. Do this only in the compat case,
3189 // normally an SwFlyPortion is created instead that increases the height
3190 // of the first table row.
3191 bShiftDown
= aTabRange
.overlaps(aFlyRange
);
3200 // any comb. of body, footnote, header/footer
3201 // to keep it safe, check only in doc body vs page margin for now
3202 tools::Long nBottom
= aRectFnSet
.GetBottom(aFlyRect
);
3203 // tdf#138039 don't grow beyond the page body
3204 // if the fly is anchored below the table; the fly
3205 // must move with its anchor frame to the next page
3206 SwRectFnSet
fnPage(pPage
);
3207 if (!IsInDocBody() // TODO
3208 || fnPage
.YDiff(fnPage
.GetBottom(aFlyRect
), fnPage
.GetPrtBottom(*pPage
)) <= 0
3209 || !IsNextOnSamePage(
3211 *static_cast<SwTextFrame
*>(pFly
->GetAnchorFrameContainingAnchPos())))
3213 if (aRectFnSet
.YDiff(nPrtPos
, nBottom
) < 0)
3215 // tdf#116501 subtract flys blocking space from below
3216 // TODO this may not work ideally for multiple flys
3217 if (pSpaceBelowBottom
&& aRectFnSet
.YDiff(aRectFnSet
.GetBottom(aRect
), nBottom
) < 0)
3219 if (aRectFnSet
.YDiff(aRectFnSet
.GetTop(aRect
), aRectFnSet
.GetTop(aFlyRect
)) < 0)
3221 aRectFnSet
.SetBottom(aRect
, aRectFnSet
.GetTop(aFlyRect
));
3225 aRectFnSet
.SetHeight(aRect
, 0);
3228 bInvalidatePrtArea
= true;
3232 if ((css::text::WrapTextMode_RIGHT
== nSurround
3233 || css::text::WrapTextMode_PARALLEL
== nSurround
)
3234 && text::HoriOrientation::LEFT
== rHori
.GetHoriOrient()
3237 const tools::Long nWidth
3238 = aRectFnSet
.XDiff(aRectFnSet
.GetRight(aFlyRect
),
3239 aRectFnSet
.GetLeft(pFly
->GetAnchorFrame()->getFrameArea()));
3240 rLeftOffset
= std::max(rLeftOffset
, nWidth
);
3241 bInvalidatePrtArea
= true;
3243 if ((css::text::WrapTextMode_LEFT
== nSurround
3244 || css::text::WrapTextMode_PARALLEL
== nSurround
)
3245 && text::HoriOrientation::RIGHT
== rHori
.GetHoriOrient())
3247 const tools::Long nWidth
3248 = aRectFnSet
.XDiff(aRectFnSet
.GetRight(pFly
->GetAnchorFrame()->getFrameArea()),
3249 aRectFnSet
.GetLeft(aFlyRect
));
3250 rRightOffset
= std::max(rRightOffset
, nWidth
);
3251 bInvalidatePrtArea
= true;
3254 rUpper
= aRectFnSet
.YDiff( nPrtPos
, aRectFnSet
.GetTop(getFrameArea()) );
3255 if (pSpaceBelowBottom
)
3257 *pSpaceBelowBottom
= aRectFnSet
.GetHeight(aRect
);
3260 return bInvalidatePrtArea
;
3263 /// "Formats" the frame; Frame and PrtArea.
3264 /// The fixed size is not adjusted here.
3265 void SwTabFrame::Format( vcl::RenderContext
* /*pRenderContext*/, const SwBorderAttrs
*pAttrs
)
3267 OSL_ENSURE( pAttrs
, "TabFrame::Format, pAttrs is 0." );
3269 SwRectFnSet
aRectFnSet(this);
3270 if ( !isFrameAreaSizeValid() )
3272 tools::Long nDiff
= aRectFnSet
.GetWidth(GetUpper()->getFramePrintArea()) -
3273 aRectFnSet
.GetWidth(getFrameArea());
3276 SwFrameAreaDefinition::FrameAreaWriteAccess
aFrm(*this);
3277 aRectFnSet
.AddRight( aFrm
, nDiff
);
3281 //VarSize is always the height.
3282 //For the upper/lower margins the same rules apply as for ContentFrames (see
3283 //MakePrtArea() of those).
3285 SwTwips nUpper
= CalcUpperSpace( pAttrs
);
3287 // We want to dodge the flys. Two possibilities:
3288 // 1. There are flys with SurroundNone, dodge them completely
3289 // 2. There are flys which only wrap on the right or the left side and
3290 // those are right or left aligned, those set the minimum for the margins
3291 tools::Long nTmpRight
= -1000000,
3293 if (CalcFlyOffsets(nUpper
, nLeftOffset
, nTmpRight
, nullptr))
3295 setFramePrintAreaValid(false);
3298 tools::Long nRightOffset
= std::max( tools::Long(0), nTmpRight
);
3300 SwTwips nLower
= pAttrs
->CalcBottomLine();
3302 if ( IsCollapsingBorders() )
3303 nLower
+= GetBottomLineSize();
3305 if ( !isFramePrintAreaValid() )
3307 setFramePrintAreaValid(true);
3309 // The width of the PrintArea is given by the FrameFormat, the margins
3310 // have to be set accordingly.
3311 // Minimum margins are determined depending on borders and shadows.
3312 // The margins are set so that the PrintArea is aligned into the
3313 // Frame according to the adjustment.
3314 // If the adjustment is 0, the margins are set according to the border
3317 const SwTwips nOldHeight
= aRectFnSet
.GetHeight(getFramePrintArea());
3318 const SwTwips nMax
= aRectFnSet
.GetWidth(getFrameArea());
3320 // OD 14.03.2003 #i9040# - adjust variable names.
3321 const SwTwips nLeftLine
= pAttrs
->CalcLeftLine();
3322 const SwTwips nRightLine
= pAttrs
->CalcRightLine();
3324 // The width possibly is a percentage value. If the table is inside
3325 // something else, the value refers to the environment. If it's in the
3326 // body then in the BrowseView the value refers to the screen width.
3327 const SwFormatFrameSize
&rSz
= GetFormat()->GetFrameSize();
3328 // OD 14.03.2003 #i9040# - adjust variable name.
3329 const SwTwips nWishedTableWidth
= CalcRel( rSz
);
3331 bool bCheckBrowseWidth
= false;
3333 // OD 14.03.2003 #i9040# - insert new variables for left/right spacing.
3334 SwTwips nLeftSpacing
= 0;
3335 SwTwips nRightSpacing
= 0;
3336 switch ( GetFormat()->GetHoriOrient().GetHoriOrient() )
3338 case text::HoriOrientation::LEFT
:
3341 nLeftSpacing
= nLeftLine
+ nLeftOffset
;
3342 // OD 06.03.2003 #i9040# - correct calculation of right indent:
3343 // - Consider right indent given by right line attributes.
3344 // - Consider negative right indent.
3345 // wished right indent determined by wished table width and
3346 // left offset given by surround fly frames on the left:
3347 const SwTwips nWishRight
= nMax
- nWishedTableWidth
- nLeftOffset
;
3348 if ( nRightOffset
> 0 )
3350 // surrounding fly frames on the right
3351 // -> right indent is maximum of given right offset
3352 // and wished right offset.
3353 nRightSpacing
= nRightLine
+ std::max( SwTwips(nRightOffset
), nWishRight
);
3357 // no surrounding fly frames on the right
3358 // If intrinsic right indent (intrinsic means not considering
3359 // determined left indent) is negative,
3360 // then hold this intrinsic indent,
3361 // otherwise non negative wished right indent is hold.
3362 nRightSpacing
= nRightLine
+
3363 ( ( (nWishRight
+nLeftOffset
) < 0 ) ?
3364 (nWishRight
+nLeftOffset
) :
3365 std::max( SwTwips(0), nWishRight
) );
3369 case text::HoriOrientation::RIGHT
:
3372 nRightSpacing
= nRightLine
+ nRightOffset
;
3373 // OD 06.03.2003 #i9040# - correct calculation of left indent:
3374 // - Consider left indent given by left line attributes.
3375 // - Consider negative left indent.
3376 // wished left indent determined by wished table width and
3377 // right offset given by surrounding fly frames on the right:
3378 const SwTwips nWishLeft
= nMax
- nWishedTableWidth
- nRightOffset
;
3379 if ( nLeftOffset
> 0 )
3381 // surrounding fly frames on the left
3382 // -> right indent is maximum of given left offset
3383 // and wished left offset.
3384 nLeftSpacing
= nLeftLine
+ std::max( SwTwips(nLeftOffset
), nWishLeft
);
3388 // no surrounding fly frames on the left
3389 // If intrinsic left indent (intrinsic = not considering
3390 // determined right indent) is negative,
3391 // then hold this intrinsic indent,
3392 // otherwise non negative wished left indent is hold.
3393 nLeftSpacing
= nLeftLine
+
3394 ( ( (nWishLeft
+nRightOffset
) < 0 ) ?
3395 (nWishLeft
+nRightOffset
) :
3396 std::max( SwTwips(0), nWishLeft
) );
3400 case text::HoriOrientation::CENTER
:
3402 // OD 07.03.2003 #i9040# - consider left/right line attribute.
3403 const SwTwips nCenterSpacing
= ( nMax
- nWishedTableWidth
) / 2;
3404 nLeftSpacing
= nLeftLine
+
3405 ( (nLeftOffset
> 0) ?
3406 std::max( nCenterSpacing
, SwTwips(nLeftOffset
) ) :
3408 nRightSpacing
= nRightLine
+
3409 ( (nRightOffset
> 0) ?
3410 std::max( nCenterSpacing
, SwTwips(nRightOffset
) ) :
3414 case text::HoriOrientation::FULL
:
3415 //This things grows over the whole width.
3416 //Only the free space needed for the border is taken into
3417 //account. The attribute values of LRSpace are ignored
3419 bCheckBrowseWidth
= true;
3420 nLeftSpacing
= nLeftLine
+ nLeftOffset
;
3421 nRightSpacing
= nRightLine
+ nRightOffset
;
3423 case text::HoriOrientation::NONE
:
3425 // The margins are defined by the LRSpace attribute.
3426 nLeftSpacing
= pAttrs
->CalcLeft( this );
3429 // OD 07.03.2003 #i9040# - surround fly frames only, if
3430 // they overlap with the table.
3431 // Thus, take maximum of left spacing and left offset.
3432 // OD 10.03.2003 #i9040# - consider left line attribute.
3433 nLeftSpacing
= std::max( nLeftSpacing
, SwTwips( nLeftOffset
+ nLeftLine
) );
3435 // OD 23.01.2003 #106895# - add 1st param to <SwBorderAttrs::CalcRight(..)>
3436 nRightSpacing
= pAttrs
->CalcRight( this );
3439 // OD 07.03.2003 #i9040# - surround fly frames only, if
3440 // they overlap with the table.
3441 // Thus, take maximum of right spacing and right offset.
3442 // OD 10.03.2003 #i9040# - consider right line attribute.
3443 nRightSpacing
= std::max( nRightSpacing
, SwTwips( nRightOffset
+ nRightLine
) );
3447 case text::HoriOrientation::LEFT_AND_WIDTH
:
3449 // count left border and width (Word specialty)
3450 // OD 10.03.2003 #i9040# - no width alignment in online mode.
3451 //bCheckBrowseWidth = true;
3452 nLeftSpacing
= pAttrs
->CalcLeft( this );
3455 // OD 10.03.2003 #i9040# - surround fly frames only, if
3456 // they overlap with the table.
3457 // Thus, take maximum of right spacing and right offset.
3458 // OD 10.03.2003 #i9040# - consider left line attribute.
3459 nLeftSpacing
= std::max( nLeftSpacing
, SwTwips( pAttrs
->CalcLeftLine() + nLeftOffset
) );
3461 // OD 10.03.2003 #i9040# - consider right and left line attribute.
3462 const SwTwips nWishRight
=
3463 nMax
- (nLeftSpacing
-pAttrs
->CalcLeftLine()) - nWishedTableWidth
;
3464 nRightSpacing
= nRightLine
+
3465 ( (nRightOffset
> 0) ?
3466 std::max( nWishRight
, SwTwips(nRightOffset
) ) :
3471 OSL_FAIL( "Invalid orientation for table." );
3474 // #i26250# - extend bottom printing area, if table
3475 // is last content inside a table cell.
3476 if ( GetFormat()->getIDocumentSettingAccess().get(DocumentSettingId::ADD_PARA_SPACING_TO_TABLE_CELLS
) &&
3477 GetUpper()->IsInTab() && !GetIndNext() )
3479 nLower
+= pAttrs
->GetULSpace().GetLower();
3481 aRectFnSet
.SetYMargins( *this, nUpper
, nLower
);
3482 if( (nMax
- MINLAY
) < (nLeftSpacing
+ nRightSpacing
) )
3483 aRectFnSet
.SetXMargins( *this, 0, 0 );
3485 aRectFnSet
.SetXMargins( *this, nLeftSpacing
, nRightSpacing
);
3487 SwViewShell
*pSh
= getRootFrame()->GetCurrShell();
3488 if ( bCheckBrowseWidth
&&
3489 pSh
&& pSh
->GetViewOptions()->getBrowseMode() &&
3490 GetUpper()->IsPageBodyFrame() && // only PageBodyFrames and not ColBodyFrames
3491 pSh
->VisArea().Width() )
3493 //Don't go beyond the edge of the visible area.
3494 //The page width can be bigger because objects with
3495 //"over-size" are possible (RootFrame::ImplCalcBrowseWidth())
3496 tools::Long nWidth
= pSh
->GetBrowseWidth();
3497 nWidth
-= getFramePrintArea().Left();
3498 nWidth
-= pAttrs
->CalcRightLine();
3500 SwFrameAreaDefinition::FramePrintAreaWriteAccess
aPrt(*this);
3501 aPrt
.Width( std::min( nWidth
, aPrt
.Width() ) );
3504 if ( nOldHeight
!= aRectFnSet
.GetHeight(getFramePrintArea()) )
3506 setFrameAreaSizeValid(false);
3510 if ( isFrameAreaSizeValid() )
3513 setFrameAreaSizeValid(true);
3515 // The size is defined by the content plus the margins.
3516 SwTwips nRemaining
= 0, nDiff
;
3517 SwFrame
*pFrame
= m_pLower
;
3520 nRemaining
+= aRectFnSet
.GetHeight(pFrame
->getFrameArea());
3521 pFrame
= pFrame
->GetNext();
3523 // And now add the margins
3524 nRemaining
+= nUpper
+ nLower
;
3526 nDiff
= aRectFnSet
.GetHeight(getFrameArea()) - nRemaining
;
3529 else if ( nDiff
< 0 )
3533 SwTwips
SwTabFrame::GrowFrame( SwTwips nDist
, bool bTst
, bool bInfo
)
3535 SwRectFnSet
aRectFnSet(this);
3536 SwTwips nHeight
= aRectFnSet
.GetHeight(getFrameArea());
3537 if( nHeight
> 0 && nDist
> ( LONG_MAX
- nHeight
) )
3538 nDist
= LONG_MAX
- nHeight
;
3540 if ( bTst
&& !IsRestrictTableGrowth() )
3545 //The upper only grows as far as needed. nReal provides the distance
3546 //which is already available.
3547 SwTwips nReal
= aRectFnSet
.GetHeight(GetUpper()->getFramePrintArea());
3548 SwFrame
*pFrame
= GetUpper()->Lower();
3549 while ( pFrame
&& GetFollow() != pFrame
)
3551 nReal
-= aRectFnSet
.GetHeight(pFrame
->getFrameArea());
3552 pFrame
= pFrame
->GetNext();
3555 if ( nReal
< nDist
)
3557 tools::Long nTmp
= GetUpper()->Grow( nDist
- std::max
<tools::Long
>(nReal
, 0), bTst
, bInfo
);
3559 if ( IsRestrictTableGrowth() )
3561 nTmp
= std::min( tools::Long(nDist
), nReal
+ nTmp
);
3562 nDist
= nTmp
< 0 ? 0 : nTmp
;
3569 SwFrameAreaDefinition::FrameAreaWriteAccess
aFrm(*this);
3570 aRectFnSet
.AddBottom( aFrm
, nDist
);
3573 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
3574 SwRootFrame
*pRootFrame
= getRootFrame();
3575 if( pRootFrame
&& pRootFrame
->IsAnyShellAccessible() &&
3576 pRootFrame
->GetCurrShell() )
3578 SwRect
aOldFrame( getFrameArea() );
3579 pRootFrame
->GetCurrShell()->Imp()->MoveAccessibleFrame( this, aOldFrame
);
3585 if ( !bTst
&& ( nDist
|| IsRestrictTableGrowth() ) )
3587 SwPageFrame
*pPage
= FindPageFrame();
3590 GetNext()->InvalidatePos_();
3591 if ( GetNext()->IsContentFrame() )
3592 GetNext()->InvalidatePage( pPage
);
3594 // #i28701# - Due to the new object positioning the
3595 // frame on the next page/column can flow backward (e.g. it was moved
3596 // forward due to the positioning of its objects ). Thus, invalivate this
3597 // next frame, if document compatibility option 'Consider wrapping style
3598 // influence on object positioning' is ON.
3599 else if ( GetFormat()->getIDocumentSettingAccess().get(DocumentSettingId::CONSIDER_WRAP_ON_OBJECT_POSITION
) )
3601 InvalidateNextPos();
3604 InvalidatePage( pPage
);
3607 std::unique_ptr
<SvxBrushItem
> aBack
= GetFormat()->makeBackgroundBrushItem();
3608 const SvxGraphicPosition ePos
= aBack
->GetGraphicPos();
3609 if ( GPOS_NONE
!= ePos
&& GPOS_TILED
!= ePos
)
3615 void SwTabFrame::Invalidate(SwTabFrameInvFlags eInvFlags
)
3617 if(eInvFlags
== SwTabFrameInvFlags::NONE
)
3619 SwPageFrame
* pPage
= FindPageFrame();
3620 InvalidatePage(pPage
);
3621 if(eInvFlags
& SwTabFrameInvFlags::InvalidatePrt
)
3623 if(eInvFlags
& SwTabFrameInvFlags::InvalidatePos
)
3625 SwFrame
* pTmp
= GetIndNext();
3628 if(eInvFlags
& SwTabFrameInvFlags::InvalidateIndNextPrt
)
3630 pTmp
->InvalidatePrt_();
3631 if(pTmp
->IsContentFrame())
3632 pTmp
->InvalidatePage(pPage
);
3634 if(eInvFlags
& SwTabFrameInvFlags::SetIndNextCompletePaint
)
3635 pTmp
->SetCompletePaint();
3637 if(eInvFlags
& SwTabFrameInvFlags::InvalidatePrevPrt
&& nullptr != (pTmp
= GetPrev()))
3639 pTmp
->InvalidatePrt_();
3640 if(pTmp
->IsContentFrame())
3641 pTmp
->InvalidatePage(pPage
);
3643 if(eInvFlags
& SwTabFrameInvFlags::InvalidateBrowseWidth
)
3645 if(pPage
&& pPage
->GetUpper() && !IsFollow())
3646 static_cast<SwRootFrame
*>(pPage
->GetUpper())->InvalidateBrowseWidth();
3648 if(eInvFlags
& SwTabFrameInvFlags::InvalidateNextPos
)
3649 InvalidateNextPos();
3652 void SwTabFrame::SwClientNotify(const SwModify
& rMod
, const SfxHint
& rHint
)
3654 if(rHint
.GetId() == SfxHintId::SwTableHeadingChange
)
3656 HandleTableHeadlineChange();
3659 else if (rHint
.GetId() != SfxHintId::SwLegacyModify
)
3661 auto pLegacy
= static_cast<const sw::LegacyModifyHint
*>(&rHint
);
3662 SwTabFrameInvFlags eInvFlags
= SwTabFrameInvFlags::NONE
;
3663 bool bAttrSetChg
= pLegacy
->m_pNew
&& RES_ATTRSET_CHG
== pLegacy
->m_pNew
->Which();
3667 auto& rOldSetChg
= *static_cast<const SwAttrSetChg
*>(pLegacy
->m_pOld
);
3668 auto& rNewSetChg
= *static_cast<const SwAttrSetChg
*>(pLegacy
->m_pNew
);
3669 SfxItemIter
aOIter(*rOldSetChg
.GetChgSet());
3670 SfxItemIter
aNIter(*rNewSetChg
.GetChgSet());
3671 const SfxPoolItem
* pOItem
= aOIter
.GetCurItem();
3672 const SfxPoolItem
* pNItem
= aNIter
.GetCurItem();
3673 SwAttrSetChg
aOldSet(rOldSetChg
);
3674 SwAttrSetChg
aNewSet(rNewSetChg
);
3677 UpdateAttr_(pOItem
, pNItem
, eInvFlags
, &aOldSet
, &aNewSet
);
3678 pNItem
= aNIter
.NextItem();
3679 pOItem
= aOIter
.NextItem();
3681 if(aOldSet
.Count() || aNewSet
.Count())
3682 SwLayoutFrame::SwClientNotify(rMod
, sw::LegacyModifyHint(&aOldSet
, &aNewSet
));
3685 UpdateAttr_(pLegacy
->m_pOld
, pLegacy
->m_pNew
, eInvFlags
);
3686 Invalidate(eInvFlags
);
3689 void SwTabFrame::HandleTableHeadlineChange()
3693 // Delete remaining headlines:
3694 SwRowFrame
* pLowerRow
= nullptr;
3695 while(nullptr != (pLowerRow
= static_cast<SwRowFrame
*>(Lower())) && pLowerRow
->IsRepeatedHeadline())
3698 SwFrame::DestroyFrame(pLowerRow
);
3701 // insert new headlines
3702 const sal_uInt16 nNewRepeat
= GetTable()->GetRowsToRepeat();
3703 auto& rLines
= GetTable()->GetTabLines();
3704 for(sal_uInt16 nIdx
= 0; nIdx
< nNewRepeat
; ++nIdx
)
3706 SwRowFrame
* pHeadline
= new SwRowFrame(*rLines
[nIdx
], this);
3708 sw::FlyCreationSuppressor aSuppressor
;
3709 pHeadline
->SetRepeatedHeadline(true);
3711 pHeadline
->Paste(this, pLowerRow
);
3713 Invalidate(SwTabFrameInvFlags::InvalidatePrt
);
3716 void SwTabFrame::UpdateAttr_( const SfxPoolItem
*pOld
, const SfxPoolItem
*pNew
,
3717 SwTabFrameInvFlags
&rInvFlags
,
3718 SwAttrSetChg
*pOldSet
, SwAttrSetChg
*pNewSet
)
3721 const sal_uInt16 nWhich
= pOld
? pOld
->Which() : pNew
? pNew
->Which() : 0;
3725 case RES_HORI_ORIENT
:
3726 rInvFlags
|= SwTabFrameInvFlags::InvalidatePrt
| SwTabFrameInvFlags::InvalidateBrowseWidth
;
3729 case RES_PAGEDESC
: //Attribute changes (on/off)
3730 if ( IsInDocBody() )
3732 rInvFlags
|= SwTabFrameInvFlags::InvalidatePos
;
3733 SwPageFrame
*pPage
= FindPageFrame();
3737 CheckPageDescs( pPage
);
3738 if (GetFormat()->GetPageDesc().GetNumOffset())
3739 static_cast<SwRootFrame
*>(pPage
->GetUpper())->SetVirtPageNum( true );
3740 GetFormat()->GetDoc()->getIDocumentFieldsAccess().UpdatePageFields(pPage
->getFrameArea().Top());
3746 rInvFlags
|= SwTabFrameInvFlags::InvalidatePos
| SwTabFrameInvFlags::InvalidateNextPos
;
3749 case RES_LAYOUT_SPLIT
:
3751 rInvFlags
|= SwTabFrameInvFlags::InvalidatePos
;
3754 SetDerivedR2L( false );
3757 case RES_COLLAPSING_BORDERS
:
3758 rInvFlags
|= SwTabFrameInvFlags::InvalidatePrt
;
3759 lcl_InvalidateAllLowersPrt( this );
3762 rInvFlags
|= SwTabFrameInvFlags::InvalidateIndNextPrt
| SwTabFrameInvFlags::InvalidatePrevPrt
| SwTabFrameInvFlags::SetIndNextCompletePaint
;
3771 if ( pOldSet
|| pNewSet
)
3774 pOldSet
->ClearItem( nWhich
);
3776 pNewSet
->ClearItem( nWhich
);
3781 SwLayoutFrame::SwClientNotify(aMod
, sw::LegacyModifyHint(pOld
, pNew
));
3785 bool SwTabFrame::GetInfo( SfxPoolItem
&rHint
) const
3787 if ( RES_VIRTPAGENUM_INFO
== rHint
.Which() && IsInDocBody() && !IsFollow() )
3789 SwVirtPageNumInfo
&rInfo
= static_cast<SwVirtPageNumInfo
&>(rHint
);
3790 const SwPageFrame
*pPage
= FindPageFrame();
3793 if ( pPage
== rInfo
.GetOrigPage() && !GetPrev() )
3795 // Should be the one (can temporarily be different, should we be
3796 // concerned about this possibility?)
3797 rInfo
.SetInfo( pPage
, this );
3800 if ( pPage
->GetPhyPageNum() < rInfo
.GetOrigPage()->GetPhyPageNum() &&
3801 (!rInfo
.GetPage() || pPage
->GetPhyPageNum() > rInfo
.GetPage()->GetPhyPageNum()))
3803 //This could be the one.
3804 rInfo
.SetInfo( pPage
, this );
3811 SwFrame
*SwTabFrame::FindLastContentOrTable()
3813 SwFrame
*pRet
= m_pLower
;
3815 while ( pRet
&& !pRet
->IsContentFrame() )
3817 SwFrame
*pOld
= pRet
;
3819 SwFrame
*pTmp
= pRet
; // To skip empty section frames
3820 while ( pRet
->GetNext() )
3822 pRet
= pRet
->GetNext();
3823 if( !pRet
->IsSctFrame() || static_cast<SwSectionFrame
*>(pRet
)->GetSection() )
3828 if ( pRet
->GetLower() )
3829 pRet
= pRet
->GetLower();
3832 // Check all other columns if there is a column based section with
3833 // an empty last column at the end of the last cell - this is done
3834 // by SwSectionFrame::FindLastContent
3835 if( pRet
->IsColBodyFrame() )
3837 #if OSL_DEBUG_LEVEL > 0
3838 SwSectionFrame
* pSect
= pRet
->FindSctFrame();
3839 OSL_ENSURE( pSect
, "Where does this column come from?");
3840 OSL_ENSURE( IsAnLower( pSect
), "Split cell?" );
3842 return pRet
->FindSctFrame()->FindLastContent();
3845 // pRet may be a cell frame without a lower (cell has been split).
3846 // We have to find the last content the hard way:
3848 OSL_ENSURE( pRet
->IsCellFrame(), "SwTabFrame::FindLastContent failed" );
3849 const SwFrame
* pRow
= pRet
->GetUpper();
3850 while ( pRow
&& !pRow
->GetUpper()->IsTabFrame() )
3851 pRow
= pRow
->GetUpper();
3852 const SwContentFrame
* pContentFrame
= pRow
? static_cast<const SwLayoutFrame
*>(pRow
)->ContainsContent() : nullptr;
3855 while ( pContentFrame
&& static_cast<const SwLayoutFrame
*>(pRow
)->IsAnLower( pContentFrame
) )
3857 pRet
= const_cast<SwContentFrame
*>(pContentFrame
);
3858 pContentFrame
= pContentFrame
->GetNextContentFrame();
3863 // #112929# There actually is a situation, which results in pRet = 0:
3864 // Insert frame, insert table via text <-> table. This gives you a frame
3865 // containing a table without any other content frames. Split the table
3866 // and undo the splitting. This operation gives us a table frame without
3870 while ( pRet
->GetNext() )
3871 pRet
= pRet
->GetNext();
3873 if (pRet
->IsSctFrame())
3874 pRet
= static_cast<SwSectionFrame
*>(pRet
)->FindLastContent();
3877 assert(pRet
== nullptr || dynamic_cast<SwContentFrame
*>(pRet
) || dynamic_cast<SwTabFrame
*>(pRet
));
3881 SwContentFrame
*SwTabFrame::FindLastContent()
3883 SwFrame
* pRet(FindLastContentOrTable());
3885 while (pRet
&& pRet
->IsTabFrame()) // possibly there's only tables here!
3886 { // tdf#126138 skip table, don't look inside
3887 pRet
= pRet
->GetPrev();
3890 assert(pRet
== nullptr || dynamic_cast<SwContentFrame
*>(pRet
));
3891 return static_cast<SwContentFrame
*>(pRet
);
3894 /// Return value defines if the frm needs to be relocated
3895 bool SwTabFrame::ShouldBwdMoved( SwLayoutFrame
*pNewUpper
, bool &rReformat
)
3898 if ( SwFlowFrame::IsMoveBwdJump() || !IsPrevObjMove() )
3900 //Flowing back Frames is quite time consuming unfortunately.
3901 //Most often the location where the Frame wants to flow to has the same
3902 //FixSize as the Frame itself. In such a situation it's easy to check if
3903 //the Frame will find enough space for its VarSize, if this is not the
3904 //case, the relocation can be skipped.
3905 //Checking if the Frame will find enough space is done by the Frame itself,
3906 //this also takes the possibility of splitting the Frame into account.
3907 //If the FixSize is different or Flys are involved (at the old or the
3908 //new position) the checks are pointless, the Frame then
3909 //needs to be relocated tentatively (if a bit of space is available).
3911 //The FixSize of the environments which contain tables is always the
3914 SwPageFrame
*pOldPage
= FindPageFrame(),
3915 *pNewPage
= pNewUpper
->FindPageFrame();
3916 bool bMoveAnyway
= false;
3919 SwRectFnSet
aRectFnSet(this);
3920 if ( !SwFlowFrame::IsMoveBwdJump() )
3923 tools::Long nOldWidth
= aRectFnSet
.GetWidth(GetUpper()->getFramePrintArea());
3924 SwRectFnSet
fnRectX(pNewUpper
);
3925 tools::Long nNewWidth
= fnRectX
.GetWidth(pNewUpper
->getFramePrintArea());
3926 if( std::abs( nNewWidth
- nOldWidth
) < 2 )
3928 bMoveAnyway
= BwdMoveNecessary( pOldPage
, getFrameArea() ) > 1;
3931 SwRect
aRect( pNewUpper
->getFramePrintArea() );
3932 aRect
.Pos() += pNewUpper
->getFrameArea().Pos();
3933 const SwFrame
*pPrevFrame
= pNewUpper
->Lower();
3934 while ( pPrevFrame
&& pPrevFrame
!= this )
3936 fnRectX
.SetTop( aRect
, fnRectX
.GetBottom(pPrevFrame
->getFrameArea()) );
3937 pPrevFrame
= pPrevFrame
->GetNext();
3939 bMoveAnyway
= BwdMoveNecessary( pNewPage
, aRect
) > 1;
3941 // #i54861# Due to changes made in PrepareMake,
3942 // the tabfrm may not have a correct position. Therefore
3943 // it is possible that pNewUpper->getFramePrintArea().Height == 0. In this
3944 // case the above calculation of nSpace might give wrong
3945 // results and we really do not want to MoveBackward into a
3946 // 0 height frame. If nTmpSpace is already <= 0, we take this
3948 const SwTwips nTmpSpace
= fnRectX
.GetHeight(aRect
);
3949 if ( fnRectX
.GetHeight(pNewUpper
->getFramePrintArea()) > 0 || nTmpSpace
<= 0 )
3952 const SwViewShell
*pSh
= getRootFrame()->GetCurrShell();
3953 if( pSh
&& pSh
->GetViewOptions()->getBrowseMode() )
3954 nSpace
+= pNewUpper
->Grow( LONG_MAX
, true );
3955 if (0 < nSpace
&& GetPrecede())
3957 SwTwips
nUpperDummy(0);
3958 tools::Long
nLeftOffsetDummy(0), nRightOffsetDummy(0);
3959 // tdf#116501 check for no-wrap fly overlap
3960 static_cast<const SwTabFrame
*>(GetPrecede())->CalcFlyOffsets(
3961 nUpperDummy
, nLeftOffsetDummy
, nRightOffsetDummy
, &nSpace
);
3965 else if (!m_bLockBackMove
)
3969 m_bWantBackMove
= true;
3972 else if (!m_bLockBackMove
)
3976 m_bWantBackMove
= true;
3985 bool bFits
= nSpace
> 0;
3986 if (!bFits
&& aRectFnSet
.GetHeight(getFrameArea()) == 0)
3987 // This frame fits into pNewUpper in case it has no space, but this
3989 bFits
= nSpace
>= 0;
3992 // #i26945# - check, if follow flow line
3993 // contains frame, which are moved forward due to its object
3995 const SwRowFrame
* pFirstRow
= GetFirstNonHeadlineRow();
3996 if ( pFirstRow
&& pFirstRow
->IsInFollowFlowRow() &&
3997 SwLayouter::DoesRowContainMovedFwdFrame(
3998 *(pFirstRow
->GetFormat()->GetDoc()),
4003 SwTwips nTmpHeight
= CalcHeightOfFirstContentLine();
4005 // For some mysterious reason, I changed the good old
4006 // 'return nHeight <= nSpace' to 'return nTmpHeight < nSpace'.
4007 // This obviously results in problems with table frames in
4008 // sections. Remember: Every twip is sacred.
4009 if (nTmpHeight
<= nSpace
)
4011 if (m_bLockBackMove
)
4013 m_bWantBackMove
= true;
4025 void SwTabFrame::Cut()
4027 OSL_ENSURE( GetUpper(), "Cut without Upper()." );
4029 SwPageFrame
*pPage
= FindPageFrame();
4030 InvalidatePage( pPage
);
4031 SwFrame
*pFrame
= GetNext();
4034 // Possibly the old follow calculated a spacing to the predecessor
4035 // which is obsolete now when it becomes the first frame
4036 pFrame
->InvalidatePrt_();
4037 pFrame
->InvalidatePos_();
4038 if ( pFrame
->IsContentFrame() )
4039 pFrame
->InvalidatePage( pPage
);
4040 if( IsInSct() && !GetPrev() )
4042 SwSectionFrame
* pSct
= FindSctFrame();
4043 if( !pSct
->IsFollow() )
4045 pSct
->InvalidatePrt_();
4046 pSct
->InvalidatePage( pPage
);
4052 InvalidateNextPos();
4053 //Someone has to do the retouch: predecessor or upper
4055 if ( nullptr != pFrame
)
4057 pFrame
->SetRetouche();
4058 pFrame
->Prepare( PrepareHint::WidowsOrphans
);
4059 pFrame
->InvalidatePos_();
4060 if ( pFrame
->IsContentFrame() )
4061 pFrame
->InvalidatePage( pPage
);
4063 //If I am (was) the only FlowFrame in my own upper, it has to do
4064 //the retouch. Moreover a new empty page might be created.
4066 { SwRootFrame
*pRoot
= static_cast<SwRootFrame
*>(pPage
->GetUpper());
4067 pRoot
->SetSuperfluous();
4068 GetUpper()->SetCompletePaint();
4071 SwSectionFrame
* pSct
= FindSctFrame();
4072 if( !pSct
->IsFollow() )
4074 pSct
->InvalidatePrt_();
4075 pSct
->InvalidatePage( pPage
);
4081 //First remove, then shrink the upper.
4082 SwLayoutFrame
*pUp
= GetUpper();
4083 SwRectFnSet
aRectFnSet(this);
4087 OSL_ENSURE( !pUp
->IsFootnoteFrame(), "Table in Footnote." );
4088 SwSectionFrame
*pSct
= nullptr;
4089 SwFlyFrame
*pFly
= nullptr;
4090 // #126020# - adjust check for empty section
4091 // #130797# - correct fix #126020#
4092 if ( !pUp
->Lower() && pUp
->IsInSct() &&
4093 !(pSct
= pUp
->FindSctFrame())->ContainsContent() &&
4094 !pSct
->ContainsAny( true ) )
4096 if ( pUp
->GetUpper() )
4098 pSct
->DelEmpty( false );
4099 pSct
->InvalidateSize_();
4102 else if (!pUp
->Lower() && pUp
->IsInFly() &&
4103 !(pFly
= pUp
->FindFlyFrame())->ContainsContent() &&
4104 !pFly
->ContainsAny())
4106 bool bSplitFly
= pFly
->IsFlySplitAllowed();
4107 if (!bSplitFly
&& pFly
->IsFlyAtContentFrame())
4109 // If the fly is not allowed to split, it's still possible that it was allowed to
4110 // split. That is definitely the case when the fly is a follow.
4111 auto pFlyAtContent
= static_cast<SwFlyAtContentFrame
*>(pFly
);
4112 bSplitFly
= pFlyAtContent
->IsFollow();
4114 if (pUp
== pFly
&& bSplitFly
)
4116 auto pFlyAtContent
= static_cast<SwFlyAtContentFrame
*>(pFly
);
4117 pFlyAtContent
->DelEmpty();
4120 // table-in-footnote: delete empty footnote frames (like SwContentFrame::Cut)
4121 else if (!pUp
->Lower() && pUp
->IsFootnoteFrame() && !pUp
->IsColLocked())
4123 if (pUp
->GetNext() && !pUp
->GetPrev())
4125 if (SwFrame
*const pTmp
= static_cast<SwLayoutFrame
*>(pUp
->GetNext())->ContainsAny())
4127 pTmp
->InvalidatePrt_();
4130 if (!pUp
->IsDeleteForbidden())
4133 SwFrame::DestroyFrame(pUp
);
4136 else if( aRectFnSet
.GetHeight(getFrameArea()) )
4138 // OD 26.08.2003 #i18103# - *no* 'ColUnlock' of section -
4139 // undo changes of fix for #104992#
4140 pUp
->Shrink( getFrameArea().Height() );
4145 if ( pPage
&& !IsFollow() && pPage
->GetUpper() )
4146 static_cast<SwRootFrame
*>(pPage
->GetUpper())->InvalidateBrowseWidth();
4149 void SwTabFrame::Paste( SwFrame
* pParent
, SwFrame
* pSibling
)
4151 OSL_ENSURE( pParent
, "No parent for pasting." );
4152 OSL_ENSURE( pParent
->IsLayoutFrame(), "Parent is ContentFrame." );
4153 OSL_ENSURE( pParent
!= this, "I'm the parent myself." );
4154 OSL_ENSURE( pSibling
!= this, "I'm my own neighbour." );
4155 OSL_ENSURE( !GetPrev() && !GetNext() && !GetUpper(),
4156 "I'm still registered somewhere." );
4158 //Insert in the tree.
4159 InsertBefore( static_cast<SwLayoutFrame
*>(pParent
), pSibling
);
4162 SwPageFrame
*pPage
= FindPageFrame();
4163 InvalidatePage( pPage
);
4167 GetNext()->InvalidatePos_();
4168 GetNext()->InvalidatePrt_();
4169 if ( GetNext()->IsContentFrame() )
4170 GetNext()->InvalidatePage( pPage
);
4173 SwRectFnSet
aRectFnSet(this);
4174 if( aRectFnSet
.GetHeight(getFrameArea()) )
4175 pParent
->Grow( aRectFnSet
.GetHeight(getFrameArea()) );
4177 if( aRectFnSet
.GetWidth(getFrameArea()) != aRectFnSet
.GetWidth(pParent
->getFramePrintArea()) )
4178 Prepare( PrepareHint::FixSizeChanged
);
4183 GetPrev()->InvalidateSize();
4184 if ( GetPrev()->IsContentFrame() )
4185 GetPrev()->InvalidatePage( pPage
);
4188 else if ( GetNext() )
4189 // Take the spacing into account when dealing with ContentFrames.
4190 // There are two situations (both always happen at the same time):
4191 // a) The Content becomes the first in a chain
4192 // b) The new follower was previously the first in a chain
4193 GetNext()->InvalidatePrt_();
4195 if ( !pPage
|| IsFollow() )
4198 if ( pPage
->GetUpper() )
4199 static_cast<SwRootFrame
*>(pPage
->GetUpper())->InvalidateBrowseWidth();
4201 if ( !GetPrev() )//At least needed for HTML with a table at the beginning.
4203 const SwPageDesc
*pDesc
= GetFormat()->GetPageDesc().GetPageDesc();
4204 if ( (pDesc
&& pDesc
!= pPage
->GetPageDesc()) ||
4205 (!pDesc
&& pPage
->GetPageDesc() != &GetFormat()->GetDoc()->GetPageDesc(0)) )
4206 CheckPageDescs( pPage
);
4210 bool SwTabFrame::Prepare( const PrepareHint eHint
, const void *, bool )
4212 if( PrepareHint::BossChanged
== eHint
)
4217 SwRowFrame::SwRowFrame(const SwTableLine
&rLine
, SwFrame
* pSib
, bool bInsertContent
)
4218 : SwLayoutFrame( rLine
.GetFrameFormat(), pSib
)
4219 , m_pTabLine( &rLine
)
4220 , m_pFollowRow( nullptr )
4222 , mnTopMarginForLowers( 0 )
4223 , mnBottomMarginForLowers( 0 )
4224 , mnBottomLineSize( 0 )
4225 // --> split table rows
4226 , m_bIsFollowFlowRow( false )
4227 // <-- split table rows
4228 , m_bIsRepeatedHeadline( false )
4229 , m_bIsRowSpanLine( false )
4230 , m_bForceRowSplitAllowed( false )
4231 , m_bIsInSplit( false )
4233 mnFrameType
= SwFrameType::Row
;
4235 //Create the boxes and insert them.
4236 const SwTableBoxes
&rBoxes
= rLine
.GetTabBoxes();
4237 SwFrame
*pTmpPrev
= nullptr;
4239 bool bHiddenRedlines
= getRootFrame()->IsHideRedlines() &&
4240 !GetFormat()->GetDoc()->getIDocumentRedlineAccess().GetRedlineTable().empty();
4241 for ( size_t i
= 0; i
< rBoxes
.size(); ++i
)
4243 // skip cells deleted with track changes
4244 if ( bHiddenRedlines
&& RedlineType::Delete
== rBoxes
[i
]->GetRedlineType() )
4247 SwCellFrame
*pNew
= new SwCellFrame( *rBoxes
[i
], this, bInsertContent
);
4248 pNew
->InsertBehind( this, pTmpPrev
);
4253 void SwRowFrame::DestroyImpl()
4255 sw::BroadcastingModify
* pMod
= GetFormat();
4258 pMod
->Remove( this );
4259 if( !pMod
->HasWriterListeners() )
4263 SwLayoutFrame::DestroyImpl();
4266 SwRowFrame::~SwRowFrame()
4270 void SwRowFrame::RegistFlys( SwPageFrame
*pPage
)
4272 ::RegistFlys( pPage
? pPage
: FindPageFrame(), this );
4275 void SwRowFrame::OnFrameSize(const SfxPoolItem
& rSize
)
4277 SwTabFrame
* pTab
= FindTabFrame();
4280 const bool bInFirstNonHeadlineRow
= pTab
->IsFollow() && this == pTab
->GetFirstNonHeadlineRow();
4282 // Invalidation required is pRow is last row
4283 if(bInFirstNonHeadlineRow
)
4284 pTab
= pTab
->FindMaster();
4285 if(bInFirstNonHeadlineRow
|| !GetNext())
4286 pTab
->InvalidatePos();
4288 const sw::BroadcastingModify aMod
;
4289 SwLayoutFrame::SwClientNotify(aMod
, sw::LegacyModifyHint(nullptr, &rSize
));
4292 void SwRowFrame::SwClientNotify(const SwModify
& rModify
, const SfxHint
& rHint
)
4294 if(auto pNewFormatHint
= dynamic_cast<const sw::TableLineFormatChanged
*>(&rHint
))
4296 if(GetTabLine() != &pNewFormatHint
->m_rTabLine
)
4298 RegisterToFormat(const_cast<SwTableLineFormat
&>(pNewFormatHint
->m_rNewFormat
));
4302 ReinitializeFrameSizeAttrFlags();
4305 // consider 'split row allowed' attribute
4306 SwTabFrame
* pTab
= FindTabFrame();
4307 bool bInFollowFlowRow
= false;
4308 const bool bInFirstNonHeadlineRow
= pTab
->IsFollow() && this == pTab
->GetFirstNonHeadlineRow();
4309 if(bInFirstNonHeadlineRow
||
4311 (bInFollowFlowRow
= IsInFollowFlowRow()) ||
4312 nullptr != IsInSplitTableRow() )
4314 if(bInFirstNonHeadlineRow
|| bInFollowFlowRow
)
4315 pTab
= pTab
->FindMaster();
4317 pTab
->SetRemoveFollowFlowLinePending(true);
4318 pTab
->InvalidatePos();
4321 else if(auto pMoveTableLineHint
= dynamic_cast<const sw::MoveTableLineHint
*>(&rHint
))
4324 if(GetTabLine() != &pMoveTableLineHint
->m_rTableLine
)
4326 const_cast<SwFrameFormat
*>(&pMoveTableLineHint
->m_rNewFormat
)->Add(this);
4328 ReinitializeFrameSizeAttrFlags();
4331 if (rHint
.GetId() != SfxHintId::SwLegacyModify
)
4333 auto pLegacy
= static_cast<const sw::LegacyModifyHint
*>(&rHint
);
4334 if(!pLegacy
->m_pNew
)
4336 // possibly not needed?
4337 SwLayoutFrame::SwClientNotify(rModify
, rHint
);
4340 switch(pLegacy
->m_pNew
->Which())
4342 case RES_ATTRSET_CHG
:
4344 const SwAttrSet
* pChgSet
= static_cast<const SwAttrSetChg
*>(pLegacy
->m_pNew
)->GetChgSet();
4345 const SfxPoolItem
* pItem
= nullptr;
4346 pChgSet
->GetItemState(RES_FRM_SIZE
, false, &pItem
);
4348 pChgSet
->GetItemState(RES_ROW_SPLIT
, false, &pItem
);
4350 OnFrameSize(*pItem
);
4352 SwLayoutFrame::SwClientNotify(rModify
, rHint
); // possibly not needed?
4357 OnFrameSize(*static_cast<const SwFormatFrameSize
*>(pLegacy
->m_pNew
));
4362 void SwRowFrame::MakeAll(vcl::RenderContext
* pRenderContext
)
4366 setFrameAreaSizeValid(false);
4369 SwLayoutFrame::MakeAll(pRenderContext
);
4372 void SwRowFrame::dumpAsXml(xmlTextWriterPtr writer
) const
4374 (void)xmlTextWriterStartElement(writer
, reinterpret_cast<const xmlChar
*>("row"));
4375 dumpAsXmlAttributes(writer
);
4377 (void)xmlTextWriterStartElement(writer
, BAD_CAST("infos"));
4378 dumpInfosAsXml(writer
);
4379 (void)xmlTextWriterEndElement(writer
);
4380 dumpChildrenAsXml(writer
);
4382 (void)xmlTextWriterEndElement(writer
);
4385 tools::Long
CalcHeightWithFlys( const SwFrame
*pFrame
)
4387 SwRectFnSet
aRectFnSet(pFrame
);
4388 tools::Long nHeight
= 0;
4389 const SwFrame
* pTmp
= pFrame
->IsSctFrame() ?
4390 static_cast<const SwSectionFrame
*>(pFrame
)->ContainsContent() : pFrame
;
4393 // #i26945# - consider follow text frames
4394 const SwSortedObjs
* pObjs( nullptr );
4395 bool bIsFollow( false );
4396 if ( pTmp
->IsTextFrame() && static_cast<const SwTextFrame
*>(pTmp
)->IsFollow() )
4398 const SwFrame
* pMaster
;
4399 // #i46450# Master does not necessarily have
4400 // to exist if this function is called from JoinFrame() ->
4401 // Cut() -> Shrink()
4402 const SwTextFrame
* pTmpFrame
= static_cast<const SwTextFrame
*>(pTmp
);
4403 if ( pTmpFrame
->GetPrev() && pTmpFrame
->GetPrev()->IsTextFrame() &&
4404 static_cast<const SwTextFrame
*>(pTmpFrame
->GetPrev())->GetFollow() &&
4405 static_cast<const SwTextFrame
*>(pTmpFrame
->GetPrev())->GetFollow() != pTmp
)
4408 pMaster
= pTmpFrame
->FindMaster();
4412 pObjs
= static_cast<const SwTextFrame
*>(pTmp
)->FindMaster()->GetDrawObjs();
4418 pObjs
= pTmp
->GetDrawObjs();
4422 for (SwAnchoredObject
* pAnchoredObj
: *pObjs
)
4424 // #i26945# - if <pTmp> is follow, the
4425 // anchor character frame has to be <pTmp>.
4427 pAnchoredObj
->FindAnchorCharFrame() != pTmp
)
4431 // #i26945# - consider also drawing objects
4433 // OD 30.09.2003 #i18732# - only objects, which follow
4434 // the text flow have to be considered.
4435 const SwFrameFormat
& rFrameFormat
= pAnchoredObj
->GetFrameFormat();
4436 bool bFollowTextFlow
= rFrameFormat
.GetFollowTextFlow().GetValue();
4437 bool bIsFarAway
= pAnchoredObj
->GetObjRect().Top() != FAR_AWAY
;
4438 const SwPageFrame
* pPageFrm
= pTmp
->FindPageFrame();
4439 bool bIsAnchoredToTmpFrm
= false;
4440 if ( pPageFrm
&& pPageFrm
->IsPageFrame() && pAnchoredObj
->GetPageFrame())
4441 bIsAnchoredToTmpFrm
= pAnchoredObj
->GetPageFrame() == pPageFrm
||
4442 (pPageFrm
->GetFormatPage().GetPhyPageNum() == pAnchoredObj
->GetPageFrame()->GetFormatPage().GetPhyPageNum() + 1);
4443 const bool bConsiderObj
=
4444 (rFrameFormat
.GetAnchor().GetAnchorId() != RndStdIds::FLY_AS_CHAR
) &&
4446 bFollowTextFlow
&& bIsAnchoredToTmpFrm
;
4447 bool bWrapThrough
= rFrameFormat
.GetSurround().GetValue() == text::WrapTextMode_THROUGH
;
4448 bool bInBackground
= !rFrameFormat
.GetOpaque().GetValue();
4449 // Legacy render requires in-background setting, the new mode does not.
4450 bool bConsiderFollowTextFlow
= bInBackground
4451 || !rFrameFormat
.getIDocumentSettingAccess().get(
4452 DocumentSettingId::USE_FORMER_TEXT_WRAPPING
);
4453 if (pFrame
->IsInTab() && bFollowTextFlow
&& bWrapThrough
&& bConsiderFollowTextFlow
)
4455 // Ignore wrap-through objects when determining the cell height.
4456 // Normally FollowTextFlow requires a resize of the cell, but not in case of
4463 const SwFormatFrameSize
&rSz
= rFrameFormat
.GetFrameSize();
4464 if( !rSz
.GetHeightPercent() )
4466 const SwTwips nDistOfFlyBottomToAnchorTop
=
4467 aRectFnSet
.GetHeight(pAnchoredObj
->GetObjRect()) +
4468 ( aRectFnSet
.IsVert() ?
4469 pAnchoredObj
->GetCurrRelPos().X() :
4470 pAnchoredObj
->GetCurrRelPos().Y() );
4472 const SwTwips nFrameDiff
=
4474 aRectFnSet
.GetTop(pTmp
->getFrameArea()),
4475 aRectFnSet
.GetTop(pFrame
->getFrameArea()) );
4477 nHeight
= std::max( nHeight
, nDistOfFlyBottomToAnchorTop
+ nFrameDiff
-
4478 aRectFnSet
.GetHeight(pFrame
->getFrameArea()) );
4480 // #i56115# The first height calculation
4481 // gives wrong results if pFrame->getFramePrintArea().Y() > 0. We do
4482 // a second calculation based on the actual rectangles of
4483 // pFrame and pAnchoredObj, and use the maximum of the results.
4484 // I do not want to remove the first calculation because
4485 // if clipping has been applied, using the GetCurrRelPos
4486 // might be the better option to calculate nHeight.
4487 const SwTwips nDistOfFlyBottomToAnchorTop2
= aRectFnSet
.YDiff(
4488 aRectFnSet
.GetBottom(pAnchoredObj
->GetObjRect()),
4489 aRectFnSet
.GetBottom(pFrame
->getFrameArea()) );
4491 nHeight
= std::max( nHeight
, tools::Long(nDistOfFlyBottomToAnchorTop2
));
4497 if( !pFrame
->IsSctFrame() )
4499 pTmp
= pTmp
->FindNextCnt();
4500 if( !static_cast<const SwSectionFrame
*>(pFrame
)->IsAnLower( pTmp
) )
4506 static SwTwips
lcl_CalcTopAndBottomMargin( const SwLayoutFrame
& rCell
, const SwBorderAttrs
& rAttrs
)
4508 const SwTabFrame
* pTab
= rCell
.FindTabFrame();
4509 SwTwips nTopSpace
= 0;
4510 SwTwips nBottomSpace
= 0;
4513 if ( pTab
->IsCollapsingBorders() && rCell
.Lower() && !rCell
.Lower()->IsRowFrame() )
4515 nTopSpace
= static_cast<const SwRowFrame
*>(rCell
.GetUpper())->GetTopMarginForLowers();
4516 nBottomSpace
= static_cast<const SwRowFrame
*>(rCell
.GetUpper())->GetBottomMarginForLowers();
4520 if ( pTab
->IsVertical() != rCell
.IsVertical() )
4522 nTopSpace
= rAttrs
.CalcLeft( &rCell
);
4523 nBottomSpace
= rAttrs
.CalcRight( &rCell
);
4527 nTopSpace
= rAttrs
.CalcTop();
4528 nBottomSpace
= rAttrs
.CalcBottom();
4532 return nTopSpace
+ nBottomSpace
;
4535 // #i26945# - add parameter <_bConsiderObjs> in order to
4536 // control, if floating screen objects have to be considered for the minimal
4538 static SwTwips
lcl_CalcMinCellHeight( const SwLayoutFrame
*_pCell
,
4539 const bool _bConsiderObjs
,
4540 const SwBorderAttrs
*pAttrs
= nullptr )
4542 SwRectFnSet
aRectFnSet(_pCell
);
4543 SwTwips nHeight
= 0;
4544 const SwFrame
* pLow
= _pCell
->Lower();
4547 tools::Long nFlyAdd
= 0;
4550 if ( pLow
->IsRowFrame() )
4553 nHeight
+= ::lcl_CalcMinRowHeight( static_cast<const SwRowFrame
*>(pLow
),
4558 tools::Long nLowHeight
= aRectFnSet
.GetHeight(pLow
->getFrameArea());
4559 nHeight
+= nLowHeight
;
4561 if ( _bConsiderObjs
)
4563 nFlyAdd
= std::max( tools::Long(0), nFlyAdd
- nLowHeight
);
4564 nFlyAdd
= std::max( nFlyAdd
, ::CalcHeightWithFlys( pLow
) );
4568 pLow
= pLow
->GetNext();
4573 // The border/margin needs to be considered too, unfortunately it can't be
4574 // calculated using PrintArea and FrameArea because any or all of those
4576 if ( _pCell
->Lower() )
4579 nHeight
+= lcl_CalcTopAndBottomMargin( *_pCell
, *pAttrs
);
4582 SwBorderAttrAccess
aAccess( SwFrame::GetCache(), _pCell
);
4583 const SwBorderAttrs
&rAttrs
= *aAccess
.Get();
4584 nHeight
+= lcl_CalcTopAndBottomMargin( *_pCell
, rAttrs
);
4590 // #i26945# - add parameter <_bConsiderObjs> in order to control,
4591 // if floating screen objects have to be considered for the minimal cell height
4592 static SwTwips
lcl_CalcMinRowHeight( const SwRowFrame
* _pRow
,
4593 const bool _bConsiderObjs
)
4595 SwTwips nHeight
= 0;
4596 if ( !_pRow
->IsRowSpanLine() )
4598 const SwFormatFrameSize
&rSz
= _pRow
->GetFormat()->GetFrameSize();
4599 if ( _pRow
->HasFixSize() )
4601 OSL_ENSURE(SwFrameSize::Fixed
== rSz
.GetHeightSizeType(), "pRow claims to have fixed size");
4602 return rSz
.GetHeight();
4604 // If this row frame is being split, then row's minimal height shouldn't restrict
4605 // this frame's minimal height, because the rest will go to follow frame.
4606 else if ( !_pRow
->IsInSplit() && rSz
.GetHeightSizeType() == SwFrameSize::Minimum
)
4608 bool bSplitFly
= false;
4609 if (_pRow
->IsInFly())
4611 // See if we're in a split fly that is anchored on a page that has enough space to
4612 // host this row with its minimum row height.
4613 const SwFlyFrame
* pFly
= _pRow
->FindFlyFrame();
4614 if (pFly
->IsFlySplitAllowed())
4616 SwFrame
* pAnchor
= const_cast<SwFlyFrame
*>(pFly
)->FindAnchorCharFrame();
4619 if (pAnchor
->FindPageFrame()->getFramePrintArea().Height() > rSz
.GetHeight())
4629 // Split fly: enforce minimum row height for the master and follows.
4630 nHeight
= rSz
.GetHeight();
4634 nHeight
= rSz
.GetHeight() - lcl_calcHeightOfRowBeforeThisFrame(*_pRow
);
4639 SwRectFnSet
aRectFnSet(_pRow
);
4640 const SwCellFrame
* pLow
= static_cast<const SwCellFrame
*>(_pRow
->Lower());
4644 const tools::Long nRowSpan
= pLow
->GetLayoutRowSpan();
4646 // Consider height of
4647 // 1. current cell if RowSpan == 1
4648 // 2. current cell if cell is "follow" cell of a cell with RowSpan == -1
4649 // 3. master cell if RowSpan == -1
4650 if ( 1 == nRowSpan
)
4652 nTmp
= ::lcl_CalcMinCellHeight( pLow
, _bConsiderObjs
);
4654 else if ( -1 == nRowSpan
)
4656 // Height of the last cell of a row span is height of master cell
4657 // minus the height of the other rows which are covered by the master
4659 const SwCellFrame
& rMaster
= pLow
->FindStartEndOfRowSpanCell( true );
4660 nTmp
= ::lcl_CalcMinCellHeight( &rMaster
, _bConsiderObjs
);
4661 const SwFrame
* pMasterRow
= rMaster
.GetUpper();
4662 while ( pMasterRow
&& pMasterRow
!= _pRow
)
4664 nTmp
-= aRectFnSet
.GetHeight(pMasterRow
->getFrameArea());
4665 pMasterRow
= pMasterRow
->GetNext();
4670 // Do not consider rotated cells:
4671 if ( pLow
->IsVertical() == aRectFnSet
.IsVert() && nTmp
> nHeight
)
4674 pLow
= static_cast<const SwCellFrame
*>(pLow
->GetNext());
4682 // Calculate the maximum of (TopLineSize + TopLineDist) over all lowers:
4683 static sal_uInt16
lcl_GetTopSpace( const SwRowFrame
& rRow
)
4685 sal_uInt16 nTopSpace
= 0;
4686 for ( const SwCellFrame
* pCurrLower
= static_cast<const SwCellFrame
*>(rRow
.Lower()); pCurrLower
;
4687 pCurrLower
= static_cast<const SwCellFrame
*>(pCurrLower
->GetNext()) )
4689 sal_uInt16 nTmpTopSpace
= 0;
4690 if ( pCurrLower
->Lower() && pCurrLower
->Lower()->IsRowFrame() )
4691 nTmpTopSpace
= lcl_GetTopSpace( *static_cast<const SwRowFrame
*>(pCurrLower
->Lower()) );
4694 const SwAttrSet
& rSet
= const_cast<SwCellFrame
*>(pCurrLower
)->GetFormat()->GetAttrSet();
4695 const SvxBoxItem
& rBoxItem
= rSet
.GetBox();
4696 nTmpTopSpace
= rBoxItem
.CalcLineSpace( SvxBoxItemLine::TOP
, true );
4698 nTopSpace
= std::max( nTopSpace
, nTmpTopSpace
);
4703 // Calculate the maximum of TopLineDist over all lowers:
4704 static sal_uInt16
lcl_GetTopLineDist( const SwRowFrame
& rRow
)
4706 sal_uInt16 nTopLineDist
= 0;
4707 for ( const SwCellFrame
* pCurrLower
= static_cast<const SwCellFrame
*>(rRow
.Lower()); pCurrLower
;
4708 pCurrLower
= static_cast<const SwCellFrame
*>(pCurrLower
->GetNext()) )
4710 sal_uInt16 nTmpTopLineDist
= 0;
4711 if ( pCurrLower
->Lower() && pCurrLower
->Lower()->IsRowFrame() )
4712 nTmpTopLineDist
= lcl_GetTopLineDist( *static_cast<const SwRowFrame
*>(pCurrLower
->Lower()) );
4715 const SwAttrSet
& rSet
= const_cast<SwCellFrame
*>(pCurrLower
)->GetFormat()->GetAttrSet();
4716 const SvxBoxItem
& rBoxItem
= rSet
.GetBox();
4717 nTmpTopLineDist
= rBoxItem
.GetDistance( SvxBoxItemLine::TOP
);
4719 nTopLineDist
= std::max( nTopLineDist
, nTmpTopLineDist
);
4721 return nTopLineDist
;
4724 // Calculate the maximum of BottomLineSize over all lowers:
4725 static sal_uInt16
lcl_GetBottomLineSize( const SwRowFrame
& rRow
)
4727 sal_uInt16 nBottomLineSize
= 0;
4728 for ( const SwCellFrame
* pCurrLower
= static_cast<const SwCellFrame
*>(rRow
.Lower()); pCurrLower
;
4729 pCurrLower
= static_cast<const SwCellFrame
*>(pCurrLower
->GetNext()) )
4731 sal_uInt16 nTmpBottomLineSize
= 0;
4732 if ( pCurrLower
->Lower() && pCurrLower
->Lower()->IsRowFrame() )
4734 const SwFrame
* pRow
= pCurrLower
->GetLastLower();
4735 nTmpBottomLineSize
= lcl_GetBottomLineSize( *static_cast<const SwRowFrame
*>(pRow
) );
4739 const SwAttrSet
& rSet
= const_cast<SwCellFrame
*>(pCurrLower
)->GetFormat()->GetAttrSet();
4740 const SvxBoxItem
& rBoxItem
= rSet
.GetBox();
4741 nTmpBottomLineSize
= rBoxItem
.CalcLineSpace( SvxBoxItemLine::BOTTOM
, true ) -
4742 rBoxItem
.GetDistance( SvxBoxItemLine::BOTTOM
);
4744 nBottomLineSize
= std::max( nBottomLineSize
, nTmpBottomLineSize
);
4746 return nBottomLineSize
;
4749 // Calculate the maximum of BottomLineDist over all lowers:
4750 static sal_uInt16
lcl_GetBottomLineDist( const SwRowFrame
& rRow
)
4752 sal_uInt16 nBottomLineDist
= 0;
4753 for ( const SwCellFrame
* pCurrLower
= static_cast<const SwCellFrame
*>(rRow
.Lower()); pCurrLower
;
4754 pCurrLower
= static_cast<const SwCellFrame
*>(pCurrLower
->GetNext()) )
4756 sal_uInt16 nTmpBottomLineDist
= 0;
4757 if ( pCurrLower
->Lower() && pCurrLower
->Lower()->IsRowFrame() )
4759 const SwFrame
* pRow
= pCurrLower
->GetLastLower();
4760 nTmpBottomLineDist
= lcl_GetBottomLineDist( *static_cast<const SwRowFrame
*>(pRow
) );
4764 const SwAttrSet
& rSet
= const_cast<SwCellFrame
*>(pCurrLower
)->GetFormat()->GetAttrSet();
4765 const SvxBoxItem
& rBoxItem
= rSet
.GetBox();
4766 nTmpBottomLineDist
= rBoxItem
.GetDistance( SvxBoxItemLine::BOTTOM
);
4768 nBottomLineDist
= std::max( nBottomLineDist
, nTmpBottomLineDist
);
4770 return nBottomLineDist
;
4773 // tdf#104425: calculate the height of all row frames,
4774 // for which this frame is a follow.
4775 // When a row has fixed/minimum height, it may span over
4776 // several pages. The minimal height on this page should
4777 // take into account the sum of all the heights of previous
4778 // frames that constitute the table row on previous pages.
4779 // Otherwise, trying to split a too high row frame will
4780 // result in loop trying to create that too high row
4781 // on each following page
4782 static SwTwips
lcl_calcHeightOfRowBeforeThisFrame(const SwRowFrame
& rRow
)
4784 // We don't need to account for previous instances of repeated headlines
4785 if (rRow
.IsRepeatedHeadline())
4787 SwRectFnSet
aRectFnSet(&rRow
);
4788 const SwTableLine
* pLine
= rRow
.GetTabLine();
4789 const SwTabFrame
* pTab
= rRow
.FindTabFrame();
4790 if (!pLine
|| !pTab
|| !pTab
->IsFollow())
4792 SwTwips nResult
= 0;
4793 SwIterator
<SwRowFrame
, SwFormat
> aIter(*pLine
->GetFrameFormat());
4794 for (const SwRowFrame
* pCurRow
= aIter
.First(); pCurRow
; pCurRow
= aIter
.Next())
4796 if (pCurRow
!= &rRow
&& pCurRow
->GetTabLine() == pLine
)
4798 // We've found another row frame that is part of the same table row
4799 const SwTabFrame
* pCurTab
= pCurRow
->FindTabFrame();
4800 // A row frame may not belong to a table frame, when it is being cut, e.g., in
4801 // lcl_PostprocessRowsInCells().
4802 // Its SwRowFrame::Cut() has been called; it in turn called SwLayoutFrame::Cut(),
4803 // which nullified row's upper in RemoveFromLayout(), and then called Shrink()
4804 // for its former upper.
4805 // Regardless of whether it will be pasted back, or destroyed, currently it's not
4806 // part of layout, and its height does not count
4807 if (pCurTab
&& pCurTab
->IsAnFollow(pTab
))
4809 // The found row frame belongs to a table frame that precedes
4810 // (above) this one in chain. So, include it in the sum
4811 nResult
+= aRectFnSet
.GetHeight(pCurRow
->getFrameArea());
4818 void SwRowFrame::Format( vcl::RenderContext
* /*pRenderContext*/, const SwBorderAttrs
*pAttrs
)
4820 SwRectFnSet
aRectFnSet(this);
4821 OSL_ENSURE( pAttrs
, "SwRowFrame::Format without Attrs." );
4823 const bool bFix
= mbFixSize
;
4825 if ( !isFramePrintAreaValid() )
4827 // RowFrames don't have borders/margins therefore the PrintArea always
4828 // matches the FrameArea.
4829 setFramePrintAreaValid(true);
4832 SwFrameAreaDefinition::FramePrintAreaWriteAccess
aPrt(*this);
4835 aPrt
.Width ( getFrameArea().Width() );
4836 aPrt
.Height( getFrameArea().Height() );
4840 // Here we calculate the top-printing area for the lower cell frames
4841 SwTabFrame
* pTabFrame
= FindTabFrame();
4842 if ( pTabFrame
->IsCollapsingBorders() )
4844 const sal_uInt16 nTopSpace
= lcl_GetTopSpace( *this );
4845 const sal_uInt16 nTopLineDist
= lcl_GetTopLineDist( *this );
4846 const sal_uInt16 nBottomLineSize
= lcl_GetBottomLineSize( *this );
4847 const sal_uInt16 nBottomLineDist
= lcl_GetBottomLineDist( *this );
4849 const SwRowFrame
* pPreviousRow
= nullptr;
4852 // In order to calculate the top printing area for the lower cell
4853 // frames, we have to find the 'previous' row frame and compare
4854 // the bottom values of the 'previous' row with the 'top' values
4855 // of this row. The best way to find the 'previous' row is to
4856 // use the table structure:
4857 const SwTable
* pTable
= pTabFrame
->GetTable();
4858 const SwTableLine
* pPrevTabLine
= nullptr;
4859 const SwRowFrame
* pTmpRow
= this;
4861 while ( pTmpRow
&& !pPrevTabLine
)
4864 const SwTableLines
& rLines
= pTmpRow
->GetTabLine()->GetUpper() ?
4865 pTmpRow
->GetTabLine()->GetUpper()->GetTabLines() :
4866 pTable
->GetTabLines();
4868 while ( rLines
[ nIdx
] != pTmpRow
->GetTabLine() )
4873 // pTmpRow has a 'previous' row in the table structure:
4874 pPrevTabLine
= rLines
[ nIdx
- 1 ];
4878 // pTmpRow is a first row in the table structure.
4879 // We go up in the table structure:
4880 pTmpRow
= pTmpRow
->GetUpper()->GetUpper() &&
4881 pTmpRow
->GetUpper()->GetUpper()->IsRowFrame() ?
4882 static_cast<const SwRowFrame
*>( pTmpRow
->GetUpper()->GetUpper() ) :
4887 // If we found a 'previous' row, we look for the appropriate row frame:
4890 SwIterator
<SwRowFrame
,SwFormat
> aIter( *pPrevTabLine
->GetFrameFormat() );
4891 for ( SwRowFrame
* pRow
= aIter
.First(); pRow
; pRow
= aIter
.Next() )
4893 // #115759# - do *not* take repeated
4894 // headlines, because during split of table it can be
4895 // invalid and thus can't provide correct border values.
4896 if ( pRow
->GetTabLine() == pPrevTabLine
&&
4897 !pRow
->IsRepeatedHeadline() )
4899 pPreviousRow
= pRow
;
4905 sal_uInt16 nTopPrtMargin
= nTopSpace
;
4908 const sal_uInt16 nTmpPrtMargin
= pPreviousRow
->GetBottomLineSize() + nTopLineDist
;
4909 if ( nTmpPrtMargin
> nTopPrtMargin
)
4910 nTopPrtMargin
= nTmpPrtMargin
;
4913 // table has to be notified if it has to change its lower
4914 // margin due to changes of nBottomLineSize:
4915 if ( !GetNext() && nBottomLineSize
!= GetBottomLineSize() )
4916 pTabFrame
->InvalidatePrt_();
4918 // If there are rows nested inside this row, the nested rows
4919 // may not have been calculated yet. Therefore the
4920 // ::lcl_CalcMinRowHeight( this ) operation later in this
4921 // function cannot consider the correct border values. We
4922 // have to trigger the invalidation of the outer row frame
4924 // Note: If any further invalidations should be necessary, we
4925 // should consider moving the invalidation stuff to the
4926 // appropriate SwNotify object.
4927 if ( GetUpper()->GetUpper()->IsRowFrame() &&
4928 ( nBottomLineDist
!= GetBottomMarginForLowers() ||
4929 nTopPrtMargin
!= GetTopMarginForLowers() ) )
4930 GetUpper()->GetUpper()->InvalidateSize_();
4932 SetBottomMarginForLowers( nBottomLineDist
); // 3.
4933 SetBottomLineSize( nBottomLineSize
); // 4.
4934 SetTopMarginForLowers( nTopPrtMargin
); // 5.
4939 while ( !isFrameAreaSizeValid() )
4941 setFrameAreaSizeValid(true);
4943 #if OSL_DEBUG_LEVEL > 0
4946 const SwFormatFrameSize
&rFrameSize
= GetFormat()->GetFrameSize();
4947 OSL_ENSURE( rFrameSize
.GetSize().Height() > 0, "Has it" );
4950 const SwTwips nDiff
= aRectFnSet
.GetHeight(getFrameArea()) -
4951 ( HasFixSize() && !IsRowSpanLine()
4952 ? pAttrs
->GetSize().Height()
4954 : ::lcl_CalcMinRowHeight( this,
4955 FindTabFrame()->IsConsiderObjsForMinCellHeight() ) );
4960 Shrink( nDiff
, false, true );
4961 else if ( nDiff
< 0 )
4967 // last row will fill the space in its upper.
4971 //The last fills the remaining space in the upper.
4972 SwTwips nDiff
= aRectFnSet
.GetHeight(GetUpper()->getFramePrintArea());
4973 SwFrame
*pSibling
= GetUpper()->Lower();
4975 { nDiff
-= aRectFnSet
.GetHeight(pSibling
->getFrameArea());
4976 pSibling
= pSibling
->GetNext();
4977 } while ( pSibling
);
4983 setFrameAreaSizeValid(true);
4987 void SwRowFrame::AdjustCells( const SwTwips nHeight
, const bool bHeight
)
4989 SwFrame
*pFrame
= Lower();
4992 SwRectFnSet
aRectFnSet(this);
4993 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
4999 SwFrame
* pNotify
= nullptr;
5001 SwCellFrame
* pCellFrame
= static_cast<SwCellFrame
*>(pFrame
);
5004 // Which cells need to be adjusted if the current row changes
5007 // Current frame is a covered frame:
5008 // Set new height for covered cell and adjust master cell:
5009 if ( pCellFrame
->GetTabBox()->getRowSpan() < 1 )
5011 // Set height of current (covered) cell to new line height.
5012 const tools::Long nDiff
= nHeight
- aRectFnSet
.GetHeight(pCellFrame
->getFrameArea());
5016 SwFrameAreaDefinition::FrameAreaWriteAccess
aFrm(*pCellFrame
);
5017 aRectFnSet
.AddBottom( aFrm
, nDiff
);
5020 pCellFrame
->InvalidatePrt_();
5024 SwCellFrame
* pToAdjust
= nullptr;
5025 SwFrame
* pToAdjustRow
= nullptr;
5027 // If current frame is covered frame, we still want to adjust the
5028 // height of the cell starting the row span
5029 if ( pCellFrame
->GetLayoutRowSpan() < 1 )
5031 pToAdjust
= const_cast< SwCellFrame
*>(&pCellFrame
->FindStartEndOfRowSpanCell( true ));
5032 pToAdjustRow
= pToAdjust
->GetUpper();
5036 pToAdjust
= pCellFrame
;
5037 pToAdjustRow
= this;
5040 // Set height of master cell to height of all lines spanned by this line.
5041 tools::Long nRowSpan
= pToAdjust
->GetLayoutRowSpan();
5042 SwTwips nSumRowHeight
= 0;
5043 while ( pToAdjustRow
)
5045 // Use new height for the current row:
5046 nSumRowHeight
+= pToAdjustRow
== this ?
5048 aRectFnSet
.GetHeight(pToAdjustRow
->getFrameArea());
5050 if ( nRowSpan
-- == 1 )
5053 pToAdjustRow
= pToAdjustRow
->GetNext();
5056 if ( pToAdjustRow
&& pToAdjustRow
!= this )
5057 pToAdjustRow
->InvalidateSize_();
5059 const tools::Long nDiff
= nSumRowHeight
- aRectFnSet
.GetHeight(pToAdjust
->getFrameArea());
5062 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
5063 aOldFrame
= pToAdjust
->getFrameArea();
5065 SwFrameAreaDefinition::FrameAreaWriteAccess
aFrm(*pToAdjust
);
5066 aRectFnSet
.AddBottom( aFrm
, nDiff
);
5067 pNotify
= pToAdjust
;
5072 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
5073 SwRootFrame
*pRootFrame
= getRootFrame();
5074 if( pRootFrame
&& pRootFrame
->IsAnyShellAccessible() && pRootFrame
->GetCurrShell() )
5075 pRootFrame
->GetCurrShell()->Imp()->MoveAccessibleFrame( pNotify
, aOldFrame
);
5078 pNotify
->InvalidatePrt_();
5081 pFrame
= pFrame
->GetNext();
5087 pFrame
->InvalidateAll_();
5088 pFrame
= pFrame
->GetNext();
5094 void SwRowFrame::Cut()
5096 SwTabFrame
*pTab
= FindTabFrame();
5097 if ( pTab
&& pTab
->IsFollow() && this == pTab
->GetFirstNonHeadlineRow() )
5099 pTab
->FindMaster()->InvalidatePos();
5102 SwLayoutFrame::Cut();
5105 SwTwips
SwRowFrame::GrowFrame( SwTwips nDist
, bool bTst
, bool bInfo
)
5109 SwTabFrame
* pTab
= FindTabFrame();
5110 SwRectFnSet
aRectFnSet(pTab
);
5112 bool bRestrictTableGrowth
;
5113 bool bHasFollowFlowLine
= pTab
->HasFollowFlowLine();
5115 if ( GetUpper()->IsTabFrame() )
5117 const SwRowFrame
* pFollowFlowRow
= IsInSplitTableRow();
5118 bRestrictTableGrowth
= pFollowFlowRow
&& !pFollowFlowRow
->IsRowSpanLine();
5122 OSL_ENSURE( GetUpper()->IsCellFrame(), "RowFrame->GetUpper neither table nor cell" );
5123 bRestrictTableGrowth
= GetFollowRow() && bHasFollowFlowLine
;
5124 OSL_ENSURE( !bRestrictTableGrowth
|| !GetNext(),
5125 "GetFollowRow for row frame that has a Next" );
5127 // There may still be some space left in my direct upper:
5128 const SwTwips nAdditionalSpace
=
5129 aRectFnSet
.BottomDist( getFrameArea(), aRectFnSet
.GetPrtBottom(*GetUpper()->GetUpper()) );
5130 if ( bRestrictTableGrowth
&& nAdditionalSpace
> 0 )
5132 nReal
= std::min( nAdditionalSpace
, nDist
);
5136 SwFrameAreaDefinition::FrameAreaWriteAccess
aFrm(*this);
5137 aRectFnSet
.AddBottom( aFrm
, nReal
);
5142 if ( bRestrictTableGrowth
)
5143 pTab
->SetRestrictTableGrowth( true );
5146 // Ok, this looks like a hack, indeed, it is a hack.
5147 // If the current row frame is inside another cell frame,
5148 // and the current row frame has no follow, it should not
5149 // be allowed to grow. In fact, setting bRestrictTableGrowth
5150 // to 'false' does not work, because the surrounding RowFrame
5151 // would set this to 'true'.
5152 pTab
->SetFollowFlowLine( false );
5155 nReal
+= SwLayoutFrame::GrowFrame( nDist
, bTst
, bInfo
);
5157 pTab
->SetRestrictTableGrowth( false );
5158 pTab
->SetFollowFlowLine( bHasFollowFlowLine
);
5160 //Update the height of the cells to the newest value.
5163 SwRectFnSet
fnRectX(this);
5164 AdjustCells( fnRectX
.GetHeight(getFramePrintArea()) + nReal
, true );
5172 SwTwips
SwRowFrame::ShrinkFrame( SwTwips nDist
, bool bTst
, bool bInfo
)
5174 SwRectFnSet
aRectFnSet(this);
5177 AdjustCells( aRectFnSet
.GetHeight(getFramePrintArea()), true );
5181 // bInfo may be set to true by SwRowFrame::Format; we need to handle this
5183 const bool bShrinkAnyway
= bInfo
;
5185 //Only shrink as much as the content of the biggest cell allows.
5186 SwTwips nRealDist
= nDist
;
5187 SwFormat
* pMod
= GetFormat();
5190 const SwFormatFrameSize
&rSz
= pMod
->GetFrameSize();
5191 SwTwips nMinHeight
= 0;
5192 if (rSz
.GetHeightSizeType() == SwFrameSize::Minimum
)
5193 nMinHeight
= std::max(rSz
.GetHeight() - lcl_calcHeightOfRowBeforeThisFrame(*this),
5196 // Only necessary to calculate minimal row height if height
5197 // of pRow is at least nMinHeight. Otherwise nMinHeight is the
5199 if( nMinHeight
< aRectFnSet
.GetHeight(getFrameArea()) )
5202 OSL_ENSURE( FindTabFrame(), "<SwRowFrame::ShrinkFrame(..)> - no table frame -> crash." );
5203 const bool bConsiderObjs( FindTabFrame()->IsConsiderObjsForMinCellHeight() );
5204 nMinHeight
= lcl_CalcMinRowHeight( this, bConsiderObjs
);
5207 if ( (aRectFnSet
.GetHeight(getFrameArea()) - nRealDist
) < nMinHeight
)
5208 nRealDist
= aRectFnSet
.GetHeight(getFrameArea()) - nMinHeight
;
5210 if ( nRealDist
< 0 )
5213 SwTwips nReal
= nRealDist
;
5218 SwTwips nHeight
= aRectFnSet
.GetHeight(getFrameArea());
5219 SwFrameAreaDefinition::FrameAreaWriteAccess
aFrm(*this);
5220 aRectFnSet
.SetHeight( aFrm
, nHeight
- nReal
);
5222 if( IsVertical() && !IsVertLR() )
5224 aFrm
.Pos().AdjustX(nReal
);
5228 SwLayoutFrame
* pFrame
= GetUpper();
5229 SwTwips nTmp
= pFrame
? pFrame
->Shrink(nReal
, bTst
) : 0;
5230 if ( !bShrinkAnyway
&& !GetNext() && nTmp
!= nReal
)
5232 //The last one gets the leftover in the upper and therefore takes
5233 //care (otherwise: endless loop)
5237 SwTwips nHeight
= aRectFnSet
.GetHeight(getFrameArea());
5238 SwFrameAreaDefinition::FrameAreaWriteAccess
aFrm(*this);
5239 aRectFnSet
.SetHeight( aFrm
, nHeight
+ nReal
);
5241 if( IsVertical() && !IsVertLR() )
5243 aFrm
.Pos().AdjustX( -nReal
);
5250 // Invalidate appropriately and update the height to the newest value.
5256 GetNext()->InvalidatePos_();
5260 SwTabFrame
*pTab
= FindTabFrame();
5261 if ( !pTab
->IsRebuildLastLine()
5263 && this == pTab
->GetFirstNonHeadlineRow()
5264 && !pTab
->IsInRecalcLowerRow() )
5266 SwTabFrame
* pMasterTab
= pTab
->FindMaster();
5267 pMasterTab
->InvalidatePos();
5270 AdjustCells( aRectFnSet
.GetHeight(getFramePrintArea()) - nReal
, true );
5275 bool SwRowFrame::IsRowSplitAllowed() const
5277 // Fixed size rows are never allowed to split:
5280 OSL_ENSURE( SwFrameSize::Fixed
== GetFormat()->GetFrameSize().GetHeightSizeType(), "pRow claims to have fixed size" );
5284 // Repeated headlines are never allowed to split:
5285 const SwTabFrame
* pTabFrame
= FindTabFrame();
5286 if ( pTabFrame
->GetTable()->GetRowsToRepeat() > 0 &&
5287 pTabFrame
->IsInHeadline( *this ) )
5290 if ( IsForceRowSplitAllowed() )
5293 const SwTableLineFormat
* pFrameFormat
= static_cast<SwTableLineFormat
*>(GetTabLine()->GetFrameFormat());
5294 const SwFormatRowSplit
& rLP
= pFrameFormat
->GetRowSplit();
5295 return rLP
.GetValue();
5298 bool SwRowFrame::ShouldRowKeepWithNext( const bool bCheckParents
) const
5300 // No KeepWithNext if nested in another table
5301 if ( GetUpper()->GetUpper()->IsCellFrame() )
5304 const SwCellFrame
* pCell
= static_cast<const SwCellFrame
*>(Lower());
5305 const SwFrame
* pText
= pCell
->Lower();
5307 return pText
&& pText
->IsTextFrame() &&
5308 static_cast<const SwTextFrame
*>(pText
)->GetTextNodeForParaProps()->GetSwAttrSet().GetKeep(bCheckParents
).GetValue();
5311 SwCellFrame::SwCellFrame(const SwTableBox
&rBox
, SwFrame
* pSib
, bool bInsertContent
)
5312 : SwLayoutFrame( rBox
.GetFrameFormat(), pSib
)
5313 , m_pTabBox( &rBox
)
5315 mnFrameType
= SwFrameType::Cell
;
5317 if ( !bInsertContent
)
5320 //If a StartIdx is available, ContentFrames are added in the cell, otherwise
5321 //Rows have to be present and those are added.
5322 if ( SwNodeOffset nIndex
= rBox
.GetSttIdx() )
5324 ::InsertCnt_( this, rBox
.GetFrameFormat()->GetDoc(), ++nIndex
);
5328 const SwTableLines
&rLines
= rBox
.GetTabLines();
5329 SwFrame
*pTmpPrev
= nullptr;
5330 for ( size_t i
= 0; i
< rLines
.size(); ++i
)
5332 SwRowFrame
*pNew
= new SwRowFrame( *rLines
[i
], this, bInsertContent
);
5333 pNew
->InsertBehind( this, pTmpPrev
);
5339 void SwCellFrame::DestroyImpl()
5341 sw::BroadcastingModify
* pMod
= GetFormat();
5344 // At this stage the lower frames aren't destroyed already,
5345 // therefore we have to do a recursive dispose.
5346 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
5347 SwRootFrame
*pRootFrame
= getRootFrame();
5348 if( pRootFrame
&& pRootFrame
->IsAnyShellAccessible() &&
5349 pRootFrame
->GetCurrShell() )
5351 pRootFrame
->GetCurrShell()->Imp()->DisposeAccessibleFrame( this, true );
5355 pMod
->Remove( this );
5356 if( !pMod
->HasWriterListeners() )
5360 SwLayoutFrame::DestroyImpl();
5363 SwCellFrame::~SwCellFrame()
5367 static bool lcl_ArrangeLowers( SwLayoutFrame
*pLay
, tools::Long lYStart
, bool bInva
)
5370 SwFrame
*pFrame
= pLay
->Lower();
5371 SwRectFnSet
aRectFnSet(pLay
);
5374 tools::Long nFrameTop
= aRectFnSet
.GetTop(pFrame
->getFrameArea());
5375 if( nFrameTop
!= lYStart
)
5378 const tools::Long lDiff
= aRectFnSet
.YDiff( lYStart
, nFrameTop
);
5379 const tools::Long lDiffX
= lYStart
- nFrameTop
;
5382 SwFrameAreaDefinition::FrameAreaWriteAccess
aFrm(*pFrame
);
5383 aRectFnSet
.SubTop( aFrm
, -lDiff
);
5384 aRectFnSet
.AddBottom( aFrm
, lDiff
);
5387 pFrame
->SetCompletePaint();
5389 if ( !pFrame
->GetNext() )
5390 pFrame
->SetRetouche();
5392 pFrame
->Prepare( PrepareHint::FramePositionChanged
);
5393 if ( pFrame
->IsLayoutFrame() && static_cast<SwLayoutFrame
*>(pFrame
)->Lower() )
5394 lcl_ArrangeLowers( static_cast<SwLayoutFrame
*>(pFrame
),
5395 aRectFnSet
.GetTop(static_cast<SwLayoutFrame
*>(pFrame
)->Lower()->getFrameArea())
5397 if ( pFrame
->GetDrawObjs() )
5399 for ( size_t i
= 0; i
< pFrame
->GetDrawObjs()->size(); ++i
)
5401 SwAnchoredObject
* pAnchoredObj
= (*pFrame
->GetDrawObjs())[i
];
5402 // #i26945# - check, if anchored object
5403 // is lower of layout frame by checking, if the anchor
5404 // frame, which contains the anchor position, is a lower
5405 // of the layout frame.
5406 if ( !pLay
->IsAnLower( pAnchoredObj
->GetAnchorFrameContainingAnchPos() ) )
5410 // #i52904# - distinguish between anchored
5411 // objects, whose vertical position depends on its anchor
5412 // frame and whose vertical position is independent
5413 // from its anchor frame.
5414 bool bVertPosDepOnAnchor( true );
5416 SwFormatVertOrient
aVert( pAnchoredObj
->GetFrameFormat().GetVertOrient() );
5417 switch ( aVert
.GetRelationOrient() )
5419 case text::RelOrientation::PAGE_FRAME
:
5420 case text::RelOrientation::PAGE_PRINT_AREA
:
5421 bVertPosDepOnAnchor
= false;
5426 if ( auto pFly
= pAnchoredObj
->DynCastFlyFrame() )
5429 // OD 2004-05-18 #i28701# - no direct move of objects,
5430 // which are anchored to-paragraph/to-character, if
5431 // the wrapping style influence has to be considered
5432 // on the object positioning.
5433 // #i52904# - no direct move of objects,
5434 // whose vertical position doesn't depend on anchor frame.
5435 const bool bDirectMove
=
5436 FAR_AWAY
!= pFly
->getFrameArea().Top() &&
5437 bVertPosDepOnAnchor
&&
5438 !pFly
->ConsiderObjWrapInfluenceOnObjPos();
5442 SwFrameAreaDefinition::FrameAreaWriteAccess
aFrm(*pFly
);
5443 aRectFnSet
.SubTop( aFrm
, -lDiff
);
5444 aRectFnSet
.AddBottom( aFrm
, lDiff
);
5447 pFly
->GetVirtDrawObj()->SetBoundAndSnapRectsDirty();
5448 // --> OD 2004-08-17 - also notify view of <SdrObject>
5449 // instance, which represents the Writer fly frame in
5450 // the drawing layer
5451 pFly
->GetVirtDrawObj()->SetChanged();
5453 pFly
->InvalidateObjRectWithSpaces();
5456 if ( pFly
->IsFlyInContentFrame() )
5458 static_cast<SwFlyInContentFrame
*>(pFly
)->AddRefOfst( lDiff
);
5459 // #115759# - reset current relative
5460 // position to get re-positioned, if not directly moved.
5463 pAnchoredObj
->SetCurrRelPos( Point( 0, 0 ) );
5466 else if( pFly
->IsAutoPos() )
5468 pFly
->AddLastCharY( lDiff
);
5469 // OD 2004-05-18 #i28701# - follow-up of #i22341#
5470 // <mnLastTopOfLine> has also been adjusted.
5471 pFly
->AddLastTopOfLineY( lDiff
);
5473 // #i26945# - re-registration at
5474 // page frame of anchor frame, if table frame isn't
5475 // a follow table and table frame isn't in its
5476 // rebuild of last line.
5477 const SwTabFrame
* pTabFrame
= pLay
->FindTabFrame();
5478 // - save: check, if table frame is found.
5480 !( pTabFrame
->IsFollow() &&
5481 pTabFrame
->FindMaster()->IsRebuildLastLine() ) &&
5482 pFly
->IsFlyFreeFrame() )
5484 SwPageFrame
* pPageFrame
= pFly
->GetPageFrame();
5485 SwPageFrame
* pPageOfAnchor
= pFrame
->FindPageFrame();
5486 if ( pPageFrame
!= pPageOfAnchor
)
5488 pFly
->InvalidatePos();
5490 pPageFrame
->MoveFly( pFly
, pPageOfAnchor
);
5492 pPageOfAnchor
->AppendFlyToPage( pFly
);
5495 // OD 2004-05-11 #i28701# - Because of the introduction
5496 // of new positionings and alignments (e.g. aligned at
5497 // page area, but anchored at-character), the position
5498 // of the Writer fly frame has to be invalidated.
5499 pFly
->InvalidatePos();
5501 // #i26945# - follow-up of #i3317#
5502 // No arrangement of lowers, if Writer fly frame isn't
5505 ::lcl_ArrangeLowers( pFly
,
5506 aRectFnSet
.GetPrtTop(*pFly
),
5509 pFly
->SetCompletePaint();
5512 else if ( dynamic_cast< const SwAnchoredDrawObject
*>( pAnchoredObj
) != nullptr )
5515 const SwTabFrame
* pTabFrame
= pLay
->FindTabFrame();
5517 !( pTabFrame
->IsFollow() &&
5518 pTabFrame
->FindMaster()->IsRebuildLastLine() ) &&
5519 (pAnchoredObj
->GetFrameFormat().GetAnchor().GetAnchorId()
5520 != RndStdIds::FLY_AS_CHAR
))
5522 SwPageFrame
* pPageFrame
= pAnchoredObj
->GetPageFrame();
5523 SwPageFrame
* pPageOfAnchor
= pFrame
->FindPageFrame();
5524 if ( pPageFrame
!= pPageOfAnchor
)
5526 pAnchoredObj
->InvalidateObjPos();
5529 pPageFrame
->RemoveDrawObjFromPage( *pAnchoredObj
);
5531 pPageOfAnchor
->AppendDrawObjToPage( *pAnchoredObj
);
5534 // #i28701# - adjust last character
5535 // rectangle and last top of line.
5536 pAnchoredObj
->AddLastCharY( lDiff
);
5537 pAnchoredObj
->AddLastTopOfLineY( lDiff
);
5538 // #i52904# - re-introduce direct move
5539 // of drawing objects
5540 const bool bDirectMove
=
5541 static_cast<const SwDrawFrameFormat
&>(pAnchoredObj
->GetFrameFormat()).IsPosAttrSet() &&
5542 bVertPosDepOnAnchor
&&
5543 !pAnchoredObj
->ConsiderObjWrapInfluenceOnObjPos();
5546 SwObjPositioningInProgress
aObjPosInProgress( *pAnchoredObj
);
5547 if ( aRectFnSet
.IsVert() )
5549 pAnchoredObj
->DrawObj()->Move( Size( lDiff
, 0 ) );
5553 pAnchoredObj
->DrawObj()->Move( Size( 0, lDiff
) );
5556 pAnchoredObj
->InvalidateObjRectWithSpaces();
5558 pAnchoredObj
->InvalidateObjPos();
5562 OSL_FAIL( "<lcl_ArrangeLowers(..)> - unknown type of anchored object!" );
5567 // Columns and cells are ordered horizontal, not vertical
5568 if( !pFrame
->IsColumnFrame() && !pFrame
->IsCellFrame() )
5569 lYStart
= aRectFnSet
.YInc( lYStart
,
5570 aRectFnSet
.GetHeight(pFrame
->getFrameArea()) );
5572 // Nowadays, the content inside a cell can flow into the follow table.
5573 // Thus, the cell may only grow up to the end of the environment.
5574 // So the content may have grown, but the cell could not grow.
5575 // Therefore we have to trigger a formatting for the frames, which do
5576 // not fit into the cell anymore:
5577 SwTwips nDistanceToUpperPrtBottom
=
5578 aRectFnSet
.BottomDist( pFrame
->getFrameArea(), aRectFnSet
.GetPrtBottom(*pLay
) );
5579 // #i56146# - Revise fix of issue #i26945#
5580 // do *not* consider content inside fly frames, if it's an undersized paragraph.
5581 // #i26945# - consider content inside fly frames
5582 if ( nDistanceToUpperPrtBottom
< 0 &&
5583 ( ( pFrame
->IsInFly() &&
5584 ( !pFrame
->IsTextFrame() ||
5585 !static_cast<SwTextFrame
*>(pFrame
)->IsUndersized() ) ) ||
5586 pFrame
->IsInSplitTableRow() ) )
5588 pFrame
->InvalidatePos();
5591 pFrame
= pFrame
->GetNext();
5596 void SwCellFrame::Format( vcl::RenderContext
* /*pRenderContext*/, const SwBorderAttrs
*pAttrs
)
5598 OSL_ENSURE( pAttrs
, "CellFrame::Format, pAttrs is 0." );
5599 const SwTabFrame
* pTab
= FindTabFrame();
5600 SwRectFnSet
aRectFnSet(pTab
);
5602 if ( !isFramePrintAreaValid() )
5604 setFramePrintAreaValid(true);
5609 SwTwips nTopSpace
, nBottomSpace
, nLeftSpace
, nRightSpace
;
5611 if ( pTab
->IsCollapsingBorders() && !Lower()->IsRowFrame() )
5613 const SvxBoxItem
& rBoxItem
= pAttrs
->GetBox();
5614 nLeftSpace
= rBoxItem
.GetDistance( SvxBoxItemLine::LEFT
);
5615 nRightSpace
= rBoxItem
.GetDistance( SvxBoxItemLine::RIGHT
);
5616 nTopSpace
= static_cast<SwRowFrame
*>(GetUpper())->GetTopMarginForLowers();
5617 nBottomSpace
= static_cast<SwRowFrame
*>(GetUpper())->GetBottomMarginForLowers();
5621 // OD 23.01.2003 #106895# - add 1st param to <SwBorderAttrs::CalcRight(..)>
5622 nLeftSpace
= pAttrs
->CalcLeft( this );
5623 nRightSpace
= pAttrs
->CalcRight( this );
5624 nTopSpace
= pAttrs
->CalcTop();
5625 nBottomSpace
= pAttrs
->CalcBottom();
5627 aRectFnSet
.SetXMargins( *this, nLeftSpace
, nRightSpace
);
5628 aRectFnSet
.SetYMargins( *this, nTopSpace
, nBottomSpace
);
5632 tools::Long nRemaining
= GetTabBox()->getRowSpan() >= 1 ?
5633 ::lcl_CalcMinCellHeight( this, pTab
->IsConsiderObjsForMinCellHeight(), pAttrs
) :
5635 if ( !isFrameAreaSizeValid() )
5637 setFrameAreaSizeValid(true);
5639 //The VarSize of the CellFrames is always the width.
5640 //The width is not variable though, it is defined by the format.
5641 //This predefined value however does not necessary match the actual
5642 //width. The width is calculated based on the attribute, the value in
5643 //the attribute matches the desired value of the TabFrame. Changes which
5644 //were done there are taken into account here proportionately.
5645 //If the cell doesn't have a neighbour anymore, it does not take the
5646 //attribute into account and takes the rest of the upper instead.
5650 const SwTwips nWish
= pTab
->GetFormat()->GetFrameSize().GetWidth();
5651 nWidth
= pAttrs
->GetSize().Width();
5653 OSL_ENSURE( nWish
, "Table without width?" );
5654 OSL_ENSURE( nWidth
<= nWish
, "Width of cell larger than table." );
5655 OSL_ENSURE( nWidth
> 0, "Box without width" );
5657 const tools::Long nPrtWidth
= aRectFnSet
.GetWidth(pTab
->getFramePrintArea());
5658 if ( nWish
!= nPrtWidth
)
5660 // Avoid rounding problems, at least for the new table model
5661 if ( pTab
->GetTable()->IsNewModel() )
5663 // 1. sum of widths of cells up to this cell (in model)
5664 const SwTableLine
* pTabLine
= GetTabBox()->GetUpper();
5665 const SwTableBoxes
& rBoxes
= pTabLine
->GetTabBoxes();
5666 const SwTableBox
* pTmpBox
= nullptr;
5668 SwTwips nSumWidth
= 0;
5672 pTmpBox
= rBoxes
[ i
++ ];
5673 nSumWidth
+= pTmpBox
->GetFrameFormat()->GetFrameSize().GetWidth();
5675 while ( pTmpBox
!= GetTabBox() );
5677 // 2. calculate actual width of cells up to this one
5678 double nTmpWidth
= nSumWidth
;
5679 nTmpWidth
*= nPrtWidth
;
5681 nWidth
= static_cast<SwTwips
>(nTmpWidth
);
5683 // 3. calculate frame widths of cells up to this one:
5684 const SwFrame
* pTmpCell
= static_cast<const SwLayoutFrame
*>(GetUpper())->Lower();
5685 SwTwips nSumFrameWidths
= 0;
5686 while ( pTmpCell
!= this )
5688 nSumFrameWidths
+= aRectFnSet
.GetWidth(pTmpCell
->getFrameArea());
5689 pTmpCell
= pTmpCell
->GetNext();
5692 nWidth
= nWidth
- nSumFrameWidths
;
5696 // #i12092# use double instead of long,
5697 // otherwise this could lead to overflows
5698 double nTmpWidth
= nWidth
;
5699 nTmpWidth
*= nPrtWidth
;
5701 nWidth
= static_cast<SwTwips
>(nTmpWidth
);
5707 OSL_ENSURE( pAttrs
->GetSize().Width() > 0, "Box without width" );
5708 nWidth
= aRectFnSet
.GetWidth(GetUpper()->getFramePrintArea());
5709 SwFrame
*pPre
= GetUpper()->Lower();
5710 while ( pPre
!= this )
5712 nWidth
-= aRectFnSet
.GetWidth(pPre
->getFrameArea());
5713 pPre
= pPre
->GetNext();
5717 const tools::Long nDiff
= nWidth
- aRectFnSet
.GetWidth(getFrameArea());
5720 SwFrameAreaDefinition::FrameAreaWriteAccess
aFrm(*this);
5722 if( IsNeighbourFrame() && IsRightToLeft() )
5724 aRectFnSet
.SubLeft( aFrm
, nDiff
);
5728 aRectFnSet
.AddRight( aFrm
, nDiff
);
5733 SwFrameAreaDefinition::FramePrintAreaWriteAccess
aPrt(*this);
5734 aRectFnSet
.AddRight( aPrt
, nDiff
);
5737 //Adjust the height, it's defined through the content and the margins.
5738 const tools::Long nDiffHeight
= nRemaining
- aRectFnSet
.GetHeight(getFrameArea());
5741 if ( nDiffHeight
> 0 )
5743 //Validate again if no growth happened. Invalidation is done
5744 //through AdjustCells of the row.
5745 if ( !Grow( nDiffHeight
) )
5747 setFrameAreaSizeValid(true);
5748 setFramePrintAreaValid(true);
5753 // Only keep invalidated if shrinking was actually done; the
5754 // attempt can be ignored because all horizontally adjoined
5755 // cells have to be the same height.
5756 if ( !Shrink( -nDiffHeight
) )
5758 setFrameAreaSizeValid(true);
5759 setFramePrintAreaValid(true);
5764 const SwFormatVertOrient
&rOri
= pAttrs
->GetAttrSet().GetVertOrient();
5769 // From now on, all operations are related to the table cell.
5770 aRectFnSet
.Refresh(this);
5772 SwPageFrame
* pPg
= nullptr;
5773 if ( !FindTabFrame()->IsRebuildLastLine() && text::VertOrientation::NONE
!= rOri
.GetVertOrient() &&
5774 // #158225# no vertical alignment of covered cells
5776 (pPg
= FindPageFrame())!=nullptr )
5778 if ( !Lower()->IsContentFrame() && !Lower()->IsSctFrame() && !Lower()->IsTabFrame() )
5780 // OSL_ENSURE(for HTML-import!
5781 OSL_ENSURE( false, "VAlign to cell without content" );
5784 bool bVertDir
= true;
5785 // #i43913# - no vertical alignment, if wrapping
5786 // style influence is considered on object positioning and
5787 // an object is anchored inside the cell.
5788 const bool bConsiderWrapOnObjPos( GetFormat()->getIDocumentSettingAccess().get(DocumentSettingId::CONSIDER_WRAP_ON_OBJECT_POSITION
) );
5789 // No alignment if fly with wrap overlaps the cell.
5790 if ( pPg
->GetSortedObjs() )
5792 SwRect
aRect( getFramePrintArea() ); aRect
+= getFrameArea().Pos();
5793 for (SwAnchoredObject
* pAnchoredObj
: *pPg
->GetSortedObjs())
5795 SwRect
aTmp( pAnchoredObj
->GetObjRect() );
5796 const SwFrame
* pAnch
= pAnchoredObj
->GetAnchorFrame();
5797 if ( (bConsiderWrapOnObjPos
&& IsAnLower( pAnch
)) || (!bConsiderWrapOnObjPos
&& aTmp
.Overlaps( aRect
)) )
5799 const SwFrameFormat
& rAnchoredObjFrameFormat
= pAnchoredObj
->GetFrameFormat();
5800 const SwFormatSurround
&rSur
= rAnchoredObjFrameFormat
.GetSurround();
5802 if ( bConsiderWrapOnObjPos
|| css::text::WrapTextMode_THROUGH
!= rSur
.GetSurround() )
5804 // frames, which the cell is a lower of, aren't relevant
5805 if ( auto pFly
= pAnchoredObj
->DynCastFlyFrame() )
5807 if ( pFly
->IsAnLower( this ) )
5812 // #i52904# - no vertical alignment,
5813 // if object, anchored inside cell, has temporarily
5814 // consider its wrapping style on object positioning.
5815 // #i58806# - no vertical alignment
5816 // if object does not follow the text flow.
5817 if ( bConsiderWrapOnObjPos
||
5818 !IsAnLower( pAnch
) ||
5819 pAnchoredObj
->IsTmpConsiderWrapInfluence() ||
5820 !rAnchoredObjFrameFormat
.GetFollowTextFlow().GetValue() )
5830 tools::Long nPrtHeight
= aRectFnSet
.GetHeight(getFramePrintArea());
5831 if( ( bVertDir
&& ( nRemaining
-= lcl_CalcTopAndBottomMargin( *this, *pAttrs
) ) < nPrtHeight
) ||
5832 aRectFnSet
.GetTop(Lower()->getFrameArea()) != aRectFnSet
.GetPrtTop(*this) )
5834 tools::Long nDiff
= aRectFnSet
.GetHeight(getFramePrintArea()) - nRemaining
;
5837 tools::Long lTopOfst
= 0;
5840 switch ( rOri
.GetVertOrient() )
5842 case text::VertOrientation::CENTER
: lTopOfst
= nDiff
/ 2; break;
5843 case text::VertOrientation::BOTTOM
: lTopOfst
= nDiff
; break;
5847 tools::Long nTmp
= aRectFnSet
.YInc(
5848 aRectFnSet
.GetPrtTop(*this), lTopOfst
);
5849 if ( lcl_ArrangeLowers( this, nTmp
, !bVertDir
) )
5856 //Was an old alignment taken into account?
5857 if ( Lower()->IsContentFrame() )
5859 const tools::Long lYStart
= aRectFnSet
.GetPrtTop(*this);
5860 lcl_ArrangeLowers( this, lYStart
, true );
5864 // Handle rotated portions of lowers: it's possible that we have changed amount of vertical
5865 // space since the last format, and this affects how many rotated portions we need. So throw
5866 // away the current portions to build them using the new line width.
5867 for (SwFrame
* pFrame
= Lower(); pFrame
; pFrame
= pFrame
->GetNext())
5869 if (!pFrame
->IsTextFrame())
5874 auto pTextFrame
= static_cast<SwTextFrame
*>(pFrame
);
5875 if (!pTextFrame
->GetHasRotatedPortions())
5880 pTextFrame
->Prepare();
5884 void SwCellFrame::SwClientNotify(const SwModify
& rMod
, const SfxHint
& rHint
)
5886 if(auto pNewFormatHint
= dynamic_cast<const sw::TableBoxFormatChanged
*>(&rHint
))
5888 if(GetTabBox() != &pNewFormatHint
->m_rTableBox
)
5890 RegisterToFormat(const_cast<SwTableBoxFormat
&>(pNewFormatHint
->m_rNewFormat
));
5894 SetDerivedVert(false);
5898 // make sure that the row will be formatted, in order
5899 // to have the correct Get(Top|Bottom)MarginForLowers values
5901 const SwTabFrame
* pTab
= FindTabFrame();
5902 if(pTab
&& pTab
->IsCollapsingBorders())
5904 SwFrame
* pRow
= GetUpper();
5905 pRow
->InvalidateSize_();
5906 pRow
->InvalidatePrt_();
5909 else if(auto pMoveTableBoxHint
= dynamic_cast<const sw::MoveTableBoxHint
*>(&rHint
))
5911 if(GetTabBox() != &pMoveTableBoxHint
->m_rTableBox
)
5913 const_cast<SwFrameFormat
*>(&pMoveTableBoxHint
->m_rNewFormat
)->Add(this);
5915 ReinitializeFrameSizeAttrFlags();
5916 SetDerivedVert(false);
5920 else if (rHint
.GetId() == SfxHintId::SwLegacyModify
)
5922 auto pLegacy
= static_cast<const sw::LegacyModifyHint
*>(&rHint
);
5923 const SfxPoolItem
* pVertOrientItem
= nullptr;
5924 const SfxPoolItem
* pProtectItem
= nullptr;
5925 const SfxPoolItem
* pFrameDirItem
= nullptr;
5926 const SfxPoolItem
* pBoxItem
= nullptr;
5927 const auto nWhich
= pLegacy
->m_pNew
? pLegacy
->m_pNew
->Which() : 0;
5930 case RES_ATTRSET_CHG
:
5932 auto& rChgSet
= *static_cast<const SwAttrSetChg
*>(pLegacy
->m_pNew
)->GetChgSet();
5933 pVertOrientItem
= rChgSet
.GetItemIfSet(RES_VERT_ORIENT
, false);
5934 pProtectItem
= rChgSet
.GetItemIfSet(RES_PROTECT
, false);
5935 pFrameDirItem
= rChgSet
.GetItemIfSet(RES_FRAMEDIR
, false);
5936 pBoxItem
= rChgSet
.GetItemIfSet(RES_BOX
, false);
5939 case RES_VERT_ORIENT
:
5940 pVertOrientItem
= pLegacy
->m_pNew
;
5943 pProtectItem
= pLegacy
->m_pNew
;
5946 pFrameDirItem
= pLegacy
->m_pNew
;
5949 pBoxItem
= pLegacy
->m_pNew
;
5955 const auto eVertOrient
= static_cast<const SwFormatVertOrient
*>(pVertOrientItem
)->GetVertOrient();
5956 if(text::VertOrientation::NONE
== eVertOrient
&& Lower() && Lower()->IsContentFrame())
5958 SwRectFnSet
aRectFnSet(this);
5959 const tools::Long lYStart
= aRectFnSet
.GetPrtTop(*this);
5960 bInva
= lcl_ArrangeLowers(this, lYStart
, false);
5968 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
5971 SwViewShell
* pSh
= getRootFrame()->GetCurrShell();
5972 if(pSh
&& pSh
->GetLayout()->IsAnyShellAccessible())
5973 pSh
->Imp()->InvalidateAccessibleEditableState(true, this);
5978 SetDerivedVert(false);
5984 SwFrame
* pTmpUpper
= GetUpper();
5985 while(pTmpUpper
->GetUpper() && !pTmpUpper
->GetUpper()->IsTabFrame())
5986 pTmpUpper
= pTmpUpper
->GetUpper();
5988 SwTabFrame
* pTabFrame
= static_cast<SwTabFrame
*>(pTmpUpper
->GetUpper());
5989 if(pTabFrame
->IsCollapsingBorders())
5991 // Invalidate lowers of this and next row:
5992 lcl_InvalidateAllLowersPrt(static_cast<SwRowFrame
*>(pTmpUpper
));
5993 pTmpUpper
= pTmpUpper
->GetNext();
5995 lcl_InvalidateAllLowersPrt(static_cast<SwRowFrame
*>(pTmpUpper
));
5997 pTabFrame
->InvalidatePrt();
6000 SwLayoutFrame::SwClientNotify(rMod
, rHint
);
6004 tools::Long
SwCellFrame::GetLayoutRowSpan() const
6006 const SwTableBox
*pTabBox
= GetTabBox();
6007 tools::Long nRet
= pTabBox
? pTabBox
->getRowSpan() : 0;
6010 const SwFrame
* pRow
= GetUpper();
6011 const SwTabFrame
* pTab
= pRow
? static_cast<const SwTabFrame
*>(pRow
->GetUpper()) : nullptr;
6013 if ( pTab
&& pTab
->IsFollow() && pRow
== pTab
->GetFirstNonHeadlineRow() )
6019 const SwCellFrame
* SwCellFrame::GetCoveredCellInRow(const SwRowFrame
& rRow
) const
6021 if (GetLayoutRowSpan() <= 1)
6023 // Not merged vertically.
6027 for (const SwFrame
* pCell
= rRow
.GetLower(); pCell
; pCell
= pCell
->GetNext())
6029 if (!pCell
->IsCellFrame())
6034 auto pCellFrame
= static_cast<const SwCellFrame
*>(pCell
);
6035 if (!pCellFrame
->IsCoveredCell())
6040 if (pCellFrame
->getFrameArea().Left() != getFrameArea().Left())
6045 if (pCellFrame
->getFrameArea().Width() != getFrameArea().Width())
6050 // pCellFrame is covered, there are only covered cell frames between "this" and pCellFrame
6051 // and the horizontal position/size matches "this".
6058 std::vector
<const SwCellFrame
*> SwCellFrame::GetCoveredCells() const
6060 std::vector
<const SwCellFrame
*> aRet
;
6061 if (GetLayoutRowSpan() <= 1)
6066 if (!GetUpper()->IsRowFrame())
6071 auto pFirstRowFrame
= static_cast<const SwRowFrame
*>(GetUpper());
6072 if (!pFirstRowFrame
->GetNext())
6077 if (!pFirstRowFrame
->GetNext()->IsRowFrame())
6082 for (const SwFrame
* pRow
= pFirstRowFrame
->GetNext(); pRow
; pRow
= pRow
->GetNext())
6084 if (!pRow
->IsRowFrame())
6089 auto pRowFrame
= static_cast<const SwRowFrame
*>(pRow
);
6090 const SwCellFrame
* pCovered
= GetCoveredCellInRow(*pRowFrame
);
6096 // Found a cell in a next row that is covered by "this".
6097 aRet
.push_back(pCovered
);
6103 void SwCellFrame::dumpAsXmlAttributes(xmlTextWriterPtr pWriter
) const
6105 SwFrame::dumpAsXmlAttributes(pWriter
);
6106 if (SwCellFrame
* pFollow
= GetFollowCell())
6107 (void)xmlTextWriterWriteFormatAttribute(pWriter
, BAD_CAST("follow"), "%" SAL_PRIuUINT32
, pFollow
->GetFrameId());
6109 if (SwCellFrame
* pPrevious
= GetPreviousCell())
6110 (void)xmlTextWriterWriteFormatAttribute(pWriter
, BAD_CAST("precede"), "%" SAL_PRIuUINT32
, pPrevious
->GetFrameId());
6113 void SwCellFrame::dumpAsXml(xmlTextWriterPtr writer
) const
6115 (void)xmlTextWriterStartElement(writer
, reinterpret_cast<const xmlChar
*>("cell"));
6116 dumpAsXmlAttributes(writer
);
6117 (void)xmlTextWriterWriteFormatAttribute( writer
, BAD_CAST( "rowspan" ), "%ld", GetLayoutRowSpan() );
6119 (void)xmlTextWriterStartElement(writer
, BAD_CAST("infos"));
6120 dumpInfosAsXml(writer
);
6121 (void)xmlTextWriterEndElement(writer
);
6122 dumpChildrenAsXml(writer
);
6124 (void)xmlTextWriterEndElement(writer
);
6128 void SwCellFrame::Cut()
6130 // notification for accessibility
6131 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
6133 SwRootFrame
*pRootFrame
= getRootFrame();
6134 if( pRootFrame
&& pRootFrame
->IsAnyShellAccessible() )
6136 SwViewShell
* pVSh
= pRootFrame
->GetCurrShell();
6137 if ( pVSh
&& pVSh
->Imp() )
6139 pVSh
->Imp()->DisposeAccessibleFrame( this );
6145 SwLayoutFrame::Cut();
6148 // Helper functions for repeated headlines:
6150 bool SwTabFrame::IsInHeadline( const SwFrame
& rFrame
) const
6152 OSL_ENSURE( IsAnLower( &rFrame
) && rFrame
.IsInTab(),
6153 "SwTabFrame::IsInHeadline called for frame not lower of table" );
6155 const SwFrame
* pTmp
= &rFrame
;
6156 while ( !pTmp
->GetUpper()->IsTabFrame() )
6157 pTmp
= pTmp
->GetUpper();
6159 return GetTable()->IsHeadline( *static_cast<const SwRowFrame
*>(pTmp
)->GetTabLine() );
6163 * If this is a master table, we can may assume, that there are at least
6164 * nRepeat lines in the table.
6165 * If this is a follow table, there are intermediate states for the table
6166 * layout, e.g., during deletion of rows, which makes it necessary to find
6167 * the first non-headline row by evaluating the headline flag at the row frame.
6169 SwRowFrame
* SwTabFrame::GetFirstNonHeadlineRow() const
6171 SwRowFrame
* pRet
= const_cast<SwRowFrame
*>(static_cast<const SwRowFrame
*>(Lower()));
6176 while ( pRet
&& pRet
->IsRepeatedHeadline() )
6177 pRet
= static_cast<SwRowFrame
*>(pRet
->GetNext());
6181 sal_uInt16 nRepeat
= GetTable()->GetRowsToRepeat();
6182 while ( pRet
&& nRepeat
> 0 )
6184 pRet
= static_cast<SwRowFrame
*>(pRet
->GetNext());
6193 bool SwTable::IsHeadline( const SwTableLine
& rLine
) const
6195 for ( sal_uInt16 i
= 0; i
< GetRowsToRepeat(); ++i
)
6196 if ( GetTabLines()[ i
] == &rLine
)
6202 bool SwTabFrame::IsLayoutSplitAllowed() const
6204 return GetFormat()->GetLayoutSplit().GetValue();
6209 sal_uInt16
SwTabFrame::GetBottomLineSize() const
6211 OSL_ENSURE( IsCollapsingBorders(),
6212 "BottomLineSize only required for collapsing borders" );
6214 OSL_ENSURE( Lower(), "Warning! Trying to prevent a crash" );
6216 const SwFrame
* pTmp
= GetLastLower();
6218 // #124755# Try to make code robust
6219 if ( !pTmp
) return 0;
6221 return static_cast<const SwRowFrame
*>(pTmp
)->GetBottomLineSize();
6224 bool SwTabFrame::IsCollapsingBorders() const
6226 return GetFormat()->GetAttrSet().Get( RES_COLLAPSING_BORDERS
).GetValue();
6229 void SwTabFrame::dumpAsXml(xmlTextWriterPtr writer
) const
6231 (void)xmlTextWriterStartElement(writer
, reinterpret_cast<const xmlChar
*>("tab"));
6232 dumpAsXmlAttributes(writer
);
6234 (void)xmlTextWriterStartElement(writer
, BAD_CAST("infos"));
6235 dumpInfosAsXml(writer
);
6236 (void)xmlTextWriterEndElement(writer
);
6237 dumpChildrenAsXml(writer
);
6239 (void)xmlTextWriterEndElement(writer
);
6242 /// Local helper function to calculate height of first text row
6243 static SwTwips
lcl_CalcHeightOfFirstContentLine( const SwRowFrame
& rSourceLine
)
6245 // Find corresponding split line in master table
6246 const SwTabFrame
* pTab
= rSourceLine
.FindTabFrame();
6247 SwRectFnSet
aRectFnSet(pTab
);
6248 const SwCellFrame
* pCurrSourceCell
= static_cast<const SwCellFrame
*>(rSourceLine
.Lower());
6250 // 1. Case: rSourceLine is a follow flow line.
6251 // In this case we have to return the minimum of the heights
6252 // of the first lines in rSourceLine.
6254 // 2. Case: rSourceLine is not a follow flow line.
6255 // In this case we have to return the maximum of the heights
6256 // of the first lines in rSourceLine.
6257 bool bIsInFollowFlowLine
= rSourceLine
.IsInFollowFlowRow();
6258 SwTwips nHeight
= bIsInFollowFlowLine
? LONG_MAX
: 0;
6260 while ( pCurrSourceCell
)
6263 // Skip cells which are not responsible for the height of
6264 // the follow flow line:
6265 if ( bIsInFollowFlowLine
&& pCurrSourceCell
->GetLayoutRowSpan() > 1 )
6267 pCurrSourceCell
= static_cast<const SwCellFrame
*>(pCurrSourceCell
->GetNext());
6271 const SwFrame
*pTmp
= pCurrSourceCell
->Lower();
6274 SwTwips nTmpHeight
= USHRT_MAX
;
6275 // #i32456# Consider lower row frames
6276 if ( pTmp
->IsRowFrame() )
6278 const SwRowFrame
* pTmpSourceRow
= static_cast<const SwRowFrame
*>(pCurrSourceCell
->Lower());
6279 nTmpHeight
= lcl_CalcHeightOfFirstContentLine( *pTmpSourceRow
);
6281 else if (pTmp
->IsTabFrame() || (pTmp
->IsSctFrame() && pTmp
->GetLower() && pTmp
->GetLower()->IsTabFrame()))
6283 SwTabFrame
const*const pTabFrame(pTmp
->IsTabFrame()
6284 ? static_cast<SwTabFrame
const*>(pTmp
)
6285 : static_cast<SwTabFrame
const*>(pTmp
->GetLower()));
6286 nTmpHeight
= pTabFrame
->CalcHeightOfFirstContentLine();
6288 else if (pTmp
->IsTextFrame() || (pTmp
->IsSctFrame() && pTmp
->GetLower() && pTmp
->GetLower()->IsTextFrame()))
6290 // Section frames don't influence the size/position of text
6291 // frames, so 'text frame' and 'text frame in section frame' is
6293 SwTextFrame
* pTextFrame
= nullptr;
6294 if (pTmp
->IsTextFrame())
6295 pTextFrame
= const_cast<SwTextFrame
*>(static_cast<const SwTextFrame
*>(pTmp
));
6297 pTextFrame
= const_cast<SwTextFrame
*>(static_cast<const SwTextFrame
*>(pTmp
->GetLower()));
6298 pTextFrame
->GetFormatted();
6299 nTmpHeight
= pTextFrame
->FirstLineHeight();
6302 if ( USHRT_MAX
!= nTmpHeight
)
6304 const SwCellFrame
* pPrevCell
= pCurrSourceCell
->GetPreviousCell();
6307 // If we are in a split row, there may be some space
6308 // left in the cell frame of the master row.
6309 // We look for the minimum of all first line heights;
6310 SwTwips nReal
= aRectFnSet
.GetHeight(pPrevCell
->getFramePrintArea());
6311 const SwFrame
* pFrame
= pPrevCell
->Lower();
6312 const SwFrame
* pLast
= pFrame
;
6315 nReal
-= aRectFnSet
.GetHeight(pFrame
->getFrameArea());
6317 pFrame
= pFrame
->GetNext();
6320 // #i26831#, #i26520#
6321 // The additional lower space of the current last.
6322 // #115759# - do *not* consider the
6323 // additional lower space for 'master' text frames
6324 if ( pLast
&& pLast
->IsFlowFrame() &&
6325 ( !pLast
->IsTextFrame() ||
6326 !static_cast<const SwTextFrame
*>(pLast
)->GetFollow() ) )
6328 nReal
+= SwFlowFrame::CastFlowFrame(pLast
)->CalcAddLowerSpaceAsLastInTableCell();
6330 // Don't forget the upper space and lower space,
6331 // #115759# - do *not* consider the upper
6332 // and the lower space for follow text frames.
6333 if ( pTmp
->IsFlowFrame() &&
6334 ( !pTmp
->IsTextFrame() ||
6335 !static_cast<const SwTextFrame
*>(pTmp
)->IsFollow() ) )
6337 nTmpHeight
+= SwFlowFrame::CastFlowFrame(pTmp
)->CalcUpperSpace( nullptr, pLast
);
6338 nTmpHeight
+= SwFlowFrame::CastFlowFrame(pTmp
)->CalcLowerSpace();
6340 // #115759# - consider additional lower
6341 // space of <pTmp>, if contains only one line.
6342 // In this case it would be the new last text frame, which
6343 // would have no follow and thus would add this space.
6344 if ( pTmp
->IsTextFrame() &&
6345 const_cast<SwTextFrame
*>(static_cast<const SwTextFrame
*>(pTmp
))
6346 ->GetLineCount(TextFrameIndex(COMPLETE_STRING
)) == 1)
6348 nTmpHeight
+= SwFlowFrame::CastFlowFrame(pTmp
)
6349 ->CalcAddLowerSpaceAsLastInTableCell();
6352 nTmpHeight
-= nReal
;
6356 // pFirstRow is not a FollowFlowRow. In this case,
6357 // we look for the maximum of all first line heights:
6358 SwBorderAttrAccess
aAccess( SwFrame::GetCache(), pCurrSourceCell
);
6359 const SwBorderAttrs
&rAttrs
= *aAccess
.Get();
6360 nTmpHeight
+= rAttrs
.CalcTop() + rAttrs
.CalcBottom();
6362 // Don't forget the upper space and lower space,
6363 if ( pTmp
->IsFlowFrame() )
6365 nTmpHeight
+= SwFlowFrame::CastFlowFrame(pTmp
)->CalcUpperSpace();
6366 nTmpHeight
+= SwFlowFrame::CastFlowFrame(pTmp
)->CalcLowerSpace();
6371 if ( bIsInFollowFlowLine
)
6374 if ( nTmpHeight
< nHeight
)
6375 nHeight
= nTmpHeight
;
6380 if ( nTmpHeight
> nHeight
&& USHRT_MAX
!= nTmpHeight
)
6381 nHeight
= nTmpHeight
;
6385 pCurrSourceCell
= static_cast<const SwCellFrame
*>(pCurrSourceCell
->GetNext());
6388 return ( LONG_MAX
== nHeight
) ? 0 : nHeight
;
6391 /// Function to calculate height of first text row
6392 SwTwips
SwTabFrame::CalcHeightOfFirstContentLine() const
6394 SwRectFnSet
aRectFnSet(this);
6396 const bool bDontSplit
= !IsFollow() && !GetFormat()->GetLayoutSplit().GetValue();
6400 // Table is not allowed to split: Take the whole height, that's all
6401 return aRectFnSet
.GetHeight(getFrameArea());
6404 SwTwips nTmpHeight
= 0;
6406 const SwRowFrame
* pFirstRow
= GetFirstNonHeadlineRow();
6407 OSL_ENSURE( !IsFollow() || pFirstRow
, "FollowTable without Lower" );
6410 if ( pFirstRow
&& pFirstRow
->IsRowSpanLine() && pFirstRow
->GetNext() )
6411 pFirstRow
= static_cast<const SwRowFrame
*>(pFirstRow
->GetNext());
6413 // Calculate the height of the headlines:
6414 const sal_uInt16 nRepeat
= GetTable()->GetRowsToRepeat();
6415 SwTwips nRepeatHeight
= nRepeat
? lcl_GetHeightOfRows( GetLower(), nRepeat
) : 0;
6417 // Calculate the height of the keeping lines
6418 // (headlines + following keeping lines):
6419 SwTwips nKeepHeight
= nRepeatHeight
;
6420 if ( GetFormat()->GetDoc()->GetDocumentSettingManager().get(DocumentSettingId::TABLE_ROW_KEEP
) )
6422 sal_uInt16 nKeepRows
= nRepeat
;
6424 // Check how many rows want to keep together
6425 while ( pFirstRow
&& pFirstRow
->ShouldRowKeepWithNext() )
6428 pFirstRow
= static_cast<const SwRowFrame
*>(pFirstRow
->GetNext());
6431 if ( nKeepRows
> nRepeat
)
6432 nKeepHeight
= lcl_GetHeightOfRows( GetLower(), nKeepRows
);
6435 // For master tables, the height of the headlines + the height of the
6436 // keeping lines (if any) has to be considered. For follow tables, we
6437 // only consider the height of the keeping rows without the repeated lines:
6440 nTmpHeight
= nKeepHeight
;
6444 nTmpHeight
= nKeepHeight
- nRepeatHeight
;
6447 // pFirstRow row is the first non-heading row.
6448 // nTmpHeight is the height of the heading row if we are a follow.
6451 const bool bSplittable
= pFirstRow
->IsRowSplitAllowed();
6452 const SwTwips nFirstLineHeight
= aRectFnSet
.GetHeight(pFirstRow
->getFrameArea());
6456 // pFirstRow is not splittable, but it is still possible that the line height of pFirstRow
6457 // actually is determined by a lower cell with rowspan = -1. In this case we should not
6458 // just return the height of the first line. Basically we need to get the height of the
6459 // line as it would be on the last page. Since this is quite complicated to calculate,
6460 // we only calculate the height of the first line.
6461 SwFormatFrameSize
const& rFrameSize(pFirstRow
->GetAttrSet()->GetFrameSize());
6462 if ( pFirstRow
->GetPrev() &&
6463 static_cast<const SwRowFrame
*>(pFirstRow
->GetPrev())->IsRowSpanLine()
6464 && rFrameSize
.GetHeightSizeType() != SwFrameSize::Fixed
)
6466 // Calculate maximum height of all cells with rowspan = 1:
6467 SwTwips nMaxHeight
= rFrameSize
.GetHeightSizeType() == SwFrameSize::Minimum
6468 ? rFrameSize
.GetHeight()
6470 const SwCellFrame
* pLower2
= static_cast<const SwCellFrame
*>(pFirstRow
->Lower());
6473 if ( 1 == pLower2
->GetTabBox()->getRowSpan() )
6475 const SwTwips nCellHeight
= lcl_CalcMinCellHeight( pLower2
, true );
6476 nMaxHeight
= std::max( nCellHeight
, nMaxHeight
);
6478 pLower2
= static_cast<const SwCellFrame
*>(pLower2
->GetNext());
6480 nTmpHeight
+= nMaxHeight
;
6484 nTmpHeight
+= nFirstLineHeight
;
6488 // Optimization: lcl_CalcHeightOfFirstContentLine actually can trigger
6489 // a formatting of the row frame (via the GetFormatted()). We don't
6490 // want this formatting if the row does not have a height.
6491 else if ( 0 != nFirstLineHeight
)
6493 const bool bOldJoinLock
= IsJoinLocked();
6494 const_cast<SwTabFrame
*>(this)->LockJoin();
6495 const SwTwips nHeightOfFirstContentLine
= lcl_CalcHeightOfFirstContentLine( *pFirstRow
);
6497 // Consider minimum row height:
6498 const SwFormatFrameSize
&rSz
= pFirstRow
->GetFormat()->GetFrameSize();
6500 SwTwips nMinRowHeight
= 0;
6501 if (rSz
.GetHeightSizeType() == SwFrameSize::Minimum
)
6503 nMinRowHeight
= std::max(rSz
.GetHeight() - lcl_calcHeightOfRowBeforeThisFrame(*pFirstRow
),
6507 nTmpHeight
+= std::max( nHeightOfFirstContentLine
, nMinRowHeight
);
6509 if ( !bOldJoinLock
)
6510 const_cast<SwTabFrame
*>(this)->UnlockJoin();
6517 // Some more functions for covered/covering cells. This way inclusion of
6518 // SwCellFrame can be avoided
6520 bool SwFrame::IsLeaveUpperAllowed() const
6525 bool SwCellFrame::IsLeaveUpperAllowed() const
6527 return GetLayoutRowSpan() > 1;
6530 bool SwFrame::IsCoveredCell() const
6535 bool SwCellFrame::IsCoveredCell() const
6537 return GetLayoutRowSpan() < 1;
6540 bool SwFrame::IsInCoveredCell() const
6544 const SwFrame
* pThis
= this;
6545 while ( pThis
&& !pThis
->IsCellFrame() )
6546 pThis
= pThis
->GetUpper();
6549 bRet
= pThis
->IsCoveredCell();
6554 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */