Akihiro Sagawa : gdi32: Try Fontconfig substitutions when the font face is missing.

Alexandre Julliard julliard at winehq.org
Thu Nov 29 15:33:00 CST 2018


Module: wine
Branch: master
Commit: 11ab9ff7b3c43bb41c0325fe9417b1d7f44ad516
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=11ab9ff7b3c43bb41c0325fe9417b1d7f44ad516

Author: Akihiro Sagawa <sagawa.aki at gmail.com>
Date:   Wed Nov 28 00:50:20 2018 +0900

gdi32: Try Fontconfig substitutions when the font face is missing.

This improves font selection. With this patch, we can choose a decent
font family by Fontconfig.

Otherwise, Wine chooses some fonts based on supported charset, e.g. Droid
Sans Fallback. Droid Sans Fallback supports various scripts including
Japanese. However, as it's a fallback font, it doesn't have Latin alphabet
glyphs. If the font is chosen, typically Japanese Ubuntu environment, users
see a lot of squares instead of Latin alphabets.

This patch asks Fontconfig for the best font for the current locale. If the
font is returned and matches requested charset, the font is used. If failure,
it fallbacks to existing procedure.

Signed-off-by: Akihiro Sagawa <sagawa.aki at gmail.com>
Signed-off-by: Huw Davies <huw at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/gdi32/freetype.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 88 insertions(+)

diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c
index 5a47272..441a771 100644
--- a/dlls/gdi32/freetype.c
+++ b/dlls/gdi32/freetype.c
@@ -173,9 +173,12 @@ static FT_Error (*pFT_Library_SetLcdFilter)(FT_Library, FT_LcdFilter);
 #ifdef SONAME_LIBFONTCONFIG
 #include <fontconfig/fontconfig.h>
 MAKE_FUNCPTR(FcConfigSubstitute);
+MAKE_FUNCPTR(FcDefaultSubstitute);
 MAKE_FUNCPTR(FcFontList);
+MAKE_FUNCPTR(FcFontMatch);
 MAKE_FUNCPTR(FcFontSetDestroy);
 MAKE_FUNCPTR(FcInit);
+MAKE_FUNCPTR(FcPatternAddString);
 MAKE_FUNCPTR(FcPatternCreate);
 MAKE_FUNCPTR(FcPatternDestroy);
 MAKE_FUNCPTR(FcPatternGetBool);
@@ -2790,9 +2793,12 @@ static void init_fontconfig(void)
 
 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fc_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); return;}
     LOAD_FUNCPTR(FcConfigSubstitute);
+    LOAD_FUNCPTR(FcDefaultSubstitute);
     LOAD_FUNCPTR(FcFontList);
+    LOAD_FUNCPTR(FcFontMatch);
     LOAD_FUNCPTR(FcFontSetDestroy);
     LOAD_FUNCPTR(FcInit);
+    LOAD_FUNCPTR(FcPatternAddString);
     LOAD_FUNCPTR(FcPatternCreate);
     LOAD_FUNCPTR(FcPatternDestroy);
     LOAD_FUNCPTR(FcPatternGetBool);
@@ -5196,6 +5202,82 @@ done:
     return ret;
 }
 
+#ifdef SONAME_LIBFONTCONFIG
+static Family* get_fontconfig_family(DWORD pitch_and_family, const CHARSETINFO *csi)
+{
+    const char *name;
+    WCHAR nameW[LF_FACESIZE];
+    FcChar8 *str;
+    FcPattern *pat = NULL, *best = NULL;
+    FcResult result;
+    FcBool r;
+    int ret, i;
+    Family *family = NULL;
+
+    if (!csi->fs.fsCsb[0]) return NULL;
+
+    if((pitch_and_family & FIXED_PITCH) ||
+       (pitch_and_family & 0xF0) == FF_MODERN)
+        name = "monospace";
+    else if((pitch_and_family & 0xF0) == FF_ROMAN)
+        name = "serif";
+    else
+        name = "sans-serif";
+
+    pat = pFcPatternCreate();
+    if (!pat) return NULL;
+    r = pFcPatternAddString(pat, FC_FAMILY, (const FcChar8 *)name);
+    if (!r) goto end;
+    r = pFcPatternAddString(pat, FC_NAMELANG, (const FcChar8 *)"en-us");
+    if (!r) goto end;
+    r = pFcPatternAddString(pat, FC_PRGNAME, (const FcChar8 *)"wine");
+    if (!r) goto end;
+    r = pFcConfigSubstitute(NULL, pat, FcMatchPattern);
+    if (!r) goto end;
+    pFcDefaultSubstitute(pat);
+
+    best = pFcFontMatch(NULL, pat, &result);
+    if (!best || result != FcResultMatch) goto end;
+
+    for (i = 0;
+         !family && pFcPatternGetString(best, FC_FAMILY, i, &str) == FcResultMatch;
+         i++)
+    {
+        Face *face;
+        const SYSTEM_LINKS *font_link;
+        const struct list *face_list;
+
+        ret = MultiByteToWideChar(CP_UTF8, 0, (const char*)str, -1,
+                                  nameW, ARRAY_SIZE(nameW));
+        if (!ret) continue;
+        family = find_family_from_any_name(nameW);
+        if (!family) continue;
+
+        font_link = find_font_link(family->FamilyName);
+        face_list = get_face_list_from_family(family);
+        LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
+            if (!face->scalable)
+                continue;
+            if (csi->fs.fsCsb[0] & face->fs.fsCsb[0])
+                goto found;
+            if (font_link != NULL &&
+                csi->fs.fsCsb[0] & font_link->fs.fsCsb[0])
+                goto found;
+        }
+        family = NULL;
+    }
+
+found:
+    if (family)
+        TRACE("got %s\n", wine_dbgstr_w(nameW));
+
+end:
+    if (!pat) pFcPatternDestroy(pat);
+    if (!best) pFcPatternDestroy(best);
+    return family;
+}
+#endif
+
 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
 {
     const GSUB_ScriptList *script;
@@ -5584,6 +5666,12 @@ static HFONT freetype_SelectFont( PHYSDEV dev, HFONT hfont, UINT *aa_flags )
         }
     }
 
+#ifdef SONAME_LIBFONTCONFIG
+    /* Try FontConfig substitutions if the face isn't found */
+    family = get_fontconfig_family(lf.lfPitchAndFamily, &csi);
+    if (family) goto found;
+#endif
+
     last_resort_family = NULL;
     LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
         font_link = find_font_link(family->FamilyName);




More information about the wine-cvs mailing list