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 0f0a80123d970ef6f3f8269619813e5277fff4df 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.) Change-Id: Iec88d9bf1032d1d89194bd272500d6780c3c2224 Reviewed-on: https://gerrit.libreoffice.org/51589 Tested-by: Jenkins <c...@libreoffice.org> Reviewed-by: Miklos Vajna <vmik...@collabora.co.uk> 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 860fe0712044..6ddc2239be6c 100644 --- a/sw/qa/extras/rtfimport/rtfimport.cxx +++ b/sw/qa/extras/rtfimport/rtfimport.cxx @@ -656,6 +656,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 66789d3e6824..bad8111a77aa 100644 --- a/writerfilter/source/rtftok/rtfdispatchvalue.cxx +++ b/writerfilter/source/rtftok/rtfdispatchvalue.cxx @@ -665,12 +665,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 4d5cf17c0b6e..d779e18bce71 100644 --- a/writerfilter/source/rtftok/rtfdocumentimpl.cxx +++ b/writerfilter/source/rtftok/rtfdocumentimpl.cxx @@ -114,6 +114,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); @@ -470,8 +479,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; } @@ -2996,6 +3021,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: @@ -3146,6 +3172,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 ae05d7a0647d..2200122ed030 100644 --- a/writerfilter/source/rtftok/rtfdocumentimpl.hxx +++ b/writerfilter/source/rtftok/rtfdocumentimpl.hxx @@ -335,6 +335,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; @@ -394,9 +398,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); @@ -556,6 +563,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 271ad821cef3..8ebf9fd9ec5e 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 bb9228074277..7232b04e9351 100644 --- a/writerfilter/source/rtftok/rtfsprm.hxx +++ b/writerfilter/source/rtftok/rtfsprm.hxx @@ -56,6 +56,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