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 80e8b5e925b0059226c36abe2f0d49a8299084f7 Author: Mike Kaganski <mike.kagan...@collabora.com> AuthorDate: Wed May 31 18:07:14 2023 +0300 Commit: Michael Stahl <michael.st...@allotropia.de> CommitDate: Thu Jun 1 11:42:12 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> 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 c3b6a07a36e9..ea2da4974693 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