tdf#154863 Add unit test to cover crash on image move

This reverts commit 332faa63407305852f5044e4bbc41302ccfe46cd.

This change adds a CppUnit test that changes the position
of an image in an example document which causes a crash
if the bug exists.

Also, keep a reference to the validity of the SwTextFrame
so that the objects that use it know whether they should
use it or not if it's been destructed already.

Change-Id: I5cfec75681a5877c007df33c23d9a5e61e4292c8
diff --git a/sw/qa/core/objectpositioning/data/tdf154863-img-move-crash.docx b/sw/qa/core/objectpositioning/data/tdf154863-img-move-crash.docx
new file mode 100644
index 0000000..ca402ed
--- /dev/null
+++ b/sw/qa/core/objectpositioning/data/tdf154863-img-move-crash.docx
Binary files differ
diff --git a/sw/qa/core/objectpositioning/objectpositioning.cxx b/sw/qa/core/objectpositioning/objectpositioning.cxx
index bf560cb..717d63d 100644
--- a/sw/qa/core/objectpositioning/objectpositioning.cxx
+++ b/sw/qa/core/objectpositioning/objectpositioning.cxx
@@ -25,6 +25,8 @@
#include <flyfrm.hxx>
#include <frmatr.hxx>

#include <vcl/scheduler.hxx>

namespace
{
/// Covers sw/source/core/objectpositioning/ fixes.
@@ -56,6 +58,18 @@ CPPUNIT_TEST_FIXTURE(Test, testOverlapCrash)
    pWrtShell->SplitNode();
}

CPPUNIT_TEST_FIXTURE(Test, testImgMoveCrash)
{
    createSwDoc("tdf154863-img-move-crash.docx");
    uno::Reference<drawing::XShape> xShape(getShapeByName(u"Image26"), uno::UNO_QUERY);
    uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY);
    xShapeProps->setPropertyValue("VertOrient", uno::Any(static_cast<sal_Int32>(0)));
    xShapeProps->setPropertyValue("VertOrientPosition", uno::Any(static_cast<sal_Int32>(3000)));
    Scheduler::ProcessEventsToIdle();
    // Crash expected before assert if bug exists
    CPPUNIT_ASSERT(true);
}

CPPUNIT_TEST_FIXTURE(Test, testVertPosFromBottom)
{
    // Create a document, insert a shape and position it 1cm above the bottom of the body area.
diff --git a/sw/source/core/inc/objectformatter.hxx b/sw/source/core/inc/objectformatter.hxx
index f85c12d..8d48402 100644
--- a/sw/source/core/inc/objectformatter.hxx
+++ b/sw/source/core/inc/objectformatter.hxx
@@ -73,6 +73,7 @@ class SwObjectFormatter
        void FormatObjContent( SwAnchoredObject& _rAnchoredObj );

    protected:
        virtual bool getIsValidFrame() { return true; }
        SwObjectFormatter( const SwPageFrame& _rPageFrame,
                           SwLayAction* _pLayAction,
                           const bool _bCollectPgNumOfAnchors = false );
diff --git a/sw/source/core/inc/txtfrm.hxx b/sw/source/core/inc/txtfrm.hxx
index a906571..df1a757 100644
--- a/sw/source/core/inc/txtfrm.hxx
+++ b/sw/source/core/inc/txtfrm.hxx
@@ -56,6 +56,17 @@ class SwFlyAtContentFrame;

#define NON_PRINTING_CHARACTER_COLOR Color(0x26, 0x8b, 0xd2)

class ValidFrame : public salhelper::SimpleReferenceObject
{
public:
    bool mbIsValid;
    ValidFrame()
        : mbIsValid(false)
    {

    }
};

/// a clone of SwInterHyphInfo, but with TextFrameIndex instead of node index
class SwInterHyphInfoTextFrame
{
@@ -340,8 +351,10 @@ class SW_DLLPUBLIC SwTextFrame final : public SwContentFrame
    /// Like GetDrawObjs(), but limit to fly frames which are allowed to split.
    std::vector<SwFlyAtContentFrame*> GetSplitFlyDrawObjs() const;

public:
    rtl::Reference<ValidFrame> mrIsValid;

public:
    void setFrameValidPtr(rtl::Reference<ValidFrame> rValid) { mrIsValid = rValid; }
    virtual const SvxFormatBreakItem& GetBreakItem() const override;
    virtual const SwFormatPageDesc& GetPageDescItem() const override;

diff --git a/sw/source/core/layout/objectformatter.cxx b/sw/source/core/layout/objectformatter.cxx
index 547aa3c..9c7f02e 100644
--- a/sw/source/core/layout/objectformatter.cxx
+++ b/sw/source/core/layout/objectformatter.cxx
@@ -352,6 +352,10 @@ void SwObjectFormatter::FormatObj_( SwAnchoredObject& _rAnchoredObj )
*/
bool SwObjectFormatter::FormatObjsAtFrame_( SwTextFrame* _pMasterTextFrame )
{
    if (!getIsValidFrame())
        return true;
    if (GetAnchorFrame().IsInDtor())
        return true;
    // --> #i26945#
    SwFrame* pAnchorFrame( nullptr );
    if ( GetAnchorFrame().IsTextFrame() &&
diff --git a/sw/source/core/layout/objectformattertxtfrm.cxx b/sw/source/core/layout/objectformattertxtfrm.cxx
index 1b71301..d2e3cec 100644
--- a/sw/source/core/layout/objectformattertxtfrm.cxx
+++ b/sw/source/core/layout/objectformattertxtfrm.cxx
@@ -71,6 +71,18 @@ SwObjectFormatterTextFrame::SwObjectFormatterTextFrame( SwTextFrame& _rAnchorTex
      mrAnchorTextFrame( _rAnchorTextFrame ),
      mpMasterAnchorTextFrame( _pMasterAnchorTextFrame )
{
    mrIsTextFrameValid = new ValidFrame();
    if (!mrIsTextFrameValid)
        return;
    mrIsTextFrameValid->mbIsValid = true;
    mrAnchorTextFrame.setFrameValidPtr(mrIsTextFrameValid);
}

bool SwObjectFormatterTextFrame::getIsValidFrame()
{
    if (mrIsTextFrameValid)
        return mrIsTextFrameValid->mbIsValid;
    return false;
}

SwObjectFormatterTextFrame::~SwObjectFormatterTextFrame()
diff --git a/sw/source/core/layout/objectformattertxtfrm.hxx b/sw/source/core/layout/objectformattertxtfrm.hxx
index 25a7a7e..a88ebaf 100644
--- a/sw/source/core/layout/objectformattertxtfrm.hxx
+++ b/sw/source/core/layout/objectformattertxtfrm.hxx
@@ -21,6 +21,7 @@

#include <objectformatter.hxx>
#include <sal/types.h>
#include <txtfrm.hxx>

class SwTextFrame;

@@ -30,6 +31,7 @@ class SwTextFrame;
class SwObjectFormatterTextFrame : public SwObjectFormatter
{
    private:
    rtl::Reference < ValidFrame> mrIsTextFrameValid;
        // anchor text frame
        SwTextFrame& mrAnchorTextFrame;

@@ -112,6 +114,8 @@ class SwObjectFormatterTextFrame : public SwObjectFormatter

    protected:

        virtual bool getIsValidFrame() override;

        virtual SwFrame& GetAnchorFrame() override;

    public:
diff --git a/sw/source/core/text/txtfrm.cxx b/sw/source/core/text/txtfrm.cxx
index c3b4f76..7f1e9d2 100644
--- a/sw/source/core/text/txtfrm.cxx
+++ b/sw/source/core/text/txtfrm.cxx
@@ -786,6 +786,7 @@ SwTextFrame::SwTextFrame(SwTextNode * const pNode, SwFrame* pSib,
    , mbHasAnimation( false )
    , mbIsSwapped( false )
    , mbFollowFormatAllowed( true )
    , mrIsValid(rtl::Reference<ValidFrame>())
{
    mnFrameType = SwFrameType::Txt;
    // note: this may call SwClientNotify if it's in a list so do it last
@@ -1009,6 +1010,8 @@ void SwTextFrame::DestroyImpl()

SwTextFrame::~SwTextFrame()
{
    if (mrIsValid)
        mrIsValid->mbIsValid = false;
    RemoveFromCache();
}