forked from enlightenment/efl
1487 lines
40 KiB
C
1487 lines
40 KiB
C
#ifdef HAVE_CONFIG_H
|
|
# include <config.h>
|
|
#endif
|
|
|
|
#ifdef _WIN32
|
|
# include <evil_private.h> /* evil_path_is_absolute */
|
|
#endif
|
|
|
|
#include <Eet.h>
|
|
|
|
#ifdef HAVE_FONTCONFIG
|
|
#include <fontconfig/fontconfig.h>
|
|
#include <fontconfig/fcfreetype.h>
|
|
#endif
|
|
|
|
#include "evas_font.h"
|
|
|
|
/* General types - used for script type chceking */
|
|
#define OPAQUE_TYPE(type) struct __##type { int a; }; \
|
|
typedef struct __##type type
|
|
|
|
OPAQUE_TYPE(Evas_Font_Set); /* General type for RGBA_Font */
|
|
OPAQUE_TYPE(Evas_Font_Instance); /* General type for RGBA_Font_Int */
|
|
|
|
/* font dir cache */
|
|
static Eina_Hash *font_dirs = NULL;
|
|
static Eina_List *fonts_cache = NULL;
|
|
static Eina_List *fonts_zero = NULL;
|
|
static Eina_List *global_font_path = NULL;
|
|
|
|
typedef struct _Fndat Fndat;
|
|
|
|
struct _Fndat
|
|
{
|
|
Evas_Font_Description *fdesc;
|
|
const char *source;
|
|
Evas_Font_Size size;
|
|
Evas_Font_Set *font;
|
|
int ref;
|
|
Font_Rend_Flags wanted_rend;
|
|
Efl_Text_Font_Bitmap_Scalable bitmap_scalable;
|
|
|
|
#ifdef HAVE_FONTCONFIG
|
|
FcFontSet *set;
|
|
FcPattern *p_nm;
|
|
|
|
Eina_Bool file_font : 1; /* Indicates this is a font that uses a file rather than fontconfig. */
|
|
#endif
|
|
};
|
|
|
|
/* private methods for font dir cache */
|
|
static Eina_Bool font_cache_dir_free(const Eina_Hash *hash, const void *key, void *data, void *fdata);
|
|
static Evas_Font_Dir *object_text_font_cache_dir_update(char *dir, Evas_Font_Dir *fd);
|
|
static Evas_Font *object_text_font_cache_font_find_x(Evas_Font_Dir *fd, char *font);
|
|
static Evas_Font *object_text_font_cache_font_find_file(Evas_Font_Dir *fd, char *font);
|
|
static Evas_Font *object_text_font_cache_font_find_alias(Evas_Font_Dir *fd, char *font);
|
|
static Evas_Font *object_text_font_cache_font_find(Evas_Font_Dir *fd, char *font);
|
|
static Evas_Font_Dir *object_text_font_cache_dir_add(char *dir);
|
|
static void object_text_font_cache_dir_del(char *dir, Evas_Font_Dir *fd);
|
|
static int evas_object_text_font_string_parse(char *buffer, char dest[14][256]);
|
|
|
|
#ifdef HAVE_FONTCONFIG
|
|
static FcConfig *fc_config = NULL;
|
|
#endif
|
|
|
|
/* FIXME move these helper function to eina_file or eina_path */
|
|
/* get the casefold feature! */
|
|
#include <fnmatch.h>
|
|
#include <unistd.h>
|
|
#include <sys/param.h>
|
|
int
|
|
_file_path_is_full_path(const char *path)
|
|
{
|
|
if (!path) return 0;
|
|
#ifdef _WIN32
|
|
if (evil_path_is_absolute(path)) return 1;
|
|
#else
|
|
if (path[0] == '/') return 1;
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
static DATA64
|
|
_file_modified_time(const char *file)
|
|
{
|
|
struct stat st;
|
|
|
|
if (stat(file, &st) < 0) return 0;
|
|
if (st.st_ctime > st.st_mtime) return (DATA64)st.st_ctime;
|
|
else return (DATA64)st.st_mtime;
|
|
return 0;
|
|
}
|
|
|
|
Eina_List *
|
|
_file_path_list(char *path, const char *match, int match_case)
|
|
{
|
|
Eina_File_Direct_Info *info;
|
|
Eina_Iterator *it;
|
|
Eina_List *files = NULL;
|
|
int flags;
|
|
|
|
flags = FNM_PATHNAME;
|
|
#ifdef FNM_CASEFOLD
|
|
if (!match_case)
|
|
flags |= FNM_CASEFOLD;
|
|
#elif defined FNM_IGNORECASE
|
|
if (!match_case)
|
|
flags |= FNM_IGNORECASE;
|
|
#else
|
|
/*#warning "Your libc does not provide case-insensitive matching!"*/
|
|
#endif
|
|
|
|
it = eina_file_direct_ls(path);
|
|
EINA_ITERATOR_FOREACH(it, info)
|
|
{
|
|
if (match)
|
|
{
|
|
if (fnmatch(match, info->path + info->name_start, flags) == 0)
|
|
files = eina_list_append(files, strdup(info->path + info->name_start));
|
|
}
|
|
else
|
|
files = eina_list_append(files, strdup(info->path + info->name_start));
|
|
}
|
|
if (it) eina_iterator_free(it);
|
|
return files;
|
|
}
|
|
|
|
static void
|
|
evas_font_init(void)
|
|
{
|
|
#ifdef HAVE_FONTCONFIG
|
|
if (!fc_config)
|
|
{
|
|
Eina_List *l;
|
|
char *path;
|
|
|
|
fc_config = FcInitLoadConfigAndFonts();
|
|
|
|
EINA_LIST_FOREACH(global_font_path, l, path)
|
|
FcConfigAppFontAddDir(fc_config, (const FcChar8 *) path);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void
|
|
evas_font_dir_cache_free(void)
|
|
{
|
|
if (font_dirs)
|
|
{
|
|
eina_hash_foreach(font_dirs, font_cache_dir_free, NULL);
|
|
eina_hash_free(font_dirs);
|
|
font_dirs = NULL;
|
|
}
|
|
#ifdef HAVE_FONTCONFIG
|
|
if (fc_config)
|
|
{
|
|
FcConfigDestroy(fc_config);
|
|
fc_config = NULL;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
const char *
|
|
evas_font_dir_cache_find(char *dir, char *font)
|
|
{
|
|
Evas_Font_Dir *fd = NULL;
|
|
|
|
if (!font_dirs) font_dirs = eina_hash_string_superfast_new(NULL);
|
|
else fd = eina_hash_find(font_dirs, dir);
|
|
fd = object_text_font_cache_dir_update(dir, fd);
|
|
if (fd)
|
|
{
|
|
Evas_Font *fn;
|
|
|
|
fn = object_text_font_cache_font_find(fd, font);
|
|
if (fn)
|
|
{
|
|
return fn->path;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static Eina_List *
|
|
evas_font_set_get(const char *name)
|
|
{
|
|
Eina_List *fonts = NULL;
|
|
char *p;
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(name, NULL);
|
|
if (!*name) return NULL;
|
|
|
|
p = strchr(name, ',');
|
|
if (!p)
|
|
{
|
|
fonts = eina_list_append(fonts, eina_stringshare_add(name));
|
|
}
|
|
else
|
|
{
|
|
const char *pp;
|
|
char *nm;
|
|
|
|
pp = name;
|
|
while (p)
|
|
{
|
|
nm = alloca(p - pp + 1);
|
|
strncpy(nm, pp, p - pp);
|
|
nm[p - pp] = 0;
|
|
fonts = eina_list_append(fonts, eina_stringshare_add(nm));
|
|
pp = p + 1;
|
|
p = strchr(pp, ',');
|
|
if (!p) fonts = eina_list_append(fonts, eina_stringshare_add(pp));
|
|
}
|
|
}
|
|
return fonts;
|
|
}
|
|
|
|
void
|
|
evas_fonts_zero_free()
|
|
{
|
|
Fndat *fd;
|
|
|
|
EINA_LIST_FREE(fonts_zero, fd)
|
|
{
|
|
if (fd->fdesc) evas_font_desc_unref(fd->fdesc);
|
|
if (fd->source) eina_stringshare_del(fd->source);
|
|
evas_common_font_free((RGBA_Font *)fd->font);
|
|
#ifdef HAVE_FONTCONFIG
|
|
if (fd->set) FcFontSetDestroy(fd->set);
|
|
if (fd->p_nm) FcPatternDestroy(fd->p_nm);
|
|
#endif
|
|
free(fd);
|
|
}
|
|
}
|
|
|
|
void
|
|
evas_fonts_zero_pressure()
|
|
{
|
|
Fndat *fd;
|
|
|
|
while (fonts_zero
|
|
&& eina_list_count(fonts_zero) > 4) /* 4 is arbitrary */
|
|
{
|
|
fd = eina_list_data_get(fonts_zero);
|
|
|
|
if (fd->ref != 0) break;
|
|
fonts_zero = eina_list_remove_list(fonts_zero, fonts_zero);
|
|
|
|
if (fd->fdesc) evas_font_desc_unref(fd->fdesc);
|
|
if (fd->source) eina_stringshare_del(fd->source);
|
|
evas_common_font_free((RGBA_Font *)fd->font);
|
|
#ifdef HAVE_FONTCONFIG
|
|
if (fd->set) FcFontSetDestroy(fd->set);
|
|
if (fd->p_nm) FcPatternDestroy(fd->p_nm);
|
|
#endif
|
|
free(fd);
|
|
|
|
if (eina_list_count(fonts_zero) < 5) break;
|
|
}
|
|
}
|
|
|
|
void
|
|
evas_font_free(void *font)
|
|
{
|
|
Eina_List *l;
|
|
Fndat *fd;
|
|
|
|
EINA_LIST_FOREACH(fonts_cache, l, fd)
|
|
{
|
|
if (fd->font == font)
|
|
{
|
|
fd->ref--;
|
|
if (fd->ref == 0)
|
|
{
|
|
fonts_cache = eina_list_remove_list(fonts_cache, l);
|
|
fonts_zero = eina_list_append(fonts_zero, fd);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
while (fonts_zero
|
|
&& eina_list_count(fonts_zero) > 42) /* 42 is arbitrary */
|
|
{
|
|
fd = eina_list_data_get(fonts_zero);
|
|
|
|
if (fd->ref != 0) break;
|
|
fonts_zero = eina_list_remove_list(fonts_zero, fonts_zero);
|
|
|
|
if (fd->fdesc) evas_font_desc_unref(fd->fdesc);
|
|
if (fd->source) eina_stringshare_del(fd->source);
|
|
evas_common_font_free((RGBA_Font *)fd->font);
|
|
#ifdef HAVE_FONTCONFIG
|
|
if (fd->set) FcFontSetDestroy(fd->set);
|
|
if (fd->p_nm) FcPatternDestroy(fd->p_nm);
|
|
#endif
|
|
free(fd);
|
|
|
|
if (eina_list_count(fonts_zero) < 43) break;
|
|
}
|
|
}
|
|
|
|
#ifdef HAVE_FONTCONFIG
|
|
static Evas_Font_Set *
|
|
_evas_load_fontconfig(Evas_Font_Set *font, FcFontSet *set, int size,
|
|
Font_Rend_Flags wanted_rend, Efl_Text_Font_Bitmap_Scalable bitmap_scalable)
|
|
{
|
|
int i;
|
|
|
|
/* Do loading for all in family */
|
|
for (i = 0; i < set->nfont; i++)
|
|
{
|
|
FcValue filename;
|
|
|
|
if (FcPatternGet(set->fonts[i], FC_FILE, 0, &filename) == FcResultMatch)
|
|
{
|
|
if (font)
|
|
evas_common_font_add((RGBA_Font *)font, (char *)filename.u.s, size, wanted_rend, bitmap_scalable);
|
|
else
|
|
font = (Evas_Font_Set *)evas_common_font_load((char *)filename.u.s, size, wanted_rend, bitmap_scalable);
|
|
}
|
|
}
|
|
|
|
return font;
|
|
}
|
|
#endif
|
|
|
|
#ifdef HAVE_FONTCONFIG
|
|
/* In sync with Evas_Font_Style, Evas_Font_Weight and Evas_Font_Width */
|
|
static int _fc_slant_map[] =
|
|
{
|
|
FC_SLANT_ROMAN,
|
|
FC_SLANT_OBLIQUE,
|
|
FC_SLANT_ITALIC
|
|
};
|
|
|
|
/* Apparently EXTRABLACK is not always available, hardcode. */
|
|
# ifndef FC_WEIGHT_EXTRABLACK
|
|
# define FC_WEIGHT_EXTRABLACK 215
|
|
# endif
|
|
static int _fc_weight_map[] =
|
|
{
|
|
FC_WEIGHT_NORMAL,
|
|
FC_WEIGHT_THIN,
|
|
FC_WEIGHT_ULTRALIGHT,
|
|
FC_WEIGHT_EXTRALIGHT,
|
|
FC_WEIGHT_LIGHT,
|
|
FC_WEIGHT_BOOK,
|
|
FC_WEIGHT_MEDIUM,
|
|
FC_WEIGHT_SEMIBOLD,
|
|
FC_WEIGHT_BOLD,
|
|
FC_WEIGHT_ULTRABOLD,
|
|
FC_WEIGHT_EXTRABOLD,
|
|
FC_WEIGHT_BLACK,
|
|
FC_WEIGHT_EXTRABLACK
|
|
};
|
|
|
|
# ifdef FC_WIDTH
|
|
static int _fc_width_map[] =
|
|
{
|
|
FC_WIDTH_NORMAL,
|
|
FC_WIDTH_ULTRACONDENSED,
|
|
FC_WIDTH_EXTRACONDENSED,
|
|
FC_WIDTH_CONDENSED,
|
|
FC_WIDTH_SEMICONDENSED,
|
|
FC_WIDTH_SEMIEXPANDED,
|
|
FC_WIDTH_EXPANDED,
|
|
FC_WIDTH_EXTRAEXPANDED,
|
|
FC_WIDTH_ULTRAEXPANDED
|
|
};
|
|
# endif
|
|
|
|
static int _fc_spacing_map[] =
|
|
{
|
|
FC_PROPORTIONAL,
|
|
FC_DUAL,
|
|
FC_MONO,
|
|
FC_CHARCELL
|
|
};
|
|
|
|
#endif
|
|
|
|
struct _Style_Map
|
|
{
|
|
const char *name;
|
|
int type;
|
|
};
|
|
typedef struct _Style_Map Style_Map;
|
|
|
|
static Style_Map _style_width_map[] =
|
|
{
|
|
{"normal", EVAS_FONT_WIDTH_NORMAL},
|
|
{"ultracondensed", EVAS_FONT_WIDTH_ULTRACONDENSED},
|
|
{"extracondensed", EVAS_FONT_WIDTH_EXTRACONDENSED},
|
|
{"condensed", EVAS_FONT_WIDTH_CONDENSED},
|
|
{"semicondensed", EVAS_FONT_WIDTH_SEMICONDENSED},
|
|
{"semiexpanded", EVAS_FONT_WIDTH_SEMIEXPANDED},
|
|
{"expanded", EVAS_FONT_WIDTH_EXPANDED},
|
|
{"extraexpanded", EVAS_FONT_WIDTH_EXTRAEXPANDED},
|
|
{"ultraexpanded", EVAS_FONT_WIDTH_ULTRAEXPANDED},
|
|
};
|
|
|
|
static Style_Map _style_weight_map[] =
|
|
{
|
|
{"normal", EVAS_FONT_WEIGHT_NORMAL},
|
|
{"thin", EVAS_FONT_WEIGHT_THIN},
|
|
{"ultralight", EVAS_FONT_WEIGHT_ULTRALIGHT},
|
|
{"extralight", EVAS_FONT_WEIGHT_EXTRALIGHT},
|
|
{"light", EVAS_FONT_WEIGHT_LIGHT},
|
|
{"book", EVAS_FONT_WEIGHT_BOOK},
|
|
{"medium", EVAS_FONT_WEIGHT_MEDIUM},
|
|
{"semibold", EVAS_FONT_WEIGHT_SEMIBOLD},
|
|
{"bold", EVAS_FONT_WEIGHT_BOLD},
|
|
{"ultrabold", EVAS_FONT_WEIGHT_ULTRABOLD},
|
|
{"extrabold", EVAS_FONT_WEIGHT_EXTRABOLD},
|
|
{"black", EVAS_FONT_WEIGHT_BLACK},
|
|
{"extrablack", EVAS_FONT_WEIGHT_EXTRABLACK}
|
|
};
|
|
|
|
static Style_Map _style_slant_map[] =
|
|
{
|
|
{"normal", EVAS_FONT_SLANT_NORMAL},
|
|
{"oblique", EVAS_FONT_SLANT_OBLIQUE},
|
|
{"italic", EVAS_FONT_SLANT_ITALIC}
|
|
};
|
|
|
|
static Style_Map _style_spacing_map[] =
|
|
{
|
|
{"proportional", EVAS_FONT_SPACING_PROPORTIONAL},
|
|
{"dualwidth", EVAS_FONT_SPACING_DUAL},
|
|
{"monospace", EVAS_FONT_SPACING_MONO},
|
|
{"charcell", EVAS_FONT_SPACING_CHARCELL}
|
|
};
|
|
|
|
#define _STYLE_MAP_LEN(x) (sizeof(x) / sizeof(*(x)))
|
|
|
|
/**
|
|
* @internal
|
|
* Find the string from the map at a style
|
|
* @return the string at a style type
|
|
*/
|
|
static const char*
|
|
_evas_font_style_find_str_internal(int type, Style_Map _map[], size_t map_len)
|
|
{
|
|
size_t i;
|
|
for ( i = 0; i < map_len; i++ )
|
|
{
|
|
if (_map[i].type == type)
|
|
return _map[i].name;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
const char*
|
|
evas_font_style_find_str(int type, Evas_Font_Style style)
|
|
{
|
|
#define _RET_STYLE(x) \
|
|
return _evas_font_style_find_str_internal(type, \
|
|
_style_##x##_map, _STYLE_MAP_LEN(_style_##x##_map));
|
|
switch (style)
|
|
{
|
|
case EVAS_FONT_STYLE_SLANT:
|
|
_RET_STYLE(slant);
|
|
case EVAS_FONT_STYLE_WEIGHT:
|
|
_RET_STYLE(weight);
|
|
case EVAS_FONT_STYLE_WIDTH:
|
|
_RET_STYLE(width);
|
|
default:
|
|
return NULL;
|
|
}
|
|
#undef _RET_STYLE
|
|
}
|
|
|
|
/**
|
|
* @internal
|
|
* Find a certain attribute from the map in the style.
|
|
* @return the index of the found one.
|
|
*/
|
|
static unsigned int
|
|
_evas_font_style_find_internal(const char *style, const char *style_end,
|
|
Style_Map _map[], size_t map_len)
|
|
{
|
|
size_t i;
|
|
while (style < style_end)
|
|
{
|
|
for (i = 0 ; i < map_len ; i++)
|
|
{
|
|
size_t len;
|
|
const char *cur = _map[i].name;
|
|
len = strlen(cur);
|
|
if (!strncasecmp(style, cur, len) &&
|
|
(!cur[len] || (cur[len] == ' ')))
|
|
{
|
|
return _map[i].type;
|
|
}
|
|
}
|
|
style = strchr(style, ' ');
|
|
if (!style)
|
|
break;
|
|
|
|
while (*style && (*style == ' '))
|
|
style++;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
unsigned int
|
|
evas_font_style_find(const char *start, const char *end,
|
|
Evas_Font_Style style)
|
|
{
|
|
#define _RET_STYLE(x) \
|
|
return _evas_font_style_find_internal(start, end, \
|
|
_style_##x##_map, _STYLE_MAP_LEN(_style_##x##_map));
|
|
switch (style)
|
|
{
|
|
case EVAS_FONT_STYLE_SLANT:
|
|
_RET_STYLE(slant);
|
|
case EVAS_FONT_STYLE_WEIGHT:
|
|
_RET_STYLE(weight);
|
|
case EVAS_FONT_STYLE_WIDTH:
|
|
_RET_STYLE(width);
|
|
default:
|
|
return 0;
|
|
}
|
|
#undef _RET_STYLE
|
|
}
|
|
|
|
void
|
|
evas_font_desc_unref(Evas_Font_Description *fdesc)
|
|
{
|
|
if (--(fdesc->ref) == 0)
|
|
{
|
|
eina_stringshare_del(fdesc->name);
|
|
eina_stringshare_del(fdesc->style);
|
|
eina_stringshare_del(fdesc->fallbacks);
|
|
eina_stringshare_del(fdesc->lang);
|
|
free(fdesc);
|
|
}
|
|
}
|
|
|
|
Evas_Font_Description *
|
|
evas_font_desc_ref(Evas_Font_Description *fdesc)
|
|
{
|
|
fdesc->ref++;
|
|
return fdesc;
|
|
}
|
|
|
|
Evas_Font_Description *
|
|
evas_font_desc_new(void)
|
|
{
|
|
Evas_Font_Description *fdesc;
|
|
fdesc = calloc(1, sizeof(*fdesc));
|
|
fdesc->ref = 1;
|
|
fdesc->is_new = EINA_TRUE;
|
|
|
|
return fdesc;
|
|
}
|
|
|
|
Evas_Font_Description *
|
|
evas_font_desc_dup(const Evas_Font_Description *fdesc)
|
|
{
|
|
Evas_Font_Description *new;
|
|
new = evas_font_desc_new();
|
|
memcpy(new, fdesc, sizeof(*new));
|
|
new->ref = 1;
|
|
new->is_new = EINA_TRUE;
|
|
new->name = eina_stringshare_ref(new->name);
|
|
new->fallbacks = eina_stringshare_ref(new->fallbacks);
|
|
new->lang = eina_stringshare_ref(new->lang);
|
|
new->style = eina_stringshare_ref(new->style);
|
|
|
|
return new;
|
|
}
|
|
|
|
int
|
|
evas_font_desc_cmp(const Evas_Font_Description *a,
|
|
const Evas_Font_Description *b)
|
|
{
|
|
/* FIXME: Do actual comparison, i.e less than and bigger than. */
|
|
return !((a->name == b->name) && (a->weight == b->weight) &&
|
|
(a->slant == b->slant) && (a->width == b->width) &&
|
|
(a->spacing == b->spacing) && (a->lang == b->lang) &&
|
|
(a->fallbacks == b->fallbacks));
|
|
}
|
|
|
|
const char *
|
|
evas_font_lang_normalize(const char *lang)
|
|
{
|
|
if (!lang || !strcmp(lang, "none")) return NULL;
|
|
|
|
if (!strcmp(lang, "auto"))
|
|
return evas_common_language_from_locale_full_get();
|
|
|
|
return lang;
|
|
}
|
|
|
|
void
|
|
evas_font_name_parse(Evas_Font_Description *fdesc, const char *name)
|
|
{
|
|
const char *end;
|
|
|
|
end = strchr(name, ':');
|
|
if (!end)
|
|
eina_stringshare_replace(&(fdesc->name), name);
|
|
else
|
|
eina_stringshare_replace_length(&(fdesc->name), name, end - name);
|
|
|
|
while (end)
|
|
{
|
|
const char *tend;
|
|
name = end;
|
|
end = strchr(end + 1, ':');
|
|
if (!end)
|
|
tend = name + strlen(name);
|
|
else
|
|
tend = end;
|
|
|
|
if (!strncmp(name, ":style=", 7))
|
|
{
|
|
#define _SET_STYLE(x, len) \
|
|
fdesc->x = _evas_font_style_find_internal(name + len, tend, \
|
|
_style_##x##_map, _STYLE_MAP_LEN(_style_##x##_map));
|
|
eina_stringshare_replace_length(&(fdesc->style), name + 7, tend - (name + 7));
|
|
_SET_STYLE(slant, 7);
|
|
_SET_STYLE(weight, 7);
|
|
_SET_STYLE(width, 7);
|
|
}
|
|
else if (!strncmp(name, ":slant=", 7))
|
|
{
|
|
_SET_STYLE(slant, 7);
|
|
}
|
|
else if (!strncmp(name, ":weight=", 8))
|
|
{
|
|
_SET_STYLE(weight, 8);
|
|
}
|
|
else if (!strncmp(name, ":width=", 7))
|
|
{
|
|
_SET_STYLE(width, 7);
|
|
}
|
|
else if (!strncmp(name, ":spacing=", 9))
|
|
{
|
|
_SET_STYLE(spacing, 9);
|
|
#undef _SET_STYLE
|
|
}
|
|
else if (!strncmp(name, ":lang=", 6))
|
|
{
|
|
const char *tmp = name + 6;
|
|
eina_stringshare_replace_length(&(fdesc->lang), tmp, tend - tmp);
|
|
eina_stringshare_replace(&(fdesc->lang), evas_font_lang_normalize(fdesc->lang));
|
|
}
|
|
else if (!strncmp(name, ":fallbacks=", 11))
|
|
{
|
|
const char *tmp = name + 11;
|
|
eina_stringshare_replace_length(&(fdesc->fallbacks), tmp, tend - tmp);
|
|
}
|
|
}
|
|
}
|
|
|
|
void *
|
|
evas_font_load(const Eina_List *font_paths, int hinting, Evas_Font_Description *fdesc, const char *source, Evas_Font_Size size, Efl_Text_Font_Bitmap_Scalable bitmap_scalable)
|
|
{
|
|
#ifdef HAVE_FONTCONFIG
|
|
FcPattern *p_nm = NULL;
|
|
FcFontSet *set = NULL;
|
|
Eina_Bool file_font = EINA_FALSE;
|
|
#endif
|
|
|
|
Evas_Font_Set *font = NULL;
|
|
Eina_List *fonts, *l, *l_next;
|
|
Fndat *fd;
|
|
#ifdef HAVE_FONTCONFIG
|
|
Fndat *found_fd = NULL;
|
|
#endif
|
|
char *nm;
|
|
Font_Rend_Flags wanted_rend = 0;
|
|
|
|
if (!fdesc) return NULL;
|
|
fdesc->is_new = EINA_FALSE;
|
|
|
|
if (fdesc->slant != EVAS_FONT_SLANT_NORMAL)
|
|
wanted_rend |= FONT_REND_SLANT;
|
|
if (fdesc->weight == EVAS_FONT_WEIGHT_BOLD)
|
|
wanted_rend |= FONT_REND_WEIGHT;
|
|
|
|
evas_font_init();
|
|
|
|
EINA_LIST_FOREACH(fonts_cache, l, fd)
|
|
{
|
|
if (!evas_font_desc_cmp(fdesc, fd->fdesc))
|
|
{
|
|
if (((!source) && (!fd->source)) ||
|
|
((source) && (fd->source) && (!strcmp(source, fd->source))))
|
|
{
|
|
if ((size == fd->size) &&
|
|
(wanted_rend == fd->wanted_rend) &&
|
|
(bitmap_scalable == fd->bitmap_scalable))
|
|
{
|
|
fonts_cache = eina_list_promote_list(fonts_cache, l);
|
|
fd->ref++;
|
|
return fd->font;
|
|
}
|
|
#ifdef HAVE_FONTCONFIG
|
|
else if (fd->set && fd->p_nm && !fd->file_font)
|
|
{
|
|
found_fd = fd;
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef HAVE_FONTCONFIG
|
|
if (found_fd)
|
|
{
|
|
font = _evas_load_fontconfig(font, found_fd->set, size, wanted_rend, bitmap_scalable);
|
|
goto on_find;
|
|
}
|
|
#endif
|
|
|
|
EINA_LIST_FOREACH_SAFE(fonts_zero, l, l_next, fd)
|
|
{
|
|
if (!evas_font_desc_cmp(fdesc, fd->fdesc))
|
|
{
|
|
if (((!source) && (!fd->source)) ||
|
|
((source) && (fd->source) && (!strcmp(source, fd->source))))
|
|
{
|
|
if ((size == fd->size) &&
|
|
(wanted_rend == fd->wanted_rend))
|
|
{
|
|
fonts_zero = eina_list_remove_list(fonts_zero, l);
|
|
fonts_cache = eina_list_prepend(fonts_cache, fd);
|
|
fd->ref++;
|
|
return fd->font;
|
|
}
|
|
#ifdef HAVE_FONTCONFIG
|
|
else if (fd->set && fd->p_nm && !fd->file_font)
|
|
{
|
|
found_fd = fd;
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef HAVE_FONTCONFIG
|
|
if (found_fd)
|
|
{
|
|
font = _evas_load_fontconfig(font, found_fd->set, size, wanted_rend, bitmap_scalable);
|
|
goto on_find;
|
|
}
|
|
#endif
|
|
|
|
fonts = evas_font_set_get(fdesc->name);
|
|
EINA_LIST_FOREACH(fonts, l, nm) /* Load each font in append */
|
|
{
|
|
if (l == fonts || !font) /* First iteration OR no font */
|
|
{
|
|
/*This will suppress warnings for resource leak*/
|
|
if (font)
|
|
{
|
|
evas_common_font_free((RGBA_Font*)font);
|
|
font = NULL;
|
|
}
|
|
|
|
if (source) /* Load Font from "eet" source */
|
|
{
|
|
Eet_File *ef;
|
|
char fake_name[PATH_MAX];
|
|
|
|
eina_file_path_join(fake_name, PATH_MAX, source, nm);
|
|
font = (Evas_Font_Set *)evas_common_font_load(fake_name, size, wanted_rend, bitmap_scalable);
|
|
if (!font) /* Load from fake name failed, probably not cached */
|
|
{
|
|
/* read original!!! */
|
|
ef = eet_open(source, EET_FILE_MODE_READ);
|
|
if (ef)
|
|
{
|
|
void *fdata;
|
|
int fsize = 0;
|
|
|
|
fdata = eet_read(ef, nm, &fsize);
|
|
if (fdata)
|
|
{
|
|
font = (Evas_Font_Set *)evas_common_font_memory_load(source, nm, size, fdata, fsize, wanted_rend, bitmap_scalable);
|
|
free(fdata);
|
|
}
|
|
eet_close(ef);
|
|
}
|
|
}
|
|
}
|
|
if (!font) /* Source load failed */
|
|
{
|
|
if (_file_path_is_full_path((char *)nm)) /* Try filename */
|
|
font = (Evas_Font_Set *)evas_common_font_load((char *)nm, size, wanted_rend, bitmap_scalable);
|
|
else /* search font path */
|
|
{
|
|
const Eina_List *ll;
|
|
char *dir;
|
|
|
|
EINA_LIST_FOREACH(font_paths, ll, dir)
|
|
{
|
|
const char *f_file;
|
|
|
|
f_file = evas_font_dir_cache_find(dir, (char *)nm);
|
|
if (f_file)
|
|
{
|
|
font = (Evas_Font_Set *)evas_common_font_load(f_file, size, wanted_rend, bitmap_scalable);
|
|
if (font) break;
|
|
}
|
|
}
|
|
|
|
if (!font)
|
|
{
|
|
EINA_LIST_FOREACH(global_font_path, ll, dir)
|
|
{
|
|
const char *f_file;
|
|
|
|
f_file = evas_font_dir_cache_find(dir, (char *)nm);
|
|
if (f_file)
|
|
{
|
|
font = (Evas_Font_Set *)evas_common_font_load(f_file, size, wanted_rend, bitmap_scalable);
|
|
if (font) break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else /* Base font loaded, append others */
|
|
{
|
|
void *ok = NULL;
|
|
|
|
if (source)
|
|
{
|
|
Eet_File *ef;
|
|
char fake_name[PATH_MAX];
|
|
|
|
eina_file_path_join(fake_name, PATH_MAX, source, nm);
|
|
if (!evas_common_font_add((RGBA_Font *)font, fake_name, size, wanted_rend, bitmap_scalable))
|
|
{
|
|
/* read original!!! */
|
|
ef = eet_open(source, EET_FILE_MODE_READ);
|
|
if (ef)
|
|
{
|
|
void *fdata;
|
|
int fsize = 0;
|
|
|
|
fdata = eet_read(ef, nm, &fsize);
|
|
if ((fdata) && (fsize > 0))
|
|
{
|
|
ok = evas_common_font_memory_add((RGBA_Font *)font, source, nm, size, fdata, fsize, wanted_rend, bitmap_scalable);
|
|
}
|
|
eet_close(ef);
|
|
free(fdata);
|
|
}
|
|
}
|
|
else
|
|
ok = (void *)1;
|
|
}
|
|
if (!ok)
|
|
{
|
|
if (_file_path_is_full_path((char *)nm))
|
|
evas_common_font_add((RGBA_Font *)font, (char *)nm, size, wanted_rend, bitmap_scalable);
|
|
else
|
|
{
|
|
const Eina_List *ll;
|
|
char *dir;
|
|
RGBA_Font *fn = NULL;
|
|
|
|
EINA_LIST_FOREACH(font_paths, ll, dir)
|
|
{
|
|
const char *f_file;
|
|
|
|
f_file = evas_font_dir_cache_find(dir, (char *)nm);
|
|
if (f_file)
|
|
{
|
|
fn = evas_common_font_add((RGBA_Font *)font, f_file, size, wanted_rend, bitmap_scalable);
|
|
if (fn)
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!fn)
|
|
{
|
|
EINA_LIST_FOREACH(global_font_path, ll, dir)
|
|
{
|
|
const char *f_file;
|
|
|
|
f_file = evas_font_dir_cache_find(dir, (char *)nm);
|
|
if (f_file)
|
|
{
|
|
fn = evas_common_font_add((RGBA_Font *)font, f_file, size, wanted_rend, bitmap_scalable);
|
|
if (fn)
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
eina_stringshare_del(nm);
|
|
}
|
|
eina_list_free(fonts);
|
|
|
|
#ifdef HAVE_FONTCONFIG
|
|
if (!font) /* Search using fontconfig */
|
|
{
|
|
FcResult res;
|
|
|
|
p_nm = FcPatternBuild (NULL,
|
|
FC_WEIGHT, FcTypeInteger, _fc_weight_map[fdesc->weight],
|
|
FC_SLANT, FcTypeInteger, _fc_slant_map[fdesc->slant],
|
|
FC_SPACING, FcTypeInteger, _fc_spacing_map[fdesc->spacing],
|
|
#ifdef FC_WIDTH
|
|
FC_WIDTH, FcTypeInteger, _fc_width_map[fdesc->width],
|
|
#endif
|
|
NULL);
|
|
FcPatternAddString (p_nm, FC_FAMILY, (FcChar8*) fdesc->name);
|
|
|
|
if (fdesc->style)
|
|
FcPatternAddString (p_nm, FC_STYLE, (FcChar8*) fdesc->style);
|
|
|
|
/* Handle font fallbacks */
|
|
if (fdesc->fallbacks)
|
|
{
|
|
const char *start, *end;
|
|
start = fdesc->fallbacks;
|
|
|
|
while (start)
|
|
{
|
|
end = strchr(start, ',');
|
|
if (end)
|
|
{
|
|
char *tmp = alloca((end - start) + 1);
|
|
strncpy(tmp, start, end - start);
|
|
tmp[end - start] = 0;
|
|
FcPatternAddString (p_nm, FC_FAMILY, (FcChar8*) tmp);
|
|
start = end + 1;
|
|
}
|
|
else
|
|
{
|
|
FcPatternAddString (p_nm, FC_FAMILY, (FcChar8*) start);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (fdesc->lang)
|
|
FcPatternAddString (p_nm, FC_LANG, (FcChar8 *) fdesc->lang);
|
|
|
|
FcConfigSubstitute(fc_config, p_nm, FcMatchPattern);
|
|
FcDefaultSubstitute(p_nm);
|
|
|
|
/* do matching */
|
|
set = FcFontSort(fc_config, p_nm, FcTrue, NULL, &res);
|
|
if (!set)
|
|
{
|
|
//FIXME add ERR log capability
|
|
//ERR("No fontconfig font matches '%s'. It was the last resource, no font found!", fdesc->name);
|
|
FcPatternDestroy(p_nm);
|
|
p_nm = NULL;
|
|
}
|
|
else
|
|
{
|
|
font = _evas_load_fontconfig(font, set, size, wanted_rend, bitmap_scalable);
|
|
}
|
|
}
|
|
else /* Add a fallback list from fontconfig according to the found font. */
|
|
{
|
|
#if FC_MAJOR >= 2 && FC_MINOR >= 11
|
|
FcResult res;
|
|
|
|
FT_Face face = evas_common_font_freetype_face_get((RGBA_Font *) font);
|
|
|
|
file_font = EINA_TRUE;
|
|
|
|
if (face)
|
|
{
|
|
p_nm = FcFreeTypeQueryFace(face, (FcChar8 *) "", 0, NULL);
|
|
FcConfigSubstitute(fc_config, p_nm, FcMatchPattern);
|
|
FcDefaultSubstitute(p_nm);
|
|
|
|
/* do matching */
|
|
set = FcFontSort(fc_config, p_nm, FcTrue, NULL, &res);
|
|
if (!set)
|
|
{
|
|
FcPatternDestroy(p_nm);
|
|
p_nm = NULL;
|
|
}
|
|
else
|
|
{
|
|
font = _evas_load_fontconfig(font, set, size, wanted_rend, bitmap_scalable);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
#ifdef HAVE_FONTCONFIG
|
|
on_find:
|
|
#endif
|
|
fd = calloc(1, sizeof(Fndat));
|
|
if (fd)
|
|
{
|
|
fd->fdesc = evas_font_desc_ref(fdesc);
|
|
if (source) fd->source = eina_stringshare_add(source);
|
|
fd->font = font;
|
|
fd->wanted_rend = wanted_rend;
|
|
fd->size = size;
|
|
fd->bitmap_scalable = bitmap_scalable;
|
|
fd->ref = 1;
|
|
fonts_cache = eina_list_prepend(fonts_cache, fd);
|
|
#ifdef HAVE_FONTCONFIG
|
|
fd->set = set;
|
|
fd->p_nm = p_nm;
|
|
fd->file_font = file_font;
|
|
#endif
|
|
}
|
|
|
|
if (font)
|
|
evas_common_font_hinting_set((RGBA_Font *)font, hinting);
|
|
return font;
|
|
}
|
|
|
|
void
|
|
evas_font_load_hinting_set(void *font, int hinting)
|
|
{
|
|
evas_common_font_hinting_set((RGBA_Font *) font, hinting);
|
|
}
|
|
|
|
Eina_List *
|
|
evas_font_dir_available_list(const Eina_List *font_paths)
|
|
{
|
|
const Eina_List *l;
|
|
Eina_List *ll;
|
|
Eina_List *available = NULL;
|
|
char *dir;
|
|
|
|
#ifdef HAVE_FONTCONFIG
|
|
/* Add font config fonts */
|
|
FcPattern *p;
|
|
FcFontSet *set = NULL;
|
|
FcObjectSet *os;
|
|
int i;
|
|
|
|
evas_font_init();
|
|
|
|
p = FcPatternCreate();
|
|
os = FcObjectSetBuild(FC_FAMILY, FC_STYLE, NULL);
|
|
|
|
if (p && os) set = FcFontList(fc_config, p, os);
|
|
|
|
if (p) FcPatternDestroy(p);
|
|
if (os) FcObjectSetDestroy(os);
|
|
|
|
if (set)
|
|
{
|
|
for (i = 0; i < set->nfont; i++)
|
|
{
|
|
char *font;
|
|
|
|
font = (char *)FcNameUnparse(set->fonts[i]);
|
|
available = eina_list_append(available, eina_stringshare_add(font));
|
|
free(font);
|
|
}
|
|
|
|
FcFontSetDestroy(set);
|
|
}
|
|
#endif
|
|
|
|
/* Add fonts in font_paths*/
|
|
if (font_paths)
|
|
{
|
|
if (!font_dirs) font_dirs = eina_hash_string_superfast_new(NULL);
|
|
|
|
EINA_LIST_FOREACH(font_paths, l, dir)
|
|
{
|
|
Evas_Font_Dir *fd;
|
|
|
|
fd = eina_hash_find(font_dirs, dir);
|
|
fd = object_text_font_cache_dir_update(dir, fd);
|
|
if (fd && fd->aliases)
|
|
{
|
|
Evas_Font_Alias *fa;
|
|
|
|
EINA_LIST_FOREACH(fd->aliases, ll, fa)
|
|
available = eina_list_append(available, eina_stringshare_add((char *)fa->alias));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (global_font_path)
|
|
{
|
|
if (!font_dirs) font_dirs = eina_hash_string_superfast_new(NULL);
|
|
|
|
EINA_LIST_FOREACH(global_font_path, l, dir)
|
|
{
|
|
Evas_Font_Dir *fd;
|
|
|
|
fd = eina_hash_find(font_dirs, dir);
|
|
fd = object_text_font_cache_dir_update(dir, fd);
|
|
if (fd && fd->aliases)
|
|
{
|
|
Evas_Font_Alias *fa;
|
|
|
|
EINA_LIST_FOREACH(fd->aliases, ll, fa)
|
|
available = eina_list_append(available, eina_stringshare_add((char *)fa->alias));
|
|
}
|
|
}
|
|
}
|
|
|
|
return available;
|
|
}
|
|
|
|
void
|
|
evas_font_dir_available_list_free(Eina_List *available)
|
|
{
|
|
while (available)
|
|
{
|
|
eina_stringshare_del(available->data);
|
|
available = eina_list_remove(available, available->data);
|
|
}
|
|
}
|
|
|
|
/* private stuff */
|
|
static Eina_Bool
|
|
font_cache_dir_free(const Eina_Hash *hash EINA_UNUSED, const void *key, void *data, void *fdata EINA_UNUSED)
|
|
{
|
|
object_text_font_cache_dir_del((char *) key, data);
|
|
return 1;
|
|
}
|
|
|
|
static Evas_Font_Dir *
|
|
object_text_font_cache_dir_update(char *dir, Evas_Font_Dir *fd)
|
|
{
|
|
char file_path[PATH_MAX];
|
|
DATA64 mt;
|
|
|
|
if (fd)
|
|
{
|
|
mt = _file_modified_time(dir);
|
|
if (mt != fd->dir_mod_time)
|
|
{
|
|
eina_hash_del(font_dirs, dir, fd);
|
|
object_text_font_cache_dir_del(dir, fd);
|
|
}
|
|
else
|
|
{
|
|
eina_file_path_join(file_path, PATH_MAX, dir, "fonts.dir");
|
|
mt = _file_modified_time(file_path);
|
|
if (mt != fd->fonts_dir_mod_time)
|
|
{
|
|
eina_hash_del(font_dirs, dir, fd);
|
|
object_text_font_cache_dir_del(dir, fd);
|
|
}
|
|
else
|
|
{
|
|
eina_file_path_join(file_path, PATH_MAX, dir, "fonts.alias");
|
|
mt = _file_modified_time(file_path);
|
|
if (mt != fd->fonts_alias_mod_time)
|
|
{
|
|
eina_hash_del(font_dirs, dir, fd);
|
|
object_text_font_cache_dir_del(dir, fd);
|
|
}
|
|
else
|
|
return fd;
|
|
}
|
|
}
|
|
}
|
|
return object_text_font_cache_dir_add(dir);
|
|
}
|
|
|
|
static Evas_Font *
|
|
object_text_font_cache_font_find_x(Evas_Font_Dir *fd, char *font)
|
|
{
|
|
Eina_List *l;
|
|
char font_prop[14][256];
|
|
int num;
|
|
Evas_Font *fn;
|
|
|
|
num = evas_object_text_font_string_parse(font, font_prop);
|
|
if (num != 14) return NULL;
|
|
EINA_LIST_FOREACH(fd->fonts, l, fn)
|
|
{
|
|
if (fn->type == 1)
|
|
{
|
|
int i;
|
|
int match = 0;
|
|
|
|
for (i = 0; i < 14; i++)
|
|
{
|
|
if ((font_prop[i][0] == '*') && (font_prop[i][1] == 0))
|
|
match++;
|
|
else
|
|
{
|
|
if (!strcasecmp(font_prop[i], fn->x.prop[i])) match++;
|
|
else break;
|
|
}
|
|
}
|
|
if (match == 14) return fn;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static Evas_Font *
|
|
object_text_font_cache_font_find_file(Evas_Font_Dir *fd, char *font)
|
|
{
|
|
Eina_List *l;
|
|
Evas_Font *fn;
|
|
|
|
EINA_LIST_FOREACH(fd->fonts, l, fn)
|
|
{
|
|
if (fn->type == 0)
|
|
{
|
|
if (!strcasecmp(font, fn->simple.name)) return fn;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static Evas_Font *
|
|
object_text_font_cache_font_find_alias(Evas_Font_Dir *fd, char *font)
|
|
{
|
|
Eina_List *l;
|
|
Evas_Font_Alias *fa;
|
|
|
|
EINA_LIST_FOREACH(fd->aliases, l, fa)
|
|
if (!strcasecmp(fa->alias, font)) return fa->fn;
|
|
return NULL;
|
|
}
|
|
|
|
static Evas_Font *
|
|
object_text_font_cache_font_find(Evas_Font_Dir *fd, char *font)
|
|
{
|
|
Evas_Font *fn;
|
|
|
|
fn = eina_hash_find(fd->lookup, font);
|
|
if (fn) return fn;
|
|
fn = object_text_font_cache_font_find_alias(fd, font);
|
|
if (!fn) fn = object_text_font_cache_font_find_x(fd, font);
|
|
if (!fn) fn = object_text_font_cache_font_find_file(fd, font);
|
|
if (!fn) return NULL;
|
|
eina_hash_add(fd->lookup, font, fn);
|
|
return fn;
|
|
}
|
|
|
|
static Evas_Font_Dir *
|
|
object_text_font_cache_dir_add(char *dir)
|
|
{
|
|
char file_path[PATH_MAX];
|
|
Evas_Font_Dir *fd;
|
|
char *file;
|
|
char tmp2[PATH_MAX];
|
|
Eina_List *fdir;
|
|
Evas_Font *fn;
|
|
FILE *f;
|
|
|
|
fd = calloc(1, sizeof(Evas_Font_Dir));
|
|
if (!fd) return NULL;
|
|
fd->lookup = eina_hash_string_superfast_new(NULL);
|
|
|
|
eina_hash_add(font_dirs, dir, fd);
|
|
|
|
/* READ fonts.alias, fonts.dir and directory listing */
|
|
|
|
/* fonts.dir */
|
|
eina_file_path_join(file_path, PATH_MAX, dir, "fonts.dir");
|
|
|
|
f = fopen(file_path, "rb");
|
|
if (f)
|
|
{
|
|
int num;
|
|
char fname[4096], fdef[4096];
|
|
|
|
if (fscanf(f, "%i\n", &num) != 1) goto cant_read;
|
|
/* read font lines */
|
|
while (fscanf(f, "%4090s %[^\n]\n", fname, fdef) == 2)
|
|
{
|
|
char font_prop[14][256];
|
|
int i;
|
|
|
|
/* skip comments */
|
|
if ((fdef[0] == '!') || (fdef[0] == '#')) continue;
|
|
/* parse font def */
|
|
num = evas_object_text_font_string_parse((char *)fdef, font_prop);
|
|
if (num == 14)
|
|
{
|
|
fn = calloc(1, sizeof(Evas_Font));
|
|
if (fn)
|
|
{
|
|
fn->type = 1;
|
|
for (i = 0; i < 14; i++)
|
|
fn->x.prop[i] = eina_stringshare_add(font_prop[i]);
|
|
eina_file_path_join(tmp2, PATH_MAX, dir, fname);
|
|
fn->path = eina_stringshare_add(tmp2);
|
|
fd->fonts = eina_list_append(fd->fonts, fn);
|
|
}
|
|
}
|
|
}
|
|
cant_read: ;
|
|
fclose(f);
|
|
}
|
|
|
|
/* directoy listing */
|
|
fdir = _file_path_list(dir, "*.ttf", 0);
|
|
EINA_LIST_FREE(fdir, file)
|
|
{
|
|
eina_file_path_join(file_path, PATH_MAX, dir, file);
|
|
fn = calloc(1, sizeof(Evas_Font));
|
|
if (fn)
|
|
{
|
|
char *p;
|
|
|
|
fn->type = 0;
|
|
p = strrchr(file, '.');
|
|
if (p) fn->simple.name = eina_stringshare_add_length(file, p - file);
|
|
else fn->simple.name = eina_stringshare_add(file);
|
|
eina_file_path_join(tmp2, PATH_MAX, dir, file);
|
|
fn->path = eina_stringshare_add(tmp2);
|
|
fd->fonts = eina_list_append(fd->fonts, fn);
|
|
}
|
|
free(file);
|
|
}
|
|
|
|
/* fonts.alias */
|
|
eina_file_path_join(file_path, PATH_MAX, dir, "fonts.alias");
|
|
|
|
f = fopen(file_path, "rb");
|
|
if (f)
|
|
{
|
|
char fname[4096], fdef[4096];
|
|
|
|
/* read font alias lines */
|
|
while (fscanf(f, "%4090s %4090[^\n]\n", fname, fdef) == 2)
|
|
{
|
|
Evas_Font_Alias *fa;
|
|
|
|
/* skip comments */
|
|
if ((fname[0] == '!') || (fname[0] == '#')) continue;
|
|
fa = calloc(1, sizeof(Evas_Font_Alias));
|
|
if (fa)
|
|
{
|
|
fa->alias = eina_stringshare_add(fname);
|
|
fa->fn = object_text_font_cache_font_find_x(fd, fdef);
|
|
if ((!fa->alias) || (!fa->fn))
|
|
{
|
|
if (fa->alias) eina_stringshare_del(fa->alias);
|
|
free(fa);
|
|
}
|
|
else
|
|
fd->aliases = eina_list_append(fd->aliases, fa);
|
|
}
|
|
}
|
|
fclose(f);
|
|
}
|
|
|
|
fd->dir_mod_time = _file_modified_time(dir);
|
|
|
|
eina_file_path_join(file_path, PATH_MAX, dir, "fonts.dir");
|
|
fd->fonts_dir_mod_time = _file_modified_time(file_path);
|
|
|
|
eina_file_path_join(file_path, PATH_MAX, dir, "fonts.alias");
|
|
fd->fonts_alias_mod_time = _file_modified_time(file_path);
|
|
|
|
return fd;
|
|
}
|
|
|
|
static void
|
|
object_text_font_cache_dir_del(char *dir EINA_UNUSED, Evas_Font_Dir *fd)
|
|
{
|
|
if (fd->lookup) eina_hash_free(fd->lookup);
|
|
while (fd->fonts)
|
|
{
|
|
Evas_Font *fn;
|
|
int i;
|
|
|
|
fn = fd->fonts->data;
|
|
fd->fonts = eina_list_remove(fd->fonts, fn);
|
|
for (i = 0; i < 14; i++)
|
|
{
|
|
if (fn->x.prop[i]) eina_stringshare_del(fn->x.prop[i]);
|
|
}
|
|
if (fn->simple.name) eina_stringshare_del(fn->simple.name);
|
|
if (fn->path) eina_stringshare_del(fn->path);
|
|
free(fn);
|
|
}
|
|
while (fd->aliases)
|
|
{
|
|
Evas_Font_Alias *fa;
|
|
|
|
fa = fd->aliases->data;
|
|
fd->aliases = eina_list_remove(fd->aliases, fa);
|
|
if (fa->alias) eina_stringshare_del(fa->alias);
|
|
free(fa);
|
|
}
|
|
free(fd);
|
|
}
|
|
|
|
static int
|
|
evas_object_text_font_string_parse(char *buffer, char dest[14][256])
|
|
{
|
|
char *p;
|
|
int n, m, i;
|
|
|
|
n = 0;
|
|
m = 0;
|
|
p = buffer;
|
|
if (p[0] != '-') return 0;
|
|
i = 1;
|
|
while (p[i])
|
|
{
|
|
dest[n][m] = p[i];
|
|
if ((p[i] == '-') || (m == 255))
|
|
{
|
|
dest[n][m] = 0;
|
|
n++;
|
|
m = -1;
|
|
}
|
|
i++;
|
|
m++;
|
|
if (n == 14) return n;
|
|
}
|
|
dest[n][m] = 0;
|
|
n++;
|
|
return n;
|
|
}
|
|
|
|
EVAS_API void
|
|
evas_font_path_global_append(const char *path)
|
|
{
|
|
if (!path) return;
|
|
global_font_path = eina_list_append(global_font_path, eina_stringshare_add(path));
|
|
#ifdef HAVE_FONTCONFIG
|
|
if (fc_config)
|
|
FcConfigAppFontAddDir(fc_config, (const FcChar8 *) path);
|
|
#endif
|
|
}
|
|
|
|
EVAS_API void
|
|
evas_font_path_global_prepend(const char *path)
|
|
{
|
|
if (!path) return;
|
|
global_font_path = eina_list_prepend(global_font_path, eina_stringshare_add(path));
|
|
#ifdef HAVE_FONTCONFIG
|
|
if (fc_config)
|
|
FcConfigAppFontAddDir(fc_config, (const FcChar8 *) path);
|
|
#endif
|
|
}
|
|
|
|
EVAS_API void
|
|
evas_font_path_global_clear(void)
|
|
{
|
|
while (global_font_path)
|
|
{
|
|
eina_stringshare_del(global_font_path->data);
|
|
global_font_path = eina_list_remove(global_font_path, global_font_path->data);
|
|
}
|
|
#ifdef HAVE_FONTCONFIG
|
|
if (fc_config)
|
|
FcConfigAppFontClear(fc_config);
|
|
#endif
|
|
}
|
|
|
|
EVAS_API const Eina_List *
|
|
evas_font_path_global_list(void)
|
|
{
|
|
return global_font_path;
|
|
}
|
|
|
|
EVAS_API void
|
|
evas_font_reinit(void)
|
|
{
|
|
#ifdef HAVE_FONTCONFIG
|
|
Eina_List *l;
|
|
char *path;
|
|
|
|
if (fc_config)
|
|
{
|
|
FcConfigDestroy(fc_config);
|
|
fc_config = FcInitLoadConfigAndFonts();
|
|
|
|
EINA_LIST_FOREACH(global_font_path, l, path)
|
|
FcConfigAppFontAddDir(fc_config, (const FcChar8 *) path);
|
|
}
|
|
#endif
|
|
}
|