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 117 kB image not shown  

Quelle  ftnfrm.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 <libxml/xmlwriter.h>

#include <txtftn.hxx>
#include <fmtftn.hxx>
#include <ftnidx.hxx>
#include <pagefrm.hxx>
#include <colfrm.hxx>
#include <rootfrm.hxx>
#include <frmtool.hxx>
#include <ftnfrm.hxx>
#include <txtfrm.hxx>
#include <tabfrm.hxx>
#include <pagedesc.hxx>
#include <ftninfo.hxx>
#include <sectfrm.hxx>
#include <objectformatter.hxx>
#include <viewopt.hxx>
#include <calbck.hxx>
#include <ndindex.hxx>
#include <pam.hxx>
#include <ndtxt.hxx>
#include <osl/diagnose.h>
#include <sal/log.hxx>
#include <IDocumentSettingAccess.hxx>
#include <flyfrm.hxx>
#include <IDocumentStylePoolAccess.hxx>
#include <docsh.hxx>
#include <poolfmt.hxx>
#include <swfntcch.hxx>
#include <wrtsh.hxx>

#define ENDNOTE 0x80000000

namespace
{
/// Calculates the height of the line that hosts the separator line (the top margin of the
/// container), based on the default paragraph style in rDoc.
bool FootnoteSeparatorHeightFromParagraph(SwDoc& rDoc, SwTwips& rHeight)
{
        const SwTextFormatColl* pDefaultParaFormat
            = rDoc.getIDocumentStylePoolAccess().GetTextCollFromPool(RES_POOLCOLL_STANDARD);
        if (!pDefaultParaFormat)
        {
            return false;
        }

        SwViewShell* pSh = rDoc.GetDocShell()->GetWrtShell();
        if (!pSh)
        {
            return false;
        }

        SwFontAccess aFontAccess(pDefaultParaFormat, pSh);
        SwFont aFont(aFontAccess.Get()->GetFont());
        OutputDevice& rOut = pSh->GetRefDev();
        rHeight = aFont.GetHeight(pSh, rOut);
        return true;
}
}

/// Search the position of an attribute in the FootnoteArray at the document,
/// because all footnotes are located there, ordered by their index.
static sal_uInt32 lcl_FindFootnotePos( const SwDoc& rDoc, const SwTextFootnote *pAttr )
{
    const SwFootnoteIdxs &rFootnoteIdxs = rDoc.GetFootnoteIdxs();

    SwTextFootnote* pBla = const_cast<SwTextFootnote*>(pAttr);
    SwFootnoteIdxs::const_iterator it = rFootnoteIdxs.find( pBla );
    if ( it != rFootnoteIdxs.end() )
    {
        sal_uInt32 nRet = it - rFootnoteIdxs.begin();
        if( pAttr->GetFootnote().IsEndNote() )
            return nRet + ENDNOTE;
        return nRet;
    }
    return 0;
}

bool SwFootnoteFrame::operator<( const SwTextFootnote* pTextFootnote ) const
{
    const SwDoc& rDoc = GetFormat()->GetDoc();
    return lcl_FindFootnotePos( rDoc, GetAttr() ) <
           lcl_FindFootnotePos( rDoc, pTextFootnote );
}

/*
|*
|*  bool lcl_NextFootnoteBoss( SwFootnoteBossFrame* pBoss, SwPageFrame* pPage)
|*  sets pBoss on the next SwFootnoteBossFrame, which can either be a column
|*  or a page (without columns). If the page changes meanwhile,
|*  pPage contains the new page and this function returns true.
|*
|*/


static bool lcl_NextFootnoteBoss( SwFootnoteBossFrame* &rpBoss, SwPageFrame* &rpPage,
    bool bDontLeave )
{
    if( rpBoss->IsColumnFrame() )
    {
        if( rpBoss->GetNext() )
        {
            rpBoss = static_cast<SwFootnoteBossFrame*>(rpBoss->GetNext()); //next column
            return false;
        }
        if( rpBoss->IsInSct() )
        {
            SwSectionFrame* pSct = rpBoss->FindSctFrame()->GetFollow();
            if( pSct )
            {
                SwFrame* pLower = pSct->Lower();
                OSL_ENSURE( pLower && pLower->IsColumnFrame(),
                        "Where's the column?" );
                rpBoss = static_cast<SwColumnFrame*>(pLower);
                SwPageFrame* pOld = rpPage;
                rpPage = pSct->FindPageFrame();
                return pOld != rpPage;
            }
            else if( bDontLeave )
            {
                rpPage = nullptr;
                rpBoss = nullptr;
                return false;
            }
        }
    }
    rpPage = static_cast<SwPageFrame*>(rpPage->GetNext()); // next page
    rpBoss = rpPage;
    if( rpPage )
    {
        SwLayoutFrame* pBody = rpPage->FindBodyCont();
        SwFrame* pLower = pBody ? pBody->Lower() : nullptr;
        if (pLower && pLower->IsColumnFrame() )
            rpBoss = static_cast<SwFootnoteBossFrame*>(pLower); // first column
    }
    return true;
}

/// @returns column number if pBoss is a column, otherwise 0.
static sal_uInt16 lcl_ColumnNum( const SwFrame* pBoss )
{
    sal_uInt16 nRet = 0;
    if( !pBoss->IsColumnFrame() )
        return 0;
    const SwFrame* pCol;
    if( pBoss->IsInSct() )
    {
        pCol = pBoss->GetUpper()->FindColFrame();
        if( pBoss->GetNext() || pBoss->GetPrev() )
        {
            while( pBoss )
            {
                ++nRet;                     // Section columns
                pBoss = pBoss->GetPrev();
            }
        }
    }
    else
        pCol = pBoss;
    while( pCol )
    {
        nRet += 256;                    // Page columns
        pCol = pCol->GetPrev();
    }
    return nRet;
}

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

SwFootnoteFrame* SwFootnoteContFrame::AddChained(bool bAppend, SwFrame* pThis, bool bDefaultFormat)
{
    SwFootnoteFrame *pOld = pThis->FindFootnoteFrame();
    SwFrameFormat *pFormat = pOld->GetFormat();
    if (bDefaultFormat)
        pFormat = pFormat->GetDoc().GetDfltFrameFormat();

    SwFootnoteFrame *pNew = new SwFootnoteFrame(pFormat, pOld, pOld->GetRef(), pOld->GetAttr());

    if (bAppend)
    {
        if (pOld->GetFollow())
        {
            pNew->SetFollow(pOld->GetFollow());
            pOld->GetFollow()->SetMaster(pNew);
        }
        pOld->SetFollow(pNew);
        pNew->SetMaster(pOld);
    }
    else
    {
        if (pOld->GetMaster())
        {
            pNew->SetMaster(pOld->GetMaster());
            pOld->GetMaster()->SetFollow(pNew);
        }
        pNew->SetFollow(pOld);
        pOld->SetMaster(pNew);
    }

    return pNew;
}

// lcl_Undersize(..) walks over a SwFrame and its contents
// and returns the sum of all requested TextFrame magnifications.

static tools::Long lcl_Undersize( const SwFrame* pFrame )
{
    tools::Long nRet = 0;
    SwRectFnSet aRectFnSet(pFrame);
    if( pFrame->IsTextFrame() )
    {
        ifstatic_cast<const SwTextFrame*>(pFrame)->IsUndersized() )
        {
            // Does this TextFrame would like to be a little bit bigger?
            nRet = static_cast<const SwTextFrame*>(pFrame)->GetParHeight() -
                    aRectFnSet.GetHeight(pFrame->getFramePrintArea());
            if( nRet < 0 )
                nRet = 0;
        }
    }
    else if( pFrame->IsLayoutFrame() )
    {
        const SwFrame* pNxt = static_cast<const SwLayoutFrame*>(pFrame)->Lower();
        while( pNxt )
        {
            nRet += lcl_Undersize( pNxt );
            pNxt = pNxt->GetNext();
        }
    }
    return nRet;
}

