/* -*- 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 *pDoc, const SwTextFootnote *pAttr )
{
    const SwFootnoteIdxs &rFootnoteIdxs = pDoc->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;
    }
    OSL_ENSURE( !pDoc, "FootnotePos not found." );
    return 0;
}
 
bool SwFootnoteFrame::operator<( const SwTextFootnote* pTextFootnote ) const
{
    const SwDoc* pDoc = GetFormat()->GetDoc();
    OSL_ENSURE( pDoc, "SwFootnoteFrame: Missing doc!" );
    return lcl_FindFootnotePos( pDoc, GetAttr() ) <
           lcl_FindFootnotePos( pDoc, 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 )
            {
                OSL_ENSURE( pSct->Lower() && pSct->Lower()->IsColumnFrame(),
                        "Where's the column?" );
                rpBoss = static_cast<SwColumnFrame*>(pSct->Lower());
                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();
        if( pBody && pBody->Lower() && pBody->Lower()->IsColumnFrame() )
            rpBoss = static_cast<SwFootnoteBossFrame*>(pBody->Lower()); // 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::FtnCont;
}
 
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() )
    {
        if( static_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();
                    if( static_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::Ftn;
}
 
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 *pDoc = GetFormat()->GetDoc();
    if ( GetPrev() )
    {
        OSL_ENSURE( lcl_FindFootnotePos( pDoc, static_cast<SwFootnoteFrame*>(GetPrev())->GetAttr() ) <=
                lcl_FindFootnotePos( pDoc, GetAttr() ), "Prev is not FootnotePrev" );
    }
    if ( GetNext() )
    {
        OSL_ENSURE( lcl_FindFootnotePos( pDoc, GetAttr() ) <=
                lcl_FindFootnotePos( pDoc, 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();
        if( pLay && pLay->Lower() && pLay->Lower()->IsColumnFrame() )
            pBoss = static_cast<SwFootnoteBossFrame*>(pLay->Lower());
    }
    // 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 )
                {
                    if ( pBody->Lower() && pBody->Lower()->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 && pBody->Lower() )
            {
                SwFrame* pLow = pBody->Lower();
                while (pLow)
                {
                    if( pLow->IsSctFrame() && ( !pLow->GetNext() ||
                        static_cast<SwSectionFrame*>(pLow)->IsAnyNoteAtEnd() ) &&
                        static_cast<SwSectionFrame*>(pLow)->Lower() &&
                        static_cast<SwSectionFrame*>(pLow)->Lower()->IsColumnFrame() )
                        sw_RemoveFootnotes( static_cast<SwColumnFrame*>(static_cast<SwSectionFrame*>(pLow)->Lower()),
                            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());
 
    do
    {   // On columned pages we have to clean up in all columns
        SwFootnoteBossFrame* pBoss;
        SwLayoutFrame* pBody = pPage->FindBodyCont();
        if( pBody && pBody->Lower() && pBody->Lower()->IsColumnFrame() )
            pBoss = static_cast<SwFootnoteBossFrame*>(pBody->Lower()); // 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;
 
    } while ( pPage );
}
 
/// 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, true, false);
    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 *pDoc = GetFormat()->GetDoc();
    const sal_uInt32 nStPos = ::lcl_FindFootnotePos( pDoc, pNew->GetAttr() );
 
    sal_uInt32 nCmpPos = 0;
    sal_uInt32 nLastPos = 0;
    SwFootnoteContFrame *pParent = nullptr;
    if( pSibling )
    {
        nCmpPos = ::lcl_FindFootnotePos( pDoc, 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( pDoc, 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( pDoc, 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( pDoc, 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( pDoc, pSibling->GetAttr() );
            if (pSibling && (pSibling != pLastSib))
            {
                // too far?
                if ( (nLastPos < nCmpPos) && (nCmpPos > nStPos) )
                {
                    pSibling = pLastSib;
                    bEnd = true;
                }
            }
        }
    }
    if ( pSibling )
    {
        nCmpPos = ::lcl_FindFootnotePos( pDoc, 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 *pDoc, 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(pDoc, pAttr);
    while (pNxt && (bEnd ? pNxt->IsEndNotePage() : pNxt->IsFootnotePage() && !pNxt->IsEndNotePage()))
    {
        const SwFootnoteContFrame *pCont = pNxt->FindFootnoteCont();
        if (pCont && pCont->Lower())
        {
            OSL_ENSURE( pCont->Lower()->IsFootnoteFrame(), "no footnote in the container" );
            if (nStPos > ::lcl_FindFootnotePos(pDoc,
                                static_cast<const SwFootnoteFrame*>(pCont->Lower())->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 *pDoc = 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 = pDoc->GetEndNoteInfo().GetSwSection(*pDoc);
                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 = pDoc->GetEndNoteInfo().GetPageDesc( *pDoc );
                pPage = ::InsertNewPage( *pDesc, pPage->GetUpper(),
                        !pPage->OnRightPage(), false, false, true, nullptr );
                pPage->SetEndNotePage( true );
                bChgPage = true;
            }
            else
                pPage = lcl_GetApproximateFootnotePage(true, pPage, pDoc, pAttr);
        }
    }
    else if( FTNPOS_CHAPTER == pDoc->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 = pDoc->GetFootnoteInfo().GetPageDesc( *pDoc );
            pPage = ::InsertNewPage( *pDesc, pPage->GetUpper(),
                !pPage->OnRightPage(), false, false, true, pPage->GetNext() );
            bChgPage = true;
        }
        else
            pPage = lcl_GetApproximateFootnotePage(false, pPage, pDoc, 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( pDoc->GetDfltFrameFormat(), this, pRef, pAttr );
    {
        SwNodeIndex aIdx( *pAttr->GetStartNode(), 1 );
        ::InsertCnt_( pNew, pDoc, 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() )
            pBoss = static_cast<SwFootnoteBossFrame*>(pBody->Lower());
        else
            pBoss = pPage; // page if no columns exist
    }
    pBoss->InsertFootnote( pNew );
    if ( pNew->GetUpper() ) // inserted or not?
    {
        ::RegistFlys( pNew->FindPageFrame(), pNew );
        SwSectionFrame* pSect = FindSctFrame();
        // The content of a FootnoteContainer in a (column) section only need to be calculated
        // if the section stretches already to the bottom edge of the Upper.
        if( pSect && !pSect->IsJoinLocked() && ( bEnd ? !pSect->IsEndnAtEnd() :
            !pSect->IsFootnoteAtEnd() ) && pSect->Growable() )
            pSect->InvalidateSize();
        else
        {
            // #i49383# - disable unlock of position of
            // lower objects during format of footnote content.
            const bool bOldFootnoteFrameLocked( pNew->IsColLocked() );
            pNew->ColLock();
            pNew->KeepLockPosOfLowerObjs();
            // #i57914# - adjust fix #i49383#
            SwContentFrame *pCnt = pNew->ContainsContent();
            while ( pCnt && pCnt->FindFootnoteFrame()->GetAttr() == pAttr )
            {
                pCnt->Calc(getRootFrame()->GetCurrShell()->GetOut());
                // #i49383# - format anchored objects
                if ( pCnt->IsTextFrame() && pCnt->isFrameAreaDefinitionValid() )
                {
                    if ( !SwObjectFormatter::FormatObjsAtFrame( *pCnt,
                                                              *(pCnt->FindPageFrame()) ) )
                    {
                        // restart format with first content
                        pCnt = pNew->ContainsContent();
                        continue;
                    }
                }
                pCnt = pCnt->FindNextCnt();
            }
            // #i49383#
            if ( !bOldFootnoteFrameLocked )
            {
                pNew->ColUnlock();
            }
            // #i57914# - adjust fix #i49383#
            // enable lock of lower object position before format of footnote frame.
            pNew->UnlockPosOfLowerObjs();
            pNew->Calc(getRootFrame()->GetCurrShell()->GetOut());
            // #i57914# - adjust fix #i49383#
            if ( !bOldFootnoteFrameLocked && !pNew->GetLower() &&
                 !pNew->IsColLocked() && !pNew->IsBackMoveLocked() &&
                 !pNew->IsDeleteForbidden() )
            {
                pNew->Cut();
                SwFrame::DestroyFrame(pNew);
            }
        }
        pMyPage->UpdateFootnoteNum();
    }
    else
        SwFrame::DestroyFrame(pNew);
}
 
SwFootnoteFrame *SwFootnoteBossFrame::FindFootnote( const SwContentFrame *pRef, const SwTextFootnote *pAttr )
{
    // the easiest and savest way goes via the attribute
    OSL_ENSURE( pAttr->GetStartNode(), "FootnoteAtr without StartNode." );
    SwNodeIndex aIdx( *pAttr->GetStartNode(), 1 );
    SwContentNode *pNd = aIdx.GetNode().GetContentNode();
    if ( !pNd )
        pNd = SwNodes::GoNextSection(&aIdx, true, false);
    if ( !pNd )
        return nullptr;
    SwIterator<SwFrame, SwContentNode, sw::IteratorMode::UnwrapMulti> aIter(*pNd);
    SwFrame* pFrame = aIter.First();
    if( pFrame )
        do
        {
                pFrame = pFrame->GetUpper();
                // #i28500#, #i27243# Due to the endnode collector, there are
                // SwFootnoteFrames, which are not in the layout. Therefore the
                // bInfFootnote flags are not set correctly, and a cell of FindFootnoteFrame
                // would return 0. Therefore we better call ImplFindFootnoteFrame().
                SwFootnoteFrame *pFootnote = pFrame->ImplFindFootnoteFrame();
                if ( pFootnote && pFootnote->GetRef() == pRef )
                {
                    // The following condition becomes true, if the whole
                    // footnotecontent is a section. While no frames exist,
                    // the HiddenFlag of the section is set, this causes
                    // the GoNextSection-function leaves the footnote.
                    if( pFootnote->GetAttr() != pAttr )
                        return nullptr;
                    while ( pFootnote && pFootnote->GetMaster() )
                        pFootnote = pFootnote->GetMaster();
                    return pFootnote;
                }
 
        } while ( nullptr != (pFrame = aIter.Next()) );
 
    return nullptr;
}
 
bool SwFootnoteBossFrame::RemoveFootnote(
        const SwContentFrame *const pRef, const SwTextFootnote *const pAttr,
                              bool bPrep )
{
    bool ret(false);
    SwFootnoteFrame *pFootnote = FindFootnote( pRef, pAttr );
    if( pFootnote )
    {
        ret = true;
        do
        {
            SwFootnoteFrame *pFoll = pFootnote->GetFollow();
            pFootnote->Cut();
            SwFrame::DestroyFrame(pFootnote);
            pFootnote = pFoll;
        } while ( pFootnote );
        if( bPrep && pRef->IsFollow() )
        {
            OSL_ENSURE( pRef->IsTextFrame(), "NoTextFrame has Footnote?" );
            SwTextFrame* pMaster = pRef->FindMaster();
            if( !pMaster->IsLocked() )
                pMaster->Prepare( PrepareHint::FootnoteInvalidationGone );
        }
    }
    FindPageFrame()->UpdateFootnoteNum();
    return ret;
}
 
void SwFootnoteBossFrame::ChangeFootnoteRef( const SwContentFrame *pOld, const SwTextFootnote *pAttr,
                                 SwContentFrame *pNew )
{
    SwFootnoteFrame *pFootnote = FindFootnote( pOld, pAttr );
    while ( pFootnote )
    {
        pFootnote->SetRef( pNew );
        pFootnote = pFootnote->GetFollow();
    }
}
 
/// OD 03.04.2003 #108446# - add parameter <_bCollectOnlyPreviousFootnotes> in
/// order to control, if only footnotes, which are positioned before the
/// footnote boss frame <this> have to be collected.
void SwFootnoteBossFrame::CollectFootnotes( const SwContentFrame* _pRef,
                                SwFootnoteBossFrame*     _pOld,
                                SwFootnoteFrames&        _rFootnoteArr,
                                const bool    _bCollectOnlyPreviousFootnotes )
{
    SwFootnoteFrame *pFootnote = _pOld->FindFirstFootnote();
    while( !pFootnote )
    {
        if( _pOld->IsColumnFrame() )
        {
            // visit columns
            while ( !pFootnote && _pOld->GetPrev() )
            {
                // Still no problem if no footnote was found yet. The loop is needed to pick up
                // following rows in tables. In all other cases it might correct bad contexts.
                _pOld = static_cast<SwFootnoteBossFrame*>(_pOld->GetPrev());
                pFootnote = _pOld->FindFirstFootnote();
            }
        }
        if( !pFootnote )
        {
            // previous page
            SwPageFrame* pPg;
            for ( SwFrame* pTmp = _pOld;
                  nullptr != ( pPg = static_cast<SwPageFrame*>(pTmp->FindPageFrame()->GetPrev()))
                    && pPg->IsEmptyPage() ;
                )
            {
                pTmp = pPg;
            }
            if( !pPg )
                return;
 
            SwLayoutFrame* pBody = pPg->FindBodyCont();
            if( pBody->Lower() && pBody->Lower()->IsColumnFrame() )
            {
                // multiple columns on one page => search last column
                _pOld = static_cast<SwFootnoteBossFrame*>(pBody->GetLastLower());
            }
            else
                _pOld = pPg; // single column page
            pFootnote = _pOld->FindFirstFootnote();
        }
    }
 
    CollectFootnotes_(_pRef, pFootnote, _rFootnoteArr, _bCollectOnlyPreviousFootnotes ? this : nullptr);
}
 
static void FootnoteInArr( SwFootnoteFrames& rFootnoteArr, SwFootnoteFrame* pFootnote )
{
    if ( rFootnoteArr.end() == std::find( rFootnoteArr.begin(), rFootnoteArr.end(), pFootnote ) )
        rFootnoteArr.push_back( pFootnote );
}
 
void SwFootnoteBossFrame::CollectFootnotes_( const SwContentFrame*   _pRef,
                                 SwFootnoteFrame*           _pFootnote,
                                 SwFootnoteFrames&          _rFootnoteArr,
                                 const SwFootnoteBossFrame* _pRefFootnoteBossFrame)
{
    // Collect all footnotes referenced by pRef (attribute by attribute), combine them
    // (the content might be divided over multiple pages) and cut them.
 
    // For robustness, we do not log the corresponding footnotes here. If a footnote
    // is touched twice, there might be a crash. This allows this function here to
    // also handle corrupt layouts in some degrees (without loops or even crashes).
    SwFootnoteFrames aNotFootnoteArr;
 
    // here we have a footnote placed in front of the first one of the reference
    OSL_ENSURE( !_pFootnote->GetMaster() || _pFootnote->GetRef() != _pRef, "move FollowFootnote?" );
    while ( _pFootnote->GetMaster() )
        _pFootnote = _pFootnote->GetMaster();
 
    bool bFound = false;
 
    do
    {
        // Search for the next footnote in this column/page so that
        // we do not start from zero again after cutting one footnote.
        SwFootnoteFrame *pNxtFootnote = _pFootnote;
        while ( pNxtFootnote->GetFollow() )
            pNxtFootnote = pNxtFootnote->GetFollow();
        pNxtFootnote = static_cast<SwFootnoteFrame*>(pNxtFootnote->GetNext());
 
        if ( !pNxtFootnote )
        {
            SwFootnoteBossFrame* pBoss = _pFootnote->FindFootnoteBossFrame();
            SwPageFrame* pPage = pBoss->FindPageFrame();
            do
            {
                lcl_NextFootnoteBoss( pBoss, pPage, false );
                if( pBoss )
                {
                    SwLayoutFrame* pCont = pBoss->FindFootnoteCont();
                    if( pCont )
                    {
                        pNxtFootnote = static_cast<SwFootnoteFrame*>(pCont->Lower());
                        if( pNxtFootnote )
                        {
                            while( pNxtFootnote->GetMaster() )
                                pNxtFootnote = pNxtFootnote->GetMaster();
                            if( pNxtFootnote == _pFootnote )
                                pNxtFootnote = nullptr;
                        }
                    }
                }
            } while( !pNxtFootnote && pBoss );
        }
        else if( !pNxtFootnote->GetAttr()->GetFootnote().IsEndNote() )
        {
            OSL_ENSURE( !pNxtFootnote->GetMaster(), "_CollectFootnote: Master expected" );
            while ( pNxtFootnote->GetMaster() )
                pNxtFootnote = pNxtFootnote->GetMaster();
        }
        if ( pNxtFootnote == _pFootnote )
        {
            OSL_FAIL(   "_CollectFootnote: Vicious circle" );
            pNxtFootnote = nullptr;
        }
 
        // OD 03.04.2003 #108446# - determine, if found footnote has to be collected.
        bool bCollectFoundFootnote = false;
        // Ignore endnotes which are on a separate endnote page.
        bool bEndNote = _pFootnote->GetAttr()->GetFootnote().IsEndNote();
        if (_pFootnote->GetRef() == _pRef && !bEndNote)
        {
            if (_pRefFootnoteBossFrame)
            {
                SwFootnoteBossFrame* pBossOfFoundFootnote = _pFootnote->FindFootnoteBossFrame( true );
                OSL_ENSURE( pBossOfFoundFootnote,
                        "<SwFootnoteBossFrame::CollectFootnotes_(..)> - footnote boss frame of found footnote frame missing.\nWrong layout!" );
                if ( !pBossOfFoundFootnote ||    // don't crash, if no footnote boss is found.
                     pBossOfFoundFootnote->IsBefore( _pRefFootnoteBossFrame )
                   )
                {
                    bCollectFoundFootnote = true;
                }
            }
            else
            {
                bCollectFoundFootnote = true;
            }
        }
 
        if ( bCollectFoundFootnote )
        {
            OSL_ENSURE( !_pFootnote->GetMaster(), "move FollowFootnote?" );
            SwFootnoteFrame *pNxt = _pFootnote->GetFollow();
            while ( pNxt )
            {
                SwFrame *pCnt = pNxt->ContainsAny();
                if ( pCnt )
                {
                    // destroy the follow on the way as it is empty
                    do
                    {   SwFrame *pNxtCnt = pCnt->GetNext();
                        pCnt->Cut();
                        pCnt->Paste( _pFootnote );
                        pCnt = pNxtCnt;
                    } while ( pCnt );
                }
                else
                {
                    OSL_ENSURE( !pNxt, "footnote without content?" );
                    pNxt->Cut();
                    SwFrame::DestroyFrame(pNxt);
                }
                pNxt = _pFootnote->GetFollow();
            }
            _pFootnote->Cut();
            FootnoteInArr( _rFootnoteArr, _pFootnote );
            bFound = true;
        }
        else
        {
            FootnoteInArr( aNotFootnoteArr, _pFootnote );
            if( bFound )
                break;
        }
        if ( pNxtFootnote &&
             _rFootnoteArr.end() == std::find( _rFootnoteArr.begin(), _rFootnoteArr.end(), pNxtFootnote ) &&
             aNotFootnoteArr.end() == std::find( aNotFootnoteArr.begin(), aNotFootnoteArr.end(), pNxtFootnote ) )
            _pFootnote = pNxtFootnote;
        else
            break;
    }
    while ( _pFootnote );
}
 
void SwFootnoteBossFrame::MoveFootnotes_( SwFootnoteFrames &rFootnoteArr, bool bCalc )
{
    // All footnotes referenced by pRef need to be moved
    // to a new position (based on the new column/page)
    const sal_uInt16 nMyNum = FindPageFrame()->GetPhyPageNum();
    const sal_uInt16 nMyCol = lcl_ColumnNum( this );
    SwRectFnSet aRectFnSet(this);
 
    // #i21478# - keep last inserted footnote in order to
    // format the content of the following one.
    SwFootnoteFrame* pLastInsertedFootnote = nullptr;
    for (SwFootnoteFrame* pFootnote : rFootnoteArr)
    {
        SwFootnoteBossFrame* pRefBoss(pFootnote->GetRef()->FindFootnoteBossFrame(
                !pFootnote->GetAttr()->GetFootnote().IsEndNote()));
        if( pRefBoss != this )
        {
            const sal_uInt16 nRefNum = pRefBoss->FindPageFrame()->GetPhyPageNum();
            const sal_uInt16 nRefCol = lcl_ColumnNum( this );
            if( nRefNum < nMyNum || ( nRefNum == nMyNum && nRefCol <= nMyCol ) )
                pRefBoss = this;
        }
        pRefBoss->InsertFootnote( pFootnote );
 
        if ( pFootnote->GetUpper() ) // robust, e.g. with duplicates
        {
            // First condense the content so that footnote frames that do not fit on the page
            // do not do too much harm (Loop 66312). So, the footnote content first grows as
            // soon as the content gets formatted and it is sure that it fits on the page.
            SwFrame *pCnt = pFootnote->ContainsAny();
            while( pCnt )
            {
                if( pCnt->IsLayoutFrame() )
                {
                    SwFrame* pTmp = static_cast<SwLayoutFrame*>(pCnt)->ContainsAny();
                    while( pTmp && static_cast<SwLayoutFrame*>(pCnt)->IsAnLower( pTmp ) )
                    {
                        pTmp->Prepare( PrepareHint::FootnoteMove );
 
                        SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*pTmp);
                        aRectFnSet.SetHeight(aFrm, 0);
 
                        SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*pTmp);
                        aRectFnSet.SetHeight(aPrt, 0);
 
                        pTmp = pTmp->FindNext();
                    }
                }
                else
                {
                    pCnt->Prepare( PrepareHint::FootnoteMove );
                }
 
                SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*pCnt);
                aRectFnSet.SetHeight(aFrm, 0);
 
                SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*pCnt);
                aRectFnSet.SetHeight(aPrt, 0);
 
                pCnt = pCnt->GetNext();
            }
 
            {
                SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*pFootnote);
                aRectFnSet.SetHeight(aFrm, 0);
            }
 
            {
                SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*pFootnote);
                aRectFnSet.SetHeight(aPrt, 0);
            }
 
            pFootnote->Calc(getRootFrame()->GetCurrShell()->GetOut());
            pFootnote->GetUpper()->Calc(getRootFrame()->GetCurrShell()->GetOut());
 
            if( bCalc )
            {
                SwTextFootnote *pAttr = pFootnote->GetAttr();
                pCnt = pFootnote->ContainsAny();
                bool bUnlock = !pFootnote->IsBackMoveLocked();
                pFootnote->LockBackMove();
 
                // #i49383# - disable unlock of position of
                // lower objects during format of footnote content.
                pFootnote->KeepLockPosOfLowerObjs();
                // #i57914# - adjust fix #i49383#
 
                while ( pCnt && pCnt->FindFootnoteFrame()->GetAttr() == pAttr )
                {
                    pCnt->InvalidatePos_();
                    pCnt->Calc(getRootFrame()->GetCurrShell()->GetOut());
                    // #i49383# - format anchored objects
                    if ( pCnt->IsTextFrame() && pCnt->isFrameAreaDefinitionValid() )
                    {
                        if ( !SwObjectFormatter::FormatObjsAtFrame( *pCnt,
                                                                  *(pCnt->FindPageFrame()) ) )
                        {
                            // restart format with first content
                            pCnt = pFootnote->ContainsAny();
                            continue;
                        }
                    }
                    if( pCnt->IsSctFrame() )
                    {
                        // If the area is not empty, iterate also over the content
                        SwFrame* pTmp = static_cast<SwSectionFrame*>(pCnt)->ContainsAny();
                        if( pTmp )
                            pCnt = pTmp;
                        else
                            pCnt = pCnt->FindNext();
                    }
                    else
                        pCnt = pCnt->FindNext();
                }
                if( bUnlock )
                {
                    pFootnote->UnlockBackMove();
                    if( !pFootnote->ContainsAny() && !pFootnote->IsColLocked() )
                    {
                        pFootnote->Cut();
                        SwFrame::DestroyFrame(pFootnote);
                        // #i21478#
                        pFootnote = nullptr;
                    }
                }
                // #i49383#
                if ( pFootnote )
                {
                    // #i57914# - adjust fix #i49383#
                    // enable lock of lower object position before format of footnote frame.
                    pFootnote->UnlockPosOfLowerObjs();
                    pFootnote->Calc(getRootFrame()->GetCurrShell()->GetOut());
                }
            }
        }
        else
        {
            OSL_ENSURE( !pFootnote->GetMaster() && !pFootnote->GetFollow(),
                    "DelFootnote and Master/Follow?" );
            SwFrame::DestroyFrame(pFootnote);
            // #i21478#
            pFootnote = nullptr;
        }
 
        // #i21478#
        if ( pFootnote )
        {
            pLastInsertedFootnote = pFootnote;
        }
    }
 
    // #i21478# - format content of footnote following
    // the new inserted ones.
    if ( !(bCalc && pLastInsertedFootnote) )
        return;
 
    if ( !pLastInsertedFootnote->GetNext() )
        return;
 
    SwFootnoteFrame* pNextFootnote = static_cast<SwFootnoteFrame*>(pLastInsertedFootnote->GetNext());
    SwTextFootnote* pAttr = pNextFootnote->GetAttr();
    SwFrame* pCnt = pNextFootnote->ContainsAny();
 
    bool bUnlock = !pNextFootnote->IsBackMoveLocked();
    pNextFootnote->LockBackMove();
    // #i49383# - disable unlock of position of
    // lower objects during format of footnote content.
    pNextFootnote->KeepLockPosOfLowerObjs();
    // #i57914# - adjust fix #i49383#
 
    while ( pCnt && pCnt->FindFootnoteFrame()->GetAttr() == pAttr )
    {
        pCnt->InvalidatePos_();
        pCnt->Calc(getRootFrame()->GetCurrShell()->GetOut());
        // #i49383# - format anchored objects
        if ( pCnt->IsTextFrame() && pCnt->isFrameAreaDefinitionValid() )
        {
            if ( !SwObjectFormatter::FormatObjsAtFrame( *pCnt,
                                                      *(pCnt->FindPageFrame()) ) )
            {
                // restart format with first content
                pCnt = pNextFootnote->ContainsAny();
                continue;
            }
        }
        if( pCnt->IsSctFrame() )
        {
            // If the area is not empty, iterate also over the content
            SwFrame* pTmp = static_cast<SwSectionFrame*>(pCnt)->ContainsAny();
            if( pTmp )
                pCnt = pTmp;
            else
                pCnt = pCnt->FindNext();
        }
        else
            pCnt = pCnt->FindNext();
    }
    if( bUnlock )
    {
        pNextFootnote->UnlockBackMove();
    }
    // #i49383#
    // #i57914# - adjust fix #i49383#
    // enable lock of lower object position before format of footnote frame.
    pNextFootnote->UnlockPosOfLowerObjs();
    pNextFootnote->Calc(getRootFrame()->GetCurrShell()->GetOut());
}
 
void SwFootnoteBossFrame::MoveFootnotes( const SwContentFrame *pSrc, SwContentFrame *pDest,
                             SwTextFootnote const *pAttr )
{
    if( ( GetFormat()->GetDoc()->GetFootnoteInfo().m_ePos == FTNPOS_CHAPTER &&
        (!GetUpper()->IsSctFrame() || !static_cast<SwSectionFrame*>(GetUpper())->IsFootnoteAtEnd()))
        || pAttr->GetFootnote().IsEndNote() )
        return;
 
    OSL_ENSURE( this == pSrc->FindFootnoteBossFrame( true ),
            "SwPageFrame::MoveFootnotes: source frame isn't on that FootnoteBoss" );
 
    SwFootnoteFrame *pFootnote = FindFirstFootnote();
    if( !pFootnote )
        return;
 
    ChangeFootnoteRef( pSrc, pAttr, pDest );
    SwFootnoteBossFrame *pDestBoss = pDest->FindFootnoteBossFrame( true );
    OSL_ENSURE( pDestBoss, "+SwPageFrame::MoveFootnotes: no destination boss" );
    if( !pDestBoss )     // robust
        return;
 
    SwFootnoteFrames aFootnoteArr;
    SwFootnoteBossFrame::CollectFootnotes_(pDest, pFootnote, aFootnoteArr, nullptr);
    if ( aFootnoteArr.empty() )
        return;
 
    pDestBoss->MoveFootnotes_( aFootnoteArr, true );
    SwPageFrame* pSrcPage = FindPageFrame();
    SwPageFrame* pDestPage = pDestBoss->FindPageFrame();
    // update FootnoteNum only at page change
    if( pSrcPage != pDestPage )
    {
        if( pSrcPage->GetPhyPageNum() > pDestPage->GetPhyPageNum() )
            pSrcPage->UpdateFootnoteNum();
        pDestPage->UpdateFootnoteNum();
    }
}
 
void SwFootnoteBossFrame::RearrangeFootnotes( const SwTwips nDeadLine, const bool bLock,
                                  const SwTextFootnote *pAttr )
{
    // Format all footnotes of a column/page so that they might change the column/page.
 
    SwSaveFootnoteHeight aSave( this, nDeadLine );
    SwFootnoteFrame *pFootnote = FindFirstFootnote();
    if( pFootnote && pFootnote->GetPrev() && bLock )
    {
        SwFootnoteFrame* pFirst = static_cast<SwFootnoteFrame*>(pFootnote->GetUpper()->Lower());
        SwFrame* pContent = pFirst->ContainsAny();
        if( pContent )
        {
            bool bUnlock = !pFirst->IsBackMoveLocked();
            pFirst->LockBackMove();
            pFirst->Calc(getRootFrame()->GetCurrShell()->GetOut());
            pContent->Calc(getRootFrame()->GetCurrShell()->GetOut());
            // #i49383# - format anchored objects
            if ( pContent->IsTextFrame() && pContent->isFrameAreaDefinitionValid() )
            {
                SwObjectFormatter::FormatObjsAtFrame( *pContent,
                                                    *(pContent->FindPageFrame()) );
            }
            if( bUnlock )
                pFirst->UnlockBackMove();
        }
        pFootnote = FindFirstFootnote();
    }
    SwDoc *pDoc = GetFormat()->GetDoc();
    const sal_uInt32 nFootnotePos = pAttr ? ::lcl_FindFootnotePos( pDoc, pAttr ) : 0;
    SwFrame *pCnt = pFootnote ? pFootnote->ContainsAny() : nullptr;
    if ( !pCnt )
        return;
 
    bool bMore = true;
    bool bStart = pAttr == nullptr; // If no attribute is given, process all
    // #i49383# - disable unlock of position of
    // lower objects during format of footnote and footnote content.
    SwFootnoteFrame* pLastFootnoteFrame( nullptr );
    // footnote frame needs to be locked, if <bLock> isn't set.
    bool bUnlockLastFootnoteFrame( false );
    do
    {
        if( !bStart )
            bStart = ::lcl_FindFootnotePos( pDoc, pCnt->FindFootnoteFrame()->GetAttr() )
                     == nFootnotePos;
        if( bStart )
        {
            pCnt->InvalidatePos_();
            pCnt->InvalidateSize_();
            pCnt->Prepare( PrepareHint::AdjustSizeWithoutFormatting );
            SwFootnoteFrame* pFootnoteFrame = pCnt->FindFootnoteFrame();
            assert(pFootnoteFrame);
            // #i49383#
            if ( pFootnoteFrame != pLastFootnoteFrame )
            {
                if ( pLastFootnoteFrame )
                {
                    if ( !bLock && bUnlockLastFootnoteFrame )
                    {
                        pLastFootnoteFrame->ColUnlock();
                    }
                    // #i57914# - adjust fix #i49383#
                    // enable lock of lower object position before format of footnote frame.
                    pLastFootnoteFrame->UnlockPosOfLowerObjs();
                    pLastFootnoteFrame->Calc(getRootFrame()->GetCurrShell()->GetOut());
                    if ( !bLock && bUnlockLastFootnoteFrame &&
                         !pLastFootnoteFrame->GetLower() &&
                         !pLastFootnoteFrame->IsColLocked() &&
                         !pLastFootnoteFrame->IsBackMoveLocked() &&
                         !pLastFootnoteFrame->IsDeleteForbidden() )
                    {
                        pLastFootnoteFrame->Cut();
                        SwFrame::DestroyFrame(pLastFootnoteFrame);
                        // pLastFootnoteFrame overwritten at end of block
                    }
                }
                if ( !bLock )
                {
                    bUnlockLastFootnoteFrame = !pFootnoteFrame->IsColLocked();
                    pFootnoteFrame->ColLock();
                }
                pFootnoteFrame->KeepLockPosOfLowerObjs();
                pLastFootnoteFrame = pFootnoteFrame;
            }
            // OD 30.10.2002 #97265# - invalidate position of footnote
            // frame, if it's below its footnote container, in order to
            // assure its correct position, probably calculating its previous
            // footnote frames.
            {
                SwRectFnSet aRectFnSet(this);
                SwFrame* pFootnoteContFrame = pFootnoteFrame->GetUpper();
                if ( aRectFnSet.TopDist(pFootnoteFrame->getFrameArea(), aRectFnSet.GetPrtBottom(*pFootnoteContFrame)) > 0 )
                {
                    pFootnoteFrame->InvalidatePos_();
                }
            }
            if ( bLock )
            {
                bool bUnlock = !pFootnoteFrame->IsBackMoveLocked();
                pFootnoteFrame->LockBackMove();
                pFootnoteFrame->Calc(getRootFrame()->GetCurrShell()->GetOut());
                pCnt->Calc(getRootFrame()->GetCurrShell()->GetOut());
                // #i49383# - format anchored objects
                if ( pCnt->IsTextFrame() && pCnt->isFrameAreaDefinitionValid() )
                {
                    SwFrameDeleteGuard aDeleteGuard(pFootnote);
                    if ( !SwObjectFormatter::FormatObjsAtFrame( *pCnt,
                                                              *(pCnt->FindPageFrame()) ) )
                    {
                        // restart format with first content
                        pCnt = pFootnote ? pFootnote->ContainsAny() : nullptr;
                        if (!pCnt)
                            bMore = false;
                        continue;
                    }
                }
                if( bUnlock )
                {
                    pFootnoteFrame->UnlockBackMove();
                    if( !pFootnoteFrame->Lower() &&
                        !pFootnoteFrame->IsColLocked() )
                    {
                        // #i49383#
                        OSL_ENSURE( pLastFootnoteFrame == pFootnoteFrame,
                                "<SwFootnoteBossFrame::RearrangeFootnotes(..)> - <pLastFootnoteFrame> != <pFootnoteFrame>" );
                        pLastFootnoteFrame = nullptr;
                        pFootnoteFrame->Cut();
                        SwFrame::DestroyFrame(pFootnoteFrame);
                        if (pFootnote == pFootnoteFrame)
                            pFootnote = nullptr;
                    }
                }
            }
            else
            {
                pFootnoteFrame->Calc(getRootFrame()->GetCurrShell()->GetOut());
                pCnt->Calc(getRootFrame()->GetCurrShell()->GetOut());
                // #i49383# - format anchored objects
                if ( pCnt->IsTextFrame() && pCnt->isFrameAreaDefinitionValid() )
                {
                    if ( !SwObjectFormatter::FormatObjsAtFrame( *pCnt,
                                                              *(pCnt->FindPageFrame()) ) )
                    {
                        // restart format with first content
                        pCnt = pFootnote->ContainsAny();
                        continue;
                    }
                }
            }
        }
        SwSectionFrame *pDel = nullptr;
        if( pCnt->IsSctFrame() )
        {
            SwFrame* pTmp = static_cast<SwSectionFrame*>(pCnt)->ContainsAny();
            if( pTmp )
            {
                pCnt = pTmp;
                continue;
            }
            pDel = static_cast<SwSectionFrame*>(pCnt);
        }
        if ( pCnt->GetNext() )
            pCnt = pCnt->GetNext();
        else
        {
            pCnt = pCnt->FindNext();
            if ( pCnt )
            {
                SwFootnoteFrame* pFootnoteFrame = pCnt->FindFootnoteFrame();
                if( pFootnoteFrame->GetRef()->FindFootnoteBossFrame(
                    pFootnoteFrame->GetAttr()->GetFootnote().IsEndNote() ) != this )
                    bMore = false;
            }
            else
                bMore = false;
        }
        if( pDel )
        {
            bool bUnlockLastFootnoteFrameGuard = pLastFootnoteFrame && !pLastFootnoteFrame->IsColLocked();
            if (bUnlockLastFootnoteFrameGuard)
                pLastFootnoteFrame->ColLock();
            pDel->Cut();
            if (bUnlockLastFootnoteFrameGuard)
                pLastFootnoteFrame->ColUnlock();
            SwFrame::DestroyFrame(pDel);
        }
        if ( bMore )
        {
            // Go not further than to the provided footnote (if given)
            if ( pAttr &&
                 (::lcl_FindFootnotePos( pDoc,
                                pCnt->FindFootnoteFrame()->GetAttr()) > nFootnotePos ) )
                bMore = false;
        }
    } while ( bMore );
    // #i49383#
    if ( !pLastFootnoteFrame )
        return;
 
    if ( !bLock && bUnlockLastFootnoteFrame )
    {
        pLastFootnoteFrame->ColUnlock();
    }
    // #i57914# - adjust fix #i49383#
    // enable lock of lower object position before format of footnote frame.
    pLastFootnoteFrame->UnlockPosOfLowerObjs();
    pLastFootnoteFrame->Calc(getRootFrame()->GetCurrShell()->GetOut());
    if ( !bLock && bUnlockLastFootnoteFrame &&
         !pLastFootnoteFrame->GetLower() &&
         !pLastFootnoteFrame->IsColLocked() &&
         !pLastFootnoteFrame->IsBackMoveLocked() &&
         !pLastFootnoteFrame->IsDeleteForbidden() )
    {
        pLastFootnoteFrame->Cut();
        SwFrame::DestroyFrame(pLastFootnoteFrame);
    }
}
 
void SwPageFrame::UpdateFootnoteNum()
{
    // page numbering only if set at the document
    if ( GetFormat()->GetDoc()->GetFootnoteInfo().m_eNum != FTNNUM_PAGE )
        return;
 
    SwLayoutFrame* pBody = FindBodyCont();
    if( !pBody || !pBody->Lower() )
        return;
 
    SwContentFrame* pContent = pBody->ContainsContent();
    sal_uInt16 nNum = 0;
 
    while( pContent && pContent->FindPageFrame() == this )
    {
        if( static_cast<SwTextFrame*>(pContent)->HasFootnote() )
        {
            SwFootnoteBossFrame* pBoss = pContent->FindFootnoteBossFrame( true );
            if( pBoss->GetUpper()->IsSctFrame() &&
                static_cast<SwSectionFrame*>(pBoss->GetUpper())->IsOwnFootnoteNum() )
                pContent = static_cast<SwSectionFrame*>(pBoss->GetUpper())->FindLastContent();
            else
            {
                SwFootnoteFrame* pFootnote = const_cast<SwFootnoteFrame*>(pBoss->FindFirstFootnote( pContent ));
                while( pFootnote )
                {
                    SwTextFootnote* pTextFootnote = pFootnote->GetAttr();
                    if( !pTextFootnote->GetFootnote().IsEndNote() &&
                         pTextFootnote->GetFootnote().GetNumStr().isEmpty() &&
                         !pFootnote->GetMaster())
                    {
                        // sw_redlinehide: the layout can only keep one number
                        // up to date; depending on its setting, this is either
                        // the non-hidden or the hidden number; the other
                        // number will simply be preserved as-is (so in case
                        // there are 2 layouts, maybe both can be updated...)
                        ++nNum;
                        sal_uInt16 const nOldNum(pTextFootnote->GetFootnote().GetNumber());
                        sal_uInt16 const nOldNumRLHidden(pTextFootnote->GetFootnote().GetNumberRLHidden());
                        if (getRootFrame()->IsHideRedlines())
                        {
                            if (nNum != nOldNumRLHidden)
                            {
                                pTextFootnote->SetNumber(nOldNum, nNum, OUString());
                            }
                        }
                        else
                        {
                            if (nNum != nOldNum)
                            {
                                pTextFootnote->SetNumber(nNum, nOldNumRLHidden, OUString());
                            }
                        }
                    }
                    if ( pFootnote->GetNext() )
                        pFootnote = static_cast<SwFootnoteFrame*>(pFootnote->GetNext());
                    else
                    {
                        SwFootnoteBossFrame* pTmpBoss = pFootnote->FindFootnoteBossFrame( true );
                        if( pTmpBoss )
                        {
                            SwPageFrame* pPage = pTmpBoss->FindPageFrame();
                            pFootnote = nullptr;
                            lcl_NextFootnoteBoss( pTmpBoss, pPage, false );
                            SwFootnoteContFrame *pCont = pTmpBoss ? pTmpBoss->FindNearestFootnoteCont() : nullptr;
                            if ( pCont )
                                pFootnote = static_cast<SwFootnoteFrame*>(pCont->Lower());
                        }
                    }
                    if( pFootnote && pFootnote->GetRef() != pContent )
                        pFootnote = nullptr;
                }
            }
        }
        pContent = pContent->FindNextCnt();
    }
}
 
void SwFootnoteBossFrame::SetFootnoteDeadLine( const SwTwips nDeadLine )
{
    SwFrame *pBody = FindBodyCont();
    pBody->Calc(getRootFrame()->GetCurrShell()->GetOut());
 
    SwFrame *pCont = FindFootnoteCont();
    const SwTwips nMax = m_nMaxFootnoteHeight;// current should exceed MaxHeight
    SwRectFnSet aRectFnSet(this);
    if ( pCont )
    {
        pCont->Calc(getRootFrame()->GetCurrShell()->GetOut());
        m_nMaxFootnoteHeight = -aRectFnSet.BottomDist( pCont->getFrameArea(), nDeadLine );
    }
    else
        m_nMaxFootnoteHeight = -aRectFnSet.BottomDist( pBody->getFrameArea(), nDeadLine );
 
    const SwViewShell *pSh = getRootFrame() ? getRootFrame()->GetCurrShell() : nullptr;
    if( pSh && pSh->GetViewOptions()->getBrowseMode() )
        m_nMaxFootnoteHeight += pBody->Grow( LONG_MAX, true );
    if ( IsInSct() )
        m_nMaxFootnoteHeight += FindSctFrame()->Grow( LONG_MAX, true );
 
    if ( m_nMaxFootnoteHeight < 0 )
        m_nMaxFootnoteHeight = 0;
    if ( nMax != LONG_MAX && m_nMaxFootnoteHeight > nMax )
        m_nMaxFootnoteHeight = nMax;
}
 
SwTwips SwFootnoteBossFrame::GetVarSpace() const
{
    // To not fall below 20% of the page height
    // (in contrast to MSOffice where footnotes can fill a whole column/page)
 
    const SwPageFrame* pPg = FindPageFrame();
    OSL_ENSURE( pPg || IsInSct(), "Footnote lost page" );
 
    const SwFrame *pBody = FindBodyCont();
    SwTwips nRet;
    if( pBody )
    {
        SwRectFnSet aRectFnSet(this);
        nRet = aRectFnSet.GetHeight(pBody->getFrameArea());
        if( IsInSct() )
        {
            SwTwips nTmp = aRectFnSet.YDiff( aRectFnSet.GetPrtTop(*pBody),
                                               aRectFnSet.GetTop(getFrameArea()) );
            const SwSectionFrame* pSect = FindSctFrame();
            //  Endnotes in a ftncontainer causes a deadline:
            // the bottom of the last contentfrm
            if( pSect->IsEndnAtEnd() ) // endnotes allowed?
            {
                OSL_ENSURE( !Lower() || !Lower()->GetNext() || Lower()->GetNext()->
                        IsFootnoteContFrame(), "FootnoteContainer expected" );
                const SwFootnoteContFrame* pCont = Lower() ?
                    static_cast<const SwFootnoteContFrame*>(Lower()->GetNext()) : nullptr;
                if( pCont )
                {
                    const SwFootnoteFrame* pFootnote = static_cast<const SwFootnoteFrame*>(pCont->Lower());
                    while( pFootnote)
                    {
                        if( pFootnote->GetAttr()->GetFootnote().IsEndNote() )
                        { // endnote found
                            const SwFrame* pFrame = static_cast<const SwLayoutFrame*>(Lower())->Lower();
                            if( pFrame )
                            {
                                while( pFrame->GetNext() )
                                    pFrame = pFrame->GetNext(); // last cntntfrm
                                nTmp += aRectFnSet.YDiff(
                                         aRectFnSet.GetTop(getFrameArea()),
                                         aRectFnSet.GetBottom(pFrame->getFrameArea()) );
                            }
                            break;
                        }
                        pFootnote = static_cast<const SwFootnoteFrame*>(pFootnote->GetNext());
                    }
                }
            }
            if( nTmp < 0 )
                nRet += nTmp;
        }
        else
        {
            assert(pPg);
            nRet -= aRectFnSet.GetHeight(pPg->getFramePrintArea())/5;
        }
        if( nRet < 0 )
            nRet = 0;
    }
    else
        nRet = 0;
    if ( IsPageFrame() )
    {
        const SwViewShell *pSh = getRootFrame() ? getRootFrame()->GetCurrShell() : nullptr;
        if( pSh && pSh->GetViewOptions()->getBrowseMode() )
            nRet += BROWSE_HEIGHT - getFrameArea().Height();
    }
    return nRet;
}
 
/** Obtain if pFrame's size adjustment should be processed
 *
 * For a page frame of columns directly below the page AdjustNeighbourhood() needs
 * to be called, or Grow()/ Shrink() for frame columns respectively.
 *
 * A column section is special, since if there is a footnote container in a column
 * and those footnotes are not collected, it is handled like a page frame.
 *
 * @see AdjustNeighbourhood()
 * @see Grow()
 * @see Shrink()
 */
SwNeighbourAdjust SwFootnoteBossFrame::NeighbourhoodAdjustment_() const
{
    SwNeighbourAdjust nRet = SwNeighbourAdjust::OnlyAdjust;
    if( GetUpper() && !GetUpper()->IsPageBodyFrame() )
    {
        // column sections need grow/shrink
        if( GetUpper()->IsFlyFrame() )
            nRet = SwNeighbourAdjust::GrowShrink;
        else
        {
            OSL_ENSURE( GetUpper()->IsSctFrame(), "NeighbourhoodAdjustment: Unexpected Upper" );
            if( !GetNext() && !GetPrev() )
                nRet = SwNeighbourAdjust::GrowAdjust; // section with a single column (FootnoteAtEnd)
            else
            {
                const SwFrame* pTmp = Lower();
                assert(pTmp && "NeighbourhoodAdjustment: Missing Lower()");
                if( !pTmp->GetNext() )
                    nRet = SwNeighbourAdjust::GrowShrink;
                else if( !GetUpper()->IsColLocked() )
                    nRet = SwNeighbourAdjust::AdjustGrow;
                OSL_ENSURE( !pTmp->GetNext() || pTmp->GetNext()->IsFootnoteContFrame(),
                        "NeighbourhoodAdjustment: Who's that guy?" );
            }
        }
    }
    return nRet;
}
 
