summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sw/qa/core/layout/data/floattable-move-master.docxbin0 -> 13635 bytes
-rw-r--r--sw/qa/core/layout/flycnt.cxx42
-rw-r--r--sw/source/core/inc/rootfrm.hxx1
-rw-r--r--sw/source/core/inc/txtfrm.hxx2
-rw-r--r--sw/source/core/layout/calcmove.cxx13
-rw-r--r--sw/source/core/layout/flycnt.cxx27
-rw-r--r--sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx6
-rw-r--r--sw/source/core/text/itratr.cxx10
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
new file mode 100644
index 000000000000..03087eb358a8
--- /dev/null
+++ b/sw/qa/core/layout/data/floattable-move-master.docx
Binary files differ
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