namespace sw {

SwTwips FootnoteSeparatorHeight(SwDoc& rDoc, SwPageFootnoteInfo const& rInf)
{
    const IDocumentSettingAccess& rIDSA = rDoc.getIDocumentSettingAccess();
    if (rIDSA.get(DocumentSettingId::CONTINUOUS_ENDNOTES))
    {
        // Word style: try to calculate the height from the default para format.
        SwTwips nHeight{};
        if (FootnoteSeparatorHeightFromParagraph(rDoc, nHeight))
        {
            return nHeight;
        }
    }

    // Writer style: calculate from the page style.
    return rInf.GetTopDist() + rInf.GetBottomDist() + rInf.GetLineWidth();
}

// namespace sw

/// "format" the frame (Fixsize is not set here).
void SwFootnoteContFrame::Format( vcl::RenderContext* /*pRenderContext*/, const SwBorderAttrs * )
{
    // calculate total border, only one distance to the top
    const SwPageFrame* pPage = FindPageFrame();
    const SwPageFootnoteInfo &rInf = pPage->GetPageDesc()->GetFootnoteInfo();
    SwDoc* pDoc = getRootFrame()->GetCurrShell()->GetDoc();
    const SwTwips nBorder = sw::FootnoteSeparatorHeight(*pDoc, rInf);
    SwRectFnSet aRectFnSet(this);

    if ( !isFramePrintAreaValid() )
    {
        setFramePrintAreaValid(true);
        SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this);

        aRectFnSet.SetTop( aPrt, nBorder );
        aRectFnSet.SetWidth( aPrt, aRectFnSet.GetWidth(getFrameArea()) );
        aRectFnSet.SetHeight(aPrt, aRectFnSet.GetHeight(getFrameArea()) - nBorder );

        if( aRectFnSet.GetHeight(aPrt) < 0 && !pPage->IsFootnotePage() )
        {
            setFrameAreaSizeValid(false);
        }
    }

    if ( isFrameAreaSizeValid() )
        return;

    bool bGrow = pPage->IsFootnotePage();
    if( bGrow )
    {
        const SwViewShell *pSh = getRootFrame() ? getRootFrame()->GetCurrShell() : nullptr;
        if( pSh && pSh->GetViewOptions()->getBrowseMode() )
            bGrow = false;
    }
    if( bGrow )
            Grow( LONG_MAX );
    else
    {
        // VarSize is determined based on the content plus the borders
        SwTwips nRemaining = 0;
        SwFrame *pFrame = m_pLower;
        while ( pFrame )
        {   // lcl_Undersize(..) respects (recursively) TextFrames, which
            // would like to be bigger. They are created especially in
            // columnized borders, if these do not have their maximum
            // size yet.
            nRemaining += aRectFnSet.GetHeight(pFrame->getFrameArea()) + lcl_Undersize( pFrame );
            pFrame = pFrame->GetNext();
        }
        // add the own border
        nRemaining += nBorder;

        SwTwips nDiff;
        if( IsInSct() )
        {
            nDiff = -aRectFnSet.BottomDist( getFrameArea(), aRectFnSet.GetPrtBottom(*GetUpper()) );
            if( nDiff > 0 )
            {
                if( nDiff > aRectFnSet.GetHeight(getFrameArea()) )
                {
                    nDiff = aRectFnSet.GetHeight(getFrameArea());
                }

                SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
                aRectFnSet.AddBottom( aFrm, -nDiff );
                aRectFnSet.AddHeight( aFrm, -nDiff );
            }
        }
        nDiff = aRectFnSet.GetHeight(getFrameArea()) - nRemaining;
        if ( nDiff > 0 )
            Shrink( nDiff );
        else if ( nDiff < 0 )
        {
            Grow( -nDiff );
            // It may happen that there is less space available,
            // than what the border needs - the size of the PrtArea
            // will then be negative.
            SwTwips nPrtHeight = aRectFnSet.GetHeight(getFramePrintArea());
            if( nPrtHeight < 0 )
            {
                const SwTwips nTmpDiff = std::max( SwTwips(aRectFnSet.GetTop(getFramePrintArea())), -nPrtHeight );
                SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this);
                aRectFnSet.SubTop( aPrt, nTmpDiff );
            }
        }
    }

    setFrameAreaSizeValid(true);
}

SwTwips SwFootnoteContFrame::GrowFrame(SwTwips nDist, SwResizeLimitReason& reason, bool bTst, bool)
{
    // No check if FixSize since FootnoteContainer are variable up to their max. height.
    // If the max. height is LONG_MAX, take as much space as needed.
    // If the page is a special footnote page, take also as much as possible.
    assert(GetUpper() && GetUpper()->IsFootnoteBossFrame());

    const auto nOrigDist = std::max(nDist, SwTwips(0));
    reason = SwResizeLimitReason::Unspecified;

    SwRectFnSet aRectFnSet(this);
    if( aRectFnSet.GetHeight(getFrameArea()) > 0 &&
         nDist > ( LONG_MAX - aRectFnSet.GetHeight(getFrameArea()) ) )
        nDist = LONG_MAX - aRectFnSet.GetHeight(getFrameArea());

    SwFootnoteBossFrame *pBoss = static_cast<SwFootnoteBossFrame*>(GetUpper());
    if( IsInSct() )
    {
        SwSectionFrame* pSect = FindSctFrame();
        OSL_ENSURE( pSect, "GrowFrame: Missing SectFrame" );
        // In a section, which has to maximize, a footnotecontainer is allowed
        // to grow, when the section can't grow anymore.
        if( !bTst && !pSect->IsColLocked() &&
            pSect->ToMaximize( false ) && pSect->Growable() )
        {
            pSect->InvalidateSize();
            if (nOrigDist)
                reason = SwResizeLimitReason::FlowToFollow;
            return 0;
        }
    }
    const SwViewShell *pSh = getRootFrame() ? getRootFrame()->GetCurrShell() : nullptr;
    const bool bBrowseMode = pSh && pSh->GetViewOptions()->getBrowseMode();
    SwPageFrame *pPage = pBoss->FindPageFrame();
    if ( bBrowseMode || !pPage->IsFootnotePage() )
    {
        if ( pBoss->GetMaxFootnoteHeight() != LONG_MAX )
        {
            nDist = std::min( nDist,
                        SwTwips(pBoss->GetMaxFootnoteHeight() - aRectFnSet.GetHeight(getFrameArea())) );
            if ( nDist <= 0 )
            {
                if (nOrigDist)
                    reason = SwResizeLimitReason::FlowToFollow;
                return 0;
            }
        }
        // FootnoteBoss also influences the max value
        if( !IsInSct() )
        {
            const SwTwips nMax = pBoss->GetVarSpace();
            if ( nDist > nMax )
            {
                nDist = nMax;
                if (nOrigDist)
                    reason = SwResizeLimitReason::FlowToFollow;
            }
            if ( nDist <= 0 )
                return 0;
        }
    }
    else if( nDist > aRectFnSet.GetHeight(GetPrev()->getFrameArea()) )
    {
        // do not use more space than the body has
        nDist = aRectFnSet.GetHeight(GetPrev()->getFrameArea());
        if (nOrigDist)
            reason = SwResizeLimitReason::FlowToFollow;
    }

    tools::Long nAvail = 0;
    if ( bBrowseMode )
    {
        nAvail = GetUpper()->getFramePrintArea().Height();
        const SwFrame *pAvail = GetUpper()->Lower();
        do
        {   nAvail -= pAvail->getFrameArea().Height();
            pAvail = pAvail->GetNext();
        } while ( pAvail );
        if ( nAvail > nDist )
            nAvail = nDist;
    }

    if ( !bTst )
    {
        SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
        aRectFnSet.SetHeight( aFrm, aRectFnSet.GetHeight(aFrm) + nDist );

        if( IsVertical() && !IsVertLR() )
        {
            aFrm.Pos().AdjustX( -nDist );
        }
    }
    tools::Long nGrow = nDist - nAvail,
         nReal = 0;
    if ( nGrow > 0 )
    {
        SwNeighbourAdjust nAdjust = pBoss->NeighbourhoodAdjustment();
        if( SwNeighbourAdjust::OnlyAdjust == nAdjust )
            nReal = AdjustNeighbourhood( nGrow, bTst );
        else
        {
            if( SwNeighbourAdjust::GrowAdjust == nAdjust )
            {
                SwFrame* pFootnote = Lower();
                if( pFootnote )
                {
                    while( pFootnote->GetNext() )
                        pFootnote = pFootnote->GetNext();
                    ifstatic_cast<SwFootnoteFrame*>(pFootnote)->GetAttr()->GetFootnote().IsEndNote() )
                    {
                        nReal = AdjustNeighbourhood( nGrow, bTst );
                        nAdjust = SwNeighbourAdjust::GrowShrink; // no more AdjustNeighbourhood
                    }
                }
            }
            nReal += pBoss->Grow(nGrow - nReal, reason, bTst, false);
            if( ( SwNeighbourAdjust::GrowAdjust == nAdjust || SwNeighbourAdjust::AdjustGrow == nAdjust )
                  && nReal < nGrow )
                nReal += AdjustNeighbourhood( nGrow - nReal, bTst );
        }
    }

    nReal += nAvail;

    if ( !bTst )
    {
        if ( nReal != nDist )
        {
            nDist -= nReal;

            // We can only respect the boundless wish so much
            SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
            aFrm.AddHeight( -nDist );

            if( IsVertical() && !IsVertLR() )
            {
                aFrm.Pos().AdjustX(nDist );
            }
        }

        // growing happens upwards, so successors to not need to be invalidated
        if( nReal )
        {
            InvalidateSize_();
            InvalidatePos_();
            InvalidatePage( pPage );
        }
    }
    if (nOrigDist > nReal && reason == SwResizeLimitReason::Unspecified)
        reason = SwResizeLimitReason::FlowToFollow;
    return nReal;
}

SwTwips SwFootnoteContFrame::ShrinkFrame( SwTwips nDiff, bool bTst, bool bInfo )
{
    SwPageFrame *pPage = FindPageFrame();
    bool bShrink = false;
    if ( pPage )
    {
        if( !pPage->IsFootnotePage() )
            bShrink = true;
        else
        {
            const SwViewShell *pSh = getRootFrame()->GetCurrShell();
            if( pSh && pSh->GetViewOptions()->getBrowseMode() )
                bShrink = true;
        }
    }
    if( bShrink )
    {
        SwTwips nRet = SwLayoutFrame::ShrinkFrame( nDiff, bTst, bInfo );
        if( IsInSct() && !bTst )
            FindSctFrame()->InvalidateNextPos();
        if ( !bTst && nRet )
        {
            InvalidatePos_();
            InvalidatePage( pPage );
        }
        return nRet;
    }
    return 0;
}

SwFootnoteFrame::SwFootnoteFrame( SwFrameFormat *pFormat, SwFrame* pSib, SwContentFrame *pCnt, SwTextFootnote *pAt ):
    SwLayoutFrame( pFormat, pSib ),
    mpFollow( nullptr ),
    mpMaster( nullptr ),
    mpReference( pCnt ),
    mpAttribute( pAt ),
    mbBackMoveLocked( false ),
    // #i49383#
    mbUnlockPosOfLowerObjs( true )
{
    mnFrameType = SwFrameType::Footnote;
}

void SwFootnoteFrame::InvalidateNxtFootnoteCnts( SwPageFrame const *pPage )
{
    if ( !GetNext() )
        return;

    SwFrame *pCnt = static_cast<SwLayoutFrame*>(GetNext())->ContainsAny();
    if( !pCnt )
        return;

    pCnt->InvalidatePage( pPage );
    pCnt->InvalidatePrt_();
    do
    {   pCnt->InvalidatePos_();
        if( pCnt->IsSctFrame() )
        {
            SwFrame* pTmp = static_cast<SwSectionFrame*>(pCnt)->ContainsAny();
            if( pTmp )
                pTmp->InvalidatePos_();
        }
        pCnt->GetUpper()->InvalidateSize_();
        pCnt = pCnt->FindNext();
    } while ( pCnt && GetUpper()->IsAnLower( pCnt ) );
}

bool SwFootnoteFrame::IsDeleteForbidden() const
{
    if (SwLayoutFrame::IsDeleteForbidden())
        return true;
    // needs to be in sync with the ::Cut logic
    const SwLayoutFrame *pUp = GetUpper();
    if (pUp)
    {
        if (GetPrev())
            return false;

        // The last footnote takes its container along if it
        // is deleted. Cut would put pUp->Lower() to the value
        // of GetNext(), so if there is no GetNext then
        // Cut would delete pUp. If that condition is true
        // here then check if the container is delete-forbidden
        return !GetNext() && pUp->IsDeleteForbidden();
    }
    return false;
}

void SwFootnoteFrame::Cut()
{
    if ( GetNext() )
        GetNext()->InvalidatePos();
    else if ( GetPrev() )
        GetPrev()->SetRetouche();

    // first move then shrink Upper
    SwLayoutFrame *pUp = GetUpper();

    // correct chaining
    SwFootnoteFrame *pFootnote = this;
    if ( pFootnote->GetFollow() )
        pFootnote->GetFollow()->SetMaster( pFootnote->GetMaster() );
    if ( pFootnote->GetMaster() )
        pFootnote->GetMaster()->SetFollow( pFootnote->GetFollow() );
    pFootnote->SetFollow( nullptr );
    pFootnote->SetMaster( nullptr );

    // cut all connections
    RemoveFromLayout();

    if ( !pUp )
        return;

    // The last footnote takes its container along
    if (!pUp->Lower())
    {
        SwPageFrame *pPage = pUp->FindPageFrame();
        if ( pPage )
        {
            SwLayoutFrame *pBody = pPage->FindBodyCont();
            if( pBody && !pBody->ContainsContent() )
                pPage->getRootFrame()->SetSuperfluous();
        }
        SwSectionFrame* pSect = pUp->FindSctFrame();
        pUp->Cut();
        SwFrame::DestroyFrame(pUp);
        // If the last footnote container was removed from a column
        // section without a Follow, then this section can be shrunk.
        if( pSect && !pSect->ToMaximize( false ) && !pSect->IsColLocked() )
            pSect->InvalidateSize_();
    }
    else
    {   if ( getFrameArea().Height() )
            pUp->Shrink( getFrameArea().Height() );
        pUp->SetCompletePaint();
        pUp->InvalidatePage();
    }
}

void SwFootnoteFrame::Paste(  SwFrame* pParent, SwFrame* pSibling )
{
    OSL_ENSURE( pParent, "no parent in Paste." );
    OSL_ENSURE( pParent->IsLayoutFrame(), "Parent is ContentFrame." );
    OSL_ENSURE( pParent != this"I am my own parent." );
    OSL_ENSURE( pSibling != this"I am my own sibling." );
    OSL_ENSURE( !GetPrev() && !GetNext() && !GetUpper(),
            "I am still somewhere registered." );

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

    SwRectFnSet aRectFnSet(this);
    if( aRectFnSet.GetWidth(getFrameArea())!=aRectFnSet.GetWidth(pParent->getFramePrintArea()) )
        InvalidateSize_();
    InvalidatePos_();
    if (SwFrame *const pContent = ContainsContent())
    {   // tdf#139687 invalidate possibly stale top margin (computed from previous frame)
        pContent->InvalidatePrt_();
    }
    SwPageFrame *pPage = FindPageFrame();
    InvalidatePage( pPage );
    if (SwFootnoteFrame *const pNext = static_cast<SwFootnoteFrame *>(GetNext()))
    {
        pNext->InvalidatePos_();
        if (SwFrame *const pContent = pNext->ContainsContent())
        {   // tdf#139687 invalidate possibly stale top margin (computed from previous frame)
            pContent->InvalidatePrt_();
        }
    }
    if( aRectFnSet.GetHeight(getFrameArea()) )
        pParent->Grow( aRectFnSet.GetHeight(getFrameArea()) );

    // If the predecessor is the master and/or the successor is the Follow,
    // then take their content and destroy them.
    if ( GetPrev() && GetPrev() == GetMaster() )
    {
        OSL_ENSURE( SwFlowFrame::CastFlowFrame( GetPrev()->GetLower() ),
                "Footnote without content?" );
        SwFlowFrame::CastFlowFrame( GetPrev()->GetLower())->
            MoveSubTree( this, GetLower() );
        SwFrame *pDel = GetPrev();
        assert(pDel != this);
        pDel->Cut();
        SwFrame::DestroyFrame(pDel);
    }
    if ( GetNext() && GetNext() == GetFollow() )
    {
        OSL_ENSURE( SwFlowFrame::CastFlowFrame( GetNext()->GetLower() ),
                "Footnote without content?" );
        SwFlowFrame::CastFlowFrame( GetNext()->GetLower() )->MoveSubTree( this );
        SwFrame *pDel = GetNext();
        assert(pDel != this);
        pDel->Cut();
        SwFrame::DestroyFrame(pDel);
    }
#if OSL_DEBUG_LEVEL > 0
    SwDoc& rDoc = GetFormat()->GetDoc();
    if ( GetPrev() )
    {
        OSL_ENSURE( lcl_FindFootnotePos( rDoc, static_cast<SwFootnoteFrame*>(GetPrev())->GetAttr() ) <=
                lcl_FindFootnotePos( rDoc, GetAttr() ), "Prev is not FootnotePrev" );
    }
    if ( GetNext() )
    {
        OSL_ENSURE( lcl_FindFootnotePos( rDoc, GetAttr() ) <=
                lcl_FindFootnotePos( rDoc, static_cast<SwFootnoteFrame*>(GetNext())->GetAttr() ),
                "Next is not FootnoteNext" );
    }
#endif
    InvalidateNxtFootnoteCnts( pPage );
}

/// Return the next layout leaf in that the frame can be moved.
/// New pages will only be created if specified by the parameter.
SwLayoutFrame *SwFrame::GetNextFootnoteLeaf( MakePageType eMakePage )
{
    SwFootnoteBossFrame *pOldBoss = FindFootnoteBossFrame();
    SwPageFrame* pOldPage = pOldBoss->FindPageFrame();
    SwPageFrame* pPage;
    SwFootnoteBossFrame *pBoss = pOldBoss->IsColumnFrame() ?
        static_cast<SwFootnoteBossFrame*>(pOldBoss->GetNext()) : nullptr; // next column, if existing
    if( pBoss )
        pPage = nullptr;
    else
    {
        if( pOldBoss->GetUpper()->IsSctFrame() )
        {   // this can only be in a column area
            SwLayoutFrame* pNxt = pOldBoss->GetNextSctLeaf( eMakePage );
            if( pNxt )
            {
                OSL_ENSURE( pNxt->IsColBodyFrame(), "GetNextFootnoteLeaf: Funny Leaf" );
                pBoss = static_cast<SwFootnoteBossFrame*>(pNxt->GetUpper());
                pPage = pBoss->FindPageFrame();
            }
            else
                return nullptr;
        }
        else
        {
            // next page
            pPage = static_cast<SwPageFrame*>(pOldPage->GetNext());
            // skip empty pages
            if( pPage && pPage->IsEmptyPage() )
                pPage = static_cast<SwPageFrame*>(pPage->GetNext());
            pBoss = pPage;
        }
    }
    // What do we have until here?
    // pBoss != NULL, pPage==NULL => pBoss is the next column on the same page
    // pBoss != NULL, pPage!=NULL => pBoss and pPage are the following page (empty pages skipped)
    // pBoss == NULL => pPage == NULL, so there are no following pages

    // If the footnote has already a Follow we do not need to search.
    // However, if there are unwanted empty columns/pages between Footnote and Follow,
    // create another Follow on the next best column/page and the rest will sort itself out.
    SwFootnoteFrame *pFootnote = FindFootnoteFrame();
    if ( pFootnote && pFootnote->GetFollow() )
    {
        SwFootnoteBossFrame* pTmpBoss = pFootnote->GetFollow()->FindFootnoteBossFrame();
        // Following cases will be handled:
        // 1. both "FootnoteBoss"es are neighboring columns/pages
        // 2. the new one is the first column of a neighboring page
        // 3. the new one is the first column in a section of the next page
        while( pTmpBoss != pBoss && pTmpBoss && !pTmpBoss->GetPrev() )
            pTmpBoss = pTmpBoss->GetUpper()->FindFootnoteBossFrame();
        if( pTmpBoss == pBoss )
            return pFootnote->GetFollow();
    }

    // If no pBoss could be found or it is a "wrong" page, we need a new page.
    if ( !pBoss || ( pPage && pPage->IsEndNotePage() && !pOldPage->IsEndNotePage() ) )
    {
        if ( eMakePage == MAKEPAGE_APPEND || eMakePage == MAKEPAGE_INSERT )
        {
            pBoss = InsertPage( pOldPage, pOldPage->IsFootnotePage() );
            static_cast<SwPageFrame*>(pBoss)->SetEndNotePage( pOldPage->IsEndNotePage() );
        }
        else
            return nullptr;
    }
    if( pBoss->IsPageFrame() )
    {
        // If this page has columns, then go to the first one
        SwLayoutFrame* pLay = pBoss->FindBodyCont();
        SwFrame* pLower = pLay ? pLay->Lower() : nullptr;
        if( pLower && pLower->IsColumnFrame() )
            pBoss = static_cast<SwFootnoteBossFrame*>(pLower);
    }
    // found column/page - add myself
    SwFootnoteContFrame *pCont = pBoss->FindFootnoteCont();
    if ( !pCont && pBoss->GetMaxFootnoteHeight() &&
         ( eMakePage == MAKEPAGE_APPEND || eMakePage == MAKEPAGE_INSERT ) )
        pCont = pBoss->MakeFootnoteCont();
    return pCont;
}

/// Get the preceding layout leaf in that the frame can be moved.
SwLayoutFrame *SwFrame::GetPrevFootnoteLeaf( MakePageType eMakeFootnote )
{
    // The predecessor of a footnote is (if possible)
    // the master of the chain of the footnote.
    SwFootnoteFrame *pFootnote = FindFootnoteFrame();
    SwLayoutFrame *pRet = pFootnote->GetMaster();

    SwFootnoteBossFrame* pOldBoss = FindFootnoteBossFrame();
    SwPageFrame *pOldPage = pOldBoss->FindPageFrame();

    if ( !pOldBoss->GetPrev() && !pOldPage->GetPrev() )
        return pRet; // there is neither a predecessor column nor page

    if ( !pRet )
    {
        bool bEndn = pFootnote->GetAttr()->GetFootnote().IsEndNote();
        SwFrame* pTmpRef = nullptr;
        const IDocumentSettingAccess& rSettings
            = pFootnote->GetAttrSet()->GetDoc().getIDocumentSettingAccess();
        bool bContEndnotes = rSettings.get(DocumentSettingId::CONTINUOUS_ENDNOTES);
        if( bEndn && pFootnote->IsInSct() && !bContEndnotes)
        {
            SwSectionFrame* pSect = pFootnote->FindSctFrame();
            if( pSect->IsEndnAtEnd() )
                // Endnotes at the end of the section.
                pTmpRef = pSect->FindLastContent( SwFindMode::LastCnt );
        }
        else if (bEndn && bContEndnotes)
        {
            // Endnotes at the end of the document.
            pTmpRef = pFootnote->FindFootnoteBossFrame();
        }
        if( !pTmpRef )
            // Endnotes on a separate page.
            pTmpRef = pFootnote->GetRef();
        SwFootnoteBossFrame* pStop = pTmpRef->FindFootnoteBossFrame( !bEndn );

        const sal_uInt16 nNum = pStop->GetPhyPageNum();

        // Do not leave the corresponding page if the footnote should
        // be shown at the document ending or the footnote is an endnote.
        const bool bEndNote = pOldPage->IsEndNotePage();
        const bool bFootnoteEndDoc = pOldPage->IsFootnotePage();
        SwFootnoteBossFrame* pNxtBoss = pOldBoss;
        SwSectionFrame *pSect = pNxtBoss->GetUpper()->IsSctFrame() ?
                              static_cast<SwSectionFrame*>(pNxtBoss->GetUpper()) : nullptr;

        do
        {
            if( pNxtBoss->IsColumnFrame() && pNxtBoss->GetPrev() )
                pNxtBoss = static_cast<SwFootnoteBossFrame*>(pNxtBoss->GetPrev());  // one column backwards
            else // one page backwards
            {
                SwLayoutFrame* pBody = nullptr;
                if( pSect )
                {
                    if( pSect->IsFootnoteLock() )
                    {
                        if( pNxtBoss == pOldBoss )
                            return nullptr;
                        pStop = pNxtBoss;
                    }
                    else
                    {
                        pSect = pSect->FindMaster();
                        if( !pSect || !pSect->Lower() )
                            return nullptr;
                        OSL_ENSURE( pSect->Lower()->IsColumnFrame(),
                                "GetPrevFootnoteLeaf: Where's the column?" );
                        pNxtBoss = static_cast<SwFootnoteBossFrame*>(pSect->Lower());
                        pBody = pSect;
                    }
                }
                else
                {
                    SwPageFrame* pPage = static_cast<SwPageFrame*>(pNxtBoss->FindPageFrame()->GetPrev());
                    if( !pPage || pPage->GetPhyPageNum() < nNum ||
                        bEndNote != pPage->IsEndNotePage() || bFootnoteEndDoc != pPage->IsFootnotePage() )
                        return nullptr; // no further pages found
                    pNxtBoss = pPage;
                    pBody = pPage->FindBodyCont();
                }
                // We have the previous page, we might need to find the last column of it
                if( pBody )
                {
                    SwFrame* pLower = pBody->Lower();
                    if ( pLower && pLower->IsColumnFrame() )
                    {
                        pNxtBoss = static_cast<SwFootnoteBossFrame*>(pBody->GetLastLower());
                    }
                }
            }
            SwFootnoteContFrame *pCont = pNxtBoss->FindFootnoteCont();
            if ( pCont )
            {
                pRet = pCont;
                break;
            }
            if ( pStop == pNxtBoss )
            {
                // Reached the column/page of the reference.
                // Try to add a container and paste our content.
                if ( eMakeFootnote == MAKEPAGE_FTN && pNxtBoss->GetMaxFootnoteHeight() )
                    pRet = pNxtBoss->MakeFootnoteCont();
                break;
            }
        } while( !pRet );
    }
    if ( pRet )
    {
        const SwFootnoteBossFrame* pNewBoss = pRet->FindFootnoteBossFrame();
        bool bJump = false;
        if( pOldBoss->IsColumnFrame() && pOldBoss->GetPrev() ) // a previous column exists
            bJump = pOldBoss->GetPrev() != static_cast<SwFrame const *>(pNewBoss); // did we chose it?
        else if( pNewBoss->IsColumnFrame() && pNewBoss->GetNext() )
            bJump = true// there is another column after the boss (not the old boss)
        else
        {
            // Will be reached only if old and new boss are both either pages or the last (new)
            // or first (old) column of a page. In this case, check if pages were skipped.
            const sal_uInt16 nDiff = pOldPage->GetPhyPageNum() - pRet->FindPageFrame()->GetPhyPageNum();
            if ( nDiff > 2 ||
                 (nDiff > 1 && !static_cast<SwPageFrame*>(pOldPage->GetPrev())->IsEmptyPage()) )
                bJump = true;
        }
        if( bJump )
            SwFlowFrame::SetMoveBwdJump( true );
    }
    return pRet;
}

