EPUB export: handle paragraph properties from paragraph styles

This adds support for inheriting paragraph properties from named
paragraph styles.

Change-Id: I3cb787f6704329a5e0d11d3cd0266254749ac5ae
Reviewed-on: https://gerrit.libreoffice.org/41938
Reviewed-by: Miklos Vajna <vmiklos@collabora.co.uk>
Tested-by: Jenkins <ci@libreoffice.org>
diff --git a/writerperfect/qa/unit/EPUBExportTest.cxx b/writerperfect/qa/unit/EPUBExportTest.cxx
index 61a6da2..5163c72 100644
--- a/writerperfect/qa/unit/EPUBExportTest.cxx
+++ b/writerperfect/qa/unit/EPUBExportTest.cxx
@@ -54,6 +54,7 @@ public:
    void testSpanAutostyle();
    void testParaAutostyleCharProps();
    void testMeta();
    void testParaNamedstyle();

    CPPUNIT_TEST_SUITE(EPUBExportTest);
    CPPUNIT_TEST(testOutlineLevel);
@@ -63,6 +64,7 @@ public:
    CPPUNIT_TEST(testSpanAutostyle);
    CPPUNIT_TEST(testParaAutostyleCharProps);
    CPPUNIT_TEST(testMeta);
    CPPUNIT_TEST(testParaNamedstyle);
    CPPUNIT_TEST_SUITE_END();
};

@@ -215,6 +217,16 @@ void EPUBExportTest::testMeta()
    assertXPathContent(mpXmlDoc, "/opf:package/opf:metadata/dc:title", "Title");
}

void EPUBExportTest::testParaNamedstyle()
{
    createDoc("para-namedstyle.fodt", {});

    mpXmlDoc = parseExport("OEBPS/sections/section0001.xhtml");
    assertXPath(mpXmlDoc, "//xhtml:p[1]", "class", "para0");
    // This failed, paragraph properties from style were not exported.
    assertXPath(mpXmlDoc, "//xhtml:p[2]", "class", "para1");
}

CPPUNIT_TEST_SUITE_REGISTRATION(EPUBExportTest);

}
diff --git a/writerperfect/qa/unit/data/writer/epubexport/para-namedstyle.fodt b/writerperfect/qa/unit/data/writer/epubexport/para-namedstyle.fodt
new file mode 100644
index 0000000..887a5c1
--- /dev/null
+++ b/writerperfect/qa/unit/data/writer/epubexport/para-namedstyle.fodt
@@ -0,0 +1,18 @@
<?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 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>
  </office:styles>
  <office:body>
    <office:text>
      <text:h text:style-name="Heading" text:outline-level="1">Heading</text:h>
      <text:p>Text Body</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 293fb10..b812549 100644
--- a/writerperfect/source/writer/exp/txtparai.cxx
+++ b/writerperfect/source/writer/exp/txtparai.cxx
@@ -156,13 +156,23 @@ void XMLParaContext::startElement(const OUString &/*rName*/, const css::uno::Ref

            // Reference to an automatic style, try to look it up.
            auto itStyle = mrImport.GetAutomaticParagraphStyles().find(m_aStyleName);
            if (itStyle == mrImport.GetAutomaticParagraphStyles().end())
            if (itStyle != mrImport.GetAutomaticParagraphStyles().end())
            {
                // Found an automatic paragraph style.
                librevenge::RVNGPropertyList::Iter itProp(itStyle->second);
                for (itProp.rewind(); itProp.next();)
                    aPropertyList.insert(itProp.key(), itProp()->clone());
                continue;
            }

            // Found an automatic paragraph style.
            librevenge::RVNGPropertyList::Iter itProp(itStyle->second);
            for (itProp.rewind(); itProp.next();)
                aPropertyList.insert(itProp.key(), itProp()->clone());
            itStyle = mrImport.GetParagraphStyles().find(m_aStyleName);
            if (itStyle != mrImport.GetParagraphStyles().end())
            {
                // Found a paragraph style.
                librevenge::RVNGPropertyList::Iter itProp(itStyle->second);
                for (itProp.rewind(); itProp.next();)
                    aPropertyList.insert(itProp.key(), itProp()->clone());
            }
        }
        else
        {
diff --git a/writerperfect/source/writer/exp/txtstyli.cxx b/writerperfect/source/writer/exp/txtstyli.cxx
index 49c2ccd..a3e8395 100644
--- a/writerperfect/source/writer/exp/txtstyli.cxx
+++ b/writerperfect/source/writer/exp/txtstyli.cxx
@@ -9,6 +9,7 @@

#include "txtstyli.hxx"

#include "xmlfmt.hxx"
#include "xmlimp.hxx"

using namespace com::sun::star;
@@ -74,8 +75,9 @@ void XMLTextPropertiesContext::startElement(const OUString &/*rName*/, const css
    }
}

