sw/source/core/inc/txtfrm.hxx      |    3 ++-
 sw/source/core/layout/calcmove.cxx |   28 ++++++++++++++++++++++++----
 sw/source/core/layout/layact.cxx   |    2 +-
 sw/source/core/layout/tabfrm.cxx   |    4 ++++
 sw/source/core/text/txtfrm.cxx     |   21 ++++++++++++++++-----
 5 files changed, 47 insertions(+), 11 deletions(-)

New commits:
commit 0a3f5169acc6708c352cad0fa07fdb4af8c8b2dd
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Thu Nov 28 14:28:58 2024 +0100
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Fri Nov 29 17:26:45 2024 +0100

    sw: layout: fix toggling Hidden Paragraphs resulting in bad layout
    
    1. SwContentFrame::MakeAll() needs some more checks to ensure that it
       never Formats a hidden text frame. This fixes the reported problem
       that turning off "Hidden Paragraphs" in Tools->Options->Writer->View
       results in bad layout (extra completely empty page at the end).
    
    3. This means HideAndShowObjects() must be called manually in that case
       as it was previously called inside Format(), see
       testHiddenSectionFlys.
    
    2. SwTextFrame::Prepare() as called from calcing some upper (table cell)
       in the bugdoc needs to avoid invalidating a hidden frame so it isn't
       formatted (triggered new assert).
    
    4. SwLayAction::IsShortCut() had what looks like an obvious and ancient
       mistake that was causing a crash in testTdf155011.
    
    5. SwTabFrame::MakeAll() should not calc the next if it's hidden, that
       was causing a problem in testThemeCrash where a hidden frame moved
       back into an overfull body and immediately forward again, triggering
       the new asserts.
    
    6. SwTextFrame::IsHiddenNow() caused interesting problem where some
       ancient (CVS import) check for a 0 width would skip the invalidating
       due to the 2. change when called from SwViewShell::Reformat() ...
       lcl_InvalidateContent() in testParagraphMarkInCell; unclear why this
       check exists, let's avoid it for the cases where we definitely know
       that only doc model should determine visibility.
    
    7. JunitTest_sw_unoapi_1 triggers new asserts because MakePos() in a
       cell ends up invalidating the text frame; fix it up again.
    
    (presumably regression from commit
     0c96119895b347f8eb5bb89f393351bd3c02b9f1 or one of its follow-ups)
    
    Change-Id: I619f4be852eca5124f49d9a91e1de658b7070074
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/177486
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>

diff --git a/sw/source/core/inc/txtfrm.hxx b/sw/source/core/inc/txtfrm.hxx
index 4a3ed2bba186..9d48e488316c 100644
--- a/sw/source/core/inc/txtfrm.hxx
+++ b/sw/source/core/inc/txtfrm.hxx
@@ -557,7 +557,8 @@ public:
 #endif
 
     /// Hidden
-    virtual bool IsHiddenNow() const override; // bHidden && pOut == pPrt
+    virtual bool IsHiddenNow() const override;
+    bool IsHiddenNowImpl() const;
     void HideHidden();              // Remove appendage if Hidden
     void HideFootnotes(TextFrameIndex nStart, TextFrameIndex nEnd);
 
diff --git a/sw/source/core/layout/calcmove.cxx 
b/sw/source/core/layout/calcmove.cxx
index 8f99488ca86b..5947a4858153 100644
--- a/sw/source/core/layout/calcmove.cxx
+++ b/sw/source/core/layout/calcmove.cxx
@@ -1297,8 +1297,12 @@ void SwContentFrame::MakeAll(vcl::RenderContext* 
/*pRenderContext*/)
         return;
     }
 
-    if (IsHiddenNow())
+    bool const isHiddenNow(static_cast<SwTextFrame*>(this)->IsHiddenNowImpl());
+    if (isHiddenNow)
+    {
         MakeValidZeroHeight();
+        HideAndShowObjects();
+    }
 
     std::optional<SwFrameDeleteGuard> oDeleteGuard(std::in_place, this);
     LockJoin();
@@ -1469,11 +1473,18 @@ void SwContentFrame::MakeAll(vcl::RenderContext* 
/*pRenderContext*/)
         aOldPrtPos = aRectFnSet.GetPos(getFramePrintArea());
 
         if ( !isFrameAreaPositionValid() )
