sw/qa/extras/rtfimport/data/tdf116269.rtf       |   22 +++++++++
 sw/qa/extras/rtfimport/rtfimport.cxx            |    8 +++
 writerfilter/source/rtftok/rtfdispatchvalue.cxx |    4 +
 writerfilter/source/rtftok/rtfdocumentimpl.cxx  |   30 ++++++++++++
 writerfilter/source/rtftok/rtfdocumentimpl.hxx  |   13 +++++
 writerfilter/source/rtftok/rtfsprm.cxx          |   57 ++++++++++++++++++++++++
 writerfilter/source/rtftok/rtfsprm.hxx          |    2 
 7 files changed, 134 insertions(+), 2 deletions(-)

New commits:
commit 01d7bbdc13594965aad55269c1283716974ae743
Author: Miklos Vajna <vmik...@collabora.co.uk>
Date:   Mon Mar 19 21:38:43 2018 +0100

    tdf#116269 RTF import: implement reverse deduplication for lists
    
    This is the same mechanism that was added in commit
    1be0a3fa9ebb22b607c54b47739d4467acfed259 (n#825305: writerfilter RTF
    import: override style properties like Word, 2014-06-17), except that
    here the reference is a list definition, not a paragraph style.
    
    Also, this commit only implements the part that inserts explicit
    defaults for not repeated properties, not the actual deduplication, as
    that already works at a dmapper level.
    
    (Saving the bugdoc as DOCX, it's visible in document.xml that DOCX marks
    these defaults explicitly:
    
    <w:ind w:left="0" w:right="-6" w:firstLine="0"/>
    
    but RTF does not, so the right place to fix this is in the tokenizer.)
    
    (cherry picked from commit 0f0a80123d970ef6f3f8269619813e5277fff4df)
    
    Change-Id: Iec88d9bf1032d1d89194bd272500d6780c3c2224
    Reviewed-on: https://gerrit.libreoffice.org/51690
    Tested-by: Jenkins <c...@libreoffice.org>
    Reviewed-by: Caolán McNamara <caol...@redhat.com>
    Tested-by: Caolán McNamara <caol...@redhat.com>

