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 af20a7544531d074cd3e555540f736e9c1e6a4e0
Author:     Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk>
AuthorDate: Thu Nov 30 16:42:26 2023 +0900
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Mon Dec 4 09:00:16 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>
    (cherry picked from commit 963de9feb37105560fde14b44d992e47f341bb5b)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/160192
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>
    Reviewed-by: Miklos Vajna <vmik...@collabora.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 1f1dd5c2db70..23e91a2db4b1 100644
--- a/sw/qa/core/header_footer/HeaderFooterTest.cxx
+++ b/sw/qa/core/header_footer/HeaderFooterTest.cxx
@@ -49,6 +49,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 9e8df615959a..97fddbdbc87d 100644
--- a/sw/source/core/doc/docfmt.cxx
+++ b/sw/source/core/doc/docfmt.cxx
@@ -1542,14 +1542,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 d93b47517e5b..40a7b5865766 100644
--- a/sw/source/core/layout/pagedesc.cxx
+++ b/sw/source/core/layout/pagedesc.cxx
@@ -470,7 +470,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)
     {

Reply via email to