From 9b1c3fd42fa256b58dfb4dedd070954406c25596 Mon Sep 17 00:00:00 2001 From: Mark Hung 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 #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 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