sw/qa/extras/layout/data/hideSection.fodt | 39 ++++++++++++++++++++++++++++++ sw/qa/extras/layout/layout5.cxx | 24 ++++++++++++++++++ sw/source/core/layout/sectfrm.cxx | 9 ------ sw/source/core/layout/trvlfrm.cxx | 4 ++- 4 files changed, 67 insertions(+), 9 deletions(-)
New commits: commit 4cfd0c99d1bd85a4927cb3b433b903cc26f5ef95 Author: Mike Kaganski <mike.kagan...@collabora.com> AuthorDate: Sat Jun 21 17:25:25 2025 +0500 Commit: Mike Kaganski <mike.kagan...@collabora.com> CommitDate: Sat Jun 21 17:29:36 2025 +0200 tdf#166978: replace HUGE_POSITIVE hack with proper upper invalidation The problem was, that the change of section's height (either to zero when hiding, or from zero to some height when showing) could keep its upper's size unchanged and valid. Invalidating the upper's size in SfxHintId::SwSectionHidden handler was not enough; in the following layout calculation, the upper sets its mbFrameAreaSizeValid to true before its lowers' calculation. Then, during their calculation: * If the section was hiding, SwFrame::MakeValidZeroHeight would fail in ShrinkFrame, then force its height to 0 in 'if (IsLayoutFrame())' block, and not notify upper; * If the section was showing, SwSectionFrame::Grow_ could see that the upper has space enough for the section (e.g., when there are more children after this section), and also not notify upper. The HUGE_POSITIVE hack allowed to force following re-layout in some cases; but the bugdoc failed when the cell was initially made very tall, and hat to split; then the section in it was shrinked to 0,and that didn't cause the merge with the follow. This fixes the problem by: 1. Removing of the HUGE_POSITIVE hack; 2. Invalidating upper cell frame in SwSectionFrame::Grow_, similar to commit ee57229154a91cf632871cfcb1eb9609908f3882 (Fix #88178#: Sectionframe in headerframe, don't grow without invalidation, 2001-06-13); 3. Invalidating layout frame's upper in SwFrame::MakeValidZeroHeight, when ShrinkFrame didn't make it 0-height. In #3, I decided to not check the upper's kind, for robustness; if needed, checks may be added in follow-ups, for specific problems. Change-Id: Iafdd1c41b52d2170d5dd2b3bc2cbc1a5f657c0fb Reviewed-on: https://gerrit.libreoffice.org/c/core/+/186779 Tested-by: Jenkins Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com> diff --git a/sw/qa/extras/layout/data/hideSection.fodt b/sw/qa/extras/layout/data/hideSection.fodt new file mode 100644 index 000000000000..ba953e5103e8 --- /dev/null +++ b/sw/qa/extras/layout/data/hideSection.fodt @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style: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.4" office:mimetype="application/vnd.oasis.opendocument.text"> + <office:automatic-styles> + <style:style style:name="Table1" style:family="table"> + <style:table-properties table:align="margins"/> + </style:style> + <style:style style:name="Table1.A1" style:family="table-cell"> + <style:table-cell-properties fo:border="0.05pt solid #000000"/> + </style:style> + </office:automatic-styles> + <office:body> + <office:text> + <table:table table:name="Table1" table:style-name="Table1"> + <table:table-column/> + <table:table-column/> + <table:table-row> + <table:table-cell table:style-name="Table1.A1" office:value-type="string"> + <text:p>A1</text:p> + </table:table-cell> + <table:table-cell table:style-name="Table1.A1" office:value-type="string"> + <text:section text:name="Section1"> + <text:p>Section1: hide me</text:p> + </text:section> + <text:p>B1</text:p> + </table:table-cell> + </table:table-row> + <table:table-row> + <table:table-cell table:style-name="Table1.A1" office:value-type="string"> + <text:p>A2: this row suddenly jumps to the next page</text:p> + </table:table-cell> + <table:table-cell table:style-name="Table1.A1" office:value-type="string"> + <text:p>B2</text:p> + </table:table-cell> + </table:table-row> + </table:table> + </office:text> + </office:body> +</office:document> \ No newline at end of file diff --git a/sw/qa/extras/layout/layout5.cxx b/sw/qa/extras/layout/layout5.cxx index 075c1a58417d..de3df0d3b1d7 100644 --- a/sw/qa/extras/layout/layout5.cxx +++ b/sw/qa/extras/layout/layout5.cxx @@ -1785,6 +1785,30 @@ CPPUNIT_TEST_FIXTURE(SwLayoutWriter5, testTdf166871) assertXPath(pXmlDoc, "//page[12]/body/column[6]/body/txt", 0); } +CPPUNIT_TEST_FIXTURE(SwLayoutWriter5, testTdf166978) +{ + // Given a document with a table, which cell has a section: + createSwDoc("hideSection.fodt"); + CPPUNIT_ASSERT_EQUAL(1, getPages()); + + // Hide the section + auto xTextSectionsSupplier = mxComponent.queryThrow<css::text::XTextSectionsSupplier>(); + auto xSections = xTextSectionsSupplier->getTextSections(); + CPPUNIT_ASSERT(xSections); + auto xSection = xSections->getByName(u"Section1"_ustr).queryThrow<css::beans::XPropertySet>(); + xSection->setPropertyValue(u"IsVisible"_ustr, css::uno::Any(false)); + Scheduler::ProcessEventsToIdle(); + + CPPUNIT_ASSERT_EQUAL(1, getPages()); // must not split the second row of the table to page 2 + // Check the layout dump; the whole table must be still on the first page + auto pXmlDoc = parseLayoutDump(); + assertXPath(pXmlDoc, "//page", 1); + assertXPath(pXmlDoc, "//page[1]/body/tab", 1); + assertXPath(pXmlDoc, "//page[1]/body/tab/row", 2); + assertXPathContent(pXmlDoc, "//page[1]/body/tab/row[2]/cell[1]", + u"A2: this row suddenly jumps to the next page"); +} + 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 613ac7f9194d..9b11ff0c3e31 100644 --- a/sw/source/core/layout/sectfrm.cxx +++ b/sw/source/core/layout/sectfrm.cxx @@ -2364,7 +2364,7 @@ SwTwips SwSectionFrame::Grow_(SwTwips nDist, SwResizeLimitReason& reason, bool b SetCompletePaint(); InvalidatePage(); } - if( GetUpper() && GetUpper()->IsHeaderFrame() ) + if (GetUpper() && (GetUpper()->IsHeaderFrame() || GetUpper()->IsCellFrame())) GetUpper()->InvalidateSize(); } @@ -2788,13 +2788,6 @@ void SwSectionFrame::SwClientNotify(const SwModify& rMod, const SfxHint& rHint) { InvalidateAll(); InvalidateObjs(false); - { - // Set it to a huge positive value, to make sure a recalculation fires - constexpr SwTwips HUGE_POSITIVE = o3tl::toTwips(100, o3tl::Length::m); - SwFrameAreaDefinition::FrameAreaWriteAccess area(*this); - SwRectFnSet(this).SetHeight(area, HUGE_POSITIVE); - } - GetUpper()->InvalidateSize(); InvalidateFramesInSection(Lower()); if (Lower()) diff --git a/sw/source/core/layout/trvlfrm.cxx b/sw/source/core/layout/trvlfrm.cxx index 5fb7f94b3aaf..86cd2c1c0ca4 100644 --- a/sw/source/core/layout/trvlfrm.cxx +++ b/sw/source/core/layout/trvlfrm.cxx @@ -1745,10 +1745,12 @@ void SwFrame::MakeValidZeroHeight() aRectFnSet.SetHeight(area, 0); } ShrinkFrame(aRectFnSet.GetHeight(getFrameArea())); - if (IsLayoutFrame()) // ShrinkFrame might do nothing! + if (IsLayoutFrame() && aRectFnSet.GetHeight(getFrameArea())) // ShrinkFrame might do nothing! { SwFrameAreaDefinition::FrameAreaWriteAccess area(*this); aRectFnSet.SetHeight(area, 0); + if (GetUpper()) + GetUpper()->InvalidateSize(); } setFrameAreaSizeValid(true); setFramePrintAreaValid(true);