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:
parent
da2e51b3a6
commit
11ab9ff7b3
|
@ -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)
|
||||||
|
|
||||||
#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:
|
||||||
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 )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#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);
|
||||||
|
|
Loading…
Reference in New Issue