XMLStyleContext::XMLStyleContext(XMLImport &rImport)
    : XMLImportContext(rImport)
XMLStyleContext::XMLStyleContext(XMLImport &rImport, XMLStylesContext &rStyles)
    : XMLImportContext(rImport),
      m_rStyles(rStyles)
{
}

@@ -106,9 +108,9 @@ void XMLStyleContext::endElement(const OUString &/*rName*/)
        return;

    if (m_aFamily == "text" || m_aFamily == "paragraph")
        mrImport.GetAutomaticTextStyles()[m_aName] = m_aTextPropertyList;
        m_rStyles.GetCurrentTextStyles()[m_aName] = m_aTextPropertyList;
    if (m_aFamily == "paragraph")
        mrImport.GetAutomaticParagraphStyles()[m_aName] = m_aParagraphPropertyList;
        m_rStyles.GetCurrentParagraphStyles()[m_aName] = m_aParagraphPropertyList;
}

librevenge::RVNGPropertyList &XMLStyleContext::GetTextPropertyList()
diff --git a/writerperfect/source/writer/exp/txtstyli.hxx b/writerperfect/source/writer/exp/txtstyli.hxx
index af9d1bb..83ffd78 100644
--- a/writerperfect/source/writer/exp/txtstyli.hxx
+++ b/writerperfect/source/writer/exp/txtstyli.hxx
@@ -19,11 +19,13 @@ namespace writerperfect
namespace exp
{

class XMLStylesContext;

/// Handler for <style:style>.
class XMLStyleContext : public XMLImportContext
{
public:
    XMLStyleContext(XMLImport &rImport);
    XMLStyleContext(XMLImport &rImport, XMLStylesContext &rStyles);

    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;
@@ -37,6 +39,7 @@ private:
    OUString m_aFamily;
    librevenge::RVNGPropertyList m_aTextPropertyList;
    librevenge::RVNGPropertyList m_aParagraphPropertyList;
    XMLStylesContext &m_rStyles;
};

} // namespace exp
diff --git a/writerperfect/source/writer/exp/xmlfmt.cxx b/writerperfect/source/writer/exp/xmlfmt.cxx
index 64fe313..b331728 100644
--- a/writerperfect/source/writer/exp/xmlfmt.cxx
+++ b/writerperfect/source/writer/exp/xmlfmt.cxx
@@ -19,18 +19,30 @@ namespace writerperfect
namespace exp
{

XMLAutomaticStylesContext::XMLAutomaticStylesContext(XMLImport &rImport)
    : XMLImportContext(rImport)
XMLStylesContext::XMLStylesContext(XMLImport &rImport, std::map<OUString, librevenge::RVNGPropertyList> &rParagraphStyles, std::map<OUString, librevenge::RVNGPropertyList> &rTextStyles)
    : XMLImportContext(rImport),
      m_rParagraphStyles(rParagraphStyles),
      m_rTextStyles(rTextStyles)
{
}

XMLImportContext *XMLAutomaticStylesContext::CreateChildContext(const OUString &rName, const css::uno::Reference<css::xml::sax::XAttributeList> &/*xAttribs*/)
XMLImportContext *XMLStylesContext::CreateChildContext(const OUString &rName, const css::uno::Reference<css::xml::sax::XAttributeList> &/*xAttribs*/)
{
    if (rName == "style:style")
        return new XMLStyleContext(mrImport);
        return new XMLStyleContext(mrImport, *this);
    return nullptr;
}

std::map<OUString, librevenge::RVNGPropertyList> &XMLStylesContext::GetCurrentParagraphStyles()
{
    return m_rParagraphStyles;
}

std::map<OUString, librevenge::RVNGPropertyList> &XMLStylesContext::GetCurrentTextStyles()
{
    return m_rTextStyles;
}

} // namespace exp
} // namespace writerperfect

diff --git a/writerperfect/source/writer/exp/xmlfmt.hxx b/writerperfect/source/writer/exp/xmlfmt.hxx
index 1ace95b..394be55 100644
--- a/writerperfect/source/writer/exp/xmlfmt.hxx
+++ b/writerperfect/source/writer/exp/xmlfmt.hxx
@@ -10,6 +10,8 @@
#ifndef INCLUDED_WRITERPERFECT_SOURCE_WRITER_EXP_XMLFMT_HXX
#define INCLUDED_WRITERPERFECT_SOURCE_WRITER_EXP_XMLFMT_HXX

