Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  sectfrm.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 <sal/config.h>
#include <sal/log.hxx>

#include <o3tl/safeint.hxx>
#include <osl/diagnose.h>
#include <svl/itemiter.hxx>
#include <txtftn.hxx>
#include <fmtftn.hxx>
#include <fmtclbl.hxx>
#include <sectfrm.hxx>
#include <cellfrm.hxx>
#include <section.hxx>
#include <IDocumentSettingAccess.hxx>
#include <rootfrm.hxx>
#include <pagefrm.hxx>
#include <txtfrm.hxx>
#include <fmtclds.hxx>
#include <colfrm.hxx>
#include <tabfrm.hxx>
#include <ftnfrm.hxx>
#include "layhelp.hxx"
#include <layouter.hxx>
#include <dbg_lay.hxx>
#include <viewopt.hxx>
#include <viewimp.hxx>
#include <editeng/brushitem.hxx>
#include <fmtftntx.hxx>
#include <flyfrm.hxx>
#include <sortedobjs.hxx>
#include <hints.hxx>
#include <frmatr.hxx>
#include <frmtool.hxx>

namespace
{
/**
 * Performs the correct type of position invalidation depending on if we're in
 * CalcContent().
 */

void InvalidateFramePos(SwFrame* pFrame, bool bInCalcContent)
{
    if (bInCalcContent)
        pFrame->InvalidatePos_();
    else
        pFrame->InvalidatePos();
}
}

SwSectionFrame::SwSectionFrame( SwSection &rSect, SwFrame* pSib )
    : SwLayoutFrame( rSect.GetFormat(), pSib )
    , SwFlowFrame( static_cast<SwFrame&>(*this) )
    , m_pSection( &rSect )
    , m_bFootnoteAtEnd(false)
    , m_bEndnAtEnd(false)
    , m_bContentLock(false)
    , m_bOwnFootnoteNum(false)
    , m_bFootnoteLock(false)
{
    StartListening(rSect.GetFormat()->GetNotifier());

    mnFrameType = SwFrameType::Section;

    CalcFootnoteAtEndFlag();
    CalcEndAtEndFlag();
}

SwSectionFrame::SwSectionFrame( SwSectionFrame &rSect, bool bMaster ) :
    SwLayoutFrame( rSect.GetFormat(), rSect.getRootFrame() ),
    SwFlowFrame( static_cast<SwFrame&>(*this) ),
    m_pSection( rSect.GetSection() ),
    m_bFootnoteAtEnd( rSect.IsFootnoteAtEnd() ),
    m_bEndnAtEnd( rSect.IsEndnAtEnd() ),
    m_bContentLock( false ),
    m_bOwnFootnoteNum( false ),
    m_bFootnoteLock( false )
{
    m_bEndNoteSection = rSect.m_bEndNoteSection;
    StartListening(rSect.GetFormat()->GetNotifier());

    mnFrameType = SwFrameType::Section;

    PROTOCOL( this, PROT::Section, bMaster ? DbgAction::CreateMaster : DbgAction::CreateFollow, &rSect )

    if( bMaster )
    {
        SwSectionFrame* pMaster = rSect.IsFollow() ? rSect.FindMaster() : nullptr;
        if (pMaster)
            pMaster->SetFollow( this );
        SetFollow( &rSect );
    }
    else
    {
        SetFollow( rSect.GetFollow() );
        rSect.SetFollow( this );
        if( !GetFollow() )
            rSect.SimpleFormat();
        if( !rSect.IsColLocked() )
            rSect.InvalidateSize();
    }
}

// NOTE: call <SwSectionFrame::Init()> directly after creation of a new section
//       frame and its insert in the layout.
void SwSectionFrame::Init()
{
    assert(GetUpper() && "SwSectionFrame::Init before insertion?!");
    SwRectFnSet aRectFnSet(this);
    tools::Long nWidth = aRectFnSet.GetWidth(GetUpper()->getFramePrintArea());

    {
        SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
        aRectFnSet.SetWidth( aFrm, nWidth );
        aRectFnSet.SetHeight( aFrm, 0 );
    }

    // #109700# LRSpace for sections
    const SvxLRSpaceItem& rLRSpace = GetFormat()->GetLRSpace();

    {
        SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this);
        aRectFnSet.SetLeft(aPrt, rLRSpace.ResolveLeft({}));
        aRectFnSet.SetWidth(aPrt, nWidth - rLRSpace.ResolveLeft({}) - rLRSpace.ResolveRight({}));
        aRectFnSet.SetHeight( aPrt, 0 );
    }

    const SwFormatCol &rCol = GetFormat()->GetCol();
    if( ( rCol.GetNumCols() > 1 || IsAnyNoteAtEnd() ) && !IsInFootnote() )
    {
        const SwFormatCol *pOld = Lower() ? &rCol : new SwFormatCol;
        ChgColumns( *pOld, rCol, IsAnyNoteAtEnd() );
        if (!SfxPoolItem::areSame( pOld, &rCol ))
            delete pOld;
    }
}

void SwSectionFrame::DestroyImpl()
{
    if( GetFormat() && !GetFormat()->GetDoc().IsInDtor() )
    {
        SwRootFrame *pRootFrame = getRootFrame();
        if( pRootFrame )
            pRootFrame->RemoveFromList( this );
        if( IsFollow() )
        {
            SwSectionFrame *pMaster = FindMaster();
            if( pMaster )
            {
                PROTOCOL( this, PROT::Section, DbgAction::DelFollow, pMaster )
                pMaster->SetFollow( GetFollow() );
                // A Master always grabs the space until the lower edge of his
                // Upper. If he doesn't have a Follow anymore, he can
                // release it, which is why the Size of the Master is
                // invalidated.
                if( !GetFollow() )
                    pMaster->InvalidateSize();
            }
        }
#if defined DBG_UTIL
        else if( HasFollow() )
        {
            PROTOCOL( this, PROT::Section, DbgAction::DelMaster, GetFollow() )
        }
#endif
    }

    SwLayoutFrame::DestroyImpl();
}

SwSectionFrame::~SwSectionFrame()
{
}

//virtual
bool SwSectionFrame::IsHiddenNow() const
{
    const auto* pSection = GetSection();
    return !pSection || pSection->CalcHiddenFlag();
}

void SwSectionFrame::DelEmpty( bool bRemove )
{
    if( IsColLocked() )
    {
        OSL_ENSURE( !bRemove, "Don't delete locked SectionFrames" );
        return;
    }
    SwFrame* pUp = GetUpper();
    if( pUp )
    {
        // #i27138#
        // notify accessibility paragraphs objects about changed
        // CONTENT_FLOWS_FROM/_TO relation.
        // Relation CONTENT_FLOWS_FROM for current next paragraph will change
        // and relation CONTENT_FLOWS_TO for current previous paragraph will change.
#if !ENABLE_WASM_STRIP_ACCESSIBILITY
        {
            SwViewShell* pViewShell( getRootFrame()->GetCurrShell() );
            if ( pViewShell && pViewShell->GetLayout() &&
                 pViewShell->GetLayout()->IsAnyShellAccessible() )
            {
                auto pNext = FindNextCnt( true );
                auto pPrev = FindPrevCnt();
                pViewShell->InvalidateAccessibleParaFlowRelation(
                                pNext ? pNext->DynCastTextFrame() : nullptr,
                                pPrev ? pPrev->DynCastTextFrame() : nullptr );
            }
        }
#endif
        Cut_( bRemove );
    }
    SwSectionFrame *pMaster = IsFollow() ? FindMaster() : nullptr;
    if (pMaster)
    {
        pMaster->SetFollow( GetFollow() );
        // A Master always grabs the space until the lower edge of his
        // Upper. If he doesn't have a Follow anymore, he can
        // release it, which is why the Size of the Master is
        // invalidated.
        if( !GetFollow() && !pMaster->IsColLocked() )
            pMaster->InvalidateSize();
    }
    SetFollow(nullptr);
    if( !pUp )
        return;

    {
        SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
        aFrm.Height( 0 );
    }

    // If we are destroyed immediately anyway, we don't need
    // to put us into the list
    if( bRemove )
    {   // If we already were half dead before this DelEmpty,
        // we are likely in the list and have to remove us from
        // it
        if( !m_pSection && getRootFrame() )
            getRootFrame()->RemoveFromList( this );
    }
    else if( getRootFrame() )
    {
        getRootFrame()->InsertEmptySct( this );
    }

    m_pSection = nullptr;  // like this a reanimation is virtually impossible though
}

