sw/qa/core/layout/data/floattable-then-table.docx |binary
 sw/qa/core/layout/flycnt.cxx                      |   18 ++++++++++++++++++
 sw/source/core/layout/flycnt.cxx                  |   16 ++++++++++++++--
 3 files changed, 32 insertions(+), 2 deletions(-)

New commits:
commit e0017ad2a5b008111b716c0814c5a0c5b0f1e05b
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Mon Apr 24 12:43:26 2023 +0200
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Mon Apr 24 17:06:27 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.
    
    Change-Id: I6e1533369db24c7c275ec1d7dceaddc4128c268a
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/150904
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>
    Tested-by: Jenkins

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 3b2b9e257e7e..f5d4c76c936f 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 candidate 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);

Reply via email to