1 #include "evas_common.h"
2 #include "evas_private.h"
3 #ifdef BUILD_FONT_LOADER_EET
7 #include <fontconfig/fontconfig.h>
11 static Evas_Hash *font_dirs = NULL;
12 static Evas_List *fonts_cache = NULL;
13 static Evas_List *fonts_zero = NULL;
15 typedef struct _Fndat Fndat;
26 /* private methods for font dir cache */
27 static Evas_Bool font_cache_dir_free(const Evas_Hash *hash, const char *key, void *data, void *fdata);
28 static Evas_Font_Dir *object_text_font_cache_dir_update(char *dir, Evas_Font_Dir *fd);
29 static Evas_Font *object_text_font_cache_font_find_x(Evas_Font_Dir *fd, char *font);
30 static Evas_Font *object_text_font_cache_font_find_file(Evas_Font_Dir *fd, char *font);
31 static Evas_Font *object_text_font_cache_font_find_alias(Evas_Font_Dir *fd, char *font);
32 static Evas_Font *object_text_font_cache_font_find(Evas_Font_Dir *fd, char *font);
33 static Evas_Font_Dir *object_text_font_cache_dir_add(char *dir);
34 static void object_text_font_cache_dir_del(char *dir, Evas_Font_Dir *fd);
35 static int evas_object_text_font_string_parse(char *buffer, char dest[14][256]);
38 evas_font_dir_cache_free(void)
40 if (!font_dirs) return;
42 evas_hash_foreach(font_dirs, font_cache_dir_free, NULL);
43 evas_hash_free(font_dirs);
48 evas_font_dir_cache_find(char *dir, char *font)
52 fd = evas_hash_find(font_dirs, dir);
53 fd = object_text_font_cache_dir_update(dir, fd);
58 fn = object_text_font_cache_font_find(fd, font);
68 evas_font_set_get(const char *name)
70 Evas_List *fonts = NULL;
73 p = strchr(name, ',');
76 fonts = evas_list_append(fonts, evas_stringshare_add(name));
86 nm = alloca(p - pp + 1);
87 strncpy(nm, pp, p - pp);
89 fonts = evas_list_append(fonts, evas_stringshare_add(nm));
92 if (!p) fonts = evas_list_append(fonts, evas_stringshare_add(pp));
99 evas_font_free(Evas *evas, void *font)
103 for (l = fonts_cache; l; l = l->next)
108 if (fd->font == font)
113 fonts_cache = evas_list_remove_list(fonts_cache, l);
114 fonts_zero = evas_list_append(fonts_zero, fd);
119 while ((fonts_zero) &&
120 (evas_list_count(fonts_zero) > 4)) /* 4 is arbitrary */
124 fd = evas_list_data(fonts_zero);
125 if (fd->ref != 0) break;
126 fonts_zero = evas_list_remove_list(fonts_zero, fonts_zero);
127 if (fd->name) evas_stringshare_del(fd->name);
128 if (fd->source) evas_stringshare_del(fd->source);
129 evas->engine.func->font_free(evas->engine.data.output, fd->font);
135 evas_font_load(Evas *evas, const char *name, const char *source, int size)
138 Evas_List *fonts, *l;
141 if (!name) return NULL;
142 if (name[0] == 0) return NULL;
144 for (l = fonts_cache; l; l = l->next)
147 if (!strcmp(name, fd->name))
149 if (((!source) && (!fd->source)) ||
150 ((source) && (fd->source) && (!strcmp(source, fd->source))))
152 if (size == fd->size)
154 fonts_cache = evas_list_promote_list(fonts_cache, l);
162 for (l = fonts_zero; l; l = l->next)
165 if (!strcmp(name, fd->name))
167 if (((!source) && (!fd->source)) ||
168 ((source) && (fd->source) && (!strcmp(source, fd->source))))
170 if (size == fd->size)
172 fonts_zero = evas_list_remove_list(fonts_zero, l);
173 fonts_cache = evas_list_prepend(fonts_cache, fd);
180 fonts = evas_font_set_get(name);
181 for (l = fonts; l; l = l->next) /* Load each font in append */
186 if ((l == fonts) || (!font)) /* First iteration OR no font */
188 #ifdef BUILD_FONT_LOADER_EET
189 if (source) /* Load Font from "eet" source */
194 fake_name = evas_file_path_join(source, nm);
197 font = evas->engine.func->font_load(evas->engine.data.output, fake_name, size);
198 if (!font) /* Load from fake name failed, probably not cached */
200 /* read original!!! */
201 ef = eet_open(source, EET_FILE_MODE_READ);
207 fdata = eet_read(ef, nm, &fsize);
208 if ((fdata) && (fsize > 0))
210 font = evas->engine.func->font_memory_load(evas->engine.data.output, fake_name, size, fdata, fsize);
219 if (!font) /* Source load failed */
222 if (evas_file_path_is_full_path((char *)nm)) /* Try filename */
223 font = evas->engine.func->font_load(evas->engine.data.output, (char *)nm, size);
224 else /* search font path */
228 for (l = evas->font_path; l; l = l->next)
232 f_file = evas_font_dir_cache_find(l->data, (char *)nm);
235 font = evas->engine.func->font_load(evas->engine.data.output, f_file, size);
240 #ifdef BUILD_FONT_LOADER_EET
244 else /* Base font loaded, append others */
246 #ifdef BUILD_FONT_LOADER_EET
254 fake_name = evas_file_path_join(source, nm);
257 /* FIXME: make an engine func */
258 if (!evas->engine.func->font_add(evas->engine.data.output, font, fake_name, size))
260 /* read original!!! */
261 ef = eet_open(source, EET_FILE_MODE_READ);
267 fdata = eet_read(ef, nm, &fsize);
268 if ((fdata) && (fsize > 0))
270 ok = evas->engine.func->font_memory_add(evas->engine.data.output, font, fake_name, size, fdata, fsize);
284 if (evas_file_path_is_full_path((char *)nm))
285 evas->engine.func->font_add(evas->engine.data.output, font, (char *)nm, size);
290 for (l = evas->font_path; l; l = l->next)
294 f_file = evas_font_dir_cache_find(l->data, (char *)nm);
297 if (evas->engine.func->font_add(evas->engine.data.output, font, f_file, size))
302 #ifdef BUILD_FONT_LOADER_EET
306 evas_stringshare_del(nm);
308 evas_list_free(fonts);
310 #ifdef HAVE_FONTCONFIG
312 if (!font) /* Search using fontconfig */
314 FcPattern *p_nm = NULL;
319 p_nm = FcNameParse((FcChar8 *)name);
320 FcConfigSubstitute(NULL, p_nm, FcMatchPattern);
321 FcDefaultSubstitute(p_nm);
324 set = FcFontSort(NULL, p_nm, FcTrue, NULL, &res);
326 /* Do loading for all in family */
327 for (i = 0; i < set->nfont; i++)
331 FcPatternGet(set->fonts[i], FC_FILE, 0, &filename);
334 evas->engine.func->font_add(evas->engine.data.output, font, (char *)filename.u.s, size);
336 font = evas->engine.func->font_load(evas->engine.data.output, (char *)filename.u.s, size);
339 FcFontSetDestroy(set);
340 FcPatternDestroy(p_nm);
344 fd = calloc(1, sizeof(Fndat));
347 fd->name = evas_stringshare_add(name);
348 if (source) fd->source = evas_stringshare_add(source);
352 fonts_cache = evas_list_prepend(fonts_cache, fd);
356 evas->engine.func->font_hinting_set(evas->engine.data.output, font,
362 evas_font_load_hinting_set(Evas *evas, void *font, int hinting)
364 evas->engine.func->font_hinting_set(evas->engine.data.output, font,
369 evas_font_dir_available_list(const Evas *evas)
373 Evas_List *available = NULL;
375 #ifdef HAVE_FONTCONFIG
376 /* Add font config fonts */
378 FcFontSet *set = NULL;
382 p = FcPatternCreate();
383 os = FcObjectSetBuild(FC_FAMILY, FC_STYLE, NULL);
385 if (p && os) set = FcFontList(NULL, p, os);
387 if (p) FcPatternDestroy(p);
388 if (os) FcObjectSetDestroy(os);
392 for (i = 0; i < set->nfont; i++)
396 font = (char *)FcNameUnparse(set->fonts[i]);
397 available = evas_list_append(available, evas_stringshare_add(font));
401 FcFontSetDestroy(set);
405 /* Add fonts in evas font_path*/
406 if (!evas->font_path)
409 for (l = evas->font_path; l; l = l->next)
413 fd = evas_hash_find(font_dirs, (char *)l->data);
414 fd = object_text_font_cache_dir_update((char *)l->data, fd);
415 if (fd && fd->aliases)
417 for (ll = fd->aliases; ll; ll = ll->next)
422 available = evas_list_append(available, evas_stringshare_add((char *)fa->alias));
431 evas_font_dir_available_list_free(Evas_List *available)
435 evas_stringshare_del(available->data);
436 available = evas_list_remove(available, available->data);
442 font_cache_dir_free(const Evas_Hash *hash, const char *key, void *data, void *fdata)
444 object_text_font_cache_dir_del((char *) key, data);
448 static Evas_Font_Dir *
449 object_text_font_cache_dir_update(char *dir, Evas_Font_Dir *fd)
456 mt = evas_file_modified_time(dir);
457 if (mt != fd->dir_mod_time)
459 object_text_font_cache_dir_del(dir, fd);
460 font_dirs = evas_hash_del(font_dirs, dir, fd);
464 tmp = evas_file_path_join(dir, "fonts.dir");
467 mt = evas_file_modified_time(tmp);
469 if (mt != fd->fonts_dir_mod_time)
471 object_text_font_cache_dir_del(dir, fd);
472 font_dirs = evas_hash_del(font_dirs, dir, fd);
476 tmp = evas_file_path_join(dir, "fonts.alias");
479 mt = evas_file_modified_time(tmp);
482 if (mt != fd->fonts_alias_mod_time)
484 object_text_font_cache_dir_del(dir, fd);
485 font_dirs = evas_hash_del(font_dirs, dir, fd);
493 return object_text_font_cache_dir_add(dir);
497 object_text_font_cache_font_find_x(Evas_Font_Dir *fd, char *font)
500 char font_prop[14][256];
503 num = evas_object_text_font_string_parse(font, font_prop);
504 if (num != 14) return NULL;
505 for (l = fd->fonts; l; l = l->next)
515 for (i = 0; i < 14; i++)
517 if ((font_prop[i][0] == '*') && (font_prop[i][1] == 0))
521 if (!strcasecmp(font_prop[i], fn->x.prop[i])) match++;
525 if (match == 14) return fn;
532 object_text_font_cache_font_find_file(Evas_Font_Dir *fd, char *font)
536 for (l = fd->fonts; l; l = l->next)
543 if (!strcasecmp(font, fn->simple.name)) return fn;
550 object_text_font_cache_font_find_alias(Evas_Font_Dir *fd, char *font)
554 for (l = fd->aliases; l; l = l->next)
559 if (!strcasecmp(fa->alias, font)) return fa->fn;
565 object_text_font_cache_font_find(Evas_Font_Dir *fd, char *font)
569 fn = evas_hash_find(fd->lookup, font);
571 fn = object_text_font_cache_font_find_alias(fd, font);
572 if (!fn) fn = object_text_font_cache_font_find_x(fd, font);
573 if (!fn) fn = object_text_font_cache_font_find_file(fd, font);
574 if (!fn) return NULL;
575 fd->lookup = evas_hash_add(fd->lookup, font, fn);
579 static Evas_Font_Dir *
580 object_text_font_cache_dir_add(char *dir)
586 fd = calloc(1, sizeof(Evas_Font_Dir));
587 if (!fd) return NULL;
588 font_dirs = evas_hash_add(font_dirs, dir, fd);
590 /* READ fonts.alias, fonts.dir and directory listing */
593 tmp = evas_file_path_join(dir, "fonts.dir");
602 char fname[4096], fdef[4096];
604 if (fscanf(f, "%i\n", &num) != 1) goto cant_read;
605 /* read font lines */
606 while (fscanf(f, "%4090s %[^\n]\n", fname, fdef) == 2)
608 char font_prop[14][256];
612 if ((fdef[0] == '!') || (fdef[0] == '#')) continue;
614 num = evas_object_text_font_string_parse((char *)fdef, font_prop);
619 fn = calloc(1, sizeof(Evas_Font));
623 for (i = 0; i < 14; i++)
624 fn->x.prop[i] = evas_stringshare_add(font_prop[i]);
625 tmp2 = evas_file_path_join(dir, fname);
628 fn->path = evas_stringshare_add(tmp2);
631 fd->fonts = evas_list_append(fd->fonts, fn);
641 /* directoy listing */
642 fdir = evas_file_path_list(dir, "*.ttf", 0);
645 tmp = evas_file_path_join(dir, fdir->data);
650 fn = calloc(1, sizeof(Evas_Font));
656 tmp2 = alloca(strlen(fdir->data) + 1);
657 strcpy(tmp2, fdir->data);
658 p = strrchr(tmp2, '.');
660 fn->simple.name = evas_stringshare_add(tmp2);
661 tmp2 = evas_file_path_join(dir, fdir->data);
664 fn->path = evas_stringshare_add(tmp2);
667 fd->fonts = evas_list_append(fd->fonts, fn);
672 fdir = evas_list_remove(fdir, fdir->data);
676 tmp = evas_file_path_join(dir, "fonts.alias");
684 char fname[4096], fdef[4096];
686 /* read font alias lines */
687 while (fscanf(f, "%4090s %[^\n]\n", fname, fdef) == 2)
692 if ((fname[0] == '!') || (fname[0] == '#')) continue;
693 fa = calloc(1, sizeof(Evas_Font_Alias));
696 fa->alias = evas_stringshare_add(fname);
697 fa->fn = object_text_font_cache_font_find_x(fd, fdef);
698 if ((!fa->alias) || (!fa->fn))
700 if (fa->alias) evas_stringshare_del(fa->alias);
704 fd->aliases = evas_list_append(fd->aliases, fa);
712 fd->dir_mod_time = evas_file_modified_time(dir);
713 tmp = evas_file_path_join(dir, "fonts.dir");
716 fd->fonts_dir_mod_time = evas_file_modified_time(tmp);
719 tmp = evas_file_path_join(dir, "fonts.alias");
722 fd->fonts_alias_mod_time = evas_file_modified_time(tmp);
730 object_text_font_cache_dir_del(char *dir, Evas_Font_Dir *fd)
732 if (fd->lookup) evas_hash_free(fd->lookup);
738 fn = fd->fonts->data;
739 fd->fonts = evas_list_remove(fd->fonts, fn);
740 for (i = 0; i < 14; i++)
742 if (fn->x.prop[i]) evas_stringshare_del(fn->x.prop[i]);
744 if (fn->simple.name) evas_stringshare_del(fn->simple.name);
745 if (fn->path) evas_stringshare_del(fn->path);
752 fa = fd->aliases->data;
753 fd->aliases = evas_list_remove(fd->aliases, fa);
754 if (fa->alias) evas_stringshare_del(fa->alias);
761 evas_object_text_font_string_parse(char *buffer, char dest[14][256])
769 if (p[0] != '-') return 0;
774 if ((p[i] == '-') || (m == 256))
782 if (n == 14) return n;