sw/inc/formatflysplit.hxx | 5 -- sw/source/core/attr/formatflysplit.cxx | 9 +++++ sw/source/core/inc/flyfrm.hxx | 3 + sw/source/core/inc/flyfrms.hxx | 2 + sw/source/core/inc/frame.hxx | 1 sw/source/core/layout/findfrm.cxx | 16 ++++++++- sw/source/core/layout/flowfrm.cxx | 8 ++++ sw/source/core/layout/fly.cxx | 26 +++++++++++++++ sw/source/core/layout/flycnt.cxx | 56 ++++++++++++++++++++++++++++++++- 9 files changed, 119 insertions(+), 7 deletions(-)
New commits: commit a9b113740c02f0f25ca83d6c17d3c404b587f9ab Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Thu Feb 2 08:27:33 2023 +0100 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Mon Feb 27 08:41:50 2023 +0100 sw: call GetNextFlyLeaf() in SwFrame::GetLeaf() - improve SwFrame::GetLeaf() so that in case we are in a fly frame and that is allowed to split, then we call GetNextFlyLeaf() - GetNextFlyLeaf() uses GetNextLayoutLeaf(), if that finds nothing then calls InsertPage() and then tries again. The second GetNextLayoutLeaf() is meant to find the follow frame's parent, but fly frames don't in general have uppers, so teach it about split fly frames - finally improve SwFrame::GetNextFlyLeaf() a bit, so that it does fly insertion similar to AppendObj(): first move the anchor to the next page then append the just created fly there With this, a fly frame with 2 paragraphs crossing the bottom of the body frame is split, although the second fly frame contains both paragraphs, which still needs fixing. Towards an initial layout for multi-page fly frames. (cherry picked from commit 4c6c317e1743166ee772ab03413f0fa59c59f859) Change-Id: Iec038e9fed462b1f8ee0b48fbb3fd76641c96d5c diff --git a/sw/source/core/layout/findfrm.cxx b/sw/source/core/layout/findfrm.cxx index a58c74afa876..07290dee5f2a 100644 --- a/sw/source/core/layout/findfrm.cxx +++ b/sw/source/core/layout/findfrm.cxx @@ -360,6 +360,16 @@ const SwLayoutFrame *SwFrame::ImplGetNextLayoutLeaf( bool bFwd ) const // I cannot go forward, because there is no next frame. // I'll try to go up: p = pFrame->GetUpper(); + + if (!p && pFrame->IsFlyFrame()) + { + const SwFlyFrame* pFlyFrame = pFrame->FindFlyFrame(); + if (pFlyFrame->IsFlySplitAllowed()) + { + p = pFlyFrame->GetAnchorFrame(); + } + } + bGoingUp = nullptr != p; if ( !bGoingUp ) { diff --git a/sw/source/core/layout/flowfrm.cxx b/sw/source/core/layout/flowfrm.cxx index 0e762f371aa4..9939dceafa1b 100644 --- a/sw/source/core/layout/flowfrm.cxx +++ b/sw/source/core/layout/flowfrm.cxx @@ -877,6 +877,14 @@ SwLayoutFrame *SwFrame::GetLeaf( MakePageType eMakePage, bool bFwd ) if ( bInSct ) return bFwd ? GetNextSctLeaf( eMakePage ) : GetPrevSctLeaf(); + if (IsInFly() && FindFlyFrame()->IsFlySplitAllowed()) + { + if (bFwd) + { + return GetNextFlyLeaf(eMakePage); + } + } + return bFwd ? GetNextLeaf( eMakePage ) : GetPrevLeaf(); } diff --git a/sw/source/core/layout/flycnt.cxx b/sw/source/core/layout/flycnt.cxx index 0fc135b48b5f..c2fd6bc28666 100644 --- a/sw/source/core/layout/flycnt.cxx +++ b/sw/source/core/layout/flycnt.cxx @@ -83,7 +83,8 @@ SwFlyAtContentFrame::SwFlyAtContentFrame( SwFlyFrameFormat *pFormat, SwFrame* pS } SwFlyAtContentFrame::SwFlyAtContentFrame(SwFlyAtContentFrame& rPrecede) - : SwFlyAtContentFrame(rPrecede.GetFormat(), rPrecede.getRootFrame(), /*pAnchor=*/nullptr) + : SwFlyAtContentFrame(rPrecede.GetFormat(), const_cast<SwFrame*>(rPrecede.GetAnchorFrame()), + const_cast<SwFrame*>(rPrecede.GetAnchorFrame())) { SetFollow(rPrecede.GetFollow()); rPrecede.SetFollow(this); @@ -1560,21 +1561,23 @@ SwLayoutFrame *SwFrame::GetNextFlyLeaf( MakePageType eMakePage ) if( pLayLeaf ) { SwFlyAtContentFrame* pNew = nullptr; + SwFrame* pFlyAnchor = const_cast<SwFrame*>(pFly->GetAnchorFrame()); + if (pFlyAnchor) { - pNew = new SwFlyAtContentFrame( *pFly ); - pNew->InsertBefore( pLayLeaf, pLayLeaf->Lower() ); - - SwFrame* pTmp = pFly->GetNext(); - if( pTmp && pTmp != pFly->GetFollow() ) + SwFrame* pTmp = pFlyAnchor->GetNext(); + if (pTmp) { SwFlowFrame* pNxt = nullptr; - if( pTmp->IsContentFrame() ) + if (pTmp->IsContentFrame()) { pNxt = static_cast<SwContentFrame*>(pTmp); } if (pNxt) { - pNxt->MoveSubTree(pLayLeaf, pNew->GetNext()); + pNxt->MoveSubTree(pLayLeaf); + + pNew = new SwFlyAtContentFrame( *pFly ); + pNxt->GetFrame().AppendFly( pNew ); } } } commit ef39f0fdfecf91a3e22a21684478e71979602826 Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Wed Feb 1 08:07:39 2023 +0100 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Mon Feb 27 08:41:50 2023 +0100 sw: introduce SwFlyFrame::IsFlySplitAllowed() And use it in SwFrame::IsMoveable(). With this, SwContentFrame::MakeAll() calls into SwFlowFrame::MoveFwd() for a paragraph that's inside a fly frame that doesn't fit is body frame in fly split mode. Towards an initial layout for multi-page fly frames. (cherry picked from commit b052ec2f2fbe0f3044ba824c064a280a5ee9cd7f) Change-Id: I5a1d5ca499c08dd32432cfacf49d01f393e5d324 diff --git a/sw/source/core/inc/flyfrm.hxx b/sw/source/core/inc/flyfrm.hxx index 467407d1654e..1931054b0ce0 100644 --- a/sw/source/core/inc/flyfrm.hxx +++ b/sw/source/core/inc/flyfrm.hxx @@ -199,6 +199,9 @@ public: SwFlyFrame *FindChainNeighbour( SwFrameFormat const &rFormat, SwFrame *pAnch = nullptr ); + /// Is this fly allowed to split across pages? (Disabled by default.) + bool IsFlySplitAllowed() const; + // #i26791# const SwVirtFlyDrawObj* GetVirtDrawObj() const; SwVirtFlyDrawObj *GetVirtDrawObj(); diff --git a/sw/source/core/layout/findfrm.cxx b/sw/source/core/layout/findfrm.cxx index d6a70186231a..a58c74afa876 100644 --- a/sw/source/core/layout/findfrm.cxx +++ b/sw/source/core/layout/findfrm.cxx @@ -40,6 +40,7 @@ #include <osl/diagnose.h> #include <sal/log.hxx> #include <IDocumentSettingAccess.hxx> +#include <formatflysplit.hxx> /// Searches the first ContentFrame in BodyText below the page. @@ -1447,9 +1448,10 @@ bool SwFrame::IsMoveable( const SwLayoutFrame* _pLayoutFrame ) const { if ( _pLayoutFrame->IsInFly() ) { - // if fly frame has a follow (next linked fly frame), + // if fly frame has a follow (next linked fly frame) or can split, // frame is moveable. - if ( const_cast<SwLayoutFrame*>(_pLayoutFrame)->FindFlyFrame()->GetNextLink() ) + SwFlyFrame* pFlyFrame = const_cast<SwLayoutFrame*>(_pLayoutFrame)->FindFlyFrame(); + if ( pFlyFrame->GetNextLink() || pFlyFrame->IsFlySplitAllowed() ) { bRetVal = true; } diff --git a/sw/source/core/layout/fly.cxx b/sw/source/core/layout/fly.cxx index 1ece49fb78b5..91188af711c9 100644 --- a/sw/source/core/layout/fly.cxx +++ b/sw/source/core/layout/fly.cxx @@ -594,6 +594,16 @@ SwFlyFrame *SwFlyFrame::FindChainNeighbour( SwFrameFormat const &rChain, SwFrame return pFly; } +bool SwFlyFrame::IsFlySplitAllowed() const +{ + if (!IsFlyAtContentFrame()) + { + return false; + } + + return GetFormat()->GetFlySplit().GetValue(); +} + SwFrame *SwFlyFrame::FindLastLower() { SwFrame *pRet = ContainsAny(); @@ -1306,7 +1316,7 @@ void SwFlyFrame::Format( vcl::RenderContext* /*pRenderContext*/, const SwBorderA const SwFrame* pAnchor = GetAnchorFrame(); const SwFrame* pAnchorUpper = pAnchor ? pAnchor->GetUpper() : nullptr; - if (pAnchorUpper && GetFormat()->GetFlySplit().GetValue()) + if (pAnchorUpper && IsFlySplitAllowed()) { // If the fly is allowed to be split, then limit its size to the upper of the // anchor. commit 5ef49bcfd6d657c1d6fbf6d22d7ff55ce421f7a6 Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Tue Jan 31 08:29:44 2023 +0100 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Mon Feb 27 08:41:50 2023 +0100 sw: if the fly is to be split, then limit its growth in SwFlyFrame::Format() It seems the first direct cause why flys are not split is because flys can grow forever, so an inner paragraph's SwContentFrame::MakeAll() will never hit the nBottomDist < 0 condition, which is necessary to call into SwFlowFrame::MoveFwd(). With this, at least nBottomDist is negative when a fly with two paragraphs is at the bottom of a page and only one of them fits the body frame. Also add a debug environment variable, so I can debug the "fly split" case till we don't have import/export filters for this. Towards an initial layout for multi-page fly frames. (cherry picked from commit ed9d987e2ad8f6af554a5fc1f858ca48c6970446) Change-Id: I43114b5795dd42e518a1d776ccd2e7ab607ad859 diff --git a/sw/inc/formatflysplit.hxx b/sw/inc/formatflysplit.hxx index a7cbb82847bb..5f7dda675ed2 100644 --- a/sw/inc/formatflysplit.hxx +++ b/sw/inc/formatflysplit.hxx @@ -29,10 +29,7 @@ class SW_DLLPUBLIC SwFormatFlySplit final : public SfxBoolItem { public: - SwFormatFlySplit(bool bSplit = false) - : SfxBoolItem(RES_FLY_SPLIT, bSplit) - { - } + SwFormatFlySplit(bool bSplit = false); SwFormatFlySplit* Clone(SfxItemPool* pPool = nullptr) const override; diff --git a/sw/source/core/attr/formatflysplit.cxx b/sw/source/core/attr/formatflysplit.cxx index 72816b2ead4e..bcbfcc2d5e96 100644 --- a/sw/source/core/attr/formatflysplit.cxx +++ b/sw/source/core/attr/formatflysplit.cxx @@ -21,6 +21,15 @@ #include <libxml/xmlwriter.h> +SwFormatFlySplit::SwFormatFlySplit(bool bSplit) + : SfxBoolItem(RES_FLY_SPLIT, bSplit) +{ + if (getenv("SW_FORCE_FLY_SPLIT")) + { + SetValue(true); + } +} + SwFormatFlySplit* SwFormatFlySplit::Clone(SfxItemPool*) const { return new SwFormatFlySplit(*this); diff --git a/sw/source/core/layout/fly.cxx b/sw/source/core/layout/fly.cxx index 4cee6d9e712d..1ece49fb78b5 100644 --- a/sw/source/core/layout/fly.cxx +++ b/sw/source/core/layout/fly.cxx @@ -75,6 +75,7 @@ #include <bodyfrm.hxx> #include <FrameControlsManager.hxx> #include <ndtxt.hxx> +#include <formatflysplit.hxx> using namespace ::com::sun::star; @@ -1303,6 +1304,21 @@ void SwFlyFrame::Format( vcl::RenderContext* /*pRenderContext*/, const SwBorderA if ( nRemaining < MINFLY ) nRemaining = MINFLY; + const SwFrame* pAnchor = GetAnchorFrame(); + const SwFrame* pAnchorUpper = pAnchor ? pAnchor->GetUpper() : nullptr; + if (pAnchorUpper && GetFormat()->GetFlySplit().GetValue()) + { + // If the fly is allowed to be split, then limit its size to the upper of the + // anchor. + SwTwips nDeadline = aRectFnSet.GetPrtBottom(*pAnchorUpper); + SwTwips nTop = aRectFnSet.GetTop(getFrameArea()); + SwTwips nBottom = aRectFnSet.GetTop(getFrameArea()) + nRemaining; + if (nBottom > nDeadline) + { + nRemaining = nDeadline - nTop; + } + } + { SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this); aRectFnSet.SetHeight( aPrt, nRemaining ); commit ad593e31ab2c73bf8a80450f5c0d3d3edf621bd6 Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Mon Jan 30 08:59:15 2023 +0100 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Mon Feb 27 08:41:50 2023 +0100 sw: add an initial SwFrame::GetNextFlyLeaf() To be called by SwFrame::GetLeaf() in the future. Towards an initial layout for multi-page fly frames. (cherry picked from commit 66d235012c0c02db3b25f91a0fc981c66ed7388e) Change-Id: I62f895c2db89513fe124113c81c9f14bfb8ed697 diff --git a/sw/source/core/inc/flyfrms.hxx b/sw/source/core/inc/flyfrms.hxx index 4f6bc91922f2..01ac3872dcd6 100644 --- a/sw/source/core/inc/flyfrms.hxx +++ b/sw/source/core/inc/flyfrms.hxx @@ -193,6 +193,8 @@ public: format isn't possible, if method <MakeAll()> is already in progress. */ virtual bool IsFormatPossible() const override; + const SwFlyAtContentFrame* GetFollow() const; + SwFlyAtContentFrame* GetFollow(); }; // Flys that are bound to a character in Content diff --git a/sw/source/core/inc/frame.hxx b/sw/source/core/inc/frame.hxx index e5b4c4c9bf5c..8102a7e26e56 100644 --- a/sw/source/core/inc/frame.hxx +++ b/sw/source/core/inc/frame.hxx @@ -544,6 +544,7 @@ public: SwLayoutFrame *GetNextLeaf ( MakePageType eMakePage ); SwLayoutFrame *GetNextFootnoteLeaf( MakePageType eMakePage ); SwLayoutFrame *GetNextSctLeaf( MakePageType eMakePage ); + SwLayoutFrame *GetNextFlyLeaf( MakePageType eMakePage ); SwLayoutFrame *GetNextCellLeaf(); SwLayoutFrame *GetPrevLeaf (); SwLayoutFrame *GetPrevFootnoteLeaf( MakePageType eMakeFootnote ); diff --git a/sw/source/core/layout/flycnt.cxx b/sw/source/core/layout/flycnt.cxx index afe01a91897f..0fc135b48b5f 100644 --- a/sw/source/core/layout/flycnt.cxx +++ b/sw/source/core/layout/flycnt.cxx @@ -1532,4 +1532,55 @@ bool SwFlyAtContentFrame::ShouldBwdMoved(SwLayoutFrame* /*pNewUpper*/, bool& /*r return false; } +const SwFlyAtContentFrame* SwFlyAtContentFrame::GetFollow() const +{ + return static_cast<const SwFlyAtContentFrame*>(SwFlowFrame::GetFollow()); +} + +SwFlyAtContentFrame* SwFlyAtContentFrame::GetFollow() +{ + return static_cast<SwFlyAtContentFrame*>(SwFlowFrame::GetFollow()); +} + +SwLayoutFrame *SwFrame::GetNextFlyLeaf( MakePageType eMakePage ) +{ + auto pFly = dynamic_cast<SwFlyAtContentFrame*>(FindFlyFrame()); + assert(pFly && "GetNextFlyLeaf: missing fly frame"); + + SwLayoutFrame *pLayLeaf = GetNextLayoutLeaf(); + if (!pLayLeaf) + { + if (eMakePage == MAKEPAGE_INSERT) + { + InsertPage(FindPageFrame(), false); + pLayLeaf = GetNextLayoutLeaf(); + } + } + + if( pLayLeaf ) + { + SwFlyAtContentFrame* pNew = nullptr; + { + pNew = new SwFlyAtContentFrame( *pFly ); + pNew->InsertBefore( pLayLeaf, pLayLeaf->Lower() ); + + SwFrame* pTmp = pFly->GetNext(); + if( pTmp && pTmp != pFly->GetFollow() ) + { + SwFlowFrame* pNxt = nullptr; + if( pTmp->IsContentFrame() ) + { + pNxt = static_cast<SwContentFrame*>(pTmp); + } + if (pNxt) + { + pNxt->MoveSubTree(pLayLeaf, pNew->GetNext()); + } + } + } + pLayLeaf = pNew; + } + return pLayLeaf; +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */