sw/qa/extras/layout/data/tdf155611_table_and_nested_section.fodt |   33 
++++++++++
 sw/qa/extras/layout/layout2.cxx                                  |   31 
+++++++++
 sw/source/core/layout/sectfrm.cxx                                |   16 ++++
 3 files changed, 79 insertions(+), 1 deletion(-)

New commits:
commit 09656811089a319979dc3997f550734ceaa6c905
Author:     Mike Kaganski <mike.kagan...@collabora.com>
AuthorDate: Wed May 31 18:07:14 2023 +0300
Commit:     Mike Kaganski <mike.kagan...@collabora.com>
CommitDate: Fri Jun 2 22:10:50 2023 +0200

    tdf#155611: SwFrame::FindNext sometimes returns a sub-frame of this frame
    
    This resulted in wrong split of the section frame, when the table frame
    was the last in the section, the split needed to happen after that table
    (i.e., at the very end of the section), and passing the table frame as
    pFrameStartAfter gave its last cell's subtable as pSav (i.e., the frame
    to move after the split). The first frame of the last cell (the one prior
    to pSav) got lost from the layout, and wasn't destroyed when SwRootFrame
    was destroyed, and then it crashed referencing destroyed root frame and
    view shell.
    
    Change-Id: I1a539818aa890f65e961f4185ce50916ce7e4e4f
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/152454
    Tested-by: Jenkins
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/152465
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/152482
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>

diff --git a/sw/qa/extras/layout/data/tdf155611_table_and_nested_section.fodt 
b/sw/qa/extras/layout/data/tdf155611_table_and_nested_section.fodt
new file mode 100644
index 000000000000..28c0701ea2fc
--- /dev/null
+++ b/sw/qa/extras/layout/data/tdf155611_table_and_nested_section.fodt
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<office:document 
xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" 
xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" 
xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" 
office:version="1.3" office:mimetype="application/vnd.oasis.opendocument.text">
+ <office:body>
+  <office:text>
+   <text:section text:name="Outer section">
+    <table:table>
+     <table:table-column table:number-columns-repeated="2"/>
+     <table:table-row>
+      <table:table-cell>
+       <text:p>foo</text:p>
+      </table:table-cell>
+      <table:table-cell>
+       <text:p>bar</text:p>
+       <table:table>
+        <table:table-column/>
+        <table:table-row>
+         <table:table-cell>
+          <text:p>baz</text:p>
+         </table:table-cell>
+        </table:table-row>
+       </table:table>
+      </table:table-cell>
+     </table:table-row>
+    </table:table>
+    <text:section text:name="Inner section">
+     <text:p>abc</text:p>
+    </text:section>
+   </text:section>
+   <text:p/>
+  </office:text>
+ </office:body>
+</office:document>
\ No newline at end of file
diff --git a/sw/qa/extras/layout/layout2.cxx b/sw/qa/extras/layout/layout2.cxx
index 4b272d0725f2..cd921ab50241 100644
--- a/sw/qa/extras/layout/layout2.cxx
+++ b/sw/qa/extras/layout/layout2.cxx
@@ -2815,6 +2815,37 @@ CPPUNIT_TEST_FIXTURE(SwLayoutWriter2, testTdf138124)
     assertXPath(pXml, 
"/root/page/ftncont/ftn/txt//SwLinePortion[@type='PortionType::FlyCnt']", 1);
 }
 
+CPPUNIT_TEST_FIXTURE(SwLayoutWriter2, testTdf155611)
+{
+    createSwDoc("tdf155611_table_and_nested_section.fodt");
+    Scheduler::ProcessEventsToIdle();
+
+    xmlDocUniquePtr pXml = parseLayoutDump();
+    CPPUNIT_ASSERT(pXml);
+
+    // Check the layout: single page, two section frames (no section frames 
after the one for Inner
+    // section), correct table structure and content in the first section 
frame, including nested
+    // table in the last cell, and the last section text.
+    assertXPath(pXml, "/root/page");
+    // Without the fix in place, this would fail with
+    // - Expected: 2
+    // - Actual  : 3
+    assertXPath(pXml, "/root/page/body/section", 2);
+    assertXPath(pXml, "/root/page/body/section[1]/tab");
+    assertXPath(pXml, "/root/page/body/section[1]/tab/row");
+    assertXPath(pXml, "/root/page/body/section[1]/tab/row/cell", 2);
+    assertXPath(pXml, 
"/root/page/body/section[1]/tab/row/cell[1]/txt/SwParaPortion/SwLineLayout/"
+                      "SwParaPortion[@portion='foo']");
+    assertXPath(pXml, 
"/root/page/body/section[1]/tab/row/cell[2]/txt/SwParaPortion/SwLineLayout/"
+                      "SwParaPortion[@portion='bar']");
+    assertXPath(pXml, 
"/root/page/body/section[1]/tab/row/cell[2]/tab/row/cell/txt/SwParaPortion/"
+                      "SwLineLayout/SwParaPortion[@portion='baz']");
+    assertXPath(pXml, 
"/root/page/body/section[2]/txt[1]/SwParaPortion/SwLineLayout/"
+                      "SwParaPortion[@portion='abc']");
+
+    // Also must not crash on close because of a frame that accidentally fell 
off of the layout
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/layout/sectfrm.cxx 
b/sw/source/core/layout/sectfrm.cxx
index 0b1ac612bfd9..b9249de5c340 100644
--- a/sw/source/core/layout/sectfrm.cxx
+++ b/sw/source/core/layout/sectfrm.cxx
@@ -523,7 +523,21 @@ void SwSectionFrame::MergeNext( SwSectionFrame* pNxt )
 SwSectionFrame* SwSectionFrame::SplitSect( SwFrame* pFrameStartAfter, SwFrame* 
pFramePutAfter )
 {
     assert(!pFrameStartAfter || IsAnLower(pFrameStartAfter));
-    SwFrame* pSav = pFrameStartAfter ? pFrameStartAfter->FindNext() : 
ContainsAny();
+    SwFrame* pSav;
+    if (pFrameStartAfter)
+    {
+        pSav = pFrameStartAfter->FindNext();
+        // If pFrameStartAfter is a complex object like table, and it has no 
next,
+        // its FindNext may return its own last subframe. In this case, assume 
that
+        // we are at the end.
+        if (pSav && pFrameStartAfter->IsLayoutFrame())
+            if (static_cast<SwLayoutFrame*>(pFrameStartAfter)->IsAnLower(pSav))
+                pSav = nullptr;
+    }
+    else
+    {
+        pSav = ContainsAny();
+    }
     if (pSav && !IsAnLower(pSav))
         pSav = nullptr; // we are at the very end
 

Reply via email to