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@gmail.com>
Signed-off-by: Huw Davies <huw@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Akihiro Sagawa 2018-11-28 00:50:20 +09:00 committed by Alexandre Julliard
parent da2e51b3a6
commit 11ab9ff7b3
1 changed files with 88 additions and 0 deletions

View File

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