flowfrm.hxx
为框架提供一般功能的基类
允许在分页符(流程)并应在下一页继续(可以
拆分),例如段落 (ContentFrame) 或表格 (TabFrame)。
这些功能的某些部分在 FlowFrame 中实现,而
具体的在相应的 Frame 类中完成。 FlowFrame 必须
被视为基类。因此,它本身不是框架,因此没有直接的
FlowFrame 的实例可以存在。
实际上它甚至不是一个真正的框架。明显的实现将是
FlowFrame 实际上是从 SwFrame 继承而来的,并且可以与自己的
会员资料。更多的类需要从 FlowFrame 和(通过
多个基类,因为类树恰好在分支处分裂
从 SwFrame 到 SwContentFrame 和 SwLayoutFrame)实际上也从 SwFrame 作为
好。不幸的是,这会导致 - 除了编译器和
调试程序 - 高昂的额外成本,恕我直言,我们无法做到
现在负担得起。
因此,我们使用另一种技术:FlowFrame 保持对 SwFrame 的引用
- 它实际上是它本身 - 他们是朋友。结果,该
FlowFrame 可以使用对 SwFrame 的引用而不是使用
它自己的 this 指针。
calcmove.cxx
sw\source\core\layout
*void MakeNxt( SwFrame pFrame, SwFrame pNxt )
void SwContentFrame::MakeAll(vcl::RenderContext /pRenderContext/)
{
OSL_ENSURE( GetUpper(), “no Upper?” );
OSL_ENSURE( IsTextFrame(), “MakeAll(), NoText” );
if ( !IsFollow() && StackHack::IsLocked() )
return;
if ( IsJoinLocked() )
return;
OSL_ENSURE( !static_cast<SwTextFrame*>(this)->IsSwapped(), "Calculation of a swapped frame" );
StackHack aHack;
if ( static_cast<SwTextFrame*>(this)->IsLocked() )
{
OSL_FAIL( "Format for locked TextFrame." );
return;
}
auto xDeleteGuard = std::make_unique<SwFrameDeleteGuard>(this);
LockJoin();
long nFormatCount = 0;
// - loop prevention
int nConsecutiveFormatsWithoutChange = 0;
PROTOCOL_ENTER( this, PROT::MakeAll, DbgAction::NONE, nullptr )
// takes care of the notification in the dtor
std::unique_ptr<SwContentNotify, o3tl::default_delete<SwContentNotify>> pNotify(new SwContentNotify( this ));
// as long as bMakePage is true, a new page can be created (exactly once)
bool bMakePage = true;
// bMovedBwd gets set to true when the frame flows backwards
bool bMovedBwd = false;
// as long as bMovedFwd is false, the Frame may flow backwards (until
// it has been moved forward once)
bool bMovedFwd = false;
sal_Bool bFormatted = false; // For the widow/orphan rules, we encourage the
// last ContentFrame of a chain to format. This only
// needs to happen once. Every time the Frame is
// moved, the flag will have to be reset.
bool bMustFit = false; // Once the emergency brake is pulled,
// no other prepares will be triggered
bool bFitPromise = false; // If a paragraph didn't fit, but promises
// with WouldFit that it would adjust accordingly,
// this flag is set. If it turns out that it
// didn't keep it's promise, we can act in a
// controlled fashion.
const bool bFly = IsInFly();
const bool bTab = IsInTab();
const bool bFootnote = IsInFootnote();
const bool bSct = IsInSct();
Point aOldFramePos; // This is so we can compare with the last pos
Point aOldPrtPos; // and determine whether it makes sense to Prepare
SwBorderAttrAccess aAccess( SwFrame::GetCache(), this );
const SwBorderAttrs &rAttrs = *aAccess.Get();
if ( !IsFollow() && rAttrs.JoinedWithPrev( *(this) ) )
{
pNotify->SetBordersJoinedWithPrev();
}
const bool bKeep = IsKeep(rAttrs.GetAttrSet().GetKeep(), GetBreakItem());
std::unique_ptr<SwSaveFootnoteHeight> pSaveFootnote;
if ( bFootnote )
{
SwFootnoteFrame *pFootnote = FindFootnoteFrame();
SwSectionFrame* pSct = pFootnote->FindSctFrame();
if ( !static_cast<SwTextFrame*>(pFootnote->GetRef())->IsLocked() )
{
SwFootnoteBossFrame* pBoss = pFootnote->GetRef()->FindFootnoteBossFrame(
pFootnote->GetAttr()->GetFootnote().IsEndNote() );
if( !pSct || pSct->IsColLocked() || !pSct->Growable() )
pSaveFootnote.reset( new SwSaveFootnoteHeight( pBoss,
static_cast<SwTextFrame*>(pFootnote->GetRef())->GetFootnoteLine( pFootnote->GetAttr() ) ) );
}
}
if ( GetUpper()->IsSctFrame() &&
HasFollow() && !GetFollow()->IsDeleteForbidden() &&
&GetFollow()->GetFrame() == GetNext() )
{
dynamic_cast<SwTextFrame&>(*this).JoinFrame();
}
// #i28701# - move master forward, if it has to move,
// because of its object positioning.
if ( !static_cast<SwTextFrame*>(this)->IsFollow() )
{
sal_uInt32 nToPageNum = 0;
const bool bMoveFwdByObjPos = SwLayouter::FrameMovedFwdByObjPos(
*(GetAttrSet()->GetDoc()),
*static_cast<SwTextFrame*>(this),
nToPageNum );
// #i58182#
// Also move a paragraph forward, which is the first one inside a table cell.
if ( bMoveFwdByObjPos &&
FindPageFrame()->GetPhyPageNum() < nToPageNum &&
( lcl_Prev( this ) ||
GetUpper()->IsCellFrame() ||
( GetUpper()->IsSctFrame() &&
GetUpper()->GetUpper()->IsCellFrame() ) ) &&
IsMoveable() )
{
bMovedFwd = true;
MoveFwd( bMakePage, false );
}
}
// If a Follow sits next to its Master and doesn't fit, we know it can
// be moved right now.
if ( lcl_Prev( this ) && static_cast<SwTextFrame*>(this)->IsFollow() && IsMoveable() )
{
bMovedFwd = true;
// If follow frame is in table, its master will be the last in the
// current table cell. Thus, invalidate the printing area of the master.
if ( IsInTab() )
{
lcl_Prev( this )->InvalidatePrt();
}
MoveFwd( bMakePage, false );
}
// Check footnote content for forward move.
// If a content of a footnote is on a prior page/column as its invalid
// reference, it can be moved forward.
if ( bFootnote && !isFrameAreaPositionValid() )
{
SwFootnoteFrame* pFootnote = FindFootnoteFrame();
SwContentFrame* pRefCnt = pFootnote ? pFootnote->GetRef() : nullptr;
if ( pRefCnt && !pRefCnt->isFrameAreaDefinitionValid() )
{
SwFootnoteBossFrame* pFootnoteBossOfFootnote = pFootnote->FindFootnoteBossFrame();
SwFootnoteBossFrame* pFootnoteBossOfRef = pRefCnt->FindFootnoteBossFrame();
//<loop of movefwd until condition held or no move>
if ( pFootnoteBossOfFootnote && pFootnoteBossOfRef &&
pFootnoteBossOfFootnote != pFootnoteBossOfRef &&
pFootnoteBossOfFootnote->IsBefore( pFootnoteBossOfRef ) )
{
bMovedFwd = true;
MoveFwd( bMakePage, false );
}
}
}
SwRectFnSet aRectFnSet(this);
SwFrame const* pMoveBwdPre(nullptr);
bool isMoveBwdPreValid(false);
SwRect aOldFrame_StopFormat, aOldFrame_StopFormat2;
SwRect aOldPrt_StopFormat, aOldPrt_StopFormat2;
while ( !isFrameAreaPositionValid() || !isFrameAreaSizeValid() || !isFramePrintAreaValid() )
{
// - loop prevention
aOldFrame_StopFormat2 = aOldFrame_StopFormat;
aOldPrt_StopFormat2 = aOldPrt_StopFormat;
aOldFrame_StopFormat = getFrameArea();
aOldPrt_StopFormat = getFramePrintArea();
bool bMoveable = IsMoveable();
if (bMoveable)
{
SwFrame *pPre = GetIndPrev();
if ( CheckMoveFwd( bMakePage, bKeep, bMovedBwd ) )
{
aRectFnSet.Refresh(this);
bMovedFwd = true;
if ( bMovedBwd )
{
// While flowing back, the Upper was encouraged to
// completely re-paint itself. We can skip this now after
// flowing back and forth.
GetUpper()->ResetCompletePaint();
// The predecessor was invalidated, so this is obsolete as well now.
assert(pPre);
if ((pPre == pMoveBwdPre && isMoveBwdPreValid) && !pPre->IsSctFrame())
::ValidateSz( pPre );
}
bMoveable = IsMoveable();
}
}
aOldFramePos = aRectFnSet.GetPos(getFrameArea());
aOldPrtPos = aRectFnSet.GetPos(getFramePrintArea());
if ( !isFrameAreaPositionValid() )
MakePos();
//Set FixSize. VarSize is being adjusted by Format().
if ( !isFrameAreaSizeValid() )
{
// invalidate printing area flag, if the following conditions are hold:
// - current frame width is 0.
// - current printing area width is 0.
// - frame width is adjusted to a value greater than 0.
// - printing area flag is true.
// Thus, it's assured that the printing area is adjusted, if the
// frame area width changes its width from 0 to something greater
// than 0.
// Note: A text frame can be in such a situation, if the format is
// triggered by method call <SwCursorShell::SetCursor()> after
// loading the document.
const SwTwips nNewFrameWidth = aRectFnSet.GetWidth(GetUpper()->getFramePrintArea());
if ( isFramePrintAreaValid() &&
nNewFrameWidth > 0 &&
aRectFnSet.GetWidth(getFrameArea()) == 0 &&
aRectFnSet.GetWidth(getFramePrintArea()) == 0 )
{
setFramePrintAreaValid(false);
}
{
SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
aRectFnSet.SetWidth( aFrm, nNewFrameWidth );
}
// When a lower of a vertically aligned fly frame changes its size we need to recalculate content pos.
if( GetUpper() && GetUpper()->IsFlyFrame() &&
GetUpper()->GetFormat()->GetTextVertAdjust().GetValue() != SDRTEXTVERTADJUST_TOP )
{
static_cast<SwFlyFrame*>(GetUpper())->InvalidateContentPos();
GetUpper()->SetCompletePaint();
}
}
if ( !isFramePrintAreaValid() )
{
const long nOldW = aRectFnSet.GetWidth(getFramePrintArea());
// #i34730# - keep current frame height
const SwTwips nOldH = aRectFnSet.GetHeight(getFrameArea());
MakePrtArea( rAttrs );
if ( nOldW != aRectFnSet.GetWidth(getFramePrintArea()) )
Prepare( PrepareHint::FixSizeChanged );
// #i34730# - check, if frame height has changed.
// If yes, send a PrepareHint::AdjustSizeWithoutFormatting and invalidate the size flag to
// force a format. The format will check in its method
// <SwTextFrame::CalcPreps()>, if the already formatted lines still
// fit and if not, performs necessary actions.
// #i40150# - no check, if frame is undersized.
if ( isFrameAreaSizeValid() && !IsUndersized() && nOldH != aRectFnSet.GetHeight(getFrameArea()) )
{
// #115759# - no PrepareHint::AdjustSizeWithoutFormatting and size
// invalidation, if height decreases only by the additional
// lower space as last content of a table cell and an existing
// follow containing one line exists.
const SwTwips nHDiff = nOldH - aRectFnSet.GetHeight(getFrameArea());
const bool bNoPrepAdjustFrame =
nHDiff > 0 && IsInTab() && GetFollow() &&
(1 == static_cast<SwTextFrame*>(GetFollow())->GetLineCount(TextFrameIndex(COMPLETE_STRING))
|| aRectFnSet.GetWidth(static_cast<SwTextFrame*>(GetFollow())->getFrameArea()) < 0) &&
GetFollow()->CalcAddLowerSpaceAsLastInTableCell() == nHDiff;
if ( !bNoPrepAdjustFrame )
{
Prepare( PrepareHint::AdjustSizeWithoutFormatting );
setFrameAreaSizeValid(false);
}
}
}
// To make the widow and orphan rules work, we need to notify the ContentFrame.
// Criteria:
// - It needs to be movable (otherwise, splitting doesn't make sense)
// - It needs to overlap with the lower edge of the PrtArea of the Upper
if ( !bMustFit )
{
bool bWidow = true;
const SwTwips nDeadLine = aRectFnSet.GetPrtBottom(*GetUpper());
if( bMoveable && !bFormatted &&
( GetFollow() || aRectFnSet.OverStep( getFrameArea(), nDeadLine ) ) )
{
Prepare( PrepareHint::WidowsOrphans, nullptr, false );
setFrameAreaSizeValid(false);
bWidow = false;
}
if( aRectFnSet.GetPos(getFrameArea()) != aOldFramePos ||
aRectFnSet.GetPos(getFramePrintArea()) != aOldPrtPos )
{
// In this Prepare, an InvalidateSize_() might happen.
// isFrameAreaSizeValid() becomes false and Format() gets called.
Prepare( PrepareHint::FramePositionChanged, static_cast<const void*>(&bFormatted), false );
if ( bWidow && GetFollow() )
{
Prepare( PrepareHint::WidowsOrphans, nullptr, false );
setFrameAreaSizeValid(false);
}
}
}
if ( !isFrameAreaSizeValid() )
{
setFrameAreaSizeValid(true);
bFormatted = true;
++nFormatCount;
if( nFormatCount > STOP_FLY_FORMAT )
SetFlyLock( true );
// - loop prevention
// No format any longer, if <cnStopFormat> consecutive formats
// without change occur.
if ( nConsecutiveFormatsWithoutChange <= cnStopFormat )
{
Format(getRootFrame()->GetCurrShell()->GetOut());
}
#if OSL_DEBUG_LEVEL > 0
else
{
OSL_FAIL( “debug assertion: SwContentFrame::MakeAll() - format of text frame suppressed by fix b6448963” );
}
#endif
}
// If this is the first one in a chain, check if this can flow
// backwards (if this is movable at all).
// To prevent oscillations/loops, check that this has not just
// flowed forwards.
bool bDummy;
auto const pTemp(GetIndPrev());
auto const bTemp(pTemp && pTemp->isFrameAreaSizeValid()
&& pTemp->isFramePrintAreaValid());
if ( !lcl_Prev( this ) &&
!bMovedFwd &&
( bMoveable || ( bFly && !bTab ) ) &&
( !bFootnote || !GetUpper()->FindFootnoteFrame()->GetPrev() )
&& MoveBwd( bDummy ) )
{
aRectFnSet.Refresh(this);
pMoveBwdPre = pTemp;
isMoveBwdPreValid = bTemp;
bMovedBwd = true;
bFormatted = false;
if ( bKeep && bMoveable )
{
if( CheckMoveFwd( bMakePage, false, bMovedBwd ) )
{
bMovedFwd = true;
bMoveable = IsMoveable();
aRectFnSet.Refresh(this);
}
Point aOldPos = aRectFnSet.GetPos(getFrameArea());
MakePos();
if( aOldPos != aRectFnSet.GetPos(getFrameArea()) )
{
Prepare( PrepareHint::FramePositionChanged, static_cast<const void*>(&bFormatted), false );
if ( !isFrameAreaSizeValid() )
{
{
SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
aRectFnSet.SetWidth( aFrm, aRectFnSet.GetWidth(GetUpper()->getFramePrintArea()) );
}
if ( !isFramePrintAreaValid() )
{
const long nOldW = aRectFnSet.GetWidth(getFramePrintArea());
MakePrtArea( rAttrs );
if( nOldW != aRectFnSet.GetWidth(getFramePrintArea()) )
Prepare( PrepareHint::FixSizeChanged, nullptr, false );
}
if( GetFollow() )
{
Prepare( PrepareHint::WidowsOrphans, nullptr, false );
}
setFrameAreaSizeValid(true);
bFormatted = true;
Format(getRootFrame()->GetCurrShell()->GetOut());
}
}
SwFrame *pNxt = HasFollow() ? nullptr : FindNext();
while( pNxt && pNxt->IsSctFrame() )
{ // Leave empty sections out, go into the other ones.
if( static_cast<SwSectionFrame*>(pNxt)->GetSection() )
{
SwFrame* pTmp = static_cast<SwSectionFrame*>(pNxt)->ContainsAny();
if( pTmp )
{
pNxt = pTmp;
break;
}
}
pNxt = pNxt->FindNext();
}
if ( pNxt )
{
pNxt->Calc(getRootFrame()->GetCurrShell()->GetOut());
if( isFrameAreaPositionValid() && !GetIndNext() )
{
SwSectionFrame *pSct = FindSctFrame();
if( pSct && !pSct->isFrameAreaSizeValid() )
{
SwSectionFrame* pNxtSct = pNxt->FindSctFrame();
if( pNxtSct && pSct->IsAnFollow( pNxtSct ) )
{
setFrameAreaPositionValid(false);
}
}
else
{
setFrameAreaPositionValid(false);
}
}
}
}
}
// In footnotes, the TextFrame may validate itself, which can lead to the
// situation that it's position is wrong despite being "valid".
if ( isFrameAreaPositionValid() )
{
// #i59341#
// Workaround for inadequate layout algorithm:
// suppress invalidation and calculation of position, if paragraph
// has formatted itself at least STOP_FLY_FORMAT times and
// has anchored objects.
// Thus, the anchored objects get the possibility to format itself
// and this probably solve the layout loop.
if ( bFootnote &&
nFormatCount <= STOP_FLY_FORMAT &&
!GetDrawObjs() )
{
setFrameAreaPositionValid(false);
MakePos();
aOldFramePos = aRectFnSet.GetPos(getFrameArea());
aOldPrtPos = aRectFnSet.GetPos(getFramePrintArea());
}
}
// - loop prevention
{
if ( (aOldFrame_StopFormat == getFrameArea() || aOldFrame_StopFormat2 == getFrameArea() ) &&
(aOldPrt_StopFormat == getFramePrintArea() || aOldPrt_StopFormat2 == getFramePrintArea()))
{
++nConsecutiveFormatsWithoutChange;
}
//office developer 修复word绘制过程中造成卡死现象
//else
//{
// nConsecutiveFormatsWithoutChange = 0;
//}
}
// Yet again an invalid value? Repeat from the start...
if ( !isFrameAreaPositionValid() || !isFrameAreaSizeValid() || !isFramePrintAreaValid() )
continue;
// Done?
// Attention: because height == 0, it's better to use Top()+Height() instead of
// Bottom(). This might happen with undersized TextFrames on the lower edge of a
// multi-column section
const long nPrtBottom = aRectFnSet.GetPrtBottom(*GetUpper());
long nBottomDist = aRectFnSet.BottomDist(getFrameArea(), nPrtBottom);
// Hide whitespace may require not to insert a new page.
SwPageFrame* pPageFrame = FindPageFrame();
const bool bHeightValid = pPageFrame->CheckPageHeightValidForHideWhitespace(nBottomDist);
if (!bHeightValid)
{
pPageFrame->InvalidateSize();
nBottomDist = 0;
}
// office developer OFFICEWIN-3052 begin
if (IsTextFrame())
{
const SwTextFrame* pText = static_cast<const SwTextFrame*>(this);
if (nBottomDist < 0 && pText->IsHeldInOwnPage())
nBottomDist = 0;
}
// office developer OFFICEWIN-3052 end
if( nBottomDist >= 0 )
{
if ( bKeep && bMoveable )
{
// We make sure the successor will be formatted the same.
// This way, we keep control until (almost) everything is stable,
// allowing us to avoid endless loops caused by ever repeating
// retries.
// bMoveFwdInvalid is required for #38407#. This was originally solved
// in flowfrm.cxx rev 1.38, but broke the above schema and
// preferred to play towers of hanoi (#43669#).
SwFrame *pNxt = HasFollow() ? nullptr : FindNext();
// For sections we prefer the content, because it can change
// the page if required.
while( pNxt && pNxt->IsSctFrame() )
{
if( static_cast<SwSectionFrame*>(pNxt)->GetSection() )
{
pNxt = static_cast<SwSectionFrame*>(pNxt)->ContainsAny();
break;
}
pNxt = pNxt->FindNext();
}
if ( pNxt )
{
const bool bMoveFwdInvalid = nullptr != GetIndNext();
const bool bNxtNew =
( 0 == aRectFnSet.GetHeight(pNxt->getFramePrintArea()) ) &&
(!pNxt->IsTextFrame() ||!static_cast<SwTextFrame*>(pNxt)->IsHiddenNow());
pNxt->Calc(getRootFrame()->GetCurrShell()->GetOut());
if ( !bMovedBwd &&
((bMoveFwdInvalid && !GetIndNext()) ||
bNxtNew) )
{
if( bMovedFwd )
pNotify->SetInvaKeep();
bMovedFwd = false;
}
}
}
continue;
}
// I don't fit into my parents, so it's time to make changes
// as constructively as possible.
//If I'm NOT allowed to leave the parent Frame, I've got a problem.
// Following Arthur Dent, we do the only thing that you can do with
// an unsolvable problem: We ignore it with all our power.
if ( !bMoveable || IsUndersized() )
{
if( !bMoveable && IsInTab() )
{
long nDiff = -aRectFnSet.BottomDist( getFrameArea(), aRectFnSet.GetPrtBottom(*GetUpper()) );
long nReal = GetUpper()->Grow( nDiff );
if( nReal )
continue;
}
break;
}
// If there's no way I can make myself fit into my Upper, the situation
// could still probably be mitigated by splitting up.
// This situation arises with freshly created Follows that had been moved
// to the next page but is still too big for it - ie. needs to be split
// as well.
// If I'm unable to split (WouldFit()) and can't be fitted, I'm going
// to tell my TextFrame part that, if possible, we still need to split despite
// the "don't split" attribute.
bool bMoveOrFit = false;
bool bDontMoveMe = !GetIndPrev();
if( bDontMoveMe && IsInSct() )
{
SwFootnoteBossFrame* pBoss = FindFootnoteBossFrame();
bDontMoveMe = !pBoss->IsInSct() ||
( !pBoss->Lower()->GetNext() && !pBoss->GetPrev() );
}
// Finally, we are able to split table rows. Therefore, bDontMoveMe
// can be set to false:
if( bDontMoveMe && IsInTab() &&
nullptr != GetNextCellLeaf() )
bDontMoveMe = false;
assert(bMoveable);
if ( bDontMoveMe && aRectFnSet.GetHeight(getFrameArea()) >
aRectFnSet.GetHeight(GetUpper()->getFramePrintArea()) )
{
if ( !bFitPromise )
{
SwTwips nTmp = aRectFnSet.GetHeight(GetUpper()->getFramePrintArea()) -
aRectFnSet.GetTop(getFramePrintArea());
bool bSplit = !IsFwdMoveAllowed();
if ( nTmp > 0 && WouldFit( nTmp, bSplit, false ) )
{
Prepare( PrepareHint::WidowsOrphans, nullptr, false );
setFrameAreaSizeValid(false);
bFitPromise = true;
continue;
}
/*
* In earlier days, we never tried to fit TextFrames in
* frames and sections using bMoveOrFit by ignoring
* its attributes (Widows, Keep).
* This should have been done at least for column frames;
* as it must be tried anyway with linked frames and sections.
* Exception: If we sit in FormatWidthCols, we must not ignore
* the attributes.
*/
else if ( !bFootnote &&
( !bFly || !FindFlyFrame()->IsColLocked() ) &&
( !bSct || !FindSctFrame()->IsColLocked() ) )
bMoveOrFit = true;
}
#if OSL_DEBUG_LEVEL > 0
else
{
OSL_FAIL( “+TextFrame didn’t respect WouldFit promise.” );
}
#endif
}
// Let's see if I can find some space somewhere...
// footnotes in the neighbourhood are moved into _MoveFootnoteCntFwd
SwFrame *pPre = GetIndPrev();
SwFrame *pOldUp = GetUpper();
/* MA 13. Oct. 98: What is this supposed to be!?
- AMA 14. Dec 98: If a column section can’t find any space for its first ContentFrame, it should be
-
moved not only to the next column, but probably even to the next page, creating
-
a section-follow there.
/
if( IsInSct() && bMovedFwd && bMakePage && pOldUp->IsColBodyFrame() &&
pOldUp->GetUpper()->GetUpper()->IsSctFrame() &&
( pPre || pOldUp->GetUpper()->GetPrev() ) &&
static_cast<SwSectionFrame>(pOldUp->GetUpper()->GetUpper())->MoveAllowed(this) )
{
bMovedFwd = false;
}
const bool bCheckForGrownBody = pOldUp->IsBodyFrame();
const long nOldBodyHeight = aRectFnSet.GetHeight(pOldUp->getFrameArea());
if ( !bMovedFwd && !MoveFwd( bMakePage, false ) )
bMakePage = false;
aRectFnSet.Refresh(this);
if (!bMovedFwd && bFootnote && GetIndPrev() != pPre)
{ // SwFlowFrame::CutTree() could have formatted and deleted pPre
auto const pPrevFootnoteFrame(static_cast<SwFootnoteFrame const*>(
FindFootnoteFrame())->GetMaster());
bool bReset = true;
if (pPrevFootnoteFrame)
{ // use GetIndNext() in case there are sections
for (auto p = pPrevFootnoteFrame->Lower(); p; p = p->GetIndNext())
{
if (p == pPre)
{
bReset = false;
break;
}
}
}
if (bReset)
{
pPre = nullptr;
}
}
// If MoveFwd moves the paragraph to the next page, a following
// paragraph, which contains footnotes can cause the old upper
// frame to grow. In this case we explicitly allow a new check
// for MoveBwd. Robust: We also check the bMovedBwd flag again.
// If pOldUp was a footnote frame, it has been deleted inside MoveFwd.
// Therefore we only check for growing body frames.
bMovedFwd = !bCheckForGrownBody || bMovedBwd || pOldUp == GetUpper() ||
aRectFnSet.GetHeight(pOldUp->getFrameArea()) <= nOldBodyHeight;
bFormatted = false;
if ( bMoveOrFit && GetUpper() == pOldUp )
{
// FME 2007-08-30 #i81146# new loop control
if ( nConsecutiveFormatsWithoutChange <= cnStopFormat )
{
Prepare( PrepareHint::MustFit, nullptr, false );
setFrameAreaSizeValid(false);
bMustFit = true;
continue;
}
#if OSL_DEBUG_LEVEL > 0
OSL_FAIL( “LoopControl in SwContentFrame::MakeAll” );
#endif
}
if ( bMovedBwd && GetUpper() )
{ // Retire invalidations that have become useless.
GetUpper()->ResetCompletePaint();
if( pPre && !pPre->IsSctFrame() )
::ValidateSz( pPre );
}
} //while ( !isFrameAreaPositionValid() || !isFrameAreaSizeValid() || !isFramePrintAreaValid() )
// NEW: Looping Louie (Light). Should not be applied in balanced sections.
// Should only be applied if there is no better solution!
LOOPING_LOUIE_LIGHT( bMovedFwd && bMovedBwd && !IsInBalancedSection() &&
(
( bFootnote && !FindFootnoteFrame()->GetRef()->IsInSct() ) ||
// #i33887#
( IsInSct() && bKeep )
// ... add your conditions here ...
),
static_cast<SwTextFrame&>(*this) );
pSaveFootnote.reset();
UnlockJoin();
xDeleteGuard.reset();
if ( bMovedFwd || bMovedBwd )
pNotify->SetInvaKeep();
if ( bMovedFwd )
{
pNotify->SetInvalidatePrevPrtArea();
}
pNotify.reset();
SetFlyLock( false );
}
SWFrame
Writer 布局元素的基类。
这不仅包括飞行框架,还包括段落的所有内容
级别:页面、页眉、页脚等(在段落 SwLinePortion 内
使用实例。)
SWLayoutFrame
布局框架是包含其他框架 (m_pLower) 的框架,例如 SwPageFrame 或 SwTabFrame。
// 不幸的是,向后浮动一个 frm 使用了一些时间。
// 最常见的情况如下: Frame 想要浮动到
// FixSize 与 Frame 本身已经相同的地方。
// 在这种情况下,很容易检查 Frame 是否有足够的空间
// 对于它的 VarSize。如果不是这种情况,我们已经知道
// 我们不需要移动。
// Frame 检查自己是否有足够的空间 - 尊重事实
// 如果需要,它可能会自行分裂。
// 但是,如果 FixSize 不同于 Frame 或涉及 Flys
//(无论是在旧位置还是新位置),检查是没有意义的,
// 我们必须移动 Frame 来看看会发生什么 - 如果有
// 一些可用的空间来做到这一点,也就是说。
// Contents 容器的 FixSize 始终是宽度。
// 如果我们向后移动了不止一张纸(例如跳过空的
// 页面),我们必须向任一方向移动。否则,如果框架不适合
// 进入页面,将不再尊重空页面。
//prepareMake
为“格式化”准备 Frame (MakeAll())。
*
- 此方法用于节省堆栈空间:计算 Frame 的位置
- 我们必须确保 Upper 和 Prev 的位置分别是
- 有效的。 这可能需要递归调用(循环会非常昂贵,
- 因为它不是经常需要的)。
- 每次调用 MakeAll 需要大约 500 个字节的堆栈 - 您很容易
- 看看这会导致什么。 这种方法只需要一点点堆栈
- 空间,所以递归调用在这里应该不成问题。
- 另一个好处是在美好的一天,这种方法和它
- 可以避免前辈的格式化。 那么它可能是
- 可以“快速”跳转到文档末尾。
/ AdjustFollow 预计会出现以下情况:
// SwTextIter指向Master的下端,在Follow中设置Offset。
// nOffset 保存文本字符串中的 Offset,Master 从中关闭
// 然后跟随开始。
// 如果为0,则删除FollowFrame。