sw/qa/extras/layout/data/tdf160958_orphans_move_section.fodt |   52 +++
 sw/qa/extras/layout/data/tdf160958_page_break.fodt           |   39 ++
 sw/qa/extras/layout/layout3.cxx                              |  169 +++++++++++
 sw/source/core/inc/frame.hxx                                 |   22 -
 sw/source/core/layout/calcmove.cxx                           |   14 
 sw/source/core/layout/colfrm.cxx                             |   16 -
 sw/source/core/layout/paintfrm.cxx                           |   49 +--
 sw/source/core/layout/sectfrm.cxx                            |   52 +++
 sw/source/core/layout/ssfrm.cxx                              |   36 +-
 sw/source/core/layout/wsfrm.cxx                              |   66 ++--
 10 files changed, 410 insertions(+), 105 deletions(-)

New commits:
commit ae92ffe8f058a86b35318517e6136701f1886d74
Author:     Mike Kaganski <mike.kagan...@collabora.com>
AuthorDate: Thu May 30 21:05:28 2024 +0500
Commit:     Mike Kaganski <mike.kagan...@collabora.com>
CommitDate: Fri May 31 09:25:40 2024 +0200

    Drop direct uses of SwRectFn; use SwRectFnSet instead
    
    Change-Id: I4eadf4fc132ef838581dcd6afdc9540195e80151
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/168268
    Tested-by: Jenkins
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>

