forked from enlightenment/efl
* Evas: Improve RGBA_Font_* cache using hash and stringshare correctly.
Note: This should not impact font rendering, but if you notice anything wrong, please don't hesitate to report this to me. SVN revision: 41050
This commit is contained in:
parent
fdca8644a2
commit
0839ec65ea
|
@ -68,4 +68,7 @@ EAPI int evas_common_font_query_char_coords (RGBA_Font *fn, con
|
|||
EAPI int evas_common_font_query_text_at_pos (RGBA_Font *fn, const char *text, int x, int y, int *cx, int *cy, int *cw, int *ch);
|
||||
EAPI int evas_common_font_query_last_up_to_pos (RGBA_Font *fn, const char *text, int x, int y);
|
||||
|
||||
void evas_common_font_load_init(void);
|
||||
void evas_common_font_load_shutdown(void);
|
||||
|
||||
#endif /* _EVAS_FONT_H */
|
||||
|
|
|
@ -5,22 +5,127 @@
|
|||
#include "evas_common.h"
|
||||
#include "evas_private.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
extern FT_Library evas_ft_lib;
|
||||
|
||||
static int font_cache_usage = 0;
|
||||
static int font_cache = 0;
|
||||
static Eina_Inlist * fonts_src = NULL;
|
||||
static Eina_Inlist * fonts = NULL;
|
||||
|
||||
static Eina_Hash * fonts_src = NULL;
|
||||
static Eina_Hash * fonts = NULL;
|
||||
static Eina_List * fonts_lru = NULL;
|
||||
|
||||
static Evas_Bool font_modify_cache_cb(const Eina_Hash *hash, const void *key, void *data, void *fdata);
|
||||
static Evas_Bool font_flush_free_glyph_cb(const Eina_Hash *hash, const void *key, void *data, void *fdata);
|
||||
|
||||
static unsigned int
|
||||
_evas_font_cache_int_length(const RGBA_Font_Int *key)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
_evas_font_cache_int_cmp(const RGBA_Font_Int *k1, int k1_length,
|
||||
const RGBA_Font_Int *k2, int k2_length)
|
||||
{
|
||||
/* RGBA_Font_Source->name is a stringshare */
|
||||
if (k1->src->name == k2->src->name)
|
||||
return k1->size - k2->size;
|
||||
return strcmp(k1->src->name, k2->src->name);;
|
||||
}
|
||||
|
||||
static int
|
||||
_evas_font_cache_int_hash(const RGBA_Font_Int *key, int key_length)
|
||||
{
|
||||
int hash;
|
||||
|
||||
hash = eina_hash_djb2(key->src->name, eina_stringshare_strlen(key->src->name) + 1);
|
||||
hash ^= eina_hash_int32(&key->size, sizeof (int));
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
static void
|
||||
_evas_common_font_source_free(RGBA_Font_Source *fs)
|
||||
{
|
||||
FT_Done_Face(fs->ft.face);
|
||||
if (fs->charmap) evas_array_hash_free(fs->charmap);
|
||||
if (fs->name) eina_stringshare_del(fs->name);
|
||||
free(fs);
|
||||
}
|
||||
|
||||
|
||||
static Eina_Bool
|
||||
font_flush_free_glyph_cb(const Eina_Hash *hash, const void *key, void *data, void *fdata)
|
||||
{
|
||||
RGBA_Font_Glyph *fg;
|
||||
|
||||
fg = data;
|
||||
FT_Done_Glyph(fg->glyph);
|
||||
/* extension calls */
|
||||
if (fg->ext_dat_free) fg->ext_dat_free(fg->ext_dat);
|
||||
free(fg);
|
||||
return 1;
|
||||
hash = 0;
|
||||
key = 0;
|
||||
fdata = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
_evas_common_font_int_free(RGBA_Font_Int *fi)
|
||||
{
|
||||
FT_Done_Size(fi->ft.size);
|
||||
|
||||
evas_common_font_int_modify_cache_by(fi, -1);
|
||||
|
||||
eina_hash_foreach(fi->glyphs, font_flush_free_glyph_cb, NULL);
|
||||
eina_hash_free(fi->glyphs);
|
||||
|
||||
eina_hash_free(fi->kerning);
|
||||
eina_hash_free(fi->indexes);
|
||||
|
||||
#ifdef HAVE_PTHREAD
|
||||
pthread_mutex_destroy(&fi->ft_mutex);
|
||||
#endif
|
||||
|
||||
evas_common_font_source_free(fi->src);
|
||||
|
||||
if (fi->references == 0)
|
||||
fonts_lru = eina_list_remove(fonts_lru, fi);
|
||||
|
||||
free(fi);
|
||||
}
|
||||
|
||||
void
|
||||
evas_common_font_load_init(void)
|
||||
{
|
||||
fonts_src = eina_hash_string_small_new(EINA_FREE_CB(_evas_common_font_source_free));
|
||||
fonts = eina_hash_new(EINA_KEY_LENGTH(_evas_font_cache_int_length),
|
||||
EINA_KEY_CMP(_evas_font_cache_int_cmp),
|
||||
EINA_KEY_HASH(_evas_font_cache_int_hash),
|
||||
EINA_FREE_CB(_evas_common_font_int_free),
|
||||
5);
|
||||
}
|
||||
|
||||
void
|
||||
evas_common_font_load_shutdown(void)
|
||||
{
|
||||
eina_hash_free(fonts);
|
||||
fonts = NULL;
|
||||
|
||||
eina_hash_free(fonts_src);
|
||||
fonts_src = NULL;
|
||||
}
|
||||
|
||||
EAPI RGBA_Font_Source *
|
||||
evas_common_font_source_memory_load(const char *name, const void *data, int data_size)
|
||||
{
|
||||
int error;
|
||||
RGBA_Font_Source *fs;
|
||||
|
||||
assert(name != NULL);
|
||||
|
||||
fs = calloc(1, sizeof(RGBA_Font_Source) + data_size);
|
||||
if (!fs) return NULL;
|
||||
fs->data = ((unsigned char *)fs) + sizeof(RGBA_Font_Source);
|
||||
|
@ -38,7 +143,8 @@ evas_common_font_source_memory_load(const char *name, const void *data, int data
|
|||
error = FT_Select_Charmap(fs->ft.face, ft_encoding_unicode);
|
||||
fs->ft.orig_upem = fs->ft.face->units_per_EM;
|
||||
fs->references = 1;
|
||||
fonts_src = eina_inlist_prepend(fonts_src, EINA_INLIST_GET(fs));
|
||||
|
||||
eina_hash_direct_add(fonts_src, fs->name, fs);
|
||||
return fs;
|
||||
}
|
||||
|
||||
|
@ -47,6 +153,8 @@ evas_common_font_source_load(const char *name)
|
|||
{
|
||||
RGBA_Font_Source *fs;
|
||||
|
||||
assert(name != NULL);
|
||||
|
||||
fs = calloc(1, sizeof(RGBA_Font_Source));
|
||||
if (!fs) return NULL;
|
||||
fs->data = NULL;
|
||||
|
@ -60,7 +168,8 @@ evas_common_font_source_load(const char *name)
|
|||
fs->ft.orig_upem = 0;
|
||||
|
||||
fs->references = 1;
|
||||
fonts_src = eina_inlist_prepend(fonts_src, EINA_INLIST_GET(fs));
|
||||
|
||||
eina_hash_direct_add(fonts_src, fs->name, fs);
|
||||
return fs;
|
||||
}
|
||||
|
||||
|
@ -94,14 +203,11 @@ evas_common_font_source_find(const char *name)
|
|||
RGBA_Font_Source *fs;
|
||||
|
||||
if (!name) return NULL;
|
||||
EINA_INLIST_FOREACH(fonts_src, fs)
|
||||
fs = eina_hash_find(fonts_src, name);
|
||||
if (fs)
|
||||
{
|
||||
if ((fs->name) && (!strcmp(name, fs->name)))
|
||||
{
|
||||
fs->references++;
|
||||
fonts_src = eina_inlist_demote(fonts_src, EINA_INLIST_GET(fs));
|
||||
return fs;
|
||||
}
|
||||
fs->references++;
|
||||
return fs;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
@ -112,24 +218,17 @@ evas_common_font_source_free(RGBA_Font_Source *fs)
|
|||
fs->references--;
|
||||
if (fs->references > 0) return;
|
||||
|
||||
fonts_src = eina_inlist_remove(fonts_src, EINA_INLIST_GET(fs));
|
||||
FT_Done_Face(fs->ft.face);
|
||||
if (fs->charmap) evas_array_hash_free(fs->charmap);
|
||||
if (fs->name) eina_stringshare_del(fs->name);
|
||||
free(fs);
|
||||
eina_hash_del(fonts_src, fs->name, fs);
|
||||
}
|
||||
|
||||
EAPI void
|
||||
evas_common_font_size_use(RGBA_Font *fn)
|
||||
{
|
||||
RGBA_Font_Int *fi;
|
||||
Eina_List *l;
|
||||
|
||||
for (l = fn->fonts; l; l = l->next)
|
||||
EINA_LIST_FOREACH(fn->fonts, l, fi)
|
||||
{
|
||||
RGBA_Font_Int *fi;
|
||||
|
||||
fi = l->data;
|
||||
|
||||
if (fi->src->current_size != fi->size)
|
||||
{
|
||||
FT_Activate_Size(fi->ft.size);
|
||||
|
@ -178,7 +277,7 @@ _evas_common_font_double_int_hash(const unsigned int key[2], int key_length)
|
|||
}
|
||||
|
||||
static void
|
||||
_evas_commont_font_int_cache_init(RGBA_Font_Int *fi)
|
||||
_evas_common_font_int_cache_init(RGBA_Font_Int *fi)
|
||||
{
|
||||
/* Add some font kerning cache. */
|
||||
fi->indexes = eina_hash_new(EINA_KEY_LENGTH(_evas_common_font_int_length),
|
||||
|
@ -194,7 +293,6 @@ _evas_commont_font_int_cache_init(RGBA_Font_Int *fi)
|
|||
#endif
|
||||
}
|
||||
|
||||
|
||||
EAPI RGBA_Font_Int *
|
||||
evas_common_font_int_memory_load(const char *name, int size, const void *data, int data_size)
|
||||
{
|
||||
|
@ -218,7 +316,7 @@ evas_common_font_int_memory_load(const char *name, int size, const void *data, i
|
|||
|
||||
fi->size = size;
|
||||
|
||||
_evas_commont_font_int_cache_init(fi);
|
||||
_evas_common_font_int_cache_init(fi);
|
||||
|
||||
fi = evas_common_font_int_load_init(fi);
|
||||
evas_common_font_int_load_complete(fi);
|
||||
|
@ -249,7 +347,7 @@ evas_common_font_int_load(const char *name, int size)
|
|||
|
||||
fi->size = size;
|
||||
|
||||
_evas_commont_font_int_cache_init(fi);
|
||||
_evas_common_font_int_cache_init(fi);
|
||||
|
||||
return evas_common_font_int_load_init(fi);
|
||||
}
|
||||
|
@ -261,7 +359,8 @@ evas_common_font_int_load_init(RGBA_Font_Int *fi)
|
|||
fi->glyphs = eina_hash_int32_new(NULL);
|
||||
fi->usage = 0;
|
||||
fi->references = 1;
|
||||
fonts = eina_inlist_prepend(fonts, EINA_INLIST_GET(fi));
|
||||
|
||||
eina_hash_direct_add(fonts, fi, fi);
|
||||
|
||||
return fi;
|
||||
}
|
||||
|
@ -359,6 +458,7 @@ evas_common_font_load(const char *name, int size)
|
|||
fi->references--;
|
||||
if (fi->references == 0)
|
||||
{
|
||||
fonts_lru = eina_list_prepend(fonts_lru, fi);
|
||||
evas_common_font_int_modify_cache_by(fi, 1);
|
||||
evas_common_font_flush();
|
||||
}
|
||||
|
@ -374,6 +474,7 @@ evas_common_font_load(const char *name, int size)
|
|||
fi->references--;
|
||||
if (fi->references == 0)
|
||||
{
|
||||
fonts_lru = eina_list_prepend(fonts_lru, fi);
|
||||
evas_common_font_int_modify_cache_by(fi, 1);
|
||||
evas_common_font_flush();
|
||||
}
|
||||
|
@ -436,10 +537,11 @@ evas_common_font_free(RGBA_Font *fn)
|
|||
fi->references--;
|
||||
if (fi->references == 0)
|
||||
{
|
||||
fonts_lru = eina_list_append(fonts_lru, fi);
|
||||
evas_common_font_int_modify_cache_by(fi, 1);
|
||||
evas_common_font_flush();
|
||||
}
|
||||
}
|
||||
evas_common_font_flush();
|
||||
eina_list_free(fn->fonts);
|
||||
LKD(fn->lock);
|
||||
free(fn);
|
||||
|
@ -580,71 +682,44 @@ evas_common_font_flush(void)
|
|||
while (font_cache_usage > font_cache) evas_common_font_flush_last();
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
font_flush_free_glyph_cb(const Eina_Hash *hash, const void *key, void *data, void *fdata)
|
||||
{
|
||||
RGBA_Font_Glyph *fg;
|
||||
|
||||
fg = data;
|
||||
FT_Done_Glyph(fg->glyph);
|
||||
/* extension calls */
|
||||
if (fg->ext_dat_free) fg->ext_dat_free(fg->ext_dat);
|
||||
free(fg);
|
||||
return 1;
|
||||
hash = 0;
|
||||
key = 0;
|
||||
fdata = 0;
|
||||
}
|
||||
|
||||
/* We run this when the cache gets larger than allowed size
|
||||
* We check cache size each time a fi->references goes to 0
|
||||
* PERFORMS: Find font_int(s) with references == 0 and delete them */
|
||||
EAPI void
|
||||
evas_common_font_flush_last(void)
|
||||
{
|
||||
RGBA_Font_Int *fi_tmp;
|
||||
RGBA_Font_Int *fi = NULL;
|
||||
|
||||
EINA_INLIST_FOREACH(fonts, fi_tmp)
|
||||
{
|
||||
if (fi_tmp->references == 0) fi = fi_tmp;
|
||||
}
|
||||
if (!fi) return;
|
||||
if (!fonts_lru) return ;
|
||||
|
||||
FT_Done_Size(fi->ft.size);
|
||||
fi = eina_list_data_get(fonts_lru);
|
||||
fonts_lru = eina_list_remove_list(fonts_lru, fonts_lru);
|
||||
|
||||
fonts = eina_inlist_remove(fonts, EINA_INLIST_GET(fi));
|
||||
evas_common_font_int_modify_cache_by(fi, -1);
|
||||
|
||||
eina_hash_foreach(fi->glyphs, font_flush_free_glyph_cb, NULL);
|
||||
eina_hash_free(fi->glyphs);
|
||||
|
||||
eina_hash_free(fi->kerning);
|
||||
eina_hash_free(fi->indexes);
|
||||
|
||||
#ifdef HAVE_PTHREAD
|
||||
pthread_mutex_destroy(&fi->ft_mutex);
|
||||
#endif
|
||||
|
||||
evas_common_font_source_free(fi->src);
|
||||
|
||||
free(fi);
|
||||
eina_hash_del(fonts, fi, fi);
|
||||
}
|
||||
|
||||
EAPI RGBA_Font_Int *
|
||||
evas_common_font_int_find(const char *name, int size)
|
||||
{
|
||||
RGBA_Font_Int tmp_fi;
|
||||
RGBA_Font_Source tmp_fn;
|
||||
RGBA_Font_Int *fi;
|
||||
|
||||
EINA_INLIST_FOREACH(fonts, fi)
|
||||
tmp_fn.name = (char*) eina_stringshare_add(name);
|
||||
tmp_fi.src = &tmp_fn;
|
||||
tmp_fi.size = size;
|
||||
|
||||
fi = eina_hash_find(fonts, &tmp_fi);
|
||||
if (fi)
|
||||
{
|
||||
if ((fi->size == size) && (!strcmp(name, fi->src->name)))
|
||||
if (fi->references == 0)
|
||||
{
|
||||
if (fi->references == 0) evas_common_font_int_modify_cache_by(fi, -1);
|
||||
fi->references++;
|
||||
fonts = eina_inlist_promote(fonts, EINA_INLIST_GET(fi));
|
||||
return fi;
|
||||
evas_common_font_int_modify_cache_by(fi, -1);
|
||||
fonts_lru = eina_list_remove(fonts_lru, fi);
|
||||
}
|
||||
fi->references++;
|
||||
}
|
||||
return NULL;
|
||||
|
||||
eina_stringshare_del(tmp_fn.name);
|
||||
return fi;
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ evas_common_font_init(void)
|
|||
initialised--;
|
||||
return;
|
||||
}
|
||||
evas_common_font_load_init();
|
||||
}
|
||||
|
||||
EAPI void
|
||||
|
@ -30,6 +31,7 @@ evas_common_font_shutdown(void)
|
|||
initialised--;
|
||||
if (initialised != 0) return;
|
||||
|
||||
evas_common_font_load_shutdown();
|
||||
evas_common_font_cache_set(0);
|
||||
evas_common_font_flush();
|
||||
|
||||
|
|
|
@ -800,8 +800,6 @@ struct _RGBA_Font
|
|||
|
||||
struct _RGBA_Font_Int
|
||||
{
|
||||
EINA_INLIST;
|
||||
|
||||
RGBA_Font_Source *src;
|
||||
|
||||
int size;
|
||||
|
@ -814,7 +812,7 @@ struct _RGBA_Font_Int
|
|||
Eina_Hash *glyphs;
|
||||
|
||||
LK(ft_mutex);
|
||||
|
||||
|
||||
Eina_Hash *kerning;
|
||||
Eina_Hash *indexes;
|
||||
|
||||
|
@ -822,12 +820,11 @@ struct _RGBA_Font_Int
|
|||
Font_Hint_Flags hinting;
|
||||
|
||||
int references;
|
||||
|
||||
};
|
||||
|
||||
struct _RGBA_Font_Source
|
||||
{
|
||||
EINA_INLIST;
|
||||
|
||||
const char *name;
|
||||
const char *file;
|
||||
|
||||
|
|
Loading…
Reference in New Issue