tdf#119126 forcepoint#76 avoid deleting footnote that would delete ...

... undeletable page

(cherry picked from commit 0005b330eaed0b5559042d2597fb45e0c9125d7e)

Conflicts:
	sw/qa/extras/layout/layout.cxx

Change-Id: I4622569eb9c757c6dcbdda32081ddc94e53db919
Reviewed-on: https://gerrit.libreoffice.org/66393
Tested-by: Xisco Faulí <xiscofauli@libreoffice.org>
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
diff --git a/sw/qa/extras/layout/data/forcepoint76-1.rtf b/sw/qa/extras/layout/data/forcepoint76-1.rtf
new file mode 100644
index 0000000..f3ed2cc
--- /dev/null
+++ b/sw/qa/extras/layout/data/forcepoint76-1.rtf
Binary files differ
diff --git a/sw/qa/extras/layout/layout.cxx b/sw/qa/extras/layout/layout.cxx
index 0e2bc91..7d6eecc 100755
--- a/sw/qa/extras/layout/layout.cxx
+++ b/sw/qa/extras/layout/layout.cxx
@@ -27,6 +27,7 @@ public:
    void testTdf117245();
    void testTdf109077();
    void testTdf109137();
    void testForcepoint76();
    void testTdf118058();
    void testTdf117188();
    void testTdf119875();
@@ -43,6 +44,7 @@ public:
    CPPUNIT_TEST(testTdf117245);
    CPPUNIT_TEST(testTdf109077);
    CPPUNIT_TEST(testTdf109137);
    CPPUNIT_TEST(testForcepoint76);
    CPPUNIT_TEST(testTdf118058);
    CPPUNIT_TEST(testTdf117188);
    CPPUNIT_TEST(testTdf119875);
@@ -236,6 +238,9 @@ void SwLayoutWriter::testTdf109137()
                /*nNumberOfNodes=*/1);
}

//just care it doesn't crash/assert
void SwLayoutWriter::testForcepoint76() { createDoc("forcepoint76-1.rtf"); }

void SwLayoutWriter::testTdf118058()
{
    SwDoc* pDoc = createDoc("tdf118058.fodt");
diff --git a/sw/source/core/inc/frame.hxx b/sw/source/core/inc/frame.hxx
index 4f6375d..ec78d7b 100644
--- a/sw/source/core/inc/frame.hxx
+++ b/sw/source/core/inc/frame.hxx
@@ -852,7 +852,7 @@ public:
    bool IsProtected() const;

    bool IsColLocked()  const { return mbColLocked; }
    bool IsDeleteForbidden()  const { return mbForbidDelete; }
    virtual bool IsDeleteForbidden() const { return mbForbidDelete; }

    /// this is the only way to delete a SwFrame instance
    static void DestroyFrame(SwFrame *const pFrame);
diff --git a/sw/source/core/inc/ftnfrm.hxx b/sw/source/core/inc/ftnfrm.hxx
index 7f964d6..57ee6be 100644
--- a/sw/source/core/inc/ftnfrm.hxx
+++ b/sw/source/core/inc/ftnfrm.hxx
@@ -70,6 +70,7 @@ class SwFootnoteFrame: public SwLayoutFrame
public:
    SwFootnoteFrame( SwFrameFormat*, SwFrame*, SwContentFrame*, SwTextFootnote* );

    virtual bool IsDeleteForbidden() const override;
    virtual void Cut() override;
    virtual void Paste( SwFrame* pParent, SwFrame* pSibling = nullptr ) override;

diff --git a/sw/source/core/layout/calcmove.cxx b/sw/source/core/layout/calcmove.cxx
index 2b56272..04acfca 100644
--- a/sw/source/core/layout/calcmove.cxx
+++ b/sw/source/core/layout/calcmove.cxx
@@ -242,6 +242,7 @@ void SwFrame::PrepareMake(vcl::RenderContext* pRenderContext)
    StackHack aHack;
    if ( GetUpper() )
    {
        SwFrameDeleteGuard aDeleteGuard(this);
        if ( lcl_IsCalcUpperAllowed( *this ) )
            GetUpper()->Calc(pRenderContext);
        OSL_ENSURE( GetUpper(), ":-( Layout unstable (Upper gone)." );
diff --git a/sw/source/core/layout/ftnfrm.cxx b/sw/source/core/layout/ftnfrm.cxx
index e34c260..7fd3bcb 100644
--- a/sw/source/core/layout/ftnfrm.cxx
+++ b/sw/source/core/layout/ftnfrm.cxx
@@ -473,6 +473,27 @@ void SwFootnoteFrame::InvalidateNxtFootnoteCnts( SwPageFrame const *pPage )
    }
}

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() )
@@ -498,7 +519,7 @@ void SwFootnoteFrame::Cut()
    if ( pUp )
    {
        // The last footnote takes its container along
        if ( !pUp->Lower() )
        if (!pUp->Lower())
        {
            SwPageFrame *pPage = pUp->FindPageFrame();
            if ( pPage )
@@ -1589,7 +1610,8 @@ void SwFootnoteBossFrame::AppendFootnote( SwContentFrame *pRef, SwTextFootnote *
            pNew->Calc(getRootFrame()->GetCurrShell()->GetOut());
            // #i57914# - adjust fix #i49383#
            if ( !bOldFootnoteFrameLocked && !pNew->GetLower() &&
                 !pNew->IsColLocked() && !pNew->IsBackMoveLocked() )
                 !pNew->IsColLocked() && !pNew->IsBackMoveLocked() &&
                 !pNew->IsDeleteForbidden() )
            {
                pNew->Cut();
                SwFrame::DestroyFrame(pNew);
@@ -2194,7 +2216,8 @@ void SwFootnoteBossFrame::RearrangeFootnotes( const SwTwips nDeadLine, const boo
                        if ( !bLock && bUnlockLastFootnoteFrame &&
                             !pLastFootnoteFrame->GetLower() &&
                             !pLastFootnoteFrame->IsColLocked() &&
                             !pLastFootnoteFrame->IsBackMoveLocked() )
                             !pLastFootnoteFrame->IsBackMoveLocked() &&
                             !pLastFootnoteFrame->IsDeleteForbidden() )
                        {
                            pLastFootnoteFrame->Cut();
                            SwFrame::DestroyFrame(pLastFootnoteFrame);
diff --git a/sw/source/core/layout/tabfrm.cxx b/sw/source/core/layout/tabfrm.cxx
index ae20788..8e3d9b1 100644
--- a/sw/source/core/layout/tabfrm.cxx
+++ b/sw/source/core/layout/tabfrm.cxx
@@ -852,6 +852,11 @@ bool SwTabFrame::RemoveFollowFlowLine()
    // #140081# Make code robust.
    if ( !pFollowFlowLine || !pLastLine )
        return true;
    if (pFollowFlowLine->IsDeleteForbidden())
    {
        SAL_WARN("sw.layout", "Cannot remove in-use Follow Flow Line");
        return true;
    }

    // Move content
    lcl_MoveRowContent( *pFollowFlowLine, *static_cast<SwRowFrame*>(pLastLine) );