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

Quelle  pagechg.cxx   Sprache: C

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


#include <config_wasm_strip.h>

#include <comphelper/lok.hxx>
#include <ndole.hxx>
#include <sal/log.hxx>
#include <osl/diagnose.h>
#include <svl/itemiter.hxx>
#include <fmtfsize.hxx>
#include <fmthdft.hxx>
#include <fmtclds.hxx>
#include <fmtpdsc.hxx>
#include <fmtornt.hxx>
#include <fmtsrnd.hxx>
#include <ftninfo.hxx>
#include <frmtool.hxx>
#include <tgrditem.hxx>
#include <viewopt.hxx>
#include <docsh.hxx>
#include <wrtsh.hxx>
#include <view.hxx>
#include <edtwin.hxx>
#include <frameformats.hxx>

#include <viewimp.hxx>
#include <pagefrm.hxx>
#include <rootfrm.hxx>
#include <IDocumentDrawModelAccess.hxx>
#include <IDocumentSettingAccess.hxx>
#include <IDocumentFieldsAccess.hxx>
#include <dcontact.hxx>
#include <hints.hxx>
#include <FrameControlsManager.hxx>

#include <ftnidx.hxx>
#include <bodyfrm.hxx>
#include <ftnfrm.hxx>
#include <tabfrm.hxx>
#include <txtfrm.hxx>
#include <notxtfrm.hxx>
#include <sectfrm.hxx>
#include <layact.hxx>
#include <flyfrms.hxx>
#include <htmltbl.hxx>
#include <pagedesc.hxx>
#include <editeng/frmdiritem.hxx>
#include <sortedobjs.hxx>
#include <calbck.hxx>
#include <txtfly.hxx>
#include <frmatr.hxx>

using namespace ::com::sun::star;

SwBodyFrame::SwBodyFrame( SwFrameFormat *pFormat, SwFrame* pSib ):
    SwLayoutFrame( pFormat, pSib )
{
    mnFrameType = SwFrameType::Body;
}

void SwBodyFrame::Format( vcl::RenderContext* /*pRenderContext*/, const SwBorderAttrs * )
{
    // Formatting of the body is too simple, thus, it gets its own format method.
    // Borders etc. are not taken into account here.
    // Width is taken from the PrtArea of the Upper. Height is the height of the
    // PrtArea of the Upper minus any neighbors (for robustness).
    // The PrtArea has always the size of the frame.

    if ( !isFrameAreaSizeValid() )
    {
        SwTwips nHeight = GetUpper()->getFramePrintArea().Height();
        SwTwips nWidth = GetUpper()->getFramePrintArea().Width();
        const SwFrame *pFrame = GetUpper()->Lower();
        while (pFrame)
        {
            if ( pFrame != this )
            {
                if( pFrame->IsVertical() )
                    nWidth -= pFrame->getFrameArea().Width();
                else
                    nHeight -= pFrame->getFrameArea().Height();
            }
            pFrame = pFrame->GetNext();
        }

        if ( nHeight < 0 )
        {
            nHeight = 0;
        }

        SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
        aFrm.Height( nHeight );

        if( IsVertical() && !IsVertLR() && nWidth != aFrm.Width() )
        {
            aFrm.Pos().setX(aFrm.Pos().getX() + aFrm.Width() - nWidth);
        }

        aFrm.Width( nWidth );
    }

    bool bNoGrid = true;
    if( GetUpper()->IsPageFrame() && static_cast<SwPageFrame*>(GetUpper())->HasGrid() )
    {
        SwTextGridItem const*const pGrid(
                GetGridItem(static_cast<SwPageFrame*>(GetUpper())));

        bool bCenterGrid = !GetFormat()->getIDocumentSettingAccess().get(
            DocumentSettingId::MS_WORD_COMP_GRID_METRICS);
        if (pGrid && bCenterGrid)
        {
            bNoGrid = false;
            tools::Long nSum = pGrid->GetBaseHeight() + pGrid->GetRubyHeight();
            SwRectFnSet aRectFnSet(this);
            tools::Long nSize = aRectFnSet.GetWidth(getFrameArea());
            tools::Long nBorder = 0;
            if( SwTextGrid::LinesAndChars == pGrid->GetGridType() )
            {
                //for textgrid refactor
                SwDoc& rDoc = GetFormat()->GetDoc();
                nBorder = nSize % (GetGridWidth(*pGrid, rDoc));
                nSize -= nBorder;
                nBorder /= 2;
            }

            SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this);
            aRectFnSet.SetPosX( aPrt, nBorder );
            aRectFnSet.SetWidth( aPrt, nSize );

            // Height of body frame:
            nBorder = aRectFnSet.GetHeight(getFrameArea());

            // Number of possible lines in area of body frame:
            tools::Long nNumberOfLines = nBorder / nSum;
            if( nNumberOfLines > pGrid->GetLines() )
                nNumberOfLines = pGrid->GetLines();

            // Space required for nNumberOfLines lines:
            nSize = nNumberOfLines * nSum;
            nBorder -= nSize;
            nBorder /= 2;

            // #i21774# Footnotes and centering the grid does not work together:
            const bool bAdjust = static_cast<SwPageFrame*>(GetUpper())->GetFormat()->GetDoc().
                                        GetFootnoteIdxs().empty();

            aRectFnSet.SetPosY( aPrt, bAdjust ? nBorder : 0 );
            aRectFnSet.SetHeight( aPrt, nSize );
        }
    }

    if( bNoGrid )
    {
        SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this);
        aPrt.Pos().setX(0);
        aPrt.Pos().setY(0);
        aPrt.Height( getFrameArea().Height() );
        aPrt.Width( getFrameArea().Width() );
    }

    setFrameAreaSizeValid(true);
    setFramePrintAreaValid(true);
}

void SwBodyFrame::dumpAsXml(xmlTextWriterPtr writer) const
{
    (void)xmlTextWriterStartElement(writer, reinterpret_cast<const xmlChar*>("body"));
    dumpAsXmlAttributes(writer);

    SwLayoutFrame::dumpAsXml(writer);

    (void)xmlTextWriterEndElement(writer);
}

SwPageFrame::SwPageFrame( SwFrameFormat *pFormat, SwFrame* pSib, SwPageDesc *pPgDsc ) :
    SwFootnoteBossFrame( pFormat, pSib ),
    m_pDesc( pPgDsc ),
    m_nPhyPageNum( 0 )
{
    SetDerivedVert( false );
    SetDerivedR2L( false );
    if( m_pDesc )
    {
        m_bHasGrid = true;
        SwTextGridItem const*const pGrid(GetGridItem(this));
        if( !pGrid )
            m_bHasGrid = false;
    }
    else
        m_bHasGrid = false;
    SetMaxFootnoteHeight( pPgDsc->GetFootnoteInfo().GetHeight() ?
                     pPgDsc->GetFootnoteInfo().GetHeight() : LONG_MAX );
    mnFrameType = SwFrameType::Page;
    m_bInvalidLayout = m_bInvalidContent = m_bInvalidSpelling = m_bInvalidSmartTags = m_bInvalidAutoCmplWrds = m_bInvalidWordCount = true;
    m_bInvalidFlyLayout = m_bInvalidFlyContent = m_bInvalidFlyInCnt = m_bFootnotePage = m_bEndNotePage = false;

    SwViewShell *pSh = getRootFrame()->GetCurrShell();
    const bool bBrowseMode = pSh && pSh->GetViewOptions()->getBrowseMode();
    vcl::RenderContext* pRenderContext = pSh ? pSh->GetOut() : nullptr;

    {
        SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);

        if ( bBrowseMode )
        {
            aFrm.Height( 0 );
            tools::Long nWidth = pSh->VisArea().Width();

            if ( !nWidth )
            {
                nWidth = 5000;     // changes anyway
            }

            aFrm.Width ( nWidth );
        }
        else
        {
            aFrm.SSize( pFormat->GetFrameSize().GetSize() );
        }
    }

    // create and insert body area if it is not a blank page
    SwDoc& rDoc(pFormat->GetDoc());
    m_bEmptyPage = (pFormat == rDoc.GetEmptyPageFormat());

    if(m_bEmptyPage)
    {
        return;
    }

    Calc(pRenderContext); // so that the PrtArea is correct
    SwBodyFrame *pBodyFrame = new SwBodyFrame( rDoc.GetDfltFrameFormat(), this );
    pBodyFrame->ChgSize( getFramePrintArea().SSize() );
    pBodyFrame->Paste( this );
    pBodyFrame->Calc(pRenderContext); // so that the columns can be inserted correctly
    pBodyFrame->InvalidatePos();

    if ( bBrowseMode )
        InvalidateSize_();

    // insert header/footer,, but only if active.
    if ( pFormat->GetHeader().IsActive() )
        PrepareHeader();
    if ( pFormat->GetFooter().IsActive() )
        PrepareFooter();

    const SwFormatCol &rCol = pFormat->GetCol();
    if ( rCol.GetNumCols() > 1 )
    {
        const SwFormatCol aOld; //ChgColumns() needs an old value
        pBodyFrame->ChgColumns( aOld, rCol );
    }

}

void SwPageFrame::DestroyImpl()
{
    // Cleanup the header-footer controls in all SwEditWins
    SwViewShell* pSh = getRootFrame()->GetCurrShell();
    if (pSh)
    {
        for (SwViewShell& rSh : pSh->GetRingContainer())
        {
            SwWrtShell* pWrtSh = dynamic_cast< SwWrtShell* >( &rSh );
            if ( pWrtSh )
            {
                SwEditWin& rEditWin = pWrtSh->GetView().GetEditWin();
                rEditWin.GetFrameControlsManager( ).RemoveControls( this );
            }
        }
    }

    // empty FlyContainer, deletion of the Flys is done by the anchor (in base class SwFrame)
    if (m_pSortedObjs)
    {
        // Objects can be anchored at pages that are before their anchors (why ever...).
        // In such cases, we would access already freed memory.
        for (SwAnchoredObject* pAnchoredObj : *m_pSortedObjs)
        {
            pAnchoredObj->SetPageFrame( nullptr );
        }
        m_pSortedObjs.reset(); // reset to zero to prevent problems when detaching the Flys
    }

    // prevent access to destroyed pages
    if( GetFormat() && !GetFormat()->GetDoc().IsInDtor() )
    {
        if ( pSh )
        {
            SwViewShellImp *pImp = pSh->Imp();
            pImp->SetFirstVisPageInvalid();
            if ( pImp->IsAction() )
                pImp->GetLayAction().SetAgain(true);
            // #i9719# - retouche area of page
            // including border and shadow area.
            const bool bRightSidebar = (SidebarPosition() == sw::sidebarwindows::SidebarPosition::RIGHT);
            SwRect aRetoucheRect;
            SwPageFrame::GetBorderAndShadowBoundRect( getFrameArea(), pSh, pSh->GetOut(), aRetoucheRect, IsLeftShadowNeeded(), IsRightShadowNeeded(), bRightSidebar );
            pSh->AddPaintRect( aRetoucheRect );
        }
    }

    SwFootnoteBossFrame::DestroyImpl();
}

SwPageFrame::~SwPageFrame()
{
}

void SwPageFrame::CheckGrid( bool bInvalidate )
{
    bool bOld = m_bHasGrid;
    m_bHasGrid = true;
    SwTextGridItem const*const pGrid(GetGridItem(this));
    m_bHasGrid = nullptr != pGrid;
    if( !(bInvalidate || bOld != m_bHasGrid) )
        return;

    SwLayoutFrame* pBody = FindBodyCont();
    if( pBody )
    {
        pBody->InvalidatePrt();
        SwContentFrame* pFrame = pBody->ContainsContent();
        while( pBody->IsAnLower( pFrame ) )
        {
            static_cast<SwTextFrame*>(pFrame)->Prepare();
            pFrame = pFrame->GetNextContentFrame();
        }
    }
    SetCompletePaint();
}

void SwPageFrame::CheckDirection( bool bVert )
{
    SvxFrameDirection nDir = GetFormat()->GetFormatAttr( RES_FRAMEDIR ).GetValue();
    if( bVert )
    {
        if( SvxFrameDirection::Horizontal_LR_TB == nDir || SvxFrameDirection::Horizontal_RL_TB == nDir )
        {
            mbVertLR = false;
            mbVertical = false;
        }
        else
        {
            const SwViewShell *pSh = getRootFrame()->GetCurrShell();
            if( pSh && pSh->GetViewOptions()->getBrowseMode() )
            {
                mbVertLR = false;
                mbVertical = false;
            }
            else
            {
                mbVertical = true;

                if(SvxFrameDirection::Vertical_RL_TB == nDir)
                    mbVertLR = false;
                else if(SvxFrameDirection::Vertical_LR_TB==nDir)
                    mbVertLR = true;
            }
        }

        mbInvalidVert = false;
    }
    else
    {
        if( SvxFrameDirection::Horizontal_RL_TB == nDir )
            mbRightToLeft = true;
        else
            mbRightToLeft = false;
        mbInvalidR2L = false;
    }
}

/// create specific Flys for this page and format generic content
static void lcl_FormatLay( SwLayoutFrame *pLay )
{
    vcl::RenderContext* pRenderContext = pLay->getRootFrame()->GetCurrShell()->GetOut();
    // format all LayoutFrames - no tables, Flys etc.

    SwFrame *pTmp = pLay->Lower();
    // first the low-level ones
    while ( pTmp )
    {
        const SwFrameType nTypes = SwFrameType::Root | SwFrameType::Page | SwFrameType::Column
                           | SwFrameType::Header | SwFrameType::Footer | SwFrameType::FootnoteContainer
                           | SwFrameType::Footnote | SwFrameType::Body;
        if ( pTmp->GetType() & nTypes )
            ::lcl_FormatLay( static_cast<SwLayoutFrame*>(pTmp) );
        pTmp = pTmp->GetNext();
    }
    pLay->Calc(pRenderContext);
}

/// Create Flys or register draw objects
static void lcl_MakeObjs(const sw::FrameFormats<sw::SpzFrameFormat*>& rSpzs, SwPageFrame* pPage)
{
    // formats are in the special table of the document
    const sal_uInt16 nPhyPageNum = pPage->GetPhyPageNum();
    size_t i = 0;
    const size_t nSpzsCnt = rSpzs.size();
    while (i < nSpzsCnt)
    {
        auto pSpz = rSpzs[i];
        const SwFormatAnchor &rAnch = pSpz->GetAnchor();
        if ( rAnch.GetPageNum() == nPhyPageNum )
        {
            if( rAnch.GetAnchorNode() )
            {
                if (RndStdIds::FLY_AT_PAGE == rAnch.GetAnchorId())
                {
                    SwFormatAnchor aAnch( rAnch );
                    aAnch.SetAnchor( nullptr );
                    pSpz->SetFormatAttr( aAnch );
                }
                else
                {
                    ++i;
                    continue;
                }
            }

            // is it a border or a SdrObject?
            bool bSdrObj = RES_DRAWFRMFMT == pSpz->Which();
            SdrObject *pSdrObj = nullptr;
            if ( bSdrObj  && nullptr == (pSdrObj = pSpz->FindSdrObject()) )
            {
                OSL_FAIL( "DrawObject not found." );
                pSpz->GetDoc().DelFrameFormat( pSpz );
                continue;
            }
            // The object might be anchored to another page, e.g. when inserting
            // a new page due to a page descriptor change. In such cases, the
            // object needs to be moved.
            // In some cases the object is already anchored to the correct page.
            // This will be handled here and does not need to be coded extra.
            SwPageFrame *pPg = pPage->IsEmptyPage() ? static_cast<SwPageFrame*>(pPage->GetNext()) : pPage;
            if ( bSdrObj )
            {
                // OD 23.06.2003 #108784# - consider 'virtual' drawing objects
                if (SwDrawContact *pContact =
                            static_cast<SwDrawContact*>(::GetUserCall(pSdrObj)))
                {
                    if ( auto pDrawVirtObj = dynamic_cast<SwDrawVirtObj *>( pSdrObj ) )
                    {
                        pDrawVirtObj->RemoveFromWriterLayout();
                        pDrawVirtObj->RemoveFromDrawingPage();
                        pPg->AppendDrawObj( *(pContact->GetAnchoredObj( pDrawVirtObj )) );
                    }
                    else
                    {
                        if ( pContact->GetAnchorFrame() )
                            pContact->DisconnectFromLayout( false );
                        pPg->AppendDrawObj( *(pContact->GetAnchoredObj( pSdrObj )) );
                    }
                }
            }
            else
            {
                SwIterator<SwFlyFrame,SwFormat> aIter( *pSpz );
                SwFlyFrame *pFly = aIter.First();
                if ( pFly)
                {
                    if( pFly->GetAnchorFrame() )
                        pFly->AnchorFrame()->RemoveFly( pFly );
                }
                else
                    pFly = new SwFlyLayFrame( static_cast<SwFlyFrameFormat*>(pSpz), pPg, pPg );
                pPg->AppendFly( pFly );
                ::RegistFlys( pPg, pFly );
            }
        }
        ++i;
    }
}

void SwPageFrame::PreparePage( bool bFootnote )
{
    SetFootnotePage( bFootnote );

    // #i82258#
    // Due to made change on OOo 2.0 code line, method <::lcl_FormatLay(..)> has
    // the side effect, that the content of page header and footer are formatted.
    // For this formatting it is needed that the anchored objects are registered
    // at the <SwPageFrame> instance.
    // Thus, first calling <::RegistFlys(..)>, then call <::lcl_FormatLay(..)>
    ::RegistFlys( thisthis );

    if ( Lower() )
    {
                ::lcl_FormatLay( this );
    }

    // Flys and draw objects that are still attached to the document.
    // Footnote pages do not have page-bound Flys!
    // There might be Flys or draw objects that want to be placed on
    // empty pages, however, the empty pages ignore that and the following
    // pages take care of them.
    if ( !bFootnote && !IsEmptyPage() )
    {
        SwDoc& rDoc = GetFormat()->GetDoc();

        if ( GetPrev() && static_cast<SwPageFrame*>(GetPrev())->IsEmptyPage() )
            lcl_MakeObjs( *rDoc.GetSpzFrameFormats(), static_cast<SwPageFrame*>(GetPrev()) );
        lcl_MakeObjs( *rDoc.GetSpzFrameFormats(), this );
    }
}

void SwPageFrame::SwClientNotify(const SwModify& rModify, const SfxHint& rHint)
{
    if(rHint.GetId() == SfxHintId::SwPageFootnote)
    {
        // currently the savest way:
        static_cast<SwRootFrame*>(GetUpper())->SetSuperfluous();
        SetMaxFootnoteHeight(m_pDesc->GetFootnoteInfo().GetHeight());
        if(!GetMaxFootnoteHeight())
            SetMaxFootnoteHeight(LONG_MAX);
        SetColMaxFootnoteHeight();
        // here, the page might be destroyed:
        static_cast<SwRootFrame*>(GetUpper())->RemoveFootnotes(nullptr, falsetrue);
    }
    else if (rHint.GetId() == SfxHintId::SwAutoFormatUsedHint)
    {
        // a page frame exists, so use this one
        static_cast<const sw::AutoFormatUsedHint&>(rHint).SetUsed();
        return;
    }
    else if (rHint.GetId() == SfxHintId::SwLegacyModify || rHint.GetId() == SfxHintId::SwFormatChange
            || rHint.GetId() == SfxHintId::SwAttrSetChange)
    {
        if(auto pSh = getRootFrame()->GetCurrShell())
            pSh->SetFirstVisPageInvalid();

        SwPageFrameInvFlags eInvFlags = SwPageFrameInvFlags::NONE;
        if (rHint.GetId() == SfxHintId::SwLegacyModify)
        {
            auto pLegacy = static_cast<const sw::LegacyModifyHint*>(&rHint);
            UpdateAttr_(pLegacy->m_pOld, pLegacy->m_pNew, eInvFlags);
        }
        else if (rHint.GetId() == SfxHintId::SwAttrSetChange)
        {
            auto pChangeHint = static_cast<const sw::AttrSetChangeHint*>(&rHint);
            if(pChangeHint->m_pNew)
            {
                const SwAttrSetChg& rOldSetChg = *pChangeHint->m_pOld;
                const SwAttrSetChg& rNewSetChg = *pChangeHint->m_pNew;
                SfxItemIter aOIter(*rOldSetChg.GetChgSet());
                SfxItemIter aNIter(*rNewSetChg.GetChgSet());
                const SfxPoolItem* pOItem = aOIter.GetCurItem();
                const SfxPoolItem* pNItem = aNIter.GetCurItem();
                SwAttrSetChg aOldSet(rOldSetChg);
                SwAttrSetChg aNewSet(rNewSetChg);
                do
                {
                    UpdateAttr_(pOItem, pNItem, eInvFlags, &aOldSet, &aNewSet);
                    pOItem = aOIter.NextItem();
                    pNItem = aNIter.NextItem();
                } while(pNItem);
                if(aOldSet.Count() || aNewSet.Count())
                    SwLayoutFrame::SwClientNotify(rModify, sw::AttrSetChangeHint(&aOldSet, &aNewSet));
            }
        }
        else // rHint.GetId() == SfxHintId::SwFormatChange
        {
            auto pChangeHint = static_cast<const SwFormatChangeHint*>(&rHint);
            UpdateAttrForFormatChange(pChangeHint->m_pOldFormat, pChangeHint->m_pNewFormat, eInvFlags);
        }

        if (eInvFlags == SwPageFrameInvFlags::NONE)
            return;

        InvalidatePage( this );
        if(eInvFlags & SwPageFrameInvFlags::InvalidatePrt)
            InvalidatePrt_();
        if(eInvFlags & SwPageFrameInvFlags::SetCompletePaint)
            SetCompletePaint();
        if(eInvFlags & SwPageFrameInvFlags::InvalidateNextPos && GetNext() )
            GetNext()->InvalidatePos();
        if(eInvFlags & SwPageFrameInvFlags::PrepareHeader)
            PrepareHeader();
        if(eInvFlags & SwPageFrameInvFlags::PrepareFooter)
            PrepareFooter();
        if(eInvFlags & SwPageFrameInvFlags::CheckGrid)
            CheckGrid(bool(eInvFlags & SwPageFrameInvFlags::InvalidateGrid));
    } else
        SwFrame::SwClientNotify(rModify, rHint);
}

void SwPageFrame::UpdateAttr_( const SfxPoolItem *pOld, const SfxPoolItem *pNew,
                             SwPageFrameInvFlags &rInvFlags,
                             SwAttrSetChg *pOldSet, SwAttrSetChg *pNewSet )
{
    bool bClear = true;
    const sal_uInt16 nWhich = pOld ? pOld->Which() : pNew ? pNew->Which() : 0;
    switch( nWhich )
    {
        case RES_FRM_SIZE:
        {
            const SwRect aOldPageFrameRect( getFrameArea() );
            SwViewShell *pSh = getRootFrame()->GetCurrShell();
            if( pSh && pSh->GetViewOptions()->getBrowseMode() )
            {
                setFrameAreaSizeValid(false);
                // OD 28.10.2002 #97265# - Don't call <SwPageFrame::MakeAll()>
                // Calculation of the page is not necessary, because its size is
                // invalidated here and further invalidation is done in the
                // calling method <SwPageFrame::Modify(..)> and probably by calling
                // <SwLayoutFrame::SwClientNotify(..)> at the end.
                // It can also causes inconsistences, because the lowers are
                // adjusted, but not calculated, and a <SwPageFrame::MakeAll()> of
                // a next page is called. This is performed on the switch to the
                // online layout.
                //MakeAll();
            }
            else if (pNew)
            {
                const SwFormatFrameSize &rSz = static_cast<const SwFormatFrameSize&>(*pNew);

                {
                    SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
                    aFrm.Height( std::max( rSz.GetHeight(), tools::Long(MINLAY) ) );
                    aFrm.Width ( std::max( rSz.GetWidth(),  tools::Long(MINLAY) ) );
                }

                if ( GetUpper() )
                {
                    static_cast<SwRootFrame*>(GetUpper())->CheckViewLayout( nullptr, nullptr );
                }
            }
            // cleanup Window
            if( pSh && pSh->GetWin() && aOldPageFrameRect.HasArea() )
            {
                // #i9719# - consider border and shadow of
                // page frame for determine 'old' rectangle - it's used for invalidating.
                const bool bRightSidebar = (SidebarPosition() == sw::sidebarwindows::SidebarPosition::RIGHT);
                SwRect aOldRectWithBorderAndShadow;
                SwPageFrame::GetBorderAndShadowBoundRect( aOldPageFrameRect, pSh, pSh->GetOut(), aOldRectWithBorderAndShadow,
                    IsLeftShadowNeeded(), IsRightShadowNeeded(), bRightSidebar );
                pSh->InvalidateWindows( aOldRectWithBorderAndShadow );
            }
            rInvFlags |= SwPageFrameInvFlags::InvalidatePrt | SwPageFrameInvFlags::SetCompletePaint;
            if ( aOldPageFrameRect.Height() != getFrameArea().Height() )
                rInvFlags |= SwPageFrameInvFlags::InvalidateNextPos;
        }
        break;

        case RES_COL:
            assert(pOld && pNew); //COL Missing Format
            if (pOld && pNew)
            {
                SwLayoutFrame *pB = FindBodyCont();
                assert(pB); //page without body
                pB->ChgColumns( *static_cast<const SwFormatCol*>(pOld), *static_cast<const SwFormatCol*>(pNew) );
                rInvFlags |= SwPageFrameInvFlags::SetCompletePaint | SwPageFrameInvFlags::CheckGrid;
            }
        break;

        case RES_HEADER:
            rInvFlags |= SwPageFrameInvFlags::PrepareHeader;
            break;

        case RES_FOOTER:
            rInvFlags |= SwPageFrameInvFlags::PrepareFooter;
            break;
        case RES_TEXTGRID:
            rInvFlags |= SwPageFrameInvFlags::CheckGrid | SwPageFrameInvFlags::InvalidateGrid;
            break;
        case RES_FRAMEDIR :
            CheckDirChange();
            break;

        default:
            bClear = false;
    }
    if ( !bClear )
        return;

    if ( pOldSet || pNewSet )
    {
        if ( pOldSet )
            pOldSet->ClearItem( nWhich );
        if ( pNewSet )
            pNewSet->ClearItem( nWhich );
    }
    else
    {
        SwModify aMod;
        SwLayoutFrame::SwClientNotify(aMod, sw::LegacyModifyHint(pOld, pNew));
    }
}

