editeng/qa/editeng/editeng.cxx      |   32 ++++++++++++++++++++++++++++++++
 editeng/source/editeng/impedit4.cxx |   14 +++++++++-----
 2 files changed, 41 insertions(+), 5 deletions(-)

New commits:
commit 4eac1d004898a2063b21a83a7e5785e22c50ba8a
Author:     Miklos Vajna <[email protected]>
AuthorDate: Tue Dec 17 16:02:48 2024 +0100
Commit:     Caolán McNamara <[email protected]>
CommitDate: Tue Dec 17 17:45:51 2024 +0100

    tdf#164359 editeng RTF export: track unused parent styles recursively
    
    Start edit mode for the shape in the document, double-click on a word
    which has a "level 2" bullet associated with it -> crash.
    
    This is a regression from c8b607b7c0096c58dc5187262bf0133dee728d50
    (tdf#163883 editeng RTF export: fix broken offsets into the para style
    table, 2024-11-19), the direct cause is that ImpEditEngine::WriteRTF()
    maps all style pointers to a style ID and once we write the parent
    property in the style table, we unconditionally dereference our search
    result, because we know all styles should be in that map.
    
    The root of the problem seems to be that once parent styles are marked
    as used for the "only write used styles for the clipboard" case, those
    parents themselves can have parents, and we didn't mark those as used.
    Combined with the unconditional dereference, this leads to a crash. Fix
    this by walking up the parent chain till we get no parent.
    
    This assumes that importers create a valid document model, so there
    can't be loops while walking the parent chain. If that would be a
    problem in practice, we could check for that in the future.
    
    Change-Id: I4b416e78f26bf455040d95ee8ed220cfe870e33a
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/178677
    Reviewed-by: Caolán McNamara <[email protected]>
    Tested-by: Jenkins CollaboraOffice <[email protected]>
    Tested-by: Caolán McNamara <[email protected]>

diff --git a/editeng/qa/editeng/editeng.cxx b/editeng/qa/editeng/editeng.cxx
index 5a4ed4d051cc..6c44c557d9b3 100644
--- a/editeng/qa/editeng/editeng.cxx
+++ b/editeng/qa/editeng/editeng.cxx
@@ -128,6 +128,38 @@ CPPUNIT_TEST_FIXTURE(Test, testRTFStyleExportReferToStyle)
     // i.e. \s2 was used to refer to \s1, so the paragraph style was lost.
     CPPUNIT_ASSERT_EQUAL(xReader->m_aStyleValues[0], 
xReader->m_aStyleValues[1]);
 }
+
+CPPUNIT_TEST_FIXTURE(Test, testRTFStyleExportParentRecursive)
+{
+    // Given a document with text that has a paragraph style with a parent 
that itself has a parent:
+    EditEngine aEditEngine(mpItemPool.get());
+    rtl::Reference<SfxStyleSheetPool> xStyles(new 
SfxStyleSheetPool(*mpItemPool));
+    xStyles->Make("mystyle1", SfxStyleFamily::Para);
+    xStyles->Make("mystyle2", SfxStyleFamily::Para);
+    xStyles->Make("mystyle3", SfxStyleFamily::Para);
+    auto pStyle1 = static_cast<SfxStyleSheet*>(xStyles->Find("mystyle1", 
SfxStyleFamily::Para));
+    auto pStyle2 = static_cast<SfxStyleSheet*>(xStyles->Find("mystyle2", 
SfxStyleFamily::Para));
+    pStyle2->SetParent(pStyle1->GetName());
+    auto pStyle3 = static_cast<SfxStyleSheet*>(xStyles->Find("mystyle3", 
SfxStyleFamily::Para));
+    pStyle3->SetParent(pStyle2->GetName());
+    pStyle3->GetItemSet().SetRanges(svl::Items<WEIGHT_BOLD, EE_CHAR_WEIGHT>);
+    SvxWeightItem aItem(WEIGHT_BOLD, EE_CHAR_WEIGHT);
+    pStyle3->GetItemSet().Put(aItem);
+    aEditEngine.SetStyleSheetPool(xStyles.get());
+    OUString aText = u"mytest"_ustr;
+    aEditEngine.SetText(aText);
+    aEditEngine.SetStyleSheet(0, pStyle3);
+
+    // When copying to the clipboard as RTF:
+    // Without the accompanying fix in place, this test would have crashed 
here:
+    uno::Reference<datatransfer::XTransferable> xData
+        = aEditEngine.CreateTransferable(ESelection(0, 0, 0, 
aText.getLength()));
+
+    // Then make sure we produce RTF and not crash:
+    auto pData = dynamic_cast<EditDataObject*>(xData.get());
+    SvMemoryStream& rStream = pData->GetRTFStream();
+    CPPUNIT_ASSERT_GREATER(static_cast<sal_uInt64>(0), 
rStream.remainingSize());
+}
 }
 
 CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/editeng/source/editeng/impedit4.cxx 
b/editeng/source/editeng/impedit4.cxx
index 1a5685256536..17d3c8cd7495 100644
--- a/editeng/source/editeng/impedit4.cxx
+++ b/editeng/source/editeng/impedit4.cxx
@@ -443,15 +443,19 @@ ErrCode ImpEditEngine::WriteRTF( SvStream& rOutput, 
EditSelection aSel, bool bCl
 
                 aUsedParagraphStyles.insert(pParaStyle);
 
-                const OUString& rParent = pParaStyle->GetParent();
-                if (!rParent.isEmpty())
+                // Collect parents of the style recursively.
+                OUString aParent = pParaStyle->GetParent();
+                while (!aParent.isEmpty())
                 {
                     auto pParent = static_cast<SfxStyleSheet*>(
-                        GetStyleSheetPool()->Find(rParent, 
pParaStyle->GetFamily()));
-                    if (pParent)
+                        GetStyleSheetPool()->Find(aParent, 
pParaStyle->GetFamily()));
+                    if (!pParent)
                     {
-                        aUsedParagraphStyles.insert(pParent);
+                        break;
                     }
+
+                    aUsedParagraphStyles.insert(pParent);
+                    aParent = pParent->GetParent();
                 }
 
                 const OUString& rFollow = pParaStyle->GetFollow();

Reply via email to