bool SwFrame::IsFootnoteAllowed() const
{
    bool bSplitFly = false;
    const SwFlyFrame* pFlyFrame = FindFlyFrame();
    if (pFlyFrame)
    {
        // This is a fly. Check if it's a split fly, which is OK to host a footnote.
        bSplitFly = pFlyFrame->IsFlySplitAllowed();
    }

    if (!IsInDocBody() && !bSplitFly)
        return false;

    if ( IsInTab() )
    {
        // no footnotes in repeated headlines
        const SwTabFrame *pTab = const_cast<SwFrame*>(this)->ImplFindTabFrame();
        assert(pTab);
        if ( pTab->IsFollow() )
            return !pTab->IsInHeadline( *this );
    }
    return true;
}

void SwRootFrame::UpdateFootnoteNums()
{
    // page numbering only if set at the document
    if ( GetFormat()->GetDoc().GetFootnoteInfo().m_eNum == FTNNUM_PAGE )
    {
        SwPageFrame *pPage = static_cast<SwPageFrame*>(Lower());
        while ( pPage && !pPage->IsFootnotePage() )
        {
            pPage->UpdateFootnoteNum();
            pPage = static_cast<SwPageFrame*>(pPage->GetNext());
        }
    }
}

/// remove all footnotes (not the references) and all footnote pages
void sw_RemoveFootnotes( SwFootnoteBossFrame* pBoss, bool bPageOnly, bool bEndNotes )
{
    do
    {
        SwFootnoteContFrame *pCont = pBoss->FindFootnoteCont();
        if ( pCont )
        {
            SwFootnoteFrame *pFootnote = static_cast<SwFootnoteFrame*>(pCont->Lower());
            assert(pFootnote);
            if ( bPageOnly )
                while ( pFootnote->GetMaster() )
                    pFootnote = pFootnote->GetMaster();
            do
            {
                SwFootnoteFrame *pNxt = static_cast<SwFootnoteFrame*>(pFootnote->GetNext());
                if ( !pFootnote->GetAttr()->GetFootnote().IsEndNote() ||
                        bEndNotes )
                {
                    SwContentFrame* pCF = pFootnote->GetRef();
                    // it's possible that the contentframe is empty when closing Writer
                    if (!pCF)
                        return;
                    if (!pCF->IsInDtor())
                        // NOTE: I REPRO'D A CRASH HERE BUT THE DEBUGGER DIDN'T INDICATE
                        // WHAT THE PROBLEM WAS -- the objects are valid.  Happens when
                        // undoing/redoing rapidly for some time then saving and the crash
                        // happens on close of LO
                        pCF->Prepare(PrepareHint::FootnoteInvalidation,
                                     static_cast<void*>(pFootnote->GetAttr()));
                    if ( bPageOnly && !pNxt )
                        pNxt = pFootnote->GetFollow();
                    pFootnote->Cut();
                    SwFrame::DestroyFrame(pFootnote);
                }
                pFootnote = pNxt;

            } while ( pFootnote );
        }
        if( !pBoss->IsInSct() )
        {
            // A sectionframe with the Footnote/EndnAtEnd-flags may contain
            // foot/endnotes. If the last lower frame of the bodyframe is
            // a multicolumned sectionframe, it may contain footnotes, too.
            SwLayoutFrame* pBody = pBoss->FindBodyCont();
            if( pBody )
            {
                SwFrame* pLow = pBody->Lower();
                while (pLow)
                {
                    if( pLow->IsSctFrame() && ( !pLow->GetNext() ||
                        static_cast<SwSectionFrame*>(pLow)->IsAnyNoteAtEnd() ) )
                    {
                        SwFrame* pLowerLower = static_cast<SwSectionFrame*>(pLow)->Lower();
                        if (pLowerLower && pLowerLower->IsColumnFrame() )
                            sw_RemoveFootnotes( static_cast<SwColumnFrame*>(pLowerLower),
                                bPageOnly, bEndNotes );
                    }
                    pLow = pLow->GetNext();
                }
            }
        }
        // is there another column?
        pBoss = pBoss->IsColumnFrame() ? static_cast<SwColumnFrame*>(pBoss->GetNext()) : nullptr;
    } while( pBoss );
}

void SwRootFrame::RemoveFootnotes( SwPageFrame *pPage, bool bPageOnly, bool bEndNotes )
{
    if ( !pPage )
        pPage = static_cast<SwPageFrame*>(Lower());

    while (pPage)
    {   // On columned pages we have to clean up in all columns
        SwFootnoteBossFrame* pBoss;
        SwLayoutFrame* pBody = pPage->FindBodyCont();
        SwFrame* pLower = pBody ? pBody->Lower() : nullptr;
        if( pLower && pLower->IsColumnFrame() )
            pBoss = static_cast<SwFootnoteBossFrame*>(pLower); // the first column
        else
            pBoss = pPage; // no columns
        sw_RemoveFootnotes( pBoss, bPageOnly, bEndNotes );
        if ( !bPageOnly )
        {
            if ( pPage->IsFootnotePage() &&
                 (!pPage->IsEndNotePage() || bEndNotes) )
            {
                SwFrame *pDel = pPage;
                pPage = static_cast<SwPageFrame*>(pPage->GetNext());
                pDel->Cut();
                SwFrame::DestroyFrame(pDel);
            }
            else
                pPage = static_cast<SwPageFrame*>(pPage->GetNext());
        }
        else
            break;
    }

}

/// Change the page template of the footnote pages
void SwRootFrame::CheckFootnotePageDescs( bool bEndNote )
{
    SwPageFrame *pPage = static_cast<SwPageFrame*>(Lower());
    while ( pPage && !pPage->IsFootnotePage() )
        pPage = static_cast<SwPageFrame*>(pPage->GetNext());
    while ( pPage && pPage->IsEndNotePage() != bEndNote )
        pPage = static_cast<SwPageFrame*>(pPage->GetNext());

    if ( pPage )
        SwFrame::CheckPageDescs( pPage, false );
}

/** Insert a footnote container
 *
 * A footnote container is always placed directly behind the body text.
 *
 * The frame format (FrameFormat) is always the default frame format.
 *
 * @return footnote container frame
 */

SwFootnoteContFrame *SwFootnoteBossFrame::MakeFootnoteCont()
{
    SAL_WARN_IF(FindFootnoteCont(), "sw.core""footnote container exists already");

    SwFootnoteContFrame *pNew = new SwFootnoteContFrame( GetFormat()->GetDoc().GetDfltFrameFormat(), this );
    SwLayoutFrame *pLay = FindBodyCont();
    pNew->Paste( this, pLay->GetNext() );
    return pNew;
}

SwFootnoteContFrame *SwFootnoteBossFrame::FindFootnoteCont()
{
    SwFrame *pFrame = Lower();
    while( pFrame && !pFrame->IsFootnoteContFrame() )
        pFrame = pFrame->GetNext();

#if OSL_DEBUG_LEVEL > 0
    if ( pFrame )
    {
        SwFrame *pFootnote = pFrame->GetLower();
        assert(pFootnote);
        while ( pFootnote )
        {
            assert(pFootnote->IsFootnoteFrame() && "Neighbor of footnote must be a footnote");
            pFootnote = pFootnote->GetNext();
        }
    }
#endif

    return static_cast<SwFootnoteContFrame*>(pFrame);
}

/// Search the next available footnote container.
SwFootnoteContFrame *SwFootnoteBossFrame::FindNearestFootnoteCont( bool bDontLeave )
{
    SwFootnoteContFrame *pCont = nullptr;
    if ( !GetFormat()->GetDoc().GetFootnoteIdxs().empty() )
    {
        pCont = FindFootnoteCont();
        if ( !pCont )
        {
            SwPageFrame *pPage = FindPageFrame();
            SwFootnoteBossFrame* pBoss = this;
            bool bEndNote = pPage->IsEndNotePage();
            do
            {
                bool bChgPage = lcl_NextFootnoteBoss( pBoss, pPage, bDontLeave );
                // Found another boss? When changing pages, also the endnote flag must match.
                if( pBoss && ( !bChgPage || pPage->IsEndNotePage() == bEndNote ) )
                    pCont = pBoss->FindFootnoteCont();
            } while ( !pCont && pPage );
        }
    }
    return pCont;
}

SwFootnoteFrame *SwFootnoteBossFrame::FindFirstFootnote()
{
    // search for the nearest footnote container
    SwFootnoteContFrame *pCont = FindNearestFootnoteCont();
    if ( !pCont )
        return nullptr;

    // Starting from the first footnote, search the first
    // footnote that is referenced by the current column/page

    SwFootnoteFrame *pRet = static_cast<SwFootnoteFrame*>(pCont->Lower());
    const sal_uInt16 nRefNum = FindPageFrame()->GetPhyPageNum();
    const sal_uInt16 nRefCol = lcl_ColumnNum( this );
    sal_uInt16 nPgNum, nColNum; // page number, column number
    SwFootnoteBossFrame* pBoss;
    SwPageFrame* pPage;
    if( pRet )
    {
        pBoss = pRet->GetRef()->FindFootnoteBossFrame();
        OSL_ENSURE( pBoss, "FindFirstFootnote: No boss found" );
        if( !pBoss )
            return nullptr; // ?There must be a bug, but no GPF
        pPage = pBoss->FindPageFrame();
        // it's possible that there is no page frame when performing an undo operation
        if (!pPage)
            return nullptr;
        nPgNum = pPage->GetPhyPageNum();
        if ( nPgNum == nRefNum )
        {
            nColNum = lcl_ColumnNum( pBoss );
            if( nColNum == nRefCol )
                return pRet; // found
            else if( nColNum > nRefCol )
                return nullptr; // at least one column too far
        }
        else if ( nPgNum > nRefNum )
            return nullptr;    // at least one column too far
    }
    else
        return nullptr;
    // Done if Ref is on a subsequent page or on the same page in a subsequent column

    do
    {
        while ( pRet->GetFollow() )
            pRet = pRet->GetFollow();

        SwFootnoteFrame *pNxt = static_cast<SwFootnoteFrame*>(pRet->GetNext());
        if ( !pNxt )
        {
            pBoss = pRet->FindFootnoteBossFrame();
            // it's possible that there is no boss frame when performing an undo operation
            if (!pBoss)
                return nullptr;
            // it's possible that there is no page frame when performing an undo operation
            pPage = pBoss->FindPageFrame();
            if (!pPage)
                return nullptr;
            lcl_NextFootnoteBoss( pBoss, pPage, false ); // next FootnoteBoss
            pCont = pBoss ? pBoss->FindNearestFootnoteCont() : nullptr;
            if ( pCont )
                pNxt = static_cast<SwFootnoteFrame*>(pCont->Lower());
        }
        if ( pNxt )
        {
            pRet = pNxt;
            pBoss = pRet->GetRef()->FindFootnoteBossFrame();
            // it's possible that there is no boss frame when performing an undo operation
            if (!pBoss)
                return nullptr;
            // it's possible that there is no page frame when performing an undo operation
            pPage = pBoss->FindPageFrame();
            if (!pPage)
                return nullptr;
            nPgNum = pPage->GetPhyPageNum();
            if ( nPgNum == nRefNum )
            {
                nColNum = lcl_ColumnNum( pBoss );
                if( nColNum == nRefCol )
                    break// found
                else if( nColNum > nRefCol )
                    pRet = nullptr; // at least one column too far
            }
            else if ( nPgNum > nRefNum )
                pRet = nullptr;   // at least a page too far
        }
        else
            pRet = nullptr;   // there is none
    } while( pRet );
    return pRet;
}

/// Get the first footnote of a given content
const SwFootnoteFrame *SwFootnoteBossFrame::FindFirstFootnote( SwContentFrame const *pCnt ) const
{
    const SwFootnoteFrame *pRet = const_cast<SwFootnoteBossFrame*>(this)->FindFirstFootnote();
    if ( pRet )
    {
        const sal_uInt16 nColNum = lcl_ColumnNum( this );
        const sal_uInt16 nPageNum = GetPhyPageNum();
        while ( pRet && (pRet->GetRef() != pCnt) )
        {
            while ( pRet->GetFollow() )
                pRet = pRet->GetFollow();

            if ( pRet->GetNext() )
                pRet = static_cast<const SwFootnoteFrame*>(pRet->GetNext());
            else
            {   SwFootnoteBossFrame *pBoss = const_cast<SwFootnoteBossFrame*>(pRet->FindFootnoteBossFrame());
                SwPageFrame *pPage = pBoss->FindPageFrame();
                lcl_NextFootnoteBoss( pBoss, pPage, false ); // next FootnoteBoss
                SwFootnoteContFrame *pCont = pBoss ? pBoss->FindNearestFootnoteCont() : nullptr;
                pRet = pCont ? static_cast<SwFootnoteFrame*>(pCont->Lower()) : nullptr;
            }
            if ( pRet )
            {
                const SwFootnoteBossFrame* pBoss = pRet->GetRef()->FindFootnoteBossFrame();
                if( !pBoss || pBoss->GetPhyPageNum() != nPageNum ||
                    nColNum != lcl_ColumnNum( pBoss ) )
                    pRet = nullptr;
            }
        }
    }
    return pRet;
}

void SwFootnoteBossFrame::ResetFootnote( const SwFootnoteFrame *pCheck )
{
    // Destroy the incarnations of footnotes to an attribute, if they don't
    // belong to pAssumed
    OSL_ENSURE( !pCheck->GetMaster(), "given master is not a Master." );

    SwNodeIndex aIdx( *pCheck->GetAttr()->GetStartNode(), 1 );
    SwContentNode *pNd = aIdx.GetNode().GetContentNode();
    if ( !pNd )
        pNd = SwNodes::GoNextSection(&aIdx, truefalse);
    SwIterator<SwFrame, SwContentNode, sw::IteratorMode::UnwrapMulti> aIter(*pNd);
    SwFrame* pFrame = aIter.First();
    while( pFrame )
    {
        if( pFrame->getRootFrame() == pCheck->getRootFrame() )
        {
            SwFrame *pTmp = pFrame->GetUpper();
            while ( pTmp && !pTmp->IsFootnoteFrame() )
                pTmp = pTmp->GetUpper();

            SwFootnoteFrame *pFootnote = static_cast<SwFootnoteFrame*>(pTmp);
            while ( pFootnote && pFootnote->GetMaster() )
                pFootnote = pFootnote->GetMaster();
            if ( pFootnote != pCheck )
            {
                while (pFootnote && !pFootnote->IsDeleteForbidden())
                {
                    SwFootnoteFrame *pNxt = pFootnote->GetFollow();
                    pFootnote->Cut();
                    SwFrame::DestroyFrame(pFootnote);
                    pFootnote = pNxt;
                }
            }
        }

        pFrame = aIter.Next();
    }
}

