[poppler] poppler/CairoFontEngine.cc

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Wed Mar 16 09:20:33 UTC 2022


 poppler/CairoFontEngine.cc |  134 ++++++++++++++-------------------------------
 1 file changed, 44 insertions(+), 90 deletions(-)

New commits:
commit 11c63a7bb9bfc2c997883ba81ff5f39f81697704
Author: Oliver Sander <oliver.sander at tu-dresden.de>
Date:   Wed Mar 16 09:20:31 2022 +0000

    Rewrite Cairo font caching without hashing the entire font

diff --git a/poppler/CairoFontEngine.cc b/poppler/CairoFontEngine.cc
index 5b7d04bb..4d8609ee 100644
--- a/poppler/CairoFontEngine.cc
+++ b/poppler/CairoFontEngine.cc
@@ -42,6 +42,7 @@
 
 #include <cstring>
 #include <forward_list>
+#include <fstream>
 #include "CairoFontEngine.h"
 #include "CairoOutputDev.h"
 #include "GlobalParams.h"
@@ -53,13 +54,6 @@
 #include "Gfx.h"
 #include "Page.h"
 
-#if defined(HAVE_FCNTL_H) && defined(HAVE_SYS_MMAN_H) && defined(HAVE_SYS_STAT_H)
-#    include <fcntl.h>
-#    include <sys/stat.h>
-#    include <sys/mman.h>
-#    define CAN_CHECK_OPEN_FACES 1
-#endif
-
 //------------------------------------------------------------------------
 // CairoFont
 //------------------------------------------------------------------------
@@ -181,14 +175,18 @@ static bool _ft_new_face_uncached(FT_Library lib, const char *filename, char *fo
     return true;
 }
 
-#ifdef CAN_CHECK_OPEN_FACES
 struct _ft_face_data
 {
-    int fd;
-    unsigned long hash;
+    _ft_face_data() = default;
+
+    _ft_face_data(FT_Library libA, const char *filenameA, Ref embFontIDA) : size(0), bytes(nullptr), filename(filenameA ? filenameA : ""), embFontID(embFontIDA), lib(libA), face(nullptr), font_face(nullptr) { }
+
     size_t size;
     unsigned char *bytes;
 
+    std::string filename;
+    Ref embFontID;
+
     FT_Library lib;
     FT_Face face;
     cairo_font_face_t *font_face;
@@ -207,97 +205,57 @@ public:
 
 static thread_local std::forward_list<_FtFaceDataProxy> _local_open_faces;
 
-static unsigned long _djb_hash(const unsigned char *bytes, size_t len)
+static bool operator==(_ft_face_data &a, _ft_face_data &b)
 {
-    unsigned long hash = 5381;
-    while (len--) {
-        unsigned char c = *bytes++;
-        hash *= 33;
-        hash ^= c;
-    }
-    return hash;
-}
-
-static bool _ft_face_data_equal(struct _ft_face_data *a, struct _ft_face_data *b)
-{
-    if (a->lib != b->lib) {
-        return false;
-    }
-    if (a->size != b->size) {
+    if (a.lib != b.lib) {
         return false;
     }
-    if (a->hash != b->hash) {
+
+    if (a.embFontID != b.embFontID) {
         return false;
     }
 
-    return memcmp(a->bytes, b->bytes, a->size) == 0;
+    return a.filename == b.filename;
 }
 
 static void _ft_done_face(void *closure)
 {
     struct _ft_face_data *data = (struct _ft_face_data *)closure;
 
-    if (data->fd != -1) {
-#    if defined(__SUNPRO_CC) && defined(__sun) && defined(__SVR4)
-        munmap((char *)data->bytes, data->size);
-#    else
-        munmap(data->bytes, data->size);
-#    endif
-        close(data->fd);
-    } else {
+    if (data->bytes) {
         gfree(data->bytes);
     }
 
     FT_Done_Face(data->face);
-    gfree(data);
+    delete data;
 }
 
-static bool _ft_new_face(FT_Library lib, const char *filename, char *font_data, int font_data_len, FT_Face *face_out, cairo_font_face_t **font_face_out)
+static bool _ft_new_face(FT_Library lib, const char *filename, Ref embFontID, char *font_data, int font_data_len, FT_Face *face_out, cairo_font_face_t **font_face_out)
 {
-    struct stat st;
-    struct _ft_face_data tmpl;
-
-    tmpl.fd = -1;
+    struct _ft_face_data ft_face_data(lib, filename, embFontID);
 
     if (font_data == nullptr) {
-        /* if we fail to mmap the file, just pass it to FreeType instead */
-        tmpl.fd = openFileDescriptor(filename, O_RDONLY);
-        if (tmpl.fd == -1) {
-            return _ft_new_face_uncached(lib, filename, font_data, font_data_len, face_out, font_face_out);
-        }
 
-        if (fstat(tmpl.fd, &st) == -1) {
-            close(tmpl.fd);
+        /* if we fail to open the file, just pass it to FreeType instead */
+        std::ifstream font_data_fstream(filename, std::ios::binary);
+        if (!font_data_fstream.is_open()) {
             return _ft_new_face_uncached(lib, filename, font_data, font_data_len, face_out, font_face_out);
         }
 
-        tmpl.bytes = (unsigned char *)mmap(nullptr, st.st_size, PROT_READ, MAP_PRIVATE, tmpl.fd, 0);
-        if (tmpl.bytes == MAP_FAILED) {
-            close(tmpl.fd);
-            return _ft_new_face_uncached(lib, filename, font_data, font_data_len, face_out, font_face_out);
-        }
-        tmpl.size = st.st_size;
+        /* get length of file */
+        font_data_fstream.seekg(0, font_data_fstream.end);
+        ft_face_data.size = font_data_fstream.tellg();
     } else {
-        tmpl.bytes = (unsigned char *)font_data;
-        tmpl.size = font_data_len;
+        ft_face_data.bytes = (unsigned char *)font_data;
+        ft_face_data.size = font_data_len;
     }
 
     /* check to see if this is a duplicate of any of the currently open fonts */
-    tmpl.lib = lib;
-    tmpl.hash = _djb_hash(tmpl.bytes, tmpl.size);
-
     for (_FtFaceDataProxy &face_proxy : _local_open_faces) {
         _ft_face_data *l = static_cast<_ft_face_data *>(face_proxy);
-        if (_ft_face_data_equal(l, &tmpl)) {
-            if (tmpl.fd != -1) {
-#    if defined(__SUNPRO_CC) && defined(__sun) && defined(__SVR4)
-                munmap((char *)tmpl.bytes, tmpl.size);
-#    else
-                munmap(tmpl.bytes, tmpl.size);
-#    endif
-                close(tmpl.fd);
-            } else {
-                gfree(tmpl.bytes);
+        if ((*l) == ft_face_data) {
+            if (ft_face_data.bytes) {
+                gfree(ft_face_data.bytes);
             }
             *face_out = l->face;
             *font_face_out = cairo_font_face_reference(l->font_face);
@@ -306,23 +264,20 @@ static bool _ft_new_face(FT_Library lib, const char *filename, char *font_data,
     }
 
     /* not a dup, open and insert into list */
-    if (FT_New_Memory_Face(lib, (FT_Byte *)tmpl.bytes, tmpl.size, 0, &tmpl.face)) {
-        if (tmpl.fd != -1) {
-#    if defined(__SUNPRO_CC) && defined(__sun) && defined(__SVR4)
-            munmap((char *)tmpl.bytes, tmpl.size);
-#    else
-            munmap(tmpl.bytes, tmpl.size);
-#    endif
-
-            close(tmpl.fd);
+    if (font_data == nullptr) {
+        if (FT_New_Face(lib, filename, 0, &ft_face_data.face)) {
+            return false;
+        }
+    } else {
+        if (FT_New_Memory_Face(lib, (FT_Byte *)ft_face_data.bytes, ft_face_data.size, 0, &ft_face_data.face)) {
+            return false;
         }
-        return false;
     }
 
-    struct _ft_face_data *l = (struct _ft_face_data *)gmallocn(1, sizeof(struct _ft_face_data));
-    *l = tmpl;
+    struct _ft_face_data *l = new _ft_face_data;
+    *l = std::move(ft_face_data);
 
-    l->font_face = cairo_ft_font_face_create_for_ft_face(tmpl.face, FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP);
+    l->font_face = cairo_ft_font_face_create_for_ft_face(l->face, FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP);
     if (cairo_font_face_set_user_data(l->font_face, &_ft_cairo_key, l, _ft_done_face)) {
         cairo_font_face_destroy(l->font_face);
         _ft_done_face(l);
@@ -339,9 +294,6 @@ static bool _ft_new_face(FT_Library lib, const char *filename, char *font_data,
     *font_face_out = l->font_face;
     return true;
 }
-#else
-#    define _ft_new_face _ft_new_face_uncached
-#endif
 
 CairoFreeTypeFont::CairoFreeTypeFont(Ref refA, cairo_font_face_t *cairo_font_faceA, int *codeToGIDA, unsigned int codeToGIDLenA, bool substituteA) : CairoFont(refA, cairo_font_faceA, codeToGIDA, codeToGIDLenA, substituteA, true) { }
 
@@ -375,6 +327,8 @@ CairoFreeTypeFont *CairoFreeTypeFont::create(GfxFont *gfxFont, XRef *xref, FT_Li
     bool substitute = false;
 
     ref = *gfxFont->getID();
+    Ref embFontID = Ref::INVALID();
+    gfxFont->getEmbeddedFontID(&embFontID);
     fontType = gfxFont->getType();
 
     if (!(fontLoc = gfxFont->locateFont(xref, nullptr))) {
@@ -404,7 +358,7 @@ CairoFreeTypeFont *CairoFreeTypeFont::create(GfxFont *gfxFont, XRef *xref, FT_Li
     case fontType1:
     case fontType1C:
     case fontType1COT:
-        if (!_ft_new_face(lib, fileNameC, font_data, font_data_len, &face, &font_face)) {
+        if (!_ft_new_face(lib, fileNameC, embFontID, font_data, font_data_len, &face, &font_face)) {
             error(errSyntaxError, -1, "could not create type1 face");
             goto err2;
         }
@@ -472,7 +426,7 @@ CairoFreeTypeFont *CairoFreeTypeFont::create(GfxFont *gfxFont, XRef *xref, FT_Li
             codeToGID = ((Gfx8BitFont *)gfxFont)->getCodeToGIDMap(ff.get());
             codeToGIDLen = 256;
         }
-        if (!_ft_new_face(lib, fileNameC, font_data, font_data_len, &face, &font_face)) {
+        if (!_ft_new_face(lib, fileNameC, embFontID, font_data, font_data_len, &face, &font_face)) {
             error(errSyntaxError, -1, "could not create truetype face\n");
             goto err2;
         }
@@ -496,7 +450,7 @@ CairoFreeTypeFont *CairoFreeTypeFont::create(GfxFont *gfxFont, XRef *xref, FT_Li
             }
         }
 
-        if (!_ft_new_face(lib, fileNameC, font_data, font_data_len, &face, &font_face)) {
+        if (!_ft_new_face(lib, fileNameC, embFontID, font_data, font_data_len, &face, &font_face)) {
             error(errSyntaxError, -1, "could not create cid face\n");
             goto err2;
         }
@@ -529,7 +483,7 @@ CairoFreeTypeFont *CairoFreeTypeFont::create(GfxFont *gfxFont, XRef *xref, FT_Li
                 }
             }
         }
-        if (!_ft_new_face(lib, fileNameC, font_data, font_data_len, &face, &font_face)) {
+        if (!_ft_new_face(lib, fileNameC, embFontID, font_data, font_data_len, &face, &font_face)) {
             error(errSyntaxError, -1, "could not create cid (OT) face\n");
             goto err2;
         }


More information about the poppler mailing list