+        {
             MakePos();
+            if (isHiddenNow && !isFrameAreaSizeValid())
+            {   // in a table cell, might be invalidated by ~SwLayNotify
+                MakeValidZeroHeight();
+            }
+        }
 
         //Set FixSize. VarSize is being adjusted by Format().
         if ( !isFrameAreaSizeValid() )
         {
+            assert(!isHiddenNow); // hidden frame must not be formatted
             // invalidate printing area flag, if the following conditions are 
hold:
             // - current frame width is 0.
             // - current printing area width is 0.
@@ -1510,6 +1521,7 @@ void SwContentFrame::MakeAll(vcl::RenderContext* 
/*pRenderContext*/)
         }
         if ( !isFramePrintAreaValid() )
         {
+            assert(!isHiddenNow); // hidden frame must not be formatted
             const tools::Long nOldW = aRectFnSet.GetWidth(getFramePrintArea());
             // #i34730# - keep current frame height
             const SwTwips nOldH = aRectFnSet.GetHeight(getFrameArea());
@@ -1546,7 +1558,7 @@ void SwContentFrame::MakeAll(vcl::RenderContext* 
/*pRenderContext*/)
         // Criteria:
         // - It needs to be movable (otherwise, splitting doesn't make sense)
         // - It needs to overlap with the lower edge of the PrtArea of the 
Upper
-        if ( !bMustFit )
+        if (!bMustFit && !isHiddenNow)
         {
             bool bWidow = true;
             const SwTwips nDeadLine = aRectFnSet.GetPrtBottom(*GetUpper());
@@ -1572,6 +1584,7 @@ void SwContentFrame::MakeAll(vcl::RenderContext* 
/*pRenderContext*/)
         }
         if ( !isFrameAreaSizeValid() )
         {
+            assert(!isHiddenNow); // hidden frame must not be formatted
             setFrameAreaSizeValid(true);
             bFormatted = true;
             ++nFormatCount;
@@ -1610,8 +1623,15 @@ void SwContentFrame::MakeAll(vcl::RenderContext* 
/*pRenderContext*/)
             pMoveBwdPre = pTemp;
             isMoveBwdPreValid = bTemp;
             bMovedBwd = true;
-            bFormatted = false;
-            if ( bKeep && bMoveable )
+            if (isHiddenNow)
+            {   // MoveBwd invalidated the size! Validate to prevent Format!
+                MakeValidZeroHeight();
+            }
+            else
+            {
+                bFormatted = false;
+            }
+            if (bKeep && bMoveable && !isHiddenNow)
             {
                 if( CheckMoveFwd( bMakePage, false, bMovedBwd ) )
                 {
diff --git a/sw/source/core/layout/layact.cxx b/sw/source/core/layout/layact.cxx
index b03fd1fe2380..98de8dc1370d 100644
--- a/sw/source/core/layout/layact.cxx
+++ b/sw/source/core/layout/layact.cxx
@@ -1105,7 +1105,7 @@ bool SwLayAction::IsShortCut( SwPageFrame *&prPage )
                 if ( pLst->IsInTab() )
                     pLst = pContent->FindTabFrame();
                 if ( pLst->IsInSct() )
-                    pLst = pContent->FindSctFrame();
+                    pLst = pLst->FindSctFrame();
                 pLst = pLst->FindPrev();
                 if ( pLst &&
                      (pLst->getFrameArea().Top() >= rVis.Bottom() ||
diff --git a/sw/source/core/layout/tabfrm.cxx b/sw/source/core/layout/tabfrm.cxx
index bedda6f8895a..ddc7e2646c93 100644
--- a/sw/source/core/layout/tabfrm.cxx
+++ b/sw/source/core/layout/tabfrm.cxx
@@ -3156,6 +3156,10 @@ void SwTabFrame::MakeAll(vcl::RenderContext* 
pRenderContext)
                                             bCalcNxt = false;
                                         }
                                     }
+                                    if (pNxt->IsHiddenNow())
+                                    {   // e.g. "testThemeCrash"
+                                        bCalcNxt = false;
+                                    }
                                     if ( bCalcNxt )
                                     {
                                         // tdf#119109 follow was just 
formatted,
diff --git a/sw/source/core/text/txtfrm.cxx b/sw/source/core/text/txtfrm.cxx
index 2067c2981ae4..126c0b93231e 100644
--- a/sw/source/core/text/txtfrm.cxx
+++ b/sw/source/core/text/txtfrm.cxx
@@ -1497,6 +1497,12 @@ bool SwTextFrame::IsHiddenNow() const
         return true;
     }
 
+    // TODO: what is the above check good for and can it be removed?
+    return IsHiddenNowImpl();
+}
+
+bool SwTextFrame::IsHiddenNowImpl() const
+{
     if (SwContentFrame::IsHiddenNow())
         return true;
 
@@ -2987,12 +2993,17 @@ bool SwTextFrame::Prepare( const PrepareHint ePrep, 
const void* pVoid,
 
     if( !HasPara() && !bSplitFlyAnchor && PrepareHint::MustFit != ePrep )
     {
-        SetInvalidVert( true ); // Test
         OSL_ENSURE( !IsLocked(), "SwTextFrame::Prepare: three of a perfect 
pair" );
-        if ( bNotify )
-            InvalidateSize();
-        else
-            InvalidateSize_();
+        // check while ignoring frame width (testParagraphMarkInCell)
+        // because it's called from InvalidateAllContent()
+        if (!IsHiddenNowImpl())
+        {
+            SetInvalidVert( true ); // Test
+            if ( bNotify )
+                InvalidateSize();
+            else
+                InvalidateSize_();
+        }
         return bParaPossiblyInvalid;
     }
 

Reply via email to