void SwSectionFrame::Cut()
{
    Cut_( true );
}

void SwSectionFrame::Cut_( bool bRemove )
{
    OSL_ENSURE( GetUpper(), "Cut without Upper()." );

    PROTOCOL( this, PROT::Cut, DbgAction::NONE, GetUpper() )

    SwPageFrame *pPage = FindPageFrame();
    InvalidatePage( pPage );
    SwFrame *pFrame = GetNext();
    SwFrame* pPrepFrame = nullptr;
    while( pFrame && pFrame->IsSctFrame() && !static_cast<SwSectionFrame*>(pFrame)->GetSection() )
        pFrame = pFrame->GetNext();
    if( pFrame )
    {   // The former successor might have calculated a gap to the predecessor
        // which is now obsolete since he becomes the first
        pFrame->InvalidatePrt_();
        pFrame->InvalidatePos_();
        if( pFrame->IsSctFrame() )
            pFrame = static_cast<SwSectionFrame*>(pFrame)->ContainsAny();
        if ( pFrame && pFrame->IsContentFrame() )
        {
            pFrame->InvalidatePage( pPage );
            if( IsInFootnote() && !GetIndPrev() )
                pPrepFrame = pFrame;
        }
    }
    else
    {
        InvalidateNextPos();
        // Someone has to take over the retouching: predecessor or Upper
        pFrame = GetPrev();
        if ( nullptr != pFrame )
        {
            pFrame->SetRetouche();
            pFrame->Prepare( PrepareHint::WidowsOrphans );
            if ( pFrame->IsContentFrame() )
                pFrame->InvalidatePage( pPage );
        }
        // If I am (was) the only FlowFrame in my Upper, then he has to take over
        // the retouching.
        // Furthermore a blank page could have emerged
        else
        {   SwRootFrame *pRoot = static_cast<SwRootFrame*>(pPage->GetUpper());
            pRoot->SetSuperfluous();
            GetUpper()->SetCompletePaint();
        }
    }
    // First remove, then shrink Upper
    SwLayoutFrame *pUp = GetUpper();
    if( bRemove )
    {
        RemoveFromLayout();
        if( pUp && !pUp->Lower() && pUp->IsFootnoteFrame() && !pUp->IsColLocked() &&
            pUp->GetUpper() )
        {
            pUp->Cut();
            SwFrame::DestroyFrame(pUp);
            pUp = nullptr;
        }
    }
    if( pPrepFrame )
        pPrepFrame->Prepare( PrepareHint::FootnoteInvalidation );
    if ( !pUp )
        return;

    SwRectFnSet aRectFnSet(this);
    SwTwips nFrameHeight = aRectFnSet.GetHeight(getFrameArea());
    if( nFrameHeight <= 0 )
        return;

    if( !bRemove )
    {
        SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
        aRectFnSet.SetHeight( aFrm, 0 );

        SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this);
        aRectFnSet.SetHeight( aPrt, 0 );
    }

    pUp->Shrink( nFrameHeight );
}

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

    PROTOCOL( this, PROT::Paste, DbgAction::NONE, GetUpper() )

    // Add to the tree
    SwSectionFrame* pSect = pParent->FindSctFrame();
    // Assure that parent is not inside a table frame, which is inside the found section frame.
    if ( pSect )
    {
        SwTabFrame* pTableFrame = pParent->FindTabFrame();
        if ( pTableFrame &&
             pSect->IsAnLower( pTableFrame ) )
        {
            pSect = nullptr;
        }
    }

    SwRectFnSet aRectFnSet(pParent);
    if( pSect && HasToBreak( pSect ) )
    {
        if( pParent->IsColBodyFrame() ) // dealing with a single-column area
        {
            // If we are coincidentally at the end of a column, pSibling
            // has to point to the first frame of the next column in order
            // for the content of the next column to be moved correctly to the
            // newly created pSect by the InsertGroup
            SwColumnFrame *pCol = static_cast<SwColumnFrame*>(pParent->GetUpper());
            while( !pSibling && nullptr != ( pCol = static_cast<SwColumnFrame*>(pCol->GetNext()) ) )
                pSibling = static_cast<SwLayoutFrame*>(pCol->Lower())->Lower();
            if( pSibling )
            {
                // Even worse: every following column content has to
                // be attached to the pSibling-chain in order to be
                // taken along
                SwFrame *pTmp = pSibling;
                while ( nullptr != ( pCol = static_cast<SwColumnFrame*>(pCol->GetNext()) ) )
                {
                    while ( pTmp->GetNext() )
                        pTmp = pTmp->GetNext();
                    SwFrame* pSave = ::SaveContent( pCol );
                    if (pSave)
                        ::RestoreContent( pSave, pSibling->GetUpper(), pTmp );
                }
            }
        }
        pParent = pSect;
        pSect = new SwSectionFrame( *static_cast<SwSectionFrame*>(pParent)->GetSection(), pParent );
        // if pParent is decomposed into two parts, its Follow has to be attached
        // to the new second part
        pSect->SetFollow( static_cast<SwSectionFrame*>(pParent)->GetFollow() );
        static_cast<SwSectionFrame*>(pParent)->SetFollow( nullptr );
        if( pSect->GetFollow() )
            pParent->InvalidateSize_();

        const bool bInserted = InsertGroupBefore( pParent, pSibling, pSect );
        if (bInserted)
        {
            pSect->Init();
            aRectFnSet.MakePos( *pSect, pSect->GetUpper(), pSect->GetPrev(), true);
        }
        if( !static_cast<SwLayoutFrame*>(pParent)->Lower() )
        {
            SwSectionFrame::MoveContentAndDelete( static_cast<SwSectionFrame*>(pParent), false );
            pParent = this;
        }
    }
    else
        InsertGroupBefore( pParent, pSibling, nullptr );

    InvalidateAll_();
    SwPageFrame *pPage = FindPageFrame();
    InvalidatePage( pPage );

    if ( pSibling )
    {
        pSibling->InvalidatePos_();
        pSibling->InvalidatePrt_();
        if ( pSibling->IsContentFrame() )
            pSibling->InvalidatePage( pPage );
    }

    SwTwips nFrameHeight = aRectFnSet.GetHeight(getFrameArea());
    if( nFrameHeight )
        pParent->Grow( nFrameHeight );

    if ( GetPrev() && !IsFollow() )
    {
        GetPrev()->InvalidateSize();
        if ( GetPrev()->IsContentFrame() )
            GetPrev()->InvalidatePage( pPage );
    }
}

/**
|*  Here it's decided whether the this-SectionFrame should break up
|*  the passed (Section)frm (or not).
|*  Initially, all superior sections are broken up. Later on that could
|*  be made configurable.
|*/

bool SwSectionFrame::HasToBreak( const SwFrame* pFrame ) const
{
    if( !pFrame->IsSctFrame() )
        return false;

    const SwSectionFormat *pTmp = static_cast<const SwSectionFormat*>(GetFormat());

    const SwFrameFormat *pOtherFormat = static_cast<const SwSectionFrame*>(pFrame)->GetFormat();
    do
    {
        pTmp = pTmp->GetParent();
        if( !pTmp )
            return false;
        if( pTmp == pOtherFormat )
            return true;
    } whiletrue ); // ( pTmp->GetSect().GetValue() );
}

/**
|*  Merges two SectionFrames, in case it's about the same section.
|*  This can be necessary when a (sub)section is deleted that had
|*  divided another part into two.
|*/

void SwSectionFrame::MergeNext( SwSectionFrame* pNxt )
{
    if (pNxt->IsDeleteForbidden())
        return;

    if (pNxt->IsJoinLocked() || GetSection() != pNxt->GetSection())
        return;

    PROTOCOL( this, PROT::Section, DbgAction::Merge, pNxt )

    SwFrame* pTmp = ::SaveContent( pNxt );
    if( pTmp )
    {
        SwFrame* pLast = Lower();
        SwLayoutFrame* pLay = this;
        if( pLast )
        {
            while( pLast->GetNext() )
                pLast = pLast->GetNext();
            if( pLast->IsColumnFrame() )
            {   // Columns now with BodyFrame
                pLay = static_cast<SwLayoutFrame*>(static_cast<SwLayoutFrame*>(pLast)->Lower());
                pLast = pLay->Lower();
                if( pLast )
                    while( pLast->GetNext() )
                        pLast = pLast->GetNext();
            }
        }
        ::RestoreContent( pTmp, pLay, pLast );
    }
    SetFollow( pNxt->GetFollow() );
    pNxt->SetFollow( nullptr );
    pNxt->Cut();
    SwFrame::DestroyFrame(pNxt);
    InvalidateSize();
}

/**
|*  Divides a SectionFrame into two parts. The content of the second one
|*  starts after pFrameStartAfter; the created second section frame itself
|*  is put after pFramePutAfter.
|*  If pFrameStartAfter is nullptr, the split happens at the start.
|*  This is required when inserting an inner section, because the MoveFwd
|*  cannot have the desired effect within a frame or a table cell.
|*  Splitting at the start/end makes sense, because the empty frame would
|*  be removed after the InsertCnt_ finished.
|*/

SwSectionFrame* SwSectionFrame::SplitSect( SwFrame* pFrameStartAfter, SwFrame* pFramePutAfter )
{
    assert(!pFrameStartAfter || IsAnLower(pFrameStartAfter));
    SwFrame* pSav;
    if (pFrameStartAfter)
    {
        pSav = pFrameStartAfter->FindNext();
        // If pFrameStartAfter is a complex object like table, and it has no next,
        // its FindNext may return its own last subframe. In this case, assume that
        // we are at the end.
        if (pSav && pFrameStartAfter->IsLayoutFrame())
            if (static_cast<SwLayoutFrame*>(pFrameStartAfter)->IsAnLower(pSav))
                pSav = nullptr;
    }
    else
    {
        pSav = ContainsAny();
    }
    if (pSav && !IsAnLower(pSav))
        pSav = nullptr; // we are at the very end

    // Put the content aside
    if (pSav)
        pSav = ::SaveContent( this, pSav );

    // Create a new SctFrame, not as a Follower/master
    if (!pFramePutAfter)
        pFramePutAfter = this;
    SwSectionFrame* pNew = new SwSectionFrame( *GetSection(), this );
    pNew->InsertBehind( pFramePutAfter->GetUpper(), pFramePutAfter );
    pNew->Init();
    SwRectFnSet aRectFnSet(this);
    aRectFnSet.MakePos( *pNew, nullptr, pFramePutAfter, true );
    // OD 25.03.2003 #108339# - restore content:
    // determine layout frame for restoring content after the initialization
    // of the section frame. In the section initialization the columns are
    // created.
    if (pSav)
    {
        SwLayoutFrame* pLay = pNew;
        // Search for last layout frame, e.g. for columned sections.
        SwFrame* pLower = pLay->Lower();
        while( pLower && pLower->IsLayoutFrame() )
        {
            pLay = static_cast<SwLayoutFrame*>(pLower);
            pLower = pLay->Lower();
        }
        ::RestoreContent( pSav, pLay, nullptr );
    }
    InvalidateSize_();
    if( HasFollow() )
    {
        pNew->SetFollow( GetFollow() );
        SetFollow( nullptr );
    }
    return pNew;
}

/**
|*  MoveContent is called for destroying a SectionFrames, due to
|*  the cancellation or hiding of a section, to handle the content.
|*  If the SectionFrame hasn't broken up another one, then the content
|*  is moved to the Upper. Otherwise the content is moved to another
|*  SectionFrame, which has to be potentially merged.
|*/

// If a multi-column section is cancelled, the ContentFrames have to be
// invalidated
static void lcl_InvalidateInfFlags( SwFrame* pFrame, bool bInva )
{
    while ( pFrame )
    {
        pFrame->InvalidateInfFlags();
        if( bInva )
        {
            pFrame->InvalidatePos_();
            pFrame->InvalidateSize_();
            pFrame->InvalidatePrt_();
        }
        pFrame = pFrame->GetNext();
    }
}

// Works like SwContentFrame::ImplGetNextContentFrame, but starts with a LayoutFrame
static SwContentFrame* lcl_GetNextContentFrame( const SwLayoutFrame* pLay, bool bFwd )
{
    if ( bFwd )
    {
        if ( pLay->GetNext() && pLay->GetNext()->IsContentFrame() )
            return const_cast<SwContentFrame*>(static_cast<const SwContentFrame*>(pLay->GetNext()));
    }
    else
    {
        if ( pLay->GetPrev() && pLay->GetPrev()->IsContentFrame() )
            return const_cast<SwContentFrame*>(static_cast<const SwContentFrame*>(pLay->GetPrev()));
    }

    const SwFrame* pFrame = pLay;
    SwContentFrame *pContentFrame = nullptr;
    bool bGoingUp = true;
    do {
        const SwFrame *p = nullptr;
        bool bGoingFwdOrBwd = false;

        bool bGoingDown = !bGoingUp && pFrame->IsLayoutFrame();
        if (bGoingDown)
        {
            p = static_cast<const SwLayoutFrame*>(pFrame)->Lower();
            bGoingDown = nullptr != p;
        }
        if ( !bGoingDown )
        {
            p = pFrame->IsFlyFrame() ?
                ( bFwd ? static_cast<const SwFlyFrame*>(pFrame)->GetNextLink() : static_cast<const SwFlyFrame*>(pFrame)->GetPrevLink() ) :
                ( bFwd ? pFrame->GetNext() :pFrame->GetPrev() );
            bGoingFwdOrBwd = nullptr != p;
            if ( !bGoingFwdOrBwd )
            {
                p = pFrame->GetUpper();
                bGoingUp = nullptr != p;
                if ( !bGoingUp )
                    return nullptr;
            }
        }

        bGoingUp = !( bGoingFwdOrBwd || bGoingDown );
        assert(p);
        if (!bFwd && bGoingDown)
            while ( p->GetNext() )
                p = p->GetNext();

        pFrame = p;
    } while ( nullptr == (pContentFrame = (pFrame->IsContentFrame() ? const_cast<SwContentFrame*>(static_cast<const SwContentFrame*>(pFrame)) : nullptr) ));

    return pContentFrame;
}

namespace
{
    SwLayoutFrame* FirstLeaf(SwSectionFrame* pLayFrame)
    {
        SwFrame* pLower = pLayFrame->Lower();
        if (pLower && pLower->IsColumnFrame())
            return pLayFrame->GetNextLayoutLeaf();
        return pLayFrame;
    }

    /// Checks if pFrame has a parent that can contain a split section frame.
    bool CanContainSplitSection(const SwFrame* pFrame)
    {
        if (!pFrame->IsInTab())
            return true;

        // The frame is in a table, see if the table is in a section.
        bool bRet = !pFrame->FindTabFrame()->IsInSct();

        if (bRet)
        {
            // Don't try to split if the frame itself is a section frame with
            // multiple columns.
            if (pFrame->IsSctFrame())
            {
                const SwFrame* pLower = pFrame->GetLower();
                if (pLower && pLower->IsColumnFrame())
                    bRet = false;
            }
        }

        return bRet;
    }
}

void SwSectionFrame::MoveContentAndDelete( SwSectionFrame* pDel, bool bSave )
{
    bool bSize = pDel->Lower() && pDel->Lower()->IsColumnFrame();
    SwFrame* pPrv = pDel->GetPrev();
    SwLayoutFrame* pUp = pDel->GetUpper();
    // OD 27.03.2003 #i12711# - initialize local pointer variables.
    SwSectionFrame* pPrvSct = nullptr;
    SwSectionFrame* pNxtSct = nullptr;
    SwSectionFormat* pParent = static_cast<SwSectionFormat*>(pDel->GetFormat())->GetParent();
    if( pDel->IsInTab() && pParent )
    {
        SwTabFrame *pTab = pDel->FindTabFrame();
        // If we are within a table, we can only have broken up sections that
        // are inside as well, but not a section that contains the whole table.
        if( pTab->IsInSct() && pParent == pTab->FindSctFrame()->GetFormat() )
            pParent = nullptr;
    }
    // If our Format has a parent, we have probably broken up another
    // SectionFrame, which has to be checked. To do so we first acquire the
    // succeeding and the preceding ContentFrame, let's see if they
    // lay in the SectionFrames.
    // OD 27.03.2003 #i12711# - check, if previous and next section belonging
    // together and can be joined, *not* only if deleted section contains content.
    if ( pParent )
    {
        SwFrame* pPrvContent = lcl_GetNextContentFrame( pDel, false );
        pPrvSct = pPrvContent ? pPrvContent->FindSctFrame() : nullptr;
        SwFrame* pNxtContent = lcl_GetNextContentFrame( pDel, true );
        pNxtSct = pNxtContent ? pNxtContent->FindSctFrame() : nullptr;
    }
    else
    {
        pParent = nullptr;
        pPrvSct = pNxtSct = nullptr;
    }

    // Now the content is put aside and the frame is destroyed
    SwFrame *pSave = bSave ? ::SaveContent( pDel ) : nullptr;
    bool bOldFootnote = true;
    if( pSave && pUp->IsFootnoteFrame() )
    {
        bOldFootnote = static_cast<SwFootnoteFrame*>(pUp)->IsColLocked();
        static_cast<SwFootnoteFrame*>(pUp)->ColLock();
    }
    pDel->DelEmpty( true );
    SwFrame::DestroyFrame(pDel);
    if( pParent )
    {   // Search for the appropriate insert position
        if( pNxtSct && pNxtSct->GetFormat() == pParent )
        {   // Here we can insert ourselves at the beginning
            pUp = FirstLeaf( pNxtSct );
            pPrv = nullptr;
            if( pPrvSct && ( pPrvSct->GetFormat() != pParent ) )
                pPrvSct = nullptr; // In order that nothing is merged
        }
        else if( pPrvSct && pPrvSct->GetFormat() == pParent )
        {   // Wonderful, here we can insert ourselves at the end
            pUp = pPrvSct;
            SwFrame* pLower = pUp->Lower();
            if( pLower && pLower->IsColumnFrame() )
            {
                pUp = static_cast<SwLayoutFrame*>(pUp->GetLastLower());
                // The body of the last column
                pUp = static_cast<SwLayoutFrame*>(pUp->Lower());
            }
            // In order to perform the insertion after the last one
            pPrv = pUp->GetLastLower();
            pPrvSct = nullptr; // Such that nothing is merged
        }
        else
        {
            if( pSave )
            {   // Following situations: before and after the section-to-be
                // deleted there is the section boundary of the enclosing
                // section, or another (sibling) section connects subsequently,
                // that derives from the same Parent.
                // In that case, there's not (yet) a part of our parent available
                // that can store the content, so we create it here.
                pPrvSct = new SwSectionFrame( *pParent->GetSection(), pUp );
                pPrvSct->InsertBehind( pUp, pPrv );
                pPrvSct->Init();
                SwRectFnSet aRectFnSet(pUp);
                aRectFnSet.MakePos( *pPrvSct, pUp, pPrv, true );
                pUp = FirstLeaf( pPrvSct );
                pPrv = nullptr;
            }
            pPrvSct = nullptr; // Such that nothing will be merged
        }
    }
    // The content is going to be inserted...
    if( pSave )
    {
        lcl_InvalidateInfFlags( pSave, bSize );
        ::RestoreContent( pSave, pUp, pPrv );
        pUp->FindPageFrame()->InvalidateContent();
        if( !bOldFootnote )
            static_cast<SwFootnoteFrame*>(pUp)->ColUnlock();
    }
    // Now two parts of the superior section could possibly be merged
    if( pPrvSct && !pPrvSct->IsJoinLocked() )
    {
        OSL_ENSURE( pNxtSct, "MoveContent: No Merge" );
        pPrvSct->MergeNext( pNxtSct );
    }
}

void SwSectionFrame::MakeAll(vcl::RenderContext* pRenderContext)
{
    if ( IsJoinLocked() || IsColLocked() || StackHack::IsLocked() || StackHack::Count() > 50 )
        return;
    if( !m_pSection ) // Via DelEmpty
    {
#ifdef DBG_UTIL
        OSL_ENSURE( getRootFrame()->IsInDelList( this ), "SectionFrame without Section" );
#endif
        if( !isFrameAreaPositionValid() )
        {
            if( GetUpper() )
            {
                SwRectFnSet aRectFnSet(GetUpper());
                aRectFnSet.MakePos( *this, GetUpper(), GetPrev(), false );
            }

            if (getFrameArea().Height() == 0)
            {
                // SwLayoutFrame::MakeAll() is not called for to-be-deleted
                // section frames (which would invalidate the position of the
                // next frame via the SwLayNotify dtor), so call it manually.
                if (SwFrame* pNext = GetNext())
                    pNext->InvalidatePos();
            }
        }

        setFrameAreaPositionValid(true);
        setFrameAreaSizeValid(true);
        setFramePrintAreaValid(true);
        return;
    }

    if (!GetPrev() && !IsFollow() && IsInDocBody() && IsHiddenNow())
    {
        // This may be the first frame on a page, and it may had moved to that page because its
        // content required that (a page break in the first paragraph, or a tall first line, or
        // "do not break paragraph" setting, or the like). Try to move back, to allow following
        // frames to move back, if possible. Sections cannot move back; workaround by a call to
        // GetPrevSctLeaf(), which may return a candidate upper frame on a previous page, or it
        // may create a new master for this at the end of the previous page. Cut and paste this
        // appropriately; then drop the temporary, if needed.
        if (SwLayoutFrame* moveBackPos = GetPrevSctLeaf())
        {
            if (moveBackPos->IsColBodyFrame())
            {
                moveBackPos = moveBackPos->GetUpper()->GetUpper();
            }
            SwLayoutFrame* newUpper = moveBackPos;
            SwFrame* newSibling = nullptr;
            const bool temporaryMasterCreated = IsFollow();
            if (temporaryMasterCreated)
            {
                assert(moveBackPos == &GetPrecede()->GetFrame());
                newUpper = moveBackPos->GetUpper();
                newSibling = moveBackPos->GetNext(); // actually, will be also nullptr
            }
            if (newUpper != GetUpper())
            {
                // Can't use MoveSubTree, because the move needs to fire events to re-layout
                Cut();
                Paste(newUpper, newSibling);
            }
            if (temporaryMasterCreated)
            {
                moveBackPos->Cut();
                DestroyFrame(moveBackPos);
            }
            assert(!IsFollow());
        }
    }

    LockJoin(); // I don't let myself to be destroyed on the way

    while( GetNext() && GetNext() == GetFollow() )
    {
        const SwFrame* pFoll = GetFollow();
        MergeNext( static_cast<SwSectionFrame*>(GetNext()) );
        if( pFoll == GetFollow() )
            break;
    }

    if (GetFollow() && IsHiddenNow())
    {
        // Merge all the follows of this hidden section
        while (auto* follow = GetFollow())
        {
            MergeNext(follow);
            if (GetFollow() == follow) // failed to merge
                break// avoid endless loop
        }
    }

    // OD 2004-03-15 #116561# - In online layout join the follows, if section
    // can grow.
    const SwViewShell *pSh = getRootFrame()->GetCurrShell();

    // Split sections inside table cells: need to merge all follows of the
    // section here, as later we won't attempt doing so.
    bool bCanContainSplitSection = false;
    if (IsInTab() && GetUpper())
        bCanContainSplitSection = CanContainSplitSection(GetUpper());

    if( pSh && (pSh->GetViewOptions()->getBrowseMode() || bCanContainSplitSection) &&
         ( Grow( LONG_MAX, true ) > 0 ) )
    {
        while( GetFollow() )
        {
            const SwFrame* pFoll = GetFollow();
            MergeNext( GetFollow() );
            if( pFoll == GetFollow() )
                break;
        }
    }

    // A section with Follow uses all the space until the lower edge of the
    // Upper. If it moves, its size can grow or decrease...
    if( !isFrameAreaPositionValid() && ToMaximize( false ) )
    {
        setFrameAreaSizeValid(false);
    }

    SwLayoutFrame::MakeAll(getRootFrame()->GetCurrShell()->GetOut());

    if (IsInTab())
    {
        // In case the section is in a table, then calculate the lower right
        // now. Just setting the valid size flag of the lower to false may not
        // be enough, as lcl_RecalcRow() can call
        // SwFrame::ValidateThisAndAllLowers(), and then we don't attempt
        // calculating the proper position of the lower.
        SwFrame* pLower = Lower();
        if (pLower && !pLower->isFrameAreaPositionValid())
            pLower->Calc(pRenderContext);
    }

    UnlockJoin();
    if( m_pSection && IsSuperfluous() )
        DelEmpty( false );
}

bool SwSectionFrame::ShouldBwdMoved( SwLayoutFrame *, bool & )
{
    OSL_FAIL( "Oops, where is my tinfoil hat?" );
    return false;
}

const SwSectionFormat* SwSectionFrame::GetEndSectFormat_() const
{
    const SwSectionFormat *pFormat = m_pSection->GetFormat();
    while( !pFormat->GetEndAtTextEnd().IsAtEnd() )
    {
        ifauto pNewFormat = dynamic_castconst SwSectionFormat *>( pFormat->GetRegisteredIn()) )
            pFormat = pNewFormat;
        else
            return nullptr;
    }
    return pFormat;
}

static void lcl_FindContentFrame( SwContentFrame* &rpContentFrame, SwFootnoteFrame* &rpFootnoteFrame,
    SwFrame* pFrame, bool &rbChkFootnote )
{
    if( !pFrame )
        return;

    while( pFrame->GetNext() )
        pFrame = pFrame->GetNext();
    while( !rpContentFrame && pFrame )
    {
        if( pFrame->IsContentFrame() )
            rpContentFrame = static_cast<SwContentFrame*>(pFrame);
        else if( pFrame->IsLayoutFrame() )
        {
            if( pFrame->IsFootnoteFrame() )
            {
                if( rbChkFootnote )
                {
                    rpFootnoteFrame = static_cast<SwFootnoteFrame*>(pFrame);
                    rbChkFootnote = rpFootnoteFrame->GetAttr()->GetFootnote().IsEndNote();
                }
            }
            else
                lcl_FindContentFrame( rpContentFrame, rpFootnoteFrame,
                    static_cast<SwLayoutFrame*>(pFrame)->Lower(), rbChkFootnote );
        }
        pFrame = pFrame->GetPrev();
    }
}

SwContentFrame *SwSectionFrame::FindLastContent( SwFindMode nMode )
{
    SwContentFrame *pRet = nullptr;
    SwFootnoteFrame *pFootnoteFrame = nullptr;
    SwSectionFrame *pSect = this;
    if( nMode != SwFindMode::None )
    {
        const SwSectionFormat *pFormat = IsEndnAtEnd() ? GetEndSectFormat() :
                                     m_pSection->GetFormat();
        do {
            while( pSect->HasFollow() )
                pSect = pSect->GetFollow();
            SwFrame* pTmp = pSect->FindNext();
            while( pTmp && pTmp->IsSctFrame() &&
                   !static_cast<SwSectionFrame*>(pTmp)->GetSection() )
                pTmp = pTmp->FindNext();
            if( pTmp && pTmp->IsSctFrame() &&
                static_cast<SwSectionFrame*>(pTmp)->IsDescendantFrom( pFormat ) )
                pSect = static_cast<SwSectionFrame*>(pTmp);
            else
                break;
        } whiletrue );
    }
    bool bFootnoteFound = nMode == SwFindMode::EndNote;
    do
    {
        lcl_FindContentFrame( pRet, pFootnoteFrame, pSect->Lower(), bFootnoteFound );
        if( pRet || !pSect->IsFollow() || nMode == SwFindMode::None ||
            ( SwFindMode::MyLast == nMode && this == pSect ) )
            break;
        pSect = pSect->FindMaster();
    } while( pSect );
    if( ( nMode == SwFindMode::EndNote ) && pFootnoteFrame )
        pRet = pFootnoteFrame->ContainsContent();
    return pRet;
}

bool SwSectionFrame::CalcMinDiff( SwTwips& rMinDiff ) const
{
    if( ToMaximize( true ) )
    {
        SwRectFnSet aRectFnSet(this);
        rMinDiff = aRectFnSet.GetPrtBottom(*GetUpper());
        rMinDiff = aRectFnSet.BottomDist( getFrameArea(), rMinDiff );
        return true;
    }
    return false;
}

/**
 *  CollectEndnotes looks for endnotes in the sectionfrm and his follows,
 *  the endnotes will cut off the layout and put into the array.
 *  If the first endnote is not a master-SwFootnoteFrame, the whole sectionfrm
 *  contains only endnotes and it is not necessary to collect them.
 */

static SwFootnoteFrame* lcl_FindEndnote( SwSectionFrame* &rpSect, bool &rbEmpty,
    SwLayouter *pLayouter )
{
    // if rEmpty is set, the rpSect is already searched
    SwSectionFrame* pSect = rbEmpty ? rpSect->GetFollow() : rpSect;
    while( pSect )
    {
        SwFrame* pLower = pSect->Lower();
        OSL_ENSURE( (pLower && pLower->IsColumnFrame()) || pSect->GetUpper()->IsFootnoteFrame(),
                "InsertEndnotes: Where's my column?" );

        // i73332: Columned section in endnote
        SwColumnFrame* pCol = nullptr;
        if(pLower && pLower->IsColumnFrame())
            pCol = static_cast<SwColumnFrame*>(pLower);

        while( pCol ) // check all columns
        {
            SwFootnoteContFrame* pFootnoteCont = pCol->FindFootnoteCont();
            if( pFootnoteCont )
            {
                SwFootnoteFrame* pRet = static_cast<SwFootnoteFrame*>(pFootnoteCont->Lower());
                while( pRet ) // look for endnotes
                {
                    /* CollectEndNode can destroy pRet so we need to get the
                       next early
                    */

                    SwFootnoteFrame* pRetNext = static_cast<SwFootnoteFrame*>(pRet->GetNext());
                    if( pRet->GetAttr()->GetFootnote().IsEndNote() )
                    {
                        if( pRet->GetMaster() )
                        {
                            if( pLayouter )
                                pLayouter->CollectEndnote( pRet );
                            else
                                return nullptr;
                        }
                        else
                            return pRet; // Found
                    }
                    pRet = pRetNext;
                }
            }
            pCol = static_cast<SwColumnFrame*>(pCol->GetNext());
        }
        rpSect = pSect;
        pSect = pLayouter ? pSect->GetFollow() : nullptr;
        rbEmpty = true;
    }
    return nullptr;
}

static void lcl_ColumnRefresh( SwSectionFrame* pSect, bool bFollow )
{
    vcl::RenderContext* pRenderContext = pSect->getRootFrame()->GetCurrShell()->GetOut();
    while( pSect )
    {
        bool bOldLock = pSect->IsColLocked();
        pSect->ColLock();
        SwFrame* pLower = pSect->Lower();
        if( pLower && pLower->IsColumnFrame() )
        {
            SwColumnFrame *pCol = static_cast<SwColumnFrame*>(pLower);
            do
            {   pCol->InvalidateSize_();
                pCol->InvalidatePos_();
                if (SwFrame* pColLower = static_cast<SwLayoutFrame*>(pCol)->Lower())
                {
                    pColLower->InvalidateSize_();
                    pCol->Calc(pRenderContext);   // calculation of column and
                    pColLower->Calc(pRenderContext);  // body
                }
                pCol = static_cast<SwColumnFrame*>(pCol->GetNext());
            } while ( pCol );
        }
        if( !bOldLock )
            pSect->ColUnlock();
        if( bFollow )
            pSect = pSect->GetFollow();
        else
            pSect = nullptr;
    }
}

void SwSectionFrame::CollectEndnotes( SwLayouter* pLayouter )
{
    OSL_ENSURE( IsColLocked(), "CollectEndnotes: You love the risk?" );
    // i73332: Section in footnode does not have columns!
    SwFrame* pLower = Lower();
    OSL_ENSURE( (pLower && pLower->IsColumnFrame()) || GetUpper()->IsFootnoteFrame(), "Where's my column?" );

    SwSectionFrame* pSect = this;
    SwFootnoteFrame* pFootnote;
    bool bEmpty = false;
    // pSect is the last sectionfrm without endnotes or the this-pointer
    // the first sectionfrm with endnotes may be destroyed, when the endnotes
    // is cutted
    while( nullptr != (pFootnote = lcl_FindEndnote( pSect, bEmpty, pLayouter )) )
        pLayouter->CollectEndnote( pFootnote );
    if( pLayouter->HasEndnotes() )
        lcl_ColumnRefresh( thistrue );
}

/** Fits the size to the surroundings.
|*
|*  Those that have a Follow or foot notes, have to extend until
|*  the lower edge of a upper (bMaximize)
|*  They must not extend above the Upper, as the case may be one can
|*  try to grow its upper (bGrow)
|*  If the size had to be changed, the content is calculated.
|*
|*  @note: perform calculation of content, only if height has changed (OD 18.09.2002 #100522#)
|*/

void SwSectionFrame::CheckClipping( bool bGrow, bool bMaximize )
{
    SwRectFnSet aRectFnSet(this);
    tools::Long nDiff;
    SwTwips nDeadLine = aRectFnSet.GetPrtBottom(*GetUpper());
    if( bGrow && ( !IsInFly() || !GetUpper()->IsColBodyFrame() ||
                   !FindFlyFrame()->IsLocked() ) )
    {
        nDiff = -aRectFnSet.BottomDist( getFrameArea(), nDeadLine );
        if( !bMaximize )
            nDiff += Undersize();
        if( nDiff > 0 )
        {
            tools::Long nAdd = GetUpper()->Grow( nDiff );
            if( aRectFnSet.IsVert() )
                nDeadLine -= nAdd;
            else
                nDeadLine += nAdd;
        }
    }
    nDiff = -aRectFnSet.BottomDist( getFrameArea(), nDeadLine );
    SetUndersized( !bMaximize && nDiff >= 0 );
    const bool bCalc = ( IsUndersized() || bMaximize ) &&
                       ( nDiff ||
                         aRectFnSet.GetTop(getFramePrintArea()) > aRectFnSet.GetHeight(getFrameArea()) );
    // OD 03.11.2003 #i19737# - introduce local variable <bExtraCalc> to indicate
    // that a calculation has to be done beside the value of <bCalc>.
    bool bExtraCalc = false;
    if( !bCalc && !bGrow && IsAnyNoteAtEnd() && !IsInFootnote() )
    {
        SwSectionFrame *pSect = this;
        bool bEmpty = false;
        SwLayoutFrame* pFootnote = IsEndnAtEnd() ?
            lcl_FindEndnote( pSect, bEmpty, nullptr ) : nullptr;
        if( pFootnote )
        {
            pFootnote = pFootnote->FindFootnoteBossFrame();
            SwFrame* pTmp = FindLastContent( SwFindMode::LastCnt );
            // OD 08.11.2002 #104840# - use <SwLayoutFrame::IsBefore(..)>
            if ( pTmp && pFootnote->IsBefore( pTmp->FindFootnoteBossFrame() ) )
                bExtraCalc = true;
        }
        else if( GetFollow() && !GetFollow()->ContainsAny() )
            bExtraCalc = true;
    }
    if ( !(bCalc || bExtraCalc) )
        return;

    nDiff = aRectFnSet.YDiff( nDeadLine, aRectFnSet.GetTop(getFrameArea()) );
    if( nDiff < 0 )
        nDeadLine = aRectFnSet.GetTop(getFrameArea());
    const Size aOldSz( getFramePrintArea().SSize() );
    tools::Long nTop = aRectFnSet.GetTopMargin(*this);

    {
        SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
        aRectFnSet.SetBottom( aFrm, nDeadLine );
    }

    nDiff = aRectFnSet.GetHeight(getFrameArea());
    if( nTop > nDiff )
        nTop = nDiff;
    aRectFnSet.SetYMargins( *this, nTop, 0 );

    // OD 18.09.2002 #100522#
    // Determine, if height has changed.
    // Note: In vertical layout the height equals the width value.
    bool bHeightChanged = aRectFnSet.IsVert() ?
                        (aOldSz.Width() != getFramePrintArea().Width()) :
                        (aOldSz.Height() != getFramePrintArea().Height());
    // Last but not least we have changed the height again, thus the inner
    // layout (columns) is calculated and the content as well.
    // OD 18.09.2002 #100522#
    // calculate content, only if height has changed.
    // OD 03.11.2003 #i19737# - restriction of content calculation too strong.
    // If an endnote has an incorrect position or a follow section contains
    // no content except footnotes/endnotes, the content has also been calculated.
    if ( !(( bHeightChanged || bExtraCalc ) && Lower()) )
        return;

    SwFrame* pLower = Lower();
    if( pLower && pLower->IsColumnFrame() )
    {
        lcl_ColumnRefresh( thisfalse );
        ::CalcContent( this );
    }
    else
    {
        ChgLowersProp( aOldSz );
        if( !bMaximize && !IsContentLocked() )
            ::CalcContent( this );
    }
}

void SwSectionFrame::SimpleFormat()
{
    if ( IsJoinLocked() || IsColLocked() )
        return;
    LockJoin();
    SwRectFnSet aRectFnSet(this);
    if( GetPrev() || GetUpper() )
    {
        // assure notifications on position changes.
        const SwLayNotify aNotify( this );
        aRectFnSet.MakePos( *this, GetUpper(), GetPrev(), false );
        setFrameAreaPositionValid(true);
    }
    SwTwips nDeadLine = aRectFnSet.GetPrtBottom(*GetUpper());
    // OD 22.10.2002 #97265# - call always method <lcl_ColumnRefresh(..)>, in
    // order to get calculated lowers, not only if there space left in its upper.
    if (aRectFnSet.BottomDist(getFrameArea(), nDeadLine) >= 0)
    {
        {
            SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
            aRectFnSet.SetBottom( aFrm, nDeadLine );
        }

        tools::Long nHeight = aRectFnSet.GetHeight(getFrameArea());
        tools::Long nTop = CalcUpperSpace();
        if( nTop > nHeight )
            nTop = nHeight;
        aRectFnSet.SetYMargins( *this, nTop, 0 );
    }
    lcl_ColumnRefresh( thisfalse );
    UnlockJoin();
}

namespace {

// #i40147# - helper class to perform extra section format
// to position anchored objects and to keep the position of whose objects locked.
class ExtraFormatToPositionObjs
{
    private:
        SwSectionFrame* mpSectFrame;
        bool mbExtraFormatPerformed;

    public:
        explicit ExtraFormatToPositionObjs( SwSectionFrame& _rSectFrame)
            : mpSectFrame( &_rSectFrame ),
              mbExtraFormatPerformed( false )
        {}

        ~ExtraFormatToPositionObjs()
        {
            if ( !mbExtraFormatPerformed )
                return;

            // release keep locked position of lower floating screen objects
            SwPageFrame* pPageFrame = mpSectFrame->FindPageFrame();
            SwSortedObjs* pObjs = pPageFrame ? pPageFrame->GetSortedObjs() : nullptr;
            if ( pObjs )
            {
                for (SwAnchoredObject* pAnchoredObj : *pObjs)
                {
                    if ( mpSectFrame->IsAnLower( pAnchoredObj->GetAnchorFrame() ) )
                    {
                        pAnchoredObj->SetKeepPosLocked( false );
                    }
                }
            }
        }

        // #i81555#
        void InitObjs( SwFrame& rFrame )
        {
            SwSortedObjs* pObjs = rFrame.GetDrawObjs();
            if ( pObjs )
            {
                for (SwAnchoredObject* pAnchoredObj : *pObjs)
                {
                    pAnchoredObj->UnlockPosition();
                    pAnchoredObj->SetClearedEnvironment( false );
                }
            }
            if ( rFrame.IsLayoutFrame() )
            {
                SwFrame* pLowerFrame = rFrame.GetLower();
                while ( pLowerFrame != nullptr )
                {
                    InitObjs( *pLowerFrame );

                    pLowerFrame = pLowerFrame->GetNext();
                }
            }
        }

        void FormatSectionToPositionObjs()
        {
            vcl::RenderContext* pRenderContext = mpSectFrame->getRootFrame()->GetCurrShell()->GetOut();
            // perform extra format for multi-columned section.
            SwFrame* pLower = mpSectFrame->Lower();
            if ( !(pLower && pLower->IsColumnFrame() && pLower->GetNext()) )
                return;

            // grow section till bottom of printing area of upper frame
            SwRectFnSet aRectFnSet(mpSectFrame);
            SwTwips nTopMargin = aRectFnSet.GetTopMargin(*mpSectFrame);
            Size aOldSectPrtSize( mpSectFrame->getFramePrintArea().SSize() );
            SwTwips nDiff = aRectFnSet.BottomDist( mpSectFrame->getFrameArea(), aRectFnSet.GetPrtBottom(*mpSectFrame->GetUpper()) );

            {
                SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*mpSectFrame);
                aRectFnSet.AddBottom( aFrm, nDiff );
            }

            aRectFnSet.SetYMargins( *mpSectFrame, nTopMargin, 0 );
            // #i59789#
            // suppress formatting, if printing area of section is too narrow
            if ( aRectFnSet.GetHeight(mpSectFrame->getFramePrintArea()) <= 0 )
            {
                return;
            }
            mpSectFrame->ChgLowersProp( aOldSectPrtSize );

            // format column frames and its body and footnote container
            SwColumnFrame* pColFrame = static_cast<SwColumnFrame*>(mpSectFrame->Lower());
            while ( pColFrame )
            {
                pColFrame->Calc(pRenderContext);
                if (SwFrame* pColLower = pColFrame->Lower())
                {
                    pColLower->Calc(pRenderContext);
                    if ( pColLower->GetNext() )
                    {
                        pColLower->GetNext()->Calc(pRenderContext);
                    }
                }

                pColFrame = static_cast<SwColumnFrame*>(pColFrame->GetNext());
            }

            // unlock position of lower floating screen objects for the extra format
            // #i81555#
            // Section frame can already have changed the page and its content
            // can still be on the former page.
            // Thus, initialize objects via lower-relationship
            InitObjs( *mpSectFrame );

            // format content - first with collecting its foot-/endnotes before content
            // format, second without collecting its foot-/endnotes.
            ::CalcContent( mpSectFrame );
            ::CalcContent( mpSectFrame, true );

            // keep locked position of lower floating screen objects
            SwPageFrame* pPageFrame = mpSectFrame->FindPageFrame();
            SwSortedObjs* pObjs = pPageFrame ? pPageFrame->GetSortedObjs() : nullptr;
            if ( pObjs )
            {
                for (SwAnchoredObject* pAnchoredObj : *pObjs)
                {
                    if ( mpSectFrame->IsAnLower( pAnchoredObj->GetAnchorFrame() ) )
                    {
                        pAnchoredObj->SetKeepPosLocked( true );
                    }
                }
            }

            mbExtraFormatPerformed = true;

        }
};

}

/// "formats" the frame; Frame and PrtArea
void SwSectionFrame::Format( vcl::RenderContext* pRenderContext, const SwBorderAttrs *pAttr )
{
    if( !m_pSection ) // via DelEmpty
    {
#ifdef DBG_UTIL
        OSL_ENSURE( getRootFrame()->IsInDelList( this ), "SectionFrame without Section" );
#endif
        setFrameAreaPositionValid(true);
        setFrameAreaSizeValid(true);
        setFramePrintAreaValid(true);
        return;
    }

    SwRectFnSet aRectFnSet(this);

    if (GetSection()->CalcHiddenFlag())
    {
        {
            SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
            aRectFnSet.SetHeight(aFrm, 0);
        }
        {
            SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this);
            aRectFnSet.SetHeight(aPrt, 0);
        }
        setFrameAreaSizeValid(true);
        setFramePrintAreaValid(true);
    }

    if ( !isFramePrintAreaValid() )
    {
        PROTOCOL( this, PROT::PrintArea, DbgAction::NONE, nullptr )
        setFramePrintAreaValid(true);
        SwTwips nUpper = CalcUpperSpace();

        // #109700# LRSpace for sections
        const SvxLRSpaceItem& rLRSpace = GetFormat()->GetLRSpace();
        aRectFnSet.SetXMargins(*this, rLRSpace.ResolveLeft({}), rLRSpace.ResolveRight({}));

        if( nUpper != aRectFnSet.GetTopMargin(*this) )
        {
            setFrameAreaSizeValid(false);
            SwFrame* pOwn = ContainsAny();
            if( pOwn )
                pOwn->InvalidatePos_();
        }
        aRectFnSet.SetYMargins( *this, nUpper, 0 );
    }

    if ( isFrameAreaSizeValid() )
        return;

    PROTOCOL_ENTER( this, PROT::Size, DbgAction::NONE, nullptr )
    const tools::Long nOldHeight = aRectFnSet.GetHeight(getFrameArea());
    bool bOldLock = IsColLocked();
    ColLock();

    setFrameAreaSizeValid(true);

    // The size is only determined by the content, if the SectFrame does not have a
    // Follow. Otherwise it fills (occupies) the Upper down to the lower edge.
    // It is not responsible for the text flow, but the content is.
    bool bMaximize = ToMaximize( false );

    // OD 2004-05-17 #i28701# - If the wrapping style has to be considered
    // on object positioning, an extra formatting has to be performed
    // to determine the correct positions the floating screen objects.
    // #i40147#
    // use new helper class <ExtraFormatToPositionObjs>.
    // This class additionally keep the locked position of the objects
    // and releases this position lock keeping on destruction.
    ExtraFormatToPositionObjs aExtraFormatToPosObjs( *this );
    if ( !bMaximize &&
         GetFormat()->getIDocumentSettingAccess().get(DocumentSettingId::CONSIDER_WRAP_ON_OBJECT_POSITION) &&
         !GetFormat()->GetBalancedColumns().GetValue() )
    {
        aExtraFormatToPosObjs.FormatSectionToPositionObjs();
    }

    // Column widths have to be adjusted before calling CheckClipping.
    // CheckClipping can cause the formatting of the lower frames
    // which still have a width of 0.
    const bool bHasColumns = Lower() && Lower()->IsColumnFrame();
    if ( bHasColumns && Lower()->GetNext() )
        AdjustColumns( nullptr, false );

    if( GetUpper() )
    {
        const tools::Long nWidth = aRectFnSet.GetWidth(GetUpper()->getFramePrintArea());

        {
            SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
            aRectFnSet.SetWidth( aFrm, nWidth );
        }

        // #109700# LRSpace for sections
        {
            const SvxLRSpaceItem& rLRSpace = GetFormat()->GetLRSpace();
            SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this);
            aRectFnSet.SetWidth(aPrt,
                                nWidth - rLRSpace.ResolveLeft({}) - rLRSpace.ResolveRight({}));
        }

        // OD 15.10.2002 #103517# - allow grow in online layout
        // Thus, set <..IsBrowseMode()> as parameter <bGrow> on calling
        // method <CheckClipping(..)>.
        const SwViewShell *pSh = getRootFrame()->GetCurrShell();
        CheckClipping( pSh && pSh->GetViewOptions()->getBrowseMode(), bMaximize );
        bMaximize = ToMaximize( false );
        setFrameAreaSizeValid(true);
    }

    // Check the width of the columns and adjust if necessary
    if ( bHasColumns && ! Lower()->GetNext() && bMaximize )
        static_cast<SwColumnFrame*>(Lower())->Lower()->Calc(pRenderContext);

    if ( !bMaximize )
    {
        SwTwips nRemaining = aRectFnSet.GetTopMargin(*this);
        SwFrame *pFrame = m_pLower;
        if( pFrame )
        {
            if( pFrame->IsColumnFrame() && pFrame->GetNext() )
            {
                // #i61435#
                // suppress formatting, if upper frame has height <= 0
                if ( aRectFnSet.GetHeight(GetUpper()->getFrameArea()) > 0 )
                {
                    FormatWidthCols( *pAttr, nRemaining, MINLAY );
                }
                // #126020# - adjust check for empty section
                // #130797# - correct fix #126020#
                while( HasFollow() && !GetFollow()->ContainsContent() &&
                       !GetFollow()->ContainsAny( true ) )
                {
                    SwFrame* pOld = GetFollow();
                    GetFollow()->DelEmpty( false );
                    if( pOld == GetFollow() )
                        break;
                }
                bMaximize = ToMaximize( false );
                nRemaining += aRectFnSet.GetHeight(pFrame->getFrameArea());
            }
            else
            {
                if( pFrame->IsColumnFrame() )
                {
                    pFrame->Calc(pRenderContext);
                    pFrame = static_cast<SwColumnFrame*>(pFrame)->Lower();
                    pFrame->Calc(pRenderContext);
                    pFrame = static_cast<SwLayoutFrame*>(pFrame)->Lower();
                    CalcFootnoteContent();
                }
                // If we are in a columned frame which calls a CalcContent
                // in the FormatWidthCols, the content might need calculating
                if( pFrame && !pFrame->isFrameAreaDefinitionValid() && IsInFly() &&
                    FindFlyFrame()->IsColLocked() )
                    ::CalcContent( this );
                nRemaining += InnerHeight();
                bMaximize = HasFollow();
            }
        }

        SwTwips nDiff = aRectFnSet.GetHeight(getFrameArea()) - nRemaining;
        if( nDiff < 0)
        {
            SwTwips nDeadLine = aRectFnSet.GetPrtBottom(*GetUpper());
            {
                tools::Long nBottom = aRectFnSet.GetBottom(getFrameArea());
                nBottom = aRectFnSet.YInc( nBottom, -nDiff );
                tools::Long nTmpDiff = aRectFnSet.YDiff( nBottom, nDeadLine );
                if( nTmpDiff > 0 )
                {
                    nTmpDiff = GetUpper()->Grow( nTmpDiff, true );
                    nDeadLine = aRectFnSet.YInc( nDeadLine, nTmpDiff );
                    nTmpDiff = aRectFnSet.YDiff( nBottom, nDeadLine );
                    if( nTmpDiff > 0 )
                        nDiff += nTmpDiff;
                    if( nDiff > 0 )
                        nDiff = 0;
                }
            }
        }
        if( nDiff )
        {
            tools::Long nTmp = nRemaining - aRectFnSet.GetHeight(getFrameArea());
            tools::Long nTop = aRectFnSet.GetTopMargin(*this);

            {
                SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
                aRectFnSet.AddBottom( aFrm, nTmp );
            }

            aRectFnSet.SetYMargins( *this, nTop, 0 );
            InvalidateNextPos();

            if (m_pLower && (!m_pLower->IsColumnFrame() || !m_pLower->GetNext()))
            {
                // If a single-column section just created the space that
                // was requested by the "undersized" paragraphs, then they
                // have to be invalidated and calculated, so they fully cover it
                pFrame = m_pLower;
                if( pFrame->IsColumnFrame() )
                {
                    pFrame->InvalidateSize_();
                    pFrame->InvalidatePos_();
                    pFrame->Calc(pRenderContext);
                    pFrame = static_cast<SwColumnFrame*>(pFrame)->Lower();
                    pFrame->Calc(pRenderContext);
                    pFrame = static_cast<SwLayoutFrame*>(pFrame)->Lower();
                    CalcFootnoteContent();
                }
                bool bUnderSz = false;
                while( pFrame )
                {
                    if( pFrame->IsTextFrame() && static_cast<SwTextFrame*>(pFrame)->IsUndersized() )
                    {
                        pFrame->Prepare( PrepareHint::AdjustSizeWithoutFormatting );
                        bUnderSz = true;
                    }
                    pFrame = pFrame->GetNext();
                }
                if( bUnderSz && !IsContentLocked() )
                    ::CalcContent( this );
            }
        }
    }

    // Do not exceed the lower edge of the Upper.
    // Do not extend below the lower edge with Sections with Follows
    if ( GetUpper() )
        CheckClipping( true, bMaximize );
    if( !bOldLock )
        ColUnlock();
    tools::Long nDiff = nOldHeight - aRectFnSet.GetHeight(getFrameArea());

    if( nDiff > 0 )
    {
        if( !GetNext() )
            SetRetouche(); // Take over the retouching ourselves
        if( GetUpper() && !GetUpper()->IsFooterFrame() )
            GetUpper()->Shrink( nDiff );
    }

    if( IsUndersized() )
    {
        setFramePrintAreaValid(true);
    }

}