diff --git a/sw/qa/extras/rtfimport/data/tdf116269.rtf 
b/sw/qa/extras/rtfimport/data/tdf116269.rtf
new file mode 100644
index 000000000000..39504c1ae9d5
--- /dev/null
+++ b/sw/qa/extras/rtfimport/data/tdf116269.rtf
@@ -0,0 +1,22 @@
+{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf360
+{\*\listtable
+{\list\listtemplateid1\listhybrid
+{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0
+{\*\levelmarker \{decimal\}.}
+{\leveltext\leveltemplateid1\'02\'00.;}
+{\levelnumbers\'01;}
+\fi-360\li720\lin720 }
+{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0
+{\*\levelmarker \{decimal\}.}
+{\leveltext\leveltemplateid2\'02\'01.;}
+{\levelnumbers\'01;}
+\fi-360\li1440\lin1440 }
+{\listname ;}
+\listid42}
+}
+{\*\listoverridetable
+{\listoverride\listid42\listoverridecount0\ls1}
+}
+\paperw11900\paperh16840\margl1417\margr1417\margb1701\margt1984
+\pard\ri-6\ls1\ilvl1 Gaming proposal
+}
diff --git a/sw/qa/extras/rtfimport/rtfimport.cxx 
b/sw/qa/extras/rtfimport/rtfimport.cxx
index 233cf1d5dc3b..254e203398e3 100644
--- a/sw/qa/extras/rtfimport/rtfimport.cxx
+++ b/sw/qa/extras/rtfimport/rtfimport.cxx
@@ -662,6 +662,14 @@ DECLARE_RTFIMPORT_TEST(testFdo81033, "fdo81033.rtf")
     CPPUNIT_ASSERT_EQUAL(u'_', tabs[1].FillChar);
 }
 
+DECLARE_RTFIMPORT_TEST(testTdf116269, "tdf116269.rtf")
+{
+    // This was 2540, implicit 0 left margin was ignored on import (inherited
+    // value from list definition is repeated if it's not 0).
+    CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0),
+                         getProperty<sal_Int32>(getParagraph(1), 
"ParaLeftMargin"));
+}
+
 DECLARE_RTFIMPORT_TEST(testFdo66565, "fdo66565.rtf")
 {
     uno::Reference<text::XTextTablesSupplier> xTextTablesSupplier(mxComponent, 
uno::UNO_QUERY);
diff --git a/writerfilter/source/rtftok/rtfdispatchvalue.cxx 
b/writerfilter/source/rtftok/rtfdispatchvalue.cxx
index 7079962c69d1..489875e3e78c 100644
--- a/writerfilter/source/rtftok/rtfdispatchvalue.cxx
+++ b/writerfilter/source/rtftok/rtfdispatchvalue.cxx
@@ -663,12 +663,16 @@ RTFError RTFDocumentImpl::dispatchValue(RTFKeyword 
nKeyword, int nParam)
                                                      pIntValue);
             else if (m_aStates.top().eDestination == 
Destination::LISTOVERRIDEENTRY)
                 
m_aStates.top().aTableSprms.set(NS_ooxml::LN_CT_Num_abstractNumId, pIntValue);
+            m_aStates.top().nCurrentListIndex = nParam;
         }
         break;
         case RTF_LS:
         {
             if (m_aStates.top().eDestination == Destination::LISTOVERRIDEENTRY)
+            {
                 
m_aStates.top().aTableAttributes.set(NS_ooxml::LN_CT_AbstractNum_nsid, 
pIntValue);
+                m_aStates.top().nCurrentListOverrideIndex = nParam;
+            }
             else
             {
                 // Insert at the start, so properties inherited from the list
diff --git a/writerfilter/source/rtftok/rtfdocumentimpl.cxx 
b/writerfilter/source/rtftok/rtfdocumentimpl.cxx
index 0a5d3993ff43..b3bc922dd437 100644
--- a/writerfilter/source/rtftok/rtfdocumentimpl.cxx
+++ b/writerfilter/source/rtftok/rtfdocumentimpl.cxx
@@ -125,6 +125,15 @@ RTFValue::Pointer_t getNestedAttribute(RTFSprms& rSprms, 
Id nParent, Id nId)
     return rAttributes.find(nId);
 }
 
+RTFValue::Pointer_t getNestedSprm(RTFSprms& rSprms, Id nParent, Id nId)
+{
+    RTFValue::Pointer_t pParent = rSprms.find(nParent);
+    if (!pParent)
+        return RTFValue::Pointer_t();
+    RTFSprms& rInner = pParent->getSprms();
+    return rInner.find(nId);
+}
+
 bool eraseNestedAttribute(RTFSprms& rSprms, Id nParent, Id nId)
 {
     RTFValue::Pointer_t pParent = rSprms.find(nParent);
@@ -479,8 +488,24 @@ RTFDocumentImpl::getProperties(RTFSprms& rAttributes, 
RTFSprms& rSprms, Id nStyl
         RTFSprms const 
attributes(rAttributes.cloneAndDeduplicate(aStyleAttributes));
         return std::make_shared<RTFReferenceProperties>(attributes, sprms);
     }
+
+    RTFSprms aSprms(rSprms);
+    RTFValue::Pointer_t pNumId
+        = getNestedSprm(aSprms, NS_ooxml::LN_CT_PPrBase_numPr, 
NS_ooxml::LN_CT_NumPr_numId);
+    if (pNumId)
+    {
+        // We have a numbering, see if defaults has to be inserted for not
+        // repeated direct formatting.
+        auto itNumId = m_aListOverrideTable.find(pNumId->getInt());
+        if (itNumId != m_aListOverrideTable.end())
+        {
+            auto itAbstract = m_aListTable.find(itNumId->second);
+            if (itAbstract != m_aListTable.end())
+                aSprms.duplicateList(itAbstract->second);
+        }
+    }
     writerfilter::Reference<Properties>::Pointer_t pRet
-        = std::make_shared<RTFReferenceProperties>(rAttributes, rSprms);
+        = std::make_shared<RTFReferenceProperties>(rAttributes, aSprms);
     return pRet;
 }
 
@@ -3015,6 +3040,7 @@ RTFError RTFDocumentImpl::popState()
             auto pValue = std::make_shared<RTFValue>(aState.aTableAttributes, 
aState.aTableSprms);
             m_aListTableSprms.set(NS_ooxml::LN_CT_Numbering_abstractNum, 
pValue,
                                   RTFOverwrite::NO_APPEND);
+            m_aListTable[aState.nCurrentListIndex] = pValue;
         }
         break;
         case Destination::PARAGRAPHNUMBERING:
