mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-06-16 14:33:52 -04:00
font: cache top-level fonts
This greatly improves the performance when loading user-configured fallback fonts. Previously, we had to re-load these fallback fonts over and over again for each (new) glyph.
This commit is contained in:
parent
bf5ad13df0
commit
04edd96018
2 changed files with 65 additions and 2 deletions
65
font.c
65
font.c
|
|
@ -20,6 +20,12 @@
|
||||||
static FT_Library ft_lib;
|
static FT_Library ft_lib;
|
||||||
static mtx_t ft_lock;
|
static mtx_t ft_lock;
|
||||||
|
|
||||||
|
struct font_cache_entry {
|
||||||
|
uint64_t hash;
|
||||||
|
struct font *font;
|
||||||
|
};
|
||||||
|
static tll(struct font_cache_entry) font_cache = tll_init();
|
||||||
|
|
||||||
static const size_t cache_size = 512;
|
static const size_t cache_size = 512;
|
||||||
|
|
||||||
static void __attribute__((constructor))
|
static void __attribute__((constructor))
|
||||||
|
|
@ -33,6 +39,8 @@ init(void)
|
||||||
static void __attribute__((destructor))
|
static void __attribute__((destructor))
|
||||||
fini(void)
|
fini(void)
|
||||||
{
|
{
|
||||||
|
assert(tll_length(font_cache) == 0);
|
||||||
|
|
||||||
mtx_destroy(&ft_lock);
|
mtx_destroy(&ft_lock);
|
||||||
FT_Done_FreeType(ft_lib);
|
FT_Done_FreeType(ft_lib);
|
||||||
FcFini();
|
FcFini();
|
||||||
|
|
@ -212,6 +220,7 @@ from_font_set(FcPattern *pattern, FcFontSet *fonts, int start_idx, const font_li
|
||||||
font->is_fallback = is_fallback;
|
font->is_fallback = is_fallback;
|
||||||
font->pixel_size_fixup = scalable ? pixel_fixup : 1.;
|
font->pixel_size_fixup = scalable ? pixel_fixup : 1.;
|
||||||
font->bgr = fc_rgba == FC_RGBA_BGR || fc_rgba == FC_RGBA_VBGR;
|
font->bgr = fc_rgba == FC_RGBA_BGR || fc_rgba == FC_RGBA_VBGR;
|
||||||
|
font->ref_counter = 1;
|
||||||
|
|
||||||
if (is_fallback) {
|
if (is_fallback) {
|
||||||
font->fc_idx = 0;
|
font->fc_idx = 0;
|
||||||
|
|
@ -247,9 +256,49 @@ from_font_set(FcPattern *pattern, FcFontSet *fonts, int start_idx, const font_li
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct font *
|
static uint64_t
|
||||||
from_name(const char *base_name, const font_list_t *fallbacks, const char *attributes, bool is_fallback)
|
hash_font(const char *base_name, const font_list_t *fallbacks,
|
||||||
|
const char *attributes, bool is_fallback)
|
||||||
{
|
{
|
||||||
|
#define rot(h, n) (((h) << (n)) | ((h) >> (64 - (n))))
|
||||||
|
|
||||||
|
/* TODO: better string hash */
|
||||||
|
uint64_t hash = 0;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < strlen(base_name); i++)
|
||||||
|
hash = rot(hash, 7) ^ base_name[i];
|
||||||
|
|
||||||
|
if (fallbacks != NULL) {
|
||||||
|
tll_foreach(*fallbacks, it) {
|
||||||
|
for (size_t i = 0; i < strlen(it->item); i++)
|
||||||
|
hash = rot(hash, 17) ^ it->item[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attributes != NULL) {
|
||||||
|
for (size_t i = 0; i < strlen(attributes); i++)
|
||||||
|
hash = rot(hash, 11) ^ attributes[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_fallback)
|
||||||
|
hash = rot(hash, 27);
|
||||||
|
|
||||||
|
return hash;
|
||||||
|
#undef rot
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct font *
|
||||||
|
from_name(const char *base_name, const font_list_t *fallbacks,
|
||||||
|
const char *attributes, bool is_fallback)
|
||||||
|
{
|
||||||
|
uint64_t hash = hash_font(base_name, fallbacks, attributes, is_fallback);
|
||||||
|
tll_foreach(font_cache, it) {
|
||||||
|
if (it->item.hash == hash) {
|
||||||
|
it->item.font->ref_counter++;
|
||||||
|
return it->item.font;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
size_t attr_len = attributes == NULL ? 0 : strlen(attributes);
|
size_t attr_len = attributes == NULL ? 0 : strlen(attributes);
|
||||||
bool have_attrs = attr_len > 0;
|
bool have_attrs = attr_len > 0;
|
||||||
|
|
||||||
|
|
@ -298,6 +347,7 @@ from_name(const char *base_name, const font_list_t *fallbacks, const char *attri
|
||||||
FcPatternDestroy(pattern);
|
FcPatternDestroy(pattern);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tll_push_back(font_cache, ((struct font_cache_entry){.hash = hash, .font = font}));
|
||||||
return font;
|
return font;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -605,6 +655,9 @@ font_destroy(struct font *font)
|
||||||
if (font == NULL)
|
if (font == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (--font->ref_counter > 0)
|
||||||
|
return;
|
||||||
|
|
||||||
tll_free_and_free(font->fallbacks, free);
|
tll_free_and_free(font->fallbacks, free);
|
||||||
|
|
||||||
if (font->face != NULL) {
|
if (font->face != NULL) {
|
||||||
|
|
@ -647,5 +700,13 @@ font_destroy(struct font *font)
|
||||||
free(font->cache[i]);
|
free(font->cache[i]);
|
||||||
}
|
}
|
||||||
free(font->cache);
|
free(font->cache);
|
||||||
|
|
||||||
|
tll_foreach(font_cache, it) {
|
||||||
|
if (it->item.font == font) {
|
||||||
|
tll_remove(font_cache, it);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
free(font);
|
free(font);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
2
font.h
2
font.h
|
|
@ -52,6 +52,8 @@ struct font {
|
||||||
bool is_fallback;
|
bool is_fallback;
|
||||||
tll(char *) fallbacks;
|
tll(char *) fallbacks;
|
||||||
|
|
||||||
|
size_t ref_counter;
|
||||||
|
|
||||||
/* Fields below are only valid for non-fallback fonts */
|
/* Fields below are only valid for non-fallback fonts */
|
||||||
FcPattern *fc_pattern;
|
FcPattern *fc_pattern;
|
||||||
FcFontSet *fc_fonts;
|
FcFontSet *fc_fonts;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue