Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/LibreOffice/sw/source/core/layout/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 94 kB image not shown  

Quelle  calcmove.cxx   Sprache: C

 
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */


#include <memory>
#include <rootfrm.hxx>
#include <pagefrm.hxx>
#include <viewopt.hxx>
#include <frmatr.hxx>
#include <frmtool.hxx>
#include <txtftn.hxx>
#include <fmtftn.hxx>
#include <ndtxt.hxx>
#include <editeng/ulspitem.hxx>
#include <editeng/keepitem.hxx>
#include <osl/diagnose.h>
#include <svx/sdtaitm.hxx>

#include <fmtfsize.hxx>
#include <fmtanchr.hxx>
#include <fmtclbl.hxx>

#include <tabfrm.hxx>
#include <ftnfrm.hxx>
#include <txtfrm.hxx>
#include <sectfrm.hxx>
#include <dbg_lay.hxx>

#include <sortedobjs.hxx>
#include <layouter.hxx>
#include <flyfrms.hxx>

#include <DocumentSettingManager.hxx>
#include <IDocumentLayoutAccess.hxx>

// Move methods

/// Return value tells whether the Frame should be moved.
bool SwContentFrame::ShouldBwdMoved( SwLayoutFrame *pNewUpper, bool & )
{
    if ( SwFlowFrame::IsMoveBwdJump() || !IsPrevObjMove() )
    {
        // Floating back a frm uses a bit of time unfortunately.
        // The most common case is the following: The Frame wants to float to
        // somewhere where the FixSize is the same that the Frame itself has already.
        // In that case it's pretty easy to check if the Frame has enough space
        // for its VarSize. If this is NOT the case, we already know that
        // we don't need to move.
        // The Frame checks itself whether it has enough space - respecting the fact
        // that it could possibly split itself if needed.
        // If, however, the FixSize differs from the Frame or Flys are involved
        // (either in the old or the new position), checking is pointless,
        // and we have to move the Frame just to see what happens - if there's
        // some space available to do it, that is.

        // The FixSize of the containers of Contents is always the width.

        // If we moved more than one sheet back (for example jumping over empty
        // pages), we have to move either way. Otherwise, if the Frame doesn't fit
        // into the page, empty pages wouldn't be respected anymore.
        sal_uInt8 nMoveAnyway = 0;
        SwPageFrame * const pNewPage = pNewUpper->FindPageFrame();
        SwPageFrame *pOldPage = FindPageFrame();

        if ( SwFlowFrame::IsMoveBwdJump() )
            return true;

        if( IsInFootnote() && IsInSct() )
        {
            SwFootnoteFrame* pFootnote = FindFootnoteFrame();
            SwSectionFrame* pMySect = pFootnote->FindSctFrame();
            if( pMySect && pMySect->IsFootnoteLock() )
            {
                SwSectionFrame *pSect = pNewUpper->FindSctFrame();
                while( pSect && pSect->IsInFootnote() )
                    pSect = pSect->GetUpper()->FindSctFrame();
                OSL_ENSURE( pSect, "Escaping footnote" );
                if( pSect != pMySect )
                    return false;
            }
        }
        SwRectFnSet aRectFnSet(this);
        SwRectFnSet fnRectX(pNewUpper);
        if( std::abs( fnRectX.GetWidth(pNewUpper->getFramePrintArea()) -
                 aRectFnSet.GetWidth(GetUpper()->getFramePrintArea()) ) > 1 ) {
            // In this case, only a WouldFit_ with test move is possible
            nMoveAnyway = 2;
        }

        // Do *not* move backward, if <nMoveAnyway> equals 3 and no space is left in new upper.
        nMoveAnyway |= BwdMoveNecessary( pOldPage, getFrameArea() );
        {
            const IDocumentSettingAccess& rIDSA = pNewPage->GetFormat()->getIDocumentSettingAccess();
            SwTwips nSpace = 0;
            SwRect aRect( pNewUpper->getFramePrintArea() );
            aRect.Pos() += pNewUpper->getFrameArea().Pos();
            const SwFrame *pPrevFrame = pNewUpper->Lower();
            while ( pPrevFrame )
            {
                SwTwips nNewTop = fnRectX.GetBottom(pPrevFrame->getFrameArea());
                // Consider lower spacing of last frame in a table cell
                {
                    // Check if last frame is inside table and if it includes its lower spacing.
                    if ( !pPrevFrame->GetNext() && pPrevFrame->IsInTab() &&
                         rIDSA.get(DocumentSettingId::ADD_PARA_SPACING_TO_TABLE_CELLS) )
                    {
                        const SwFrame* pLastFrame = pPrevFrame;
                        // if last frame is a section, take its last content
                        if ( pPrevFrame->IsSctFrame() )
                        {
                            pLastFrame = static_cast<const SwSectionFrame*>(pPrevFrame)->FindLastContent();
                            if ( pLastFrame &&
                                 pLastFrame->FindTabFrame() != pPrevFrame->FindTabFrame() )
                            {
                                pLastFrame = pLastFrame->FindTabFrame();
                            }
                        }

                        if ( pLastFrame )
                        {
                            SwBorderAttrAccess aAccess( SwFrame::GetCache(), pLastFrame );
                            const SwBorderAttrs& rAttrs = *aAccess.Get();
                            nNewTop -= rAttrs.GetULSpace().GetLower();
                            if (rIDSA.get(DocumentSettingId::ADD_PARA_LINE_SPACING_TO_TABLE_CELLS))
                            {
                                nNewTop -= rAttrs.CalcLineSpacing();
                            }
                        }
                    }
                }
                fnRectX.SetTop( aRect, nNewTop );

                pPrevFrame = pPrevFrame->GetNext();
            }

            nMoveAnyway |= BwdMoveNecessary( pNewPage, aRect);

            //determine space left in new upper frame
            nSpace = fnRectX.GetHeight(aRect);
            const SwViewShell *pSh = pNewUpper->getRootFrame()->GetCurrShell();
            if ( IsInFootnote() ||
                 (pSh && pSh->GetViewOptions()->getBrowseMode()) ||
                 pNewUpper->IsCellFrame() ||
                 ( pNewUpper->IsInSct() && ( pNewUpper->IsSctFrame() ||
                   ( pNewUpper->IsColBodyFrame() &&
                     !pNewUpper->GetUpper()->GetPrev() &&
                     !pNewUpper->GetUpper()->GetNext() ) ) ) )
                nSpace += pNewUpper->Grow( LONG_MAX, true );

            auto pTextFrame = DynCastTextFrame();
            if (pTextFrame)
            {
                // This is a text frame. Check if it's an anchor for a non-last element in a split
                // fly chain. If so, we can only move back in case not only the text frame itself,
                // but also its fly fits nSpace.
                SwFlyAtContentFrame* pFly = pTextFrame->HasNonLastSplitFlyDrawObj();
                if (pFly && pFly->getFrameArea().Height() > nSpace)
                {
                    return false;
                }
            }

            if ( nMoveAnyway < 3 )
            {
                if (nSpace || IsHiddenNow())
                {
                    // Do not notify footnotes which are stuck to the paragraph:
                    // This would require extremely confusing code, taking into
                    // account the widths
                    // and Flys, that in turn influence the footnotes, ...

                    // WouldFit_ can only be used if the width is the same and
                    // ONLY self-anchored Flys are present.

                    // WouldFit_ can also be used if ONLY Flys anchored
                    // somewhere else are present.
                    // In this case, the width doesn't even matter,
                    // because we're running a TestFormat in the new upper.
                    const sal_uInt8 nBwdMoveNecessaryResult =
                                            BwdMoveNecessary( pNewPage, aRect);
                    const bool bObjsInNewUpper( nBwdMoveNecessaryResult == 2 ||
                                                nBwdMoveNecessaryResult == 3 );

                    return WouldFit_( nSpace, pNewUpper, nMoveAnyway == 2,
                                      bObjsInNewUpper );
                }
                // It's impossible for WouldFit_ to return a usable result if
                // we have a fresh multi-column section - so we really have to
                // float back unless there is no space.
                return pNewUpper->IsInSct() && pNewUpper->IsColBodyFrame() &&
                       !fnRectX.GetWidth(pNewUpper->getFramePrintArea()) &&
                       ( pNewUpper->GetUpper()->GetPrev() ||
                         pNewUpper->GetUpper()->GetNext() );
            }

            // Check for space left in new upper
            return nSpace != 0 || IsHiddenNow();
        }
    }
    return false;
}

// Calc methods

// Two little friendships form a secret society
inline void PrepareLock( SwFlowFrame *pTab )
{
    pTab->LockJoin();
}
inline void PrepareUnlock( SwFlowFrame *pTab )
{
    pTab->UnlockJoin();

}

// hopefully, one day this function simply will return 'false'
static bool lcl_IsCalcUpperAllowed( const SwFrame& rFrame )
{
    return !rFrame.GetUpper()->IsSctFrame() &&
           !rFrame.GetUpper()->IsFooterFrame() &&
           // No format of upper Writer fly frame
           !rFrame.GetUpper()->IsFlyFrame() &&
           !( rFrame.GetUpper()->IsTabFrame() && rFrame.GetUpper()->GetUpper()->IsInTab() ) &&
           !( rFrame.IsTabFrame() && rFrame.GetUpper()->IsInTab() );
}

/** Prepares the Frame for "formatting" (MakeAll()).
 *
 * This method serves to save stack space: To calculate the position of the Frame
 * we have to make sure that the positions of Upper and Prev respectively are
 * valid. This may require a recursive call (a loop would be quite expensive,
 * as it's not required very often).
 *
 * Every call of MakeAll requires around 500 bytes on the stack - you easily
 * see where this leads to. This method requires only a little bit of stack
 * space, so the recursive call should not be a problem here.
 *
 * Another advantage is that one nice day, this method and with it the
 * formatting of predecessors could be avoided. Then it could probably be
 * possible to jump "quickly" to the document's end.
 *
 * @see MakeAll()
 */

void SwFrame::PrepareMake(vcl::RenderContext* pRenderContext)
{
    StackHack aHack;
    if ( GetUpper() )
    {
        SwFrameDeleteGuard aDeleteGuard(this);
        if ( lcl_IsCalcUpperAllowed( *this ) )
            GetUpper()->Calc(pRenderContext);
        OSL_ENSURE( GetUpper(), ":-( Layout unstable (Upper gone)." );
        if ( !GetUpper() )
            return;

        const bool bCnt = IsContentFrame();
        const bool bTab = IsTabFrame();
        bool bNoSect = IsInSct();
        bool bOldTabLock = false, bFoll = false;
        SwFlowFrame* pThis = bCnt ? static_cast<SwContentFrame*>(this) : nullptr;

        if ( bTab )
        {
            pThis = static_cast<SwTabFrame*>(this);
            bOldTabLock = static_cast<SwTabFrame*>(this)->IsJoinLocked();
            ::PrepareLock( static_cast<SwTabFrame*>(this) );
            bFoll = pThis->IsFollow();
        }
        else if( IsSctFrame() )
        {
            pThis = static_cast<SwSectionFrame*>(this);
            bFoll = pThis->IsFollow();
            bNoSect = false;
        }
        else if ( bCnt )
        {
            bFoll = pThis->IsFollow();
            if ( bFoll && GetPrev() )
            {
                // Do not follow the chain when we need only one instance
                const SwTextFrame* pMaster = static_cast<SwContentFrame*>(this)->FindMaster();
                if ( pMaster && pMaster->IsLocked() )
                {
                    MakeAll(pRenderContext);
                    return;
                }
            }
        }

        // There is no format of previous frame, if current frame is a table
        // frame and its previous frame wants to keep with it.
        bool bFormatPrev{!bTab};
        if (!bFormatPrev)
        {
            SwFrame const* pPrev{this};
            do
            {
                pPrev = pPrev->GetPrev();
            }
            while (pPrev && pPrev->IsHiddenNow());
            bFormatPrev = pPrev && !pPrev->GetAttrSet()->GetKeep().GetValue();
        }
        if ( bFormatPrev )
        {
            SwFrame *pFrame = GetUpper()->Lower();
            while ( pFrame != this )
            {
                OSL_ENSURE( pFrame, ":-( Layout unstable (this not found)." );
                if ( !pFrame )
                    return//Oioioioi ...

                if ( !pFrame->isFrameAreaDefinitionValid() )
                {
                    // A small interference that hopefully improves on the stability:
                    // If I'm Follow AND neighbor of a Frame before me, it would delete
                    // me when formatting. This as you can see could easily become a
                    // confusing situation that we want to avoid.
                    if ( bFoll && pFrame->IsFlowFrame() &&
                         SwFlowFrame::CastFlowFrame(pFrame)->IsAnFollow( pThis ) )
                        break;

                    bool const isLast(pFrame->GetNext() == this);
                    // note: this seems obvious but does *not* hold, a MakeAll()
                    // could move more than 1 frame backwards!
                    // that's why FindNext() is used below
                    // assert(pFrame->GetUpper() == GetUpper());
                    pFrame->MakeAll(pRenderContext);
                    if( IsSctFrame() && !static_cast<SwSectionFrame*>(this)->GetSection() )
                        break;
                    if (isLast && pFrame->GetUpper() != GetUpper())
                    {
                        assert(GetUpper()->Lower() == this
                            // empty section frames are created all the time...
                            || GetUpper()->Lower()->IsSctFrame()
                            // tab frame/section frame may split multiple times
                            || (   SwFlowFrame::CastFlowFrame(pFrame)
                                && SwFlowFrame::CastFlowFrame(GetUpper()->Lower())
                                && SwFlowFrame::CastFlowFrame(pFrame)->IsAnFollow(
                                    SwFlowFrame::CastFlowFrame(GetUpper()->Lower()))
                                && (GetUpper()->Lower()->GetNext() == this
                                    // if it's more than 10 pages long...
                                    || (SwFlowFrame::CastFlowFrame(GetUpper()->Lower())->GetFollow()
                                            == SwFlowFrame::CastFlowFrame(GetUpper()->Lower()->GetNext())
                                        && GetUpper()->Lower()->GetNext()->GetNext() == this)
                                    // pre-existing empty section frames may end up between them...
                                    || GetUpper()->Lower()->GetNext()->IsSctFrame())));
                        break// tdf#119109 frame was moved backward, prevent
                               // FindNext() returning a frame inside this if
                    }          // this is a table!
                }
                // With ContentFrames, the chain may be broken while walking through
                // it. Therefore we have to figure out the next frame in a bit more
                // complicated way. However, I'll HAVE to get back to myself
                // sometime again.
                pFrame = pFrame->FindNext();

                // If we started out in a SectionFrame, it might have happened that
                // we landed in a Section Follow via the MakeAll calls.
                // FindNext only gives us the SectionFrame, not it's content - we
                // won't find ourselves anymore!
                if( bNoSect && pFrame && pFrame->IsSctFrame() )
                {
                    SwFrame* pCnt = static_cast<SwSectionFrame*>(pFrame)->ContainsAny();
                    if( pCnt )
                        pFrame = pCnt;
                }
            }
            OSL_ENSURE( GetUpper(), "Layout unstable (Upper gone II)." );
            if ( !GetUpper() )
                return;

            if ( lcl_IsCalcUpperAllowed( *this ) )
                GetUpper()->Calc(pRenderContext);

            OSL_ENSURE( GetUpper(), "Layout unstable (Upper gone III)." );
        }

        if ( bTab && !bOldTabLock )
            ::PrepareUnlock( static_cast<SwTabFrame*>(this) );
    }
    MakeAll(pRenderContext);
}

void SwFrame::OptPrepareMake()
{
    // #i23129#, #i36347# - no format of upper Writer fly frame
    if ( GetUpper() && !GetUpper()->IsFooterFrame() &&
         !GetUpper()->IsFlyFrame() )
    {
        {
            SwFrameDeleteGuard aDeleteGuard(this);
            GetUpper()->Calc(getRootFrame()->GetCurrShell() ? getRootFrame()->GetCurrShell()->GetOut() : nullptr);
        }
        OSL_ENSURE( GetUpper(), ":-( Layout unstable (Upper gone)." );
        if ( !GetUpper() )
            return;
    }
    if ( GetPrev() && !GetPrev()->isFrameAreaDefinitionValid() )
    {
        PrepareMake(getRootFrame()->GetCurrShell() ? getRootFrame()->GetCurrShell()->GetOut() : nullptr);
    }
    else
    {
        StackHack aHack;
        MakeAll(IsRootFrame() ? nullptr : getRootFrame()->GetCurrShell()->GetOut());
    }
}

void SwFrame::PrepareCursor()
{
    StackHack aHack;
    if( GetUpper() && !GetUpper()->IsSctFrame() )
    {
        const bool bCnt = IsContentFrame();
        const bool bTab = IsTabFrame();
        bool bNoSect = IsInSct();

        std::optional<FlowFrameJoinLockGuard> tabGuard;
        std::optional<SwFrameDeleteGuard> rowGuard;
        SwFlowFrame* pThis = bCnt ? static_cast<SwContentFrame*>(this) : nullptr;

        if ( bTab )
        {
            tabGuard.emplace(static_cast<SwTabFrame*>(this)); // tdf#125741
            pThis = static_cast<SwTabFrame*>(this);
        }
        else if (IsRowFrame())
        {
            rowGuard.emplace(this); // tdf#125741 keep this alive
        }
        else if( IsSctFrame() )
        {
            pThis = static_cast<SwSectionFrame*>(this);
            bNoSect = false;
        }

        GetUpper()->PrepareCursor();
        GetUpper()->Calc(getRootFrame()->GetCurrShell() ? getRootFrame()->GetCurrShell()->GetOut() : nullptr);

        OSL_ENSURE( GetUpper(), ":-( Layout unstable (Upper gone)." );
        if ( !GetUpper() )
            return;

        bool const bFoll = pThis && pThis->IsFollow();

        SwFrame *pFrame = GetUpper()->Lower();
        while ( pFrame != this )
        {
            OSL_ENSURE( pFrame, ":-( Layout unstable (this not found)." );
            if ( !pFrame )
                return//Oioioioi ...

            if ( !pFrame->isFrameAreaDefinitionValid() )
            {
                // A small interference that hopefully improves on the stability:
                // If I'm Follow AND neighbor of a Frame before me, it would delete
                // me when formatting. This as you can see could easily become a
                // confusing situation that we want to avoid.
                if ( bFoll && pFrame->IsFlowFrame() &&
                     SwFlowFrame::CastFlowFrame(pFrame)->IsAnFollow( pThis ) )
                    break;

                bool const isLast(pFrame->GetNext() == this);
                pFrame->MakeAll(getRootFrame()->GetCurrShell()->GetOut());
                if (isLast && pFrame->GetUpper() != GetUpper())
                {
                    assert(GetUpper()->Lower() == this
                        // empty section frames are created all the time...
                        || GetUpper()->Lower()->IsSctFrame()
                        // tab frame/section frame may split multiple times
                        || (   SwFlowFrame::CastFlowFrame(pFrame)
                            && SwFlowFrame::CastFlowFrame(GetUpper()->Lower())
                            && SwFlowFrame::CastFlowFrame(pFrame)->IsAnFollow(
                                SwFlowFrame::CastFlowFrame(GetUpper()->Lower()))
                            && (GetUpper()->Lower()->GetNext() == this
                                // if it's more than 10 pages long...
                                || (SwFlowFrame::CastFlowFrame(GetUpper()->Lower())->GetFollow()
                                        == SwFlowFrame::CastFlowFrame(GetUpper()->Lower()->GetNext())
                                    && GetUpper()->Lower()->GetNext()->GetNext() == this)
                                // pre-existing empty section frames may end up between them...
                                || GetUpper()->Lower()->GetNext()->IsSctFrame())));
                    break// tdf#119109 frame was moved backward, prevent
                           // FindNext() returning a frame inside this if
                }          // this is a table!
            }
            // With ContentFrames, the chain may be broken while walking through
            // it. Therefore we have to figure out the next frame in a bit more
            // complicated way. However, I'll HAVE to get back to myself
            // sometime again.
            pFrame = pFrame->FindNext();
            if( bNoSect && pFrame && pFrame->IsSctFrame() )
            {
                SwFrame* pCnt = static_cast<SwSectionFrame*>(pFrame)->ContainsAny();
                if( pCnt )
                    pFrame = pCnt;
            }
        }
        OSL_ENSURE( GetUpper(), "Layout unstable (Upper gone II)." );
        if ( !GetUpper() )
            return;

        GetUpper()->Calc(getRootFrame()->GetCurrShell()->GetOut());

        OSL_ENSURE( GetUpper(), "Layout unstable (Upper gone III)." );
    }
    Calc(getRootFrame()->GetCurrShell() ? getRootFrame()->GetCurrShell()->GetOut() : nullptr);
}

