summaryrefslogtreecommitdiff
path: root/sw/source/core/text/frmform.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sw/source/core/text/frmform.cxx')
-rw-r--r--sw/source/core/text/frmform.cxx432
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;
}