summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--external/libepubgen/libepubgen-epub3.patch.1556
-rw-r--r--writerperfect/Library_wpftwriter.mk1
-rw-r--r--writerperfect/qa/unit/EPUBExportTest.cxx12
-rw-r--r--writerperfect/qa/unit/data/writer/epubexport/footnote.fodt8
-rw-r--r--writerperfect/source/writer/exp/XMLFootnoteImportContext.cxx121
-rw-r--r--writerperfect/source/writer/exp/XMLFootnoteImportContext.hxx44
-rw-r--r--writerperfect/source/writer/exp/txtparai.cxx4
7 files changed, 746 insertions, 0 deletions
diff --git a/external/libepubgen/libepubgen-epub3.patch.1 b/external/libepubgen/libepubgen-epub3.patch.1
index 39bac59c51ff..28f9c3771708 100644
--- a/external/libepubgen/libepubgen-epub3.patch.1
+++ b/external/libepubgen/libepubgen-epub3.patch.1
@@ -4497,3 +4497,559 @@ index 62dac6e..1cb1112 100644
--
2.13.6
+From 8c447caee18b4400170ecce36ea3714fdc377989 Mon Sep 17 00:00:00 2001
+From: Miklos Vajna <vmiklos@collabora.co.uk>
+Date: Thu, 23 Nov 2017 16:42:13 +0100
+Subject: [PATCH 1/4] EPUBHTMLGenerator: fix footnotes/endnotes/comments
+
+There were two problems here:
+
+- when working with two sinks (footnote and main), make sure that we
+ save the main one before the push of the sink stack
+
+- when handing out a non-const xml sink reference, make sure there is no
+ parallel empty bool that tracks its size, otherwise these can out of
+ sync (empty is still true, even if there is footnote content)
+---
+ src/lib/EPUBHTMLGenerator.cpp | 24 +++++++-----------------
+ src/lib/EPUBXMLSink.cpp | 5 +++++
+ src/lib/EPUBXMLSink.h | 2 ++
+ src/test/EPUBTextGeneratorTest.cpp | 24 ++++++++++++++++++++++++
+ 4 files changed, 38 insertions(+), 17 deletions(-)
+
+diff --git a/src/lib/EPUBHTMLGenerator.cpp b/src/lib/EPUBHTMLGenerator.cpp
+index 614dd02..3c8862b 100644
+--- a/src/lib/EPUBHTMLGenerator.cpp
++++ b/src/lib/EPUBHTMLGenerator.cpp
+@@ -51,20 +51,16 @@ public:
+ const EPUBXMLSink &get() const;
+ EPUBXMLSink &get();
+
+- bool empty() const;
+-
+ bool endsInLineBreak() const;
+
+ private:
+ EPUBXMLSink m_sink;
+ std::string m_lastCloseElement;
+- bool m_empty;
+ };
+
+ ZoneSinkImpl::ZoneSinkImpl()
+ : m_sink()
+ , m_lastCloseElement()
+- , m_empty(true)
+ {
+ }
+
+@@ -72,28 +68,24 @@ void ZoneSinkImpl::openElement(const char *const name, const librevenge::RVNGPro
+ {
+ m_sink.openElement(name, attributes);
+ m_lastCloseElement.clear();
+- m_empty = false;
+ }
+
+ void ZoneSinkImpl::closeElement(const char *const name)
+ {
+ m_sink.closeElement(name);
+ m_lastCloseElement = name;
+- m_empty = false;
+ }
+
+ void ZoneSinkImpl::insertCharacters(const librevenge::RVNGString &characters)
+ {
+ m_sink.insertCharacters(characters);
+ m_lastCloseElement.clear();
+- m_empty = false;
+ }
+
+ void ZoneSinkImpl::append(const ZoneSinkImpl &other)
+ {
+ m_sink.append(other.m_sink);
+ m_lastCloseElement = other.m_lastCloseElement;
+- m_empty |= other.m_empty;
+ }
+
+ const EPUBXMLSink &ZoneSinkImpl::get() const
+@@ -106,11 +98,6 @@ EPUBXMLSink &ZoneSinkImpl::get()
+ return m_sink;
+ }
+
+-bool ZoneSinkImpl::empty() const
+-{
+- return m_empty;
+-}
+-
+ bool ZoneSinkImpl::endsInLineBreak() const
+ {
+ return m_lastCloseElement == "p"
+@@ -154,7 +141,7 @@ struct EPUBHTMLTextZone
+ bool isEmpty() const
+ {
+ for (const auto &zoneSink : m_zoneSinks)
+- if (!zoneSink.empty())
++ if (!zoneSink.get().empty())
+ return false;
+ return true;
+ }
+@@ -791,8 +778,9 @@ void EPUBHTMLGenerator::openFootnote(const RVNGPropertyList &)
+ {
+ if (m_impl->m_ignore)
+ return;
++ EPUBXMLSink &output = m_impl->output();
+ m_impl->push(EPUBHTMLTextZone::Z_FootNote);
+- m_impl->getSink().addLabel(m_impl->output());
++ m_impl->getSink().addLabel(output);
+ }
+
+ void EPUBHTMLGenerator::closeFootnote()
+@@ -806,8 +794,9 @@ void EPUBHTMLGenerator::openEndnote(const RVNGPropertyList &)
+ {
+ if (m_impl->m_ignore)
+ return;
++ EPUBXMLSink &output = m_impl->output();
+ m_impl->push(EPUBHTMLTextZone::Z_EndNote);
+- m_impl->getSink().addLabel(m_impl->output());
++ m_impl->getSink().addLabel(output);
+ }
+
+ void EPUBHTMLGenerator::closeEndnote()
+@@ -821,8 +810,9 @@ void EPUBHTMLGenerator::openComment(const RVNGPropertyList & /*propList*/)
+ {
+ if (m_impl->m_ignore)
+ return;
++ EPUBXMLSink &output = m_impl->output();
+ m_impl->push(EPUBHTMLTextZone::Z_Comment);
+- m_impl->getSink().addLabel(m_impl->output());
++ m_impl->getSink().addLabel(output);
+ }
+
+ void EPUBHTMLGenerator::closeComment()
+diff --git a/src/lib/EPUBXMLSink.cpp b/src/lib/EPUBXMLSink.cpp
+index 7c12c6d..db480d7 100644
+--- a/src/lib/EPUBXMLSink.cpp
++++ b/src/lib/EPUBXMLSink.cpp
+@@ -155,6 +155,11 @@ void EPUBXMLSink::append(const EPUBXMLSink &other)
+ m_elements.insert(m_elements.end(), other.m_elements.begin(), other.m_elements.end());
+ }
+
++bool EPUBXMLSink::empty() const
++{
++ return m_elements.empty();
++}
++
+ void EPUBXMLSink::writeTo(EPUBPackage &package, const char *const name)
+ {
+ package.openXMLFile(name);
+diff --git a/src/lib/EPUBXMLSink.h b/src/lib/EPUBXMLSink.h
+index ea7ac7a..a2bf951 100644
+--- a/src/lib/EPUBXMLSink.h
++++ b/src/lib/EPUBXMLSink.h
+@@ -40,6 +40,8 @@ public:
+
+ void writeTo(EPUBPackage &package, const char *name);
+
++ bool empty() const;
++
+ private:
+ std::deque<EPUBXMLElementPtr_t> m_elements;
+ };
+--
+2.13.6
+
+
+From 9c723bbe42673906d8d0faf5083a186cf86d05ce Mon Sep 17 00:00:00 2001
+From: Miklos Vajna <vmiklos@collabora.co.uk>
+Date: Thu, 23 Nov 2017 17:27:00 +0100
+Subject: [PATCH 2/4] EPUBHTMLGenerator: avoid <title> in EPUB3 XHTML content
+ documents
+
+- there were multiple of them, which is invalid
+- just don't write them, content.opf has the same info
+---
+ src/lib/EPUBGenerator.cpp | 2 +-
+ src/lib/EPUBHTMLGenerator.cpp | 18 ++++++++++++------
+ src/lib/EPUBHTMLGenerator.h | 2 +-
+ src/lib/EPUBHTMLManager.cpp | 4 ++--
+ src/lib/EPUBHTMLManager.h | 2 +-
+ src/test/EPUBTextGeneratorTest.cpp | 5 ++++-
+ 6 files changed, 21 insertions(+), 12 deletions(-)
+
+diff --git a/src/lib/EPUBGenerator.cpp b/src/lib/EPUBGenerator.cpp
+index 1cb1112..571f0eb 100644
+--- a/src/lib/EPUBGenerator.cpp
++++ b/src/lib/EPUBGenerator.cpp
+@@ -117,7 +117,7 @@ void EPUBGenerator::startNewHtmlFile()
+
+ m_splitGuard.onSplit();
+
+- m_currentHtml = m_htmlManager.create(m_imageManager, m_fontManager, m_listStyleManager, m_paragraphStyleManager, m_spanStyleManager, m_tableStyleManager, m_stylesheetPath, m_stylesMethod);
++ m_currentHtml = m_htmlManager.create(m_imageManager, m_fontManager, m_listStyleManager, m_paragraphStyleManager, m_spanStyleManager, m_tableStyleManager, m_stylesheetPath, m_stylesMethod, m_version);
+
+ // restore state in the new file
+ m_currentHtml->startDocument(m_documentProps);
+diff --git a/src/lib/EPUBHTMLGenerator.cpp b/src/lib/EPUBHTMLGenerator.cpp
+index 3c8862b..209e7e1 100644
+--- a/src/lib/EPUBHTMLGenerator.cpp
++++ b/src/lib/EPUBHTMLGenerator.cpp
+@@ -338,7 +338,7 @@ std::string EPUBHTMLTextZone::label(int id) const
+ struct EPUBHTMLGeneratorImpl
+ {
+ //! constructor
+- EPUBHTMLGeneratorImpl(EPUBXMLSink &document, EPUBImageManager &imageManager, EPUBFontManager &fontManager, EPUBListStyleManager &listStyleManager, EPUBParagraphStyleManager &paragraphStyleManager, EPUBSpanStyleManager &spanStyleManager, EPUBTableStyleManager &tableStyleManager, const EPUBPath &path, const EPUBPath &stylesheetPath, EPUBStylesMethod stylesMethod)
++ EPUBHTMLGeneratorImpl(EPUBXMLSink &document, EPUBImageManager &imageManager, EPUBFontManager &fontManager, EPUBListStyleManager &listStyleManager, EPUBParagraphStyleManager &paragraphStyleManager, EPUBSpanStyleManager &spanStyleManager, EPUBTableStyleManager &tableStyleManager, const EPUBPath &path, const EPUBPath &stylesheetPath, EPUBStylesMethod stylesMethod, int version)
+ : m_document(document)
+ , m_imageManager(imageManager)
+ , m_fontManager(fontManager)
+@@ -351,6 +351,7 @@ struct EPUBHTMLGeneratorImpl
+ , m_actualPage(0)
+ , m_ignore(false)
+ , m_hasText(false)
++ , m_version(version)
+ , m_frameAnchorTypes()
+ , m_framePropertiesStack()
+ , m_stylesMethod(stylesMethod)
+@@ -442,6 +443,7 @@ struct EPUBHTMLGeneratorImpl
+ bool m_ignore;
+ /// Does the currently opened paragraph have some text?
+ bool m_hasText;
++ int m_version;
+
+ std::stack<std::string> m_frameAnchorTypes;
+ std::stack<RVNGPropertyList> m_framePropertiesStack;
+@@ -458,8 +460,8 @@ private:
+ EPUBHTMLGeneratorImpl operator=(EPUBHTMLGeneratorImpl const &orig);
+ };
+
+-EPUBHTMLGenerator::EPUBHTMLGenerator(EPUBXMLSink &document, EPUBImageManager &imageManager, EPUBFontManager &fontManager, EPUBListStyleManager &listStyleManager, EPUBParagraphStyleManager &paragraphStyleManager, EPUBSpanStyleManager &spanStyleManager, EPUBTableStyleManager &tableStyleManager, const EPUBPath &path, const EPUBPath &stylesheetPath, EPUBStylesMethod stylesMethod)
+- : m_impl(new EPUBHTMLGeneratorImpl(document, imageManager, fontManager, listStyleManager, paragraphStyleManager, spanStyleManager, tableStyleManager, path, stylesheetPath, stylesMethod))
++EPUBHTMLGenerator::EPUBHTMLGenerator(EPUBXMLSink &document, EPUBImageManager &imageManager, EPUBFontManager &fontManager, EPUBListStyleManager &listStyleManager, EPUBParagraphStyleManager &paragraphStyleManager, EPUBSpanStyleManager &spanStyleManager, EPUBTableStyleManager &tableStyleManager, const EPUBPath &path, const EPUBPath &stylesheetPath, EPUBStylesMethod stylesMethod, int version)
++ : m_impl(new EPUBHTMLGeneratorImpl(document, imageManager, fontManager, listStyleManager, paragraphStyleManager, spanStyleManager, tableStyleManager, path, stylesheetPath, stylesMethod, version))
+ {
+ }
+
+@@ -509,14 +511,18 @@ void EPUBHTMLGenerator::endDocument()
+ htmlAttrs.insert("xmlns", "http://www.w3.org/1999/xhtml");
+ m_impl->m_document.openElement("html", htmlAttrs);
+ m_impl->m_document.openElement("head", RVNGPropertyList());
+- m_impl->m_document.openElement("title", RVNGPropertyList());
+- m_impl->m_document.closeElement("title");
++ if (m_impl->m_version != 30)
++ {
++ m_impl->m_document.openElement("title", RVNGPropertyList());
++ m_impl->m_document.closeElement("title");
++ }
+ RVNGPropertyList metaAttrs;
+ metaAttrs.insert("http-equiv", "content-type");
+ metaAttrs.insert("content", "text/html; charset=UTF-8");
+ m_impl->m_document.openElement("meta", metaAttrs);
+ m_impl->m_document.closeElement("meta");
+- m_impl->sendMetaData(m_impl->m_document);
++ if (m_impl->m_version != 30)
++ m_impl->sendMetaData(m_impl->m_document);
+ RVNGPropertyList linkAttrs;
+ linkAttrs.insert("href", m_impl->m_stylesheetPath.relativeTo(m_impl->m_path).str().c_str());
+ linkAttrs.insert("type", "text/css");
+diff --git a/src/lib/EPUBHTMLGenerator.h b/src/lib/EPUBHTMLGenerator.h
+index 49f76a3..11f20cb 100644
+--- a/src/lib/EPUBHTMLGenerator.h
++++ b/src/lib/EPUBHTMLGenerator.h
+@@ -31,7 +31,7 @@ class EPUBPath;
+ class EPUBHTMLGenerator : public librevenge::RVNGTextInterface
+ {
+ public:
+- EPUBHTMLGenerator(EPUBXMLSink &document, EPUBImageManager &imageManager, EPUBFontManager &fontManager, EPUBListStyleManager &listStyleManager, EPUBParagraphStyleManager &paragraphStyleManager, EPUBSpanStyleManager &spanStyleManager, EPUBTableStyleManager &tableStyleManager, const EPUBPath &path, const EPUBPath &stylesheetPath, EPUBStylesMethod stylesMethod);
++ EPUBHTMLGenerator(EPUBXMLSink &document, EPUBImageManager &imageManager, EPUBFontManager &fontManager, EPUBListStyleManager &listStyleManager, EPUBParagraphStyleManager &paragraphStyleManager, EPUBSpanStyleManager &spanStyleManager, EPUBTableStyleManager &tableStyleManager, const EPUBPath &path, const EPUBPath &stylesheetPath, EPUBStylesMethod stylesMethod, int version);
+ ~EPUBHTMLGenerator() override;
+
+ void setDocumentMetaData(const librevenge::RVNGPropertyList &propList) override;
+diff --git a/src/lib/EPUBHTMLManager.cpp b/src/lib/EPUBHTMLManager.cpp
+index 9d4c507..d2c21da 100644
+--- a/src/lib/EPUBHTMLManager.cpp
++++ b/src/lib/EPUBHTMLManager.cpp
+@@ -41,7 +41,7 @@ EPUBHTMLManager::EPUBHTMLManager(EPUBManifest &manifest)
+ {
+ }
+
+-const EPUBHTMLGeneratorPtr_t EPUBHTMLManager::create(EPUBImageManager &imageManager, EPUBFontManager &fontManager, EPUBListStyleManager &listStyleManager, EPUBParagraphStyleManager &paragraphStyleManager, EPUBSpanStyleManager &spanStyleManager, EPUBTableStyleManager &tableStyleManager, const EPUBPath &stylesheetPath, EPUBStylesMethod stylesMethod)
++const EPUBHTMLGeneratorPtr_t EPUBHTMLManager::create(EPUBImageManager &imageManager, EPUBFontManager &fontManager, EPUBListStyleManager &listStyleManager, EPUBParagraphStyleManager &paragraphStyleManager, EPUBSpanStyleManager &spanStyleManager, EPUBTableStyleManager &tableStyleManager, const EPUBPath &stylesheetPath, EPUBStylesMethod stylesMethod, int version)
+ {
+ std::ostringstream nameBuf;
+ nameBuf << "section" << std::setw(4) << std::setfill('0') << m_number.next();
+@@ -55,7 +55,7 @@ const EPUBHTMLGeneratorPtr_t EPUBHTMLManager::create(EPUBImageManager &imageMana
+ m_contents.push_back(EPUBXMLSink());
+
+ const EPUBHTMLGeneratorPtr_t gen(
+- new EPUBHTMLGenerator(m_contents.back(), imageManager, fontManager, listStyleManager, paragraphStyleManager, spanStyleManager, tableStyleManager, m_paths.back(), stylesheetPath, stylesMethod));
++ new EPUBHTMLGenerator(m_contents.back(), imageManager, fontManager, listStyleManager, paragraphStyleManager, spanStyleManager, tableStyleManager, m_paths.back(), stylesheetPath, stylesMethod, version));
+
+ return gen;
+ }
+diff --git a/src/lib/EPUBHTMLManager.h b/src/lib/EPUBHTMLManager.h
+index ef56a52..e1205e6 100644
+--- a/src/lib/EPUBHTMLManager.h
++++ b/src/lib/EPUBHTMLManager.h
+@@ -41,7 +41,7 @@ class EPUBHTMLManager
+ public:
+ explicit EPUBHTMLManager(EPUBManifest &manifest);
+
+- const EPUBHTMLGeneratorPtr_t create(EPUBImageManager &imageManager, EPUBFontManager &fontManager, EPUBListStyleManager &listStyleManager, EPUBParagraphStyleManager &paragraphStyleManager, EPUBSpanStyleManager &spanStyleManager, EPUBTableStyleManager &tableStyleManager, const EPUBPath &stylesheetPath, EPUBStylesMethod stylesMethod);
++ const EPUBHTMLGeneratorPtr_t create(EPUBImageManager &imageManager, EPUBFontManager &fontManager, EPUBListStyleManager &listStyleManager, EPUBParagraphStyleManager &paragraphStyleManager, EPUBSpanStyleManager &spanStyleManager, EPUBTableStyleManager &tableStyleManager, const EPUBPath &stylesheetPath, EPUBStylesMethod stylesMethod, int version);
+
+ void writeTo(EPUBPackage &package);
+
+--
+2.13.6
+
+
+From 502948041df07729572bf4f2b222e03073baa6c8 Mon Sep 17 00:00:00 2001
+From: Miklos Vajna <vmiklos@collabora.co.uk>
+Date: Fri, 24 Nov 2017 10:29:15 +0100
+Subject: [PATCH 3/4] EPUBHTMLGenerator: implement EPUB3 footnote markup
+
+The main difference is that in the EPUB3 case the footnote has an
+explicit end.
+---
+ src/lib/EPUBHTMLGenerator.cpp | 56 ++++++++++++++++++++++++++++----------
+ src/test/EPUBTextGeneratorTest.cpp | 26 ++++++++++++++++++
+ 2 files changed, 68 insertions(+), 14 deletions(-)
+
+diff --git a/src/lib/EPUBHTMLGenerator.cpp b/src/lib/EPUBHTMLGenerator.cpp
+index 209e7e1..96e7623 100644
+--- a/src/lib/EPUBHTMLGenerator.cpp
++++ b/src/lib/EPUBHTMLGenerator.cpp
+@@ -122,7 +122,7 @@ struct EPUBHTMLTextZone
+ //! the different zone
+ enum Type { Z_Comment=0, Z_EndNote, Z_FootNote, Z_Main, Z_MetaData, Z_TextBox, Z_Unknown, Z_NumZones= Z_Unknown+1};
+ //! constructor for basic stream
+- EPUBHTMLTextZone(Type tp=Z_Unknown) : m_type(tp), m_actualId(0), m_zoneSinks()
++ EPUBHTMLTextZone(Type tp=Z_Unknown) : m_type(tp), m_actualId(0), m_zoneSinks(), m_version(20)
+ {
+ }
+ //! the type
+@@ -135,6 +135,14 @@ struct EPUBHTMLTextZone
+ {
+ m_type=tp;
+ }
++ void setVersion(int version)
++ {
++ m_version = version;
++ }
++ int getVersion() const
++ {
++ return m_version;
++ }
+ //! returns a new sink corresponding to this zone
+ std::unique_ptr<TextZoneSink> getNewSink();
+ //! returns true if there is no data
+@@ -150,7 +158,7 @@ struct EPUBHTMLTextZone
+ {
+ if (isEmpty() || m_type==Z_Unknown || m_type==Z_Main)
+ return;
+- if (m_type!=Z_MetaData)
++ if (m_type!=Z_MetaData && m_version < 30)
+ {
+ out.openElement("hr", RVNGPropertyList());
+ out.closeElement("hr");
+@@ -197,6 +205,7 @@ protected:
+ mutable int m_actualId;
+ //! the list of data string
+ std::vector<ZoneSinkImpl> m_zoneSinks;
++ int m_version;
+ private:
+ EPUBHTMLTextZone(EPUBHTMLTextZone const &orig);
+ EPUBHTMLTextZone operator=(EPUBHTMLTextZone const &orig);
+@@ -218,11 +227,16 @@ struct TextZoneSink
+ std::string lbl=label();
+ if (!lbl.length())
+ return;
++ int version = 20;
++ if (m_zone)
++ version = m_zone->getVersion();
+ {
+ RVNGPropertyList supAttrs;
+ supAttrs.insert("id", ("called" + lbl).c_str());
+ output.openElement("sup", supAttrs);
+ RVNGPropertyList aAttrs;
++ if (version == 30)
++ aAttrs.insert("epub:type", "noteref");
+ aAttrs.insert("href", ("#data" + lbl).c_str());
+ output.openElement("a", aAttrs);
+ output.insertCharacters(lbl.c_str());
+@@ -230,17 +244,23 @@ struct TextZoneSink
+ output.closeElement("sup");
+ }
+ flush();
++ if (version == 30)
+ {
+- RVNGPropertyList supAttrs;
+- supAttrs.insert("id", ("data" + lbl).c_str());
+- m_delayedLabel.openElement("sup", supAttrs);
+- RVNGPropertyList aAttrs;
+- aAttrs.insert("href", ("#called" + lbl).c_str());
+- m_delayedLabel.openElement("a", aAttrs);
+- m_delayedLabel.insertCharacters(lbl.c_str());
+- m_delayedLabel.closeElement("a");
+- m_delayedLabel.closeElement("sup");
++ RVNGPropertyList asideAttrs;
++ asideAttrs.insert("epub:type", "footnote");
++ asideAttrs.insert("id", ("data" + lbl).c_str());
++ m_sink.openElement("aside", asideAttrs);
+ }
++ RVNGPropertyList supAttrs;
++ if (version < 30)
++ supAttrs.insert("id", ("data" + lbl).c_str());
++ m_delayedLabel.openElement("sup", supAttrs);
++ RVNGPropertyList aAttrs;
++ aAttrs.insert("href", ("#called" + lbl).c_str());
++ m_delayedLabel.openElement("a", aAttrs);
++ m_delayedLabel.insertCharacters(lbl.c_str());
++ m_delayedLabel.closeElement("a");
++ m_delayedLabel.closeElement("sup");
+ }
+ //! flush delayed label, ...
+ void flush()
+@@ -359,7 +379,10 @@ struct EPUBHTMLGeneratorImpl
+ , m_sinkStack()
+ {
+ for (int i = 0; i < EPUBHTMLTextZone::Z_NumZones; ++i)
++ {
+ m_zones[i].setType(EPUBHTMLTextZone::Type(i));
++ m_zones[i].setVersion(version);
++ }
+ m_actualSink=m_zones[EPUBHTMLTextZone::Z_Main].getNewSink();
+ }
+ //! destructor
+@@ -511,7 +534,7 @@ void EPUBHTMLGenerator::endDocument()
+ htmlAttrs.insert("xmlns", "http://www.w3.org/1999/xhtml");
+ m_impl->m_document.openElement("html", htmlAttrs);
+ m_impl->m_document.openElement("head", RVNGPropertyList());
+- if (m_impl->m_version != 30)
++ if (m_impl->m_version < 30)
+ {
+ m_impl->m_document.openElement("title", RVNGPropertyList());
+ m_impl->m_document.closeElement("title");
+@@ -521,7 +544,7 @@ void EPUBHTMLGenerator::endDocument()
+ metaAttrs.insert("content", "text/html; charset=UTF-8");
+ m_impl->m_document.openElement("meta", metaAttrs);
+ m_impl->m_document.closeElement("meta");
+- if (m_impl->m_version != 30)
++ if (m_impl->m_version < 30)
+ m_impl->sendMetaData(m_impl->m_document);
+ RVNGPropertyList linkAttrs;
+ linkAttrs.insert("href", m_impl->m_stylesheetPath.relativeTo(m_impl->m_path).str().c_str());
+@@ -529,7 +552,10 @@ void EPUBHTMLGenerator::endDocument()
+ linkAttrs.insert("rel", "stylesheet");
+ m_impl->m_document.insertEmptyElement("link", linkAttrs);
+ m_impl->m_document.closeElement("head");
+- m_impl->m_document.openElement("body", RVNGPropertyList());
++ RVNGPropertyList bodyAttrs;
++ if (m_impl->m_version == 30)
++ bodyAttrs.insert("xmlns:epub", "http://www.idpf.org/2007/ops");
++ m_impl->m_document.openElement("body", bodyAttrs);
+ m_impl->flushUnsent(m_impl->m_document);
+ m_impl->m_document.closeElement("body");
+ m_impl->m_document.closeElement("html");
+@@ -793,6 +819,8 @@ void EPUBHTMLGenerator::closeFootnote()
+ {
+ if (m_impl->m_ignore)
+ return;
++ if (m_impl->m_version == 30)
++ m_impl->output().closeElement("aside");
+ m_impl->pop();
+ }
+
+--
+2.13.6
+
+
+From a8444b113df52769849ad45ea440def8d1884b15 Mon Sep 17 00:00:00 2001
+From: Miklos Vajna <vmiklos@collabora.co.uk>
+Date: Fri, 24 Nov 2017 11:10:34 +0100
+Subject: [PATCH 4/4] EPUBHTMLGenerator: implement custom footnote anchor text
+
+Try to avoid our default F<N> anchor text if possible, which only makes
+sense in English.
+---
+ src/lib/EPUBHTMLGenerator.cpp | 22 +++++++++++++++-------
+ src/test/EPUBTextGeneratorTest.cpp | 25 +++++++++++++++++++++++++
+ 2 files changed, 40 insertions(+), 7 deletions(-)
+
+diff --git a/src/lib/EPUBHTMLGenerator.cpp b/src/lib/EPUBHTMLGenerator.cpp
+index 96e7623..6b4c7c2 100644
+--- a/src/lib/EPUBHTMLGenerator.cpp
++++ b/src/lib/EPUBHTMLGenerator.cpp
+@@ -222,9 +222,14 @@ struct TextZoneSink
+ //! destructor
+ ~TextZoneSink() { }
+ //! add a label called on main and a label in this ( delayed to allow openParagraph to be called )
+- void addLabel(EPUBXMLSink &output)
++ void addLabel(EPUBXMLSink &output, const librevenge::RVNGString &number)
+ {
++ // Unique label, e.g. 'F1' for the first footnote.
+ std::string lbl=label();
++ // User-visible label, e.g. '1'.
++ std::string uiLabel = lbl;
++ if (!number.empty())
++ uiLabel = number.cstr();
+ if (!lbl.length())
+ return;
+ int version = 20;
+@@ -239,7 +244,7 @@ struct TextZoneSink
+ aAttrs.insert("epub:type", "noteref");
+ aAttrs.insert("href", ("#data" + lbl).c_str());
+ output.openElement("a", aAttrs);
+- output.insertCharacters(lbl.c_str());
++ output.insertCharacters(uiLabel.c_str());
+ output.closeElement("a");
+ output.closeElement("sup");
+ }
+@@ -258,7 +263,7 @@ struct TextZoneSink
+ RVNGPropertyList aAttrs;
+ aAttrs.insert("href", ("#called" + lbl).c_str());
+ m_delayedLabel.openElement("a", aAttrs);
+- m_delayedLabel.insertCharacters(lbl.c_str());
++ m_delayedLabel.insertCharacters(uiLabel.c_str());
+ m_delayedLabel.closeElement("a");
+ m_delayedLabel.closeElement("sup");
+ }
+@@ -806,13 +811,16 @@ void EPUBHTMLGenerator::closeListElement()
+ m_impl->output().closeElement("li");
+ }
+
+-void EPUBHTMLGenerator::openFootnote(const RVNGPropertyList &)
++void EPUBHTMLGenerator::openFootnote(const RVNGPropertyList &propList)
+ {
+ if (m_impl->m_ignore)
+ return;
+ EPUBXMLSink &output = m_impl->output();
+ m_impl->push(EPUBHTMLTextZone::Z_FootNote);
+- m_impl->getSink().addLabel(output);
++ librevenge::RVNGString number;
++ if (const librevenge::RVNGProperty *numProp = propList["librevenge:number"])
++ number = numProp->getStr();
++ m_impl->getSink().addLabel(output, number);
+ }
+
+ void EPUBHTMLGenerator::closeFootnote()
+@@ -830,7 +838,7 @@ void EPUBHTMLGenerator::openEndnote(const RVNGPropertyList &)
+ return;
+ EPUBXMLSink &output = m_impl->output();
+ m_impl->push(EPUBHTMLTextZone::Z_EndNote);
+- m_impl->getSink().addLabel(output);
++ m_impl->getSink().addLabel(output, librevenge::RVNGString());
+ }
+
+ void EPUBHTMLGenerator::closeEndnote()
+@@ -846,7 +854,7 @@ void EPUBHTMLGenerator::openComment(const RVNGPropertyList & /*propList*/)
+ return;
+ EPUBXMLSink &output = m_impl->output();
+ m_impl->push(EPUBHTMLTextZone::Z_Comment);
+- m_impl->getSink().addLabel(output);
++ m_impl->getSink().addLabel(output, librevenge::RVNGString());
+ }
+
+ void EPUBHTMLGenerator::closeComment()
+--
+2.13.6
+
diff --git a/writerperfect/Library_wpftwriter.mk b/writerperfect/Library_wpftwriter.mk
index bf605e718dc1..5e356304544d 100644
--- a/writerperfect/Library_wpftwriter.mk
+++ b/writerperfect/Library_wpftwriter.mk
@@ -78,6 +78,7 @@ $(eval $(call gb_Library_add_exception_objects,wpftwriter,\
writerperfect/source/writer/StarOfficeWriterImportFilter \
writerperfect/source/writer/WordPerfectImportFilter \
writerperfect/source/writer/exp/XMLBase64ImportContext \
+ writerperfect/source/writer/exp/XMLFootnoteImportContext \
writerperfect/source/writer/exp/XMLSectionContext \
writerperfect/source/writer/exp/XMLTextFrameContext \
writerperfect/source/writer/exp/XMLTextListContext \
diff --git a/writerperfect/qa/unit/EPUBExportTest.cxx b/writerperfect/qa/unit/EPUBExportTest.cxx
index d04c2eeeaaa3..04df33257b6d 100644
--- a/writerperfect/qa/unit/EPUBExportTest.cxx
+++ b/writerperfect/qa/unit/EPUBExportTest.cxx
@@ -88,6 +88,7 @@ public:
void testTextBox();
void testFontEmbedding();
void testImageLink();
+ void testFootnote();
CPPUNIT_TEST_SUITE(EPUBExportTest);
CPPUNIT_TEST(testOutlineLevel);
@@ -124,6 +125,7 @@ public:
CPPUNIT_TEST(testTextBox);
CPPUNIT_TEST(testFontEmbedding);
CPPUNIT_TEST(testImageLink);
+ CPPUNIT_TEST(testFootnote);
CPPUNIT_TEST_SUITE_END();
};
@@ -690,6 +692,16 @@ void EPUBExportTest::testImageLink()
assertXPath(mpXmlDoc, "//xhtml:p/xhtml:a/xhtml:img", 1);
}
+void EPUBExportTest::testFootnote()
+{
+ createDoc("footnote.fodt", {});
+
+ mpXmlDoc = parseExport("OEBPS/sections/section0001.xhtml");
+ // These were missing, footnote was lost.
+ assertXPath(mpXmlDoc, "//xhtml:body/xhtml:p/xhtml:sup/xhtml:a", "type", "noteref");
+ assertXPath(mpXmlDoc, "//xhtml:body/xhtml:aside", "type", "footnote");
+}
+
CPPUNIT_TEST_SUITE_REGISTRATION(EPUBExportTest);
}
diff --git a/writerperfect/qa/unit/data/writer/epubexport/footnote.fodt b/writerperfect/qa/unit/data/writer/epubexport/footnote.fodt
new file mode 100644
index 000000000000..a846d64ed03d
--- /dev/null
+++ b/writerperfect/qa/unit/data/writer/epubexport/footnote.fodt
@@ -0,0 +1,8 @@
+<?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" xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" xmlns:css3t="http://www.w3.org/TR/css3-text/" office:version="1.2" office:mimetype="application/vnd.oasis.opendocument.text">
+ <office:body>
+ <office:text>
+ <text:p>before<text:note text:id="ftn0" text:note-class="footnote"><text:note-citation>1</text:note-citation><text:note-body><text:p>Footnote content</text:p></text:note-body></text:note>after</text:p>
+ </office:text>
+ </office:body>
+</office:document>
diff --git a/writerperfect/source/writer/exp/XMLFootnoteImportContext.cxx b/writerperfect/source/writer/exp/XMLFootnoteImportContext.cxx
new file mode 100644
index 000000000000..e23f60932773
--- /dev/null
+++ b/writerperfect/source/writer/exp/XMLFootnoteImportContext.cxx
@@ -0,0 +1,121 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "XMLFootnoteImportContext.hxx"
+
+#include "xmlimp.hxx"
+#include "xmltext.hxx"
+
+using namespace com::sun::star;
+
+namespace writerperfect
+{
+namespace exp
+{
+/// Handler for <text:note-citation>.
+class XMLTextNoteCitationContext : public XMLImportContext
+{
+public:
+ XMLTextNoteCitationContext(XMLImport& rImport, librevenge::RVNGPropertyList& rProperties);
+
+ void SAL_CALL characters(const OUString& rCharacters) override;
+ void SAL_CALL endElement(const OUString& rName) override;
+
+private:
+ librevenge::RVNGPropertyList& m_rProperties;
+ OUString m_aCharacters;
+};
+
+XMLTextNoteCitationContext::XMLTextNoteCitationContext(XMLImport& rImport,
+ librevenge::RVNGPropertyList& rProperties)
+ : XMLImportContext(rImport)
+ , m_rProperties(rProperties)
+{
+}
+
+void XMLTextNoteCitationContext::endElement(const OUString& /*rName*/)
+{
+ m_rProperties.insert("librevenge:number", m_aCharacters.toUtf8().getStr());
+}
+
+void XMLTextNoteCitationContext::characters(const OUString& rCharacters)
+{
+ m_aCharacters += rCharacters;
+}
+
+/// Handler for <text:note-body>.
+class XMLFootnoteBodyImportContext : public XMLImportContext
+{
+public:
+ XMLFootnoteBodyImportContext(XMLImport& rImport,
+ const librevenge::RVNGPropertyList& rProperties);
+
+ rtl::Reference<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;
+
+private:
+ const librevenge::RVNGPropertyList& m_rProperties;
+};
+
+XMLFootnoteBodyImportContext::XMLFootnoteBodyImportContext(
+ XMLImport& rImport, const librevenge::RVNGPropertyList& rProperties)
+ : XMLImportContext(rImport)
+ , m_rProperties(rProperties)
+{
+}
+
+rtl::Reference<XMLImportContext> XMLFootnoteBodyImportContext::CreateChildContext(
+ const OUString& rName, const css::uno::Reference<css::xml::sax::XAttributeList>& /*xAttribs*/)
+{
+ return CreateTextChildContext(mrImport, rName);
+}
+
+void XMLFootnoteBodyImportContext::startElement(
+ const OUString& /*rName*/,
+ const css::uno::Reference<css::xml::sax::XAttributeList>& /*xAttribs*/)
+{
+ mrImport.GetGenerator().openFootnote(m_rProperties);
+}
+
+void XMLFootnoteBodyImportContext::endElement(const OUString& /*rName*/)
+{
+ mrImport.GetGenerator().closeFootnote();
+}
+
+XMLFootnoteImportContext::XMLFootnoteImportContext(XMLImport& rImport)
+ : XMLImportContext(rImport)
+{
+}
+
+rtl::Reference<XMLImportContext> XMLFootnoteImportContext::CreateChildContext(
+ const OUString& rName, const css::uno::Reference<css::xml::sax::XAttributeList>& /*xAttribs*/)
+{
+ if (rName == "text:note-citation")
+ return new XMLTextNoteCitationContext(mrImport, m_aProperties);
+ if (rName == "text:note-body")
+ return new XMLFootnoteBodyImportContext(mrImport, m_aProperties);
+ SAL_WARN("writerperfect", "XMLFootnoteImportContext::CreateChildContext: unhandled " << rName);
+ return nullptr;
+}
+
+void XMLFootnoteImportContext::startElement(
+ const OUString& /*rName*/,
+ const css::uno::Reference<css::xml::sax::XAttributeList>& /*xAttribs*/)
+{
+}
+} // namespace exp
+} // namespace writerperfect
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerperfect/source/writer/exp/XMLFootnoteImportContext.hxx b/writerperfect/source/writer/exp/XMLFootnoteImportContext.hxx
new file mode 100644
index 000000000000..7bd221162bb9
--- /dev/null
+++ b/writerperfect/source/writer/exp/XMLFootnoteImportContext.hxx
@@ -0,0 +1,44 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_WRITERPERFECT_SOURCE_WRITER_EXP_XMLFOOTNOTEIMPORTCONTEXT_HXX
+#define INCLUDED_WRITERPERFECT_SOURCE_WRITER_EXP_XMLFOOTNOTEIMPORTCONTEXT_HXX
+
+#include <rtl/ref.hxx>
+
+#include "xmlictxt.hxx"
+
+namespace writerperfect
+{
+namespace exp
+{
+/// Handler for <text:note>.
+class XMLFootnoteImportContext : public XMLImportContext
+{
+public:
+ XMLFootnoteImportContext(XMLImport& rImport);
+
+ rtl::Reference<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;
+
+private:
+ librevenge::RVNGPropertyList m_aProperties;
+};
+
+} // namespace exp
+} // namespace writerperfect
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerperfect/source/writer/exp/txtparai.cxx b/writerperfect/source/writer/exp/txtparai.cxx
index a7d899547759..bfd1b2842a83 100644
--- a/writerperfect/source/writer/exp/txtparai.cxx
+++ b/writerperfect/source/writer/exp/txtparai.cxx
@@ -9,6 +9,7 @@
#include "txtparai.hxx"
+#include "XMLFootnoteImportContext.hxx"
#include "XMLTextFrameContext.hxx"
#include "xmlimp.hxx"
@@ -425,6 +426,9 @@ rtl::Reference<XMLImportContext> CreateParagraphOrSpanChildContext(XMLImport &rI
return new XMLTextFrameContext(rImport);
if (rName == "text:sequence")
return new XMLTextSequenceContext(rImport, rTextPropertyList);
+ if (rName == "text:note")
+ return new XMLFootnoteImportContext(rImport);
+ SAL_WARN("writerperfect", "CreateParagraphOrSpanChildContext: unhandled " << rName);
return nullptr;
}