sw/qa/uitest/data/tdf163325.odt |binary sw/source/core/inc/flowfrm.hxx | 3 ++ sw/source/core/layout/calcmove.cxx | 50 +++++++++++++++++++++++++--------- sw/source/core/layout/flowfrm.cxx | 53 +++++++++++++++++++++++++++++++++---- sw/source/core/layout/fly.cxx | 5 ++- sw/source/core/layout/frmtool.cxx | 2 - sw/source/core/layout/sectfrm.cxx | 8 +++-- sw/source/core/layout/tabfrm.cxx | 14 ++++----- 8 files changed, 104 insertions(+), 31 deletions(-)
New commits: commit 7a7066401aefca1a2da6851c72a98ab1c0843b5a Author: Michael Stahl <michael.st...@allotropia.de> AuthorDate: Fri Dec 6 14:24:12 2024 +0100 Commit: Michael Stahl <michael.st...@allotropia.de> CommitDate: Fri Dec 6 16:51:20 2024 +0100 sw: layout: ignore Keep-With-Next on hidden frames, part3 SwTabFrame: :MakeAll(), SwRowFrame::ShouldRowKeepWithNext() Change-Id: I7cb6e558dc05736658a9bc75d6c735e6a47062b0 diff --git a/sw/source/core/layout/tabfrm.cxx b/sw/source/core/layout/tabfrm.cxx index e57ba525df0b..c5a5897b7ccb 100644 --- a/sw/source/core/layout/tabfrm.cxx +++ b/sw/source/core/layout/tabfrm.cxx @@ -2026,10 +2026,10 @@ void SwTabFrame::MakeAll(vcl::RenderContext* pRenderContext) const bool bLargeTable = GetTable()->GetTabLines().size() > 64; //arbitrary value, virtually guaranteed to be larger than one page. const bool bEmulateTableKeep = !bLargeTable && AreAllRowsKeepWithNext( GetFirstNonHeadlineRow(), /*bCheckParents=*/false ); + bool const isHiddenNow(IsHiddenNow()); // The beloved keep attribute - const bool bKeep = IsKeep(pAttrs->GetAttrSet().GetKeep(), GetBreakItem(), bEmulateTableKeep); + const bool bKeep{!isHiddenNow && IsKeep(pAttrs->GetAttrSet().GetKeep(), GetBreakItem(), bEmulateTableKeep)}; - bool const isHiddenNow(IsHiddenNow()); // All rows should keep together const bool bDontSplit = isHiddenNow || (!IsFollow() && !GetFormat()->GetLayoutSplit().GetValue()); @@ -2150,9 +2150,8 @@ void SwTabFrame::MakeAll(vcl::RenderContext* pRenderContext) } aNotify.SetLowersComplete( false ); } - SwFrame *pPre; - if ( bKeep || (nullptr != (pPre = FindPrev()) && - pPre->GetAttrSet()->GetKeep().GetValue()) ) + SwFrame const*const pPre{bKeep ? nullptr : FindPrevIgnoreHidden()}; + if (bKeep || (nullptr != pPre && pPre->GetAttrSet()->GetKeep().GetValue())) { m_bCalcLowers = true; } @@ -2435,7 +2434,8 @@ void SwTabFrame::MakeAll(vcl::RenderContext* pRenderContext) pAccess = std::make_unique<SwBorderAttrAccess>(SwFrame::GetCache(), this); pAttrs = pAccess->Get(); } - if (IsKeep(pAttrs->GetAttrSet().GetKeep(), GetBreakItem(), true) + if (!isHiddenNow + && IsKeep(pAttrs->GetAttrSet().GetKeep(), GetBreakItem(), true) && pLastRow->ShouldRowKeepWithNext()) { bFormat = true; @@ -4862,7 +4862,7 @@ bool SwRowFrame::ShouldRowKeepWithNext( const bool bCheckParents ) const const SwCellFrame* pCell = static_cast<const SwCellFrame*>(Lower()); const SwFrame* pText = pCell->Lower(); - return pText && pText->IsTextFrame() && + return pText && pText->IsTextFrame() && !pText->IsHiddenNow() && static_cast<const SwTextFrame*>(pText)->GetTextNodeForParaProps()->GetSwAttrSet().GetKeep(bCheckParents).GetValue(); } commit 4ef7153ad62dc042fe5b9f211be89a69360e0ea1 Author: Michael Stahl <michael.st...@allotropia.de> AuthorDate: Fri Dec 6 14:20:22 2024 +0100 Commit: Michael Stahl <michael.st...@allotropia.de> CommitDate: Fri Dec 6 16:51:20 2024 +0100 sw: layout: ignore Keep-With-Next on hidden frames, part2 SwFrame::PrepareMake(), SwContentFrame::MakeAll(), SwContentFrame::WouldFit_() Change-Id: I2a909ac6d147668dddece97bd99e31fdddcf20eb diff --git a/sw/source/core/layout/calcmove.cxx b/sw/source/core/layout/calcmove.cxx index 221686d4306f..2473d8cfd8e9 100644 --- a/sw/source/core/layout/calcmove.cxx +++ b/sw/source/core/layout/calcmove.cxx @@ -290,9 +290,17 @@ void SwFrame::PrepareMake(vcl::RenderContext* pRenderContext) // There is no format of previous frame, if current frame is a table // frame and its previous frame wants to keep with it. - const bool bFormatPrev = !bTab || - !GetPrev() || - !GetPrev()->GetAttrSet()->GetKeep().GetValue(); + bool bFormatPrev{!bTab}; + if (!bFormatPrev) + { + SwFrame const* pPrev{this}; + do + { + pPrev = pPrev->GetPrev(); + } + while (pPrev && pPrev->IsHiddenNow()); + bFormatPrev = pPrev && !pPrev->GetAttrSet()->GetKeep().GetValue(); + } if ( bFormatPrev ) { SwFrame *pFrame = GetUpper()->Lower(); @@ -1297,7 +1305,7 @@ void SwContentFrame::MakeAll(vcl::RenderContext* /*pRenderContext*/) pNotify->SetBordersJoinedWithPrev(); } - const bool bKeep = IsKeep(rAttrs.GetAttrSet().GetKeep(), GetBreakItem()); + const bool bKeep{!isHiddenNow && IsKeep(rAttrs.GetAttrSet().GetKeep(), GetBreakItem())}; std::unique_ptr<SwSaveFootnoteHeight> pSaveFootnote; if ( bFootnote ) @@ -1715,7 +1723,7 @@ void SwContentFrame::MakeAll(vcl::RenderContext* /*pRenderContext*/) if( nBottomDist >= 0 ) { - if ( bKeep && bMoveable ) + if (bKeep && bMoveable && !isHiddenNow) { // We make sure the successor will be formatted the same. // This way, we keep control until (almost) everything is stable, @@ -2049,10 +2057,29 @@ bool SwContentFrame::WouldFit_( SwTwips nSpace, const SwFrame *pTmpPrev = pNewUpper->Lower(); if( pTmpPrev && pTmpPrev->IsFootnoteFrame() ) pTmpPrev = static_cast<const SwFootnoteFrame*>(pTmpPrev)->Lower(); - while ( pTmpPrev && pTmpPrev->GetNext() ) - pTmpPrev = pTmpPrev->GetNext(); + { + SwFrame const* pTmpNonHidden{pTmpPrev && pTmpPrev->IsHiddenNow() ? nullptr : pTmpPrev}; + while (pTmpPrev && pTmpPrev->GetNext()) + { + pTmpPrev = pTmpPrev->GetNext(); + if (!pTmpPrev->IsHiddenNow()) + { + pTmpNonHidden = pTmpPrev; + } + } + pTmpPrev = pTmpNonHidden; + } + do { + if (pFrame->IsHiddenNow()) + { // shortcut + assert(pFrame == this); + bRet = true; + pFrame = nullptr; + break; + } + // #i46181# SwTwips nSecondCheck = 0; SwTwips nOldSpace = nSpace; @@ -2217,8 +2244,8 @@ bool SwContentFrame::WouldFit_( SwTwips nSpace, return true; } } - SwFrame *pNxt; - if( nullptr != (pNxt = pFrame->FindNext()) && pNxt->IsContentFrame() && + SwFrame *const pNxt{pFrame->FindNextIgnoreHidden()}; + if (nullptr != pNxt && pNxt->IsContentFrame() && ( !pFootnoteFrame || ( pNxt->IsInFootnote() && pNxt->FindFootnoteFrame()->GetAttr() == pFootnoteFrame->GetAttr() ) ) ) { @@ -2244,10 +2271,7 @@ bool SwContentFrame::WouldFit_( SwTwips nSpace, pTmpPrev = nullptr; else { - if (pFrame->IsHiddenNow()) - pTmpPrev = lcl_NotHiddenPrev( pFrame ); - else - pTmpPrev = pFrame; + pTmpPrev = pFrame; } pFrame = static_cast<SwContentFrame*>(pNxt); } commit 648dac932228808ea1a5ce785571dd7caa075933 Author: Michael Stahl <michael.st...@allotropia.de> AuthorDate: Fri Dec 6 14:10:32 2024 +0100 Commit: Michael Stahl <michael.st...@allotropia.de> CommitDate: Fri Dec 6 16:51:20 2024 +0100 sw: layout: ignore Keep-With-Next on hidden frames, part1 When a frame is hidden, don't consider it when evaluating keep-with-next attributes - this was the case for content in hidden sections before commit 0c96119895b347f8eb5bb89f393351bd3c02b9f1 ~SwFrameNotify() invalidating position of hidden frame with keep attribute causes layout loops. Also skip hidden frames in SwFlowFrame::IsKeepFwdMoveAllowed(), SwFlowFrame::CheckKeep(), SwFlowFrame::IsPrevObjMove(), SwFlowFrame::MoveBwd(), CalcContent(). Change-Id: I68556ba0a8e016d962399f3ce199e5eda0378867 diff --git a/sw/source/core/inc/flowfrm.hxx b/sw/source/core/inc/flowfrm.hxx index 078ef9326837..5859b5688bd9 100644 --- a/sw/source/core/inc/flowfrm.hxx +++ b/sw/source/core/inc/flowfrm.hxx @@ -183,6 +183,9 @@ public: SvxFormatBreakItem const& rBreak, bool bBreakCheck = false ) const; + SwFrame * FindPrevIgnoreHidden() const; + SwFrame * FindNextIgnoreHidden() const; + bool HasLockedFollow() const; bool HasParaSpaceAtPages( bool bSct ) const; diff --git a/sw/source/core/layout/flowfrm.cxx b/sw/source/core/layout/flowfrm.cxx index 5d7ea3c02a99..d642eb26de97 100644 --- a/sw/source/core/layout/flowfrm.cxx +++ b/sw/source/core/layout/flowfrm.cxx @@ -129,7 +129,9 @@ bool SwFlowFrame::IsKeepFwdMoveAllowed( bool bIgnoreMyOwnKeepValue ) if ( bIgnoreMyOwnKeepValue && pFrame->GetIndPrev() ) pFrame = pFrame->GetIndPrev(); do - { if ( pFrame->GetAttrSet()->GetKeep().GetValue() ) + { + if (pFrame->GetAttrSet()->GetKeep().GetValue() + || pFrame->IsHiddenNow()) pFrame = pFrame->GetIndPrev(); else return true; @@ -148,22 +150,42 @@ void SwFlowFrame::CheckKeep() // it's possible for the whole troop to move back. SwFrame *pPre = m_rThis.GetIndPrev(); assert(pPre); + while (pPre && pPre->IsHiddenNow()) + { + pPre = pPre->GetIndPrev(); + } + if (!pPre) + { + return; + } if( pPre->IsSctFrame() ) { SwFrame *pLast = static_cast<SwSectionFrame*>(pPre)->FindLastContent(); + while (pLast && pLast->IsHiddenNow()) + { + pLast = pLast->GetIndPrev(); + } if( pLast && pLast->FindSctFrame() == pPre ) pPre = pLast; else return; } - SwFrame* pTmp; + SwFrame* pTmp{pPre}; bool bKeep; while ( (bKeep = pPre->GetAttrSet()->GetKeep().GetValue()) && - nullptr != ( pTmp = pPre->GetIndPrev() ) ) + nullptr != (pTmp = pTmp->GetIndPrev()) ) { + if (pTmp->IsHiddenNow()) + { + continue; + } if( pTmp->IsSctFrame() ) { SwFrame *pLast = static_cast<SwSectionFrame*>(pTmp)->FindLastContent(); + while (pLast && pLast->IsHiddenNow()) + { + pLast = pLast->GetIndPrev(); + } if( pLast && pLast->FindSctFrame() == pTmp ) pTmp = pLast; else @@ -179,6 +201,7 @@ bool SwFlowFrame::IsKeep(SvxFormatKeepItem const& rKeep, SvxFormatBreakItem const& rBreak, bool const bCheckIfLastRowShouldKeep) const { + assert(!m_rThis.IsHiddenNow()); // check it before? // 1. The keep attribute is ignored inside footnotes // 2. For compatibility reasons, the keep attribute is // ignored for frames inside table cells @@ -269,6 +292,26 @@ bool SwFlowFrame::IsKeep(SvxFormatKeepItem const& rKeep, return bKeep; } +SwFrame * SwFlowFrame::FindPrevIgnoreHidden() const +{ + SwFrame * pRet{m_rThis.FindPrev()}; + while (pRet && pRet->IsHiddenNow()) + { + pRet = pRet->FindPrev(); + } + return pRet; +} + +SwFrame * SwFlowFrame::FindNextIgnoreHidden() const +{ + SwFrame * pRet{m_rThis.FindNext()}; + while (pRet && pRet->IsHiddenNow()) + { + pRet = pRet->FindNext(); + } + return pRet; +} + sal_uInt8 SwFlowFrame::BwdMoveNecessary( const SwPageFrame *pPage, const SwRect &rRect ) { // The return value helps deciding whether we need to flow back (3), @@ -1074,7 +1117,7 @@ bool SwFlowFrame::IsPrevObjMove() const if( pSh && pSh->GetViewOptions()->getBrowseMode() ) return false; - SwFrame *pPre = m_rThis.FindPrev(); + SwFrame *const pPre{FindPrevIgnoreHidden()}; if ( pPre && pPre->GetDrawObjs() ) { @@ -2428,7 +2471,7 @@ bool SwFlowFrame::MoveBwd( bool &rbReformat ) // keep with next frame and next frame is locked. // #i38232# - If next frame is a table, do *not* check, // if it's locked. - if ( pNewUpper && !IsFollow() && + if ( pNewUpper && !IsFollow() && !m_rThis.IsHiddenNow() && m_rThis.GetAttrSet()->GetKeep().GetValue() && m_rThis.GetIndNext() ) { SwFrame* pIndNext = m_rThis.GetIndNext(); diff --git a/sw/source/core/layout/fly.cxx b/sw/source/core/layout/fly.cxx index 190e799dbc56..6829f749953e 100644 --- a/sw/source/core/layout/fly.cxx +++ b/sw/source/core/layout/fly.cxx @@ -1510,9 +1510,10 @@ void CalcContent( SwLayoutFrame *pLay, bool bNoColl ) // frame due to its keep-attribute, if it can't move forward. // #i57765# - do not consider invalid previous // frame, if current frame has a column/page break before attribute. - SwFrame* pTmpPrev = pFrame->FindPrev(); + assert(pFrame->IsFlowFrame()); + SwFlowFrame* pTmpFlowFrame = SwFlowFrame::CastFlowFrame(pFrame); + SwFrame* pTmpPrev = pTmpFlowFrame->FindPrevIgnoreHidden(); SwFlowFrame* pTmpPrevFlowFrame = pTmpPrev && pTmpPrev->IsFlowFrame() ? SwFlowFrame::CastFlowFrame(pTmpPrev) : nullptr; - SwFlowFrame* pTmpFlowFrame = pFrame->IsFlowFrame() ? SwFlowFrame::CastFlowFrame(pFrame) : nullptr; bool bPrevInvalid = pTmpPrevFlowFrame && pTmpFlowFrame && !pTmpFlowFrame->IsFollow() && diff --git a/sw/source/core/layout/frmtool.cxx b/sw/source/core/layout/frmtool.cxx index 4093623976fc..1ff2f7cb7656 100644 --- a/sw/source/core/layout/frmtool.cxx +++ b/sw/source/core/layout/frmtool.cxx @@ -129,7 +129,7 @@ SwFrameNotify::~SwFrameNotify() COVERITY_NOEXCEPT_FALSE { if ( mbInvaKeep ) { - SwFrame *pPre = mpFrame->FindPrev(); + SwFrame *pPre = pFlow->FindPrevIgnoreHidden(); if ( pPre && pPre->IsFlowFrame() ) { // 1. pPre wants to keep with me: commit 484619d972632d2340e4c72cb7179c33107a2d5b Author: Andreas Heinisch <andreas.heini...@yahoo.de> AuthorDate: Mon Nov 25 09:17:45 2024 +0100 Commit: Michael Stahl <michael.st...@allotropia.de> CommitDate: Fri Dec 6 16:51:20 2024 +0100 tdf#163325 - Check Lower() frame during ToC preview Change-Id: Ife0e974d66d5ddbe3c831c64e4da28442e476da4 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/177234 Reviewed-by: Andreas Heinisch <andreas.heini...@yahoo.de> Tested-by: Jenkins (cherry picked from commit 2145204724049cad1585743c0b980ed2c6561212) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/177529 Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org> (cherry picked from commit 2d57e13895703b541b918c0933b7dc5bbe25c300) diff --git a/sw/qa/uitest/data/tdf163325.odt b/sw/qa/uitest/data/tdf163325.odt new file mode 100644 index 000000000000..3d2e6e8673cf Binary files /dev/null and b/sw/qa/uitest/data/tdf163325.odt differ diff --git a/sw/source/core/layout/sectfrm.cxx b/sw/source/core/layout/sectfrm.cxx index 96fe04aa89b0..ac2120e7837b 100644 --- a/sw/source/core/layout/sectfrm.cxx +++ b/sw/source/core/layout/sectfrm.cxx @@ -2694,7 +2694,8 @@ void SwSectionFrame::Modify( const SfxPoolItem* pOld, const SfxPoolItem * pNew ) } InvalidateFramesInSection(Lower()); - Lower()->HideAndShowObjects(); // recursive + if (Lower()) + Lower()->HideAndShowObjects(); // recursive // Check if any page-breaks have been unhidden, create the new pages. // Call IsHiddenNow() because a parent section could still hide. if (!IsFollow() && IsInDocBody() && !IsInTab() && !IsHiddenNow()) @@ -2721,8 +2722,9 @@ void SwSectionFrame::Modify( const SfxPoolItem* pOld, const SfxPoolItem * pNew ) pFirstOnPage = pFirstOnPage->GetUpper(); } assert(pFirstOnPage->IsContentFrame() || pFirstOnPage->IsTabFrame()); - SwColumnFrame * pColumn{Lower()->IsColumnFrame() - ? static_cast<SwColumnFrame*>(Lower()) : nullptr}; + SwColumnFrame* pColumn{ Lower() && Lower()->IsColumnFrame() + ? static_cast<SwColumnFrame*>(Lower()) + : nullptr }; auto IterateLower = [&pColumn](SwFrame *const pLowerFrame) -> SwFrame* { if (pLowerFrame->GetNext())