@@ -3165,6 +3191,8 @@ RTFError RTFDocumentImpl::popState()
                         = std::make_shared<RTFValue>(aState.aTableAttributes, 
aState.aTableSprms);
                     m_aListTableSprms.set(NS_ooxml::LN_CT_Numbering_num, 
pValue,
                                           RTFOverwrite::NO_APPEND);
+                    m_aListOverrideTable[aState.nCurrentListOverrideIndex]
+                        = aState.nCurrentListIndex;
                 }
             }
             break;
diff --git a/writerfilter/source/rtftok/rtfdocumentimpl.hxx 
b/writerfilter/source/rtftok/rtfdocumentimpl.hxx
index d17fbf7844b7..6d215a6653c7 100644
--- a/writerfilter/source/rtftok/rtfdocumentimpl.hxx
+++ b/writerfilter/source/rtftok/rtfdocumentimpl.hxx
@@ -313,6 +313,10 @@ public:
     int nCurrentStyleIndex;
     /// Index of the current character style.
     int nCurrentCharacterStyleIndex;
+    /// Current listid, points to a listtable entry.
+    int nCurrentListIndex = -1;
+    /// Current ls, points to a listoverridetable entry.
+    int nCurrentListOverrideIndex = -1;
 
     /// Points to the active buffer, if there is one.
     RTFBuffer_t* pCurrentBuffer;
@@ -372,9 +376,12 @@ void putNestedAttribute(RTFSprms& rSprms, Id nParent, Id 
nId, const RTFValue::Po
                         RTFOverwrite eOverwrite = RTFOverwrite::YES, bool 
bAttribute = true);
 bool eraseNestedAttribute(RTFSprms& rSprms, Id nParent, Id nId);
 
-/// Looks up the nParent then the nested nId key in rSprms.
+/// Looks up the nParent then the nested nId attribute in rSprms.
 RTFValue::Pointer_t getNestedAttribute(RTFSprms& rSprms, Id nParent, Id nId);
 
+/// Looks up the nParent then the nested nId sprm in rSprms.
+RTFValue::Pointer_t getNestedSprm(RTFSprms& rSprms, Id nParent, Id nId);
+
 /// Checks if rName is contained at least once in rProperties as a key.
 bool findPropertyName(const std::vector<css::beans::PropertyValue>& 
rProperties,
                       const OUString& rName);
@@ -534,6 +541,10 @@ private:
     bool m_bNeedFinalPar;
     /// The list table and list override table combined.
     RTFSprms m_aListTableSprms;
+    /// Maps between listoverridetable and listtable indexes.
+    std::map<int, int> m_aListOverrideTable;
+    /// Maps listtable indexes to listtable entries.
+    std::map<int, RTFValue::Pointer_t> m_aListTable;
     /// The settings table attributes.
     RTFSprms m_aSettingsTableAttributes;
     /// The settings table sprms.
diff --git a/writerfilter/source/rtftok/rtfsprm.cxx 
b/writerfilter/source/rtftok/rtfsprm.cxx
index e021feee623c..eb959cb3496b 100644
--- a/writerfilter/source/rtftok/rtfsprm.cxx
+++ b/writerfilter/source/rtftok/rtfsprm.cxx
@@ -11,6 +11,7 @@
 #include <ooxml/resourceids.hxx>
 #include <ooxml/QNameToString.hxx>
 #include <rtl/strbuf.hxx>
+#include "rtfdocumentimpl.hxx"
 
 namespace writerfilter
 {
@@ -145,6 +146,7 @@ static RTFValue::Pointer_t getDefaultSPRM(Id const id)
         case NS_ooxml::LN_EG_RPrBase_b:
         case NS_ooxml::LN_CT_Ind_left:
         case NS_ooxml::LN_CT_Ind_right:
+        case NS_ooxml::LN_CT_Ind_firstLine:
             return std::make_shared<RTFValue>(0);
 
         default:
@@ -239,6 +241,61 @@ static void cloneAndDeduplicateSprm(std::pair<Id, 
RTFValue::Pointer_t> const& rS
     }
 }
 
+/// Extracts the list level matching nLevel from pAbstract.
+static RTFValue::Pointer_t getListLevel(RTFValue::Pointer_t pAbstract, int 
nLevel)
+{
+    for (const auto& rPair : pAbstract->getSprms())
+    {
+        if (rPair.first != NS_ooxml::LN_CT_AbstractNum_lvl)
+            continue;
+
+        RTFValue::Pointer_t pLevel = 
rPair.second->getAttributes().find(NS_ooxml::LN_CT_Lvl_ilvl);
+        if (!pLevel)
+            continue;
+
+        if (pLevel->getInt() != nLevel)
+            continue;
+
+        return rPair.second;
+    }
+
+    return RTFValue::Pointer_t();
+}
+
+void RTFSprms::duplicateList(RTFValue::Pointer_t pAbstract)
+{
+    int nLevel = 0;
+    RTFValue::Pointer_t pLevelId
+        = getNestedSprm(*this, NS_ooxml::LN_CT_PPrBase_numPr, 
NS_ooxml::LN_CT_NumPr_ilvl);
+    if (pLevelId)
+        nLevel = pLevelId->getInt();
+
+    RTFValue::Pointer_t pLevel = getListLevel(pAbstract, nLevel);
+    if (!pLevel)
+        return;
+
+    RTFValue::Pointer_t pLevelInd = 
pLevel->getSprms().find(NS_ooxml::LN_CT_PPrBase_ind);
+    if (!pLevelInd)
+        return;
+
+    for (const auto& rListLevelPair : pLevelInd->getAttributes())
+    {
+        switch (rListLevelPair.first)
+        {
+            case NS_ooxml::LN_CT_Ind_left:
+            case NS_ooxml::LN_CT_Ind_right:
+            case NS_ooxml::LN_CT_Ind_firstLine:
+                RTFValue::Pointer_t pParagraphValue
+                    = getNestedAttribute(*this, NS_ooxml::LN_CT_PPrBase_ind, 
rListLevelPair.first);
+                if (!pParagraphValue)
+                    putNestedAttribute(*this, NS_ooxml::LN_CT_PPrBase_ind, 
rListLevelPair.first,
+                                       getDefaultSPRM(rListLevelPair.first));
+
+                break;
+        }
+    }
+}
+
 RTFSprms RTFSprms::cloneAndDeduplicate(RTFSprms& rReference) const
 {
     RTFSprms ret(*this);
diff --git a/writerfilter/source/rtftok/rtfsprm.hxx 
b/writerfilter/source/rtftok/rtfsprm.hxx
index 7839682343b8..6a79d5b7a55a 100644
--- a/writerfilter/source/rtftok/rtfsprm.hxx
+++ b/writerfilter/source/rtftok/rtfsprm.hxx
@@ -65,6 +65,8 @@ public:
     /// Also insert default values to override attributes of style
     /// (yes, really; that's what Word does).
     RTFSprms cloneAndDeduplicate(RTFSprms& rReference) const;
+    /// Inserts default values to override attributes of pAbstract.
+    void duplicateList(RTFValue::Pointer_t pAbstract);
     std::size_t size() const { return m_pSprms->size(); }
     bool empty() const { return m_pSprms->empty(); }
     Entry_t& back() { return m_pSprms->back(); }
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to