sw/qa/core/layout/data/floattable-nested-overlap.odt |binary sw/qa/core/layout/flycnt.cxx | 23 +++++++++ sw/source/core/layout/tabfrm.cxx | 23 +-------- sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx | 24 ++++++++-- 4 files changed, 48 insertions(+), 22 deletions(-)
New commits: commit e20bacc209a8e8483209cb4ec51c9e0b55423cdb Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Mon Sep 11 08:26:43 2023 +0200 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Mon Sep 11 09:22:37 2023 +0200 sw floattable, nesting: fix overlap support The bugdoc had a nested, split floating table with overlap=never and that lead to a layout loop. The root of the trouble seems to be that the inner fly will obviously overlap with its outer fly but we tried to prevent that and we failed. Fix the problem by ignoring inner flys in SwToContentAnchoredObjectPosition::CalcOverlap(). This also allows removing special handling of nested split flys in lcl_ArrangeLowers() and special handling of split flys at an other place in the same function, because now the non-bDirectMove case works out of the box. Change-Id: Icf3a8f776aa758ef4ae2c2994a7216c5a6142a62 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/156810 Reviewed-by: Miklos Vajna <vmik...@collabora.com> Tested-by: Jenkins diff --git a/sw/qa/core/layout/data/floattable-nested-overlap.odt b/sw/qa/core/layout/data/floattable-nested-overlap.odt new file mode 100644 index 000000000000..b90ae9a7b01e Binary files /dev/null and b/sw/qa/core/layout/data/floattable-nested-overlap.odt differ diff --git a/sw/qa/core/layout/flycnt.cxx b/sw/qa/core/layout/flycnt.cxx index 1c69606c8a24..73a107c4bc5e 100644 --- a/sw/qa/core/layout/flycnt.cxx +++ b/sw/qa/core/layout/flycnt.cxx @@ -1080,6 +1080,29 @@ CPPUNIT_TEST_FIXTURE(Test, testSplitFlyNested) CPPUNIT_ASSERT(!pPage2Fly2->GetAnchorFrameContainingAnchPos()->IsInFly()); CPPUNIT_ASSERT(pPage2Fly2->GetPrecede()); } + +CPPUNIT_TEST_FIXTURE(Test, testSplitFlyNestedOverlap) +{ + // Given a document with a nested, multi-page floating table, enabling the "don't overlap" logic: + // When calculating the layout: + createSwDoc("floattable-nested-overlap.odt"); + calcLayout(); + + // Then make sure we get 2 pages (2 flys on each page): + // Without the accompanying fix in place, this test would have failed with a layout loop. + SwDoc* pDoc = getSwDoc(); + SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout(); + auto pPage1 = pLayout->Lower()->DynCastPageFrame(); + CPPUNIT_ASSERT(pPage1); + CPPUNIT_ASSERT(pPage1->GetSortedObjs()); + SwSortedObjs& rPage1Objs = *pPage1->GetSortedObjs(); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), rPage1Objs.size()); + auto pPage2 = pPage1->GetNext()->DynCastPageFrame(); + CPPUNIT_ASSERT(pPage2); + CPPUNIT_ASSERT(pPage2->GetSortedObjs()); + SwSortedObjs& rPage2Objs = *pPage2->GetSortedObjs(); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), rPage2Objs.size()); +} } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/layout/tabfrm.cxx b/sw/source/core/layout/tabfrm.cxx index bbd7ebece6d8..68bb19b7f39d 100644 --- a/sw/source/core/layout/tabfrm.cxx +++ b/sw/source/core/layout/tabfrm.cxx @@ -5287,24 +5287,11 @@ static bool lcl_ArrangeLowers( SwLayoutFrame *pLay, tools::Long lYStart, bool bI lcl_ArrangeLowers( static_cast<SwLayoutFrame*>(pFrame), aRectFnSet.GetTop(static_cast<SwLayoutFrame*>(pFrame)->Lower()->getFrameArea()) + lDiffX, bInva ); - SwSortedObjs* pDrawObjs = pFrame->GetDrawObjs(); - auto pTextFrame = pFrame->DynCastTextFrame(); - if (pTextFrame && pTextFrame->IsInFly()) + if ( pFrame->GetDrawObjs() ) { - // See if this is a follow anchor. If so, we want the flys anchored in the master - // which are also lowers of pFrame. - SwTextFrame* pMaster = pTextFrame; - while (pMaster->IsFollow()) + for ( size_t i = 0; i < pFrame->GetDrawObjs()->size(); ++i ) { - pMaster = pMaster->FindMaster(); - } - pDrawObjs = pMaster->GetDrawObjs(); - } - if (pDrawObjs) - { - for (size_t i = 0; i < pDrawObjs->size(); ++i) - { - SwAnchoredObject* pAnchoredObj = (*pDrawObjs)[i]; + SwAnchoredObject* pAnchoredObj = (*pFrame->GetDrawObjs())[i]; // #i26945# - check, if anchored object // is lower of layout frame by checking, if the anchor // frame, which contains the anchor position, is a lower @@ -5338,12 +5325,10 @@ static bool lcl_ArrangeLowers( SwLayoutFrame *pLay, tools::Long lYStart, bool bI // on the object positioning. // #i52904# - no direct move of objects, // whose vertical position doesn't depend on anchor frame. - // Also move split flys directly, otherwise the follows would not be moved - // at all. const bool bDirectMove = FAR_AWAY != pFly->getFrameArea().Top() && bVertPosDepOnAnchor && - (!pFly->ConsiderObjWrapInfluenceOnObjPos() || pFly->IsFlySplitAllowed()); + !pFly->ConsiderObjWrapInfluenceOnObjPos(); if ( bDirectMove ) { { diff --git a/sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx b/sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx index 9c1c491b24c9..b83d979d31b7 100644 --- a/sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx +++ b/sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx @@ -1212,6 +1212,14 @@ void SwToContentAnchoredObjectPosition::CalcOverlap(const SwTextFrame* pAnchorFr // At least for split flys we need to consider objects on the same page, but anchored in // different text frames. bSplitFly = true; + + SwFrame* pFlyFrameAnchor = pFlyFrame->GetAnchorFrameContainingAnchPos(); + if (pFlyFrameAnchor && pFlyFrameAnchor->IsInFly()) + { + // An inner fly overlapping with its outer fly is fine. + return; + } + const SwPageFrame* pPageFrame = pAnchorFrameForVertPos->FindPageFrame(); if (pPageFrame) { @@ -1239,10 +1247,20 @@ void SwToContentAnchoredObjectPosition::CalcOverlap(const SwTextFrame* pAnchorFr } SwFlyFrame* pAnchoredObjFly = pAnchoredObj->DynCastFlyFrame(); - if (bSplitFly && !pAnchoredObjFly) + if (bSplitFly) { - // This is a split fly, then overlap is only checked against other split flys. - continue; + if (!pAnchoredObjFly) + { + // This is a split fly, then overlap is only checked against other split flys. + continue; + } + + SwFrame* pAnchoredObjFlyAnchor = pAnchoredObjFly->GetAnchorFrameContainingAnchPos(); + if (pAnchoredObjFlyAnchor && pAnchoredObjFlyAnchor->IsInFly()) + { + // An inner fly overlapping with its outer fly is fine. + continue; + } } css::text::WrapTextMode eWrap = pAnchoredObj->GetFrameFormat().GetSurround().GetSurround();