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="'Liberation Serif'" 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'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'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's breeze. Could this be the haven he'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="'Liberation Serif'" 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()) {