sw/qa/core/text/data/floattable-heading-split.docx |binary sw/qa/core/text/widorp.cxx | 22 +++++++++++++++++++++ sw/source/core/text/widorp.cxx | 8 +++++++ 3 files changed, 30 insertions(+)
New commits: commit b8009818d619bff16d19a0f589a733f78a46ec0b Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Mon Jul 14 09:28:52 2025 +0200 Commit: Caolán McNamara <caolan.mcnam...@collabora.com> CommitDate: Mon Jul 14 11:18:28 2025 +0200 tdf#167222 sw floattable: allow split of fly and its keep-together anchor text Regression from commit 3eb6d764b3023500f2299d36bf1860bc8e67db9f (DOCX import: floating table with negative top margin has to be a fly frame, 2022-01-21), open the bugdoc, notice that the floating table should be at the end of page 1 but is at the start of page 2. This happens because in general keep-together means no split should happen for all anchored objects and lines of a text frame, but Word allows floating tables to be split from the next regular paragraph in the document. Fix the problem by building on top of the work done in commit 2d0a4ef1d83b8de6cb133970c2c35ae706fb058e (sw floattable: fix negative vertical offset handling on page boundary, 2023-06-20), which makes this split to "floating table" and "anchor text" pieces possible, but that didn't help here, since the anchor text node happened to be a heading, with both a split property set to false and a keep-with-next property set to true. Now we ignore both properties in case the paragraph is a floating table anchor, which means that in SwTextFrame::FormatAdjust(), rFrameBreak.IsBreakNow() can return true, resulting in a call to SplitFrame(), as needed. The behavior for other types of anchored objects is unchanged, those don't go to a separate page in Word, either. Change-Id: I48835f355fa5aeb09b1a92bd8cee7e06cd148240 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/187845 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com> diff --git a/sw/qa/core/text/data/floattable-heading-split.docx b/sw/qa/core/text/data/floattable-heading-split.docx new file mode 100644 index 000000000000..adfd173c172e Binary files /dev/null and b/sw/qa/core/text/data/floattable-heading-split.docx differ diff --git a/sw/qa/core/text/widorp.cxx b/sw/qa/core/text/widorp.cxx index 54d26aa2db07..7dd48bc9b879 100644 --- a/sw/qa/core/text/widorp.cxx +++ b/sw/qa/core/text/widorp.cxx @@ -60,6 +60,28 @@ CPPUNIT_TEST_FIXTURE(Test, testHideWhitespaceWidorp) // went to page 1, so it was not split anymore. CPPUNIT_ASSERT(pPara2->HasFollow()); } + +CPPUNIT_TEST_FIXTURE(Test, testFloattableHeadingSplit) +{ + // Given a document which ends with a floating table and a heading paragraph: + // When loading that document & laying it out: + createSwDoc("floattable-heading-split.docx"); + + // Then make sure that the floating table is on page 1 and the last heading is on page 2: + SwDocShell* pDocShell = getSwDocShell(); + SwDoc* pDoc = pDocShell->GetDoc(); + SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout(); + auto pPage1 = pLayout->Lower()->DynCastPageFrame(); + // Without the accompanying fix in place, this test would have failed, the floating table went + // to page 2, not to page 1. + CPPUNIT_ASSERT(pPage1->GetSortedObjs()); + // Make sure that page 2 has no floating table and has the heading on the correct page. + auto pPage2 = pPage1->GetNext()->DynCastPageFrame(); + CPPUNIT_ASSERT(!pPage2->GetSortedObjs()); + SwLayoutFrame* pBody2 = pPage2->FindBodyCont(); + SwTextFrame* pPage2Para1 = pBody2->ContainsContent()->DynCastTextFrame(); + CPPUNIT_ASSERT_EQUAL(u"page 2"_ustr, pPage2Para1->GetText()); +} } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/text/widorp.cxx b/sw/source/core/text/widorp.cxx index 4c0dd129da04..b6c5dd5b70aa 100644 --- a/sw/source/core/text/widorp.cxx +++ b/sw/source/core/text/widorp.cxx @@ -73,6 +73,14 @@ SwTextFrameBreak::SwTextFrameBreak( SwTextFrame *pNewFrame, const SwTwips nRst ) } m_bKeep = m_bKeep || !m_pFrame->GetTextNodeForParaProps()->GetSwAttrSet().GetSplit().GetValue() || m_pFrame->GetTextNodeForParaProps()->GetSwAttrSet().GetKeep().GetValue(); + + if (m_bKeep && m_pFrame->HasSplitFlyDrawObjs()) + { + // Ignore keep-together and keep-with-next if this is an anchor for a floating table. It's + // OK to split the text frame into two, to separate the floating table and the anchor text. + m_bKeep = false; + } + m_bBreak = false; if( !m_nRstHeight && !m_pFrame->IsFollow() && m_pFrame->IsInFootnote() && m_pFrame->HasPara() )