diff options
-rw-r--r-- | external/libepubgen/0001-Enclose-span-with-ruby-if-text-ruby-text-is-set.patch.1 | 117 | ||||
-rw-r--r-- | external/libepubgen/UnpackedTarball_libepubgen.mk | 2 | ||||
-rw-r--r-- | writerperfect/qa/unit/EPUBExportTest.cxx | 10 | ||||
-rw-r--r-- | writerperfect/qa/unit/data/writer/epubexport/simple-ruby.odt | bin | 0 -> 8307 bytes | |||
-rw-r--r-- | writerperfect/source/writer/exp/txtparai.cxx | 85 |
5 files changed, 214 insertions, 0 deletions
diff --git a/external/libepubgen/0001-Enclose-span-with-ruby-if-text-ruby-text-is-set.patch.1 b/external/libepubgen/0001-Enclose-span-with-ruby-if-text-ruby-text-is-set.patch.1 new file mode 100644 index 000000000000..99c8523a9dc9 --- /dev/null +++ b/external/libepubgen/0001-Enclose-span-with-ruby-if-text-ruby-text-is-set.patch.1 @@ -0,0 +1,117 @@ +From 16c4e93af6d5eb9d021a671c54af664edc120df9 Mon Sep 17 00:00:00 2001 +From: Mark Hung <marklh9@gmail.com> +Date: Mon, 23 Apr 2018 01:24:48 +0800 +Subject: [PATCH] Enclose <span> with <ruby> if text:ruby-text is set. + +--- + src/lib/EPUBHTMLGenerator.cpp | 22 ++++++++++++++++++++++ + src/test/EPUBTextGeneratorTest.cpp | 25 +++++++++++++++++++++++++ + 2 files changed, 47 insertions(+) + +diff --git a/src/lib/EPUBHTMLGenerator.cpp b/src/lib/EPUBHTMLGenerator.cpp +index 0080816..a4467a9 100644 +--- a/src/lib/EPUBHTMLGenerator.cpp ++++ b/src/lib/EPUBHTMLGenerator.cpp +@@ -397,6 +397,7 @@ struct EPUBHTMLGeneratorImpl + , m_linkPropertiesStack() + , m_paragraphAttributesStack() + , m_spanAttributesStack() ++ , m_rubyText() + , m_stylesMethod(stylesMethod) + , m_layoutMethod(layoutMethod) + , m_actualSink() +@@ -500,6 +501,9 @@ struct EPUBHTMLGeneratorImpl + std::stack<RVNGPropertyList> m_paragraphAttributesStack; + std::stack<RVNGPropertyList> m_spanAttributesStack; + ++ /// This is set when the span has ruby text and should be wrapped in <ruby></ruby>. ++ std::string m_rubyText; ++ + EPUBStylesMethod m_stylesMethod; + EPUBLayoutMethod m_layoutMethod; + +@@ -743,6 +747,14 @@ void EPUBHTMLGenerator::openSpan(const RVNGPropertyList &propList) + attrs.insert("style", m_impl->m_spanManager.getStyle(propList, false).c_str()); + break; + } ++ ++ const librevenge::RVNGProperty *rubyText = propList["text:ruby-text"]; ++ if (rubyText) ++ { ++ m_impl->m_rubyText = rubyText->getStr().cstr(); ++ m_impl->output(false).openElement("ruby", attrs); ++ } ++ + m_impl->output(false).openElement("span", attrs); + + librevenge::RVNGPropertyList::Iter i(attrs); +@@ -761,6 +773,16 @@ void EPUBHTMLGenerator::closeSpan() + m_impl->m_spanAttributesStack.pop(); + + m_impl->output().closeElement("span"); ++ ++ if (m_impl->m_rubyText.length()) ++ { ++ m_impl->output().openElement("rt"); ++ m_impl->output().insertCharacters(m_impl->m_rubyText.c_str()); ++ m_impl->output().closeElement("rt"); ++ m_impl->output().closeElement("ruby"); ++ m_impl->m_hasText = true; ++ m_impl->m_rubyText.clear(); ++ } + } + + void EPUBHTMLGenerator::openLink(const RVNGPropertyList &propList) +diff --git a/src/test/EPUBTextGeneratorTest.cpp b/src/test/EPUBTextGeneratorTest.cpp +index f03824f..61c7cac 100644 +--- a/src/test/EPUBTextGeneratorTest.cpp ++++ b/src/test/EPUBTextGeneratorTest.cpp +@@ -240,6 +240,7 @@ private: + CPPUNIT_TEST(testSplitOnHeadingInPageSpan); + CPPUNIT_TEST(testSplitOnSizeInPageSpan); + CPPUNIT_TEST(testManyWritingModes); ++ CPPUNIT_TEST(testRubyElements); + CPPUNIT_TEST_SUITE_END(); + + private: +@@ -284,6 +285,7 @@ private: + void testSplitOnHeadingInPageSpan(); + void testSplitOnSizeInPageSpan(); + void testManyWritingModes(); ++ void testRubyElements(); + + /// 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); +@@ -1507,6 +1509,29 @@ void EPUBTextGeneratorTest::testManyWritingModes() + assertXPath(package.m_streams["OEBPS/sections/section0002.xhtml"], "//xhtml:body", "class", "body1"); + } + ++void EPUBTextGeneratorTest::testRubyElements() ++{ ++ StringEPUBPackage package; ++ libepubgen::EPUBTextGenerator generator(&package); ++ generator.startDocument(librevenge::RVNGPropertyList()); ++ generator.openParagraph(librevenge::RVNGPropertyList()); ++ { ++ librevenge::RVNGPropertyList span; ++ span.insert("text:ruby-text", "ruby text"); ++ generator.openSpan(span); ++ generator.insertText("base text"); ++ generator.closeSpan(); ++ } ++ generator.closeParagraph(); ++ generator.endDocument(); ++ ++ // Expects: <ruby><span>base text</span><rt>ruby text</rt></ruby> ++ CPPUNIT_ASSERT_XPATH(package.m_streams["OEBPS/sections/section0001.xhtml"], "//xhtml:ruby", 1); ++ CPPUNIT_ASSERT_XPATH_CONTENT(package.m_streams["OEBPS/sections/section0001.xhtml"], "//xhtml:ruby/xhtml:rt", "ruby text"); ++ CPPUNIT_ASSERT_XPATH_CONTENT(package.m_streams["OEBPS/sections/section0001.xhtml"], "//xhtml:ruby/xhtml:span", "base text"); ++} ++ ++ + CPPUNIT_TEST_SUITE_REGISTRATION(EPUBTextGeneratorTest); + + } +-- +2.14.1 + diff --git a/external/libepubgen/UnpackedTarball_libepubgen.mk b/external/libepubgen/UnpackedTarball_libepubgen.mk index a6b2020f5f07..d7159f7e7bb5 100644 --- a/external/libepubgen/UnpackedTarball_libepubgen.mk +++ b/external/libepubgen/UnpackedTarball_libepubgen.mk @@ -16,6 +16,8 @@ epubgen_patches += 0001-Support-writing-mode-for-reflowable-layout-method.patch. 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 +# Backport of <https://sourceforge.net/p/libepubgen/code/ci/aa254c9e6f2d1ecfa2512111746a77c05ba9717f/> +epubgen_patches += 0001-Enclose-span-with-ruby-if-text-ruby-text-is-set.patch.1 ifeq ($(COM_IS_CLANG),TRUE) ifneq ($(filter -fsanitize=%,$(CC)),) diff --git a/writerperfect/qa/unit/EPUBExportTest.cxx b/writerperfect/qa/unit/EPUBExportTest.cxx index ce8f2964b0b7..90e97ba77799 100644 --- a/writerperfect/qa/unit/EPUBExportTest.cxx +++ b/writerperfect/qa/unit/EPUBExportTest.cxx @@ -103,6 +103,7 @@ public: void testTdf115623SingleWritingMode(); void testTdf115623SplitByChapter(); void testTdf115623ManyPageSpans(); + void testSimpleRuby(); CPPUNIT_TEST_SUITE(EPUBExportTest); CPPUNIT_TEST(testOutlineLevel); @@ -152,6 +153,7 @@ public: CPPUNIT_TEST(testTdf115623SingleWritingMode); CPPUNIT_TEST(testTdf115623SplitByChapter); CPPUNIT_TEST(testTdf115623ManyPageSpans); + CPPUNIT_TEST(testSimpleRuby); CPPUNIT_TEST_SUITE_END(); }; @@ -967,6 +969,14 @@ void EPUBExportTest::testTdf115623ManyPageSpans() } } +void EPUBExportTest::testSimpleRuby() +{ + createDoc("simple-ruby.odt", {}); + mpXmlDoc = parseExport("OEBPS/sections/section0001.xhtml"); + assertXPathContent(mpXmlDoc, "//xhtml:body/xhtml:p/xhtml:ruby/xhtml:span", "base text"); + assertXPathContent(mpXmlDoc, "//xhtml:body/xhtml:p/xhtml:ruby/xhtml:rt", "ruby text"); +} + CPPUNIT_TEST_SUITE_REGISTRATION(EPUBExportTest); } diff --git a/writerperfect/qa/unit/data/writer/epubexport/simple-ruby.odt b/writerperfect/qa/unit/data/writer/epubexport/simple-ruby.odt Binary files differnew file mode 100644 index 000000000000..160dd00ee1e7 --- /dev/null +++ b/writerperfect/qa/unit/data/writer/epubexport/simple-ruby.odt diff --git a/writerperfect/source/writer/exp/txtparai.cxx b/writerperfect/source/writer/exp/txtparai.cxx index f219cf711880..297c5824ccf8 100644 --- a/writerperfect/source/writer/exp/txtparai.cxx +++ b/writerperfect/source/writer/exp/txtparai.cxx @@ -148,6 +148,89 @@ void XMLSpanContext::characters(const OUString& rChars) mrImport.GetGenerator().closeSpan(); } +/// Handler for <text:ruby>. +class XMLRubyContext : public XMLImportContext +{ +public: + XMLRubyContext(XMLImport& rImport, const librevenge::RVNGPropertyList& rPropertyList); + + rtl::Reference<XMLImportContext> + CreateChildContext(const OUString& rName, + const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) override; + + void SAL_CALL endElement(const OUString& rName) override; + + OUString m_sRubyText; + OUString m_sRubyBase; + +private: + librevenge::RVNGPropertyList m_aPropertyList; +}; + +/// Handler for <text:ruby-text>. +class XMLRubyTextContext : public XMLImportContext +{ +public: + XMLRubyTextContext(XMLImport& rImport, XMLRubyContext& rParent) + : XMLImportContext(rImport) + , m_rParent(rParent) + { + } + + void SAL_CALL characters(const OUString& rChars) override { m_rParent.m_sRubyText = rChars; } + +private: + XMLRubyContext& m_rParent; +}; + +/// Handler for <text:ruby-base>. +class XMLRubyBaseContext : public XMLImportContext +{ +public: + XMLRubyBaseContext(XMLImport& rImport, XMLRubyContext& rParent) + : XMLImportContext(rImport) + , m_rParent(rParent) + { + } + + void SAL_CALL characters(const OUString& rChars) override { m_rParent.m_sRubyBase += rChars; } + +private: + XMLRubyContext& m_rParent; +}; + +XMLRubyContext::XMLRubyContext(XMLImport& rImport, + const librevenge::RVNGPropertyList& rPropertyList) + : XMLImportContext(rImport) + , m_sRubyText() +{ + // Inherit properties from parent. + librevenge::RVNGPropertyList::Iter itProp(rPropertyList); + for (itProp.rewind(); itProp.next();) + m_aPropertyList.insert(itProp.key(), itProp()->clone()); +} + +rtl::Reference<XMLImportContext> XMLRubyContext::CreateChildContext( + const OUString& rName, const css::uno::Reference<css::xml::sax::XAttributeList>& /*xAttribs*/) +{ + if (rName == "text:ruby-base") + return new XMLRubyBaseContext(mrImport, *this); + if (rName == "text:ruby-text") + return new XMLRubyTextContext(mrImport, *this); + return nullptr; +} + +void XMLRubyContext::endElement(const OUString& /*rName*/) +{ + OString sRubyText = OUStringToOString(m_sRubyText, RTL_TEXTENCODING_UTF8); + OString sRubyBase = OUStringToOString(m_sRubyBase, RTL_TEXTENCODING_UTF8); + if (sRubyText.getLength()) + m_aPropertyList.insert("text:ruby-text", sRubyText.getStr()); + mrImport.GetGenerator().openSpan(m_aPropertyList); + mrImport.GetGenerator().insertText(sRubyBase.getStr()); + mrImport.GetGenerator().closeSpan(); +} + /// Base class for contexts that represent a single character only. class XMLCharContext : public XMLImportContext { @@ -426,6 +509,8 @@ rtl::Reference<XMLImportContext> XMLParaContext::CreateChildContext( return new XMLHyperlinkContext(mrImport, m_aTextPropertyList); if (rName == "draw:a") return new XMLTextFrameHyperlinkContext(mrImport, m_aTextPropertyList); + if (rName == "text:ruby") + return new XMLRubyContext(mrImport, m_aTextPropertyList); return CreateParagraphOrSpanChildContext(mrImport, rName, m_aTextPropertyList); } |