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 215f8155a7bb51e5268d3339cef153c137591b03
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Tue Jul 16 14:49:23 2024 +0200
Commit:     Xisco Fauli <xiscofa...@libreoffice.org>
CommitDate: Mon Jul 22 20:01:21 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
    (cherry picked from commit 09da7fd9cec9b36f2e09c1105a9263b83e2c66e4)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/170555
    Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org>

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;
 }

Reply via email to