gdi32: Move the handling of font family fallbacks out of freetype.c.

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Alexandre Julliard 2020-11-04 09:16:19 +01:00
parent caf0b9c082
commit 4cddf0d47d
3 changed files with 90 additions and 103 deletions

View File

@ -240,32 +240,25 @@ static const WCHAR liberation_sans[] = {'L','i','b','e','r','a','t','i','o','n',
static const WCHAR liberation_serif[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0};
static const WCHAR times_new_roman[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
static const WCHAR * const default_serif_list[] =
static const WCHAR * const default_serif_list[3] =
{
times_new_roman,
liberation_serif,
bitstream_vera_serif,
NULL
bitstream_vera_serif
};
static const WCHAR * const default_fixed_list[] =
static const WCHAR * const default_fixed_list[3] =
{
courier_new,
liberation_mono,
bitstream_vera_sans_mono,
NULL
bitstream_vera_sans_mono
};
static const WCHAR * const default_sans_list[] =
static const WCHAR * const default_sans_list[3] =
{
arial,
liberation_sans,
bitstream_vera_sans,
NULL
bitstream_vera_sans
};
const WCHAR *default_serif = times_new_roman;
const WCHAR *default_fixed = courier_new;
const WCHAR *default_sans = arial;
static const struct nls_update_font_list
{
UINT ansi_cp, oem_cp;
@ -732,26 +725,44 @@ static void dump_gdi_font_list(void)
}
}
static const WCHAR *set_default_family( const WCHAR * const *name_list )
static BOOL enum_fallbacks( DWORD pitch_and_family, int index, WCHAR buffer[LF_FACESIZE] )
{
if (index < 3)
{
const WCHAR * const *defaults;
if ((pitch_and_family & FIXED_PITCH) || (pitch_and_family & 0xf0) == FF_MODERN)
defaults = default_fixed_list;
else if ((pitch_and_family & 0xf0) == FF_ROMAN)
defaults = default_serif_list;
else
defaults = default_sans_list;
lstrcpynW( buffer, defaults[index], LF_FACESIZE );
return TRUE;
}
return font_funcs->enum_family_fallbacks( pitch_and_family, index - 3, buffer );
}
static void set_default_family( DWORD pitch_and_family )
{
struct gdi_font_family *family;
const WCHAR * const *entry;
WCHAR name[LF_FACESIZE];
int i = 0;
for (entry = name_list; *entry; entry++)
while (enum_fallbacks( pitch_and_family, i++, name ))
{
if (!(family = find_family_from_name( *entry ))) continue;
if (!(family = find_family_from_name( name ))) continue;
list_remove( &family->entry );
list_add_head( &font_list, &family->entry );
return *entry;
return;
}
return *name_list;
}
static void reorder_font_list(void)
{
default_serif = set_default_family( default_serif_list );
default_fixed = set_default_family( default_fixed_list );
default_sans = set_default_family( default_sans_list );
set_default_family( FF_ROMAN );
set_default_family( FF_MODERN );
set_default_family( FF_SWISS );
}
static void release_face( struct gdi_font_face *face )
@ -1483,14 +1494,28 @@ struct gdi_font_face *find_any_face( const LOGFONTW *lf, FONTSIGNATURE fs,
{
struct gdi_font_family *family;
struct gdi_font_face *face;
WCHAR name[LF_FACESIZE];
int i = 0;
/* first try only scalable */
/* first try the family fallbacks */
while (enum_fallbacks( lf->lfPitchAndFamily, i++, name ))
{
LIST_FOR_EACH_ENTRY( family, &font_list, struct gdi_font_family, entry )
{
if ((family->family_name[0] == '@') == !want_vertical) continue;
if (strcmpiW( family->family_name + want_vertical, name ) &&
strcmpiW( family->second_name + want_vertical, name )) continue;
if ((face = find_best_matching_face( family, lf, fs, FALSE ))) return face;
}
}
/* otherwise try only scalable */
LIST_FOR_EACH_ENTRY( family, &font_list, struct gdi_font_family, entry )
{
if ((family->family_name[0] == '@') == !want_vertical) continue;
if ((face = find_best_matching_face( family, lf, fs, FALSE ))) return face;
}
if (!can_use_bitmap) return NULL;
/* then also bitmap fonts */
LIST_FOR_EACH_ENTRY( family, &font_list, struct gdi_font_family, entry )
{
if ((family->family_name[0] == '@') == !want_vertical) continue;

View File

@ -1218,6 +1218,9 @@ static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
#ifdef SONAME_LIBFONTCONFIG
static BOOL fontconfig_enabled;
static FcPattern *pattern_serif;
static FcPattern *pattern_fixed;
static FcPattern *pattern_sans;
static UINT parse_aa_pattern( FcPattern *pattern )
{
@ -1242,6 +1245,23 @@ static UINT parse_aa_pattern( FcPattern *pattern )
return aa_flags;
}
static FcPattern *create_family_pattern( const char *name )
{
FcPattern *ret, *pattern = pFcPatternCreate();
FcResult result;
pFcPatternAddString( pattern, FC_FAMILY, (const FcChar8 *)name );
pFcPatternAddString( pattern, FC_NAMELANG, (const FcChar8 *)"en-us" );
pFcPatternAddString( pattern, FC_PRGNAME, (const FcChar8 *)"wine" );
pFcConfigSubstitute( NULL, pattern, FcMatchPattern );
pFcDefaultSubstitute( pattern );
ret = pFcFontMatch( NULL, pattern, &result );
pFcPatternDestroy( pattern );
if (ret && result == FcResultMatch) return ret;
pFcPatternDestroy( ret );
return NULL;
}
static void init_fontconfig(void)
{
void *fc_handle = dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW);
@ -1281,6 +1301,9 @@ static void init_fontconfig(void)
default_aa_flags = parse_aa_pattern( pattern );
pFcPatternDestroy( pattern );
}
pattern_serif = create_family_pattern( "serif" );
pattern_fixed = create_family_pattern( "monospace" );
pattern_sans = create_family_pattern( "sans" );
TRACE( "enabled, default flags = %x\n", default_aa_flags );
fontconfig_enabled = TRUE;
@ -2070,67 +2093,28 @@ done:
return ret;
}
#ifdef SONAME_LIBFONTCONFIG
static struct gdi_font_face *get_fontconfig_face( const LOGFONTW *lf, FONTSIGNATURE fs, BOOL want_vertical )
/*************************************************************
* fontconfig_enum_family_fallbacks
*/
static BOOL CDECL fontconfig_enum_family_fallbacks( DWORD pitch_and_family, int index,
WCHAR buffer[LF_FACESIZE] )
{
const char *name;
WCHAR nameW[LF_FACESIZE];
#ifdef SONAME_LIBFONTCONFIG
FcPattern *pat;
FcChar8 *str;
FcPattern *pat = NULL, *best = NULL;
FcResult result;
FcBool r;
int ret, i;
struct gdi_font_face *face = NULL;
if (!fs.fsCsb[0]) return NULL;
if ((pitch_and_family & FIXED_PITCH) || (pitch_and_family & 0xf0) == FF_MODERN) pat = pattern_fixed;
else if ((pitch_and_family & 0xf0) == FF_ROMAN) pat = pattern_serif;
else pat = pattern_sans;
if((lf->lfPitchAndFamily & FIXED_PITCH) ||
(lf->lfPitchAndFamily & 0xF0) == FF_MODERN)
name = "monospace";
else if((lf->lfPitchAndFamily & 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; pFcPatternGetString(best, FC_FAMILY, i, &str) == FcResultMatch; i++)
{
if (!want_vertical)
{
ret = MultiByteToWideChar(CP_UTF8, 0, (const char*)str, -1,
nameW, ARRAY_SIZE(nameW));
}
else
{
nameW[0] = '@';
ret = MultiByteToWideChar(CP_UTF8, 0, (const char*)str, -1,
nameW + 1, ARRAY_SIZE(nameW) - 1);
}
if (!ret) continue;
if ((face = find_matching_face_by_name( nameW, NULL, lf, fs, FALSE ))) break;
}
if (face) TRACE("got %s\n", wine_dbgstr_w(nameW));
end:
pFcPatternDestroy(pat);
pFcPatternDestroy(best);
return face;
}
if (!pat) return FALSE;
if (pFcPatternGetString( pat, FC_FAMILY, index, &str ) != FcResultMatch) return FALSE;
if (!MultiByteToWideChar( CP_UTF8, 0, (char *)str, -1, buffer, LF_FACESIZE ))
buffer[LF_FACESIZE - 1] = 0;
return TRUE;
#endif
return FALSE;
}
static DWORD get_ttc_offset( FT_Face ft_face, UINT face_index )
{
@ -2340,27 +2324,6 @@ static struct gdi_font * CDECL freetype_SelectFont( DC *dc, HFONT hfont )
want_vertical = (lf.lfFaceName[0] == '@');
/* Face families are in the top 4 bits of lfPitchAndFamily,
so mask with 0xF0 before testing */
if((lf.lfPitchAndFamily & FIXED_PITCH) ||
(lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
strcpyW(lf.lfFaceName, default_fixed);
else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
strcpyW(lf.lfFaceName, default_serif);
else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
strcpyW(lf.lfFaceName, default_sans);
else
strcpyW(lf.lfFaceName, default_sans);
if ((face = find_matching_face_by_name( lf.lfFaceName, NULL, &lf, csi.fs, can_use_bitmap )))
goto found_face;
#ifdef SONAME_LIBFONTCONFIG
/* Try FontConfig substitutions if the face isn't found */
if ((face = get_fontconfig_face( &lf, csi.fs, want_vertical ))) goto found_face;
#endif
if ((face = find_any_face( &lf, csi.fs, can_use_bitmap, want_vertical ))) goto found_face;
csi.fs.fsCsb[0] = 0;
if ((face = find_any_face( &lf, csi.fs, can_use_bitmap, want_vertical ))) goto found_face;
@ -4231,6 +4194,7 @@ static const struct font_backend_funcs font_funcs =
{
freetype_SelectFont,
freetype_load_fonts,
fontconfig_enum_family_fallbacks,
freetype_add_font,
freetype_add_mem_font,
freetype_load_font,

View File

@ -428,6 +428,7 @@ struct font_backend_funcs
struct gdi_font * (CDECL *pSelectFont)( DC *dc, HFONT hfont );
void (CDECL *load_fonts)(void);
BOOL (CDECL *enum_family_fallbacks)( DWORD pitch_and_family, int index, WCHAR buffer[LF_FACESIZE] );
INT (CDECL *add_font)( const WCHAR *file, DWORD flags );
INT (CDECL *add_mem_font)( void *ptr, SIZE_T size, DWORD flags );
@ -474,9 +475,6 @@ extern struct gdi_font *create_gdi_font( const struct gdi_font_face *face, const
const LOGFONTW *lf ) DECLSPEC_HIDDEN;
extern void *get_GSUB_vert_feature( struct gdi_font *font ) DECLSPEC_HIDDEN;
extern void font_init(void) DECLSPEC_HIDDEN;
extern const WCHAR *default_serif DECLSPEC_HIDDEN;
extern const WCHAR *default_fixed DECLSPEC_HIDDEN;
extern const WCHAR *default_sans DECLSPEC_HIDDEN;
/* freetype.c */