// Here we return GetPrev(); however we will ignore empty SectionFrames
static SwFrame* lcl_Prev( SwFrame* pFrame, bool bSectPrv = true )
{
    SwFrame* pRet = pFrame->GetPrev();
    if( !pRet && pFrame->GetUpper() && pFrame->GetUpper()->IsSctFrame() &&
        bSectPrv && !pFrame->IsColumnFrame() )
        pRet = pFrame->GetUpper()->GetPrev();
    while( pRet && pRet->IsSctFrame() &&
           !static_cast<SwSectionFrame*>(pRet)->GetSection() )
        pRet = pRet->GetPrev();
    return pRet;
}

static SwFrame* lcl_NotHiddenPrev( SwFrame* pFrame )
{
    SwFrame *pRet = pFrame;
    do
    {
        pRet = lcl_Prev( pRet );
    } while ( pRet && pRet->IsHiddenNow() );
    return pRet;
}

void SwFrame::MakePos()
{
    if ( isFrameAreaPositionValid() )
        return;

    setFrameAreaPositionValid(true);
    bool bUseUpper = false;
    SwFrame* pPrv = lcl_Prev( this );
    if ( pPrv &&
         ( !pPrv->IsContentFrame() ||
           ( static_cast<SwContentFrame*>(pPrv)->GetFollow() != this ) )
       )
    {
        if ( !StackHack::IsLocked() &&
             ( !IsInSct() || IsSctFrame() ) &&
             !pPrv->IsSctFrame() &&
             !pPrv->GetAttrSet()->GetKeep().GetValue()
           )
        {
            // tdf#151866 pPrv may MoveBwd and if this is a newly created
            // section frame then CheckPageDescs() may delete the whole page!
            SwFrameDeleteGuard g(this); // Prevent it.
            pPrv->Calc(getRootFrame()->GetCurrShell() ? getRootFrame()->GetCurrShell()->GetOut() : nullptr);   // This may cause Prev to vanish!
        }
        else if ( pPrv->getFrameArea().Top() == 0 )
        {
            bUseUpper = true;
        }
    }

    pPrv = lcl_Prev( thisfalse );
    const SwFrameType nMyType = GetType();
    SwRectFnSet aRectFnSet((IsCellFrame() && GetUpper() ? GetUpper() : this));
    if ( !bUseUpper && pPrv )
    {
        SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
        aFrm.Pos( pPrv->getFrameArea().Pos() );

        if( FRM_NEIGHBOUR & nMyType )
        {
            const bool bR2L = IsRightToLeft();

            if( bR2L )
            {
                aRectFnSet.SetPosX( aFrm, aRectFnSet.GetLeft(aFrm) - aRectFnSet.GetWidth(aFrm) );
            }
            else
            {
                aRectFnSet.SetPosX( aFrm, aRectFnSet.GetLeft(aFrm) + aRectFnSet.GetWidth(pPrv->getFrameArea()) );
            }

            // cells may now leave their uppers
            if( aRectFnSet.IsVert() && SwFrameType::Cell & nMyType )
            {
                aFrm.Pos().setX(aFrm.Pos().getX() - aFrm.Width() + pPrv->getFrameArea().Width());
            }
        }
        else if( aRectFnSet.IsVert() && FRM_NOTE_VERT & nMyType )
        {
            if ( aRectFnSet.IsVertL2R() )
            {
                aFrm.Pos().setX(aFrm.Pos().getX() + pPrv->getFrameArea().Width());
            }
            else
            {
                aFrm.Pos().setX(aFrm.Pos().getX() - aFrm.Width());
            }
        }
        else
        {
            aFrm.Pos().setY(aFrm.Pos().getY() + pPrv->getFrameArea().Height());
        }
    }
    else if ( GetUpper() )
    {
        // If parent frame is a footer frame and its <ColLocked()>, then
        // do *not* calculate it.
        // NOTE: Footer frame is <ColLocked()> during its
        //     <FormatSize(..)>, which is called from <Format(..)>, which
        //     is called from <MakeAll()>, which is called from <Calc()>.
        // #i56850#
        // - no format of upper Writer fly frame, which is anchored
        //   at-paragraph or at-character.
        if ( !GetUpper()->IsTabFrame() &&
             !( IsTabFrame() && GetUpper()->IsInTab() ) &&
             !GetUpper()->IsSctFrame() &&
             !dynamic_cast<SwFlyAtContentFrame*>(GetUpper()) &&
             !( GetUpper()->IsFooterFrame() &&
                GetUpper()->IsColLocked() )
           )
        {
            GetUpper()->Calc(getRootFrame()->GetCurrShell()->GetOut());
        }
        pPrv = lcl_Prev( thisfalse );
        if ( !bUseUpper && pPrv )
        {
            SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
            aFrm.Pos( pPrv->getFrameArea().Pos() );

            if( FRM_NEIGHBOUR & nMyType )
            {
                const bool bR2L = IsRightToLeft();

                if( bR2L )
                {
                    aRectFnSet.SetPosX( aFrm, aRectFnSet.GetLeft(aFrm) - aRectFnSet.GetWidth(aFrm) );
                }
                else
                {
                    aRectFnSet.SetPosX( aFrm, aRectFnSet.GetLeft(aFrm) + aRectFnSet.GetWidth(pPrv->getFrameArea()) );
                }

                // cells may now leave their uppers
                if( aRectFnSet.IsVert() && SwFrameType::Cell & nMyType )
                {
                    aFrm.Pos().setX(aFrm.Pos().getX() - aFrm.Width() + pPrv->getFrameArea().Width());
                }
            }
            else if( aRectFnSet.IsVert() && FRM_NOTE_VERT & nMyType )
            {
                aFrm.Pos().setX(aFrm.Pos().getX() - aFrm.Width());
            }
            else
            {
                aFrm.Pos().setY(aFrm.Pos().getY() + pPrv->getFrameArea().Height());
            }
        }
        else
        {
            SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
            aFrm.Pos( GetUpper()->getFrameArea().Pos() );

            if( GetUpper()->IsFlyFrame() )
            {
                aFrm.Pos() += static_cast<SwFlyFrame*>(GetUpper())->ContentPos();
            }
            else
            {
                aFrm.Pos() += GetUpper()->getFramePrintArea().Pos();
            }

            if( FRM_NEIGHBOUR & nMyType && IsRightToLeft() )
            {
                if( aRectFnSet.IsVert() )
                {
                    aFrm.Pos().setY(aFrm.Pos().getY() + GetUpper()->getFramePrintArea().Height() - aFrm.Height());
                }
                else
                {
                    aFrm.Pos().setX(aFrm.Pos().getX() + GetUpper()->getFramePrintArea().Width() - aFrm.Width());
                }
            }
            else if( aRectFnSet.IsVert() && !aRectFnSet.IsVertL2R() && FRM_NOTE_VERT & nMyType )
            {
                aFrm.Pos().setX(aFrm.Pos().getX() - aFrm.Width() + GetUpper()->getFramePrintArea().Width());
            }
        }
    }
    else
    {
        SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
        aFrm.Pos().setX(0);
        aFrm.Pos().setY(0);
    }

    if( IsBodyFrame() && aRectFnSet.IsVert() && !aRectFnSet.IsVertL2R() && GetUpper() )
    {
        SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
        aFrm.Pos().setX(aFrm.Pos().getX() + GetUpper()->getFramePrintArea().Width() - aFrm.Width());
    }

    setFrameAreaPositionValid(true);
}

