From 11ab9ff7b3c43bb41c0325fe9417b1d7f44ad516 Mon Sep 17 00:00:00 2001 From: Akihiro Sagawa Date: Wed, 28 Nov 2018 00:50:20 +0900 Subject: [PATCH] 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 Signed-off-by: Huw Davies Signed-off-by: Alexandre Julliard --- dlls/gdi32/freetype.c | 88 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c index 5a4727239c1..441a771e29a 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 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);