sw/qa/core/objectpositioning/data/floattable-vert-orient-top.odt |binary sw/qa/core/objectpositioning/objectpositioning.cxx | 24 ++++++++++ sw/source/core/inc/frame.hxx | 2 sw/source/core/layout/findfrm.cxx | 10 ++++ sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx | 5 +- 5 files changed, 40 insertions(+), 1 deletion(-)
New commits: commit 38192482e552195a5c76a6e40fc3586cc6f0355c Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Fri Sep 1 08:51:20 2023 +0200 Commit: Xisco Fauli <xiscofa...@libreoffice.org> CommitDate: Mon Sep 4 17:26:09 2023 +0200 Related: tdf#156318 sw floattable: fix handling of vert orient == top The bugdoc resulted in a layout loop on load. It was created by forcing pages to be in a single column + increasing the top+bottom margin of the page to 2.5cm. The problem was that the SwFormatVertOrient's m_eOrient is usually text::VertOrientation::NONE ("from top" with 0 offset), but here it's text::VertOrientation::TOP. These are meant to be more or less equivalent, but SwToContentAnchoredObjectPosition::CalcPosition() has different codepath for them. Fix the problem by making sure that TOP doesn't have a vertical offset for follow fly frame: do this by realizing that in case the "orient frame" and the "anchor" is not the same that may need no action, since the fly frame case changes the "orient" to the follow anchor and the "anchor" is the master anchor. The original scenario still needs more work, we don't hang anymore but the follow fly appears on page 3 instead of page 2. Change-Id: I1596a07b78575583070d494ddb8e1400e5653820 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/156392 Reviewed-by: Miklos Vajna <vmik...@collabora.com> Tested-by: Jenkins (cherry picked from commit 7d4213b9f0253b323750acceca8f4edb9d1a7fc5) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/156530 Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org> diff --git a/sw/qa/core/objectpositioning/data/floattable-vert-orient-top.odt b/sw/qa/core/objectpositioning/data/floattable-vert-orient-top.odt new file mode 100644 index 000000000000..b10f0b7188fa Binary files /dev/null and b/sw/qa/core/objectpositioning/data/floattable-vert-orient-top.odt differ diff --git a/sw/qa/core/objectpositioning/objectpositioning.cxx b/sw/qa/core/objectpositioning/objectpositioning.cxx index 4958b8b6deb4..611ce1294c22 100644 --- a/sw/qa/core/objectpositioning/objectpositioning.cxx +++ b/sw/qa/core/objectpositioning/objectpositioning.cxx @@ -313,6 +313,30 @@ CPPUNIT_TEST_FIXTURE(SwCoreObjectpositioningTest, testFloatingTableOverlapNever) CPPUNIT_ASSERT_GREATER(pFlyFrame1->getFrameArea().Bottom(), pFlyFrame2->getFrameArea().Top()); } +CPPUNIT_TEST_FIXTURE(SwCoreObjectpositioningTest, testFloatingTableVertOrientTop) +{ + // Given a document with a vert-orient=from-top anchored floating table: + createSwDoc("floattable-vert-orient-top.odt"); + + // When laying out that document: + calcLayout(); + + // Then make sure we correctly split the table to two pages: + // Without the accompanying fix in place, this test would have produced a layout loop. + SwDoc* pDoc = getSwDoc(); + SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout(); + auto pPage1 = pLayout->Lower()->DynCastPageFrame(); + CPPUNIT_ASSERT(pPage1); + CPPUNIT_ASSERT(pPage1->GetSortedObjs()); + const SwSortedObjs& rPage1Objs = *pPage1->GetSortedObjs(); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rPage1Objs.size()); + auto pPage2 = pPage1->GetNext()->DynCastPageFrame(); + CPPUNIT_ASSERT(pPage2); + CPPUNIT_ASSERT(pPage2->GetSortedObjs()); + const SwSortedObjs& rPage2Objs = *pPage2->GetSortedObjs(); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rPage2Objs.size()); +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/inc/frame.hxx b/sw/source/core/inc/frame.hxx index ec47266ec468..885a0d223f24 100644 --- a/sw/source/core/inc/frame.hxx +++ b/sw/source/core/inc/frame.hxx @@ -874,6 +874,8 @@ public: inline bool IsTextFrame() const; SwTextFrame* DynCastTextFrame(); const SwTextFrame* DynCastTextFrame() const; + SwPageFrame* DynCastPageFrame(); + const SwPageFrame* DynCastPageFrame() const; inline bool IsNoTextFrame() const; // Frames where its PrtArea depends on their neighbors and that are // positioned in the content flow diff --git a/sw/source/core/layout/findfrm.cxx b/sw/source/core/layout/findfrm.cxx index 1a98f6cf6747..5331baacd93e 100644 --- a/sw/source/core/layout/findfrm.cxx +++ b/sw/source/core/layout/findfrm.cxx @@ -1944,4 +1944,14 @@ const SwTextFrame* SwFrame::DynCastTextFrame() const return IsTextFrame() ? static_cast<const SwTextFrame*>(this) : nullptr; } +SwPageFrame* SwFrame::DynCastPageFrame() +{ + return IsPageFrame() ? static_cast<SwPageFrame*>(this) : nullptr; +} + +const SwPageFrame* SwFrame::DynCastPageFrame() const +{ + return IsPageFrame() ? static_cast<const SwPageFrame*>(this) : nullptr; +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx b/sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx index 33168ceba432..561c16fd8115 100644 --- a/sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx +++ b/sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx @@ -422,7 +422,10 @@ void SwToContentAnchoredObjectPosition::CalcPosition() // the frame, the object is oriented at. // #i28701# - correction: adjust relative position, // only if the floating screen object has to follow the text flow. - if ( DoesObjFollowsTextFlow() && pOrientFrame != &rAnchorTextFrame ) + // Also don't do this for split flys: pOrientFrame already points to the follow anchor, + // so pOrientFrame is not the anchor text frame anymore, and that would lead to an + // additional, unwanted increase of nRelPosY. + if (DoesObjFollowsTextFlow() && pOrientFrame != &rAnchorTextFrame && !bFollowSplitFly) { // #i11860# - use new method <GetTopForObjPos> // to get top of frame for object positioning.