2021-08-03

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。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值