editeng/qa/editeng/editeng.cxx      |   38 ++++++++++++++++++++++++++++++++++--
 editeng/source/editeng/impedit4.cxx |   27 +++++++++++++++----------
 2 files changed, 52 insertions(+), 13 deletions(-)

New commits:
commit 2a611e42dda356d53d399424cd4e92543fe08034
Author:     Miklos Vajna <[email protected]>
AuthorDate: Tue Nov 19 08:20:26 2024 +0100
Commit:     Caolán McNamara <[email protected]>
CommitDate: Tue Nov 19 16:26:21 2024 +0100

    tdf#163883 editeng RTF export: fix broken offsets into the para style table
    
    Regression from commit 70d1bd6ee0eba9d6661cd6280566f77a87f2d068
    (tdf#161652 editeng, RTF copy: only write used paragraph styles,
    2024-06-20), type a few characters into the title placeholder shape in
    Impress, switch to the Outline view, select all, copy, paste into
    Writer: the resulting text nodes won't have paragraph styles, just
    direct formatting.
    
    Inspecting the produced RTF, the problem is that the styles table
    started to omit unused styles, but the style -> offset mapping table
    still included them, so the offset didn't match, which results in losing
    the style on RTF import.
    
    Fix the problem by building the mapping table later also also ignoring
    unused paragraph styles there, to restore consistency between declaring
    style entries and referring to them.
    
    Change-Id: I9156a881543cc710eb12990f110ceefc77a1858b
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/176767
    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 5c1f23e7e389..5a4ed4d051cc 100644
--- a/editeng/qa/editeng/editeng.cxx
+++ b/editeng/qa/editeng/editeng.cxx
@@ -9,12 +9,11 @@
 
 #include <test/bootstrapfixture.hxx>
 
-#include <memory>
-
 #include <editeng/editeng.hxx>
 #include <sfx2/app.hxx>
 #include <svtools/parrtf.hxx>
 #include <svtools/rtftoken.h>
+#include <editeng/wghtitem.hxx>
 
 #include <editdoc.hxx>
 #include <eeobj.hxx>
@@ -54,6 +53,7 @@ public:
     void NextToken(int nToken) override;
 
     int m_nStyles = 0;
+    std::vector<int> m_aStyleValues;
 };
 
 StyleCounter::StyleCounter(SvStream& rStream)
@@ -66,6 +66,7 @@ void StyleCounter::NextToken(int nToken)
     if (nToken == RTF_S)
     {
         ++m_nStyles;
+        m_aStyleValues.push_back(nTokenValue);
     }
 }
 
@@ -94,6 +95,39 @@ CPPUNIT_TEST_FIXTURE(Test, testRTFStyleExport)
     // i.e. unreferenced paragraph styles were exported.
     CPPUNIT_ASSERT_EQUAL(0, xReader->m_nStyles);
 }
+
+CPPUNIT_TEST_FIXTURE(Test, testRTFStyleExportReferToStyle)
+{
+    // Given a document with one unused and one used style:
+    EditEngine aEditEngine(mpItemPool.get());
+    rtl::Reference<SfxStyleSheetPool> xStyles(new 
SfxStyleSheetPool(*mpItemPool));
+    xStyles->Make("mystyle", SfxStyleFamily::Para);
+    xStyles->Make("mystyle2", SfxStyleFamily::Para);
+    auto pStyle = static_cast<SfxStyleSheet*>(xStyles->Find("mystyle2", 
SfxStyleFamily::Para));
+    pStyle->GetItemSet().SetRanges(svl::Items<WEIGHT_BOLD, EE_CHAR_WEIGHT>);
+    SvxWeightItem aItem(WEIGHT_BOLD, EE_CHAR_WEIGHT);
+    pStyle->GetItemSet().Put(aItem);
+    aEditEngine.SetStyleSheetPool(xStyles.get());
+    OUString aText = u"mytest"_ustr;
+    aEditEngine.SetText(aText);
+    aEditEngine.SetStyleSheet(0, pStyle);
+
+    // When copying a word from that document:
+    uno::Reference<datatransfer::XTransferable> xData
+        = aEditEngine.CreateTransferable(ESelection(0, 0, 0, 
aText.getLength()));
+
+    // Then make sure the declared and referred style indexes for the used 
style match:
+    auto pData = dynamic_cast<EditDataObject*>(xData.get());
+    SvMemoryStream& rStream = pData->GetRTFStream();
+    tools::SvRef<StyleCounter> xReader(new StyleCounter(rStream));
+    CPPUNIT_ASSERT(xReader->CallParser() != SvParserState::Error);
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), 
xReader->m_aStyleValues.size());
+    // Without the accompanying fix in place, this test would have failed with:
+    // - Expected: 1
+    // - Actual  : 2
+    // 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_PLUGIN_IMPLEMENT();
diff --git a/editeng/source/editeng/impedit4.cxx 
b/editeng/source/editeng/impedit4.cxx
index 716a8b223c5f..1a5685256536 100644
--- a/editeng/source/editeng/impedit4.cxx
+++ b/editeng/source/editeng/impedit4.cxx
@@ -423,17 +423,6 @@ ErrCode ImpEditEngine::WriteRTF( SvStream& rOutput, 
EditSelection aSel, bool bCl
     // StyleSheets...
     if ( GetStyleSheetPool() )
     {
-        std::shared_ptr<SfxStyleSheetIterator> aSSSIterator = 
std::make_shared<SfxStyleSheetIterator>(GetStyleSheetPool(),
-                SfxStyleFamily::All);
-        // fill aStyleSheetToIdMap
-        sal_uInt32 nId = 1;
-        for ( SfxStyleSheetBase* pStyle = aSSSIterator->First(); pStyle;
-                                 pStyle = aSSSIterator->Next() )
-        {
-            aStyleSheetToIdMap[pStyle] = nId;
-            nId++;
-        }
-
         // Collect used paragraph styles when copying to the clipboard.
         std::set<SfxStyleSheetBase*> aUsedParagraphStyles;
         if (bClipboard)
@@ -478,6 +467,22 @@ ErrCode ImpEditEngine::WriteRTF( SvStream& rOutput, 
EditSelection aSel, bool bCl
             }
         }
 
+        std::shared_ptr<SfxStyleSheetIterator> aSSSIterator = 
std::make_shared<SfxStyleSheetIterator>(GetStyleSheetPool(),
+                SfxStyleFamily::All);
+        // fill aStyleSheetToIdMap
+        sal_uInt32 nId = 1;
+        for ( SfxStyleSheetBase* pStyle = aSSSIterator->First(); pStyle;
+                                 pStyle = aSSSIterator->Next() )
+        {
+            if (bClipboard && !aUsedParagraphStyles.contains(pStyle))
+            {
+                // Don't include unused paragraph styles in the clipboard case.
+                continue;
+            }
+            aStyleSheetToIdMap[pStyle] = nId;
+            nId++;
+        }
+
         if ( aSSSIterator->Count() )
         {
 

Reply via email to