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