diff options
author | Po Lu <luangruo@yahoo.com> | 2022-04-21 03:09:22 +0000 |
---|---|---|
committer | Po Lu <luangruo@yahoo.com> | 2022-04-21 03:09:22 +0000 |
commit | 8c282d68bde6d8ef348da5ca30f697f6a47e5b81 (patch) | |
tree | 956add41fe468f4cc7c865550c1429a89d0fb5b7 /src/haiku_font_support.cc | |
parent | ab530ddeb57084993fbf5f5857f3f8f3b4ec606c (diff) | |
download | emacs-8c282d68bde6d8ef348da5ca30f697f6a47e5b81.tar.gz |
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.
Diffstat (limited to 'src/haiku_font_support.cc')
-rw-r--r-- | src/haiku_font_support.cc | 216 |
1 files changed, 187 insertions, 29 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 <https://www.gnu.org/licenses/>. */ #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; + } +} |