From 8c282d68bde6d8ef348da5ca30f697f6a47e5b81 Mon Sep 17 00:00:00 2001 From: Po Lu Date: Thu, 21 Apr 2022 03:09:22 +0000 Subject: [PATCH] Use a cache on Haiku to avoid constantly reading fonts during font lookup * src/haiku_font_support.cc (struct font_object_cache_bucket): New struct. (language_code_points): Make `int'. (hash_string): New function. (cache_font_object_data, lookup_font_object_data) (font_object_has_chars): New functions. (font_check_wanted_chars, font_check_one_of) (font_check_language): Lookup in cached font object instead. (be_init_font_data, be_evict_font_cache): New functions. * src/haiku_support.h (struct haiku_font_pattern): Make `uint32_t's ints instead. * src/haikufont.c (haikufont_apply_registry, syms_of_haikufont): Adjust for those changes. * src/haikuterm.c (haiku_frame_up_to_date): Clear font lookup cache every 50 updates. --- src/haiku_font_support.cc | 216 +++++++++++++++++++++++++++++++++----- src/haiku_support.h | 6 +- src/haikufont.c | 4 +- src/haikuterm.c | 11 ++ 4 files changed, 205 insertions(+), 32 deletions(-) diff --git a/src/haiku_font_support.cc b/src/haiku_font_support.cc index 6bb934af5f4..8da2437d660 100644 --- a/src/haiku_font_support.cc +++ b/src/haiku_font_support.cc @@ -27,15 +27,111 @@ along with GNU Emacs. If not, see . */ #include "haiku_support.h" +/* Cache used during font lookup. It contains an opened font object + we can look inside, and some previously determined information. */ +struct font_object_cache_bucket +{ + struct font_object_cache_bucket *next; + unsigned int hash; + + BFont *font_object; +}; + +static struct font_object_cache_bucket *font_object_cache[2048]; + /* Haiku doesn't expose font language data in BFont objects. Thus, we select a few representative characters for each supported `:lang' (currently Chinese, Korean and Japanese,) and test for those instead. */ -static uint32_t language_code_points[MAX_LANGUAGE][4] = - {{20154, 20754, 22996, 0}, /* Chinese. */ - {51312, 49440, 44544, 0}, /* Korean. */ - {26085, 26412, 12371, 0}, /* Japanese. */}; +static int language_code_points[MAX_LANGUAGE][3] = + {{20154, 20754, 22996}, /* Chinese. */ + {51312, 49440, 44544}, /* Korean. */ + {26085, 26412, 12371}, /* Japanese. */}; + +static unsigned int +hash_string (const char *name_or_style) +{ + unsigned int i; + + i = 3323198485ul; + for (; *name_or_style; ++name_or_style) + { + i ^= *name_or_style; + i *= 0x5bd1e995; + i ^= i >> 15; + } + return i; +} + +static struct font_object_cache_bucket * +cache_font_object_data (const char *family, const char *style, + BFont *font_object) +{ + uint32_t hash; + struct font_object_cache_bucket *bucket, *next; + + hash = hash_string (family) ^ hash_string (style); + bucket = font_object_cache[hash % 2048]; + + for (next = bucket; next; next = next->next) + { + if (next->hash == hash) + { + delete next->font_object; + next->font_object = font_object; + + return next; + } + } + + next = new struct font_object_cache_bucket; + next->font_object = font_object; + next->hash = hash; + next->next = bucket; + font_object_cache[hash % 2048] = next; + return next; +} + +static struct font_object_cache_bucket * +lookup_font_object_data (const char *family, const char *style) +{ + uint32_t hash; + struct font_object_cache_bucket *bucket, *next; + + hash = hash_string (family) ^ hash_string (style); + bucket = font_object_cache[hash % 2048]; + + for (next = bucket; next; next = next->next) + { + if (next->hash == hash) + return next; + } + + return NULL; +} + +static bool +font_object_has_chars (struct font_object_cache_bucket *cached, + int *chars, int nchars, bool just_one_of) +{ + int i; + + for (i = 0; i < nchars; ++i) + { + if (just_one_of + && cached->font_object->IncludesBlock (chars[i], + chars[i])) + return true; + + if (!just_one_of + && !cached->font_object->IncludesBlock (chars[i], + chars[i])) + return false; + } + + return !just_one_of; +} static void estimate_font_ascii (BFont *font, int *max_width, @@ -299,54 +395,86 @@ static bool font_check_wanted_chars (struct haiku_font_pattern *pattern, font_family family, char *style) { - BFont ft; + BFont *ft; + static struct font_object_cache_bucket *cached; + unicode_block wanted_block; - if (ft.SetFamilyAndStyle (family, style) != B_OK) - return false; + cached = lookup_font_object_data (family, style); + if (cached) + ft = cached->font_object; + else + { + ft = new BFont; - for (int i = 0; i < pattern->want_chars_len; ++i) - if (!ft.IncludesBlock (pattern->wanted_chars[i], - pattern->wanted_chars[i])) - return false; + if (ft->SetFamilyAndStyle (family, style) != B_OK) + { + delete ft; + return false; + } - return true; + cached = cache_font_object_data (family, style, ft); + } + + return font_object_has_chars (cached, pattern->wanted_chars, + pattern->want_chars_len, false); } static bool font_check_one_of (struct haiku_font_pattern *pattern, font_family family, char *style) { - BFont ft; + BFont *ft; + static struct font_object_cache_bucket *cached; + unicode_block wanted_block; - if (ft.SetFamilyAndStyle (family, style) != B_OK) - return false; + cached = lookup_font_object_data (family, style); + if (cached) + ft = cached->font_object; + else + { + ft = new BFont; + + if (ft->SetFamilyAndStyle (family, style) != B_OK) + { + delete ft; + return false; + } - for (int i = 0; i < pattern->need_one_of_len; ++i) - if (ft.IncludesBlock (pattern->need_one_of[i], - pattern->need_one_of[i])) - return true; + cached = cache_font_object_data (family, style, ft); + } - return false; + return font_object_has_chars (cached, pattern->need_one_of, + pattern->need_one_of_len, true); } static bool font_check_language (struct haiku_font_pattern *pattern, font_family family, char *style) { - BFont ft; + BFont *ft; + static struct font_object_cache_bucket *cached; - if (ft.SetFamilyAndStyle (family, style) != B_OK) - return false; + cached = lookup_font_object_data (family, style); + if (cached) + ft = cached->font_object; + else + { + ft = new BFont; + + if (ft->SetFamilyAndStyle (family, style) != B_OK) + { + delete ft; + return false; + } + + cached = cache_font_object_data (family, style, ft); + } if (pattern->language == MAX_LANGUAGE) return false; - for (uint32_t *ch = (uint32_t *) - &language_code_points[pattern->language]; *ch; ch++) - if (!ft.IncludesBlock (*ch, *ch)) - return false; - - return true; + return font_object_has_chars (cached, language_code_points[pattern->language], + 3, false); } static bool @@ -645,3 +773,33 @@ be_list_font_families (size_t *length) return array; } + +void +be_init_font_data (void) +{ + memset (&font_object_cache, 0, sizeof font_object_cache); +} + +/* Free the font object cache. This is called every 50 updates of a + frame. */ +void +be_evict_font_cache (void) +{ + struct font_object_cache_bucket *bucket, *last; + int i; + + for (i = 0; i < 2048; ++i) + { + bucket = font_object_cache[i]; + + while (bucket) + { + last = bucket; + bucket = bucket->next; + delete last->font_object; + delete last; + } + + font_object_cache[i] = NULL; + } +} diff --git a/src/haiku_support.h b/src/haiku_support.h index dfcf83bf3b7..3f071f2b09e 100644 --- a/src/haiku_support.h +++ b/src/haiku_support.h @@ -304,8 +304,8 @@ struct haiku_font_pattern enum haiku_font_slant slant; enum haiku_font_width width; enum haiku_font_language language; - uint32_t *wanted_chars; - uint32_t *need_one_of; + int *wanted_chars; + int *need_one_of; int oblique_seen_p; }; @@ -633,6 +633,8 @@ extern void BMenu_add_title (void *, const char *); extern int be_plain_font_height (void); extern int be_string_width_with_plain_font (const char *); +extern void be_init_font_data (void); +extern void be_evict_font_cache (void); extern int be_get_display_screens (void); extern bool be_use_subpixel_antialiasing (void); extern const char *be_find_setting (const char *); diff --git a/src/haikufont.c b/src/haikufont.c index 960ca466bc0..7dd23fba7aa 100644 --- a/src/haikufont.c +++ b/src/haikufont.c @@ -137,7 +137,7 @@ haikufont_apply_registry (struct haiku_font_pattern *pattern, for (l = 0; uniquifier[l]; ++l); - uint32_t *a = xmalloc (l * sizeof *a); + int *a = xmalloc (l * sizeof *a); for (l = 0; uniquifier[l]; ++l) a[l] = uniquifier[l]; @@ -1111,4 +1111,6 @@ syms_of_haikufont (void) font_cache = list (Qnil); staticpro (&font_cache); + + be_init_font_data (); } diff --git a/src/haikuterm.c b/src/haikuterm.c index 64c657fef56..213641d6073 100644 --- a/src/haikuterm.c +++ b/src/haikuterm.c @@ -46,6 +46,10 @@ along with GNU Emacs. If not, see . */ struct haiku_display_info *x_display_list = NULL; extern frame_parm_handler haiku_frame_parm_handlers[]; +/* This is used to determine when to evict the font lookup cache, + which we do every 50 updates. */ +static int up_to_date_count; + static void **fringe_bmps; static int max_fringe_bmp = 0; @@ -231,6 +235,13 @@ haiku_frame_up_to_date (struct frame *f) FRAME_MOUSE_UPDATE (f); if (FRAME_DIRTY_P (f) && !buffer_flipping_blocked_p ()) haiku_flip_buffers (f); + + up_to_date_count++; + if (up_to_date_count == 50) + { + be_evict_font_cache (); + up_to_date_count = 0; + } unblock_input (); } -- 2.39.2