aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/evas/src/lib/canvas/evas_font_dir.c
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/evas/src/lib/canvas/evas_font_dir.c')
-rw-r--r--libraries/evas/src/lib/canvas/evas_font_dir.c1349
1 files changed, 0 insertions, 1349 deletions
diff --git a/libraries/evas/src/lib/canvas/evas_font_dir.c b/libraries/evas/src/lib/canvas/evas_font_dir.c
deleted file mode 100644
index e97f7f7..0000000
--- a/libraries/evas/src/lib/canvas/evas_font_dir.c
+++ /dev/null
@@ -1,1349 +0,0 @@
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 */
21static Eina_Hash *font_dirs = NULL;
22static Eina_List *fonts_cache = NULL;
23static Eina_List *fonts_zero = NULL;
24
25typedef struct _Fndat Fndat;
26
27struct _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 */
43static Eina_Bool font_cache_dir_free(const Eina_Hash *hash, const void *key, void *data, void *fdata);
44static Evas_Font_Dir *object_text_font_cache_dir_update(char *dir, Evas_Font_Dir *fd);
45static Evas_Font *object_text_font_cache_font_find_x(Evas_Font_Dir *fd, char *font);
46static Evas_Font *object_text_font_cache_font_find_file(Evas_Font_Dir *fd, char *font);
47static Evas_Font *object_text_font_cache_font_find_alias(Evas_Font_Dir *fd, char *font);
48static Evas_Font *object_text_font_cache_font_find(Evas_Font_Dir *fd, char *font);
49static Evas_Font_Dir *object_text_font_cache_dir_add(char *dir);
50static void object_text_font_cache_dir_del(char *dir, Evas_Font_Dir *fd);
51static int evas_object_text_font_string_parse(char *buffer, char dest[14][256]);
52
53#ifdef HAVE_FONTCONFIG
54static int fc_init = 0;
55#endif
56
57void
58evas_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
80const char *
81evas_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
101static Eina_List *
102evas_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
132void
133evas_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
150void
151evas_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
176void
177evas_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
216static void
217evas_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
233static Evas_Font_Set *
234evas_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 */
259static int _fc_slant_map[] =
260{
261 FC_SLANT_ROMAN,
262 FC_SLANT_OBLIQUE,
263 FC_SLANT_ITALIC
264};
265
266static 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
282static 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
298struct _Style_Map
299{
300 const char *name;
301 int type;
302};
303typedef struct _Style_Map Style_Map;
304
305static 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
318static 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
333static 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 */
346static 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
374int
375evas_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
395void
396evas_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
407Evas_Font_Description *
408evas_font_desc_ref(Evas_Font_Description *fdesc)
409{
410 fdesc->ref++;
411 return fdesc;
412}
413
414Evas_Font_Description *
415evas_font_desc_new(void)
416{
417 Evas_Font_Description *fdesc;
418 fdesc = calloc(1, sizeof(*fdesc));
419 fdesc->ref = 1;
420 fdesc->is_new = EINA_TRUE;
421
422 return fdesc;
423}
424
425Evas_Font_Description *
426evas_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->is_new = EINA_TRUE;
433 new->name = eina_stringshare_ref(new->name);
434
435 return new;
436}
437
438int
439evas_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
448void
449evas_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
487void *
488evas_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->is_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 if (!font) /* Search using fontconfig */
695 {
696 FcResult res;
697
698 p_nm = FcPatternBuild (NULL,
699 FC_WEIGHT, FcTypeInteger, _fc_weight_map[fdesc->weight],
700 FC_SLANT, FcTypeInteger, _fc_slant_map[fdesc->slant],
701#ifdef FC_WIDTH
702 FC_WIDTH, FcTypeInteger, _fc_width_map[fdesc->width],
703#endif
704 NULL);
705 FcPatternAddString (p_nm, FC_FAMILY, (FcChar8*) fdesc->name);
706
707 /* Handle font fallbacks */
708 if (fdesc->fallbacks)
709 {
710 while (1)
711 {
712 const char *start, *end;
713 start = fdesc->fallbacks;
714 end = strchr(start, ',');
715 if (end)
716 {
717 char *tmp = alloca((end - start) + 1);
718 strncpy(tmp, start, end - start);
719 tmp[end - start] = 0;
720 FcPatternAddString (p_nm, FC_FAMILY, (FcChar8*) tmp);
721 }
722 else
723 {
724 FcPatternAddString (p_nm, FC_FAMILY, (FcChar8*) start);
725 break;
726 }
727 }
728 }
729
730 if (fdesc->lang)
731 FcPatternAddString (p_nm, FC_LANG, (FcChar8 *) fdesc->lang);
732
733 FcConfigSubstitute(NULL, p_nm, FcMatchPattern);
734 FcDefaultSubstitute(p_nm);
735
736 /* do matching */
737 set = FcFontSort(NULL, p_nm, FcTrue, NULL, &res);
738 if (!set)
739 {
740 ERR("No fontconfig font matches '%s'. It was the last resource, no font found!", fdesc->name);
741 FcPatternDestroy(p_nm);
742 p_nm = NULL;
743 }
744 else
745 {
746 font = evas_load_fontconfig(evas, set, size, wanted_rend);
747 }
748 }
749#endif
750
751#ifdef HAVE_FONTCONFIG
752 on_find:
753#endif
754 fd = calloc(1, sizeof(Fndat));
755 if (fd)
756 {
757 fd->fdesc = evas_font_desc_ref(fdesc);
758 if (source) fd->source = eina_stringshare_add(source);
759 fd->font = font;
760 fd->wanted_rend = wanted_rend;
761 fd->size = size;
762 fd->ref = 1;
763 fonts_cache = eina_list_prepend(fonts_cache, fd);
764#ifdef HAVE_FONTCONFIG
765 fd->set = set;
766 fd->p_nm = p_nm;
767#endif
768 }
769
770 if (font)
771 evas->engine.func->font_hinting_set(evas->engine.data.output, font,
772 evas->hinting);
773 return font;
774}
775
776void
777evas_font_load_hinting_set(Evas *evas, void *font, int hinting)
778{
779 evas->engine.func->font_hinting_set(evas->engine.data.output, font,
780 hinting);
781}
782
783Eina_List *
784evas_font_dir_available_list(const Evas *evas)
785{
786 Eina_List *l;
787 Eina_List *ll;
788 Eina_List *available = NULL;
789 char *dir;
790
791#ifdef HAVE_FONTCONFIG
792 /* Add font config fonts */
793 FcPattern *p;
794 FcFontSet *set = NULL;
795 FcObjectSet *os;
796 int i;
797
798 evas_font_init();
799
800 p = FcPatternCreate();
801 os = FcObjectSetBuild(FC_FAMILY, FC_STYLE, NULL);
802
803 if (p && os) set = FcFontList(NULL, p, os);
804
805 if (p) FcPatternDestroy(p);
806 if (os) FcObjectSetDestroy(os);
807
808 if (set)
809 {
810 for (i = 0; i < set->nfont; i++)
811 {
812 char *font;
813
814 font = (char *)FcNameUnparse(set->fonts[i]);
815 available = eina_list_append(available, eina_stringshare_add(font));
816 free(font);
817 }
818
819 FcFontSetDestroy(set);
820 }
821#endif
822
823 /* Add fonts in evas font_path*/
824 if (!evas->font_path)
825 return available;
826
827 if (!font_dirs) font_dirs = eina_hash_string_superfast_new(NULL);
828
829 EINA_LIST_FOREACH(evas->font_path, l, dir)
830 {
831 Evas_Font_Dir *fd;
832
833 fd = eina_hash_find(font_dirs, dir);
834 fd = object_text_font_cache_dir_update(dir, fd);
835 if (fd && fd->aliases)
836 {
837 Evas_Font_Alias *fa;
838
839 EINA_LIST_FOREACH(fd->aliases, ll, fa)
840 available = eina_list_append(available, eina_stringshare_add((char *)fa->alias));
841 }
842 }
843
844 return available;
845}
846
847void
848evas_font_dir_available_list_free(Eina_List *available)
849{
850 while (available)
851 {
852 eina_stringshare_del(available->data);
853 available = eina_list_remove(available, available->data);
854 }
855}
856
857/* private stuff */
858static Eina_Bool
859font_cache_dir_free(const Eina_Hash *hash __UNUSED__, const void *key, void *data, void *fdata __UNUSED__)
860{
861 object_text_font_cache_dir_del((char *) key, data);
862 return 1;
863}
864
865static Evas_Font_Dir *
866object_text_font_cache_dir_update(char *dir, Evas_Font_Dir *fd)
867{
868 DATA64 mt;
869 char *tmp;
870
871 if (fd)
872 {
873 mt = evas_file_modified_time(dir);
874 if (mt != fd->dir_mod_time)
875 {
876 object_text_font_cache_dir_del(dir, fd);
877 eina_hash_del(font_dirs, dir, fd);
878 }
879 else
880 {
881 tmp = evas_file_path_join(dir, "fonts.dir");
882 if (tmp)
883 {
884 mt = evas_file_modified_time(tmp);
885 free(tmp);
886 if (mt != fd->fonts_dir_mod_time)
887 {
888 object_text_font_cache_dir_del(dir, fd);
889 eina_hash_del(font_dirs, dir, fd);
890 }
891 else
892 {
893 tmp = evas_file_path_join(dir, "fonts.alias");
894 if (tmp)
895 {
896 mt = evas_file_modified_time(tmp);
897 free(tmp);
898 }
899 if (mt != fd->fonts_alias_mod_time)
900 {
901 object_text_font_cache_dir_del(dir, fd);
902 eina_hash_del(font_dirs, dir, fd);
903 }
904 else
905 return fd;
906 }
907 }
908 }
909 }
910 return object_text_font_cache_dir_add(dir);
911}
912
913static Evas_Font *
914object_text_font_cache_font_find_x(Evas_Font_Dir *fd, char *font)
915{
916 Eina_List *l;
917 char font_prop[14][256];
918 int num;
919 Evas_Font *fn;
920
921 num = evas_object_text_font_string_parse(font, font_prop);
922 if (num != 14) return NULL;
923 EINA_LIST_FOREACH(fd->fonts, l, fn)
924 {
925 if (fn->type == 1)
926 {
927 int i;
928 int match = 0;
929
930 for (i = 0; i < 14; i++)
931 {
932 if ((font_prop[i][0] == '*') && (font_prop[i][1] == 0))
933 match++;
934 else
935 {
936 if (!strcasecmp(font_prop[i], fn->x.prop[i])) match++;
937 else break;
938 }
939 }
940 if (match == 14) return fn;
941 }
942 }
943 return NULL;
944}
945
946static Evas_Font *
947object_text_font_cache_font_find_file(Evas_Font_Dir *fd, char *font)
948{
949 Eina_List *l;
950 Evas_Font *fn;
951
952 EINA_LIST_FOREACH(fd->fonts, l, fn)
953 {
954 if (fn->type == 0)
955 {
956 if (!strcasecmp(font, fn->simple.name)) return fn;
957 }
958 }
959 return NULL;
960}
961
962static Evas_Font *
963object_text_font_cache_font_find_alias(Evas_Font_Dir *fd, char *font)
964{
965 Eina_List *l;
966 Evas_Font_Alias *fa;
967
968 EINA_LIST_FOREACH(fd->aliases, l, fa)
969 if (!strcasecmp(fa->alias, font)) return fa->fn;
970 return NULL;
971}
972
973static Evas_Font *
974object_text_font_cache_font_find(Evas_Font_Dir *fd, char *font)
975{
976 Evas_Font *fn;
977
978 fn = eina_hash_find(fd->lookup, font);
979 if (fn) return fn;
980 fn = object_text_font_cache_font_find_alias(fd, font);
981 if (!fn) fn = object_text_font_cache_font_find_x(fd, font);
982 if (!fn) fn = object_text_font_cache_font_find_file(fd, font);
983 if (!fn) return NULL;
984 eina_hash_add(fd->lookup, font, fn);
985 return fn;
986}
987
988static Evas_Font_Dir *
989object_text_font_cache_dir_add(char *dir)
990{
991 Evas_Font_Dir *fd;
992 char *tmp, *tmp2;
993 Eina_List *fdir;
994 Evas_Font *fn;
995
996 fd = calloc(1, sizeof(Evas_Font_Dir));
997 if (!fd) return NULL;
998 fd->lookup = eina_hash_string_superfast_new(NULL);
999
1000 eina_hash_add(font_dirs, dir, fd);
1001
1002 /* READ fonts.alias, fonts.dir and directory listing */
1003
1004 /* fonts.dir */
1005 tmp = evas_file_path_join(dir, "fonts.dir");
1006 if (tmp)
1007 {
1008 FILE *f;
1009
1010 f = fopen(tmp, "rb");
1011 if (f)
1012 {
1013 int num;
1014 char fname[4096], fdef[4096];
1015
1016 if (fscanf(f, "%i\n", &num) != 1) goto cant_read;
1017 /* read font lines */
1018 while (fscanf(f, "%4090s %[^\n]\n", fname, fdef) == 2)
1019 {
1020 char font_prop[14][256];
1021 int i;
1022
1023 /* skip comments */
1024 if ((fdef[0] == '!') || (fdef[0] == '#')) continue;
1025 /* parse font def */
1026 num = evas_object_text_font_string_parse((char *)fdef, font_prop);
1027 if (num == 14)
1028 {
1029 fn = calloc(1, sizeof(Evas_Font));
1030 if (fn)
1031 {
1032 fn->type = 1;
1033 for (i = 0; i < 14; i++)
1034 fn->x.prop[i] = eina_stringshare_add(font_prop[i]);
1035 tmp2 = evas_file_path_join(dir, fname);
1036 if (tmp2)
1037 {
1038 fn->path = eina_stringshare_add(tmp2);
1039 free(tmp2);
1040 }
1041 fd->fonts = eina_list_append(fd->fonts, fn);
1042 }
1043 }
1044 }
1045 cant_read: ;
1046 fclose(f);
1047 }
1048 free(tmp);
1049 }
1050
1051 /* directoy listing */
1052 fdir = evas_file_path_list(dir, "*.ttf", 0);
1053 while (fdir)
1054 {
1055 tmp = evas_file_path_join(dir, fdir->data);
1056 if (tmp)
1057 {
1058 fn = calloc(1, sizeof(Evas_Font));
1059 if (fn)
1060 {
1061 char *p;
1062
1063 fn->type = 0;
1064 tmp2 = alloca(strlen(fdir->data) + 1);
1065 strcpy(tmp2, fdir->data);
1066 p = strrchr(tmp2, '.');
1067 if (p) *p = 0;
1068 fn->simple.name = eina_stringshare_add(tmp2);
1069 tmp2 = evas_file_path_join(dir, fdir->data);
1070 if (tmp2)
1071 {
1072 fn->path = eina_stringshare_add(tmp2);
1073 free(tmp2);
1074 }
1075 fd->fonts = eina_list_append(fd->fonts, fn);
1076 }
1077 free(tmp);
1078 }
1079 free(fdir->data);
1080 fdir = eina_list_remove(fdir, fdir->data);
1081 }
1082
1083 /* fonts.alias */
1084 tmp = evas_file_path_join(dir, "fonts.alias");
1085 if (tmp)
1086 {
1087 FILE *f;
1088
1089 f = fopen(tmp, "rb");
1090 if (f)
1091 {
1092 char fname[4096], fdef[4096];
1093
1094 /* read font alias lines */
1095 while (fscanf(f, "%4090s %[^\n]\n", fname, fdef) == 2)
1096 {
1097 Evas_Font_Alias *fa;
1098
1099 /* skip comments */
1100 if ((fname[0] == '!') || (fname[0] == '#')) continue;
1101 fa = calloc(1, sizeof(Evas_Font_Alias));
1102 if (fa)
1103 {
1104 fa->alias = eina_stringshare_add(fname);
1105 fa->fn = object_text_font_cache_font_find_x(fd, fdef);
1106 if ((!fa->alias) || (!fa->fn))
1107 {
1108 if (fa->alias) eina_stringshare_del(fa->alias);
1109 free(fa);
1110 }
1111 else
1112 fd->aliases = eina_list_append(fd->aliases, fa);
1113 }
1114 }
1115 fclose(f);
1116 }
1117 free(tmp);
1118 }
1119
1120 fd->dir_mod_time = evas_file_modified_time(dir);
1121 tmp = evas_file_path_join(dir, "fonts.dir");
1122 if (tmp)
1123 {
1124 fd->fonts_dir_mod_time = evas_file_modified_time(tmp);
1125 free(tmp);
1126 }
1127 tmp = evas_file_path_join(dir, "fonts.alias");
1128 if (tmp)
1129 {
1130 fd->fonts_alias_mod_time = evas_file_modified_time(tmp);
1131 free(tmp);
1132 }
1133
1134 return fd;
1135}
1136
1137static void
1138object_text_font_cache_dir_del(char *dir __UNUSED__, Evas_Font_Dir *fd)
1139{
1140 if (fd->lookup) eina_hash_free(fd->lookup);
1141 while (fd->fonts)
1142 {
1143 Evas_Font *fn;
1144 int i;
1145
1146 fn = fd->fonts->data;
1147 fd->fonts = eina_list_remove(fd->fonts, fn);
1148 for (i = 0; i < 14; i++)
1149 {
1150 if (fn->x.prop[i]) eina_stringshare_del(fn->x.prop[i]);
1151 }
1152 if (fn->simple.name) eina_stringshare_del(fn->simple.name);
1153 if (fn->path) eina_stringshare_del(fn->path);
1154 free(fn);
1155 }
1156 while (fd->aliases)
1157 {
1158 Evas_Font_Alias *fa;
1159
1160 fa = fd->aliases->data;
1161 fd->aliases = eina_list_remove(fd->aliases, fa);
1162 if (fa->alias) eina_stringshare_del(fa->alias);
1163 free(fa);
1164 }
1165 free(fd);
1166}
1167
1168static int
1169evas_object_text_font_string_parse(char *buffer, char dest[14][256])
1170{
1171 char *p;
1172 int n, m, i;
1173
1174 n = 0;
1175 m = 0;
1176 p = buffer;
1177 if (p[0] != '-') return 0;
1178 i = 1;
1179 while (p[i])
1180 {
1181 dest[n][m] = p[i];
1182 if ((p[i] == '-') || (m == 255))
1183 {
1184 dest[n][m] = 0;
1185 n++;
1186 m = -1;
1187 }
1188 i++;
1189 m++;
1190 if (n == 14) return n;
1191 }
1192 dest[n][m] = 0;
1193 n++;
1194 return n;
1195}
1196
1197EAPI void
1198evas_font_path_clear(Evas *e)
1199{
1200 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
1201 return;
1202 MAGIC_CHECK_END();
1203 while (e->font_path)
1204 {
1205 eina_stringshare_del(e->font_path->data);
1206 e->font_path = eina_list_remove(e->font_path, e->font_path->data);
1207 }
1208}
1209
1210EAPI void
1211evas_font_path_append(Evas *e, const char *path)
1212{
1213 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
1214 return;
1215 MAGIC_CHECK_END();
1216
1217 if (!path) return;
1218 e->font_path = eina_list_append(e->font_path, eina_stringshare_add(path));
1219}
1220
1221EAPI void
1222evas_font_path_prepend(Evas *e, const char *path)
1223{
1224 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
1225 return;
1226 MAGIC_CHECK_END();
1227
1228 if (!path) return;
1229 e->font_path = eina_list_prepend(e->font_path, eina_stringshare_add(path));
1230}
1231
1232EAPI const Eina_List *
1233evas_font_path_list(const Evas *e)
1234{
1235 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
1236 return NULL;
1237 MAGIC_CHECK_END();
1238 return e->font_path;
1239}
1240
1241static void
1242evas_font_object_rehint(Evas_Object *obj)
1243{
1244 if (obj->smart.smart)
1245 {
1246 EINA_INLIST_FOREACH(evas_object_smart_members_get_direct(obj), obj)
1247 evas_font_object_rehint(obj);
1248 }
1249 else
1250 {
1251 if (!strcmp(obj->type, "text"))
1252 _evas_object_text_rehint(obj);
1253 if (!strcmp(obj->type, "textblock"))
1254 _evas_object_textblock_rehint(obj);
1255 }
1256}
1257
1258EAPI void
1259evas_font_hinting_set(Evas *e, Evas_Font_Hinting_Flags hinting)
1260{
1261 Evas_Layer *lay;
1262
1263 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
1264 return;
1265 MAGIC_CHECK_END();
1266 if (e->hinting == hinting) return;
1267 e->hinting = hinting;
1268
1269 EINA_INLIST_FOREACH(e->layers, lay)
1270 {
1271 Evas_Object *obj;
1272
1273 EINA_INLIST_FOREACH(lay->objects, obj)
1274 evas_font_object_rehint(obj);
1275 }
1276}
1277
1278EAPI Evas_Font_Hinting_Flags
1279evas_font_hinting_get(const Evas *e)
1280{
1281 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
1282 return EVAS_FONT_HINTING_BYTECODE;
1283 MAGIC_CHECK_END();
1284 return e->hinting;
1285}
1286
1287EAPI Eina_Bool
1288evas_font_hinting_can_hint(const Evas *e, Evas_Font_Hinting_Flags hinting)
1289{
1290 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
1291 return 0;
1292 MAGIC_CHECK_END();
1293 if (e->engine.func->font_hinting_can_hint)
1294 return e->engine.func->font_hinting_can_hint(e->engine.data.output,
1295 hinting);
1296 return EINA_FALSE;
1297}
1298
1299EAPI void
1300evas_font_cache_flush(Evas *e)
1301{
1302 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
1303 return;
1304 MAGIC_CHECK_END();
1305
1306 e->engine.func->font_cache_flush(e->engine.data.output);
1307}
1308
1309EAPI void
1310evas_font_cache_set(Evas *e, int size)
1311{
1312 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
1313 return;
1314 MAGIC_CHECK_END();
1315
1316 if (size < 0) size = 0;
1317 e->engine.func->font_cache_set(e->engine.data.output, size);
1318}
1319
1320EAPI int
1321evas_font_cache_get(const Evas *e)
1322{
1323 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
1324 return 0;
1325 MAGIC_CHECK_END();
1326
1327 return e->engine.func->font_cache_get(e->engine.data.output);
1328}
1329
1330EAPI Eina_List *
1331evas_font_available_list(const Evas *e)
1332{
1333 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
1334 return NULL;
1335 MAGIC_CHECK_END();
1336
1337 return evas_font_dir_available_list(e);
1338}
1339
1340EAPI void
1341evas_font_available_list_free(Evas *e, Eina_List *available)
1342{
1343 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
1344 return;
1345 MAGIC_CHECK_END();
1346
1347 evas_font_dir_available_list_free(available);
1348}
1349