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

Reply via email to