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

Reply via email to