// #i28701# - new type <SwSortedObjs>
static void lcl_CheckObjects(SwSortedObjs& rSortedObjs, const SwFrame* pFrame, tools::Long& rBot)
{
    // And then there can be paragraph anchored frames that sit below their paragraph.
    tools::Long nMax = 0;
    for (SwAnchoredObject* pObj : rSortedObjs)
    {
        // #i28701# - consider changed type of <SwSortedObjs>
        // entries.
        tools::Long nTmp = 0;
        if ( auto pFly = pObj->DynCastFlyFrame() )
        {
            if( pFly->getFrameArea().Top() != FAR_AWAY &&
                ( pFrame->IsPageFrame() ? pFly->IsFlyLayFrame() :
                  ( pFly->IsFlyAtContentFrame() &&
                    ( pFrame->IsBodyFrame() ? pFly->GetAnchorFrame()->IsInDocBody() :
                                          pFly->GetAnchorFrame()->IsInFootnote() ) ) ) )
            {
                nTmp = pFly->getFrameArea().Bottom();
            }
        }
        else
            nTmp = pObj->GetObjRect().Bottom();
        nMax = std::max( nTmp, nMax );
    }
    ++nMax; // Lower edge vs. height!
    rBot = std::max( rBot, nMax );
}

size_t SwPageFrame::GetContentHeight(const tools::Long nTop, const tools::Long nBottomconst
{
    OSL_ENSURE(!(FindBodyCont() && FindBodyCont()->Lower() && FindBodyCont()->Lower()->IsColumnFrame()),
               "SwPageFrame::GetContentHeight(): No support for columns.");

    // In pages without columns, the content defines the size.
    tools::Long nBot = getFrameArea().Top() + nTop;
    const SwFrame *pFrame = Lower();
    while (pFrame)
    {
        tools::Long nTmp = 0;
        const SwFrame *pCnt = static_cast<const SwLayoutFrame*>(pFrame)->ContainsAny();
        while (pCnt && (pCnt->GetUpper() == pFrame ||
               static_cast<const SwLayoutFrame*>(pFrame)->IsAnLower(pCnt)))
        {
            nTmp += pCnt->getFrameArea().Height();
            if (pCnt->IsTextFrame() &&
                static_cast<const SwTextFrame*>(pCnt)->IsUndersized())
            {
                // This TextFrame would like to be a bit bigger.
                nTmp += static_cast<const SwTextFrame*>(pCnt)->GetParHeight()
                      - pCnt->getFramePrintArea().Height();
            }
            else if (pCnt->IsSctFrame())
            {
                // Grow if undersized, but don't shrink if oversized.
                const auto delta = static_cast<const SwSectionFrame*>(pCnt)->CalcUndersize();
                if (delta > 0)
                    nTmp += delta;
            }

            pCnt = pCnt->FindNext();
        }
        // Consider invalid body frame properties
        if (pFrame->IsBodyFrame() &&
            (!pFrame->isFrameAreaSizeValid() ||
            !pFrame->isFramePrintAreaValid()) &&
            (pFrame->getFrameArea().Height() < pFrame->getFramePrintArea().Height())
            )
        {
            nTmp = std::min(nTmp, pFrame->getFrameArea().Height());
        }
        else
        {
            // Assert invalid lower property
            OSL_ENSURE(!(pFrame->getFrameArea().Height() < pFrame->getFramePrintArea().Height()),
                "SwPageFrame::GetContentHeight(): Lower with frame height < printing height");
            nTmp += pFrame->getFrameArea().Height() - pFrame->getFramePrintArea().Height();
        }
        if (!pFrame->IsBodyFrame())
            nTmp = std::min(nTmp, pFrame->getFrameArea().Height());
        nBot += nTmp;
        // Here we check whether paragraph anchored objects
        // protrude outside the Body/FootnoteCont.
        if (m_pSortedObjs && !pFrame->IsHeaderFrame() &&
            !pFrame->IsFooterFrame())
            lcl_CheckObjects(*m_pSortedObjs, pFrame, nBot);
        pFrame = pFrame->GetNext();
    }
    nBot += nBottom;
    // And the page anchored ones
    if (m_pSortedObjs)
        lcl_CheckObjects(*m_pSortedObjs, this, nBot);
    nBot -= getFrameArea().Top();

    return nBot;
}

void SwPageFrame::MakeAll(vcl::RenderContext* pRenderContext)
{
    PROTOCOL_ENTER( this, PROT::MakeAll, DbgAction::NONE, nullptr )

    const SwRect aOldRect( getFrameArea() );     // Adjust root size
    const SwLayNotify aNotify( this );  // takes care of the notification in the dtor
    std::optional<SwBorderAttrAccess> oAccess;
    const SwBorderAttrs*pAttrs = nullptr;

    while ( !isFrameAreaPositionValid() || !isFrameAreaSizeValid() || !isFramePrintAreaValid() )
    {
        if ( !isFrameAreaPositionValid() )
        {
            setFrameAreaPositionValid(true); // positioning of the pages is taken care of by the root frame
        }

        if ( !isFrameAreaSizeValid() || !isFramePrintAreaValid() )
        {
            if ( IsEmptyPage() )
            {
                SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
                aFrm.Width( 0 );
                aFrm.Height( 0 );

                SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this);
                aPrt.Width( 0 );
                aPrt.Height( 0 );
                aPrt.Left( 0 );
                aPrt.Top( 0 );

                setFrameAreaSizeValid(true);
                setFramePrintAreaValid(true);
            }
            else
            {
                if (!oAccess)
                {
                    oAccess.emplace(SwFrame::GetCache(), this);
                    pAttrs = oAccess->Get();
                }
                assert(pAttrs);

                SwRootFrame* pRootFrame = getRootFrame();
                SwViewShell* pSh = pRootFrame->GetCurrShell();
                if (pSh && pSh->GetViewOptions()->getBrowseMode())
                {
                    // In BrowseView, we use fixed settings
                    const Size aBorder = pRenderContext->PixelToLogic( pSh->GetBrowseBorder() );
                    const tools::Long nTop    = pAttrs->CalcTopLine()   + aBorder.Height();
                    const tools::Long nBottom = pAttrs->CalcBottomLine()+ aBorder.Height();

                    tools::Long nWidth = GetUpper() ? static_cast<SwRootFrame*>(GetUpper())->GetBrowseWidth() : 0;
                    const auto nDefWidth = pSh->GetBrowseWidth();
                    if (nWidth < nDefWidth)
                        nWidth = nDefWidth;
                    nWidth += + 2 * aBorder.Width();

                    constexpr tools::Long constTwips_2cm = o3tl::toTwips(2, o3tl::Length::cm);
                    nWidth = std::max(nWidth, 2L * aBorder.Width() + constTwips_2cm);

                    {
                        SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
                        aFrm.Width( nWidth );

                        SwLayoutFrame *pBody = FindBodyCont();
                        if ( pBody && pBody->Lower() && pBody->Lower()->IsColumnFrame() )
                        {
                            // Columns have a fixed height
                            aFrm.Height( pAttrs->GetSize().Height() );
                        }
                        else
                        {
                            // In pages without columns, the content defines the size.
                            tools::Long nBot = GetContentHeight(nTop, nBottom);

                            // #i35143# - If second page frame
                            // exists, the first page doesn't have to fulfill the
                            // visible area.
                            if ( !GetPrev() && !GetNext() )
                            {
                                nBot = std::max( nBot, pSh->VisArea().Height() );
                            }
                            // #i35143# - Assure, that the page
                            // doesn't exceed the defined browse height.
                            aFrm.Height( std::min( nBot, BROWSE_HEIGHT ) );
                        }
                    }

                    {
                        SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this);
                        aPrt.Left ( pAttrs->CalcLeftLine() + aBorder.Width() );
                        aPrt.Top  ( nTop );
                        aPrt.Width( getFrameArea().Width() - ( aPrt.Left() + pAttrs->CalcRightLine() + aBorder.Width() ) );
                        aPrt.Height( getFrameArea().Height() - (nTop + nBottom) );
                    }

                    setFrameAreaSizeValid(true);
                    setFramePrintAreaValid(true);
                    continue;
                }
                else if (pSh && pSh->GetViewOptions()->IsWhitespaceHidden())
                {
                    tools::Long height = 0;
                    SwLayoutFrame *pBody = FindBodyCont();
                    SwTwips nFullBodyHeight = pAttrs->GetSize().Height() - pAttrs->CalcTop() - pAttrs->CalcBottom();
                    if (pRootFrame->GetLastPage() == this)
                    {
                        // Last page is only reduced by the top/bottom margin, the body frame height
                        // is not reduced.
                        height = nFullBodyHeight;
                    }
                    else if ( pBody && pBody->Lower() && pBody->Lower()->IsColumnFrame() )
                    {
                        // Columns have a fixed height
                        height = pAttrs->GetSize().Height();
                    }
                    else
                    {
                        // No need for borders.
                        height = GetContentHeight(0, 0);
                        if (height > nFullBodyHeight)
                        {
                            // Content height would be larger than the show-whitespace body height,
                            // limit it.
                            height = nFullBodyHeight;
                        }
                    }

                    if (height > 0)
                    {
                        ChgSize(Size(getFrameArea().Width(), height));
                        SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this);
                        aPrt.Top(0);
                        aPrt.Height(height);
                        setFrameAreaSizeValid(true);
                        setFramePrintAreaValid(true);
                        continue;
                    }

                    // Fallback to default formatting. Especially relevant
                    // when loading a doc when Hide Whitespace is enabled.
                    // Heights are zero initially.
                }

                // Set FixSize. For pages, this is not done from Upper, but from
                // the attribute.
                //FIXME: This resets the size when (isFrameAreaSizeValid() && !isFramePrintAreaValid()).
                {
                    SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
                    aFrm.SSize( pAttrs->GetSize() );
                }
                Format( pRenderContext, pAttrs );
            }
        }
    } //while ( !isFrameAreaPositionValid() || !isFrameAreaSizeValid() || !isFramePrintAreaValid() )

    if ( getFrameArea() != aOldRect && GetUpper() )
        static_cast<SwRootFrame*>(GetUpper())->CheckViewLayout( nullptr, nullptr );

    OSL_ENSURE( !GetUpper() || GetUpper()->getFramePrintArea().Width() >= getFrameArea().Width(),
        "Upper (Root) must be wide enough to contain the widest page");
}

