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 <sal/config.h>
21 #include <sal/log.hxx>
22 #include <osl/diagnose.h>
23 #include <svx/svdobj.hxx>
25 #include <anchoredobject.hxx>
26 #include <bodyfrm.hxx>
27 #include <swtable.hxx>
28 #include <rootfrm.hxx>
29 #include <pagefrm.hxx>
30 #include <viewimp.hxx>
31 #include <viewopt.hxx>
33 #include <frmtool.hxx>
34 #include <IDocumentFieldsAccess.hxx>
35 #include <editeng/formatbreakitem.hxx>
36 #include <editeng/keepitem.hxx>
37 #include <fmtanchr.hxx>
38 #include <fmtsrnd.hxx>
39 #include <fmtpdsc.hxx>
40 #include <editeng/ulspitem.hxx>
41 #include <tgrditem.hxx>
44 #include <editeng/pgrditem.hxx>
48 #include <notxtfrm.hxx>
51 #include <pagedesc.hxx>
54 #include <sectfrm.hxx>
55 #include <section.hxx>
56 #include <dbg_lay.hxx>
57 #include <lineinfo.hxx>
58 #include <fmtclbl.hxx>
59 #include <sortedobjs.hxx>
60 #include <layouter.hxx>
61 #include <fmtfollowtextflow.hxx>
63 #include <IDocumentSettingAccess.hxx>
64 #include <IDocumentDrawModelAccess.hxx>
67 #include <flyfrms.hxx>
69 bool SwFlowFrame::s_bMoveBwdJump
= false;
71 SwFlowFrame::SwFlowFrame( SwFrame
&rFrame
) :
74 m_pPrecede( nullptr ),
76 m_bUndersized( false ),
80 SwFlowFrame::~SwFlowFrame()
84 m_pFollow
->m_pPrecede
= nullptr;
88 m_pPrecede
->m_pFollow
= nullptr;
92 void SwFlowFrame::SetFollow(SwFlowFrame
*const pFollow
)
96 assert(this == m_pFollow
->m_pPrecede
);
97 m_pFollow
->m_pPrecede
= nullptr;
100 if (m_pFollow
!= nullptr)
102 if (m_pFollow
->m_pPrecede
) // re-chaining pFollow?
104 assert(m_pFollow
== m_pFollow
->m_pPrecede
->m_pFollow
);
105 m_pFollow
->m_pPrecede
->m_pFollow
= nullptr;
107 m_pFollow
->m_pPrecede
= this;
111 /// @return true if any follow has the JoinLocked flag
112 bool SwFlowFrame::HasLockedFollow() const
114 const SwFlowFrame
* pFrame
= GetFollow();
117 if( pFrame
->IsJoinLocked() )
119 pFrame
= pFrame
->GetFollow();
124 bool SwFlowFrame::IsKeepFwdMoveAllowed( bool bIgnoreMyOwnKeepValue
)
126 // If all the predecessors up to the first of the chain have
127 // the 'keep' attribute set, and the first of the chain's
128 // IsFwdMoveAllowed returns false, then we're not allowed to move.
129 SwFrame
*pFrame
= &m_rThis
;
130 if ( !pFrame
->IsInFootnote() ) {
131 if ( bIgnoreMyOwnKeepValue
&& pFrame
->GetIndPrev() )
132 pFrame
= pFrame
->GetIndPrev();
135 if (pFrame
->GetAttrSet()->GetKeep().GetValue()
136 || pFrame
->IsHiddenNow())
137 pFrame
= pFrame
->GetIndPrev();
142 //See IsFwdMoveAllowed()
144 if ( pFrame
&& pFrame
->GetIndPrev() )
149 void SwFlowFrame::CheckKeep()
151 // Kick off the "last" predecessor with a 'keep' attribute, because
152 // it's possible for the whole troop to move back.
153 SwFrame
*pPre
= m_rThis
.GetIndPrev();
155 while (pPre
&& pPre
->IsHiddenNow())
157 pPre
= pPre
->GetIndPrev();
163 if( pPre
->IsSctFrame() )
165 SwFrame
*pLast
= static_cast<SwSectionFrame
*>(pPre
)->FindLastContent();
166 while (pLast
&& pLast
->IsHiddenNow())
168 pLast
= pLast
->GetIndPrev();
170 if( pLast
&& pLast
->FindSctFrame() == pPre
)
177 while ( (bKeep
= pPre
->GetAttrSet()->GetKeep().GetValue()) &&
178 nullptr != (pTmp
= pTmp
->GetIndPrev()) )
180 if (pTmp
->IsHiddenNow())
184 if( pTmp
->IsSctFrame() )
186 SwFrame
*pLast
= static_cast<SwSectionFrame
*>(pTmp
)->FindLastContent();
187 while (pLast
&& pLast
->IsHiddenNow())
189 pLast
= pLast
->GetIndPrev();
191 if( pLast
&& pLast
->FindSctFrame() == pTmp
)
199 pPre
->InvalidatePos();
205 * Determines if the next content frame after rThis will require the full area of the parent body
208 bool IsNextContentFullPage(const SwFrame
& rThis
)
210 const SwFrame
* pNext
= rThis
.FindNextCnt();
216 const SwSortedObjs
* pNextDrawObjs
= pNext
->GetDrawObjs();
217 if (!pNextDrawObjs
|| !pNextDrawObjs
->size())
222 for (const auto& pDrawObj
: *pNextDrawObjs
)
229 SwTwips nDrawObjHeight
= pDrawObj
->GetObjRectWithSpaces().Height();
230 const SwPageFrame
* pPageFrame
= pDrawObj
->GetPageFrame();
236 SwTwips nBodyHeight
= pPageFrame
->GetLower()->getFrameArea().Height();
237 if (nDrawObjHeight
< nBodyHeight
)
242 const SwFormatSurround
& rSurround
= pDrawObj
->GetFrameFormat()->GetSurround();
243 if (rSurround
.GetSurround() != text::WrapTextMode_NONE
)
248 // At this point the height of the draw object will use all the vertical available space,
249 // and also no wrapping will be performed, so all horizontal space will be taken as well.
257 bool SwFlowFrame::IsKeep(SvxFormatKeepItem
const& rKeep
,
258 SvxFormatBreakItem
const& rBreak
,
259 bool const bCheckIfLastRowShouldKeep
) const
261 assert(m_rThis
.IsTextFrame() ? !static_cast<SwTextFrame
const&>(m_rThis
).IsHiddenNowImpl() : !m_rThis
.IsHiddenNow()); // check it before?
262 // 1. The keep attribute is ignored inside footnotes
263 // 2. For compatibility reasons, the keep attribute is
264 // ignored for frames inside table cells
265 // 3. If bBreakCheck is set to true, this function only checks
266 // if there are any break after attributes set at rAttrs
267 // or break before attributes set for the next content (or next table)
268 // 4. Keep is ignored if the next frame will require its own page.
269 bool bKeep
= bCheckIfLastRowShouldKeep
||
270 ( !m_rThis
.IsInFootnote() &&
271 ( !m_rThis
.IsInTab() || m_rThis
.IsTabFrame() ) &&
272 rKeep
.GetValue() && !IsNextContentFullPage(m_rThis
));
274 if (bKeep
&& m_rThis
.IsTextFrame())
276 auto& rTextFrame
= static_cast<SwTextFrame
&>(m_rThis
);
277 if (rTextFrame
.HasNonLastSplitFlyDrawObj())
279 // Allow split for the non-last anchors of a split fly, even if rKeep.GetValue() is
285 OSL_ENSURE( !bCheckIfLastRowShouldKeep
|| m_rThis
.IsTabFrame(),
286 "IsKeep with bCheckIfLastRowShouldKeep should only be used for tabfrms" );
288 // Ignore keep attribute if there are break situations:
291 switch (rBreak
.GetBreak())
293 case SvxBreak::ColumnAfter
:
294 case SvxBreak::ColumnBoth
:
295 case SvxBreak::PageAfter
:
296 case SvxBreak::PageBoth
:
306 if( nullptr != (pNxt
= m_rThis
.FindNextCnt()) &&
307 (!m_pFollow
|| pNxt
!= &m_pFollow
->GetFrame()))
309 // The last row of a table only keeps with the next content
310 // it they are in the same section:
311 if ( bCheckIfLastRowShouldKeep
)
313 const SwSection
* pThisSection
= nullptr;
314 const SwSection
* pNextSection
= nullptr;
315 const SwSectionFrame
* pThisSectionFrame
= m_rThis
.FindSctFrame();
316 const SwSectionFrame
* pNextSectionFrame
= pNxt
->FindSctFrame();
318 if ( pThisSectionFrame
)
319 pThisSection
= pThisSectionFrame
->GetSection();
321 if ( pNextSectionFrame
)
322 pNextSection
= pNextSectionFrame
->GetSection();
324 if ( pThisSection
!= pNextSection
)
330 SvxFormatBreakItem
const* pBreak
;
331 SwFormatPageDesc
const* pPageDesc
;
332 SwTabFrame
* pTab
= pNxt
->IsInTab() ? pNxt
->FindTabFrame() : nullptr;
333 if (pTab
&& (!m_rThis
.IsInTab() || m_rThis
.FindTabFrame() != pTab
))
335 const SwAttrSet
*const pSet
= &pTab
->GetFormat()->GetAttrSet();
336 pBreak
= &pSet
->GetBreak();
337 pPageDesc
= &pSet
->GetPageDesc();
341 pBreak
= &pNxt
->GetBreakItem();
342 pPageDesc
= &pNxt
->GetPageDescItem();
345 if (pPageDesc
->GetPageDesc())
347 else switch (pBreak
->GetBreak())
349 case SvxBreak::ColumnBefore
:
350 case SvxBreak::ColumnBoth
:
351 case SvxBreak::PageBefore
:
352 case SvxBreak::PageBoth
:
364 SwFrame
* SwFlowFrame::FindPrevIgnoreHidden() const
366 SwFrame
* pRet
{m_rThis
.FindPrev()};
367 while (pRet
&& pRet
->IsHiddenNow())
369 pRet
= pRet
->FindPrev();
374 SwFrame
* SwFlowFrame::FindNextIgnoreHidden() const
376 SwFrame
* pRet
{m_rThis
.FindNext()};
377 while (pRet
&& pRet
->IsHiddenNow())
379 pRet
= pRet
->FindNext();
384 sal_uInt8
SwFlowFrame::BwdMoveNecessary( const SwPageFrame
*pPage
, const SwRect
&rRect
)
386 // The return value helps deciding whether we need to flow back (3),
387 // or whether we can use the good old WouldFit (0, 1), or if
388 // it's reasonable to relocate and test-format (2).
390 // Bit 1 in this case means that there are objects anchored to myself,
391 // bit 2 means that I have to evade other objects.
393 // If a SurroundObj that desires to be wrapped around overlaps with the
394 // Rect, it's required to flow (because we can't guess the relationships).
395 // However it's possible for a test formatting to happen.
396 // If the SurroundObj is a Fly and I'm a Lower, or the Fly is a Lower of
397 // mine, then it doesn't matter.
398 // If the SurroundObj is anchored in a character bound Fly, and I'm not
399 // a Lower of that character bound Fly myself, then the Fly doesn't matter.
401 // If the object is anchored with me, i can ignore it, because
402 // it's likely that it will follow me with the flow. A test formatting is
403 // not allowed in that case, however!
405 SwFlowFrame
*pTmp
= this;
407 { // If there are objects hanging either on me or on a follow, we can't
408 // do a test formatting, because paragraph bound objects wouldn't
409 // be properly considered, and character bound objects shouldn't
410 // be test formatted at all.
411 if( pTmp
->GetFrame().GetDrawObjs() )
413 pTmp
= pTmp
->GetFollow();
414 } while ( !nRet
&& pTmp
);
415 const SwSortedObjs
*pObjs
= pPage
? pPage
->GetSortedObjs() : nullptr;
419 const SwSortedObjs
&rObjs
= *pObjs
;
420 SwNodeOffset nIndex
= NODE_OFFSET_MAX
;
421 for ( size_t i
= 0; nRet
< 3 && i
< rObjs
.size(); ++i
)
424 SwAnchoredObject
* pObj
= rObjs
[i
];
425 const SwFrameFormat
* pFormat
= pObj
->GetFrameFormat();
426 const SwRect
aRect( pObj
->GetObjRect() );
427 if ( aRect
.Overlaps( rRect
) &&
428 pFormat
->GetSurround().GetSurround() != css::text::WrapTextMode_THROUGH
)
430 if( m_rThis
.IsLayoutFrame() && //Fly Lower of This?
431 Is_Lower_Of( &m_rThis
, pObj
->GetDrawObj() ) )
433 if( auto pFly
= pObj
->DynCastFlyFrame() )
435 if ( pFly
->IsAnLower( &m_rThis
) )//This Lower of Fly?
439 const SwFrame
* pAnchor
= pObj
->GetAnchorFrame();
440 if ( pAnchor
== &m_rThis
)
446 // Don't do this if the object is anchored behind me in the text
447 // flow, because then I wouldn't evade it.
448 if ( ::IsFrameInSameContext( pAnchor
, &m_rThis
) )
450 if ( pFormat
->GetAnchor().GetAnchorId() == RndStdIds::FLY_AT_PARA
)
452 // The index of the other one can be retrieved using the anchor attribute.
453 SwNodeOffset nTmpIndex
= pFormat
->GetAnchor().GetAnchorNode()->GetIndex();
454 // Now we're going to check whether the current paragraph before
455 // the anchor of the displacing object sits in the text. If this
456 // is the case, we don't try to evade it.
457 // The index is being determined via SwFormatAnchor, because it's
458 // getting quite expensive otherwise.
459 if( NODE_OFFSET_MAX
== nIndex
)
462 if (m_rThis
.IsTextFrame())
463 pNode
= static_cast<SwTextFrame
&>(m_rThis
).GetTextNodeFirst();
464 else if (m_rThis
.IsNoTextFrame())
465 pNode
= static_cast<SwNoTextFrame
&>(m_rThis
).GetNode();
466 else if( m_rThis
.IsSctFrame() )
467 pNode
= static_cast<SwSectionFormat
*>(static_cast<SwSectionFrame
&>(m_rThis
).
468 GetFormat())->GetSectionNode();
471 assert(!m_rThis
.IsContentFrame());
472 OSL_ENSURE( m_rThis
.IsTabFrame(), "new FowFrame?" );
473 pNode
= static_cast<SwTabFrame
&>(m_rThis
).GetTable()->
474 GetTabSortBoxes()[0]->GetSttNd()->FindTableNode();
476 nIndex
= pNode
->GetIndex();
478 if (nIndex
< nTmpIndex
&&
479 (!m_rThis
.IsTextFrame() ||
480 !FrameContainsNode(static_cast<SwTextFrame
&>(m_rThis
), nTmpIndex
)))
496 /// A specialized form of Cut(), which relocates a whole chain (this and the following,
497 /// in particular). During this process, only the minimum operations and notifications are done.
498 SwLayoutFrame
*SwFlowFrame::CutTree( SwFrame
*pStart
)
500 // Cut the Start and all the neighbours; they are chained together and
501 // a handle to the first one is returned. Residuals are invalidated
504 SwLayoutFrame
*pLay
= pStart
->GetUpper();
505 if ( pLay
->IsInFootnote() )
506 pLay
= pLay
->FindFootnoteFrame();
509 // <pPrepare( PrepareHint::QuoVadis )> only for frames in footnotes
510 if( pStart
->IsInFootnote() )
512 SwFrame
* pTmp
= pStart
->GetIndPrev();
514 pTmp
->Prepare( PrepareHint::QuoVadis
);
517 // Just cut quickly and take care that we don't cause problems with the
518 // left-behinds. The pointers of the chain being cut can point who-knows where.
519 if ( pStart
== pStart
->GetUpper()->Lower() )
520 pStart
->GetUpper()->m_pLower
= nullptr;
521 if ( pStart
->GetPrev() )
523 pStart
->GetPrev()->mpNext
= nullptr;
524 pStart
->mpPrev
= nullptr;
527 if ( pLay
->IsFootnoteFrame() )
529 if ( !pLay
->Lower() && !pLay
->IsColLocked() &&
530 !static_cast<SwFootnoteFrame
*>(pLay
)->IsBackMoveLocked() )
532 // tdf#101821 don't delete it while iterating over it
533 if (!pLay
->IsDeleteForbidden())
536 SwFrame::DestroyFrame(pLay
);
538 // else: assume there is code on the stack to clean up empty
540 // (don't go into the else branch below, it produces a disconnected
541 // footnote with null upper that can be returned by
542 // SwFootnoteBossFrame::FindFootnote() causing null pointer deref
543 // in SwTextFrame::ConnectFootnote()
547 bool bUnlock
= !static_cast<SwFootnoteFrame
*>(pLay
)->IsBackMoveLocked();
548 static_cast<SwFootnoteFrame
*>(pLay
)->LockBackMove();
549 pLay
->InvalidateSize();
550 pLay
->Calc(pLay
->getRootFrame()->GetCurrShell()->GetOut());
551 SwContentFrame
*pCnt
= pLay
->ContainsContent();
552 while ( pCnt
&& pLay
->IsAnLower( pCnt
) )
554 // It's possible for the ContentFrame to be locked, and we don't want
555 // to end up in an endless page migration, so we're not even
556 // going to call Calc!
557 OSL_ENSURE( pCnt
->IsTextFrame(), "The Graphic has landed." );
558 if ( static_cast<SwTextFrame
*>(pCnt
)->IsLocked() ||
559 static_cast<SwTextFrame
*>(pCnt
)->GetFollow() == pStart
)
561 pCnt
->Calc(pCnt
->getRootFrame()->GetCurrShell()->GetOut());
562 pCnt
= pCnt
->GetNextContentFrame();
565 static_cast<SwFootnoteFrame
*>(pLay
)->UnlockBackMove();
572 /// A specialized form of Paste(), which relocates a whole chain (this and the following,
573 /// in particular). During this process, only the minimum operations and notifications are done.
574 bool SwFlowFrame::PasteTree( SwFrame
*pStart
, SwLayoutFrame
*pParent
, SwFrame
*pSibling
,
575 SwFrame
*pOldParent
)
577 // returns true if there's a LayoutFrame in the chain.
580 // The chain beginning with pStart is inserted before pSibling
581 // under the parent. We take care to invalidate as required.
583 // I'm receiving a finished chain. We need to update the pointers for
584 // the beginning of the chain, then all the uppers and finally the end.
585 // On the way there, we invalidate as required.
588 pStart
->mpPrev
= pSibling
->GetPrev();
589 if ( nullptr != pStart
->mpPrev
)
590 pStart
->GetPrev()->mpNext
= pStart
;
592 pParent
->m_pLower
= pStart
;
593 pSibling
->InvalidatePos_();
594 pSibling
->InvalidatePrt_();
598 pStart
->mpPrev
= pParent
->Lower();
599 if ( nullptr == pStart
->mpPrev
)
600 pParent
->m_pLower
= pStart
;
603 //If the pParent has more than 1 child nodes, former design will
604 //ignore them directly without any collection work. It will make some
605 //dangling pointers. This lead the crash...
606 //The new design will find the last child of pParent in loop way, and
607 //add the pStart after the last child.
608 // pParent->Lower()->pNext = pStart;
610 SwFrame
* pTemp
= pParent
->m_pLower
;
614 pTemp
= pTemp
->mpNext
;
617 pStart
->mpPrev
= pTemp
;
618 pTemp
->mpNext
= pStart
;
626 if ( pParent
->IsSctFrame() )
628 // We have no sibling because pParent is a section frame and
629 // has just been created to contain some content. The printing
630 // area of the frame behind pParent has to be invalidated, so
631 // that the correct distance between pParent and the next frame
632 // can be calculated.
633 pParent
->InvalidateNextPrtArea();
636 SwFrame
*pFloat
= pStart
;
637 SwFrame
*pLst
= nullptr;
638 SwRectFnSet
aRectFnSet(pParent
);
639 SwTwips nGrowVal
= 0;
641 { pFloat
->mpUpper
= pParent
;
642 pFloat
->InvalidateAll_();
643 pFloat
->CheckDirChange();
645 // I'm a friend of the TextFrame and thus am allowed to do many things.
646 // The CacheIdx idea seems to be a bit risky!
647 if ( pFloat
->IsTextFrame() )
649 if ( static_cast<SwTextFrame
*>(pFloat
)->GetCacheIdx() != USHRT_MAX
)
650 static_cast<SwTextFrame
*>(pFloat
)->Init(); // I'm his friend.
655 nGrowVal
= o3tl::saturating_add(nGrowVal
, aRectFnSet
.GetHeight(pFloat
->getFrameArea()));
656 if ( pFloat
->GetNext() )
657 pFloat
= pFloat
->GetNext();
667 pLst
->mpNext
= pSibling
;
668 pSibling
->mpPrev
= pLst
;
669 if( pSibling
->IsInFootnote() )
671 if( pSibling
->IsSctFrame() )
672 pSibling
= static_cast<SwSectionFrame
*>(pSibling
)->ContainsAny();
674 pSibling
->Prepare( PrepareHint::ErgoSum
);
679 if ( pOldParent
&& pOldParent
->IsBodyFrame() ) // For variable page height while browsing
680 pOldParent
->Shrink( nGrowVal
);
681 pParent
->Grow( nGrowVal
);
684 if ( pParent
->IsFootnoteFrame() )
685 static_cast<SwFootnoteFrame
*>(pParent
)->InvalidateNxtFootnoteCnts( pParent
->FindPageFrame() );
689 void SwFlowFrame::MoveSubTree( SwLayoutFrame
* pParent
, SwFrame
* pSibling
)
691 OSL_ENSURE( pParent
, "No parent given." );
692 OSL_ENSURE( m_rThis
.GetUpper(), "Where are we coming from?" );
694 // Be economical with notifications if an action is running.
695 SwViewShell
*pSh
= m_rThis
.getRootFrame()->GetCurrShell();
696 const SwViewShellImp
*pImp
= pSh
? pSh
->Imp() : nullptr;
697 const bool bComplete
= pImp
&& pImp
->IsAction() && pImp
->GetLayAction().IsComplete();
701 SwFrame
*pPre
= m_rThis
.GetIndPrev();
705 // follow-up of i#26250
706 // invalidate printing area of previous frame, if it's in a table
707 if ( pPre
->GetUpper()->IsInTab() )
709 pPre
->InvalidatePrt_();
711 pPre
->InvalidatePage();
715 m_rThis
.GetUpper()->SetCompletePaint();
716 m_rThis
.GetUpper()->InvalidatePage();
720 SwPageFrame
*pOldPage
= m_rThis
.FindPageFrame();
722 SwLayoutFrame
*pOldParent
;
726 //JoinLock pParent for the lifetime of the Cut/Paste call to avoid
727 //SwSectionFrame::MergeNext removing the pParent we're trying to reparent
729 FlowFrameJoinLockGuard
aJoinGuard(pParent
);
730 SwFrameDeleteGuard
aDeleteGuard(pParent
);
731 pOldParent
= CutTree( &m_rThis
);
732 bInvaLay
= PasteTree( &m_rThis
, pParent
, pSibling
, pOldParent
);
735 // If, by cutting & pasting, an empty SectionFrame came into existence, it should
736 // disappear automatically.
737 SwSectionFrame
*pSct
;
739 SwFlyFrame
* pFly
= nullptr;
740 if ( pOldParent
&& !pOldParent
->Lower() &&
741 ( pOldParent
->IsInSct() &&
742 !(pSct
= pOldParent
->FindSctFrame())->ContainsContent() &&
743 !pSct
->ContainsAny( true ) ) )
745 pSct
->DelEmpty( false );
747 else if (pOldParent
&& !pOldParent
->Lower()
748 && (pOldParent
->IsInFly() && !(pFly
= pOldParent
->FindFlyFrame())->ContainsContent()
749 && !pFly
->ContainsAny()))
751 if (pFly
->IsFlySplitAllowed())
753 // Master fly is empty now that we pasted the content to the follow, mark it for
755 auto pFlyAtContent
= static_cast<SwFlyAtContentFrame
*>(pFly
);
756 pFlyAtContent
->DelEmpty();
760 // If we're in a column section, we'd rather not call Calc "from below"
761 if( !m_rThis
.IsInSct() &&
762 ( !m_rThis
.IsInTab() || ( m_rThis
.IsTabFrame() && !m_rThis
.GetUpper()->IsInTab() ) ) )
763 m_rThis
.GetUpper()->Calc(m_rThis
.getRootFrame()->GetCurrShell()->GetOut());
764 else if( m_rThis
.GetUpper()->IsSctFrame() )
766 SwSectionFrame
* pTmpSct
= static_cast<SwSectionFrame
*>(m_rThis
.GetUpper());
767 bool bOld
= pTmpSct
->IsContentLocked();
768 pTmpSct
->SetContentLock( true );
769 pTmpSct
->Calc(m_rThis
.getRootFrame()->GetCurrShell()->GetOut());
771 pTmpSct
->SetContentLock( false );
773 SwPageFrame
*pPage
= m_rThis
.FindPageFrame();
775 if ( pOldPage
!= pPage
)
777 m_rThis
.InvalidatePage( pPage
);
778 if ( m_rThis
.IsLayoutFrame() )
780 SwContentFrame
*pCnt
= static_cast<SwLayoutFrame
*>(&m_rThis
)->ContainsContent();
782 pCnt
->InvalidatePage( pPage
);
784 else if ( pSh
&& pSh
->GetDoc()->GetLineNumberInfo().IsRestartEachPage()
785 && pPage
->FindFirstBodyContent() == &m_rThis
)
787 m_rThis
.InvalidateLineNum_();
790 if ( bInvaLay
|| (pSibling
&& pSibling
->IsLayoutFrame()) )
791 m_rThis
.GetUpper()->InvalidatePage( pPage
);
794 bool SwFlowFrame::IsAnFollow( const SwFlowFrame
*pAssumed
) const
796 const SwFlowFrame
*pFoll
= this;
798 { if ( pAssumed
== pFoll
)
800 pFoll
= pFoll
->GetFollow();
805 SwTextFrame
* SwContentFrame::FindMaster() const
807 OSL_ENSURE( IsFollow(), "SwContentFrame::FindMaster(): !IsFollow" );
809 const SwContentFrame
* pPrec
= static_cast<const SwContentFrame
*>(SwFlowFrame::GetPrecede());
811 if ( pPrec
&& pPrec
->HasFollow() && pPrec
->GetFollow() == this )
813 OSL_ENSURE( pPrec
->IsTextFrame(), "NoTextFrame with follow found" );
814 return const_cast<SwTextFrame
*>(static_cast< const SwTextFrame
* >(pPrec
));
817 OSL_FAIL( "Follow is lost in Space." );
821 SwSectionFrame
* SwSectionFrame::FindMaster() const
823 OSL_ENSURE( IsFollow(), "SwSectionFrame::FindMaster(): !IsFollow" );
828 SwIterator
<SwSectionFrame
,SwFormat
> aIter( *m_pSection
->GetFormat() );
829 SwSectionFrame
* pSect
= aIter
.First();
832 if (pSect
->GetFollow() == this)
834 pSect
= aIter
.Next();
837 OSL_FAIL( "Follow is lost in Space." );
841 SwTabFrame
* SwTabFrame::FindMaster( bool bFirstMaster
) const
843 OSL_ENSURE( IsFollow(), "SwTabFrame::FindMaster(): !IsFollow" );
845 SwIterator
<SwTabFrame
,SwFormat
> aIter( *GetTable()->GetFrameFormat() );
846 SwTabFrame
* pTab
= aIter
.First();
851 // Optimization. This makes code like this obsolete:
852 // while ( pTab->IsFollow() )
853 // pTab = pTab->FindMaster();
855 if ( !pTab
->IsFollow() )
857 SwTabFrame
* pNxt
= pTab
;
860 if ( pNxt
->GetFollow() == this )
862 pNxt
= pNxt
->GetFollow();
868 if ( pTab
->GetFollow() == this )
875 OSL_FAIL( "Follow is lost in Space." );
880 * Returns the next/previous Layout leaf that's NOT below this (or even is this itself).
881 * Also, that leaf must be in the same text flow as the pAnch origin frame (Body, Footnote)
883 const SwLayoutFrame
*SwFrame::GetLeaf( MakePageType eMakePage
, bool bFwd
,
884 const SwFrame
*pAnch
) const
886 // No flow, no joy...
887 if ( !(IsInDocBody() || IsInFootnote() || IsInFly()) )
890 const SwFrame
*pLeaf
= this;
894 { pLeaf
= const_cast<SwFrame
*>(pLeaf
)->GetLeaf( eMakePage
, bFwd
);
897 (!IsLayoutFrame() || !static_cast<const SwLayoutFrame
*>(this)->IsAnLower( pLeaf
)))
899 if ( pAnch
->IsInDocBody() == pLeaf
->IsInDocBody() &&
900 pAnch
->IsInFootnote() == pLeaf
->IsInFootnote() )
905 } while ( !bFound
&& pLeaf
);
907 return static_cast<const SwLayoutFrame
*>(pLeaf
);
910 SwLayoutFrame
*SwFrame::GetLeaf( MakePageType eMakePage
, bool bFwd
)
912 if ( IsInFootnote() )
913 return bFwd
? GetNextFootnoteLeaf( eMakePage
) : GetPrevFootnoteLeaf( eMakePage
);
916 // A frame could be inside a table AND inside a section.
917 // Thus, it has to be determined, which is the first parent.
918 bool bInTab( IsInTab() );
919 bool bInSct( IsInSct() );
920 if ( bInTab
&& bInSct
)
922 const SwFrame
* pUpperFrame( GetUpper() );
923 while ( pUpperFrame
)
925 if ( pUpperFrame
->IsTabFrame() )
927 // the table is the first.
931 else if ( pUpperFrame
->IsSctFrame() )
933 // the section is the first.
938 pUpperFrame
= pUpperFrame
->GetUpper();
942 if ( bInTab
&& ( !IsTabFrame() || GetUpper()->IsCellFrame() ) ) // TABLE IN TABLE
943 return bFwd
? GetNextCellLeaf() : GetPrevCellLeaf();
946 return bFwd
? GetNextSctLeaf( eMakePage
) : GetPrevSctLeaf();
948 if (IsInFly() && FindFlyFrame()->IsFlySplitAllowed())
952 return GetNextFlyLeaf(eMakePage
);
956 return GetPrevFlyLeaf();
960 return bFwd
? GetNextLeaf( eMakePage
) : GetPrevLeaf();
965 bool HasPageBreakBefore(SwPageFrame
const& rPage
)
967 SwFrame
const* pFlow(rPage
.FindFirstBodyContent());
972 while (pFlow
->GetUpper()->IsInTab())
974 pFlow
= pFlow
->GetUpper()->FindTabFrame();
976 return pFlow
->GetPageDescItem().GetPageDesc()
977 || pFlow
->GetBreakItem().GetBreak() == SvxBreak::PageBefore
978 || pFlow
->GetBreakItem().GetBreak() == SvxBreak::PageBoth
;
983 bool SwFrame::WrongPageDesc( SwPageFrame
* pNew
)
985 // Now it's getting a bit complicated:
987 // Maybe I'm bringing a Pagedesc myself; in that case,
988 // the pagedesc of the next page needs to correspond.
989 // Otherwise, I'll have to dig a bit deeper to see where
990 // the following Pagedesc is coming from.
991 // If the following page itself tells me that it's pagedesc
992 // is wrong, I can happily exchange it.
993 // If the page however thinks that it's pagedesc is correct,
994 // this doesn't mean it's useful to me:
995 // If the first BodyContent asks for a PageDesc or a PageBreak,
996 // I'll have to insert a new page - except the desired page is
998 // If I inserted a new page, the problems only get started:
999 // because then it's likely for the next page to have been
1000 // wrong and having been swapped because of that.
1001 // This in turn means that I have a new (and correct) page,
1002 // but the conditions to swap still apply.
1003 // Way out of the situation: Try to preliminarily insert a
1004 // new page once (empty pages are already inserted by InsertPage()
1007 //My Pagedesc doesn't count if I'm a follow!
1008 const SwPageDesc
*pDesc
= nullptr;
1009 std::optional
<sal_uInt16
> oTmp
;
1010 SwFlowFrame
*pFlow
= SwFlowFrame::CastFlowFrame( this );
1011 if ( !pFlow
|| !pFlow
->IsFollow() )
1013 const SwFormatPageDesc
&rFormatDesc
= GetPageDescItem();
1014 pDesc
= rFormatDesc
.GetPageDesc();
1017 if( !pDesc
->GetRightFormat() )
1019 else if( !pDesc
->GetLeftFormat() )
1021 else if( rFormatDesc
.GetNumOffset() )
1022 oTmp
= rFormatDesc
.GetNumOffset();
1026 // Does the Content bring a Pagedesc or do we need the
1027 // virtual page number of the new layout leaf?
1028 // PageDesc isn't allowed with Follows
1029 const bool isRightPage
= oTmp
? sw::IsRightPageByNumber(*mpRoot
, *oTmp
) : pNew
->OnRightPage();
1031 pDesc
= pNew
->FindPageDesc();
1033 bool bFirst
= pNew
->OnFirstPage();
1035 const SwFlowFrame
*pNewFlow
= pNew
->FindFirstBodyContent();
1036 // Did we find ourselves?
1037 if( pNewFlow
== pFlow
)
1039 if ( pNewFlow
&& pNewFlow
->GetFrame().IsInTab() )
1040 pNewFlow
= pNewFlow
->GetFrame().FindTabFrame();
1041 const SwPageDesc
*pNewDesc
= ( pNewFlow
&& !pNewFlow
->IsFollow() )
1042 ? pNewFlow
->GetFrame().GetPageDescItem().GetPageDesc()
1045 SAL_INFO( "sw.pageframe", "WrongPageDesc p: " << pNew
<< " phys: " << pNew
->GetPhyPageNum() );
1046 SAL_INFO( "sw.pageframe", "WrongPageDesc " << pNew
->GetPageDesc() << " " << pDesc
);
1047 SAL_INFO( "sw.pageframe", "WrongPageDesc right: " << isRightPage
1048 << " first: " << bFirst
<< " " << pNew
->GetFormat() << " == "
1049 << (isRightPage
? pDesc
->GetRightFormat(bFirst
) : pDesc
->GetLeftFormat(bFirst
)) << " "
1050 << (isRightPage
? pDesc
->GetLeftFormat(bFirst
) : pDesc
->GetRightFormat(bFirst
)) );
1052 return (pNew
->GetPageDesc() != pDesc
) // own desc ?
1053 || (pNew
->GetFormat() !=
1054 (isRightPage
? pDesc
->GetRightFormat(bFirst
) : pDesc
->GetLeftFormat(bFirst
)))
1055 || (pNewDesc
&& pNewDesc
== pDesc
);
1058 /// Returns the next layout leaf in which we can move the frame.
1059 SwLayoutFrame
*SwFrame::GetNextLeaf( MakePageType eMakePage
)
1061 OSL_ENSURE( !IsInFootnote(), "GetNextLeaf(), don't call me for Footnote." );
1062 OSL_ENSURE( !IsInSct(), "GetNextLeaf(), don't call me for Sections." );
1064 const bool bBody
= IsInDocBody(); // If I'm coming from the DocBody,
1065 // I want to end up in the body.
1067 // It doesn't make sense to insert pages, as we only want to search the
1070 eMakePage
= MAKEPAGE_NONE
;
1072 // For tables, we just take the big leap. A simple GetNext would
1073 // iterate through the first cells and, in turn, all other cells.
1074 SwLayoutFrame
*pLayLeaf
= nullptr;
1077 SwFrame
*const pTmp
= static_cast<SwTabFrame
*>(this)->FindLastContentOrTable();
1079 pLayLeaf
= pTmp
->GetUpper();
1082 pLayLeaf
= GetNextLayoutLeaf();
1084 SwLayoutFrame
*pOldLayLeaf
= nullptr; // Make sure that we don't have to
1085 // start searching from top when we
1086 // have a freshly created page.
1087 bool bNewPg
= false; // Only insert a new page once.
1093 // There's yet another LayoutFrame. Let's see if it's ready to host
1095 // It only needs to be of the same kind like my starting point
1096 // (DocBody or Footnote respectively)
1097 if ( pLayLeaf
->FindPageFrame()->IsFootnotePage() )
1098 { // If I ended up at the end note pages, we're done.
1102 if ( (bBody
&& !pLayLeaf
->IsInDocBody()) || pLayLeaf
->IsInTab()
1103 || pLayLeaf
->IsInSct() )
1105 // They don't want me! Try again
1106 pOldLayLeaf
= pLayLeaf
;
1107 pLayLeaf
= pLayLeaf
->GetNextLayoutLeaf();
1111 // I'm wanted, therefore I'm done. However, it may still be that,
1112 // during a page break, the page type isn't the desired one. In that
1113 // case we have to insert a page of the correct type.
1115 if( !IsFlowFrame() && ( eMakePage
== MAKEPAGE_NONE
||
1116 eMakePage
==MAKEPAGE_APPEND
|| eMakePage
==MAKEPAGE_NOSECTION
) )
1119 SwPageFrame
*pNew
= pLayLeaf
->FindPageFrame();
1120 const SwViewShell
*pSh
= getRootFrame()->GetCurrShell();
1121 // The pagedesc check does not make sense for frames in fly frames
1122 if ( pNew
!= FindPageFrame() && !bNewPg
&& !IsInFly() &&
1124 // Do not consider page descriptions in browse mode (since
1125 // MoveBwd ignored them)
1126 !(pSh
&& pSh
->GetViewOptions()->getBrowseMode() ) )
1128 if( WrongPageDesc( pNew
) )
1130 SwFootnoteContFrame
*pCont
= pNew
->FindFootnoteCont();
1133 // If the reference of the first footnote of this page
1134 // lies before the page, we'd rather not insert a new page.
1136 SwFootnoteFrame
*pFootnote
= static_cast<SwFootnoteFrame
*>(pCont
->Lower());
1137 if( pFootnote
&& pFootnote
->GetRef() )
1139 const sal_uInt16 nRefNum
= pNew
->GetPhyPageNum();
1140 if( pFootnote
->GetRef()->GetPhyPageNum() < nRefNum
)
1144 //Gotcha! The following page is wrong, therefore we need to
1146 if ( eMakePage
== MAKEPAGE_INSERT
)
1150 SwPageFrame
*pPg
= pOldLayLeaf
?
1151 pOldLayLeaf
->FindPageFrame() : nullptr;
1152 if ( pPg
&& pPg
->IsEmptyPage() )
1153 // Don't insert behind. Insert before the EmptyPage.
1154 pPg
= static_cast<SwPageFrame
*>(pPg
->GetPrev());
1156 if ( !pPg
|| pPg
== pNew
)
1157 pPg
= FindPageFrame();
1159 InsertPage( pPg
, false );
1160 pLayLeaf
= GetNextLayoutLeaf();
1161 pOldLayLeaf
= nullptr;
1172 // There's no other matching LayoutFrame, so we have to insert
1174 if ( eMakePage
== MAKEPAGE_APPEND
|| eMakePage
== MAKEPAGE_INSERT
)
1177 pOldLayLeaf
? pOldLayLeaf
->FindPageFrame() : FindPageFrame(),
1180 // And again from the start.
1181 pLayLeaf
= pOldLayLeaf
? pOldLayLeaf
: GetNextLayoutLeaf();
1190 /// Returns the previous layout leaf where we can move the frame.
1191 SwLayoutFrame
*SwFrame::GetPrevLeaf()
1193 OSL_ENSURE( !IsInFootnote(), "GetPrevLeaf(), don't call me for Footnote." );
1195 const bool bBody
= IsInDocBody(); // If I'm coming from the DocBody,
1196 // I want to end up in the body.
1197 const bool bFly
= IsInFly();
1199 SwLayoutFrame
*pLayLeaf
= GetPrevLayoutLeaf();
1200 SwLayoutFrame
*pPrevLeaf
= nullptr;
1204 if ( pLayLeaf
->IsInTab() || // Never go into tables.
1205 pLayLeaf
->IsInSct() ) // Same goes for sections!
1206 pLayLeaf
= pLayLeaf
->GetPrevLayoutLeaf();
1207 else if ( bBody
&& pLayLeaf
->IsInDocBody() )
1209 if ( pLayLeaf
->Lower() )
1211 pPrevLeaf
= pLayLeaf
;
1212 pLayLeaf
= pLayLeaf
->GetPrevLayoutLeaf();
1214 SwFlowFrame::SetMoveBwdJump( true );
1217 break; //Contents in Flys should accept any layout leaf.
1219 pLayLeaf
= pLayLeaf
->GetPrevLayoutLeaf();
1221 return pLayLeaf
? pLayLeaf
: pPrevLeaf
;
1224 bool SwFlowFrame::IsPrevObjMove() const
1226 // true: The FlowFrame must respect the a border of the predecessor, also needs
1227 // to insert a break if required.
1229 //!!!!!!!!!!!Hack!!!!!!!!!!!
1230 const SwViewShell
*pSh
= m_rThis
.getRootFrame()->GetCurrShell();
1231 if( pSh
&& pSh
->GetViewOptions()->getBrowseMode() )
1234 SwFrame
*const pPre
{FindPrevIgnoreHidden()};
1236 if ( pPre
&& pPre
->GetDrawObjs() )
1238 OSL_ENSURE( SwFlowFrame::CastFlowFrame( pPre
), "new flowfrm?" );
1239 if( SwFlowFrame::CastFlowFrame( pPre
)->IsAnFollow( this ) )
1241 if (SwFlowFrame::CastFlowFrame(pPre
)->IsJoinLocked())
1243 SwBorderAttrAccess
baa(SwFrame::GetCache(), pPre
);
1244 SwBorderAttrs
const& rAttrs(*baa
.Get());
1245 if (SwFlowFrame::CastFlowFrame(pPre
)->IsKeep(rAttrs
.GetAttrSet().GetKeep(), pPre
->GetBreakItem()))
1246 { // pPre is currently being formatted - maybe it moved back but
1247 // its objects still have the old page's body as
1248 // mpVertPosOrientFrame and SwContentFrame::MakeAll() is calling
1249 // pNxt->Calc() in this case so allow this frame to move back
1250 return false; // too, else pPre is forced to move forward again.
1253 SwLayoutFrame
* pPreUp
= pPre
->GetUpper();
1254 // If the upper is a SectionFrame, or a column of a SectionFrame, we're
1255 // allowed to protrude out of it. However, we need to respect the
1256 // Upper of the SectionFrame.
1257 if( pPreUp
->IsInSct() )
1259 if( pPreUp
->IsSctFrame() )
1260 pPreUp
= pPreUp
->GetUpper();
1261 else if( pPreUp
->IsColBodyFrame() &&
1262 pPreUp
->GetUpper()->GetUpper()->IsSctFrame() )
1263 pPreUp
= pPreUp
->GetUpper()->GetUpper()->GetUpper();
1265 // i#26945 - re-factoring
1266 // use <GetVertPosOrientFrame()> to determine, if object has followed the
1267 // text flow to the next layout frame
1268 for (SwAnchoredObject
* pObj
: *pPre
->GetDrawObjs())
1270 const SwFrameFormat
* pObjFormat
= pObj
->GetFrameFormat();
1271 // Do not consider hidden objects
1272 // i#26945 - do not consider object, which
1273 // doesn't follow the text flow.
1274 if ( pObjFormat
->GetDoc()->getIDocumentDrawModelAccess().IsVisibleLayerId(
1275 pObj
->GetDrawObj()->GetLayer() ) &&
1276 pObjFormat
->GetFollowTextFlow().GetValue() )
1278 const SwLayoutFrame
* pVertPosOrientFrame
= pObj
->GetVertPosOrientFrame();
1279 if ( pVertPosOrientFrame
&&
1280 pPreUp
!= pVertPosOrientFrame
&&
1281 !pPreUp
->IsAnLower( pVertPosOrientFrame
) )
1292 |* If there's a hard page break before the Frame AND there's a
1293 |* predecessor on the same page, true is returned (we need to create a
1294 |* new PageBreak). Otherwise, returns false.
1295 |* If bAct is set to true, this function returns true if
1296 |* there's a PageBreak.
1297 |* Of course, we don't evaluate the hard page break for follows.
1298 |* The page break is in its own FrameFormat (BEFORE) or in the FrameFormat of the
1299 |* predecessor (AFTER). If there's no predecessor on the page, we don't
1300 |* need to think further.
1301 |* Also, a page break (or the need for one) is also present if
1302 |* the FrameFormat contains a PageDesc.
1303 |* The implementation works only on ContentFrames! - the definition
1304 |* of the predecessor is not clear for LayoutFrames.
1306 bool SwFlowFrame::IsPageBreak( bool bAct
) const
1308 if ( !IsFollow() && m_rThis
.IsInDocBody() &&
1309 ( !m_rThis
.IsInTab() || ( m_rThis
.IsTabFrame() && !m_rThis
.GetUpper()->IsInTab() ) ) ) // i66968
1311 const SwViewShell
*pSh
= m_rThis
.getRootFrame()->GetCurrShell();
1312 if( pSh
&& pSh
->GetViewOptions()->getBrowseMode() )
1315 // Determine predecessor
1316 const SwFrame
*pPrev
= m_rThis
.FindPrev();
1317 while (pPrev
&& (!pPrev
->IsInDocBody() || pPrev
->IsHiddenNow()))
1318 pPrev
= pPrev
->FindPrev();
1322 OSL_ENSURE( pPrev
->IsInDocBody(), "IsPageBreak: Not in DocBody?" );
1324 { if ( m_rThis
.FindPageFrame() == pPrev
->FindPageFrame() )
1328 { if ( m_rThis
.FindPageFrame() != pPrev
->FindPageFrame() )
1332 //for compatibility, also break at column break if no columns exist
1333 const IDocumentSettingAccess
& rIDSA
= m_rThis
.GetUpper()->GetFormat()->getIDocumentSettingAccess();
1334 const bool bTreatSingleColumnBreakAsPageBreak
= rIDSA
.get(DocumentSettingId::TREAT_SINGLE_COLUMN_BREAK_AS_PAGE_BREAK
);
1335 const SvxBreak eBreak
= m_rThis
.GetBreakItem().GetBreak();
1336 if ( eBreak
== SvxBreak::PageBefore
||
1337 eBreak
== SvxBreak::PageBoth
||
1338 ( bTreatSingleColumnBreakAsPageBreak
&& eBreak
== SvxBreak::ColumnBefore
&& !m_rThis
.FindColFrame() ))
1342 const SvxBreak ePrB
= pPrev
->GetBreakItem().GetBreak();
1343 if ( ePrB
== SvxBreak::PageAfter
||
1344 ePrB
== SvxBreak::PageBoth
||
1345 m_rThis
.GetPageDescItem().GetPageDesc())
1356 |* If there's a hard column break before the Frame AND there is
1357 |* a predecessor in the same column, we return true (we need to create
1358 |* a ColBreak). Otherwise, we return false.
1359 |* If bAct is set to true, we return true if there's a ColBreak.
1360 |* Of course, we don't evaluate the hard column break for follows.
1362 |* The column break is in its own FrameFormat (BEFORE) or in the FrameFormat of the
1363 |* predecessor (AFTER). If there's no predecessor in the column, we don't
1364 |* need to think further.
1365 |* The implementation works only on ContentFrames! - the definition
1366 |* of the predecessor is not clear for LayoutFrames.
1368 bool SwFlowFrame::IsColBreak( bool bAct
) const
1370 if ( !IsFollow() && (m_rThis
.IsMoveable() || bAct
) )
1372 const SwFrame
*pCol
= m_rThis
.FindColFrame();
1375 // Determine predecessor
1376 const SwFrame
*pPrev
= m_rThis
.FindPrev();
1377 while( pPrev
&& ( ( !pPrev
->IsInDocBody() && !m_rThis
.IsInFly() && !m_rThis
.FindFooterOrHeader() ) ||
1378 pPrev
->IsHiddenNow() ) )
1379 pPrev
= pPrev
->FindPrev();
1384 { if ( pCol
== pPrev
->FindColFrame() )
1388 { if ( pCol
!= pPrev
->FindColFrame() )
1392 const SvxBreak eBreak
= m_rThis
.GetBreakItem().GetBreak();
1393 if ( eBreak
== SvxBreak::ColumnBefore
||
1394 eBreak
== SvxBreak::ColumnBoth
)
1398 const SvxBreak ePrB
= pPrev
->GetBreakItem().GetBreak();
1399 if ( ePrB
== SvxBreak::ColumnAfter
||
1400 ePrB
== SvxBreak::ColumnBoth
)
1409 // Skip hidden paragraphs and empty sections on the same level
1410 static const SwFrame
* skipHiddenSiblingFrames_(const SwFrame
* pFrame
)
1412 while (pFrame
&& pFrame
->IsHiddenNow())
1413 pFrame
= pFrame
->GetPrev();
1417 bool SwFlowFrame::HasParaSpaceAtPages( bool bSct
) const
1419 if( m_rThis
.IsInSct() )
1421 const SwFrame
* pTmp
= m_rThis
.GetUpper();
1424 if( pTmp
->IsCellFrame() || pTmp
->IsFlyFrame() ||
1425 pTmp
->IsFooterFrame() || pTmp
->IsHeaderFrame() ||
1426 ( pTmp
->IsFootnoteFrame() && !static_cast<const SwFootnoteFrame
*>(pTmp
)->GetMaster() ) )
1428 if( pTmp
->IsPageFrame() )
1429 return !pTmp
->GetPrev() || IsPageBreak(true);
1430 if( pTmp
->IsColumnFrame() && pTmp
->GetPrev() )
1431 return IsColBreak( true );
1432 if (pTmp
->IsSctFrame() && (!bSct
|| skipHiddenSiblingFrames_(pTmp
->GetPrev())))
1434 pTmp
= pTmp
->GetUpper();
1436 OSL_FAIL( "HasParaSpaceAtPages: Where's my page?" );
1439 if( !m_rThis
.IsInDocBody() || ( m_rThis
.IsInTab() && !m_rThis
.IsTabFrame()) ||
1440 IsPageBreak( true ) || ( m_rThis
.FindColFrame() && IsColBreak( true ) ) )
1442 const SwFrame
* pTmp
= m_rThis
.FindColFrame();
1445 if( pTmp
->GetPrev() )
1450 pTmp
= pTmp
->FindPageFrame();
1451 return pTmp
&& !pTmp
->GetPrev();
1454 // Skip hidden paragraphs and empty sections
1455 static const SwFrame
* skipHiddenFrames_(const SwFrame
* pFrame
)
1459 pFrame
= skipHiddenSiblingFrames_(pFrame
);
1460 if (!pFrame
|| !pFrame
->IsSctFrame())
1462 // Special case: found previous frame is a section
1463 // Search for the last content in the section
1464 auto pSectFrame
= static_cast<const SwSectionFrame
*>(pFrame
);
1465 pFrame
= pSectFrame
->FindLastContent();
1466 // If the last content is in a table _inside_ the section,
1467 // take the table herself.
1468 // Correction: Check directly, if table is inside table, instead of indirectly
1469 // by checking, if section isn't inside a table
1470 if (pFrame
&& pFrame
->IsInTab())
1472 const SwTabFrame
* pTableFrame
= pFrame
->FindTabFrame();
1473 if (pSectFrame
->IsAnLower(pTableFrame
))
1479 /** helper method to determine previous frame for calculation of the
1484 const SwFrame
* SwFlowFrame::GetPrevFrameForUpperSpaceCalc_( const SwFrame
* _pProposedPrevFrame
) const
1486 const SwFrame
* pPrevFrame
1487 = skipHiddenFrames_(_pProposedPrevFrame
? _pProposedPrevFrame
: m_rThis
.GetPrev());
1488 if (pPrevFrame
|| !m_rThis
.IsInFootnote()
1489 || !(m_rThis
.IsSctFrame() || !m_rThis
.IsInSct() || !m_rThis
.FindSctFrame()->IsInFootnote()))
1492 // Special case: no direct previous frame is found but frame is in footnote
1493 // Search for a previous frame in previous footnote,
1494 // if frame isn't in a section, which is also in the footnote
1495 const SwFootnoteFrame
* pPrevFootnoteFrame
=
1496 static_cast<const SwFootnoteFrame
*>(m_rThis
.FindFootnoteFrame()->GetPrev());
1497 if ( pPrevFootnoteFrame
)
1498 return skipHiddenFrames_(pPrevFootnoteFrame
->GetLastLower());
1503 // This should be renamed to something like lcl_UseULSpacing
1504 /// Compare styles attached to these text frames.
1505 static bool lcl_IdenticalStyles(const SwFrame
* pPrevFrame
, const SwFrame
* pFrame
)
1507 if (!pFrame
|| !pFrame
->IsTextFrame())
1510 // Identical styles only applies if "the paragraphs belong to the same content area".
1511 if (pPrevFrame
&& pPrevFrame
->FindSctFrame() != pFrame
->FindSctFrame())
1514 SwTextFormatColl
*pPrevFormatColl
= nullptr;
1515 if (pPrevFrame
&& pPrevFrame
->IsTextFrame())
1517 const SwTextFrame
*pTextFrame
= static_cast< const SwTextFrame
* >( pPrevFrame
);
1518 pPrevFormatColl
= dynamic_cast<SwTextFormatColl
*>(
1519 pTextFrame
->GetTextNodeForParaProps()->GetFormatColl());
1522 const SwTextFrame
* pTextFrame
= static_cast<const SwTextFrame
*>(pFrame
);
1523 SwTextFormatColl
* const pFormatColl
1524 = dynamic_cast<SwTextFormatColl
*>(pTextFrame
->GetTextNodeForParaProps()->GetFormatColl());
1525 return pPrevFormatColl
== pFormatColl
;
1528 static bool lcl_getContextualSpacing(const SwFrame
* pPrevFrame
)
1531 SwBorderAttrAccess
aAccess(SwFrame::GetCache(), pPrevFrame
);
1532 const SwBorderAttrs
*pAttrs
= aAccess
.Get();
1534 bRet
= pAttrs
->GetULSpace().GetContext();
1540 SwTwips
SwFlowFrame::CalcUpperSpace( const SwBorderAttrs
*pAttrs
,
1542 const bool _bConsiderGrid
) const
1544 if (m_rThis
.IsHiddenNow())
1547 const SwFrame
* pPrevFrame
= GetPrevFrameForUpperSpaceCalc_( pPr
);
1549 std::optional
<SwBorderAttrAccess
> oAccess
;
1553 if( m_rThis
.IsSctFrame() )
1555 SwSectionFrame
* pFoll
= &static_cast<SwSectionFrame
&>(m_rThis
);
1557 pOwn
= pFoll
->ContainsAny();
1558 while( !pOwn
&& nullptr != ( pFoll
= pFoll
->GetFollow() ) );
1564 oAccess
.emplace(SwFrame::GetCache(), pOwn
);
1565 pAttrs
= oAccess
->Get();
1574 const IDocumentSettingAccess
& rIDSA
= m_rThis
.GetUpper()->GetFormat()->getIDocumentSettingAccess();
1577 const bool bUseFormerLineSpacing
= rIDSA
.get(DocumentSettingId::OLD_LINE_SPACING
);
1578 const bool bContextualSpacingThis
= pAttrs
->GetULSpace().GetContext();
1579 const bool bContextualSpacingPrev
= lcl_getContextualSpacing(pPrevFrame
);
1580 bool bIdenticalStyles
= lcl_IdenticalStyles(pPrevFrame
, &m_rThis
);
1582 const bool bContextualSpacing
= bContextualSpacingThis
1583 && bContextualSpacingPrev
1584 && bIdenticalStyles
;
1586 // tdf#125893 always ignore own top margin setting of the actual paragraph
1587 // with contextual spacing, if the previous paragraph is identical
1588 const bool bHalfContextualSpacing
= !bContextualSpacing
1589 && bContextualSpacingThis
1590 && !bContextualSpacingPrev
1591 && bIdenticalStyles
;
1593 // tdf#134463 always ignore own bottom margin setting of the previous paragraph
1594 // with contextual spacing, if the actual paragraph is identical
1595 const bool bHalfContextualSpacingPrev
= !bContextualSpacing
1596 && !bContextualSpacingThis
1597 && bContextualSpacingPrev
1598 && bIdenticalStyles
;
1600 // i#11860 - use new method to determine needed spacing
1601 // values of found previous frame and use these values.
1602 SwTwips nPrevLowerSpace
= 0;
1603 SwTwips nPrevLineSpacing
= 0;
1605 bool bPrevLineSpacingProportional
= false;
1606 GetSpacingValuesOfFrame( (*pPrevFrame
),
1607 nPrevLowerSpace
, nPrevLineSpacing
,
1608 bPrevLineSpacingProportional
,
1610 if( rIDSA
.get(DocumentSettingId::PARA_SPACE_MAX
) )
1612 // FIXME: apply bHalfContextualSpacing for better portability?
1613 nUpper
= bContextualSpacing
? 0 : nPrevLowerSpace
+ pAttrs
->GetULSpace().GetUpper();
1614 SwTwips nAdd
= nPrevLineSpacing
;
1615 // i#11859 - consideration of the line spacing
1616 // for the upper spacing of a text frame
1617 if ( bUseFormerLineSpacing
)
1619 // former consideration
1620 if ( pOwn
->IsTextFrame() )
1622 nAdd
= std::max( nAdd
, SwTwips(static_cast<SwTextFrame
*>(pOwn
)->GetLineSpace()) );
1628 // new consideration:
1629 // Only the proportional line spacing of the previous
1630 // text frame is considered for the upper spacing and
1631 // the line spacing values are add up instead of
1632 // building its maximum.
1633 if ( pOwn
->IsTextFrame() )
1637 // A proportional line spacing of the previous text frame
1638 // is added up to an own leading line spacing.
1639 // Otherwise, the maximum of the leading line spacing
1640 // of the previous text frame and the own leading line
1641 // spacing is built.
1642 if ( bPrevLineSpacingProportional
)
1644 nAdd
+= static_cast<SwTextFrame
*>(pOwn
)->GetLineSpace( true );
1648 nAdd
= std::max( nAdd
, SwTwips(static_cast<SwTextFrame
*>(pOwn
)->GetLineSpace( true )) );
1656 nUpper
= bContextualSpacing
? 0 : std::max(
1657 bHalfContextualSpacingPrev
? 0 : static_cast<tools::Long
>(nPrevLowerSpace
),
1658 bHalfContextualSpacing
? 0 : static_cast<tools::Long
>(pAttrs
->GetULSpace().GetUpper()) );
1660 // i#11859 - consideration of the line spacing
1661 // for the upper spacing of a text frame
1662 if ( bUseFormerLineSpacing
)
1664 // former consideration
1665 if ( pOwn
->IsTextFrame() )
1666 nUpper
= std::max( nUpper
, SwTwips(static_cast<SwTextFrame
*>(pOwn
)->GetLineSpace()) );
1667 if ( nPrevLineSpacing
!= 0 )
1669 nUpper
= std::max( nUpper
, nPrevLineSpacing
);
1674 // new consideration:
1675 // Only the proportional line spacing of the previous
1676 // text frame is considered for the upper spacing and
1677 // the line spacing values are add up and added to
1678 // the paragraph spacing instead of building the
1679 // maximum of the line spacings and the paragraph spacing.
1680 SwTwips nAdd
= nPrevLineSpacing
;
1681 if ( pOwn
->IsTextFrame() )
1685 // A proportional line spacing of the previous text frame
1686 // is added up to an own leading line spacing.
1687 // Otherwise, the maximum of the leading line spacing
1688 // of the previous text frame and the own leading line
1689 // spacing is built.
1690 if ( bPrevLineSpacingProportional
)
1692 nAdd
+= static_cast<SwTextFrame
*>(pOwn
)->GetLineSpace( true );
1696 nAdd
= std::max( nAdd
, SwTwips(static_cast<SwTextFrame
*>(pOwn
)->GetLineSpace( true )) );
1703 else if ( rIDSA
.get(DocumentSettingId::PARA_SPACE_MAX_AT_PAGES
) &&
1704 CastFlowFrame( pOwn
)->HasParaSpaceAtPages( m_rThis
.IsSctFrame() ) )
1706 nUpper
= pAttrs
->GetULSpace().GetUpper();
1708 if (m_rThis
.IsCollapseUpper())
1715 // i#25029 - pass previous frame <pPrevFrame>
1716 // to method <GetTopLine(..)>, if parameter <pPr> is set.
1717 // Note: parameter <pPr> is set, if method is called from <SwTextFrame::WouldFit(..)>
1718 nUpper
+= pAttrs
->GetTopLine( m_rThis
, (pPr
? pPrevFrame
: nullptr) );
1720 // i#11860 - consider value of new parameter <_bConsiderGrid>
1721 // and use new method <GetUpperSpaceAmountConsideredForPageGrid(..)>
1723 //consider grid in square page mode
1724 if ( _bConsiderGrid
&& m_rThis
.GetUpper()->GetFormat()->GetDoc()->IsSquaredPageMode() )
1726 nUpper
+= GetUpperSpaceAmountConsideredForPageGrid_( nUpper
);
1731 /** method to determine the upper space amount, which is considered for
1735 Precondition: Position of frame is valid.
1737 SwTwips
SwFlowFrame::GetUpperSpaceAmountConsideredForPageGrid_(
1738 const SwTwips _nUpperSpaceWithoutGrid
) const
1740 SwTwips nUpperSpaceAmountConsideredForPageGrid
= 0;
1742 if ( m_rThis
.IsInDocBody() && m_rThis
.GetAttrSet()->GetParaGrid().GetValue() )
1744 const SwPageFrame
* pPageFrame
= m_rThis
.FindPageFrame();
1745 SwTextGridItem
const*const pGrid(GetGridItem(pPageFrame
));
1748 const SwFrame
* pBodyFrame
= pPageFrame
->FindBodyCont();
1751 const tools::Long nGridLineHeight
=
1752 pGrid
->GetBaseHeight() + pGrid
->GetRubyHeight();
1754 SwRectFnSet
aRectFnSet(&m_rThis
);
1755 const SwTwips nBodyPrtTop
= aRectFnSet
.GetPrtTop(*pBodyFrame
);
1756 const SwTwips nProposedPrtTop
=
1757 aRectFnSet
.YInc( aRectFnSet
.GetTop(m_rThis
.getFrameArea()),
1758 _nUpperSpaceWithoutGrid
);
1760 const SwTwips nSpaceAbovePrtTop
=
1761 aRectFnSet
.YDiff( nProposedPrtTop
, nBodyPrtTop
);
1762 const SwTwips nSpaceOfCompleteLinesAbove
=
1763 nGridLineHeight
* ( nSpaceAbovePrtTop
/ nGridLineHeight
);
1764 SwTwips nNewPrtTop
=
1765 aRectFnSet
.YInc( nBodyPrtTop
, nSpaceOfCompleteLinesAbove
);
1766 if ( aRectFnSet
.YDiff( nProposedPrtTop
, nNewPrtTop
) > 0 )
1768 nNewPrtTop
= aRectFnSet
.YInc( nNewPrtTop
, nGridLineHeight
);
1771 const SwTwips nNewUpperSpace
=
1772 aRectFnSet
.YDiff( nNewPrtTop
,
1773 aRectFnSet
.GetTop(m_rThis
.getFrameArea()) );
1775 nUpperSpaceAmountConsideredForPageGrid
=
1776 nNewUpperSpace
- _nUpperSpaceWithoutGrid
;
1778 OSL_ENSURE( nUpperSpaceAmountConsideredForPageGrid
>= 0,
1779 "<SwFlowFrame::GetUpperSpaceAmountConsideredForPageGrid(..)> - negative space considered for page grid!" );
1783 return nUpperSpaceAmountConsideredForPageGrid
;
1786 /** method to determine the upper space amount, which is considered for
1791 SwTwips
SwFlowFrame::GetUpperSpaceAmountConsideredForPrevFrame() const
1793 SwTwips nUpperSpaceAmountOfPrevFrame
= 0;
1795 const SwFrame
* pPrevFrame
= GetPrevFrameForUpperSpaceCalc_();
1798 SwTwips nPrevLowerSpace
= 0;
1799 SwTwips nPrevLineSpacing
= 0;
1801 bool bDummy
= false;
1802 GetSpacingValuesOfFrame( (*pPrevFrame
), nPrevLowerSpace
, nPrevLineSpacing
, bDummy
, lcl_IdenticalStyles(pPrevFrame
, &m_rThis
));
1803 if ( nPrevLowerSpace
> 0 || nPrevLineSpacing
> 0 )
1805 const IDocumentSettingAccess
& rIDSA
= m_rThis
.GetUpper()->GetFormat()->getIDocumentSettingAccess();
1806 if ( rIDSA
.get(DocumentSettingId::PARA_SPACE_MAX
) ||
1807 !rIDSA
.get(DocumentSettingId::OLD_LINE_SPACING
) )
1809 nUpperSpaceAmountOfPrevFrame
= nPrevLowerSpace
+ nPrevLineSpacing
;
1813 nUpperSpaceAmountOfPrevFrame
= std::max( nPrevLowerSpace
, nPrevLineSpacing
);
1818 return nUpperSpaceAmountOfPrevFrame
;
1821 /** method to determine the upper space amount, which is considered for
1822 the previous frame and the page grid, if option 'Use former object
1827 SwTwips
SwFlowFrame::GetUpperSpaceAmountConsideredForPrevFrameAndPageGrid() const
1829 SwTwips nUpperSpaceAmountConsideredForPrevFrameAndPageGrid
= 0;
1831 if (!m_rThis
.GetUpper() || !m_rThis
.GetUpper()->GetFormat())
1833 return nUpperSpaceAmountConsideredForPrevFrameAndPageGrid
;
1836 if ( !m_rThis
.GetUpper()->GetFormat()->getIDocumentSettingAccess().get(DocumentSettingId::USE_FORMER_OBJECT_POS
) )
1838 nUpperSpaceAmountConsideredForPrevFrameAndPageGrid
=
1839 GetUpperSpaceAmountConsideredForPrevFrame() +
1840 ( m_rThis
.GetUpper()->GetFormat()->GetDoc()->IsSquaredPageMode()
1841 ? GetUpperSpaceAmountConsideredForPageGrid_( CalcUpperSpace( nullptr, nullptr, false ) )
1845 return nUpperSpaceAmountConsideredForPrevFrameAndPageGrid
;
1848 // Calculation of lower space
1850 SwTwips
SwFlowFrame::CalcLowerSpace( const SwBorderAttrs
* _pAttrs
) const
1852 if (m_rThis
.IsHiddenNow())
1855 SwTwips nLowerSpace
= 0;
1857 std::optional
<SwBorderAttrAccess
> oAttrAccess
;
1860 oAttrAccess
.emplace(SwFrame::GetCache(), &m_rThis
);
1861 _pAttrs
= oAttrAccess
->Get();
1864 bool bCommonBorder
= true;
1865 if ( m_rThis
.IsInSct() && m_rThis
.GetUpper()->IsColBodyFrame() )
1867 const SwSectionFrame
* pSectFrame
= m_rThis
.FindSctFrame();
1868 bCommonBorder
= pSectFrame
->GetFormat()->GetBalancedColumns().GetValue();
1870 nLowerSpace
= bCommonBorder
?
1871 _pAttrs
->GetBottomLine( m_rThis
) :
1872 _pAttrs
->CalcBottomLine();
1875 // - correct consideration of table frames
1876 // - use new method <CalcAddLowerSpaceAsLastInTableCell(..)>
1877 if ( ( ( m_rThis
.IsTabFrame() && m_rThis
.GetUpper()->IsInTab() ) ||
1878 // No lower spacing, if frame has a follow
1879 ( m_rThis
.IsInTab() && !GetFollow() ) ) &&
1880 !m_rThis
.GetIndNext() )
1882 nLowerSpace
+= CalcAddLowerSpaceAsLastInTableCell( _pAttrs
);
1885 // tdf#128195 Consider para spacing below last paragraph in header
1886 bool bHasSpacingBelowPara
= m_rThis
.GetUpper()->GetFormat()->getIDocumentSettingAccess().get(
1887 DocumentSettingId::HEADER_SPACING_BELOW_LAST_PARA
);
1888 if (bHasSpacingBelowPara
&& !m_rThis
.IsInTab() && !m_rThis
.IsInFly()
1889 && m_rThis
.FindFooterOrHeader() && !GetFollow() && !m_rThis
.GetIndNext())
1891 nLowerSpace
+= _pAttrs
->GetULSpace().GetLower() + _pAttrs
->CalcLineSpacing();
1897 /** calculation of the additional space to be considered, if flow frame
1898 is the last inside a table cell
1902 SwTwips
SwFlowFrame::CalcAddLowerSpaceAsLastInTableCell(
1903 const SwBorderAttrs
* _pAttrs
) const
1905 if (m_rThis
.IsHiddenNow())
1908 SwTwips nAdditionalLowerSpace
= 0;
1910 IDocumentSettingAccess
const& rIDSA(m_rThis
.GetUpper()->GetFormat()->getIDocumentSettingAccess());
1911 if (rIDSA
.get(DocumentSettingId::ADD_PARA_SPACING_TO_TABLE_CELLS
))
1913 const SwFrame
* pFrame
= &m_rThis
;
1914 if ( pFrame
->IsSctFrame() )
1916 const SwSectionFrame
* pSectFrame
= static_cast<const SwSectionFrame
*>(pFrame
);
1917 pFrame
= pSectFrame
->FindLastContent();
1918 if ( pFrame
&& pFrame
->IsInTab() )
1920 const SwTabFrame
* pTableFrame
= pFrame
->FindTabFrame();
1921 if ( pSectFrame
->IsAnLower( pTableFrame
) )
1923 pFrame
= pTableFrame
;
1928 std::optional
<SwBorderAttrAccess
> oAttrAccess
;
1929 if (pFrame
&& (!_pAttrs
|| pFrame
!= &m_rThis
))
1931 oAttrAccess
.emplace(SwFrame::GetCache(), pFrame
);
1932 _pAttrs
= oAttrAccess
->Get();
1937 nAdditionalLowerSpace
+= _pAttrs
->GetULSpace().GetLower();
1939 if (rIDSA
.get(DocumentSettingId::ADD_PARA_LINE_SPACING_TO_TABLE_CELLS
))
1941 nAdditionalLowerSpace
+= _pAttrs
->CalcLineSpacing();
1946 return nAdditionalLowerSpace
;
1949 /// Moves the Frame forward if it seems necessary regarding the current conditions and attributes.
1950 bool SwFlowFrame::CheckMoveFwd( bool& rbMakePage
, bool bKeep
, bool bIgnoreMyOwnKeepValue
)
1952 if (m_rThis
.IsHiddenNow())
1954 const SwFrame
* pNxt
= m_rThis
.GetIndNext();
1956 if ( bKeep
&& //!bMovedBwd &&
1957 ( !pNxt
|| ( pNxt
->IsTextFrame() && static_cast<const SwTextFrame
*>(pNxt
)->IsEmptyMaster() ) ) &&
1958 ( nullptr != (pNxt
= m_rThis
.FindNext()) ) && IsKeepFwdMoveAllowed(bIgnoreMyOwnKeepValue
) )
1960 if( pNxt
->IsSctFrame() )
1961 { // Don't get fooled by empty SectionFrames
1962 const SwFrame
* pTmp
= nullptr;
1963 while( pNxt
&& pNxt
->IsSctFrame() &&
1964 ( !static_cast<const SwSectionFrame
*>(pNxt
)->GetSection() ||
1965 nullptr == ( pTmp
= static_cast<const SwSectionFrame
*>(pNxt
)->ContainsAny() ) ) )
1967 pNxt
= pNxt
->FindNext();
1971 pNxt
= pTmp
; // the content of the next notempty sectionfrm
1973 if( pNxt
&& pNxt
->isFrameAreaPositionValid() )
1976 const SwSectionFrame
*pSct
= m_rThis
.FindSctFrame();
1977 if( pSct
&& !pSct
->isFrameAreaSizeValid() )
1979 const SwSectionFrame
* pNxtSct
= pNxt
->FindSctFrame();
1980 if( pNxtSct
&& pSct
->IsAnFollow( pNxtSct
) )
1987 //Keep together with the following frame
1988 MoveFwd( rbMakePage
, false );
1994 bool bMovedFwd
= false;
1996 if ( m_rThis
.GetIndPrev() )
1998 if ( IsPrevObjMove() ) // Should we care about objects of the Prev?
2001 if ( !MoveFwd( rbMakePage
, false ) )
2006 if ( IsPageBreak( false ) )
2008 while ( MoveFwd( rbMakePage
, true ) )
2013 else if ( IsColBreak ( false ) )
2015 const SwPageFrame
*pPage
= m_rThis
.FindPageFrame();
2016 SwFrame
*pCol
= m_rThis
.FindColFrame();
2018 { MoveFwd( rbMakePage
, false );
2019 SwFrame
*pTmp
= m_rThis
.FindColFrame();
2027 } while ( IsColBreak( false ) );
2028 if ( pPage
!= m_rThis
.FindPageFrame() )
2036 bool SwFlowFrame::ForbiddenForFootnoteCntFwd() const
2038 return m_rThis
.IsTabFrame() || m_rThis
.IsInTab();
2041 /// Return value guarantees that a new page was not created,
2042 /// although false does not NECESSARILY indicate that a new page was created.
2043 /// Either false or true(MoveFootnoteCntFwd) can be returned if no changes were made
2044 bool SwFlowFrame::MoveFwd( bool bMakePage
, bool bPageBreak
, bool bMoveAlways
)
2046 //!!!!MoveFootnoteCntFwd might need to be updated as well.
2047 SwFootnoteBossFrame
*pOldBoss
= m_rThis
.FindFootnoteBossFrame();
2048 if (m_rThis
.IsInFootnote())
2050 assert(!ForbiddenForFootnoteCntFwd()); // prevented by IsMoveable()
2051 if (!m_rThis
.IsContentFrame() || !pOldBoss
)
2053 SAL_WARN("sw.core", "Tables in footnotes are not truly supported");
2056 return static_cast<SwContentFrame
&>(m_rThis
).MoveFootnoteCntFwd( bMakePage
, pOldBoss
);
2059 if( !IsFwdMoveAllowed() && !bMoveAlways
)
2062 if( m_rThis
.IsInSct() )
2064 SwFootnoteBossFrame
* pBoss
= m_rThis
.FindFootnoteBossFrame();
2065 bNoFwd
= !pBoss
->IsInSct() || ( !pBoss
->Lower()->GetNext() &&
2066 !pBoss
->GetPrev() );
2069 // Allow the MoveFwd even if we do not have an IndPrev in these cases:
2070 if ( m_rThis
.IsInTab() &&
2071 ( !m_rThis
.IsTabFrame() ||
2072 m_rThis
.GetUpper()->IsInTab() ) &&
2073 nullptr != m_rThis
.GetNextCellLeaf() )
2080 // It's allowed to move PageBreaks if the Frame isn't the first
2085 const SwFrame
*pCol
= m_rThis
.FindColFrame();
2086 if ( !pCol
|| !pCol
->GetPrev() )
2091 // prevent -Werror=maybe-uninitialized under gcc 11.2.0
2092 #if defined __GNUC__ && !defined __clang__ && __GNUC__ == 13
2093 #pragma GCC diagnostic push
2094 #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
2096 std::optional
<SwFrameDeleteGuard
> oDeleteGuard
;
2097 #if defined __GNUC__ && !defined __clang__ && __GNUC__ == 13
2098 #pragma GCC diagnostic pop
2101 oDeleteGuard
.emplace(pOldBoss
);
2103 bool bSamePage
= true;
2104 SwLayoutFrame
*pNewUpper
=
2105 m_rThis
.GetLeaf( bMakePage
? MAKEPAGE_INSERT
: MAKEPAGE_NONE
, true );
2109 PROTOCOL_ENTER( &m_rThis
, PROT::MoveFwd
, DbgAction::NONE
, nullptr );
2110 SwPageFrame
*pOldPage
= pOldBoss
->FindPageFrame();
2111 // We move ourself and all the direct successors before the
2112 // first ContentFrame below the new Upper.
2114 // If our NewUpper lies in a SectionFrame, we need to make sure
2115 // that it won't destroy itself in Calc.
2116 SwSectionFrame
* pSect
= pNewUpper
->FindSctFrame();
2119 // If we only switch column within our SectionFrame, we better don't
2120 // call Calc, as this would format the SectionFrame, which in turn would
2121 // call us again, etc.
2122 if( pSect
!= m_rThis
.FindSctFrame() )
2124 bool bUnlock
= !pSect
->IsColLocked();
2126 pNewUpper
->Calc(m_rThis
.getRootFrame()->GetCurrShell()->GetOut());
2131 // Do not calculate split cell frames.
2132 else if ( !pNewUpper
->IsCellFrame() || pNewUpper
->Lower() )
2133 pNewUpper
->Calc(m_rThis
.getRootFrame()->GetCurrShell()->GetOut());
2135 SwFootnoteBossFrame
*pNewBoss
= pNewUpper
->FindFootnoteBossFrame();
2136 bool bBossChg
= pNewBoss
!= pOldBoss
;
2137 pNewBoss
= pNewBoss
->FindFootnoteBossFrame( true );
2138 pOldBoss
= pOldBoss
->FindFootnoteBossFrame( true );
2139 SwPageFrame
* pNewPage
= pOldPage
;
2141 oDeleteGuard
.reset();
2143 // First, we move the footnotes.
2144 bool bFootnoteMoved
= false;
2147 // If pSect has just been created, the printing area of pSect has
2148 // been calculated based on the first content of its follow.
2149 // In this case we prefer to call a SimpleFormat for this new
2150 // section after we inserted the contents. Otherwise the section
2151 // frame will invalidate its lowers, if its printing area changes
2152 // in SwSectionFrame::Format, which can cause loops.
2153 const bool bForceSimpleFormat
= pSect
&& pSect
->HasFollow() &&
2154 !pSect
->ContainsAny();
2156 if ( pNewBoss
!= pOldBoss
)
2158 pNewPage
= pNewBoss
->FindPageFrame();
2159 bSamePage
= pNewPage
== pOldPage
;
2160 // Set deadline, so the footnotes don't think up
2162 SwRectFnSet
aRectFnSet(pOldBoss
);
2163 SwSaveFootnoteHeight
aHeight( pOldBoss
,
2164 aRectFnSet
.GetBottom(pOldBoss
->getFrameArea()) );
2165 SwContentFrame
* pStart
= m_rThis
.IsContentFrame() ?
2166 static_cast<SwContentFrame
*>(&m_rThis
) : static_cast<SwLayoutFrame
&>(m_rThis
).ContainsContent();
2167 OSL_ENSURE( pStart
|| ( m_rThis
.IsTabFrame() && !static_cast<SwTabFrame
&>(m_rThis
).Lower() ),
2168 "MoveFwd: Missing Content" );
2169 SwLayoutFrame
* pBody
= pStart
? ( pStart
->IsTextFrame() ?
2170 const_cast<SwBodyFrame
*>(static_cast<SwTextFrame
*>(pStart
)->FindBodyFrame()) : nullptr ) : nullptr;
2172 bFootnoteMoved
= pBody
->MoveLowerFootnotes( pStart
, pOldBoss
, pNewBoss
,
2175 // It's possible when dealing with SectionFrames that we have been moved
2176 // by pNewUpper->Calc(), for instance into the pNewUpper.
2177 // MoveSubTree or PasteTree respectively is not prepared to handle such a
2179 if( pNewUpper
!= m_rThis
.GetUpper() )
2182 SwSectionFrame
* pOldSct
= nullptr;
2183 if ( m_rThis
.GetUpper()->IsSctFrame() )
2185 pOldSct
= static_cast<SwSectionFrame
*>(m_rThis
.GetUpper());
2188 MoveSubTree( pNewUpper
, pNewUpper
->Lower() );
2191 if ( pOldSct
&& pOldSct
->GetSection() )
2193 // Prevent loops by setting the new height at
2194 // the section frame if footnotes have been moved.
2195 // Otherwise the call of SwLayNotify::~SwLayNotify() for
2196 // the (invalid) section frame will invalidate the first
2197 // lower of its follow, because it grows due to the removed
2199 // Note: If pOldSct has become empty during MoveSubTree, it
2200 // has already been scheduled for removal. No SimpleFormat
2202 pOldSct
->SimpleFormat();
2206 if ( bForceSimpleFormat
)
2208 pSect
->SimpleFormat();
2211 if ( bFootnoteMoved
&& !bSamePage
)
2213 pOldPage
->UpdateFootnoteNum();
2214 pNewPage
->UpdateFootnoteNum();
2219 m_rThis
.Prepare( PrepareHint::BossChanged
, nullptr, false );
2222 SwViewShell
*pSh
= m_rThis
.getRootFrame()->GetCurrShell();
2223 if ( pSh
&& !pSh
->Imp()->IsUpdateExpFields() )
2224 pSh
->GetDoc()->getIDocumentFieldsAccess().SetNewFieldLst(true); // Will be done by CalcLayout() later on!
2226 pNewPage
->InvalidateSpelling();
2227 pNewPage
->InvalidateSmartTags();
2228 pNewPage
->InvalidateAutoCompleteWords();
2229 pNewPage
->InvalidateWordCount();
2233 // No <CheckPageDesc(..)> in online layout
2234 const SwViewShell
*pSh
= m_rThis
.getRootFrame()->GetCurrShell();
2236 if ( !( pSh
&& pSh
->GetViewOptions()->getBrowseMode() ) )
2239 // check page description not only in situation with sections.
2241 ((!IsFollow() && m_rThis
.GetPageDescItem().GetPageDesc()) ||
2242 pOldPage
->GetPageDesc()->GetFollow() != pNewPage
->GetPageDesc() ) )
2244 SwFrame::CheckPageDescs( pNewPage
, false );
2251 /** Return value tells whether any changes have been made.
2252 * If true, the frame has moved backwards to an earlier column/section/frame/page etc.
2254 * @note This should be called by derived classes.
2255 * @note The actual moving must be implemented in the subclasses via Cut()/Paste().
2257 bool SwFlowFrame::MoveBwd( bool &rbReformat
)
2259 SwFlowFrame::SetMoveBwdJump( false );
2261 SwFootnoteFrame
* pFootnote
= m_rThis
.FindFootnoteFrame();
2262 if ( pFootnote
&& pFootnote
->IsBackMoveLocked() )
2265 // Text frames, which are directly inside
2266 // tables aren't allowed to move backward.
2267 if ( m_rThis
.IsTextFrame() && m_rThis
.IsInTab() )
2269 const SwLayoutFrame
* pUpperFrame
= m_rThis
.GetUpper();
2270 while ( pUpperFrame
)
2272 if ( pUpperFrame
->IsTabFrame() || pUpperFrame
->IsRowFrame() )
2276 // If the text frame is a follow-section-in-table, that can move
2277 // backward as well.
2278 bool bIsFollowSection
= pUpperFrame
->IsSctFrame() && static_cast<const SwSectionFrame
*>(pUpperFrame
)->GetPrecede();
2280 // If the text frame is a follow-in-table, that can move
2281 // backward as well.
2282 bool bIsFollow
= const_cast<SwLayoutFrame
*>(pUpperFrame
)->GetPrevCellLeaf();
2284 if ( ( pUpperFrame
->IsColumnFrame() && pUpperFrame
->IsInSct() ) || bIsFollowSection
|| bIsFollow
)
2288 pUpperFrame
= pUpperFrame
->GetUpper();
2292 SwFootnoteBossFrame
* pOldBoss
= m_rThis
.FindFootnoteBossFrame();
2296 SwPageFrame
* const pOldPage
= pOldBoss
->FindPageFrame();
2297 SwLayoutFrame
*pNewUpper
= nullptr;
2298 bool bCheckPageDescs
= false;
2299 bool bCheckPageDescOfNextPage
= false;
2303 // If the footnote already sits on the same page/column as the reference,
2304 // we can't flow back. The breaks don't need to be checked for footnotes.
2306 // i#37084 FindLastContent does not necessarily
2307 // have to have a result != 0
2308 SwFrame
* pRef
= nullptr;
2309 const bool bEndnote
= pFootnote
->GetAttr()->GetFootnote().IsEndNote();
2310 const IDocumentSettingAccess
& rSettings
2311 = pFootnote
->GetAttrSet()->GetDoc()->getIDocumentSettingAccess();
2312 bool bContEndnotes
= rSettings
.get(DocumentSettingId::CONTINUOUS_ENDNOTES
);
2313 if( bEndnote
&& pFootnote
->IsInSct() && !bContEndnotes
)
2315 SwSectionFrame
* pSect
= pFootnote
->FindSctFrame();
2316 if( pSect
->IsEndnAtEnd() )
2317 // Endnotes at the end of the section.
2318 pRef
= pSect
->FindLastContent( SwFindMode::LastCnt
);
2320 else if (bEndnote
&& bContEndnotes
)
2322 // Endnotes at the end of the document.
2323 SwSectionFrame
* pSect
= pFootnote
->FindSctFrame();
2324 if (!pSect
->GetPrev() && !pSect
->FindMaster())
2326 // The section is at the top of the page, and is not a follow of a master section.
2327 // See if there is a previous body frame.
2328 SwLayoutFrame
* pPrev
= pSect
->GetPrevLayoutLeaf();
2329 if (pPrev
&& pPrev
->IsBodyFrame())
2331 // There is, then see if that's on a different page.
2332 SwPageFrame
* pSectPage
= pSect
->FindPageFrame();
2333 SwPageFrame
* pPage
= pPrev
->FindPageFrame();
2334 if (pPage
!= pSectPage
)
2336 // It is, then create a new section frame at the end of that previous body
2338 auto pNew
= new SwSectionFrame(*pSect
, /*bMaster=*/true);
2339 pNew
->InsertBehind(pPage
->FindBodyCont(), pPage
->FindLastBodyContent());
2341 SwFrame
* pLower
= pNew
->GetLower();
2342 if (pLower
->IsColumnFrame())
2351 pRef
= pFootnote
->FindFootnoteBossFrame();
2355 // Endnotes on a separate page.
2356 pRef
= pFootnote
->GetRef();
2358 OSL_ENSURE( pRef
, "MoveBwd: Endnote for an empty section?" );
2361 pOldBoss
= pOldBoss
->FindFootnoteBossFrame( true );
2362 SwFootnoteBossFrame
*pRefBoss
= pRef
->FindFootnoteBossFrame( !bEndnote
);
2363 if ( pOldBoss
!= pRefBoss
&&
2366 pRefBoss
->IsBefore( pOldBoss
) )
2368 pNewUpper
= m_rThis
.GetLeaf( MAKEPAGE_FTN
, false );
2370 // Do we have to respect a PageBreak?
2371 else if (IsPageBreak(true) && (!m_rThis
.IsInSct() || !m_rThis
.FindSctFrame()->IsHiddenNow()))
2373 // If the previous page doesn't have a Frame in the body,
2374 // flowing back makes sense despite the PageBreak (otherwise,
2375 // we'd get an empty page).
2376 // Of course we need to overlook empty pages!
2377 const SwFrame
*pFlow
= &m_rThis
;
2380 pFlow
= pFlow
->FindPrev();
2382 ( pFlow
->FindPageFrame() == pOldPage
||
2383 !pFlow
->IsInDocBody() ) );
2386 tools::Long nDiff
= pOldPage
->GetPhyPageNum() - pFlow
->GetPhyPageNum();
2389 if ( static_cast<SwPageFrame
*>(pOldPage
->GetPrev())->IsEmptyPage() )
2393 pNewUpper
= m_rThis
.GetLeaf( MAKEPAGE_NONE
, false );
2395 // Now <pNewUpper> is a previous layout frame, which contains
2396 // content. But the new upper layout frame has to be the next one.
2397 // Thus, hack for issue i14206 no longer needed, but fix for issue 114442
2398 // Correct fix for i53139
2399 // Check for wrong page description before using next new upper.
2400 // i#66051 - further correction of fix for i53139
2401 // Check for correct type of new next upper layout frame
2402 // Another correction of fix for i53139
2403 // Assumption, that in all cases <pNewUpper> is a previous
2404 // layout frame, which contains content, is wrong.
2405 // Another correction of fix for i53139
2406 // Beside type check, check also, if proposed new next upper
2407 // frame is inside the same frame types.
2408 // i#73194 - and yet another correction
2409 // of fix for i53139:
2410 // Assure that the new next upper layout frame doesn't
2411 // equal the current one.
2412 // E.g.: content is on page 3, on page 2 is only a 'ghost'
2413 // section and on page 1 is normal content. Method <FindPrev(..)>
2414 // will find the last content of page 1, but <GetLeaf(..)>
2415 // returns new upper on page 2.
2416 if (pNewUpper
&& pNewUpper
->Lower())
2418 SwLayoutFrame
* pNewNextUpper
= pNewUpper
->GetLeaf( MAKEPAGE_NONE
, true );
2419 if ( pNewNextUpper
&&
2420 pNewNextUpper
!= m_rThis
.GetUpper() &&
2421 pNewNextUpper
->GetType() == pNewUpper
->GetType() &&
2422 pNewNextUpper
->IsInDocBody() == pNewUpper
->IsInDocBody() &&
2423 pNewNextUpper
->IsInFootnote() == pNewUpper
->IsInFootnote() &&
2424 pNewNextUpper
->IsInTab() == pNewUpper
->IsInTab() &&
2425 pNewNextUpper
->IsInSct() == pNewUpper
->IsInSct() &&
2426 !m_rThis
.WrongPageDesc( pNewNextUpper
->FindPageFrame() ) )
2428 pNewUpper
= pNewNextUpper
;
2429 bCheckPageDescOfNextPage
= true;
2433 bCheckPageDescs
= true;
2438 else if (IsColBreak(true))
2440 // If the previous column doesn't contain a ContentFrame, flowing back
2441 // makes sense despite the ColumnBreak, as otherwise we'd get
2443 if( m_rThis
.IsInSct() )
2445 pNewUpper
= m_rThis
.GetLeaf( MAKEPAGE_NONE
, false );
2446 if( pNewUpper
&& !SwFlowFrame::IsMoveBwdJump() &&
2447 ( pNewUpper
->ContainsContent() ||
2448 ( ( !pNewUpper
->IsColBodyFrame() ||
2449 !pNewUpper
->GetUpper()->GetPrev() ) &&
2450 !pNewUpper
->FindSctFrame()->GetPrev() ) ) )
2452 pNewUpper
= nullptr;
2455 // i#69409 - check <pNewUpper>
2456 // i#71065 - check <SwFlowFrame::IsMoveBwdJump()>
2457 else if ( pNewUpper
&& !SwFlowFrame::IsMoveBwdJump() )
2459 // Now <pNewUpper> is a previous layout frame, which
2460 // contains content. But the new upper layout frame
2461 // has to be the next one.
2462 // Correct fix for i53139
2463 // Check for wrong page description before using next new upper.
2464 // i#66051 - further correction of fix for i53139
2465 // Check for correct type of new next upper layout frame
2466 // Another correction of fix for i53139
2467 // Beside type check, check also, if proposed new next upper
2468 // frame is inside the same frame types.
2469 SwLayoutFrame
* pNewNextUpper
= pNewUpper
->GetLeaf( MAKEPAGE_NOSECTION
, true );
2470 if ( pNewNextUpper
&&
2471 pNewNextUpper
->GetType() == pNewUpper
->GetType() &&
2472 pNewNextUpper
->IsInDocBody() == pNewUpper
->IsInDocBody() &&
2473 pNewNextUpper
->IsInFootnote() == pNewUpper
->IsInFootnote() &&
2474 pNewNextUpper
->IsInTab() == pNewUpper
->IsInTab() &&
2475 pNewNextUpper
->IsInSct() == pNewUpper
->IsInSct() &&
2476 !m_rThis
.WrongPageDesc( pNewNextUpper
->FindPageFrame() ) )
2478 pNewUpper
= pNewNextUpper
;
2484 const SwFrame
*pCol
= m_rThis
.FindColFrame();
2490 if ( pCol
->GetPrev() )
2491 pCol
= pCol
->GetPrev();
2495 pCol
= m_rThis
.GetLeaf( MAKEPAGE_NONE
, false );
2499 // ColumnFrames now with BodyFrame
2500 SwLayoutFrame
* pColBody
= pCol
->IsColumnFrame() ?
2501 const_cast<SwLayoutFrame
*>(static_cast<const SwLayoutFrame
*>(static_cast<const SwLayoutFrame
*>(pCol
)->Lower())) :
2502 const_cast<SwLayoutFrame
*>(static_cast<const SwLayoutFrame
*>(pCol
));
2503 if ( pColBody
->ContainsContent() )
2505 bGoOn
= false; // We have content here! we accept this
2506 // only if GetLeaf() has set the MoveBwdJump.
2507 if( SwFlowFrame::IsMoveBwdJump() )
2509 pNewUpper
= pColBody
;
2511 // Now <pNewUpper> is a previous layout frame, which
2512 // contains content. But the new upper layout frame
2513 // has to be the next one.
2514 // Correct fix for i53139
2515 // Check for wrong page description before using next new upper.
2516 // i#66051 - further correction of fix for i53139
2517 // Check for correct type of new next upper layout frame
2518 // Another correction of fix for i53139
2519 // Beside type check, check also, if proposed new next upper
2520 // frame is inside the same frame types.
2522 // Check that the proposed new next upper layout
2523 // frame isn't the current one.
2524 SwLayoutFrame
* pNewNextUpper
= pNewUpper
->GetLeaf( MAKEPAGE_NONE
, true );
2525 if ( pNewNextUpper
&&
2526 pNewNextUpper
!= m_rThis
.GetUpper() &&
2527 pNewNextUpper
->GetType() == pNewUpper
->GetType() &&
2528 pNewNextUpper
->IsInDocBody() == pNewUpper
->IsInDocBody() &&
2529 pNewNextUpper
->IsInFootnote() == pNewUpper
->IsInFootnote() &&
2530 pNewNextUpper
->IsInTab() == pNewUpper
->IsInTab() &&
2531 pNewNextUpper
->IsInSct() == pNewUpper
->IsInSct() &&
2532 !m_rThis
.WrongPageDesc( pNewNextUpper
->FindPageFrame() ) )
2534 pNewUpper
= pNewNextUpper
;
2540 if( pNewUpper
) // We already had an empty column, in other
2541 bJump
= true; // words we skipped one.
2542 pNewUpper
= pColBody
; // this empty column could be considered,
2543 // but we continue searching nevertheless.
2548 SwFlowFrame::SetMoveBwdJump( true );
2551 else // No breaks - we can flow back.
2552 pNewUpper
= m_rThis
.GetLeaf( MAKEPAGE_NONE
, false );
2554 // i#27801 - no move backward of 'master' text frame,
2555 // if - due to its object positioning - it isn't allowed to be on the new page frame
2556 // i#44049 - add another condition for not moving backward
2557 // If one of its objects has restarted the layout process, moving backward
2558 // isn't sensible either.
2559 // i#47697 - refine condition made for issue i44049
2560 // - allow move backward as long as the anchored object is only temporarily
2561 // positions considering its wrapping style.
2563 m_rThis
.IsTextFrame() && !IsFollow() )
2565 sal_uInt32
nToPageNum( 0 );
2566 const bool bMoveFwdByObjPos
= SwLayouter::FrameMovedFwdByObjPos(
2567 *(pOldPage
->GetFormat()->GetDoc()),
2568 static_cast<SwTextFrame
&>(m_rThis
),
2570 if ( bMoveFwdByObjPos
&&
2571 pNewUpper
->FindPageFrame()->GetPhyPageNum() < nToPageNum
)
2573 pNewUpper
= nullptr;
2575 // i#44049 - check, if one of its anchored objects
2576 // has restarted the layout process.
2577 else if ( m_rThis
.GetDrawObjs() )
2579 for (SwAnchoredObject
* pAnchoredObj
: *m_rThis
.GetDrawObjs())
2581 // i#47697 - refine condition - see above
2582 if ( pAnchoredObj
->RestartLayoutProcess() &&
2583 !pAnchoredObj
->IsTmpConsiderWrapInfluence() )
2585 pNewUpper
= nullptr;
2592 // With Follows, it's only allowed to flow back if there's no neighbor
2593 // in the new environment (because that would be the Master).
2594 // (6677) If however we skipped empty pages, we still have to move.
2595 if ( pNewUpper
&& IsFollow() && pNewUpper
->Lower() )
2598 // neglect empty sections in proposed new upper frame
2599 bool bProposedNewUpperContainsOnlyEmptySections( true );
2601 const SwFrame
* pLower( pNewUpper
->Lower() );
2604 if ( pLower
->IsSctFrame() &&
2605 !dynamic_cast<const SwSectionFrame
&>(*pLower
).GetSection() )
2607 pLower
= pLower
->GetNext();
2612 bProposedNewUpperContainsOnlyEmptySections
= false;
2617 if ( !bProposedNewUpperContainsOnlyEmptySections
)
2619 if ( SwFlowFrame::IsMoveBwdJump() )
2621 // Don't move after the Master, but into the next empty page.
2622 SwFrame
*pFrame
= pNewUpper
->Lower();
2623 while ( pFrame
->GetNext() )
2624 pFrame
= pFrame
->GetNext();
2625 pNewUpper
= pFrame
->GetLeaf( MAKEPAGE_INSERT
, true );
2626 if( pNewUpper
== m_rThis
.GetUpper() ) // Did we end up in the same place?
2627 pNewUpper
= nullptr; // If so, moving is not needed.
2630 pNewUpper
= nullptr;
2633 if ( pNewUpper
&& !ShouldBwdMoved( pNewUpper
, rbReformat
) )
2635 if( !pNewUpper
->Lower() )
2637 if( pNewUpper
->IsFootnoteContFrame() )
2640 SwFrame::DestroyFrame(pNewUpper
);
2644 SwSectionFrame
* pSectFrame
= pNewUpper
->FindSctFrame();
2646 if ( pSectFrame
&& !pSectFrame
->IsColLocked() &&
2647 !pSectFrame
->ContainsContent() && !pSectFrame
->ContainsAny( true ) )
2649 pSectFrame
->DelEmpty( true );
2650 SwFrame::DestroyFrame(pSectFrame
);
2651 m_rThis
.setFrameAreaPositionValid(true);
2655 pNewUpper
= nullptr;
2658 // i#21478 - don't move backward, if flow frame wants to
2659 // keep with next frame and next frame is locked.
2660 // i#38232 - If next frame is a table, do *not* check,
2662 if ( pNewUpper
&& !IsFollow() && !m_rThis
.IsHiddenNow() &&
2663 m_rThis
.GetAttrSet()->GetKeep().GetValue() && m_rThis
.GetIndNext() )
2665 SwFrame
* pIndNext
= m_rThis
.GetIndNext();
2667 if ( !pIndNext
->IsTabFrame() )
2669 // get first content of section, while empty sections are skipped
2670 while ( pIndNext
&& pIndNext
->IsSctFrame() )
2672 if( static_cast<SwSectionFrame
*>(pIndNext
)->GetSection() )
2674 SwFrame
* pTmp
= static_cast<SwSectionFrame
*>(pIndNext
)->ContainsAny();
2681 pIndNext
= pIndNext
->GetIndNext();
2683 OSL_ENSURE( !pIndNext
|| dynamic_cast<const SwTextFrame
*>( pIndNext
) != nullptr,
2684 "<SwFlowFrame::MovedBwd(..)> - incorrect next found." );
2685 if ( pIndNext
&& pIndNext
->IsFlowFrame() &&
2686 SwFlowFrame::CastFlowFrame(pIndNext
)->IsJoinLocked() )
2688 pNewUpper
= nullptr;
2694 // layout loop control for flowing content again and again moving
2695 // backward under the same layout condition.
2696 if ( pNewUpper
&& !IsFollow() &&
2697 pNewUpper
!= m_rThis
.GetUpper() &&
2698 SwLayouter::MoveBwdSuppressed( *(pOldPage
->GetFormat()->GetDoc()),
2699 *this, *pNewUpper
) )
2701 SwLayoutFrame
* pNextNewUpper
= pNewUpper
->GetLeaf(
2702 ( !m_rThis
.IsSctFrame() && m_rThis
.IsInSct() )
2703 ? MAKEPAGE_NOSECTION
2706 // i#73194 - make code robust
2707 OSL_ENSURE( pNextNewUpper
, "<SwFlowFrame::MoveBwd(..)> - missing next new upper" );
2708 if ( pNextNewUpper
&&
2709 ( pNextNewUpper
== m_rThis
.GetUpper() ||
2710 pNextNewUpper
->GetType() != m_rThis
.GetUpper()->GetType() ) )
2712 // tdf#107398 do not leave empty footnote container around
2713 if (!pNewUpper
->Lower() && pNewUpper
->IsFootnoteContFrame())
2716 SwFrame::DestroyFrame(pNewUpper
);
2718 pNewUpper
= nullptr;
2719 OSL_FAIL( "<SwFlowFrame::MoveBwd(..)> - layout loop control for layout action <Move Backward> applied!" );
2723 OSL_ENSURE( pNewUpper
!= m_rThis
.GetUpper(),
2724 "<SwFlowFrame::MoveBwd(..)> - moving backward to the current upper frame!?" );
2727 PROTOCOL_ENTER( &m_rThis
, PROT::MoveBack
, DbgAction::NONE
, nullptr );
2728 if ( pNewUpper
->IsFootnoteContFrame() )
2730 // I may have gotten a Container
2731 SwFootnoteFrame
*pNew
= SwFootnoteContFrame::PrependChained(&m_rThis
, false);
2732 pNew
->Paste( pNewUpper
);
2735 if( pNewUpper
->IsFootnoteFrame() && m_rThis
.IsInSct() )
2737 SwSectionFrame
* pSct
= m_rThis
.FindSctFrame();
2738 // If we're in a section of a footnote, we may need to create
2739 // a SwSectionFrame in the new upper
2740 if( pSct
->IsInFootnote() )
2742 SwFrame
* pTmp
= pNewUpper
->Lower();
2745 while( pTmp
->GetNext() )
2746 pTmp
= pTmp
->GetNext();
2747 if( !pTmp
->IsSctFrame() ||
2748 static_cast<SwSectionFrame
*>(pTmp
)->GetFollow() != pSct
)
2752 pNewUpper
= static_cast<SwSectionFrame
*>(pTmp
);
2755 pSct
= new SwSectionFrame( *pSct
, true );
2756 pSct
->Paste( pNewUpper
);
2759 pSct
->SimpleFormat();
2763 bool bUnlock
= false;
2764 bool bFollow
= false;
2765 // Lock section. Otherwise, it could get destroyed if the only Content
2766 // moves e.g. from the second into the first column.
2767 SwSectionFrame
* pSect
= pNewUpper
->FindSctFrame();
2770 bUnlock
= !pSect
->IsColLocked();
2772 bFollow
= pSect
->HasFollow();
2776 auto const pOld
= m_rThis
.GetUpper();
2777 ::std::optional
<SwFrameDeleteGuard
> g
;
2778 if (m_rThis
.GetUpper()->IsCellFrame())
2780 // note: IsFollowFlowRow() is never set for new-style tables
2781 SwTabFrame
const*const pTabFrame(m_rThis
.FindTabFrame());
2782 if ( pTabFrame
->IsFollow()
2783 && static_cast<SwTabFrame
const*>(pTabFrame
->GetPrecede())->HasFollowFlowLine()
2784 && pTabFrame
->GetFirstNonHeadlineRow() == m_rThis
.GetUpper()->GetUpper())
2786 // lock follow-flow-row (similar to sections above)
2787 g
.emplace(m_rThis
.GetUpper()->GetUpper());
2788 assert(m_rThis
.GetUpper()->GetUpper()->IsDeleteForbidden());
2791 pNewUpper
->Calc(m_rThis
.getRootFrame()->GetCurrShell()->GetOut());
2792 SAL_WARN_IF(pOld
!= m_rThis
.GetUpper(), "sw.core",
2793 "MoveBwd(): pNewUpper->Calc() moved this frame?");
2798 // optimization: format section, if its size is invalidated and if it's
2799 // the new parent of moved backward frame.
2800 bool bFormatSect( false );
2804 if( pSect
->HasFollow() != bFollow
)
2806 pSect
->InvalidateSize();
2808 if ( pSect
== pNewUpper
)
2813 m_rThis
.Paste( pNewUpper
);
2816 pSect
->Calc(m_rThis
.getRootFrame()->GetCurrShell()->GetOut());
2818 SwPageFrame
*pNewPage
= m_rThis
.FindPageFrame();
2819 if( pNewPage
!= pOldPage
)
2821 m_rThis
.Prepare( PrepareHint::BossChanged
, static_cast<const void*>(pOldPage
), false );
2822 SwViewShell
*pSh
= m_rThis
.getRootFrame()->GetCurrShell();
2823 if ( pSh
&& !pSh
->Imp()->IsUpdateExpFields() )
2824 pSh
->GetDoc()->getIDocumentFieldsAccess().SetNewFieldLst(true); // Will be done by CalcLayout() later on
2826 pNewPage
->InvalidateSpelling();
2827 pNewPage
->InvalidateSmartTags();
2828 pNewPage
->InvalidateAutoCompleteWords();
2829 pNewPage
->InvalidateWordCount();
2831 // No <CheckPageDesc(..)> in online layout
2832 if ( !( pSh
&& pSh
->GetViewOptions()->getBrowseMode() ) )
2834 if ( bCheckPageDescs
&& pNewPage
->GetNext() )
2836 SwPageFrame
* pStartPage
= bCheckPageDescOfNextPage
?
2838 static_cast<SwPageFrame
*>(pNewPage
->GetNext());
2839 SwFrame::CheckPageDescs( pStartPage
, false);
2841 else if (m_rThis
.GetPageDescItem().GetPageDesc())
2843 // First page could get empty for example by disabling
2845 SwFrame::CheckPageDescs( pNewPage
, false);
2850 return pNewUpper
!= nullptr;
2853 SwFlowFrame
*SwFlowFrame::CastFlowFrame( SwFrame
*pFrame
)
2855 if ( pFrame
->IsContentFrame() )
2856 return static_cast<SwContentFrame
*>(pFrame
);
2857 if ( pFrame
->IsTabFrame() )
2858 return static_cast<SwTabFrame
*>(pFrame
);
2859 if ( pFrame
->IsSctFrame() )
2860 return static_cast<SwSectionFrame
*>(pFrame
);
2864 const SwFlowFrame
*SwFlowFrame::CastFlowFrame( const SwFrame
*pFrame
)
2866 if ( pFrame
->IsContentFrame() )
2867 return static_cast<const SwContentFrame
*>(pFrame
);
2868 if ( pFrame
->IsTabFrame() )
2869 return static_cast<const SwTabFrame
*>(pFrame
);
2870 if ( pFrame
->IsSctFrame() )
2871 return static_cast<const SwSectionFrame
*>(pFrame
);
2875 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */