sw/qa/core/layout/data/floattable-in-text-section.docx |binary sw/qa/core/layout/data/floattable-then-table.docx |binary sw/qa/core/layout/flycnt.cxx | 26 +++++++++++++++++ sw/source/core/layout/flycnt.cxx | 25 ++++++++++++++-- 4 files changed, 48 insertions(+), 3 deletions(-)
New commits: commit 56a9c6e985a99e64dece99c8d4b75bfb7fe1e43a Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Tue Apr 25 08:05:55 2023 +0200 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Wed Apr 26 11:06:21 2023 +0200 sw floattable, crashtesting: fix PDF export of fdo72790-1.docx, part 1 Converting the bugdoc to PDF crashed Writer layout since commit ce3308a926f036b87515b8cd97d2b197063dc77a (tdf#61594 sw floattable: import floating tables as split flys by default, 2023-04-12). What happens is that the DOCX file has a continuous section break, that is mapped to a Writer section, but then the fly splitting code didn't expect that the anchor might be inside a section frame. Fix this by explicitly checking for an in-section anchor in SwFrame::GetNextFlyLeaf(), which will give us a suitable insertion point on the next page. This does not fully fix the handling of the bugdoc, but at least now a reduced sample doesn't crash and is handled correctly. (cherry picked from commit 3c2e4d454aaabcd61593e670a90638a185046539) Change-Id: I52b5c901d899533bbb78131f443789d55db41000 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/151032 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> Reviewed-by: Miklos Vajna <vmik...@collabora.com> diff --git a/sw/qa/core/layout/data/floattable-in-text-section.docx b/sw/qa/core/layout/data/floattable-in-text-section.docx new file mode 100644 index 000000000000..5b377dd0379f Binary files /dev/null and b/sw/qa/core/layout/data/floattable-in-text-section.docx differ diff --git a/sw/qa/core/layout/flycnt.cxx b/sw/qa/core/layout/flycnt.cxx index ca2f0f7cbb95..14254b1dbc22 100644 --- a/sw/qa/core/layout/flycnt.cxx +++ b/sw/qa/core/layout/flycnt.cxx @@ -699,6 +699,14 @@ CPPUNIT_TEST_FIXTURE(Test, testSplitFlyThenTable) // This crashed, due to a stack overflow in layout code. save("writer_pdf_Export"); } + +CPPUNIT_TEST_FIXTURE(Test, testSplitFlyInTextSection) +{ + // The document contains a DOCX cont sect break, which is mapped to a TextSection. + // This crashed, the anchor was split directly, so the follow anchor was moved outside the + // section frame, which is broken. + createSwDoc("floattable-in-text-section.docx"); +} } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/layout/flycnt.cxx b/sw/source/core/layout/flycnt.cxx index 5f9cd6a39a07..3821ac66b1df 100644 --- a/sw/source/core/layout/flycnt.cxx +++ b/sw/source/core/layout/flycnt.cxx @@ -1558,7 +1558,14 @@ SwLayoutFrame *SwFrame::GetNextFlyLeaf( MakePageType eMakePage ) bool bBody = pFlyAnchor && pFlyAnchor->IsInDocBody(); SwLayoutFrame *pLayLeaf = nullptr; // Look up the first candidate. - if (IsTabFrame()) + SwSectionFrame* pFlyAnchorSection = pFlyAnchor ? pFlyAnchor->FindSctFrame() : nullptr; + if (pFlyAnchorSection) + { + // We can't just move the split anchor to the next page, that would be outside the section. + // Rather split that section as well. + pLayLeaf = pFlyAnchorSection->GetNextSctLeaf(eMakePage); + } + else if (IsTabFrame()) { // If we're in a table, try to find the next frame of the table's last content. SwFrame* pContent = static_cast<SwTabFrame*>(this)->FindLastContentOrTable(); commit ae26b819875bd76acad079499d6ca3ff2aea3777 Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Mon Apr 24 12:43:26 2023 +0200 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Wed Apr 26 11:06:09 2023 +0200 sw floattable, crashtesting: fix PDF export of fdo80989-1.docx Converting the bugdoc to PDF crashed Writer layout since commit ce3308a926f036b87515b8cd97d2b197063dc77a (tdf#61594 sw floattable: import floating tables as split flys by default, 2023-04-12). There were two problems here: 1) We assumed that when we move content to a next page, that page is empty. This may not be true, and in case the next page has content, we should insert the content at the start of the page, not at the end. Specifying the sibling for MoveSubTree() fixes this. 2) We also hoped that if we ask for the next layout leaf, that will be from the next page. Again, this may not be true, SwFrame::GetNextSctLeaf() has quite complex conditions to detect this. Split flys don't have to span over multiple columns, so just require that the candidate is inside a different body then our anchor. The bugdoc has to be loaded in hidden mode, otherwise we already calc the layout on load, and then the problem is not visible. (cherry picked from commit e0017ad2a5b008111b716c0814c5a0c5b0f1e05b) Change-Id: I6e1533369db24c7c275ec1d7dceaddc4128c268a Reviewed-on: https://gerrit.libreoffice.org/c/core/+/150958 Tested-by: Miklos Vajna <vmik...@collabora.com> Reviewed-by: Miklos Vajna <vmik...@collabora.com> diff --git a/sw/qa/core/layout/data/floattable-then-table.docx b/sw/qa/core/layout/data/floattable-then-table.docx new file mode 100644 index 000000000000..eb06507bd8bb Binary files /dev/null and b/sw/qa/core/layout/data/floattable-then-table.docx differ diff --git a/sw/qa/core/layout/flycnt.cxx b/sw/qa/core/layout/flycnt.cxx index 4a8578f58524..ca2f0f7cbb95 100644 --- a/sw/qa/core/layout/flycnt.cxx +++ b/sw/qa/core/layout/flycnt.cxx @@ -10,6 +10,7 @@ #include <swmodeltestbase.hxx> #include <svx/svdview.hxx> +#include <comphelper/propertyvalue.hxx> #include <IDocumentLayoutAccess.hxx> #include <anchoredobject.hxx> @@ -681,6 +682,23 @@ CPPUNIT_TEST_FIXTURE(Test, testSplitFlyInSection) // This crashed, the layout assumed that the floating table is directly under the body frame. createSwDoc("floattable-in-section.docx"); } + +CPPUNIT_TEST_FIXTURE(Test, testSplitFlyThenTable) +{ + // Given a document with a 2 page floating table, followed by an other table: + // Intentionally load the document as hidden to avoid layout during load (see TestTdf150616): + uno::Sequence<beans::PropertyValue> aFilterOptions = { + comphelper::makePropertyValue("Hidden", true), + }; + mxComponent = loadFromDesktop(m_directories.getURLFromSrc(u"/sw/qa/core/layout/data/") + + "floattable-then-table.docx", + "com.sun.star.text.TextDocument", aFilterOptions); + + // When layout is calculated during PDF export: + // Then make sure that finishes without errors: + // This crashed, due to a stack overflow in layout code. + save("writer_pdf_Export"); +} } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/layout/flycnt.cxx b/sw/source/core/layout/flycnt.cxx index 1185a980dbc3..5f9cd6a39a07 100644 --- a/sw/source/core/layout/flycnt.cxx +++ b/sw/source/core/layout/flycnt.cxx @@ -51,6 +51,7 @@ #include <fmtfollowtextflow.hxx> #include <unoprnms.hxx> #include <rootfrm.hxx> +#include <bodyfrm.hxx> using namespace ::com::sun::star; @@ -1577,7 +1578,17 @@ SwLayoutFrame *SwFrame::GetNextFlyLeaf( MakePageType eMakePage ) bool bLeftBody = bBody && !pLayLeaf->IsInDocBody(); // If the candiate is in a fly, make sure that the candidate is a child of our follow. bool bLeftFly = pLayLeaf->IsInFly() && pLayLeaf->FindFlyFrame() != pFly->GetFollow(); - if (bLeftBody || bLeftFly) + bool bSameBody = false; + if (bBody && pLayLeaf->IsInDocBody()) + { + // Make sure the candidate is not inside the same body frame, that would prevent + // inserting a new page. + if (pFlyAnchor->FindBodyFrame() == pLayLeaf->FindBodyFrame()) + { + bSameBody = true; + } + } + if (bLeftBody || bLeftFly || bSameBody) { // The above conditions are not held, reject. pOldLayLeaf = pLayLeaf; @@ -1609,7 +1620,8 @@ SwLayoutFrame *SwFrame::GetNextFlyLeaf( MakePageType eMakePage ) // Split the anchor at char 0: all the content goes to the follow of the anchor. pFlyAnchor->SplitFrame(TextFrameIndex(0)); auto pNext = static_cast<SwTextFrame*>(pFlyAnchor->GetNext()); - pNext->MoveSubTree(pLayLeaf); + // Move the new anchor frame, before the first child of pLayLeaf. + pNext->MoveSubTree(pLayLeaf, pLayLeaf->Lower()); // Now create the follow of the fly and anchor it in the master of the anchor. pNew = new SwFlyAtContentFrame(*pFly);