summaryrefslogtreecommitdiff
path: root/external/libepubgen
diff options
context:
space:
mode:
authorMark Hung <marklh9@gmail.com>2018-03-28 07:26:08 +0800
committerMiklos Vajna <vmiklos@collabora.co.uk>2018-04-04 09:03:22 +0200
commit75c166d058717a7edd26273f50a86fe5f2cc7fb0 (patch)
treebe50a490d470c3d5b7296b8af307d6165d96789d /external/libepubgen
parent791fb3979df47a9fe21a1fbb9debbc955f3e035b (diff)
tdf#115623: patch libepubgen to support writing-mode.
Backport three patches from libepubgen master branch to support exporting style:writing-mode as body CSS styles. 1. Support writing-mode for reflowable layout method. https://sourceforge.net/p/libepubgen/code/ci/9a284081eea4a95235a6d6a6a50cbe3f7ad323ba/ 2. Always keep page properties when splitting. https://sourceforge.net/p/libepubgen/code/ci/0318031b9094b9180d1d391d0ca31a782b016e99/ 3. Ensure page properties in the page span work https://sourceforge.net/p/libepubgen/code/ci/1f602fcaa74fc9dbc6457019d11c602ff4040a4e/ Change-Id: I9033cb1f5fcbfedb423308fb29b9bd4d6d7d7a43 Reviewed-on: https://gerrit.libreoffice.org/52083 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Miklos Vajna <vmiklos@collabora.co.uk>
Diffstat (limited to 'external/libepubgen')
-rw-r--r--external/libepubgen/0001-Support-writing-mode-for-reflowable-layout-method.patch.1264
-rw-r--r--external/libepubgen/0002-Always-keep-page-properties-when-splitting-the-HTML-.patch.1181
-rw-r--r--external/libepubgen/0003-Ensure-page-properties-in-the-page-span-works.patch.1225
-rw-r--r--external/libepubgen/UnpackedTarball_libepubgen.mk6
4 files changed, 676 insertions, 0 deletions
diff --git a/external/libepubgen/0001-Support-writing-mode-for-reflowable-layout-method.patch.1 b/external/libepubgen/0001-Support-writing-mode-for-reflowable-layout-method.patch.1
new file mode 100644
index 000000000000..d3799d1d6e8b
--- /dev/null
+++ b/external/libepubgen/0001-Support-writing-mode-for-reflowable-layout-method.patch.1
@@ -0,0 +1,264 @@
+From 9b1c3fd42fa256b58dfb4dedd070954406c25596 Mon Sep 17 00:00:00 2001
+From: Mark Hung <marklh9@gmail.com>
+Date: Mon, 19 Mar 2018 20:36:11 +0800
+Subject: [PATCH 1/3] Support writing-mode for reflowable layout method.
+
+Convert style:writing-mode in page properties to css style for
+HTML body element. The class names of body elements will be like
+"body0".
+---
+ src/lib/EPUBGenerator.cpp | 1 +
+ src/lib/EPUBHTMLGenerator.cpp | 18 +++++++++++++--
+ src/lib/EPUBSpanStyleManager.cpp | 45 ++++++++++++++++++++++++++++++++------
+ src/lib/EPUBSpanStyleManager.h | 14 ++++++++----
+ src/test/EPUBTextGeneratorTest.cpp | 25 +++++++++++++++++++++
+ 5 files changed, 90 insertions(+), 13 deletions(-)
+
+diff --git a/src/lib/EPUBGenerator.cpp b/src/lib/EPUBGenerator.cpp
+index 83f3f40..56db4dc 100644
+--- a/src/lib/EPUBGenerator.cpp
++++ b/src/lib/EPUBGenerator.cpp
+@@ -122,6 +122,7 @@ void EPUBGenerator::startNewHtmlFile()
+ if (m_layoutMethod == EPUB_LAYOUT_METHOD_FIXED && m_currentHtml)
+ m_currentHtml->getPageProperties(pageProperties);
+ m_currentHtml = m_htmlManager.create(m_imageManager, m_fontManager, m_listStyleManager, m_paragraphStyleManager, m_spanStyleManager, m_tableStyleManager, m_stylesheetPath, m_stylesMethod, m_layoutMethod, m_version);
++
+ if (m_layoutMethod == EPUB_LAYOUT_METHOD_FIXED)
+ m_currentHtml->setPageProperties(pageProperties);
+
+diff --git a/src/lib/EPUBHTMLGenerator.cpp b/src/lib/EPUBHTMLGenerator.cpp
+index 342213e..d5cc0d2 100644
+--- a/src/lib/EPUBHTMLGenerator.cpp
++++ b/src/lib/EPUBHTMLGenerator.cpp
+@@ -600,6 +600,20 @@ void EPUBHTMLGenerator::endDocument()
+ RVNGPropertyList bodyAttrs;
+ if (m_impl->m_version >= 30)
+ bodyAttrs.insert("xmlns:epub", "http://www.idpf.org/2007/ops");
++
++ if (m_impl->m_actualPageProperties["style:writing-mode"])
++ {
++ switch (m_impl->m_stylesMethod)
++ {
++ case EPUB_STYLES_METHOD_CSS:
++ bodyAttrs.insert("class", m_impl->m_spanManager.getClass(m_impl->m_actualPageProperties, true).c_str());
++ break;
++ case EPUB_STYLES_METHOD_INLINE:
++ bodyAttrs.insert("style", m_impl->m_spanManager.getStyle(m_impl->m_actualPageProperties, true).c_str());
++ break;
++ }
++ }
++
+ m_impl->m_document.openElement("body", bodyAttrs);
+ m_impl->flushUnsent(m_impl->m_document);
+ m_impl->m_document.closeElement("body");
+@@ -710,10 +724,10 @@ void EPUBHTMLGenerator::openSpan(const RVNGPropertyList &propList)
+ switch (m_impl->m_stylesMethod)
+ {
+ case EPUB_STYLES_METHOD_CSS:
+- attrs.insert("class", m_impl->m_spanManager.getClass(propList).c_str());
++ attrs.insert("class", m_impl->m_spanManager.getClass(propList, false).c_str());
+ break;
+ case EPUB_STYLES_METHOD_INLINE:
+- attrs.insert("style", m_impl->m_spanManager.getStyle(propList).c_str());
++ attrs.insert("style", m_impl->m_spanManager.getStyle(propList, false).c_str());
+ break;
+ }
+ m_impl->output(false).openElement("span", attrs);
+diff --git a/src/lib/EPUBSpanStyleManager.cpp b/src/lib/EPUBSpanStyleManager.cpp
+index e25fa26..ded34ba 100644
+--- a/src/lib/EPUBSpanStyleManager.cpp
++++ b/src/lib/EPUBSpanStyleManager.cpp
+@@ -21,7 +21,7 @@ namespace libepubgen
+
+ using librevenge::RVNGPropertyList;
+
+-std::string EPUBSpanStyleManager::getClass(RVNGPropertyList const &pList)
++std::string EPUBSpanStyleManager::getClass(RVNGPropertyList const &pList, bool bIsBody)
+ {
+ if (pList["librevenge:span-id"])
+ {
+@@ -31,20 +31,31 @@ std::string EPUBSpanStyleManager::getClass(RVNGPropertyList const &pList)
+ }
+
+ EPUBCSSProperties content;
+- extractProperties(pList, content);
++ if (bIsBody)
++ extractBodyProperties(pList, content);
++ else
++ extractSpanProperties(pList, content);
++
+ ContentNameMap_t::const_iterator it = m_contentNameMap.find(content);
+ if (it != m_contentNameMap.end())
+ return it->second;
+ std::stringstream s;
+- s << "span" << m_contentNameMap.size();
++ if (bIsBody)
++ s << "body" << (m_numberBody.next() - 1);
++ else
++ s << "span" << (m_numberSpan.next() - 1);
++
+ m_contentNameMap[content]=s.str();
+ return s.str();
+ }
+
+-std::string EPUBSpanStyleManager::getStyle(RVNGPropertyList const &pList)
++std::string EPUBSpanStyleManager::getStyle(RVNGPropertyList const &pList, bool bIsBody)
+ {
+ EPUBCSSProperties content;
+- extractProperties(pList, content);
++ if (bIsBody)
++ extractBodyProperties(pList, content);
++ else
++ extractSpanProperties(pList, content);
+
+ std::stringstream s;
+ for (const auto &property : content)
+@@ -62,7 +73,7 @@ void EPUBSpanStyleManager::defineSpan(RVNGPropertyList const &propList)
+ int id=propList["librevenge:span-id"]->getInt();
+ RVNGPropertyList pList(propList);
+ pList.remove("librevenge:span-id");
+- m_idNameMap[id]=getClass(pList);
++ m_idNameMap[id]=getClass(pList, false);
+ }
+
+ void EPUBSpanStyleManager::send(EPUBCSSSink &out)
+@@ -75,7 +86,7 @@ void EPUBSpanStyleManager::send(EPUBCSSSink &out)
+ }
+ }
+
+-void EPUBSpanStyleManager::extractProperties(RVNGPropertyList const &pList, EPUBCSSProperties &cssProps) const
++void EPUBSpanStyleManager::extractSpanProperties(RVNGPropertyList const &pList, EPUBCSSProperties &cssProps) const
+ {
+ if (pList["fo:background-color"])
+ cssProps["background-color"] = pList["fo:background-color"]->getStr().cstr();
+@@ -227,6 +238,26 @@ void EPUBSpanStyleManager::extractTextPosition(char const *value, EPUBCSSPropert
+ }
+ }
+
++void EPUBSpanStyleManager::extractBodyProperties(RVNGPropertyList const &pList, EPUBCSSProperties &cssProps) const
++{
++ if (pList["style:writing-mode"])
++ {
++ std::string mode = pList["style:writing-mode"]->getStr().cstr();
++ if (mode == "tb-rl" || mode == "tb")
++ mode = "vertical-rl";
++ else if (mode == "tb-lr")
++ mode = "vertical-lr";
++ else // For the rest: lr, lr-tb, rl, rl-tb
++ {
++ mode = "horizontal-tb";
++ cssProps["direction"] = (mode == "rl-tb" || mode == "rl")?"rtl":"ltr";
++ }
++
++ cssProps["-epub-writing-mode"] = mode;
++ cssProps["-webkit-writing-mode"] = mode;
++ cssProps["writing-mode"] = mode;
++ }
++}
+ }
+
+ /* vim:set shiftwidth=2 softtabstop=2 expandtab: */
+diff --git a/src/lib/EPUBSpanStyleManager.h b/src/lib/EPUBSpanStyleManager.h
+index ec9d0e5..6c18392 100644
+--- a/src/lib/EPUBSpanStyleManager.h
++++ b/src/lib/EPUBSpanStyleManager.h
+@@ -19,6 +19,7 @@
+ #include <librevenge/librevenge.h>
+
+ #include "EPUBCSSProperties.h"
++#include "EPUBCounter.h"
+
+ namespace libepubgen
+ {
+@@ -32,7 +33,7 @@ class EPUBSpanStyleManager
+
+ public:
+ //! constructor
+- EPUBSpanStyleManager() : m_contentNameMap(), m_idNameMap()
++ EPUBSpanStyleManager() : m_contentNameMap(), m_idNameMap(), m_numberSpan(), m_numberBody()
+ {
+ }
+ //! destructor
+@@ -42,14 +43,16 @@ public:
+ //! define a span style
+ void defineSpan(librevenge::RVNGPropertyList const &pList);
+ //! returns the class name corresponding to a propertylist
+- std::string getClass(librevenge::RVNGPropertyList const &pList);
++ std::string getClass(librevenge::RVNGPropertyList const &pList, bool bIsBody);
+ //! returns the style string corresponding to a propertylist
+- std::string getStyle(librevenge::RVNGPropertyList const &pList);
++ std::string getStyle(librevenge::RVNGPropertyList const &pList, bool bIsBody);
+ //! send the data to the sink
+ void send(EPUBCSSSink &out);
+ protected:
+ //! convert a property list into a CSS property map
+- void extractProperties(librevenge::RVNGPropertyList const &pList, EPUBCSSProperties &cssProps) const;
++ void extractSpanProperties(librevenge::RVNGPropertyList const &pList, EPUBCSSProperties &cssProps) const;
++ //! Extract body styles from a property list into a CSS property map
++ void extractBodyProperties(librevenge::RVNGPropertyList const &pList, EPUBCSSProperties &cssProps) const;
+ //! add data corresponding to a text position into the map
+ void extractTextPosition(char const *value, EPUBCSSProperties &cssProps) const;
+ //! add data corresponding to the line decoration into the map
+@@ -59,6 +62,9 @@ protected:
+ //! a map id -> name
+ std::map<int, std::string> m_idNameMap;
+
++ EPUBCounter m_numberSpan;
++ EPUBCounter m_numberBody;
++
+ private:
+ EPUBSpanStyleManager(EPUBSpanStyleManager const &orig);
+ EPUBSpanStyleManager operator=(EPUBSpanStyleManager const &orig);
+diff --git a/src/test/EPUBTextGeneratorTest.cpp b/src/test/EPUBTextGeneratorTest.cpp
+index ddf0c90..cf5e35f 100644
+--- a/src/test/EPUBTextGeneratorTest.cpp
++++ b/src/test/EPUBTextGeneratorTest.cpp
+@@ -235,6 +235,7 @@ private:
+ CPPUNIT_TEST(testFixedLayoutSpine);
+ CPPUNIT_TEST(testPageBreak);
+ CPPUNIT_TEST(testPageBreakImage);
++ CPPUNIT_TEST(testWritingMode);
+ CPPUNIT_TEST_SUITE_END();
+
+ private:
+@@ -274,6 +275,7 @@ private:
+ void testFixedLayoutSpine();
+ void testPageBreak();
+ void testPageBreakImage();
++ void testWritingMode();
+
+ /// Asserts that exactly one xpath exists in buffer, and its content equals content.
+ void assertXPathContent(xmlBufferPtr buffer, const std::string &xpath, const std::string &content);
+@@ -1350,6 +1352,29 @@ void EPUBTextGeneratorTest::testPageBreakImage()
+ CPPUNIT_ASSERT(package.m_streams.find("OEBPS/sections/section0002.xhtml") != package.m_streams.end());
+ }
+
++void EPUBTextGeneratorTest::testWritingMode()
++{
++ StringEPUBPackage package;
++ libepubgen::EPUBTextGenerator generator(&package);
++ generator.setOption(libepubgen::EPUB_GENERATOR_OPTION_SPLIT, libepubgen::EPUB_SPLIT_METHOD_PAGE_BREAK);
++ generator.startDocument(librevenge::RVNGPropertyList());
++
++ {
++ librevenge::RVNGPropertyList page;
++ page.insert("style:writing-mode", "tb");
++ generator.openPageSpan(page);
++
++ librevenge::RVNGPropertyList para;
++ generator.openParagraph(para);
++ generator.insertText("Para1");
++ generator.closeParagraph();
++ generator.closePageSpan();
++ }
++ generator.endDocument();
++ assertCss(package.m_cssStreams["OEBPS/styles/stylesheet.css"], ".body0", "writing-mode: vertical-rl", true);
++ assertXPath(package.m_streams["OEBPS/sections/section0001.xhtml"], "//xhtml:body", "class", "body0");
++}
++
+ CPPUNIT_TEST_SUITE_REGISTRATION(EPUBTextGeneratorTest);
+
+ }
+--
+2.14.1
+
diff --git a/external/libepubgen/0002-Always-keep-page-properties-when-splitting-the-HTML-.patch.1 b/external/libepubgen/0002-Always-keep-page-properties-when-splitting-the-HTML-.patch.1
new file mode 100644
index 000000000000..9b26c279fa5c
--- /dev/null
+++ b/external/libepubgen/0002-Always-keep-page-properties-when-splitting-the-HTML-.patch.1
@@ -0,0 +1,181 @@
+From c3bd3bee2f6e01f0b5f5a8fb376ce175573a8e96 Mon Sep 17 00:00:00 2001
+From: Mark Hung <marklh9@gmail.com>
+Date: Sat, 24 Mar 2018 12:50:12 +0800
+Subject: [PATCH 2/3] Always keep page properties when splitting the HTML file.
+
+Those page properties shall be changed only via openPageSpan.
+It was kept only when the layout out method is EPUB_LAYOUT_METHOD_FIXED
+before.
+---
+ src/lib/EPUBGenerator.cpp | 9 ++--
+ src/test/EPUBTextGeneratorTest.cpp | 98 ++++++++++++++++++++++++++++++++++++--
+ 2 files changed, 99 insertions(+), 8 deletions(-)
+
+diff --git a/src/lib/EPUBGenerator.cpp b/src/lib/EPUBGenerator.cpp
+index 56db4dc..110667f 100644
+--- a/src/lib/EPUBGenerator.cpp
++++ b/src/lib/EPUBGenerator.cpp
+@@ -110,21 +110,20 @@ void EPUBGenerator::setDocumentMetaData(const RVNGPropertyList &props)
+ void EPUBGenerator::startNewHtmlFile()
+ {
+ // close the current HTML file
++ librevenge::RVNGPropertyList pageProperties;
+ if (bool(m_currentHtml))
+ {
+ endHtmlFile();
+ m_currentHtml->endDocument();
++ m_currentHtml->getPageProperties(pageProperties);
+ }
+
+ m_splitGuard.onSplit();
+
+- librevenge::RVNGPropertyList pageProperties;
+- if (m_layoutMethod == EPUB_LAYOUT_METHOD_FIXED && m_currentHtml)
+- m_currentHtml->getPageProperties(pageProperties);
+ m_currentHtml = m_htmlManager.create(m_imageManager, m_fontManager, m_listStyleManager, m_paragraphStyleManager, m_spanStyleManager, m_tableStyleManager, m_stylesheetPath, m_stylesMethod, m_layoutMethod, m_version);
+
+- if (m_layoutMethod == EPUB_LAYOUT_METHOD_FIXED)
+- m_currentHtml->setPageProperties(pageProperties);
++ // Splitted html file should keep the same page property.
++ m_currentHtml->setPageProperties(pageProperties);
+
+ // restore state in the new file
+ m_currentHtml->startDocument(m_documentProps);
+diff --git a/src/test/EPUBTextGeneratorTest.cpp b/src/test/EPUBTextGeneratorTest.cpp
+index cf5e35f..0946408 100644
+--- a/src/test/EPUBTextGeneratorTest.cpp
++++ b/src/test/EPUBTextGeneratorTest.cpp
+@@ -235,7 +235,10 @@ private:
+ CPPUNIT_TEST(testFixedLayoutSpine);
+ CPPUNIT_TEST(testPageBreak);
+ CPPUNIT_TEST(testPageBreakImage);
+- CPPUNIT_TEST(testWritingMode);
++ CPPUNIT_TEST(testPageSpanProperties);
++ CPPUNIT_TEST(testSplitOnPageBreakInPageSpan);
++ CPPUNIT_TEST(testSplitOnHeadingInPageSpan);
++ CPPUNIT_TEST(testSplitOnSizeInPageSpan);
+ CPPUNIT_TEST_SUITE_END();
+
+ private:
+@@ -275,7 +278,10 @@ private:
+ void testFixedLayoutSpine();
+ void testPageBreak();
+ void testPageBreakImage();
+- void testWritingMode();
++ void testPageSpanProperties();
++ void testSplitOnPageBreakInPageSpan();
++ void testSplitOnHeadingInPageSpan();
++ void testSplitOnSizeInPageSpan();
+
+ /// Asserts that exactly one xpath exists in buffer, and its content equals content.
+ void assertXPathContent(xmlBufferPtr buffer, const std::string &xpath, const std::string &content);
+@@ -1352,7 +1358,7 @@ void EPUBTextGeneratorTest::testPageBreakImage()
+ CPPUNIT_ASSERT(package.m_streams.find("OEBPS/sections/section0002.xhtml") != package.m_streams.end());
+ }
+
+-void EPUBTextGeneratorTest::testWritingMode()
++void EPUBTextGeneratorTest::testPageSpanProperties()
+ {
+ StringEPUBPackage package;
+ libepubgen::EPUBTextGenerator generator(&package);
+@@ -1368,11 +1374,97 @@ void EPUBTextGeneratorTest::testWritingMode()
+ generator.openParagraph(para);
+ generator.insertText("Para1");
+ generator.closeParagraph();
++ }
++ generator.endDocument();
++ assertCss(package.m_cssStreams["OEBPS/styles/stylesheet.css"], ".body0", "writing-mode: vertical-rl", true);
++ assertXPath(package.m_streams["OEBPS/sections/section0001.xhtml"], "//xhtml:body", "class", "body0");
++}
++
++void EPUBTextGeneratorTest::testSplitOnPageBreakInPageSpan()
++{
++ StringEPUBPackage package;
++ libepubgen::EPUBTextGenerator generator(&package);
++ generator.setOption(libepubgen::EPUB_GENERATOR_OPTION_SPLIT, libepubgen::EPUB_SPLIT_METHOD_PAGE_BREAK);
++ generator.startDocument(librevenge::RVNGPropertyList());
++
++ {
++ librevenge::RVNGPropertyList page;
++ page.insert("style:writing-mode", "tb");
++ generator.openPageSpan(page);
++
++ librevenge::RVNGPropertyList para;
++ generator.openParagraph(para);
++ generator.insertText("Para1");
++ generator.closeParagraph();
++ // Splitting a new html file inside the page span, the writing-mode shall not change.
++ para.insert("fo:break-before", "page");
++ generator.openParagraph(para);
++ generator.insertText("Para2");
++ generator.closeParagraph();
++ generator.closePageSpan();
++ }
++ generator.endDocument();
++ assertCss(package.m_cssStreams["OEBPS/styles/stylesheet.css"], ".body0", "writing-mode: vertical-rl", true);
++ assertXPath(package.m_streams["OEBPS/sections/section0001.xhtml"], "//xhtml:body", "class", "body0");
++ assertXPath(package.m_streams["OEBPS/sections/section0002.xhtml"], "//xhtml:body", "class", "body0");
++}
++
++void EPUBTextGeneratorTest::testSplitOnHeadingInPageSpan()
++{
++ StringEPUBPackage package;
++ libepubgen::EPUBTextGenerator generator(&package);
++ generator.setOption(libepubgen::EPUB_GENERATOR_OPTION_SPLIT, libepubgen::EPUB_SPLIT_METHOD_HEADING);
++ generator.startDocument(librevenge::RVNGPropertyList());
++
++ {
++ librevenge::RVNGPropertyList page;
++ page.insert("style:writing-mode", "tb");
++ generator.openPageSpan(page);
++
++ librevenge::RVNGPropertyList para;
++ para.insert("text:outline-level", "1");
++ generator.openParagraph(para);
++ generator.insertText("Chapter1");
++ generator.closeParagraph();
++ // Splitting a new html file inside the page span, the writing-mode shall not change.
++ generator.openParagraph(para);
++ generator.insertText("Chapter2");
++ generator.closeParagraph();
++ generator.closePageSpan();
++ }
++ generator.endDocument();
++ assertCss(package.m_cssStreams["OEBPS/styles/stylesheet.css"], ".body0", "writing-mode: vertical-rl", true);
++ assertXPath(package.m_streams["OEBPS/sections/section0001.xhtml"], "//xhtml:body", "class", "body0");
++ assertXPath(package.m_streams["OEBPS/sections/section0002.xhtml"], "//xhtml:body", "class", "body0");
++}
++
++void EPUBTextGeneratorTest::testSplitOnSizeInPageSpan()
++{
++ StringEPUBPackage package;
++ libepubgen::EPUBTextGenerator generator(&package);
++ generator.setOption(libepubgen::EPUB_GENERATOR_OPTION_SPLIT, libepubgen::EPUB_SPLIT_METHOD_SIZE);
++ generator.setSplitSize(5);
++ generator.startDocument(librevenge::RVNGPropertyList());
++
++ {
++ librevenge::RVNGPropertyList page;
++ page.insert("style:writing-mode", "tb");
++ generator.openPageSpan(page);
++
++ librevenge::RVNGPropertyList para;
++ generator.openParagraph(para);
++ generator.insertText("Hello!");
++ generator.closeParagraph();
++ // Splitting a new html file inside the page span, the writing-mode shall not change.
++ generator.openParagraph(para);
++ generator.insertText("Hello!");
++ generator.closeParagraph();
+ generator.closePageSpan();
+ }
+ generator.endDocument();
+ assertCss(package.m_cssStreams["OEBPS/styles/stylesheet.css"], ".body0", "writing-mode: vertical-rl", true);
+ assertXPath(package.m_streams["OEBPS/sections/section0001.xhtml"], "//xhtml:body", "class", "body0");
++ assertXPath(package.m_streams["OEBPS/sections/section0002.xhtml"], "//xhtml:body", "class", "body0");
+ }
+
+ CPPUNIT_TEST_SUITE_REGISTRATION(EPUBTextGeneratorTest);
+--
+2.14.1
+
diff --git a/external/libepubgen/0003-Ensure-page-properties-in-the-page-span-works.patch.1 b/external/libepubgen/0003-Ensure-page-properties-in-the-page-span-works.patch.1
new file mode 100644
index 000000000000..62dd2cbab5dd
--- /dev/null
+++ b/external/libepubgen/0003-Ensure-page-properties-in-the-page-span-works.patch.1
@@ -0,0 +1,225 @@
+From 715786e10deaa6849a6e46b5a9884edde44e194b Mon Sep 17 00:00:00 2001
+From: Mark Hung <marklh9@gmail.com>
+Date: Sun, 25 Mar 2018 10:27:07 +0800
+Subject: [PATCH 3/3] Ensure page properties in the page span works.
+
+As the page properties are converted to CSS styles of the
+body element, this patch force it to start a new HTML file
+when openPageSpan is invoked to open the second page span.
+
+This ensures that page properties in every page span works,
+even there are multiple page spans between intentional HTML
+page splits such as on size, on headings, or on page breaks.
+---
+ src/lib/EPUBGenerator.cpp | 4 +++-
+ src/lib/EPUBSplitGuard.cpp | 19 ++++++++++++++++++-
+ src/lib/EPUBSplitGuard.h | 7 ++++++-
+ src/lib/EPUBTextGenerator.cpp | 5 +++++
+ src/test/EPUBTextGeneratorTest.cpp | 38 ++++++++++++++++++++++++++++++++++++++
+ 5 files changed, 70 insertions(+), 3 deletions(-)
+
+diff --git a/src/lib/EPUBGenerator.cpp b/src/lib/EPUBGenerator.cpp
+index 110667f..9e0c972 100644
+--- a/src/lib/EPUBGenerator.cpp
++++ b/src/lib/EPUBGenerator.cpp
+@@ -44,7 +44,7 @@ EPUBGenerator::EPUBGenerator(EPUBPackage *const package, int version)
+ , m_documentProps()
+ , m_metadata()
+ , m_currentHtml()
+- , m_splitGuard(EPUB_SPLIT_METHOD_PAGE_BREAK)
++ , m_splitGuard(EPUB_SPLIT_METHOD_PAGE_BREAK,true)
+ , m_version(version)
+ , m_stylesMethod(EPUB_STYLES_METHOD_CSS)
+ , m_layoutMethod(EPUB_LAYOUT_METHOD_REFLOWABLE)
+@@ -173,6 +173,8 @@ void EPUBGenerator::setLayoutMethod(EPUBLayoutMethod layout)
+ if (m_layoutMethod == EPUB_LAYOUT_METHOD_FIXED)
+ // Fixed layout implies split on page break.
+ m_splitGuard.setSplitMethod(EPUB_SPLIT_METHOD_PAGE_BREAK);
++
++ m_splitGuard.setSplitOnSecondPageSpan(m_layoutMethod == EPUB_LAYOUT_METHOD_REFLOWABLE);
+ }
+
+ void EPUBGenerator::writeContainer()
+diff --git a/src/lib/EPUBSplitGuard.cpp b/src/lib/EPUBSplitGuard.cpp
+index 4f7531d..5bee515 100644
+--- a/src/lib/EPUBSplitGuard.cpp
++++ b/src/lib/EPUBSplitGuard.cpp
+@@ -15,8 +15,10 @@ namespace libepubgen
+ static const unsigned DEFAULT_SPLIT_HEADING_LEVEL = 1;
+ static const unsigned DEFAULT_SPLIT_SIZE = 1 << 16;
+
+-EPUBSplitGuard::EPUBSplitGuard(const EPUBSplitMethod method)
++EPUBSplitGuard::EPUBSplitGuard(const EPUBSplitMethod method,bool splitOnSecondPageSpan)
+ : m_method(method)
++ , m_splitOnSecondPageSpan(splitOnSecondPageSpan)
++ , m_htmlEverInPageSpan(false)
+ , m_headingLevel(DEFAULT_SPLIT_HEADING_LEVEL)
+ , m_currentHeadingLevel(0)
+ , m_size(DEFAULT_SPLIT_SIZE)
+@@ -25,6 +27,11 @@ EPUBSplitGuard::EPUBSplitGuard(const EPUBSplitMethod method)
+ {
+ }
+
++void EPUBSplitGuard::setHtmlEverInPageSpan(bool value)
++{
++ m_htmlEverInPageSpan = value;
++}
++
+ void EPUBSplitGuard::setSplitHeadingLevel(const unsigned level)
+ {
+ m_headingLevel = level;
+@@ -45,6 +52,11 @@ void EPUBSplitGuard::setSplitMethod(EPUBSplitMethod method)
+ m_method = method;
+ }
+
++void EPUBSplitGuard::setSplitOnSecondPageSpan(bool value)
++{
++ m_splitOnSecondPageSpan = value;
++}
++
+ void EPUBSplitGuard::openLevel()
+ {
+ ++m_nestingLevel;
+@@ -70,6 +82,11 @@ bool EPUBSplitGuard::splitOnHeading(const unsigned level) const
+ return canSplit(EPUB_SPLIT_METHOD_HEADING) && (m_headingLevel >= level);
+ }
+
++bool EPUBSplitGuard::splitOnSecondPageSpan() const
++{
++ return m_splitOnSecondPageSpan && m_htmlEverInPageSpan;
++}
++
+ bool EPUBSplitGuard::inHeading(bool any) const
+ {
+ if (!m_currentHeadingLevel)
+diff --git a/src/lib/EPUBSplitGuard.h b/src/lib/EPUBSplitGuard.h
+index ff55846..a55bad3 100644
+--- a/src/lib/EPUBSplitGuard.h
++++ b/src/lib/EPUBSplitGuard.h
+@@ -18,13 +18,15 @@ namespace libepubgen
+ class EPUBSplitGuard
+ {
+ public:
+- explicit EPUBSplitGuard(EPUBSplitMethod method);
++ explicit EPUBSplitGuard(EPUBSplitMethod method,bool splitOnSecondPageSpan);
+
+ void setSplitHeadingLevel(unsigned level);
+ void setCurrentHeadingLevel(unsigned level);
+ void setSplitSize(unsigned size);
++ void setHtmlEverInPageSpan(bool value);
+ /// Allows overwriting the value given in the constructor.
+ void setSplitMethod(EPUBSplitMethod method);
++ void setSplitOnSecondPageSpan(bool value);
+
+ void openLevel();
+ void closeLevel();
+@@ -32,6 +34,7 @@ public:
+
+ bool splitOnPageBreak() const;
+ bool splitOnHeading(unsigned level) const;
++ bool splitOnSecondPageSpan() const;
+ bool inHeading(bool any) const;
+ bool splitOnSize() const;
+
+@@ -42,6 +45,8 @@ private:
+
+ private:
+ EPUBSplitMethod m_method;
++ bool m_splitOnSecondPageSpan;
++ bool m_htmlEverInPageSpan;
+ unsigned m_headingLevel;
+ unsigned m_currentHeadingLevel;
+ unsigned m_size;
+diff --git a/src/lib/EPUBTextGenerator.cpp b/src/lib/EPUBTextGenerator.cpp
+index 8e88adb..db9d360 100644
+--- a/src/lib/EPUBTextGenerator.cpp
++++ b/src/lib/EPUBTextGenerator.cpp
+@@ -110,6 +110,7 @@ void EPUBTextGenerator::Impl::startHtmlFile()
+
+ void EPUBTextGenerator::Impl::endHtmlFile()
+ {
++ getSplitGuard().setHtmlEverInPageSpan(false);
+ if (m_inPageSpan)
+ getHtml()->openPageSpan(m_pageSpanProps);
+ if (bool(m_currentHeader))
+@@ -206,10 +207,14 @@ void EPUBTextGenerator::openPageSpan(const librevenge::RVNGPropertyList &propLis
+ {
+ assert(!m_impl->m_inPageSpan);
+
++ if (m_impl->getSplitGuard().splitOnSecondPageSpan())
++ m_impl->startNewHtmlFile();
++
+ m_impl->m_inPageSpan = true;
+ m_impl->m_pageSpanProps = propList;
+
+ m_impl->getHtml()->openPageSpan(propList);
++ m_impl->getSplitGuard().setHtmlEverInPageSpan(true);
+ }
+
+ void EPUBTextGenerator::closePageSpan()
+diff --git a/src/test/EPUBTextGeneratorTest.cpp b/src/test/EPUBTextGeneratorTest.cpp
+index 0946408..b5e43a5 100644
+--- a/src/test/EPUBTextGeneratorTest.cpp
++++ b/src/test/EPUBTextGeneratorTest.cpp
+@@ -239,6 +239,7 @@ private:
+ CPPUNIT_TEST(testSplitOnPageBreakInPageSpan);
+ CPPUNIT_TEST(testSplitOnHeadingInPageSpan);
+ CPPUNIT_TEST(testSplitOnSizeInPageSpan);
++ CPPUNIT_TEST(testManyWritingModes);
+ CPPUNIT_TEST_SUITE_END();
+
+ private:
+@@ -282,6 +283,7 @@ private:
+ void testSplitOnPageBreakInPageSpan();
+ void testSplitOnHeadingInPageSpan();
+ void testSplitOnSizeInPageSpan();
++ void testManyWritingModes();
+
+ /// Asserts that exactly one xpath exists in buffer, and its content equals content.
+ void assertXPathContent(xmlBufferPtr buffer, const std::string &xpath, const std::string &content);
+@@ -1467,6 +1469,42 @@ void EPUBTextGeneratorTest::testSplitOnSizeInPageSpan()
+ assertXPath(package.m_streams["OEBPS/sections/section0002.xhtml"], "//xhtml:body", "class", "body0");
+ }
+
++void EPUBTextGeneratorTest::testManyWritingModes()
++{
++ StringEPUBPackage package;
++ libepubgen::EPUBTextGenerator generator(&package);
++ generator.setOption(libepubgen::EPUB_GENERATOR_OPTION_SPLIT, libepubgen::EPUB_SPLIT_METHOD_PAGE_BREAK);
++ generator.startDocument(librevenge::RVNGPropertyList());
++
++ {
++ librevenge::RVNGPropertyList page;
++ page.insert("style:writing-mode", "tb");
++ generator.openPageSpan(page);
++
++ librevenge::RVNGPropertyList para;
++ generator.openParagraph(para);
++ generator.insertText("Para1");
++ generator.closeParagraph();
++ generator.closePageSpan();
++ }
++ {
++ librevenge::RVNGPropertyList page;
++ page.insert("style:writing-mode", "lr");
++ generator.openPageSpan(page);
++
++ librevenge::RVNGPropertyList para;
++ generator.openParagraph(para);
++ generator.insertText("Para1");
++ generator.closeParagraph();
++ generator.closePageSpan();
++ }
++ generator.endDocument();
++ assertCss(package.m_cssStreams["OEBPS/styles/stylesheet.css"], ".body0", "writing-mode: vertical-rl", true);
++ assertCss(package.m_cssStreams["OEBPS/styles/stylesheet.css"], ".body1", "writing-mode: horizontal-tb", true);
++ assertXPath(package.m_streams["OEBPS/sections/section0001.xhtml"], "//xhtml:body", "class", "body0");
++ assertXPath(package.m_streams["OEBPS/sections/section0002.xhtml"], "//xhtml:body", "class", "body1");
++}
++
+ CPPUNIT_TEST_SUITE_REGISTRATION(EPUBTextGeneratorTest);
+
+ }
+--
+2.14.1
+
diff --git a/external/libepubgen/UnpackedTarball_libepubgen.mk b/external/libepubgen/UnpackedTarball_libepubgen.mk
index 47b21d7ee5d0..a6b2020f5f07 100644
--- a/external/libepubgen/UnpackedTarball_libepubgen.mk
+++ b/external/libepubgen/UnpackedTarball_libepubgen.mk
@@ -10,6 +10,12 @@
epubgen_patches :=
# Backport of <https://sourceforge.net/p/libepubgen/code/ci/006848cb62225647c418d5143d4e88a9d73829da/>.
epubgen_patches += libepubgen-epub3.patch.1
+# Backport of <https://sourceforge.net/p/libepubgen/code/ci/9a284081eea4a95235a6d6a6a50cbe3f7ad323ba/>.
+epubgen_patches += 0001-Support-writing-mode-for-reflowable-layout-method.patch.1
+# Backport of <https://sourceforge.net/p/libepubgen/code/ci/0318031b9094b9180d1d391d0ca31a782b016e99/>.
+epubgen_patches += 0002-Always-keep-page-properties-when-splitting-the-HTML-.patch.1
+# Backport of <https://sourceforge.net/p/libepubgen/code/ci/1f602fcaa74fc9dbc6457019d11c602ff4040a4e/>.
+epubgen_patches += 0003-Ensure-page-properties-in-the-page-span-works.patch.1
ifeq ($(COM_IS_CLANG),TRUE)
ifneq ($(filter -fsanitize=%,$(CC)),)