emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

master 8c282d68bd: Use a cache on Haiku to avoid constantly reading font


From: Po Lu
Subject: master 8c282d68bd: Use a cache on Haiku to avoid constantly reading fonts during font lookup
Date: Wed, 20 Apr 2022 23:09:45 -0400 (EDT)

branch: master
commit 8c282d68bde6d8ef348da5ca30f697f6a47e5b81
Author: Po Lu <luangruo@yahoo.com>
Commit: Po Lu <luangruo@yahoo.com>

    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 6bb934af5f..8da2437d66 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;
+    }
+}
diff --git a/src/haiku_support.h b/src/haiku_support.h
index dfcf83bf3b..3f071f2b09 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 960ca466bc..7dd23fba7a 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 64c657fef5..213641d607 100644
--- a/src/haikuterm.c
+++ b/src/haikuterm.c
@@ -46,6 +46,10 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
 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 ();
 }
 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]