/* -*- 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 <hints.hxx>
#include <svl/itemiter.hxx>
#include <editeng/brushitem.hxx>
#include <fmtornt.hxx>
#include <pagefrm.hxx>
#include <section.hxx>
#include <rootfrm.hxx>
#include <anchoreddrawobject.hxx>
#include <fmtanchr.hxx>
#include <viewimp.hxx>
#include <viewopt.hxx>
#include <IDocumentSettingAccess.hxx>
#include <IDocumentFieldsAccess.hxx>
#include <fesh.hxx>
#include <docsh.hxx>
#include <ftninfo.hxx>
#include <fmtclbl.hxx>
#include <fmtfsize.hxx>
#include <fmtpdsc.hxx>
#include <txtftn.hxx>
#include <fmtftn.hxx>
#include <fmtsrnd.hxx>
#include <ftnfrm.hxx>
#include <tabfrm.hxx>
#include <flyfrms.hxx>
#include <sectfrm.hxx>
#include <fmtclds.hxx>
#include <txtfrm.hxx>
#include <bodyfrm.hxx>
#include <cellfrm.hxx>
#include <dbg_lay.hxx>
#include <editeng/frmdiritem.hxx>
#include <sortedobjs.hxx>
 
// RotateFlyFrame3
#include <basegfx/matrix/b2dhommatrixtools.hxx>
 
using namespace ::com::sun::star;
 
SwFrameAreaDefinition::SwFrameAreaDefinition()
:   maFrameArea(),
    maFramePrintArea(),
    mbFrameAreaPositionValid(false),
    mbFrameAreaSizeValid(false),
    mbFramePrintAreaValid(false)
{
}
 
SwFrameAreaDefinition::~SwFrameAreaDefinition()
{
}
 
void SwFrameAreaDefinition::setFrameAreaPositionValid(bool bNew)
{
    if(mbFrameAreaPositionValid != bNew)
    {
        mbFrameAreaPositionValid = bNew;
    }
}
 
void SwFrameAreaDefinition::setFrameAreaSizeValid(bool bNew)
{
    if(mbFrameAreaSizeValid != bNew)
    {
        mbFrameAreaSizeValid = bNew;
    }
}
 
void SwFrameAreaDefinition::setFramePrintAreaValid(bool bNew)
{
    if(mbFramePrintAreaValid != bNew)
    {
        mbFramePrintAreaValid = bNew;
    }
}
 
SwFrameAreaDefinition::FrameAreaWriteAccess::~FrameAreaWriteAccess()
{
    if(mrTarget.maFrameArea != *this)
    {
        mrTarget.maFrameArea = *this;
    }
}
 
SwFrameAreaDefinition::FramePrintAreaWriteAccess::~FramePrintAreaWriteAccess()
{
    if(mrTarget.maFramePrintArea != *this)
    {
        mrTarget.maFramePrintArea = *this;
    }
}
 
// RotateFlyFrame3 - Support for Transformations
basegfx::B2DHomMatrix SwFrameAreaDefinition::getFrameAreaTransformation() const
{
    // default implementation hands out FrameArea (outer frame)
    const SwRect& rFrameArea(getFrameArea());
 
    return basegfx::utils::createScaleTranslateB2DHomMatrix(
        rFrameArea.Width(), rFrameArea.Height(),
        rFrameArea.Left(), rFrameArea.Top());
}
 
basegfx::B2DHomMatrix SwFrameAreaDefinition::getFramePrintAreaTransformation() const
{
    // default implementation hands out FramePrintArea (outer frame)
    // Take into account that FramePrintArea is relative to FrameArea
    const SwRect& rFrameArea(getFrameArea());
    const SwRect& rFramePrintArea(getFramePrintArea());
 
    return basegfx::utils::createScaleTranslateB2DHomMatrix(
        rFramePrintArea.Width(), rFramePrintArea.Height(),
        rFramePrintArea.Left() + rFrameArea.Left(),
        rFramePrintArea.Top() + rFrameArea.Top());
}
 
void SwFrameAreaDefinition::transform_translate(const Point& rOffset)
{
    // RotateFlyFrame3: default is to change the FrameArea, FramePrintArea needs no
    // change since it is relative to FrameArea
    SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
 
    if (aFrm.Pos().X() != FAR_AWAY)
    {
        aFrm.Pos().AdjustX(rOffset.X() );
    }
 
    if (aFrm.Pos().Y() != FAR_AWAY)
    {
        aFrm.Pos().AdjustY(rOffset.Y() );
    }
}
 
SwRect TransformableSwFrame::getUntransformedFrameArea() const
{
    const basegfx::B2DHomMatrix& rSource(getLocalFrameAreaTransformation());
 
    if(rSource.isIdentity())
    {
        return mrSwFrameAreaDefinition.getFrameArea();
    }
    else
    {
        basegfx::B2DVector aScale, aTranslate;
        double fRotate, fShearX;
        rSource.decompose(aScale, aTranslate, fRotate, fShearX);
        const basegfx::B2DPoint aCenter(rSource * basegfx::B2DPoint(0.5, 0.5));
        const basegfx::B2DVector aAbsScale(basegfx::absolute(aScale));
 
        return SwRect(
            basegfx::fround(aCenter.getX() - (0.5 * aAbsScale.getX())),
            basegfx::fround(aCenter.getY() - (0.5 * aAbsScale.getY())),
            basegfx::fround(aAbsScale.getX()),
            basegfx::fround(aAbsScale.getY()));
    }
}
 
SwRect TransformableSwFrame::getUntransformedFramePrintArea() const
{
    const basegfx::B2DHomMatrix& rSource(getLocalFramePrintAreaTransformation());
 
    if(rSource.isIdentity())
    {
        return mrSwFrameAreaDefinition.getFramePrintArea();
    }
    else
    {
        basegfx::B2DVector aScale, aTranslate;
        double fRotate, fShearX;
        rSource.decompose(aScale, aTranslate, fRotate, fShearX);
        const basegfx::B2DPoint aCenter(rSource * basegfx::B2DPoint(0.5, 0.5));
        const basegfx::B2DVector aAbsScale(basegfx::absolute(aScale));
        const SwRect aUntransformedFrameArea(getUntransformedFrameArea());
 
        return SwRect(
            basegfx::fround(aCenter.getX() - (0.5 * aAbsScale.getX())) - aUntransformedFrameArea.Left(),
            basegfx::fround(aCenter.getY() - (0.5 * aAbsScale.getY())) - aUntransformedFrameArea.Top(),
            basegfx::fround(aAbsScale.getX()),
            basegfx::fround(aAbsScale.getY()));
    }
}
 
void TransformableSwFrame::createFrameAreaTransformations(
    double fRotation,
    const basegfx::B2DPoint& rCenter)
{
    const basegfx::B2DHomMatrix aRotateAroundCenter(
        basegfx::utils::createRotateAroundPoint(
            rCenter.getX(),
            rCenter.getY(),
            fRotation));
    const SwRect& rFrameArea(mrSwFrameAreaDefinition.getFrameArea());
    const SwRect& rFramePrintArea(mrSwFrameAreaDefinition.getFramePrintArea());
 
    maFrameAreaTransformation = aRotateAroundCenter * basegfx::utils::createScaleTranslateB2DHomMatrix(
        rFrameArea.Width(), rFrameArea.Height(),
        rFrameArea.Left(), rFrameArea.Top());
    maFramePrintAreaTransformation = aRotateAroundCenter * basegfx::utils::createScaleTranslateB2DHomMatrix(
        rFramePrintArea.Width(), rFramePrintArea.Height(),
        rFramePrintArea.Left() + rFrameArea.Left(), rFramePrintArea.Top() + rFrameArea.Top());
}
 
void TransformableSwFrame::adaptFrameAreasToTransformations()
{
    if(!getLocalFrameAreaTransformation().isIdentity())
    {
        basegfx::B2DRange aRangeFrameArea(0.0, 0.0, 1.0, 1.0);
        aRangeFrameArea.transform(getLocalFrameAreaTransformation());
        const SwRect aNewFrm(
            basegfx::fround(aRangeFrameArea.getMinX()), basegfx::fround(aRangeFrameArea.getMinY()),
            basegfx::fround(aRangeFrameArea.getWidth()), basegfx::fround(aRangeFrameArea.getHeight()));
 
        if(aNewFrm != mrSwFrameAreaDefinition.getFrameArea())
        {
            SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(mrSwFrameAreaDefinition);
            aFrm.setSwRect(aNewFrm);
        }
    }
 
    if(!getLocalFramePrintAreaTransformation().isIdentity())
    {
        basegfx::B2DRange aRangeFramePrintArea(0.0, 0.0, 1.0, 1.0);
        aRangeFramePrintArea.transform(getLocalFramePrintAreaTransformation());
        const SwRect aNewPrt(
            basegfx::fround(aRangeFramePrintArea.getMinX()) - mrSwFrameAreaDefinition.getFrameArea().Left(),
            basegfx::fround(aRangeFramePrintArea.getMinY()) - mrSwFrameAreaDefinition.getFrameArea().Top(),
            basegfx::fround(aRangeFramePrintArea.getWidth()),
            basegfx::fround(aRangeFramePrintArea.getHeight()));
 
        if(aNewPrt != mrSwFrameAreaDefinition.getFramePrintArea())
        {
            SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(mrSwFrameAreaDefinition);
            aPrt.setSwRect(aNewPrt);
        }
    }
}
 
void TransformableSwFrame::restoreFrameAreas()
{
    // This can be done fully based on the Transformations currently
    // set, so use this. Only needed when transformation *is* used
    if(!getLocalFrameAreaTransformation().isIdentity())
    {
        SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(mrSwFrameAreaDefinition);
        aFrm.setSwRect(getUntransformedFrameArea());
    }
 
    if(!getLocalFramePrintAreaTransformation().isIdentity())
    {
        SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(mrSwFrameAreaDefinition);
        aPrt.setSwRect(getUntransformedFramePrintArea());
    }
}
 
// transform by given B2DHomMatrix
void TransformableSwFrame::transform(const basegfx::B2DHomMatrix& aTransform)
{
    maFrameAreaTransformation *= aTransform;
    maFramePrintAreaTransformation *= aTransform;
}
 
SwFrame::SwFrame( SwModify *pMod, SwFrame* pSib )
:   SwFrameAreaDefinition(),
    SwClient( pMod ),
    SfxBroadcaster(),
    mnFrameId( SwFrame::mnLastFrameId++ ),
    mpRoot( pSib ? pSib->getRootFrame() : nullptr ),
    mpUpper(nullptr),
    mpNext(nullptr),
    mpPrev(nullptr),
    mnFrameType(SwFrameType::None),
    mbInDtor(false),
    mbInvalidR2L(true),
    mbDerivedR2L(false),
    mbRightToLeft(false),
    mbInvalidVert(true),
    mbDerivedVert(false),
    mbVertical(false),
    mbVertLR(false),
    mbValidLineNum(false),
    mbFixSize(false),
    mbCompletePaint(true),
    mbRetouche(false),
    mbInfInvalid(true),
    mbInfBody( false ),
    mbInfTab ( false ),
    mbInfFly ( false ),
    mbInfFootnote ( false ),
    mbInfSct ( false ),
    mbColLocked(false),
    m_isInDestroy(false),
    mbForbidDelete(false)
{
    OSL_ENSURE( pMod, "No frame format given." );
}
 
const IDocumentDrawModelAccess& SwFrame::getIDocumentDrawModelAccess()
{
    return GetUpper()->GetFormat()->getIDocumentDrawModelAccess();
}
 
bool SwFrame::KnowsFormat( const SwFormat& rFormat ) const
{
    return GetRegisteredIn() == &rFormat;
}
 
void SwFrame::RegisterToFormat( SwFormat& rFormat )
{
    rFormat.Add( this );
}
 
void SwFrame::CheckDir( SvxFrameDirection nDir, bool bVert, bool bOnlyBiDi, bool bBrowse )
{
    if( SvxFrameDirection::Environment == nDir || ( bVert && bOnlyBiDi ) )
    {
        mbDerivedVert = true;
        if( SvxFrameDirection::Environment == nDir )
            mbDerivedR2L = true;
        SetDirFlags( bVert );
    }
    else if( bVert )
    {
        mbInvalidVert = false;
        if( SvxFrameDirection::Horizontal_LR_TB == nDir || SvxFrameDirection::Horizontal_RL_TB == nDir
            || bBrowse )
        {
            mbVertical = false;
            mbVertLR = false;
        }
        else
           {
            mbVertical = true;
            if(SvxFrameDirection::Vertical_RL_TB == nDir)
                mbVertLR = false;
               else if(SvxFrameDirection::Vertical_LR_TB==nDir)
                       mbVertLR = true;
        }
    }
    else
    {
        mbInvalidR2L = false;
        if( SvxFrameDirection::Horizontal_RL_TB == nDir )
            mbRightToLeft = true;
        else
            mbRightToLeft = false;
    }
}
 
void SwFrame::CheckDirection( bool bVert )
{
    if( bVert )
    {
        if( !IsHeaderFrame() && !IsFooterFrame() )
        {
            mbDerivedVert = true;
            SetDirFlags( bVert );
        }
    }
    else
    {
        mbDerivedR2L = true;
        SetDirFlags( bVert );
    }
}
 
void SwSectionFrame::CheckDirection( bool bVert )
{
    const SwFrameFormat* pFormat = GetFormat();
    if( pFormat )
    {
        const SwViewShell *pSh = getRootFrame()->GetCurrShell();
        const bool bBrowseMode = pSh && pSh->GetViewOptions()->getBrowseMode();
        CheckDir(pFormat->GetFormatAttr(RES_FRAMEDIR).GetValue(),
                    bVert, true, bBrowseMode );
    }
    else
        SwFrame::CheckDirection( bVert );
}
 
void SwFlyFrame::CheckDirection( bool bVert )
{
    const SwFrameFormat* pFormat = GetFormat();
    if( pFormat )
    {
        const SwViewShell *pSh = getRootFrame()->GetCurrShell();
        const bool bBrowseMode = pSh && pSh->GetViewOptions()->getBrowseMode();
        CheckDir(pFormat->GetFormatAttr(RES_FRAMEDIR).GetValue(),
                    bVert, false, bBrowseMode );
    }
    else
        SwFrame::CheckDirection( bVert );
}
 
void SwTabFrame::CheckDirection( bool bVert )
{
    const SwFrameFormat* pFormat = GetFormat();
    if( pFormat )
    {
        const SwViewShell *pSh = getRootFrame()->GetCurrShell();
        const bool bBrowseMode = pSh && pSh->GetViewOptions()->getBrowseMode();
        CheckDir(pFormat->GetFormatAttr(RES_FRAMEDIR).GetValue(),
                    bVert, true, bBrowseMode );
    }
    else
        SwFrame::CheckDirection( bVert );
}
 
void SwCellFrame::CheckDirection( bool bVert )
{
    const SwFrameFormat* pFormat = GetFormat();
    const SfxPoolItem* pItem;
    // Check if the item is set, before actually
    // using it. Otherwise the dynamic pool default is used, which may be set
    // to LTR in case of OOo 1.0 documents.
    if( pFormat && SfxItemState::SET == pFormat->GetItemState( RES_FRAMEDIR, true, &pItem ) )
    {
        const SvxFrameDirectionItem* pFrameDirItem = static_cast<const SvxFrameDirectionItem*>(pItem);
        const SwViewShell *pSh = getRootFrame()->GetCurrShell();
        const bool bBrowseMode = pSh && pSh->GetViewOptions()->getBrowseMode();
        CheckDir( pFrameDirItem->GetValue(), bVert, false, bBrowseMode );
    }
    else
        SwFrame::CheckDirection( bVert );
}
 
void SwTextFrame::CheckDirection( bool bVert )
{
    const SwViewShell *pSh = getRootFrame()->GetCurrShell();
    const bool bBrowseMode = pSh && pSh->GetViewOptions()->getBrowseMode();
    CheckDir(GetTextNodeForParaProps()->GetSwAttrSet().GetFrameDir().GetValue(),
             bVert, true, bBrowseMode);
}
 
void SwFrame::Modify( const SfxPoolItem* pOld, const SfxPoolItem * pNew )
{
    sal_uInt8 nInvFlags = 0;
 
    if( pOld && pNew && RES_ATTRSET_CHG == pNew->Which() )
    {
        SfxItemIter aNIter( *static_cast<const SwAttrSetChg*>(pNew)->GetChgSet() );
        SfxItemIter aOIter( *static_cast<const SwAttrSetChg*>(pOld)->GetChgSet() );
        while( true )
        {
            UpdateAttrFrame( aOIter.GetCurItem(),
                         aNIter.GetCurItem(), nInvFlags );
            if( aNIter.IsAtEnd() )
                break;
            aNIter.NextItem();
            aOIter.NextItem();
        }
    }
    else
        UpdateAttrFrame( pOld, pNew, nInvFlags );
 
    if ( nInvFlags != 0 )
    {
        SwPageFrame *pPage = FindPageFrame();
        InvalidatePage( pPage );
        if ( nInvFlags & 0x01 )
        {
            InvalidatePrt_();
            if( !GetPrev() && IsTabFrame() && IsInSct() )
                FindSctFrame()->InvalidatePrt_();
        }
        if ( nInvFlags & 0x02 )
            InvalidateSize_();
        if ( nInvFlags & 0x04 )
            InvalidatePos_();
        if ( nInvFlags & 0x08 )
            SetCompletePaint();
        SwFrame *pNxt;
        if ( nInvFlags & 0x30 && nullptr != (pNxt = GetNext()) )
        {
            pNxt->InvalidatePage( pPage );
            if ( nInvFlags & 0x10 )
                pNxt->InvalidatePos_();
            if ( nInvFlags & 0x20 )
                pNxt->SetCompletePaint();
        }
    }
}
 
void SwFrame::UpdateAttrFrame( const SfxPoolItem *pOld, const SfxPoolItem *pNew,
                         sal_uInt8 &rInvFlags )
{
    sal_uInt16 nWhich = pOld ? pOld->Which() : pNew ? pNew->Which() : 0;
    switch( nWhich )
    {
        case RES_BOX:
        case RES_SHADOW:
            Prepare( PREP_FIXSIZE_CHG );
            SAL_FALLTHROUGH;
        case RES_LR_SPACE:
        case RES_UL_SPACE:
            rInvFlags |= 0x0B;
            break;
 
        case RES_HEADER_FOOTER_EAT_SPACING:
            rInvFlags |= 0x03;
            break;
 
        case RES_BACKGROUND:
            rInvFlags |= 0x28;
            break;
 
        case RES_KEEP:
            rInvFlags |= 0x04;
            break;
 
        case RES_FRM_SIZE:
            ReinitializeFrameSizeAttrFlags();
            rInvFlags |= 0x13;
            break;
 
        case RES_FMT_CHG:
            rInvFlags |= 0x0F;
            break;
 
        case RES_ROW_SPLIT:
        {
            if ( IsRowFrame() )
            {
                bool bInFollowFlowRow = nullptr != IsInFollowFlowRow();
                if ( bInFollowFlowRow || nullptr != IsInSplitTableRow() )
                {
                    SwTabFrame* pTab = FindTabFrame();
                    if ( bInFollowFlowRow )
                        pTab = pTab->FindMaster();
                    pTab->SetRemoveFollowFlowLinePending( true );
                }
            }
            break;
        }
        case RES_COL:
            OSL_FAIL( "Columns for new FrameType?" );
            break;
 
        default:
            // the new FillStyle has to do the same as previous RES_BACKGROUND
            if(nWhich >= XATTR_FILL_FIRST && nWhich <= XATTR_FILL_LAST)
            {
                rInvFlags |= 0x28;
            }
            /* do Nothing */;
    }
}
 
bool SwFrame::Prepare( const PrepareHint, const void *, bool )
{
    /* Do nothing */
    return false;
}
 
/**
 * Invalidates the page in which the Frame is currently placed.
 * The page is invalidated depending on the type (Layout, Content, FlyFrame)
 */
void SwFrame::InvalidatePage( const SwPageFrame *pPage ) const
{
    if ( !pPage )
    {
        pPage = FindPageFrame();
        // #i28701# - for at-character and as-character
        // anchored Writer fly frames additionally invalidate also page frame
        // its 'anchor character' is on.
        if ( pPage && pPage->GetUpper() && IsFlyFrame() )
        {
            const SwFlyFrame* pFlyFrame = static_cast<const SwFlyFrame*>(this);
            if ( pFlyFrame->IsAutoPos() || pFlyFrame->IsFlyInContentFrame() )
            {
                // #i33751#, #i34060# - method <GetPageFrameOfAnchor()>
                // is replaced by method <FindPageFrameOfAnchor()>. It's return value
                // have to be checked.
                SwPageFrame* pPageFrameOfAnchor =
                        const_cast<SwFlyFrame*>(pFlyFrame)->FindPageFrameOfAnchor();
                if ( pPageFrameOfAnchor && pPageFrameOfAnchor != pPage )
                {
                    InvalidatePage( pPageFrameOfAnchor );
                }
            }
        }
    }
 
    if ( pPage && pPage->GetUpper() )
    {
        if ( pPage->GetFormat()->GetDoc()->IsInDtor() )
            return;
 
        SwRootFrame *pRoot = const_cast<SwRootFrame*>(static_cast<const SwRootFrame*>(pPage->GetUpper()));
        const SwFlyFrame *pFly = FindFlyFrame();
        if ( IsContentFrame() )
        {
            if ( pRoot->IsTurboAllowed() )
            {
                // If a ContentFrame wants to register for a second time, make it a TurboAction.
                if ( !pRoot->GetTurbo() || this == pRoot->GetTurbo() )
                    pRoot->SetTurbo( static_cast<const SwContentFrame*>(this) );
                else
                {
                    pRoot->DisallowTurbo();
                    //The page of the Turbo could be a different one then mine,
                    //therefore we have to invalidate it.
                    const SwFrame *pTmp = pRoot->GetTurbo();
                    pRoot->ResetTurbo();
                    pTmp->InvalidatePage();
                }
            }
            if ( !pRoot->GetTurbo() )
            {
                if ( pFly )
                {   if( !pFly->IsLocked() )
                    {
                        if ( pFly->IsFlyInContentFrame() )
                        {   pPage->InvalidateFlyInCnt();
                            pFly->GetAnchorFrame()->InvalidatePage();
                        }
                        else
                            pPage->InvalidateFlyContent();
                    }
                }
                else
                    pPage->InvalidateContent();
            }
        }
        else
        {
            pRoot->DisallowTurbo();
            if ( pFly )
            {
                if ( !pFly->IsLocked() )
                {
                    if ( pFly->IsFlyInContentFrame() )
                    {
                        pPage->InvalidateFlyInCnt();
                        pFly->GetAnchorFrame()->InvalidatePage();
                    }
                    else
                        pPage->InvalidateFlyLayout();
                }
            }
            else
                pPage->InvalidateLayout();
 
            if ( pRoot->GetTurbo() )
            {   const SwFrame *pTmp = pRoot->GetTurbo();
                pRoot->ResetTurbo();
                pTmp->InvalidatePage();
            }
        }
        pRoot->SetIdleFlags();
 
        if (IsTextFrame())
        {
            SwTextFrame const*const pText(static_cast<SwTextFrame const*>(this));
            if (sw::MergedPara const*const pMergedPara = pText->GetMergedPara())
            {
                SwTextNode const* pNode(nullptr);
                for (auto const& e : pMergedPara->extents)
                {
                    if (e.pNode != pNode)
                    {
                        pNode = e.pNode;
                        if (pNode->IsGrammarCheckDirty())
                        {
                            pRoot->SetNeedGrammarCheck( true );
                            break;
                        }
                    }
                }
            }
            else
            {
                if (pText->GetTextNodeFirst()->IsGrammarCheckDirty())
                {
                    pRoot->SetNeedGrammarCheck( true );
                }
            }
        }
    }
}
 
Size SwFrame::ChgSize( const Size& aNewSize )
{
    mbFixSize = true;
    const Size aOldSize( getFrameArea().SSize() );
    if ( aNewSize == aOldSize )
        return aOldSize;
 
    if ( GetUpper() )
    {
        bool bNeighb = IsNeighbourFrame();
        SwRectFn fnRect = IsVertical() == bNeighb ? fnRectHori : ( IsVertLR() ? fnRectVertL2R : fnRectVert );
        SwRect aNew( Point(0,0), aNewSize );
 
        {
            SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
            (aFrm.*fnRect->fnSetWidth)( (aNew.*fnRect->fnGetWidth)() );
        }
 
        long nNew = (aNew.*fnRect->fnGetHeight)();
        long nDiff = nNew - (getFrameArea().*fnRect->fnGetHeight)();
 
        if( nDiff )
        {
            if ( GetUpper()->IsFootnoteBossFrame() && HasFixSize() &&
                 SwNeighbourAdjust::GrowShrink !=
                 static_cast<SwFootnoteBossFrame*>(GetUpper())->NeighbourhoodAdjustment() )
            {
                {
                    SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
                    (aFrm.*fnRect->fnSetHeight)( nNew );
                }
 
                SwTwips nReal = static_cast<SwLayoutFrame*>(this)->AdjustNeighbourhood(nDiff);
 
                if ( nReal != nDiff )
                {
                    SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
                    (aFrm.*fnRect->fnSetHeight)( nNew - nDiff + nReal );
                }
            }
            else
            {
                // OD 24.10.2002 #97265# - grow/shrink not for neighbour frames
                // NOTE: neighbour frames are cell and column frames.
                if ( !bNeighb )
                {
                    if ( nDiff > 0 )
                        Grow( nDiff );
                    else
                        Shrink( -nDiff );
 
                    if ( GetUpper() && (getFrameArea().*fnRect->fnGetHeight)() != nNew )
                    {
                        GetUpper()->InvalidateSize_();
                    }
                }
 
                // Even if grow/shrink did not yet set the desired width, for
                // example when called by ChgColumns to set the column width, we
                // set the right width now.
                SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
                (aFrm.*fnRect->fnSetHeight)( nNew );
            }
        }
    }
    else
    {
        SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
        aFrm.SSize( aNewSize );
    }
 
    if ( getFrameArea().SSize() != aOldSize )
    {
        SwPageFrame *pPage = FindPageFrame();
        if ( GetNext() )
        {
            GetNext()->InvalidatePos_();
            GetNext()->InvalidatePage( pPage );
        }
        if( IsLayoutFrame() )
        {
            if( IsRightToLeft() )
                InvalidatePos_();
            if( static_cast<SwLayoutFrame*>(this)->Lower() )
                static_cast<SwLayoutFrame*>(this)->Lower()->InvalidateSize_();
        }
        InvalidatePrt_();
        InvalidateSize_();
        InvalidatePage( pPage );
    }
 
    return getFrameArea().SSize();
}
 
/** Insert SwFrame into existing structure.
 *
 * Insertion is done below the parent either before pBehind or
 * at the end of the chain if pBehind is empty.
 */
void SwFrame::InsertBefore( SwLayoutFrame* pParent, SwFrame* pBehind )
{
    OSL_ENSURE( pParent, "No parent for insert." );
    OSL_ENSURE( (!pBehind || pParent == pBehind->GetUpper()),
            "Frame tree is inconsistent." );
 
    mpUpper = pParent;
    mpNext = pBehind;
    if( pBehind )
    {   //Insert before pBehind.
        if( nullptr != (mpPrev = pBehind->mpPrev) )
            mpPrev->mpNext = this;
        else
            mpUpper->m_pLower = this;
        pBehind->mpPrev = this;
    }
    else
    {   //Insert at the end, or as first node in the sub tree
        mpPrev = mpUpper->Lower();
        if ( mpPrev )
        {
            while( mpPrev->mpNext )
                mpPrev = mpPrev->mpNext;
            mpPrev->mpNext = this;
        }
        else
            mpUpper->m_pLower = this;
    }
}
 
/** Insert SwFrame into existing structure.
 *
 * Insertion is done below the parent either after pBehind or
 * at the beginning of the chain if pBehind is empty.
 */
void SwFrame::InsertBehind( SwLayoutFrame *pParent, SwFrame *pBefore )
{
    OSL_ENSURE( pParent, "No Parent for Insert." );
    OSL_ENSURE( (!pBefore || pParent == pBefore->GetUpper()),
            "Frame tree is inconsistent." );
 
    mpUpper = pParent;
    mpPrev = pBefore;
    if ( pBefore )
    {
        //Insert after pBefore
        if ( nullptr != (mpNext = pBefore->mpNext) )
            mpNext->mpPrev = this;
        pBefore->mpNext = this;
    }
    else
    {
        //Insert at the beginning of the chain
        mpNext = pParent->Lower();
        if ( pParent->Lower() )
            pParent->Lower()->mpPrev = this;
        pParent->m_pLower = this;
    }
}
 
/** Insert a chain of SwFrames into an existing structure
 *
 * Currently, this method is used to insert a SectionFrame (which may have some siblings) into an
 * existing structure. If the third parameter is NULL, this method is (besides handling the
 * siblings) equal to SwFrame::InsertBefore(..).
 *
 * If the third parameter is passed, the following happens:
 *  - this becomes mpNext of pParent
 *  - pSct becomes mpNext of the last one in the this-chain
 *  - pBehind is reconnected from pParent to pSct
 * The purpose is: a SectionFrame (this) won't become a child of another SectionFrame (pParent), but
 * pParent gets split into two siblings (pParent+pSect) and this is inserted between.
 */
bool SwFrame::InsertGroupBefore( SwFrame* pParent, SwFrame* pBehind, SwFrame* pSct )
{
    OSL_ENSURE( pParent, "No parent for insert." );
    OSL_ENSURE( (!pBehind || ( (pBehind && (pParent == pBehind->GetUpper()))
            || ((pParent->IsSctFrame() && pBehind->GetUpper()->IsColBodyFrame())) ) ),
            "Frame tree inconsistent." );
    if( pSct )
    {
        mpUpper = pParent->GetUpper();
        SwFrame *pLast = this;
        while( pLast->GetNext() )
        {
            pLast = pLast->GetNext();
            pLast->mpUpper = GetUpper();
        }
        if( pBehind )
        {
            pLast->mpNext = pSct;
            pSct->mpPrev = pLast;
            pSct->mpNext = pParent->GetNext();
        }
        else
        {
            pLast->mpNext = pParent->GetNext();
            if( pLast->GetNext() )
                pLast->GetNext()->mpPrev = pLast;
        }
        pParent->mpNext = this;
        mpPrev = pParent;
        if( pSct->GetNext() )
            pSct->GetNext()->mpPrev = pSct;
        while( pLast->GetNext() )
        {
            pLast = pLast->GetNext();
            pLast->mpUpper = GetUpper();
        }
        if( pBehind )
        {   // Insert before pBehind.
            if( pBehind->GetPrev() )
                pBehind->GetPrev()->mpNext = nullptr;
            else
                pBehind->GetUpper()->m_pLower = nullptr;
            pBehind->mpPrev = nullptr;
            SwLayoutFrame* pTmp = static_cast<SwLayoutFrame*>(pSct);
            if( pTmp->Lower() )
            {
                OSL_ENSURE( pTmp->Lower()->IsColumnFrame(), "InsertGrp: Used SectionFrame" );
                pTmp = static_cast<SwLayoutFrame*>(static_cast<SwLayoutFrame*>(pTmp->Lower())->Lower());
                OSL_ENSURE( pTmp, "InsertGrp: Missing ColBody" );
            }
            pBehind->mpUpper = pTmp;
            pBehind->GetUpper()->m_pLower = pBehind;
            pLast = pBehind->GetNext();
            while ( pLast )
            {
                pLast->mpUpper = pBehind->GetUpper();
                pLast = pLast->GetNext();
            }
        }
        else
        {
            OSL_ENSURE( pSct->IsSctFrame(), "InsertGroup: For SectionFrames only" );
            SwFrame::DestroyFrame(pSct);
            return false;
        }
    }
    else
    {
        mpUpper = static_cast<SwLayoutFrame*>(pParent);
        SwFrame *pLast = this;
        while( pLast->GetNext() )
        {
            pLast = pLast->GetNext();
            pLast->mpUpper = GetUpper();
        }
        pLast->mpNext = pBehind;
        if( pBehind )
        {   // Insert before pBehind.
            if( nullptr != (mpPrev = pBehind->mpPrev) )
                mpPrev->mpNext = this;
            else
                mpUpper->m_pLower = this;
            pBehind->mpPrev = pLast;
        }
        else
        {
            //Insert at the end, or ... the first node in the subtree
            mpPrev = mpUpper->Lower();
            if ( mpPrev )
            {
                while( mpPrev->mpNext )
                    mpPrev = mpPrev->mpNext;
                mpPrev->mpNext = this;
            }
            else
                mpUpper->m_pLower = this;
        }
    }
    return true;
}
 
void SwFrame::RemoveFromLayout()
{
    OSL_ENSURE( mpUpper, "Remove without upper?" );
 
    if( mpPrev )
        // one out of the middle is removed
        mpPrev->mpNext = mpNext;
    else
    {   // the first in a list is removed //TODO
        OSL_ENSURE( mpUpper->m_pLower == this, "Layout is inconsistent." );
        mpUpper->m_pLower = mpNext;
    }
    if( mpNext )
        mpNext->mpPrev = mpPrev;
 
    // Remove link
    mpNext  = mpPrev  = nullptr;
    mpUpper = nullptr;
}
 
void SwContentFrame::Paste( SwFrame* pParent, SwFrame* pSibling)
{
    OSL_ENSURE( pParent, "No parent for pasting." );
    OSL_ENSURE( pParent->IsLayoutFrame(), "Parent is ContentFrame." );
    OSL_ENSURE( pParent != this, "I'm the parent." );
    OSL_ENSURE( pSibling != this, "I'm my own neighbour." );
    OSL_ENSURE( !GetPrev() && !GetNext() && !GetUpper(),
            "I'm still registered somewhere" );
    OSL_ENSURE( !pSibling || pSibling->IsFlowFrame(),
            "<SwContentFrame::Paste(..)> - sibling not of expected type." );
 
    //Insert in the tree.
    InsertBefore( static_cast<SwLayoutFrame*>(pParent), pSibling );
 
    SwPageFrame *pPage = FindPageFrame();
    InvalidateAll_();
    InvalidatePage( pPage );
 
    if( pPage )
    {
        pPage->InvalidateSpelling();
        pPage->InvalidateSmartTags();
        pPage->InvalidateAutoCompleteWords();
        pPage->InvalidateWordCount();
    }
 
    if ( GetNext() )
    {
        SwFrame* pNxt = GetNext();
        pNxt->InvalidatePrt_();
        pNxt->InvalidatePos_();
        pNxt->InvalidatePage( pPage );
        if( pNxt->IsSctFrame() )
            pNxt = static_cast<SwSectionFrame*>(pNxt)->ContainsContent();
        if( pNxt && pNxt->IsTextFrame() && pNxt->IsInFootnote() )
            pNxt->Prepare( PREP_FTN, nullptr, false );
    }
 
    if ( getFrameArea().Height() )
        pParent->Grow( getFrameArea().Height() );
 
    if ( getFrameArea().Width() != pParent->getFramePrintArea().Width() )
        Prepare( PREP_FIXSIZE_CHG );
 
    if ( GetPrev() )
    {
        if ( IsFollow() )
            //I'm a direct follower of my master now
            static_cast<SwContentFrame*>(GetPrev())->Prepare( PREP_FOLLOW_FOLLOWS );
        else
        {
            if ( GetPrev()->getFrameArea().Height() !=
                 GetPrev()->getFramePrintArea().Height() + GetPrev()->getFramePrintArea().Top() )
            {
                // Take the border into account?
                GetPrev()->InvalidatePrt_();
            }
            // OD 18.02.2003 #104989# - force complete paint of previous frame,
            // if frame is inserted at the end of a section frame, in order to
            // get subsidiary lines repainted for the section.
            if ( pParent->IsSctFrame() && !GetNext() )
            {
                // force complete paint of previous frame, if new inserted frame
                // in the section is the last one.
                GetPrev()->SetCompletePaint();
            }
            GetPrev()->InvalidatePage( pPage );
        }
    }
    if ( IsInFootnote() )
    {
        SwFrame* pFrame = GetIndPrev();
        if( pFrame && pFrame->IsSctFrame() )
            pFrame = static_cast<SwSectionFrame*>(pFrame)->ContainsAny();
        if( pFrame )
            pFrame->Prepare( PREP_QUOVADIS, nullptr, false );
        if( !GetNext() )
        {
            pFrame = FindFootnoteFrame()->GetNext();
            if( pFrame && nullptr != (pFrame=static_cast<SwLayoutFrame*>(pFrame)->ContainsAny()) )
                pFrame->InvalidatePrt_();
        }
    }
 
    InvalidateLineNum_();
    SwFrame *pNxt = FindNextCnt();
    if ( pNxt  )
    {
        while ( pNxt && pNxt->IsInTab() )
        {
            if( nullptr != (pNxt = pNxt->FindTabFrame()) )
                pNxt = pNxt->FindNextCnt();
        }
        if ( pNxt )
        {
            pNxt->InvalidateLineNum_();
            if ( pNxt != GetNext() )
                pNxt->InvalidatePage();
        }
    }
}
 
void SwContentFrame::Cut()
{
    OSL_ENSURE( GetUpper(), "Cut without Upper()." );
 
    SwPageFrame *pPage = FindPageFrame();
    InvalidatePage( pPage );
    SwFrame *pFrame = GetIndPrev();
    if( pFrame )
    {
        if( pFrame->IsSctFrame() )
            pFrame = static_cast<SwSectionFrame*>(pFrame)->ContainsAny();
        if ( pFrame && pFrame->IsContentFrame() )
        {
            pFrame->InvalidatePrt_();
            if( IsInFootnote() )
                pFrame->Prepare( PREP_QUOVADIS, nullptr, false );
        }
        // #i26250# - invalidate printing area of previous
        // table frame.
        else if ( pFrame && pFrame->IsTabFrame() )
        {
            pFrame->InvalidatePrt();
        }
    }
 
    SwFrame *pNxt = FindNextCnt();
    if ( pNxt )
    {
        while ( pNxt && pNxt->IsInTab() )
        {
            if( nullptr != (pNxt = pNxt->FindTabFrame()) )
                pNxt = pNxt->FindNextCnt();
        }
        if ( pNxt )
        {
            pNxt->InvalidateLineNum_();
            if ( pNxt != GetNext() )
                pNxt->InvalidatePage();
        }
    }
 
    if( nullptr != (pFrame = GetIndNext()) )
    {
        // The old follow may have calculated a gap to the predecessor which
        // now becomes obsolete or different as it becomes the first one itself
        pFrame->InvalidatePrt_();
        pFrame->InvalidatePos_();
        pFrame->InvalidatePage( pPage );
        if( pFrame->IsSctFrame() )
        {
            pFrame = static_cast<SwSectionFrame*>(pFrame)->ContainsAny();
            if( pFrame )
            {
                pFrame->InvalidatePrt_();
                pFrame->InvalidatePos_();
                pFrame->InvalidatePage( pPage );
            }
        }
        if( pFrame && IsInFootnote() )
            pFrame->Prepare( PREP_ERGOSUM, nullptr, false );
        if( IsInSct() && !GetPrev() )
        {
            SwSectionFrame* pSct = FindSctFrame();
            if( !pSct->IsFollow() )
            {
                pSct->InvalidatePrt_();
                pSct->InvalidatePage( pPage );
            }
        }
    }
    else
    {
        InvalidateNextPos();
        //Someone needs to do the retouching: predecessor or upper
        if ( nullptr != (pFrame = GetPrev()) )
        {   pFrame->SetRetouche();
            pFrame->Prepare( PREP_WIDOWS_ORPHANS );
            pFrame->InvalidatePos_();
            pFrame->InvalidatePage( pPage );
        }
        // If I'm (was) the only ContentFrame in my upper, it has to do the
        // retouching. Also, perhaps a page became empty.
        else
        {   SwRootFrame *pRoot = getRootFrame();
            if ( pRoot )
            {
                pRoot->SetSuperfluous();
                GetUpper()->SetCompletePaint();
                GetUpper()->InvalidatePage( pPage );
            }
            if( IsInSct() )
            {
                SwSectionFrame* pSct = FindSctFrame();
                if( !pSct->IsFollow() )
                {
                    pSct->InvalidatePrt_();
                    pSct->InvalidatePage( pPage );
                }
            }
            // #i52253# The master table should take care
            // of removing the follow flow line.
            if ( IsInTab() )
            {
                SwTabFrame* pThisTab = FindTabFrame();
                SwTabFrame* pMasterTab = pThisTab && pThisTab->IsFollow() ? pThisTab->FindMaster() : nullptr;
                if ( pMasterTab )
                {
                    pMasterTab->InvalidatePos_();
                    pMasterTab->SetRemoveFollowFlowLinePending( true );
                }
            }
        }
    }
    //Remove first, then shrink the upper.
    SwLayoutFrame *pUp = GetUpper();
    RemoveFromLayout();
    if ( pUp )
    {
        SwSectionFrame *pSct = nullptr;
        if ( !pUp->Lower() &&
             ( ( pUp->IsFootnoteFrame() && !pUp->IsColLocked() ) ||
               ( pUp->IsInSct() &&
                 // #i29438#
                 // We have to consider the case that the section may be "empty"
                 // except from a temporary empty table frame.
                 // This can happen due to the new cell split feature.
                 !pUp->IsCellFrame() &&
                 // #126020# - adjust check for empty section
                 // #130797# - correct fix #126020#
                 !(pSct = pUp->FindSctFrame())->ContainsContent() &&
                 !pSct->ContainsAny( true ) ) ) )
        {
            if ( pUp->GetUpper() )
            {
 
                // prevent delete of <ColLocked> footnote frame
                if ( pUp->IsFootnoteFrame() && !pUp->IsColLocked())
                {
                    if( pUp->GetNext() && !pUp->GetPrev() )
                    {
                        SwFrame* pTmp = static_cast<SwLayoutFrame*>(pUp->GetNext())->ContainsAny();
                        if( pTmp )
                            pTmp->InvalidatePrt_();
                    }
                    if (!pUp->IsDeleteForbidden())
                    {
                        pUp->Cut();
                        SwFrame::DestroyFrame(pUp);
                    }
                }
                else
                {
 
                    if ( pSct->IsColLocked() || !pSct->IsInFootnote() ||
                         ( pUp->IsFootnoteFrame() && pUp->IsColLocked() ) )
                    {
                        pSct->DelEmpty( false );
                        // If a locked section may not be deleted then at least
                        // its size became invalid after removing its last
                        // content.
                        pSct->InvalidateSize_();
                    }
                    else
                    {
                        pSct->DelEmpty( true );
                        SwFrame::DestroyFrame(pSct);
                    }
                }
            }
        }
        else
        {
            SwRectFnSet aRectFnSet(this);
            long nFrameHeight = aRectFnSet.GetHeight(getFrameArea());
            if( nFrameHeight )
                pUp->Shrink( nFrameHeight );
        }
    }
}
 
void SwLayoutFrame::Paste( SwFrame* pParent, SwFrame* pSibling)
{
    OSL_ENSURE( pParent, "No parent for pasting." );
    OSL_ENSURE( pParent->IsLayoutFrame(), "Parent is ContentFrame." );
    OSL_ENSURE( pParent != this, "I'm the parent oneself." );
    OSL_ENSURE( pSibling != this, "I'm my own neighbour." );
    OSL_ENSURE( !GetPrev() && !GetNext() && !GetUpper(),
            "I'm still registered somewhere." );
 
    //Insert in the tree.
    InsertBefore( static_cast<SwLayoutFrame*>(pParent), pSibling );
 
    // OD 24.10.2002 #103517# - correct setting of variable <fnRect>
    // <fnRect> is used for the following:
    // (1) To invalidate the frame's size, if its size, which has to be the
    //      same as its upper/parent, differs from its upper's/parent's.
    // (2) To adjust/grow the frame's upper/parent, if it has a dimension in its
    //      size, which is not determined by its upper/parent.
    // Which size is which depends on the frame type and the layout direction
    // (vertical or horizontal).
    // There are the following cases:
    // (A) Header and footer frames both in vertical and in horizontal layout
    //      have to size the width to the upper/parent. A dimension in the height
    //      has to cause a adjustment/grow of the upper/parent.
    //      --> <fnRect> = fnRectHori
    // (B) Cell and column frames in vertical layout, the width has to be the
    //          same as upper/parent and a dimension in height causes adjustment/grow
    //          of the upper/parent.
    //          --> <fnRect> = fnRectHori
    //      in horizontal layout the other way around
    //          --> <fnRect> = fnRectVert
    // (C) Other frames in vertical layout, the height has to be the
    //          same as upper/parent and a dimension in width causes adjustment/grow
    //          of the upper/parent.
    //          --> <fnRect> = fnRectVert
    //      in horizontal layout the other way around
    //          --> <fnRect> = fnRectHori
    //SwRectFn fnRect = IsVertical() ? fnRectHori : fnRectVert;
    SwRectFn fnRect;
    if ( IsHeaderFrame() || IsFooterFrame() )
        fnRect = fnRectHori;
    else if ( IsCellFrame() || IsColumnFrame() )
        fnRect = GetUpper()->IsVertical() ? fnRectHori : ( GetUpper()->IsVertLR() ? fnRectVertL2R : fnRectVert );
    else
        fnRect = GetUpper()->IsVertical() ? ( GetUpper()->IsVertLR() ? fnRectVertL2R : fnRectVert ) : fnRectHori;
 
    if( (getFrameArea().*fnRect->fnGetWidth)() != (pParent->getFramePrintArea().*fnRect->fnGetWidth)())
        InvalidateSize_();
    InvalidatePos_();
    const SwPageFrame *pPage = FindPageFrame();
    InvalidatePage( pPage );
    if( !IsColumnFrame() )
    {
        SwFrame *pFrame = GetIndNext();
        if( nullptr != pFrame )
        {
            pFrame->InvalidatePos_();
            if( IsInFootnote() )
            {
                if( pFrame->IsSctFrame() )
                    pFrame = static_cast<SwSectionFrame*>(pFrame)->ContainsAny();
                if( pFrame )
                    pFrame->Prepare( PREP_ERGOSUM, nullptr, false );
            }
        }
        if ( IsInFootnote() && nullptr != ( pFrame = GetIndPrev() ) )
        {
            if( pFrame->IsSctFrame() )
                pFrame = static_cast<SwSectionFrame*>(pFrame)->ContainsAny();
            if( pFrame )
                pFrame->Prepare( PREP_QUOVADIS, nullptr, false );
        }
    }
 
    if( (getFrameArea().*fnRect->fnGetHeight)() )
    {
        // AdjustNeighbourhood is now also called in columns which are not
        // placed inside a frame
        SwNeighbourAdjust nAdjust = GetUpper()->IsFootnoteBossFrame() ?
                static_cast<SwFootnoteBossFrame*>(GetUpper())->NeighbourhoodAdjustment()
                : SwNeighbourAdjust::GrowShrink;
        SwTwips nGrow = (getFrameArea().*fnRect->fnGetHeight)();
        if( SwNeighbourAdjust::OnlyAdjust == nAdjust )
            AdjustNeighbourhood( nGrow );
        else
        {
            SwTwips nReal = 0;
            if( SwNeighbourAdjust::AdjustGrow == nAdjust )
                nReal = AdjustNeighbourhood( nGrow );
            if( nReal < nGrow )
                nReal += pParent->Grow( nGrow - nReal );
            if( SwNeighbourAdjust::GrowAdjust == nAdjust && nReal < nGrow )
                AdjustNeighbourhood( nGrow - nReal );
        }
    }
}
 
void SwLayoutFrame::Cut()
{
    if ( GetNext() )
        GetNext()->InvalidatePos_();
 
    SwRectFnSet aRectFnSet(this);
    SwTwips nShrink = aRectFnSet.GetHeight(getFrameArea());
 
    // Remove first, then shrink upper.
    SwLayoutFrame *pUp = GetUpper();
 
    // AdjustNeighbourhood is now also called in columns which are not
    // placed inside a frame.
 
    // Remove must not be called before an AdjustNeighbourhood, but it has to
    // be called before the upper-shrink-call, if the upper-shrink takes care
    // of its content.
    if ( pUp && nShrink )
    {
        if( pUp->IsFootnoteBossFrame() )
        {
            SwNeighbourAdjust nAdjust= static_cast<SwFootnoteBossFrame*>(pUp)->NeighbourhoodAdjustment();
            if( SwNeighbourAdjust::OnlyAdjust == nAdjust )
                AdjustNeighbourhood( -nShrink );
            else
            {
                SwTwips nReal = 0;
                if( SwNeighbourAdjust::AdjustGrow == nAdjust )
                    nReal = -AdjustNeighbourhood( -nShrink );
                if( nReal < nShrink )
                {
                    const SwTwips nOldHeight = aRectFnSet.GetHeight(getFrameArea());
 
                    // seems as if this needs to be forwarded to the SwFrame already here,
                    // changing to zero seems temporary anyways
                    {
                        SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
                        aRectFnSet.SetHeight( aFrm, 0 );
                    }
 
                    nReal += pUp->Shrink( nShrink - nReal );
 
                    {
                        SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
                        aRectFnSet.SetHeight( aFrm, nOldHeight );
                    }
                }
 
                if( SwNeighbourAdjust::GrowAdjust == nAdjust && nReal < nShrink )
                    AdjustNeighbourhood( nReal - nShrink );
            }
            RemoveFromLayout();
        }
        else
        {
            RemoveFromLayout();
            pUp->Shrink( nShrink );
        }
    }
    else
        RemoveFromLayout();
 
    if( pUp && !pUp->Lower() )
    {
        pUp->SetCompletePaint();
        pUp->InvalidatePage();
    }
}
 
SwTwips SwFrame::Grow( SwTwips nDist, bool bTst, bool bInfo )
{
    OSL_ENSURE( nDist >= 0, "Negative growth?" );
 
    PROTOCOL_ENTER( this, bTst ? PROT::GrowTest : PROT::Grow, DbgAction::NONE, &nDist )
 
    if ( nDist )
    {
        SwRectFnSet aRectFnSet(this);
 
        SwTwips nPrtHeight = aRectFnSet.GetHeight(getFramePrintArea());
        if( nPrtHeight > 0 && nDist > (LONG_MAX - nPrtHeight) )
            nDist = LONG_MAX - nPrtHeight;
 
        if ( IsFlyFrame() )
            return static_cast<SwFlyFrame*>(this)->Grow_( nDist, bTst );
        else if( IsSctFrame() )
            return static_cast<SwSectionFrame*>(this)->Grow_( nDist, bTst );
        else
        {
            const SwCellFrame* pThisCell = dynamic_cast<const SwCellFrame*>(this);
            if ( pThisCell )
            {
                const SwTabFrame* pTab = FindTabFrame();
 
                // NEW TABLES
                if ( pTab->IsVertical() != IsVertical() ||
                     pThisCell->GetLayoutRowSpan() < 1 )
                    return 0;
            }
 
            const SwTwips nReal = GrowFrame( nDist, bTst, bInfo );
            if( !bTst )
            {
                nPrtHeight = aRectFnSet.GetHeight(getFramePrintArea());
 
                SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this);
                aRectFnSet.SetHeight( aPrt, nPrtHeight + ( IsContentFrame() ? nDist : nReal ) );
            }
            return nReal;
        }
    }
    return 0;
}
 
SwTwips SwFrame::Shrink( SwTwips nDist, bool bTst, bool bInfo )
{
    OSL_ENSURE( nDist >= 0, "Negative reduction?" );
 
    PROTOCOL_ENTER( this, bTst ? PROT::ShrinkTest : PROT::Shrink, DbgAction::NONE, &nDist )
 
    if ( nDist )
    {
        if ( IsFlyFrame() )
            return static_cast<SwFlyFrame*>(this)->Shrink_( nDist, bTst );
        else if( IsSctFrame() )
            return static_cast<SwSectionFrame*>(this)->Shrink_( nDist, bTst );
        else
        {
            const SwCellFrame* pThisCell = dynamic_cast<const SwCellFrame*>(this);
            if ( pThisCell )
            {
                const SwTabFrame* pTab = FindTabFrame();
 
                // NEW TABLES
                if ( (pTab && pTab->IsVertical() != IsVertical()) ||
                     pThisCell->GetLayoutRowSpan() < 1 )
                    return 0;
            }
 
            SwRectFnSet aRectFnSet(this);
            SwTwips nReal = aRectFnSet.GetHeight(getFrameArea());
            ShrinkFrame( nDist, bTst, bInfo );
            nReal -= aRectFnSet.GetHeight(getFrameArea());
            if( !bTst )
            {
                const SwTwips nPrtHeight = aRectFnSet.GetHeight(getFramePrintArea());
                SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this);
                aRectFnSet.SetHeight( aPrt, nPrtHeight - ( IsContentFrame() ? nDist : nReal ) );
            }
            return nReal;
        }
    }
    return 0;
}
 
/** Adjust surrounding neighbourhood after insertion
 *
 * A Frame needs "normalization" if it is directly placed below a footnote boss (page/column) and its
 * size changes. There is always a frame that takes the maximum possible space (the frame that
 * contains the Body text) and zero or more frames which only take the space needed (header/footer
 * area, footnote container). If one of these frames changes, the body-text-frame has to grow or
 * shrink accordingly, even though it's fixed.
 *
 * !! Is it possible to do this in a generic way and not restrict it to the page and a distinct
 * frame which takes the maximum space (controlled using the FrameSize attribute)?
 * Problems:
 *   - What if multiple frames taking the maximum space are placed next to each other?
 *   - How is the maximum space calculated?
 *   - How small can those frames become?
 *
 * In any case, only a certain amount of space is allowed, so we never go below a minimum value for
 * the height of the body.
 *
 * @param nDiff the value around which the space has to be allocated
 */
SwTwips SwFrame::AdjustNeighbourhood( SwTwips nDiff, bool bTst )
{
    PROTOCOL_ENTER( this, PROT::AdjustN, DbgAction::NONE, &nDiff );
 
    if ( !nDiff || !GetUpper()->IsFootnoteBossFrame() ) // only inside pages/columns
        return 0;
 
    const SwViewShell *pSh = getRootFrame()->GetCurrShell();
    const bool bBrowse = pSh && pSh->GetViewOptions()->getBrowseMode();
 
    //The (Page-)Body only changes in BrowseMode, but only if it does not
    //contain columns.
    if ( IsPageBodyFrame() && (!bBrowse ||
          (static_cast<SwLayoutFrame*>(this)->Lower() &&
           static_cast<SwLayoutFrame*>(this)->Lower()->IsColumnFrame())) )
        return 0;
 
    //In BrowseView mode the PageFrame can handle some of the requests.
    long nBrowseAdd = 0;
    if ( bBrowse && GetUpper()->IsPageFrame() ) // only (Page-)BodyFrames
    {
        SwViewShell *pViewShell = getRootFrame()->GetCurrShell();
        SwLayoutFrame *pUp = GetUpper();
        long nChg;
        const long nUpPrtBottom = pUp->getFrameArea().Height() -
                                  pUp->getFramePrintArea().Height() - pUp->getFramePrintArea().Top();
        SwRect aInva( pUp->getFrameArea() );
        if ( pViewShell )
        {
            aInva.Pos().setX( pViewShell->VisArea().Left() );
            aInva.Width( pViewShell->VisArea().Width() );
        }
        if ( nDiff > 0 )
        {
            nChg = BROWSE_HEIGHT - pUp->getFrameArea().Height();
            nChg = std::min( nDiff, nChg );
 
            if ( !IsBodyFrame() )
            {
                SetCompletePaint();
                if ( !pViewShell || pViewShell->VisArea().Height() >= pUp->getFrameArea().Height() )
                {
                    //First minimize Body, it will grow again later.
                    SwFrame *pBody = static_cast<SwFootnoteBossFrame*>(pUp)->FindBodyCont();
                    const long nTmp = nChg - pBody->getFramePrintArea().Height();
                    if ( !bTst )
                    {
                        {
                            SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*pBody);
                            aFrm.Height(std::max( 0L, aFrm.Height() - nChg ));
                        }
 
                        pBody->InvalidatePrt_();
                        pBody->InvalidateSize_();
                        if ( pBody->GetNext() )
                            pBody->GetNext()->InvalidatePos_();
                        if ( !IsHeaderFrame() )
                            pBody->SetCompletePaint();
                    }
                    nChg = nTmp <= 0 ? 0 : nTmp;
                }
            }
 
            const long nTmp = nUpPrtBottom + 20;
            aInva.Top( aInva.Bottom() - nTmp );
            aInva.Height( nChg + nTmp );
        }
        else
        {
            //The page can shrink to 0. The first page keeps the same size like
            //VisArea.
            nChg = nDiff;
            long nInvaAdd = 0;
            if ( pViewShell && !pUp->GetPrev() &&
                 pUp->getFrameArea().Height() + nDiff < pViewShell->VisArea().Height() )
            {
                // This means that we have to invalidate adequately.
                nChg = pViewShell->VisArea().Height() - pUp->getFrameArea().Height();
                nInvaAdd = -(nDiff - nChg);
            }
 
            //Invalidate including bottom border.
            long nBorder = nUpPrtBottom + 20;
            nBorder -= nChg;
            aInva.Top( aInva.Bottom() - (nBorder+nInvaAdd) );
            if ( !IsBodyFrame() )
            {
                SetCompletePaint();
                if ( !IsHeaderFrame() )
                    static_cast<SwFootnoteBossFrame*>(pUp)->FindBodyCont()->SetCompletePaint();
            }
            //Invalidate the page because of the frames. Thereby the page becomes
            //the right size again if a frame didn't fit. This only works
            //randomly for paragraph bound frames otherwise (NotifyFlys).
            pUp->InvalidateSize();
        }
        if ( !bTst )
        {
            //Independent from nChg
            if ( pViewShell && aInva.HasArea() && pUp->GetUpper() )
                pViewShell->InvalidateWindows( aInva );
        }
        if ( !bTst && nChg )
        {
            {
                SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*pUp);
                aFrm.SSize().AdjustHeight(nChg );
            }
 
            {
                SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*pUp);
                aPrt.SSize().AdjustHeight(nChg );
            }
 
            if ( pViewShell )
                pViewShell->Imp()->SetFirstVisPageInvalid();
 
            if ( GetNext() )
                GetNext()->InvalidatePos_();
 
            //Trigger a repaint if necessary.
            SvxBrushItem aBack(pUp->GetFormat()->makeBackgroundBrushItem());
            const SvxGraphicPosition ePos = aBack.GetGraphicPos();
            if ( ePos != GPOS_NONE && ePos != GPOS_TILED )
                pViewShell->InvalidateWindows( pUp->getFrameArea() );
 
            if ( pUp->GetUpper() )
            {
                if ( pUp->GetNext() )
                    pUp->GetNext()->InvalidatePos();
 
                //Sad but true: during notify on ViewImp a Calc on the page and
                //its Lower may be called. The values should not be changed
                //because the caller takes care of the adjustment of Frame and
                //Prt.
                const long nOldFrameHeight = getFrameArea().Height();
                const long nOldPrtHeight = getFramePrintArea().Height();
                const bool bOldComplete = IsCompletePaint();
 
                if ( IsBodyFrame() )
                {
                    SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this);
                    aPrt.SSize().setHeight( nOldFrameHeight );
                }
 
                if ( pUp->GetUpper() )
                {
                    static_cast<SwRootFrame*>(pUp->GetUpper())->CheckViewLayout( nullptr, nullptr );
                }
 
                SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
                aFrm.SSize().setHeight( nOldFrameHeight );
 
                SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this);
                aPrt.SSize().setHeight( nOldPrtHeight );
 
                mbCompletePaint = bOldComplete;
            }
            if ( !IsBodyFrame() )
                pUp->InvalidateSize_();
            InvalidatePage( static_cast<SwPageFrame*>(pUp) );
        }
        nDiff -= nChg;
        if ( !nDiff )
            return nChg;
        else
            nBrowseAdd = nChg;
    }
 
    const SwFootnoteBossFrame *pBoss = static_cast<SwFootnoteBossFrame*>(GetUpper());
 
    SwTwips nReal = 0,
            nAdd  = 0;
    SwFrame *pFrame = nullptr;
    SwRectFnSet aRectFnSet(this);
 
    if( IsBodyFrame() )
    {
        if( IsInSct() )
        {
            SwSectionFrame *pSect = FindSctFrame();
            if( nDiff > 0 && pSect->IsEndnAtEnd() && GetNext() &&
                GetNext()->IsFootnoteContFrame() )
            {
                SwFootnoteContFrame* pCont = static_cast<SwFootnoteContFrame*>(GetNext());
                SwTwips nMinH = 0;
                SwFootnoteFrame* pFootnote = static_cast<SwFootnoteFrame*>(pCont->Lower());
                bool bFootnote = false;
                while( pFootnote )
                {
                    if( !pFootnote->GetAttr()->GetFootnote().IsEndNote() )
                    {
                        nMinH += aRectFnSet.GetHeight(pFootnote->getFrameArea());
                        bFootnote = true;
                    }
                    pFootnote = static_cast<SwFootnoteFrame*>(pFootnote->GetNext());
                }
                if( bFootnote )
                    nMinH += aRectFnSet.GetTop(pCont->getFramePrintArea());
                nReal = aRectFnSet.GetHeight(pCont->getFrameArea()) - nMinH;
                if( nReal > nDiff )
                    nReal = nDiff;
                if( nReal > 0 )
                    pFrame = GetNext();
                else
                    nReal = 0;
            }
            if( !bTst && !pSect->IsColLocked() )
                pSect->InvalidateSize();
        }
        if( !pFrame )
            return nBrowseAdd;
    }
    else
    {
        const bool bFootnotePage = pBoss->IsPageFrame() && static_cast<const SwPageFrame*>(pBoss)->IsFootnotePage();
        if ( bFootnotePage && !IsFootnoteContFrame() )
            pFrame = const_cast<SwFrame*>(static_cast<SwFrame const *>(pBoss->FindFootnoteCont()));
        if ( !pFrame )
            pFrame = const_cast<SwFrame*>(static_cast<SwFrame const *>(pBoss->FindBodyCont()));
 
        if ( !pFrame )
            return 0;
 
        //If not one is found, everything else is solved.
        nReal = aRectFnSet.GetHeight(pFrame->getFrameArea());
        if( nReal > nDiff )
            nReal = nDiff;
        if( !bFootnotePage )
        {
            //Respect the minimal boundary!
            if( nReal )
            {
                const SwTwips nMax = pBoss->GetVarSpace();
                if ( nReal > nMax )
                    nReal = nMax;
            }
            if( !IsFootnoteContFrame() && nDiff > nReal &&
                pFrame->GetNext() && pFrame->GetNext()->IsFootnoteContFrame()
                && ( pFrame->GetNext()->IsVertical() == IsVertical() )
                )
            {
                //If the Body doesn't return enough, we look for a footnote, if
                //there is one, we steal there accordingly.
                const SwTwips nAddMax = aRectFnSet.GetHeight(pFrame->GetNext()->getFrameArea());
                nAdd = nDiff - nReal;
                if ( nAdd > nAddMax )
                    nAdd = nAddMax;
                if ( !bTst )
                {
                    {
                        SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*pFrame->GetNext());
                        aRectFnSet.SetHeight(aFrm, nAddMax-nAdd);
 
                        if( aRectFnSet.IsVert() && !aRectFnSet.IsVertL2R() )
                        {
                            aFrm.Pos().AdjustX(nAdd );
                        }
                    }
 
                    pFrame->GetNext()->InvalidatePrt();
 
                    if ( pFrame->GetNext()->GetNext() )
                    {
                        pFrame->GetNext()->GetNext()->InvalidatePos_();
                    }
                }
            }
        }
    }
 
    if ( !bTst && nReal )
    {
        SwTwips nTmp = aRectFnSet.GetHeight(pFrame->getFrameArea());
 
        {
            SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*pFrame);
            aRectFnSet.SetHeight( aFrm, nTmp - nReal );
 
            if( aRectFnSet.IsVert() && !aRectFnSet.IsVertL2R() )
            {
                aFrm.Pos().AdjustX(nReal );
            }
        }
 
        pFrame->InvalidatePrt();
 
        if ( pFrame->GetNext() )
            pFrame->GetNext()->InvalidatePos_();
 
        if( nReal < 0 && pFrame->IsInSct() )
        {
            SwLayoutFrame* pUp = pFrame->GetUpper();
            if( pUp && nullptr != ( pUp = pUp->GetUpper() ) && pUp->IsSctFrame() &&
                !pUp->IsColLocked() )
                pUp->InvalidateSize();
        }
        if( ( IsHeaderFrame() || IsFooterFrame() ) && pBoss->GetDrawObjs() )
        {
            const SwSortedObjs &rObjs = *pBoss->GetDrawObjs();
            OSL_ENSURE( pBoss->IsPageFrame(), "Header/Footer out of page?" );
            for (SwAnchoredObject* pAnchoredObj : rObjs)
            {
                if ( dynamic_cast< const SwFlyFrame *>( pAnchoredObj ) !=  nullptr )
                {
                    SwFlyFrame* pFly = static_cast<SwFlyFrame*>(pAnchoredObj);
                    OSL_ENSURE( !pFly->IsFlyInContentFrame(), "FlyInCnt at Page?" );
                    const SwFormatVertOrient &rVert =
                                        pFly->GetFormat()->GetVertOrient();
                    // When do we have to invalidate?
                    // If a frame is aligned on a PageTextArea and the header
                    // changes a TOP, MIDDLE or NONE aligned frame needs to
                    // recalculate it's position; if the footer changes a BOTTOM
                    // or MIDDLE aligned frame needs to recalculate it's
                    // position.
                    if( ( rVert.GetRelationOrient() == text::RelOrientation::PRINT_AREA ||
                          rVert.GetRelationOrient() == text::RelOrientation::PAGE_PRINT_AREA )    &&
                        ((IsHeaderFrame() && rVert.GetVertOrient()!=text::VertOrientation::BOTTOM) ||
                         (IsFooterFrame() && rVert.GetVertOrient()!=text::VertOrientation::NONE &&
                          rVert.GetVertOrient() != text::VertOrientation::TOP)) )
                    {
                        pFly->InvalidatePos_();
                        pFly->Invalidate_();
                    }
                }
            }
        }
    }
    return (nBrowseAdd + nReal + nAdd);
}
 
/** method to perform additional actions on an invalidation (2004-05-19 #i28701#) */
void SwFrame::ActionOnInvalidation( const InvalidationType )
{
    // default behaviour is to perform no additional action
}
 
/** method to determine, if an invalidation is allowed (2004-05-19 #i28701#) */
bool SwFrame::InvalidationAllowed( const InvalidationType ) const
{
    // default behaviour is to allow invalidation
    return true;
}
 
void SwFrame::ImplInvalidateSize()
{
    if ( InvalidationAllowed( INVALID_SIZE ) )
    {
        setFrameAreaSizeValid(false);
 
        if ( IsFlyFrame() )
            static_cast<SwFlyFrame*>(this)->Invalidate_();
        else
            InvalidatePage();
 
        // OD 2004-05-19 #i28701#
        ActionOnInvalidation( INVALID_SIZE );
    }
}
 
void SwFrame::ImplInvalidatePrt()
{
    if ( InvalidationAllowed( INVALID_PRTAREA ) )
    {
        setFramePrintAreaValid(false);
 
        if ( IsFlyFrame() )
            static_cast<SwFlyFrame*>(this)->Invalidate_();
        else
            InvalidatePage();
 
        // OD 2004-05-19 #i28701#
        ActionOnInvalidation( INVALID_PRTAREA );
    }
}
 
void SwFrame::ImplInvalidatePos()
{
    if ( InvalidationAllowed( INVALID_POS ) )
    {
        setFrameAreaPositionValid(false);
 
        if ( IsFlyFrame() )
        {
            static_cast<SwFlyFrame*>(this)->Invalidate_();
        }
        else
        {
            InvalidatePage();
        }
 
        // OD 2004-05-19 #i28701#
        ActionOnInvalidation( INVALID_POS );
    }
}
 
void SwFrame::ImplInvalidateLineNum()
{
    if ( InvalidationAllowed( INVALID_LINENUM ) )
    {
        mbValidLineNum = false;
        OSL_ENSURE( IsTextFrame(), "line numbers are implemented for text only" );
        InvalidatePage();
 
        // OD 2004-05-19 #i28701#
        ActionOnInvalidation( INVALID_LINENUM );
    }
}
 
void SwFrame::ReinitializeFrameSizeAttrFlags()
{
    const SwFormatFrameSize &rFormatSize = GetAttrSet()->GetFrameSize();
    if ( ATT_VAR_SIZE == rFormatSize.GetHeightSizeType() ||
         ATT_MIN_SIZE == rFormatSize.GetHeightSizeType())
    {
        mbFixSize = false;
        if ( GetType() & (SwFrameType::Header | SwFrameType::Footer | SwFrameType::Row) )
        {
            SwFrame *pFrame = static_cast<SwLayoutFrame*>(this)->Lower();
            while ( pFrame )
            {   pFrame->InvalidateSize_();
                pFrame->InvalidatePrt_();
                pFrame = pFrame->GetNext();
            }
            SwContentFrame *pCnt = static_cast<SwLayoutFrame*>(this)->ContainsContent();
            // #i36991# - be save.
            // E.g., a row can contain *no* content.
            if ( pCnt )
            {
                pCnt->InvalidatePage();
                do
                {
                    pCnt->Prepare( PREP_ADJUST_FRM );
                    pCnt->InvalidateSize_();
                    pCnt = pCnt->GetNextContentFrame();
                } while ( static_cast<SwLayoutFrame*>(this)->IsAnLower( pCnt ) );
            }
        }
    }
    else if ( rFormatSize.GetHeightSizeType() == ATT_FIX_SIZE )
    {
        if( IsVertical() )
            ChgSize( Size( rFormatSize.GetWidth(), getFrameArea().Height()));
        else
            ChgSize( Size( getFrameArea().Width(), rFormatSize.GetHeight()));
    }
}
 
void SwFrame::ValidateThisAndAllLowers( const sal_uInt16 nStage )
{
    // Stage 0: Only validate frames. Do not process any objects.
    // Stage 1: Only validate fly frames and all of their contents.
    // Stage 2: Validate all.
 
    const bool bOnlyObject = 1 == nStage;
    const bool bIncludeObjects = 1 <= nStage;
 
    if ( !bOnlyObject || dynamic_cast< const SwFlyFrame *>( this ) !=  nullptr )
    {
        setFrameAreaSizeValid(true);
        setFramePrintAreaValid(true);
        setFrameAreaPositionValid(true);
    }
 
    if ( bIncludeObjects )
    {
        const SwSortedObjs* pObjs = GetDrawObjs();
        if ( pObjs )
        {
            const size_t nCnt = pObjs->size();
            for ( size_t i = 0; i < nCnt; ++i )
            {
                SwAnchoredObject* pAnchObj = (*pObjs)[i];
                if ( dynamic_cast< const SwFlyFrame *>( pAnchObj ) !=  nullptr )
                    static_cast<SwFlyFrame*>(pAnchObj)->ValidateThisAndAllLowers( 2 );
                else if ( dynamic_cast< const SwAnchoredDrawObject *>( pAnchObj ) !=  nullptr )
                    static_cast<SwAnchoredDrawObject*>(pAnchObj)->ValidateThis();
            }
        }
    }
 
    if ( IsLayoutFrame() )
    {
        SwFrame* pLower = static_cast<SwLayoutFrame*>(this)->Lower();
        while ( pLower )
        {
            pLower->ValidateThisAndAllLowers( nStage );
            pLower = pLower->GetNext();
        }
    }
}
 
SwTwips SwContentFrame::GrowFrame( SwTwips nDist, bool bTst, bool bInfo )
{
    SwRectFnSet aRectFnSet(this);
 
    SwTwips nFrameHeight = aRectFnSet.GetHeight(getFrameArea());
    if( nFrameHeight > 0 &&
         nDist > (LONG_MAX - nFrameHeight ) )
        nDist = LONG_MAX - nFrameHeight;
 
    const SwViewShell *pSh = getRootFrame()->GetCurrShell();
    const bool bBrowse = pSh && pSh->GetViewOptions()->getBrowseMode();
    SwFrameType nTmpType = SwFrameType::Cell | SwFrameType::Column;
    if (bBrowse)
        nTmpType |= SwFrameType::Body;
    if( !(GetUpper()->GetType() & nTmpType) && GetUpper()->HasFixSize() )
    {
        if ( !bTst )
        {
            {
                SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
                aRectFnSet.SetHeight( aFrm, nFrameHeight + nDist );
 
                if( IsVertical() && !IsVertLR() )
                {
                    aFrm.Pos().AdjustX( -nDist );
                }
            }
 
            if ( GetNext() )
            {
                GetNext()->InvalidatePos();
            }
            // #i28701# - Due to the new object positioning the
            // frame on the next page/column can flow backward (e.g. it was moved forward
            // due to the positioning of its objects ). Thus, invalivate this next frame,
            // if document compatibility option 'Consider wrapping style influence on
            // object positioning' is ON.
            else if ( GetUpper()->GetFormat()->getIDocumentSettingAccess().get(DocumentSettingId::CONSIDER_WRAP_ON_OBJECT_POSITION) )
            {
                InvalidateNextPos();
            }
        }
        return 0;
    }
 
    SwTwips nReal = aRectFnSet.GetHeight(GetUpper()->getFramePrintArea());
    SwFrame *pFrame = GetUpper()->Lower();
    while( pFrame && nReal > 0 )
    {   nReal -= aRectFnSet.GetHeight(pFrame->getFrameArea());
        pFrame = pFrame->GetNext();
    }
 
    if ( !bTst )
    {
        //Contents are always resized to the wished value.
        long nOld = aRectFnSet.GetHeight(getFrameArea());
 
        {
            SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
 
            aRectFnSet.SetHeight( aFrm, nOld + nDist );
 
            if( IsVertical()&& !IsVertLR() )
            {
                aFrm.Pos().AdjustX( -nDist );
            }
        }
 
        SwTabFrame *pTab = (nOld && IsInTab()) ? FindTabFrame() : nullptr;
        if (pTab)
        {
            if ( pTab->GetTable()->GetHTMLTableLayout() &&
                 !pTab->IsJoinLocked() &&
                 !pTab->GetFormat()->GetDoc()->GetDocShell()->IsReadOnly() )
            {
                pTab->InvalidatePos();
                pTab->SetResizeHTMLTable();
            }
        }
    }
 
    //Only grow Upper if necessary.
    if ( nReal < nDist )
    {
        if( GetUpper() )
        {
            if( bTst || !GetUpper()->IsFooterFrame() )
                nReal = GetUpper()->Grow( nDist - std::max<long>(nReal, 0),
                                          bTst, bInfo );
            else
            {
                nReal = 0;
                GetUpper()->InvalidateSize();
            }
        }
        else
            nReal = 0;
    }
    else
        nReal = nDist;
 
    // #i28701# - Due to the new object positioning the
    // frame on the next page/column can flow backward (e.g. it was moved forward
    // due to the positioning of its objects ). Thus, invalivate this next frame,
    // if document compatibility option 'Consider wrapping style influence on
    // object positioning' is ON.
    if ( !bTst )
    {
        if ( GetNext() )
        {
            GetNext()->InvalidatePos();
        }
        else if ( GetUpper()->GetFormat()->getIDocumentSettingAccess().get(DocumentSettingId::CONSIDER_WRAP_ON_OBJECT_POSITION) )
        {
            InvalidateNextPos();
        }
    }
 
    return nReal;
}
 
SwTwips SwContentFrame::ShrinkFrame( SwTwips nDist, bool bTst, bool bInfo )
{
    SwRectFnSet aRectFnSet(this);
    OSL_ENSURE( nDist >= 0, "nDist < 0" );
    OSL_ENSURE( nDist <= aRectFnSet.GetHeight(getFrameArea()),
            "nDist > than current size." );
 
    if ( !bTst )
    {
        SwTwips nRstHeight;
        if( GetUpper() )
            nRstHeight = aRectFnSet.BottomDist( getFrameArea(), aRectFnSet.GetPrtBottom(*GetUpper()) );
        else
            nRstHeight = 0;
        if( nRstHeight < 0 )
        {
            SwTwips nNextHeight = 0;
            if( GetUpper()->IsSctFrame() && nDist > LONG_MAX/2 )
            {
                SwFrame *pNxt = GetNext();
                while( pNxt )
                {
                    nNextHeight += aRectFnSet.GetHeight(pNxt->getFrameArea());
                    pNxt = pNxt->GetNext();
                }
            }
            nRstHeight = nDist + nRstHeight - nNextHeight;
        }
        else
        {
            nRstHeight = nDist;
        }
 
        {
            SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
            aRectFnSet.SetHeight( aFrm, aRectFnSet.GetHeight(aFrm) - nDist );
 
            if( IsVertical() && !IsVertLR() )
            {
                aFrm.Pos().AdjustX(nDist );
            }
        }
 
        nDist = nRstHeight;
        SwTabFrame *pTab = IsInTab() ? FindTabFrame() : nullptr;
        if (pTab)
        {
            if ( pTab->GetTable()->GetHTMLTableLayout() &&
                 !pTab->IsJoinLocked() &&
                 !pTab->GetFormat()->GetDoc()->GetDocShell()->IsReadOnly() )
            {
                pTab->InvalidatePos();
                pTab->SetResizeHTMLTable();
            }
        }
    }
 
    SwTwips nReal;
    if( GetUpper() && nDist > 0 )
    {
        if( bTst || !GetUpper()->IsFooterFrame() )
            nReal = GetUpper()->Shrink( nDist, bTst, bInfo );
        else
        {
            nReal = 0;
 
            // #108745# Sorry, dear old footer friend, I'm not gonna invalidate you,
            // if there are any objects anchored inside your content, which
            // overlap with the shrinking frame.
            // This may lead to a footer frame that is too big, but this is better
            // than looping.
            // #109722# : The fix for #108745# was too strict.
 
            bool bInvalidate = true;
            const SwRect aRect( getFrameArea() );
            const SwPageFrame* pPage = FindPageFrame();
            const SwSortedObjs* pSorted = pPage ? pPage->GetSortedObjs() : nullptr;
            if( pSorted )
            {
                for (SwAnchoredObject* pAnchoredObj : *pSorted)
                {
                    const SwRect aBound( pAnchoredObj->GetObjRectWithSpaces() );
 
                    if( aBound.Left() > aRect.Right() )
                        continue;
 
                    if( aBound.IsOver( aRect ) )
                    {
                        const SwFrameFormat& rFormat = pAnchoredObj->GetFrameFormat();
                        if( css::text::WrapTextMode_THROUGH != rFormat.GetSurround().GetSurround() )
                        {
                            const SwFrame* pAnchor = pAnchoredObj->GetAnchorFrame();
                            if ( pAnchor && pAnchor->FindFooterOrHeader() == GetUpper() )
                            {
                                bInvalidate = false;
                                break;
                            }
                        }
                    }
                }
            }
 
            if ( bInvalidate )
                GetUpper()->InvalidateSize();
        }
    }
    else
        nReal = 0;
 
    if ( !bTst )
    {
        //The position of the next Frame changes for sure.
        InvalidateNextPos();
 
        //If I don't have a successor I have to do the retouch by myself.
        if ( !GetNext() )
            SetRetouche();
    }
    return nReal;
}
 
