From 006848cb62225647c418d5143d4e88a9d73829da Mon Sep 17 00:00:00 2001 From: Miklos Vajna Date: Fri, 22 Dec 2017 16:33:52 +0100 Subject: [PATCH] EPUBHTMLGenerator: avoid
inside

and/or This is not allowed in XHTML, but we wrote that markup when a text frame was inside a span or a paragraph. The closest allowed markup in XHTML seems to be closing the span/paragraph before opening the text box and doing the opposite after the text box is closed. --- src/lib/EPUBHTMLGenerator.cpp | 33 +++++++++++++++++++++++++++++++++ src/test/EPUBTextGeneratorTest.cpp | 4 +++- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/src/lib/EPUBHTMLGenerator.cpp b/src/lib/EPUBHTMLGenerator.cpp index 342213e..bc9c1b7 100644 --- a/src/lib/EPUBHTMLGenerator.cpp +++ b/src/lib/EPUBHTMLGenerator.cpp @@ -395,6 +395,8 @@ struct EPUBHTMLGeneratorImpl , m_frameAnchorTypes() , m_framePropertiesStack() , m_linkPropertiesStack() + , m_paragraphAttributesStack() + , m_spanAttributesStack() , m_stylesMethod(stylesMethod) , m_layoutMethod(layoutMethod) , m_actualSink() @@ -495,6 +497,8 @@ struct EPUBHTMLGeneratorImpl std::stack m_framePropertiesStack; /// This is used for links which don't have a href. std::stack m_linkPropertiesStack; + std::stack m_paragraphAttributesStack; + std::stack m_spanAttributesStack; EPUBStylesMethod m_stylesMethod; EPUBLayoutMethod m_layoutMethod; @@ -683,6 +687,12 @@ void EPUBHTMLGenerator::openParagraph(const RVNGPropertyList &propList) } m_impl->output(false).openElement("p", attrs); m_impl->m_hasText = false; + + librevenge::RVNGPropertyList::Iter i(attrs); + RVNGPropertyList paragraphAttributes; + for (i.rewind(); i.next();) + paragraphAttributes.insert(i.key(), i()->clone()); + m_impl->m_paragraphAttributesStack.push(paragraphAttributes); } void EPUBHTMLGenerator::closeParagraph() @@ -690,6 +700,9 @@ void EPUBHTMLGenerator::closeParagraph() if (m_impl->m_ignore) return; + if (!m_impl->m_paragraphAttributesStack.empty()) + m_impl->m_paragraphAttributesStack.pop(); + if (!m_impl->m_hasText) insertSpace(); @@ -717,12 +730,22 @@ void EPUBHTMLGenerator::openSpan(const RVNGPropertyList &propList) break; } m_impl->output(false).openElement("span", attrs); + + librevenge::RVNGPropertyList::Iter i(attrs); + RVNGPropertyList spanAttributes; + for (i.rewind(); i.next();) + spanAttributes.insert(i.key(), i()->clone()); + m_impl->m_spanAttributesStack.push(spanAttributes); } void EPUBHTMLGenerator::closeSpan() { if (m_impl->m_ignore) return; + + if (!m_impl->m_spanAttributesStack.empty()) + m_impl->m_spanAttributesStack.pop(); + m_impl->output().closeElement("span"); } @@ -931,6 +954,11 @@ void EPUBHTMLGenerator::openTextBox(const RVNGPropertyList & /*propList*/) if (m_impl->m_ignore) return; + if (!m_impl->m_spanAttributesStack.empty()) + m_impl->output().closeElement("span"); + if (!m_impl->m_paragraphAttributesStack.empty()) + m_impl->output().closeElement("p"); + RVNGPropertyList attrs; if (!m_impl->m_framePropertiesStack.empty()) @@ -968,6 +996,11 @@ void EPUBHTMLGenerator::closeTextBox() m_impl->output().insertEmptyElement("br", attrs); } } + + if (!m_impl->m_paragraphAttributesStack.empty()) + m_impl->output(false).openElement("p", m_impl->m_paragraphAttributesStack.top()); + if (!m_impl->m_spanAttributesStack.empty()) + m_impl->output(false).openElement("span", m_impl->m_spanAttributesStack.top()); } void EPUBHTMLGenerator::openTable(const RVNGPropertyList &propList) -- 2.13.6 From a97e7f40bddba8e5d572b29811a19f34536190dc Mon Sep 17 00:00:00 2001 From: Miklos Vajna Date: Fri, 22 Dec 2017 17:16:23 +0100 Subject: [PATCH] EPUBTableStyleManager: avoid vertical-align key without value ERROR(CSS-008): test.epub/OEBPS/styles/stylesheet.css(1625,19): An error occurred while parsing the CSS: Token ';' not allowed here, expecting a property value. --- src/lib/EPUBTableStyleManager.cpp | 5 +++-- src/test/EPUBTextGeneratorTest.cpp | 6 +++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/lib/EPUBTableStyleManager.cpp b/src/lib/EPUBTableStyleManager.cpp index a1ce33e..cf08737 100644 --- a/src/lib/EPUBTableStyleManager.cpp +++ b/src/lib/EPUBTableStyleManager.cpp @@ -255,8 +255,9 @@ void EPUBTableStyleManager::extractCellProperties(RVNGPropertyList const &pList, else cssProps["text-align"] = pList["fo:text-align"]->getStr().cstr(); } - if (pList["style:vertical-align"]) - cssProps["vertical-align"] = pList["style:vertical-align"]->getStr().cstr(); + const librevenge::RVNGProperty *verticalAlign = pList["style:vertical-align"]; + if (verticalAlign && !verticalAlign->getStr().empty()) + cssProps["vertical-align"] = verticalAlign->getStr().cstr(); else cssProps["vertical-align"] = "top"; if (pList["fo:background-color"]) -- 2.13.6 From 60baa7fb597cde57c3489d8b5066937e7edb779f Mon Sep 17 00:00:00 2001 From: Miklos Vajna Date: Fri, 22 Dec 2017 17:39:31 +0100 Subject: [PATCH] EPUBHTMLGenerator: fix invalid XHTML with links at footnote start ERROR(RSC-005): test3.epub/OEBPS/sections/section0001.xhtml(2,568): Error while parsing file: The a element must not appear inside a elements. --- src/lib/EPUBHTMLGenerator.cpp | 4 +++- src/test/EPUBTextGeneratorTest.cpp | 9 +++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/lib/EPUBHTMLGenerator.cpp b/src/lib/EPUBHTMLGenerator.cpp index bc9c1b7..59ded90 100644 --- a/src/lib/EPUBHTMLGenerator.cpp +++ b/src/lib/EPUBHTMLGenerator.cpp @@ -781,7 +781,9 @@ void EPUBHTMLGenerator::openLink(const RVNGPropertyList &propList) m_impl->m_linkPropertiesStack.push(linkProperties); } else - m_impl->output(false).openElement("a", attrs); + // Implicit sendDelayed=true, so that in case the link is at the start of a + // footnote, links are not nested. + m_impl->output().openElement("a", attrs); } void EPUBHTMLGenerator::closeLink() -- 2.13.6 From 51e17dc87d85f1dc71b380906f9260de4cd0371c Mon Sep 17 00:00:00 2001 From: Miklos Vajna Date: Thu, 18 Jan 2018 14:54:06 +0100 Subject: [PATCH] EPUBImageManager: handle relative and absolute width --- src/lib/EPUBImageManager.cpp | 6 +++++ src/test/EPUBTextGeneratorTest.cpp | 54 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/src/lib/EPUBImageManager.cpp b/src/lib/EPUBImageManager.cpp index bdf3bf0..cb4efee 100644 --- a/src/lib/EPUBImageManager.cpp +++ b/src/lib/EPUBImageManager.cpp @@ -171,6 +171,12 @@ void EPUBImageManager::extractImageProperties(librevenge::RVNGPropertyList const continue; cssProps[type[i]] = pList[field.c_str()]->getStr().cstr(); } + + // Extract size. + if (auto pRelWidth = pList["style:rel-width"]) + cssProps["width"] = pRelWidth->getStr().cstr(); + else if (auto pWidth = pList["svg:width"]) + cssProps["width"] = pWidth->getStr().cstr(); } std::string EPUBImageManager::getWrapStyle(librevenge::RVNGPropertyList const &pList) -- 2.13.6 From c081609849b18113340c39a73b6af432a103a102 Mon Sep 17 00:00:00 2001 From: Miklos Vajna Date: Mon, 22 Jan 2018 14:39:19 +0100 Subject: [PATCH] fixed layout: allow defining chapter names Fixed layout normally just works with SVG images (one image / page), but readable navigation document is still expected, e.g. PDF provides it. So add a way to mention what chapters start on a given page. --- src/lib/EPUBHTMLManager.cpp | 25 +++++++++++++++++++++++++ src/lib/EPUBHTMLManager.h | 3 +++ src/lib/EPUBPath.cpp | 11 +++++++++++ src/lib/EPUBPath.h | 4 ++++ src/lib/EPUBTextGenerator.cpp | 15 +++++++++++++++ src/test/EPUBTextGeneratorTest.cpp | 37 +++++++++++++++++++++++++++++++++++++ 6 files changed, 95 insertions(+) diff --git a/src/lib/EPUBHTMLManager.cpp b/src/lib/EPUBHTMLManager.cpp index 5e96d1d..d35bc3f 100644 --- a/src/lib/EPUBHTMLManager.cpp +++ b/src/lib/EPUBHTMLManager.cpp @@ -93,6 +93,23 @@ void EPUBHTMLManager::writeTocTo(EPUBXMLSink &sink, const EPUBPath &tocPath, int { for (std::vector::size_type i = 0; m_paths.size() != i; ++i) { + const std::vector &chapters = m_paths[i].getChapters(); + if (!chapters.empty()) + { + for (const auto &chapter : chapters) + { + sink.openElement("li"); + librevenge::RVNGPropertyList anchorAttrs; + anchorAttrs.insert("href", m_paths[i].relativeTo(tocPath).str().c_str()); + sink.openElement("a", anchorAttrs); + std::ostringstream label; + sink.insertCharacters(chapter.c_str()); + sink.closeElement("a"); + sink.closeElement("li"); + } + continue; + } + sink.openElement("li"); librevenge::RVNGPropertyList anchorAttrs; anchorAttrs.insert("href", m_paths[i].relativeTo(tocPath).str().c_str()); @@ -140,6 +157,14 @@ void EPUBHTMLManager::insertHeadingText(const std::string &text) m_paths.back().appendTitle(text); } +void EPUBHTMLManager::addChapterName(const std::string &text) +{ + if (m_paths.empty()) + return; + + m_paths.back().addChapter(text); +} + bool EPUBHTMLManager::hasHeadingText() const { if (m_paths.empty()) diff --git a/src/lib/EPUBHTMLManager.h b/src/lib/EPUBHTMLManager.h index 157896b..d48ddf2 100644 --- a/src/lib/EPUBHTMLManager.h +++ b/src/lib/EPUBHTMLManager.h @@ -51,6 +51,9 @@ public: /// Appends text to the title of the current heading. void insertHeadingText(const std::string &text); + /// Registers a chapter name for the current page (fixed layout case). + void addChapterName(const std::string &text); + /// If the current heading has a title. bool hasHeadingText() const; diff --git a/src/lib/EPUBPath.cpp b/src/lib/EPUBPath.cpp index e1c05ed..be24de5 100644 --- a/src/lib/EPUBPath.cpp +++ b/src/lib/EPUBPath.cpp @@ -54,6 +54,7 @@ EPUBPath::Relative::Relative(const std::vector &components) EPUBPath::EPUBPath(const std::string &path) : m_components() , m_title() + , m_chapters() { const std::string trimmed(algorithm::trim_left_copy_if(path, algorithm::is_any_of("/"))); algorithm::split(m_components, trimmed, algorithm::is_any_of("/"), algorithm::token_compress_on); @@ -116,6 +117,16 @@ void EPUBPath::appendTitle(const std::string &title) m_title += title; } +void EPUBPath::addChapter(const std::string &chapter) +{ + m_chapters.push_back(chapter); +} + +const std::vector &EPUBPath::getChapters() const +{ + return m_chapters; +} + std::string EPUBPath::getTitle() const { return m_title; diff --git a/src/lib/EPUBPath.h b/src/lib/EPUBPath.h index 12b8f25..76f2d7b 100644 --- a/src/lib/EPUBPath.h +++ b/src/lib/EPUBPath.h @@ -51,9 +51,13 @@ public: void appendTitle(const std::string &title); std::string getTitle() const; + /// Adds chapter name (fixed layout). + void addChapter(const std::string &chapter); + const std::vector &getChapters() const; private: std::vector m_components; std::string m_title; + std::vector m_chapters; }; bool operator==(const EPUBPath &left, const EPUBPath &right); diff --git a/src/lib/EPUBTextGenerator.cpp b/src/lib/EPUBTextGenerator.cpp index 8e88adb..38ddcdf 100644 --- a/src/lib/EPUBTextGenerator.cpp +++ b/src/lib/EPUBTextGenerator.cpp @@ -270,7 +270,9 @@ void EPUBTextGenerator::openParagraph(const librevenge::RVNGPropertyList &propLi { const RVNGProperty *const breakBefore = propList["fo:break-before"]; if (isPageBreak(breakBefore) && m_impl->getSplitGuard().splitOnPageBreak()) + { m_impl->startNewHtmlFile(); + } const RVNGProperty *const breakAfter = propList["fo:break-after"]; m_impl->m_breakAfterPara = isPageBreak(breakAfter); if (m_impl->getSplitGuard().splitOnSize()) @@ -282,6 +284,19 @@ void EPUBTextGenerator::openParagraph(const librevenge::RVNGPropertyList &propLi m_impl->startNewHtmlFile(); m_impl->getSplitGuard().setCurrentHeadingLevel(outlineLevel ? outlineLevel->getInt() : 0); + if (const librevenge::RVNGPropertyListVector *chapterNames = m_impl->m_pageSpanProps.child("librevenge:chapter-names")) + { + for (unsigned long i = 0; i < chapterNames->count(); i++) + { + RVNGPropertyList const &chapter=(*chapterNames)[i]; + const RVNGProperty *const chapterName = chapter["librevenge:name"]; + if (!chapterName) + continue; + + m_impl->getHtmlManager().addChapterName(chapterName->getStr().cstr()); + } + } + m_impl->getSplitGuard().openLevel(); if (m_impl->m_inHeader || m_impl->m_inFooter) -- 2.13.6 From b6081f659e3000d9f3d5851278d8abdd33448353 Mon Sep 17 00:00:00 2001 From: Miklos Vajna Date: Mon, 22 Jan 2018 15:54:43 +0100 Subject: [PATCH] fixed layout: avoid Page entries when chapter names are provided --- src/lib/EPUBHTMLManager.cpp | 31 ++++++++++++++++++------------- src/test/EPUBTextGeneratorTest.cpp | 16 ++++++++++++++++ 2 files changed, 34 insertions(+), 13 deletions(-) diff --git a/src/lib/EPUBHTMLManager.cpp b/src/lib/EPUBHTMLManager.cpp index d35bc3f..35d82e8 100644 --- a/src/lib/EPUBHTMLManager.cpp +++ b/src/lib/EPUBHTMLManager.cpp @@ -7,6 +7,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include #include #include #include @@ -91,24 +92,28 @@ void EPUBHTMLManager::writeTocTo(EPUBXMLSink &sink, const EPUBPath &tocPath, int { if (version >= 30) { + bool hasChapterNames = std::find_if(m_paths.begin(), m_paths.end(), [](const EPUBPath &path) + { + return !path.getChapters().empty(); + }) != m_paths.end(); for (std::vector::size_type i = 0; m_paths.size() != i; ++i) { const std::vector &chapters = m_paths[i].getChapters(); - if (!chapters.empty()) + for (const auto &chapter : chapters) { - for (const auto &chapter : chapters) - { - sink.openElement("li"); - librevenge::RVNGPropertyList anchorAttrs; - anchorAttrs.insert("href", m_paths[i].relativeTo(tocPath).str().c_str()); - sink.openElement("a", anchorAttrs); - std::ostringstream label; - sink.insertCharacters(chapter.c_str()); - sink.closeElement("a"); - sink.closeElement("li"); - } - continue; + sink.openElement("li"); + librevenge::RVNGPropertyList anchorAttrs; + anchorAttrs.insert("href", m_paths[i].relativeTo(tocPath).str().c_str()); + sink.openElement("a", anchorAttrs); + std::ostringstream label; + sink.insertCharacters(chapter.c_str()); + sink.closeElement("a"); + sink.closeElement("li"); } + if (hasChapterNames) + // Chapter names are provided for this document, so never write Page + // entries. + continue; sink.openElement("li"); librevenge::RVNGPropertyList anchorAttrs; -- 2.13.6