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();
}