Keeping them sorted with the vertical / default family rules.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com ---
This series brings another ~150ms prefix startup time improvement, from 1.65s to 1.50s execution time for "wine cmd /c exit" on average, when lot of system fonts are installed (for instance with the Noto fonts).
dlls/gdi32/font.c | 136 +++++++++++++++++++++++----------------------- 1 file changed, 68 insertions(+), 68 deletions(-)
diff --git a/dlls/gdi32/font.c b/dlls/gdi32/font.c index 6ad03df176b..ce3b2bc915f 100644 --- a/dlls/gdi32/font.c +++ b/dlls/gdi32/font.c @@ -56,7 +56,8 @@ static inline struct font_physdev *get_font_dev( PHYSDEV dev )
struct gdi_font_family { - struct list entry; + struct wine_rb_entry entry; + struct wine_rb_entry entry_second; unsigned int refcount; WCHAR family_name[LF_FACESIZE]; WCHAR second_name[LF_FACESIZE]; @@ -251,6 +252,9 @@ static const WCHAR * const default_sans_list[3] = L"Liberation Sans", L"Bitstream Vera Sans" }; +static WCHAR ff_roman_default[LF_FACESIZE]; +static WCHAR ff_modern_default[LF_FACESIZE]; +static WCHAR ff_swiss_default[LF_FACESIZE];
static const struct nls_update_font_list { @@ -530,7 +534,39 @@ static void load_gdi_font_subst(void)
/* font families */
-static struct list font_list = LIST_INIT(font_list); +static int family_namecmp( const WCHAR *str1, const WCHAR *str2 ) +{ + int prio1, prio2, vert1 = (str1[0] == '@' ? 1 : 0), vert2 = (str2[0] == '@' ? 1 : 0); + + if (!wcsnicmp( str1, ff_swiss_default, LF_FACESIZE - 1 )) prio1 = 0; + else if (!wcsnicmp( str1, ff_modern_default, LF_FACESIZE - 1 )) prio1 = 1; + else if (!wcsnicmp( str1, ff_roman_default, LF_FACESIZE - 1 )) prio1 = 2; + else prio1 = 3; + + if (!wcsnicmp( str2, ff_swiss_default, LF_FACESIZE - 1 )) prio2 = 0; + else if (!wcsnicmp( str2, ff_modern_default, LF_FACESIZE - 1 )) prio2 = 1; + else if (!wcsnicmp( str2, ff_roman_default, LF_FACESIZE - 1 )) prio2 = 2; + else prio2 = 3; + + if (prio1 != prio2) return prio1 - prio2; + if (vert1 != vert2) return vert1 - vert2; + return wcsnicmp( str1 + vert1, str2 + vert2, LF_FACESIZE - 1 ); +} + +static int family_name_compare( const void *key, const struct wine_rb_entry *entry ) +{ + const struct gdi_font_family *family = WINE_RB_ENTRY_VALUE( entry, const struct gdi_font_family, entry ); + return family_namecmp( (const WCHAR *)key, family->family_name ); +} + +static int family_second_name_compare( const void *key, const struct wine_rb_entry *entry ) +{ + const struct gdi_font_family *family = WINE_RB_ENTRY_VALUE( entry, const struct gdi_font_family, entry_second ); + return family_namecmp( (const WCHAR *)key, family->second_name ); +} + +static struct wine_rb_tree family_tree = { family_name_compare }; +static struct wine_rb_tree family_second_tree = { family_second_name_compare };
static struct gdi_font_family *create_family( const WCHAR *name, const WCHAR *second_name ) { @@ -546,7 +582,8 @@ static struct gdi_font_family *create_family( const WCHAR *name, const WCHAR *se else family->second_name[0] = 0; list_init( &family->faces ); family->replacement = NULL; - list_add_tail( &font_list, &family->entry ); + wine_rb_put( &family_tree, family->family_name, &family->entry ); + if (family->second_name[0]) wine_rb_put( &family_second_tree, family->second_name, &family->entry_second ); return family; }
@@ -554,30 +591,26 @@ static void release_family( struct gdi_font_family *family ) { if (--family->refcount) return; assert( list_empty( &family->faces )); - list_remove( &family->entry ); + wine_rb_remove( &family_tree, &family->entry ); + if (family->second_name[0]) wine_rb_remove( &family_second_tree, &family->entry_second ); if (family->replacement) release_family( family->replacement ); HeapFree( GetProcessHeap(), 0, family ); }
static struct gdi_font_family *find_family_from_name( const WCHAR *name ) { - struct gdi_font_family *family; - - LIST_FOR_EACH_ENTRY( family, &font_list, struct gdi_font_family, entry ) - if (!wcsnicmp( family->family_name, name, LF_FACESIZE - 1 )) return family; - return NULL; + struct wine_rb_entry *entry; + if (!(entry = wine_rb_get( &family_tree, name ))) return NULL; + return WINE_RB_ENTRY_VALUE( entry, struct gdi_font_family, entry ); }
static struct gdi_font_family *find_family_from_any_name( const WCHAR *name ) { + struct wine_rb_entry *entry; struct gdi_font_family *family; - - LIST_FOR_EACH_ENTRY( family, &font_list, struct gdi_font_family, entry ) - { - if (!wcsnicmp( family->family_name, name, LF_FACESIZE - 1 )) return family; - if (!wcsnicmp( family->second_name, name, LF_FACESIZE - 1 )) return family; - } - return NULL; + if ((family = find_family_from_name( name ))) return family; + if (!(entry = wine_rb_get( &family_second_tree, name ))) return NULL; + return WINE_RB_ENTRY_VALUE( entry, struct gdi_font_family, entry_second ); }
static const struct list *get_family_face_list( const struct gdi_font_family *family ) @@ -593,7 +626,7 @@ static struct gdi_font_face *find_face_from_filename( const WCHAR *file_name, co
TRACE( "looking for file %s name %s\n", debugstr_w(file_name), debugstr_w(family_name) );
- LIST_FOR_EACH_ENTRY( family, &font_list, struct gdi_font_family, entry ) + WINE_RB_FOR_EACH_ENTRY( family, &family_tree, struct gdi_font_family, entry ) { if (family_name && wcsnicmp( family_name, family->family_name, LF_FACESIZE - 1 )) continue; LIST_FOR_EACH_ENTRY( face, get_family_face_list(family), struct gdi_font_face, entry ) @@ -695,7 +728,7 @@ static void dump_gdi_font_list(void) struct gdi_font_family *family; struct gdi_font_face *face;
- LIST_FOR_EACH_ENTRY( family, &font_list, struct gdi_font_family, entry ) + WINE_RB_FOR_EACH_ENTRY( family, &family_tree, struct gdi_font_family, entry ) { TRACE( "Family: %s\n", debugstr_w(family->family_name) ); LIST_FOR_EACH_ENTRY( face, &family->faces, struct gdi_font_face, entry ) @@ -726,26 +759,27 @@ static BOOL enum_fallbacks( DWORD pitch_and_family, int index, WCHAR buffer[LF_F return font_funcs->enum_family_fallbacks( pitch_and_family, index - 3, buffer ); }
-static void set_default_family( DWORD pitch_and_family ) +static void set_default_family( DWORD pitch_and_family, WCHAR *default_name ) { - struct gdi_font_family *family; + struct wine_rb_entry *entry; WCHAR name[LF_FACESIZE]; int i = 0;
while (enum_fallbacks( pitch_and_family, i++, name )) { - if (!(family = find_family_from_name( name ))) continue; - list_remove( &family->entry ); - list_add_head( &font_list, &family->entry ); + if (!(entry = wine_rb_get( &family_tree, name ))) continue; + wine_rb_remove( &family_tree, entry ); + lstrcpynW( default_name, name, LF_FACESIZE - 1 ); + wine_rb_put( &family_tree, name, entry ); return; } }
static void reorder_font_list(void) { - set_default_family( FF_ROMAN ); - set_default_family( FF_MODERN ); - set_default_family( FF_SWISS ); + set_default_family( FF_ROMAN, ff_roman_default ); + set_default_family( FF_MODERN, ff_modern_default ); + set_default_family( FF_SWISS, ff_swiss_default ); }
static void release_face( struct gdi_font_face *face ) @@ -771,7 +805,7 @@ static int remove_font( const WCHAR *file, DWORD flags ) int count = 0;
EnterCriticalSection( &font_cs ); - LIST_FOR_EACH_ENTRY_SAFE( family, family_next, &font_list, struct gdi_font_family, entry ) + WINE_RB_FOR_EACH_ENTRY_DESTRUCTOR( family, family_next, &family_tree, struct gdi_font_family, entry ) { family->refcount++; LIST_FOR_EACH_ENTRY_SAFE( face, face_next, &family->faces, struct gdi_font_face, entry ) @@ -1018,38 +1052,6 @@ static void load_face_from_cache( HKEY hkey_family, struct gdi_font_family *fami } }
-/* move vertical fonts after their horizontal counterpart */ -/* assumes that font_list is already sorted by family name */ -static void reorder_vertical_fonts(void) -{ - struct gdi_font_family *family, *next, *vert_family; - struct list *ptr, *vptr; - struct list vertical_families = LIST_INIT( vertical_families ); - - LIST_FOR_EACH_ENTRY_SAFE( family, next, &font_list, struct gdi_font_family, entry ) - { - if (family->family_name[0] != '@') continue; - list_remove( &family->entry ); - list_add_tail( &vertical_families, &family->entry ); - } - - ptr = list_head( &font_list ); - vptr = list_head( &vertical_families ); - while (ptr && vptr) - { - family = LIST_ENTRY( ptr, struct gdi_font_family, entry ); - vert_family = LIST_ENTRY( vptr, struct gdi_font_family, entry ); - if (wcsicmp( family->family_name, vert_family->family_name + 1 ) > 0) - { - list_remove( vptr ); - list_add_before( ptr, vptr ); - vptr = list_head( &vertical_families ); - } - else ptr = list_next( &font_list, ptr ); - } - list_move_tail( &font_list, &vertical_families ); -} - static void load_font_list_from_cache(void) { DWORD size, family_index = 0; @@ -1074,8 +1076,6 @@ static void load_font_list_from_cache(void) release_family( family ); size = sizeof(buffer); } - - reorder_vertical_fonts(); }
static void add_face_to_cache( struct gdi_font_face *face ) @@ -1465,7 +1465,7 @@ static struct gdi_font_face *find_matching_face_by_name( const WCHAR *name, cons }
/* search by full face name */ - LIST_FOR_EACH_ENTRY( family, &font_list, struct gdi_font_family, entry ) + WINE_RB_FOR_EACH_ENTRY( family, &family_tree, struct gdi_font_family, entry ) LIST_FOR_EACH_ENTRY( face, get_family_face_list(family), struct gdi_font_face, entry ) if (!wcsnicmp( face->full_name, name, LF_FACESIZE - 1 ) && can_select_face( face, fs, can_use_bitmap )) @@ -1489,7 +1489,7 @@ static struct gdi_font_face *find_any_face( const LOGFONTW *lf, FONTSIGNATURE fs /* first try the family fallbacks */ while (enum_fallbacks( lf->lfPitchAndFamily, i++, name )) { - LIST_FOR_EACH_ENTRY( family, &font_list, struct gdi_font_family, entry ) + WINE_RB_FOR_EACH_ENTRY( family, &family_tree, struct gdi_font_family, entry ) { if ((family->family_name[0] == '@') == !want_vertical) continue; if (wcsicmp( family->family_name + want_vertical, name ) && @@ -1498,14 +1498,14 @@ static struct gdi_font_face *find_any_face( const LOGFONTW *lf, FONTSIGNATURE fs } } /* otherwise try only scalable */ - LIST_FOR_EACH_ENTRY( family, &font_list, struct gdi_font_family, entry ) + WINE_RB_FOR_EACH_ENTRY( family, &family_tree, 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 ) + WINE_RB_FOR_EACH_ENTRY( family, &family_tree, struct gdi_font_family, entry ) { if ((family->family_name[0] == '@') == !want_vertical) continue; if ((face = find_best_matching_face( family, lf, fs, can_use_bitmap ))) return face; @@ -2788,7 +2788,7 @@ static BOOL CDECL font_EnumFonts( PHYSDEV dev, LOGFONTW *lf, FONTENUMPROCW proc, } else face_name = lf->lfFaceName;
- LIST_FOR_EACH_ENTRY( family, &font_list, struct gdi_font_family, entry ) + WINE_RB_FOR_EACH_ENTRY( family, &family_tree, struct gdi_font_family, entry ) { if (!family_matches(family, face_name)) continue; LIST_FOR_EACH_ENTRY( face, get_family_face_list(family), struct gdi_font_face, entry ) @@ -2802,7 +2802,7 @@ static BOOL CDECL font_EnumFonts( PHYSDEV dev, LOGFONTW *lf, FONTENUMPROCW proc, else { TRACE( "charset %d\n", charset ); - LIST_FOR_EACH_ENTRY( family, &font_list, struct gdi_font_family, entry ) + WINE_RB_FOR_EACH_ENTRY( family, &family_tree, struct gdi_font_family, entry ) { face = LIST_ENTRY( list_head(get_family_face_list(family)), struct gdi_font_face, entry ); if (!enum_face_charsets( family, face, enum_charsets, count, proc, lparam, NULL )) @@ -7815,7 +7815,7 @@ static void update_external_font_keys( HKEY hkey )
/* enumerate the fonts and add external ones to the two keys */
- LIST_FOR_EACH_ENTRY( family, &font_list, struct gdi_font_family, entry ) + WINE_RB_FOR_EACH_ENTRY( family, &family_tree, struct gdi_font_family, entry ) { LIST_FOR_EACH_ENTRY( face, &family->faces, struct gdi_font_face, entry ) {
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/gdi32/font.c | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-)
diff --git a/dlls/gdi32/font.c b/dlls/gdi32/font.c index ce3b2bc915f..219cff68b61 100644 --- a/dlls/gdi32/font.c +++ b/dlls/gdi32/font.c @@ -618,29 +618,39 @@ static const struct list *get_family_face_list( const struct gdi_font_family *fa return family->replacement ? &family->replacement->faces : &family->faces; }
+static struct gdi_font_face *family_find_face_from_filename( struct gdi_font_family *family, const WCHAR *file_name ) +{ + struct gdi_font_face *face; + const WCHAR *file; + LIST_FOR_EACH_ENTRY( face, get_family_face_list(family), struct gdi_font_face, entry ) + { + if (!face->file) continue; + file = wcsrchr(face->file, '\'); + if (!file) file = face->file; + else file++; + if (wcsicmp( file, file_name )) continue; + face->refcount++; + return face; + } + return NULL; +} + static struct gdi_font_face *find_face_from_filename( const WCHAR *file_name, const WCHAR *family_name ) { struct gdi_font_family *family; struct gdi_font_face *face; - const WCHAR *file;
TRACE( "looking for file %s name %s\n", debugstr_w(file_name), debugstr_w(family_name) );
- WINE_RB_FOR_EACH_ENTRY( family, &family_tree, struct gdi_font_family, entry ) + if (!family_name) { - if (family_name && wcsnicmp( family_name, family->family_name, LF_FACESIZE - 1 )) continue; - LIST_FOR_EACH_ENTRY( face, get_family_face_list(family), struct gdi_font_face, entry ) - { - if (!face->file) continue; - file = wcsrchr(face->file, '\'); - if (!file) file = face->file; - else file++; - if (wcsicmp( file, file_name )) continue; - face->refcount++; - return face; - } + WINE_RB_FOR_EACH_ENTRY( family, &family_tree, struct gdi_font_family, entry ) + if ((face = family_find_face_from_filename( family, file_name ))) return face; + return NULL; } - return NULL; + + if (!(family = find_family_from_name( family_name ))) return NULL; + return family_find_face_from_filename( family, file_name ); }
static BOOL add_family_replacement( const WCHAR *new_name, const WCHAR *replace )
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/gdi32/font.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/dlls/gdi32/font.c b/dlls/gdi32/font.c index 219cff68b61..284446e4227 100644 --- a/dlls/gdi32/font.c +++ b/dlls/gdi32/font.c @@ -1493,19 +1493,20 @@ static 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]; + WCHAR name[LF_FACESIZE + 1]; int i = 0;
/* first try the family fallbacks */ while (enum_fallbacks( lf->lfPitchAndFamily, i++, name )) { - WINE_RB_FOR_EACH_ENTRY( family, &family_tree, struct gdi_font_family, entry ) + if (want_vertical) { - if ((family->family_name[0] == '@') == !want_vertical) continue; - if (wcsicmp( family->family_name + want_vertical, name ) && - wcsicmp( family->second_name + want_vertical, name )) continue; - if ((face = find_best_matching_face( family, lf, fs, FALSE ))) return face; + memmove(name + 1, name, min(lstrlenW(name), LF_FACESIZE)); + name[0] = '@'; } + + if (!(family = find_family_from_any_name(name))) continue; + if ((face = find_best_matching_face( family, lf, fs, FALSE ))) return face; } /* otherwise try only scalable */ WINE_RB_FOR_EACH_ENTRY( family, &family_tree, struct gdi_font_family, entry )
On Thu, Nov 12, 2020 at 12:39:52PM +0100, Rémi Bernon wrote:
Keeping them sorted with the vertical / default family rules.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com
This series brings another ~150ms prefix startup time improvement, from 1.65s to 1.50s execution time for "wine cmd /c exit" on average, when lot of system fonts are installed (for instance with the Noto fonts).
Nice!
I've sent in a v2 with renamed trees and entries which I think make it a little clearer.
Huw.