diff options
author | Miklos Vajna <vmiklos@collabora.com> | 2021-03-11 13:01:16 +0100 |
---|---|---|
committer | Miklos Vajna <vmiklos@collabora.com> | 2021-03-11 16:14:57 +0100 |
commit | 08e783903cf67e9c6673e21f99dfff816f8d5872 (patch) | |
tree | ea359afb12e7b112ce3324dd2fa021c506ffb39f /xmloff | |
parent | f92510321dc860f43e471473db67167c0fefcbea (diff) |
ODF export: sort <style:font-face> elements based on the style:name attribute
m_pFontAutoStylePool is already sorted, but sorting ignores
XMLFontAutoStylePoolEntry_Impl::sName, and changing
XMLFontAutoStylePoolEntryCmp_Impl would affect how find() works in
XMLFontAutoStylePool::Add(), so just extend
XMLFontAutoStylePool::exportXML() instead.
With this, the order of <style:font-face> elements is meant to be stable
in content.xml and styles.xml, helping use-cases where a document is
converted to ODF multiple times and an integration test wants to assert
that the output is the same.
Change-Id: If0dbfa40a1b204aebe5e141fe64f71ac2ca92405
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/112339
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
Tested-by: Jenkins
Diffstat (limited to 'xmloff')
-rw-r--r-- | xmloff/CppunitTest_xmloff_style.mk | 2 | ||||
-rw-r--r-- | xmloff/qa/unit/style.cxx | 69 | ||||
-rw-r--r-- | xmloff/source/style/XMLFontAutoStylePool.cxx | 12 |
3 files changed, 82 insertions, 1 deletions
diff --git a/xmloff/CppunitTest_xmloff_style.mk b/xmloff/CppunitTest_xmloff_style.mk index 866224e70159..8d603833c7a8 100644 --- a/xmloff/CppunitTest_xmloff_style.mk +++ b/xmloff/CppunitTest_xmloff_style.mk @@ -13,6 +13,7 @@ $(eval $(call gb_CppunitTest_CppunitTest,xmloff_style)) $(eval $(call gb_CppunitTest_use_externals,xmloff_style,\ boost_headers \ + libxml2 \ )) $(eval $(call gb_CppunitTest_add_exception_objects,xmloff_style, \ @@ -26,6 +27,7 @@ $(eval $(call gb_CppunitTest_use_libraries,xmloff_style, \ sal \ test \ unotest \ + utl \ )) $(eval $(call gb_CppunitTest_use_sdk_api,xmloff_style)) diff --git a/xmloff/qa/unit/style.cxx b/xmloff/qa/unit/style.cxx index f2d9cdbedc37..eaae3bbd1b92 100644 --- a/xmloff/qa/unit/style.cxx +++ b/xmloff/qa/unit/style.cxx @@ -13,16 +13,25 @@ #include <test/bootstrapfixture.hxx> #include <unotest/macros_test.hxx> +#include <test/xmltesttools.hxx> #include <com/sun/star/frame/Desktop.hpp> #include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/frame/XStorable.hpp> +#include <com/sun/star/packages/zip/ZipFileAccess.hpp> + +#include <comphelper/propertysequence.hxx> +#include <unotools/tempfile.hxx> +#include <unotools/ucbstreamhelper.hxx> using namespace ::com::sun::star; constexpr OUStringLiteral DATA_DIRECTORY = u"/xmloff/qa/unit/data/"; /// Covers xmloff/source/style/ fixes. -class XmloffStyleTest : public test::BootstrapFixture, public unotest::MacrosTest +class XmloffStyleTest : public test::BootstrapFixture, + public unotest::MacrosTest, + public XmlTestTools { private: uno::Reference<lang::XComponent> mxComponent; @@ -30,6 +39,7 @@ private: public: void setUp() override; void tearDown() override; + void registerNamespaces(xmlXPathContextPtr& pXmlXpathCtx) override; uno::Reference<lang::XComponent>& getComponent() { return mxComponent; } void load(std::u16string_view rURL); }; @@ -49,6 +59,14 @@ void XmloffStyleTest::tearDown() test::BootstrapFixture::tearDown(); } +void XmloffStyleTest::registerNamespaces(xmlXPathContextPtr& pXmlXpathCtx) +{ + xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("office"), + BAD_CAST("urn:oasis:names:tc:opendocument:xmlns:office:1.0")); + xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("style"), + BAD_CAST("urn:oasis:names:tc:opendocument:xmlns:style:1.0")); +} + void XmloffStyleTest::load(std::u16string_view rFileName) { OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + rFileName; @@ -68,6 +86,55 @@ CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testFillImageBase64) CPPUNIT_ASSERT(xBitmaps->hasByName("libreoffice_0")); } +CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testFontSorting) +{ + // Given an empty document with default fonts (Liberation Sans, Lucida Sans, etc): + getComponent() = loadFromDesktop("private:factory/swriter"); + + // When saving that document to ODT: + uno::Reference<frame::XStorable> xStorable(getComponent(), uno::UNO_QUERY); + utl::TempFile aTempFile; + aTempFile.EnableKillingFile(); + uno::Sequence<beans::PropertyValue> aStoreProps = comphelper::InitPropertySequence({ + { "FilterName", uno::makeAny(OUString("writer8")) }, + }); + xStorable->storeToURL(aTempFile.GetURL(), aStoreProps); + + // Then make sure <style:font-face> elements are sorted (by style:name="..."): + uno::Reference<packages::zip::XZipFileAccess2> xNameAccess + = packages::zip::ZipFileAccess::createWithURL(mxComponentContext, aTempFile.GetURL()); + uno::Reference<io::XInputStream> xInputStream(xNameAccess->getByName("content.xml"), + uno::UNO_QUERY); + std::unique_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream(xInputStream, true)); + xmlDocUniquePtr pXmlDoc = parseXmlStream(pStream.get()); + xmlXPathObjectPtr pXPath + = getXPathNode(pXmlDoc, "/office:document-content/office:font-face-decls/style:font-face"); + xmlNodeSetPtr pXmlNodes = pXPath->nodesetval; + int nNodeCount = xmlXPathNodeSetGetLength(pXmlNodes); + std::vector<OString> aXMLNames; + std::set<OString> aSortedNames; + for (int i = 0; i < nNodeCount; ++i) + { + xmlNodePtr pXmlNode = pXmlNodes->nodeTab[i]; + xmlChar* pName = xmlGetProp(pXmlNode, BAD_CAST("name")); + OString aName(reinterpret_cast<char const*>(pName)); + aXMLNames.push_back(aName); + aSortedNames.insert(aName); + xmlFree(pName); + } + size_t nIndex = 0; + for (const auto& rName : aSortedNames) + { + // Without the accompanying fix in place, this test would have failed with: + // - Expected: Liberation Sans + // - Actual : Lucida Sans1 + // i.e. the output was not lexicographically sorted, "u" was before "i". + CPPUNIT_ASSERT_EQUAL(rName, aXMLNames[nIndex]); + ++nIndex; + } + xmlXPathFreeObject(pXPath); +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/XMLFontAutoStylePool.cxx b/xmloff/source/style/XMLFontAutoStylePool.cxx index 248bb2bc8dcf..bffdfad796a5 100644 --- a/xmloff/source/style/XMLFontAutoStylePool.cxx +++ b/xmloff/source/style/XMLFontAutoStylePool.cxx @@ -406,8 +406,20 @@ void XMLFontAutoStylePool::exportXML() if (m_bEmbedUsedOnly) aUsedFontNames = getUsedFontList(); + // Sort <style:font-face> elements based on their style:name attribute. + std::vector<XMLFontAutoStylePoolEntry_Impl*> aFontAutoStyles; for (const auto& pEntry : *m_pFontAutoStylePool) { + aFontAutoStyles.push_back(pEntry.get()); + } + std::sort( + aFontAutoStyles.begin(), aFontAutoStyles.end(), + [](const XMLFontAutoStylePoolEntry_Impl* pA, XMLFontAutoStylePoolEntry_Impl* pB) -> bool { + return pA->GetName() < pB->GetName(); + }); + + for (const auto& pEntry : aFontAutoStyles) + { GetExport().AddAttribute(XML_NAMESPACE_STYLE, XML_NAME, pEntry->GetName()); aAny <<= pEntry->GetFamilyName(); |