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