void SwPageFrame::UpdateAttrForFormatChange( SwFormat* pOldFormat, SwFormat* pNewFormat,
                             SwPageFrameInvFlags &rInvFlags )
{
    // state of m_bEmptyPage needs to be determined newly
    const bool bNewState(GetFormat() == GetFormat()->GetDoc().GetEmptyPageFormat());

    if(m_bEmptyPage != bNewState)
    {
        // copy new state
        m_bEmptyPage = bNewState;

        if(nullptr == GetLower())
        {
            // if we were an empty page before there is not yet a BodyArea in the
            // form of a SwBodyFrame, see constructor
            SwViewShell* pSh(getRootFrame()->GetCurrShell());
            vcl::RenderContext* pRenderContext(pSh ? pSh->GetOut() : nullptr);
            Calc(pRenderContext); // so that the PrtArea is correct
            SwBodyFrame* pBodyFrame = new SwBodyFrame(GetFormat(), this);
            pBodyFrame->ChgSize(getFramePrintArea().SSize());
            pBodyFrame->Paste(this);
            pBodyFrame->InvalidatePos();
        }
    }

    // If the frame format is changed, several things might also change:
    // 1. columns:
    assert(pOldFormat && pNewFormat); //FMT_CHG Missing Format
    const SwFormatCol &rOldCol = pOldFormat->GetCol();
    const SwFormatCol &rNewCol = pNewFormat->GetCol();
    if( rOldCol != rNewCol )
    {
        SwLayoutFrame *pB = FindBodyCont();
        assert(pB && "Page without Body.");
        pB->ChgColumns( rOldCol, rNewCol );
        rInvFlags |= SwPageFrameInvFlags::CheckGrid;
    }

    // 2. header and footer:
    const SwFormatHeader &rOldH = pOldFormat->GetHeader();
    const SwFormatHeader &rNewH = pNewFormat->GetHeader();
    if( rOldH != rNewH )
        rInvFlags |= SwPageFrameInvFlags::PrepareHeader;

    const SwFormatFooter &rOldF = pOldFormat->GetFooter();
    const SwFormatFooter &rNewF = pNewFormat->GetFooter();
    if( rOldF != rNewF )
        rInvFlags |= SwPageFrameInvFlags::PrepareFooter;
    CheckDirChange();

    const SwRect aOldPageFrameRect( getFrameArea() );
    SwViewShell *pSh = getRootFrame()->GetCurrShell();
    if( pSh && pSh->GetViewOptions()->getBrowseMode() )
    {
        setFrameAreaSizeValid(false);
        // OD 28.10.2002 #97265# - Don't call <SwPageFrame::MakeAll()>
        // Calculation of the page is not necessary, because its size is
        // invalidated here and further invalidation is done in the
        // calling method <SwPageFrame::Modify(..)> and probably by calling
        // <SwLayoutFrame::SwClientNotify(..)> at the end.
        // It can also causes inconsistences, because the lowers are
        // adjusted, but not calculated, and a <SwPageFrame::MakeAll()> of
        // a next page is called. This is performed on the switch to the
        // online layout.
        //MakeAll();
    }
    else if (pNewFormat)
    {
        const SwFormatFrameSize &rSz = pNewFormat->GetFrameSize();

        {
            SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
            aFrm.Height( std::max( rSz.GetHeight(), tools::Long(MINLAY) ) );
            aFrm.Width ( std::max( rSz.GetWidth(),  tools::Long(MINLAY) ) );
        }

        if ( GetUpper() )
        {
            static_cast<SwRootFrame*>(GetUpper())->CheckViewLayout( nullptr, nullptr );
        }
    }
    // cleanup Window
    if( pSh && pSh->GetWin() && aOldPageFrameRect.HasArea() )
    {
        // #i9719# - consider border and shadow of
        // page frame for determine 'old' rectangle - it's used for invalidating.
        const bool bRightSidebar = (SidebarPosition() == sw::sidebarwindows::SidebarPosition::RIGHT);
        SwRect aOldRectWithBorderAndShadow;
        SwPageFrame::GetBorderAndShadowBoundRect( aOldPageFrameRect, pSh, pSh->GetOut(), aOldRectWithBorderAndShadow,
            IsLeftShadowNeeded(), IsRightShadowNeeded(), bRightSidebar );
        pSh->InvalidateWindows( aOldRectWithBorderAndShadow );
    }
    rInvFlags |= SwPageFrameInvFlags::InvalidatePrt | SwPageFrameInvFlags::SetCompletePaint;
    if ( aOldPageFrameRect.Height() != getFrameArea().Height() )
        rInvFlags |= SwPageFrameInvFlags::InvalidateNextPos;

    SwModify aMod;
    SwLayoutFrame::SwClientNotify(aMod, SwFormatChangeHint(pOldFormat, pNewFormat));
}

void  SwPageFrame::SetPageDesc( SwPageDesc *pNew, SwFrameFormat *pFormat )
{
    m_pDesc = pNew;
    if ( pFormat )
        SetFrameFormat( pFormat );
}

/* determine the right PageDesc:
 *  0.  from the document for footnote and endnote pages
 *  1.  from the first BodyContent below a page
 *  2.  from PageDesc of the predecessor page
 *  3.  from PageDesc of the previous page if blank page
 *  3.1 from PageDesc of the next page if no predecessor exists
 *  4.  default PageDesc
 *  5.  In BrowseMode use the first paragraph or default PageDesc.
 */

SwPageDesc *SwPageFrame::FindPageDesc()
{
    // 0.
    if ( IsFootnotePage() )
    {
        SwDoc& rDoc = GetFormat()->GetDoc();
        if ( IsEndNotePage() )
            return rDoc.GetEndNoteInfo().GetPageDesc( rDoc );
        else
            return rDoc.GetFootnoteInfo().GetPageDesc( rDoc );
    }

    SwPageDesc *pRet = nullptr;

    //5.
    const SwViewShell *pSh = getRootFrame()->GetCurrShell();
    if( pSh && pSh->GetViewOptions()->getBrowseMode() )
    {
        SwContentFrame *pFrame = GetUpper()->ContainsContent();
        while (pFrame && !pFrame->IsInDocBody())
            pFrame = pFrame->GetNextContentFrame();
        if (pFrame)
        {
            SwFrame *pFlow = pFrame;
            if ( pFlow->IsInTab() )
                pFlow = pFlow->FindTabFrame();
            pRet = const_cast<SwPageDesc*>(pFlow->GetPageDescItem().GetPageDesc());
        }
        if ( !pRet )
            pRet = &GetFormat()->GetDoc().GetPageDesc( 0 );
        return pRet;
    }

    SwContentFrame* pFirstContent = FindFirstBodyContent();
    while (pFirstContent && pFirstContent->IsInSct()
            && pFirstContent->FindSctFrame()->IsHiddenNow())
    {
        pFirstContent = pFirstContent->GetNextContentFrame();
    }
    SwFrame* pFlow = pFirstContent;
    if ( pFlow && pFlow->IsInTab() )
        pFlow = pFlow->FindTabFrame();

    //1.
    if ( pFlow )
    {
        SwFlowFrame *pTmp = SwFlowFrame::CastFlowFrame( pFlow );
        if ( !pTmp->IsFollow() )
            pRet = const_cast<SwPageDesc*>(pFlow->GetPageDescItem().GetPageDesc());
    }

    //3. and 3.1
    if ( !pRet && IsEmptyPage() )
            // FME 2008-03-03 #i81544# lijian/fme: an empty page should have
            // the same page description as its prev, just like after construction
            // of the empty page.
        pRet = GetPrev() ? static_cast<SwPageFrame*>(GetPrev())->GetPageDesc() :
               GetNext() ? static_cast<SwPageFrame*>(GetNext())->GetPageDesc() : nullptr;

    //2.
    if ( !pRet )
        pRet = GetPrev() ?
                    static_cast<SwPageFrame*>(GetPrev())->GetPageDesc()->GetFollow() : nullptr;

    //4.
    if ( !pRet )
        pRet = &GetFormat()->GetDoc().GetPageDesc( 0 );

    OSL_ENSURE( pRet, "could not find page descriptor." );
    return pRet;
}

// Notify if the RootFrame changes its size
void AdjustSizeChgNotify( SwRootFrame *pRoot )
{
    const bool bOld = pRoot->IsSuperfluous();
    pRoot->mbCheckSuperfluous = false;
    if ( pRoot->GetCurrShell() )
    {
        for(SwViewShell& rSh : pRoot->GetCurrShell()->GetRingContainer())
        {
            if( pRoot == rSh.GetLayout() )
            {
                rSh.SizeChgNotify();
                if ( rSh.Imp() )
                    rSh.Imp()->NotifySizeChg( pRoot->getFrameArea().SSize() );
            }
        }
    }
    pRoot->mbCheckSuperfluous = bOld;
}

inline void SetLastPage( SwPageFrame *pPage )
{
    static_cast<SwRootFrame*>(pPage->GetUpper())->mpLastPage = pPage;
}

void SwPageFrame::Cut()
{
    SwViewShell *pSh = getRootFrame()->GetCurrShell();
    if ( !IsEmptyPage() )
    {
        if ( GetNext() )
            GetNext()->InvalidatePos();

        // move Flys whose anchor is on a different page (draw objects are not relevant here)
        if ( GetSortedObjs() )
        {
            size_t i = 0;
            while ( GetSortedObjs() && i < GetSortedObjs()->size() )
            {
                // #i28701#
                SwAnchoredObject* pAnchoredObj = (*GetSortedObjs())[i];

                if ( auto pFly = dynamic_cast<SwFlyAtContentFrame *>( pAnchoredObj ) )
                {
                    SwPageFrame *pAnchPage = pFly->GetAnchorFrame() ?
                                pFly->AnchorFrame()->FindPageFrame() : nullptr;
                    if ( pAnchPage && (pAnchPage != this) )
                    {
                        MoveFly( pFly, pAnchPage );
                        pFly->InvalidateSize();
                        pFly->InvalidatePos_();
                        // Do not increment index, in this case
                        continue;
                    }
                }
                ++i;
            }
        }
        // cleanup Window
        if ( pSh && pSh->GetWin() )
            pSh->InvalidateWindows( getFrameArea() );
    }

    // decrease the root's page number
    static_cast<SwRootFrame*>(GetUpper())->DecrPhyPageNums();
    SwPageFrame *pPg = static_cast<SwPageFrame*>(GetNext());
    if ( pPg )
    {
        while ( pPg )
        {
            --pPg->m_nPhyPageNum;
            pPg = static_cast<SwPageFrame*>(pPg->GetNext());
        }
    }
    else
        ::SetLastPage( static_cast<SwPageFrame*>(GetPrev()) );

    SwFrame* pRootFrame = GetUpper();

    // cut all connections
    RemoveFromLayout();

    if ( pRootFrame )
        static_cast<SwRootFrame*>(pRootFrame)->CheckViewLayout( nullptr, nullptr );
}

void SwPageFrame::Paste( SwFrame* pParent, SwFrame* pSibling )
{
    OSL_ENSURE( pParent->IsRootFrame(), "Parent is no Root." );
    assert(pParent && "No parent for Paste().");
    OSL_ENSURE( pParent != this"I'm my own parent." );
    OSL_ENSURE( pSibling != this"I'm my own neighbour." );
    OSL_ENSURE( !GetPrev() && !GetNext() && !GetUpper(),
            "I am still registered somewhere." );

    // insert into tree structure
    InsertBefore( static_cast<SwLayoutFrame*>(pParent), pSibling );

    // increase the root's page number
    static_cast<SwRootFrame*>(GetUpper())->IncrPhyPageNums();
    if( GetPrev() )
        SetPhyPageNum( static_cast<SwPageFrame*>(GetPrev())->GetPhyPageNum() + 1 );
    else
        SetPhyPageNum( 1 );
    SwPageFrame *pPg = static_cast<SwPageFrame*>(GetNext());
    if ( pPg )
    {
        while ( pPg )
        {
            ++pPg->m_nPhyPageNum;
            pPg->InvalidatePos_();
            pPg->InvalidateLayout();
            pPg = static_cast<SwPageFrame*>(pPg->GetNext());
        }
    }
    else
        ::SetLastPage( this );

    if( getFrameArea().Width() != pParent->getFramePrintArea().Width() )
        InvalidateSize_();

    InvalidatePos();

    SwViewShell *pSh = getRootFrame()->GetCurrShell();
    if ( pSh )
        pSh->SetFirstVisPageInvalid();

    getRootFrame()->CheckViewLayout( nullptr, nullptr );
}

static void lcl_PrepFlyInCntRegister( SwContentFrame *pFrame )
{
    pFrame->Prepare( PrepareHint::Register );
    if( !pFrame->GetDrawObjs() )
        return;

    for(SwAnchoredObject* pAnchoredObj : *pFrame->GetDrawObjs())
    {
        // #i28701#
        if ( auto pFly = dynamic_cast<SwFlyInContentFrame *>( pAnchoredObj ) )
        {
            SwContentFrame *pCnt = pFly->ContainsContent();
            while ( pCnt )
            {
                lcl_PrepFlyInCntRegister( pCnt );
                pCnt = pCnt->GetNextContentFrame();
            }
        }
    }
}

void SwPageFrame::PrepareRegisterChg()
{
    SwContentFrame *pFrame = FindFirstBodyContent();
    while( pFrame )
    {
        lcl_PrepFlyInCntRegister( pFrame );
        pFrame = pFrame->GetNextContentFrame();
        if( !IsAnLower( pFrame ) )
            break;
    }
    if( !GetSortedObjs() )
        return;

    for(SwAnchoredObject* pAnchoredObj : *GetSortedObjs())
    {
        // #i28701#
        if ( auto pFly = pAnchoredObj->DynCastFlyFrame() )
        {
            pFrame = pFly->ContainsContent();
            while ( pFrame )
            {
                ::lcl_PrepFlyInCntRegister( pFrame );
                pFrame = pFrame->GetNextContentFrame();
            }
        }
    }
}

