summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--writerperfect/CppunitTest_writerperfect_epubexport.mk3
-rw-r--r--writerperfect/qa/unit/EPUBExportTest.cxx44
-rw-r--r--writerperfect/qa/unit/data/writer/epubexport/nested-span.fodt21
-rw-r--r--writerperfect/source/writer/exp/txtparai.cxx35
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="&apos;Liberation Mono&apos;" 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="&apos;Liberation Mono&apos;" 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;