void SwPageFrame::SetColMaxFootnoteHeight()
{
    SwLayoutFrame *pBody = FindBodyCont();
    if( pBody && pBody->Lower() && pBody->Lower()->IsColumnFrame() )
    {
        SwColumnFrame* pCol = static_cast<SwColumnFrame*>(pBody->Lower());
        do
        {
            pCol->SetMaxFootnoteHeight( GetMaxFootnoteHeight() );
            pCol = static_cast<SwColumnFrame*>(pCol->GetNext());
        } while ( pCol );
    }
}
 
bool SwLayoutFrame::MoveLowerFootnotes( SwContentFrame *pStart, SwFootnoteBossFrame *pOldBoss,
                                 SwFootnoteBossFrame *pNewBoss, const bool bFootnoteNums )
{
    SwDoc *pDoc = GetFormat()->GetDoc();
    if ( pDoc->GetFootnoteIdxs().empty() )
        return false;
    if( pDoc->GetFootnoteInfo().m_ePos == FTNPOS_CHAPTER &&
        ( !IsInSct() || !FindSctFrame()->IsFootnoteAtEnd() ) )
        return true;
 
    if ( !pNewBoss )
        pNewBoss = FindFootnoteBossFrame( true );
    if ( pNewBoss == pOldBoss )
        return false;
 
    bool bMoved = false;
    if( !pStart )
        pStart = ContainsContent();
 
    SwFootnoteFrames aFootnoteArr;
 
    while ( IsAnLower( pStart ) )
    {
        if ( static_cast<SwTextFrame*>(pStart)->HasFootnote() )
        {
            // OD 03.04.2003 #108446# - To avoid unnecessary moves of footnotes
            // use new parameter <_bCollectOnlyPreviousFootnote> (4th parameter of
            // method <SwFootnoteBossFrame::CollectFootnote(..)>) to control, that only
            // footnotes have to be collected, that are positioned before the
            // new dedicated footnote boss frame.
            pNewBoss->CollectFootnotes( pStart, pOldBoss, aFootnoteArr, true );
        }
        pStart = pStart->GetNextContentFrame();
    }
 
    OSL_ENSURE( pOldBoss->IsInSct() == pNewBoss->IsInSct(),
            "MoveLowerFootnotes: Section confusion" );
    std::unique_ptr<SwFootnoteFrames> pFootnoteArr;
    SwLayoutFrame* pNewChief = nullptr;
    SwLayoutFrame* pOldChief = nullptr;
 
    bool bFoundCandidate = false;
    if (pStart && pOldBoss->IsInSct())
    {
        pOldChief = pOldBoss->FindSctFrame();
        pNewChief = pNewBoss->FindSctFrame();
        bFoundCandidate = pOldChief != pNewChief;
    }
 
    if (bFoundCandidate)
    {
        pFootnoteArr.reset(new SwFootnoteFrames);
        pOldChief = pOldBoss->FindFootnoteBossFrame( true );
        pNewChief = pNewBoss->FindFootnoteBossFrame( true );
        while( pOldChief->IsAnLower( pStart ) )
        {
            if ( static_cast<SwTextFrame*>(pStart)->HasFootnote() )
                static_cast<SwFootnoteBossFrame*>(pNewChief)->CollectFootnotes( pStart,
                                        pOldBoss, *pFootnoteArr );
            pStart = pStart->GetNextContentFrame();
        }
        if( pFootnoteArr->empty() )
        {
            pFootnoteArr.reset();
        }
    }
    else
        pFootnoteArr = nullptr;
 
    if ( !aFootnoteArr.empty() || pFootnoteArr )
    {
        if( !aFootnoteArr.empty() )
            pNewBoss->MoveFootnotes_( aFootnoteArr, true );
        if( pFootnoteArr )
        {
            assert(pNewChief);
            static_cast<SwFootnoteBossFrame*>(pNewChief)->MoveFootnotes_( *pFootnoteArr, true );
            pFootnoteArr.reset();
        }
        bMoved = true;
 
        // update FootnoteNum only at page change
        if ( bFootnoteNums )
        {
            SwPageFrame* pOldPage = pOldBoss->FindPageFrame();
            SwPageFrame* pNewPage =pNewBoss->FindPageFrame();
            if( pOldPage != pNewPage )
            {
                pOldPage->UpdateFootnoteNum();
                pNewPage->UpdateFootnoteNum();
            }
        }
    }
    return bMoved;
}
 
/// Return value guarantees that a new page was not created. See SwFlowFrame::MoveFwd.
bool SwContentFrame::MoveFootnoteCntFwd( bool bMakePage, SwFootnoteBossFrame *pOldBoss )
{
    OSL_ENSURE( IsInFootnote(), "no footnote." );
    SwLayoutFrame *pFootnote = FindFootnoteFrame();
 
    // The first paragraph in the first footnote in the first column in the
    // sectionfrm at the top of the page has not to move forward, if the
    // columnbody is empty.
    if( pOldBoss->IsInSct() && !pOldBoss->GetIndPrev() && !GetIndPrev() &&
        !pFootnote->GetPrev() )
    {
        SwLayoutFrame* pBody = pOldBoss->FindBodyCont();
        if( !pBody || !pBody->Lower() )
            return true;
    }
 
    //fix(9538): if the footnote has neighbors behind itself, remove them temporarily
    SwLayoutFrame *pNxt = static_cast<SwLayoutFrame*>(pFootnote->GetNext());
    SwLayoutFrame *pLst = nullptr;
    while ( pNxt )
    {
        while ( pNxt->GetNext() )
            pNxt = static_cast<SwLayoutFrame*>(pNxt->GetNext());
        if ( pNxt == pLst )
            pNxt = nullptr;
        else
        {   pLst = pNxt;
            SwContentFrame *pCnt = pNxt->ContainsContent();
            if( pCnt )
                pCnt->MoveFootnoteCntFwd( true, pOldBoss );
            pNxt = static_cast<SwLayoutFrame*>(pFootnote->GetNext());
        }
    }
 
    bool bSamePage = true;
    SwLayoutFrame *pNewUpper =
                GetLeaf( bMakePage ? MAKEPAGE_INSERT : MAKEPAGE_NONE, true );
 
    if ( pNewUpper )
    {
        SwFootnoteBossFrame * const pNewBoss = pNewUpper->FindFootnoteBossFrame();
        // Are we changing the column/page?
        bool bSameBoss = pNewBoss == pOldBoss;
        if ( !bSameBoss )
        {
            bSamePage = pOldBoss->FindPageFrame() == pNewBoss->FindPageFrame(); // page change?
            pNewUpper->Calc(getRootFrame()->GetCurrShell()->GetOut());
        }
 
        // The layout leaf of the footnote is either a footnote container or a footnote.
        // If it is a footnote and it has the same footnote reference like the old Upper,
        // then move the content inside of it.
        // If it is a container or the reference differs, create a new footnote and add
        // it into the container.
        // Create also a SectionFrame if currently in an area inside a footnote.
        SwFootnoteFrame* pTmpFootnote = pNewUpper->IsFootnoteFrame() ? static_cast<SwFootnoteFrame*>(pNewUpper) : nullptr;
        if (!pTmpFootnote)
        {
            assert(pNewUpper->IsFootnoteContFrame() && "New Upper not a FootnoteCont");
            SwFootnoteContFrame *pCont = static_cast<SwFootnoteContFrame*>(pNewUpper);
            pTmpFootnote = SwFootnoteContFrame::AppendChained(this, true);
            SwFrame* pNx = pCont->Lower();
            if( pNx && pTmpFootnote->GetAttr()->GetFootnote().IsEndNote() )
                while(pNx && !static_cast<SwFootnoteFrame*>(pNx)->GetAttr()->GetFootnote().IsEndNote())
                    pNx = pNx->GetNext();
            pTmpFootnote->Paste( pCont, pNx );
            pTmpFootnote->Calc(getRootFrame()->GetCurrShell()->GetOut());
        }
        OSL_ENSURE( pTmpFootnote->GetAttr() == FindFootnoteFrame()->GetAttr(), "Wrong Footnote!" );
        // areas inside of footnotes get a special treatment
        SwLayoutFrame *pNewUp = pTmpFootnote;
        if( IsInSct() )
        {
            SwSectionFrame* pSect = FindSctFrame();
            // area inside of a footnote (or only footnote in an area)?
            if( pSect->IsInFootnote() )
            {
                if( pTmpFootnote->Lower() && pTmpFootnote->Lower()->IsSctFrame() &&
                    pSect->GetFollow() == static_cast<SwSectionFrame*>(pTmpFootnote->Lower()) )
                    pNewUp = static_cast<SwSectionFrame*>(pTmpFootnote->Lower());
                else
                {
                    pNewUp = new SwSectionFrame( *pSect, false );
                    pNewUp->InsertBefore( pTmpFootnote, pTmpFootnote->Lower() );
                    static_cast<SwSectionFrame*>(pNewUp)->Init();
 
                    {
                        SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*pNewUp);
                        aFrm.Pos() = pTmpFootnote->getFrameArea().Pos();
                        aFrm.Pos().AdjustY(1 ); // for notifications
                    }
 
                    // If the section frame has a successor then the latter needs
                    // to be moved behind the new Follow of the section frame.
                    SwFrame* pTmp = pSect->GetNext();
                    if( pTmp )
                    {
                        SwFlowFrame* pTmpNxt;
                        if( pTmp->IsContentFrame() )
                            pTmpNxt = static_cast<SwContentFrame*>(pTmp);
                        else if( pTmp->IsSctFrame() )
                            pTmpNxt = static_cast<SwSectionFrame*>(pTmp);
                        else
                        {
                            OSL_ENSURE( pTmp->IsTabFrame(), "GetNextSctLeaf: Wrong Type" );
                            pTmpNxt = static_cast<SwTabFrame*>(pTmp);
                        }
                        // we will dereference pNewUp in the following MoveSubTree call
                        // so it certainly should not be deleted before that
                        SwFrameDeleteGuard aDeleteGuard(pNewUp);
                        pTmpNxt->MoveSubTree( pTmpFootnote, pNewUp->GetNext() );
                    }
                }
            }
        }
 
        MoveSubTree( pNewUp, pNewUp->Lower() );
 
        if( !bSameBoss )
            Prepare( PrepareHint::BossChanged );
    }
    return bSamePage;
}
 
