sw/qa/core/layout/flycnt.cxx         |   13 +++++++++-
 sw/source/core/inc/sortedobjs.hxx    |    2 +
 sw/source/core/layout/sortedobjs.cxx |   44 ++++++++++++++++++++++++++++++++++-
 3 files changed, 57 insertions(+), 2 deletions(-)

New commits:
commit 9c9a2e349c11e1d50fe675c6c73443f3f4e8af47
Author:     Mike Kaganski <[email protected]>
AuthorDate: Fri Feb 6 19:23:28 2026 +0500
Commit:     Mike Kaganski <[email protected]>
CommitDate: Sat Feb 7 10:14:49 2026 +0100

    sw floattable: sort split fly frames in SwSortedObjs from start to end
    
    Previously, there was no rule in ObjAnchorOrder to define the order
    of such split fly frames, that share everything that was previously
    compared there. Therefore, new follows were added to front of the
    vector, making it effectively sorted in the reverse direction. That
    meant, that all loops over elements of GetSortedObjs() handled the
    objects in the opposite direction (first follows, then precedes).
    
    This change adds a sorting rule to handle related split fly frames.
    To handle previous follow flys, that have already been removed from
    the chain, but are still in a sorted list, the sorting rules move
    these to the end, to guarantee correct partitioning.
    
    Incidentally, this allowed to fix a pre-existing unit test to test
    page 3, as intended.
    
    Change-Id: I79f3a3f32630d72f098d34a2b1ade1262b1c66b8
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/198842
    Reviewed-by: Mike Kaganski <[email protected]>
    Tested-by: Jenkins

diff --git a/sw/qa/core/layout/flycnt.cxx b/sw/qa/core/layout/flycnt.cxx
index e390f0a7e3c9..0eb297393502 100644
--- a/sw/qa/core/layout/flycnt.cxx
+++ b/sw/qa/core/layout/flycnt.cxx
@@ -229,7 +229,7 @@ CPPUNIT_TEST_FIXTURE(Test, testSplitFly3Pages)
     // No vert offset on the second page:
     CPPUNIT_ASSERT_EQUAL(static_cast<SwTwips>(0), nPage2FlyTop - 
nPage2AnchorTop);
     // 3rd page:
-    auto pPage3 = dynamic_cast<SwPageFrame*>(pPage1->GetNext());
+    auto pPage3 = dynamic_cast<SwPageFrame*>(pPage2->GetNext());
     CPPUNIT_ASSERT(pPage3);
     const SwSortedObjs& rPage3Objs = *pPage3->GetSortedObjs();
     CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rPage3Objs.size());
@@ -241,6 +241,17 @@ CPPUNIT_TEST_FIXTURE(Test, testSplitFly3Pages)
     SwTwips nPage3FlyTop = pPage3Fly->getFrameArea().Top();
     // No vert offset on the 3rd page:
     CPPUNIT_ASSERT_EQUAL(static_cast<SwTwips>(0), nPage3FlyTop - 
nPage3AnchorTop);
+
+    // Check that the split fly frames, that are all registered at the same 
(first fly's) anchor,
+    // are sorted there from precede to follow (previously, the order was the 
opposite):
+    auto pRootAnchor = pPage3Fly->GetAnchorFrame(); // Unlike 
FindAnchorCharFrame, this gives root
+    CPPUNIT_ASSERT(pRootAnchor);
+    CPPUNIT_ASSERT_EQUAL(pPage1Fly->GetAnchorFrame(), pRootAnchor);
+    const auto& rAnchoredObjects = *pRootAnchor->GetDrawObjs();
+    CPPUNIT_ASSERT_EQUAL(size_t(3), rAnchoredObjects.size());
+    CPPUNIT_ASSERT_EQUAL(static_cast<SwAnchoredObject*>(pPage1Fly), 
rAnchoredObjects[0]);
+    CPPUNIT_ASSERT_EQUAL(static_cast<SwAnchoredObject*>(pPage2Fly), 
rAnchoredObjects[1]);
+    CPPUNIT_ASSERT_EQUAL(static_cast<SwAnchoredObject*>(pPage3Fly), 
rAnchoredObjects[2]);
 }
 
 CPPUNIT_TEST_FIXTURE(Test, testSplitFlyRow)
diff --git a/sw/source/core/inc/sortedobjs.hxx 
b/sw/source/core/inc/sortedobjs.hxx
index 4ffcd69b3a24..395d7831a922 100644
--- a/sw/source/core/inc/sortedobjs.hxx
+++ b/sw/source/core/inc/sortedobjs.hxx
@@ -42,6 +42,8 @@ class SwAnchoredObject;
       - order 1: to-paragraph, 2: to-character, 3: as-character
     - anchor node position
     - internal anchor order number
+    - split fly precede / follow relation
+      - order 1: precede, 2: follow
     If one of the sort criteria attributes of an anchored object changes,
     the sorting has to be updated - use method <Update(..)>
 */
diff --git a/sw/source/core/layout/sortedobjs.cxx 
b/sw/source/core/layout/sortedobjs.cxx
index d15c4e79db2b..f74ba71b675b 100644
--- a/sw/source/core/layout/sortedobjs.cxx
+++ b/sw/source/core/layout/sortedobjs.cxx
@@ -21,6 +21,8 @@
 
 #include <algorithm>
 #include <anchoredobject.hxx>
+#include <flyfrm.hxx>
+#include <flyfrms.hxx>
 #include <fmtanchr.hxx>
 #include <fmtsrnd.hxx>
 #include <fmtwrapinfluenceonobjpos.hxx>
@@ -198,7 +200,47 @@ struct ObjAnchorOrder
         // objects anchored at the same content position/page/fly with same
         // wrap influence.
         // Thus, compare anchor order number
-        return pAnchorListed->GetOrder() < pAnchorNew->GetOrder();
+        if (pAnchorListed->GetOrder() != pAnchorNew->GetOrder())
+            return pAnchorListed->GetOrder() < pAnchorNew->GetOrder();
+
+        // return true, when _pListedAnchoredObj is a precede split fly of 
_pNewAnchoredObj
+        {
+            auto pLHFly = _pListedAnchoredObj->DynCastFlyFrame();
+            auto pLHSplitFly = pLHFly && pLHFly->IsFlySplitAllowed()
+                                   ? static_cast<const 
SwFlyAtContentFrame*>(pLHFly)
+                                   : nullptr;
+            auto pRHFly = _pNewAnchoredObj->DynCastFlyFrame();
+            auto pRHSplitFly = pRHFly && pRHFly->IsFlySplitAllowed()
+                                   ? static_cast<const 
SwFlyAtContentFrame*>(pRHFly)
+                                   : nullptr;
+
+            // split fly after others
+            if (!pLHSplitFly && pRHSplitFly)
+                return true;
+            if (pLHSplitFly && !pRHSplitFly)
+                return false;
+
+            if (pLHSplitFly && pRHSplitFly)
+            {
+                // standalone split fly after grouped
+                auto isInGroup
+                    = [](const SwFlyAtContentFrame* p) { return p->HasFollow() 
|| p->IsFollow(); };
+                if (isInGroup(pLHSplitFly) && !isInGroup(pRHSplitFly))
+                    return true;
+                if (!isInGroup(pLHSplitFly) && isInGroup(pRHSplitFly))
+                    return false;
+
+                if (pLHSplitFly->HasFollow() && pRHSplitFly->IsFollow())
+                {
+                    for (auto p = pRHSplitFly->GetPrecede(); p; p = 
p->GetPrecede())
+                    {
+                        if (p == pLHSplitFly)
+                            return true;
+                    }
+                }
+            }
+        }
+        return false;
     }
 };
 

Reply via email to