efl/legacy/evas/src/lib/engines/common/evas_font_load.c

910 lines
23 KiB
C

#include "evas_common.h"
#include "evas_private.h"
#include <assert.h>
#include "evas_font_private.h" /* for Frame-Queuing support */
#include "evas_font_ot.h"
#ifdef EVAS_CSERVE2
# include "../../cserve2/evas_cs2_private.h"
#endif
#ifdef USE_HARFBUZZ
# include <hb.h>
# include <hb-ft.h>
#endif
extern FT_Library evas_ft_lib;
static int font_cache_usage = 0;
static int font_cache = 0;
static int font_dpi = 75;
static Eina_Hash *fonts_src = NULL;
static Eina_Hash *fonts = NULL;
static Eina_List *fonts_lru = NULL;
static Eina_Inlist *fonts_use_lru = NULL;
static int fonts_use_usage = 0;
static void _evas_common_font_int_clear(RGBA_Font_Int *fi);
static int
_evas_font_cache_int_cmp(const RGBA_Font_Int *k1, int k1_length __UNUSED__,
const RGBA_Font_Int *k2, int k2_length __UNUSED__)
{
/* RGBA_Font_Source->name is a stringshare */
if (k1->src->name == k2->src->name)
{
if (k1->size == k2->size)
return k1->wanted_rend - k2->wanted_rend;
else
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 __UNUSED__)
{
int hash;
unsigned int wanted_rend = key->wanted_rend;
hash = eina_hash_djb2(key->src->name, eina_stringshare_strlen(key->src->name) + 1);
hash ^= eina_hash_int32(&key->size, sizeof (int));
hash ^= eina_hash_int32(&wanted_rend, sizeof (int));
return hash;
}
static void
_evas_common_font_source_free(RGBA_Font_Source *fs)
{
FTLOCK();
FT_Done_Face(fs->ft.face);
FTUNLOCK();
if (fs->name) eina_stringshare_del(fs->name);
if (fs->file) eina_stringshare_del(fs->file);
free(fs);
}
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);
_evas_common_font_int_clear(fi);
eina_hash_free(fi->kerning);
LKD(fi->ft_mutex);
#ifdef USE_HARFBUZZ
hb_font_destroy(fi->ft.hb_font);
#endif
evas_common_font_source_free(fi->src);
if (fi->references <= 0) fonts_lru = eina_list_remove(fonts_lru, fi);
if (fi->fash) fi->fash->freeme(fi->fash);
if (fi->inuse)
{
fonts_use_lru = eina_inlist_remove(fonts_use_lru, EINA_INLIST_GET(fi));
fi->inuse = 0;
fonts_use_usage -= fi->usage;
fi->usage = 0;
}
#ifdef EVAS_CSERVE2
evas_cserve2_font_free(fi->cs2_handler);
#endif
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(NULL,
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 void
evas_common_font_dpi_set(int dpi)
{
font_dpi = dpi;
}
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);
fs->data_size = data_size;
fs->current_size = 0;
memcpy(fs->data, data, data_size);
FTLOCK();
error = FT_New_Memory_Face(evas_ft_lib, fs->data, fs->data_size, 0, &(fs->ft.face));
FTUNLOCK();
if (error)
{
free(fs);
return NULL;
}
fs->name = eina_stringshare_add(name);
fs->file = NULL;
FTLOCK();
error = FT_Select_Charmap(fs->ft.face, ft_encoding_unicode);
if (error)
{
FT_Done_Face(fs->ft.face);
fs->ft.face = NULL;
free(fs);
return NULL;
}
FTUNLOCK();
fs->ft.orig_upem = fs->ft.face->units_per_EM;
fs->references = 1;
eina_hash_direct_add(fonts_src, fs->name, fs);
return fs;
}
EAPI RGBA_Font_Source *
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;
fs->data_size = 0;
fs->current_size = 0;
fs->ft.face = NULL;
fs->name = eina_stringshare_add(name);
fs->file = eina_stringshare_ref(fs->name);
fs->ft.orig_upem = 0;
fs->references = 1;
eina_hash_direct_add(fonts_src, fs->name, fs);
return fs;
}
void
evas_common_font_source_unload(RGBA_Font_Source *fs)
{
FTLOCK();
FT_Done_Face(fs->ft.face);
fs->ft.face = NULL;
FTUNLOCK();
}
void
evas_common_font_source_reload(RGBA_Font_Source *fs)
{
if (fs->ft.face) return;
if (fs->data)
{
int error;
FTLOCK();
error = FT_New_Memory_Face(evas_ft_lib, fs->data, fs->data_size, 0, &(fs->ft.face));
FTUNLOCK();
if (error) return;
FTLOCK();
error = FT_Select_Charmap(fs->ft.face, ft_encoding_unicode);
if (error)
{
FT_Done_Face(fs->ft.face);
fs->ft.face = NULL;
}
FTUNLOCK();
}
else
evas_common_font_source_load_complete(fs);
}
EAPI int
evas_common_font_source_load_complete(RGBA_Font_Source *fs)
{
int error;
FTLOCK();
error = FT_New_Face(evas_ft_lib, fs->file, 0, &(fs->ft.face));
if (error)
{
FTUNLOCK();
fs->ft.face = NULL;
return error;
}
error = FT_Select_Charmap(fs->ft.face, ft_encoding_unicode);
if (error)
{
FT_Done_Face(fs->ft.face);
FTUNLOCK();
fs->ft.face = NULL;
return error;
}
FTUNLOCK();
fs->ft.orig_upem = fs->ft.face->units_per_EM;
return error;
}
EAPI RGBA_Font_Source *
evas_common_font_source_find(const char *name)
{
RGBA_Font_Source *fs;
if (!name) return NULL;
fs = eina_hash_find(fonts_src, name);
if (fs)
{
fs->references++;
return fs;
}
return NULL;
}
EAPI void
evas_common_font_source_free(RGBA_Font_Source *fs)
{
fs->references--;
if (fs->references > 0) return;
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;
EINA_LIST_FOREACH(fn->fonts, l, fi)
{
if (fi->src->current_size != fi->size)
{
evas_common_font_source_reload(fi->src);
FTLOCK();
FT_Activate_Size(fi->ft.size);
FTUNLOCK();
fi->src->current_size = fi->size;
}
}
}
static int
_evas_common_font_double_int_cmp(const int *key1, __UNUSED__ int key1_length,
const int *key2, __UNUSED__ int key2_length)
{
if (key1[0] - key2[0] == 0) return key1[1] - key2[1];
return key1[0] - key2[0];
}
static int
_evas_common_font_double_int_hash(const unsigned int key[2], int key_length)
{
return
eina_hash_int32(&key[0], key_length) ^
eina_hash_int32(&key[1], key_length);
}
static void
_evas_common_font_int_cache_init(RGBA_Font_Int *fi)
{
/* Add some font kerning cache. */
fi->kerning = eina_hash_new(NULL,
EINA_KEY_CMP(_evas_common_font_double_int_cmp),
EINA_KEY_HASH(_evas_common_font_double_int_hash),
free, 3);
LKI(fi->ft_mutex);
}
EAPI RGBA_Font_Int *
evas_common_font_int_memory_load(const char *source, const char *name, int size, const void *data, int data_size, Font_Rend_Flags wanted_rend)
{
RGBA_Font_Int *fi;
char *fake_name;
fake_name = evas_file_path_join(source, name);
fi = evas_common_font_int_find(fake_name, size, wanted_rend);
if (fi)
{
free(fake_name);
return fi;
}
fi = calloc(1, sizeof(RGBA_Font_Int));
if (!fi)
{
free(fake_name);
return NULL;
}
fi->src = evas_common_font_source_find(fake_name);
if (!fi->src)
fi->src = evas_common_font_source_memory_load(fake_name, data, data_size);
if (!fi->src)
{
free(fi);
free(fake_name);
return NULL;
}
fi->size = size;
_evas_common_font_int_cache_init(fi);
fi = evas_common_font_int_load_init(fi);
evas_common_font_int_load_complete(fi);
#ifdef EVAS_CSERVE2
if (evas_cserve2_use_get())
fi->cs2_handler = evas_cserve2_font_load(source, name, size, font_dpi,
wanted_rend);
#endif
free(fake_name);
return fi;
}
EAPI RGBA_Font_Int *
evas_common_font_int_load(const char *name, int size,
Font_Rend_Flags wanted_rend)
{
RGBA_Font_Int *fi;
fi = evas_common_font_int_find(name, size, wanted_rend);
if (fi) return fi;
fi = calloc(1, sizeof(RGBA_Font_Int));
if (!fi) return NULL;
fi->src = evas_common_font_source_find(name);
if (!fi->src && evas_file_path_is_file(name))
fi->src = evas_common_font_source_load(name);
if (!fi->src)
{
free(fi);
return NULL;
}
fi->size = size;
fi->wanted_rend = wanted_rend;
_evas_common_font_int_cache_init(fi);
fi = evas_common_font_int_load_init(fi);
#ifdef EVAS_CSERVE2
if (evas_cserve2_use_get())
fi->cs2_handler = evas_cserve2_font_load(NULL, name, size, font_dpi,
wanted_rend);
#endif
// evas_common_font_int_load_complete(fi);
return fi;
}
EAPI RGBA_Font_Int *
evas_common_font_int_load_init(RGBA_Font_Int *fi)
{
fi->ft.size = NULL;
fi->references = 1;
eina_hash_direct_add(fonts, fi, fi);
return fi;
}
EAPI RGBA_Font_Int *
evas_common_font_int_load_complete(RGBA_Font_Int *fi)
{
int val, dv;
int ret;
int error;
FTLOCK();
error = FT_New_Size(fi->src->ft.face, &(fi->ft.size));
if (!error)
{
FT_Activate_Size(fi->ft.size);
}
fi->real_size = fi->size * 64;
error = FT_Set_Char_Size(fi->src->ft.face, 0, fi->real_size, font_dpi, font_dpi);
if (error)
error = FT_Set_Pixel_Sizes(fi->src->ft.face, 0, fi->real_size);
FTUNLOCK();
if (error)
{
int i, maxd = 0x7fffffff;
int chosen_size = 0;
int chosen_size2 = 0;
for (i = 0; i < fi->src->ft.face->num_fixed_sizes; i++)
{
int s, cd;
s = fi->src->ft.face->available_sizes[i].size;
cd = chosen_size - fi->real_size;
if (cd < 0) cd = -cd;
if (cd < maxd)
{
maxd = cd;
chosen_size = s;
chosen_size2 = fi->src->ft.face->available_sizes[i].y_ppem;
if (maxd == 0) break;
}
}
fi->real_size = chosen_size;
FTLOCK();
error = FT_Set_Pixel_Sizes(fi->src->ft.face, 0, fi->real_size);
FTUNLOCK();
if (error)
{
error = FT_Set_Char_Size(fi->src->ft.face, 0, fi->real_size, font_dpi, font_dpi);
if (error)
{
/* hack around broken fonts */
fi->real_size = (chosen_size2 / 64) * 60;
error = FT_Set_Char_Size(fi->src->ft.face, 0, fi->real_size, font_dpi, font_dpi);
if (error)
{
/* couldn't choose the size anyway... what now? */
}
}
}
}
fi->src->current_size = 0;
fi->max_h = 0;
val = (int)fi->src->ft.face->bbox.yMax;
if (fi->src->ft.face->units_per_EM != 0)
{
dv = (fi->src->ft.orig_upem * 2048) / fi->src->ft.face->units_per_EM;
ret = FONT_METRIC_CONV(val, dv, fi->src->ft.face->size->metrics.y_scale);
}
else
{
if ((fi->src->ft.face->bbox.yMax == 0) &&
(fi->src->ft.face->bbox.yMin == 0))
ret = FONT_METRIC_ROUNDUP((int)fi->ft.size->metrics.ascender);
else
ret = val;
}
fi->max_h += ret;
val = -(int)fi->src->ft.face->bbox.yMin;
if (fi->src->ft.face->units_per_EM != 0)
{
dv = (fi->src->ft.orig_upem * 2048) / fi->src->ft.face->units_per_EM;
ret = FONT_METRIC_CONV(val, dv, fi->src->ft.face->size->metrics.y_scale);
}
else
{
if ((fi->src->ft.face->bbox.yMax == 0) &&
(fi->src->ft.face->bbox.yMin == 0))
ret = FONT_METRIC_ROUNDUP(-(int)fi->ft.size->metrics.descender);
else
ret = val;
}
fi->max_h += ret;
/* If the loaded font doesn't match with wanted_rend value requested by
* textobject and textblock, Set the runtime_rend value as FONT_REND_SLANT
* or FONT_REND_WEIGHT for software rendering. */
fi->runtime_rend = FONT_REND_REGULAR;
if ((fi->wanted_rend & FONT_REND_SLANT) &&
!(fi->src->ft.face->style_flags & FT_STYLE_FLAG_ITALIC))
fi->runtime_rend |= FONT_REND_SLANT;
if ((fi->wanted_rend & FONT_REND_WEIGHT) &&
!(fi->src->ft.face->style_flags & FT_STYLE_FLAG_BOLD))
fi->runtime_rend |= FONT_REND_WEIGHT;
return fi;
}
EAPI RGBA_Font *
evas_common_font_memory_load(const char *source, const char *name, int size, const void *data, int data_size, Font_Rend_Flags wanted_rend)
{
RGBA_Font *fn;
RGBA_Font_Int *fi;
fi = evas_common_font_int_memory_load(source, name, size, data, data_size,
wanted_rend);
if (!fi) return NULL;
fn = calloc(1, sizeof(RGBA_Font));
if (!fn)
{
evas_common_font_int_unref(fi);
return NULL;
}
fn->fonts = eina_list_append(fn->fonts, fi);
fn->hinting = FONT_BYTECODE_HINT;
fi->hinting = fn->hinting;
fn->references = 1;
LKI(fn->lock);
if (fi->inuse) evas_common_font_int_promote(fi);
else
{
fi->inuse = 1;
fonts_use_lru = eina_inlist_prepend(fonts_use_lru, EINA_INLIST_GET(fi));
}
return fn;
}
//ZZZ: font struct looks like:
// fn->(fi, fi, fi, ...)
// fi->fs
EAPI RGBA_Font *
evas_common_font_load(const char *name, int size, Font_Rend_Flags wanted_rend)
{
RGBA_Font *fn;
RGBA_Font_Int *fi;
fi = evas_common_font_int_load(name, size, wanted_rend);
if (!fi) return NULL;
/* First font, complete load */
if (!fi->ft.size)
{
if (!fi->src->ft.face)
{
if (evas_common_font_source_load_complete(fi->src))
{
evas_common_font_int_unref(fi);
return NULL;
}
}
evas_common_font_int_load_complete(fi);
}
fn = calloc(1, sizeof(RGBA_Font));
if (!fn)
{
evas_common_font_int_unref(fi);
return NULL;
}
fn->fonts = eina_list_append(fn->fonts, fi);
fn->hinting = FONT_BYTECODE_HINT;
fi->hinting = fn->hinting;
fn->references = 1;
LKI(fn->lock);
if (fi->inuse) evas_common_font_int_promote(fi);
else
{
fi->inuse = 1;
fonts_use_lru = eina_inlist_prepend(fonts_use_lru, EINA_INLIST_GET(fi));
}
return fn;
}
EAPI RGBA_Font *
evas_common_font_add(RGBA_Font *fn, const char *name, int size, Font_Rend_Flags wanted_rend)
{
RGBA_Font_Int *fi;
if (!fn) return NULL;
fi = evas_common_font_int_load(name, size, wanted_rend);
if (fi)
{
fn->fonts = eina_list_append(fn->fonts, fi);
fi->hinting = fn->hinting;
if (fi->inuse) evas_common_font_int_promote(fi);
else
{
fi->inuse = 1;
fonts_use_lru = eina_inlist_prepend(fonts_use_lru, EINA_INLIST_GET(fi));
}
return fn;
}
return NULL;
}
EAPI RGBA_Font *
evas_common_font_memory_add(RGBA_Font *fn, const char *source, const char *name, int size, const void *data, int data_size, Font_Rend_Flags wanted_rend)
{
RGBA_Font_Int *fi;
if (!fn)
return NULL;
fi = evas_common_font_int_memory_load(source, name, size, data, data_size, wanted_rend);
if (fi)
{
fn->fonts = eina_list_append(fn->fonts, fi);
fi->hinting = fn->hinting;
if (fi->inuse) evas_common_font_int_promote(fi);
else
{
fi->inuse = 1;
fonts_use_lru = eina_inlist_prepend(fonts_use_lru, EINA_INLIST_GET(fi));
}
return fn;
}
return NULL;
}
EAPI void
evas_common_font_int_unref(RGBA_Font_Int *fi)
{
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();
}
}
EAPI void
evas_common_font_free(RGBA_Font *fn)
{
Eina_List *l;
RGBA_Font_Int *fi;
if (!fn) return;
fn->references--;
if (fn->references > 0) return;
EINA_LIST_FOREACH(fn->fonts, l, fi)
evas_common_font_int_unref(fi);
evas_common_font_flush();
eina_list_free(fn->fonts);
if (fn->fash) fn->fash->freeme(fn->fash);
LKD(fn->lock);
free(fn);
}
EAPI void
evas_common_font_hinting_set(RGBA_Font *fn, Font_Hint_Flags hinting)
{
Eina_List *l;
RGBA_Font_Int *fi;
if (!fn) return;
fn->hinting = hinting;
EINA_LIST_FOREACH(fn->fonts, l, fi)
{
fi->hinting = fn->hinting;
}
}
EAPI Eina_Bool
evas_common_hinting_available(Font_Hint_Flags hinting)
{
switch (hinting)
{
case FONT_NO_HINT:
case FONT_AUTO_HINT:
/* these two hinting modes are always available */
return EINA_TRUE;
case FONT_BYTECODE_HINT:
/* Only use the bytecode interpreter if support for the _patented_
* algorithms is available because the free bytecode
* interpreter's results are too crappy.
*
* On freetyp 2.2+, we can ask the library about support for
* the patented interpreter. On older versions, we need to use
* macros to check for it.
*/
#if FREETYPE_MINOR >= 2
return FT_Get_TrueType_Engine_Type(evas_ft_lib) >=
FT_TRUETYPE_ENGINE_TYPE_PATENTED;
#else
/* we may not rely on TT_CONFIG_OPTION_BYTECODE_INTERPRETER
* here to find out whether it's supported.
*
* so, assume it is. o_O
*/
return EINA_TRUE;
#endif
}
/* shouldn't get here - need to add another case statement */
return EINA_FALSE;
}
EAPI RGBA_Font *
evas_common_font_memory_hinting_load(const char *source, const char *name, int size, const void *data, int data_size, Font_Hint_Flags hinting, Font_Rend_Flags wanted_rend)
{
RGBA_Font *fn;
fn = evas_common_font_memory_load(source, name, size, data, data_size, wanted_rend);
if (fn) evas_common_font_hinting_set(fn, hinting);
return fn;
}
EAPI RGBA_Font *
evas_common_font_hinting_load(const char *name, int size, Font_Hint_Flags hinting, Font_Rend_Flags wanted_rend)
{
RGBA_Font *fn;
fn = evas_common_font_load(name, size, wanted_rend);
if (fn) evas_common_font_hinting_set(fn, hinting);
return fn;
}
EAPI RGBA_Font *
evas_common_font_hinting_add(RGBA_Font *fn, const char *name, int size, Font_Hint_Flags hinting, Font_Rend_Flags wanted_rend)
{
fn = evas_common_font_add(fn, name, size, wanted_rend);
if (fn) evas_common_font_hinting_set(fn, hinting);
return fn;
}
EAPI RGBA_Font *
evas_common_font_memory_hinting_add(RGBA_Font *fn, const char *source, const char *name, int size, const void *data, int data_size, Font_Hint_Flags hinting, Font_Rend_Flags wanted_rend)
{
fn = evas_common_font_memory_add(fn, source, name, size, data, data_size,
wanted_rend);
if (fn) evas_common_font_hinting_set(fn, hinting);
return fn;
}
static void
_evas_common_font_int_clear(RGBA_Font_Int *fi)
{
LKL(fi->ft_mutex);
if (!fi->fash)
{
LKU(fi->ft_mutex);
return;
}
evas_common_font_int_modify_cache_by(fi, -1);
if (fi->references <= 1)
{
if (fi->fash)
{
fi->fash->freeme(fi->fash);
fi->fash = NULL;
}
}
if (fi->inuse) fonts_use_usage -= fi->usage;
fi->usage = 0;
fi->generation++;
LKU(fi->ft_mutex);
}
static Eina_Bool
_evas_common_font_all_clear_cb(const Eina_Hash *hash __UNUSED__, const void *key __UNUSED__, void *data, void *fdata __UNUSED__)
{
RGBA_Font_Int *fi = data;
_evas_common_font_int_clear(fi);
return 1;
}
EAPI void
evas_common_font_all_clear(void)
{
eina_hash_foreach(fonts, _evas_common_font_all_clear_cb, NULL);
}
void
evas_common_font_int_promote(RGBA_Font_Int *fi)
{
return;
if (fonts_use_lru == (Eina_Inlist *)fi) return;
if (!fi->inuse) return;
fonts_use_lru = eina_inlist_remove(fonts_use_lru, EINA_INLIST_GET(fi));
fonts_use_lru = eina_inlist_prepend(fonts_use_lru, EINA_INLIST_GET(fi));
}
void
evas_common_font_int_use_increase(int size)
{
fonts_use_usage += size;
}
void
evas_common_font_int_use_trim(void)
{
Eina_Inlist *l;
return;
if (fonts_use_usage <= (font_cache << 1)) return;
if (!fonts_use_lru) return;
l = fonts_use_lru->last;
while (l)
{
RGBA_Font_Int *fi = (RGBA_Font_Int *)l;
if (fonts_use_usage <= (font_cache << 1)) break;
// FIXME: del fi->kerning content
_evas_common_font_int_clear(fi);
evas_common_font_int_unload(fi);
evas_common_font_int_promote(fi);
l = l->prev;
}
}
void
evas_common_font_int_unload(RGBA_Font_Int *fi)
{
return;
if (!fi->src->ft.face) return;
_evas_common_font_int_clear(fi);
FT_Done_Size(fi->ft.size);
fi->ft.size = NULL;
evas_common_font_source_unload(fi->src);
}
void
evas_common_font_int_reload(RGBA_Font_Int *fi)
{
if (fi->src->ft.face) return;
evas_common_font_source_load_complete(fi->src);
return;
evas_common_font_source_reload(fi->src);
evas_common_font_int_load_complete(fi);
}
/* when the fi->references == 0 we increase this instead of really deleting
* we then check if the cache_useage size is larger than allowed
* !If the cache is NOT too large we dont delete font_int
* !If the cache is too large we really delete font_int */
EAPI void
evas_common_font_int_modify_cache_by(RGBA_Font_Int *fi, int dir)
{
font_cache_usage += dir * (sizeof(RGBA_Font) + fi->usage +
sizeof(FT_FaceRec) + 16384); /* fudge values */
}
EAPI int
evas_common_font_cache_get(void)
{
return font_cache;
}
EAPI void
evas_common_font_cache_set(int size)
{
font_cache = size;
evas_common_font_flush();
evas_common_font_int_use_trim();
}
EAPI void
evas_common_font_flush(void)
{
if (font_cache_usage < font_cache) return;
while (font_cache_usage > font_cache)
{
int pfont_cache_usage;
pfont_cache_usage = font_cache_usage;
evas_common_font_flush_last();
if (pfont_cache_usage == font_cache_usage) break;
}
}
/* 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 = NULL;
if (!fonts_lru) return ;
fi = eina_list_data_get(fonts_lru);
fonts_lru = eina_list_remove_list(fonts_lru, fonts_lru);
eina_hash_del(fonts, fi, fi);
}
EAPI RGBA_Font_Int *
evas_common_font_int_find(const char *name, int size,
Font_Rend_Flags wanted_rend)
{
RGBA_Font_Int tmp_fi;
RGBA_Font_Source tmp_fn;
RGBA_Font_Int *fi;
tmp_fn.name = (char*) eina_stringshare_add(name);
tmp_fi.src = &tmp_fn;
tmp_fi.size = size;
tmp_fi.wanted_rend = wanted_rend;
fi = eina_hash_find(fonts, &tmp_fi);
if (fi)
{
if (fi->references == 0)
{
evas_common_font_int_modify_cache_by(fi, -1);
fonts_lru = eina_list_remove(fonts_lru, fi);
}
fi->references++;
}
eina_stringshare_del(tmp_fn.name);
return fi;
}