/// Returns the next layout sheet where the frame can be moved in.
/// New pages are created only if specified by the parameter.
SwLayoutFrame *SwFrame::GetNextSctLeaf( MakePageType eMakePage )
{
    // Attention: Nested sections are currently not supported

    PROTOCOL_ENTER( this, PROT::Leaf, DbgAction::NextSect, GetUpper()->FindSctFrame() )

    // Shortcuts for "columned" sections, if we're not in the last column
    // Can we slide to the next column of the section?
    if( IsColBodyFrame() && GetUpper()->GetNext() )
        return static_cast<SwLayoutFrame*>(static_cast<SwLayoutFrame*>(GetUpper()->GetNext())->Lower());
    if( GetUpper()->IsColBodyFrame() && GetUpper()->GetUpper()->GetNext() )
        return static_cast<SwLayoutFrame*>(static_cast<SwLayoutFrame*>(GetUpper()->GetUpper()->GetNext())->Lower());
    // Inside a table-in-section, or sections of headers/footers, there can be only
    // one column shift be made, one of the above shortcuts should have applied!
    if( !CanContainSplitSection(GetUpper()) || FindFooterOrHeader() )
        return nullptr;

    SwSectionFrame *pSect = FindSctFrame();
    bool bWrongPage = false;
    assert(pSect && "GetNextSctLeaf: Missing SectionFrame");

    // Shortcut for sections with Follows. That's ok,
    // if no columns or pages (except dummy pages) lie in between.
    // In case of linked frames and in footnotes the shortcut would get
    // even more costly
    if( pSect->HasFollow() && pSect->IsInDocBody() && !pSect->IsInTab() )
    {
        if( pSect->GetFollow() == pSect->GetNext() )
        {
            SwPageFrame *pPg = pSect->GetFollow()->FindPageFrame();
            if( WrongPageDesc( pPg ) )
                bWrongPage = true;
            else
                return FirstLeaf( pSect->GetFollow() );
        }
        else
        {
            SwFrame* pTmp;
            if( !pSect->GetUpper()->IsColBodyFrame() ||
                nullptr == ( pTmp = pSect->GetUpper()->GetUpper()->GetNext() ) )
                pTmp = pSect->FindPageFrame()->GetNext();
            if( pTmp ) // is now the next column or page
            {
                SwFrame* pTmpX = pTmp;
                if( pTmp->IsPageFrame() && static_cast<SwPageFrame*>(pTmp)->IsEmptyPage() )
                    pTmp = pTmp->GetNext(); // skip dummy pages
                SwFrame *pUp = pSect->GetFollow()->GetUpper();
                // pUp becomes the next column if the Follow lies in a column
                // that is not a "not first" one, otherwise the page
                if( !pUp->IsColBodyFrame() ||
                    !( pUp = pUp->GetUpper() )->GetPrev() )
                    pUp = pUp->FindPageFrame();
                // Now pUp and pTmp have to be the same page/column, otherwise
                // pages or columns lie between Master and Follow
                if( pUp == pTmp || pUp->GetNext() == pTmpX )
                {
                    SwPageFrame* pNxtPg = pUp->IsPageFrame() ?
                                        static_cast<SwPageFrame*>(pUp) : pUp->FindPageFrame();
                    if( WrongPageDesc( pNxtPg ) )
                        bWrongPage = true;
                    else
                        return FirstLeaf( pSect->GetFollow() );
                }
            }
        }
    }

#ifndef NDEBUG
    std::vector<SwFrame *> parents;
    for (SwFrame * pTmp = GetUpper(); pTmp && !pTmp->IsPageFrame(); pTmp = pTmp->GetUpper())
    {
        parents.push_back(pTmp);
    }
#endif

    // Always end up in the same section: Body again inside Body etc.
    const bool bBody = IsInDocBody();
    const bool bFootnotePage = FindPageFrame()->IsFootnotePage();

    // The "pLayLeaf is in a table" case is rejected by default, so that it
    // can't happen that we try to move a table to one of its own cells.
    bool bLayLeafTableAllowed = false;
    SwLayoutFrame *pLayLeaf;

    SwLayoutFrame* pCellLeaf = nullptr;
    if (GetUpper()->IsInTab())
    {
        if (IsTabFrame())
        {
            return nullptr; // table in section in table: split disabled for now
        }
        // We are *in* a table (not an outermost SwTabFrame), see if there
        // is a follow cell frame created already.
        pCellLeaf = GetNextCellLeaf();
        if (!pCellLeaf)
        {
            SAL_WARN("sw.layout""section is in table, but the table is not split");
            return nullptr;
        }
    }

    // A shortcut for TabFrames such that not all cells need to be visited
    if( bWrongPage )
        pLayLeaf = nullptr;
    else if( IsTabFrame() )
    {
        SwFrame *const pTmpCnt = static_cast<SwTabFrame*>(this)->FindLastContentOrTable();
        pLayLeaf = pTmpCnt ? pTmpCnt->GetUpper() : nullptr;
    }
    else if (pCellLeaf && CanContainSplitSection(this))
    {
        // This frame is in a table-not-in-section, its follow should be
        // inserted under the follow of the frame's cell.
        pLayLeaf = pCellLeaf;
        if (pLayLeaf->FindTabFrame() == FindTabFrame())
            SAL_WARN("sw.layout""my table frame and my follow's table frame is the same");
        // In this case pLayLeaf pointing to an in-table frame is OK.
        bLayLeafTableAllowed = true;
    }
    else
    {
        pLayLeaf = GetNextLayoutLeaf();
        if( IsColumnFrame() )
        {
            while( pLayLeaf && static_cast<SwColumnFrame*>(this)->IsAnLower( pLayLeaf ) )
                pLayLeaf = pLayLeaf->GetNextLayoutLeaf();
        }
    }

    SwLayoutFrame *pOldLayLeaf = nullptr;           // Such that in case of newly
                                            // created pages, the search is
--> --------------------

--> maximum size reached

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

Messung V0.5
C=94 H=91 G=92

¤ Dauer der Verarbeitung: 0.28 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

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

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge