Commit 11ab9ff7 authored by Akihiro Sagawa's avatar Akihiro Sagawa Committed by Alexandre Julliard

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: 's avatarAkihiro Sagawa <sagawa.aki@gmail.com> Signed-off-by: 's avatarHuw Davies <huw@codeweavers.com> Signed-off-by: 's avatarAlexandre Julliard <julliard@winehq.org>
parent da2e51b3
...@@ -173,9 +173,12 @@ static FT_Error (*pFT_Library_SetLcdFilter)(FT_Library, FT_LcdFilter); ...@@ -173,9 +173,12 @@ static FT_Error (*pFT_Library_SetLcdFilter)(FT_Library, FT_LcdFilter);
#ifdef SONAME_LIBFONTCONFIG #ifdef SONAME_LIBFONTCONFIG
#include <fontconfig/fontconfig.h> #include <fontconfig/fontconfig.h>
MAKE_FUNCPTR(FcConfigSubstitute); MAKE_FUNCPTR(FcConfigSubstitute);
MAKE_FUNCPTR(FcDefaultSubstitute);
MAKE_FUNCPTR(FcFontList); MAKE_FUNCPTR(FcFontList);
MAKE_FUNCPTR(FcFontMatch);
MAKE_FUNCPTR(FcFontSetDestroy); MAKE_FUNCPTR(FcFontSetDestroy);
MAKE_FUNCPTR(FcInit); MAKE_FUNCPTR(FcInit);
MAKE_FUNCPTR(FcPatternAddString);
MAKE_FUNCPTR(FcPatternCreate); MAKE_FUNCPTR(FcPatternCreate);
MAKE_FUNCPTR(FcPatternDestroy); MAKE_FUNCPTR(FcPatternDestroy);
MAKE_FUNCPTR(FcPatternGetBool); MAKE_FUNCPTR(FcPatternGetBool);
...@@ -2790,9 +2793,12 @@ static void init_fontconfig(void) ...@@ -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;} #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(FcConfigSubstitute);
LOAD_FUNCPTR(FcDefaultSubstitute);
LOAD_FUNCPTR(FcFontList); LOAD_FUNCPTR(FcFontList);
LOAD_FUNCPTR(FcFontMatch);
LOAD_FUNCPTR(FcFontSetDestroy); LOAD_FUNCPTR(FcFontSetDestroy);
LOAD_FUNCPTR(FcInit); LOAD_FUNCPTR(FcInit);
LOAD_FUNCPTR(FcPatternAddString);
LOAD_FUNCPTR(FcPatternCreate); LOAD_FUNCPTR(FcPatternCreate);
LOAD_FUNCPTR(FcPatternDestroy); LOAD_FUNCPTR(FcPatternDestroy);
LOAD_FUNCPTR(FcPatternGetBool); LOAD_FUNCPTR(FcPatternGetBool);
...@@ -5196,6 +5202,82 @@ done: ...@@ -5196,6 +5202,82 @@ done:
return ret; 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) static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
{ {
const GSUB_ScriptList *script; const GSUB_ScriptList *script;
...@@ -5584,6 +5666,12 @@ static HFONT freetype_SelectFont( PHYSDEV dev, HFONT hfont, UINT *aa_flags ) ...@@ -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; last_resort_family = NULL;
LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) { LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
font_link = find_font_link(family->FamilyName); font_link = find_font_link(family->FamilyName);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment