diff options
-rw-r--r-- | external/libepubgen/libepubgen-epub3.patch.1 | 556 | ||||
-rw-r--r-- | writerperfect/Library_wpftwriter.mk | 1 | ||||
-rw-r--r-- | writerperfect/qa/unit/EPUBExportTest.cxx | 12 | ||||
-rw-r--r-- | writerperfect/qa/unit/data/writer/epubexport/footnote.fodt | 8 | ||||
-rw-r--r-- | writerperfect/source/writer/exp/XMLFootnoteImportContext.cxx | 121 | ||||
-rw-r--r-- | writerperfect/source/writer/exp/XMLFootnoteImportContext.hxx | 44 | ||||
-rw-r--r-- | writerperfect/source/writer/exp/txtparai.cxx | 4 |
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 ¶graphStyleManager, EPUBSpanStyleManager &spanStyleManager, EPUBTableStyleManager &tableStyleManager, const EPUBPath &path, const EPUBPath &stylesheetPath, EPUBStylesMethod stylesMethod) ++ EPUBHTMLGeneratorImpl(EPUBXMLSink &document, EPUBImageManager &imageManager, EPUBFontManager &fontManager, EPUBListStyleManager &listStyleManager, EPUBParagraphStyleManager ¶graphStyleManager, 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 ¶graphStyleManager, 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 ¶graphStyleManager, 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 ¶graphStyleManager, EPUBSpanStyleManager &spanStyleManager, EPUBTableStyleManager &tableStyleManager, const EPUBPath &path, const EPUBPath &stylesheetPath, EPUBStylesMethod stylesMethod); ++ EPUBHTMLGenerator(EPUBXMLSink &document, EPUBImageManager &imageManager, EPUBFontManager &fontManager, EPUBListStyleManager &listStyleManager, EPUBParagraphStyleManager ¶graphStyleManager, 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 ¶graphStyleManager, EPUBSpanStyleManager &spanStyleManager, EPUBTableStyleManager &tableStyleManager, const EPUBPath &stylesheetPath, EPUBStylesMethod stylesMethod) ++const EPUBHTMLGeneratorPtr_t EPUBHTMLManager::create(EPUBImageManager &imageManager, EPUBFontManager &fontManager, EPUBListStyleManager &listStyleManager, EPUBParagraphStyleManager ¶graphStyleManager, 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 ¶graphStyleManager, EPUBSpanStyleManager &spanStyleManager, EPUBTableStyleManager &tableStyleManager, const EPUBPath &stylesheetPath, EPUBStylesMethod stylesMethod); ++ const EPUBHTMLGeneratorPtr_t create(EPUBImageManager &imageManager, EPUBFontManager &fontManager, EPUBListStyleManager &listStyleManager, EPUBParagraphStyleManager ¶graphStyleManager, 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; } |