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 52e23e2b784b24cb860e86321b1bcb317a2e771e Author: Mike Kaganski <[email protected]> AuthorDate: Fri Feb 6 19:23:28 2026 +0500 Commit: Miklos Vajna <[email protected]> CommitDate: Mon Feb 9 13:04:28 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 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/198934 Tested-by: Jenkins CollaboraOffice <[email protected]> Reviewed-by: Miklos Vajna <[email protected]> diff --git a/sw/qa/core/layout/flycnt.cxx b/sw/qa/core/layout/flycnt.cxx index d065b5cc27b7..e8a8aba074b2 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 6d524f492802..3f526046f64d 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 da3fba27598a..a434fa9f9ed0 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; } };