void SwLayoutFrame::MakeAll(vcl::RenderContext* /*pRenderContext*/)
{
    PROTOCOL_ENTER( this, PROT::MakeAll, DbgAction::NONE, nullptr )

    // takes care of the notification in the dtor
    const SwLayNotify aNotify( this );
    bool bVert = IsVertical();

    SwRectFnSet fnRect(IsNeighbourFrame() != bVert, IsVertLR(), IsVertLRBT());

    std::optional<SwBorderAttrAccess> oAccess;
    const SwBorderAttrs*pAttrs = nullptr;

    while ( !isFrameAreaPositionValid() || !isFrameAreaSizeValid() || !isFramePrintAreaValid() )
    {
        if ( !isFrameAreaPositionValid() )
        {
            MakePos();
        }

        if (IsHiddenNow())
        {
            MakeValidZeroHeight();
        }

        if ( GetUpper() )
        {
            // NEW TABLES
            if ( IsLeaveUpperAllowed() )
            {
                if ( !isFrameAreaSizeValid() )
                {
                    setFramePrintAreaValid(false);
                }
            }
            else
            {
                if ( !isFrameAreaSizeValid() )
                {
                    // Set FixSize; VarSize is set by Format() after calculating the PrtArea
                    setFramePrintAreaValid(false);

                    SwTwips nPrtWidth = fnRect.GetWidth(GetUpper()->getFramePrintArea());
                    if( bVert && ( IsBodyFrame() || IsFootnoteContFrame() ) )
                    {
                        SwFrame* pNxt = GetPrev();
                        while( pNxt && !pNxt->IsHeaderFrame() )
                            pNxt = pNxt->GetPrev();
                        if( pNxt )
                            nPrtWidth -= pNxt->getFrameArea().Height();
                        pNxt = GetNext();
                        while( pNxt && !pNxt->IsFooterFrame() )
                            pNxt = pNxt->GetNext();
                        if( pNxt )
                            nPrtWidth -= pNxt->getFrameArea().Height();
                    }

                    const tools::Long nDiff = nPrtWidth - fnRect.GetWidth(getFrameArea());
                    SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
                    // SwRectFn switched between horizontal and vertical when bVert == IsNeighbourFrame().
                    // We pick fnSubLeft or fnAddRight that is correspondent to SwRectFn->fnAddBottom
                    if( ( IsCellFrame() && IsRightToLeft() ) || ( IsColumnFrame() && bVert && !IsVertLR() ) )
                    {
                        fnRect.SubLeft(aFrm, nDiff);
                    }
                    else
                    {
                        fnRect.AddRight(aFrm, nDiff);
                    }
                }
                else
                {
                    // Don't leave your upper
                    const SwTwips nDeadLine = fnRect.GetPrtBottom(*GetUpper());
                    if (fnRect.OverStep(getFrameArea(), nDeadLine))
                    {
                        setFrameAreaSizeValid(false);
                    }
                }
            }
        }

        if ( !isFrameAreaSizeValid() || !isFramePrintAreaValid() )
        {
            if ( !oAccess )
            {
                oAccess.emplace(SwFrame::GetCache(), this);
                pAttrs  = oAccess->Get();
            }
            Format( getRootFrame()->GetCurrShell()->GetOut(), pAttrs );
        }
    } //while ( !isFrameAreaPositionValid() || !isFrameAreaSizeValid() || !isFramePrintAreaValid() )
}