void SwFootnoteBossFrame::InsertFootnote( SwFootnoteFrame* pNew )
{
    // Place the footnote in front of the footnote whose attribute
    // is in front of the new one (get position via the Doc).
    // If there is no footnote in this footnote-boss yet, create a new container.
    // If there is a container but no footnote for this footnote-boss yet, place
    // the footnote behind the last footnote of the closest previous column/page.

    ResetFootnote( pNew );
    SwFootnoteFrame *pSibling = FindFirstFootnote();
    bool bDontLeave = false;

    // Ok, a sibling has been found, but is the sibling in an acceptable
    // environment?
    if( IsInSct() )
    {
        SwSectionFrame* pMySect = ImplFindSctFrame();
        bool bEndnt = pNew->GetAttr()->GetFootnote().IsEndNote();
        if( bEndnt )
        {
            const SwSectionFormat* pEndFormat = pMySect->GetEndSectFormat();
            bDontLeave = nullptr != pEndFormat;
            if( pSibling )
            {
                if( pEndFormat )
                {
                    if( !pSibling->IsInSct() ||
                        !pSibling->ImplFindSctFrame()->IsDescendantFrom( pEndFormat ) )
                        pSibling = nullptr;
                }
                else if( pSibling->IsInSct() )
                    pSibling = nullptr;
            }
        }
        else
        {
            bDontLeave = pMySect->IsFootnoteAtEnd();
            if( pSibling )
            {
                if( pMySect->IsFootnoteAtEnd() )
                {
                    if( !pSibling->IsInSct() ||
                        !pMySect->IsAnFollow( pSibling->ImplFindSctFrame() ) )
                        pSibling = nullptr;
                }
                else if( pSibling->IsInSct() )
                    pSibling = nullptr;
            }
        }
    }

    if( pSibling && pSibling->FindPageFrame()->IsEndNotePage() !=
        FindPageFrame()->IsEndNotePage() )
        pSibling = nullptr;

    // use the Doc to find out the position
    SwDoc& rDoc = GetFormat()->GetDoc();
    const sal_uInt32 nStPos = ::lcl_FindFootnotePos( rDoc, pNew->GetAttr() );

    sal_uInt32 nCmpPos = 0;
    sal_uInt32 nLastPos = 0;
    SwFootnoteContFrame *pParent = nullptr;
    if( pSibling )
    {
        nCmpPos = ::lcl_FindFootnotePos( rDoc, pSibling->GetAttr() );
        if( nCmpPos > nStPos )
            pSibling = nullptr;
    }

    if ( !pSibling )
    {   pParent = FindFootnoteCont();
        if ( !pParent )
        {
            // There is no footnote container yet. Before creating one, keep in mind that
            // there might exist another following footnote that must be placed before the
            // new inserted one e.g. because it was divided over multiple pages etc.
            pParent = FindNearestFootnoteCont( bDontLeave );
            if ( pParent )
            {
                SwFootnoteFrame *pFootnote = static_cast<SwFootnoteFrame*>(pParent->Lower());
                if ( pFootnote )
                {

                    nCmpPos = ::lcl_FindFootnotePos( rDoc, pFootnote->GetAttr() );
                    if ( nCmpPos > nStPos )
                        pParent = nullptr;
                }
                else
                    pParent = nullptr;
            }
        }
        if ( !pParent )
            // here, we are sure that we can create a footnote container
            pParent = MakeFootnoteCont();
        else
        {
            // Based on the first footnote below the Parent, search for the first footnote whose
            // index is after the index of the newly inserted, to place the new one correctly
            pSibling = static_cast<SwFootnoteFrame*>(pParent->Lower());
            if ( !pSibling )
            {
                OSL_ENSURE( false"Could not find space for footnote.");
                return;
            }
            nCmpPos  = ::lcl_FindFootnotePos( rDoc, pSibling->GetAttr() );

            SwFootnoteBossFrame *pNxtB; // remember the last one to not
            SwFootnoteFrame  *pLastSib = nullptr;    // go too far.

            while ( pSibling && nCmpPos <= nStPos )
            {
                pLastSib = pSibling; // potential candidate
                nLastPos = nCmpPos;

                while ( pSibling->GetFollow() )
                    pSibling = pSibling->GetFollow();

                if ( pSibling->GetNext() )
                {
                    pSibling = static_cast<SwFootnoteFrame*>(pSibling->GetNext());
                    OSL_ENSURE( !pSibling->GetMaster() || ( ENDNOTE > nStPos &&
                            pSibling->GetAttr()->GetFootnote().IsEndNote() ),
                            "InsertFootnote: Master expected I" );
                }
                else
                {
                    pNxtB = pSibling->FindFootnoteBossFrame();
                    SwPageFrame *pSibPage = pNxtB->FindPageFrame();
                    bool bEndNote = pSibPage->IsEndNotePage();
                    bool bChgPage = lcl_NextFootnoteBoss( pNxtB, pSibPage, bDontLeave );
                    // When changing pages, also the endnote flag must match.
                    SwFootnoteContFrame *pCont = pNxtB && ( !bChgPage ||
                        pSibPage->IsEndNotePage() == bEndNote )
                        ? pNxtB->FindNearestFootnoteCont( bDontLeave ) : nullptr;
                    if( pCont )
                        pSibling = static_cast<SwFootnoteFrame*>(pCont->Lower());
                    else // no further FootnoteContainer, insert after pSibling
                        break;
                }
                if ( pSibling )
                {
                    nCmpPos = ::lcl_FindFootnotePos( rDoc, pSibling->GetAttr() );
                    OSL_ENSURE( nCmpPos > nLastPos, "InsertFootnote: Order of FootnoteFrame's buggy" );
                }
            }
            // pLastSib is the last footnote before the new one and
            // pSibling is empty or the first one after the new one
            if ( pSibling && pLastSib && (pSibling != pLastSib) )
            {
                // too far?
                if ( nCmpPos > nStPos )
                    pSibling = pLastSib;
            }
            else if ( !pSibling )
            {
                // Last chance: Take the last footnote of the parent.
                // Special case that happens e.g. when moving paragraphs with multiple footnotes.
                // To keep the order, use the parent of the last inspected footnote.
                pSibling = pLastSib;
                while( pSibling->GetFollow() )
                    pSibling = pSibling->GetFollow();
                OSL_ENSURE( !pSibling->GetNext(), "InsertFootnote: Who's that guy?" );
            }
        }
    }
    else
    {
        // First footnote of the column/page found. Now search from there for the first one on the
        // same column/page whose index is after the given one. The last one found is the predecessor.
        SwFootnoteBossFrame* pBoss = pNew->GetRef()->FindFootnoteBossFrame(
            !pNew->GetAttr()->GetFootnote().IsEndNote() );
        sal_uInt16 nRefNum = pBoss->GetPhyPageNum();    // page number of the new footnote
        sal_uInt16 nRefCol = lcl_ColumnNum( pBoss );    // column number of the new footnote
        bool bEnd = false;
        SwFootnoteFrame *pLastSib = nullptr;
        while ( pSibling && !bEnd && (nCmpPos <= nStPos) )
        {
            pLastSib = pSibling;
            nLastPos = nCmpPos;

            while ( pSibling->GetFollow() )
                pSibling = pSibling->GetFollow();

            SwFootnoteFrame *pFoll = static_cast<SwFootnoteFrame*>(pSibling->GetNext());
            if ( pFoll )
            {
                pBoss = pSibling->GetRef()->FindFootnoteBossFrame( !pSibling->
                                            GetAttr()->GetFootnote().IsEndNote() );
                sal_uInt16 nTmpRef;
                // it's possible pBoss is empty here on an undo/redo operation
                if (pBoss && (nStPos >= ENDNOTE ||
                    (nTmpRef = pBoss->GetPhyPageNum()) < nRefNum ||
                    ( nTmpRef == nRefNum && lcl_ColumnNum( pBoss ) <= nRefCol )))
                    pSibling = pFoll;
                else
                    bEnd = true;
            }
            else
            {
                SwFootnoteBossFrame* pNxtB = pSibling->FindFootnoteBossFrame();
                SwPageFrame *pSibPage = pNxtB->FindPageFrame();
                bool bEndNote = pSibPage->IsEndNotePage();
                bool bChgPage = lcl_NextFootnoteBoss( pNxtB, pSibPage, bDontLeave );
                // When changing pages, also the endnote flag must match.
                SwFootnoteContFrame *pCont = pNxtB && ( !bChgPage ||
                    pSibPage->IsEndNotePage() == bEndNote )
                    ? pNxtB->FindNearestFootnoteCont( bDontLeave ) : nullptr;
                if ( pCont )
                    pSibling = static_cast<SwFootnoteFrame*>(pCont->Lower());
                else
                    bEnd = true;
            }
            if ( !bEnd && pSibling )
                nCmpPos = ::lcl_FindFootnotePos( rDoc, pSibling->GetAttr() );
            if (pSibling && (pSibling != pLastSib))
            {
                // too far?
                if ( (nLastPos < nCmpPos) && (nCmpPos > nStPos) )
                {
                    pSibling = pLastSib;
                    bEnd = true;
                }
            }
        }
    }
    if ( pSibling )
    {
        nCmpPos = ::lcl_FindFootnotePos( rDoc, pSibling->GetAttr() );
        if ( nCmpPos < nStPos )
        {
            while ( pSibling->GetFollow() )
                pSibling = pSibling->GetFollow();
            pParent = static_cast<SwFootnoteContFrame*>(pSibling->GetUpper());
            pSibling = static_cast<SwFootnoteFrame*>(pSibling->GetNext());
        }
        else
        {
            if( pSibling->GetMaster() )
            {
                if( ENDNOTE > nCmpPos || nStPos >= ENDNOTE )
                {
                    OSL_FAIL( "InsertFootnote: Master expected II" );
                    do
                        pSibling = pSibling->GetMaster();
                    while ( pSibling->GetMaster() );
                }
            }
            pParent = static_cast<SwFootnoteContFrame*>(pSibling->GetUpper());
        }
    }
    OSL_ENSURE( pParent, "paste in space?" );
    pNew->Paste( pParent, pSibling );
}

static SwPageFrame* lcl_GetApproximateFootnotePage(const bool bEnd, const SwPageFrame* pPage,
                                                   const SwDoc& rDoc, const SwTextFootnote *pAttr)
{
    // We can at least search the approximately correct page
    // to ensure that we will finish in finite time even if
    // hundreds of footnotes exist.
    const SwPageFrame *pNxt = static_cast<const SwPageFrame*>(pPage->GetNext());
    const sal_uInt32 nStPos = ::lcl_FindFootnotePos(rDoc, pAttr);
    while (pNxt && (bEnd ? pNxt->IsEndNotePage() : pNxt->IsFootnotePage() && !pNxt->IsEndNotePage()))
    {
        const SwFootnoteContFrame *pCont = pNxt->FindFootnoteCont();
        const SwFrame* pLower = pCont ? pCont->Lower() : nullptr;
        if (pLower)
        {
            OSL_ENSURE( pLower->IsFootnoteFrame(), "no footnote in the container" );
            if (nStPos > ::lcl_FindFootnotePos(rDoc,
                                static_cast<const SwFootnoteFrame*>(pLower)->GetAttr()))
            {
                pPage = pNxt;
                pNxt = static_cast<const SwPageFrame*>(pPage->GetNext());
                continue;
            }
        }
        break;
    }
    return const_cast<SwPageFrame*>(pPage);
}

void SwFootnoteBossFrame::AppendFootnote( SwContentFrame *pRef, SwTextFootnote *pAttr )
{
    // If the footnote already exists, do nothing.
    if ( FindFootnote( pRef, pAttr ) )
        return;

    // If footnotes are inserted at the end of the document,
    // we only need to search from the relevant page on.
    // If there is none yet, we need to create one.
    // If it is an Endnote, we need to search for or create an
    // Endnote page.
    SwDoc& rDoc = GetFormat()->GetDoc();
    SwFootnoteBossFrame *pBoss = this;
    SwPageFrame *pPage = FindPageFrame();
    SwPageFrame *pMyPage = pPage;
    bool bChgPage = false;
    const bool bEnd = pAttr->GetFootnote().IsEndNote();
    if (bEnd)
    {
        const IDocumentSettingAccess& rSettings = *pAttr->GetTextNode().getIDocumentSettingAccess();
        if( GetUpper()->IsSctFrame() &&
            static_cast<SwSectionFrame*>(GetUpper())->IsEndnAtEnd() )
        {
            // Endnotes at the end of the section.
            SwFrame* pLast =
                static_cast<SwSectionFrame*>(GetUpper())->FindLastContent( SwFindMode::EndNote );
            if( pLast )
            {
                pBoss = pLast->FindFootnoteBossFrame();
                pPage = pBoss->FindPageFrame();
            }
        }
        else if (rSettings.get(DocumentSettingId::CONTINUOUS_ENDNOTES))
        {
            // Endnotes at the end of the document.
            // Find the first page that hosts an endnote section.
            SwSectionFrame* pEndnoteSection = pPage->GetEndNoteSection();
            while (pPage->GetNext() && !pEndnoteSection)
            {
                pPage = pPage->GetNext()->DynCastPageFrame();
                pEndnoteSection = pPage->GetEndNoteSection();
            }
            // If there are no endnotes sections yet, create one at the end of the document.
            // Ignore sections which are already marked for deletion, they don't have an SwSection
            // anymore, so not usable for us.
            if (!pEndnoteSection || !pEndnoteSection->GetSection())
            {
                SwSection* pSwSection = rDoc.GetEndNoteInfo().GetSwSection(rDoc);
                pEndnoteSection = new SwSectionFrame(*pSwSection, pPage);
                SwLayoutFrame* pParent = pPage->FindBodyCont();
                SwFrame* pBefore = pPage->FindLastBodyContent();
                while (pBefore)
                {
                    // Check if the last content frame is directly under the body frame or there is
                    // something in-between, e.g. a section frame.
                    if (pBefore->GetUpper() == pParent)
                    {
                        break;
                    }

                    // If so, insert behind the parent of the content frame, not inside the parent.
                    pBefore = pBefore->GetUpper();
                }
                pEndnoteSection->InsertBehind(pParent, pBefore);
                pEndnoteSection->Init();
                pEndnoteSection->SetEndNoteSection(true);
            }

            SwFrame* pColumnFrame = pEndnoteSection->GetLower();
            if (pColumnFrame->IsColumnFrame())
            {
                pBoss = static_cast<SwColumnFrame*>(pColumnFrame);
            }
        }
        else
        {
            // Endnotes on a separate page.
            while ( pPage->GetNext() && !pPage->IsEndNotePage() )
            {
                pPage = static_cast<SwPageFrame*>(pPage->GetNext());
                bChgPage = true;
            }
            if ( !pPage->IsEndNotePage() )
            {
                SwPageDesc *pDesc = rDoc.GetEndNoteInfo().GetPageDesc( rDoc );
                pPage = ::InsertNewPage( *pDesc, pPage->GetUpper(),
                        !pPage->OnRightPage(), falsefalsetrue, nullptr );
                pPage->SetEndNotePage( true );
                bChgPage = true;
            }
            else
                pPage = lcl_GetApproximateFootnotePage(true, pPage, rDoc, pAttr);
        }
    }
    else if( FTNPOS_CHAPTER == rDoc.GetFootnoteInfo().m_ePos && ( !GetUpper()->
             IsSctFrame() || !static_cast<SwSectionFrame*>(GetUpper())->IsFootnoteAtEnd() ) )
    {
        while ( pPage->GetNext() && !pPage->IsFootnotePage() &&
                !static_cast<SwPageFrame*>(pPage->GetNext())->IsEndNotePage() )
        {
            pPage = static_cast<SwPageFrame*>(pPage->GetNext());
            bChgPage = true;
        }

        if ( !pPage->IsFootnotePage() )
        {
            SwPageDesc *pDesc = rDoc.GetFootnoteInfo().GetPageDesc( rDoc );
            pPage = ::InsertNewPage( *pDesc, pPage->GetUpper(),
                !pPage->OnRightPage(), falsefalsetrue, pPage->GetNext() );
            bChgPage = true;
        }
        else
            pPage = lcl_GetApproximateFootnotePage(false, pPage, rDoc, pAttr);
    }

    // For now, create a footnote and the corresponding content frames
    if ( !pAttr->GetStartNode() )
    {
        OSL_ENSURE( false"no footnote content." );
        return;
    }

    // If there is already a footnote content on the column/page,
    // another one cannot be created in a column area.
    if( pBoss->IsInSct() && pBoss->IsColumnFrame() && !pPage->IsFootnotePage() )
    {
        SwSectionFrame* pSct = pBoss->FindSctFrame();
        if( bEnd ? !pSct->IsEndnAtEnd() : !pSct->IsFootnoteAtEnd() )
        {
            SwFootnoteContFrame* pFootnoteCont = pSct->FindFootnoteBossFrame(!bEnd)->FindFootnoteCont();
            if( pFootnoteCont )
            {
                SwFootnoteFrame* pTmp = static_cast<SwFootnoteFrame*>(pFootnoteCont->Lower());
                if( bEnd )
                    while( pTmp && !pTmp->GetAttr()->GetFootnote().IsEndNote() )
                        pTmp = static_cast<SwFootnoteFrame*>(pTmp->GetNext());
                if( pTmp && *pTmp < pAttr )
                    return;
            }
        }
    }

    SwFootnoteFrame *pNew = new SwFootnoteFrame( rDoc.GetDfltFrameFormat(), this, pRef, pAttr );
    {
        SwNodeIndex aIdx( *pAttr->GetStartNode(), 1 );
        ::InsertCnt_( pNew, rDoc, aIdx.GetIndex() );
    }
    // If the page was changed or newly created,
    // we need to place ourselves in the first column
    if( bChgPage )
    {
        SwLayoutFrame* pBody = pPage->FindBodyCont();
        OSL_ENSURE( pBody, "AppendFootnote: NoPageBody?" );
        if( pBody->Lower() && pBody->Lower()->IsColumnFrame() )
--> --------------------

--> maximum size reached

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

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

¤ Dauer der Verarbeitung: 0.20 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.