font: cache loaded fonts

Instantiating a new font is expensive, both in CPU and
memory. Mitigate by adding a cache. On a hit, instead of instantiating
a new font, clone the one from the cache.

Remember, cloning is basically just a ref counter bump.
This commit is contained in:
Daniel Eklöf 2019-01-15 20:48:04 +01:00
parent fae2e5cb18
commit 7525ae99eb

18
font.c
View file

@ -10,12 +10,15 @@
#define LOG_MODULE "font" #define LOG_MODULE "font"
#define LOG_ENABLE_DBG 0 #define LOG_ENABLE_DBG 0
#include "log.h" #include "log.h"
#include "tllist.h"
struct font { struct font {
char *name; char *name;
cairo_scaled_font_t *scaled_font; cairo_scaled_font_t *scaled_font;
}; };
static tll(const struct font *) cache = tll_init();
static void __attribute__((constructor)) static void __attribute__((constructor))
init(void) init(void)
{ {
@ -37,11 +40,18 @@ static void __attribute__((destructor))
fini(void) fini(void)
{ {
FcFini(); FcFini();
assert(tll_length(cache) == 0);
} }
struct font * struct font *
font_new(const char *name) font_new(const char *name)
{ {
/* Check if font have already been loaded */
tll_foreach(cache, it) {
if (strcmp(name, it->item->name) == 0)
return font_clone(it->item);
}
FcPattern *pattern = FcNameParse((const unsigned char *)name); FcPattern *pattern = FcNameParse((const unsigned char *)name);
if (pattern == NULL) { if (pattern == NULL) {
LOG_ERR("%s: failed to lookup font", name); LOG_ERR("%s: failed to lookup font", name);
@ -104,6 +114,7 @@ font_new(const char *name)
font->name = strdup(name); font->name = strdup(name);
font->scaled_font = scaled_font; font->scaled_font = scaled_font;
tll_push_back(cache, font);
return font; return font;
} }
@ -124,6 +135,13 @@ font_destroy(struct font *font)
if (font == NULL) if (font == NULL)
return; return;
tll_foreach(cache, it) {
if (it->item == font) {
tll_remove(cache, it);
break;
}
}
cairo_scaled_font_destroy(font->scaled_font); cairo_scaled_font_destroy(font->scaled_font);
free(font->name); free(font->name);
free(font); free(font);