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:
parent
caf0b9c082
commit
4cddf0d47d
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
Loading…
Reference in New Issue