diff options
-rw-r--r-- | writerperfect/CppunitTest_writerperfect_epubexport.mk | 3 | ||||
-rw-r--r-- | writerperfect/qa/unit/EPUBExportTest.cxx | 44 | ||||
-rw-r--r-- | writerperfect/qa/unit/data/writer/epubexport/nested-span.fodt | 21 | ||||
-rw-r--r-- | writerperfect/source/writer/exp/txtparai.cxx | 35 |
4 files changed, 81 insertions, 22 deletions
diff --git a/writerperfect/CppunitTest_writerperfect_epubexport.mk b/writerperfect/CppunitTest_writerperfect_epubexport.mk index a74de9ebc7fd..d634e59b87da 100644 --- a/writerperfect/CppunitTest_writerperfect_epubexport.mk +++ b/writerperfect/CppunitTest_writerperfect_epubexport.mk @@ -21,9 +21,10 @@ $(eval $(call gb_CppunitTest_use_libraries,writerperfect_epubexport, \ cppuhelper \ sal \ test \ + tl \ unotest \ utl \ - tl \ + wpftwriter \ $(gb_UWINAPI) \ )) diff --git a/writerperfect/qa/unit/EPUBExportTest.cxx b/writerperfect/qa/unit/EPUBExportTest.cxx index 7b5de434bf8f..a7bb9c322c5e 100644 --- a/writerperfect/qa/unit/EPUBExportTest.cxx +++ b/writerperfect/qa/unit/EPUBExportTest.cxx @@ -44,6 +44,8 @@ public: void setUp() override; void tearDown() override; void registerNamespaces(xmlXPathContextPtr &pXmlXpathCtx) override; + /// Asserts that rCssDoc has a key named rKey and one of its rules is rValue. + void assertCss(const std::map< OString, std::vector<OString> > &rCssDoc, const OString &rKey, const OString &rValue); void createDoc(const OUString &rFile, const uno::Sequence<beans::PropertyValue> &rFilterData); /// Returns an XML representation of the stream named rName in the exported package. xmlDocPtr parseExport(const OUString &rName); @@ -59,6 +61,7 @@ public: void testParaNamedstyle(); void testCharNamedstyle(); void testNamedStyleInheritance(); + void testNestedSpan(); CPPUNIT_TEST_SUITE(EPUBExportTest); CPPUNIT_TEST(testOutlineLevel); @@ -71,6 +74,7 @@ public: CPPUNIT_TEST(testParaNamedstyle); CPPUNIT_TEST(testCharNamedstyle); CPPUNIT_TEST(testNamedStyleInheritance); + CPPUNIT_TEST(testNestedSpan); CPPUNIT_TEST_SUITE_END(); }; @@ -103,6 +107,16 @@ void EPUBExportTest::registerNamespaces(xmlXPathContextPtr &pXmlXpathCtx) xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("xhtml"), BAD_CAST("http://www.w3.org/1999/xhtml")); } +void EPUBExportTest::assertCss(const std::map< OString, std::vector<OString> > &rCssDoc, const OString &rKey, const OString &rValue) +{ + auto it = rCssDoc.find(rKey); + CPPUNIT_ASSERT(it != rCssDoc.end()); + + const std::vector<OString> &rRule = it->second; + CPPUNIT_ASSERT_MESSAGE(OString("In '" + rKey + "', rule '" + rValue + "' is not found.").getStr(), + std::find(rRule.begin(), rRule.end(), rValue) != rRule.end()); +} + void EPUBExportTest::createDoc(const OUString &rFile, const uno::Sequence<beans::PropertyValue> &rFilterData) { // Import the bugdoc and export as EPUB. @@ -275,16 +289,32 @@ void EPUBExportTest::testNamedStyleInheritance() // Find the CSS rule for the blue text. mpXmlDoc = parseExport("OEBPS/sections/section0001.xhtml"); - OUString aBlue = getXPath(mpXmlDoc, "//xhtml:p[2]/xhtml:span[2]", "class"); + OString aBlue = getXPath(mpXmlDoc, "//xhtml:p[2]/xhtml:span[2]", "class").toUtf8(); - std::map< OString, std::vector<OString> > aTree; - parseCssExport("OEBPS/styles/stylesheet.css", aTree); - CPPUNIT_ASSERT(aTree.find(aBlue.toUtf8()) != aTree.end()); - const std::vector<OString> &rRule = aTree[aBlue.toUtf8()]; - CPPUNIT_ASSERT(std::find(rRule.begin(), rRule.end(), " color: #0000ff;") != rRule.end()); + std::map< OString, std::vector<OString> > aCssDoc; + parseCssExport("OEBPS/styles/stylesheet.css", aCssDoc); + assertCss(aCssDoc, aBlue, " color: #0000ff;"); // This failed, the span only had the properties from its style, but not // from the style's parent(s). - CPPUNIT_ASSERT(std::find(rRule.begin(), rRule.end(), " font-family: 'Liberation Mono';") != rRule.end()); + assertCss(aCssDoc, aBlue, " font-family: 'Liberation Mono';"); +} + +void EPUBExportTest::testNestedSpan() +{ + createDoc("nested-span.fodt", {}); + + // Check textural content of nested span. + mpXmlDoc = parseExport("OEBPS/sections/section0001.xhtml"); + // This crashed, span had no content. + assertXPathContent(mpXmlDoc, "//xhtml:p/xhtml:span[2]", "red"); + + // Check formatting of nested span. + OString aRed = getXPath(mpXmlDoc, "//xhtml:p/xhtml:span[2]", "class").toUtf8(); + std::map< OString, std::vector<OString> > aCssDoc; + parseCssExport("OEBPS/styles/stylesheet.css", aCssDoc); + // This failed, direct formatting on top of named style was lost. + assertCss(aCssDoc, aRed, " color: #ff0000;"); + assertCss(aCssDoc, aRed, " font-family: 'Liberation Mono';"); } CPPUNIT_TEST_SUITE_REGISTRATION(EPUBExportTest); diff --git a/writerperfect/qa/unit/data/writer/epubexport/nested-span.fodt b/writerperfect/qa/unit/data/writer/epubexport/nested-span.fodt new file mode 100644 index 000000000000..a593ff348262 --- /dev/null +++ b/writerperfect/qa/unit/data/writer/epubexport/nested-span.fodt @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8"?> +<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" office:version="1.2" office:mimetype="application/vnd.oasis.opendocument.text"> + <office:font-face-decls> + <style:font-face style:name="Liberation Mono" svg:font-family="'Liberation Mono'" style:font-family-generic="modern" style:font-pitch="fixed"/> + </office:font-face-decls> + <office:styles> + <style:style style:name="Source_20_Text" style:display-name="Source Text" style:family="text"> + <style:text-properties style:font-name="Liberation Mono" fo:font-family="'Liberation Mono'" style:font-family-generic="modern" style:font-pitch="fixed"/> + </style:style> + </office:styles> + <office:automatic-styles> + <style:style style:name="T1" style:family="text"> + <style:text-properties fo:color="#ff0000"/> + </style:style> + </office:automatic-styles> + <office:body> + <office:text> + <text:p>before<text:span text:style-name="Source_20_Text"><text:span text:style-name="T1">red</text:span></text:span></text:p> + </office:text> + </office:body> +</office:document> diff --git a/writerperfect/source/writer/exp/txtparai.cxx b/writerperfect/source/writer/exp/txtparai.cxx index 9658d79f48b9..984070ba7fc4 100644 --- a/writerperfect/source/writer/exp/txtparai.cxx +++ b/writerperfect/source/writer/exp/txtparai.cxx @@ -74,56 +74,63 @@ namespace exp class XMLSpanContext : public XMLImportContext { public: - XMLSpanContext(XMLImport &rImport); + XMLSpanContext(XMLImport &rImport, const librevenge::RVNGPropertyList *pPropertyList); XMLImportContext *CreateChildContext(const OUString &rName, const css::uno::Reference<css::xml::sax::XAttributeList> &xAttribs) override; void SAL_CALL startElement(const OUString &rName, const css::uno::Reference<css::xml::sax::XAttributeList> &xAttribs) override; - void SAL_CALL endElement(const OUString &rName) override; void SAL_CALL characters(const OUString &rChars) override; + +private: + librevenge::RVNGPropertyList m_aPropertyList; }; -XMLSpanContext::XMLSpanContext(XMLImport &rImport) +XMLSpanContext::XMLSpanContext(XMLImport &rImport, const librevenge::RVNGPropertyList *pPropertyList) : XMLImportContext(rImport) { + if (!pPropertyList) + return; + + // Inherit properties from parent span. + librevenge::RVNGPropertyList::Iter itProp(*pPropertyList); + for (itProp.rewind(); itProp.next();) + m_aPropertyList.insert(itProp.key(), itProp()->clone()); } XMLImportContext *XMLSpanContext::CreateChildContext(const OUString &rName, const css::uno::Reference<css::xml::sax::XAttributeList> &/*xAttribs*/) { if (rName == "draw:frame") return new XMLTextFrameContext(mrImport); + if (rName == "text:span") + return new XMLSpanContext(mrImport, &m_aPropertyList); return nullptr; } void XMLSpanContext::startElement(const OUString &/*rName*/, const css::uno::Reference<css::xml::sax::XAttributeList> &xAttribs) { - librevenge::RVNGPropertyList aPropertyList; for (sal_Int16 i = 0; i < xAttribs->getLength(); ++i) { const OUString &rAttributeName = xAttribs->getNameByIndex(i); const OUString &rAttributeValue = xAttribs->getValueByIndex(i); if (rAttributeName == "text:style-name") - FillStyles(rAttributeValue, mrImport.GetAutomaticTextStyles(), mrImport.GetTextStyles(), aPropertyList); + FillStyles(rAttributeValue, mrImport.GetAutomaticTextStyles(), mrImport.GetTextStyles(), m_aPropertyList); else { OString sName = OUStringToOString(rAttributeName, RTL_TEXTENCODING_UTF8); OString sValue = OUStringToOString(rAttributeValue, RTL_TEXTENCODING_UTF8); - aPropertyList.insert(sName.getStr(), sValue.getStr()); + m_aPropertyList.insert(sName.getStr(), sValue.getStr()); } } - - mrImport.GetGenerator().openSpan(aPropertyList); -} - -void XMLSpanContext::endElement(const OUString &/*rName*/) -{ - mrImport.GetGenerator().closeSpan(); } void XMLSpanContext::characters(const OUString &rChars) { + mrImport.GetGenerator().openSpan(m_aPropertyList); + OString sCharU8 = OUStringToOString(rChars, RTL_TEXTENCODING_UTF8); mrImport.GetGenerator().insertText(librevenge::RVNGString(sCharU8.getStr())); + + mrImport.GetGenerator().closeSpan(); } /// Handler for <text:a>. @@ -178,7 +185,7 @@ XMLParaContext::XMLParaContext(XMLImport &rImport) XMLImportContext *XMLParaContext::CreateChildContext(const OUString &rName, const css::uno::Reference<css::xml::sax::XAttributeList> &/*xAttribs*/) { if (rName == "text:span") - return new XMLSpanContext(mrImport); + return new XMLSpanContext(mrImport, nullptr); if (rName == "text:a") return new XMLHyperlinkContext(mrImport); return nullptr; |