#include <map>

#include <librevenge/librevenge.h>

#include "xmlictxt.hxx"
@@ -19,13 +21,19 @@ namespace writerperfect
namespace exp
{

/// Handler for <office:automatic-styles>.
class XMLAutomaticStylesContext : public XMLImportContext
/// Handler for <office:automatic-styles>/<office:styles>.
class XMLStylesContext : public XMLImportContext
{
public:
    XMLAutomaticStylesContext(XMLImport &rImport);
    XMLStylesContext(XMLImport &rImport, std::map<OUString, librevenge::RVNGPropertyList> &rParagraphStyles, std::map<OUString, librevenge::RVNGPropertyList> &rTextStyles);

    XMLImportContext *CreateChildContext(const OUString &rName, const css::uno::Reference<css::xml::sax::XAttributeList> &xAttribs) override;

    std::map<OUString, librevenge::RVNGPropertyList> &GetCurrentParagraphStyles();
    std::map<OUString, librevenge::RVNGPropertyList> &GetCurrentTextStyles();
private:
    std::map<OUString, librevenge::RVNGPropertyList> &m_rParagraphStyles;
    std::map<OUString, librevenge::RVNGPropertyList> &m_rTextStyles;
};

} // namespace exp
diff --git a/writerperfect/source/writer/exp/xmlimp.cxx b/writerperfect/source/writer/exp/xmlimp.cxx
index 5c95efb..2370399e 100644
--- a/writerperfect/source/writer/exp/xmlimp.cxx
+++ b/writerperfect/source/writer/exp/xmlimp.cxx
@@ -63,7 +63,9 @@ XMLImportContext *XMLOfficeDocContext::CreateChildContext(const OUString &rName,
    else if (rName == "office:meta")
        return new XMLMetaDocumentContext(mrImport);
    else if (rName == "office:automatic-styles")
        return new XMLAutomaticStylesContext(mrImport);
        return new XMLStylesContext(mrImport, mrImport.GetAutomaticParagraphStyles(), mrImport.GetAutomaticTextStyles());
    else if (rName == "office:styles")
        return new XMLStylesContext(mrImport, mrImport.GetParagraphStyles(), mrImport.GetTextStyles());
    return nullptr;
}

@@ -94,6 +96,16 @@ std::map<OUString, librevenge::RVNGPropertyList> &XMLImport::GetAutomaticParagra
    return maAutomaticParagraphStyles;
}

std::map<OUString, librevenge::RVNGPropertyList> &XMLImport::GetTextStyles()
{
    return maTextStyles;
}

std::map<OUString, librevenge::RVNGPropertyList> &XMLImport::GetParagraphStyles()
{
    return maParagraphStyles;
}

void XMLImport::startDocument()
{
    mrGenerator.startDocument(librevenge::RVNGPropertyList());
diff --git a/writerperfect/source/writer/exp/xmlimp.hxx b/writerperfect/source/writer/exp/xmlimp.hxx
index ed63503..128a88c 100644
--- a/writerperfect/source/writer/exp/xmlimp.hxx
+++ b/writerperfect/source/writer/exp/xmlimp.hxx
@@ -36,7 +36,9 @@ class XMLImport : public cppu::WeakImplHelper
    librevenge::RVNGTextInterface &mrGenerator;
    std::stack< rtl::Reference<XMLImportContext> > maContexts;
    std::map<OUString, librevenge::RVNGPropertyList> maAutomaticTextStyles;
    std::map<OUString, librevenge::RVNGPropertyList> maTextStyles;
    std::map<OUString, librevenge::RVNGPropertyList> maAutomaticParagraphStyles;
    std::map<OUString, librevenge::RVNGPropertyList> maParagraphStyles;

public:
    XMLImport(librevenge::RVNGTextInterface &rGenerator);
@@ -46,6 +48,8 @@ public:
    librevenge::RVNGTextInterface &GetGenerator() const;
    std::map<OUString, librevenge::RVNGPropertyList> &GetAutomaticTextStyles();
    std::map<OUString, librevenge::RVNGPropertyList> &GetAutomaticParagraphStyles();
    std::map<OUString, librevenge::RVNGPropertyList> &GetTextStyles();
    std::map<OUString, librevenge::RVNGPropertyList> &GetParagraphStyles();

    // XDocumentHandler
    void SAL_CALL startDocument() override;