diff options
Diffstat (limited to 'sw/source/core/layout/objectformattertxtfrm.cxx')
-rw-r--r-- | sw/source/core/layout/objectformattertxtfrm.cxx | 213 |
1 files changed, 183 insertions, 30 deletions
diff --git a/sw/source/core/layout/objectformattertxtfrm.cxx b/sw/source/core/layout/objectformattertxtfrm.cxx index 1ba020a84901..57c3c7680da0 100644 --- a/sw/source/core/layout/objectformattertxtfrm.cxx +++ b/sw/source/core/layout/objectformattertxtfrm.cxx @@ -29,6 +29,7 @@ #include <fmtwrapinfluenceonobjpos.hxx> #include <fmtfollowtextflow.hxx> #include <layact.hxx> +#include <flyfrm.hxx> #include <ftnfrm.hxx> using namespace ::com::sun::star; @@ -224,11 +225,16 @@ bool SwObjectFormatterTextFrame::DoFormatObj( SwAnchoredObject& _rAnchoredObj, sal_uInt32 nToPageNum( 0 ); // #i43913# bool bDummy( false ); - // #i58182# - consider new method signature + bool bPageHasFlysAnchoredBelowThis(false); + // see how SwObjectFormatter::FormatObjsAtFrame_() checks + // "pPageFrameOfAnchor == &mrPageFrame" - only caller relevant for + // this subclass + assert(GetPageFrame().GetPhyPageNum() == GetPgNumOfCollected(nIdx)); if ( SwObjectFormatterTextFrame::CheckMovedFwdCondition( *GetCollectedObj( nIdx ), - GetPgNumOfCollected( nIdx ), + GetPageFrame(), IsCollectedAnchoredAtMaster( nIdx ), - nToPageNum, bDummy ) ) + nToPageNum, bDummy, + bPageHasFlysAnchoredBelowThis)) { // #i49987# - consider, that anchor frame // could already been marked to move forward. @@ -239,7 +245,12 @@ bool SwObjectFormatterTextFrame::DoFormatObj( SwAnchoredObject& _rAnchoredObj, rDoc, mrAnchorTextFrame, nMovedFwdToPageNum ) ) { if ( nMovedFwdToPageNum < nToPageNum ) - SwLayouter::RemoveMovedFwdFrame( rDoc, mrAnchorTextFrame ); + { + if (!bPageHasFlysAnchoredBelowThis) + { + SwLayouter::RemoveMovedFwdFrame(rDoc, mrAnchorTextFrame); + } + } else bInsert = false; } @@ -247,8 +258,11 @@ bool SwObjectFormatterTextFrame::DoFormatObj( SwAnchoredObject& _rAnchoredObj, { // Indicate that anchor text frame has to move forward and // invalidate its position to force a re-format. - SwLayouter::InsertMovedFwdFrame( rDoc, mrAnchorTextFrame, - nToPageNum ); + if (!bPageHasFlysAnchoredBelowThis) + { + SwLayouter::InsertMovedFwdFrame(rDoc, + mrAnchorTextFrame, nToPageNum); + } mrAnchorTextFrame.InvalidatePos(); // Indicate restart of the layout process @@ -293,7 +307,7 @@ bool SwObjectFormatterTextFrame::DoFormatObjs() { // notify layout action, thus is can restart the layout process on // a previous page. - GetLayAction()->SetAgain(); + GetLayAction()->SetAgain(true); } else { @@ -350,13 +364,14 @@ bool SwObjectFormatterTextFrame::DoFormatObjs() sal_uInt32 nToPageNum( 0 ); // #i43913# bool bInFollow( false ); + bool bPageHasFlysAnchoredBelowThis(false); SwAnchoredObject* pObj = nullptr; if ( !mrAnchorTextFrame.IsFollow() ) { pObj = GetFirstObjWithMovedFwdAnchor( // #i35017# - constant name has changed text::WrapInfluenceOnPosition::ONCE_CONCURRENT, - nToPageNum, bInFollow ); + nToPageNum, bInFollow, bPageHasFlysAnchoredBelowThis ); } // #i35911# if ( pObj && pObj->HasClearedEnvironment() ) @@ -377,14 +392,22 @@ bool SwObjectFormatterTextFrame::DoFormatObjs() rDoc, mrAnchorTextFrame, nTmpToPageNum ) ) { if ( nTmpToPageNum < pAnchorPageFrame->GetPhyPageNum() ) - SwLayouter::RemoveMovedFwdFrame( rDoc, mrAnchorTextFrame ); + { + if (!bPageHasFlysAnchoredBelowThis) + { + SwLayouter::RemoveMovedFwdFrame(rDoc, mrAnchorTextFrame); + } + } else bInsert = false; } if ( bInsert ) { - SwLayouter::InsertMovedFwdFrame( rDoc, mrAnchorTextFrame, - pAnchorPageFrame->GetPhyPageNum() ); + if (!bPageHasFlysAnchoredBelowThis) + { + SwLayouter::InsertMovedFwdFrame(rDoc, mrAnchorTextFrame, + pAnchorPageFrame->GetPhyPageNum()); + } mrAnchorTextFrame.InvalidatePos(); bSuccess = false; InvalidatePrevObjs( *pObj ); @@ -503,7 +526,8 @@ void SwObjectFormatterTextFrame::InvalidateFollowObjs( SwAnchoredObject& _rAncho SwAnchoredObject* SwObjectFormatterTextFrame::GetFirstObjWithMovedFwdAnchor( const sal_Int16 _nWrapInfluenceOnPosition, sal_uInt32& _noToPageNum, - bool& _boInFollow ) + bool& _boInFollow, + bool& o_rbPageHasFlysAnchoredBelowThis) { // #i35017# - constant names have changed OSL_ENSURE( _nWrapInfluenceOnPosition == text::WrapInfluenceOnPosition::ONCE_SUCCESSIVE || @@ -521,13 +545,17 @@ SwAnchoredObject* SwObjectFormatterTextFrame::GetFirstObjWithMovedFwdAnchor( // #i35017# - handle ITERATIVE as ONCE_SUCCESSIVE GetWrapInfluenceOnObjPos( true ) == _nWrapInfluenceOnPosition ) { + // see how SwObjectFormatter::FormatObjsAtFrame_() checks + // "pPageFrameOfAnchor == &mrPageFrame" - only caller relevant for + // this subclass + assert(GetPageFrame().GetPhyPageNum() == GetPgNumOfCollected(i)); // #i26945# - use new method <_CheckMovedFwdCondition(..)> // #i43913# - // #i58182# - consider new method signature if ( SwObjectFormatterTextFrame::CheckMovedFwdCondition( *GetCollectedObj( i ), - GetPgNumOfCollected( i ), + GetPageFrame(), IsCollectedAnchoredAtMaster( i ), - _noToPageNum, _boInFollow ) ) + _noToPageNum, _boInFollow, + o_rbPageHasFlysAnchoredBelowThis) ) { pRetAnchoredObj = pAnchoredObj; break; @@ -538,15 +566,49 @@ SwAnchoredObject* SwObjectFormatterTextFrame::GetFirstObjWithMovedFwdAnchor( return pRetAnchoredObj; } +static SwRowFrame const* FindTopLevelRowFrame(SwFrame const*const pFrame) +{ + SwRowFrame * pRow = const_cast<SwFrame*>(pFrame)->FindRowFrame(); + // looks like SwTabFrame has mbInfTab = true so go up 2 levels + while (pRow->GetUpper()->GetUpper()->IsInTab()) + { + pRow = pRow->GetUpper()->GetUpper()->FindRowFrame(); + } + return pRow; +} + +static SwContentFrame const* FindFrameInBody(SwAnchoredObject const& rAnchored) +{ + SwFrame const*const pAnchor(rAnchored.GetAnchorFrame()); + assert(pAnchor); + if (pAnchor->IsPageFrame() || pAnchor->FindFooterOrHeader()) + { + return nullptr; + } + if (pAnchor->IsInFly()) + { + return FindFrameInBody(*pAnchor->FindFlyFrame()); + } + if (pAnchor->IsInFootnote()) + { + return pAnchor->FindFootnoteFrame()->GetRef(); + } + assert(pAnchor->IsInDocBody()); + assert(pAnchor->IsContentFrame()); + return static_cast<SwContentFrame const*>(pAnchor); +} + // #i58182# // - replace private method by corresponding static public method bool SwObjectFormatterTextFrame::CheckMovedFwdCondition( SwAnchoredObject& _rAnchoredObj, - const sal_uInt32 _nFromPageNum, + SwPageFrame const& rFromPageFrame, const bool _bAnchoredAtMasterBeforeFormatAnchor, sal_uInt32& _noToPageNum, - bool& _boInFollow ) + bool& _boInFollow, + bool& o_rbPageHasFlysAnchoredBelowThis) { + const sal_uInt32 _nFromPageNum(rFromPageFrame.GetPhyPageNum()); bool bAnchorIsMovedForward( false ); SwPageFrame* pPageFrameOfAnchor = _rAnchoredObj.FindPageFrameOfAnchor(); @@ -621,6 +683,69 @@ bool SwObjectFormatterTextFrame::CheckMovedFwdCondition( } } + if (bAnchorIsMovedForward) + { + // tdf#138518 try to determine if there is a fly on page rFromPageFrame + // which is anchored in a frame that is "below" the anchor frame + // of _rAnchoredObj, such that it should move to the next page before + // _rAnchoredObj does + if (auto * pObjs = rFromPageFrame.GetSortedObjs()) + { + for (SwAnchoredObject *const pObj : *pObjs) + { + SwPageFrame const*const pObjAnchorPage(pObj->FindPageFrameOfAnchor()); + assert(pObjAnchorPage); + if ((pObjAnchorPage == &rFromPageFrame + ? _boInFollow // same-page but will move forward + : rFromPageFrame.GetPhyPageNum() < pObjAnchorPage->GetPhyPageNum()) + && pObj->GetFrameFormat().GetAnchor().GetAnchorId() + != RndStdIds::FLY_AS_CHAR) + { + if (pPageFrameOfAnchor->GetPhyPageNum() < pObjAnchorPage->GetPhyPageNum()) + { + SAL_INFO("sw.layout", "SwObjectFormatterTextFrame::CheckMovedFwdCondition(): o_rbPageHasFlysAnchoredBelowThis because next page"); + o_rbPageHasFlysAnchoredBelowThis = true; + break; + } + // on same page: check if it's in next-chain in the document body + // (in case both are in the same fly the flag must not be + // set because the whole fly moves at once) + SwContentFrame const*const pInBodyFrameObj(FindFrameInBody(*pObj)); + SwContentFrame const*const pInBodyFrameAnchoredObj(FindFrameInBody(_rAnchoredObj)); + if (pInBodyFrameObj && pInBodyFrameAnchoredObj) + { + bool isBreakMore(false); + // currently this ignores index of at-char flys + for (SwContentFrame const* pContentFrame = pInBodyFrameAnchoredObj->FindNextCnt(); + pContentFrame; + pContentFrame = pContentFrame->FindNextCnt()) + { + if (pInBodyFrameObj == pContentFrame) + { + // subsequent cells in a row are not automatically + // "below" and the row could potentially be split + // TODO refine check if needed + if (!pInBodyFrameAnchoredObj->IsInTab() + || FindTopLevelRowFrame(pInBodyFrameAnchoredObj) + != FindTopLevelRowFrame(pInBodyFrameAnchoredObj)) + { // anchored in next chain on same page + SAL_INFO("sw.layout", "SwObjectFormatterTextFrame::CheckMovedFwdCondition(): o_rbPageHasFlysAnchoredBelowThis because next chain on same page"); + o_rbPageHasFlysAnchoredBelowThis = true; + isBreakMore = true; + } + break; + } + } + if (isBreakMore) + { + break; + } + } + } + } + } + } + return bAnchorIsMovedForward; } @@ -641,6 +766,7 @@ static void lcl_FormatContentOfLayoutFrame( SwLayoutFrame* pLayFrame, if ( pLowerFrame->IsLayoutFrame() ) { SwFrameDeleteGuard aCrudeHack(pLowerFrame); // ??? any issue setting this for non-footnote frames? + // prevent moving footnotes by formatting if they are already being moved lcl_FormatContentOfLayoutFrame( static_cast<SwLayoutFrame*>(pLowerFrame), pLastLowerFrame ); } @@ -686,21 +812,46 @@ void SwObjectFormatterTextFrame::FormatAnchorFrameAndItsPrevs( SwTextFrame& _rAn // for follow text frames. if ( !_rAnchorTextFrame.IsFollow() ) { + // In case the anchor frame is in a column or section, format its + // previous frames first - but don't jump out of the current layout + // environment, e.g. from footnotes into the footnote boss. + SwFrame * pSectFrame(nullptr); + SwFrame * pColFrameOfAnchor(nullptr); + for (SwFrame* pUpper = _rAnchorTextFrame.GetUpper(); + pUpper != nullptr; pUpper = pUpper->GetUpper()) + { + if (pUpper->IsCellFrame()) + { + break; // apparently nothing to be done? + } + if (pUpper->IsFootnoteFrame()) + { + SAL_INFO_IF(pColFrameOfAnchor == nullptr && pUpper->FindColFrame(), + "sw.layout", "tdf#122894 skipping column for footnote in column"); + break; // stop: prevent crash in case footnotes are being moved + } + if (pUpper->IsSctFrame()) + { + pColFrameOfAnchor = nullptr; + pSectFrame = pUpper; + break; + } + if (pColFrameOfAnchor != nullptr) + { // parent of column not a section frame => column not in section + break; + } + if (pUpper->IsColumnFrame()) + { + pColFrameOfAnchor = pUpper; + } + } + // if anchor frame is directly inside a section, format this section and // its previous frames. // Note: It's a very simple format without formatting objects. - if ( _rAnchorTextFrame.IsInSct() ) + if (pSectFrame) { - SwFrame* pSectFrame = _rAnchorTextFrame.GetUpper(); - while ( pSectFrame ) - { - if ( pSectFrame->IsSctFrame() || pSectFrame->IsCellFrame() ) - { - break; - } - pSectFrame = pSectFrame->GetUpper(); - } - if ( pSectFrame && pSectFrame->IsSctFrame() ) + assert(pSectFrame->IsSctFrame()); { SwFrameDeleteGuard aDeleteGuard(&_rAnchorTextFrame); // #i44049# @@ -711,6 +862,8 @@ void SwObjectFormatterTextFrame::FormatAnchorFrameAndItsPrevs( SwTextFrame& _rAn // Thus, check for valid <pFrame>. while ( pFrame && pFrame != pSectFrame ) { + SwFrameDeleteGuard aDeleteFrameGuard(pFrame); + if ( pFrame->IsLayoutFrame() ) lcl_FormatContentOfLayoutFrame( static_cast<SwLayoutFrame*>(pFrame) ); else @@ -728,9 +881,9 @@ void SwObjectFormatterTextFrame::FormatAnchorFrameAndItsPrevs( SwTextFrame& _rAn // #i40140# - if anchor frame is inside a column, // format the content of the previous columns. // Note: It's a very simple format without formatting objects. - SwFrame* pColFrameOfAnchor = _rAnchorTextFrame.FindColFrame(); - if ( pColFrameOfAnchor ) + if (pColFrameOfAnchor) { + assert(pColFrameOfAnchor->IsColumnFrame()); // #i44049# _rAnchorTextFrame.LockJoin(); SwFrame* pColFrame = pColFrameOfAnchor->GetUpper()->GetLower(); |