sw/qa/core/layout/data/floattable-rowsplit.docx |binary sw/qa/core/layout/flycnt.cxx | 53 ++++++++++++++++++++++++ sw/source/core/text/frmform.cxx | 14 +++++- 3 files changed, 66 insertions(+), 1 deletion(-)
New commits: commit f13eb476ea6620bc444d9533959fea78afe720c5 Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Tue Feb 28 08:11:01 2023 +0100 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Tue Feb 28 08:07:36 2023 +0000 sw floattable: fix fly pos invalidation in follow anchor frames The problem was that in case a row split moved the 2nd half of the row to a new page, the follow fly frame had a wrong position (top left corner of the page). What happened was that the follow anchor (text frame) was not yet positioned by the time the follow fly was positioned, and there was no invalidation once the follow anchor got its position. Fix the problem by improving SwTextFrame::MakePos(): it already had code to invalidate the position of follow flys when the position of the anchor changes, but it assumed that the flys of a follow anchor are in the follow anchor, while in fact flys are always nominally anchored in the master, so we didn't find the relevant fly frame and no invalidation happened. Once we use FindMaster() to look up the master and filter based on FindAnchorCharFrame(), we find the relevant fly to invalidate and the position is correct. Change-Id: Ic485527bb9dd05b3d5aed383eb5fa1c4f9f6a76d Reviewed-on: https://gerrit.libreoffice.org/c/core/+/147943 Reviewed-by: Miklos Vajna <vmik...@collabora.com> Tested-by: Jenkins diff --git a/sw/qa/core/layout/data/floattable-rowsplit.docx b/sw/qa/core/layout/data/floattable-rowsplit.docx new file mode 100644 index 000000000000..8e1e9fb30184 Binary files /dev/null and b/sw/qa/core/layout/data/floattable-rowsplit.docx differ diff --git a/sw/qa/core/layout/flycnt.cxx b/sw/qa/core/layout/flycnt.cxx index 4b083914b74d..75e6d64366c7 100644 --- a/sw/qa/core/layout/flycnt.cxx +++ b/sw/qa/core/layout/flycnt.cxx @@ -210,6 +210,59 @@ CPPUNIT_TEST_FIXTURE(Test, testSplitFly3Pages) // No vert offset on the 3rd page: CPPUNIT_ASSERT_EQUAL(static_cast<SwTwips>(0), nPage3FlyTop - nPage3AnchorTop); } + +CPPUNIT_TEST_FIXTURE(Test, testSplitFlyRow) +{ + // Given a document with a floattable, single row split on 2 pages: + std::shared_ptr<comphelper::ConfigurationChanges> pChanges( + comphelper::ConfigurationChanges::create()); + officecfg::Office::Writer::Filter::Import::DOCX::ImportFloatingTableAsSplitFly::set(true, + pChanges); + pChanges->commit(); + comphelper::ScopeGuard g([pChanges] { + officecfg::Office::Writer::Filter::Import::DOCX::ImportFloatingTableAsSplitFly::set( + false, pChanges); + pChanges->commit(); + }); + createSwDoc("floattable-rowsplit.docx"); + + // When laying out that document: + calcLayout(); + + // Then make sure that the single row is split to 2 pages, and the fly frames have the correct + // coordinates: + 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); + auto pPage1Anchor = dynamic_cast<SwTextFrame*>(pPage1->FindLastBodyContent()); + CPPUNIT_ASSERT(pPage1Anchor); + // ~No offset between the fly and its anchor: + SwTwips nPage1AnchorTop = pPage1Anchor->getFrameArea().Top(); + SwTwips nPage1FlyTop = pPage1Fly->getFrameArea().Top(); + CPPUNIT_ASSERT_EQUAL(static_cast<SwTwips>(1), nPage1FlyTop - nPage1AnchorTop); + // Second page: + 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); + auto pPage2Anchor = dynamic_cast<SwTextFrame*>(pPage2->FindLastBodyContent()); + CPPUNIT_ASSERT(pPage2Anchor); + // No offset between the fly and its anchor: + SwTwips nPage2AnchorTop = pPage2Anchor->getFrameArea().Top(); + SwTwips nPage2FlyTop = pPage2Fly->getFrameArea().Top(); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 0 + // - Actual : -1440 + // i.e. the 2nd page's fly had a wrong position. + CPPUNIT_ASSERT_EQUAL(static_cast<SwTwips>(0), nPage2FlyTop - nPage2AnchorTop); +} } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/text/frmform.cxx b/sw/source/core/text/frmform.cxx index 74d1a7cec04e..b1e98d9771bc 100644 --- a/sw/source/core/text/frmform.cxx +++ b/sw/source/core/text/frmform.cxx @@ -342,8 +342,20 @@ void SwTextFrame::MakePos() { SwFrame::MakePos(); - for (const auto& pFly : GetSplitFlyDrawObjs()) + // 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()) + { + 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->InvalidatePos();