diff --git a/writerfilter/source/rtftok/rtfdocumentimpl.cxx b/writerfilter/source/rtftok/rtfdocumentimpl.cxx index d57f96f188c8..84461831f424 100644 --- a/writerfilter/source/rtftok/rtfdocumentimpl.cxx +++ b/writerfilter/source/rtftok/rtfdocumentimpl.cxx @@ -84,6 +84,57 @@ static Id lcl_getParagraphBorder(sal_uInt32 nIndex) return aBorderIds[nIndex]; } +namespace +{ + bool isTrivialCharSprm(Id nSprm) + { + bool bRet = false; + switch (nSprm) + { + case NS_sprm::LN_CRgFtc0: + case NS_sprm::LN_CRgFtc1: + case NS_sprm::LN_CRgFtc2: + case NS_sprm::LN_CHps: + case NS_sprm::LN_CHpsBi: + case NS_sprm::LN_CSfxText: + case NS_sprm::LN_CDxaSpace: + case NS_sprm::LN_CHpsKern: + case NS_sprm::LN_CCharScale: + case NS_sprm::LN_CRgLid0: + case NS_sprm::LN_CRgLid1: + case NS_sprm::LN_CLidBi: + bRet = true; + break; + default: + break; + } + return bRet; + } + + //rhbz#825548. rtf documents with vast sequences of replicated properties without + //any resets to defaults create a huge vector of properties and eat time and memory + // + //So if we are adding a property which already exists and there are no intermediate + //properties which would cause side effects to the property then update the existing + //one instead + bool tryToSafelyUpdateAnExistingProp(RTFSprms &rSprms, Id nSprm, RTFValue::Pointer_t xArg) + { + if (!isTrivialCharSprm(nSprm)) + return false; + + for (RTFSprms::ReverseIterator_t i = rSprms.rbegin(); i != rSprms.rend() && isTrivialCharSprm(i->first); ++i) + { + if (i->first == nSprm) + { + i->second = xArg; + return true; + } + } + + return false; + } +} + static void lcl_putNestedAttribute(RTFSprms& rSprms, Id nParent, Id nId, RTFValue::Pointer_t pValue, bool bOverwrite = false, bool bAttribute = true) { @@ -107,7 +158,8 @@ static void lcl_putNestedAttribute(RTFSprms& rSprms, Id nParent, Id nId, RTFValu } } } - rAttributes.push_back(make_pair(nId, pValue)); + if (!tryToSafelyUpdateAnExistingProp(rAttributes, nId, pValue)) + rAttributes.push_back(make_pair(nId, pValue)); } static void lcl_putNestedSprm(RTFSprms& rSprms, Id nParent, Id nId, RTFValue::Pointer_t pValue, bool bOverwrite = false) @@ -2227,7 +2279,9 @@ int RTFDocumentImpl::dispatchValue(RTFKeyword nKeyword, int nParam) } if (nSprm > 0) { - m_aStates.top().aCharacterSprms.push_back(make_pair(nSprm, pIntValue)); + RTFSprms &rSprms = m_aStates.top().aCharacterSprms; + if (!tryToSafelyUpdateAnExistingProp(rSprms, nSprm, pIntValue)) + rSprms.push_back(make_pair(nSprm, pIntValue)); // Language is a character property, but we should store it at a paragraph level as well for fields. if (nKeyword == RTF_LANG && m_bNeedPap) m_aStates.top().aParagraphSprms.push_back(make_pair(nSprm, pIntValue)); @@ -2310,7 +2364,9 @@ int RTFDocumentImpl::dispatchValue(RTFKeyword nKeyword, int nParam) { int nFontIndex = getFontIndex(nParam); RTFValue::Pointer_t pValue(new RTFValue(nFontIndex)); - m_aStates.top().aCharacterSprms.push_back(make_pair(NS_sprm::LN_CRgFtc0, pValue)); + RTFSprms &rSprms = m_aStates.top().aCharacterSprms; + if (!tryToSafelyUpdateAnExistingProp(rSprms, NS_sprm::LN_CRgFtc0, pValue)) + rSprms.push_back(make_pair(NS_sprm::LN_CRgFtc0, pValue)); m_aStates.top().nCurrentEncoding = getEncoding(nFontIndex); } break; diff --git a/writerfilter/source/rtftok/rtfsprm.hxx b/writerfilter/source/rtftok/rtfsprm.hxx index d126b728f05f..1004b596d3e6 100644 --- a/writerfilter/source/rtftok/rtfsprm.hxx +++ b/writerfilter/source/rtftok/rtfsprm.hxx @@ -40,6 +40,7 @@ namespace writerfilter { typedef ::boost::shared_ptr Pointer_t; typedef std::pair id_val; typedef std::vector< id_val >::iterator Iterator_t; + typedef std::vector< id_val >::reverse_iterator ReverseIterator_t; RTFSprms(); RTFSprms(const RTFSprms& rSprms); RTFSprms& operator=(const RTFSprms& rOther); @@ -51,6 +52,8 @@ namespace writerfilter { id_val& back() { return m_aSprms.back(); } Iterator_t begin() { return m_aSprms.begin(); } Iterator_t end() { return m_aSprms.end(); } + ReverseIterator_t rbegin() { return m_aSprms.rbegin(); } + ReverseIterator_t rend() { return m_aSprms.rend(); } void push_back(id_val aVal) { m_aSprms.push_back(aVal); } void clear() { return m_aSprms.clear(); } private: