diff options
-rw-r--r-- | sw/qa/core/layout/data/floattable-move-master.docx | bin | 0 -> 13635 bytes | |||
-rw-r--r-- | sw/qa/core/layout/flycnt.cxx | 42 | ||||
-rw-r--r-- | sw/source/core/inc/rootfrm.hxx | 1 | ||||
-rw-r--r-- | sw/source/core/inc/txtfrm.hxx | 2 | ||||
-rw-r--r-- | sw/source/core/layout/calcmove.cxx | 13 | ||||
-rw-r--r-- | sw/source/core/layout/flycnt.cxx | 27 | ||||
-rw-r--r-- | sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx | 6 | ||||
-rw-r--r-- | sw/source/core/text/itratr.cxx | 10 |
8 files changed, 95 insertions, 6 deletions
diff --git a/sw/qa/core/layout/data/floattable-move-master.docx b/sw/qa/core/layout/data/floattable-move-master.docx Binary files differnew file mode 100644 index 000000000000..03087eb358a8 --- /dev/null +++ b/sw/qa/core/layout/data/floattable-move-master.docx diff --git a/sw/qa/core/layout/flycnt.cxx b/sw/qa/core/layout/flycnt.cxx index 73a107c4bc5e..f5f5fb094a37 100644 --- a/sw/qa/core/layout/flycnt.cxx +++ b/sw/qa/core/layout/flycnt.cxx @@ -1103,6 +1103,48 @@ CPPUNIT_TEST_FIXTURE(Test, testSplitFlyNestedOverlap) SwSortedObjs& rPage2Objs = *pPage2->GetSortedObjs(); CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), rPage2Objs.size()); } + +CPPUNIT_TEST_FIXTURE(Test, testSplitFlyMoveMaster) +{ + // Given a document with a multi-page floating table on pages 1 -> 2 -> 3: + createSwDoc("floattable-move-master.docx"); + + // When adding an empty para before the table, so the table gets shifted to pages 2 -> 3: + SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell(); + pWrtShell->SttEndDoc(/*bStt=*/true); + pWrtShell->Down(/*bSelect=*/false, /*nCount=*/4); + pWrtShell->SplitNode(); + + // Then make sure page 1 has no flys, page 2 and 3 has the split fly and no flys on page 4: + SwDoc* pDoc = getSwDoc(); + SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout(); + auto pPage1 = pLayout->Lower()->DynCastPageFrame(); + CPPUNIT_ASSERT(pPage1); + // Without the accompanying fix in place, this test would have failed, the start of the fly was + // still on page 1 instead of page 2. + CPPUNIT_ASSERT(!pPage1->GetSortedObjs()); + auto pPage2 = pPage1->GetNext()->DynCastPageFrame(); + CPPUNIT_ASSERT(pPage2); + CPPUNIT_ASSERT(pPage2->GetSortedObjs()); + SwSortedObjs& rPage2Objs = *pPage2->GetSortedObjs(); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rPage2Objs.size()); + auto pPage2Fly = rPage2Objs[0]->DynCastFlyFrame()->DynCastFlyAtContentFrame(); + CPPUNIT_ASSERT(pPage2Fly); + CPPUNIT_ASSERT(!pPage2Fly->GetPrecede()); + CPPUNIT_ASSERT(pPage2Fly->HasFollow()); + auto pPage3 = pPage2->GetNext()->DynCastPageFrame(); + CPPUNIT_ASSERT(pPage3); + CPPUNIT_ASSERT(pPage3->GetSortedObjs()); + SwSortedObjs& rPage3Objs = *pPage3->GetSortedObjs(); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rPage3Objs.size()); + auto pPage3Fly = rPage3Objs[0]->DynCastFlyFrame()->DynCastFlyAtContentFrame(); + CPPUNIT_ASSERT(pPage3Fly); + CPPUNIT_ASSERT(pPage3Fly->GetPrecede()); + CPPUNIT_ASSERT(!pPage3Fly->GetFollow()); + auto pPage4 = pPage3->GetNext()->DynCastPageFrame(); + CPPUNIT_ASSERT(pPage4); + CPPUNIT_ASSERT(!pPage4->GetSortedObjs()); +} } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/inc/rootfrm.hxx b/sw/source/core/inc/rootfrm.hxx index 80e104c9c63b..29f813360d82 100644 --- a/sw/source/core/inc/rootfrm.hxx +++ b/sw/source/core/inc/rootfrm.hxx @@ -395,6 +395,7 @@ public: #ifdef DBG_UTIL bool IsInDelList( SwSectionFrame* pSct ) const; #endif + bool IsInFlyDelList( SwFlyFrame* pFly ) const; void SetCallbackActionEnabled( bool b ) { mbCallbackActionEnabled = b; } bool IsCallbackActionEnabled() const { return mbCallbackActionEnabled; } diff --git a/sw/source/core/inc/txtfrm.hxx b/sw/source/core/inc/txtfrm.hxx index 2cfa91e88dca..d73c2efa499f 100644 --- a/sw/source/core/inc/txtfrm.hxx +++ b/sw/source/core/inc/txtfrm.hxx @@ -796,7 +796,7 @@ public: /// This text frame may have a split fly frames anchored to it. Is any of them a frame that has /// a follow, i.e. not the last in a master -> follow 1 -> ... -> last follow chain? - bool HasNonLastSplitFlyDrawObj() const; + SwFlyAtContentFrame* HasNonLastSplitFlyDrawObj() const; /// This text frame has a follow and the text frame don't contain text. Additionally one split /// fly is anchored to the text frame. diff --git a/sw/source/core/layout/calcmove.cxx b/sw/source/core/layout/calcmove.cxx index 5fb30d5c7afa..4d4b2de28994 100644 --- a/sw/source/core/layout/calcmove.cxx +++ b/sw/source/core/layout/calcmove.cxx @@ -162,6 +162,19 @@ bool SwContentFrame::ShouldBwdMoved( SwLayoutFrame *pNewUpper, bool & ) !pNewUpper->GetUpper()->GetNext() ) ) ) ) nSpace += pNewUpper->Grow( LONG_MAX, true ); + auto pTextFrame = DynCastTextFrame(); + if (pTextFrame) + { + // This is a text frame. Check if it's an anchor for a non-last element in a split + // fly chain. If so, we can only move back in case not only the text frame itself, + // but also its fly fits nSpace. + SwFlyAtContentFrame* pFly = pTextFrame->HasNonLastSplitFlyDrawObj(); + if (pFly && pFly->getFrameArea().Height() > nSpace) + { + return false; + } + } + if ( nMoveAnyway < 3 ) { if ( nSpace ) diff --git a/sw/source/core/layout/flycnt.cxx b/sw/source/core/layout/flycnt.cxx index 2cba4e295728..907444efc321 100644 --- a/sw/source/core/layout/flycnt.cxx +++ b/sw/source/core/layout/flycnt.cxx @@ -1554,6 +1554,12 @@ SwLayoutFrame *SwFrame::GetNextFlyLeaf( MakePageType eMakePage ) assert(pFly && "GetNextFlyLeaf: missing fly frame"); assert(pFly->IsFlySplitAllowed() && "GetNextFlyLeaf: fly split not allowed"); + if (pFly->HasFollow()) + { + // If we already have a follow, then no need to create a new one, just use it. + return pFly->GetFollow(); + } + SwTextFrame* pFlyAnchor = pFly->FindAnchorCharFrame(); if (!pFlyAnchor) @@ -1701,6 +1707,16 @@ void SwRootFrame::DeleteEmptyFlys_() } } +bool SwRootFrame::IsInFlyDelList( SwFlyFrame* pFly ) const +{ + if (!mpFlyDestroy) + { + return false; + } + + return mpFlyDestroy->find(pFly) != mpFlyDestroy->end(); +} + const SwFlyAtContentFrame* SwFlyAtContentFrame::GetPrecede() const { return static_cast<const SwFlyAtContentFrame*>(SwFlowFrame::GetPrecede()); @@ -1721,6 +1737,17 @@ void SwFlyAtContentFrame::DelEmpty() // The anchor has a precede: invalidate it so that JoinFrame() is called on it. pAnchorPrecede->GetFrame().InvalidateSize(); } + else if (SwTextFrame* pAnchorFollow = pAnchor->GetFollow()) + { + // No precede, but has a follow. Then move the master just before the follow and join. + // This way the anchor chain and the fly chain will match even after clearing this + // frame's follow pointer. + if (pAnchorFollow != pAnchor->GetNext()) + { + pAnchor->MoveSubTree(pAnchorFollow->GetUpper(), pAnchorFollow); + pAnchor->JoinFrame(); + } + } } SwFlyAtContentFrame* pMaster = IsFollow() ? GetPrecede() : nullptr; diff --git a/sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx b/sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx index b83d979d31b7..69951ba08a2c 100644 --- a/sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx +++ b/sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx @@ -1255,6 +1255,12 @@ void SwToContentAnchoredObjectPosition::CalcOverlap(const SwTextFrame* pAnchorFr continue; } + if (pAnchoredObjFly->getRootFrame()->IsInFlyDelList(pAnchoredObjFly)) + { + // A fly overlapping with a to-be-deleted fly is fine. + continue; + } + SwFrame* pAnchoredObjFlyAnchor = pAnchoredObjFly->GetAnchorFrameContainingAnchPos(); if (pAnchoredObjFlyAnchor && pAnchoredObjFlyAnchor->IsInFly()) { diff --git a/sw/source/core/text/itratr.cxx b/sw/source/core/text/itratr.cxx index 97425515b0a0..358d6d5068f3 100644 --- a/sw/source/core/text/itratr.cxx +++ b/sw/source/core/text/itratr.cxx @@ -1480,17 +1480,17 @@ std::vector<SwFlyAtContentFrame*> SwTextFrame::GetSplitFlyDrawObjs() const return aObjs; } -bool SwTextFrame::HasNonLastSplitFlyDrawObj() const +SwFlyAtContentFrame* SwTextFrame::HasNonLastSplitFlyDrawObj() const { const SwTextFrame* pFollow = GetFollow(); if (!pFollow) { - return false; + return nullptr; } if (mnOffset != pFollow->GetOffset()) { - return false; + return nullptr; } // At this point we know what we're part of a chain that is an anchor for split fly frames, but @@ -1513,11 +1513,11 @@ bool SwTextFrame::HasNonLastSplitFlyDrawObj() const } if (pFly->GetFollow()) { - return true; + return pFly; } } - return false; + return nullptr; } bool SwTextFrame::IsEmptyMasterWithSplitFly() const |