void SwContentFrame::Modify( const SfxPoolItem* pOld, const SfxPoolItem * pNew )
{
    sal_uInt8 nInvFlags = 0;
 
    if( pNew && RES_ATTRSET_CHG == pNew->Which() && pOld )
    {
        SfxItemIter aNIter( *static_cast<const SwAttrSetChg*>(pNew)->GetChgSet() );
        SfxItemIter aOIter( *static_cast<const SwAttrSetChg*>(pOld)->GetChgSet() );
        SwAttrSetChg aOldSet( *static_cast<const SwAttrSetChg*>(pOld) );
        SwAttrSetChg aNewSet( *static_cast<const SwAttrSetChg*>(pNew) );
        while( true )
        {
            UpdateAttr_( aOIter.GetCurItem(),
                         aNIter.GetCurItem(), nInvFlags,
                         &aOldSet, &aNewSet );
            if( aNIter.IsAtEnd() )
                break;
            aNIter.NextItem();
            aOIter.NextItem();
        }
        if ( aOldSet.Count() || aNewSet.Count() )
            SwFrame::Modify( &aOldSet, &aNewSet );
    }
    else
        UpdateAttr_( pOld, pNew, nInvFlags );
 
    if ( nInvFlags == 0 )
        return;
 
    SwPageFrame *pPage = FindPageFrame();
    InvalidatePage( pPage );
    if ( nInvFlags & 0x01 )
        SetCompletePaint();
    if ( nInvFlags & 0x02 )
        InvalidatePos_();
    if ( nInvFlags & 0x04 )
        InvalidateSize_();
    if ( nInvFlags & 0x88 )
    {
        if( IsInSct() && !GetPrev() )
        {
            SwSectionFrame *pSect = FindSctFrame();
            if( pSect->ContainsAny() == this )
            {
                pSect->InvalidatePrt_();
                pSect->InvalidatePage( pPage );
            }
        }
        InvalidatePrt_();
    }
    SwFrame* pNextFrame = GetIndNext();
    if ( pNextFrame && nInvFlags & 0x10)
    {
        pNextFrame->InvalidatePrt_();
        pNextFrame->InvalidatePage( pPage );
    }
    if ( pNextFrame && nInvFlags & 0x80 )
    {
        pNextFrame->SetCompletePaint();
    }
    if ( nInvFlags & 0x20 )
    {
        SwFrame* pPrevFrame = GetPrev();
        if ( pPrevFrame )
        {
            pPrevFrame->InvalidatePrt_();
            pPrevFrame->InvalidatePage( pPage );
        }
    }
    if ( nInvFlags & 0x40 )
        InvalidateNextPos();
 
}
 
void SwContentFrame::UpdateAttr_( const SfxPoolItem* pOld, const SfxPoolItem* pNew,
                              sal_uInt8 &rInvFlags,
                            SwAttrSetChg *pOldSet, SwAttrSetChg *pNewSet )
{
    bool bClear = true;
    sal_uInt16 nWhich = pOld ? pOld->Which() : pNew ? pNew->Which() : 0;
    switch ( nWhich )
    {
        case RES_FMT_CHG:
            rInvFlags = 0xFF;
            SAL_FALLTHROUGH;
 
        case RES_PAGEDESC:                      //attribute changes (on/off)
            if ( IsInDocBody() && !IsInTab() )
            {
                rInvFlags |= 0x02;
                SwPageFrame *pPage = FindPageFrame();
                if ( !GetPrev() )
                    CheckPageDescs( pPage );
                if (GetPageDescItem().GetNumOffset())
                    static_cast<SwRootFrame*>(pPage->GetUpper())->SetVirtPageNum( true );
                SwDocPosUpdate aMsgHint( pPage->getFrameArea().Top() );
                pPage->GetFormat()->GetDoc()->getIDocumentFieldsAccess().UpdatePageFields( &aMsgHint );
            }
            break;
 
        case RES_UL_SPACE:
            {
                // OD 2004-02-18 #106629# - correction
                // Invalidation of the printing area of next frame, not only
                // for footnote content.
                if ( !GetIndNext() )
                {
                    SwFrame* pNxt = FindNext();
                    if ( pNxt )
                    {
                        SwPageFrame* pPg = pNxt->FindPageFrame();
                        pNxt->InvalidatePage( pPg );
                        pNxt->InvalidatePrt_();
                        if( pNxt->IsSctFrame() )
                        {
                            SwFrame* pCnt = static_cast<SwSectionFrame*>(pNxt)->ContainsAny();
                            if( pCnt )
                            {
                                pCnt->InvalidatePrt_();
                                pCnt->InvalidatePage( pPg );
                            }
                        }
                        pNxt->SetCompletePaint();
                    }
                }
                // OD 2004-03-17 #i11860#
                if ( GetIndNext() &&
                     !GetUpper()->GetFormat()->getIDocumentSettingAccess().get(DocumentSettingId::USE_FORMER_OBJECT_POS) )
                {
                    // OD 2004-07-01 #i28701# - use new method <InvalidateObjs(..)>
                    GetIndNext()->InvalidateObjs();
                }
                Prepare( PREP_UL_SPACE );   //TextFrame has to correct line spacing.
                rInvFlags |= 0x80;
                SAL_FALLTHROUGH;
            }
        case RES_LR_SPACE:
        case RES_BOX:
        case RES_SHADOW:
            Prepare( PREP_FIXSIZE_CHG );
            SwFrame::Modify( pOld, pNew );
            rInvFlags |= 0x30;
            break;
 
        case RES_BREAK:
            {
                rInvFlags |= 0x42;
                const IDocumentSettingAccess& rIDSA = GetUpper()->GetFormat()->getIDocumentSettingAccess();
                if( rIDSA.get(DocumentSettingId::PARA_SPACE_MAX) ||
                    rIDSA.get(DocumentSettingId::PARA_SPACE_MAX_AT_PAGES) )
                {
                    rInvFlags |= 0x1;
                    SwFrame* pNxt = FindNext();
                    if( pNxt )
                    {
                        SwPageFrame* pPg = pNxt->FindPageFrame();
                        pNxt->InvalidatePage( pPg );
                        pNxt->InvalidatePrt_();
                        if( pNxt->IsSctFrame() )
                        {
                            SwFrame* pCnt = static_cast<SwSectionFrame*>(pNxt)->ContainsAny();
                            if( pCnt )
                            {
                                pCnt->InvalidatePrt_();
                                pCnt->InvalidatePage( pPg );
                            }
                        }
                        pNxt->SetCompletePaint();
                    }
                }
            }
            break;
 
        // OD 2004-02-26 #i25029#
        case RES_PARATR_CONNECT_BORDER:
        {
            rInvFlags |= 0x01;
            if ( IsTextFrame() )
            {
                InvalidateNextPrtArea();
            }
            if ( !GetIndNext() && IsInTab() && IsInSplitTableRow() )
            {
                FindTabFrame()->InvalidateSize();
            }
        }
        break;
 
        case RES_PARATR_TABSTOP:
        case RES_CHRATR_SHADOWED:
        case RES_CHRATR_AUTOKERN:
        case RES_CHRATR_UNDERLINE:
        case RES_CHRATR_OVERLINE:
        case RES_CHRATR_KERNING:
        case RES_CHRATR_FONT:
        case RES_CHRATR_FONTSIZE:
        case RES_CHRATR_ESCAPEMENT:
        case RES_CHRATR_CONTOUR:
        case RES_PARATR_NUMRULE:
            rInvFlags |= 0x01;
            break;
 
        case RES_FRM_SIZE:
            rInvFlags |= 0x01;
            SAL_FALLTHROUGH;
 
        default:
            bClear = false;
    }
    if ( bClear )
    {
        if ( pOldSet || pNewSet )
        {
            if ( pOldSet )
                pOldSet->ClearItem( nWhich );
            if ( pNewSet )
                pNewSet->ClearItem( nWhich );
        }
        else
            SwFrame::Modify( pOld, pNew );
    }
}
 
SwLayoutFrame::SwLayoutFrame(SwFrameFormat *const pFormat, SwFrame *const pSib)
    : SwFrame(pFormat, pSib)
    , m_pLower(nullptr)
{
    const SwFormatFrameSize &rFormatSize = pFormat->GetFrameSize();
    if ( rFormatSize.GetHeightSizeType() == ATT_FIX_SIZE )
        mbFixSize = true;
}
 
// #i28701#
 
SwTwips SwLayoutFrame::InnerHeight() const
{
    const SwFrame* pCnt = Lower();
    if (!pCnt)
        return 0;
 
    SwRectFnSet aRectFnSet(this);
    SwTwips nRet = 0;
    if( pCnt->IsColumnFrame() || pCnt->IsCellFrame() )
    {
        do
        {
            SwTwips nTmp = static_cast<const SwLayoutFrame*>(pCnt)->InnerHeight();
            if( pCnt->isFramePrintAreaValid() )
                nTmp += aRectFnSet.GetHeight(pCnt->getFrameArea()) -
                        aRectFnSet.GetHeight(pCnt->getFramePrintArea());
            if( nRet < nTmp )
                nRet = nTmp;
            pCnt = pCnt->GetNext();
        } while ( pCnt );
    }
    else
    {
        do
        {
            nRet += aRectFnSet.GetHeight(pCnt->getFrameArea());
            if( pCnt->IsContentFrame() && static_cast<const SwTextFrame*>(pCnt)->IsUndersized() )
                nRet += static_cast<const SwTextFrame*>(pCnt)->GetParHeight() -
                        aRectFnSet.GetHeight(pCnt->getFramePrintArea());
            if( pCnt->IsLayoutFrame() && !pCnt->IsTabFrame() )
                nRet += static_cast<const SwLayoutFrame*>(pCnt)->InnerHeight() -
                        aRectFnSet.GetHeight(pCnt->getFramePrintArea());
            pCnt = pCnt->GetNext();
        } while( pCnt );
 
    }
    return nRet;
}
 
SwTwips SwLayoutFrame::GrowFrame( SwTwips nDist, bool bTst, bool bInfo )
{
    const SwViewShell *pSh = getRootFrame()->GetCurrShell();
    const bool bBrowse = pSh && pSh->GetViewOptions()->getBrowseMode();
    SwFrameType nTmpType = SwFrameType::Cell | SwFrameType::Column;
    if (bBrowse)
        nTmpType |= SwFrameType::Body;
    if( !(GetType() & nTmpType) && HasFixSize() )
        return 0;
 
    SwRectFnSet aRectFnSet(this);
    const SwTwips nFrameHeight = aRectFnSet.GetHeight(getFrameArea());
    const SwTwips nFramePos = getFrameArea().Pos().X();
 
    if ( nFrameHeight > 0 && nDist > (LONG_MAX - nFrameHeight) )
        nDist = LONG_MAX - nFrameHeight;
 
    SwTwips nMin = 0;
    if ( GetUpper() && !IsCellFrame() )
    {
        SwFrame *pFrame = GetUpper()->Lower();
        while( pFrame )
        {   nMin += aRectFnSet.GetHeight(pFrame->getFrameArea());
            pFrame = pFrame->GetNext();
        }
        nMin = aRectFnSet.GetHeight(GetUpper()->getFramePrintArea()) - nMin;
        if ( nMin < 0 )
            nMin = 0;
    }
 
    SwRect aOldFrame( getFrameArea() );
    bool bMoveAccFrame = false;
 
    bool bChgPos = IsVertical();
    if ( !bTst )
    {
        SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
        aRectFnSet.SetHeight( aFrm, nFrameHeight + nDist );
 
        if( bChgPos && !IsVertLR() )
        {
            aFrm.Pos().AdjustX( -nDist );
        }
 
        bMoveAccFrame = true;
    }
 
    SwTwips nReal = nDist - nMin;
    if ( nReal > 0 )
    {
        if ( GetUpper() )
        {   // AdjustNeighbourhood now only for the columns (but not in frames)
            SwNeighbourAdjust nAdjust = GetUpper()->IsFootnoteBossFrame() ?
                static_cast<SwFootnoteBossFrame*>(GetUpper())->NeighbourhoodAdjustment()
                : SwNeighbourAdjust::GrowShrink;
            if( SwNeighbourAdjust::OnlyAdjust == nAdjust )
                nReal = AdjustNeighbourhood( nReal, bTst );
            else
            {
                if( SwNeighbourAdjust::AdjustGrow == nAdjust )
                    nReal += AdjustNeighbourhood( nReal, bTst );
 
                SwTwips nGrow = 0;
                if( 0 < nReal )
                {
                    SwFrame* pToGrow = GetUpper();
                    // NEW TABLES
                    // A cell with a row span of > 1 is allowed to grow the
                    // line containing the end of the row span if it is
                    // located in the same table frame:
                    const SwCellFrame* pThisCell = dynamic_cast<const SwCellFrame*>(this);
                    if ( pThisCell && pThisCell->GetLayoutRowSpan() > 1 )
                    {
                        SwCellFrame& rEndCell = const_cast<SwCellFrame&>(pThisCell->FindStartEndOfRowSpanCell( false ));
                        if ( -1 == rEndCell.GetTabBox()->getRowSpan() )
                            pToGrow = rEndCell.GetUpper();
                        else
                            pToGrow = nullptr;
                    }
 
                    nGrow = pToGrow ? pToGrow->Grow( nReal, bTst, bInfo ) : 0;
                }
 
                if( SwNeighbourAdjust::GrowAdjust == nAdjust && nGrow < nReal )
                    nReal += AdjustNeighbourhood( nReal - nGrow, bTst );
 
                if ( IsFootnoteFrame() && (nGrow != nReal) && GetNext() )
                {
                    //Footnotes can replace their successor.
                    SwTwips nSpace = bTst ? 0 : -nDist;
                    const SwFrame *pFrame = GetUpper()->Lower();
                    do
                    {   nSpace += aRectFnSet.GetHeight(pFrame->getFrameArea());
                        pFrame = pFrame->GetNext();
                    } while ( pFrame != GetNext() );
                    nSpace = aRectFnSet.GetHeight(GetUpper()->getFramePrintArea()) -nSpace;
                    if ( nSpace < 0 )
                        nSpace = 0;
                    nSpace += nGrow;
                    if ( nReal > nSpace )
                        nReal = nSpace;
                    if ( nReal && !bTst )
                        static_cast<SwFootnoteFrame*>(this)->InvalidateNxtFootnoteCnts( FindPageFrame() );
                }
                else
                    nReal = nGrow;
            }
        }
        else
            nReal = 0;
 
        nReal += nMin;
    }
    else
        nReal = nDist;
 
    if ( !bTst )
    {
        if( nReal != nDist &&
            // NEW TABLES
            ( !IsCellFrame() || static_cast<SwCellFrame*>(this)->GetLayoutRowSpan() > 1 ) )
        {
            SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
            aRectFnSet.SetHeight( aFrm, nFrameHeight + nReal );
 
            if( bChgPos && !IsVertLR() )
            {
                aFrm.Pos().setX( nFramePos - nReal );
            }
 
            bMoveAccFrame = true;
        }
 
        if ( nReal )
        {
            SwPageFrame *pPage = FindPageFrame();
            if ( GetNext() )
            {
                GetNext()->InvalidatePos_();
                if ( GetNext()->IsContentFrame() )
                    GetNext()->InvalidatePage( pPage );
            }
            if ( !IsPageBodyFrame() )
            {
                InvalidateAll_();
                InvalidatePage( pPage );
            }
            if (!(GetType() & (SwFrameType::Row|SwFrameType::Tab|SwFrameType::FtnCont|SwFrameType::Page|SwFrameType::Root)))
                NotifyLowerObjs();
 
            if( IsCellFrame() )
                InvaPercentLowers( nReal );
 
            SvxBrushItem aBack(GetFormat()->makeBackgroundBrushItem());
            const SvxGraphicPosition ePos = aBack.GetGraphicPos();
            if ( GPOS_NONE != ePos && GPOS_TILED != ePos )
                SetCompletePaint();
        }
    }
 
    if( bMoveAccFrame && IsAccessibleFrame() )
    {
        SwRootFrame *pRootFrame = getRootFrame();
        if( pRootFrame && pRootFrame->IsAnyShellAccessible() &&
            pRootFrame->GetCurrShell() )
        {
            pRootFrame->GetCurrShell()->Imp()->MoveAccessibleFrame( this, aOldFrame );
        }
    }
    return nReal;
}
 
SwTwips SwLayoutFrame::ShrinkFrame( SwTwips nDist, bool bTst, bool bInfo )
{
    const SwViewShell *pSh = getRootFrame()->GetCurrShell();
    const bool bBrowse = pSh && pSh->GetViewOptions()->getBrowseMode();
    SwFrameType nTmpType = SwFrameType::Cell | SwFrameType::Column;
    if (bBrowse)
        nTmpType |= SwFrameType::Body;
 
    if (pSh && pSh->GetViewOptions()->IsWhitespaceHidden())
    {
        if (IsBodyFrame())
        {
            // Whitespace is hidden and this body frame will not shrink, as it
            // has a fix size.
            // Invalidate the page frame size, so in case the reason for the
            // shrink was that there is more whitespace on this page, the size
            // without whitespace will be recalculated correctly.
            SwPageFrame* pPageFrame = FindPageFrame();
            pPageFrame->InvalidateSize();
        }
    }
 
    if( !(GetType() & nTmpType) && HasFixSize() )
        return 0;
 
    OSL_ENSURE( nDist >= 0, "nDist < 0" );
    SwRectFnSet aRectFnSet(this);
    SwTwips nFrameHeight = aRectFnSet.GetHeight(getFrameArea());
    if ( nDist > nFrameHeight )
        nDist = nFrameHeight;
 
    SwTwips nMin = 0;
    bool bChgPos = IsVertical();
    if ( Lower() )
    {
        if( !Lower()->IsNeighbourFrame() )
        {   const SwFrame *pFrame = Lower();
            const long nTmp = aRectFnSet.GetHeight(getFramePrintArea());
            while( pFrame && nMin < nTmp )
            {   nMin += aRectFnSet.GetHeight(pFrame->getFrameArea());
                pFrame = pFrame->GetNext();
            }
        }
    }
    SwTwips nReal = nDist;
    SwTwips nMinDiff = aRectFnSet.GetHeight(getFramePrintArea()) - nMin;
    if( nReal > nMinDiff )
        nReal = nMinDiff;
    if( nReal <= 0 )
        return nDist;
 
    SwRect aOldFrame( getFrameArea() );
    bool bMoveAccFrame = false;
 
    SwTwips nRealDist = nReal;
    if ( !bTst )
    {
        SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
        aRectFnSet.SetHeight( aFrm, nFrameHeight - nReal );
 
        if( bChgPos && !IsVertLR() )
        {
            aFrm.Pos().AdjustX(nReal );
        }
 
        bMoveAccFrame = true;
    }
 
    SwNeighbourAdjust nAdjust = GetUpper() && GetUpper()->IsFootnoteBossFrame() ?
                   static_cast<SwFootnoteBossFrame*>(GetUpper())->NeighbourhoodAdjustment()
                   : SwNeighbourAdjust::GrowShrink;
 
    // AdjustNeighbourhood also in columns (but not in frames)
    if( SwNeighbourAdjust::OnlyAdjust == nAdjust )
    {
        if ( IsPageBodyFrame() && !bBrowse )
            nReal = nDist;
        else
        {   nReal = AdjustNeighbourhood( -nReal, bTst );
            nReal *= -1;
            if ( !bTst && IsBodyFrame() && nReal < nRealDist )
            {
                SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
                aRectFnSet.SetHeight( aFrm, aRectFnSet.GetHeight(aFrm) + nRealDist - nReal );
 
                if( bChgPos && !IsVertLR() )
                {
                    aFrm.Pos().AdjustX(nRealDist - nReal );
                }
 
                OSL_ENSURE( !IsAccessibleFrame(), "bMoveAccFrame has to be set!" );
            }
        }
    }
    else if( IsColumnFrame() || IsColBodyFrame() )
    {
        SwTwips nTmp = GetUpper()->Shrink( nReal, bTst, bInfo );
        if ( nTmp != nReal )
        {
            SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
            aRectFnSet.SetHeight( aFrm, aRectFnSet.GetHeight(aFrm) + nReal - nTmp );
 
            if( bChgPos && !IsVertLR() )
            {
                aFrm.Pos().AdjustX(nTmp - nReal );
            }
 
            OSL_ENSURE( !IsAccessibleFrame(), "bMoveAccFrame has to be set!" );
            nReal = nTmp;
        }
    }
    else
    {
        SwTwips nShrink = nReal;
        SwFrame* pToShrink = GetUpper();
        const SwCellFrame* pThisCell = dynamic_cast<const SwCellFrame*>(this);
        // NEW TABLES
        if ( pThisCell && pThisCell->GetLayoutRowSpan() > 1 )
        {
            SwCellFrame& rEndCell = const_cast<SwCellFrame&>(pThisCell->FindStartEndOfRowSpanCell( false ));
            pToShrink = rEndCell.GetUpper();
        }
 
        nReal = pToShrink ? pToShrink->Shrink( nShrink, bTst, bInfo ) : 0;
        if( ( SwNeighbourAdjust::GrowAdjust == nAdjust || SwNeighbourAdjust::AdjustGrow == nAdjust )
            && nReal < nShrink )
            AdjustNeighbourhood( nReal - nShrink );
    }
 
    if( bMoveAccFrame && IsAccessibleFrame() )
    {
        SwRootFrame *pRootFrame = getRootFrame();
        if( pRootFrame && pRootFrame->IsAnyShellAccessible() &&
            pRootFrame->GetCurrShell() )
        {
            pRootFrame->GetCurrShell()->Imp()->MoveAccessibleFrame( this, aOldFrame );
        }
    }
    if ( !bTst && (IsCellFrame() || IsColumnFrame() ? nReal : nRealDist) )
    {
        SwPageFrame *pPage = FindPageFrame();
        if ( GetNext() )
        {
            GetNext()->InvalidatePos_();
            if ( GetNext()->IsContentFrame() )
                GetNext()->InvalidatePage( pPage );
            if ( IsTabFrame() )
                static_cast<SwTabFrame*>(this)->SetComplete();
        }
        else
        {   if ( IsRetoucheFrame() )
                SetRetouche();
            if ( IsTabFrame() )
            {
                if( IsTabFrame() )
                    static_cast<SwTabFrame*>(this)->SetComplete();
                if ( Lower() )  // Can also be in the Join and be empty!
                    InvalidateNextPos();
            }
        }
        if ( !IsBodyFrame() )
        {
            InvalidateAll_();
            InvalidatePage( pPage );
            bool bCompletePaint = true;
            const SwFrameFormat* pFormat = GetFormat();
            if (pFormat)
            {
                SvxBrushItem aBack(pFormat->makeBackgroundBrushItem());
                const SvxGraphicPosition ePos = aBack.GetGraphicPos();
                if ( GPOS_NONE == ePos || GPOS_TILED == ePos )
                    bCompletePaint = false;
            }
            if (bCompletePaint)
                SetCompletePaint();
        }
 
        if (!(GetType() & (SwFrameType::Row|SwFrameType::Tab|SwFrameType::FtnCont|SwFrameType::Page|SwFrameType::Root)))
            NotifyLowerObjs();
 
        if( IsCellFrame() )
            InvaPercentLowers( nReal );
 
        SwContentFrame *pCnt;
        if( IsFootnoteFrame() && !static_cast<SwFootnoteFrame*>(this)->GetAttr()->GetFootnote().IsEndNote() &&
            ( GetFormat()->GetDoc()->GetFootnoteInfo().ePos != FTNPOS_CHAPTER ||
              ( IsInSct() && FindSctFrame()->IsFootnoteAtEnd() ) ) &&
              nullptr != (pCnt = static_cast<SwFootnoteFrame*>(this)->GetRefFromAttr() ) )
        {
            if ( pCnt->IsFollow() )
            {   // If we are in an other column/page than the frame with the
                // reference, we don't need to invalidate its master.
                SwFrame *pTmp = pCnt->FindFootnoteBossFrame(true) == FindFootnoteBossFrame(true)
                              ?  &pCnt->FindMaster()->GetFrame() : pCnt;
                pTmp->Prepare( PREP_ADJUST_FRM );
                pTmp->InvalidateSize();
            }
            else
                pCnt->InvalidatePos();
        }
    }
    return nReal;
}
 
/**
 * Changes the size of the directly subsidiary Frame's that have a fixed size, proportionally to the
 * size change of the PrtArea of the Frame's.
 *
 * The variable Frames are also proportionally adapted; they will grow/shrink again by themselves.
 */
void SwLayoutFrame::ChgLowersProp( const Size& rOldSize )
{
    // no change of lower properties for root frame or if no lower exists.
    if ( IsRootFrame() || !Lower() )
        return;
 
    // declare and init <SwFrame* pLowerFrame> with first lower
    SwFrame *pLowerFrame = Lower();
 
    // declare and init const booleans <bHeightChgd> and <bWidthChg>
    const bool bHeightChgd = rOldSize.Height() != getFramePrintArea().Height();
    const bool bWidthChgd  = rOldSize.Width()  != getFramePrintArea().Width();
 
    SwRectFnSet aRectFnSet(this);
 
    // This shortcut basically tries to handle only lower frames that
    // are affected by the size change. Otherwise much more lower frames
    // are invalidated.
    if ( !( aRectFnSet.IsVert() ? bHeightChgd : bWidthChgd ) &&
         ! Lower()->IsColumnFrame() &&
           ( ( IsBodyFrame() && IsInDocBody() && ( !IsInSct() || !FindSctFrame()->IsColLocked() ) ) ||
                // #i10826# Section frames without columns should not
                // invalidate all lowers!
               IsSctFrame() ) )
    {
        // Determine page frame the body frame resp. the section frame belongs to.
        SwPageFrame *pPage = FindPageFrame();
        // Determine last lower by traveling through them using <GetNext()>.
        // During travel check each section frame, if it will be sized to
        // maximum. If Yes, invalidate size of section frame and set
        // corresponding flags at the page.
        do
        {
            if( pLowerFrame->IsSctFrame() && static_cast<SwSectionFrame*>(pLowerFrame)->ToMaximize_() )
            {
                pLowerFrame->InvalidateSize_();
                pLowerFrame->InvalidatePage( pPage );
            }
            if( pLowerFrame->GetNext() )
                pLowerFrame = pLowerFrame->GetNext();
            else
                break;
        } while( true );
        // If found last lower is a section frame containing no section
        // (section frame isn't valid and will be deleted in the future),
        // travel backwards.
        while( pLowerFrame->IsSctFrame() && !static_cast<SwSectionFrame*>(pLowerFrame)->GetSection() &&
               pLowerFrame->GetPrev() )
            pLowerFrame = pLowerFrame->GetPrev();
        // If found last lower is a section frame, set <pLowerFrame> to its last
        // content, if the section frame is valid and is not sized to maximum.
        // Otherwise set <pLowerFrame> to NULL - In this case body frame only
        //      contains invalid section frames.
        if( pLowerFrame->IsSctFrame() )
            pLowerFrame = static_cast<SwSectionFrame*>(pLowerFrame)->GetSection() &&
                   !static_cast<SwSectionFrame*>(pLowerFrame)->ToMaximize( false ) ?
                   static_cast<SwSectionFrame*>(pLowerFrame)->FindLastContent() : nullptr;
 
        // continue with found last lower, probably the last content of a section
        if ( pLowerFrame )
        {
            // If <pLowerFrame> is in a table frame, set <pLowerFrame> to this table
            // frame and continue.
            if ( pLowerFrame->IsInTab() )
            {
                // OD 28.10.2002 #97265# - safeguard for setting <pLowerFrame> to
                // its table frame - check, if the table frame is also a lower
                // of the body frame, in order to assure that <pLowerFrame> is not
                // set to a frame, which is an *upper* of the body frame.
                SwFrame* pTableFrame = pLowerFrame->FindTabFrame();
                if ( IsAnLower( pTableFrame ) )
                {
                    pLowerFrame = pTableFrame;
                }
            }
            // Check, if variable size of body frame resp. section frame has grown
            // OD 28.10.2002 #97265# - correct check, if variable size has grown.
            SwTwips nOldHeight = aRectFnSet.IsVert() ? rOldSize.Width() : rOldSize.Height();
            if( nOldHeight < aRectFnSet.GetHeight(getFramePrintArea()) )
            {
                // If variable size of body|section frame has grown, only found
                // last lower and the position of the its next have to be invalidated.
                pLowerFrame->InvalidateAll_();
                pLowerFrame->InvalidatePage( pPage );
                if( !pLowerFrame->IsFlowFrame() ||
                    !SwFlowFrame::CastFlowFrame( pLowerFrame )->HasFollow() )
                    pLowerFrame->InvalidateNextPos( true );
                if ( pLowerFrame->IsTextFrame() )
                    static_cast<SwContentFrame*>(pLowerFrame)->Prepare( PREP_ADJUST_FRM );
            }
            else
            {
                // variable size of body|section frame has shrunk. Thus,
                // invalidate all lowers not matching the new body|section size
                // and the dedicated new last lower.
                if( aRectFnSet.IsVert() )
                {
                    SwTwips nBot = getFrameArea().Left() + getFramePrintArea().Left();
                    while ( pLowerFrame && pLowerFrame->GetPrev() && pLowerFrame->getFrameArea().Left() < nBot )
                    {
                        pLowerFrame->InvalidateAll_();
                        pLowerFrame->InvalidatePage( pPage );
                        pLowerFrame = pLowerFrame->GetPrev();
                    }
                }
                else
                {
                    SwTwips nBot = getFrameArea().Top() + getFramePrintArea().Bottom();
                    while ( pLowerFrame && pLowerFrame->GetPrev() && pLowerFrame->getFrameArea().Top() > nBot )
                    {
                        pLowerFrame->InvalidateAll_();
                        pLowerFrame->InvalidatePage( pPage );
                        pLowerFrame = pLowerFrame->GetPrev();
                    }
                }
                if ( pLowerFrame )
                {
                    pLowerFrame->InvalidateSize_();
                    pLowerFrame->InvalidatePage( pPage );
                    if ( pLowerFrame->IsTextFrame() )
                        static_cast<SwContentFrame*>(pLowerFrame)->Prepare( PREP_ADJUST_FRM );
                }
            }
            // #i41694# - improvement by removing duplicates
            if ( pLowerFrame )
            {
                if ( pLowerFrame->IsInSct() )
                {
                    // #i41694# - follow-up of issue #i10826#
                    // No invalidation of section frame, if it's the this.
                    SwFrame* pSectFrame = pLowerFrame->FindSctFrame();
                    if( pSectFrame != this && IsAnLower( pSectFrame ) )
                    {
                        pSectFrame->InvalidateSize_();
                        pSectFrame->InvalidatePage( pPage );
                    }
                }
            }
        }
        return;
    } // end of { special case }
 
    // Invalidate page for content only once.
    bool bInvaPageForContent = true;
 
    // Declare booleans <bFixChgd> and <bVarChgd>, indicating for text frame
    // adjustment, if fixed/variable size has changed.
    bool bFixChgd, bVarChgd;
    if( aRectFnSet.IsVert() == pLowerFrame->IsNeighbourFrame() )
    {
        bFixChgd = bWidthChgd;
        bVarChgd = bHeightChgd;
    }
    else
    {
        bFixChgd = bHeightChgd;
        bVarChgd = bWidthChgd;
    }
 
    // Declare const unsigned short <nFixWidth> and init it this frame types
    // which has fixed width in vertical respectively horizontal layout.
    // In vertical layout these are neighbour frames (cell and column frames),
    //      header frames and footer frames.
    // In horizontal layout these are all frames, which aren't neighbour frames.
    const SwFrameType nFixWidth = aRectFnSet.IsVert() ? (FRM_NEIGHBOUR | FRM_HEADFOOT)
                                   : ~SwFrameType(FRM_NEIGHBOUR);
 
    // Declare const unsigned short <nFixHeight> and init it this frame types
    // which has fixed height in vertical respectively horizontal layout.
    // In vertical layout these are all frames, which aren't neighbour frames,
    //      header frames, footer frames, body frames or foot note container frames.
    // In horizontal layout these are neighbour frames.
    const SwFrameType nFixHeight = aRectFnSet.IsVert() ? ~SwFrameType(FRM_NEIGHBOUR | FRM_HEADFOOT | FRM_BODYFTNC)
                                   : FRM_NEIGHBOUR;
 
    // Travel through all lowers using <GetNext()>
    while ( pLowerFrame )
    {
        if ( pLowerFrame->IsTextFrame() )
        {
            // Text frames will only be invalidated - prepare invalidation
            if ( bFixChgd )
                static_cast<SwContentFrame*>(pLowerFrame)->Prepare( PREP_FIXSIZE_CHG );
            if ( bVarChgd )
                static_cast<SwContentFrame*>(pLowerFrame)->Prepare( PREP_ADJUST_FRM );
        }
        else
        {
            // If lower isn't a table, row, cell or section frame, adjust its
            // frame size.
            const SwFrameType nLowerType = pLowerFrame->GetType();
            if ( !(nLowerType & (SwFrameType::Tab|SwFrameType::Row|SwFrameType::Cell|SwFrameType::Section)) )
            {
                if ( bWidthChgd )
                {
                    if( nLowerType & nFixWidth )
                    {
                        // Considering previous conditions:
                        // In vertical layout set width of column, header and
                        // footer frames to its upper width.
                        // In horizontal layout set width of header, footer,
                        // foot note container, foot note, body and no-text
                        // frames to its upper width.
                        SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*pLowerFrame);
                        aFrm.Width( getFramePrintArea().Width() );
                    }
                    else if( rOldSize.Width() && !pLowerFrame->IsFootnoteFrame() )
                    {
                        // Adjust frame width proportional, if lower isn't a
                        // foot note frame and condition <nLowerType & nFixWidth>
                        // isn't true.
                        // Considering previous conditions:
                        // In vertical layout these are foot note container,
                        // body and no-text frames.
                        // In horizontal layout these are column and no-text frames.
                        // OD 24.10.2002 #97265# - <double> calculation
                        // Perform <double> calculation of new width, if
                        // one of the coefficients is greater than 50000
                        SwTwips nNewWidth;
                        if ( (pLowerFrame->getFrameArea().Width() > 50000) ||
                             (getFramePrintArea().Width() > 50000) )
                        {
                            double nNewWidthTmp =
                                ( double(pLowerFrame->getFrameArea().Width())
                                  * double(getFramePrintArea().Width()) )
                                / double(rOldSize.Width());
                            nNewWidth = SwTwips(nNewWidthTmp);
                        }
                        else
                        {
                            nNewWidth =
                                (pLowerFrame->getFrameArea().Width() * getFramePrintArea().Width()) / rOldSize.Width();
                        }
 
                        SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*pLowerFrame);
                        aFrm.Width( nNewWidth );
                    }
                }
                if ( bHeightChgd )
                {
                    if( nLowerType & nFixHeight )
                    {
                        // Considering previous conditions:
                        // In vertical layout set height of foot note and
                        // no-text frames to its upper height.
                        // In horizontal layout set height of column frames
                        // to its upper height.
                        SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*pLowerFrame);
                        aFrm.Height( getFramePrintArea().Height() );
                    }
                    // OD 01.10.2002 #102211#
                    // add conditions <!pLowerFrame->IsHeaderFrame()> and
                    // <!pLowerFrame->IsFooterFrame()> in order to avoid that
                    // the <Grow> of header or footer are overwritten.
                    // NOTE: Height of header/footer frame is determined by contents.
                    else if ( rOldSize.Height() &&
                              !pLowerFrame->IsFootnoteFrame() &&
                              !pLowerFrame->IsHeaderFrame() &&
                              !pLowerFrame->IsFooterFrame()
                            )
                    {
                        // Adjust frame height proportional, if lower isn't a
                        // foot note, a header or a footer frame and
                        // condition <nLowerType & nFixHeight> isn't true.
                        // Considering previous conditions:
                        // In vertical layout these are column, foot note container,
                        // body and no-text frames.
                        // In horizontal layout these are column, foot note
                        // container, body and no-text frames.
 
                        // OD 29.10.2002 #97265# - special case for page lowers
                        // The page lowers that have to be adjusted on page height
                        // change are the body frame and the foot note container
                        // frame.
                        // In vertical layout the height of both is directly
                        // adjusted to the page height change.
                        // In horizontal layout the height of the body frame is
                        // directly adjusted to the page height change and the
                        // foot note frame height isn't touched, because its
                        // determined by its content.
                        // OD 31.03.2003 #108446# - apply special case for page
                        // lowers - see description above - also for section columns.
                        if ( IsPageFrame() ||
                             ( IsColumnFrame() && IsInSct() )
                           )
                        {
                            OSL_ENSURE( pLowerFrame->IsBodyFrame() || pLowerFrame->IsFootnoteContFrame(),
                                    "ChgLowersProp - only for body or foot note container" );
                            if ( pLowerFrame->IsBodyFrame() || pLowerFrame->IsFootnoteContFrame() )
                            {
                                if ( IsVertical() || pLowerFrame->IsBodyFrame() )
                                {
                                    SwTwips nNewHeight =
                                            pLowerFrame->getFrameArea().Height() +
                                            ( getFramePrintArea().Height() - rOldSize.Height() );
                                    if ( nNewHeight < 0)
                                    {
                                        // OD 01.04.2003 #108446# - adjust assertion condition and text
                                        OSL_ENSURE( !( IsPageFrame() &&
                                                   (pLowerFrame->getFrameArea().Height()>0) &&
                                                   (pLowerFrame->isFrameAreaDefinitionValid()) ),
                                                    "ChgLowersProg - negative height for lower.");
                                        nNewHeight = 0;
                                    }
 
                                    SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*pLowerFrame);
                                    aFrm.Height( nNewHeight );
                                }
                            }
                        }
                        else
                        {
                            SwTwips nNewHeight;
                            // OD 24.10.2002 #97265# - <double> calculation
                            // Perform <double> calculation of new height, if
                            // one of the coefficients is greater than 50000
                            if ( (pLowerFrame->getFrameArea().Height() > 50000) ||
                                 (getFramePrintArea().Height() > 50000) )
                            {
                                double nNewHeightTmp =
                                    ( double(pLowerFrame->getFrameArea().Height())
                                      * double(getFramePrintArea().Height()) )
                                    / double(rOldSize.Height());
                                nNewHeight = SwTwips(nNewHeightTmp);
                            }
                            else
                            {
                                nNewHeight = ( pLowerFrame->getFrameArea().Height()
                                             * getFramePrintArea().Height() ) / rOldSize.Height();
                            }
                            if( !pLowerFrame->GetNext() )
                            {
                                SwTwips nSum = getFramePrintArea().Height();
                                SwFrame* pTmp = Lower();
                                while( pTmp->GetNext() )
                                {
                                    if( !pTmp->IsFootnoteContFrame() || !pTmp->IsVertical() )
                                        nSum -= pTmp->getFrameArea().Height();
                                    pTmp = pTmp->GetNext();
                                }
                                if( nSum - nNewHeight == 1 &&
                                    nSum == pLowerFrame->getFrameArea().Height() )
                                    nNewHeight = nSum;
                            }
 
                            SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*pLowerFrame);
                            aFrm.Height( nNewHeight );
                        }
                    }
                }
            }
        } // end of else { NOT text frame }
 
        pLowerFrame->InvalidateAll_();
        if ( bInvaPageForContent && pLowerFrame->IsContentFrame() )
        {
            pLowerFrame->InvalidatePage();
            bInvaPageForContent = false;
        }
 
        if ( !pLowerFrame->GetNext() && pLowerFrame->IsRetoucheFrame() )
        {
            //If a growth took place and the subordinate elements can retouch
            //itself (currently Tabs, Sections and Content) we trigger it.
            if ( rOldSize.Height() < getFramePrintArea().SSize().Height() ||
                 rOldSize.Width() < getFramePrintArea().SSize().Width() )
                pLowerFrame->SetRetouche();
        }
        pLowerFrame = pLowerFrame->GetNext();
    }
 
    // Finally adjust the columns if width is set to auto
    // Possible optimization: execute this code earlier in this function and
    // return???
    if ( ( (aRectFnSet.IsVert() && bHeightChgd) || (! aRectFnSet.IsVert() && bWidthChgd) ) &&
           Lower()->IsColumnFrame() )
    {
        // get column attribute
        const SwFormatCol* pColAttr = nullptr;
        if ( IsPageBodyFrame() )
        {
            OSL_ENSURE( GetUpper()->IsPageFrame(), "Upper is not page frame" );
            pColAttr = &GetUpper()->GetFormat()->GetCol();
        }
        else
        {
            OSL_ENSURE( IsFlyFrame() || IsSctFrame(), "Columns not in fly or section" );
            pColAttr = &GetFormat()->GetCol();
        }
 
        if ( pColAttr->IsOrtho() && pColAttr->GetNumCols() > 1 )
            AdjustColumns( pColAttr, false );
    }
}
 
/** "Formats" the Frame; Frame and PrtArea.
 *
 * The Fixsize is not set here.
 */
void SwLayoutFrame::Format( vcl::RenderContext* /*pRenderContext*/, const SwBorderAttrs *pAttrs )
{
    OSL_ENSURE( pAttrs, "LayoutFrame::Format, pAttrs is 0." );
 
    if ( isFramePrintAreaValid() && isFrameAreaSizeValid() )
        return;
 
    bool bHideWhitespace = false;
    if (IsPageFrame())
    {
        SwViewShell* pShell = getRootFrame()->GetCurrShell();
        if (pShell && pShell->GetViewOptions()->IsWhitespaceHidden())
        {
            // This is needed so that no space is reserved for the margin on
            // the last page of the document. Other pages would have no margin
            // set even without this, as their frame height is the content
            // height already.
            bHideWhitespace = true;
        }
    }
 
    const sal_uInt16 nLeft = static_cast<sal_uInt16>(pAttrs->CalcLeft(this));
    const sal_uInt16 nUpper = bHideWhitespace ? 0 : pAttrs->CalcTop();
 
    const sal_uInt16 nRight = static_cast<sal_uInt16>(pAttrs->CalcRight(this));
    const sal_uInt16 nLower = bHideWhitespace ? 0 : pAttrs->CalcBottom();
 
    const bool bVert = IsVertical() && !IsPageFrame();
    SwRectFn fnRect = bVert ? ( IsVertLR() ? fnRectVertL2R : fnRectVert ) : fnRectHori;
    if ( !isFramePrintAreaValid() )
    {
        setFramePrintAreaValid(true);
        (this->*fnRect->fnSetXMargins)( nLeft, nRight );
        (this->*fnRect->fnSetYMargins)( nUpper, nLower );
    }
 
    if ( !isFrameAreaSizeValid() )
    {
        if ( !HasFixSize() )
        {
            const SwTwips nBorder = nUpper + nLower;
            const SwFormatFrameSize &rSz = GetFormat()->GetFrameSize();
            SwTwips nMinHeight = rSz.GetHeightSizeType() == ATT_MIN_SIZE ? rSz.GetHeight() : 0;
            do
            {
                setFrameAreaSizeValid(true);
 
                //The size in VarSize is calculated using the content plus the
                // borders.
                SwTwips nRemaining = 0;
                SwFrame *pFrame = Lower();
                while ( pFrame )
                {   nRemaining += (pFrame->getFrameArea().*fnRect->fnGetHeight)();
                    if( pFrame->IsTextFrame() && static_cast<SwTextFrame*>(pFrame)->IsUndersized() )
                    // This TextFrame would like to be a bit bigger
                        nRemaining += static_cast<SwTextFrame*>(pFrame)->GetParHeight()
                                      - (pFrame->getFramePrintArea().*fnRect->fnGetHeight)();
                    else if( pFrame->IsSctFrame() && static_cast<SwSectionFrame*>(pFrame)->IsUndersized() )
                        nRemaining += static_cast<SwSectionFrame*>(pFrame)->Undersize();
                    pFrame = pFrame->GetNext();
                }
                nRemaining += nBorder;
                nRemaining = std::max( nRemaining, nMinHeight );
                const SwTwips nDiff = nRemaining-(getFrameArea().*fnRect->fnGetHeight)();
                const long nOldLeft = (getFrameArea().*fnRect->fnGetLeft)();
                const long nOldTop = (getFrameArea().*fnRect->fnGetTop)();
                if ( nDiff )
                {
                    if ( nDiff > 0 )
                        Grow( nDiff );
                    else
                        Shrink( -nDiff );
                    //Updates the positions using the fast channel.
                    MakePos();
                }
                //Don't exceed the bottom edge of the Upper.
                if ( GetUpper() && (getFrameArea().*fnRect->fnGetHeight)() )
                {
                    const SwTwips nLimit = (GetUpper()->*fnRect->fnGetPrtBottom)();
                    if( (this->*fnRect->fnSetLimit)( nLimit ) &&
                        nOldLeft == (getFrameArea().*fnRect->fnGetLeft)() &&
                        nOldTop  == (getFrameArea().*fnRect->fnGetTop)() )
                    {
                        setFrameAreaSizeValid(true);
                        setFramePrintAreaValid(true);
                    }
                }
            } while ( !isFrameAreaSizeValid() );
        }
        else if (GetType() & FRM_HEADFOOT)
        {
            do
            {   if ( getFrameArea().Height() != pAttrs->GetSize().Height() )
                {
                    ChgSize( Size( getFrameArea().Width(), pAttrs->GetSize().Height()));
                }
 
                setFrameAreaSizeValid(true);
                MakePos();
            } while ( !isFrameAreaSizeValid() );
        }
        else
        {
            setFrameAreaSizeValid(true);
        }
 
        // While updating the size, PrtArea might be invalidated.
        if (!isFramePrintAreaValid())
        {
            setFramePrintAreaValid(true);
            (this->*fnRect->fnSetXMargins)(nLeft, nRight);
            (this->*fnRect->fnSetYMargins)(nUpper, nLower);
        }
    }
}
 
static void InvaPercentFlys( SwFrame *pFrame, SwTwips nDiff )
{
    OSL_ENSURE( pFrame->GetDrawObjs(), "Can't find any Objects" );
    for (SwAnchoredObject* pAnchoredObj : *pFrame->GetDrawObjs())
    {
        if ( dynamic_cast< const SwFlyFrame *>( pAnchoredObj ) !=  nullptr )
        {
            SwFlyFrame *pFly = static_cast<SwFlyFrame*>(pAnchoredObj);
            const SwFormatFrameSize &rSz = pFly->GetFormat()->GetFrameSize();
            if ( rSz.GetWidthPercent() || rSz.GetHeightPercent() )
            {
                bool bNotify = true;
                // If we've a fly with more than 90% relative height...
                if( rSz.GetHeightPercent() > 90 && pFly->GetAnchorFrame() &&
                    rSz.GetHeightPercent() != SwFormatFrameSize::SYNCED && nDiff )
                {
                    const SwFrame *pRel = pFly->IsFlyLayFrame() ? pFly->GetAnchorFrame():
                                        pFly->GetAnchorFrame()->GetUpper();
                    // ... and we have already more than 90% height and we
                    // not allow the text to go through...
                    // then a notification could cause an endless loop, e.g.
                    // 100% height and no text wrap inside a cell of a table.
                    if( pFly->getFrameArea().Height()*10 >
                        ( nDiff + pRel->getFramePrintArea().Height() )*9 &&
                        pFly->GetFormat()->GetSurround().GetSurround() !=
                        css::text::WrapTextMode_THROUGH )
                       bNotify = false;
                }
                if( bNotify )
                    pFly->InvalidateSize();
            }
        }
    }
}
 
void SwLayoutFrame::InvaPercentLowers( SwTwips nDiff )
{
    if ( GetDrawObjs() )
        ::InvaPercentFlys( this, nDiff );
 
    SwFrame *pFrame = ContainsContent();
    if ( pFrame )
        do
        {
            if ( pFrame->IsInTab() && !IsTabFrame() )
            {
                SwFrame *pTmp = pFrame->FindTabFrame();
                OSL_ENSURE( pTmp, "Where's my TabFrame?" );
                if( IsAnLower( pTmp ) )
                    pFrame = pTmp;
            }
 
            if ( pFrame->IsTabFrame() )
            {
                const SwFormatFrameSize &rSz = static_cast<SwLayoutFrame*>(pFrame)->GetFormat()->GetFrameSize();
                if ( rSz.GetWidthPercent() || rSz.GetHeightPercent() )
                    pFrame->InvalidatePrt();
            }
            else if ( pFrame->GetDrawObjs() )
                ::InvaPercentFlys( pFrame, nDiff );
            pFrame = pFrame->FindNextCnt();
        } while ( pFrame && IsAnLower( pFrame ) ) ;
}
 
long SwLayoutFrame::CalcRel( const SwFormatFrameSize &rSz ) const
{
    long nRet     = rSz.GetWidth(),
         nPercent = rSz.GetWidthPercent();
 
    if ( nPercent )
    {
        const SwFrame *pRel = GetUpper();
        long nRel = LONG_MAX;
        const SwViewShell *pSh = getRootFrame()->GetCurrShell();
        const bool bBrowseMode = pSh && pSh->GetViewOptions()->getBrowseMode();
        if( pRel->IsPageBodyFrame() && pSh && bBrowseMode && pSh->VisArea().Width() )
        {
            nRel = pSh->GetBrowseWidth();
            long nDiff = nRel - pRel->getFramePrintArea().Width();
            if ( nDiff > 0 )
                nRel -= nDiff;
        }
        nRel = std::min( nRel, pRel->getFramePrintArea().Width() );
        nRet = nRel * nPercent / 100;
    }
    return nRet;
}
 
// Local helpers for SwLayoutFrame::FormatWidthCols()
 
static long lcl_CalcMinColDiff( SwLayoutFrame *pLayFrame )
{
    long nDiff = 0, nFirstDiff = 0;
    SwLayoutFrame *pCol = static_cast<SwLayoutFrame*>(pLayFrame->Lower());
    OSL_ENSURE( pCol, "Where's the columnframe?" );
    SwFrame *pFrame = pCol->Lower();
    do
    {
        if( pFrame && pFrame->IsBodyFrame() )
            pFrame = static_cast<SwBodyFrame*>(pFrame)->Lower();
        if ( pFrame && pFrame->IsTextFrame() )
        {
            const long nTmp = static_cast<SwTextFrame*>(pFrame)->FirstLineHeight();
            if ( nTmp != USHRT_MAX )
            {
                if ( pCol == pLayFrame->Lower() )
                    nFirstDiff = nTmp;
                else
                    nDiff = nDiff ? std::min( nDiff, nTmp ) : nTmp;
            }
        }
        //Skip empty columns!
        pCol = static_cast<SwLayoutFrame*>(pCol->GetNext());
        while ( pCol && nullptr == (pFrame = pCol->Lower()) )
            pCol = static_cast<SwLayoutFrame*>(pCol->GetNext());
 
    } while ( pFrame && pCol );
 
    return nDiff ? nDiff : nFirstDiff ? nFirstDiff : 240;
}
 
static bool lcl_IsFlyHeightClipped( SwLayoutFrame *pLay )
{
    SwFrame *pFrame = pLay->ContainsContent();
    while ( pFrame )
    {
        if ( pFrame->IsInTab() )
            pFrame = pFrame->FindTabFrame();
 
        if ( pFrame->GetDrawObjs() )
        {
            const size_t nCnt = pFrame->GetDrawObjs()->size();
            for ( size_t i = 0; i < nCnt; ++i )
            {
                SwAnchoredObject* pAnchoredObj = (*pFrame->GetDrawObjs())[i];
                if ( dynamic_cast< const SwFlyFrame *>( pAnchoredObj ) !=  nullptr )
                {
                    SwFlyFrame* pFly = static_cast<SwFlyFrame*>(pAnchoredObj);
                    if ( pFly->IsHeightClipped() &&
                         ( !pFly->IsFlyFreeFrame() || pFly->GetPageFrame() ) )
                        return true;
                }
            }
        }
        pFrame = pFrame->FindNextCnt();
    }
    return false;
}
 
void SwLayoutFrame::FormatWidthCols( const SwBorderAttrs &rAttrs,
                                   const SwTwips nBorder, const SwTwips nMinHeight )
{
    //If there are columns involved, the size is adjusted using the last column.
    //1. Format content.
    //2. Calculate height of the last column: if it's too big, the Fly has to
    //   grow. The amount by which the Fly grows is not the amount of the
    //   overhang because we have to act on the assumption that some text flows
    //   back which will generate some more space.
    //   The amount which we grow by equals the overhang
    //   divided by the amount of columns or the overhang itself if it's smaller
    //   than the amount of columns.
    //3. Go back to 1. until everything is stable.
 
    const SwFormatCol &rCol = rAttrs.GetAttrSet().GetCol();
    const sal_uInt16 nNumCols = rCol.GetNumCols();
 
    bool bEnd = false;
    bool bBackLock = false;
    SwViewShell *pSh = getRootFrame()->GetCurrShell();
    SwViewShellImp *pImp = pSh ? pSh->Imp() : nullptr;
    vcl::RenderContext* pRenderContext = pSh ? pSh->GetOut() : nullptr;
    {
        // Underlying algorithm
        // We try to find the optimal height for the column.
        // nMinimum starts with the passed minimum height and is then remembered
        // as the maximum height on which column content still juts out of a
        // column.
        // nMaximum starts with LONG_MAX and is then remembered as the minimum
        // width on which the content fitted.
        // In column based sections nMaximum starts at the maximum value which
        // the surrounding defines, this can certainly be a value on which
        // content still juts out.
        // The columns are formatted. If content still juts out, nMinimum is
        // adjusted accordingly, then we grow, at least by uMinDiff but not
        // over a certain nMaximum. If no content juts out but there is still
        // some space left in the column, shrinking is done accordingly, at
        // least by nMindIff but not below the nMinimum.
        // Cancel as soon as no content juts out and the difference from minimum
        // to maximum is less than MinDiff or the maximum which was defined by
        // the surrounding is reached even if some content still juts out.
 
        // Criticism of this implementation
        // 1. Theoretically situations are possible in which the content fits in
        // a lower height but not in a higher height. To ensure that the code
        // handles such situations the code contains a few checks concerning
        // minimum and maximum which probably are never triggered.
        // 2. We use the same nMinDiff for shrinking and growing, but nMinDiff
        // is more or less the smallest first line height and doesn't seem ideal
        // as minimum value.
 
        long nMinimum = nMinHeight;
        long nMaximum;
        bool bNoBalance = false;
        SwRectFnSet aRectFnSet(this);
        if( IsSctFrame() )
        {
            nMaximum = aRectFnSet.GetHeight(getFrameArea()) - nBorder +
                       aRectFnSet.BottomDist(getFrameArea(), aRectFnSet.GetPrtBottom(*GetUpper()));
            nMaximum += GetUpper()->Grow( LONG_MAX, true );
            if( nMaximum < nMinimum )
            {
                if( nMaximum < 0 )
                    nMinimum = nMaximum = 0;
                else
                    nMinimum = nMaximum;
            }
            if( nMaximum > BROWSE_HEIGHT )
                nMaximum = BROWSE_HEIGHT;
 
            bNoBalance = static_cast<SwSectionFrame*>(this)->GetSection()->GetFormat()->
                         GetBalancedColumns().GetValue();
            SwFrame* pAny = ContainsAny();
            if( bNoBalance ||
                ( !aRectFnSet.GetHeight(getFrameArea()) && pAny ) )
            {
                long nTop = aRectFnSet.GetTopMargin(*this);
                // #i23129# - correction
                // to the calculated maximum height.
                {
                    SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
                    aRectFnSet.AddBottom( aFrm, nMaximum - aRectFnSet.GetHeight(getFrameArea()) );
                }
 
                if( nTop > nMaximum )
                    nTop = nMaximum;
                aRectFnSet.SetYMargins( *this, nTop, 0 );
            }
            if( !pAny && !static_cast<SwSectionFrame*>(this)->IsFootnoteLock() )
            {
                SwFootnoteContFrame* pFootnoteCont = static_cast<SwSectionFrame*>(this)->ContainsFootnoteCont();
                if( pFootnoteCont )
                {
                    SwFrame* pFootnoteAny = pFootnoteCont->ContainsAny();
                    if( pFootnoteAny && pFootnoteAny->isFrameAreaDefinitionValid() )
                    {
                        bBackLock = true;
                        static_cast<SwSectionFrame*>(this)->SetFootnoteLock( true );
                    }
                }
            }
        }
        else
            nMaximum = LONG_MAX;
 
        // #i3317# - reset temporarily consideration
        // of wrapping style influence
        SwPageFrame* pPageFrame = FindPageFrame();
        SwSortedObjs* pObjs = pPageFrame ? pPageFrame->GetSortedObjs() : nullptr;
        if ( pObjs )
        {
            for (SwAnchoredObject* pAnchoredObj : *pObjs)
            {
                if ( IsAnLower( pAnchoredObj->GetAnchorFrame() ) )
                {
                    pAnchoredObj->SetTmpConsiderWrapInfluence( false );
                }
            }
        }
        do
        {
            //Could take a while therefore check for Waitcrsr here.
            if ( pImp )
                pImp->CheckWaitCursor();
 
            setFrameAreaSizeValid(true);
            //First format the column as this will relieve the stack a bit.
            //Also set width and height of the column (if they are wrong)
            //while we are at it.
            SwLayoutFrame *pCol = static_cast<SwLayoutFrame*>(Lower());
 
            // #i27399#
            // Simply setting the column width based on the values returned by
            // CalcColWidth does not work for automatic column width.
            AdjustColumns( &rCol, false );
 
            for ( sal_uInt16 i = 0; i < nNumCols; ++i )
            {
                pCol->Calc(pRenderContext);
                // ColumnFrames have a BodyFrame now, which needs to be calculated
                pCol->Lower()->Calc(pRenderContext);
                if( pCol->Lower()->GetNext() )
                    pCol->Lower()->GetNext()->Calc(pRenderContext);  // SwFootnoteCont
                pCol = static_cast<SwLayoutFrame*>(pCol->GetNext());
            }
 
            ::CalcContent( this );
 
            pCol = static_cast<SwLayoutFrame*>(Lower());
            OSL_ENSURE( pCol && pCol->GetNext(), ":-( column making holidays?");
            // set bMinDiff if no empty columns exist
            bool bMinDiff = true;
            // OD 28.03.2003 #108446# - check for all column content and all columns
            while ( bMinDiff && pCol )
            {
                bMinDiff = nullptr != pCol->ContainsContent();
                pCol = static_cast<SwLayoutFrame*>(pCol->GetNext());
            }
            pCol = static_cast<SwLayoutFrame*>(Lower());
            // OD 28.03.2003 #108446# - initialize local variable
            SwTwips nDiff = 0;
            SwTwips nMaxFree = 0;
            SwTwips nAllFree = LONG_MAX;
            // set bFoundLower if there is at least one non-empty column
            bool bFoundLower = false;
            while( pCol )
            {
                SwLayoutFrame* pLay = static_cast<SwLayoutFrame*>(pCol->Lower());
                SwTwips nInnerHeight = aRectFnSet.GetHeight(pLay->getFrameArea()) -
                                       aRectFnSet.GetHeight(pLay->getFramePrintArea());
                if( pLay->Lower() )
                {
                    bFoundLower = true;
                    nInnerHeight += pLay->InnerHeight();
                }
                else if( nInnerHeight < 0 )
                    nInnerHeight = 0;
 
                if( pLay->GetNext() )
                {
                    bFoundLower = true;
                    pLay = static_cast<SwLayoutFrame*>(pLay->GetNext());
                    OSL_ENSURE( pLay->IsFootnoteContFrame(),"FootnoteContainer expected" );
                    nInnerHeight += pLay->InnerHeight();
                    nInnerHeight += aRectFnSet.GetHeight(pLay->getFrameArea()) -
                                    aRectFnSet.GetHeight(pLay->getFramePrintArea());
                }
                nInnerHeight -= aRectFnSet.GetHeight(pCol->getFramePrintArea());
                if( nInnerHeight > nDiff )
                {
                    nDiff = nInnerHeight;
                    nAllFree = 0;
                }
                else
                {
                    if( nMaxFree < -nInnerHeight )
                        nMaxFree = -nInnerHeight;
                    if( nAllFree > -nInnerHeight )
                        nAllFree = -nInnerHeight;
                }
                pCol = static_cast<SwLayoutFrame*>(pCol->GetNext());
            }
 
            if ( bFoundLower || ( IsSctFrame() && static_cast<SwSectionFrame*>(this)->HasFollow() ) )
            {
                SwTwips nMinDiff = ::lcl_CalcMinColDiff( this );
                // Here we decide if growing is needed - this is the case, if
                // column content (nDiff) or a Fly juts over.
                // In sections with columns we take into account to set the size
                // when having a non-empty Follow.
                if ( nDiff || ::lcl_IsFlyHeightClipped( this ) ||
                     ( IsSctFrame() && static_cast<SwSectionFrame*>(this)->CalcMinDiff( nMinDiff ) ) )
                {
                    long nPrtHeight = aRectFnSet.GetHeight(getFramePrintArea());
                    // The minimum must not be smaller than our PrtHeight as
                    // long as something juts over.
                    if( nMinimum < nPrtHeight )
                        nMinimum = nPrtHeight;
                    // The maximum must not be smaller than PrtHeight if
                    // something still juts over.
                    if( nMaximum < nPrtHeight )
                        nMaximum = nPrtHeight;  // Robust, but will this ever happen?
                    if( !nDiff ) // If only Flys jut over, we grow by nMinDiff
                        nDiff = nMinDiff;
                    // If we should grow more than by nMinDiff we split it over
                    // the columns
                    if ( std::abs(nDiff - nMinDiff) > nNumCols && nDiff > static_cast<long>(nNumCols) )
                        nDiff /= nNumCols;
 
                    if ( bMinDiff )
                    {   // If no empty column exists, we want to grow at least
                        // by nMinDiff. Special case: If we are smaller than the
                        // minimal FrameHeight and PrtHeight is smaller than
                        // nMindiff we grow in a way that PrtHeight is exactly
                        // nMinDiff afterwards.
                        long nFrameHeight = aRectFnSet.GetHeight(getFrameArea());
                        if ( nFrameHeight > nMinHeight || nPrtHeight >= nMinDiff )
                            nDiff = std::max( nDiff, nMinDiff );
                        else if( nDiff < nMinDiff )
                            nDiff = nMinDiff - nPrtHeight + 1;
                    }
                    // nMaximum has a size which fits the content or the
                    // requested value from the surrounding therefore we don't
                    // need to exceed this value.
                    if( nDiff + nPrtHeight > nMaximum )
                        nDiff = nMaximum - nPrtHeight;
                }
                else if( nMaximum > nMinimum ) // We fit, do we still have some margin?
                {
                    long nPrtHeight = aRectFnSet.GetHeight(getFramePrintArea());
                    if ( nMaximum < nPrtHeight )
                        nDiff = nMaximum - nPrtHeight; // We grew over a working
                        // height and shrink back to it, but will this ever
                        // happen?
                    else
                    {   // We have a new maximum, a size which fits for the content.
                        nMaximum = nPrtHeight;
                        // If the margin in the column is bigger than nMinDiff
                        // and we therefore drop under the minimum, we deflate
                        // a bit.
                        if ( !bNoBalance &&
                             // #i23129# - <nMinDiff> can be
                             // big, because of an object at the beginning of
                             // a column. Thus, decrease optimization here.
                             //nMaxFree >= nMinDiff &&
                             nMaxFree > 0 &&
                             ( !nAllFree ||
                               nMinimum < nPrtHeight - nMinDiff ) )
                        {
                            nMaxFree /= nNumCols; // disperse over the columns
                            nDiff = nMaxFree < nMinDiff ? -nMinDiff : -nMaxFree; // min nMinDiff
                            if( nPrtHeight + nDiff <= nMinimum ) // below the minimum?
                                nDiff = ( nMinimum - nMaximum ) / 2; // Take the center
                        }
                        else if( nAllFree )
                        {
                            nDiff = -nAllFree;
                            if( nPrtHeight + nDiff <= nMinimum ) // Less than minimum?
                                nDiff = ( nMinimum - nMaximum ) / 2; // Take the center
                        }
                    }
                }
                if( nDiff ) // now we shrink or grow...
                {
                    Size aOldSz( getFramePrintArea().SSize() );
                    long nTop = aRectFnSet.GetTopMargin(*this);
                    nDiff = aRectFnSet.GetHeight(getFramePrintArea()) + nDiff + nBorder - aRectFnSet.GetHeight(getFrameArea());
 
                    {
                        SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
                        aRectFnSet.AddBottom( aFrm, nDiff );
                    }
 
                    // #i68520#
                    SwFlyFrame *pFlyFrame = dynamic_cast<SwFlyFrame*>(this);
                    if (pFlyFrame)
                    {
                        pFlyFrame->InvalidateObjRectWithSpaces();
                    }
                    aRectFnSet.SetYMargins( *this, nTop, nBorder - nTop );
                    ChgLowersProp( aOldSz );
                    NotifyLowerObjs();
 
                    // #i3317# - reset temporarily consideration
                    // of wrapping style influence
                    SwPageFrame* pTmpPageFrame = FindPageFrame();
                    SwSortedObjs* pTmpObjs = pTmpPageFrame ? pTmpPageFrame->GetSortedObjs() : nullptr;
                    if ( pTmpObjs )
                    {
                        for (SwAnchoredObject* pAnchoredObj : *pTmpObjs)
                        {
                            if ( IsAnLower( pAnchoredObj->GetAnchorFrame() ) )
                            {
                                pAnchoredObj->SetTmpConsiderWrapInfluence( false );
                            }
                        }
                    }
                    //Invalidate suitable to nicely balance the Frames.
                    //- Every first one after the second column gets a
                    //  InvalidatePos();
                    pCol = static_cast<SwLayoutFrame*>(Lower()->GetNext());
                    while ( pCol )
                    {
                        SwFrame *pLow = pCol->Lower();
                        if ( pLow )
                            pLow->InvalidatePos_();
                        pCol = static_cast<SwLayoutFrame*>(pCol->GetNext());
                    }
                    if( IsSctFrame() && static_cast<SwSectionFrame*>(this)->HasFollow() )
                    {
                        // If we created a Follow, we need to give its content
                        // the opportunity to flow back inside the CalcContent
                        SwContentFrame* pTmpContent =
                            static_cast<SwSectionFrame*>(this)->GetFollow()->ContainsContent();
                        if( pTmpContent )
                            pTmpContent->InvalidatePos_();
                    }
                }
                else
                    bEnd = true;
            }
            else
                bEnd = true;
 
        } while ( !bEnd || !isFrameAreaSizeValid() );
    }
    // OD 01.04.2003 #108446# - Don't collect endnotes for sections. Thus, set
    // 2nd parameter to <true>.
    ::CalcContent( this, true );
    if( IsSctFrame() )
    {
        // OD 14.03.2003 #i11760# - adjust 2nd parameter - sal_True --> true
        ::CalcContent( this, true );
        if( bBackLock )
            static_cast<SwSectionFrame*>(this)->SetFootnoteLock( false );
    }
}
 
static SwContentFrame* lcl_InvalidateSection( SwFrame *pCnt, SwInvalidateFlags nInv )
{
    SwSectionFrame* pSect = pCnt->FindSctFrame();
    // If our ContentFrame is placed inside a table or a footnote, only sections
    // which are also placed inside are meant.
    // Exception: If a table is directly passed.
    if( ( ( pCnt->IsInTab() && !pSect->IsInTab() ) ||
        ( pCnt->IsInFootnote() && !pSect->IsInFootnote() ) ) && !pCnt->IsTabFrame() )
        return nullptr;
    if( nInv & SwInvalidateFlags::Size )
        pSect->InvalidateSize_();
    if( nInv & SwInvalidateFlags::Pos )
        pSect->InvalidatePos_();
    if( nInv & SwInvalidateFlags::PrtArea )
        pSect->InvalidatePrt_();
    SwFlowFrame *pFoll = pSect->GetFollow();
    // Temporary separation from follow
    pSect->SetFollow( nullptr );
    SwContentFrame* pRet = pSect->FindLastContent();
    pSect->SetFollow( pFoll );
    return pRet;
}
 
static SwContentFrame* lcl_InvalidateTable( SwTabFrame *pTable, SwInvalidateFlags nInv )
{
    if( ( nInv & SwInvalidateFlags::Section ) && pTable->IsInSct() )
        lcl_InvalidateSection( pTable, nInv );
    if( nInv & SwInvalidateFlags::Size )
        pTable->InvalidateSize_();
    if( nInv & SwInvalidateFlags::Pos )
        pTable->InvalidatePos_();
    if( nInv & SwInvalidateFlags::PrtArea )
        pTable->InvalidatePrt_();
    return pTable->FindLastContent();
}
 
static void lcl_InvalidateAllContent( SwContentFrame *pCnt, SwInvalidateFlags nInv );
 
static void lcl_InvalidateContent( SwContentFrame *pCnt, SwInvalidateFlags nInv )
{
    SwContentFrame *pLastTabCnt = nullptr;
    SwContentFrame *pLastSctCnt = nullptr;
    while ( pCnt )
    {
        if( nInv & SwInvalidateFlags::Section )
        {
            if( pCnt->IsInSct() )
            {
                // See above at tables
                if( !pLastSctCnt )
                    pLastSctCnt = lcl_InvalidateSection( pCnt, nInv );
                if( pLastSctCnt == pCnt )
                    pLastSctCnt = nullptr;
            }
#if OSL_DEBUG_LEVEL > 0
            else
                OSL_ENSURE( !pLastSctCnt, "Where's the last SctContent?" );
#endif
        }
        if( nInv & SwInvalidateFlags::Table )
        {
            if( pCnt->IsInTab() )
            {
                // To not call FindTabFrame() for each ContentFrame of a table and
                // then invalidate the table, we remember the last ContentFrame of
                // the table and ignore IsInTab() until we are past it.
                // When entering the table, LastSctCnt is set to null, so
                // sections inside the table are correctly invalidated.
                // If the table itself is in a section the
                // invalidation is done three times, which is acceptable.
                if( !pLastTabCnt )
                {
                    pLastTabCnt = lcl_InvalidateTable( pCnt->FindTabFrame(), nInv );
                    pLastSctCnt = nullptr;
                }
                if( pLastTabCnt == pCnt )
                {
                    pLastTabCnt = nullptr;
                    pLastSctCnt = nullptr;
                }
            }
#if OSL_DEBUG_LEVEL > 0
            else
                OSL_ENSURE( !pLastTabCnt, "Where's the last TabContent?" );
#endif
        }
 
        if( nInv & SwInvalidateFlags::Size )
            pCnt->Prepare( PREP_CLEAR, nullptr, false );
        if( nInv & SwInvalidateFlags::Pos )
            pCnt->InvalidatePos_();
        if( nInv & SwInvalidateFlags::PrtArea )
            pCnt->InvalidatePrt_();
        if ( nInv & SwInvalidateFlags::LineNum )
            pCnt->InvalidateLineNum();
        if ( pCnt->GetDrawObjs() )
            lcl_InvalidateAllContent( pCnt, nInv );
        pCnt = pCnt->GetNextContentFrame();
    }
}
 
static void lcl_InvalidateAllContent( SwContentFrame *pCnt, SwInvalidateFlags nInv )
{
    SwSortedObjs &rObjs = *pCnt->GetDrawObjs();
    for (SwAnchoredObject* pAnchoredObj : rObjs)
    {
        if ( dynamic_cast< const SwFlyFrame *>( pAnchoredObj ) !=  nullptr )
        {
            SwFlyFrame *pFly = static_cast<SwFlyFrame*>(pAnchoredObj);
            if ( pFly->IsFlyInContentFrame() )
            {
                ::lcl_InvalidateContent( pFly->ContainsContent(), nInv );
                if( nInv & SwInvalidateFlags::Direction )
                    pFly->CheckDirChange();
            }
        }
    }
}
 
void SwRootFrame::InvalidateAllContent( SwInvalidateFlags nInv )
{
    // First process all page bound FlyFrames.
    SwPageFrame *pPage = static_cast<SwPageFrame*>(Lower());
    while( pPage )
    {
        pPage->InvalidateFlyLayout();
        pPage->InvalidateFlyContent();
        pPage->InvalidateFlyInCnt();
        pPage->InvalidateLayout();
        pPage->InvalidateContent();
        pPage->InvalidatePage( pPage ); // So even the Turbo disappears if applicable
 
        if ( pPage->GetSortedObjs() )
        {
            const SwSortedObjs &rObjs = *pPage->GetSortedObjs();
            for (SwAnchoredObject* pAnchoredObj : rObjs)
            {
                if ( dynamic_cast< const SwFlyFrame *>( pAnchoredObj ) !=  nullptr )
                {
                    SwFlyFrame* pFly = static_cast<SwFlyFrame*>(pAnchoredObj);
                    ::lcl_InvalidateContent( pFly->ContainsContent(), nInv );
                    if ( nInv & SwInvalidateFlags::Direction )
                        pFly->CheckDirChange();
                }
            }
        }
        if( nInv & SwInvalidateFlags::Direction )
            pPage->CheckDirChange();
        pPage = static_cast<SwPageFrame*>(pPage->GetNext());
    }
 
    //Invalidate the whole document content and the character bound Flys here.
    ::lcl_InvalidateContent( ContainsContent(), nInv );
 
    if( nInv & SwInvalidateFlags::PrtArea )
    {
        SwViewShell *pSh  = getRootFrame()->GetCurrShell();
        if( pSh )
            pSh->InvalidateWindows( getFrameArea() );
    }
}
 
/**
 * Invalidate/re-calculate the position of all floating screen objects (Writer fly frames and
 * drawing objects), that are anchored to paragraph or to character. (2004-03-16 #i11860#)
 */
void SwRootFrame::InvalidateAllObjPos()
{
    const SwPageFrame* pPageFrame = static_cast<const SwPageFrame*>(Lower());
    while( pPageFrame )
    {
        pPageFrame->InvalidateFlyLayout();
 
        if ( pPageFrame->GetSortedObjs() )
        {
            const SwSortedObjs& rObjs = *(pPageFrame->GetSortedObjs());
            for (SwAnchoredObject* pAnchoredObj : rObjs)
            {
                const SwFormatAnchor& rAnch = pAnchoredObj->GetFrameFormat().GetAnchor();
                if ((rAnch.GetAnchorId() != RndStdIds::FLY_AT_PARA) &&
                    (rAnch.GetAnchorId() != RndStdIds::FLY_AT_CHAR))
                {
                    // only to paragraph and to character anchored objects are considered.
                    continue;
                }
                // #i28701# - special invalidation for anchored
                // objects, whose wrapping style influence has to be considered.
                if ( pAnchoredObj->ConsiderObjWrapInfluenceOnObjPos() )
                    pAnchoredObj->InvalidateObjPosForConsiderWrapInfluence();
                else
                    pAnchoredObj->InvalidateObjPos();
            }
        }
 
        pPageFrame = static_cast<const SwPageFrame*>(pPageFrame->GetNext());
    }
}
 
void SwRootFrame::SetHideRedlines(bool const bHideRedlines)
{
    if (bHideRedlines == mbHideRedlines)
    {
        return;
    }
    mbHideRedlines = bHideRedlines;
    SwNodes const& rNodes(GetFormat()->GetDoc()->GetNodes());
    // Hide->Show: clear MergedPara, create frames
    // Show->Hide: call CheckParaRedlineMerge, delete frames
    // TODO how to traverse
    // * via layout
    //      - but that won't find nodes that don't have frames in ->Show case
    // * via nodes
    //      - what about special sections before content? flys? footnotes?
    //        is order of these predictable? flys not anchored in content?
    // * ideally should call something existing that tries to create everything?
    //      - is that done automatically somewhere already?
    // * other direction ->Hide - delete frames!
    // in-order traversal should init flags in nodes *before* the nodes are found
    for (sal_uLong i = 0; i < rNodes.Count(); ++i)
    {
        SwNode *const pNode(rNodes[i]);
        if (pNode->IsTextNode())
        {
            SwTextNode & rTextNode(*pNode->GetTextNode());
            SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> aIter(rTextNode);
            std::vector<SwTextFrame*> frames;
            for (SwTextFrame * pFrame = aIter.First(); pFrame; pFrame = aIter.Next())
            {
                if (pFrame->getRootFrame() == this)
                {
                    frames.push_back(pFrame);
                }
            }
            // this messes with pRegisteredIn so do it outside SwIterator
            for (SwTextFrame * pFrame : frames)
            {
                if (mbHideRedlines && pNode->IsCreateFrameWhenHidingRedlines())
                {
                    pFrame->SetMergedPara(CheckParaRedlineMerge(*pFrame, rTextNode));
                }
                else
                {
                    if (pFrame->GetMergedPara())
                    {
                        pFrame->SetMergedPara(nullptr);
                        rTextNode.DelFrames(); // FIXME only those in this layout?
                    }
                }
            }
        }
    }
    InvalidateAllContent(SwInvalidateFlags::Size); // ??? TODO what to invalidate?
}
 
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

V571 Recurring check. The 'if (IsTabFrame())' condition was already verified in line 2879.

V678 An object is used as an argument to its own method. Consider checking the first actual argument of the 'InvalidatePage' function.

V592 The expression was enclosed by parentheses twice: ((expression)). One pair of parentheses is unnecessary or misprint is present.

V592 The expression was enclosed by parentheses twice: ((expression)). One pair of parentheses is unnecessary or misprint is present.