summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--external/libepubgen/0001-Enclose-span-with-ruby-if-text-ruby-text-is-set.patch.1117
-rw-r--r--external/libepubgen/UnpackedTarball_libepubgen.mk2
-rw-r--r--writerperfect/qa/unit/EPUBExportTest.cxx10
-rw-r--r--writerperfect/qa/unit/data/writer/epubexport/simple-ruby.odtbin0 -> 8307 bytes
-rw-r--r--writerperfect/source/writer/exp/txtparai.cxx85
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
new file mode 100644
index 000000000000..160dd00ee1e7
--- /dev/null
+++ b/writerperfect/qa/unit/data/writer/epubexport/simple-ruby.odt
Binary files differ
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);
}