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

551 lines
12 KiB
C
Raw Normal View History

2002-11-08 00:02:15 -08:00
#include "evas_common.h"
#include "evas_private.h"
2002-11-08 00:02:15 -08:00
extern FT_Library evas_ft_lib;
2002-11-08 00:02:15 -08:00
static int font_cache_usage = 0;
static int font_cache = 0;
static Evas_Object_List * fonts_src = NULL;
2002-11-08 00:02:15 -08:00
static Evas_Object_List * fonts = NULL;
static Evas_Bool font_modify_cache_cb(Evas_Hash *hash, const char *key, void *data, void *fdata);
static Evas_Bool font_flush_free_glyph_cb(Evas_Hash *hash, const char *key, void *data, void *fdata);
2002-11-08 00:02:15 -08:00
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;
2005-05-21 19:49:50 -07:00
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;
2004-01-22 21:58:34 -08:00
fs->current_size = 0;
memcpy(fs->data, data, data_size);
error = FT_New_Memory_Face(evas_ft_lib, fs->data, fs->data_size, 0, &(fs->ft.face));
if (error)
{
free(fs);
return NULL;
}
fs->name = evas_stringshare_add(name);
fs->file = NULL;
error = FT_Select_Charmap(fs->ft.face, ft_encoding_unicode);
fs->ft.orig_upem = fs->ft.face->units_per_EM;
fs->references = 1;
2005-05-21 19:49:50 -07:00
fonts_src = evas_object_list_prepend(fonts_src, fs);
return fs;
}
EAPI RGBA_Font_Source *
evas_common_font_source_load(const char *name)
{
RGBA_Font_Source *fs;
2005-05-21 19:49:50 -07:00
fs = calloc(1, sizeof(RGBA_Font_Source));
if (!fs) return NULL;
2004-01-22 21:58:34 -08:00
fs->data = NULL;
fs->data_size = 0;
fs->current_size = 0;
fs->ft.face = NULL;
fs->name = evas_stringshare_add(name);
fs->file = fs->name;
fs->ft.orig_upem = 0;
fs->references = 1;
2005-05-21 19:49:50 -07:00
fonts_src = evas_object_list_prepend(fonts_src, fs);
return fs;
}
EAPI int
evas_common_font_source_load_complete(RGBA_Font_Source *fs)
{
int error;
error = FT_New_Face(evas_ft_lib, fs->file, 0, &(fs->ft.face));
if (error) return error;
error = FT_Select_Charmap(fs->ft.face, ft_encoding_unicode);
if (error) return error;
fs->ft.orig_upem = fs->ft.face->units_per_EM;
return error;
}
EAPI RGBA_Font_Source *
evas_common_font_source_find(const char *name)
{
Evas_Object_List *l;
if (!name) return NULL;
for (l = fonts_src; l; l = l->next)
{
RGBA_Font_Source *fs;
2005-05-21 19:49:50 -07:00
fs = (RGBA_Font_Source *)l;
if ((fs->name) && (!strcmp(name, fs->name)))
{
2005-05-21 19:49:50 -07:00
fs->references++;
fonts_src = evas_object_list_remove(fonts_src, fs);
2005-05-21 19:49:50 -07:00
fonts_src = evas_object_list_prepend(fonts_src, fs);
return fs;
}
}
return NULL;
}
EAPI void
evas_common_font_source_free(RGBA_Font_Source *fs)
{
fs->references--;
if (fs->references > 0) return;
2005-05-21 19:49:50 -07:00
fonts_src = evas_object_list_remove(fonts_src, fs);
FT_Done_Face(fs->ft.face);
if (fs->charmap) evas_common_array_hash_free(fs->charmap);
if (fs->name) evas_stringshare_del(fs->name);
free(fs);
}
EAPI void
evas_common_font_size_use(RGBA_Font *fn)
{
Evas_List *l;
2005-05-21 19:49:50 -07:00
for (l = fn->fonts; l; l = l->next)
{
RGBA_Font_Int *fi;
2005-05-21 19:49:50 -07:00
fi = l->data;
if (fi->src->current_size != fi->size)
{
FT_Activate_Size(fi->ft.size);
fi->src->current_size = fi->size;
}
}
}
EAPI RGBA_Font_Int *
evas_common_font_int_memory_load(const char *name, int size, const void *data, int data_size)
{
RGBA_Font_Int *fi;
fi = evas_common_font_int_find(name, size);
if (fi) return fi;
2005-05-21 19:49:50 -07:00
fi = calloc(1, sizeof(RGBA_Font_Int));
if (!fi) return NULL;
2005-05-21 19:49:50 -07:00
fi->src = evas_common_font_source_find(name);
if (!fi->src)
fi->src = evas_common_font_source_memory_load(name, data, data_size);
if (!fi->src)
{
free(fi);
return NULL;
}
2005-05-21 19:49:50 -07:00
fi->size = size;
fi = evas_common_font_int_load_init(fi);
evas_common_font_int_load_complete(fi);
return fi;
}
2002-11-08 00:02:15 -08:00
EAPI RGBA_Font_Int *
evas_common_font_int_load(const char *name, int size)
2002-11-08 00:02:15 -08:00
{
RGBA_Font_Int *fi;
2002-11-08 00:02:15 -08:00
fi = evas_common_font_int_find(name, size);
if (fi) return fi;
2005-05-21 19:49:50 -07:00
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)
2002-11-08 00:02:15 -08:00
{
free(fi);
2002-11-08 00:02:15 -08:00
return NULL;
}
2005-05-21 19:49:50 -07:00
fi->size = size;
return evas_common_font_int_load_init(fi);
}
EAPI RGBA_Font_Int *
evas_common_font_int_load_init(RGBA_Font_Int *fi)
{
fi->ft.size = NULL;
fi->glyphs = NULL;
fi->usage = 0;
fi->references = 1;
fonts = evas_object_list_prepend(fonts, fi);
return fi;
}
EAPI RGBA_Font_Int *
evas_common_font_int_load_complete(RGBA_Font_Int *fi)
{
int error;
2005-05-21 19:49:50 -07:00
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, 75, 75);
2002-11-08 00:02:15 -08:00
if (error)
{
fi->real_size = fi->size;
error = FT_Set_Pixel_Sizes(fi->src->ft.face, 0, fi->real_size);
}
2002-11-08 00:02:15 -08:00
if (error)
{
int i;
int chosen_size = 0;
int chosen_width = 0;
for (i = 0; i < fi->src->ft.face->num_fixed_sizes; i++)
2002-11-08 00:02:15 -08:00
{
int s;
int d, cd;
2005-05-21 19:49:50 -07:00
s = fi->src->ft.face->available_sizes[i].height;
cd = chosen_size - fi->size;
2002-11-08 00:02:15 -08:00
if (cd < 0) cd = -cd;
d = s - fi->size;
2002-11-08 00:02:15 -08:00
if (d < 0) d = -d;
if (d < cd)
{
chosen_width = fi->src->ft.face->available_sizes[i].width;
2002-11-08 00:02:15 -08:00
chosen_size = s;
}
if (d == 0) break;
}
fi->real_size = chosen_size;
error = FT_Set_Pixel_Sizes(fi->src->ft.face, chosen_width, fi->real_size);
2002-11-08 00:02:15 -08:00
if (error)
{
/* couldn't choose the size anyway... what now? */
}
}
fi->src->current_size = fi->size;
return fi;
}
EAPI RGBA_Font *
evas_common_font_memory_load(const char *name, int size, const void *data, int data_size)
{
RGBA_Font *fn;
RGBA_Font_Int *fi;
fi = evas_common_font_int_memory_load(name, size, data, data_size);
if (!fi) return NULL;
fn = calloc(1, sizeof(RGBA_Font));
if (!fn)
{
free(fi);
return NULL;
}
fn->fonts = evas_list_append(fn->fonts, fi);
fn->hinting = FONT_BYTECODE_HINT;
fi->hinting = fn->hinting;
2002-11-08 00:02:15 -08:00
return fn;
}
EAPI RGBA_Font *
evas_common_font_load(const char *name, int size)
{
RGBA_Font *fn;
RGBA_Font_Int *fi;
2005-05-21 19:49:50 -07:00
fi = evas_common_font_int_load(name, size);
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))
{
fonts = evas_object_list_remove(fonts, fi);
evas_common_font_source_free(fi->src);
free(fi);
return NULL;
}
}
evas_common_font_int_load_complete(fi);
}
fn = calloc(1, sizeof(RGBA_Font));
if (!fn)
{
free(fi);
return NULL;
}
fn->fonts = evas_list_append(fn->fonts, fi);
fn->hinting = FONT_BYTECODE_HINT;
fi->hinting = fn->hinting;
return fn;
}
EAPI RGBA_Font *
evas_common_font_add(RGBA_Font *fn, const char *name, int size)
{
RGBA_Font_Int *fi;
2005-05-21 19:49:50 -07:00
if (!fn)
return NULL;
fi = evas_common_font_int_load(name, size);
if (fi)
{
fn->fonts = evas_list_append(fn->fonts, fi);
fi->hinting = fn->hinting;
2005-03-20 08:41:49 -08:00
return fn;
}
2005-03-20 08:41:49 -08:00
return NULL;
}
EAPI RGBA_Font *
evas_common_font_memory_add(RGBA_Font *fn, const char *name, int size, const void *data, int data_size)
{
RGBA_Font_Int *fi;
2005-05-21 19:49:50 -07:00
if (!fn)
return NULL;
fi = evas_common_font_int_memory_load(name, size, data, data_size);
if (fi)
{
fn->fonts = evas_list_append(fn->fonts, fi);
fi->hinting = fn->hinting;
2005-03-20 08:41:49 -08:00
return fn;
}
2005-03-20 08:41:49 -08:00
return NULL;
}
EAPI void
evas_common_font_free(RGBA_Font *fn)
2002-11-08 00:02:15 -08:00
{
Evas_List *l;
2005-05-21 19:49:50 -07:00
if (!fn)
return;
for (l = fn->fonts; l; l = l->next)
2002-11-08 00:02:15 -08:00
{
RGBA_Font_Int *fi;
2005-05-21 19:49:50 -07:00
fi = l->data;
fi->references--;
if (fi->references == 0)
{
evas_common_font_int_modify_cache_by(fi, 1);
evas_common_font_flush();
}
2002-11-08 00:02:15 -08:00
}
evas_list_free(fn->fonts);
free(fn);
2002-11-08 00:02:15 -08:00
}
EAPI void
evas_common_font_hinting_set(RGBA_Font *fn, Font_Hint_Flags hinting)
{
Evas_List *l;
if (!fn)
return;
fn->hinting = hinting;
for (l = fn->fonts; l; l = l->next)
{
RGBA_Font_Int *fi;
fi = l->data;
fi->hinting = fn->hinting;
}
}
EAPI Evas_Bool
evas_common_hinting_available(Font_Hint_Flags hinting)
{
if (hinting == FONT_NO_HINT) return 1;
else if (hinting == FONT_AUTO_HINT)
{
#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
return 1;
#else
return 1;
#endif
}
else if (hinting == FONT_BYTECODE_HINT)
{
#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
return 1;
#else
return 1;
#endif
}
return 0;
}
EAPI RGBA_Font *
evas_common_font_memory_hinting_load(const char *name, int size, const void *data, int data_size, Font_Hint_Flags hinting)
{
RGBA_Font *fn;
fn = evas_common_font_memory_load(name, size, data, data_size);
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)
{
RGBA_Font *fn;
fn = evas_common_font_load(name, size);
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)
{
fn = evas_common_font_add(fn, name, size);
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 *name, int size, const void *data, int data_size, Font_Hint_Flags hinting)
{
fn = evas_common_font_memory_add(fn, name, size, data, data_size);
if (fn) evas_common_font_hinting_set(fn, hinting);
return fn;
}
static Evas_Bool
2002-11-08 00:02:15 -08:00
font_modify_cache_cb(Evas_Hash *hash, const char *key, void *data, void *fdata)
{
int *dir;
RGBA_Font_Glyph *fg;
2005-05-21 19:49:50 -07:00
fg = data;
2002-11-08 00:02:15 -08:00
dir = fdata;
2005-05-21 19:49:50 -07:00
font_cache_usage += (*dir) *
2002-11-08 00:02:15 -08:00
((fg->glyph_out->bitmap.width * fg->glyph_out->bitmap.rows) +
sizeof(RGBA_Font_Glyph) + sizeof(Evas_List) + 400); /* fudge values */
return 1;
hash = 0;
key = 0;
}
EAPI void
evas_common_font_int_modify_cache_by(RGBA_Font_Int *fi, int dir)
2002-11-08 00:02:15 -08:00
{
int sz_hash = 0;
2005-05-21 19:49:50 -07:00
if (fi->glyphs) sz_hash = sizeof(Evas_Hash);
evas_hash_foreach(fi->glyphs, font_modify_cache_cb, &dir);
font_cache_usage += dir * (sizeof(RGBA_Font) + sz_hash +
2002-11-08 00:02:15 -08:00
sizeof(FT_FaceRec) + 16384); /* fudge values */
}
EAPI int
evas_common_font_cache_get(void)
2002-11-08 00:02:15 -08:00
{
return font_cache;
}
EAPI void
evas_common_font_cache_set(int size)
2002-11-08 00:02:15 -08:00
{
font_cache = size;
evas_common_font_flush();
2002-11-08 00:02:15 -08:00
}
EAPI void
evas_common_font_flush(void)
2002-11-08 00:02:15 -08:00
{
if (font_cache_usage < font_cache) return;
while (font_cache_usage > font_cache) evas_common_font_flush_last();
2002-11-08 00:02:15 -08:00
}
static Evas_Bool
2002-11-08 00:02:15 -08:00
font_flush_free_glyph_cb(Evas_Hash *hash, const char *key, void *data, void *fdata)
{
RGBA_Font_Glyph *fg;
2005-05-21 19:49:50 -07:00
2002-11-08 00:02:15 -08:00
fg = data;
FT_Done_Glyph(fg->glyph);
/* extension calls */
if (fg->ext_dat_free) fg->ext_dat_free(fg->ext_dat);
2002-11-08 00:02:15 -08:00
free(fg);
return 1;
hash = 0;
key = 0;
fdata = 0;
}
EAPI void
evas_common_font_flush_last(void)
2002-11-08 00:02:15 -08:00
{
Evas_Object_List *l;
RGBA_Font_Int *fi = NULL;
2005-05-21 19:49:50 -07:00
2002-11-08 00:02:15 -08:00
for (l = fonts; l; l = l->next)
{
RGBA_Font_Int *fi_tmp;
2005-05-21 19:49:50 -07:00
fi_tmp = (RGBA_Font_Int *)l;
if (fi_tmp->references == 0) fi = fi_tmp;
2002-11-08 00:02:15 -08:00
}
if (!fi) return;
2005-05-21 19:49:50 -07:00
FT_Done_Size(fi->ft.size);
2005-05-21 19:49:50 -07:00
fonts = evas_object_list_remove(fonts, fi);
evas_common_font_int_modify_cache_by(fi, -1);
2002-11-08 00:02:15 -08:00
evas_hash_foreach(fi->glyphs, font_flush_free_glyph_cb, NULL);
evas_hash_free(fi->glyphs);
2005-05-21 19:49:50 -07:00
evas_common_font_source_free(fi->src);
2005-05-21 19:49:50 -07:00
free(fi);
2002-11-08 00:02:15 -08:00
}
EAPI RGBA_Font_Int *
evas_common_font_int_find(const char *name, int size)
2002-11-08 00:02:15 -08:00
{
Evas_Object_List *l;
2005-05-21 19:49:50 -07:00
2002-11-08 00:02:15 -08:00
for (l = fonts; l; l = l->next)
{
RGBA_Font_Int *fi;
2005-05-21 19:49:50 -07:00
fi = (RGBA_Font_Int *)l;
if ((fi->size == size) && (!strcmp(name, fi->src->name)))
2002-11-08 00:02:15 -08:00
{
if (fi->references == 0) evas_common_font_int_modify_cache_by(fi, -1);
fi->references++;
fonts = evas_object_list_remove(fonts, fi);
fonts = evas_object_list_prepend(fonts, fi);
return fi;
2002-11-08 00:02:15 -08:00
}
}
return NULL;
}