1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif
4 
5 #ifdef _WIN32
6 # include <evil_private.h> /* evil_path_is_absolute */
7 #endif
8 
9 #include <Eet.h>
10 
11 #ifdef HAVE_FONTCONFIG
12 #include <fontconfig/fontconfig.h>
13 #include <fontconfig/fcfreetype.h>
14 #endif
15 
16 #include "evas_font.h"
17 
18 /* General types - used for script type chceking */
19 #define OPAQUE_TYPE(type) struct __##type { int a; }; \
20    typedef struct __##type type
21 
22 OPAQUE_TYPE(Evas_Font_Set); /* General type for RGBA_Font */
23 OPAQUE_TYPE(Evas_Font_Instance); /* General type for RGBA_Font_Int */
24 
25 /* font dir cache */
26 static Eina_Hash *font_dirs = NULL;
27 static Eina_List *fonts_cache = NULL;
28 static Eina_List *fonts_zero = NULL;
29 static Eina_List *global_font_path = NULL;
30 
31 typedef struct _Fndat Fndat;
32 
33 struct _Fndat
34 {
35    Evas_Font_Description *fdesc;
36    const char      *source;
37    Evas_Font_Size   size;
38    Evas_Font_Set   *font;
39    int              ref;
40    Font_Rend_Flags  wanted_rend;
41    Efl_Text_Font_Bitmap_Scalable bitmap_scalable;
42 
43 #ifdef HAVE_FONTCONFIG
44    FcFontSet *set;
45    FcPattern *p_nm;
46 
47    Eina_Bool file_font : 1; /* Indicates this is a font that uses a file rather than fontconfig. */
48 #endif
49 };
50 
51 /* private methods for font dir cache */
52 static Eina_Bool font_cache_dir_free(const Eina_Hash *hash, const void *key, void *data, void *fdata);
53 static Evas_Font_Dir *object_text_font_cache_dir_update(char *dir, Evas_Font_Dir *fd);
54 static Evas_Font *object_text_font_cache_font_find_x(Evas_Font_Dir *fd, char *font);
55 static Evas_Font *object_text_font_cache_font_find_file(Evas_Font_Dir *fd, char *font);
56 static Evas_Font *object_text_font_cache_font_find_alias(Evas_Font_Dir *fd, char *font);
57 static Evas_Font *object_text_font_cache_font_find(Evas_Font_Dir *fd, char *font);
58 static Evas_Font_Dir *object_text_font_cache_dir_add(char *dir);
59 static void object_text_font_cache_dir_del(char *dir, Evas_Font_Dir *fd);
60 static int evas_object_text_font_string_parse(char *buffer, char dest[14][256]);
61 
62 #ifdef HAVE_FONTCONFIG
63 static FcConfig *fc_config = NULL;
64 #endif
65 
66 /* FIXME move these helper function to eina_file or eina_path */
67 /* get the casefold feature! */
68 #include <fnmatch.h>
69 #include <unistd.h>
70 #include <sys/param.h>
71 int
_file_path_is_full_path(const char * path)72 _file_path_is_full_path(const char *path)
73 {
74    if (!path) return 0;
75 #ifdef _WIN32
76    if (evil_path_is_absolute(path)) return 1;
77 #else
78    if (path[0] == '/') return 1;
79 #endif
80    return 0;
81 }
82 
83 static DATA64
_file_modified_time(const char * file)84 _file_modified_time(const char *file)
85 {
86    struct stat st;
87 
88    if (stat(file, &st) < 0) return 0;
89    if (st.st_ctime > st.st_mtime) return (DATA64)st.st_ctime;
90    else return (DATA64)st.st_mtime;
91    return 0;
92 }
93 
94 Eina_List *
_file_path_list(char * path,const char * match,int match_case)95 _file_path_list(char *path, const char *match, int match_case)
96 {
97    Eina_File_Direct_Info *info;
98    Eina_Iterator *it;
99    Eina_List *files = NULL;
100    int flags;
101 
102    flags = FNM_PATHNAME;
103 #ifdef FNM_CASEFOLD
104    if (!match_case)
105      flags |= FNM_CASEFOLD;
106 #elif defined FNM_IGNORECASE
107    if (!match_case)
108      flags |= FNM_IGNORECASE;
109 #else
110 /*#warning "Your libc does not provide case-insensitive matching!"*/
111 #endif
112 
113    it = eina_file_direct_ls(path);
114    EINA_ITERATOR_FOREACH(it, info)
115      {
116         if (match)
117           {
118              if (fnmatch(match, info->path + info->name_start, flags) == 0)
119                files = eina_list_append(files, strdup(info->path + info->name_start));
120           }
121         else
122           files = eina_list_append(files, strdup(info->path + info->name_start));
123      }
124    if (it) eina_iterator_free(it);
125    return files;
126 }
127 
128 static void
evas_font_init(void)129 evas_font_init(void)
130 {
131 #ifdef HAVE_FONTCONFIG
132    if (!fc_config)
133      {
134         Eina_List *l;
135         char *path;
136 
137         fc_config = FcInitLoadConfigAndFonts();
138 
139         EINA_LIST_FOREACH(global_font_path, l, path)
140            FcConfigAppFontAddDir(fc_config, (const FcChar8 *) path);
141      }
142 #endif
143 }
144 
145 void
evas_font_dir_cache_free(void)146 evas_font_dir_cache_free(void)
147 {
148    if (font_dirs)
149      {
150         eina_hash_foreach(font_dirs, font_cache_dir_free, NULL);
151         eina_hash_free(font_dirs);
152         font_dirs = NULL;
153      }
154 #ifdef HAVE_FONTCONFIG
155    if (fc_config)
156      {
157         FcConfigDestroy(fc_config);
158         fc_config = NULL;
159      }
160 #endif
161 }
162 
163 const char *
evas_font_dir_cache_find(char * dir,char * font)164 evas_font_dir_cache_find(char *dir, char *font)
165 {
166    Evas_Font_Dir *fd = NULL;
167 
168    if (!font_dirs) font_dirs = eina_hash_string_superfast_new(NULL);
169    else fd = eina_hash_find(font_dirs, dir);
170    fd = object_text_font_cache_dir_update(dir, fd);
171    if (fd)
172      {
173         Evas_Font *fn;
174 
175         fn = object_text_font_cache_font_find(fd, font);
176         if (fn)
177           {
178              return fn->path;
179           }
180      }
181    return NULL;
182 }
183 
184 static Eina_List *
evas_font_set_get(const char * name)185 evas_font_set_get(const char *name)
186 {
187    Eina_List *fonts = NULL;
188    char *p;
189 
190    EINA_SAFETY_ON_NULL_RETURN_VAL(name, NULL);
191    if (!*name) return NULL;
192 
193    p = strchr(name, ',');
194    if (!p)
195      {
196         fonts = eina_list_append(fonts, eina_stringshare_add(name));
197      }
198    else
199      {
200         const char *pp;
201         char *nm;
202 
203         pp = name;
204         while (p)
205           {
206              nm = alloca(p - pp + 1);
207              strncpy(nm, pp, p - pp);
208              nm[p - pp] = 0;
209              fonts = eina_list_append(fonts, eina_stringshare_add(nm));
210              pp = p + 1;
211              p = strchr(pp, ',');
212              if (!p) fonts = eina_list_append(fonts, eina_stringshare_add(pp));
213           }
214      }
215    return fonts;
216 }
217 
218 void
evas_fonts_zero_free()219 evas_fonts_zero_free()
220 {
221    Fndat *fd;
222 
223    EINA_LIST_FREE(fonts_zero, fd)
224      {
225         if (fd->fdesc) evas_font_desc_unref(fd->fdesc);
226         if (fd->source) eina_stringshare_del(fd->source);
227         evas_common_font_free((RGBA_Font *)fd->font);
228 #ifdef HAVE_FONTCONFIG
229         if (fd->set) FcFontSetDestroy(fd->set);
230         if (fd->p_nm) FcPatternDestroy(fd->p_nm);
231 #endif
232         free(fd);
233      }
234 }
235 
236 void
evas_fonts_zero_pressure()237 evas_fonts_zero_pressure()
238 {
239    Fndat *fd;
240 
241    while (fonts_zero
242           && eina_list_count(fonts_zero) > 4) /* 4 is arbitrary */
243      {
244         fd = eina_list_data_get(fonts_zero);
245 
246         if (fd->ref != 0) break;
247         fonts_zero = eina_list_remove_list(fonts_zero, fonts_zero);
248 
249         if (fd->fdesc) evas_font_desc_unref(fd->fdesc);
250         if (fd->source) eina_stringshare_del(fd->source);
251         evas_common_font_free((RGBA_Font *)fd->font);
252       #ifdef HAVE_FONTCONFIG
253         if (fd->set) FcFontSetDestroy(fd->set);
254         if (fd->p_nm) FcPatternDestroy(fd->p_nm);
255       #endif
256         free(fd);
257 
258         if (eina_list_count(fonts_zero) < 5) break;
259      }
260 }
261 
262 void
evas_font_free(void * font)263 evas_font_free(void *font)
264 {
265    Eina_List *l;
266    Fndat *fd;
267 
268    EINA_LIST_FOREACH(fonts_cache, l, fd)
269      {
270         if (fd->font == font)
271           {
272              fd->ref--;
273              if (fd->ref == 0)
274                {
275                   fonts_cache = eina_list_remove_list(fonts_cache, l);
276                   fonts_zero = eina_list_append(fonts_zero, fd);
277                }
278              break;
279           }
280      }
281    while (fonts_zero
282           && eina_list_count(fonts_zero) > 42) /* 42 is arbitrary */
283      {
284         fd = eina_list_data_get(fonts_zero);
285 
286         if (fd->ref != 0) break;
287         fonts_zero = eina_list_remove_list(fonts_zero, fonts_zero);
288 
289         if (fd->fdesc) evas_font_desc_unref(fd->fdesc);
290         if (fd->source) eina_stringshare_del(fd->source);
291         evas_common_font_free((RGBA_Font *)fd->font);
292       #ifdef HAVE_FONTCONFIG
293         if (fd->set) FcFontSetDestroy(fd->set);
294         if (fd->p_nm) FcPatternDestroy(fd->p_nm);
295       #endif
296         free(fd);
297 
298         if (eina_list_count(fonts_zero) < 43) break;
299      }
300 }
301 
302 #ifdef HAVE_FONTCONFIG
303 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)304 _evas_load_fontconfig(Evas_Font_Set *font, FcFontSet *set, int size,
305       Font_Rend_Flags wanted_rend, Efl_Text_Font_Bitmap_Scalable bitmap_scalable)
306 {
307    int i;
308 
309    /* Do loading for all in family */
310    for (i = 0; i < set->nfont; i++)
311      {
312         FcValue filename;
313 
314         if (FcPatternGet(set->fonts[i], FC_FILE, 0, &filename) == FcResultMatch)
315           {
316              if (font)
317                evas_common_font_add((RGBA_Font *)font, (char *)filename.u.s, size, wanted_rend, bitmap_scalable);
318              else
319                font = (Evas_Font_Set *)evas_common_font_load((char *)filename.u.s, size, wanted_rend, bitmap_scalable);
320           }
321      }
322 
323    return font;
324 }
325 #endif
326 
327 #ifdef HAVE_FONTCONFIG
328 /* In sync with Evas_Font_Style, Evas_Font_Weight and Evas_Font_Width */
329 static int _fc_slant_map[] =
330 {
331    FC_SLANT_ROMAN,
332    FC_SLANT_OBLIQUE,
333    FC_SLANT_ITALIC
334 };
335 
336 /* Apparently EXTRABLACK is not always available, hardcode. */
337 # ifndef FC_WEIGHT_EXTRABLACK
338 #  define FC_WEIGHT_EXTRABLACK 215
339 # endif
340 static int _fc_weight_map[] =
341 {
342    FC_WEIGHT_NORMAL,
343    FC_WEIGHT_THIN,
344    FC_WEIGHT_ULTRALIGHT,
345    FC_WEIGHT_EXTRALIGHT,
346    FC_WEIGHT_LIGHT,
347    FC_WEIGHT_BOOK,
348    FC_WEIGHT_MEDIUM,
349    FC_WEIGHT_SEMIBOLD,
350    FC_WEIGHT_BOLD,
351    FC_WEIGHT_ULTRABOLD,
352    FC_WEIGHT_EXTRABOLD,
353    FC_WEIGHT_BLACK,
354    FC_WEIGHT_EXTRABLACK
355 };
356 
357 # ifdef FC_WIDTH
358 static int _fc_width_map[] =
359 {
360    FC_WIDTH_NORMAL,
361    FC_WIDTH_ULTRACONDENSED,
362    FC_WIDTH_EXTRACONDENSED,
363    FC_WIDTH_CONDENSED,
364    FC_WIDTH_SEMICONDENSED,
365    FC_WIDTH_SEMIEXPANDED,
366    FC_WIDTH_EXPANDED,
367    FC_WIDTH_EXTRAEXPANDED,
368    FC_WIDTH_ULTRAEXPANDED
369 };
370 # endif
371 
372 static int _fc_spacing_map[] =
373 {
374    FC_PROPORTIONAL,
375    FC_DUAL,
376    FC_MONO,
377    FC_CHARCELL
378 };
379 
380 #endif
381 
382 struct _Style_Map
383 {
384    const char *name;
385    int type;
386 };
387 typedef struct _Style_Map Style_Map;
388 
389 static Style_Map _style_width_map[] =
390 {
391      {"normal", EVAS_FONT_WIDTH_NORMAL},
392      {"ultracondensed", EVAS_FONT_WIDTH_ULTRACONDENSED},
393      {"extracondensed", EVAS_FONT_WIDTH_EXTRACONDENSED},
394      {"condensed", EVAS_FONT_WIDTH_CONDENSED},
395      {"semicondensed", EVAS_FONT_WIDTH_SEMICONDENSED},
396      {"semiexpanded", EVAS_FONT_WIDTH_SEMIEXPANDED},
397      {"expanded", EVAS_FONT_WIDTH_EXPANDED},
398      {"extraexpanded", EVAS_FONT_WIDTH_EXTRAEXPANDED},
399      {"ultraexpanded", EVAS_FONT_WIDTH_ULTRAEXPANDED},
400 };
401 
402 static Style_Map _style_weight_map[] =
403 {
404      {"normal", EVAS_FONT_WEIGHT_NORMAL},
405      {"thin", EVAS_FONT_WEIGHT_THIN},
406      {"ultralight", EVAS_FONT_WEIGHT_ULTRALIGHT},
407      {"extralight", EVAS_FONT_WEIGHT_EXTRALIGHT},
408      {"light", EVAS_FONT_WEIGHT_LIGHT},
409      {"book", EVAS_FONT_WEIGHT_BOOK},
410      {"medium", EVAS_FONT_WEIGHT_MEDIUM},
411      {"semibold", EVAS_FONT_WEIGHT_SEMIBOLD},
412      {"bold", EVAS_FONT_WEIGHT_BOLD},
413      {"ultrabold", EVAS_FONT_WEIGHT_ULTRABOLD},
414      {"extrabold", EVAS_FONT_WEIGHT_EXTRABOLD},
415      {"black", EVAS_FONT_WEIGHT_BLACK},
416      {"extrablack", EVAS_FONT_WEIGHT_EXTRABLACK}
417 };
418 
419 static Style_Map _style_slant_map[] =
420 {
421      {"normal", EVAS_FONT_SLANT_NORMAL},
422      {"oblique", EVAS_FONT_SLANT_OBLIQUE},
423      {"italic", EVAS_FONT_SLANT_ITALIC}
424 };
425 
426 static Style_Map _style_spacing_map[] =
427 {
428      {"proportional", EVAS_FONT_SPACING_PROPORTIONAL},
429      {"dualwidth", EVAS_FONT_SPACING_DUAL},
430      {"monospace", EVAS_FONT_SPACING_MONO},
431      {"charcell", EVAS_FONT_SPACING_CHARCELL}
432 };
433 
434 #define _STYLE_MAP_LEN(x) (sizeof(x) / sizeof(*(x)))
435 
436 /**
437  * @internal
438  * Find the string from the map at a style
439  * @return the string at a style type
440  */
441 static const char*
_evas_font_style_find_str_internal(int type,Style_Map _map[],size_t map_len)442 _evas_font_style_find_str_internal(int type, Style_Map _map[], size_t map_len)
443 {
444    size_t i;
445    for ( i = 0; i < map_len; i++ )
446      {
447         if (_map[i].type == type)
448           return _map[i].name;
449      }
450    return NULL;
451 }
452 
453 const char*
evas_font_style_find_str(int type,Evas_Font_Style style)454 evas_font_style_find_str(int type, Evas_Font_Style style)
455 {
456 #define _RET_STYLE(x) \
457    return _evas_font_style_find_str_internal(type, \
458                    _style_##x##_map, _STYLE_MAP_LEN(_style_##x##_map));
459    switch (style)
460      {
461         case EVAS_FONT_STYLE_SLANT:
462            _RET_STYLE(slant);
463         case EVAS_FONT_STYLE_WEIGHT:
464            _RET_STYLE(weight);
465         case EVAS_FONT_STYLE_WIDTH:
466            _RET_STYLE(width);
467         default:
468            return NULL;
469      }
470 #undef _RET_STYLE
471 }
472 
473 /**
474  * @internal
475  * Find a certain attribute from the map in the style.
476  * @return the index of the found one.
477  */
478 static unsigned int
_evas_font_style_find_internal(const char * style,const char * style_end,Style_Map _map[],size_t map_len)479 _evas_font_style_find_internal(const char *style, const char *style_end,
480       Style_Map _map[], size_t map_len)
481 {
482    size_t i;
483    while (style < style_end)
484      {
485         for (i = 0 ; i < map_len ; i++)
486           {
487              size_t len;
488              const char *cur = _map[i].name;
489              len = strlen(cur);
490              if (!strncasecmp(style, cur, len) &&
491                  (!cur[len] || (cur[len] == ' ')))
492                {
493                   return _map[i].type;
494                }
495           }
496         style = strchr(style, ' ');
497         if (!style)
498            break;
499 
500         while (*style && (*style == ' '))
501            style++;
502      }
503    return 0;
504 }
505 
506 unsigned int
evas_font_style_find(const char * start,const char * end,Evas_Font_Style style)507 evas_font_style_find(const char *start, const char *end,
508       Evas_Font_Style style)
509 {
510 #define _RET_STYLE(x) \
511    return _evas_font_style_find_internal(start, end, \
512                    _style_##x##_map, _STYLE_MAP_LEN(_style_##x##_map));
513    switch (style)
514      {
515         case EVAS_FONT_STYLE_SLANT:
516            _RET_STYLE(slant);
517         case EVAS_FONT_STYLE_WEIGHT:
518            _RET_STYLE(weight);
519         case EVAS_FONT_STYLE_WIDTH:
520            _RET_STYLE(width);
521         default:
522            return 0;
523      }
524 #undef _RET_STYLE
525 }
526 
527 void
evas_font_desc_unref(Evas_Font_Description * fdesc)528 evas_font_desc_unref(Evas_Font_Description *fdesc)
529 {
530    if (--(fdesc->ref) == 0)
531      {
532         eina_stringshare_del(fdesc->name);
533         eina_stringshare_del(fdesc->style);
534         eina_stringshare_del(fdesc->fallbacks);
535         eina_stringshare_del(fdesc->lang);
536         free(fdesc);
537      }
538 }
539 
540 Evas_Font_Description *
evas_font_desc_ref(Evas_Font_Description * fdesc)541 evas_font_desc_ref(Evas_Font_Description *fdesc)
542 {
543    fdesc->ref++;
544    return fdesc;
545 }
546 
547 Evas_Font_Description *
evas_font_desc_new(void)548 evas_font_desc_new(void)
549 {
550    Evas_Font_Description *fdesc;
551    fdesc = calloc(1, sizeof(*fdesc));
552    fdesc->ref = 1;
553    fdesc->is_new = EINA_TRUE;
554 
555    return fdesc;
556 }
557 
558 Evas_Font_Description *
evas_font_desc_dup(const Evas_Font_Description * fdesc)559 evas_font_desc_dup(const Evas_Font_Description *fdesc)
560 {
561    Evas_Font_Description *new;
562    new = evas_font_desc_new();
563    memcpy(new, fdesc, sizeof(*new));
564    new->ref = 1;
565    new->is_new = EINA_TRUE;
566    new->name = eina_stringshare_ref(new->name);
567    new->fallbacks = eina_stringshare_ref(new->fallbacks);
568    new->lang = eina_stringshare_ref(new->lang);
569    new->style = eina_stringshare_ref(new->style);
570 
571    return new;
572 }
573 
574 int
evas_font_desc_cmp(const Evas_Font_Description * a,const Evas_Font_Description * b)575 evas_font_desc_cmp(const Evas_Font_Description *a,
576       const Evas_Font_Description *b)
577 {
578    /* FIXME: Do actual comparison, i.e less than and bigger than. */
579    return !((a->name == b->name) && (a->weight == b->weight) &&
580             (a->slant == b->slant) && (a->width == b->width) &&
581             (a->spacing == b->spacing) && (a->lang == b->lang) &&
582             (a->fallbacks == b->fallbacks));
583 }
584 
585 const char *
evas_font_lang_normalize(const char * lang)586 evas_font_lang_normalize(const char *lang)
587 {
588    if (!lang || !strcmp(lang, "none")) return NULL;
589 
590    if (!strcmp(lang, "auto"))
591      return evas_common_language_from_locale_full_get();
592 
593    return lang;
594 }
595 
596 void
evas_font_name_parse(Evas_Font_Description * fdesc,const char * name)597 evas_font_name_parse(Evas_Font_Description *fdesc, const char *name)
598 {
599    const char *end;
600 
601    end = strchr(name, ':');
602    if (!end)
603      eina_stringshare_replace(&(fdesc->name), name);
604    else
605      eina_stringshare_replace_length(&(fdesc->name), name, end - name);
606 
607    while (end)
608      {
609         const char *tend;
610         name = end;
611         end = strchr(end + 1, ':');
612         if (!end)
613           tend = name + strlen(name);
614         else
615           tend = end;
616 
617         if (!strncmp(name, ":style=", 7))
618           {
619 #define _SET_STYLE(x, len) \
620              fdesc->x = _evas_font_style_find_internal(name + len, tend, \
621                    _style_##x##_map, _STYLE_MAP_LEN(_style_##x##_map));
622              eina_stringshare_replace_length(&(fdesc->style), name + 7, tend - (name + 7));
623              _SET_STYLE(slant, 7);
624              _SET_STYLE(weight, 7);
625              _SET_STYLE(width, 7);
626           }
627         else if (!strncmp(name, ":slant=", 7))
628           {
629              _SET_STYLE(slant, 7);
630           }
631         else if (!strncmp(name, ":weight=", 8))
632           {
633              _SET_STYLE(weight, 8);
634           }
635         else if (!strncmp(name, ":width=", 7))
636           {
637              _SET_STYLE(width, 7);
638           }
639         else if (!strncmp(name, ":spacing=", 9))
640           {
641              _SET_STYLE(spacing, 9);
642 #undef _SET_STYLE
643           }
644         else if (!strncmp(name, ":lang=", 6))
645           {
646              const char *tmp = name + 6;
647              eina_stringshare_replace_length(&(fdesc->lang), tmp, tend - tmp);
648              eina_stringshare_replace(&(fdesc->lang), evas_font_lang_normalize(fdesc->lang));
649           }
650         else if (!strncmp(name, ":fallbacks=", 11))
651           {
652              const char *tmp = name + 11;
653              eina_stringshare_replace_length(&(fdesc->fallbacks), tmp, tend - tmp);
654           }
655      }
656 }
657 
658 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)659 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)
660 {
661 #ifdef HAVE_FONTCONFIG
662    FcPattern *p_nm = NULL;
663    FcFontSet *set = NULL;
664    Eina_Bool file_font = EINA_FALSE;
665 #endif
666 
667    Evas_Font_Set *font = NULL;
668    Eina_List *fonts, *l, *l_next;
669    Fndat *fd;
670 #ifdef HAVE_FONTCONFIG
671    Fndat *found_fd = NULL;
672 #endif
673    char *nm;
674    Font_Rend_Flags wanted_rend = 0;
675 
676    if (!fdesc) return NULL;
677    fdesc->is_new = EINA_FALSE;
678 
679    if (fdesc->slant != EVAS_FONT_SLANT_NORMAL)
680      wanted_rend |= FONT_REND_SLANT;
681    if (fdesc->weight == EVAS_FONT_WEIGHT_BOLD)
682      wanted_rend |= FONT_REND_WEIGHT;
683 
684    evas_font_init();
685 
686    EINA_LIST_FOREACH(fonts_cache, l, fd)
687      {
688         if (!evas_font_desc_cmp(fdesc, fd->fdesc))
689           {
690               if (((!source) && (!fd->source)) ||
691                   ((source) && (fd->source) && (!strcmp(source, fd->source))))
692                 {
693                    if ((size == fd->size) &&
694                        (wanted_rend == fd->wanted_rend) &&
695                        (bitmap_scalable == fd->bitmap_scalable))
696                      {
697                         fonts_cache = eina_list_promote_list(fonts_cache, l);
698                         fd->ref++;
699                         return fd->font;
700                      }
701                 #ifdef HAVE_FONTCONFIG
702                    else if (fd->set && fd->p_nm && !fd->file_font)
703                      {
704                         found_fd = fd;
705                      }
706                 #endif
707                 }
708            }
709      }
710 
711 #ifdef HAVE_FONTCONFIG
712    if (found_fd)
713      {
714         font = _evas_load_fontconfig(font, found_fd->set, size, wanted_rend, bitmap_scalable);
715         goto on_find;
716      }
717 #endif
718 
719    EINA_LIST_FOREACH_SAFE(fonts_zero, l, l_next, fd)
720      {
721         if (!evas_font_desc_cmp(fdesc, fd->fdesc))
722           {
723              if (((!source) && (!fd->source)) ||
724                  ((source) && (fd->source) && (!strcmp(source, fd->source))))
725                {
726                   if ((size == fd->size) &&
727                                   (wanted_rend == fd->wanted_rend))
728                     {
729                        fonts_zero = eina_list_remove_list(fonts_zero, l);
730                        fonts_cache = eina_list_prepend(fonts_cache, fd);
731                        fd->ref++;
732                        return fd->font;
733                     }
734                #ifdef HAVE_FONTCONFIG
735                   else if (fd->set && fd->p_nm && !fd->file_font)
736                     {
737                        found_fd = fd;
738                     }
739                #endif
740                }
741           }
742      }
743 
744 #ifdef HAVE_FONTCONFIG
745    if (found_fd)
746      {
747         font = _evas_load_fontconfig(font, found_fd->set, size, wanted_rend, bitmap_scalable);
748         goto on_find;
749      }
750 #endif
751 
752    fonts = evas_font_set_get(fdesc->name);
753    EINA_LIST_FOREACH(fonts, l, nm) /* Load each font in append */
754      {
755         if (l == fonts || !font) /* First iteration OR no font */
756           {
757              /*This will suppress warnings for resource leak*/
758              if (font)
759                {
760                   evas_common_font_free((RGBA_Font*)font);
761                   font = NULL;
762                }
763 
764              if (source) /* Load Font from "eet" source */
765                {
766                   Eet_File *ef;
767                   char fake_name[PATH_MAX];
768 
769                    eina_file_path_join(fake_name, PATH_MAX, source, nm);
770                    font = (Evas_Font_Set *)evas_common_font_load(fake_name, size, wanted_rend, bitmap_scalable);
771                    if (!font) /* Load from fake name failed, probably not cached */
772                      {
773                         /* read original!!! */
774                         ef = eet_open(source, EET_FILE_MODE_READ);
775                         if (ef)
776                           {
777                              void *fdata;
778                              int fsize = 0;
779 
780                              fdata = eet_read(ef, nm, &fsize);
781                              if (fdata)
782                                {
783                                   font = (Evas_Font_Set *)evas_common_font_memory_load(source, nm, size, fdata, fsize, wanted_rend, bitmap_scalable);
784                                   free(fdata);
785                                }
786                              eet_close(ef);
787                           }
788                      }
789                }
790              if (!font) /* Source load failed */
791                {
792                   if (_file_path_is_full_path((char *)nm)) /* Try filename */
793                     font = (Evas_Font_Set *)evas_common_font_load((char *)nm, size, wanted_rend, bitmap_scalable);
794                   else /* search font path */
795                     {
796                        const Eina_List *ll;
797                        char *dir;
798 
799                        EINA_LIST_FOREACH(font_paths, ll, dir)
800                          {
801                             const char *f_file;
802 
803                             f_file = evas_font_dir_cache_find(dir, (char *)nm);
804                             if (f_file)
805                               {
806                                  font = (Evas_Font_Set *)evas_common_font_load(f_file, size, wanted_rend, bitmap_scalable);
807                                  if (font) break;
808                               }
809                          }
810 
811                        if (!font)
812                          {
813                             EINA_LIST_FOREACH(global_font_path, ll, dir)
814                               {
815                                  const char *f_file;
816 
817                                  f_file = evas_font_dir_cache_find(dir, (char *)nm);
818                                  if (f_file)
819                                    {
820                                       font = (Evas_Font_Set *)evas_common_font_load(f_file, size, wanted_rend, bitmap_scalable);
821                                       if (font) break;
822                                    }
823                               }
824                          }
825                     }
826                }
827           }
828         else /* Base font loaded, append others */
829           {
830              void *ok = NULL;
831 
832              if (source)
833                {
834                   Eet_File *ef;
835                   char fake_name[PATH_MAX];
836 
837                   eina_file_path_join(fake_name, PATH_MAX, source, nm);
838                   if (!evas_common_font_add((RGBA_Font *)font, fake_name, size, wanted_rend, bitmap_scalable))
839                     {
840                        /* read original!!! */
841                        ef = eet_open(source, EET_FILE_MODE_READ);
842                        if (ef)
843                          {
844                             void *fdata;
845                             int fsize = 0;
846 
847                             fdata = eet_read(ef, nm, &fsize);
848                             if ((fdata) && (fsize > 0))
849                               {
850                                  ok = evas_common_font_memory_add((RGBA_Font *)font, source, nm, size, fdata, fsize, wanted_rend, bitmap_scalable);
851                               }
852                             eet_close(ef);
853                             free(fdata);
854                          }
855                     }
856                   else
857                     ok = (void *)1;
858                }
859              if (!ok)
860                {
861                   if (_file_path_is_full_path((char *)nm))
862                     evas_common_font_add((RGBA_Font *)font, (char *)nm, size, wanted_rend, bitmap_scalable);
863                   else
864                     {
865                        const Eina_List *ll;
866                        char *dir;
867                        RGBA_Font *fn = NULL;
868 
869                        EINA_LIST_FOREACH(font_paths, ll, dir)
870                          {
871                             const char *f_file;
872 
873                             f_file = evas_font_dir_cache_find(dir, (char *)nm);
874                             if (f_file)
875                               {
876                                  fn = evas_common_font_add((RGBA_Font *)font, f_file, size, wanted_rend, bitmap_scalable);
877                                  if (fn)
878                                    break;
879                               }
880                          }
881 
882                        if (!fn)
883                          {
884                             EINA_LIST_FOREACH(global_font_path, ll, dir)
885                               {
886                                  const char *f_file;
887 
888                                  f_file = evas_font_dir_cache_find(dir, (char *)nm);
889                                  if (f_file)
890                                    {
891                                       fn = evas_common_font_add((RGBA_Font *)font, f_file, size, wanted_rend, bitmap_scalable);
892                                       if (fn)
893                                          break;
894                                    }
895                               }
896                          }
897                     }
898                }
899           }
900        eina_stringshare_del(nm);
901      }
902    eina_list_free(fonts);
903 
904 #ifdef HAVE_FONTCONFIG
905    if (!font) /* Search using fontconfig */
906      {
907         FcResult res;
908 
909         p_nm = FcPatternBuild (NULL,
910               FC_WEIGHT, FcTypeInteger, _fc_weight_map[fdesc->weight],
911               FC_SLANT,  FcTypeInteger, _fc_slant_map[fdesc->slant],
912               FC_SPACING,  FcTypeInteger, _fc_spacing_map[fdesc->spacing],
913 #ifdef FC_WIDTH
914               FC_WIDTH,  FcTypeInteger, _fc_width_map[fdesc->width],
915 #endif
916               NULL);
917         FcPatternAddString (p_nm, FC_FAMILY, (FcChar8*) fdesc->name);
918 
919         if (fdesc->style)
920           FcPatternAddString (p_nm, FC_STYLE, (FcChar8*) fdesc->style);
921 
922         /* Handle font fallbacks */
923         if (fdesc->fallbacks)
924           {
925              const char *start, *end;
926              start = fdesc->fallbacks;
927 
928              while (start)
929                {
930                   end = strchr(start, ',');
931                   if (end)
932                     {
933                        char *tmp = alloca((end - start) + 1);
934                        strncpy(tmp, start, end - start);
935                        tmp[end - start] = 0;
936                        FcPatternAddString (p_nm, FC_FAMILY, (FcChar8*) tmp);
937                        start = end + 1;
938                     }
939                   else
940                     {
941                        FcPatternAddString (p_nm, FC_FAMILY, (FcChar8*) start);
942                        break;
943                     }
944                }
945           }
946 
947         if (fdesc->lang)
948            FcPatternAddString (p_nm, FC_LANG, (FcChar8 *) fdesc->lang);
949 
950         FcConfigSubstitute(fc_config, p_nm, FcMatchPattern);
951         FcDefaultSubstitute(p_nm);
952 
953         /* do matching */
954         set = FcFontSort(fc_config, p_nm, FcTrue, NULL, &res);
955         if (!set)
956           {
957               //FIXME add ERR log capability
958              //ERR("No fontconfig font matches '%s'. It was the last resource, no font found!", fdesc->name);
959              FcPatternDestroy(p_nm);
960              p_nm = NULL;
961           }
962         else
963           {
964              font = _evas_load_fontconfig(font, set, size, wanted_rend, bitmap_scalable);
965           }
966      }
967    else /* Add a fallback list from fontconfig according to the found font. */
968      {
969 #if FC_MAJOR >= 2 && FC_MINOR >= 11
970         FcResult res;
971 
972         FT_Face face = evas_common_font_freetype_face_get((RGBA_Font *) font);
973 
974         file_font = EINA_TRUE;
975 
976         if (face)
977           {
978              p_nm = FcFreeTypeQueryFace(face, (FcChar8 *) "", 0, NULL);
979              FcConfigSubstitute(fc_config, p_nm, FcMatchPattern);
980              FcDefaultSubstitute(p_nm);
981 
982              /* do matching */
983              set = FcFontSort(fc_config, p_nm, FcTrue, NULL, &res);
984              if (!set)
985                {
986                   FcPatternDestroy(p_nm);
987                   p_nm = NULL;
988                }
989              else
990                {
991                   font = _evas_load_fontconfig(font, set, size, wanted_rend, bitmap_scalable);
992                }
993           }
994 #endif
995      }
996 #endif
997 
998 #ifdef HAVE_FONTCONFIG
999  on_find:
1000 #endif
1001    fd = calloc(1, sizeof(Fndat));
1002    if (fd)
1003      {
1004         fd->fdesc = evas_font_desc_ref(fdesc);
1005         if (source) fd->source = eina_stringshare_add(source);
1006         fd->font = font;
1007         fd->wanted_rend = wanted_rend;
1008         fd->size = size;
1009         fd->bitmap_scalable = bitmap_scalable;
1010         fd->ref = 1;
1011         fonts_cache = eina_list_prepend(fonts_cache, fd);
1012 #ifdef HAVE_FONTCONFIG
1013         fd->set = set;
1014         fd->p_nm = p_nm;
1015         fd->file_font = file_font;
1016 #endif
1017      }
1018 
1019    if (font)
1020      evas_common_font_hinting_set((RGBA_Font *)font, hinting);
1021    return font;
1022 }
1023 
1024 void
evas_font_load_hinting_set(void * font,int hinting)1025 evas_font_load_hinting_set(void *font, int hinting)
1026 {
1027    evas_common_font_hinting_set((RGBA_Font *) font, hinting);
1028 }
1029 
1030 Eina_List *
evas_font_dir_available_list(const Eina_List * font_paths)1031 evas_font_dir_available_list(const Eina_List *font_paths)
1032 {
1033    const Eina_List *l;
1034    Eina_List *ll;
1035    Eina_List *available = NULL;
1036    char *dir;
1037 
1038 #ifdef HAVE_FONTCONFIG
1039    /* Add font config fonts */
1040    FcPattern *p;
1041    FcFontSet *set = NULL;
1042    FcObjectSet *os;
1043    int i;
1044 
1045    evas_font_init();
1046 
1047    p = FcPatternCreate();
1048    os = FcObjectSetBuild(FC_FAMILY, FC_STYLE, NULL);
1049 
1050    if (p && os) set = FcFontList(fc_config, p, os);
1051 
1052    if (p) FcPatternDestroy(p);
1053    if (os) FcObjectSetDestroy(os);
1054 
1055    if (set)
1056      {
1057         for (i = 0; i < set->nfont; i++)
1058           {
1059              char *font;
1060 
1061              font = (char *)FcNameUnparse(set->fonts[i]);
1062              available = eina_list_append(available, eina_stringshare_add(font));
1063              free(font);
1064           }
1065 
1066         FcFontSetDestroy(set);
1067      }
1068 #endif
1069 
1070    /* Add fonts in font_paths*/
1071    if (font_paths)
1072      {
1073         if (!font_dirs) font_dirs = eina_hash_string_superfast_new(NULL);
1074 
1075         EINA_LIST_FOREACH(font_paths, l, dir)
1076           {
1077              Evas_Font_Dir *fd;
1078 
1079              fd = eina_hash_find(font_dirs, dir);
1080              fd = object_text_font_cache_dir_update(dir, fd);
1081              if (fd && fd->aliases)
1082                {
1083                   Evas_Font_Alias *fa;
1084 
1085                   EINA_LIST_FOREACH(fd->aliases, ll, fa)
1086                      available = eina_list_append(available, eina_stringshare_add((char *)fa->alias));
1087                }
1088           }
1089      }
1090 
1091    if (global_font_path)
1092      {
1093         if (!font_dirs) font_dirs = eina_hash_string_superfast_new(NULL);
1094 
1095         EINA_LIST_FOREACH(global_font_path, l, dir)
1096           {
1097              Evas_Font_Dir *fd;
1098 
1099              fd = eina_hash_find(font_dirs, dir);
1100              fd = object_text_font_cache_dir_update(dir, fd);
1101              if (fd && fd->aliases)
1102                {
1103                   Evas_Font_Alias *fa;
1104 
1105                   EINA_LIST_FOREACH(fd->aliases, ll, fa)
1106                      available = eina_list_append(available, eina_stringshare_add((char *)fa->alias));
1107                }
1108           }
1109      }
1110 
1111    return available;
1112 }
1113 
1114 void
evas_font_dir_available_list_free(Eina_List * available)1115 evas_font_dir_available_list_free(Eina_List *available)
1116 {
1117    while (available)
1118      {
1119         eina_stringshare_del(available->data);
1120         available = eina_list_remove(available, available->data);
1121      }
1122 }
1123 
1124 /* private stuff */
1125 static Eina_Bool
font_cache_dir_free(const Eina_Hash * hash EINA_UNUSED,const void * key,void * data,void * fdata EINA_UNUSED)1126 font_cache_dir_free(const Eina_Hash *hash EINA_UNUSED, const void *key, void *data, void *fdata EINA_UNUSED)
1127 {
1128    object_text_font_cache_dir_del((char *) key, data);
1129    return 1;
1130 }
1131 
1132 static Evas_Font_Dir *
object_text_font_cache_dir_update(char * dir,Evas_Font_Dir * fd)1133 object_text_font_cache_dir_update(char *dir, Evas_Font_Dir *fd)
1134 {
1135    char file_path[PATH_MAX];
1136    DATA64 mt;
1137 
1138    if (fd)
1139      {
1140         mt = _file_modified_time(dir);
1141         if (mt != fd->dir_mod_time)
1142           {
1143              eina_hash_del(font_dirs, dir, fd);
1144              object_text_font_cache_dir_del(dir, fd);
1145           }
1146         else
1147           {
1148              eina_file_path_join(file_path, PATH_MAX, dir, "fonts.dir");
1149              mt = _file_modified_time(file_path);
1150              if (mt != fd->fonts_dir_mod_time)
1151                {
1152                   eina_hash_del(font_dirs, dir, fd);
1153                   object_text_font_cache_dir_del(dir, fd);
1154                }
1155              else
1156                {
1157                   eina_file_path_join(file_path, PATH_MAX, dir, "fonts.alias");
1158                   mt = _file_modified_time(file_path);
1159                   if (mt != fd->fonts_alias_mod_time)
1160                     {
1161                        eina_hash_del(font_dirs, dir, fd);
1162                        object_text_font_cache_dir_del(dir, fd);
1163                     }
1164                   else
1165                     return fd;
1166                }
1167           }
1168      }
1169    return object_text_font_cache_dir_add(dir);
1170 }
1171 
1172 static Evas_Font *
object_text_font_cache_font_find_x(Evas_Font_Dir * fd,char * font)1173 object_text_font_cache_font_find_x(Evas_Font_Dir *fd, char *font)
1174 {
1175    Eina_List *l;
1176    char font_prop[14][256];
1177    int num;
1178    Evas_Font *fn;
1179 
1180    num = evas_object_text_font_string_parse(font, font_prop);
1181    if (num != 14) return NULL;
1182    EINA_LIST_FOREACH(fd->fonts, l, fn)
1183      {
1184         if (fn->type == 1)
1185           {
1186              int i;
1187              int match = 0;
1188 
1189              for (i = 0; i < 14; i++)
1190                {
1191                   if ((font_prop[i][0] == '*') && (font_prop[i][1] == 0))
1192                     match++;
1193                   else
1194                     {
1195                        if (!strcasecmp(font_prop[i], fn->x.prop[i])) match++;
1196                        else break;
1197                     }
1198                }
1199              if (match == 14) return fn;
1200           }
1201      }
1202    return NULL;
1203 }
1204 
1205 static Evas_Font *
object_text_font_cache_font_find_file(Evas_Font_Dir * fd,char * font)1206 object_text_font_cache_font_find_file(Evas_Font_Dir *fd, char *font)
1207 {
1208    Eina_List *l;
1209    Evas_Font *fn;
1210 
1211    EINA_LIST_FOREACH(fd->fonts, l, fn)
1212      {
1213         if (fn->type == 0)
1214           {
1215              if (!strcasecmp(font, fn->simple.name)) return fn;
1216           }
1217      }
1218    return NULL;
1219 }
1220 
1221 static Evas_Font *
object_text_font_cache_font_find_alias(Evas_Font_Dir * fd,char * font)1222 object_text_font_cache_font_find_alias(Evas_Font_Dir *fd, char *font)
1223 {
1224    Eina_List *l;
1225    Evas_Font_Alias *fa;
1226 
1227    EINA_LIST_FOREACH(fd->aliases, l, fa)
1228      if (!strcasecmp(fa->alias, font)) return fa->fn;
1229    return NULL;
1230 }
1231 
1232 static Evas_Font *
object_text_font_cache_font_find(Evas_Font_Dir * fd,char * font)1233 object_text_font_cache_font_find(Evas_Font_Dir *fd, char *font)
1234 {
1235    Evas_Font *fn;
1236 
1237    fn = eina_hash_find(fd->lookup, font);
1238    if (fn) return fn;
1239    fn = object_text_font_cache_font_find_alias(fd, font);
1240    if (!fn) fn = object_text_font_cache_font_find_x(fd, font);
1241    if (!fn) fn = object_text_font_cache_font_find_file(fd, font);
1242    if (!fn) return NULL;
1243    eina_hash_add(fd->lookup, font, fn);
1244    return fn;
1245 }
1246 
1247 static Evas_Font_Dir *
object_text_font_cache_dir_add(char * dir)1248 object_text_font_cache_dir_add(char *dir)
1249 {
1250    char file_path[PATH_MAX];
1251    Evas_Font_Dir *fd;
1252    char *file;
1253    char tmp2[PATH_MAX];
1254    Eina_List *fdir;
1255    Evas_Font *fn;
1256    FILE *f;
1257 
1258    fd = calloc(1, sizeof(Evas_Font_Dir));
1259    if (!fd) return NULL;
1260    fd->lookup = eina_hash_string_superfast_new(NULL);
1261 
1262    eina_hash_add(font_dirs, dir, fd);
1263 
1264    /* READ fonts.alias, fonts.dir and directory listing */
1265 
1266    /* fonts.dir */
1267    eina_file_path_join(file_path, PATH_MAX, dir, "fonts.dir");
1268 
1269    f = fopen(file_path, "rb");
1270    if (f)
1271      {
1272         int num;
1273         char fname[4096], fdef[4096];
1274 
1275         if (fscanf(f, "%i\n", &num) != 1) goto cant_read;
1276         /* read font lines */
1277         while (fscanf(f, "%4090s %[^\n]\n", fname, fdef) == 2)
1278           {
1279              char font_prop[14][256];
1280              int i;
1281 
1282              /* skip comments */
1283              if ((fdef[0] == '!') || (fdef[0] == '#')) continue;
1284              /* parse font def */
1285              num = evas_object_text_font_string_parse((char *)fdef, font_prop);
1286              if (num == 14)
1287                {
1288                   fn = calloc(1, sizeof(Evas_Font));
1289                   if (fn)
1290                     {
1291                        fn->type = 1;
1292                        for (i = 0; i < 14; i++)
1293                          fn->x.prop[i] = eina_stringshare_add(font_prop[i]);
1294                        eina_file_path_join(tmp2, PATH_MAX, dir, fname);
1295                        fn->path = eina_stringshare_add(tmp2);
1296                        fd->fonts = eina_list_append(fd->fonts, fn);
1297                     }
1298                }
1299           }
1300         cant_read: ;
1301         fclose(f);
1302      }
1303 
1304    /* directoy listing */
1305    fdir = _file_path_list(dir, "*.ttf", 0);
1306    EINA_LIST_FREE(fdir, file)
1307      {
1308         eina_file_path_join(file_path, PATH_MAX, dir, file);
1309         fn = calloc(1, sizeof(Evas_Font));
1310         if (fn)
1311           {
1312              char *p;
1313 
1314              fn->type = 0;
1315              p = strrchr(file, '.');
1316              if (p) fn->simple.name = eina_stringshare_add_length(file, p - file);
1317              else fn->simple.name = eina_stringshare_add(file);
1318              eina_file_path_join(tmp2, PATH_MAX, dir, file);
1319              fn->path = eina_stringshare_add(tmp2);
1320              fd->fonts = eina_list_append(fd->fonts, fn);
1321           }
1322         free(file);
1323      }
1324 
1325    /* fonts.alias */
1326    eina_file_path_join(file_path, PATH_MAX, dir, "fonts.alias");
1327 
1328    f = fopen(file_path, "rb");
1329    if (f)
1330      {
1331         char fname[4096], fdef[4096];
1332 
1333         /* read font alias lines */
1334         while (fscanf(f, "%4090s %4090[^\n]\n", fname, fdef) == 2)
1335           {
1336              Evas_Font_Alias *fa;
1337 
1338              /* skip comments */
1339              if ((fname[0] == '!') || (fname[0] == '#')) continue;
1340              fa = calloc(1, sizeof(Evas_Font_Alias));
1341              if (fa)
1342                {
1343                   fa->alias = eina_stringshare_add(fname);
1344                   fa->fn = object_text_font_cache_font_find_x(fd, fdef);
1345                   if ((!fa->alias) || (!fa->fn))
1346                     {
1347                        if (fa->alias) eina_stringshare_del(fa->alias);
1348                        free(fa);
1349                     }
1350                   else
1351                     fd->aliases = eina_list_append(fd->aliases, fa);
1352                }
1353           }
1354         fclose(f);
1355      }
1356 
1357    fd->dir_mod_time = _file_modified_time(dir);
1358 
1359    eina_file_path_join(file_path, PATH_MAX, dir, "fonts.dir");
1360    fd->fonts_dir_mod_time = _file_modified_time(file_path);
1361 
1362    eina_file_path_join(file_path, PATH_MAX, dir, "fonts.alias");
1363    fd->fonts_alias_mod_time = _file_modified_time(file_path);
1364 
1365    return fd;
1366 }
1367 
1368 static void
object_text_font_cache_dir_del(char * dir EINA_UNUSED,Evas_Font_Dir * fd)1369 object_text_font_cache_dir_del(char *dir EINA_UNUSED, Evas_Font_Dir *fd)
1370 {
1371    if (fd->lookup) eina_hash_free(fd->lookup);
1372    while (fd->fonts)
1373      {
1374         Evas_Font *fn;
1375         int i;
1376 
1377         fn = fd->fonts->data;
1378         fd->fonts = eina_list_remove(fd->fonts, fn);
1379         for (i = 0; i < 14; i++)
1380           {
1381              if (fn->x.prop[i]) eina_stringshare_del(fn->x.prop[i]);
1382           }
1383         if (fn->simple.name) eina_stringshare_del(fn->simple.name);
1384         if (fn->path) eina_stringshare_del(fn->path);
1385         free(fn);
1386      }
1387    while (fd->aliases)
1388      {
1389         Evas_Font_Alias *fa;
1390 
1391         fa = fd->aliases->data;
1392         fd->aliases = eina_list_remove(fd->aliases, fa);
1393         if (fa->alias) eina_stringshare_del(fa->alias);
1394         free(fa);
1395      }
1396    free(fd);
1397 }
1398 
1399 static int
evas_object_text_font_string_parse(char * buffer,char dest[14][256])1400 evas_object_text_font_string_parse(char *buffer, char dest[14][256])
1401 {
1402    char *p;
1403    int n, m, i;
1404 
1405    n = 0;
1406    m = 0;
1407    p = buffer;
1408    if (p[0] != '-') return 0;
1409    i = 1;
1410    while (p[i])
1411      {
1412         dest[n][m] = p[i];
1413         if ((p[i] == '-') || (m == 255))
1414           {
1415              dest[n][m] = 0;
1416              n++;
1417              m = -1;
1418           }
1419         i++;
1420         m++;
1421         if (n == 14) return n;
1422      }
1423    dest[n][m] = 0;
1424    n++;
1425    return n;
1426 }
1427 
1428 EAPI void
evas_font_path_global_append(const char * path)1429 evas_font_path_global_append(const char *path)
1430 {
1431    if (!path) return;
1432    global_font_path = eina_list_append(global_font_path, eina_stringshare_add(path));
1433 #ifdef HAVE_FONTCONFIG
1434    if (fc_config)
1435      FcConfigAppFontAddDir(fc_config, (const FcChar8 *) path);
1436 #endif
1437 }
1438 
1439 EAPI void
evas_font_path_global_prepend(const char * path)1440 evas_font_path_global_prepend(const char *path)
1441 {
1442    if (!path) return;
1443    global_font_path = eina_list_prepend(global_font_path, eina_stringshare_add(path));
1444 #ifdef HAVE_FONTCONFIG
1445    if (fc_config)
1446      FcConfigAppFontAddDir(fc_config, (const FcChar8 *) path);
1447 #endif
1448 }
1449 
1450 EAPI void
evas_font_path_global_clear(void)1451 evas_font_path_global_clear(void)
1452 {
1453    while (global_font_path)
1454      {
1455         eina_stringshare_del(global_font_path->data);
1456         global_font_path = eina_list_remove(global_font_path, global_font_path->data);
1457      }
1458 #ifdef HAVE_FONTCONFIG
1459    if (fc_config)
1460      FcConfigAppFontClear(fc_config);
1461 #endif
1462 }
1463 
1464 EAPI const Eina_List *
evas_font_path_global_list(void)1465 evas_font_path_global_list(void)
1466 {
1467    return global_font_path;
1468 }
1469 
1470 EAPI void
evas_font_reinit(void)1471 evas_font_reinit(void)
1472 {
1473 #ifdef HAVE_FONTCONFIG
1474    Eina_List *l;
1475    char *path;
1476 
1477    if (fc_config)
1478      {
1479         FcConfigDestroy(fc_config);
1480         fc_config = FcInitLoadConfigAndFonts();
1481 
1482         EINA_LIST_FOREACH(global_font_path, l, path)
1483            FcConfigAppFontAddDir(fc_config, (const FcChar8 *) path);
1484      }
1485 #endif
1486 }
1487