include/vcl/embeddedfontshelper.hxx | 3 sw/qa/writerfilter/dmapper/FontTable.cxx | 18 +++++ sw/qa/writerfilter/dmapper/data/subsetted-full-embedded-font.docx |binary sw/source/writerfilter/dmapper/FontTable.cxx | 15 ++-- sw/source/writerfilter/dmapper/FontTable.hxx | 3 vcl/source/gdi/embeddedfontshelper.cxx | 34 +++++++++- 6 files changed, 62 insertions(+), 11 deletions(-)
New commits: commit 09da7fd9cec9b36f2e09c1105a9263b83e2c66e4 Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Tue Jul 16 14:49:23 2024 +0200 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Tue Jul 16 17:21:05 2024 +0200 tdf#162002 DOCX import, font embed: only discard subset fonts with few glyphs Commit a9f3c11375525a7708378dd3648febc40db1ad20 (tdf#162002 DOCX import: ignore subsetted embedded fonts for editing, 2024-07-12) decided to ignore all subsetted fonts for editing, improve this a little so we only ignore subsetted fonts when they can't even provide an English alphabet in any form (lowercase, uppercase). This avoids the possible problem that a font is marked as subsetted but it's good enough in practice and we would still throw it away for editing. Change-Id: I0bc0e14ffc0c039f029220991bd16d9e3254f059 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/170570 Reviewed-by: Miklos Vajna <vmik...@collabora.com> Tested-by: Jenkins diff --git a/include/vcl/embeddedfontshelper.hxx b/include/vcl/embeddedfontshelper.hxx index cbf91ee7f09b..404afac13ec1 100644 --- a/include/vcl/embeddedfontshelper.hxx +++ b/include/vcl/embeddedfontshelper.hxx @@ -66,7 +66,8 @@ public: */ bool addEmbeddedFont( const css::uno::Reference< css::io::XInputStream >& stream, const OUString& fontName, std::u16string_view extra, - std::vector< unsigned char > const & key, bool eot = false); + std::vector< unsigned char > const & key, bool eot = false, + bool bSubsetted = false); /** Returns a URL for a file where to store contents of a given temporary font. diff --git a/sw/qa/writerfilter/dmapper/FontTable.cxx b/sw/qa/writerfilter/dmapper/FontTable.cxx index 798d68d0a193..2fe3dced2e1f 100644 --- a/sw/qa/writerfilter/dmapper/FontTable.cxx +++ b/sw/qa/writerfilter/dmapper/FontTable.cxx @@ -39,6 +39,24 @@ CPPUNIT_TEST_FIXTURE(Test, testSubsettedEmbeddedFont) // during editing may be missing from the subsetted font: CPPUNIT_ASSERT(aUrl.isEmpty()); } + +CPPUNIT_TEST_FIXTURE(Test, testSubsettedFullEmbeddedFont) +{ +#if !defined(MACOSX) // FIXME fails on macOS + // Given a document with an embedded font (marked as subsetted, but otherwise full in practice), + // loaded for editing: + loadFromFile(u"subsetted-full-embedded-font.docx"); + + // When checking if the font is available: + OUString aUrl = EmbeddedFontsHelper::fontFileUrl( + u"IBM Plex Serif Light", FAMILY_ROMAN, ITALIC_NONE, WEIGHT_NORMAL, PITCH_VARIABLE, + EmbeddedFontsHelper::FontRights::ViewingAllowed); + + // Then make sure the subsetted font is available, given that it has the reasonable amount of + // glyphs: + CPPUNIT_ASSERT(!aUrl.isEmpty()); +#endif +} } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/qa/writerfilter/dmapper/data/subsetted-full-embedded-font.docx b/sw/qa/writerfilter/dmapper/data/subsetted-full-embedded-font.docx new file mode 100644 index 000000000000..7cdbaf271d6b Binary files /dev/null and b/sw/qa/writerfilter/dmapper/data/subsetted-full-embedded-font.docx differ diff --git a/sw/source/writerfilter/dmapper/FontTable.cxx b/sw/source/writerfilter/dmapper/FontTable.cxx index 3262d732e2fb..7cc8a39b3ef1 100644 --- a/sw/source/writerfilter/dmapper/FontTable.cxx +++ b/sw/source/writerfilter/dmapper/FontTable.cxx @@ -236,11 +236,13 @@ bool FontTable::IsReadOnly() const void FontTable::addEmbeddedFont(const css::uno::Reference<css::io::XInputStream>& stream, const OUString& fontName, std::u16string_view extra, - std::vector<unsigned char> const & key) + std::vector<unsigned char> const & key, + bool bSubsetted) { if (!m_pImpl->xEmbeddedFontHelper) m_pImpl->xEmbeddedFontHelper.reset(new EmbeddedFontsHelper); - m_pImpl->xEmbeddedFontHelper->addEmbeddedFont(stream, fontName, extra, key); + m_pImpl->xEmbeddedFontHelper->addEmbeddedFont(stream, fontName, extra, key, + /*eot=*/false, bSubsetted); } EmbeddedFontHandler::EmbeddedFontHandler(FontTable& rFontTable, OUString _fontName, std::u16string_view style ) @@ -256,11 +258,6 @@ EmbeddedFontHandler::~EmbeddedFontHandler() if( !m_inputStream.is()) return; - if (m_bSubsetted && !m_fontTable.IsReadOnly()) - { - return; - } - std::vector< unsigned char > key( 32 ); if( !m_fontKey.isEmpty()) { // key for unobfuscating @@ -280,7 +277,9 @@ EmbeddedFontHandler::~EmbeddedFontHandler() key[ i + 16 ] = val; } } - m_fontTable.addEmbeddedFont( m_inputStream, m_fontName, m_style, key ); + // Ignore the "subsetted" flag if we're not editing anyway. + bool bSubsetted = m_bSubsetted && !m_fontTable.IsReadOnly(); + m_fontTable.addEmbeddedFont( m_inputStream, m_fontName, m_style, key, bSubsetted ); m_inputStream->closeInput(); } diff --git a/sw/source/writerfilter/dmapper/FontTable.hxx b/sw/source/writerfilter/dmapper/FontTable.hxx index 9ad092befe79..babb43d8aebb 100644 --- a/sw/source/writerfilter/dmapper/FontTable.hxx +++ b/sw/source/writerfilter/dmapper/FontTable.hxx @@ -53,7 +53,8 @@ class FontTable : public LoggedProperties, public LoggedTable void addEmbeddedFont(const css::uno::Reference<css::io::XInputStream>& stream, const OUString& fontName, std::u16string_view extra, - std::vector<unsigned char> const & key); + std::vector<unsigned char> const & key, + bool bSubsetted); bool IsReadOnly() const; private: diff --git a/vcl/source/gdi/embeddedfontshelper.cxx b/vcl/source/gdi/embeddedfontshelper.cxx index 1ac57ce1b59a..a6a2b61676f7 100644 --- a/vcl/source/gdi/embeddedfontshelper.cxx +++ b/vcl/source/gdi/embeddedfontshelper.cxx @@ -66,7 +66,8 @@ void EmbeddedFontsHelper::clearTemporaryFontFiles() } bool EmbeddedFontsHelper::addEmbeddedFont( const uno::Reference< io::XInputStream >& stream, const OUString& fontName, - std::u16string_view extra, std::vector< unsigned char > const & key, bool eot ) + std::u16string_view extra, std::vector< unsigned char > const & key, bool eot, + bool bSubsetted ) { OUString fileUrl = EmbeddedFontsHelper::fileUrlForTemporaryFont( fontName, extra ); osl::File file( fileUrl ); @@ -159,6 +160,37 @@ bool EmbeddedFontsHelper::addEmbeddedFont( const uno::Reference< io::XInputStrea osl::File::remove( fileUrl ); return false; } + + if (bSubsetted) + { + TrueTypeFont* font; + sal_uInt32 nGlyphs = 0; + if (OpenTTFontBuffer(fontData.data(), fontData.size(), 0, &font) == SFErrCodes::Ok) + { + sal_uInt32 nGlyphCount = font->glyphCount(); + for (sal_uInt32 i = 0; i < nGlyphCount; ++i) + { + sal_uInt32 nOffset = font->glyphOffset(i); + sal_uInt32 nNextOffset = font->glyphOffset(i + 1); + if (nOffset == nNextOffset) + { + // GetTTGlyphComponents() says this is an empty glyph, ignore it. + continue; + } + ++nGlyphs; + } + CloseTTFont(font); + } + // Check if it has reasonable amount of glyphs, set the limit to the number of glyphs in the + // English alphabet (not differentiating lowercase and uppercase). + if (nGlyphs < 26) + { + SAL_INFO("vcl.fonts", "Ignoring embedded font that only provides " << nGlyphs << " non-empty glyphs"); + osl::File::remove(fileUrl); + return false; + } + } + m_aAccumulatedFonts.emplace_back(std::make_pair(fontName, fileUrl)); return true; }