bool SwTextNode::IsCollapse() const
{
    if (GetDoc().GetDocumentSettingManager().get( DocumentSettingId::COLLAPSE_EMPTY_CELL_PARA )
        &&  GetText().isEmpty())
    {
        SwNodeOffset nIdx=GetIndex();
        const SwEndNode *pNdBefore=GetNodes()[nIdx-1]->GetEndNode();
        const SwEndNode *pNdAfter=GetNodes()[nIdx+1]->GetEndNode();

        // The paragraph is collapsed only if the NdAfter is the end of a cell
        bool bInTable = FindTableNode( ) != nullptr;

        SwSortedObjs* pObjs = getLayoutFrame( GetDoc().getIDocumentLayoutAccess().GetCurrentLayout() )->GetDrawObjs( );
        const size_t nObjs = ( pObjs != nullptr ) ? pObjs->size( ) : 0;

        return pNdBefore!=nullptr && pNdAfter!=nullptr && nObjs == 0 && bInTable;
    }

    return false;
}

bool SwFrame::IsCollapse() const
{
    if (!IsTextFrame())
        return false;

    const SwTextFrame *pTextFrame = static_cast<const SwTextFrame*>(this);
    const SwTextNode *pTextNode = pTextFrame->GetTextNodeForParaProps();
    // TODO this SwTextNode function is pointless and should be merged in here
    return pTextFrame->GetText().isEmpty() && pTextNode && pTextNode->IsCollapse();
}

bool SwFrame::IsCollapseUpper() const
{
    const SwTextFrame* pTextFrame = DynCastTextFrame();
    if (!pTextFrame)
    {
        return false;
    }

    const SwDoc& rDoc = pTextFrame->GetDoc();
    const IDocumentSettingAccess& rIDSA = rDoc.getIDocumentSettingAccess();
    if (!rIDSA.get(DocumentSettingId::TAB_OVER_SPACING) || rIDSA.get(DocumentSettingId::TAB_OVER_MARGIN))
    {
        // Writer or Word Word <= 2010 style: upper margin is never ignored.
        return false;
    }

    if (IsInFly())
    {
        // Not in a page's body.
        return false;
    }

    // Word >= 2013 style: when we're at the top of the page's body, but not on the first page, then
    // ignore the upper margin for paragraphs.
    if (GetPrev() || !GetUpper() || !GetUpper()->IsBodyFrame())
    {
        return false;
    }

    const SwPageFrame* pPageFrame = FindPageFrame();
    if (!pPageFrame || !pPageFrame->GetPrev())
    {
        return false;
    }

    // Avoid the ignore after applying a new page style (but do it after page breaks).
    const SwTextNode* pTextNode = pTextFrame->GetTextNodeForParaProps();
    if (pTextNode)
    {
        if (pTextNode->HasSwAttrSet() && pTextNode->GetSwAttrSet().HasItem(RES_PAGEDESC))
        {
            return false;
        }
    }

    return true;
}

