sw: fix issue with copying stashed frame format
When the PageDesc is copied from one document to another, we
don't make sure the stashed FrameFormat(s) are also properly
copied to the new document (which can happen at copy/paste). This
can cause a crash if the stashed FrameFormats are accessed or
destructed after the original document is destroyed.
This fixes the issue so that when we detect the PageDesc belong
to different documents, the stashed FrameFormats are copied just
like the non-stashed FrameFormats (used for headers and footers).
Change-Id: I948068dba4d39bb47c3725dfa8491c53c5833c7e
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/160065
Tested-by: Jenkins
Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
diff --git a/sw/inc/pagedesc.hxx b/sw/inc/pagedesc.hxx
index 382bbb5..11bb347 100644
--- a/sw/inc/pagedesc.hxx
+++ b/sw/inc/pagedesc.hxx
@@ -223,7 +223,7 @@ public:
const SwFrameFormat* GetStashedFrameFormat(bool bHeader, bool bLeft, bool bFirst) const;
/// Checks if the pagedescriptor has a stashed format according to the parameters or not.
bool HasStashedFormat(bool bHeader, bool bLeft, bool bFirst);
bool HasStashedFormat(bool bHeader, bool bLeft, bool bFirst) const;
/// Gives the feature of removing the stashed format by hand if it is necessary.
void RemoveStashedFormat(bool bHeader, bool bLeft, bool bFirst);
diff --git a/sw/qa/core/header_footer/HeaderFooterTest.cxx b/sw/qa/core/header_footer/HeaderFooterTest.cxx
index 8b78363..b411632 100644
--- a/sw/qa/core/header_footer/HeaderFooterTest.cxx
+++ b/sw/qa/core/header_footer/HeaderFooterTest.cxx
@@ -48,6 +48,46 @@ public:
}
};
CPPUNIT_TEST_FIXTURE(HeaderFooterTest, testStashedHeaderFooter)
{
createSwDoc();
SwDoc* pSourceDocument = getSwDoc();
uno::Reference<lang::XComponent> xSourceDocument = mxComponent;
mxComponent.clear();
createSwDoc();
SwDoc* pTargetDocument = getSwDoc();
uno::Reference<lang::XComponent> xTargetDocument = mxComponent;
mxComponent.clear();
// Source
SwPageDesc* pSourcePageDesc = pSourceDocument->MakePageDesc("SourceStyle");
pSourcePageDesc->ChgFirstShare(false);
CPPUNIT_ASSERT(!pSourcePageDesc->IsFirstShared());
pSourcePageDesc->StashFrameFormat(pSourcePageDesc->GetFirstMaster(), true, false, true);
pSourceDocument->ChgPageDesc("SourceStyle", *pSourcePageDesc);
CPPUNIT_ASSERT(pSourcePageDesc->HasStashedFormat(true, false, true));
// Target
SwPageDesc* pTargetPageDesc = pTargetDocument->MakePageDesc("TargetStyle");
// Copy source to target
pTargetDocument->CopyPageDesc(*pSourcePageDesc, *pTargetPageDesc);
// Check the stashed frame format is copied
CPPUNIT_ASSERT(pTargetPageDesc->HasStashedFormat(true, false, true));
// Check document instance
auto pSourceStashedFormat = pSourcePageDesc->GetStashedFrameFormat(true, false, true);
CPPUNIT_ASSERT_EQUAL(true, pSourceStashedFormat->GetDoc() == pSourceDocument);
auto pTargetStashedFormat = pTargetPageDesc->GetStashedFrameFormat(true, false, true);
CPPUNIT_ASSERT_EQUAL(true, pTargetStashedFormat->GetDoc() == pTargetDocument);
xSourceDocument->dispose();
xTargetDocument->dispose();
}
CPPUNIT_TEST_FIXTURE(HeaderFooterTest, testNonFirstHeaderIsDisabled)
{
// related to tdf#127778
diff --git a/sw/source/core/doc/docfmt.cxx b/sw/source/core/doc/docfmt.cxx
index d5854b3..57c42c5 100644
--- a/sw/source/core/doc/docfmt.cxx
+++ b/sw/source/core/doc/docfmt.cxx
@@ -1540,14 +1540,43 @@ void SwDoc::CopyPageDesc( const SwPageDesc& rSrcDesc, SwPageDesc& rDstDesc,
// Copy the stashed formats as well between the page descriptors...
for (bool bFirst : { true, false })
{
for (bool bLeft : { true, false })
{
for (bool bHeader : { true, false })
{
if (!bLeft && !bFirst)
continue;
if (auto pStashedFormat = rSrcDesc.GetStashedFrameFormat(bHeader, bLeft, bFirst))
rDstDesc.StashFrameFormat(*pStashedFormat, bHeader, bLeft, bFirst);
// Copy format only if it exists
if (auto pStashedFormatSrc = rSrcDesc.GetStashedFrameFormat(bHeader, bLeft, bFirst))
{
if (pStashedFormatSrc->GetDoc() != this)
{
SwFrameFormat* pNewFormat = new SwFrameFormat(GetAttrPool(), "CopyDesc", GetDfltFrameFormat());
SfxItemSet aAttrSet(pStashedFormatSrc->GetAttrSet());
aAttrSet.ClearItem(RES_HEADER);
aAttrSet.ClearItem(RES_FOOTER);
pNewFormat->DelDiffs( aAttrSet );
pNewFormat->SetFormatAttr( aAttrSet );
if (bHeader)
CopyHeader(*pStashedFormatSrc, *pNewFormat);
else
CopyFooter(*pStashedFormatSrc, *pNewFormat);
rDstDesc.StashFrameFormat(*pNewFormat, bHeader, bLeft, bFirst);
}
else
{
rDstDesc.StashFrameFormat(*pStashedFormatSrc, bHeader, bLeft, bFirst);
}
}
}
}
}
}
void SwDoc::ReplaceStyles( const SwDoc& rSource, bool bIncludePageStyles )
diff --git a/sw/source/core/layout/pagedesc.cxx b/sw/source/core/layout/pagedesc.cxx
index edfee20..2b78823 100644
--- a/sw/source/core/layout/pagedesc.cxx
+++ b/sw/source/core/layout/pagedesc.cxx
@@ -477,7 +477,7 @@ const SwFrameFormat* SwPageDesc::GetStashedFrameFormat(bool bHeader, bool bLeft,
}
}
bool SwPageDesc::HasStashedFormat(bool bHeader, bool bLeft, bool bFirst)
bool SwPageDesc::HasStashedFormat(bool bHeader, bool bLeft, bool bFirst) const
{
if (bHeader)
{