diff options
Diffstat (limited to 'sw/source/core/text/frmform.cxx')
-rw-r--r-- | sw/source/core/text/frmform.cxx | 432 |
1 files changed, 372 insertions, 60 deletions
diff --git a/sw/source/core/text/frmform.cxx b/sw/source/core/text/frmform.cxx index 0304661e8438..4e2caf27b276 100644 --- a/sw/source/core/text/frmform.cxx +++ b/sw/source/core/text/frmform.cxx @@ -17,6 +17,8 @@ * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ +#include <config_wasm_strip.h> + #include <sal/config.h> #include <sal/log.hxx> @@ -47,6 +49,9 @@ #include <editeng/tstpitem.hxx> #include <redline.hxx> #include <comphelper/lok.hxx> +#include <flyfrms.hxx> +#include <frmtool.hxx> +#include <layouter.hxx> // Tolerance in formatting and text output #define SLOPPY_TWIPS 5 @@ -212,7 +217,7 @@ bool SwTextFrame::CalcFollow(TextFrameIndex const nTextOfst) if( pPara ) { pPara->GetReformat() = SwCharRange(); - pPara->GetDelta() = 0; + pPara->SetDelta(0); } } @@ -310,7 +315,7 @@ bool SwTextFrame::CalcFollow(TextFrameIndex const nTextOfst) if( pPara ) { pPara->GetReformat() = SwCharRange(); - pPara->GetDelta() = 0; + pPara->SetDelta(0); } } @@ -323,7 +328,7 @@ bool SwTextFrame::CalcFollow(TextFrameIndex const nTextOfst) const tools::Long nRemaining = - aRectFnSet.BottomDist( GetUpper()->getFrameArea(), nOldBottom ); - if ( nRemaining > 0 && !GetUpper()->IsSctFrame() && + if ( nRemaining > 0 && nRemaining != ( aRectFnSet.IsVert() ? nMyPos - getFrameArea().Right() : getFrameArea().Top() - nMyPos ) ) @@ -337,7 +342,47 @@ bool SwTextFrame::CalcFollow(TextFrameIndex const nTextOfst) void SwTextFrame::MakePos() { + Point aOldPos = getFrameArea().Pos(); SwFrame::MakePos(); + + // Recalc split flys if our position changed. + if (aOldPos != getFrameArea().Pos()) + { + // Find the master frame. + const SwTextFrame* pMaster = this; + while (pMaster->IsFollow()) + { + pMaster = pMaster->FindMaster(); + } + // Find which flys are effectively anchored to this frame. + for (const auto& pFly : pMaster->GetSplitFlyDrawObjs()) + { + SwTextFrame* pFlyAnchor = pFly->FindAnchorCharFrame(); + if (pFlyAnchor != this) + { + continue; + } + // Possibly this fly was positioned relative to us, invalidate its position now that our + // position is changed. + SwPageFrame* pPageFrame = pFly->FindPageFrame(); + bool bFlyNeedsPositioning = false; + bool bFlyPageMismatch = false; + if (pPageFrame) + { + // Was the position just adjusted to be inside the page frame? + bFlyNeedsPositioning = pFly->getFrameArea().Pos() == pPageFrame->getFrameArea().Pos(); + // Is the fly on a page different than the anchor frame? + bFlyPageMismatch = pPageFrame != FindPageFrame(); + } + if (bFlyNeedsPositioning || bFlyPageMismatch) + { + // Not really positioned, unlock the position once to allow a recalc. + pFly->UnlockPosition(); + } + pFly->InvalidatePos(); + } + } + // Inform LOK clients about change in position of redlines (if any) if(!comphelper::LibreOfficeKit::isActive()) return; @@ -347,14 +392,14 @@ void SwTextFrame::MakePos() for (SwRedlineTable::size_type nRedlnPos = 0; nRedlnPos < rTable.size(); ++nRedlnPos) { SwRangeRedline* pRedln = rTable[nRedlnPos]; - if (pTextNode->GetIndex() == pRedln->GetPoint()->nNode.GetNode().GetIndex()) + if (pTextNode->GetIndex() == pRedln->GetPoint()->GetNode().GetIndex()) { pRedln->MaybeNotifyRedlinePositionModification(getFrameArea().Top()); if (GetMergedPara() && pRedln->GetType() == RedlineType::Delete - && pRedln->GetPoint()->nNode != pRedln->GetMark()->nNode) + && pRedln->GetPoint()->GetNode() != pRedln->GetMark()->GetNode()) { - pTextNode = pRedln->End()->nNode.GetNode().GetTextNode(); + pTextNode = pRedln->End()->GetNode().GetTextNode(); } } } @@ -456,7 +501,7 @@ void SwTextFrame::AdjustFrame( const SwTwips nChgHght, bool bHasToFit ) else nRstHeight = getFrameArea().Left() + getFrameArea().Width() - ( GetUpper()->getFrameArea().Left() + GetUpper()->getFramePrintArea().Left() ); - } + } else nRstHeight = GetUpper()->getFrameArea().Top() + GetUpper()->getFramePrintArea().Top() @@ -517,9 +562,6 @@ void SwTextFrame::AdjustFrame( const SwTwips nChgHght, bool bHasToFit ) css::uno::Sequence< css::style::TabStop > SwTextFrame::GetTabStopInfo( SwTwips CurrentPos ) { - css::uno::Sequence< css::style::TabStop > tabs(1); - css::style::TabStop ts; - SwTextFormatInfo aInf( getRootFrame()->GetCurrShell()->GetOut(), this ); SwTextFormatter aLine( this, &aInf ); SwTextCursor TextCursor( this, &aInf ); @@ -533,10 +575,11 @@ css::uno::Sequence< css::style::TabStop > SwTextFrame::GetTabStopInfo( SwTwips C if( !pTS ) { - return css::uno::Sequence< css::style::TabStop >(); + return {}; } // copy tab stop information into a Sequence, which only contains one element. + css::style::TabStop ts; ts.Position = pTS->GetTabPos(); ts.DecimalChar = pTS->GetDecimal(); ts.FillChar = pTS->GetFill(); @@ -550,8 +593,7 @@ css::uno::Sequence< css::style::TabStop > SwTextFrame::GetTabStopInfo( SwTwips C default: break; // prevent warning } - tabs[0] = ts; - return tabs; + return { ts }; } // AdjustFollow expects the following situation: @@ -568,17 +610,27 @@ void SwTextFrame::AdjustFollow_( SwTextFormatter &rLine, // We got the rest of the text mass: Delete all Follows // DummyPortions() are a special case. // Special cases are controlled by parameter <nMode>. - if( HasFollow() && !(nMode & 1) && nOffset == nEnd ) + bool bDontJoin = nMode & 1; + if( HasFollow() && !bDontJoin && nOffset == nEnd ) { while( GetFollow() ) { if( GetFollow()->IsLocked() ) { - OSL_FAIL( "+SwTextFrame::JoinFrame: Follow is locked." ); + // this can happen when follow calls pMaster->GetFormatted() + SAL_INFO("sw.core", "+SwTextFrame::JoinFrame: Follow is locked." ); return; } if (GetFollow()->IsDeleteForbidden()) return; + + if (HasNonLastSplitFlyDrawObj()) + { + // If a fly frame is anchored to us that has a follow, then don't join the anchor. + // First those fly frames have to be joined. + return; + } + JoinFrame(); } @@ -591,20 +643,46 @@ void SwTextFrame::AdjustFollow_( SwTextFormatter &rLine, const TextFrameIndex nNewOfst = (IsInFootnote() && (!GetIndNext() || HasFollow())) ? rLine.FormatQuoVadis(nOffset) : nOffset; - if( !(nMode & 1) ) + bool bHasNonLastSplitFlyDrawObj = false; + if (GetFollow() && GetOffset() == GetFollow()->GetOffset()) + { + bHasNonLastSplitFlyDrawObj = HasNonLastSplitFlyDrawObj(); + } + + if( !bDontJoin ) { // We steal text mass from our Follows // It can happen that we have to join some of them while( GetFollow() && GetFollow()->GetFollow() && nNewOfst >= GetFollow()->GetFollow()->GetOffset() ) { + if (bHasNonLastSplitFlyDrawObj) + { + // A non-last split fly is anchored to us, don't move content from the last frame to + // this one and don't join. + return; + } + JoinFrame(); } } + if (IsEmptyMasterWithSplitFly()) + { + // A split fly is anchored to us, don't move content from the follow frame to this one. + return; + } + // The Offset moved if( GetFollow() ) { + if (!bDontJoin && bHasNonLastSplitFlyDrawObj) + { + // A non-last split fly is anchored to us, our follow is the last one in the text frame + // chain. No move of text from that follow to this text frame. + return; + } + if ( nMode ) GetFollow()->ManipOfst(TextFrameIndex(0)); @@ -666,16 +744,20 @@ SwContentFrame *SwTextFrame::JoinFrame() // Relation CONTENT_FLOWS_FROM for current next paragraph will change // and relation CONTENT_FLOWS_TO for current previous paragraph, which // is <this>, will change. +#if !ENABLE_WASM_STRIP_ACCESSIBILITY { SwViewShell* pViewShell( pFoll->getRootFrame()->GetCurrShell() ); if ( pViewShell && pViewShell->GetLayout() && pViewShell->GetLayout()->IsAnyShellAccessible() ) { + auto pNext = pFoll->FindNextCnt( true ); pViewShell->InvalidateAccessibleParaFlowRelation( - dynamic_cast<SwTextFrame*>(pFoll->FindNextCnt( true )), + pNext ? pNext->DynCastTextFrame() : nullptr, this ); } } +#endif + pFoll->Cut(); SetFollow(pNxt); SwFrame::DestroyFrame(pFoll); @@ -700,16 +782,19 @@ void SwTextFrame::SplitFrame(TextFrameIndex const nTextPos) // Relation CONTENT_FLOWS_FROM for current next paragraph will change // and relation CONTENT_FLOWS_TO for current previous paragraph, which // is <this>, will change. +#if !ENABLE_WASM_STRIP_ACCESSIBILITY { SwViewShell* pViewShell( pNew->getRootFrame()->GetCurrShell() ); if ( pViewShell && pViewShell->GetLayout() && pViewShell->GetLayout()->IsAnyShellAccessible() ) { + auto pNext = pNew->FindNextCnt( true ); pViewShell->InvalidateAccessibleParaFlowRelation( - dynamic_cast<SwTextFrame*>(pNew->FindNextCnt( true )), + pNext ? pNext->DynCastTextFrame() : nullptr, this ); } } +#endif // If footnotes end up in pNew bz our actions, we need // to re-register them @@ -758,7 +843,7 @@ void SwTextFrame::SplitFrame(TextFrameIndex const nTextPos) void SwTextFrame::SetOffset_(TextFrameIndex const nNewOfst) { - // We do not need to invalidate out Follow. + // We do not need to invalidate our Follow. // We are a Follow, get formatted right away and call // SetOffset() from there mnOffset = nNewOfst; @@ -768,7 +853,7 @@ void SwTextFrame::SetOffset_(TextFrameIndex const nNewOfst) SwCharRange &rReformat = pPara->GetReformat(); rReformat.Start() = TextFrameIndex(0); rReformat.Len() = TextFrameIndex(GetText().getLength()); - pPara->GetDelta() = sal_Int32(rReformat.Len()); + pPara->SetDelta(sal_Int32(rReformat.Len())); } InvalidateSize(); } @@ -987,7 +1072,7 @@ bool SwTextFrame::CalcPreps() return bRet; } -// We rewire the footnotes and the character bound objects +// Move the as-character objects - footnotes must be moved by RemoveFootnote! void SwTextFrame::ChangeOffset( SwTextFrame* pFrame, TextFrameIndex nNew ) { if( pFrame->GetOffset() < nNew ) @@ -996,6 +1081,54 @@ void SwTextFrame::ChangeOffset( SwTextFrame* pFrame, TextFrameIndex nNew ) MoveFlyInCnt( pFrame, nNew, TextFrameIndex(COMPLETE_STRING) ); } +static bool isFirstVisibleFrameInBody(const SwTextFrame* pFrame) +{ + const SwFrame* pBodyFrame = pFrame->FindBodyFrame(); + if (!pBodyFrame) + return false; + for (const SwFrame* pCur = pFrame;;) + { + for (const SwFrame* pPrev = pCur->GetPrev(); pPrev; pPrev = pPrev->GetPrev()) + if (!pPrev->IsHiddenNow()) + return false; + pCur = pCur->GetUpper(); + assert(pCur); // We found pBodyFrame, right? + if (pCur->IsBodyFrame()) + return true; + } +} + +static bool hasFly(const SwTextFrame* pFrame) +{ + if (auto pDrawObjs = pFrame->GetDrawObjs(); pDrawObjs && pDrawObjs->size()) + { + auto anchorId = (*pDrawObjs)[0]->GetFrameFormat()->GetAnchor().GetAnchorId(); + if (anchorId == RndStdIds::FLY_AT_PARA || anchorId == RndStdIds::FLY_AT_CHAR) + return true; + } + return false; +} + +static bool hasAtPageFly(const SwFrame* pFrame) +{ + auto pPageFrame = pFrame->FindPageFrame(); + if (!pPageFrame) + return false; + auto pPageDrawObjs = pPageFrame->GetDrawObjs(); + if (pPageDrawObjs) + { + for (const auto pObject : *pPageDrawObjs) + if (pObject->GetFrameFormat()->GetAnchor().GetAnchorId() == RndStdIds::FLY_AT_PAGE) + return true; + } + return false; +} + +static bool isReallyEmptyMaster(const SwTextFrame* pFrame) +{ + return pFrame->IsEmptyMaster() && (!pFrame->GetDrawObjs() || !pFrame->GetDrawObjs()->size()); +} + void SwTextFrame::FormatAdjust( SwTextFormatter &rLine, WidowsAndOrphans &rFrameBreak, TextFrameIndex const nStrLen, @@ -1021,20 +1154,57 @@ void SwTextFrame::FormatAdjust( SwTextFormatter &rLine, !rFrameBreak.IsInside( rLine ) ) : rFrameBreak.IsBreakNow( rLine ) ) ) ) ? 1 : 0; + + SwTextFormatInfo& rInf = rLine.GetInfo(); + bool bEmptyWithSplitFly = false; + if (nNew == 0 && !nStrLen && !rInf.GetTextFly().IsOn() && IsEmptyWithSplitFly()) + { + // Empty paragraph, so IsBreakNow() is not called, but we should split the fly portion and + // the paragraph marker. + nNew = 1; + bEmptyWithSplitFly = true; + } + + const SwFrame *pBodyFrame = FindBodyFrame(); + // i#84870 // no split of text frame, which only contains an as-character anchored object - bool bOnlyContainsAsCharAnchoredObj = + bool bLoneAsCharAnchoredObj = + pBodyFrame && !IsFollow() && nStrLen == TextFrameIndex(1) && GetDrawObjs() && GetDrawObjs()->size() == 1 && - (*GetDrawObjs())[0]->GetFrameFormat().GetAnchor().GetAnchorId() == RndStdIds::FLY_AS_CHAR; - - // Still try split text frame if we have columns. - if (FindColFrame()) - bOnlyContainsAsCharAnchoredObj = false; + (*GetDrawObjs())[0]->GetFrameFormat()->GetAnchor().GetAnchorId() == RndStdIds::FLY_AS_CHAR; - if ( nNew && bOnlyContainsAsCharAnchoredObj ) + if (bLoneAsCharAnchoredObj) { - nNew = 0; + // Still try split text frame if we have columns. + if (FindColFrame()) + bLoneAsCharAnchoredObj = false; + // tdf#160526: only no split if there is no preceding frames on same page + else if (!isFirstVisibleFrameInBody(this)) + bLoneAsCharAnchoredObj = false; + else + nNew = 0; + } + else if (nNew) + { + if (IsFollow()) + { + // tdf#160549: do not split the frame at the very beginning again, if its master was empty + auto precede = static_cast<SwTextFrame*>(GetPrecede()); + assert(precede); + auto precedeText = precede->DynCastTextFrame(); + assert(precedeText); + if (isReallyEmptyMaster(precedeText)) + nNew = 0; + } + else if (!bEmptyWithSplitFly) + { + // Do not split immediately in the beginning of page (unless there is an at-para or + // at-char or at-page fly, which pushes the rest down) + if (isFirstVisibleFrameInBody(this) && !hasFly(this) && pBodyFrame && !hasAtPageFly(pBodyFrame)) + nNew = 0; + } } if ( nNew ) @@ -1042,8 +1212,6 @@ void SwTextFrame::FormatAdjust( SwTextFormatter &rLine, SplitFrame( nEnd ); } - const SwFrame *pBodyFrame = FindBodyFrame(); - const tools::Long nBodyHeight = pBodyFrame ? ( IsVertical() ? pBodyFrame->getFrameArea().Width() : pBodyFrame->getFrameArea().Height() ) : 0; @@ -1052,7 +1220,7 @@ void SwTextFrame::FormatAdjust( SwTextFormatter &rLine, // are valid now pPara->GetReformat() = SwCharRange(); bool bDelta = pPara->GetDelta() != 0; - pPara->GetDelta() = 0; + pPara->SetDelta(0); if( rLine.IsStop() ) { @@ -1067,7 +1235,11 @@ void SwTextFrame::FormatAdjust( SwTextFormatter &rLine, // AdjustFollow might execute JoinFrame() because of this. // Else, nEnd is the end of the last line in the Master. TextFrameIndex nOld = nEnd; - nEnd = rLine.GetEnd(); + // Make sure content from the last floating table anchor is not shifted to previous anchors. + if (!HasNonLastSplitFlyDrawObj()) + { + nEnd = rLine.GetEnd(); + } if( GetFollow() ) { if( nNew && nOld < nEnd ) @@ -1082,6 +1254,7 @@ void SwTextFrame::FormatAdjust( SwTextFormatter &rLine, // need to create a Follow. // We also need to do this if the whole mass of text remains in the Master, // because a hard line break could necessitate another line (without text mass)! + TextFrameIndex const nOld(nEnd); nEnd = rLine.GetEnd(); if( GetFollow() ) { @@ -1107,18 +1280,43 @@ void SwTextFrame::FormatAdjust( SwTextFormatter &rLine, // for the paragraph mark. nNew |= 1; } + // move footnotes if the follow is kept - if RemoveFootnote() is + // called in next format iteration, it will be with the *new* + // offset so no effect! + if (nNew && nOld < nEnd) + { + RemoveFootnote(nOld, nEnd - nOld); + } ChangeOffset( GetFollow(), nEnd ); + + SwFlyAtContentFrame* pNonLastSplitFlyDrawObj = HasNonLastSplitFlyDrawObj(); + if (pNonLastSplitFlyDrawObj && !pNonLastSplitFlyDrawObj->IsWrapOnAllPages()) + { + // Make sure content from the last floating table anchor is not shifted to previous + // anchors, unless we're in the special "wrap on all pages" mode. + nEnd = TextFrameIndex(0); + } + GetFollow()->ManipOfst( nEnd ); } else { + const SwTextNode* pTextNode = GetTextNodeForParaProps(); + bool bHasVisibleNumRule = nStrLen == TextFrameIndex(0) && pTextNode->GetNumRule(); + + if (!pTextNode->HasVisibleNumberingOrBullet()) + { + bHasVisibleNumRule = false; + } + // Only split frame, if the frame contains // content or contains no content, but has a numbering. // i#84870 - No split, if text frame only contains one // as-character anchored object. - if ( !bOnlyContainsAsCharAnchoredObj && - (nStrLen > TextFrameIndex(0) || - (nStrLen == TextFrameIndex(0) && GetTextNodeForParaProps()->GetNumRule())) + if (!bLoneAsCharAnchoredObj + && (bHasVisibleNumRule + || (nStrLen > TextFrameIndex(0) + && (nEnd != rLine.GetStart() || rInf.GetRest()))) ) { SplitFrame( nEnd ); @@ -1142,7 +1340,7 @@ void SwTextFrame::FormatAdjust( SwTextFormatter &rLine, SwTwips nChg = rLine.CalcBottomLine() - nDocPrtTop - nOldHeight; //#i84870# - no shrink of text frame, if it only contains one as-character anchored object. - if ( nChg < 0 && !bDelta && bOnlyContainsAsCharAnchoredObj ) + if (nChg < 0 && !bDelta && bLoneAsCharAnchoredObj) { nChg = 0; } @@ -1169,7 +1367,7 @@ void SwTextFrame::FormatAdjust( SwTextFormatter &rLine, } // bPrev is set whether Reformat.Start() was called because of Prev(). -// Else, wo don't know whether we can limit the repaint or not. +// Else, we don't know whether we can limit the repaint or not. bool SwTextFrame::FormatLine( SwTextFormatter &rLine, const bool bPrev ) { OSL_ENSURE( ! IsVertical() || IsSwapped(), @@ -1177,8 +1375,8 @@ bool SwTextFrame::FormatLine( SwTextFormatter &rLine, const bool bPrev ) SwParaPortion *pPara = rLine.GetInfo().GetParaPortion(); const SwLineLayout *pOldCur = rLine.GetCurr(); const TextFrameIndex nOldLen = pOldCur->GetLen(); - const sal_uInt16 nOldAscent = pOldCur->GetAscent(); - const sal_uInt16 nOldHeight = pOldCur->Height(); + const SwTwips nOldAscent = pOldCur->GetAscent(); + const SwTwips nOldHeight = pOldCur->Height(); const SwTwips nOldWidth = pOldCur->Width() + pOldCur->GetHangingMargin(); const bool bOldHyph = pOldCur->IsEndHyph(); SwTwips nOldTop = 0; @@ -1277,7 +1475,8 @@ bool SwTextFrame::FormatLine( SwTextFormatter &rLine, const bool bPrev ) } // Calculating the good ol' nDelta - pPara->GetDelta() -= sal_Int32(pNew->GetLen()) - sal_Int32(nOldLen); + const sal_Int32 nDiff = sal_Int32(pNew->GetLen()) - sal_Int32(nOldLen); + pPara->SetDelta(pPara->GetDelta() - nDiff); // Stop! if( rLine.IsStop() ) @@ -1596,9 +1795,27 @@ void SwTextFrame::Format_( SwTextFormatter &rLine, SwTextFormatInfo &rInf, // If we're finished formatting the text and we still // have other line objects left, these are superfluous // now because the text has gotten shorter. + bool bTruncLines = false; if( rLine.GetStart() + rLine.GetLength() >= nStrLen && rLine.GetCurr()->GetNext() ) { + bTruncLines = true; + } + else if (GetMergedPara() && rLine.GetCurr()->GetNext()) + { + // We can also have superfluous lines with redlining in case the current line is shorter + // than the text length, but the total length of lines is still more than expected. + // Truncate in this case as well. + TextFrameIndex nLen(0); + for (const SwLineLayout* pLine = pPara; pLine; pLine = pLine->GetNext()) + { + nLen += pLine->GetLen(); + } + bTruncLines = nLen > nStrLen; + } + + if (bTruncLines) + { rLine.TruncLines(); rLine.SetTruncLines( true ); } @@ -1687,7 +1904,8 @@ void SwTextFrame::FormatOnceMore( SwTextFormatter &rLine, SwTextFormatInfo &rInf } } -void SwTextFrame::Format_( vcl::RenderContext* pRenderContext, SwParaPortion *pPara ) +void SwTextFrame::FormatImpl(vcl::RenderContext* pRenderContext, SwParaPortion *pPara, + std::vector<SwAnchoredObject *> & rIntersectingObjs) { const bool bIsEmpty = GetText().isEmpty(); @@ -1722,6 +1940,18 @@ void SwTextFrame::Format_( vcl::RenderContext* pRenderContext, SwParaPortion *pP if( aLine.IsOnceMore() ) FormatOnceMore( aLine, aInf ); + if (aInf.GetTextFly().IsOn()) + { + SwRect const aRect(aInf.GetTextFly().GetFrameArea()); + for (SwAnchoredObject *const pObj : aInf.GetTextFly().GetAnchoredObjList()) + { + if (!aInf.GetTextFly().AnchoredObjToRect(pObj, aRect).IsEmpty()) + { + rIntersectingObjs.push_back(pObj); + } + } + } + if ( IsVertical() ) SwapWidthAndHeight(); @@ -1757,9 +1987,7 @@ void SwTextFrame::Format( vcl::RenderContext* pRenderContext, const SwBorderAttr if( aRectFnSet.GetWidth(getFramePrintArea()) <= 0 ) { // If MustFit is set, we shrink to the Upper's bottom edge if needed. - // Else we just take a standard size of 12 Pt. (240 twip). SwTextLineAccess aAccess( this ); - tools::Long nFrameHeight = aRectFnSet.GetHeight(getFrameArea()); if( aAccess.GetPara()->IsPrepMustFit() ) { @@ -1768,16 +1996,8 @@ void SwTextFrame::Format( vcl::RenderContext* pRenderContext, const SwBorderAttr if( nDiff > 0 ) Shrink( nDiff ); } - else if( 240 < nFrameHeight ) - { - Shrink( nFrameHeight - 240 ); - } - else if( 240 > nFrameHeight ) - { - Grow( 240 - nFrameHeight ); - } - nFrameHeight = aRectFnSet.GetHeight(getFrameArea()); + tools::Long nFrameHeight = aRectFnSet.GetHeight(getFrameArea()); const tools::Long nTop = aRectFnSet.GetTopMargin(*this); if( nTop > nFrameHeight ) @@ -1793,7 +2013,14 @@ void SwTextFrame::Format( vcl::RenderContext* pRenderContext, const SwBorderAttr return; } - const TextFrameIndex nStrLen(GetText().getLength()); + TextFrameIndex nStrLen(GetText().getLength()); + + if (HasNonLastSplitFlyDrawObj()) + { + // Non-last part of split fly anchor: consider this empty. + nStrLen = TextFrameIndex(0); + } + if ( nStrLen || !FormatEmpty() ) { @@ -1906,7 +2133,13 @@ void SwTextFrame::Format( vcl::RenderContext* pRenderContext, const SwBorderAttr } do { - Format_( pRenderContext, aAccess.GetPara() ); + ::std::vector<SwAnchoredObject *> intersectingObjs; + ::std::vector<SwFrame const*> nexts; + for (SwFrame const* pNext = GetNext(); pNext; pNext = pNext->GetNext()) + { + nexts.push_back(pNext); + } + FormatImpl(pRenderContext, aAccess.GetPara(), intersectingObjs); if( pFootnoteBoss && nFootnoteHeight ) { const SwFootnoteContFrame* pCont = pFootnoteBoss->FindFootnoteCont(); @@ -1914,12 +2147,79 @@ void SwTextFrame::Format( vcl::RenderContext* pRenderContext, const SwBorderAttr // If we lost some footnotes, we may have more space // for our main text, so we have to format again ... if( nNewHeight < nFootnoteHeight ) + { nFootnoteHeight = nNewHeight; - else - break; + continue; + } } - else - break; + if (!intersectingObjs.empty()) + { + // assumption is that FormatImpl() only moves frames + // in the next-chain to next page + SwPageFrame *const pPage(FindPageFrame()); + SwTextFrame * pLastMovedAnchor(nullptr); + auto lastIter(nexts.end()); + for (SwAnchoredObject *const pObj : intersectingObjs) + { + SwFrame *const pAnchor(pObj->AnchorFrame()); + SwPageFrame *const pAnchorPage(pAnchor->FindPageFrame()); + if (pAnchorPage != pPage) + { + auto const iter(::std::find(nexts.begin(), nexts.end(), pAnchor)); + if (iter != nexts.end()) + { + assert(pAnchor->IsTextFrame()); + // (can't check SwOszControl::IsInProgress()?) + // called in loop in FormatAnchorFrameAndItsPrevs() + if (static_cast<SwTextFrame const*>(pAnchor)->IsJoinLocked() + // called in loop in SwFrame::PrepareMake() + || pAnchor->IsDeleteForbidden()) + { + // when called via FormatAnchorFrameAndItsPrevs(): + // don't do anything, caller will handle it + pLastMovedAnchor = nullptr; + break; + } + assert(pPage->GetPhyPageNum() < pAnchorPage->GetPhyPageNum()); // how could it move backward? + + if (!pLastMovedAnchor || iter < lastIter) + { + pLastMovedAnchor = static_cast<SwTextFrame *>(pAnchor); + lastIter = iter; + } + } + } + } + SwPageFrame const*const pPrevPage(static_cast<SwPageFrame const*>(pPage->GetPrev())); + if (pLastMovedAnchor) + { + for (SwAnchoredObject *const pObj : intersectingObjs) + { + if (pObj->AnchorFrame() == pLastMovedAnchor) + { + SwPageFrame *const pAnchorPage(pLastMovedAnchor->FindPageFrame()); + SAL_INFO("sw.layout", "SwTextFrame::Format: move anchored " << pObj << " from " << pPage->GetPhyPageNum() << " to " << pAnchorPage->GetPhyPageNum()); + pObj->RegisterAtPage(*pAnchorPage); + // tdf#143239 if the position remains valid, it may not be + // positioned again so would remain on the wrong page! + pObj->InvalidateObjPos(); + ::Notify_Background(pObj->GetDrawObj(), pPage, + pObj->GetObjRect(), PrepareHint::FlyFrameLeave, false); + pObj->SetForceNotifyNewBackground(true); + } + } + if (GetFollow() // this frame was split + && (!pPrevPage // prev page is still valid + || (!pPrevPage->IsInvalid() + && (!pPrevPage->GetSortedObjs() || !pPrevPage->IsInvalidFly())))) + { // this seems a bit risky... + SwLayouter::InsertMovedFwdFrame(GetTextNodeFirst()->GetDoc(), + *pLastMovedAnchor, FindPageFrame()->GetPhyPageNum() + 1); + } + continue; // try again without the fly + } + } + break; } while ( pFootnoteBoss ); if( bOrphan ) { @@ -1937,6 +2237,18 @@ void SwTextFrame::Format( vcl::RenderContext* pRenderContext, const SwBorderAttr { pPre->InvalidatePos(); } + + if (IsEmptyMasterWithSplitFly()) + { + // A fly is anchored to us, reduce size, so we definitely still fit the current + // page. + SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this); + aRectFnSet.SetHeight(aFrm, 0); + + SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this); + aRectFnSet.SetTop(aPrt, 0); + aRectFnSet.SetHeight(aPrt, 0); + } } } @@ -2054,7 +2366,7 @@ bool SwTextFrame::FormatQuick( bool bForceQuickFormat ) // Delete reformat pPara->GetReformat() = SwCharRange(); - pPara->GetDelta() = 0; + pPara->SetDelta(0); return true; } |