diff --git a/sw/source/core/inc/frame.hxx b/sw/source/core/inc/frame.hxx
index 9972248e9744..13c196ad70cb 100644
--- a/sw/source/core/inc/frame.hxx
+++ b/sw/source/core/inc/frame.hxx
@@ -1372,19 +1372,17 @@ typedef SwRectFnCollection* SwRectFn;
 extern SwRectFn fnRectHori, fnRectVert, fnRectVertL2R, fnRectVertL2RB2T;
 class SwRectFnSet {
 public:
-    explicit SwRectFnSet(const SwFrame *pFrame)
-        : m_bVert(pFrame->IsVertical())
-        , m_bVertL2R(pFrame->IsVertLR())
-        , m_bVertL2RB2T(pFrame->IsVertLRBT())
-    {
-        m_fnRect = m_bVert ? (m_bVertL2R ? (m_bVertL2RB2T ? fnRectVertL2RB2T : 
fnRectVertL2R) : fnRectVert) : fnRectHori;
-    }
+    explicit SwRectFnSet(const SwFrame* pFrame) { Refresh(pFrame); }
+
+    explicit SwRectFnSet(bool vert, bool vL2R, bool vL2RB2T) { Refresh(vert, 
vL2R, vL2RB2T); }
+
+    void Refresh(const SwFrame* p) { Refresh(p->IsVertical(), p->IsVertLR(), 
p->IsVertLRBT()); }
 
-    void Refresh(const SwFrame *pFrame)
+    void Refresh(bool vert, bool vL2R, bool vL2RB2T)
     {
-        m_bVert = pFrame->IsVertical();
-        m_bVertL2R = pFrame->IsVertLR();
-        m_bVertL2RB2T = pFrame->IsVertLRBT();
+        m_bVert = vert;
+        m_bVertL2R = vL2R;
+        m_bVertL2RB2T = vL2RB2T;
         m_fnRect = m_bVert ? (m_bVertL2R ? (m_bVertL2RB2T ? fnRectVertL2RB2T : 
fnRectVertL2R) : fnRectVert) : fnRectHori;
     }
 
@@ -1438,7 +1436,7 @@ public:
     tools::Long  BottomDist(const SwRect& rRect, tools::Long nPos) const { 
return (rRect.*m_fnRect->fnBottomDist) (nPos); }
     tools::Long  LeftDist   (const SwRect& rRect, tools::Long nPos) const { 
return (rRect.*m_fnRect->fnLeftDist)    (nPos); }
     tools::Long  RightDist   (const SwRect& rRect, tools::Long nPos) const { 
return (rRect.*m_fnRect->fnRightDist)    (nPos); }
-    void  SetLimit (SwFrame& rFrame, tools::Long nNew) const { 
(rFrame.*m_fnRect->fnSetLimit) (nNew); }
+    bool  SetLimit (SwFrame& rFrame, tools::Long nNew) const { return 
(rFrame.*m_fnRect->fnSetLimit) (nNew); }
     bool  OverStep  (const SwRect& rRect, tools::Long nPos) const { return 
(rRect.*m_fnRect->fnOverStep)   (nPos); }
 
     void SetPos(SwRect& rRect, const Point& rNew) const { 
(rRect.*m_fnRect->fnSetPos)(rNew); }
diff --git a/sw/source/core/layout/calcmove.cxx 
b/sw/source/core/layout/calcmove.cxx
index dbd6ffe88b91..475420e32d78 100644
--- a/sw/source/core/layout/calcmove.cxx
+++ b/sw/source/core/layout/calcmove.cxx
@@ -968,7 +968,7 @@ void SwLayoutFrame::MakeAll(vcl::RenderContext* 
/*pRenderContext*/)
     if (IsHiddenNow())
         MakeValidZeroHeight();
 
-    SwRectFn fnRect = ( IsNeighbourFrame() == bVert )? fnRectHori : ( 
IsVertLR() ? (IsVertLRBT() ? fnRectVertL2RB2T : fnRectVertL2R) : fnRectVert );
+    SwRectFnSet fnRect(IsNeighbourFrame() != bVert, IsVertLR(), IsVertLRBT());
 
     std::optional<SwBorderAttrAccess> oAccess;
     const SwBorderAttrs*pAttrs = nullptr;
@@ -995,7 +995,7 @@ void SwLayoutFrame::MakeAll(vcl::RenderContext* 
/*pRenderContext*/)
                     // Set FixSize; VarSize is set by Format() after 
calculating the PrtArea
                     setFramePrintAreaValid(false);
 
-                    SwTwips nPrtWidth = 
(GetUpper()->getFramePrintArea().*fnRect->fnGetWidth)();
+                    SwTwips nPrtWidth = 
fnRect.GetWidth(GetUpper()->getFramePrintArea());
                     if( bVert && ( IsBodyFrame() || IsFootnoteContFrame() ) )
                     {
                         SwFrame* pNxt = GetPrev();
@@ -1010,24 +1010,24 @@ void SwLayoutFrame::MakeAll(vcl::RenderContext* 
/*pRenderContext*/)
                             nPrtWidth -= pNxt->getFrameArea().Height();
                     }
 
-                    const tools::Long nDiff = nPrtWidth - 
(getFrameArea().*fnRect->fnGetWidth)();
+                    const tools::Long nDiff = nPrtWidth - 
fnRect.GetWidth(getFrameArea());
                     SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
                     // SwRectFn switched between horizontal and vertical when 
bVert == IsNeighbourFrame().
                     // We pick fnSubLeft or fnAddRight that is correspondent 
to SwRectFn->fnAddBottom
                     if( ( IsCellFrame() && IsRightToLeft() ) || ( 
IsColumnFrame() && bVert && !IsVertLR() ) )
                     {
-                        (aFrm.*fnRect->fnSubLeft)( nDiff );
+                        fnRect.SubLeft(aFrm, nDiff);
                     }
                     else
                     {
-                        (aFrm.*fnRect->fnAddRight)( nDiff );
+                        fnRect.AddRight(aFrm, nDiff);
                     }
                 }
                 else
                 {
                     // Don't leave your upper
-                    const SwTwips nDeadLine = 
(GetUpper()->*fnRect->fnGetPrtBottom)();
-                    if( (getFrameArea().*fnRect->fnOverStep)( nDeadLine ) )
+                    const SwTwips nDeadLine = fnRect.GetPrtBottom(*GetUpper());
+                    if (fnRect.OverStep(getFrameArea(), nDeadLine))
                     {
                         setFrameAreaSizeValid(false);
                     }
diff --git a/sw/source/core/layout/colfrm.cxx b/sw/source/core/layout/colfrm.cxx
index 9847464b0758..e29b295c46da 100644
--- a/sw/source/core/layout/colfrm.cxx
+++ b/sw/source/core/layout/colfrm.cxx
@@ -318,9 +318,7 @@ void SwLayoutFrame::AdjustColumns( const SwFormatCol 
*pAttr, bool bAdjustAttribu
         return;
     }
 
-    const bool bVert = IsVertical();
-
-    SwRectFn fnRect = bVert ? ( IsVertLR() ? (IsVertLRBT() ? fnRectVertL2RB2T 
: fnRectVertL2R) : fnRectVert ) : fnRectHori;
+    SwRectFnSet fnRect(this);
 
     //If we have a pointer or we have to configure an attribute, we set the
     //column widths in any case. Otherwise we check if a configuration is 
needed.
@@ -329,11 +327,11 @@ void SwLayoutFrame::AdjustColumns( const SwFormatCol 
*pAttr, bool bAdjustAttribu
         pAttr = &GetFormat()->GetCol();
         if ( !bAdjustAttributes )
         {
-            tools::Long nAvail = (getFramePrintArea().*fnRect->fnGetWidth)();
+            tools::Long nAvail = fnRect.GetWidth(getFramePrintArea());
             for ( SwLayoutFrame *pCol = static_cast<SwLayoutFrame*>(Lower());
                   pCol;
                   pCol = static_cast<SwLayoutFrame*>(pCol->GetNext()) )
-                nAvail -= (pCol->getFrameArea().*fnRect->fnGetWidth)();
+                nAvail -= fnRect.GetWidth(pCol->getFrameArea());
             if ( !nAvail )
                 return;
         }
@@ -341,7 +339,7 @@ void SwLayoutFrame::AdjustColumns( const SwFormatCol 
*pAttr, bool bAdjustAttribu
 
     //The columns can now be easily adjusted.
     //The widths get counted so we can give the reminder to the last one.
-    SwTwips nAvail = (getFramePrintArea().*fnRect->fnGetWidth)();
+    SwTwips nAvail = fnRect.GetWidth(getFramePrintArea());
     const bool bLine = pAttr->GetLineAdj() != COLADJ_NONE;
     const sal_uInt16 nMin = bLine ? sal_uInt16( 20 + ( pAttr->GetLineWidth() / 
2) ) : 0;
 
@@ -360,9 +358,9 @@ void SwLayoutFrame::AdjustColumns( const SwFormatCol 
*pAttr, bool bAdjustAttribu
         {
             const SwTwips nWidth = i == (pAttr->GetNumCols() - 1) ?
                                    nAvail :
-                                   pAttr->CalcColWidth( i, sal_uInt16( 
(getFramePrintArea().*fnRect->fnGetWidth)() ) );
+                                   pAttr->CalcColWidth( i, sal_uInt16( 
fnRect.GetWidth(getFramePrintArea()) ) );
 
-            const Size aColSz = bVert ?
+            const Size aColSz = fnRect.IsVert() ?
                                 Size( getFramePrintArea().Width(), nWidth ) :
                                 Size( nWidth, getFramePrintArea().Height() );
 
@@ -445,7 +443,7 @@ void SwLayoutFrame::AdjustColumns( const SwFormatCol 
*pAttr, bool bAdjustAttribu
         if( nWidth < 0 )
             nWidth = 0;
 
-        const Size aColSz = bVert ?
+        const Size aColSz = fnRect.IsVert() ?
                             Size( getFramePrintArea().Width(), nWidth ) :
                             Size( nWidth, getFramePrintArea().Height() );
 
diff --git a/sw/source/core/layout/paintfrm.cxx 
b/sw/source/core/layout/paintfrm.cxx
index 47c9b105e10a..754495f2c8d4 100644
--- a/sw/source/core/layout/paintfrm.cxx
+++ b/sw/source/core/layout/paintfrm.cxx
@@ -1297,20 +1297,20 @@ static void lcl_CalcBorderRect( SwRect &rRect, const 
SwFrame *pFrame,
         rRect = pFrame->getFramePrintArea();
         rRect.Pos() += pFrame->getFrameArea().Pos();
 
-        SwRectFn fnRect = pFrame->IsVertical() ? ( pFrame->IsVertLR() ? 
(pFrame->IsVertLRBT() ? fnRectVertL2RB2T : fnRectVertL2R) : fnRectVert ) : 
fnRectHori;
+        SwRectFnSet fnRect(pFrame);
 
         const SvxBoxItem &rBox = rAttrs.GetBox();
-        const bool bTop = 0 != (pFrame->*fnRect->fnGetTopMargin)();
+        const bool bTop = 0 != fnRect.GetTopMargin(*pFrame);
         if ( bTop || rBox.GetTop() )
         {
             SwTwips nDiff = rBox.GetTop() ?
                 rBox.CalcLineSpace( SvxBoxItemLine::TOP, 
/*bEvenIfNoLine=*/false, /*bAllowNegative=*/true ) :
                 rBox.GetDistance( SvxBoxItemLine::TOP );
             if( nDiff )
-                (rRect.*fnRect->fnSubTop)( nDiff );
+                fnRect.SubTop(rRect, nDiff);
         }
 
-        const bool bBottom = 0 != (pFrame->*fnRect->fnGetBottomMargin)();
+        const bool bBottom = 0 != fnRect.GetBottomMargin(*pFrame);
         if ( bBottom )
         {
             SwTwips nDiff = 0;
@@ -1329,29 +1329,28 @@ static void lcl_CalcBorderRect( SwRect &rRect, const 
SwFrame *pFrame,
                     rBox.GetDistance( SvxBoxItemLine::BOTTOM );
             }
             if( nDiff )
-                (rRect.*fnRect->fnAddBottom)( nDiff );
+                fnRect.AddBottom(rRect, nDiff);
         }
 
         if ( rBox.GetLeft() )
-            (rRect.*fnRect->fnSubLeft)( rBox.CalcLineSpace( 
SvxBoxItemLine::LEFT ) );
+            fnRect.SubLeft(rRect, rBox.CalcLineSpace(SvxBoxItemLine::LEFT));
         else
-            (rRect.*fnRect->fnSubLeft)( rBox.GetDistance( SvxBoxItemLine::LEFT 
) );
+            fnRect.SubLeft(rRect, rBox.GetDistance(SvxBoxItemLine::LEFT));
 
         if ( rBox.GetRight() )
-            (rRect.*fnRect->fnAddRight)( rBox.CalcLineSpace( 
SvxBoxItemLine::RIGHT ) );
+            fnRect.AddRight(rRect, rBox.CalcLineSpace(SvxBoxItemLine::RIGHT));
         else
-            (rRect.*fnRect->fnAddRight)( rBox.GetDistance( 
SvxBoxItemLine::RIGHT ) );
+            fnRect.AddRight(rRect, rBox.GetDistance(SvxBoxItemLine::RIGHT));
 
         if ( bShadow && rAttrs.GetShadow().GetLocation() != 
SvxShadowLocation::NONE )
         {
             const SvxShadowItem &rShadow = rAttrs.GetShadow();
             if ( bTop )
-                
(rRect.*fnRect->fnSubTop)(rShadow.CalcShadowSpace(SvxShadowItemSide::TOP));
-            
(rRect.*fnRect->fnSubLeft)(rShadow.CalcShadowSpace(SvxShadowItemSide::LEFT));
+                fnRect.SubTop(rRect, 
rShadow.CalcShadowSpace(SvxShadowItemSide::TOP));
+            fnRect.SubLeft(rRect, 
rShadow.CalcShadowSpace(SvxShadowItemSide::LEFT));
             if ( bBottom )
-                (rRect.*fnRect->fnAddBottom)
-                                (rShadow.CalcShadowSpace( 
SvxShadowItemSide::BOTTOM ));
-            
(rRect.*fnRect->fnAddRight)(rShadow.CalcShadowSpace(SvxShadowItemSide::RIGHT));
+                fnRect.AddBottom(rRect, 
rShadow.CalcShadowSpace(SvxShadowItemSide::BOTTOM));
+            fnRect.AddRight(rRect, 
rShadow.CalcShadowSpace(SvxShadowItemSide::RIGHT));
         }
     }
 
@@ -5862,13 +5861,13 @@ void SwLayoutFrame::PaintColLines( const SwRect &rRect, 
const SwFormatCol &rForm
     if ( !pCol || !pCol->IsColumnFrame() )
         return;
 
-    SwRectFn fnRect = pCol->IsVertical() ? ( pCol->IsVertLR() ? 
(pCol->IsVertLRBT() ? fnRectVertL2RB2T : fnRectVertL2R) : fnRectVert ) : 
fnRectHori;
+    SwRectFnSet fnRect(pCol);
 
     SwRect aLineRect = getFramePrintArea();
     aLineRect += getFrameArea().Pos();
 
-    SwTwips nTop = 
((aLineRect.*fnRect->fnGetHeight)()*rFormatCol.GetLineHeight())
-                   / 100 - (aLineRect.*fnRect->fnGetHeight)();
+    SwTwips nTop = (fnRect.GetHeight(aLineRect)*rFormatCol.GetLineHeight())
+                   / 100 - fnRect.GetHeight(aLineRect);
     SwTwips nBottom = 0;
 
     switch ( rFormatCol.GetLineAdj() )
@@ -5884,23 +5883,23 @@ void SwLayoutFrame::PaintColLines( const SwRect &rRect, 
const SwFormatCol &rForm
     }
 
     if( nTop )
-        (aLineRect.*fnRect->fnSubTop)( nTop );
+        fnRect.SubTop(aLineRect, nTop);
     if( nBottom )
-        (aLineRect.*fnRect->fnAddBottom)( nBottom );
+        fnRect.AddBottom(aLineRect, nBottom);
 
     SwTwips nPenHalf = rFormatCol.GetLineWidth();
-    (aLineRect.*fnRect->fnSetWidth)( nPenHalf );
+    fnRect.SetWidth(aLineRect, nPenHalf);
     nPenHalf /= 2;
 
     //We need to be a bit generous here, to not lose something.
     SwRect aRect( rRect );
-    (aRect.*fnRect->fnSubLeft)( nPenHalf + gProp.nSPixelSzW );
-    (aRect.*fnRect->fnAddRight)( nPenHalf + gProp.nSPixelSzW );
-    SwRectGet fnGetX = IsRightToLeft() ? fnRect->fnGetLeft : 
fnRect->fnGetRight;
+    fnRect.SubLeft(aRect, nPenHalf + gProp.nSPixelSzW);
+    fnRect.AddRight(aRect, nPenHalf + gProp.nSPixelSzW);
     while ( pCol->GetNext() )
     {
-        (aLineRect.*fnRect->fnSetPosX)
-            ( (pCol->getFrameArea().*fnGetX)() - nPenHalf );
+        fnRect.SetPosX(aLineRect, (IsRightToLeft() ? 
fnRect.GetLeft(pCol->getFrameArea())
+                                                   : 
fnRect.GetRight(pCol->getFrameArea()))
+                                      - nPenHalf);
         if ( aRect.Overlaps( aLineRect ) )
             PaintBorderLine( aRect, aLineRect , pPage, 
&rFormatCol.GetLineColor(),
                    rFormatCol.GetLineStyle() );
diff --git a/sw/source/core/layout/ssfrm.cxx b/sw/source/core/layout/ssfrm.cxx
index 0c4934cdb495..3e2df0054299 100644
--- a/sw/source/core/layout/ssfrm.cxx
+++ b/sw/source/core/layout/ssfrm.cxx
@@ -597,11 +597,9 @@ SwRect SwFrame::GetPaintArea() const
     // NEW TABLES
     // Cell frames may not leave their upper:
     SwRect aRect = IsRowFrame() ? GetUpper()->getFrameArea() : getFrameArea();
-    const bool bVert = IsVertical();
-    SwRectFn fnRect = bVert ? ( IsVertLR() ? (IsVertLRBT() ? fnRectVertL2RB2T 
: fnRectVertL2R) : fnRectVert ) : fnRectHori;
     SwRectFnSet aRectFnSet(this);
-    tools::Long nRight = (aRect.*fnRect->fnGetRight)();
-    tools::Long nLeft  = (aRect.*fnRect->fnGetLeft)();
+    tools::Long nRight = aRectFnSet.GetRight(aRect);
+    tools::Long nLeft  = aRectFnSet.GetLeft(aRect);
     const SwFrame* pTmp = this;
     bool bLeft = true;
     bool bRight = true;
@@ -611,15 +609,15 @@ SwRect SwFrame::GetPaintArea() const
         if( pTmp->IsCellFrame() && pTmp->GetUpper() &&
             pTmp->GetUpper()->IsVertical() != pTmp->IsVertical() )
             nRowSpan = static_cast<const 
SwCellFrame*>(pTmp)->GetTabBox()->getRowSpan();
-        tools::Long nTmpRight = (pTmp->getFrameArea().*fnRect->fnGetRight)();
-        tools::Long nTmpLeft = (pTmp->getFrameArea().*fnRect->fnGetLeft)();
+        tools::Long nTmpRight = aRectFnSet.GetRight(pTmp->getFrameArea());
+        tools::Long nTmpLeft = aRectFnSet.GetLeft(pTmp->getFrameArea());
         if( pTmp->IsRowFrame() && nRowSpan > 1 )
         {
             const SwFrame* pNxt = pTmp;
             while( --nRowSpan > 0 && pNxt->GetNext() )
                 pNxt = pNxt->GetNext();
             if( pTmp->IsVertical() )
-                nTmpLeft = (pNxt->getFrameArea().*fnRect->fnGetLeft)();
+                nTmpLeft = aRectFnSet.GetLeft(pNxt->getFrameArea());
             else
             {
                 // pTmp is a row frame, but it's not vertical.
@@ -627,11 +625,11 @@ SwRect SwFrame::GetPaintArea() const
                 {
                     // This frame cell is OK to expand towards the physical 
down direction.
                     // Physical down is left.
-                    nTmpLeft = (pNxt->getFrameArea().*fnRect->fnGetLeft)();
+                    nTmpLeft = aRectFnSet.GetLeft(pNxt->getFrameArea());
                 }
                 else
                 {
-                    nTmpRight = (pNxt->getFrameArea().*fnRect->fnGetRight)();
+                    nTmpRight = aRectFnSet.GetRight(pNxt->getFrameArea());
                 }
             }
         }
@@ -668,7 +666,7 @@ SwRect SwFrame::GetPaintArea() const
                 bRight = false;
             }
         }
-        else if( bVert && pTmp->IsBodyFrame() )
+        else if (aRectFnSet.IsVert() && pTmp->IsBodyFrame())
         {
             // Header and footer frames have always horizontal direction and
             // limit the body frame.
@@ -691,8 +689,8 @@ SwRect SwFrame::GetPaintArea() const
         }
         pTmp = pTmp->GetUpper();
     }
-    (aRect.*fnRect->fnSetLeft)( nLeft );
-    (aRect.*fnRect->fnSetRight)( nRight );
+    aRectFnSet.SetLeft(aRect, nLeft);
+    aRectFnSet.SetRight(aRect, nRight);
     return aRect;
 }
 
@@ -702,13 +700,11 @@ SwRect SwFrame::GetPaintArea() const
 |*/
 SwRect SwFrame::UnionFrame( bool bBorder ) const
 {
-    bool bVert = IsVertical();
-    SwRectFn fnRect = bVert ? ( IsVertLR() ? (IsVertLRBT() ? fnRectVertL2RB2T 
: fnRectVertL2R) : fnRectVert ) : fnRectHori;
-    tools::Long nLeft = (getFrameArea().*fnRect->fnGetLeft)();
-    tools::Long nWidth = (getFrameArea().*fnRect->fnGetWidth)();
-    tools::Long nPrtLeft = (getFramePrintArea().*fnRect->fnGetLeft)();
-    tools::Long nPrtWidth = (getFramePrintArea().*fnRect->fnGetWidth)();
     SwRectFnSet aRectFnSet(this);
+    tools::Long nLeft = aRectFnSet.GetLeft(getFrameArea());
+    tools::Long nWidth = aRectFnSet.GetWidth(getFrameArea());
+    tools::Long nPrtLeft = aRectFnSet.GetLeft(getFramePrintArea());
+    tools::Long nPrtWidth = aRectFnSet.GetWidth(getFramePrintArea());
     if (aRectFnSet.XInc(nPrtLeft, nPrtWidth) > nWidth)
         nWidth = nPrtLeft + nPrtWidth;
     if( nPrtLeft < 0 )
@@ -746,8 +742,8 @@ SwRect SwFrame::UnionFrame( bool bBorder ) const
     }
     nWidth = aRectFnSet.XDiff(aRectFnSet.XInc(nRight, nAdd), nLeft);
     SwRect aRet( getFrameArea() );
-    (aRet.*fnRect->fnSetLeft)(nLeft);
-    (aRet.*fnRect->fnSetWidth)( nWidth );
+    aRectFnSet.SetLeft(aRet, nLeft);
+    aRectFnSet.SetWidth(aRet, nWidth);
     return aRet;
 }
 
diff --git a/sw/source/core/layout/wsfrm.cxx b/sw/source/core/layout/wsfrm.cxx
index 68035e025695..455a091a611b 100644
--- a/sw/source/core/layout/wsfrm.cxx
+++ b/sw/source/core/layout/wsfrm.cxx
@@ -779,16 +779,16 @@ Size SwFrame::ChgSize( const Size& aNewSize )
     if ( GetUpper() )
     {
         bool bNeighb = IsNeighbourFrame();
-        SwRectFn fnRect = IsVertical() == bNeighb ? fnRectHori : ( IsVertLR() 
? (IsVertLRBT() ? fnRectVertL2RB2T : fnRectVertL2R) : fnRectVert );
+        SwRectFnSet fnRect(IsVertical() != bNeighb, IsVertLR(), IsVertLRBT());
         SwRect aNew( Point(0,0), aNewSize );
 
         {
             SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
-            (aFrm.*fnRect->fnSetWidth)( (aNew.*fnRect->fnGetWidth)() );
+            fnRect.SetWidth(aFrm, fnRect.GetWidth(aNew));
         }
 
-        tools::Long nNew = (aNew.*fnRect->fnGetHeight)();
-        tools::Long nDiff = nNew - (getFrameArea().*fnRect->fnGetHeight)();
+        tools::Long nNew = fnRect.GetHeight(aNew);
+        tools::Long nDiff = nNew - fnRect.GetHeight(getFrameArea());
 
         if( nDiff )
         {
@@ -798,7 +798,7 @@ Size SwFrame::ChgSize( const Size& aNewSize )
             {
                 {
                     SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
-                    (aFrm.*fnRect->fnSetHeight)( nNew );
+                    fnRect.SetHeight(aFrm, nNew);
                 }
 
                 SwTwips nReal = 
static_cast<SwLayoutFrame*>(this)->AdjustNeighbourhood(nDiff);
@@ -806,7 +806,7 @@ Size SwFrame::ChgSize( const Size& aNewSize )
                 if ( nReal != nDiff )
                 {
                     SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
-                    (aFrm.*fnRect->fnSetHeight)( nNew - nDiff + nReal );
+                    fnRect.SetHeight(aFrm, nNew - nDiff + nReal);
                 }
             }
             else
@@ -820,7 +820,7 @@ Size SwFrame::ChgSize( const Size& aNewSize )
                     else
                         Shrink( -nDiff );
 
-                    if ( GetUpper() && (getFrameArea().*fnRect->fnGetHeight)() 
!= nNew )
+                    if (GetUpper() && fnRect.GetHeight(getFrameArea()) != nNew)
                     {
                         GetUpper()->InvalidateSize_();
                     }
@@ -830,7 +830,7 @@ Size SwFrame::ChgSize( const Size& aNewSize )
                 // example when called by ChgColumns to set the column width, 
we
                 // set the right width now.
                 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
-                (aFrm.*fnRect->fnSetHeight)( nNew );
+                fnRect.SetHeight(aFrm, nNew);
             }
         }
     }
@@ -1415,15 +1415,18 @@ void SwLayoutFrame::Paste( SwFrame* pParent, SwFrame* 
pSibling)
     //      in horizontal layout the other way around
     //          --> <fnRect> = fnRectHori
     //SwRectFn fnRect = IsVertical() ? fnRectHori : fnRectVert;
-    SwRectFn fnRect;
+    bool bVert, bVertL2R, bVertL2RB2T;
     if ( IsHeaderFrame() || IsFooterFrame() )
-        fnRect = fnRectHori;
-    else if ( IsCellFrame() || IsColumnFrame() )
-        fnRect = GetUpper()->IsVertical() ? fnRectHori : ( 
GetUpper()->IsVertLR() ? (GetUpper()->IsVertLRBT() ? fnRectVertL2RB2T : 
fnRectVertL2R) : fnRectVert );
+        bVert = bVertL2R = bVertL2RB2T = false;
     else
-        fnRect = GetUpper()->IsVertical() ? ( GetUpper()->IsVertLR() ? 
(GetUpper()->IsVertLRBT() ? fnRectVertL2RB2T : fnRectVertL2R) : fnRectVert ) : 
fnRectHori;
+    {
+        bVert = (IsCellFrame() || IsColumnFrame()) ? !GetUpper()->IsVertical() 
: GetUpper()->IsVertical();
+        bVertL2R = GetUpper()->IsVertLR();
+        bVertL2RB2T = GetUpper()->IsVertLRBT();
+    }
+    SwRectFnSet fnRect(bVert, bVertL2R, bVertL2RB2T);
 
-    if( (getFrameArea().*fnRect->fnGetWidth)() != 
(pParent->getFramePrintArea().*fnRect->fnGetWidth)())
+    if (fnRect.GetWidth(getFrameArea()) != 
fnRect.GetWidth(pParent->getFramePrintArea()))
         InvalidateSize_();
     InvalidatePos_();
     const SwPageFrame *pPage = FindPageFrame();
@@ -1451,7 +1454,7 @@ void SwLayoutFrame::Paste( SwFrame* pParent, SwFrame* 
pSibling)
         }
     }
 
-    if( !(getFrameArea().*fnRect->fnGetHeight)() )
+    if (!fnRect.GetHeight(getFrameArea()))
         return;
 
     // AdjustNeighbourhood is now also called in columns which are not
@@ -1459,7 +1462,7 @@ void SwLayoutFrame::Paste( SwFrame* pParent, SwFrame* 
pSibling)
     SwNeighbourAdjust nAdjust = GetUpper()->IsFootnoteBossFrame() ?
             
static_cast<SwFootnoteBossFrame*>(GetUpper())->NeighbourhoodAdjustment()
             : SwNeighbourAdjust::GrowShrink;
-    SwTwips nGrow = (getFrameArea().*fnRect->fnGetHeight)();
+    SwTwips nGrow = fnRect.GetHeight(getFrameArea());
     if( SwNeighbourAdjust::OnlyAdjust == nAdjust )
         AdjustNeighbourhood( nGrow );
     else
@@ -3543,13 +3546,12 @@ void SwLayoutFrame::Format( vcl::RenderContext* 
/*pRenderContext*/, const SwBord
     const sal_uInt16 nRight = 
o3tl::narrowing<sal_uInt16>(pAttrs->CalcRight(this));
     const sal_uInt16 nLower = bHideWhitespace ? 0 : pAttrs->CalcBottom();
 
-    const bool bVert = IsVertical() && !IsPageFrame();
-    SwRectFn fnRect = bVert ? ( IsVertLR() ? (IsVertLRBT() ? fnRectVertL2RB2T 
: fnRectVertL2R) : fnRectVert ) : fnRectHori;
+    SwRectFnSet fnRect(IsVertical() && !IsPageFrame(), IsVertLR(), 
IsVertLRBT());
     if ( !isFramePrintAreaValid() )
     {
         setFramePrintAreaValid(true);
-        (this->*fnRect->fnSetXMargins)( nLeft, nRight );
-        (this->*fnRect->fnSetYMargins)( nUpper, nLower );
+        fnRect.SetXMargins(*this, nLeft, nRight);
+        fnRect.SetYMargins(*this, nUpper, nLower);
     }
 
     if ( isFrameAreaSizeValid() )
@@ -3569,20 +3571,20 @@ void SwLayoutFrame::Format( vcl::RenderContext* 
/*pRenderContext*/, const SwBord
             SwTwips nRemaining = 0;
             SwFrame *pFrame = Lower();
             while ( pFrame )
-            {   nRemaining += (pFrame->getFrameArea().*fnRect->fnGetHeight)();
+            {   nRemaining += fnRect.GetHeight(pFrame->getFrameArea());
                 if( pFrame->IsTextFrame() && 
static_cast<SwTextFrame*>(pFrame)->IsUndersized() )
                 // This TextFrame would like to be a bit bigger
                     nRemaining += 
static_cast<SwTextFrame*>(pFrame)->GetParHeight()
-                                  - 
(pFrame->getFramePrintArea().*fnRect->fnGetHeight)();
+                                  - 
fnRect.GetHeight(pFrame->getFramePrintArea());
                 else if( pFrame->IsSctFrame() && 
static_cast<SwSectionFrame*>(pFrame)->IsUndersized() )
                     nRemaining += 
static_cast<SwSectionFrame*>(pFrame)->Undersize();
                 pFrame = pFrame->GetNext();
             }
             nRemaining += nBorder;
             nRemaining = std::max( nRemaining, nMinHeight );
-            const SwTwips nDiff = 
nRemaining-(getFrameArea().*fnRect->fnGetHeight)();
-            const tools::Long nOldLeft = (getFrameArea().*fnRect->fnGetLeft)();
-            const tools::Long nOldTop = (getFrameArea().*fnRect->fnGetTop)();
+            const SwTwips nDiff = nRemaining - 
fnRect.GetHeight(getFrameArea());
+            const tools::Long nOldLeft = fnRect.GetLeft(getFrameArea());
+            const tools::Long nOldTop = fnRect.GetTop(getFrameArea());
             if ( nDiff )
             {
                 if ( nDiff > 0 )
@@ -3593,12 +3595,12 @@ void SwLayoutFrame::Format( vcl::RenderContext* 
/*pRenderContext*/, const SwBord
                 MakePos();
             }
             //Don't exceed the bottom edge of the Upper.
-            if ( GetUpper() && (getFrameArea().*fnRect->fnGetHeight)() )
+            if (GetUpper() && fnRect.GetHeight(getFrameArea()))
             {
-                const SwTwips nLimit = (GetUpper()->*fnRect->fnGetPrtBottom)();
-                if( (this->*fnRect->fnSetLimit)( nLimit ) &&
-                    nOldLeft == (getFrameArea().*fnRect->fnGetLeft)() &&
-                    nOldTop  == (getFrameArea().*fnRect->fnGetTop)() )
+                const SwTwips nLimit = fnRect.GetPrtBottom(*GetUpper());
+                if( fnRect.SetLimit(*this, nLimit) &&
+                    nOldLeft == fnRect.GetLeft(getFrameArea()) &&
+                    nOldTop  == fnRect.GetTop(getFrameArea()) )
                 {
                     setFrameAreaSizeValid(true);
                     setFramePrintAreaValid(true);
@@ -3627,8 +3629,8 @@ void SwLayoutFrame::Format( vcl::RenderContext* 
/*pRenderContext*/, const SwBord
     if (!isFramePrintAreaValid())
     {
         setFramePrintAreaValid(true);
-        (this->*fnRect->fnSetXMargins)(nLeft, nRight);
-        (this->*fnRect->fnSetYMargins)(nUpper, nLower);
+        fnRect.SetXMargins(*this, nLeft, nRight);
+        fnRect.SetYMargins(*this, nUpper, nLower);
     }
 }
 
commit c60ad7e0fbf3cc86af167f5e98b38c25620ada7e
Author:     Mike Kaganski <mike.kagan...@collabora.com>
AuthorDate: Thu May 30 02:23:02 2024 +0500
Commit:     Mike Kaganski <mike.kagan...@collabora.com>
CommitDate: Fri May 31 09:25:33 2024 +0200

    tdf#160958: merge hidden section's follows; move first-on-page section back
    
    Change-Id: I6bd6707089dcea58d5df4bef63aa769769d97ea9
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/168235
    Tested-by: Jenkins
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>

diff --git a/sw/qa/extras/layout/data/tdf160958_orphans_move_section.fodt 
b/sw/qa/extras/layout/data/tdf160958_orphans_move_section.fodt
new file mode 100644
index 000000000000..1306cfa6226d
--- /dev/null
+++ b/sw/qa/extras/layout/data/tdf160958_orphans_move_section.fodt
@@ -0,0 +1,52 @@
+<?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" 
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="&apos;Liberation Serif&apos;" 
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: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:page-layout style:name="pm1">
+   <style:page-layout-properties fo:page-width="21cm" fo:page-height="297mm" 
style:print-orientation="portrait" fo:margin-top="2cm" fo:margin-bottom="2cm" 
fo:margin-left="2cm" fo:margin-right="2cm"/>
+  </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>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum 
consequat mi quis pretium semper. Proin luctus orci ac neque venenatis, quis 
commodo dolor posuere. Curabitur dignissim sapien quis cursus egestas. Donec 
blandit auctor arcu, nec pellentesque eros molestie eget. In consectetur 
aliquam hendrerit. Sed cursus mauris vitae ligula pellentesque, non 
pellentesque urna aliquet. Fusce placerat mauris enim, nec rutrum purus semper 
vel. Praesent tincidunt neque eu pellentesque pharetra. Fusce pellentesque est 
orci.</text:p>
+   <text:p>Integer sodales tincidunt tristique. Sed a metus posuere, 
adipiscing nunc et, viverra odio. Donec auctor molestie sem, sit amet tristique 
lectus hendrerit sed. Cras sodales nisl sed orci mattis iaculis. Nunc eget 
dolor accumsan, pharetra risus a, vestibulum mauris. Nunc vulputate lobortis 
mollis. Vivamus nec tellus faucibus, tempor magna nec, facilisis felis. Donec 
commodo enim a vehicula pellentesque. Nullam vehicula vestibulum est vel 
ultricies.</text:p>
+   <text:p>Aliquam velit massa, laoreet vel leo nec, volutpat facilisis eros. 
Donec consequat arcu ut diam tempor luctus. Cum sociis natoque penatibus et 
magnis dis parturient montes, nascetur ridiculus mus. Praesent vitae lacus vel 
leo sodales pharetra a a nibh. Vestibulum ante ipsum primis in faucibus orci 
luctus et ultrices posuere cubilia Curae; Nam luctus tempus nibh, fringilla 
dictum augue consectetur eget. Curabitur at ante sit amet tortor pharetra 
molestie eu nec ante. Mauris tincidunt, nibh eu sollicitudin molestie, dolor 
sapien congue tortor, a pulvinar sapien turpis sed ante. Donec nec est 
elementum, euismod nulla in, mollis nunc.</text:p>
+   <text:p>He heard quiet steps behind him. That didn&apos;t bode well. Who 
could be following him this late at night and in this deadbeat part of town? 
And at this particular moment, just after he pulled off the big time and was 
making off with the greenbacks. Was there another crook who&apos;d had the same 
idea, and was now watching him and waiting for a chance to grab the fruit of 
his labor? Or did the steps behind him mean that one of many law officers in 
town was on to him and just waiting to pounce and snap those cuffs on his 
wrists? He nervously looked all around. Suddenly he saw the alley. Like 
lightning he darted off to the left and disappeared between the two warehouses 
almost falling over the trash can lying in the middle of the sidewalk. He tried 
to nervously tap his way along in the inky darkness and suddenly stiffened: it 
was a dead-end, he would have to go back the way he had come. The steps got 
louder and louder, he saw the black outline of a figure coming around the
  corner. Is this the end of the line? he thought pressing himself back against 
the wall trying to make himself invisible in the dark, was all that planning 
and energy wasted? He was dripping with sweat now, cold and wet, he could smell 
the fear coming off his clothes. Suddenly next to him, with a barely noticeable 
squeak, a door swung quietly to and fro in the night&apos;s breeze. Could this 
be the haven he&apos;d prayed for? Slowly he slid toward the door, pressing 
himself more and more into the wall, into the dark, away from his enemy. Would 
this door save his hide?</text:p>
+   <text:p>foo</text:p>
+   <text:p>bar</text:p>
+   <text:p>baz</text:p>
+   <text:p>foo</text:p>
+   <text:p>bar</text:p>
+   <text:p>baz</text:p>
+   <text:p>foo</text:p>
+   <text:p>bar</text:p>
+   <text:p>baz</text:p>
+   <text:p>foo</text:p>
+   <text:p>bar</text:p>
+   <text:p>baz</text:p>
+   <text:p>foo</text:p>
+   <text:p>bar</text:p>
+   <text:p>baz</text:p>
+   <text:p>foo</text:p>
+   <text:p>bar</text:p>
+   <text:section text:name="Section1">
+    <text:p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. 
Vestibulum consequat mi quis pretium semper. Proin luctus orci ac neque 
venenatis, quis commodo dolor posuere. Curabitur dignissim sapien quis cursus 
egestas. Donec blandit auctor arcu, nec pellentesque eros molestie eget. In 
consectetur aliquam hendrerit. Sed cursus mauris vitae ligula pellentesque, non 
pellentesque urna aliquet. Fusce placerat mauris enim, nec rutrum purus semper 
vel. Praesent tincidunt neque eu pellentesque pharetra. Fusce pellentesque est 
orci.</text:p>
+    <text:p>Integer sodales tincidunt tristique. Sed a metus posuere, 
adipiscing nunc et, viverra odio. Donec auctor molestie sem, sit amet tristique 
lectus hendrerit sed. Cras sodales nisl sed orci mattis iaculis. Nunc eget 
dolor accumsan, pharetra risus a, vestibulum mauris. Nunc vulputate lobortis 
mollis. Vivamus nec tellus faucibus, tempor magna nec, facilisis felis. Donec 
commodo enim a vehicula pellentesque. Nullam vehicula vestibulum est vel 
ultricies.</text:p>
+    <text:p>Aliquam velit massa, laoreet vel leo nec, volutpat facilisis eros. 
Donec consequat arcu ut diam tempor luctus. Cum sociis natoque penatibus et 
magnis dis parturient montes, nascetur ridiculus mus. Praesent vitae lacus vel 
leo sodales pharetra a a nibh. Vestibulum ante ipsum primis in faucibus orci 
luctus et ultrices posuere cubilia Curae; Nam luctus tempus nibh, fringilla 
dictum augue consectetur eget. Curabitur at ante sit amet tortor pharetra 
molestie eu nec ante. Mauris tincidunt, nibh eu sollicitudin molestie, dolor 
sapien congue tortor, a pulvinar sapien turpis sed ante. Donec nec est 
elementum, euismod nulla in, mollis nunc.</text:p>
+   </text:section>
+   <text:p>baz</text:p>
+  </office:text>
+ </office:body>
+</office:document>
\ No newline at end of file
diff --git a/sw/qa/extras/layout/data/tdf160958_page_break.fodt 
b/sw/qa/extras/layout/data/tdf160958_page_break.fodt
new file mode 100644
index 000000000000..1d4d8863b073
--- /dev/null
+++ b/sw/qa/extras/layout/data/tdf160958_page_break.fodt
@@ -0,0 +1,39 @@
+<?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" 
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="&apos;Liberation Serif&apos;" 
style:font-family-generic="roman" style:font-pitch="variable"/>
+ </office:font-face-decls>
+ <office:styles>
+  <style:default-style style:family="paragraph">
+   <style:text-properties style:use-window-font-color="true" 
style:font-name="Liberation Serif" fo:font-size="12pt"/>
+  </style:default-style>
+ </office:styles>
+ <office:automatic-styles>
+  <style:style style:name="P1" style:family="paragraph" 
style:master-page-name="">
+   <style:paragraph-properties style:page-number="auto" 
fo:break-before="page"/>
+  </style:style>
+  <style:page-layout style:name="pm1">
+   <style:page-layout-properties fo:page-width="21cm" fo:page-height="297mm" 
style:num-format="1" style:print-orientation="portrait" fo:margin-top="2cm" 
fo:margin-bottom="2cm" fo:margin-left="2cm" fo:margin-right="2cm"/>
+  </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>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum 
consequat mi quis pretium semper. Proin luctus orci ac neque venenatis, quis 
commodo dolor posuere. Curabitur dignissim sapien quis cursus egestas. Donec 
blandit auctor arcu, nec pellentesque eros molestie eget. In consectetur 
aliquam hendrerit. Sed cursus mauris vitae ligula pellentesque, non 
pellentesque urna aliquet. Fusce placerat mauris enim, nec rutrum purus semper 
vel. Praesent tincidunt neque eu pellentesque pharetra. Fusce pellentesque est 
orci.</text:p>
+   <text:section text:name="Section1">
+    <text:p text:style-name="P1"/>
+    <text:p/>
+    <text:p/>
+    <text:p>Integer sodales tincidunt tristique. Sed a metus posuere, 
adipiscing nunc et, viverra odio. Donec auctor molestie sem, sit amet tristique 
lectus hendrerit sed. Cras sodales nisl sed orci mattis iaculis. Nunc eget 
dolor accumsan, pharetra risus a, vestibulum mauris. Nunc vulputate lobortis 
mollis. <text:soft-page-break/>Vivamus nec tellus faucibus, tempor magna nec, 
facilisis felis. Donec commodo enim a vehicula pellentesque. Nullam vehicula 
vestibulum est vel ultricies.</text:p>
+    <text:p/>
+    <text:p/>
+    <text:p/>
+   </text:section>
+   <text:p>Aliquam velit massa, laoreet vel leo nec, volutpat facilisis eros. 
Donec consequat arcu ut diam tempor luctus. Cum sociis natoque penatibus et 
magnis dis parturient montes, nascetur ridiculus mus. Praesent vitae lacus vel 
leo sodales pharetra a a nibh. Vestibulum ante ipsum primis in faucibus orci 
luctus et ultrices posuere cubilia Curae; Nam luctus tempus nibh, fringilla 
dictum augue consectetur eget. Curabitur at ante sit amet tortor pharetra 
molestie eu nec ante. Mauris tincidunt, nibh eu sollicitudin molestie, dolor 
sapien congue tortor, a pulvinar sapien turpis sed ante. Donec nec est 
elementum, euismod nulla in, mollis nunc.</text:p>
+   <text:p/>
+  </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 329c81847313..b5f013df689a 100644
--- a/sw/qa/extras/layout/layout3.cxx
+++ b/sw/qa/extras/layout/layout3.cxx
@@ -11,6 +11,7 @@
 #include <comphelper/propertysequence.hxx>
 #include <com/sun/star/linguistic2/XHyphenator.hpp>
 #include <com/sun/star/text/WrapTextMode.hpp>
+#include <com/sun/star/text/XTextSectionsSupplier.hpp>
 #include <vcl/event.hxx>
 #include <vcl/scheduler.hxx>
 #include <editeng/fontitem.hxx>
@@ -2638,6 +2639,174 @@ CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf160526)
     assertXPath(pExportDump, 
"//page[2]/body/txt/anchored/SwAnchoredDrawObject"_ostr);
 }
 
+CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf160958_page_break)
+{
+    // Given a document with a section with the first paragraph having a page 
break
+    createSwDoc("tdf160958_page_break.fodt");
+    auto pExportDump = parseLayoutDump();
+    assertXPath(pExportDump, "//page"_ostr, 2);
+    // A single paragraph on the first page, with 6 lines
+    assertXPath(pExportDump, "//page[1]/body/txt"_ostr, 1);
+    assertXPath(pExportDump, 
"//page[1]/body/txt/SwParaPortion/SwLineLayout"_ostr, 6);
+    // A section with 7 paragraphs, and two more paragraphs after the section
+    assertXPath(pExportDump, "//page[2]/body/section"_ostr, 1);
+    assertXPath(pExportDump, "//page[2]/body/section/txt"_ostr, 7);
+    assertXPath(pExportDump, 
"//page[2]/body/section/txt[1]/SwParaPortion"_ostr, 0);
+    assertXPath(pExportDump, 
"//page[2]/body/section/txt[2]/SwParaPortion"_ostr, 0);
+    assertXPath(pExportDump, 
"//page[2]/body/section/txt[3]/SwParaPortion"_ostr, 0);
+    assertXPath(pExportDump, 
"//page[2]/body/section/txt[4]/SwParaPortion/SwLineLayout"_ostr, 5);
+    assertXPath(pExportDump, 
"//page[2]/body/section/txt[5]/SwParaPortion"_ostr, 0);
+    assertXPath(pExportDump, 
"//page[2]/body/section/txt[6]/SwParaPortion"_ostr, 0);
+    assertXPath(pExportDump, 
"//page[2]/body/section/txt[7]/SwParaPortion"_ostr, 0);
+    assertXPath(pExportDump, "//page[2]/body/txt"_ostr, 2);
+    assertXPath(pExportDump, 
"//page[2]/body/txt[1]/SwParaPortion/SwLineLayout"_ostr, 7);
+    assertXPath(pExportDump, "//page[2]/body/txt[2]/SwParaPortion"_ostr, 0);
+
+    // Hide the section
+    auto xTextSectionsSupplier = 
mxComponent.queryThrow<css::text::XTextSectionsSupplier>();
+    auto xSections = xTextSectionsSupplier->getTextSections();
+    CPPUNIT_ASSERT(xSections);
+    auto xSection = 
xSections->getByName(u"Section1"_ustr).queryThrow<css::beans::XPropertySet>();
+    xSection->setPropertyValue(u"IsVisible"_ustr, css::uno::Any(false));
+
+    discardDumpedLayout();
+    calcLayout();
+    pExportDump = parseLayoutDump();
+    assertXPath(pExportDump, "//page"_ostr, 1);
+    // Three paragraphs and a hidden section on the first page
+    assertXPath(pExportDump, "//page/body/txt"_ostr, 3);
+    assertXPath(pExportDump, "//page/body/section"_ostr, 1);
+
+    assertXPath(pExportDump, "//page/body/section/infos/bounds"_ostr, 
"height"_ostr, "0");
+    assertXPath(pExportDump, 
"//page/body/txt[1]/SwParaPortion/SwLineLayout"_ostr, 6);
+    assertXPath(pExportDump, "//page/body/section/txt"_ostr, 7);
+    assertXPath(pExportDump, "//page/body/section/txt[1]/SwParaPortion"_ostr, 
0);
+    assertXPath(pExportDump, "//page/body/section/txt[2]/SwParaPortion"_ostr, 
0);
+    assertXPath(pExportDump, "//page/body/section/txt[3]/SwParaPortion"_ostr, 
0);
+    assertXPath(pExportDump, 
"//page/body/section/txt[4]/SwParaPortion/SwLineLayout"_ostr, 5);
+    assertXPath(pExportDump, "//page/body/section/txt[5]/SwParaPortion"_ostr, 
0);
+    assertXPath(pExportDump, "//page/body/section/txt[6]/SwParaPortion"_ostr, 
0);
+    assertXPath(pExportDump, "//page/body/section/txt[7]/SwParaPortion"_ostr, 
0);
+
+    assertXPath(pExportDump, 
"//page/body/txt[2]/SwParaPortion/SwLineLayout"_ostr, 7);
+    assertXPath(pExportDump, "//page/body/txt[3]/SwParaPortion"_ostr, 0);
+
+    // Show the section again
+    xSection->setPropertyValue(u"IsVisible"_ustr, css::uno::Any(true));
+
+    // Check that the layout has been restored
+    discardDumpedLayout();
+    calcLayout();
+    pExportDump = parseLayoutDump();
+    assertXPath(pExportDump, "//page"_ostr, 2);
+    assertXPath(pExportDump, "//page[1]/body/txt"_ostr, 1);
+    assertXPath(pExportDump, 
"//page[1]/body/txt/SwParaPortion/SwLineLayout"_ostr, 6);
+    assertXPath(pExportDump, "//page[2]/body/section"_ostr, 1);
+    assertXPath(pExportDump, "//page[2]/body/section/txt"_ostr, 7);
+    assertXPath(pExportDump, 
"//page[2]/body/section/txt[1]/SwParaPortion"_ostr, 0);
+    assertXPath(pExportDump, 
"//page[2]/body/section/txt[2]/SwParaPortion"_ostr, 0);
+    assertXPath(pExportDump, 
"//page[2]/body/section/txt[3]/SwParaPortion"_ostr, 0);
+    assertXPath(pExportDump, 
"//page[2]/body/section/txt[4]/SwParaPortion/SwLineLayout"_ostr, 5);
+    assertXPath(pExportDump, 
"//page[2]/body/section/txt[5]/SwParaPortion"_ostr, 0);
+    assertXPath(pExportDump, 
"//page[2]/body/section/txt[6]/SwParaPortion"_ostr, 0);
+    assertXPath(pExportDump, 
"//page[2]/body/section/txt[7]/SwParaPortion"_ostr, 0);
+    assertXPath(pExportDump, "//page[2]/body/txt"_ostr, 2);
+    assertXPath(pExportDump, 
"//page[2]/body/txt[1]/SwParaPortion/SwLineLayout"_ostr, 7);
+    assertXPath(pExportDump, "//page[2]/body/txt[2]/SwParaPortion"_ostr, 0);
+}
+
+CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf160958_orphans)
+{
+    // Given a document with a section which moves to the next page as a 
whole, because of orphans
+    createSwDoc("tdf160958_orphans_move_section.fodt");
+    auto pExportDump = parseLayoutDump();
+    assertXPath(pExportDump, "//page"_ostr, 2);
+    // 21 paragraphs on the first page
+    assertXPath(pExportDump, "//page[1]/body/txt"_ostr, 21);
+    assertXPath(pExportDump, 
"//page[1]/body/txt[1]/SwParaPortion/SwLineLayout"_ostr, 6);
+    assertXPath(pExportDump, 
"//page[1]/body/txt[2]/SwParaPortion/SwLineLayout"_ostr, 5);
+    assertXPath(pExportDump, 
"//page[1]/body/txt[3]/SwParaPortion/SwLineLayout"_ostr, 7);
+    assertXPath(pExportDump, 
"//page[1]/body/txt[4]/SwParaPortion/SwLineLayout"_ostr, 16);
+    assertXPath(pExportDump, 
"//page[1]/body/txt[5]/SwParaPortion/SwLineLayout"_ostr, 1);
+    assertXPath(pExportDump, 
"//page[1]/body/txt[6]/SwParaPortion/SwLineLayout"_ostr, 1);
+    assertXPath(pExportDump, 
"//page[1]/body/txt[7]/SwParaPortion/SwLineLayout"_ostr, 1);
+    assertXPath(pExportDump, 
"//page[1]/body/txt[8]/SwParaPortion/SwLineLayout"_ostr, 1);
+    assertXPath(pExportDump, 
"//page[1]/body/txt[9]/SwParaPortion/SwLineLayout"_ostr, 1);
+    assertXPath(pExportDump, 
"//page[1]/body/txt[10]/SwParaPortion/SwLineLayout"_ostr, 1);
+    assertXPath(pExportDump, 
"//page[1]/body/txt[11]/SwParaPortion/SwLineLayout"_ostr, 1);
+    assertXPath(pExportDump, 
"//page[1]/body/txt[12]/SwParaPortion/SwLineLayout"_ostr, 1);
+    assertXPath(pExportDump, 
"//page[1]/body/txt[13]/SwParaPortion/SwLineLayout"_ostr, 1);
+    assertXPath(pExportDump, 
"//page[1]/body/txt[14]/SwParaPortion/SwLineLayout"_ostr, 1);
+    assertXPath(pExportDump, 
"//page[1]/body/txt[15]/SwParaPortion/SwLineLayout"_ostr, 1);
+    assertXPath(pExportDump, 
"//page[1]/body/txt[16]/SwParaPortion/SwLineLayout"_ostr, 1);
+    assertXPath(pExportDump, 
"//page[1]/body/txt[17]/SwParaPortion/SwLineLayout"_ostr, 1);
+    assertXPath(pExportDump, 
"//page[1]/body/txt[18]/SwParaPortion/SwLineLayout"_ostr, 1);
+    assertXPath(pExportDump, 
"//page[1]/body/txt[19]/SwParaPortion/SwLineLayout"_ostr, 1);
+    assertXPath(pExportDump, 
"//page[1]/body/txt[20]/SwParaPortion/SwLineLayout"_ostr, 1);
+    assertXPath(pExportDump, 
"//page[1]/body/txt[21]/SwParaPortion/SwLineLayout"_ostr, 1);
+    // A section and one more paragraph after the section
+    assertXPath(pExportDump, "//page[2]/body/section"_ostr, 1);
+    assertXPath(pExportDump, "//page[2]/body/section/txt"_ostr, 3);
+    assertXPath(pExportDump, 
"//page[2]/body/section/txt[1]/SwParaPortion/SwLineLayout"_ostr, 6);
+    assertXPath(pExportDump, 
"//page[2]/body/section/txt[2]/SwParaPortion/SwLineLayout"_ostr, 5);
+    assertXPath(pExportDump, 
"//page[2]/body/section/txt[3]/SwParaPortion/SwLineLayout"_ostr, 7);
+    assertXPath(pExportDump, "//page[2]/body/txt"_ostr, 1);
+    assertXPath(pExportDump, 
"//page[2]/body/txt[1]/SwParaPortion/SwLineLayout"_ostr, 1);
+
+    // Hide the section
+    auto xTextSectionsSupplier = 
mxComponent.queryThrow<css::text::XTextSectionsSupplier>();
+    auto xSections = xTextSectionsSupplier->getTextSections();
+    CPPUNIT_ASSERT(xSections);
+    auto xSection = 
xSections->getByName(u"Section1"_ustr).queryThrow<css::beans::XPropertySet>();
+    xSection->setPropertyValue(u"IsVisible"_ustr, css::uno::Any(false));
+
+    discardDumpedLayout();
+    calcLayout();
+    pExportDump = parseLayoutDump();
+    assertXPath(pExportDump, "//page"_ostr, 1);
+    assertXPath(pExportDump, "//page/body/txt"_ostr, 22);
+    assertXPath(pExportDump, "//page/body/section"_ostr, 1);
+    assertXPath(pExportDump, "//page/body/section/infos/bounds"_ostr, 
"height"_ostr, "0");
+
+    // Show the section again
+    xSection->setPropertyValue(u"IsVisible"_ustr, css::uno::Any(true));
+
+    // Check that the layout has been restored
+    discardDumpedLayout();
+    calcLayout();
+    pExportDump = parseLayoutDump();
+    assertXPath(pExportDump, "//page"_ostr, 2);
+    assertXPath(pExportDump, "//page[1]/body/txt"_ostr, 21);
+    assertXPath(pExportDump, 
"//page[1]/body/txt[1]/SwParaPortion/SwLineLayout"_ostr, 6);
+    assertXPath(pExportDump, 
"//page[1]/body/txt[2]/SwParaPortion/SwLineLayout"_ostr, 5);
+    assertXPath(pExportDump, 
"//page[1]/body/txt[3]/SwParaPortion/SwLineLayout"_ostr, 7);
+    assertXPath(pExportDump, 
"//page[1]/body/txt[4]/SwParaPortion/SwLineLayout"_ostr, 16);
+    assertXPath(pExportDump, 
"//page[1]/body/txt[5]/SwParaPortion/SwLineLayout"_ostr, 1);
+    assertXPath(pExportDump, 
"//page[1]/body/txt[6]/SwParaPortion/SwLineLayout"_ostr, 1);
+    assertXPath(pExportDump, 
"//page[1]/body/txt[7]/SwParaPortion/SwLineLayout"_ostr, 1);
+    assertXPath(pExportDump, 
"//page[1]/body/txt[8]/SwParaPortion/SwLineLayout"_ostr, 1);
+    assertXPath(pExportDump, 
"//page[1]/body/txt[9]/SwParaPortion/SwLineLayout"_ostr, 1);
+    assertXPath(pExportDump, 
"//page[1]/body/txt[10]/SwParaPortion/SwLineLayout"_ostr, 1);
+    assertXPath(pExportDump, 
"//page[1]/body/txt[11]/SwParaPortion/SwLineLayout"_ostr, 1);
+    assertXPath(pExportDump, 
"//page[1]/body/txt[12]/SwParaPortion/SwLineLayout"_ostr, 1);
+    assertXPath(pExportDump, 
"//page[1]/body/txt[13]/SwParaPortion/SwLineLayout"_ostr, 1);
+    assertXPath(pExportDump, 
"//page[1]/body/txt[14]/SwParaPortion/SwLineLayout"_ostr, 1);
+    assertXPath(pExportDump, 
"//page[1]/body/txt[15]/SwParaPortion/SwLineLayout"_ostr, 1);
+    assertXPath(pExportDump, 
"//page[1]/body/txt[16]/SwParaPortion/SwLineLayout"_ostr, 1);
+    assertXPath(pExportDump, 
"//page[1]/body/txt[17]/SwParaPortion/SwLineLayout"_ostr, 1);
+    assertXPath(pExportDump, 
"//page[1]/body/txt[18]/SwParaPortion/SwLineLayout"_ostr, 1);
+    assertXPath(pExportDump, 
"//page[1]/body/txt[19]/SwParaPortion/SwLineLayout"_ostr, 1);
+    assertXPath(pExportDump, 
"//page[1]/body/txt[20]/SwParaPortion/SwLineLayout"_ostr, 1);
+    assertXPath(pExportDump, 
"//page[1]/body/txt[21]/SwParaPortion/SwLineLayout"_ostr, 1);
+    assertXPath(pExportDump, "//page[2]/body/section"_ostr, 1);
+    assertXPath(pExportDump, "//page[2]/body/section/txt"_ostr, 3);
+    assertXPath(pExportDump, 
"//page[2]/body/section/txt[1]/SwParaPortion/SwLineLayout"_ostr, 6);
+    assertXPath(pExportDump, 
"//page[2]/body/section/txt[2]/SwParaPortion/SwLineLayout"_ostr, 5);
+    assertXPath(pExportDump, 
"//page[2]/body/section/txt[3]/SwParaPortion/SwLineLayout"_ostr, 7);
+    assertXPath(pExportDump, "//page[2]/body/txt"_ostr, 1);
+    assertXPath(pExportDump, 
"//page[2]/body/txt[1]/SwParaPortion/SwLineLayout"_ostr, 1);
+}
+
 } // end of anonymous namespace
 
 CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sw/source/core/layout/sectfrm.cxx 
b/sw/source/core/layout/sectfrm.cxx
index 23b427c1507b..c92af1303fae 100644
--- a/sw/source/core/layout/sectfrm.cxx
+++ b/sw/source/core/layout/sectfrm.cxx
@@ -833,6 +833,42 @@ void SwSectionFrame::MakeAll(vcl::RenderContext* 
pRenderContext)
         setFramePrintAreaValid(true);
         return;
     }
+
+    if (!GetPrev() && !IsFollow() && IsInDocBody() && IsHiddenNow())
+    {
+        // This may be the first frame on a page, and it may had moved to that 
page because its
+        // content required that (a page break in the first paragraph, or a 
tall first line, or
+        // "do not break paragraph" setting, or the like). Try to move back, 
to allow following
+        // frames to move back, if possible. Sections cannot move back; 
workaround by a call to
+        // GetPrevSctLeaf(), which may return a candidate upper frame on a 
previous page, or it
+        // may create a new master for this at the end of the previous page. 
Cut and paste this
+        // appropriately; then drop the temporary, if needed.
+        if (SwLayoutFrame* moveBackPos = GetPrevSctLeaf())
+        {
+            SwLayoutFrame* newUpper = moveBackPos;
+            SwFrame* newSibling = nullptr;
+            const bool temporaryMasterCreated = IsFollow();
+            if (temporaryMasterCreated)
+            {
+                assert(moveBackPos == &GetPrecede()->GetFrame());
+                newUpper = moveBackPos->GetUpper();
+                newSibling = moveBackPos->GetNext(); // actually, will be also 
nullptr
+            }
+            if (newUpper != GetUpper())
+            {
+                // Can't use MoveSubTree, because the move needs to fire 
events to re-layout
+                Cut();
+                Paste(newUpper, newSibling);
+            }
+            if (temporaryMasterCreated)
+            {
+                moveBackPos->Cut();
+                DestroyFrame(moveBackPos);
+            }
+            assert(!IsFollow());
+        }
+    }
+
     LockJoin(); // I don't let myself to be destroyed on the way
 
     while( GetNext() && GetNext() == GetFollow() )
@@ -843,6 +879,17 @@ void SwSectionFrame::MakeAll(vcl::RenderContext* 
pRenderContext)
             break;
     }
 
+    if (GetFollow() && IsHiddenNow())
+    {
+        // Merge all the follows of this hidden section
+        while (auto* follow = GetFollow())
+        {
+            MergeNext(follow);
+            if (GetFollow() == follow) // failed to merge
+                break; // avoid endless loop
+        }
+    }
+
     // OD 2004-03-15 #116561# - In online layout join the follows, if section
     // can grow.
     const SwViewShell *pSh = getRootFrame()->GetCurrShell();
@@ -2677,6 +2724,11 @@ void SwSectionFrame::SwClientNotify(const SwModify& 
rMod, const SfxHint& rHint)
     {
         InvalidateAll();
         InvalidateObjs(false);
+        {
+            // Set it to a huge positive value, to make sure a recalculation 
fires
+            SwFrameAreaDefinition::FrameAreaWriteAccess area(*this);
+            SwRectFnSet(this).SetHeight(area, 
std::numeric_limits<tools::Long>::max());
+        }
 
         for (SwFrame* pLowerFrame = Lower(); pLowerFrame; pLowerFrame = 
pLowerFrame->GetNext())
         {

Reply via email to