[PATCH 3/4] gdi32: Load font list directly from fontconfig cache.

Rémi Bernon rbernon at codeweavers.com
Mon Nov 16 02:56:51 CST 2020


Instead of going through the -slow- font matching.

Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---

This is not strictly speaking the same, but as we then parse the matched
font files ourselves, iterating the stored faces, I figure that we are
only using fontconfig here to list system font faces and not the fc font
replacement logic. Reading the caches directly gets us the list of fonts
directly in a more time efficient way.

 dlls/gdi32/freetype.c | 180 +++++++++++++++++++++++++++++-------------
 1 file changed, 126 insertions(+), 54 deletions(-)

diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c
index dfd816a451d..c73cd2f02e4 100644
--- a/dlls/gdi32/freetype.c
+++ b/dlls/gdi32/freetype.c
@@ -190,6 +190,20 @@ MAKE_FUNCPTR(FcPatternDestroy);
 MAKE_FUNCPTR(FcPatternGetBool);
 MAKE_FUNCPTR(FcPatternGetInteger);
 MAKE_FUNCPTR(FcPatternGetString);
+MAKE_FUNCPTR(FcConfigGetFontDirs);
+MAKE_FUNCPTR(FcConfigGetCurrent);
+MAKE_FUNCPTR(FcCacheCopySet);
+MAKE_FUNCPTR(FcCacheNumSubdir);
+MAKE_FUNCPTR(FcCacheSubdir);
+MAKE_FUNCPTR(FcDirCacheRead);
+MAKE_FUNCPTR(FcDirCacheUnload);
+MAKE_FUNCPTR(FcStrListCreate);
+MAKE_FUNCPTR(FcStrListDone);
+MAKE_FUNCPTR(FcStrListNext);
+MAKE_FUNCPTR(FcStrSetAdd);
+MAKE_FUNCPTR(FcStrSetCreate);
+MAKE_FUNCPTR(FcStrSetDestroy);
+MAKE_FUNCPTR(FcStrSetMember);
 #ifndef FC_NAMELANG
 #define FC_NAMELANG "namelang"
 #endif
@@ -1345,6 +1359,51 @@ static FcPattern *create_family_pattern( const char *name )
     return NULL;
 }
 
+static void fontconfig_add_font( FcPattern *pattern, DWORD flags )
+{
+    const char *unix_name, *format;
+    WCHAR *dos_name;
+    FcBool scalable;
+    DWORD aa_flags;
+    int face_index;
+
+    TRACE( "(%p %#x)\n", pattern, flags );
+
+    if (pFcPatternGetString( pattern, FC_FILE, 0, (FcChar8 **)&unix_name ) != FcResultMatch)
+        return;
+
+    if (pFcPatternGetBool( pattern, FC_SCALABLE, 0, &scalable ) != FcResultMatch)
+        scalable = FALSE;
+
+    if (pFcPatternGetString( pattern, FC_FONTFORMAT, 0, (FcChar8 **)&format ) != FcResultMatch)
+    {
+        TRACE( "ignoring unknown font format %s\n", debugstr_a(unix_name) );
+        return;
+    }
+
+    if (!strcmp( format, "Type 1" ))
+    {
+        TRACE( "ignoring Type 1 font %s\n", debugstr_a(unix_name) );
+        return;
+    }
+
+    if (!scalable && !(flags & ADDFONT_ALLOW_BITMAP))
+    {
+        TRACE( "ignoring non-scalable font %s\n", debugstr_a(unix_name) );
+        return;
+    }
+
+    if (!(aa_flags = parse_aa_pattern( pattern ))) aa_flags = default_aa_flags;
+    flags |= ADDFONT_AA_FLAGS(aa_flags);
+
+    if (pFcPatternGetInteger( pattern, FC_INDEX, 0, &face_index ) != FcResultMatch)
+        face_index = 0;
+
+    dos_name = get_dos_file_name( unix_name );
+    add_unix_face( unix_name, dos_name, NULL, 0, face_index, flags, NULL );
+    RtlFreeHeap( GetProcessHeap(), 0, dos_name );
+}
+
 static void init_fontconfig(void)
 {
     void *fc_handle = dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW);
@@ -1368,6 +1427,20 @@ static void init_fontconfig(void)
     LOAD_FUNCPTR(FcPatternGetBool);
     LOAD_FUNCPTR(FcPatternGetInteger);
     LOAD_FUNCPTR(FcPatternGetString);
+    LOAD_FUNCPTR(FcConfigGetFontDirs);
+    LOAD_FUNCPTR(FcConfigGetCurrent);
+    LOAD_FUNCPTR(FcCacheCopySet);
+    LOAD_FUNCPTR(FcCacheNumSubdir);
+    LOAD_FUNCPTR(FcCacheSubdir);
+    LOAD_FUNCPTR(FcDirCacheRead);
+    LOAD_FUNCPTR(FcDirCacheUnload);
+    LOAD_FUNCPTR(FcStrListCreate);
+    LOAD_FUNCPTR(FcStrListDone);
+    LOAD_FUNCPTR(FcStrListNext);
+    LOAD_FUNCPTR(FcStrSetAdd);
+    LOAD_FUNCPTR(FcStrSetCreate);
+    LOAD_FUNCPTR(FcStrSetDestroy);
+    LOAD_FUNCPTR(FcStrSetMember);
 #undef LOAD_FUNCPTR
 
     if (pFcInit())
@@ -1393,70 +1466,69 @@ static void init_fontconfig(void)
     }
 }
 
-static void load_fontconfig_fonts(void)
+static void fontconfig_add_fonts_from_dir_list( FcConfig *config, FcStrList *dir_list, FcStrSet *done_set, DWORD flags )
 {
-    FcPattern *pat;
-    FcFontSet *fontset;
-    const char *format;
-    int i, len;
-    char *file;
-    const char *ext;
-
-    if (!fontconfig_enabled) return;
+    const FcChar8 *dir;
+    FcFontSet *font_set;
+    FcStrList *subdir_list = NULL;
+    FcStrSet *subdir_set = NULL;
+    FcCache *cache = NULL;
+    int i;
 
-    pat = pFcPatternCreate();
-    if (!pat) return;
+    TRACE( "(%p %p %p %#x)\n", config, dir_list, done_set, flags );
 
-    fontset = pFcFontList(NULL, pat, NULL);
-    if (!fontset)
+    while ((dir = pFcStrListNext( dir_list )))
     {
-        pFcPatternDestroy(pat);
-        return;
+        if (pFcStrSetMember( done_set, dir )) continue;
+
+        TRACE( "adding fonts from %s\n", dir );
+        if (!(cache = pFcDirCacheRead( dir, FcFalse, config ))) continue;
+
+        if (!(font_set = pFcCacheCopySet( cache ))) goto done;
+        for (i = 0; i < font_set->nfont; i++)
+            fontconfig_add_font( font_set->fonts[i], flags );
+        pFcFontSetDestroy( font_set );
+        font_set = NULL;
+
+        if (!(subdir_set = pFcStrSetCreate())) goto done;
+        for (i = 0; i < pFcCacheNumSubdir( cache ); i++)
+            pFcStrSetAdd( subdir_set, pFcCacheSubdir( cache, i ) );
+        pFcDirCacheUnload( cache );
+        cache = NULL;
+
+        if (!(subdir_list = pFcStrListCreate( subdir_set ))) goto done;
+        pFcStrSetDestroy( subdir_set );
+        subdir_set = NULL;
+
+        pFcStrSetAdd( done_set, dir );
+        fontconfig_add_fonts_from_dir_list( config, subdir_list, done_set, flags );
+        pFcStrListDone( subdir_list );
+        subdir_list = NULL;
     }
 
-    for(i = 0; i < fontset->nfont; i++) {
-        FcBool scalable;
-        DWORD aa_flags;
-
-        if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
-            continue;
-
-        pFcConfigSubstitute( NULL, fontset->fonts[i], FcMatchFont );
-
-        /* We're just interested in OT/TT fonts for now, so this hack just
-           picks up the scalable fonts without extensions .pf[ab] to save time
-           loading every other font */
-
-        if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
-        {
-            TRACE("not scalable\n");
-            continue;
-        }
+done:
+    if (font_set) pFcFontSetDestroy( font_set );
+    if (subdir_list) pFcStrListDone( subdir_list );
+    if (subdir_set) pFcStrSetDestroy( subdir_set );
+    if (cache) pFcDirCacheUnload( cache );
+}
 
-        if (pFcPatternGetString( fontset->fonts[i], FC_FONTFORMAT, 0, (FcChar8 **)&format ) != FcResultMatch)
-        {
-            TRACE( "ignoring unknown font format %s\n", debugstr_a(file) );
-            continue;
-        }
+static void load_fontconfig_fonts( void )
+{
+    FcStrList *dir_list = NULL;
+    FcStrSet *done_set = NULL;
+    FcConfig *config;
 
-        if (!strcmp( format, "Type 1" ))
-        {
-            TRACE( "ignoring Type 1 font %s\n", debugstr_a(file) );
-            continue;
-        }
+    if (!fontconfig_enabled) return;
+    if (!(config = pFcConfigGetCurrent())) goto done;
+    if (!(done_set = pFcStrSetCreate())) goto done;
+    if (!(dir_list = pFcConfigGetFontDirs( config ))) goto done;
 
-        aa_flags = parse_aa_pattern( fontset->fonts[i] );
-        TRACE("fontconfig: %s aa %x\n", file, aa_flags);
+    fontconfig_add_fonts_from_dir_list( config, dir_list, done_set, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE );
 
-        len = strlen( file );
-        if(len < 4) continue;
-        ext = &file[ len - 3 ];
-        if(_strnicmp(ext, "pfa", -1) && _strnicmp(ext, "pfb", -1))
-            AddFontToList(NULL, file, NULL, 0,
-                          ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE | ADDFONT_AA_FLAGS(aa_flags) );
-    }
-    pFcFontSetDestroy(fontset);
-    pFcPatternDestroy(pat);
+done:
+    if (dir_list) pFcStrListDone( dir_list );
+    if (done_set) pFcStrSetDestroy( done_set );
 }
 
 #elif defined(HAVE_CARBON_CARBON_H)
-- 
2.29.2




More information about the wine-devel mailing list