SwSaveFootnoteHeight::SwSaveFootnoteHeight( SwFootnoteBossFrame *pBs, const SwTwips nDeadLine ) :
    aGuard(pBs),
    pBoss( pBs ),
    nOldHeight( pBs->GetMaxFootnoteHeight() )
{
    pBoss->SetFootnoteDeadLine( nDeadLine );
    nNewHeight = pBoss->GetMaxFootnoteHeight();
}
 
SwSaveFootnoteHeight::~SwSaveFootnoteHeight()
{
    // If somebody tweaked the deadline meanwhile, we let it happen
    if ( nNewHeight == pBoss->GetMaxFootnoteHeight() )
        pBoss->m_nMaxFootnoteHeight = nOldHeight;
}
 
#ifdef DBG_UTIL
//JP 15.10.2001: in a non pro version test if the attribute has the same
//              meaning which his reference is
 
// Normally, the pRef member and the GetRefFromAttr() result has to be
// identically. Sometimes footnote will be moved from a master to its follow,
// but the GetRef() is called first, so we have to ignore a master/follow
// mismatch.
 
const SwContentFrame* SwFootnoteFrame::GetRef() const
{
    (void) GetRefFromAttr();
    return mpReference;
}
 
SwContentFrame* SwFootnoteFrame::GetRef()
{
    (void) GetRefFromAttr();
    return mpReference;
}
#endif
 
const SwContentFrame* SwFootnoteFrame::GetRefFromAttr()  const
{
    SwFootnoteFrame* pThis = const_cast<SwFootnoteFrame*>(this);
    return pThis->GetRefFromAttr();
}
 
SwContentFrame* SwFootnoteFrame::GetRefFromAttr()
{
    assert(mpAttribute && "invalid Attribute");
    SwTextNode& rTNd = const_cast<SwTextNode&>(mpAttribute->GetTextNode());
    SwPosition aPos( rTNd, mpAttribute->GetStart() );
    SwContentFrame* pCFrame = rTNd.getLayoutFrame(getRootFrame(), &aPos);
    return pCFrame;
}
 
/** search for last content in the current footnote frame
 
    OD 2005-12-02 #i27138#
*/
SwContentFrame* SwFootnoteFrame::FindLastContent()
{
    SwContentFrame* pLastContentFrame( nullptr );
 
    // find last lower, which is a content frame or contains content.
    // hidden text frames, empty sections and empty tables have to be skipped.
    SwFrame* pLastLowerOfFootnote( GetLower() );
    SwFrame* pTmpLastLower( pLastLowerOfFootnote );
    while ( pTmpLastLower && pTmpLastLower->GetNext() )
    {
        pTmpLastLower = pTmpLastLower->GetNext();
        if (!pTmpLastLower->IsHiddenNow()
            && (!pTmpLastLower->IsLayoutFrame()
                || static_cast<SwLayoutFrame*>(pTmpLastLower)->ContainsContent()))
        {
            pLastLowerOfFootnote = pTmpLastLower;
        }
    }
 
    // determine last content frame depending on type of found last lower.
    if ( pLastLowerOfFootnote && pLastLowerOfFootnote->IsTabFrame() )
    {
        pLastContentFrame = static_cast<SwTabFrame*>(pLastLowerOfFootnote)->FindLastContent();
    }
    else if ( pLastLowerOfFootnote && pLastLowerOfFootnote->IsSctFrame() )
    {
        pLastContentFrame = static_cast<SwSectionFrame*>(pLastLowerOfFootnote)->FindLastContent();
    }
    else
    {
        pLastContentFrame = dynamic_cast<SwContentFrame*>(pLastLowerOfFootnote);
    }
 
    return pLastContentFrame;
}
 
