sw/source/core/inc/txtfrm.hxx                                      |    4 +
 sw/source/core/layout/anchoredobject.cxx                           |   19 +++++
 sw/source/core/layout/fly.cxx                                      |    6 +
 sw/source/core/layout/flycnt.cxx                                   |   28 
+++-----
 sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx |   18 +++++
 sw/source/core/text/frmform.cxx                                    |   12 +++
 sw/source/core/text/itratr.cxx                                     |   32 
++++++++++
 sw/source/core/text/itrform2.cxx                                   |   29 
+--------
 8 files changed, 108 insertions(+), 40 deletions(-)

New commits:
commit ddfb800e60d98340c99c8013f6df3f2060687dd0
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Tue Feb 7 13:43:12 2023 +0100
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Tue Feb 7 13:39:52 2023 +0000

    sw: fix anchoring in SwFrame::GetNextFlyLeaf()
    
    The core of this change is in SwFrame::GetNextFlyLeaf(), which used to
    assume that there is a next frame after the fly's anchor, but it's
    perfectly valid to not have such a frame. Instead if a fly is split,
    then also split its anchor, so effectively only the last follow of such
    anchor hosts content, all the others are empty and only serve as an
    anchor of a non-last member of a split fly frame chain.
    
    Once this anchoring is changed, adjustments are needed at other places,
    so a sample split fly frame (2 paragraphs, 1st para on first page, 2nd
    para on second page) is still layout out correctly:
    
    - SwAnchoredObject::FindAnchorCharFrame(): return the right follow text
      frame for follow flys. This is needed because flys have to be anchored
      to masters, and then this function can find the frame that's used for
      positioning.
    
    - SwFlyFrame::Format(): get the rectangle of the correct body frame,
      otherwise we would get the bottom of the 1st body frame instead of the
      2nd body frame for the follow fly, leading to a negative height of the
      follow fly frame.
    
    - SwToContentAnchoredObjectPosition::CalcPosition(): position against
      the right follow text frame, similar to
      SwAnchoredObject::FindAnchorCharFrame().
    
    - SwTextFrame::AdjustFollow_(): don't join a master with its follow if
      there is a split fly frame anchored in the master. The assumption is
      that first the fly has to be moved away, then we can do such a join.
    
    - Introduce a SwTextFrame::GetSplitFlyDrawObjs() to avoid copy&paste in
      SwTextFrame::AdjustFollow_() & SwTextFormatter::FormatLine().
    
    With this, a sample split fly frame is split to two pages with correct
    anchors if SW_FORCE_FLY_SPLIT=1 is set. The anchor frame has duplicated
    text on the 1st and 2nd page still, though.
    
    Towards an initial working layout for multi-page fly frames.
    
    Change-Id: Ie99b13c2e318ec63f69c8a47bbc604771509e24a
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/146607
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>
    Tested-by: Jenkins

diff --git a/sw/source/core/inc/txtfrm.hxx b/sw/source/core/inc/txtfrm.hxx
index 3fd73ea2c6ec..cb22ebc439f8 100644
--- a/sw/source/core/inc/txtfrm.hxx
+++ b/sw/source/core/inc/txtfrm.hxx
@@ -50,6 +50,7 @@ enum class ExpandMode;
 class SwTextAttr;
 class SwWrtShell;
 class SwNode;
+class SwFlyAtContentFrame;
 
 #define NON_PRINTING_CHARACTER_COLOR Color(0x26, 0x8b, 0xd2)
 
@@ -783,6 +784,9 @@ public:
     OUString GetCurWord(SwPosition const&) const;
     sal_uInt16 GetScalingOfSelectedText(TextFrameIndex nStt, TextFrameIndex 
nEnd);
 
+    /// Like GetDrawObjs(), but limit to fly frames which are allowed to split.
+    std::vector<SwFlyAtContentFrame*> GetSplitFlyDrawObjs();
+
     virtual void dumpAsXmlAttributes(xmlTextWriterPtr writer) const override;
 };
 
diff --git a/sw/source/core/layout/anchoredobject.cxx 
b/sw/source/core/layout/anchoredobject.cxx
index 130a5d8c7553..4272437f9e25 100644
--- a/sw/source/core/layout/anchoredobject.cxx
+++ b/sw/source/core/layout/anchoredobject.cxx
@@ -31,6 +31,7 @@
 #include <pagefrm.hxx>
 #include <layouter.hxx>
 #include <osl/diagnose.h>
+#include <flyfrms.hxx>
 
 using namespace ::com::sun::star;
 
@@ -716,6 +717,24 @@ SwTextFrame* SwAnchoredObject::FindAnchorCharFrame()
             TextFrameIndex const 
nOffset(pFrame->MapModelToViewPos(*rAnch.GetContentAnchor()));
             pAnchorCharFrame = &pFrame->GetFrameAtOfst(nOffset);
         }
+        else if (SwFlyFrame* pFlyFrame = DynCastFlyFrame())
+        {
+            // See if this fly is split. If so, then the anchor is also split. 
All anchors are
+            // empty, except the last follow.
+            if (pFlyFrame->IsFlySplitAllowed())
+            {
+                auto pFlyAtContentFrame = 
static_cast<SwFlyAtContentFrame*>(pFlyFrame);
+                if (pFlyAtContentFrame->GetPrecede())
+                {
+                    SwTextFrame* 
pFrame(static_cast<SwTextFrame*>(AnchorFrame()));
+                    const SwTextFrame* pFollow = pFrame->GetFollow();
+                    if (pFollow)
+                    {
+                        pAnchorCharFrame = const_cast<SwTextFrame*>(pFollow);
+                    }
+                }
+            }
+        }
     }
 
     return pAnchorCharFrame;
diff --git a/sw/source/core/layout/fly.cxx b/sw/source/core/layout/fly.cxx
index e256a0b9e0ac..91c0f0549680 100644
--- a/sw/source/core/layout/fly.cxx
+++ b/sw/source/core/layout/fly.cxx
@@ -1318,6 +1318,12 @@ void SwFlyFrame::Format( vcl::RenderContext* 
/*pRenderContext*/, const SwBorderA
                 nRemaining = MINFLY;
 
             const SwFrame* pAnchor = GetAnchorFrame();
+            if (SwFrame* pAnchorChar = FindAnchorCharFrame())
+            {
+                // If we find a follow of the anchor that is effectively the 
anchor of this fly,
+                // then use that as the anchor for sizing purposes.
+                pAnchor = pAnchorChar;
+            }
             const SwFrame* pAnchorUpper = pAnchor ? pAnchor->GetUpper() : 
nullptr;
             if (pAnchorUpper && IsFlySplitAllowed())
             {
diff --git a/sw/source/core/layout/flycnt.cxx b/sw/source/core/layout/flycnt.cxx
index 2fcd1723d0fc..474d21bd7f97 100644
--- a/sw/source/core/layout/flycnt.cxx
+++ b/sw/source/core/layout/flycnt.cxx
@@ -1566,24 +1566,18 @@ SwLayoutFrame *SwFrame::GetNextFlyLeaf( MakePageType 
eMakePage )
     {
         SwFlyAtContentFrame* pNew = nullptr;
         SwFrame* pFlyAnchor = const_cast<SwFrame*>(pFly->GetAnchorFrame());
-        if (pFlyAnchor)
+        if (pFlyAnchor && pFlyAnchor->IsTextFrame())
         {
-            SwFrame* pTmp = pFlyAnchor->GetNext();
-            if (pTmp)
-            {
-                SwFlowFrame* pNxt = nullptr;
-                if (pTmp->IsContentFrame())
-                {
-                    pNxt = static_cast<SwContentFrame*>(pTmp);
-                }
-                if (pNxt)
-                {
-                    pNxt->MoveSubTree(pLayLeaf);
-
-                    pNew = new SwFlyAtContentFrame( *pFly );
-                    pNxt->GetFrame().AppendFly( pNew );
-                }
-            }
+            // Split the anchor at char 0: all the content goes to the follow 
of the anchor.
+            auto pFlyAnchorTextFrame = static_cast<SwTextFrame*>(pFlyAnchor);
+            pFlyAnchorTextFrame->SplitFrame(TextFrameIndex(0));
+            auto pNext = static_cast<SwTextFrame*>(pFlyAnchor->GetNext());
+            pNext->MoveSubTree(pLayLeaf);
+
+            // Now create the follow of the fly and anchor it in the just 
created follow of the
+            // anchor.
+            pNew = new SwFlyAtContentFrame(*pFly);
+            pFlyAnchorTextFrame->AppendFly(pNew);
         }
         pLayLeaf = pNew;
     }
diff --git a/sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx 
b/sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx
index 700b737b1689..7a9dd8546a3a 100644
--- a/sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx
+++ b/sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx
@@ -41,6 +41,7 @@
 #include <fmtwrapinfluenceonobjpos.hxx>
 #include <sortedobjs.hxx>
 #include <textboxhelper.hxx>
+#include <flyfrms.hxx>
 
 using namespace ::com::sun::star;
 
@@ -225,6 +226,23 @@ void SwToContentAnchoredObjectPosition::CalcPosition()
                 
rAnchorTextFrame.MapModelToViewPos(*rAnch.GetContentAnchor())));
             mpToCharOrientFrame = pOrientFrame;
         }
+        else if (SwFlyFrame* pFlyFrame = GetAnchoredObj().DynCastFlyFrame())
+        {
+            // See if this fly is split. If so, then the anchor is also split. 
All anchors are
+            // empty, except the last follow.
+            if (pFlyFrame->IsFlySplitAllowed())
+            {
+                auto pFlyAtContentFrame = 
static_cast<SwFlyAtContentFrame*>(pFlyFrame);
+                if (pFlyAtContentFrame->GetPrecede())
+                {
+                    const SwTextFrame* pFollow = rAnchorTextFrame.GetFollow();
+                    if (pFollow)
+                    {
+                        pOrientFrame = pFollow;
+                    }
+                }
+            }
+        }
     }
     aRectFnSet.Refresh(pOrientFrame);
 
diff --git a/sw/source/core/text/frmform.cxx b/sw/source/core/text/frmform.cxx
index 46d2613021cb..f36d27e68ac5 100644
--- a/sw/source/core/text/frmform.cxx
+++ b/sw/source/core/text/frmform.cxx
@@ -49,6 +49,7 @@
 #include <editeng/tstpitem.hxx>
 #include <redline.hxx>
 #include <comphelper/lok.hxx>
+#include <flyfrms.hxx>
 
 // Tolerance in formatting and text output
 #define SLOPPY_TWIPS    5
@@ -579,6 +580,17 @@ void SwTextFrame::AdjustFollow_( SwTextFormatter &rLine,
             }
             if (GetFollow()->IsDeleteForbidden())
                 return;
+
+            for (const auto& pFlyFrame : GetSplitFlyDrawObjs())
+            {
+                // If a fly frame is anchored to us that has a follow, then 
don't join the anchor.
+                // First those fly frames have to be joined.
+                if (pFlyFrame->GetFollow())
+                {
+                    return;
+                }
+            }
+
             JoinFrame();
         }
 
diff --git a/sw/source/core/text/itratr.cxx b/sw/source/core/text/itratr.cxx
index 886baef79a23..105fc5e3af30 100644
--- a/sw/source/core/text/itratr.cxx
+++ b/sw/source/core/text/itratr.cxx
@@ -57,6 +57,10 @@
 #include <editeng/lrspitem.hxx>
 #include <calbck.hxx>
 #include <frameformats.hxx>
+#include <sortedobjs.hxx>
+#include <anchoredobject.hxx>
+#include <flyfrm.hxx>
+#include <flyfrms.hxx>
 
 using namespace ::com::sun::star::i18n;
 using namespace ::com::sun::star;
@@ -1447,6 +1451,34 @@ sal_uInt16 SwTextFrame::GetScalingOfSelectedText(
     return o3tl::narrowing<sal_uInt16>( nWidth ? ((100 * 
aIter.GetFnt()->GetTextSize_( aDrawInf ).Height()) / nWidth ) : 0 );
 }
 
+std::vector<SwFlyAtContentFrame*> SwTextFrame::GetSplitFlyDrawObjs()
+{
+    std::vector<SwFlyAtContentFrame*> aObjs;
+    SwSortedObjs* pSortedObjs = GetDrawObjs();
+    if (!pSortedObjs)
+    {
+        return aObjs;
+    }
+
+    for (const auto& pSortedObj : *pSortedObjs)
+    {
+        SwFlyFrame* pFlyFrame = pSortedObj->DynCastFlyFrame();
+        if (!pFlyFrame)
+        {
+            continue;
+        }
+
+        if (!pFlyFrame->IsFlySplitAllowed())
+        {
+            continue;
+        }
+
+        aObjs.push_back(static_cast<SwFlyAtContentFrame*>(pFlyFrame));
+    }
+
+    return aObjs;
+}
+
 SwTwips SwTextNode::GetWidthOfLeadingTabs() const
 {
     SwTwips nRet = 0;
diff --git a/sw/source/core/text/itrform2.cxx b/sw/source/core/text/itrform2.cxx
index 48ad43bde8ef..e65468d62d4c 100644
--- a/sw/source/core/text/itrform2.cxx
+++ b/sw/source/core/text/itrform2.cxx
@@ -1936,36 +1936,19 @@ TextFrameIndex 
SwTextFormatter::FormatLine(TextFrameIndex const nStartPos)
             if (m_pFrame)
             {
                 // Don't oversize the line in case of split flys, so we don't 
try to move the anchor
-                // of a precede fly forward.
+                // of a precede fly forward, next to its follow.
                 bool bHasNonLastFlySplitAnchored = false;
-                SwSortedObjs* pSortedObjs = m_pFrame->GetDrawObjs();
-                if (pSortedObjs)
+                for (const auto& pFlyFrame : m_pFrame->GetSplitFlyDrawObjs())
                 {
-                    for (const auto& pSortedObj : *pSortedObjs)
+                    if (pFlyFrame->GetFollow())
                     {
-                        SwFlyFrame* pFlyFrame = pSortedObj->DynCastFlyFrame();
-                        if (!pFlyFrame)
-                        {
-                            continue;
-                        }
-
-                        if (!pFlyFrame->IsFlySplitAllowed())
-                        {
-                            continue;
-                        }
-
-                        auto pFlyAtContentFrame = 
static_cast<SwFlyAtContentFrame*>(pFlyFrame);
-                        if (pFlyAtContentFrame->GetFollow())
-                        {
-                            bHasNonLastFlySplitAnchored = true;
-                            break;
-                        }
+                        bHasNonLastFlySplitAnchored = true;
+                        break;
                     }
                 }
-
                 if (bHasNonLastFlySplitAnchored)
                 {
-                    m_pCurr->SetRealHeight( GetFrameRstHeight() );
+                    m_pCurr->SetRealHeight(GetFrameRstHeight());
                 }
             }
 

Reply via email to