sw/qa/extras/layout/data/C4_must_start_on_p1.fodt | 95 ++++++++ sw/qa/extras/layout/data/tdf162614.fodt | 75 ++++++ sw/qa/extras/layout/layout3.cxx | 120 ++++++++++ sw/source/core/inc/cntfrm.hxx | 3 sw/source/core/inc/flyfrm.hxx | 7 sw/source/core/inc/frame.hxx | 22 + sw/source/core/inc/ftnfrm.hxx | 2 sw/source/core/inc/hffrm.hxx | 2 sw/source/core/inc/layfrm.hxx | 2 sw/source/core/inc/rootfrm.hxx | 2 sw/source/core/inc/rowfrm.hxx | 2 sw/source/core/inc/sectfrm.hxx | 5 sw/source/core/inc/tabfrm.hxx | 2 sw/source/core/inc/txtfrm.hxx | 7 sw/source/core/layout/fly.cxx | 251 +++++++++++----------- sw/source/core/layout/ftnfrm.cxx | 23 +- sw/source/core/layout/hffrm.cxx | 12 - sw/source/core/layout/pagechg.cxx | 4 sw/source/core/layout/sectfrm.cxx | 236 ++++++++++---------- sw/source/core/layout/tabfrm.cxx | 21 - sw/source/core/layout/wsfrm.cxx | 112 +++++---- sw/source/core/text/widorp.cxx | 12 - sw/source/core/text/widorp.hxx | 6 23 files changed, 713 insertions(+), 310 deletions(-)
New commits: commit 60f833b43d33121c31fa263b7d1f2c837472d5cc Author: Mike Kaganski <[email protected]> AuthorDate: Sat Aug 24 23:51:25 2024 +0500 Commit: Mike Kaganski <[email protected]> CommitDate: Fri Nov 29 10:32:17 2024 +0500 tdf#162614: report the reason why a frame couldn't grow ... and use it in SwTextFrameBreak::IsBreakNow to decide if the content needs to go to a follow or not. The problem was, that in a specific case of the bugdoc, the follow text line was taller than the fixed row height on that page; that resulted in an attempt to break it again, creating an empty follow in the same table cell; it was not moved to the next page, detecting the problem in SwTextFrame::CalcFollow, and the formatting looped, until loop control fired, calling SwLooping::Drastic, which validated all page's content, including tables below, that had invalid zero client (prn) height. It was very difficult to tell when the break is needed, and when it's not, without the information why some frame eventually denied growing its height by the requested amount. In the bugdoc case, I failed to find at the SwTextFrameBreak::IsBreakNow level anything that could be used as a reliable distinction; some heuristic conditions used there broke layout in unit tests left and right. So eventually, I came with this mechanism of reporting the "why I can't grow" reason back to the caller, using the new out argument. I believe that, beyond this use case, it might be useful in many other cases, both to ease the decision, and to prevent needless trial-and- error iterations, increasing stability and performance. The enum used for the reason reporting includes 'FlowToFollow' and 'BalancedColumns', that could be used in those other cases. However, for my needs here, I only need the FixedSizeFrame reason, telling that it's not a case when breaking to a next frame is possible, so preventing the break. The choice of reported reasons in this patch is mostly best guess; it may be wrong in some places. The crucial for the current fix is the assignment inside the '!(GetType() & nTmpType) && HasFixSize()' check of SwLayoutFrame::GrowFrame. Change-Id: I9ce5dd4d2298b60e186fdf485efb85ab304308ee Reviewed-on: https://gerrit.libreoffice.org/c/core/+/172362 Reviewed-by: Mike Kaganski <[email protected]> Tested-by: Jenkins diff --git a/sw/qa/extras/layout/data/C4_must_start_on_p1.fodt b/sw/qa/extras/layout/data/C4_must_start_on_p1.fodt new file mode 100644 index 000000000000..067d1515d64a --- /dev/null +++ b/sw/qa/extras/layout/data/C4_must_start_on_p1.fodt @@ -0,0 +1,95 @@ +<?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:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible: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:font-face-decls> + <style:font-face style:name="Liberation Serif" svg:font-family="'Liberation Serif'" style:font-family-generic="roman" style:font-pitch="variable"/> + </office:font-face-decls> + <office:styles> + <style:default-style style:family="paragraph"> + <style:paragraph-properties fo:margin-top="0" fo:margin-bottom="0.3cm" style:contextual-spacing="false" fo:line-height="108%" fo:orphans="2" fo:widows="2"/> + <style:text-properties style:font-name="Liberation Serif" fo:font-size="12pt"/> + </style:default-style> + </office:styles> + <office:automatic-styles> + <style:style style:name="Table1" style:family="table"> + <style:table-properties style:width="8cm" fo:margin-left="0" fo:margin-top="0" fo:margin-bottom="0" table:align="left" style:writing-mode="page"/> + </style:style> + <style:style style:name="Table1.A" style:family="table-column"> + <style:table-column-properties style:column-width="1cm"/> + </style:style> + <style:style style:name="Table1.B" style:family="table-column"> + <style:table-column-properties style:column-width="2cm"/> + </style:style> + <style:style style:name="Table1.C" style:family="table-column"> + <style:table-column-properties style:column-width="5cm"/> + </style:style> + <style:style style:name="Table1.1" style:family="table-row"> + <style:table-row-properties style:min-row-height="1.5cm" fo:keep-together="auto"/> + </style:style> + <style:style style:name="Table1.2" style:family="table-row"> + <style:table-row-properties style:min-row-height="0.5cm" fo:keep-together="auto"/> + </style:style> + <style:style style:name="Table1.4" style:family="table-row"> + <style:table-row-properties style:min-row-height="1cm" fo:keep-together="auto"/> + </style:style> + <style:style style:name="P1" style:family="paragraph" style:parent-style-name="Standard"> + <style:paragraph-properties fo:margin-top="0" fo:margin-bottom="0" fo:line-height="100%"/> + </style:style> + <style:page-layout style:name="pm1"> + <style:page-layout-properties fo:page-width="8cm" fo:page-height="5cm" fo:margin-top="0" fo:margin-bottom="0" fo:margin-left="0" fo:margin-right="0"/> + </style:page-layout> + </office:automatic-styles> + <office:master-styles> + <style:master-page style:name="Standard" style:page-layout-name="pm1"/> + </office:master-styles> + <office:body> + <office:text> + <text:p text:style-name="P1"/> + <table:table table:name="Table1" table:style-name="Table1"> + <table:table-column table:style-name="Table1.A"/> + <table:table-column table:style-name="Table1.B"/> + <table:table-column table:style-name="Table1.C"/> + <table:table-header-rows> + <table:table-row table:style-name="Table1.1"> + <table:table-cell> + <text:p>A1</text:p> + </table:table-cell> + <table:table-cell> + <text:p>B1</text:p> + </table:table-cell> + <table:table-cell> + <text:p>C1_repeated_header</text:p> + </table:table-cell> + </table:table-row> + </table:table-header-rows> + <table:table-row table:style-name="Table1.2"> + <table:table-cell table:number-columns-spanned="3"> + <text:p>A2</text:p> + </table:table-cell> + <table:covered-table-cell/> + <table:covered-table-cell/> + </table:table-row> + <table:table-row table:style-name="Table1.2"> + <table:table-cell> + <text:p>A3</text:p> + </table:table-cell> + <table:table-cell table:number-rows-spanned="3"> + <text:p>B3</text:p> + </table:table-cell> + <table:table-cell> + <text:p>C3_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx</text:p> + </table:table-cell> + </table:table-row> + <table:table-row table:style-name="Table1.4"> + <table:table-cell> + <text:p>A4</text:p> + </table:table-cell> + <table:covered-table-cell/> + <table:table-cell> + <text:p>C4_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx</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/data/tdf162614.fodt b/sw/qa/extras/layout/data/tdf162614.fodt new file mode 100644 index 000000000000..f2e170a73c70 --- /dev/null +++ b/sw/qa/extras/layout/data/tdf162614.fodt @@ -0,0 +1,75 @@ +<?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:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible: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:font-face-decls> + <style:font-face style:name="Liberation Serif" svg:font-family="'Liberation Serif'" style:font-family-generic="roman" style:font-pitch="variable"/> + </office:font-face-decls> + <office:styles> + <style:default-style style:family="paragraph"> + <style:paragraph-properties fo:margin-bottom="4mm"/> + <style:text-properties style:font-name="Liberation Serif" fo:font-size="12pt" fo:language="en" fo:country="US"/> + </style:default-style> + </office:styles> + <office:automatic-styles> + <style:style style:name="Table2.1" style:family="table-row"> + <style:table-row-properties style:min-row-height="8mm" fo:keep-together="always"/> + </style:style> + <style:style style:name="Table2.2" style:family="table-row"> + <style:table-row-properties style:row-height="8mm" fo:keep-together="always"/> + </style:style> + <style:style style:name="A1" style:family="table-cell"> + <style:table-cell-properties fo:border="1pt solid"/> + </style:style> + <style:style style:name="P1" style:family="paragraph" style:parent-style-name="Standard"> + <style:paragraph-properties fo:margin-top="3cm"/> + </style:style> + <style:style style:name="P2" style:family="paragraph" style:parent-style-name="Standard"> + <style:paragraph-properties fo:keep-together="always"/> + </style:style> + <style:page-layout style:name="pm1"> + <style:page-layout-properties fo:page-width="9cm" fo:page-height="5cm" fo:margin-top="0" fo:margin-bottom="0"/> + </style:page-layout> + </office:automatic-styles> + <office:master-styles> + <style:master-page style:name="Standard" style:page-layout-name="pm1"/> + </office:master-styles> + <office:body> + <office:text> + <text:p text:style-name="P1">Table1 with Table2:</text:p> + <table:table table:name="Table1"> + <table:table-column/> + <table:table-row> + <table:table-cell table:style-name="A1"> + <table:table table:name="Table2"> + <table:table-column table:number-columns-repeated="2"/> + <table:table-row table:style-name="Table2.1"> + <table:table-cell table:style-name="A1"> + <text:p>Table2.A1</text:p> + </table:table-cell> + <table:table-cell table:style-name="A1" table:number-rows-spanned="2"> + <text:p text:style-name="P2">Table2.B1 <text:s text:c="99"/>(contd.)</text:p> + </table:table-cell> + </table:table-row> + <table:table-row table:style-name="Table2.2"> + <table:table-cell table:style-name="A1"> + <text:p>Table2.A2</text:p> + </table:table-cell> + <table:covered-table-cell/> + </table:table-row> + </table:table> + </table:table-cell> + </table:table-row> + </table:table> + <text:p>Press ENTER here</text:p> + <text:p>Below is Table3:</text:p> + <table:table table:name="Table3"> + <table:table-column/> + <table:table-row> + <table:table-cell table:style-name="A1"> + <text:p>This text was hidden.</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/layout3.cxx b/sw/qa/extras/layout/layout3.cxx index 70debda65dd2..0aefb9757b93 100644 --- a/sw/qa/extras/layout/layout3.cxx +++ b/sw/qa/extras/layout/layout3.cxx @@ -1909,6 +1909,126 @@ CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, TestTdf161508) assertXPath(pExportDump, "//page[2]/body/tab", 1); } +CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, TestTdf162614) +{ + // Given a table inside another table, having a fixed-height last row, with a merged cell + // spanning two rows, with a text (having a spacing below) wrapping inside that merged cell, + // positioned so that the first line of the text in on the first page, and the second line + // flows onto the second page: + createSwDoc("tdf162614.fodt"); + auto pXmlDoc = parseLayoutDump(); + + // Make sure that all the tables have the correct positions and sizes + // I find the clang-formatted version of the following awful (it is already ugly enough) + // clang-format off + + assertXPath(pXmlDoc, "//page", 2); + // One top-level table on page 1 (Table1), with a single row and a single cell + assertXPath(pXmlDoc, "//page[1]/body/tab", 1); + OUString sTable1PrecedeId = getXPath(pXmlDoc, "//page[1]/body/tab", "id"); + OUString sTable1FollowId = getXPath(pXmlDoc, "//page[1]/body/tab", "follow"); + assertXPath(pXmlDoc, "//page[1]/body/tab/infos/bounds", "top", "2261"); + assertXPath(pXmlDoc, "//page[1]/body/tab/infos/bounds", "height", "810"); + assertXPath(pXmlDoc, "//page[1]/body/tab/row", 1); + assertXPath(pXmlDoc, "//page[1]/body/tab/row/cell", 1); + OUString sTable1A1PrecedeId = getXPath(pXmlDoc, "//page[1]/body/tab/row/cell", "id"); + OUString sTable1A1FollowId = getXPath(pXmlDoc, "//page[1]/body/tab/row/cell", "follow"); + // One sub-table inside it (Table2): + assertXPath(pXmlDoc, "//page[1]/body/tab/row/cell/tab", 1); + OUString sTable2PrecedeId = getXPath(pXmlDoc, "//page[1]/body/tab/row/cell/tab", "id"); + OUString sTable2FollowId = getXPath(pXmlDoc, "//page[1]/body/tab/row/cell/tab", "follow"); + assertXPath(pXmlDoc, "//page[1]/body/tab/row/cell/tab/infos/bounds", "top", u"2508"); + assertXPath(pXmlDoc, "//page[1]/body/tab/row/cell/tab/infos/bounds", "height", u"543"); + assertXPath(pXmlDoc, "//page[1]/body/tab/row/cell/tab/row", 1); + assertXPath(pXmlDoc, "//page[1]/body/tab/row/cell/tab/row/cell", 2); + // A1 + assertXPathNoAttribute(pXmlDoc, "//page[1]/body/tab/row/cell/tab/row/cell[1]", "follow"); + assertXPath(pXmlDoc, "//page[1]/body/tab/row/cell/tab/row/cell[1]", "rowspan", u"1"); + assertXPath(pXmlDoc, "//page[1]/body/tab/row/cell/tab/row/cell[1]/txt/SwParaPortion/SwLineLayout/*", 1); + assertXPath(pXmlDoc, "//page[1]/body/tab/row/cell/tab/row/cell[1]/txt/SwParaPortion/SwLineLayout/*[1]", "type", "PortionType::Para"); + assertXPath(pXmlDoc, "//page[1]/body/tab/row/cell/tab/row/cell[1]/txt/SwParaPortion/SwLineLayout/*[1]", "portion", "Table2.A1"); + // B1 + OUString sTable2B1PrecedeId = getXPath(pXmlDoc, "//page[1]/body/tab/row/cell/tab/row/cell[2]", "id"); + OUString sTable2B1FollowId = getXPath(pXmlDoc, "//page[1]/body/tab/row/cell/tab/row/cell[2]", "follow"); + assertXPath(pXmlDoc, "//page[1]/body/tab/row/cell/tab/row/cell[2]", "rowspan", "2"); + assertXPath(pXmlDoc, "//page[1]/body/tab/row/cell/tab/row/cell[2]/infos/bounds", "height", "523"); + assertXPath(pXmlDoc, "//page[1]/body/tab/row/cell/tab/row/cell[2]/infos/prtBounds", "height", "503"); + OUString sTable2B1TextPrecedeId = getXPath(pXmlDoc, "//page[1]/body/tab/row/cell/tab/row/cell[2]/txt", "id"); + OUString sTable2B1TextFollowId = getXPath(pXmlDoc, "//page[1]/body/tab/row/cell/tab/row/cell[2]/txt", "follow"); + assertXPath(pXmlDoc, "//page[1]/body/tab/row/cell/tab/row/cell[2]/txt/infos/bounds", "height", "276"); + assertXPath(pXmlDoc, "//page[1]/body/tab/row/cell/tab/row/cell[2]/txt/infos/prtBounds", "height", "276"); + assertXPath(pXmlDoc, "//page[1]/body/tab/row/cell/tab/row/cell[2]/txt/SwParaPortion/SwLineLayout/*", 2); + assertXPath(pXmlDoc, "//page[1]/body/tab/row/cell/tab/row/cell[2]/txt/SwParaPortion/SwLineLayout/*[1]", "type", "PortionType::Text"); + assertXPath(pXmlDoc, "//page[1]/body/tab/row/cell/tab/row/cell[2]/txt/SwParaPortion/SwLineLayout/*[1]", "portion", "Table2.B1 "); + assertXPath(pXmlDoc, "//page[1]/body/tab/row/cell/tab/row/cell[2]/txt/SwParaPortion/SwLineLayout/*[2]", "type", "PortionType::Hole"); + + // Two top-level tables on page 2 + assertXPath(pXmlDoc, "//page[2]/body/tab", 2); + // Table1 (follow) + CPPUNIT_ASSERT_EQUAL(sTable1FollowId, getXPath(pXmlDoc, "//page[2]/body/tab[1]", "id")); + CPPUNIT_ASSERT_EQUAL(sTable1PrecedeId, getXPath(pXmlDoc, "//page[2]/body/tab[1]", "precede")); + assertXPath(pXmlDoc, "//page[2]/body/tab[1]/infos/bounds", "top", "3403"); + assertXPath(pXmlDoc, "//page[2]/body/tab[1]/infos/bounds", "height", "514"); + assertXPath(pXmlDoc, "//page[2]/body/tab[1]/row", 1); + assertXPath(pXmlDoc, "//page[2]/body/tab[1]/row/cell", 1); + CPPUNIT_ASSERT_EQUAL(sTable1A1FollowId, getXPath(pXmlDoc, "//page[2]/body/tab[1]/row/cell", "id")); + CPPUNIT_ASSERT_EQUAL(sTable1A1PrecedeId, getXPath(pXmlDoc, "//page[2]/body/tab[1]/row/cell", "precede")); + // Table2 (follow) + assertXPath(pXmlDoc, "//page[2]/body/tab[1]/row/cell/tab", 1); + CPPUNIT_ASSERT_EQUAL(sTable2FollowId, getXPath(pXmlDoc, "//page[2]/body/tab[1]/row/cell/tab", "id")); + CPPUNIT_ASSERT_EQUAL(sTable2PrecedeId, getXPath(pXmlDoc, "//page[2]/body/tab[1]/row/cell/tab", "precede")); + assertXPath(pXmlDoc, "//page[2]/body/tab[1]/row/cell/tab/infos/bounds", "top", "3423"); + assertXPath(pXmlDoc, "//page[2]/body/tab[1]/row/cell/tab/infos/bounds", "height", "474"); + assertXPath(pXmlDoc, "//page[2]/body/tab[1]/row/cell/tab/row", 2); + // Table2 row 1 (continued) + assertXPath(pXmlDoc, "//page[2]/body/tab[1]/row/cell/tab/row[1]/cell", 2); + // Placeholder for the cell in column 1 + assertXPath(pXmlDoc, "//page[2]/body/tab[1]/row/cell/tab/row[1]/cell[1]/infos/bounds", "height", "0"); + // B1 (follow) + CPPUNIT_ASSERT_EQUAL(sTable2B1FollowId, getXPath(pXmlDoc, "//page[2]/body/tab[1]/row/cell/tab/row[1]/cell[2]", "id")); + CPPUNIT_ASSERT_EQUAL(sTable2B1PrecedeId, getXPath(pXmlDoc, "//page[2]/body/tab[1]/row/cell/tab/row[1]/cell[2]", "precede")); + assertXPath(pXmlDoc, "//page[2]/body/tab[1]/row/cell/tab/row[1]/cell[2]", "rowspan", "2"); + // Without the fix, this failed with + // - Expected: 1 + // - Actual : 2 + // - In <>, XPath '//page[2]/body/tab[1]/row/cell/tab/row[1]/cell[2]/txt' number of nodes is incorrect + CPPUNIT_ASSERT_EQUAL(sTable2B1TextFollowId, getXPath(pXmlDoc, "//page[2]/body/tab[1]/row/cell/tab/row[1]/cell[2]/txt", "id")); + CPPUNIT_ASSERT_EQUAL(sTable2B1TextPrecedeId, getXPath(pXmlDoc, "//page[2]/body/tab[1]/row/cell/tab/row[1]/cell[2]/txt", "precede")); + assertXPath(pXmlDoc, "//page[2]/body/tab[1]/row/cell/tab/row[1]/cell[2]/txt/SwParaPortion/SwLineLayout/*", 1); + assertXPath(pXmlDoc, "//page[2]/body/tab[1]/row/cell/tab/row[1]/cell[2]/txt/SwParaPortion/SwLineLayout/*[1]", "type", "PortionType::Para"); + assertXPath(pXmlDoc, "//page[2]/body/tab[1]/row/cell/tab/row[1]/cell[2]/txt/SwParaPortion/SwLineLayout/*[1]", "portion", "(contd.)"); + // Table2 row 2 + assertXPath(pXmlDoc, "//page[2]/body/tab[1]/row/cell/tab/row[2]/cell", 2); + // A2 + assertXPath(pXmlDoc, "//page[2]/body/tab[1]/row/cell/tab/row[2]/cell[1]/txt/SwParaPortion/SwLineLayout/*", 1); + assertXPath(pXmlDoc, "//page[2]/body/tab[1]/row/cell/tab/row[2]/cell[1]/txt/SwParaPortion/SwLineLayout/*[1]", "type", "PortionType::Para"); + assertXPath(pXmlDoc, "//page[2]/body/tab[1]/row/cell/tab/row[2]/cell[1]/txt/SwParaPortion/SwLineLayout/*[1]", "portion", "Table2.A2"); + // B2 (covered cell) + assertXPath(pXmlDoc, "//page[2]/body/tab[1]/row/cell/tab/row[2]/cell[2]", "rowspan", "-1"); + + // Table3 (must not be collapsed) + assertXPath(pXmlDoc, "//page[2]/body/tab[2]/infos/bounds", "top", "4696"); + // Without the fix, this failed with + // - Expected: 770 + // - Actual : 267 + assertXPath(pXmlDoc, "//page[2]/body/tab[2]/infos/bounds", "height", "770"); + + // Now a test for a case that took me some time to fix when creating the patch. + // It is the greatly simplified tdf124795-5. + + createSwDoc("C4_must_start_on_p1.fodt"); + pXmlDoc = parseLayoutDump(); + + // The first line of C4 text must start on the first page - the initial version of the fix + // moved it to page 2. + + assertXPath(pXmlDoc, "//page[1]/body/tab/row[4]/cell[3]/txt/SwParaPortion/SwLineLayout/*", 1); + assertXPath(pXmlDoc, "//page[1]/body/tab/row[4]/cell[3]/txt/SwParaPortion/SwLineLayout/*[1]", "type", "PortionType::Para"); + assertXPath(pXmlDoc, "//page[1]/body/tab/row[4]/cell[3]/txt/SwParaPortion/SwLineLayout/*[1]", "portion", "C4_xxxxxxxxxxxxxxxxxxxx"); + + // clang-format on +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/inc/cntfrm.hxx b/sw/source/core/inc/cntfrm.hxx index 2f6c8b5ba3e4..67cfe38c4d9b 100644 --- a/sw/source/core/inc/cntfrm.hxx +++ b/sw/source/core/inc/cntfrm.hxx @@ -80,7 +80,8 @@ protected: virtual void SwClientNotify(const SwModify&, const SfxHint&) override; virtual SwTwips ShrinkFrame( SwTwips, bool bTst = false, bool bInfo = false ) override; - virtual SwTwips GrowFrame ( SwTwips, bool bTst = false, bool bInfo = false ) override; + using SwFrame::GrowFrame; + virtual SwTwips GrowFrame(SwTwips, SwResizeLimitReason&, bool bTst, bool bInfo) override; SwContentFrame( SwContentNode * const, SwFrame* ); diff --git a/sw/source/core/inc/flyfrm.hxx b/sw/source/core/inc/flyfrm.hxx index 0882f926c50e..2732016b316a 100644 --- a/sw/source/core/inc/flyfrm.hxx +++ b/sw/source/core/inc/flyfrm.hxx @@ -188,6 +188,7 @@ public: SwTwips Shrink_( SwTwips, bool bTst ); SwTwips Grow_ ( SwTwips, bool bTst ); + SwTwips Grow_(SwTwips, SwResizeLimitReason&, bool bTst); void Invalidate_( SwPageFrame const *pPage = nullptr ); bool FrameSizeChg( const SwFormatFrameSize & ); @@ -314,6 +315,12 @@ private: void UpdateUnfloatButton(SwWrtShell* pWrtSh, bool bShow) const; void PaintDecorators() const; }; + +inline SwTwips SwFlyFrame::Grow_(SwTwips nDist, bool bTst) +{ + return Grow_(nDist, o3tl::temporary(SwResizeLimitReason()), bTst); +} + #endif /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/inc/frame.hxx b/sw/source/core/inc/frame.hxx index 885a0d223f24..a73e20b733d6 100644 --- a/sw/source/core/inc/frame.hxx +++ b/sw/source/core/inc/frame.hxx @@ -27,6 +27,7 @@ #include <swrect.hxx> #include <calbck.hxx> #include <svl/SfxBroadcaster.hxx> +#include <o3tl/temporary.hxx> #include <o3tl/typed_flags_set.hxx> #include <com/sun/star/style/TabStop.hpp> #include <basegfx/matrix/b2dhommatrix.hxx> @@ -304,6 +305,15 @@ namespace o3tl { template<> struct typed_flags<SwFrameInvFlags> : is_typed_flags<SwFrameInvFlags, 0x003f> {}; } +// Possible reasons why SwFrame::Grow[Frame] failed to provide the requested growth +enum class SwResizeLimitReason +{ + Unspecified, // no specific reason + FixedSizeFrame, // e.g., fixed-height table row; children must be clipped + FlowToFollow, // content must flow to a follow; includes next page, column, linked frames + BalancedColumns, // resize is performed by Format*, not by Grow* +}; + /** * Base class of the Writer layout elements. * @@ -471,7 +481,8 @@ protected: // change only frame size not the size of PrtArea virtual SwTwips ShrinkFrame( SwTwips, bool bTst = false, bool bInfo = false ) = 0; - virtual SwTwips GrowFrame ( SwTwips, bool bTst = false, bool bInfo = false ) = 0; + virtual SwTwips GrowFrame(SwTwips, SwResizeLimitReason&, bool bTst, bool bInfo) = 0; + SwTwips GrowFrame(SwTwips, bool bTst = false, bool bInfo = false); /// use these so we can grep for SwFrame's GetRegisteredIn accesses /// beware that SwTextFrame may return sw::WriterMultiListener @@ -527,6 +538,7 @@ public: // change PrtArea size and FrameSize SwTwips Shrink( SwTwips, bool bTst = false, bool bInfo = false ); SwTwips Grow ( SwTwips, bool bTst = false, bool bInfo = false ); + SwTwips Grow(SwTwips nDist, SwResizeLimitReason&, bool bTst, bool bInfo); // different methods for inserting in layout tree (for performance reasons) @@ -1259,6 +1271,14 @@ inline bool SwFrame::IsAccessibleFrame() const { return bool(GetType() & FRM_ACCESSIBLE); } +inline SwTwips SwFrame::Grow(SwTwips nDist, bool bTst, bool bInfo) +{ + return Grow(nDist, o3tl::temporary(SwResizeLimitReason()), bTst, bInfo); +} +inline SwTwips SwFrame::GrowFrame(SwTwips nDist, bool bTst, bool bInfo) +{ + return GrowFrame(nDist, o3tl::temporary(SwResizeLimitReason()), bTst, bInfo); +} //use this to protect a SwFrame for a given scope from getting deleted class SwFrameDeleteGuard diff --git a/sw/source/core/inc/ftnfrm.hxx b/sw/source/core/inc/ftnfrm.hxx index 89d9f34f863a..22baad098a1b 100644 --- a/sw/source/core/inc/ftnfrm.hxx +++ b/sw/source/core/inc/ftnfrm.hxx @@ -56,7 +56,7 @@ public: static inline SwFootnoteFrame* PrependChained(SwFrame* pThis, bool bDefaultFormat); virtual SwTwips ShrinkFrame( SwTwips, bool bTst = false, bool bInfo = false ) override; - virtual SwTwips GrowFrame ( SwTwips, bool bTst = false, bool bInfo = false ) override; + virtual SwTwips GrowFrame(SwTwips, SwResizeLimitReason&, bool bTst, bool bInfo) override; virtual void Format( vcl::RenderContext* pRenderContext, const SwBorderAttrs *pAttrs = nullptr ) override; virtual void PaintSwFrameShadowAndBorder( const SwRect&, diff --git a/sw/source/core/inc/hffrm.hxx b/sw/source/core/inc/hffrm.hxx index 32af4dab9e30..0378d74fb797 100644 --- a/sw/source/core/inc/hffrm.hxx +++ b/sw/source/core/inc/hffrm.hxx @@ -33,7 +33,7 @@ public: SwHeadFootFrame(SwFrameFormat * pFrame, SwFrame*, SwFrameType aType); virtual void Format( vcl::RenderContext* pRenderContext, const SwBorderAttrs *pAttrs = nullptr ) override; virtual SwTwips GrowFrame( SwTwips, - bool bTst = false, bool bInfo = false ) override; + SwResizeLimitReason&, bool bTst, bool bInfo ) override; virtual SwTwips ShrinkFrame( SwTwips, bool bTst = false, bool bInfo = false ) override; virtual void PaintSubsidiaryLines( const SwPageFrame*, const SwRect& ) const override; diff --git a/sw/source/core/inc/layfrm.hxx b/sw/source/core/inc/layfrm.hxx index b0f981477499..dffe54d5f87d 100644 --- a/sw/source/core/inc/layfrm.hxx +++ b/sw/source/core/inc/layfrm.hxx @@ -54,7 +54,7 @@ protected: std::vector<SwAnchoredObject*> m_VertPosOrientFramesFor; virtual SwTwips ShrinkFrame( SwTwips, bool bTst = false, bool bInfo = false ) override; - virtual SwTwips GrowFrame ( SwTwips, bool bTst = false, bool bInfo = false ) override; + virtual SwTwips GrowFrame(SwTwips, SwResizeLimitReason&, bool bTst, bool bInfo) override; tools::Long CalcRel( const SwFormatFrameSize &rSz ) const; diff --git a/sw/source/core/inc/rootfrm.hxx b/sw/source/core/inc/rootfrm.hxx index 90d18fcf0ee4..0344baf8f321 100644 --- a/sw/source/core/inc/rootfrm.hxx +++ b/sw/source/core/inc/rootfrm.hxx @@ -243,7 +243,7 @@ public: virtual void PaintSwFrame( vcl::RenderContext& rRenderContext, SwRect const&, SwPrintData const*const pPrintData = nullptr ) const override; virtual SwTwips ShrinkFrame( SwTwips, bool bTst = false, bool bInfo = false ) override; - virtual SwTwips GrowFrame ( SwTwips, bool bTst = false, bool bInfo = false ) override; + virtual SwTwips GrowFrame(SwTwips, SwResizeLimitReason&, bool bTst, bool bInfo) override; #ifdef DBG_UTIL virtual void Cut() override; virtual void Paste( SwFrame* pParent, SwFrame* pSibling = nullptr ) override; diff --git a/sw/source/core/inc/rowfrm.hxx b/sw/source/core/inc/rowfrm.hxx index a48dacf6a37e..ea9e309679f9 100644 --- a/sw/source/core/inc/rowfrm.hxx +++ b/sw/source/core/inc/rowfrm.hxx @@ -31,7 +31,7 @@ class SwRowFrame final : public SwLayoutFrame const SwBorderAttrs* pAttrs = nullptr) override; /// Only change the Frame size, not the PrtArea SSize virtual SwTwips ShrinkFrame(SwTwips, bool bTst = false, bool bInfo = false) override; - virtual SwTwips GrowFrame(SwTwips, bool bTst = false, bool bInfo = false) override; + virtual SwTwips GrowFrame(SwTwips, SwResizeLimitReason&, bool bTst, bool bInfo) override; const SwTableLine* m_pTabLine; SwRowFrame* m_pFollowRow; ///< note: this is *only* set on old-style tables! diff --git a/sw/source/core/inc/sectfrm.hxx b/sw/source/core/inc/sectfrm.hxx index 80d8185bc1c0..710d8348d6ad 100644 --- a/sw/source/core/inc/sectfrm.hxx +++ b/sw/source/core/inc/sectfrm.hxx @@ -115,6 +115,7 @@ public: bool Growable() const; SwTwips Shrink_( SwTwips, bool bTst ); SwTwips Grow_ ( SwTwips, bool bTst ); + SwTwips Grow_(SwTwips, SwResizeLimitReason&, bool bTst); /** * A sectionfrm has to maximize, if he has a follow or a ftncontainer at @@ -183,6 +184,10 @@ inline const SwContentFrame *SwSectionFrame::FindLastContent() const { return const_cast<SwSectionFrame*>(this)->FindLastContent(); } +inline SwTwips SwSectionFrame::Grow_(SwTwips nDist, bool bTst) +{ + return Grow_(nDist, o3tl::temporary(SwResizeLimitReason()), bTst); +} #endif // INCLUDED_SW_SOURCE_CORE_INC_SECTFRM_HXX diff --git a/sw/source/core/inc/tabfrm.hxx b/sw/source/core/inc/tabfrm.hxx index 4eba886c2385..73e084b3f588 100644 --- a/sw/source/core/inc/tabfrm.hxx +++ b/sw/source/core/inc/tabfrm.hxx @@ -128,7 +128,7 @@ class SW_DLLPUBLIC SwTabFrame final: public SwLayoutFrame, public SwFlowFrame virtual void Format( vcl::RenderContext* pRenderContext, const SwBorderAttrs *pAttrs = nullptr ) override; virtual void SwClientNotify(const SwModify&, const SfxHint&) override; // only changes the Framesize, not the PrtArea size - virtual SwTwips GrowFrame ( SwTwips, bool bTst = false, bool bInfo = false ) override; + virtual SwTwips GrowFrame(SwTwips, SwResizeLimitReason&, bool bTst, bool bInfo) override; virtual const SwTabFrame* DynCastTabFrame() const override { return this; } public: diff --git a/sw/source/core/inc/txtfrm.hxx b/sw/source/core/inc/txtfrm.hxx index 6deba9f6104f..257e767dfa28 100644 --- a/sw/source/core/inc/txtfrm.hxx +++ b/sw/source/core/inc/txtfrm.hxx @@ -512,6 +512,7 @@ public: /// Test grow inline SwTwips GrowTst( const SwTwips nGrow ); + inline SwTwips GrowTst( const SwTwips nGrow, SwResizeLimitReason& ); SwParaPortion *GetPara(); inline const SwParaPortion *GetPara() const; @@ -855,7 +856,11 @@ inline bool SwTextFrame::HasPara() const inline SwTwips SwTextFrame::GrowTst( const SwTwips nGrow ) { - return Grow( nGrow, true ); + return GrowTst(nGrow, o3tl::temporary(SwResizeLimitReason())); +} +inline SwTwips SwTextFrame::GrowTst(const SwTwips nGrow, SwResizeLimitReason& reason) +{ + return Grow(nGrow, reason, true, false); } inline bool SwTextFrame::IsInside(TextFrameIndex const nPos) const diff --git a/sw/source/core/layout/fly.cxx b/sw/source/core/layout/fly.cxx index 0f51fd0e1bd8..cab9151916f3 100644 --- a/sw/source/core/layout/fly.cxx +++ b/sw/source/core/layout/fly.cxx @@ -2146,10 +2146,22 @@ SwFlyAtContentFrame* SwFlyFrame::DynCastFlyAtContentFrame() return IsFlyAtContentFrame() ? static_cast<SwFlyAtContentFrame*>(this) : nullptr; } -SwTwips SwFlyFrame::Grow_( SwTwips nDist, bool bTst ) +SwTwips SwFlyFrame::Grow_(SwTwips nDist, SwResizeLimitReason& reason, bool bTst) { - if (!Lower() || IsColLocked() || HasFixSize()) + if (!Lower()) + { + reason = SwResizeLimitReason::Unspecified; // refusing because we have no content? + return 0; + } + if (IsColLocked() || HasFixSize()) + { + if (nDist <= 0 || !HasFixSize()) + reason = SwResizeLimitReason::Unspecified; + else + reason = GetNextLink() ? SwResizeLimitReason::FlowToFollow + : SwResizeLimitReason::FixedSizeFrame; return 0; + } SwRectFnSet aRectFnSet(this); SwTwips nSize = aRectFnSet.GetHeight(getFrameArea()); @@ -2157,7 +2169,10 @@ SwTwips SwFlyFrame::Grow_( SwTwips nDist, bool bTst ) nDist = LONG_MAX - nSize; if ( nDist <= 0 ) + { + reason = SwResizeLimitReason::Unspecified; return 0; + } if ( Lower()->IsColumnFrame() ) { // If it's a Column Frame, the Format takes control of the @@ -2169,9 +2184,12 @@ SwTwips SwFlyFrame::Grow_( SwTwips nDist, bool bTst ) InvalidatePos_(); InvalidateSize(); } + reason = SwResizeLimitReason::BalancedColumns; return 0; } + reason = SwResizeLimitReason::Unspecified; + if (bTst) { // We're in test mode. Don't promise infinite growth for split flys, rather limit the diff --git a/sw/source/core/layout/ftnfrm.cxx b/sw/source/core/layout/ftnfrm.cxx index 00c5db65a27d..d8d914ce8124 100644 --- a/sw/source/core/layout/ftnfrm.cxx +++ b/sw/source/core/layout/ftnfrm.cxx @@ -318,13 +318,16 @@ void SwFootnoteContFrame::Format( vcl::RenderContext* /*pRenderContext*/, const setFrameAreaSizeValid(true); } -SwTwips SwFootnoteContFrame::GrowFrame( SwTwips nDist, bool bTst, bool ) +SwTwips SwFootnoteContFrame::GrowFrame(SwTwips nDist, SwResizeLimitReason& reason, bool bTst, bool) { // No check if FixSize since FootnoteContainer are variable up to their max. height. // If the max. height is LONG_MAX, take as much space as needed. // If the page is a special footnote page, take also as much as possible. assert(GetUpper() && GetUpper()->IsFootnoteBossFrame()); + const auto nOrigDist = std::max(nDist, SwTwips(0)); + reason = SwResizeLimitReason::Unspecified; + SwRectFnSet aRectFnSet(this); if( aRectFnSet.GetHeight(getFrameArea()) > 0 && nDist > ( LONG_MAX - aRectFnSet.GetHeight(getFrameArea()) ) ) @@ -341,6 +344,8 @@ SwTwips SwFootnoteContFrame::GrowFrame( SwTwips nDist, bool bTst, bool ) pSect->ToMaximize( false ) && pSect->Growable() ) { pSect->InvalidateSize(); + if (nOrigDist) + reason = SwResizeLimitReason::FlowToFollow; return 0; } } @@ -354,21 +359,33 @@ SwTwips SwFootnoteContFrame::GrowFrame( SwTwips nDist, bool bTst, bool ) nDist = std::min( nDist, SwTwips(pBoss->GetMaxFootnoteHeight() - aRectFnSet.GetHeight(getFrameArea())) ); if ( nDist <= 0 ) + { + if (nOrigDist) + reason = SwResizeLimitReason::FlowToFollow; return 0; + } } // FootnoteBoss also influences the max value if( !IsInSct() ) { const SwTwips nMax = pBoss->GetVarSpace(); if ( nDist > nMax ) + { nDist = nMax; + if (nOrigDist) + reason = SwResizeLimitReason::FlowToFollow; + } if ( nDist <= 0 ) return 0; } } else if( nDist > aRectFnSet.GetHeight(GetPrev()->getFrameArea()) ) + { // do not use more space than the body has nDist = aRectFnSet.GetHeight(GetPrev()->getFrameArea()); + if (nOrigDist) + reason = SwResizeLimitReason::FlowToFollow; + } tools::Long nAvail = 0; if ( bBrowseMode ) @@ -416,7 +433,7 @@ SwTwips SwFootnoteContFrame::GrowFrame( SwTwips nDist, bool bTst, bool ) } } } - nReal += pBoss->Grow( nGrow - nReal, bTst ); + nReal += pBoss->Grow(nGrow - nReal, reason, bTst, false); if( ( SwNeighbourAdjust::GrowAdjust == nAdjust || SwNeighbourAdjust::AdjustGrow == nAdjust ) && nReal < nGrow ) nReal += AdjustNeighbourhood( nGrow - nReal, bTst ); @@ -449,6 +466,8 @@ SwTwips SwFootnoteContFrame::GrowFrame( SwTwips nDist, bool bTst, bool ) InvalidatePage( pPage ); } } + if (nOrigDist > nReal && reason == SwResizeLimitReason::Unspecified) + reason = SwResizeLimitReason::FlowToFollow; return nReal; } diff --git a/sw/source/core/layout/hffrm.cxx b/sw/source/core/layout/hffrm.cxx index e15b308176df..2ac856b66696 100644 --- a/sw/source/core/layout/hffrm.cxx +++ b/sw/source/core/layout/hffrm.cxx @@ -437,17 +437,18 @@ void SwHeadFootFrame::Format(vcl::RenderContext* pRenderContext, const SwBorderA } } -SwTwips SwHeadFootFrame::GrowFrame( SwTwips nDist, bool bTst, bool bInfo ) +SwTwips SwHeadFootFrame::GrowFrame( SwTwips nDist, SwResizeLimitReason& reason, bool bTst, bool bInfo ) { SwTwips nResult; if ( IsColLocked() ) { nResult = 0; + reason = SwResizeLimitReason::Unspecified; } else if (!GetEatSpacing()) { - nResult = SwLayoutFrame::GrowFrame(nDist, bTst, bInfo); + nResult = SwLayoutFrame::GrowFrame(nDist, reason, bTst, bInfo); } else { @@ -514,15 +515,16 @@ SwTwips SwHeadFootFrame::GrowFrame( SwTwips nDist, bool bTst, bool bInfo ) if (nDist - nEat > 0) { - const SwTwips nFrameGrow = - SwLayoutFrame::GrowFrame( nDist - nEat, bTst, bInfo ); + const SwTwips nFrameGrow = SwLayoutFrame::GrowFrame(nDist - nEat, reason, bTst, bInfo); nResult += nFrameGrow; - if ( nFrameGrow > 0 ) + if (nFrameGrow > 0) { bNotifyFlys = false; } } + else + reason = SwResizeLimitReason::Unspecified; // notify fly frames, if necessary and triggered. if ( ( nResult > 0 ) && bNotifyFlys ) diff --git a/sw/source/core/layout/pagechg.cxx b/sw/source/core/layout/pagechg.cxx index 2388b5acc65a..79c04cc4a9ff 100644 --- a/sw/source/core/layout/pagechg.cxx +++ b/sw/source/core/layout/pagechg.cxx @@ -1478,14 +1478,14 @@ sw::sidebarwindows::SidebarPosition SwPageFrame::SidebarPosition() const } } -SwTwips SwRootFrame::GrowFrame( SwTwips nDist, bool bTst, bool ) +SwTwips SwRootFrame::GrowFrame(SwTwips nDist, SwResizeLimitReason& reason, bool bTst, bool) { if ( !bTst ) { SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this); aFrm.AddHeight(nDist ); } - + reason = SwResizeLimitReason::Unspecified; return nDist; } diff --git a/sw/source/core/layout/sectfrm.cxx b/sw/source/core/layout/sectfrm.cxx index cde14e1f6fb3..b0a7076096d8 100644 --- a/sw/source/core/layout/sectfrm.cxx +++ b/sw/source/core/layout/sectfrm.cxx @@ -2180,13 +2180,16 @@ bool SwSectionFrame::Growable() const return ( GetUpper() && const_cast<SwFrame*>(static_cast<SwFrame const *>(GetUpper()))->Grow( LONG_MAX, true ) ); } -SwTwips SwSectionFrame::Grow_( SwTwips nDist, bool bTst ) +SwTwips SwSectionFrame::Grow_(SwTwips nDist, SwResizeLimitReason& reason, bool bTst) { if (IsColLocked() || HasFixSize()) { + reason = HasFixSize() ? SwResizeLimitReason::FixedSizeFrame : SwResizeLimitReason::Unspecified; return 0; } + const auto nOrigDist = nDist; + reason = SwResizeLimitReason::Unspecified; SwRectFnSet aRectFnSet(this); tools::Long nFrameHeight = aRectFnSet.GetHeight(getFrameArea()); if( nFrameHeight > 0 && nDist > (LONG_MAX - nFrameHeight) ) @@ -2202,6 +2205,8 @@ SwTwips SwSectionFrame::Grow_( SwTwips nDist, bool bTst ) { SwSection* pSection = GetSection(); bGrow = pSection && pSection->GetFormat()->GetBalancedColumns().GetValue(); + if (!bGrow && nOrigDist) + reason = SwResizeLimitReason::BalancedColumns; } if( !bGrow ) { @@ -2219,6 +2224,7 @@ SwTwips SwSectionFrame::Grow_( SwTwips nDist, bool bTst ) } return 0; } + reason = SwResizeLimitReason::Unspecified; // reset what maybe was set in balanced columns check SwTwips nGrow; if( IsInFootnote() ) nGrow = 0; @@ -2250,7 +2256,7 @@ SwTwips SwSectionFrame::Grow_( SwTwips nDist, bool bTst ) if( bInCalcContent ) InvalidateSize_(); else if( nSpace < nGrow && nDist != nSpace + GetUpper()-> - Grow( nGrow - nSpace ) ) + Grow(nGrow - nSpace, reason, false, false)) InvalidateSize(); else { diff --git a/sw/source/core/layout/tabfrm.cxx b/sw/source/core/layout/tabfrm.cxx index 317ede1b986b..9bda9b409fdb 100644 --- a/sw/source/core/layout/tabfrm.cxx +++ b/sw/source/core/layout/tabfrm.cxx @@ -3568,13 +3568,15 @@ void SwTabFrame::Format( vcl::RenderContext* /*pRenderContext*/, const SwBorderA Grow( -nDiff ); } -SwTwips SwTabFrame::GrowFrame( SwTwips nDist, bool bTst, bool bInfo ) +SwTwips SwTabFrame::GrowFrame(SwTwips nDist, SwResizeLimitReason& reason, bool bTst, bool bInfo) { SwRectFnSet aRectFnSet(this); SwTwips nHeight = aRectFnSet.GetHeight(getFrameArea()); if( nHeight > 0 && nDist > ( LONG_MAX - nHeight ) ) nDist = LONG_MAX - nHeight; + reason = SwResizeLimitReason::Unspecified; + if ( bTst && !IsRestrictTableGrowth() ) return nDist; @@ -3589,7 +3591,7 @@ SwTwips SwTabFrame::GrowFrame( SwTwips nDist, bool bTst, bool bInfo ) if ( nReal < nDist ) { - tools::Long nTmp = GetUpper()->Grow(nDist - std::max(nReal, SwTwips(0)), bTst, bInfo); + tools::Long nTmp = GetUpper()->Grow(nDist - std::max(nReal, SwTwips(0)), reason, bTst, bInfo); if ( IsRestrictTableGrowth() ) { @@ -5137,8 +5139,9 @@ void SwRowFrame::Cut() SwLayoutFrame::Cut(); } -SwTwips SwRowFrame::GrowFrame( SwTwips nDist, bool bTst, bool bInfo ) +SwTwips SwRowFrame::GrowFrame(SwTwips nDist, SwResizeLimitReason& reason, bool bTst, bool bInfo) { + const auto nOrigDist = nDist; SwTwips nReal = 0; SwTabFrame* pTab = FindTabFrame(); @@ -5187,7 +5190,7 @@ SwTwips SwRowFrame::GrowFrame( SwTwips nDist, bool bTst, bool bInfo ) pTab->SetFollowFlowLine( false ); } - nReal += SwLayoutFrame::GrowFrame( nDist, bTst, bInfo); + nReal += SwLayoutFrame::GrowFrame(nDist, reason, bTst, bInfo); pTab->SetRestrictTableGrowth( false ); pTab->SetFollowFlowLine( bHasFollowFlowLine ); @@ -5200,7 +5203,8 @@ SwTwips SwRowFrame::GrowFrame( SwTwips nDist, bool bTst, bool bInfo ) if ( nReal ) SetCompletePaint(); } - + if (reason == SwResizeLimitReason::Unspecified && nReal < nOrigDist && IsInSplit()) + reason = SwResizeLimitReason::FlowToFollow; return nReal; } diff --git a/sw/source/core/layout/wsfrm.cxx b/sw/source/core/layout/wsfrm.cxx index 10eaa4c43f3a..c7bee537bbae 100644 --- a/sw/source/core/layout/wsfrm.cxx +++ b/sw/source/core/layout/wsfrm.cxx @@ -1513,18 +1513,21 @@ void SwLayoutFrame::Cut() } } -SwTwips SwFrame::Grow( SwTwips nDist, bool bTst, bool bInfo ) +SwTwips SwFrame::Grow(SwTwips nDist, SwResizeLimitReason& reason, bool bTst, bool bInfo) { OSL_ENSURE( nDist >= 0, "Negative growth?" ); PROTOCOL_ENTER( this, bTst ? PROT::GrowTest : PROT::Grow, DbgAction::NONE, &nDist ) if ( !nDist ) + { + reason = SwResizeLimitReason::Unspecified; return 0; + } if ( IsFlyFrame() ) - return static_cast<SwFlyFrame*>(this)->Grow_( nDist, bTst ); + return static_cast<SwFlyFrame*>(this)->Grow_(nDist, reason, bTst); if ( IsSctFrame() ) - return static_cast<SwSectionFrame*>(this)->Grow_( nDist, bTst ); + return static_cast<SwSectionFrame*>(this)->Grow_(nDist, reason, bTst); if (IsCellFrame()) { const SwCellFrame* pThisCell = static_cast<const SwCellFrame*>(this); @@ -1533,7 +1536,10 @@ SwTwips SwFrame::Grow( SwTwips nDist, bool bTst, bool bInfo ) // NEW TABLES if ( pTab->IsVertical() != IsVertical() || pThisCell->GetLayoutRowSpan() < 1 ) + { + reason = SwResizeLimitReason::FixedSizeFrame; return 0; + } } SwRectFnSet aRectFnSet(this); @@ -1542,7 +1548,7 @@ SwTwips SwFrame::Grow( SwTwips nDist, bool bTst, bool bInfo ) if( nPrtHeight > 0 && nDist > (LONG_MAX - nPrtHeight) ) nDist = LONG_MAX - nPrtHeight; - const SwTwips nReal = GrowFrame( nDist, bTst, bInfo ); + const SwTwips nReal = GrowFrame(nDist, reason, bTst, bInfo); if( !bTst ) { nPrtHeight = aRectFnSet.GetHeight(getFramePrintArea()); @@ -2104,7 +2110,7 @@ void SwFrame::ValidateThisAndAllLowers( const sal_uInt16 nStage ) } } -SwTwips SwContentFrame::GrowFrame( SwTwips nDist, bool bTst, bool bInfo ) +SwTwips SwContentFrame::GrowFrame(SwTwips nDist, SwResizeLimitReason& reason, bool bTst, bool bInfo) { SwRectFnSet aRectFnSet(this); @@ -2146,9 +2152,18 @@ SwTwips SwContentFrame::GrowFrame( SwTwips nDist, bool bTst, bool bInfo ) InvalidateNextPos(); } } + if (!nDist) + reason = SwResizeLimitReason::Unspecified; + else if (GetUpper()->IsBodyFrame() // Page / column body + || (GetUpper()->IsFlyFrame() + && static_cast<SwFlyFrame*>(GetUpper())->GetNextLink())) + reason = SwResizeLimitReason::FlowToFollow; + else + reason = SwResizeLimitReason::FixedSizeFrame; return 0; } + reason = SwResizeLimitReason::Unspecified; SwTwips nReal = aRectFnSet.GetHeight(GetUpper()->getFramePrintArea()); for (SwFrame* pFrame = GetUpper()->Lower(); pFrame && nReal > 0; pFrame = pFrame->GetNext()) nReal -= aRectFnSet.GetHeight(pFrame->getFrameArea()); @@ -2188,7 +2203,7 @@ SwTwips SwContentFrame::GrowFrame( SwTwips nDist, bool bTst, bool bInfo ) if( GetUpper() ) { if( bTst || !GetUpper()->IsFooterFrame() ) - nReal = GetUpper()->Grow(nDist - std::max(nReal, SwTwips(0)), bTst, bInfo); + nReal = GetUpper()->Grow(nDist - std::max(nReal, SwTwips(0)), reason, bTst, bInfo); else { nReal = 0; @@ -2630,7 +2645,7 @@ SwTwips SwLayoutFrame::InnerHeight() const return nRet; } -SwTwips SwLayoutFrame::GrowFrame( SwTwips nDist, bool bTst, bool bInfo ) +SwTwips SwLayoutFrame::GrowFrame(SwTwips nDist, SwResizeLimitReason& reason, bool bTst, bool bInfo) { const SwViewShell *pSh = getRootFrame()->GetCurrShell(); const bool bBrowse = pSh && pSh->GetViewOptions()->getBrowseMode(); @@ -2638,7 +2653,14 @@ SwTwips SwLayoutFrame::GrowFrame( SwTwips nDist, bool bTst, bool bInfo ) if (bBrowse) nTmpType |= SwFrameType::Body; if( !(GetType() & nTmpType) && HasFixSize() ) + { + if (nDist <= 0) + reason = SwResizeLimitReason::Unspecified; + else + reason = IsBodyFrame() ? SwResizeLimitReason::FlowToFollow // Page / column body + : SwResizeLimitReason::FixedSizeFrame; return 0; + } SwRectFnSet aRectFnSet(this); const SwTwips nFrameHeight = aRectFnSet.GetHeight(getFrameArea()); @@ -2674,6 +2696,7 @@ SwTwips SwLayoutFrame::GrowFrame( SwTwips nDist, bool bTst, bool bInfo ) bMoveAccFrame = true; } + reason = SwResizeLimitReason::Unspecified; SwTwips nReal = nDist - nMin; if ( nReal > 0 ) { @@ -2706,10 +2729,13 @@ SwTwips SwLayoutFrame::GrowFrame( SwTwips nDist, bool bTst, bool bInfo ) if ( -1 == rEndCell.GetTabBox()->getRowSpan() ) pToGrow = rEndCell.GetUpper(); else + { pToGrow = nullptr; + reason = SwResizeLimitReason::FlowToFollow; + } } } - nGrow = pToGrow ? pToGrow->Grow( nReal, bTst, bInfo ) : 0; + nGrow = pToGrow ? pToGrow->Grow(nReal, reason, bTst, bInfo) : 0; } if( SwNeighbourAdjust::GrowAdjust == nAdjust && nGrow < nReal ) @@ -2808,6 +2834,9 @@ SwTwips SwLayoutFrame::GrowFrame( SwTwips nDist, bool bTst, bool bInfo ) (void)aOldFrame; #endif + if (reason == SwResizeLimitReason::Unspecified && nReal < nDist && IsBodyFrame()) // Page / column body + reason = SwResizeLimitReason::FlowToFollow; + return nReal; } diff --git a/sw/source/core/text/widorp.cxx b/sw/source/core/text/widorp.cxx index 11e4193d7bd0..eeed1820b2b2 100644 --- a/sw/source/core/text/widorp.cxx +++ b/sw/source/core/text/widorp.cxx @@ -103,7 +103,7 @@ SwTextFrameBreak::SwTextFrameBreak( SwTextFrame *pNewFrame, const SwTwips nRst ) * be done until the Follow is formatted. Unfortunately this is crucial * to decide if the whole paragraph goes to the next page or not. */ -bool SwTextFrameBreak::IsInside( SwTextMargin const &rLine ) const +bool SwTextFrameBreak::IsInside(SwTextMargin const& rLine, SwResizeLimitReason& reason) const { bool bFit = false; @@ -209,7 +209,7 @@ bool SwTextFrameBreak::IsInside( SwTextMargin const &rLine ) const // The LineHeight exceeds the current Frame height. // Call a test Grow to detect if the Frame could // grow the requested area. - nHeight += m_pFrame->GrowTst( LONG_MAX ); + nHeight += m_pFrame->GrowTst(LONG_MAX, reason); // The Grow() returns the height by which the Upper of the TextFrame // would let the TextFrame grow. @@ -224,10 +224,11 @@ bool SwTextFrameBreak::IsInside( SwTextMargin const &rLine ) const bool SwTextFrameBreak::IsBreakNow( SwTextMargin &rLine ) { SwSwapIfSwapped swap(m_pFrame); + SwResizeLimitReason reason = SwResizeLimitReason::Unspecified; // bKeep is stronger than IsBreakNow() // Is there enough space ? - if( m_bKeep || IsInside( rLine ) ) + if (m_bKeep || IsInside(rLine, reason)) m_bBreak = false; else { @@ -262,6 +263,11 @@ bool SwTextFrameBreak::IsBreakNow( SwTextMargin &rLine ) if( !pTmp || !pTmp->Lower() ) m_bBreak = false; } + else if (reason == SwResizeLimitReason::FixedSizeFrame) + { + // The content is in a clipping frame - no need to break at all + m_bBreak = false; + } } return m_bBreak; diff --git a/sw/source/core/text/widorp.hxx b/sw/source/core/text/widorp.hxx index 996a7fc913bc..bf3051df2298 100644 --- a/sw/source/core/text/widorp.hxx +++ b/sw/source/core/text/widorp.hxx @@ -40,6 +40,7 @@ public: void SetKeep( const bool bNew ) { m_bKeep = bNew; } bool IsInside( SwTextMargin const &rLine ) const; + bool IsInside(SwTextMargin const& rLine, SwResizeLimitReason&) const; // In order to be able to handle special cases with Footnote. // SetRstHeight sets the rest height for SwTextFrameBreak. This is needed @@ -79,6 +80,11 @@ public: } }; +inline bool SwTextFrameBreak::IsInside(SwTextMargin const& rLine) const +{ + return IsInside(rLine, o3tl::temporary(SwResizeLimitReason())); +} + namespace sw { auto FindNonFlyPortion(SwLineLayout const& rLine) -> bool; commit 08e6a1e50932b908df9f0b01b8b2bddd2455c690 Author: Mike Kaganski <[email protected]> AuthorDate: Sat Aug 24 13:04:47 2024 +0500 Commit: Mike Kaganski <[email protected]> CommitDate: Fri Nov 29 10:21:04 2024 +0500 Simplify a bit Change-Id: Ia18d2d28d1026e3a695374dd523fb23ee97b96b5 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/172344 Tested-by: Jenkins Reviewed-by: Mike Kaganski <[email protected]> diff --git a/sw/source/core/layout/tabfrm.cxx b/sw/source/core/layout/tabfrm.cxx index a95b311d5999..317ede1b986b 100644 --- a/sw/source/core/layout/tabfrm.cxx +++ b/sw/source/core/layout/tabfrm.cxx @@ -3583,16 +3583,13 @@ SwTwips SwTabFrame::GrowFrame( SwTwips nDist, bool bTst, bool bInfo ) //The upper only grows as far as needed. nReal provides the distance //which is already available. SwTwips nReal = aRectFnSet.GetHeight(GetUpper()->getFramePrintArea()); - SwFrame *pFrame = GetUpper()->Lower(); - while ( pFrame && GetFollow() != pFrame ) - { + for (SwFrame* pFrame = GetUpper()->Lower(); pFrame && GetFollow() != pFrame; + pFrame = pFrame->GetNext()) nReal -= aRectFnSet.GetHeight(pFrame->getFrameArea()); - pFrame = pFrame->GetNext(); - } if ( nReal < nDist ) { - tools::Long nTmp = GetUpper()->Grow( nDist - std::max<tools::Long>(nReal, 0), bTst, bInfo ); + tools::Long nTmp = GetUpper()->Grow(nDist - std::max(nReal, SwTwips(0)), bTst, bInfo); if ( IsRestrictTableGrowth() ) { diff --git a/sw/source/core/layout/wsfrm.cxx b/sw/source/core/layout/wsfrm.cxx index 8435d4419259..10eaa4c43f3a 100644 --- a/sw/source/core/layout/wsfrm.cxx +++ b/sw/source/core/layout/wsfrm.cxx @@ -2150,11 +2150,8 @@ SwTwips SwContentFrame::GrowFrame( SwTwips nDist, bool bTst, bool bInfo ) } SwTwips nReal = aRectFnSet.GetHeight(GetUpper()->getFramePrintArea()); - SwFrame *pFrame = GetUpper()->Lower(); - while( pFrame && nReal > 0 ) - { nReal -= aRectFnSet.GetHeight(pFrame->getFrameArea()); - pFrame = pFrame->GetNext(); - } + for (SwFrame* pFrame = GetUpper()->Lower(); pFrame && nReal > 0; pFrame = pFrame->GetNext()) + nReal -= aRectFnSet.GetHeight(pFrame->getFrameArea()); if ( !bTst ) { @@ -2191,8 +2188,7 @@ SwTwips SwContentFrame::GrowFrame( SwTwips nDist, bool bTst, bool bInfo ) if( GetUpper() ) { if( bTst || !GetUpper()->IsFooterFrame() ) - nReal = GetUpper()->Grow( nDist - std::max<tools::Long>(nReal, 0), - bTst, bInfo ); + nReal = GetUpper()->Grow(nDist - std::max(nReal, SwTwips(0)), bTst, bInfo); else { nReal = 0; @@ -2654,11 +2650,8 @@ SwTwips SwLayoutFrame::GrowFrame( SwTwips nDist, bool bTst, bool bInfo ) SwTwips nMin = 0; if ( GetUpper() && !IsCellFrame() ) { - SwFrame *pFrame = GetUpper()->Lower(); - while( pFrame ) - { nMin += aRectFnSet.GetHeight(pFrame->getFrameArea()); - pFrame = pFrame->GetNext(); - } + for (SwFrame* pFrame = GetUpper()->Lower(); pFrame; pFrame = pFrame->GetNext()) + nMin += aRectFnSet.GetHeight(pFrame->getFrameArea()); nMin = aRectFnSet.GetHeight(GetUpper()->getFramePrintArea()) - nMin; if ( nMin < 0 ) nMin = 0; @@ -2697,7 +2690,7 @@ SwTwips SwLayoutFrame::GrowFrame( SwTwips nDist, bool bTst, bool bInfo ) nReal += AdjustNeighbourhood( nReal, bTst ); SwTwips nGrow = 0; - if( 0 < nReal ) + if( nReal > 0 ) { SwFrame* pToGrow = GetUpper(); // NEW TABLES commit 75051bcb0fa4d9bc9f03f8bf69b6519580e2cd2f Author: Mike Kaganski <[email protected]> AuthorDate: Sat Aug 24 12:35:05 2024 +0500 Commit: Mike Kaganski <[email protected]> CommitDate: Fri Nov 29 10:19:52 2024 +0500 Flatten SwFrame::Grow Change-Id: I0357a2b773ce7039697593df5f44b7ee35f89511 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/172342 Tested-by: Jenkins Reviewed-by: Mike Kaganski <[email protected]> diff --git a/sw/source/core/layout/wsfrm.cxx b/sw/source/core/layout/wsfrm.cxx index 537c79334189..8435d4419259 100644 --- a/sw/source/core/layout/wsfrm.cxx +++ b/sw/source/core/layout/wsfrm.cxx @@ -1519,42 +1519,38 @@ SwTwips SwFrame::Grow( SwTwips nDist, bool bTst, bool bInfo ) PROTOCOL_ENTER( this, bTst ? PROT::GrowTest : PROT::Grow, DbgAction::NONE, &nDist ) - if ( nDist ) + if ( !nDist ) + return 0; + if ( IsFlyFrame() ) + return static_cast<SwFlyFrame*>(this)->Grow_( nDist, bTst ); + if ( IsSctFrame() ) + return static_cast<SwSectionFrame*>(this)->Grow_( nDist, bTst ); + if (IsCellFrame()) { - SwRectFnSet aRectFnSet(this); + const SwCellFrame* pThisCell = static_cast<const SwCellFrame*>(this); + const SwTabFrame* pTab = FindTabFrame(); - SwTwips nPrtHeight = aRectFnSet.GetHeight(getFramePrintArea()); - if( nPrtHeight > 0 && nDist > (LONG_MAX - nPrtHeight) ) - nDist = LONG_MAX - nPrtHeight; + // NEW TABLES + if ( pTab->IsVertical() != IsVertical() || + pThisCell->GetLayoutRowSpan() < 1 ) + return 0; + } - if ( IsFlyFrame() ) - return static_cast<SwFlyFrame*>(this)->Grow_( nDist, bTst ); - else if( IsSctFrame() ) - return static_cast<SwSectionFrame*>(this)->Grow_( nDist, bTst ); - else - { - if (IsCellFrame()) - { - const SwCellFrame* pThisCell = static_cast<const SwCellFrame*>(this); - const SwTabFrame* pTab = FindTabFrame(); + SwRectFnSet aRectFnSet(this); - // NEW TABLES - if ( pTab->IsVertical() != IsVertical() || - pThisCell->GetLayoutRowSpan() < 1 ) - return 0; - } - const SwTwips nReal = GrowFrame( nDist, bTst, bInfo ); - if( !bTst ) - { - nPrtHeight = aRectFnSet.GetHeight(getFramePrintArea()); + SwTwips nPrtHeight = aRectFnSet.GetHeight(getFramePrintArea()); + if( nPrtHeight > 0 && nDist > (LONG_MAX - nPrtHeight) ) + nDist = LONG_MAX - nPrtHeight; - SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this); - aRectFnSet.SetHeight( aPrt, nPrtHeight + ( IsContentFrame() ? nDist : nReal ) ); - } - return nReal; - } + const SwTwips nReal = GrowFrame( nDist, bTst, bInfo ); + if( !bTst ) + { + nPrtHeight = aRectFnSet.GetHeight(getFramePrintArea()); + + SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this); + aRectFnSet.SetHeight( aPrt, nPrtHeight + ( IsContentFrame() ? nDist : nReal ) ); } - return 0; + return nReal; } SwTwips SwFrame::Shrink( SwTwips nDist, bool bTst, bool bInfo ) commit c942545ed80559a203a49cbeeee44b1380b30a25 Author: Mike Kaganski <[email protected]> AuthorDate: Sat Aug 24 00:34:44 2024 +0500 Commit: Mike Kaganski <[email protected]> CommitDate: Fri Nov 29 10:18:14 2024 +0500 Flatten SwSectionFrame::Grow_ Change-Id: Ia83785525cbb49a02a10b6c248fe2060bc6407d9 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/172339 Reviewed-by: Mike Kaganski <[email protected]> Tested-by: Jenkins diff --git a/sw/source/core/layout/sectfrm.cxx b/sw/source/core/layout/sectfrm.cxx index de4e54e27d5d..cde14e1f6fb3 100644 --- a/sw/source/core/layout/sectfrm.cxx +++ b/sw/source/core/layout/sectfrm.cxx @@ -2182,137 +2182,139 @@ bool SwSectionFrame::Growable() const SwTwips SwSectionFrame::Grow_( SwTwips nDist, bool bTst ) { - if ( !IsColLocked() && !HasFixSize() ) + if (IsColLocked() || HasFixSize()) { - SwRectFnSet aRectFnSet(this); - tools::Long nFrameHeight = aRectFnSet.GetHeight(getFrameArea()); - if( nFrameHeight > 0 && nDist > (LONG_MAX - nFrameHeight) ) - nDist = LONG_MAX - nFrameHeight; + return 0; + } + + SwRectFnSet aRectFnSet(this); + tools::Long nFrameHeight = aRectFnSet.GetHeight(getFrameArea()); + if( nFrameHeight > 0 && nDist > (LONG_MAX - nFrameHeight) ) + nDist = LONG_MAX - nFrameHeight; - if ( nDist <= 0 ) - return 0; + if ( nDist <= 0 ) + return 0; - bool bInCalcContent = GetUpper() && IsInFly() && FindFlyFrame()->IsLocked(); - // OD 2004-03-15 #116561# - allow grow in online layout - bool bGrow = !Lower() || !Lower()->IsColumnFrame() || !Lower()->GetNext(); - if (!bGrow) + bool bInCalcContent = GetUpper() && IsInFly() && FindFlyFrame()->IsLocked(); + // OD 2004-03-15 #116561# - allow grow in online layout + bool bGrow = !Lower() || !Lower()->IsColumnFrame() || !Lower()->GetNext(); + if (!bGrow) + { + SwSection* pSection = GetSection(); + bGrow = pSection && pSection->GetFormat()->GetBalancedColumns().GetValue(); + } + if( !bGrow ) + { + const SwViewShell *pSh = getRootFrame()->GetCurrShell(); + bGrow = pSh && pSh->GetViewOptions()->getBrowseMode(); + } + if (!bGrow) + { + if (!bTst) { - SwSection* pSection = GetSection(); - bGrow = pSection && pSection->GetFormat()->GetBalancedColumns().GetValue(); + if (bInCalcContent) + InvalidateSize_(); + else + InvalidateSize(); } - if( !bGrow ) + return 0; + } + SwTwips nGrow; + if( IsInFootnote() ) + nGrow = 0; + else + { + nGrow = lcl_DeadLine( this ); + nGrow = aRectFnSet.YDiff( nGrow, aRectFnSet.GetBottom(getFrameArea()) ); + } + SwTwips nSpace = nGrow; + if( !bInCalcContent && nGrow < nDist && GetUpper() ) + nGrow = o3tl::saturating_add( + nGrow, GetUpper()->Grow( LONG_MAX, true )); + + if( nGrow > nDist ) + nGrow = nDist; + if( nGrow <= 0 ) + { + nGrow = 0; + if (!bTst) { - const SwViewShell *pSh = getRootFrame()->GetCurrShell(); - bGrow = pSh && pSh->GetViewOptions()->getBrowseMode(); + if( bInCalcContent ) + InvalidateSize_(); + else + InvalidateSize(); } - if( bGrow ) + } + else if( !bTst ) + { + if( bInCalcContent ) + InvalidateSize_(); + else if( nSpace < nGrow && nDist != nSpace + GetUpper()-> + Grow( nGrow - nSpace ) ) + InvalidateSize(); + else { - SwTwips nGrow; - if( IsInFootnote() ) - nGrow = 0; - else + const SvxGraphicPosition ePos = + GetAttrSet()->GetBackground().GetGraphicPos(); + if ( GPOS_RT < ePos && GPOS_TILED != ePos ) { - nGrow = lcl_DeadLine( this ); - nGrow = aRectFnSet.YDiff( nGrow, aRectFnSet.GetBottom(getFrameArea()) ); - } - SwTwips nSpace = nGrow; - if( !bInCalcContent && nGrow < nDist && GetUpper() ) - nGrow = o3tl::saturating_add( - nGrow, GetUpper()->Grow( LONG_MAX, true )); - - if( nGrow > nDist ) - nGrow = nDist; - if( nGrow <= 0 ) - { - nGrow = 0; - if (!bTst) - { - if( bInCalcContent ) - InvalidateSize_(); - else - InvalidateSize(); - } + SetCompletePaint(); + InvalidatePage(); } - else if( !bTst ) - { - if( bInCalcContent ) - InvalidateSize_(); - else if( nSpace < nGrow && nDist != nSpace + GetUpper()-> - Grow( nGrow - nSpace ) ) - InvalidateSize(); - else - { - const SvxGraphicPosition ePos = - GetAttrSet()->GetBackground().GetGraphicPos(); - if ( GPOS_RT < ePos && GPOS_TILED != ePos ) - { - SetCompletePaint(); - InvalidatePage(); - } - if( GetUpper() && GetUpper()->IsHeaderFrame() ) - GetUpper()->InvalidateSize(); - } + if( GetUpper() && GetUpper()->IsHeaderFrame() ) + GetUpper()->InvalidateSize(); + } - { - SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this); - aRectFnSet.AddBottom( aFrm, nGrow ); - } + { + SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this); + aRectFnSet.AddBottom( aFrm, nGrow ); + } - { - const tools::Long nPrtHeight = aRectFnSet.GetHeight(getFramePrintArea()) + nGrow; - SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this); - aRectFnSet.SetHeight( aPrt, nPrtHeight ); - } + { + const tools::Long nPrtHeight = aRectFnSet.GetHeight(getFramePrintArea()) + nGrow; + SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this); + aRectFnSet.SetHeight( aPrt, nPrtHeight ); + } - if( Lower() && Lower()->IsColumnFrame() && Lower()->GetNext() ) - { - SwFrame* pTmp = Lower(); - do - { - pTmp->InvalidateSize_(); - pTmp = pTmp->GetNext(); - } while ( pTmp ); - InvalidateSize_(); - } - if( GetNext() ) - { - // Own height changed, need to invalidate the position of - // next frames. - SwFrame *pFrame = GetNext(); - while( pFrame && pFrame->IsSctFrame() && !static_cast<SwSectionFrame*>(pFrame)->GetSection() ) - { - // Invalidate all in-between frames, otherwise position - // calculation (which only looks back to one relative - // frame) will have an incorrect result. - InvalidateFramePos(pFrame, bInCalcContent); - pFrame = pFrame->GetNext(); - } - if( pFrame ) - { - InvalidateFramePos(pFrame, bInCalcContent); - } - } - // #i28701# - Due to the new object positioning - // the frame on the next page/column can flow backward (e.g. it - // was moved forward due to the positioning of its objects ). - // Thus, invalivate this next frame, if document compatibility - // option 'Consider wrapping style influence on object positioning' is ON. - else if ( GetFormat()->getIDocumentSettingAccess().get(DocumentSettingId::CONSIDER_WRAP_ON_OBJECT_POSITION) ) - { - InvalidateNextPos(); - } + if( Lower() && Lower()->IsColumnFrame() && Lower()->GetNext() ) + { + SwFrame* pTmp = Lower(); + do + { + pTmp->InvalidateSize_(); + pTmp = pTmp->GetNext(); + } while ( pTmp ); + InvalidateSize_(); + } + if( GetNext() ) + { + // Own height changed, need to invalidate the position of + // next frames. + SwFrame *pFrame = GetNext(); + while( pFrame && pFrame->IsSctFrame() && !static_cast<SwSectionFrame*>(pFrame)->GetSection() ) + { + // Invalidate all in-between frames, otherwise position + // calculation (which only looks back to one relative + // frame) will have an incorrect result. + InvalidateFramePos(pFrame, bInCalcContent); + pFrame = pFrame->GetNext(); + } + if( pFrame ) + { + InvalidateFramePos(pFrame, bInCalcContent); } - return nGrow; } - if ( !bTst ) + // #i28701# - Due to the new object positioning + // the frame on the next page/column can flow backward (e.g. it + // was moved forward due to the positioning of its objects ). + // Thus, invalivate this next frame, if document compatibility + // option 'Consider wrapping style influence on object positioning' is ON. + else if ( GetFormat()->getIDocumentSettingAccess().get(DocumentSettingId::CONSIDER_WRAP_ON_OBJECT_POSITION) ) { - if( bInCalcContent ) - InvalidateSize_(); - else - InvalidateSize(); + InvalidateNextPos(); } } - return 0; + return nGrow; } SwTwips SwSectionFrame::Shrink_( SwTwips nDist, bool bTst ) commit 749fdd6db89065ebff11a1160a7ceca5538ac094 Author: Mike Kaganski <[email protected]> AuthorDate: Fri Aug 23 23:30:26 2024 +0500 Commit: Mike Kaganski <[email protected]> CommitDate: Fri Nov 29 10:15:18 2024 +0500 Flatten SwFlyFrame::Grow_ Change-Id: I6fe29fef686e00dce30a024063f684f1eeaf3f64 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/172338 Tested-by: Jenkins Reviewed-by: Mike Kaganski <[email protected]> diff --git a/sw/source/core/layout/fly.cxx b/sw/source/core/layout/fly.cxx index fd15d4d22cd0..0f51fd0e1bd8 100644 --- a/sw/source/core/layout/fly.cxx +++ b/sw/source/core/layout/fly.cxx @@ -2148,140 +2148,137 @@ SwFlyAtContentFrame* SwFlyFrame::DynCastFlyAtContentFrame() SwTwips SwFlyFrame::Grow_( SwTwips nDist, bool bTst ) { - SwRectFnSet aRectFnSet(this); - if ( Lower() && !IsColLocked() && !HasFixSize() ) - { - SwTwips nSize = aRectFnSet.GetHeight(getFrameArea()); - if( nSize > 0 && nDist > ( LONG_MAX - nSize ) ) - nDist = LONG_MAX - nSize; + if (!Lower() || IsColLocked() || HasFixSize()) + return 0; - if ( nDist <= 0 ) - return 0; + SwRectFnSet aRectFnSet(this); + SwTwips nSize = aRectFnSet.GetHeight(getFrameArea()); + if( nSize > 0 && nDist > ( LONG_MAX - nSize ) ) + nDist = LONG_MAX - nSize; - if ( Lower()->IsColumnFrame() ) - { // If it's a Column Frame, the Format takes control of the - // resizing (due to the adjustment). - if ( !bTst ) - { - // #i28701# - unlock position of Writer fly frame - UnlockPosition(); - InvalidatePos_(); - InvalidateSize(); - } - return 0; - } + if ( nDist <= 0 ) + return 0; + if ( Lower()->IsColumnFrame() ) + { // If it's a Column Frame, the Format takes control of the + // resizing (due to the adjustment). if ( !bTst ) { - const SwRect aOld( GetObjRectWithSpaces() ); - InvalidateSize_(); - const bool bOldLock = m_bLocked; - Unlock(); - if ( IsFlyFreeFrame() ) - { - // #i37068# - no format of position here - // and prevent move in method <CheckClip(..)>. - // This is needed to prevent layout loop caused by nested - // Writer fly frames - inner Writer fly frames format its - // anchor, which grows/shrinks the outer Writer fly frame. - // Note: position will be invalidated below. - setFrameAreaPositionValid(true); + // #i28701# - unlock position of Writer fly frame + UnlockPosition(); + InvalidatePos_(); + InvalidateSize(); + } + return 0; + } - // #i55416# - // Suppress format of width for autowidth frame, because the - // format of the width would call <SwTextFrame::CalcFitToContent()> - // for the lower frame, which initiated this grow. - const bool bOldFormatHeightOnly = m_bFormatHeightOnly; - const SwFormatFrameSize& rFrameSz = GetFormat()->GetFrameSize(); - if ( rFrameSz.GetWidthSizeType() != SwFrameSize::Fixed ) - { - m_bFormatHeightOnly = true; - } - SwViewShell* pSh = getRootFrame()->GetCurrShell(); - if (pSh) - { - static_cast<SwFlyFreeFrame*>(this)->SetNoMoveOnCheckClip( true ); - static_cast<SwFlyFreeFrame*>(this)->SwFlyFreeFrame::MakeAll(pSh->GetOut()); - static_cast<SwFlyFreeFrame*>(this)->SetNoMoveOnCheckClip( false ); - } - // #i55416# - if ( rFrameSz.GetWidthSizeType() != SwFrameSize::Fixed ) - { - m_bFormatHeightOnly = bOldFormatHeightOnly; - } - } - else - MakeAll(getRootFrame()->GetCurrShell()->GetOut()); - InvalidateSize_(); - InvalidatePos(); - if ( bOldLock ) - Lock(); - SwRect aNew(GetObjRectWithSpaces()); - if (IsFlySplitAllowed() && aNew.Height() - aOld.Height() < nDist) + if (bTst) + { + // We're in test mode. Don't promise infinite growth for split flys, rather limit the + // max size to the bottom of the upper. + const SwFrame* pAnchor = GetAnchorFrame(); + if (SwFrame* pAnchorChar = FindAnchorCharFrame()) + { + pAnchor = pAnchorChar; + } + if (pAnchor && IsFlySplitAllowed()) + { + SwTwips nDeadline = GetFlyAnchorBottom(this, *pAnchor); + SwTwips nTop = aRectFnSet.GetTop(getFrameArea()); + SwTwips nBottom = nTop + aRectFnSet.GetHeight(getFrameArea()); + // Calculate max grow and compare to the requested growth, adding to nDist may + // overflow when it's LONG_MAX. + SwTwips nMaxGrow = nDeadline - nBottom; + if (nDist > nMaxGrow) { - // We are allowed to split and the actual growth is less than the requested growth. - const SwFrame* pAnchor = GetAnchorFrame(); - if (SwFrame* pAnchorChar = FindAnchorCharFrame()) - { - pAnchor = pAnchorChar; - } - if (pAnchor) - { - SwTwips nDeadline = GetFlyAnchorBottom(this, *pAnchor); - SwTwips nTop = aRectFnSet.GetTop(getFrameArea()); - SwTwips nBottom = nTop + aRectFnSet.GetHeight(getFrameArea()); - SwTwips nMaxGrow = nDeadline - nBottom; - if (nDist > nMaxGrow) - { - // The requested growth is more than what we can provide, limit it. - nDist = nMaxGrow; - } - // Grow & invalidate the size. - SwTwips nRemaining = nDist - (aNew.Height() - aOld.Height()); - { - SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this); - aRectFnSet.AddBottom(aFrm, nRemaining); - } - InvalidateObjRectWithSpaces(); - { - // Margins are unchanged, so increase the print height similar to the frame - // height. - SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this); - aRectFnSet.AddBottom(aPrt, nRemaining ); - } - aNew = GetObjRectWithSpaces(); - } + nDist = nMaxGrow; } - if ( aOld != aNew ) - ::Notify( this, FindPageFrame(), aOld ); - return aRectFnSet.GetHeight(aNew)-aRectFnSet.GetHeight(aOld); } - else + return nDist; + } + + const SwRect aOld( GetObjRectWithSpaces() ); + InvalidateSize_(); + const bool bOldLock = m_bLocked; + Unlock(); + if ( IsFlyFreeFrame() ) + { + // #i37068# - no format of position here + // and prevent move in method <CheckClip(..)>. + // This is needed to prevent layout loop caused by nested + // Writer fly frames - inner Writer fly frames format its + // anchor, which grows/shrinks the outer Writer fly frame. + // Note: position will be invalidated below. + setFrameAreaPositionValid(true); + + // #i55416# + // Suppress format of width for autowidth frame, because the + // format of the width would call <SwTextFrame::CalcFitToContent()> + // for the lower frame, which initiated this grow. + const bool bOldFormatHeightOnly = m_bFormatHeightOnly; + const SwFormatFrameSize& rFrameSz = GetFormat()->GetFrameSize(); + if ( rFrameSz.GetWidthSizeType() != SwFrameSize::Fixed ) { - // We're in test mode. Don't promise infinite growth for split flys, rather limit the - // max size to the bottom of the upper. - const SwFrame* pAnchor = GetAnchorFrame(); - if (SwFrame* pAnchorChar = FindAnchorCharFrame()) + m_bFormatHeightOnly = true; + } + SwViewShell* pSh = getRootFrame()->GetCurrShell(); + if (pSh) + { + static_cast<SwFlyFreeFrame*>(this)->SetNoMoveOnCheckClip( true ); + static_cast<SwFlyFreeFrame*>(this)->SwFlyFreeFrame::MakeAll(pSh->GetOut()); + static_cast<SwFlyFreeFrame*>(this)->SetNoMoveOnCheckClip( false ); + } + // #i55416# + if ( rFrameSz.GetWidthSizeType() != SwFrameSize::Fixed ) + { + m_bFormatHeightOnly = bOldFormatHeightOnly; + } + } + else + MakeAll(getRootFrame()->GetCurrShell()->GetOut()); + InvalidateSize_(); + InvalidatePos(); + if ( bOldLock ) + Lock(); + SwRect aNew(GetObjRectWithSpaces()); + if (IsFlySplitAllowed() && aNew.Height() - aOld.Height() < nDist) + { + // We are allowed to split and the actual growth is less than the requested growth. + const SwFrame* pAnchor = GetAnchorFrame(); + if (SwFrame* pAnchorChar = FindAnchorCharFrame()) + { + pAnchor = pAnchorChar; + } + if (pAnchor) + { + SwTwips nDeadline = GetFlyAnchorBottom(this, *pAnchor); + SwTwips nTop = aRectFnSet.GetTop(getFrameArea()); + SwTwips nBottom = nTop + aRectFnSet.GetHeight(getFrameArea()); + SwTwips nMaxGrow = nDeadline - nBottom; + if (nDist > nMaxGrow) { - pAnchor = pAnchorChar; + // The requested growth is more than what we can provide, limit it. + nDist = nMaxGrow; } - if (pAnchor && IsFlySplitAllowed()) + // Grow & invalidate the size. + SwTwips nRemaining = nDist - (aNew.Height() - aOld.Height()); { - SwTwips nDeadline = GetFlyAnchorBottom(this, *pAnchor); - SwTwips nTop = aRectFnSet.GetTop(getFrameArea()); - SwTwips nBottom = nTop + aRectFnSet.GetHeight(getFrameArea()); - // Calculate max grow and compare to the requested growth, adding to nDist may - // overflow when it's LONG_MAX. - SwTwips nMaxGrow = nDeadline - nBottom; - if (nDist > nMaxGrow) - { - nDist = nMaxGrow; - } + SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this); + aRectFnSet.AddBottom(aFrm, nRemaining); } + InvalidateObjRectWithSpaces(); + { + // Margins are unchanged, so increase the print height similar to the frame + // height. + SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this); + aRectFnSet.AddBottom(aPrt, nRemaining ); + } + aNew = GetObjRectWithSpaces(); } - return nDist; } - return 0; + if ( aOld != aNew ) + ::Notify( this, FindPageFrame(), aOld ); + return aRectFnSet.GetHeight(aNew)-aRectFnSet.GetHeight(aOld); } SwTwips SwFlyFrame::Shrink_( SwTwips nDist, bool bTst )
