diff options
author | Miklos Vajna <vmiklos@collabora.co.uk> | 2017-09-06 15:35:40 +0200 |
---|---|---|
committer | Miklos Vajna <vmiklos@collabora.co.uk> | 2017-09-06 18:08:55 +0200 |
commit | fe4c6063ec493c986f810ba676e2b12fe7dab7a9 (patch) | |
tree | 956e97b7005bca48cffe953676a3e1211a088c68 /writerperfect | |
parent | ac38af2bb850abab0039d7c9e35644752cf4feb1 (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.cxx | 41 | ||||
-rw-r--r-- | writerperfect/qa/unit/data/writer/epubexport/named-style-inheritance.fodt | 39 | ||||
-rw-r--r-- | writerperfect/source/writer/exp/txtparai.cxx | 54 | ||||
-rw-r--r-- | writerperfect/source/writer/exp/txtstyli.cxx | 11 |
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="'Liberation Mono'" style:font-family-generic="modern" style:font-pitch="fixed"/> + <style:font-face style:name="Liberation Serif" svg:font-family="'Liberation Serif'" style:font-family-generic="roman" style:font-pitch="variable"/> + <style:font-face style:name="Liberation Sans" svg:font-family="'Liberation Sans'" 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="'Liberation Sans'" 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="'Liberation Mono'" 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()); } } |