sw/qa/extras/layout/layout3.cxx | 2 - sw/source/core/inc/tabfrm.hxx | 2 - sw/source/core/layout/frmtool.cxx | 7 +++ sw/source/core/layout/layact.cxx | 5 -- sw/source/core/layout/tabfrm.cxx | 68 ++++++++++++++++++++++++++++++++------ 5 files changed, 68 insertions(+), 16 deletions(-)
New commits: commit c303981cfd95ce1c3881366023d5495ae2edce97 Author: Michael Stahl <michael.st...@allotropia.de> AuthorDate: Wed Aug 23 15:50:59 2023 +0200 Commit: Michael Stahl <michael.st...@allotropia.de> CommitDate: Thu Aug 24 12:43:25 2023 +0200 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 28b48e7ec0c9..08020de73489 100644 --- a/sw/source/core/inc/tabfrm.hxx +++ b/sw/source/core/inc/tabfrm.hxx @@ -108,7 +108,7 @@ class SW_DLLPUBLIC SwTabFrame final: public SwLayoutFrame, public SwFlowFrame * 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 49d7573dd547..e7ee78a9ae6f 100644 --- a/sw/source/core/layout/layact.cxx +++ b/sw/source/core/layout/layact.cxx @@ -1431,10 +1431,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 4acef7ffe5d1..e4be17237e58 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; @@ -1381,7 +1419,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) @@ -2641,7 +2679,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()) @@ -2674,7 +2715,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 7b1c03ed87f7a21606e09863b23074e6b96e26d1 Author: Michael Stahl <michael.st...@allotropia.de> AuthorDate: Wed Aug 23 15:51:32 2023 +0200 Commit: Michael Stahl <michael.st...@allotropia.de> CommitDate: Thu Aug 24 12:43:19 2023 +0200 tdf#154775 sw: layout: avoid breaking this with following commits The problem with commit 1b5bc2ae2f19a190bf588a5a26c4d125c3960991 is that the fix only works in case the fly is invalid at the time when SwTabFrame::CalcFlyOffsets() is called; if it is valid (which will be the case with following commits, for non-obvious reasons) then the fix does nothing, causing testTablePrintAreaLeft to fail. In Word 2013, this fly causes the table to shift down, despite its HoriOrient being LEFT; so adapt SwTabFrame::CalcFlyOffsets() to also shift down in this case. Likely it would be best not to check HoriOrient at all for ShiftDown case, but needs checking first what Word does in other cases. Change-Id: I465a55bbf1a783abce8b8d6d65099bd9df5695f8 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/155987 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 ea2b963f76f9..4acef7ffe5d1 100644 --- a/sw/source/core/layout/tabfrm.cxx +++ b/sw/source/core/layout/tabfrm.cxx @@ -2969,9 +2969,12 @@ bool SwTabFrame::CalcFlyOffsets( SwTwips& rUpper, // text frame has already changed its page. const SwTextFrame* pAnchorCharFrame = pFly->FindAnchorCharFrame(); const SwFormatHoriOrient& rHori= pFly->GetFormat()->GetHoriOrient(); + // TODO: why not just ignore HoriOrient? + bool isHoriOrientShiftDown = + rHori.GetHoriOrient() == text::HoriOrientation::NONE + || rHori.GetHoriOrient() == text::HoriOrientation::LEFT; // Only consider invalid Writer fly frames if they'll be shifted down. - bool bIgnoreFlyValidity - = bAddVerticalFlyOffsets && rHori.GetHoriOrient() == text::HoriOrientation::NONE; + bool bIgnoreFlyValidity = bAddVerticalFlyOffsets && isHoriOrientShiftDown; bool bConsiderFly = // #i46807# - do not consider invalid // Writer fly frames. @@ -3027,8 +3030,7 @@ bool SwTabFrame::CalcFlyOffsets( SwTwips& rUpper, bool bShiftDown = css::text::WrapTextMode_NONE == nSurround; if (!bShiftDown && bAddVerticalFlyOffsets) { - if (nSurround == text::WrapTextMode_PARALLEL - && rHori.GetHoriOrient() == text::HoriOrientation::NONE) + if (nSurround == text::WrapTextMode_PARALLEL && isHoriOrientShiftDown) { // We know that wrapping was requested and the table frame overlaps with // the fly frame. Check if the print area overlaps with the fly frame as @@ -3090,7 +3092,8 @@ bool SwTabFrame::CalcFlyOffsets( SwTwips& rUpper, if ((css::text::WrapTextMode_RIGHT == nSurround || css::text::WrapTextMode_PARALLEL == nSurround) - && text::HoriOrientation::LEFT == rHori.GetHoriOrient()) + && text::HoriOrientation::LEFT == rHori.GetHoriOrient() + && !bShiftDown) { const tools::Long nWidth = aRectFnSet.XDiff(aRectFnSet.GetRight(aFlyRect), commit 492ddef596c99a9c24d2778276025aafc612a7cb Author: Michael Stahl <michael.st...@allotropia.de> AuthorDate: Wed Aug 23 15:49:44 2023 +0200 Commit: Michael Stahl <michael.st...@allotropia.de> CommitDate: Thu Aug 24 12:43:13 2023 +0200 tdf#137523 sw: layout: fix text below tables in footer differently This fix is better than commit 027f8328eef1e149b6c99b478ed5df870291dc2d because it turns out the last text frame had a height of 219 in 6.1. One of the following commits would break this, so a different fix is needed. In SwFrameNotify::ImplDestroy(), if the frame changes its position the next frame's position is invalidated; if the next frame is undersized then also invalidate its size so that it will be formatted again, with more space. Change-Id: I8e6a3fe3127ebfa2246c440d2a3455b217476475 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/155986 Tested-by: Jenkins Reviewed-by: Michael Stahl <michael.st...@allotropia.de> diff --git a/sw/qa/extras/layout/layout3.cxx b/sw/qa/extras/layout/layout3.cxx index 6322b3338f80..685e65bea085 100644 --- a/sw/qa/extras/layout/layout3.cxx +++ b/sw/qa/extras/layout/layout3.cxx @@ -106,7 +106,7 @@ CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf137523) // had wrong height and were not visible assertXPath(pXmlDoc, "/root/page/footer/txt[1]/infos/bounds", "height", "304"); assertXPath(pXmlDoc, "/root/page/footer/txt[2]/infos/bounds", "height", "191"); - assertXPath(pXmlDoc, "/root/page/footer/txt[3]/infos/bounds", "height", "153"); + assertXPath(pXmlDoc, "/root/page/footer/txt[3]/infos/bounds", "height", "219"); assertXPath(pXmlDoc, "/root/page/footer/tab/infos/bounds", "height", "1378"); } diff --git a/sw/source/core/layout/frmtool.cxx b/sw/source/core/layout/frmtool.cxx index bc8437391801..afe119c65e16 100644 --- a/sw/source/core/layout/frmtool.cxx +++ b/sw/source/core/layout/frmtool.cxx @@ -202,7 +202,14 @@ void SwFrameNotify::ImplDestroy() } if ( pNxt ) + { pNxt->InvalidatePos(); + if (pNxt->IsTextFrame() && static_cast<SwTextFrame*>(pNxt)->IsUndersized()) + { // tdf#137523 it could have more space at new pos + pNxt->InvalidateSize(); + pNxt->Prepare(PrepareHint::AdjustSizeWithoutFormatting); + } + } else { // #104100# - correct condition for setting retouche