namespace sw {

/// check if there's content on the page that requires it to exist
bool IsPageFrameEmpty(SwPageFrame const& rPage)
{
    bool bExistEssentialObjs = (nullptr != rPage.GetSortedObjs());
    if (bExistEssentialObjs)
    {
        // Only because the page has Flys does not mean that it is needed. If all Flys are
        // attached to generic content it is also superfluous (checking DocBody should be enough)
        // OD 19.06.2003 - consider that drawing objects in
        // header/footer are supported now.
        bool bOnlySuperfluousObjs = true;
        SwSortedObjs const& rObjs = *rPage.GetSortedObjs();
        for (size_t i = 0; bOnlySuperfluousObjs && i < rObjs.size(); ++i)
        {
            // #i28701#
            SwAnchoredObject* pAnchoredObj = rObjs[i];
            // do not consider hidden objects
            if ( rPage.GetFormat()->GetDoc().getIDocumentDrawModelAccess().IsVisibleLayerId(
                                pAnchoredObj->GetDrawObj()->GetLayer() ) &&
                 !pAnchoredObj->GetAnchorFrame()->FindFooterOrHeader() )
            {
                bOnlySuperfluousObjs = false;
            }
        }
        bExistEssentialObjs = !bOnlySuperfluousObjs;
    }

    // optimization: check first if essential objects exist.
    if (bExistEssentialObjs)
        return false;
    else if (rPage.FindFootnoteCont())
        return false;
    else
    {
        if (const SwLayoutFrame* pBody = rPage.FindBodyCont())
        {
            const SwFrame* pLower = pBody->Lower();
            if ( pBody->ContainsContent() ||
              // check for section frames that are being formatted on the stack
              rPage.ContainsDeleteForbiddenLayFrame() ||
                // #i47580#
                // Do not delete page if there's an empty tabframe
                // left. I think it might be correct to use ContainsAny()
                // instead of ContainsContent() to cover the empty-table-case,
                // but I'm not fully sure, since ContainsAny() also returns
                // SectionFrames. Therefore I prefer to do it the safe way:
              ( pLower && pLower->IsTabFrame() ) )
                return false;
        }
    }

    return true;
}

// namespace sw

//FIXME: provide missing documentation
/** Check all pages (starting from the given one) if they use the appropriate frame format.
 *
 * If "wrong" pages are found, try to fix this as simple as possible.
 *
 * Also delete pages that don't have content on them.
 *
 * @param pStart        the page from where to start searching
 * @param bNotifyFields
 * @param ppPrev
 */

void SwFrame::CheckPageDescs( SwPageFrame *pStart, bool bNotifyFields, SwPageFrame** ppPrev )
{
    SAL_INFO( "sw.pageframe""(CheckPageDescs in phy: " << pStart->GetPhyPageNum() );
    assert(pStart && "no starting page.");

    SwViewShell *pSh   = pStart->getRootFrame()->GetCurrShell();
    SwViewShellImp *pImp  = pSh ? pSh->Imp() : nullptr;

    if ( pImp && pImp->IsAction() && !pImp->GetLayAction().IsCheckPages() )
    {
        pImp->GetLayAction().SetCheckPageNum( pStart->GetPhyPageNum() );
        SAL_INFO( "sw.pageframe""CheckPageDescs out fast - via SetCheckPageNum: "
                  << pStart->GetPhyPageNum() << ")" );
        return;
    }

    // For the update of page numbering fields, nDocPos provides
    // the page position from where invalidation should start.
    SwTwips nDocPos  = LONG_MAX;

    SwRootFrame *pRoot = static_cast<SwRootFrame*>(pStart->GetUpper());
    SwDoc& rDoc      = pStart->GetFormat()->GetDoc();
    const bool bFootnotes = !rDoc.GetFootnoteIdxs().empty();

    SwPageFrame *pPage = pStart;
    if( pPage->GetPrev() && static_cast<SwPageFrame*>(pPage->GetPrev())->IsEmptyPage() )
        pPage = static_cast<SwPageFrame*>(pPage->GetPrev());
    while ( pPage )
    {
        SwPageFrame *pPrevPage = static_cast<SwPageFrame*>(pPage->GetPrev());
        SwPageFrame *pNextPage = static_cast<SwPageFrame*>(pPage->GetNext());

        SwPageDesc *pDesc = pPage->FindPageDesc();
        /// page is intentionally empty page
        bool bIsEmpty = pPage->IsEmptyPage();
        // false for intentionally empty pages, they need additional check
        bool isPageFrameEmpty(!bIsEmpty && sw::IsPageFrameEmpty(*pPage));
        bool bIsOdd = pPage->OnRightPage();
        bool bWantOdd = pPage->WannaRightPage();
        bool bFirst = pPage->OnFirstPage();
        SwFrameFormat *pFormatWish = bWantOdd
            ? pDesc->GetRightFormat(bFirst) : pDesc->GetLeftFormat(bFirst);

        if ( bIsOdd != bWantOdd ||
             pDesc != pPage->GetPageDesc() ||        // wrong Desc
             ( pFormatWish != pPage->GetFormat() &&       // wrong format and
               ( !bIsEmpty || pFormatWish ) // not blank /empty
             )
           )
        {
            // Updating a page might take a while, so check the WaitCursor
            if( pImp )
                pImp->CheckWaitCursor();

            // invalidate the field, starting from here
            if ( nDocPos == LONG_MAX )
                nDocPos = pPrevPage ? pPrevPage->getFrameArea().Top() : pPage->getFrameArea().Top();

            // Cases:
            //  1. Empty page should be "normal" page -> remove empty page and take next one
            //  2. Empty page should have different descriptor -> change
            //  3. Normal page should be empty -> insert empty page if previous page
            //     is not empty, otherwise see (6).
            //  4. Normal page should have different descriptor -> change
            //  5. Normal page should have different format -> change
            //  6. No "wish" format provided -> take the "other" format (left/right) of the PageDesc

            if ( bIsEmpty && ( pFormatWish ||          //1.
                 ( !bWantOdd && !pPrevPage ) ) )
            {
                // Check all cases for the next page, so we don't oscillate empty pages
                // Skip case 1 and 2, as we require a non-empty next page to save the empty page
                // Case 3 is the one we actually want to predict and skip
                // We can skip the empty check of case 3, as we just work on an existing next page
                bool bNextWantOdd;
                SwPageDesc *pNextDesc;
                if ( pNextPage && !pNextPage->IsEmptyPage() &&    //3.
                     pNextPage->OnRightPage() == (bNextWantOdd = pNextPage->WannaRightPage()) &&
                     pNextPage->GetPageDesc() == (pNextDesc = pNextPage->FindPageDesc()) )   //4.
                {
                    bool bNextFirst = pNextPage->OnFirstPage();
                    SwFrameFormat *pNextFormatWish = bNextWantOdd ?   //5.
                        pNextDesc->GetRightFormat(bNextFirst) : pNextDesc->GetLeftFormat(bNextFirst);
                    if ( !pNextFormatWish )    // 6.
                        pNextFormatWish = bNextWantOdd ? pNextDesc->GetLeftFormat() : pNextDesc->GetRightFormat();
                    if ( pNextFormatWish && pNextPage->GetFormat() == pNextFormatWish )
                    {
                        SAL_INFO( "sw.pageframe""CheckPageDescs phys: " << pPage->GetPhyPageNum()
                                  << " c: 1+3 - skip next page of p: " << pPage );
                        if (pPrevPage && pPage->GetPageDesc() != pPrevPage->GetPageDesc())
                            pPage->SetPageDesc( pPrevPage->GetPageDesc(), nullptr );
                        // We can skip the next page, as all checks were already done!
                        pPage = static_cast<SwPageFrame*>(pNextPage->GetNext());
                        continue;
                    }
                }

                pPage->Cut();
                bool bUpdatePrev = false;
                if (ppPrev && *ppPrev == pPage)
                    bUpdatePrev = true;
                SAL_INFO( "sw.pageframe""CheckPageDescs phys: " << pPage->GetPhyPageNum()
                          << " c: 1 - destroy p: " << pPage );
                SwFrame::DestroyFrame(pPage);
                if ( pStart == pPage )
                    pStart = pNextPage;
                pPage = pNextPage;
                if (bUpdatePrev)
                    *ppPrev = pNextPage;
                continue;
            }
            else if ( bIsEmpty && !pFormatWish &&  //2.
                      pDesc != pPage->GetPageDesc() )
            {
                SAL_INFO( "sw.pageframe""CheckPageDescs phys: " << pPage->GetPhyPageNum()
                          << " c: 2 - set desc p: " << pPage << " d: " << pDesc );
                pPage->SetPageDesc( pDesc, nullptr );
            }
            else if ( !bIsEmpty &&      //3.
                      bIsOdd != bWantOdd &&
                      ( ( !pPrevPage && !bWantOdd ) ||
                        ( pPrevPage && !pPrevPage->IsEmptyPage() )
                      )
                    )
            {
                if ( pPrevPage )
                    pDesc = pPrevPage->GetPageDesc();
                SwPageFrame *pTmp = new SwPageFrame( rDoc.GetEmptyPageFormat(), pRoot, pDesc );
                SAL_INFO( "sw.pageframe""CheckPageDescs phys: " << pPage->GetPhyPageNum()
                          << " c: 3 - insert empty p: " << pTmp << " d: " << pDesc );
                pTmp->Paste( pRoot, pPage );
                pTmp->PreparePage( false );
                pPage = pTmp;
                isPageFrameEmpty = false// don't delete it right away!
            }
            else if ( pPage->GetPageDesc() != pDesc )           //4.
            {
                SwPageDesc *pOld = pPage->GetPageDesc();
                pPage->SetPageDesc( pDesc, pFormatWish );
                SAL_INFO( "sw.pageframe""CheckPageDescs phys: " << pPage->GetPhyPageNum()
                          << " c: 4 - set desc + format p: " << pPage
                          << " d: " << pDesc << " f: " << pFormatWish );
                if ( bFootnotes )
                {
                    // If specific values of the FootnoteInfo are changed, something has to happen.
                    // We try to limit the damage...
                    // If the page has no FootnoteCont it might be problematic.
                    // Let's hope that invalidation is enough.
                    SwFootnoteContFrame *pCont = pPage->FindFootnoteCont();
                    if ( pCont && !(pOld->GetFootnoteInfo() == pDesc->GetFootnoteInfo()) )
                        pCont->InvalidateAll_();
                }
            }
            else if ( pFormatWish && pPage->GetFormat() != pFormatWish )         //5.
            {
                pPage->SetFrameFormat( pFormatWish );
                SAL_INFO( "sw.pageframe""CheckPageDescs phys: " << pPage->GetPhyPageNum()
                          << " c: 5 - set format p: " << pPage << " f: " << pFormatWish );
            }
            else if ( !pFormatWish )                                       //6.
            {
                // get format with inverted logic
                pFormatWish = bWantOdd ? pDesc->GetLeftFormat() : pDesc->GetRightFormat();
                if ( pFormatWish && pPage->GetFormat() != pFormatWish )
                {
                    pPage->SetFrameFormat( pFormatWish );
                    SAL_INFO( "sw.pageframe""CheckPageDescs phys: " << pPage->GetPhyPageNum()
                              << " c: 6 - set format p: " << pPage << " f: " << pFormatWish );
                }
            }
#if OSL_DEBUG_LEVEL > 0
            else
            {
                OSL_FAIL( "CheckPageDescs, missing solution" );
            }
#endif
        }
        assert(!bIsEmpty || !isPageFrameEmpty);
        const bool bWantRemovePage = bIsEmpty || isPageFrameEmpty;
        if (bWantRemovePage && !pPage->IsDeleteForbidden())
        {
            // It also might be that an empty page is not needed at all.
            // However, the algorithm above cannot determine that. It is not needed if the following
            // page can live without it. Do obtain that information, we need to dig deeper...
            SwPageFrame *pPg = static_cast<SwPageFrame*>(pPage->GetNext());
            if (isPageFrameEmpty || !pPg || pPage->OnRightPage() == pPg->WannaRightPage())
            {
                // The following page can find a FrameFormat or has no successor -> empty page not needed
                SwPageFrame *pTmp = static_cast<SwPageFrame*>(pPage->GetNext());
                if (isPageFrameEmpty && pPage->GetPrev())
                {   // check previous *again* vs. its new next! see "ooo321_stylepagenumber.odt"
                    pTmp = static_cast<SwPageFrame*>(pPage->GetPrev());
                }
                pPage->Cut();
                bool bUpdatePrev = false;
                if (ppPrev && *ppPrev == pPage)
                    bUpdatePrev = true;
                SwFrame::DestroyFrame(pPage);
                SAL_INFO( "sw.pageframe""CheckPageDescs - handle bIsEmpty - destroy p: " << pPage );
                if ( pStart == pPage )
                    pStart = pTmp;
                pPage = pTmp;
                if (bUpdatePrev)
                    *ppPrev = pTmp;
                continue;
            }
        }
        pPage = static_cast<SwPageFrame*>(pPage->GetNext());
    }

    pRoot->SetAssertFlyPages();
    SwRootFrame::AssertPageFlys( pStart );

    if ( bNotifyFields && (!pImp || !pImp->IsUpdateExpFields()) )
    {
        rDoc.getIDocumentFieldsAccess().UpdatePageFields(nDocPos);
    }

#if OSL_DEBUG_LEVEL > 0
    //1. check if two empty pages are behind one another
    bool bEmpty = false;
    SwPageFrame *pPg = pStart;
    while ( pPg )
    {
        if ( pPg->IsEmptyPage() )
        {
            if ( bEmpty )
            {
                OSL_FAIL( "double empty pages." );
                break;  // once is enough
            }
            bEmpty = true;
        }
        else
            bEmpty = false;

        pPg = static_cast<SwPageFrame*>(pPg->GetNext());
    }
#endif
    SAL_INFO( "sw.pageframe""CheckPageDescs out)" );
}

namespace
{
    bool isDeleteForbidden(const SwPageFrame *pDel)
    {
        if (pDel->IsDeleteForbidden())
            return true;
        const SwLayoutFrame* pBody = pDel->FindBodyCont();
        const SwFrame* pBodyContent = pBody ? pBody->Lower() : nullptr;
        return pBodyContent && pBodyContent->IsDeleteForbidden();
    }

    bool doInsertPage( SwRootFrame *pRoot, SwPageFrame **pRefSibling,
                       SwFrameFormat *pFormat, SwPageDesc *pDesc,
                       bool bFootnote, SwPageFrame **pRefPage )
    {
        SwPageFrame *pPage = new SwPageFrame(pFormat, pRoot, pDesc);
        SwPageFrame *pSibling = *pRefSibling;
        if ( pRefPage )
        {
            *pRefPage = pPage;
            SAL_INFO( "sw.pageframe""doInsertPage p: " << pPage
                                      << " d: " << pDesc << " f: " << pFormat );
        }
        else
            SAL_INFO( "sw.pageframe""doInsertPage - insert empty p: "
                                      << pPage << " d: " << pDesc );
        pPage->Paste( pRoot, pSibling );

        SwViewShell* pViewShell = pRoot->GetCurrShell();
        if (pViewShell && pViewShell->GetViewOptions()->IsHideWhitespaceMode())
        {
            // Hide-whitespace mode does not shrink the last page, so resize the page that used to
            // be the last one.
            if (SwFrame* pPrevPage = pPage->GetPrev())
            {
                pPrevPage->InvalidateSize();
            }
        }

        pPage->PreparePage( bFootnote );
        // If the sibling has no body text, destroy it as long as it is no footnote page.
        if (!pSibling)
            return true;
        if (pSibling->IsFootnotePage())
            return true;
        if (pSibling->FindFirstBodyContent())
            return true;

        if (!pRefPage || !isDeleteForbidden(pSibling))
        {
            pRoot->RemovePage( pRefSibling, SwRemoveResult::Next ) ;
            return false;
        }

        return true;
    }
}

SwPageFrame *SwFrame::InsertPage( SwPageFrame *pPrevPage, bool bFootnote )
{
    SwRootFrame *pRoot = static_cast<SwRootFrame*>(pPrevPage->GetUpper());
    SwPageFrame *pSibling = static_cast<SwPageFrame*>(pPrevPage->GetNext());
    SwPageDesc *pDesc = nullptr;

    // insert right (odd) or left (even) page?
    bool bNextRightPage = !pPrevPage->OnRightPage();
    bool bWishedRightPage = bNextRightPage;

    // Which PageDesc is relevant?
    // For ContentFrame take the one from format if provided,
    // otherwise from the Follow of the PrevPage
    if ( IsFlowFrame() && !SwFlowFrame::CastFlowFrame( this )->IsFollow() )
    {
        SwFormatPageDesc &rDesc = const_cast<SwFormatPageDesc&>(GetPageDescItem());
        pDesc = rDesc.GetPageDesc();
        if ( rDesc.GetNumOffset() )
        {
            ::std::optional<sal_uInt16> oNumOffset = rDesc.GetNumOffset();
            bWishedRightPage = sw::IsRightPageByNumber(*pRoot, *oNumOffset);
            // use the opportunity to set the flag at root
            pRoot->SetVirtPageNum( true );
        }
    }
    if ( !pDesc )
        pDesc = pPrevPage->GetPageDesc()->GetFollow();

    assert(pDesc && "Missing PageDesc");
    if( !(bWishedRightPage ? pDesc->GetRightFormat() : pDesc->GetLeftFormat()) )
        bWishedRightPage = !bWishedRightPage;
    bool const bWishedFirst = pDesc != pPrevPage->GetPageDesc();

    SwDoc& rDoc = pPrevPage->GetFormat()->GetDoc();
    bool bCheckPages = false;
    // If there is no FrameFormat for this page, create an empty page.
    if (bWishedRightPage != bNextRightPage)
    {
        if( doInsertPage( pRoot, &pSibling, rDoc.GetEmptyPageFormat(),
                          pPrevPage->GetPageDesc(), bFootnote, nullptr ) )
            bCheckPages = true;
    }
    SwFrameFormat *const pFormat( bWishedRightPage
            ? pDesc->GetRightFormat(bWishedFirst)
            : pDesc->GetLeftFormat(bWishedFirst) );
    assert(pFormat);
    SwPageFrame *pPage = nullptr;
    if( doInsertPage( pRoot, &pSibling, pFormat, pDesc, bFootnote, &pPage ) )
        bCheckPages = true;

    if ( pSibling )
    {
        if ( bCheckPages )
        {
            CheckPageDescs( pSibling, false );
            SwViewShell *pSh = getRootFrame()->GetCurrShell();
            SwViewShellImp *pImp = pSh ? pSh->Imp() : nullptr;
            if ( pImp && pImp->IsAction() && !pImp->GetLayAction().IsCheckPages() )
            {
                const sal_uInt16 nNum = pImp->GetLayAction().GetCheckPageNum();
                if ( nNum == pPrevPage->GetPhyPageNum() + 1 )
                {
                    pImp->GetLayAction().SetCheckPageNumDirect(
                                                    pSibling->GetPhyPageNum() );
                    SAL_INFO( "sw.pageframe""InsertPage - SetCheckPageNumDirect: "
                              << pSibling->GetPhyPageNum() );
                }
                return pPage;
            }
        }
        else
            SwRootFrame::AssertPageFlys( pSibling );
    }

    // For the update of page numbering fields, nDocPos provides
    // the page position from where invalidation should start.
    SwViewShell *pSh = getRootFrame()->GetCurrShell();
    if ( !pSh || !pSh->Imp()->IsUpdateExpFields() )
    {
        rDoc.getIDocumentFieldsAccess().UpdatePageFields(pPrevPage->getFrameArea().Top());
    }
    return pPage;
}

sw::sidebarwindows::SidebarPosition SwPageFrame::SidebarPosition() const
{
    SwViewShell *pSh = getRootFrame()->GetCurrShell();
    if( !pSh || pSh->GetViewOptions()->getBrowseMode() )
    {
        return sw::sidebarwindows::SidebarPosition::RIGHT;
    }
    else
    {
        const bool bLTR = getRootFrame()->IsLeftToRightViewLayout();
        const bool bBookMode = pSh->GetViewOptions()->IsViewLayoutBookMode();
        const bool bRightSidebar = bLTR ? (!bBookMode || OnRightPage()) : (bBookMode && !OnRightPage());

        return bRightSidebar
               ? sw::sidebarwindows::SidebarPosition::RIGHT
               : sw::sidebarwindows::SidebarPosition::LEFT;
    }
}

SwTwips SwRootFrame::GrowFrame(SwTwips nDist, SwResizeLimitReason& reason, bool bTst, bool)
{
    if ( !bTst )
    {
        SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
        aFrm.AddHeight(nDist );
    }
    reason = SwResizeLimitReason::Unspecified;
    return nDist;
}

SwTwips SwRootFrame::ShrinkFrame( SwTwips nDist, bool bTst, bool )
{
    OSL_ENSURE( nDist >= 0, "nDist < 0." );
    OSL_ENSURE( nDist <= getFrameArea().Height(), "nDist greater than current size." );

    if ( !bTst )
    {
        SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
        aFrm.AddHeight( -nDist );
    }

    return nDist;
}

void SwRootFrame::RemovePage( SwPageFrame **pDelRef, SwRemoveResult eResult )
{
    SwPageFrame *pDel = *pDelRef;
    (*pDelRef) = static_cast<SwPageFrame*>(
        eResult == SwRemoveResult::Next ? pDel->GetNext() : pDel->GetPrev() );
    if ( !GetFormat()->GetDoc().GetFootnoteIdxs().empty() )
        RemoveFootnotes( pDel, true );
    pDel->Cut();
    SwFrame::DestroyFrame( pDel );
}

/// remove pages that are not needed at all
void SwRootFrame::RemoveSuperfluous()
{
    // A page is empty if the body text area has no ContentFrame, but not if there
    // is at least one Fly or one footnote attached to the page. Two runs are
    // needed: one for endnote pages and one for the pages of the body text.

    if ( !IsSuperfluous() )
        return;
    mbCheckSuperfluous = false;

    SwPageFrame *pPage = GetLastPage();
    tools::Long nDocPos = LONG_MAX;

    // Check the corresponding last page if it is empty and stop loop at the last non-empty page.
    do
    {
        if (!sw::IsPageFrameEmpty(*pPage))
        {
            if ( pPage->IsFootnotePage() )
            {
                while ( pPage->IsFootnotePage() )
                {
                    pPage = static_cast<SwPageFrame*>(pPage->GetPrev());
                    assert(pPage && "only endnote pages remain.");
                }
                continue;
            }
            else
                pPage = nullptr;
        }

        if ( pPage )
        {
            SAL_INFO( "sw.pageframe""RemoveSuperfluous - DestroyFrm p: " << pPage );
            RemovePage( &pPage, SwRemoveResult::Prev );
            nDocPos = pPage ? pPage->getFrameArea().Top() : 0;
        }
    } while ( pPage );

    SwViewShell *pSh = getRootFrame()->GetCurrShell();
    if ( nDocPos != LONG_MAX &&
         (!pSh || !pSh->Imp()->IsUpdateExpFields()) )
    {
        GetFormat()->GetDoc().getIDocumentFieldsAccess().UpdatePageFields(nDocPos);
    }
}

/// Ensures that enough pages exist, so that all page bound frames and draw objects can be placed
void SwRootFrame::AssertFlyPages()
{
    if ( !IsAssertFlyPages() )
        return;
    mbAssertFlyPages = false;

    SwDoc& rDoc = GetFormat()->GetDoc();
    const sw::SpzFrameFormats* pSpzs = rDoc.GetSpzFrameFormats();

    // what page targets the "last" Fly?
    // note the needed pages in a set
    sal_uInt16 nMaxPg(0);
    o3tl::sorted_vector< sal_uInt16 > neededPages;
    neededPages.reserve(pSpzs->size());

    for(auto pSpz: *pSpzs )
    {
        const SwFormatAnchor &rAnch = pSpz->GetAnchor();
        if(!rAnch.GetAnchorNode())
        {
            const sal_uInt16 nPageNum(rAnch.GetPageNum());

            // calc MaxPage (as before)
            nMaxPg = std::max(nMaxPg, nPageNum);

            // note as needed page
            neededPages.insert(nPageNum);
        }
    }

    // How many pages exist at the moment?
    // And are there EmptyPages that are needed?
    SwPageFrame* pPage(static_cast<SwPageFrame*>(Lower()));
    SwPageFrame* pPrevPage(nullptr);
    SwPageFrame* pFirstRevivedEmptyPage(nullptr);

    while(pPage) // moved two while-conditions to break-statements (see below)
    {
        const sal_uInt16 nPageNum(pPage->GetPhyPageNum());

        if(pPage->IsEmptyPage() &&
            nullptr != pPrevPage &&
            neededPages.find(nPageNum) != neededPages.end())
        {
            // This is an empty page, but it *is* needed since a SwFrame
            // is anchored at it directly. Initially these SwFrames are
            // not fully initialized. Need to change the format of this SwFrame
            // and let the ::Notify mechanism newly evaluate
            // m_bEmptyPage (see SwPageFrame::UpdateAttr_). Code is taken and
            // adapted from ::InsertPage (used below), this needs previous page
            bool bWishedRightPage(!pPrevPage->OnRightPage());
            SwPageDesc* pDesc(pPrevPage->GetPageDesc()->GetFollow());
            assert(pDesc && "Missing PageDesc");

            if (!(bWishedRightPage ? pDesc->GetRightFormat() : pDesc->GetLeftFormat()))
            {
                bWishedRightPage = !bWishedRightPage;
            }

            bool const bWishedFirst(pDesc != pPrevPage->GetPageDesc());
            SwFrameFormat* pFormat(bWishedRightPage ? pDesc->GetRightFormat(bWishedFirst) : pDesc->GetLeftFormat(bWishedFirst));

            // set SwFrameFormat, this will trigger SwPageFrame::UpdateAttr_ and re-evaluate
            // m_bEmptyPage, too
            pPage->SetFrameFormat(pFormat);

            if(nullptr == pFirstRevivedEmptyPage)
            {
                // remember first (lowest) SwPageFrame which needed correction
                pFirstRevivedEmptyPage = pPage;
            }
        }

        // original while-condition II
        if(nullptr == pPage->GetNext())
        {
            break;
        }

        // original while-condition III
        if(static_cast< SwPageFrame* >(pPage->GetNext())->IsFootnotePage())
        {
            break;
        }

        pPrevPage = pPage;
        pPage = static_cast<SwPageFrame*>(pPage->GetNext());
    }

    assert(pPage);

    if ( nMaxPg > pPage->GetPhyPageNum() )
    {
        for ( sal_uInt16 i = pPage->GetPhyPageNum(); i < nMaxPg; ++i )
            pPage = InsertPage( pPage, false );

        // If the endnote pages are now corrupt, destroy them.
        if ( !rDoc.GetFootnoteIdxs().empty() )
        {
            pPage = static_cast<SwPageFrame*>(Lower());
            while ( pPage && !pPage->IsFootnotePage() )
                pPage = static_cast<SwPageFrame*>(pPage->GetNext());

            if ( pPage )
            {
                SwPageDesc *pTmpDesc = pPage->FindPageDesc();
                bool isRightPage = pPage->OnRightPage();
                if ( pPage->GetFormat() !=
                     (isRightPage ? pTmpDesc->GetRightFormat() : pTmpDesc->GetLeftFormat()) )
                    RemoveFootnotes( pPage, falsetrue );
            }
        }
    }

    // if we corrected SwFrameFormat and changed one (or more) m_bEmptyPage
    // flags, we need to correct evtl. currently wrong positioned SwFrame(s)
    // which did think until now that these Page(s) are empty.
    // After trying to correct myself I found SwRootFrame::AssertPageFlys
    // directly below that already does that, so use it.
    if(nullptr != pFirstRevivedEmptyPage)
    {
        AssertPageFlys(pFirstRevivedEmptyPage);
    }

    //Remove masters that haven't been replaced yet from the list.
    RemoveMasterObjs( mpDrawPage );

#if OSL_DEBUG_LEVEL > 0
    pPage = static_cast<SwPageFrame*>(Lower());
    while ( pPage->GetNext() &&
            !static_cast<SwPageFrame*>(pPage->GetNext())->IsFootnotePage() )
    {
        SAL_INFO( "sw.pageframe",  "AssertFlyPages p: " << pPage << " d: " << pPage->GetPageDesc()
                   << " f: " << pPage->GetFormat() << " virt: " << pPage->GetVirtPageNum()
                   << " phys: " << pPage->GetPhyPageNum() << " empty: " << pPage->IsEmptyPage() );
--> --------------------

--> maximum size reached

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

Messung V0.5
C=95 H=93 G=93

¤ Dauer der Verarbeitung: 0.19 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

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

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.