sw/qa/core/layout/data/floattable-hori-pos.docx |binary sw/qa/core/layout/flycnt.cxx | 34 ++++++++++++++++++++++++ sw/source/core/text/frmform.cxx | 34 ++++++++++++++---------- 3 files changed, 54 insertions(+), 14 deletions(-)
New commits: commit 12a9009a1c19ee26c65fb44fc90f3432c88ab6a5 Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Thu Mar 23 08:09:01 2023 +0100 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Thu Mar 23 09:48:29 2023 +0000 sw floattable: fix bad position of follow fly if anchor is positioned late The bugdoc has a split fly, the master is centered horizontally. That means the follow should be centered as well, but it was aligned to the left. The problem is that the follow fly was positioned when the anchor was not positioned at all (its top left was 0,0) and then there was no invalidation of the fly position to recalc it later when the anchor got positioned. The existing InvalidatePos() call is not enough because once a fly is formatted, its position gets locked and only unlockPositionOfObjects() at the end of the layout process will unlock it. Fix the problem similar to what lcl_InvalidateLowerObjs() for SwTabFrame does: if we know that the position of the anchor changed, then unlock the position before invalidating it. If this leads to unwanted re-positioning of flys, it would be perhaps possible to do this when the anchor position changes from 0,0 to a valid position, but for now just do this all time the anchor position changes. Change-Id: I811bdfa1eb6705ff3de6ec77111e9500617e8bee Reviewed-on: https://gerrit.libreoffice.org/c/core/+/149367 Reviewed-by: Miklos Vajna <vmik...@collabora.com> Tested-by: Jenkins diff --git a/sw/qa/core/layout/data/floattable-hori-pos.docx b/sw/qa/core/layout/data/floattable-hori-pos.docx new file mode 100644 index 000000000000..7a5e033a4928 Binary files /dev/null and b/sw/qa/core/layout/data/floattable-hori-pos.docx differ diff --git a/sw/qa/core/layout/flycnt.cxx b/sw/qa/core/layout/flycnt.cxx index 528b3bc4cbc8..b9ab0ac116cb 100644 --- a/sw/qa/core/layout/flycnt.cxx +++ b/sw/qa/core/layout/flycnt.cxx @@ -509,6 +509,40 @@ CPPUNIT_TEST_FIXTURE(Test, testSplitFlyCompat14Body) SwFrame* pRow2 = pTab2->GetLower(); CPPUNIT_ASSERT(!pRow2->GetNext()); } + +CPPUNIT_TEST_FIXTURE(Test, testSplitFlyFollowHorizontalPosition) +{ + // Given a document with 2 pages, master fly on page 1, follow fly on page 2: + SwModelTestBase::FlySplitGuard aGuard; + createSwDoc("floattable-hori-pos.docx"); + + // When laying out that document: + calcLayout(); + + // Then make sure that the follow fly doesn't have a different horizontal position: + SwDoc* pDoc = getSwDoc(); + SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout(); + auto pPage1 = dynamic_cast<SwPageFrame*>(pLayout->Lower()); + CPPUNIT_ASSERT(pPage1); + const SwSortedObjs& rPage1Objs = *pPage1->GetSortedObjs(); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rPage1Objs.size()); + auto pPage1Fly = dynamic_cast<SwFlyAtContentFrame*>(rPage1Objs[0]); + CPPUNIT_ASSERT(pPage1Fly); + tools::Long nPage1FlyLeft = pPage1Fly->getFrameArea().Left(); + auto pPage2 = dynamic_cast<SwPageFrame*>(pPage1->GetNext()); + CPPUNIT_ASSERT(pPage2); + const SwSortedObjs& rPage2Objs = *pPage2->GetSortedObjs(); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rPage2Objs.size()); + auto pPage2Fly = dynamic_cast<SwFlyAtContentFrame*>(rPage2Objs[0]); + CPPUNIT_ASSERT(pPage2Fly); + tools::Long nPage2FlyLeft = pPage2Fly->getFrameArea().Left(); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 5528 + // - Actual : 284 + // i.e. the follow fly was pushed towards the left, instead of having the same position as the + // master fly. + CPPUNIT_ASSERT_EQUAL(nPage1FlyLeft, nPage2FlyLeft); +} } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/text/frmform.cxx b/sw/source/core/text/frmform.cxx index 25bd98bec92e..41b18363aed2 100644 --- a/sw/source/core/text/frmform.cxx +++ b/sw/source/core/text/frmform.cxx @@ -340,25 +340,31 @@ bool SwTextFrame::CalcFollow(TextFrameIndex const nTextOfst) void SwTextFrame::MakePos() { + Point aOldPos = getFrameArea().Pos(); SwFrame::MakePos(); - // Find the master frame. - const SwTextFrame* pMaster = this; - while (pMaster->IsFollow()) + // Recalc split flys if our position changed. + if (aOldPos != getFrameArea().Pos()) { - pMaster = pMaster->FindMaster(); - } - // Find which flys are effectively anchored to this frame. - for (const auto& pFly : pMaster->GetSplitFlyDrawObjs()) - { - SwTextFrame* pFlyAnchor = pFly->FindAnchorCharFrame(); - if (pFlyAnchor != this) + // Find the master frame. + const SwTextFrame* pMaster = this; + while (pMaster->IsFollow()) + { + pMaster = pMaster->FindMaster(); + } + // Find which flys are effectively anchored to this frame. + for (const auto& pFly : pMaster->GetSplitFlyDrawObjs()) { - continue; + SwTextFrame* pFlyAnchor = pFly->FindAnchorCharFrame(); + if (pFlyAnchor != this) + { + continue; + } + // Possibly this fly was positioned relative to us, invalidate its position now that our + // position is changed. + pFly->UnlockPosition(); + pFly->InvalidatePos(); } - // Possibly this fly was positioned relative to us, invalidate its position now that our - // position is changed. - pFly->InvalidatePos(); } // Inform LOK clients about change in position of redlines (if any)