xmloff/qa/unit/data/tdf150407_PosRelBottomMargin.docx   |binary
 xmloff/qa/unit/data/tdf150407_PosRelTopMargin.docx      |binary
 xmloff/qa/unit/data/tdf150407_WritingModeBTLR_style.odt |binary
 xmloff/qa/unit/style.cxx                                |  191 ++++++++++++++++
 xmloff/source/style/xmlexppr.cxx                        |   51 ++--
 5 files changed, 217 insertions(+), 25 deletions(-)

New commits:
commit 927b6e72274fa19a6a43e95a7f93901183ee1690
Author:     Regina Henschel <rb.hensc...@t-online.de>
AuthorDate: Sat Aug 20 20:56:11 2022 +0200
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Tue Aug 30 11:05:50 2022 +0200

    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 <rb.hensc...@t-online.de>
    (cherry picked from commit 64be7052ba7e02e248412222098e07a5f4106456)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/138541
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>
    (cherry picked from commit 34edaf8249107c4216fdaffe450d287a1908a0de)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/138547
    (cherry picked from commit 89552d1652bbe026f9572325056056b449d74716)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/138823
    Reviewed-by: Thorsten Behrens <thorsten.behr...@allotropia.de>
    Tested-by: Miklos Vajna <vmik...@collabora.com>
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>

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 1f63cbe1355a..93634ad5170d 100644
--- a/xmloff/qa/unit/style.cxx
+++ b/xmloff/qa/unit/style.cxx
@@ -23,6 +23,9 @@
 #include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
 
 #include <comphelper/propertysequence.hxx>
+#include <officecfg/Office/Common.hxx>
+#include <unotools/mediadescriptor.hxx>
+#include <unotools/saveopt.hxx>
 #include <unotools/tempfile.hxx>
 #include <unotools/ucbstreamhelper.hxx>
 #include <rtl/character.hxx>
@@ -45,6 +48,7 @@ public:
     void registerNamespaces(xmlXPathContextPtr& pXmlXpathCtx) override;
     uno::Reference<lang::XComponent>& 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<frame::XStorable> 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<comphelper::ConfigurationChanges> 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<comphelper::ConfigurationChanges> 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<SvStream> 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<comphelper::ConfigurationChanges> 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<SvStream> 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<comphelper::ConfigurationChanges> 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<comphelper::ConfigurationChanges> 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<SvStream> 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<comphelper::ConfigurationChanges> 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<SvStream> 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<comphelper::ConfigurationChanges> 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<comphelper::ConfigurationChanges> 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<SvStream> 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<comphelper::ConfigurationChanges> 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<SvStream> 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 f87f9ae1ece0..d81253238d3a 100644
--- a/xmloff/source/style/xmlexppr.cxx
+++ b/xmloff/source/style/xmlexppr.cxx
@@ -929,6 +929,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,
@@ -1057,31 +1075,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 );
         }
     }

Reply via email to