void SwContentFrame::MakePrtArea( const SwBorderAttrs &rAttrs )
{
    if ( isFramePrintAreaValid() )
        return;

    setFramePrintAreaValid(true);
    SwRectFnSet aRectFnSet(this);
    SwTwips nUpper = 0;
    if (IsTextFrame() && IsHiddenNow())
    {
        if ( static_cast<SwTextFrame*>(this)->HasFollow() )
            static_cast<SwTextFrame*>(this)->JoinFrame();

        if( aRectFnSet.GetHeight(getFramePrintArea()) )
        {
            static_cast<SwTextFrame*>(this)->HideHidden();
        }

        {
            SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this);
            aPrt.Pos().setX(0);
            aPrt.Pos().setY(0);
            aRectFnSet.SetWidth( aPrt, aRectFnSet.GetWidth(getFrameArea()) );
            aRectFnSet.SetHeight( aPrt, 0 );
        }

        nUpper = -( aRectFnSet.GetHeight(getFrameArea()) );
    }
    else
    {
        // Simplification: ContentFrames are always variable in height!

        // At the FixSize, the surrounding Frame enforces the size;
        // the borders are simply subtracted.
        const tools::Long nLeft = rAttrs.CalcLeft( this );
        const tools::Long nRight = rAttrs.CalcRight( this );
        aRectFnSet.SetXMargins( *this, nLeft, nRight );

        SwViewShell *pSh = getRootFrame()->GetCurrShell();
        SwTwips nWidthArea;
        if( pSh && 0!=(nWidthArea=aRectFnSet.GetWidth(pSh->VisArea())) &&
            GetUpper()->IsPageBodyFrame() && // but not for BodyFrames in Columns
            pSh->GetViewOptions()->getBrowseMode() )
        {
            // Do not protrude the edge of the visible area. The page may be
            // wider, because there may be objects with excess width
            // (RootFrame::ImplCalcBrowseWidth())
            tools::Long nMinWidth = 0;

            for (size_t i = 0; GetDrawObjs() && i < GetDrawObjs()->size(); ++i)
            {
                // #i28701# - consider changed type of
                // <SwSortedObjs> entries
                SwAnchoredObject* pObj = (*GetDrawObjs())[i];
                const SwFrameFormat* pFormat = pObj->GetFrameFormat();
                const bool bFly = pObj->DynCastFlyFrame() !=  nullptr;
                if ((bFly && (FAR_AWAY == pObj->GetObjRect().Width()))
                    || pFormat->GetFrameSize().GetWidthPercent())
                {
                    continue;
                }

                if ( RndStdIds::FLY_AS_CHAR == pFormat->GetAnchor().GetAnchorId() )
                {
                    nMinWidth = std::max( nMinWidth,
                                     bFly ? pFormat->GetFrameSize().GetWidth()
                                          : pObj->GetObjRect().Width() );
                }
            }

            const Size aBorder = pSh->GetOut()->PixelToLogic( pSh->GetBrowseBorder() );
            tools::Long nWidth = nWidthArea - 2 * ( IsVertical() ? aBorder.Height() : aBorder.Width() );
            nWidth -= aRectFnSet.GetLeft(getFramePrintArea());
            nWidth -= rAttrs.CalcRightLine();
            nWidth = std::max( nMinWidth, nWidth );

            SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this);
            aRectFnSet.SetWidth( aPrt, std::min( nWidth, aRectFnSet.GetWidth(aPrt) ) );
        }

        if ( aRectFnSet.GetWidth(getFramePrintArea()) <= MINLAY )
        {
            // The PrtArea should already be at least MINLAY wide, matching the
            // minimal values of the UI
            SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this);
            aRectFnSet.SetWidth( aPrt, std::min( tools::Long(MINLAY), aRectFnSet.GetWidth(getFrameArea()) ) );
            SwTwips nTmp = aRectFnSet.GetWidth(getFrameArea()) - aRectFnSet.GetWidth(aPrt);

            if( aRectFnSet.GetLeft(aPrt) > nTmp )
            {
                aRectFnSet.SetLeft( aPrt, nTmp );
            }
        }

        // The following rules apply for VarSize:
        // 1. The first entry of a chain has no top border
        // 2. There is never a bottom border
        // 3. The top border is the maximum of the distance
        //    of Prev downwards and our own distance upwards
        // Those three rules apply when calculating spacings
        // that are given by UL- and LRSpace. There might be a spacing
        // in all directions however; this may be caused by borders
        // and / or shadows.
        // 4. The spacing for TextFrames corresponds to the interline lead,
        //    at a minimum.

        nUpper = CalcUpperSpace( &rAttrs );

        SwTwips nLower = CalcLowerSpace( &rAttrs );
        if (IsCollapse()) {
            nUpper=0;
            nLower=0;
        }

        {
            SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this);
            aRectFnSet.SetPosY( aPrt, !aRectFnSet.IsVert() ? nUpper : nLower);
        }

        nUpper += nLower;
        nUpper -= aRectFnSet.GetHeight(getFrameArea()) - aRectFnSet.GetHeight(getFramePrintArea());
    }
    // If there's a difference between old and new size, call Grow() or
    // Shrink() respectively.
    if ( nUpper )
    {
        if ( nUpper > 0 )
            GrowFrame( nUpper );
        else
            ShrinkFrame( -nUpper );
    }
}

#define STOP_FLY_FORMAT 10
// - loop prevention
const int cnStopFormat = 15;

inline void ValidateSz( SwFrame *pFrame )
{
    if ( pFrame )
    {
        pFrame->setFrameAreaSizeValid(true);
        pFrame->setFramePrintAreaValid(true);
    }
}

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;
    }

    bool const isHiddenNow(static_cast<SwTextFrame*>(this)->IsHiddenNowImpl());
    if (isHiddenNow)
    {
        while (HasFollow())
        {
            static_cast<SwTextFrame&>(*this).JoinFrame();
        }
        HideAndShowObjects();
    }

    std::optional<SwFrameDeleteGuard> oDeleteGuard(std::in_place, this);
    LockJoin();
    tools::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::optional<SwContentNotify> oNotify( std::in_place, 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) ) )
    {
        oNotify->SetBordersJoinedWithPrev();
    }

    bool bKeep{!isHiddenNow && IsKeep(rAttrs.GetAttrSet().GetKeep(), GetBreakItem())};
    if (bKeep)
    {
        // The SwTextFrameBreak ctor already turns off bKeep for split fly anchors, don't
        // change that decision here.
        bKeep = IgnoringSplitFlyAnchor(bKeep);
    }

    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() )
    {
        static_cast<SwTextFrame&>(*this).JoinFrame();
    }

    // #i28701# - move master forward, if it has to move,
    // because of its object positioning.
    if (!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 );
        }
    }
    else if (auto* prev = lcl_Prev(this); prev && IsMoveable())
    {
        // If a Follow sits next to its Master and doesn't fit, we know it can be moved right now.
        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() )
        {
            prev->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();
        }

        if (isHiddenNow)
        {   // call this after MakePos() otherwise Shrink may not work
            MakeValidZeroHeight();
        }

        //Set FixSize. VarSize is being adjusted by Format().
        if ( !isFrameAreaSizeValid() )
        {
            assert(!isHiddenNow); // hidden frame must not be formatted
            // 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() )
        {
            assert(!isHiddenNow); // hidden frame must not be formatted
            const tools::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 && !isHiddenNow)
        {
            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.
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=92 H=89 G=90

¤ Dauer der Verarbeitung: 0.20 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.