move around - flatter.
[profile/ivi/evas.git] / src / lib / engines / common / evas_font_load.c
1 /*
2  * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
3  */
4
5 #include "evas_common.h"
6 #include "evas_private.h"
7
8 extern FT_Library         evas_ft_lib;
9
10 static int                font_cache_usage = 0;
11 static int                font_cache = 0;
12 static Evas_Object_List * fonts_src = NULL;
13 static Evas_Object_List * fonts = NULL;
14
15 static Evas_Bool font_modify_cache_cb(const Evas_Hash *hash, const char *key, void *data, void *fdata);
16 static Evas_Bool font_flush_free_glyph_cb(const Evas_Hash *hash, const char *key, void *data, void *fdata);
17
18 EAPI RGBA_Font_Source *
19 evas_common_font_source_memory_load(const char *name, const void *data, int data_size)
20 {
21    int error;
22    RGBA_Font_Source *fs;
23
24    fs = calloc(1, sizeof(RGBA_Font_Source) + data_size);
25    if (!fs) return NULL;
26    fs->data = ((unsigned char *)fs) + sizeof(RGBA_Font_Source);
27    fs->data_size = data_size;
28    fs->current_size = 0;
29    memcpy(fs->data, data, data_size);
30    error = FT_New_Memory_Face(evas_ft_lib, fs->data, fs->data_size, 0, &(fs->ft.face));
31    if (error)
32      {
33         free(fs);
34         return NULL;
35      }
36    fs->name = evas_stringshare_add(name);
37    fs->file = NULL;
38    error = FT_Select_Charmap(fs->ft.face, ft_encoding_unicode);
39    fs->ft.orig_upem = fs->ft.face->units_per_EM;
40    fs->references = 1;
41    fonts_src = evas_object_list_prepend(fonts_src, fs);
42    return fs;
43 }
44
45 EAPI RGBA_Font_Source *
46 evas_common_font_source_load(const char *name)
47 {
48    RGBA_Font_Source *fs;
49
50    fs = calloc(1, sizeof(RGBA_Font_Source));
51    if (!fs) return NULL;
52    fs->data = NULL;
53    fs->data_size = 0;
54    fs->current_size = 0;
55    fs->ft.face = NULL;
56
57    fs->name = evas_stringshare_add(name);
58    fs->file = fs->name;
59
60    fs->ft.orig_upem = 0;
61
62    fs->references = 1;
63    fonts_src = evas_object_list_prepend(fonts_src, fs);
64    return fs;
65 }
66
67 EAPI int
68 evas_common_font_source_load_complete(RGBA_Font_Source *fs)
69 {
70    int error;
71
72    error = FT_New_Face(evas_ft_lib, fs->file, 0, &(fs->ft.face));
73    if (error)
74      {
75         fs->ft.face = NULL;
76         return error;
77      }
78
79    error = FT_Select_Charmap(fs->ft.face, ft_encoding_unicode);
80    if (error)
81      {
82         FT_Done_Face(fs->ft.face);
83         fs->ft.face = NULL;
84         return error;
85      }
86
87    fs->ft.orig_upem = fs->ft.face->units_per_EM;
88    return error;
89 }
90
91 EAPI RGBA_Font_Source *
92 evas_common_font_source_find(const char *name)
93 {
94    Evas_Object_List *l;
95
96    if (!name) return NULL;
97    for (l = fonts_src; l; l = l->next)
98      {
99         RGBA_Font_Source *fs;
100
101         fs = (RGBA_Font_Source *)l;
102         if ((fs->name) && (!strcmp(name, fs->name)))
103           {
104              fs->references++;
105              fonts_src = evas_object_list_remove(fonts_src, fs);
106              fonts_src = evas_object_list_prepend(fonts_src, fs);
107              return fs;
108           }
109      }
110    return NULL;
111 }
112
113 EAPI void
114 evas_common_font_source_free(RGBA_Font_Source *fs)
115 {
116    fs->references--;
117    if (fs->references > 0) return;
118
119    fonts_src = evas_object_list_remove(fonts_src, fs);
120    FT_Done_Face(fs->ft.face);
121    if (fs->charmap) evas_array_hash_free(fs->charmap);
122    if (fs->name) evas_stringshare_del(fs->name);
123    free(fs);
124 }
125
126 EAPI void
127 evas_common_font_size_use(RGBA_Font *fn)
128 {
129    Evas_List *l;
130
131    for (l = fn->fonts; l; l = l->next)
132      {
133         RGBA_Font_Int *fi;
134
135         fi = l->data;
136
137         if (fi->src->current_size != fi->size)
138           {
139              FT_Activate_Size(fi->ft.size);
140              fi->src->current_size = fi->size;
141           }
142      }
143 }
144
145 EAPI RGBA_Font_Int *
146 evas_common_font_int_memory_load(const char *name, int size, const void *data, int data_size)
147 {
148    RGBA_Font_Int *fi;
149
150    fi = evas_common_font_int_find(name, size);
151    if (fi) return fi;
152
153    fi = calloc(1, sizeof(RGBA_Font_Int));
154    if (!fi) return NULL;
155
156    fi->src = evas_common_font_source_find(name);
157    if (!fi->src)
158      fi->src = evas_common_font_source_memory_load(name, data, data_size);
159
160    if (!fi->src)
161      {
162         free(fi);
163         return NULL;
164      }
165
166    fi->size = size;
167
168    fi = evas_common_font_int_load_init(fi);
169    evas_common_font_int_load_complete(fi);
170
171    return fi;
172 }
173
174 EAPI RGBA_Font_Int *
175 evas_common_font_int_load(const char *name, int size)
176 {
177    RGBA_Font_Int *fi;
178
179    fi = evas_common_font_int_find(name, size);
180    if (fi) return fi;
181
182    fi = calloc(1, sizeof(RGBA_Font_Int));
183    if (!fi) return NULL;
184
185    fi->src = evas_common_font_source_find(name);
186    if (!fi->src && evas_file_path_is_file(name))
187      fi->src = evas_common_font_source_load(name);
188
189    if (!fi->src)
190      {
191         free(fi);
192         return NULL;
193      }
194
195    fi->size = size;
196
197    return evas_common_font_int_load_init(fi);
198 }
199
200 EAPI RGBA_Font_Int *
201 evas_common_font_int_load_init(RGBA_Font_Int *fi)
202 {
203    fi->ft.size = NULL;
204    fi->glyphs = NULL;
205    fi->usage = 0;
206    fi->references = 1;
207    fonts = evas_object_list_prepend(fonts, fi);
208    return fi;
209 }
210
211 EAPI RGBA_Font_Int *
212 evas_common_font_int_load_complete(RGBA_Font_Int *fi)
213 {
214    int error;
215
216    error = FT_New_Size(fi->src->ft.face, &(fi->ft.size));
217    if (!error)
218      {
219         FT_Activate_Size(fi->ft.size);
220      }
221    fi->real_size = fi->size * 64;
222    error = FT_Set_Char_Size(fi->src->ft.face, 0, fi->real_size, 75, 75);
223    if (error)
224      {
225         fi->real_size = fi->size;
226         error = FT_Set_Pixel_Sizes(fi->src->ft.face, 0, fi->real_size);
227      }
228    if (error)
229      {
230         int i;
231         int chosen_size = 0;
232         int chosen_width = 0;
233
234         for (i = 0; i < fi->src->ft.face->num_fixed_sizes; i++)
235           {
236              int s;
237              int d, cd;
238
239              s = fi->src->ft.face->available_sizes[i].height;
240              cd = chosen_size - fi->size;
241              if (cd < 0) cd = -cd;
242              d = s - fi->size;
243              if (d < 0) d = -d;
244              if (d < cd)
245                {
246                   chosen_width = fi->src->ft.face->available_sizes[i].width;
247                   chosen_size = s;
248                }
249              if (d == 0) break;
250           }
251         fi->real_size = chosen_size;
252         error = FT_Set_Pixel_Sizes(fi->src->ft.face, chosen_width, fi->real_size);
253         if (error)
254           {
255              /* couldn't choose the size anyway... what now? */
256           }
257      }
258    fi->src->current_size = fi->size;
259
260    return fi;
261 }
262
263 EAPI RGBA_Font *
264 evas_common_font_memory_load(const char *name, int size, const void *data, int data_size)
265 {
266    RGBA_Font *fn;
267    RGBA_Font_Int *fi;
268
269    fi = evas_common_font_int_memory_load(name, size, data, data_size);
270    if (!fi) return NULL;
271    fn = calloc(1, sizeof(RGBA_Font));
272    if (!fn)
273      {
274         free(fi);
275         return NULL;
276      }
277    fn->fonts = evas_list_append(fn->fonts, fi);
278    fn->hinting = FONT_BYTECODE_HINT;
279    fi->hinting = fn->hinting;
280    fn->references = 1;
281    LKI(fn->lock);
282    return fn;
283 }
284
285 EAPI RGBA_Font *
286 evas_common_font_load(const char *name, int size)
287 {
288    RGBA_Font *fn;
289    RGBA_Font_Int *fi;
290
291    fi = evas_common_font_int_load(name, size);
292    if (!fi) return NULL;
293
294    /* First font, complete load */
295    if (!fi->ft.size)
296      {
297         if (!fi->src->ft.face)
298           {
299              if (evas_common_font_source_load_complete(fi->src))
300                {
301                   fi->references--;
302                   if (fi->references == 0)
303                     {
304                        evas_common_font_int_modify_cache_by(fi, 1);
305                        evas_common_font_flush();
306                     }
307                   return NULL;
308                }
309           }
310         evas_common_font_int_load_complete(fi);
311      }
312
313    fn = calloc(1, sizeof(RGBA_Font));
314    if (!fn)
315      {
316         fi->references--;
317         if (fi->references == 0)
318           {
319              evas_common_font_int_modify_cache_by(fi, 1);
320              evas_common_font_flush();
321           }
322         return NULL;
323      }
324    fn->fonts = evas_list_append(fn->fonts, fi);
325    fn->hinting = FONT_BYTECODE_HINT;
326    fi->hinting = fn->hinting;
327    fn->references = 1;
328    LKI(fn->lock);
329    return fn;
330 }
331
332 EAPI RGBA_Font *
333 evas_common_font_add(RGBA_Font *fn, const char *name, int size)
334 {
335    RGBA_Font_Int *fi;
336
337    if (!fn)
338       return NULL;
339    fi = evas_common_font_int_load(name, size);
340    if (fi)
341      {
342         fn->fonts = evas_list_append(fn->fonts, fi);
343         fi->hinting = fn->hinting;
344         return fn;
345      }
346    return NULL;
347 }
348
349 EAPI RGBA_Font *
350 evas_common_font_memory_add(RGBA_Font *fn, const char *name, int size, const void *data, int data_size)
351 {
352    RGBA_Font_Int *fi;
353
354    if (!fn)
355       return NULL;
356    fi = evas_common_font_int_memory_load(name, size, data, data_size);
357    if (fi)
358      {
359         fn->fonts = evas_list_append(fn->fonts, fi);
360         fi->hinting = fn->hinting;
361         return fn;
362      }
363    return NULL;
364 }
365
366 EAPI void
367 evas_common_font_free(RGBA_Font *fn)
368 {
369    Evas_List *l;
370
371    if (!fn)
372       return;
373    fn->references--;
374    if (fn->references > 0) return;
375    for (l = fn->fonts; l; l = l->next)
376      {
377         RGBA_Font_Int *fi;
378
379         fi = l->data;
380         fi->references--;
381         if (fi->references == 0)
382           {
383              evas_common_font_int_modify_cache_by(fi, 1);
384              evas_common_font_flush();
385           }
386      }
387    evas_list_free(fn->fonts);
388    LKD(fn->lock);
389    free(fn);
390 }
391
392 EAPI void
393 evas_common_font_hinting_set(RGBA_Font *fn, Font_Hint_Flags hinting)
394 {
395    Evas_List *l;
396
397    if (!fn)
398      return;
399    fn->hinting = hinting;
400    for (l = fn->fonts; l; l = l->next)
401      {
402         RGBA_Font_Int *fi;
403
404         fi = l->data;
405         fi->hinting = fn->hinting;
406      }
407 }
408
409 EAPI Evas_Bool
410 evas_common_hinting_available(Font_Hint_Flags hinting)
411 {
412    switch (hinting)
413      {
414       case FONT_NO_HINT:
415       case FONT_AUTO_HINT:
416          /* these two hinting modes are always available */
417          return 1;
418       case FONT_BYTECODE_HINT:
419          /* Only use the bytecode interpreter if support for the _patented_
420           * algorithms is available because the free bytecode
421           * interpreter's results are too crappy.
422           *
423           * On freetyp 2.2+, we can ask the library about support for
424           * the patented interpreter. On older versions, we need to use
425           * macros to check for it.
426           */
427 #if FREETYPE_MINOR >= 2
428          return FT_Get_TrueType_Engine_Type(evas_ft_lib) >=
429                 FT_TRUETYPE_ENGINE_TYPE_PATENTED;
430 #else
431          /* we may not rely on TT_CONFIG_OPTION_BYTECODE_INTERPRETER
432           * here to find out whether it's supported.
433           *
434           * so, assume it is. o_O
435           */
436          return 1;
437 #endif
438      }
439
440    /* shouldn't get here - need to add another case statement */
441    return 0;
442 }
443
444 EAPI RGBA_Font *
445 evas_common_font_memory_hinting_load(const char *name, int size, const void *data, int data_size, Font_Hint_Flags hinting)
446 {
447    RGBA_Font *fn;
448
449    fn = evas_common_font_memory_load(name, size, data, data_size);
450    if (fn) evas_common_font_hinting_set(fn, hinting);
451    return fn;
452 }
453
454 EAPI RGBA_Font *
455 evas_common_font_hinting_load(const char *name, int size, Font_Hint_Flags hinting)
456 {
457    RGBA_Font *fn;
458
459    fn = evas_common_font_load(name, size);
460    if (fn) evas_common_font_hinting_set(fn, hinting);
461    return fn;
462 }
463
464 EAPI RGBA_Font *
465 evas_common_font_hinting_add(RGBA_Font *fn, const char *name, int size, Font_Hint_Flags hinting)
466 {
467    fn = evas_common_font_add(fn, name, size);
468    if (fn) evas_common_font_hinting_set(fn, hinting);
469    return fn;
470 }
471
472 EAPI RGBA_Font *
473 evas_common_font_memory_hinting_add(RGBA_Font *fn, const char *name, int size, const void *data, int data_size, Font_Hint_Flags hinting)
474 {
475    fn = evas_common_font_memory_add(fn, name, size, data, data_size);
476    if (fn) evas_common_font_hinting_set(fn, hinting);
477    return fn;
478 }
479
480 static Evas_Bool
481 font_modify_cache_cb(const Evas_Hash *hash, const char *key, void *data, void *fdata)
482 {
483    int *dir;
484    RGBA_Font_Glyph *fg;
485
486    fg = data;
487    dir = fdata;
488    font_cache_usage += (*dir) *
489      ((fg->glyph_out->bitmap.width * fg->glyph_out->bitmap.rows) +
490       sizeof(RGBA_Font_Glyph) + sizeof(Evas_List) + 400); /* fudge values */
491    return 1;
492    hash = 0;
493    key = 0;
494 }
495
496 /* when the fi->references == 0 we increase this instead of really deleting
497  * we then check if the cache_useage size is larger than allowed
498  * !If the cache is NOT too large we dont delete font_int
499  * !If the cache is too large we really delete font_int */
500 EAPI void
501 evas_common_font_int_modify_cache_by(RGBA_Font_Int *fi, int dir)
502 {
503    int sz_hash = 0;
504
505    if (fi->glyphs) sz_hash = sizeof(Evas_Hash);
506    evas_hash_foreach(fi->glyphs, font_modify_cache_cb, &dir);
507    font_cache_usage += dir * (sizeof(RGBA_Font) + sz_hash +
508                               sizeof(FT_FaceRec) + 16384); /* fudge values */
509 }
510
511 EAPI int
512 evas_common_font_cache_get(void)
513 {
514    return font_cache;
515 }
516
517 EAPI void
518 evas_common_font_cache_set(int size)
519 {
520    font_cache = size;
521    evas_common_font_flush();
522 }
523
524 EAPI void
525 evas_common_font_flush(void)
526 {
527    if (font_cache_usage < font_cache) return;
528    while (font_cache_usage > font_cache) evas_common_font_flush_last();
529 }
530
531 static Evas_Bool
532 font_flush_free_glyph_cb(const Evas_Hash *hash, const char *key, void *data, void *fdata)
533 {
534    RGBA_Font_Glyph *fg;
535
536    fg = data;
537    FT_Done_Glyph(fg->glyph);
538    /* extension calls */
539    if (fg->ext_dat_free) fg->ext_dat_free(fg->ext_dat);
540    free(fg);
541    return 1;
542    hash = 0;
543    key = 0;
544    fdata = 0;
545 }
546
547 /* We run this when the cache gets larger than allowed size
548  * We check cache size each time a fi->references goes to 0
549  * PERFORMS: Find font_int(s) with references == 0 and delete them */
550 EAPI void
551 evas_common_font_flush_last(void)
552 {
553    Evas_Object_List *l;
554    RGBA_Font_Int *fi = NULL;
555
556    for (l = fonts; l; l = l->next)
557      {
558         RGBA_Font_Int *fi_tmp;
559
560         fi_tmp = (RGBA_Font_Int *)l;
561         if (fi_tmp->references == 0) fi = fi_tmp;
562      }
563    if (!fi) return;
564
565    FT_Done_Size(fi->ft.size);
566
567    fonts = evas_object_list_remove(fonts, fi);
568    evas_common_font_int_modify_cache_by(fi, -1);
569
570    evas_hash_foreach(fi->glyphs, font_flush_free_glyph_cb, NULL);
571    evas_hash_free(fi->glyphs);
572
573    evas_common_font_source_free(fi->src);
574
575    free(fi);
576 }
577
578 EAPI RGBA_Font_Int *
579 evas_common_font_int_find(const char *name, int size)
580 {
581    Evas_Object_List *l;
582
583    for (l = fonts; l; l = l->next)
584      {
585         RGBA_Font_Int *fi;
586
587         fi = (RGBA_Font_Int *)l;
588         if ((fi->size == size) && (!strcmp(name, fi->src->name)))
589           {
590              if (fi->references == 0) evas_common_font_int_modify_cache_by(fi, -1);
591              fi->references++;
592              fonts = evas_object_list_remove(fonts, fi);
593              fonts = evas_object_list_prepend(fonts, fi);
594              return fi;
595           }
596      }
597    return NULL;
598 }