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; } };
