From 64be7052ba7e02e248412222098e07a5f4106456 Mon Sep 17 00:00:00 2001 From: Regina Henschel Date: Sat, 20 Aug 2022 20:56:11 +0200 Subject: tdf#150407 do not use loext in save in ODF strict The 'bt-lr' attribute value of 'writing-mode' attribute and the 'page-content-bottom' and 'page-content-top' values of 'vertical-rel' attribute are not part of ODF 1.3. Therefore they need to be saved in 'loext' extended namespace. Error was, that this was done too, if the current ODF version is strict. That results in an invalid file in a productive build and a failed assert in SvXMLNamespaceMap::GetQNameByKey() in a debug build. Change-Id: Ie9ba99fdd02de21a2467b236409daa951933f011 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/138595 Tested-by: Jenkins Reviewed-by: Regina Henschel --- .../qa/unit/data/tdf150407_PosRelBottomMargin.docx | Bin 0 -> 17439 bytes xmloff/qa/unit/data/tdf150407_PosRelTopMargin.docx | Bin 0 -> 17432 bytes .../unit/data/tdf150407_WritingModeBTLR_style.odt | Bin 0 -> 11181 bytes xmloff/qa/unit/style.cxx | 191 +++++++++++++++++++++ xmloff/source/style/xmlexppr.cxx | 51 +++--- 5 files changed, 217 insertions(+), 25 deletions(-) create mode 100644 xmloff/qa/unit/data/tdf150407_PosRelBottomMargin.docx create mode 100644 xmloff/qa/unit/data/tdf150407_PosRelTopMargin.docx create mode 100644 xmloff/qa/unit/data/tdf150407_WritingModeBTLR_style.odt (limited to 'xmloff') diff --git a/xmloff/qa/unit/data/tdf150407_PosRelBottomMargin.docx b/xmloff/qa/unit/data/tdf150407_PosRelBottomMargin.docx new file mode 100644 index 000000000000..0264f89f98a6 Binary files /dev/null and b/xmloff/qa/unit/data/tdf150407_PosRelBottomMargin.docx differ diff --git a/xmloff/qa/unit/data/tdf150407_PosRelTopMargin.docx b/xmloff/qa/unit/data/tdf150407_PosRelTopMargin.docx new file mode 100644 index 000000000000..48f981506243 Binary files /dev/null and b/xmloff/qa/unit/data/tdf150407_PosRelTopMargin.docx differ diff --git a/xmloff/qa/unit/data/tdf150407_WritingModeBTLR_style.odt b/xmloff/qa/unit/data/tdf150407_WritingModeBTLR_style.odt new file mode 100644 index 000000000000..2ad2ca1219b2 Binary files /dev/null and b/xmloff/qa/unit/data/tdf150407_WritingModeBTLR_style.odt differ diff --git a/xmloff/qa/unit/style.cxx b/xmloff/qa/unit/style.cxx index f7744b503efc..c01f188c762d 100644 --- a/xmloff/qa/unit/style.cxx +++ b/xmloff/qa/unit/style.cxx @@ -23,6 +23,9 @@ #include #include +#include +#include +#include #include #include #include @@ -45,6 +48,7 @@ public: void registerNamespaces(xmlXPathContextPtr& pXmlXpathCtx) override; uno::Reference& getComponent() { return mxComponent; } void load(std::u16string_view rURL); + void save(const OUString& rFilterName, utl::TempFile& rTempFile); }; void XmloffStyleTest::setUp() @@ -73,6 +77,16 @@ void XmloffStyleTest::load(std::u16string_view rFileName) mxComponent = loadFromDesktop(aURL); } +void XmloffStyleTest::save(const OUString& rFilterName, utl::TempFile& rTempFile) +{ + uno::Reference xStorable(mxComponent, uno::UNO_QUERY); + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= rFilterName; + rTempFile.EnableKillingFile(); + xStorable->storeToURL(rTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList()); + validate(rTempFile.GetFileName(), test::ODF); +} + CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testFillImageBase64) { // Load a flat ODG that has base64-encoded bitmap as a fill style. @@ -197,6 +211,183 @@ CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testRtlGutter) CPPUNIT_ASSERT(bRtlGutter); } +CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testWritingModeBTLR) +{ + // Load document. It has a frame style with writing-mode bt-lr. + // In ODF 1.3 extended it is written as loext:writing-mode="bt-lr". + // In ODF 1.3 strict, there must not be an attribute at all. + getComponent() = loadFromDesktop(m_directories.getURLFromSrc(DATA_DIRECTORY) + + "tdf150407_WritingModeBTLR_style.odt", + "com.sun.star.text.TextDocument"); + + Resetter _([]() { + std::shared_ptr pBatch( + comphelper::ConfigurationChanges::create()); + officecfg::Office::Common::Save::ODF::DefaultVersion::set(3, pBatch); + return pBatch->commit(); + }); + + // Save to ODF 1.3 extended. Adapt 3 (=ODFVER_LATEST) to a to be ODFVER_013_EXTENDED when + // attribute value "bt-lr" is included in ODF strict. + { + std::shared_ptr pBatch( + comphelper::ConfigurationChanges::create()); + officecfg::Office::Common::Save::ODF::DefaultVersion::set(3, pBatch); + pBatch->commit(); + utl::TempFile aTempFile; + save("writer8", aTempFile); + + // With applied fix for tdf150407 still loext:writing-mode="bt-lr" has to be written. + std::unique_ptr pStream = parseExportStream(aTempFile, "styles.xml"); + xmlDocUniquePtr pXmlDoc = parseXmlStream(pStream.get()); + assertXPath(pXmlDoc, + "/office:document-styles/office:styles/style:style[@style:name='FrameBTLR']/" + "style:graphic-properties[@loext:writing-mode]"); + assertXPath(pXmlDoc, + "/office:document-styles/office:styles/style:style[@style:name='FrameBTLR']/" + "style:graphic-properties", + "writing-mode", "bt-lr"); + } + // Save to ODF 1.3 strict. + { + std::shared_ptr pBatch( + comphelper::ConfigurationChanges::create()); + officecfg::Office::Common::Save::ODF::DefaultVersion::set(10, pBatch); + pBatch->commit(); + utl::TempFile aTempFile; + save("writer8", aTempFile); + + // Without the fix an faulty 'writing-mode="bt-lr"' attribute was written in productive build. + // A debug build fails assertion in SvXMLNamespaceMap::GetQNameByKey(). + std::unique_ptr pStream = parseExportStream(aTempFile, "styles.xml"); + xmlDocUniquePtr pXmlDoc = parseXmlStream(pStream.get()); + assertXPathNoAttribute(pXmlDoc, + "/office:document-styles/office:styles/" + "style:style[@style:name='FrameBTLR']/style:graphic-properties", + "writing-mode"); + } +} + +CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testPosRelBottomMargin) +{ + // Load document. It has a frame position with vertical position relative to bottom margin. + // In ODF 1.3 extended it is written as loext:vertical-rel="page-content-bottom". + // In ODF 1.3 strict, there must not be an attribute at all. + getComponent() = loadFromDesktop(m_directories.getURLFromSrc(DATA_DIRECTORY) + + "tdf150407_PosRelBottomMargin.docx", + "com.sun.star.text.TextDocument"); + + Resetter _([]() { + std::shared_ptr pBatch( + comphelper::ConfigurationChanges::create()); + officecfg::Office::Common::Save::ODF::DefaultVersion::set(3, pBatch); + return pBatch->commit(); + }); + + // Save to ODF 1.3 extended. Adapt 3 (=ODFVER_LATEST) to a to be ODFVER_013_EXTENDED when + // attribute value "page-content-bottom" is included in ODF strict. + { + std::shared_ptr pBatch( + comphelper::ConfigurationChanges::create()); + officecfg::Office::Common::Save::ODF::DefaultVersion::set(3, pBatch); + pBatch->commit(); + utl::TempFile aTempFile; + save("writer8", aTempFile); + + // With applied fix for tdf150407 still loext:vertical-rel="page-content-bottom" has to be + // written. + std::unique_ptr pStream = parseExportStream(aTempFile, "content.xml"); + xmlDocUniquePtr pXmlDoc = parseXmlStream(pStream.get()); + assertXPath( + pXmlDoc, + "/office:document-content/office:automatic-styles/style:style[@style:name='gr1']/" + "style:graphic-properties[@loext:vertical-rel]"); + assertXPath( + pXmlDoc, + "/office:document-content/office:automatic-styles/style:style[@style:name='gr1']/" + "style:graphic-properties", + "vertical-rel", "page-content-bottom"); + } + // Save to ODF 1.3 strict. + { + std::shared_ptr pBatch( + comphelper::ConfigurationChanges::create()); + officecfg::Office::Common::Save::ODF::DefaultVersion::set(10, pBatch); + pBatch->commit(); + utl::TempFile aTempFile; + save("writer8", aTempFile); + + // Without the fix an faulty 'vertical-rel="page-content-bottom"' attribute was written in + // productive build. A debug build fails assertion in SvXMLNamespaceMap::GetQNameByKey(). + std::unique_ptr pStream = parseExportStream(aTempFile, "content.xml"); + xmlDocUniquePtr pXmlDoc = parseXmlStream(pStream.get()); + assertXPathNoAttribute(pXmlDoc, + "/office:document-content/office:automatic-styles/" + "style:style[@style:name='gr1']/style:graphic-properties", + "vertical-rel"); + } +} + +CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testPosRelTopMargin) +{ + // Load document. It has a frame position with vertical position relative to top margin. + // In ODF 1.3 extended it is written as loext:vertical-rel="page-content-top". + // In ODF 1.3 strict, there must not be an attribute at all. + getComponent() = loadFromDesktop(m_directories.getURLFromSrc(DATA_DIRECTORY) + + "tdf150407_PosRelTopMargin.docx", + "com.sun.star.text.TextDocument"); + + Resetter _([]() { + std::shared_ptr pBatch( + comphelper::ConfigurationChanges::create()); + officecfg::Office::Common::Save::ODF::DefaultVersion::set(3, pBatch); + return pBatch->commit(); + }); + + // Save to ODF 1.3 extended. Adapt 3 (=ODFVER_LATEST) to a to be ODFVER_013_EXTENDED when + // attribute value "page-content-top" is included in ODF strict. + { + std::shared_ptr pBatch( + comphelper::ConfigurationChanges::create()); + officecfg::Office::Common::Save::ODF::DefaultVersion::set(3, pBatch); + pBatch->commit(); + utl::TempFile aTempFile; + save("writer8", aTempFile); + + // With applied fix for tdf150407 still loext:vertical-rel="page-content-top has to be + // written. + std::unique_ptr pStream = parseExportStream(aTempFile, "content.xml"); + xmlDocUniquePtr pXmlDoc = parseXmlStream(pStream.get()); + assertXPath( + pXmlDoc, + "/office:document-content/office:automatic-styles/style:style[@style:name='gr1']/" + "style:graphic-properties[@loext:vertical-rel]"); + assertXPath( + pXmlDoc, + "/office:document-content/office:automatic-styles/style:style[@style:name='gr1']/" + "style:graphic-properties", + "vertical-rel", "page-content-top"); + } + // Save to ODF 1.3 strict. + { + std::shared_ptr pBatch( + comphelper::ConfigurationChanges::create()); + officecfg::Office::Common::Save::ODF::DefaultVersion::set(10, pBatch); + pBatch->commit(); + utl::TempFile aTempFile; + save("writer8", aTempFile); + + // Without the fix an faulty 'vertical-rel="page-content-top"' attribute was written in + // productive build. A debug build fails assertion in SvXMLNamespaceMap::GetQNameByKey(). + std::unique_ptr pStream = parseExportStream(aTempFile, "content.xml"); + xmlDocUniquePtr pXmlDoc = parseXmlStream(pStream.get()); + assertXPathNoAttribute(pXmlDoc, + "/office:document-content/office:automatic-styles/" + "style:style[@style:name='gr1']/style:graphic-properties", + "vertical-rel"); + } +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/xmlexppr.cxx b/xmloff/source/style/xmlexppr.cxx index 5c8310210dd9..412b578c42a9 100644 --- a/xmloff/source/style/xmlexppr.cxx +++ b/xmloff/source/style/xmlexppr.cxx @@ -930,6 +930,24 @@ void SvXMLExportPropertyMapper::_exportXML( } } +namespace +{ +// -1 = Attribute needs extended namespace, but current ODF version is strict. +// 1 = Attribute needs extended namespace and current ODF version allows it. +// 0 = Attribute does not need extended namespace +sal_Int8 CheckExtendedNamespace(std::u16string_view sXMLAttributeName, std::u16string_view sValue, + const SvtSaveOptions::ODFSaneDefaultVersion nODFVersion) +{ + if (IsXMLToken(sXMLAttributeName, XML_WRITING_MODE) && IsXMLToken(sValue, XML_BT_LR)) + return nODFVersion & SvtSaveOptions::ODFSVER_EXTENDED ? 1 : -1; + else if (IsXMLToken(sXMLAttributeName, XML_VERTICAL_REL) + && (IsXMLToken(sValue, XML_PAGE_CONTENT_BOTTOM) + || IsXMLToken(sValue, XML_PAGE_CONTENT_TOP))) + return nODFVersion & SvtSaveOptions::ODFSVER_EXTENDED ? 1 : -1; + return 0; +} +} + void SvXMLExportPropertyMapper::_exportXML( SvXMLAttributeList& rAttrList, const XMLPropertyState& rProperty, @@ -1058,31 +1076,14 @@ void SvXMLExportPropertyMapper::_exportXML( // We don't seem to have a generic mechanism to write an attribute in the extension // namespace in case of certain attribute values only, so do this manually. - if (IsXMLToken(mpImpl->mxPropMapper->GetEntryXMLName(rProperty.mnIndex), XML_WRITING_MODE)) - { - if (IsXMLToken(aValue, XML_BT_LR)) - { - sName = rNamespaceMap.GetQNameByKey( - XML_NAMESPACE_LO_EXT, - mpImpl->mxPropMapper->GetEntryXMLName(rProperty.mnIndex)); - } - } - else if (IsXMLToken(mpImpl->mxPropMapper->GetEntryXMLName(rProperty.mnIndex), XML_VERTICAL_REL)) - { - if (IsXMLToken(aValue, XML_PAGE_CONTENT_BOTTOM)) - { - sName = rNamespaceMap.GetQNameByKey( - XML_NAMESPACE_LO_EXT, - mpImpl->mxPropMapper->GetEntryXMLName(rProperty.mnIndex)); - } - if (IsXMLToken(aValue, XML_PAGE_CONTENT_TOP)) - { - sName = rNamespaceMap.GetQNameByKey( - XML_NAMESPACE_LO_EXT, - mpImpl->mxPropMapper->GetEntryXMLName(rProperty.mnIndex)); - } - } - + sal_Int8 nExtendedStatus + = CheckExtendedNamespace(mpImpl->mxPropMapper->GetEntryXMLName(rProperty.mnIndex), + aValue, rUnitConverter.getSaneDefaultVersion()); + if (nExtendedStatus == -1) + return; + if (nExtendedStatus == 1) + sName = rNamespaceMap.GetQNameByKey( + XML_NAMESPACE_LO_EXT, mpImpl->mxPropMapper->GetEntryXMLName(rProperty.mnIndex)); rAttrList.AddAttribute( sName, aValue ); } } -- cgit