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.
This commit is contained in:
parent
ab530ddeb5
commit
8c282d68bd
4 changed files with 205 additions and 32 deletions
|
@ -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;
|
||||
|
||||
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;
|
||||
if (ft->SetFamilyAndStyle (family, style) != B_OK)
|
||||
{
|
||||
delete ft;
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
cached = cache_font_object_data (family, style, ft);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 *);
|
||||
|
|
|
@ -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 ();
|
||||
}
|
||||
|
|
|
@ -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 ();
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue