From 793bbac379c5800dc09ff76f093d45047e662ff0 Mon Sep 17 00:00:00 2001 From: Miklos Vajna Date: Tue, 28 Nov 2017 09:06:07 +0100 Subject: EPUB export: implement font embedding support Also avoid librevenge::RVNGBinaryData::appendBase64Data() for performance reasons. Times with and without the XMLBase64ImportContext rework for sw/qa/extras/odfexport/data/embedded-font-props.odt: - before: 1m32.254s - after: 0m7.045s (Need to insvestigate macOS font embedding situation in general, later.) Change-Id: I5aa56bfbfa8dc64f19c021202a1b87618b4b2775 Reviewed-on: https://gerrit.libreoffice.org/45385 Tested-by: Jenkins Reviewed-by: Miklos Vajna --- .../source/writer/exp/XMLBase64ImportContext.cxx | 25 ++- .../source/writer/exp/XMLBase64ImportContext.hxx | 4 + writerperfect/source/writer/exp/xmlfmt.cxx | 169 +++++++++++++++++++++ writerperfect/source/writer/exp/xmlfmt.hxx | 9 ++ writerperfect/source/writer/exp/xmlimp.cxx | 2 + 5 files changed, 207 insertions(+), 2 deletions(-) (limited to 'writerperfect/source') diff --git a/writerperfect/source/writer/exp/XMLBase64ImportContext.cxx b/writerperfect/source/writer/exp/XMLBase64ImportContext.cxx index c073d8fc19bd..137bf01aff01 100644 --- a/writerperfect/source/writer/exp/XMLBase64ImportContext.cxx +++ b/writerperfect/source/writer/exp/XMLBase64ImportContext.cxx @@ -9,6 +9,8 @@ #include "XMLBase64ImportContext.hxx" +#include + using namespace com::sun::star; namespace writerperfect @@ -27,12 +29,31 @@ void XMLBase64ImportContext::startElement(const OUString &/*rName*/, const css:: void XMLBase64ImportContext::endElement(const OUString &/*rName*/) { + m_aBinaryData.append(static_cast(m_aStream.GetBuffer()), m_aStream.GetSize()); } void XMLBase64ImportContext::characters(const OUString &rChars) { - OString sCharU8 = OUStringToOString(rChars, RTL_TEXTENCODING_UTF8); - m_aBinaryData.appendBase64Data(librevenge::RVNGString(sCharU8.getStr())); + OUString aTrimmedChars(rChars.trim()); + + if (!aTrimmedChars.isEmpty()) + { + OUString aChars; + if (!m_aBase64CharsLeft.isEmpty()) + { + aChars = m_aBase64CharsLeft; + aChars += aTrimmedChars; + m_aBase64CharsLeft.clear(); + } + else + aChars = aTrimmedChars; + + uno::Sequence aBuffer((aChars.getLength() / 4) * 3); + const sal_Int32 nCharsDecoded = comphelper::Base64::decodeSomeChars(aBuffer, aChars); + m_aStream.WriteBytes(aBuffer.getArray(), aBuffer.getLength()); + if (nCharsDecoded != aChars.getLength()) + m_aBase64CharsLeft = aChars.copy(nCharsDecoded); + } } const librevenge::RVNGBinaryData &XMLBase64ImportContext::getBinaryData() const diff --git a/writerperfect/source/writer/exp/XMLBase64ImportContext.hxx b/writerperfect/source/writer/exp/XMLBase64ImportContext.hxx index f60122b61382..6ad850a825c1 100644 --- a/writerperfect/source/writer/exp/XMLBase64ImportContext.hxx +++ b/writerperfect/source/writer/exp/XMLBase64ImportContext.hxx @@ -12,6 +12,8 @@ #include +#include + #include "xmlictxt.hxx" namespace writerperfect @@ -33,6 +35,8 @@ public: private: librevenge::RVNGBinaryData m_aBinaryData; + SvMemoryStream m_aStream; + OUString m_aBase64CharsLeft; }; } // namespace exp diff --git a/writerperfect/source/writer/exp/xmlfmt.cxx b/writerperfect/source/writer/exp/xmlfmt.cxx index 02f96f691e9b..abd6bb9a6a72 100644 --- a/writerperfect/source/writer/exp/xmlfmt.cxx +++ b/writerperfect/source/writer/exp/xmlfmt.cxx @@ -9,6 +9,7 @@ #include "xmlfmt.hxx" +#include "XMLBase64ImportContext.hxx" #include "txtstyli.hxx" #include "xmlimp.hxx" @@ -73,6 +74,174 @@ std::map &XMLStylesContext::GetCurrentGr return m_rGraphicStyles; } +/// Handler for . +class XMLFontFaceContext : public XMLImportContext +{ +public: + XMLFontFaceContext(XMLImport &rImport); + void SAL_CALL startElement(const OUString &rName, const css::uno::Reference &xAttribs) override; + + rtl::Reference CreateChildContext(const OUString &rName, const css::uno::Reference &xAttribs) override; + + OUString maName; +}; + +/// Handler for . +class XMLFontFaceSrcContext : public XMLImportContext +{ +public: + XMLFontFaceSrcContext(XMLImport &rImport, XMLFontFaceContext &rFontFace); + + rtl::Reference CreateChildContext(const OUString &rName, const css::uno::Reference &xAttribs) override; + +private: + XMLFontFaceContext &mrFontFace; +}; + +/// Handler for . +class XMLFontFaceUriContext : public XMLImportContext +{ +public: + XMLFontFaceUriContext(XMLImport &rImport, XMLFontFaceContext &rFontFace); + void SAL_CALL startElement(const OUString &rName, const css::uno::Reference &xAttribs) override; + void SAL_CALL endElement(const OUString &rName) override; + + rtl::Reference CreateChildContext(const OUString &rName, const css::uno::Reference &xAttribs) override; + + librevenge::RVNGPropertyList maPropertyList; + +private: + rtl::Reference mxBinaryData; +}; + +/// Handler for . +class XMLFontFaceFormatContext : public XMLImportContext +{ +public: + XMLFontFaceFormatContext(XMLImport &rImport, XMLFontFaceUriContext &rFontUri); + void SAL_CALL startElement(const OUString &rName, const css::uno::Reference &xAttribs) override; + +private: + XMLFontFaceUriContext &mrFontFaceUri; +}; + +XMLFontFaceFormatContext::XMLFontFaceFormatContext(XMLImport &rImport, XMLFontFaceUriContext &rFontFaceUri) + : XMLImportContext(rImport) + , mrFontFaceUri(rFontFaceUri) +{ +} + +void XMLFontFaceFormatContext::startElement(const OUString &/*rName*/, const css::uno::Reference &xAttribs) +{ + for (sal_Int16 i = 0; i < xAttribs->getLength(); ++i) + { + const OUString &rAttributeName = xAttribs->getNameByIndex(i); + const OUString &rAttributeValue = xAttribs->getValueByIndex(i); + if (rAttributeName == "svg:string") + { + OString aAttributeValueU8 = OUStringToOString(rAttributeValue, RTL_TEXTENCODING_UTF8); + mrFontFaceUri.maPropertyList.insert("librevenge:mime-type", aAttributeValueU8.getStr()); + } + } +} + +XMLFontFaceUriContext::XMLFontFaceUriContext(XMLImport &rImport, XMLFontFaceContext &rFontFace) + : XMLImportContext(rImport) +{ + OString aNameU8 = OUStringToOString(rFontFace.maName, RTL_TEXTENCODING_UTF8); + maPropertyList.insert("librevenge:name", aNameU8.getStr()); +} + +void XMLFontFaceUriContext::startElement(const OUString &/*rName*/, const css::uno::Reference &xAttribs) +{ + for (sal_Int16 i = 0; i < xAttribs->getLength(); ++i) + { + const OUString &rAttributeName = xAttribs->getNameByIndex(i); + const OUString &rAttributeValue = xAttribs->getValueByIndex(i); + if (rAttributeName == "loext:font-style") + { + OString aAttributeValueU8 = OUStringToOString(rAttributeValue, RTL_TEXTENCODING_UTF8); + maPropertyList.insert("librevenge:font-style", aAttributeValueU8.getStr()); + } + else if (rAttributeName == "loext:font-weight") + { + OString aAttributeValueU8 = OUStringToOString(rAttributeValue, RTL_TEXTENCODING_UTF8); + maPropertyList.insert("librevenge:font-weight", aAttributeValueU8.getStr()); + } + } +} + +void XMLFontFaceUriContext::endElement(const OUString &/*rName*/) +{ + if (mxBinaryData.is()) + maPropertyList.insert("office:binary-data", mxBinaryData->getBinaryData()); + mrImport.GetGenerator().defineEmbeddedFont(maPropertyList); +} + +rtl::Reference XMLFontFaceUriContext::CreateChildContext(const OUString &rName, const css::uno::Reference &/*xAttribs*/) +{ + if (rName == "office:binary-data") + { + mxBinaryData = new XMLBase64ImportContext(mrImport); + return mxBinaryData.get(); + } + if (rName == "svg:font-face-format") + return new XMLFontFaceFormatContext(mrImport, *this); + + SAL_WARN("writerperfect", "XMLFontFaceUriContext::CreateChildContext: unhandled " << rName); + return nullptr; +} + +XMLFontFaceSrcContext::XMLFontFaceSrcContext(XMLImport &rImport, XMLFontFaceContext &rFontFace) + : XMLImportContext(rImport) + , mrFontFace(rFontFace) +{ +} + +rtl::Reference XMLFontFaceSrcContext::CreateChildContext(const OUString &rName, const css::uno::Reference &/*xAttribs*/) +{ + if (rName == "svg:font-face-uri") + return new XMLFontFaceUriContext(mrImport, mrFontFace); + SAL_WARN("writerperfect", "XMLFontFaceSrcContext::CreateChildContext: unhandled " << rName); + return nullptr; +} + +XMLFontFaceContext::XMLFontFaceContext(XMLImport &rImport) + : XMLImportContext(rImport) +{ +} + +void XMLFontFaceContext::startElement(const OUString &/*rName*/, const css::uno::Reference &xAttribs) +{ + for (sal_Int16 i = 0; i < xAttribs->getLength(); ++i) + { + const OUString &rAttributeName = xAttribs->getNameByIndex(i); + const OUString &rAttributeValue = xAttribs->getValueByIndex(i); + if (rAttributeName == "style:name") + maName = rAttributeValue; + } +} + +rtl::Reference XMLFontFaceContext::CreateChildContext(const OUString &rName, const css::uno::Reference &/*xAttribs*/) +{ + if (rName == "svg:font-face-src") + return new XMLFontFaceSrcContext(mrImport, *this); + SAL_WARN("writerperfect", "XMLFontFaceContext::CreateChildContext: unhandled " << rName); + return nullptr; +} + +XMLFontFaceDeclsContext::XMLFontFaceDeclsContext(XMLImport &rImport) + : XMLImportContext(rImport) +{ +} + +rtl::Reference XMLFontFaceDeclsContext::CreateChildContext(const OUString &rName, const css::uno::Reference &/*xAttribs*/) +{ + if (rName == "style:font-face") + return new XMLFontFaceContext(mrImport); + return nullptr; +} + } // namespace exp } // namespace writerperfect diff --git a/writerperfect/source/writer/exp/xmlfmt.hxx b/writerperfect/source/writer/exp/xmlfmt.hxx index f4d82273b4f1..3f609e98b000 100644 --- a/writerperfect/source/writer/exp/xmlfmt.hxx +++ b/writerperfect/source/writer/exp/xmlfmt.hxx @@ -46,6 +46,15 @@ private: std::map &m_rGraphicStyles; }; +/// Handler for . +class XMLFontFaceDeclsContext : public XMLImportContext +{ +public: + XMLFontFaceDeclsContext(XMLImport &rImport); + + rtl::Reference CreateChildContext(const OUString &rName, const css::uno::Reference &xAttribs) override; +}; + } // namespace exp } // namespace writerperfect diff --git a/writerperfect/source/writer/exp/xmlimp.cxx b/writerperfect/source/writer/exp/xmlimp.cxx index b301cb3deb0f..30a7ee03d404 100644 --- a/writerperfect/source/writer/exp/xmlimp.cxx +++ b/writerperfect/source/writer/exp/xmlimp.cxx @@ -66,6 +66,8 @@ rtl::Reference XMLOfficeDocContext::CreateChildContext(const O return new XMLStylesContext(mrImport, /*bAutomatic=*/true); else if (rName == "office:styles") return new XMLStylesContext(mrImport, /*bAutomatic=*/false); + else if (rName == "office:font-face-decls") + return new XMLFontFaceDeclsContext(mrImport); return nullptr; } -- cgit