sw/qa/extras/layout/data/fdo48718-1.docx |binary sw/qa/extras/layout/data/tdf161718.docx |binary sw/qa/extras/layout/layout2.cxx | 29 +++++++++++++ sw/source/core/inc/tabfrm.hxx | 2 sw/source/core/layout/layact.cxx | 5 -- sw/source/core/layout/tabfrm.cxx | 67 ++++++++++++++++++++++++++++--- sw/source/core/text/txtftn.cxx | 7 +++ 7 files changed, 100 insertions(+), 10 deletions(-)
New commits: commit 306cdedb6ba3b7e63f9d3369ae9f18814292de55 Author: Michael Stahl <michael.st...@allotropia.de> AuthorDate: Wed Jun 26 15:44:44 2024 +0200 Commit: Mike Kaganski <mike.kagan...@collabora.com> CommitDate: Wed Aug 7 11:08:33 2024 +0500 tdf#156724 sw: layout: ignore footnotes when splitting float table row (regression from commit 534d3818aedfa95ad73935235462f5ec2817f5da) Change-Id: I169d88375a93c288604a89ef89f7e895830446c8 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/169570 Tested-by: Jenkins Reviewed-by: Michael Stahl <michael.st...@allotropia.de> diff --git a/sw/qa/extras/layout/data/fdo48718-1.docx b/sw/qa/extras/layout/data/fdo48718-1.docx new file mode 100644 index 000000000000..373aa357fd5c Binary files /dev/null and b/sw/qa/extras/layout/data/fdo48718-1.docx differ diff --git a/sw/qa/extras/layout/layout2.cxx b/sw/qa/extras/layout/layout2.cxx index 7d7eb0f73f87..1cfb586d74bc 100644 --- a/sw/qa/extras/layout/layout2.cxx +++ b/sw/qa/extras/layout/layout2.cxx @@ -2977,6 +2977,18 @@ CPPUNIT_TEST_FIXTURE(SwLayoutWriter2, testTdf161718) assertXPath(pXmlDoc, "/root/page", 1); } +CPPUNIT_TEST_FIXTURE(SwLayoutWriter2, TestTdf161348) +{ + createSwDoc("fdo48718-1.docx"); + + xmlDocUniquePtr pXml = parseLayoutDump(); + + // the floating table is on page 1 + // apparently both parts of the split table are on this text frame + assertXPath(pXml, "/root/page[1]/body/txt[2]/anchored/fly", 2); + assertXPath(pXml, "/root/page[1]/body/txt[2]/anchored/fly/tab", 2); +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/layout/tabfrm.cxx b/sw/source/core/layout/tabfrm.cxx index 61f08c6bc848..98e39b254671 100644 --- a/sw/source/core/layout/tabfrm.cxx +++ b/sw/source/core/layout/tabfrm.cxx @@ -807,7 +807,8 @@ static bool lcl_RecalcSplitLine( SwRowFrame& rLastLine, SwRowFrame& rFollowLine, bRet = false; // apparently checking nFootnoteHeight here does *not* guarantee that it fits into the body - if (bRet && nDistanceToFootnoteBodyPrtBottom + nFollowFootnotes < 0) + if (bRet && rTab.IsInDocBody() + && nDistanceToFootnoteBodyPrtBottom + nFollowFootnotes < 0) { assert(rTab.GetUpper() != rTab.FindFootnoteBossFrame()->FindBodyCont()); SAL_INFO("sw.layout", "SwTabFrame Split failed because of footnote growth"); commit c8ab4dc01252741a1d9055efb7bfc6caa31f78b9 Author: Michael Stahl <michael.st...@allotropia.de> AuthorDate: Tue Jun 25 18:47:15 2024 +0200 Commit: Mike Kaganski <mike.kagan...@collabora.com> CommitDate: Wed Aug 7 11:08:23 2024 +0500 tdf#161718 sw: fix background flys blocking footnotes The problem is that the document has an unwanted page break on the paragraph with the footnote. The reason is that lcl_GetFootnoteLower() tries to evade flys, but doesn't take into account that background flys (Wrap Through) should be ignored. (somehow regression from commit c303981cfd95ce1c3881366023d5495ae2edce97) Change-Id: I02578f14644e232fac127142fe12801101f87f86 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/169530 Tested-by: Jenkins Reviewed-by: Michael Stahl <michael.st...@allotropia.de> diff --git a/sw/qa/extras/layout/data/tdf161718.docx b/sw/qa/extras/layout/data/tdf161718.docx new file mode 100644 index 000000000000..240192e07a71 Binary files /dev/null and b/sw/qa/extras/layout/data/tdf161718.docx differ diff --git a/sw/qa/extras/layout/layout2.cxx b/sw/qa/extras/layout/layout2.cxx index 2c1e197fd95e..7d7eb0f73f87 100644 --- a/sw/qa/extras/layout/layout2.cxx +++ b/sw/qa/extras/layout/layout2.cxx @@ -2960,6 +2960,23 @@ CPPUNIT_TEST_FIXTURE(SwLayoutWriter2, testTdf156724) assertXPath(pXmlDoc, "/root/page", 2); } +CPPUNIT_TEST_FIXTURE(SwLayoutWriter2, testTdf161718) +{ + createSwDoc("tdf161718.docx"); + + xmlDocUniquePtr pXmlDoc = parseLayoutDump(); + + // everything on one page + assertXPath(pXmlDoc, "/root/page/header", 1); + assertXPath(pXmlDoc, "/root/page/header/txt/anchored", 1); + assertXPath(pXmlDoc, "/root/page/footer", 1); + assertXPath(pXmlDoc, "/root/page/ftncont/ftn", 1); + assertXPath(pXmlDoc, "/root/page/ftncont/ftn/txt", 1); + assertXPath(pXmlDoc, "/root/page/body/txt", 27); + assertXPath(pXmlDoc, "/root/page/body/txt/anchored", 1); + assertXPath(pXmlDoc, "/root/page", 1); +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/text/txtftn.cxx b/sw/source/core/text/txtftn.cxx index 035158e2bd25..cefc6239a0ba 100644 --- a/sw/source/core/text/txtftn.cxx +++ b/sw/source/core/text/txtftn.cxx @@ -32,6 +32,7 @@ #include <txtftn.hxx> #include <flyfrm.hxx> #include <fmtftn.hxx> +#include <fmtsrnd.hxx> #include <ftninfo.hxx> #include <charfmt.hxx> #include <rowfrm.hxx> @@ -246,6 +247,12 @@ static SwTwips lcl_GetFootnoteLower( const SwTextFrame* pFrame, SwTwips nLower ) const SwSortedObjs &rObjs = *pStartFrame->GetDrawObjs(); for (SwAnchoredObject* pAnchoredObj : rObjs) { + if (pAnchoredObj->GetFrameFormat().GetSurround().GetSurround() + == text::WrapTextMode_THROUGH) + { + continue; // tdf#161718 no effect on text flow, skip + } + SwRect aRect( pAnchoredObj->GetObjRect() ); auto pFlyFrame = pAnchoredObj->DynCastFlyFrame(); commit 82cb612befff3da47772918bb1a3d188092a7165 Author: Michael Stahl <michael.st...@allotropia.de> AuthorDate: Wed May 15 14:43:10 2024 +0200 Commit: Mike Kaganski <mike.kagan...@collabora.com> CommitDate: Wed Aug 7 10:57:26 2024 +0500 tdf#160897 sw: layout: fail SwTabFrame::Split on footnote overlap The bugdoc has a table in a section, and the cells contain many footnotes. Somehow commit c303981cfd95ce1c3881366023d5495ae2edce97 introduced some layout looping, and it also looks worse than in 7.5. During lcl_RecalcRow(rLastLine) it may happen that first some footnotes are moved off the page, then the table/section grow during text formatting, then the footnotes are moved back onto the page, so the footnote container is the same size as before, the body is the same size as before (because it shrinks whenever the footnote container grows), but the section and table don't fit into the body any more. This fixes the layout loops, and also there are no visible overlaps of body(table) and footnotes any more; however, the layout is obviously not perfect, many footnotes are on the wrong page and there are some gaps of empty space on some pages, but at least none of the footnotes are numbered "0" any more. In 7.5, there was overlap of the body and the footnotes on page 1 and 3, and also the irritating effect that moving the mouse over the bottom of page 3 would relayout the document multiple times... Some other ideas that don't work: * it doesn't help to call Shrink() on the section frame, because it has ToMaximize() and does not actually shrink. * one aspect of the loop is that the section is always size-invalidated even when it doesn't change its size during SwTabFormat::MakeAll() and the idea was to detect this (invalidation flag set on upper but same area as before) and reset the flag, but this prevents shrinking the section to fit on the page Change-Id: I6074b5c2615a0d7f613edebe92b5350efdd7fe02 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/167693 Tested-by: Jenkins Reviewed-by: Michael Stahl <michael.st...@allotropia.de> diff --git a/sw/source/core/layout/tabfrm.cxx b/sw/source/core/layout/tabfrm.cxx index efcca2c6aa41..61f08c6bc848 100644 --- a/sw/source/core/layout/tabfrm.cxx +++ b/sw/source/core/layout/tabfrm.cxx @@ -760,6 +760,9 @@ static bool lcl_RecalcSplitLine( SwRowFrame& rLastLine, SwRowFrame& rFollowLine, // #i26945# - include check, if objects fit const SwTwips nDistanceToUpperPrtBottom = aRectFnSet.BottomDist(rTab.getFrameArea(), aRectFnSet.GetPrtBottom(*rTab.GetUpper())); + // also check the footnote boss - it *may* be smaller than the upper now! + const SwTwips nDistanceToFootnoteBodyPrtBottom = + aRectFnSet.BottomDist(rTab.getFrameArea(), aRectFnSet.GetPrtBottom(*rTab.FindFootnoteBossFrame()->FindBodyCont())); // tdf#125685 ignore footnotes that are anchored in follow-table of this // table - if split is successful they move to the next page/column anyway assert(rTab.GetFollow() == rFollowLine.GetUpper()); @@ -803,6 +806,14 @@ static bool lcl_RecalcSplitLine( SwRowFrame& rLastLine, SwRowFrame& rFollowLine, if (nDistanceToUpperPrtBottom + nFollowFootnotes < 0 || !rTab.DoesObjsFit()) bRet = false; + // apparently checking nFootnoteHeight here does *not* guarantee that it fits into the body + if (bRet && nDistanceToFootnoteBodyPrtBottom + nFollowFootnotes < 0) + { + assert(rTab.GetUpper() != rTab.FindFootnoteBossFrame()->FindBodyCont()); + SAL_INFO("sw.layout", "SwTabFrame Split failed because of footnote growth"); + bRet = false; // tdf#160897 + } + // 2. Check if each cell in the last line has at least one content frame. // Note: a FollowFlowRow may contains empty cells! commit f83390ba4e0ae20d8256ddbe0e995c4fcd37aafa Author: Michael Stahl <michael.st...@allotropia.de> AuthorDate: Wed Aug 23 15:50:59 2023 +0200 Commit: Mike Kaganski <mike.kagan...@collabora.com> CommitDate: Wed Aug 7 09:18:04 2024 +0500 tdf#156724 sw: layout: fix tables not splitting due to footnotes differently Revert commit 610c6f02b11b4b4c555a78b0feb2a1eb35159e39 and and 61a78a523a6131ff98b5d846368e5626fe58d99c instead do the opposite: never calc content frames in FormatLayout(). There were a few cases where documents looked worse with the fix, such as the somewhat pathological tdf120139-1.odt and tdf124474-1.odt, but typically these went from a bad layout to a worse layout, e.g. --convert-to pdf tdf120139-1.odt went from 11 minutes to 33 minutes (dbgutil) with twice as many more half-empty pages. Worse is that the previous fix appears to prevent tdf#128437 from working. It should also be less risky to never calc content frames in FormatLayout(), because with IsPaintLocked() check that used to be done led to doing it only for pages which were visible when loading the document, so any regressions with this new approach would appear on few pages at the start of the document, instead of many pages at the end. Note that without the previous commit, this would cause * CppunitTest_sw_core_layout CPPUNIT_TEST_NAME="testTablePrintAreaLeft" to fail * tdf#137523 SwLayoutWriter3 testTdf137523 to fail, *only* on the last text frame This also appears to fix tdf#125749. Change-Id: I3d72f8e9d2b89aa3738e554308fd9dce12e92238 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/155988 Tested-by: Michael Stahl <michael.st...@allotropia.de> Reviewed-by: Michael Stahl <michael.st...@allotropia.de> diff --git a/sw/source/core/inc/tabfrm.hxx b/sw/source/core/inc/tabfrm.hxx index 6360405e4407..9b7baf171dfc 100644 --- a/sw/source/core/inc/tabfrm.hxx +++ b/sw/source/core/inc/tabfrm.hxx @@ -106,7 +106,7 @@ class SAL_DLLPUBLIC_RTTI SwTabFrame final: public SwLayoutFrame, public SwFlowFr * created and constructed and inserted directly after this. * Join() gets the Follow's content and destroys it. */ - bool Split( const SwTwips nCutPos, bool bTryToSplit, bool bTableRowKeep ); + bool Split(const SwTwips nCutPos, bool bTryToSplit, bool bTableRowKeep, bool & rIsFootnoteGrowth); void Join(); void UpdateAttr_( diff --git a/sw/source/core/layout/layact.cxx b/sw/source/core/layout/layact.cxx index 6c85d2d223d5..5afa15fd0772 100644 --- a/sw/source/core/layout/layact.cxx +++ b/sw/source/core/layout/layact.cxx @@ -1423,10 +1423,7 @@ bool SwLayAction::FormatLayout( OutputDevice *pRenderContext, SwLayoutFrame *pLa PopFormatLayout(); } } - else if (!pLay->IsColBodyFrame()) - { // tdf#156724 unconditionally for frames in tables, so their footnotes exist before trying to split - pLow->OptCalc(); - } + // else: don't calc content frames any more if ( IsAgain() ) return false; diff --git a/sw/source/core/layout/tabfrm.cxx b/sw/source/core/layout/tabfrm.cxx index 2c6e7edc979a..efcca2c6aa41 100644 --- a/sw/source/core/layout/tabfrm.cxx +++ b/sw/source/core/layout/tabfrm.cxx @@ -646,7 +646,8 @@ inline void TableSplitRecalcLock( SwFlowFrame *pTab ) { pTab->LockJoin(); } inline void TableSplitRecalcUnlock( SwFlowFrame *pTab ) { pTab->UnlockJoin(); } static bool lcl_RecalcSplitLine( SwRowFrame& rLastLine, SwRowFrame& rFollowLine, - SwTwips nRemainingSpaceForLastRow, SwTwips nAlreadyFree ) + SwTwips nRemainingSpaceForLastRow, SwTwips nAlreadyFree, + bool & rIsFootnoteGrowth) { bool bRet = true; @@ -655,6 +656,34 @@ static bool lcl_RecalcSplitLine( SwRowFrame& rLastLine, SwRowFrame& rFollowLine, SwRectFnSet aRectFnSet(rTab.GetUpper()); SwTwips nCurLastLineHeight = aRectFnSet.GetHeight(rLastLine.getFrameArea()); + SwTwips nFootnoteHeight(0); + if (SwFootnoteBossFrame const*const pBoss = rTab.FindFootnoteBossFrame()) + { + if (SwFootnoteContFrame const*const pCont = pBoss->FindFootnoteCont()) + { + for (SwFootnoteFrame const* pFootnote = static_cast<SwFootnoteFrame const*>(pCont->Lower()); + pFootnote != nullptr; + pFootnote = static_cast<SwFootnoteFrame const*>(pFootnote->GetNext())) + { + SwContentFrame const*const pAnchor = pFootnote->GetRef(); + SwTabFrame const* pTab = pAnchor->FindTabFrame(); + if (pTab == &rTab) + { + while (pTab->GetUpper()->IsInTab()) + { + pTab = pTab->GetUpper()->FindTabFrame(); + } + // TODO currently do this only for top-level tables? + // otherwise would need to check rTab's follow and any upper table's follow? + if (pTab == &rTab) + { + nFootnoteHeight += aRectFnSet.GetHeight(pFootnote->getFrameArea()); + } + } + } + } + } + // If there are nested cells in rLastLine, the recalculation of the last // line needs some preprocessing. lcl_PreprocessRowsInCells( rTab, rLastLine, rFollowLine, nRemainingSpaceForLastRow ); @@ -759,8 +788,16 @@ static bool lcl_RecalcSplitLine( SwRowFrame& rLastLine, SwRowFrame& rFollowLine, { nFollowFootnotes += aRectFnSet.GetHeight(pFootnote->getFrameArea()); } + if (pTab == &rTab) + { + nFootnoteHeight -= aRectFnSet.GetHeight(pFootnote->getFrameArea()); + } } } + if (nFootnoteHeight < 0) + { // tdf#156724 footnotes have grown, try to split again + rIsFootnoteGrowth = true; + } } } if (nDistanceToUpperPrtBottom + nFollowFootnotes < 0 || !rTab.DoesObjsFit()) @@ -1020,7 +1057,8 @@ static bool lcl_FindSectionsInRow( const SwRowFrame& rRow ) return bRet; } -bool SwTabFrame::Split( const SwTwips nCutPos, bool bTryToSplit, bool bTableRowKeep ) +bool SwTabFrame::Split(const SwTwips nCutPos, bool bTryToSplit, + bool bTableRowKeep, bool & rIsFootnoteGrowth) { bool bRet = true; @@ -1358,7 +1396,7 @@ bool SwTabFrame::Split( const SwTwips nCutPos, bool bTryToSplit, bool bTableRowK // we also don't shrink here, because we will be doing that in lcl_RecalcSplitLine // recalculate the split line - bRet = lcl_RecalcSplitLine( *pLastRow, *pFollowRow, nRemainingSpaceForLastRow, nShrink ); + bRet = lcl_RecalcSplitLine(*pLastRow, *pFollowRow, nRemainingSpaceForLastRow, nShrink, rIsFootnoteGrowth); // RecalcSplitLine did not work. In this case we conceal the split error: if (!bRet && !bSplitRowAllowed) @@ -2590,7 +2628,10 @@ void SwTabFrame::MakeAll(vcl::RenderContext* pRenderContext) } oAccess.reset(); - const bool bSplitError = !Split( nDeadLine, bTryToSplit, ( bTableRowKeep && !(bAllowSplitOfRow || bEmulateTableKeepSplitAllowed) ) ); + bool isFootnoteGrowth(false); + const bool bSplitError = !Split(nDeadLine, bTryToSplit, + (bTableRowKeep && !(bAllowSplitOfRow || bEmulateTableKeepSplitAllowed)), + isFootnoteGrowth); // tdf#130639 don't start table on a new page after the fallback "switch off repeating header" if (bSplitError && nRepeat > GetTable()->GetRowsToRepeat()) @@ -2625,7 +2666,11 @@ void SwTabFrame::MakeAll(vcl::RenderContext* pRenderContext) { lcl_RecalcRow(*static_cast<SwRowFrame*>(Lower()), LONG_MAX); setFrameAreaPositionValid(false); - bTryToSplit = false; + // tdf#156724 if the table added footnotes, try to split *again* + if (!isFootnoteGrowth) + { + bTryToSplit = false; + } continue; } commit b6c5f64252b00d4f050cbf1d041a672621d784a5 Author: Michael Stahl <michael.st...@allotropia.de> AuthorDate: Mon Aug 14 17:27:52 2023 +0200 Commit: Mike Kaganski <mike.kagan...@collabora.com> CommitDate: Wed Aug 7 09:18:04 2024 +0500 tdf#156724 tdf#156722 sw: layout: remove IsPaintLocked() check Get rid of the problematic IsPaintLocked() and only check for a column parent; effectively this prevents formatting frames in columns even when loaded from the UI, so the layout will hopefully be the same regardless of how it is invoked. Change-Id: Ib4cc2efdb68ef4db73dcad01c7e1bd4be35de071 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/155673 Tested-by: Jenkins Reviewed-by: Michael Stahl <michael.st...@allotropia.de> diff --git a/sw/source/core/layout/layact.cxx b/sw/source/core/layout/layact.cxx index b044bbe358af..6c85d2d223d5 100644 --- a/sw/source/core/layout/layact.cxx +++ b/sw/source/core/layout/layact.cxx @@ -1423,7 +1423,7 @@ bool SwLayAction::FormatLayout( OutputDevice *pRenderContext, SwLayoutFrame *pLa PopFormatLayout(); } } - else if (m_pImp->GetShell()->IsPaintLocked() || !pLay->IsColBodyFrame()) + else if (!pLay->IsColBodyFrame()) { // tdf#156724 unconditionally for frames in tables, so their footnotes exist before trying to split pLow->OptCalc(); }