sw/inc/pagedesc.hxx | 2 - sw/qa/core/header_footer/HeaderFooterTest.cxx | 40 ++++++++++++++++++++++++++ sw/source/core/doc/docfmt.cxx | 33 ++++++++++++++++++++- sw/source/core/layout/pagedesc.cxx | 2 - 4 files changed, 73 insertions(+), 4 deletions(-)
New commits: commit 963de9feb37105560fde14b44d992e47f341bb5b Author: Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk> AuthorDate: Thu Nov 30 16:42:26 2023 +0900 Commit: Tomaž Vajngerl <qui...@gmail.com> CommitDate: Fri Dec 1 05:07:42 2023 +0100 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 <qui...@gmail.com> diff --git a/sw/inc/pagedesc.hxx b/sw/inc/pagedesc.hxx index 382bbb5f00cd..11bb347aa1fb 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 8b78363a0c1b..b411632884e1 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 d5854b3633e6..57c42c529eb1 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 edfee20aaef6..2b7882332789 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) {