void SwFootnoteFrame::dumpAsXml(xmlTextWriterPtr writer) const
{
    (void)xmlTextWriterStartElement(writer, reinterpret_cast<const xmlChar*>("ftn"));
    dumpAsXmlAttributes(writer);
 
    (void)xmlTextWriterStartElement(writer, BAD_CAST("infos"));
    dumpInfosAsXml(writer);
    (void)xmlTextWriterEndElement(writer);
    dumpChildrenAsXml(writer);
 
    (void)xmlTextWriterEndElement(writer);
}
 
void SwFootnoteFrame::dumpAsXmlAttributes(xmlTextWriterPtr writer) const
{
    SwLayoutFrame::dumpAsXmlAttributes(writer);
 
    (void)xmlTextWriterWriteFormatAttribute( writer, BAD_CAST("ref"), "%" SAL_PRIuUINT32, GetRef()->GetFrameId() );
    if (GetMaster())
        (void)xmlTextWriterWriteFormatAttribute( writer, BAD_CAST("master"), "%" SAL_PRIuUINT32, GetMaster()->GetFrameId() );
    if (GetFollow())
        (void)xmlTextWriterWriteFormatAttribute( writer, BAD_CAST("follow"), "%" SAL_PRIuUINT32, GetFollow()->GetFrameId() );
}
 
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

V654 The condition '!pRet' of loop is always true.

V654 The condition '_pFootnote' of loop is always true.

V547 Expression '!pNxt' is always false.

V1048 The 'pFootnoteArr' variable was assigned the same value.

V1051 Consider checking for misprints. It's possible that the 'nDist' should be checked here.