[Libreoffice-commits] core.git: sw/qa writerfilter/source
Miklos Vajna
vmiklos at collabora.co.uk
Tue Mar 20 08:06:40 UTC 2018
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 <vmiklos at 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 <ci at libreoffice.org>
Reviewed-by: Miklos Vajna <vmiklos at 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(); }
More information about the Libreoffice-commits
mailing list