diff --git a/dlls/gdi32/font.c b/dlls/gdi32/font.c index e28471cb2eb..55030bf95bf 100644 --- a/dlls/gdi32/font.c +++ b/dlls/gdi32/font.c @@ -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; diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c index ababde731d7..464d58df09c 100644 --- a/dlls/gdi32/freetype.c +++ b/dlls/gdi32/freetype.c @@ -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, diff --git a/dlls/gdi32/gdi_private.h b/dlls/gdi32/gdi_private.h index 0345db44b7e..ef98fa0e8fd 100644 --- a/dlls/gdi32/gdi_private.h +++ b/dlls/gdi32/gdi_private.h @@ -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 */