summaryrefslogtreecommitdiff
path: root/writerperfect
diff options
context:
space:
mode:
authorMiklos Vajna <vmiklos@collabora.co.uk>2017-09-06 15:35:40 +0200
committerMiklos Vajna <vmiklos@collabora.co.uk>2017-09-06 18:08:55 +0200
commitfe4c6063ec493c986f810ba676e2b12fe7dab7a9 (patch)
tree956e97b7005bca48cffe953676a3e1211a088c68 /writerperfect
parentac38af2bb850abab0039d7c9e35644752cf4feb1 (diff)
EPUB export: handle style parents for named styles
Character / paragraph formatting from a style hierarchy should be OK now. Also this time test the actual CSS contents, not just that the rule name for two paragraphs or spans differs. Change-Id: I18a9c11aaf16bb3c4b462415b5e819f16de0893c Reviewed-on: https://gerrit.libreoffice.org/41993 Reviewed-by: Miklos Vajna <vmiklos@collabora.co.uk> Tested-by: Jenkins <ci@libreoffice.org>
Diffstat (limited to 'writerperfect')
-rw-r--r--writerperfect/qa/unit/EPUBExportTest.cxx41
-rw-r--r--writerperfect/qa/unit/data/writer/epubexport/named-style-inheritance.fodt39
-rw-r--r--writerperfect/source/writer/exp/txtparai.cxx54
-rw-r--r--writerperfect/source/writer/exp/txtstyli.cxx11
4 files changed, 126 insertions, 19 deletions
diff --git a/writerperfect/qa/unit/EPUBExportTest.cxx b/writerperfect/qa/unit/EPUBExportTest.cxx
index 1b57655180b0..7b5de434bf8f 100644
--- a/writerperfect/qa/unit/EPUBExportTest.cxx
+++ b/writerperfect/qa/unit/EPUBExportTest.cxx
@@ -47,6 +47,8 @@ public:
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);
+ /// Loads a CSS representation of the stream named rName in the exported package into rTree.
+ void parseCssExport(const OUString &rName, std::map< OString, std::vector<OString> > &rTree);
void testOutlineLevel();
void testMimetype();
void testEPUB2();
@@ -56,6 +58,7 @@ public:
void testMeta();
void testParaNamedstyle();
void testCharNamedstyle();
+ void testNamedStyleInheritance();
CPPUNIT_TEST_SUITE(EPUBExportTest);
CPPUNIT_TEST(testOutlineLevel);
@@ -67,6 +70,7 @@ public:
CPPUNIT_TEST(testMeta);
CPPUNIT_TEST(testParaNamedstyle);
CPPUNIT_TEST(testCharNamedstyle);
+ CPPUNIT_TEST(testNamedStyleInheritance);
CPPUNIT_TEST_SUITE_END();
};
@@ -122,6 +126,25 @@ xmlDocPtr EPUBExportTest::parseExport(const OUString &rName)
return parseXmlStream(pStream.get());
}
+void EPUBExportTest::parseCssExport(const OUString &rName, std::map< OString, std::vector<OString> > &rTree)
+{
+ uno::Reference<io::XInputStream> xInputStream(mxZipFile->getByName(rName), uno::UNO_QUERY);
+ std::shared_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream(xInputStream, true));
+
+ // Minimal CSS handler till orcus is up to our needs.
+ OString aLine;
+ OString aRuleName;
+ while (!pStream->IsEof())
+ {
+ pStream->ReadLine(aLine);
+ if (aLine.endsWith("{"))
+ // '.name {' -> 'name'
+ aRuleName = aLine.copy(1, aLine.getLength() - 3);
+ else if (aLine.endsWith(";"))
+ rTree[aRuleName].push_back(aLine);
+ }
+}
+
void EPUBExportTest::testOutlineLevel()
{
createDoc("outline-level.fodt", {});
@@ -246,6 +269,24 @@ void EPUBExportTest::testCharNamedstyle()
assertXPath(mpXmlDoc, "//xhtml:p/xhtml:span[2]", "class", "span1");
}
+void EPUBExportTest::testNamedStyleInheritance()
+{
+ createDoc("named-style-inheritance.fodt", {});
+
+ // 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");
+
+ 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());
+ // 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());
+}
+
CPPUNIT_TEST_SUITE_REGISTRATION(EPUBExportTest);
}
diff --git a/writerperfect/qa/unit/data/writer/epubexport/named-style-inheritance.fodt b/writerperfect/qa/unit/data/writer/epubexport/named-style-inheritance.fodt
new file mode 100644
index 000000000000..2bd6197774c5
--- /dev/null
+++ b/writerperfect/qa/unit/data/writer/epubexport/named-style-inheritance.fodt
@@ -0,0 +1,39 @@
+<?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:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:rpt="http://openoffice.org/2005/report" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns:officeooo="http://openoffice.org/2009/office" xmlns:tableooo="http://openoffice.org/2009/table" xmlns:drawooo="http://openoffice.org/2010/draw" 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"/>
+ <style:font-face style:name="Liberation Serif" svg:font-family="&apos;Liberation Serif&apos;" style:font-family-generic="roman" style:font-pitch="variable"/>
+ <style:font-face style:name="Liberation Sans" svg:font-family="&apos;Liberation Sans&apos;" style:font-family-generic="swiss" style:font-pitch="variable"/>
+ </office:font-face-decls>
+ <office:styles>
+ <style:style style:name="Heading" style:family="paragraph" style:class="text">
+ <style:paragraph-properties fo:margin-top="0.423cm" fo:margin-bottom="0.212cm" fo:keep-with-next="always"/>
+ <style:text-properties style:font-name="Liberation Sans" fo:font-family="&apos;Liberation Sans&apos;" style:font-family-generic="swiss" style:font-pitch="variable" fo:font-size="14pt"/>
+ </style:style>
+ <style:style style:name="Heading_20_1" style:display-name="Heading 1" style:family="paragraph" style:parent-style-name="Heading" style:default-outline-level="1" style:class="text">
+ </style:style>
+ <style:style style:name="Blue_20_Source_20_Text" style:display-name="Blue Source Text" style:family="text" style:parent-style-name="Source_20_Text">
+ <style:text-properties fo:color="#0000ff"/>
+ </style:style>
+ <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:page-layout style:name="pm1">
+ <style:page-layout-properties fo:page-width="21.59cm" fo:page-height="27.94cm">
+ </style:page-layout-properties>
+ <style:header-style/>
+ <style:footer-style/>
+ </style:page-layout>
+ </office:automatic-styles>
+ <office:master-styles>
+ <style:master-page style:name="Standard" style:page-layout-name="pm1"/>
+ </office:master-styles>
+ <office:body>
+ <office:text>
+ <text:h text:style-name="Heading_20_1" text:outline-level="1">Heading 1</text:h>
+ <text:p>Text Body<text:span text:style-name="Blue_20_Source_20_Text">blue</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 f2df54d0e1b0..9658d79f48b9 100644
--- a/writerperfect/source/writer/exp/txtparai.cxx
+++ b/writerperfect/source/writer/exp/txtparai.cxx
@@ -17,32 +17,52 @@ using namespace com::sun::star;
namespace
{
-/// Looks for rName in rAutomaticStyles (and failing that, in rNamedStyles) and fills rPropertyList based on that.
+/// Looks for rName in rAutomaticStyles (and failing that, in rNamedStyles) and
+/// fills rPropertyList based on that.
+void FillStyles(const OUString &rName,
+ std::map<OUString, librevenge::RVNGPropertyList> &rAutomaticStyles,
+ std::map<OUString, librevenge::RVNGPropertyList> &rNamedStyles,
+ librevenge::RVNGPropertyList &rPropertyList);
+
+/// Looks for rName in rStyles and fills rPropertyList based on that
+/// (rAutomaticStyles and rNamedStyles are a list of possible parents).
void FillStyle(const OUString &rName,
- std::map<OUString, librevenge::RVNGPropertyList> &rNamedStyles,
+ std::map<OUString, librevenge::RVNGPropertyList> &rStyles,
std::map<OUString, librevenge::RVNGPropertyList> &rAutomaticStyles,
+ std::map<OUString, librevenge::RVNGPropertyList> &rNamedStyles,
librevenge::RVNGPropertyList &rPropertyList)
{
- auto itStyle = rAutomaticStyles.find(rName);
- if (itStyle != rAutomaticStyles.end())
- {
- // Apply properties from automatic style.
- librevenge::RVNGPropertyList::Iter itProp(itStyle->second);
- for (itProp.rewind(); itProp.next();)
- rPropertyList.insert(itProp.key(), itProp()->clone());
+ auto itStyle = rStyles.find(rName);
+ if (itStyle == rStyles.end())
return;
+
+ const librevenge::RVNGPropertyList &rStyle = itStyle->second;
+ if (rStyle["style:parent-style-name"])
+ {
+ // Style has a parent.
+ OUString aParent = OStringToOUString(rStyle["style:parent-style-name"]->getStr().cstr(), RTL_TEXTENCODING_UTF8);
+ if (!aParent.isEmpty())
+ FillStyles(aParent, rAutomaticStyles, rNamedStyles, rPropertyList);
}
- itStyle = rNamedStyles.find(rName);
- if (itStyle != rNamedStyles.end())
+ // Apply properties from named style.
+ librevenge::RVNGPropertyList::Iter itProp(rStyle);
+ for (itProp.rewind(); itProp.next();)
{
- // Apply properties from named style.
- librevenge::RVNGPropertyList::Iter itProp(itStyle->second);
- for (itProp.rewind(); itProp.next();)
+ if (OString("style:parent-style-name") != itProp.key())
rPropertyList.insert(itProp.key(), itProp()->clone());
}
}
+void FillStyles(const OUString &rName,
+ std::map<OUString, librevenge::RVNGPropertyList> &rAutomaticStyles,
+ std::map<OUString, librevenge::RVNGPropertyList> &rNamedStyles,
+ librevenge::RVNGPropertyList &rPropertyList)
+{
+ FillStyle(rName, rAutomaticStyles, rAutomaticStyles, rNamedStyles, rPropertyList);
+ FillStyle(rName, rNamedStyles, rAutomaticStyles, rNamedStyles, rPropertyList);
+}
+
}
namespace writerperfect
@@ -83,7 +103,7 @@ void XMLSpanContext::startElement(const OUString &/*rName*/, const css::uno::Ref
const OUString &rAttributeName = xAttribs->getNameByIndex(i);
const OUString &rAttributeValue = xAttribs->getValueByIndex(i);
if (rAttributeName == "text:style-name")
- FillStyle(rAttributeValue, mrImport.GetAutomaticTextStyles(), mrImport.GetTextStyles(), aPropertyList);
+ FillStyles(rAttributeValue, mrImport.GetAutomaticTextStyles(), mrImport.GetTextStyles(), aPropertyList);
else
{
OString sName = OUStringToOString(rAttributeName, RTL_TEXTENCODING_UTF8);
@@ -174,7 +194,7 @@ void XMLParaContext::startElement(const OUString &/*rName*/, const css::uno::Ref
if (rAttributeName == "text:style-name")
{
m_aStyleName = rAttributeValue;
- FillStyle(m_aStyleName, mrImport.GetAutomaticParagraphStyles(), mrImport.GetParagraphStyles(), aPropertyList);
+ FillStyles(m_aStyleName, mrImport.GetAutomaticParagraphStyles(), mrImport.GetParagraphStyles(), aPropertyList);
}
else
{
@@ -196,7 +216,7 @@ void XMLParaContext::characters(const OUString &rChars)
{
librevenge::RVNGPropertyList aPropertyList;
if (!m_aStyleName.isEmpty())
- FillStyle(m_aStyleName, mrImport.GetAutomaticTextStyles(), mrImport.GetTextStyles(), aPropertyList);
+ FillStyles(m_aStyleName, mrImport.GetAutomaticTextStyles(), mrImport.GetTextStyles(), aPropertyList);
mrImport.GetGenerator().openSpan(aPropertyList);
OString sCharU8 = OUStringToOString(rChars, RTL_TEXTENCODING_UTF8);
diff --git a/writerperfect/source/writer/exp/txtstyli.cxx b/writerperfect/source/writer/exp/txtstyli.cxx
index a3e8395d4b43..420651a1ddb0 100644
--- a/writerperfect/source/writer/exp/txtstyli.cxx
+++ b/writerperfect/source/writer/exp/txtstyli.cxx
@@ -95,10 +95,17 @@ void XMLStyleContext::startElement(const OUString &/*rName*/, const css::uno::Re
for (sal_Int16 i = 0; i < xAttribs->getLength(); ++i)
{
const OUString &rAttributeName = xAttribs->getNameByIndex(i);
+ const OUString &rAttributeValue = xAttribs->getValueByIndex(i);
if (rAttributeName == "style:name")
- m_aName = xAttribs->getValueByIndex(i);
+ m_aName = rAttributeValue;
else if (rAttributeName == "style:family")
- m_aFamily = xAttribs->getValueByIndex(i);
+ m_aFamily = rAttributeValue;
+
+ // Remember properties of the style itself, e.g. parent name.
+ OString sName = OUStringToOString(rAttributeName, RTL_TEXTENCODING_UTF8);
+ OString sValue = OUStringToOString(rAttributeValue, RTL_TEXTENCODING_UTF8);
+ m_aTextPropertyList.insert(sName.getStr(), sValue.getStr());
+ m_aParagraphPropertyList.insert(sName.getStr(), sValue.getStr());
}
}