aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/evas/src/lib/engines/common/evas_font_load.c
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/evas/src/lib/engines/common/evas_font_load.c')
-rw-r--r--libraries/evas/src/lib/engines/common/evas_font_load.c929
1 files changed, 929 insertions, 0 deletions
diff --git a/libraries/evas/src/lib/engines/common/evas_font_load.c b/libraries/evas/src/lib/engines/common/evas_font_load.c
new file mode 100644
index 0000000..3fc4521
--- /dev/null
+++ b/libraries/evas/src/lib/engines/common/evas_font_load.c
@@ -0,0 +1,929 @@
1#include "evas_common.h"
2#include "evas_private.h"
3
4#include <assert.h>
5
6#include "evas_font_private.h" /* for Frame-Queuing support */
7#include "evas_font_ot.h"
8
9#ifdef USE_HARFBUZZ
10# include <hb.h>
11# include <hb-ft.h>
12#endif
13
14extern FT_Library evas_ft_lib;
15
16static int font_cache_usage = 0;
17static int font_cache = 0;
18static int font_dpi = 75;
19
20static Eina_Hash *fonts_src = NULL;
21static Eina_Hash *fonts = NULL;
22static Eina_List *fonts_lru = NULL;
23static Eina_Inlist *fonts_use_lru = NULL;
24static int fonts_use_usage = 0;
25
26static void _evas_common_font_int_clear(RGBA_Font_Int *fi);
27
28static int
29_evas_font_cache_int_cmp(const RGBA_Font_Int *k1, int k1_length __UNUSED__,
30 const RGBA_Font_Int *k2, int k2_length __UNUSED__)
31{
32 /* RGBA_Font_Source->name is a stringshare */
33 if (k1->src->name == k2->src->name)
34 {
35 if (k1->size == k2->size)
36 return k1->wanted_rend - k2->wanted_rend;
37 else
38 return k1->size - k2->size;
39 }
40 return strcmp(k1->src->name, k2->src->name);
41}
42
43static int
44_evas_font_cache_int_hash(const RGBA_Font_Int *key, int key_length __UNUSED__)
45{
46 int hash;
47 unsigned int wanted_rend = key->wanted_rend;
48 hash = eina_hash_djb2(key->src->name, eina_stringshare_strlen(key->src->name) + 1);
49 hash ^= eina_hash_int32(&key->size, sizeof (int));
50 hash ^= eina_hash_int32(&wanted_rend, sizeof (int));
51 return hash;
52}
53
54static void
55_evas_common_font_source_free(RGBA_Font_Source *fs)
56{
57 FTLOCK();
58 FT_Done_Face(fs->ft.face);
59 FTUNLOCK();
60 if (fs->name) eina_stringshare_del(fs->name);
61 if (fs->file) eina_stringshare_del(fs->file);
62 free(fs);
63}
64
65static void
66_evas_common_font_int_free(RGBA_Font_Int *fi)
67{
68 FT_Done_Size(fi->ft.size);
69
70 evas_common_font_int_modify_cache_by(fi, -1);
71 _evas_common_font_int_clear(fi);
72 eina_hash_free(fi->kerning);
73
74#ifdef HAVE_PTHREAD
75 pthread_mutex_destroy(&fi->ft_mutex);
76#endif
77#ifdef USE_HARFBUZZ
78 hb_font_destroy(fi->ft.hb_font);
79#endif
80 evas_common_font_source_free(fi->src);
81 if (fi->references == 0) fonts_lru = eina_list_remove(fonts_lru, fi);
82 if (fi->fash) fi->fash->freeme(fi->fash);
83 if (fi->inuse)
84 {
85 fonts_use_lru = eina_inlist_remove(fonts_use_lru, EINA_INLIST_GET(fi));
86 fi->inuse = 0;
87 fonts_use_usage -= fi->usage;
88 fi->usage = 0;
89 }
90 free(fi);
91}
92
93void
94evas_common_font_load_init(void)
95{
96 fonts_src = eina_hash_string_small_new(EINA_FREE_CB(_evas_common_font_source_free));
97 fonts = eina_hash_new(NULL,
98 EINA_KEY_CMP(_evas_font_cache_int_cmp),
99 EINA_KEY_HASH(_evas_font_cache_int_hash),
100 EINA_FREE_CB(_evas_common_font_int_free),
101 5);
102}
103
104void
105evas_common_font_load_shutdown(void)
106{
107 eina_hash_free(fonts);
108 fonts = NULL;
109 eina_hash_free(fonts_src);
110 fonts_src = NULL;
111}
112
113EAPI void
114evas_common_font_dpi_set(int dpi)
115{
116 font_dpi = dpi;
117}
118
119EAPI RGBA_Font_Source *
120evas_common_font_source_memory_load(const char *name, const void *data, int data_size)
121{
122 int error;
123 RGBA_Font_Source *fs;
124
125 assert(name != NULL);
126 fs = calloc(1, sizeof(RGBA_Font_Source) + data_size);
127 if (!fs) return NULL;
128 fs->data = ((unsigned char *)fs) + sizeof(RGBA_Font_Source);
129 fs->data_size = data_size;
130 fs->current_size = 0;
131 memcpy(fs->data, data, data_size);
132 FTLOCK();
133 error = FT_New_Memory_Face(evas_ft_lib, fs->data, fs->data_size, 0, &(fs->ft.face));
134 FTUNLOCK();
135 if (error)
136 {
137 free(fs);
138 return NULL;
139 }
140 fs->name = eina_stringshare_add(name);
141 fs->file = NULL;
142 FTLOCK();
143 error = FT_Select_Charmap(fs->ft.face, ft_encoding_unicode);
144 if (error)
145 {
146 FT_Done_Face(fs->ft.face);
147 fs->ft.face = NULL;
148 free(fs);
149 return NULL;
150 }
151 FTUNLOCK();
152 fs->ft.orig_upem = fs->ft.face->units_per_EM;
153 fs->references = 1;
154 eina_hash_direct_add(fonts_src, fs->name, fs);
155 return fs;
156}
157
158EAPI RGBA_Font_Source *
159evas_common_font_source_load(const char *name)
160{
161 RGBA_Font_Source *fs;
162
163 assert(name != NULL);
164 fs = calloc(1, sizeof(RGBA_Font_Source));
165 if (!fs) return NULL;
166 fs->data = NULL;
167 fs->data_size = 0;
168 fs->current_size = 0;
169 fs->ft.face = NULL;
170 fs->name = eina_stringshare_add(name);
171 fs->file = eina_stringshare_ref(fs->name);
172 fs->ft.orig_upem = 0;
173 fs->references = 1;
174 eina_hash_direct_add(fonts_src, fs->name, fs);
175 return fs;
176}
177
178void
179evas_common_font_source_unload(RGBA_Font_Source *fs)
180{
181 FTLOCK();
182 FT_Done_Face(fs->ft.face);
183 fs->ft.face = NULL;
184 FTUNLOCK();
185}
186
187void
188evas_common_font_source_reload(RGBA_Font_Source *fs)
189{
190 if (fs->ft.face) return;
191 if (fs->data)
192 {
193 int error;
194
195 FTLOCK();
196 error = FT_New_Memory_Face(evas_ft_lib, fs->data, fs->data_size, 0, &(fs->ft.face));
197 FTUNLOCK();
198 if (error) return;
199 FTLOCK();
200 error = FT_Select_Charmap(fs->ft.face, ft_encoding_unicode);
201 if (error)
202 {
203 FT_Done_Face(fs->ft.face);
204 fs->ft.face = NULL;
205 }
206 FTUNLOCK();
207 }
208 else
209 evas_common_font_source_load_complete(fs);
210}
211
212EAPI int
213evas_common_font_source_load_complete(RGBA_Font_Source *fs)
214{
215 int error;
216
217 FTLOCK();
218 error = FT_New_Face(evas_ft_lib, fs->file, 0, &(fs->ft.face));
219 if (error)
220 {
221 FTUNLOCK();
222 fs->ft.face = NULL;
223 return error;
224 }
225 error = FT_Select_Charmap(fs->ft.face, ft_encoding_unicode);
226 if (error)
227 {
228 FT_Done_Face(fs->ft.face);
229 FTUNLOCK();
230 fs->ft.face = NULL;
231 return error;
232 }
233 FTUNLOCK();
234 fs->ft.orig_upem = fs->ft.face->units_per_EM;
235 return error;
236}
237
238EAPI RGBA_Font_Source *
239evas_common_font_source_find(const char *name)
240{
241 RGBA_Font_Source *fs;
242
243 if (!name) return NULL;
244 fs = eina_hash_find(fonts_src, name);
245 if (fs)
246 {
247 fs->references++;
248 return fs;
249 }
250 return NULL;
251}
252
253EAPI void
254evas_common_font_source_free(RGBA_Font_Source *fs)
255{
256 fs->references--;
257 if (fs->references > 0) return;
258 eina_hash_del(fonts_src, fs->name, fs);
259}
260
261EAPI void
262evas_common_font_size_use(RGBA_Font *fn)
263{
264 RGBA_Font_Int *fi;
265 Eina_List *l;
266
267 EINA_LIST_FOREACH(fn->fonts, l, fi)
268 {
269 if (fi->src->current_size != fi->size)
270 {
271 evas_common_font_source_reload(fi->src);
272 FTLOCK();
273 FT_Activate_Size(fi->ft.size);
274 FTUNLOCK();
275 fi->src->current_size = fi->size;
276 }
277 }
278}
279
280static int
281_evas_common_font_double_int_cmp(const int *key1, __UNUSED__ int key1_length,
282 const int *key2, __UNUSED__ int key2_length)
283{
284 if (key1[0] - key2[0] == 0) return key1[1] - key2[1];
285 return key1[0] - key2[0];
286}
287
288static int
289_evas_common_font_double_int_hash(const unsigned int key[2], int key_length)
290{
291 return
292 eina_hash_int32(&key[0], key_length) ^
293 eina_hash_int32(&key[1], key_length);
294}
295
296static void
297_evas_common_font_int_cache_init(RGBA_Font_Int *fi)
298{
299 /* Add some font kerning cache. */
300 fi->kerning = eina_hash_new(NULL,
301 EINA_KEY_CMP(_evas_common_font_double_int_cmp),
302 EINA_KEY_HASH(_evas_common_font_double_int_hash),
303 free, 3);
304#ifdef HAVE_PTHREAD
305 pthread_mutex_init(&fi->ft_mutex, NULL);
306#endif
307}
308
309EAPI RGBA_Font_Int *
310evas_common_font_int_memory_load(const char *name, int size, const void *data, int data_size, Font_Rend_Flags wanted_rend)
311{
312 RGBA_Font_Int *fi;
313
314 fi = evas_common_font_int_find(name, size, wanted_rend);
315 if (fi) return fi;
316 fi = calloc(1, sizeof(RGBA_Font_Int));
317 if (!fi) return NULL;
318 fi->src = evas_common_font_source_find(name);
319 if (!fi->src)
320 fi->src = evas_common_font_source_memory_load(name, data, data_size);
321 if (!fi->src)
322 {
323 free(fi);
324 return NULL;
325 }
326 fi->size = size;
327 _evas_common_font_int_cache_init(fi);
328 fi = evas_common_font_int_load_init(fi);
329 evas_common_font_int_load_complete(fi);
330 return fi;
331}
332
333EAPI RGBA_Font_Int *
334evas_common_font_int_load(const char *name, int size,
335 Font_Rend_Flags wanted_rend)
336{
337 RGBA_Font_Int *fi;
338
339 fi = evas_common_font_int_find(name, size, wanted_rend);
340 if (fi) return fi;
341 fi = calloc(1, sizeof(RGBA_Font_Int));
342 if (!fi) return NULL;
343 fi->src = evas_common_font_source_find(name);
344 if (!fi->src && evas_file_path_is_file(name))
345 fi->src = evas_common_font_source_load(name);
346
347 if (!fi->src)
348 {
349 free(fi);
350 return NULL;
351 }
352 fi->size = size;
353 fi->wanted_rend = wanted_rend;
354 _evas_common_font_int_cache_init(fi);
355 fi = evas_common_font_int_load_init(fi);
356// evas_common_font_int_load_complete(fi);
357 return fi;
358}
359
360EAPI RGBA_Font_Int *
361evas_common_font_int_load_init(RGBA_Font_Int *fi)
362{
363 fi->ft.size = NULL;
364 fi->references = 1;
365 eina_hash_direct_add(fonts, fi, fi);
366 return fi;
367}
368
369EAPI RGBA_Font_Int *
370evas_common_font_int_load_complete(RGBA_Font_Int *fi)
371{
372 int val, dv;
373 int ret;
374 int error;
375
376 FTLOCK();
377 error = FT_New_Size(fi->src->ft.face, &(fi->ft.size));
378 if (!error)
379 {
380 FT_Activate_Size(fi->ft.size);
381 }
382 fi->real_size = fi->size * 64;
383 error = FT_Set_Char_Size(fi->src->ft.face, 0, fi->real_size, font_dpi, font_dpi);
384 if (error)
385 {
386 fi->real_size = fi->size;
387 error = FT_Set_Pixel_Sizes(fi->src->ft.face, 0, fi->real_size);
388 }
389 FTUNLOCK();
390 if (error)
391 {
392 int i;
393 int chosen_size = 0;
394 int chosen_width = 0;
395
396 for (i = 0; i < fi->src->ft.face->num_fixed_sizes; i++)
397 {
398 int s;
399 int d, cd;
400
401 s = fi->src->ft.face->available_sizes[i].height;
402 cd = chosen_size - fi->size;
403 if (cd < 0) cd = -cd;
404 d = s - fi->size;
405 if (d < 0) d = -d;
406 if (d < cd)
407 {
408 chosen_width = fi->src->ft.face->available_sizes[i].width;
409 chosen_size = s;
410 }
411 if (d == 0) break;
412 }
413 fi->real_size = chosen_size;
414 FTLOCK();
415 error = FT_Set_Pixel_Sizes(fi->src->ft.face, chosen_width, fi->real_size);
416 FTUNLOCK();
417 if (error)
418 {
419 /* couldn't choose the size anyway... what now? */
420 }
421 }
422 fi->src->current_size = 0;
423 fi->max_h = 0;
424 val = (int)fi->src->ft.face->bbox.yMax;
425 if (fi->src->ft.face->units_per_EM != 0)
426 {
427 dv = (fi->src->ft.orig_upem * 2048) / fi->src->ft.face->units_per_EM;
428 ret = (val * fi->src->ft.face->size->metrics.y_scale) / (dv * dv);
429 }
430 else ret = val;
431 fi->max_h += ret;
432 val = -(int)fi->src->ft.face->bbox.yMin;
433 if (fi->src->ft.face->units_per_EM != 0)
434 {
435 dv = (fi->src->ft.orig_upem * 2048) / fi->src->ft.face->units_per_EM;
436 ret = (val * fi->src->ft.face->size->metrics.y_scale) / (dv * dv);
437 }
438 else ret = val;
439 fi->max_h += ret;
440
441 /* If the loaded font doesn't match with wanted_rend value requested by
442 * textobject and textblock, Set the runtime_rend value as FONT_REND_SLANT
443 * or FONT_REND_WEIGHT for software rendering. */
444 fi->runtime_rend = FONT_REND_REGULAR;
445 if ((fi->wanted_rend & FONT_REND_SLANT) &&
446 !(fi->src->ft.face->style_flags & FT_STYLE_FLAG_ITALIC))
447 fi->runtime_rend |= FONT_REND_SLANT;
448
449 if ((fi->wanted_rend & FONT_REND_WEIGHT) &&
450 !(fi->src->ft.face->style_flags & FT_STYLE_FLAG_BOLD))
451 fi->runtime_rend |= FONT_REND_WEIGHT;
452
453 return fi;
454}
455
456EAPI RGBA_Font *
457evas_common_font_memory_load(const char *name, int size, const void *data, int data_size, Font_Rend_Flags wanted_rend)
458{
459 RGBA_Font *fn;
460 RGBA_Font_Int *fi;
461
462 fi = evas_common_font_int_memory_load(name, size, data, data_size,
463 wanted_rend);
464 if (!fi) return NULL;
465 fn = calloc(1, sizeof(RGBA_Font));
466 if (!fn)
467 {
468 fi->references--;
469 if (fi->references == 0)
470 {
471 fonts_lru = eina_list_prepend(fonts_lru, fi);
472 evas_common_font_int_modify_cache_by(fi, 1);
473 evas_common_font_flush();
474 }
475 return NULL;
476 }
477 fn->fonts = eina_list_append(fn->fonts, fi);
478 fn->hinting = FONT_BYTECODE_HINT;
479 fi->hinting = fn->hinting;
480 fn->references = 1;
481 LKI(fn->lock);
482#ifdef EVAS_FRAME_QUEUING
483 LKI(fn->ref_fq_add);
484 LKI(fn->ref_fq_del);
485 eina_condition_new(&(fn->cond_fq_del), &(fn->ref_fq_del));
486#endif
487 if (fi->inuse) evas_common_font_int_promote(fi);
488 else
489 {
490 fi->inuse = 1;
491 fonts_use_lru = eina_inlist_prepend(fonts_use_lru, EINA_INLIST_GET(fi));
492 }
493 return fn;
494}
495
496
497//ZZZ: font struct looks like:
498// fn->(fi, fi, fi, ...)
499// fi->fs
500
501EAPI RGBA_Font *
502evas_common_font_load(const char *name, int size, Font_Rend_Flags wanted_rend)
503{
504 RGBA_Font *fn;
505 RGBA_Font_Int *fi;
506
507 fi = evas_common_font_int_load(name, size, wanted_rend);
508 if (!fi) return NULL;
509 /* First font, complete load */
510 if (!fi->ft.size)
511 {
512 if (!fi->src->ft.face)
513 {
514 if (evas_common_font_source_load_complete(fi->src))
515 {
516 fi->references--;
517 if (fi->references == 0)
518 {
519 fonts_lru = eina_list_prepend(fonts_lru, fi);
520 evas_common_font_int_modify_cache_by(fi, 1);
521 evas_common_font_flush();
522 }
523 return NULL;
524 }
525 }
526 evas_common_font_int_load_complete(fi);
527 }
528 fn = calloc(1, sizeof(RGBA_Font));
529 if (!fn)
530 {
531 fi->references--;
532 if (fi->references == 0)
533 {
534 fonts_lru = eina_list_prepend(fonts_lru, fi);
535 evas_common_font_int_modify_cache_by(fi, 1);
536 evas_common_font_flush();
537 }
538 return NULL;
539 }
540
541 fn->fonts = eina_list_append(fn->fonts, fi);
542 fn->hinting = FONT_BYTECODE_HINT;
543 fi->hinting = fn->hinting;
544 fn->references = 1;
545 LKI(fn->lock);
546#ifdef EVAS_FRAME_QUEUING
547 LKI(fn->ref_fq_add);
548 LKI(fn->ref_fq_del);
549 eina_condition_new(&(fn->cond_fq_del), &(fn->ref_fq_del));
550#endif
551 if (fi->inuse) evas_common_font_int_promote(fi);
552 else
553 {
554 fi->inuse = 1;
555 fonts_use_lru = eina_inlist_prepend(fonts_use_lru, EINA_INLIST_GET(fi));
556 }
557 return fn;
558}
559
560EAPI RGBA_Font *
561evas_common_font_add(RGBA_Font *fn, const char *name, int size, Font_Rend_Flags wanted_rend)
562{
563 RGBA_Font_Int *fi;
564
565 if (!fn) return NULL;
566 fi = evas_common_font_int_load(name, size, wanted_rend);
567 if (fi)
568 {
569 fn->fonts = eina_list_append(fn->fonts, fi);
570 fi->hinting = fn->hinting;
571 if (fi->inuse) evas_common_font_int_promote(fi);
572 else
573 {
574 fi->inuse = 1;
575 fonts_use_lru = eina_inlist_prepend(fonts_use_lru, EINA_INLIST_GET(fi));
576 }
577 return fn;
578 }
579 return NULL;
580}
581
582EAPI RGBA_Font *
583evas_common_font_memory_add(RGBA_Font *fn, const char *name, int size, const void *data, int data_size, Font_Rend_Flags wanted_rend)
584{
585 RGBA_Font_Int *fi;
586
587 if (!fn)
588 return NULL;
589 fi = evas_common_font_int_memory_load(name, size, data, data_size, wanted_rend);
590 if (fi)
591 {
592 fn->fonts = eina_list_append(fn->fonts, fi);
593 fi->hinting = fn->hinting;
594 if (fi->inuse) evas_common_font_int_promote(fi);
595 else
596 {
597 fi->inuse = 1;
598 fonts_use_lru = eina_inlist_prepend(fonts_use_lru, EINA_INLIST_GET(fi));
599 }
600 return fn;
601 }
602 return NULL;
603}
604
605EAPI void
606evas_common_font_free(RGBA_Font *fn)
607{
608 Eina_List *l;
609 RGBA_Font_Int *fi;
610
611 if (!fn) return;
612 fn->references--;
613 if (fn->references > 0) return;
614#ifdef EVAS_FRAME_QUEUING
615 LKL(fn->ref_fq_add);
616 LKL(fn->ref_fq_del);
617 if (fn->ref_fq[0] != fn->ref_fq[1])
618 {
619 LKU(fn->ref_fq_add);
620 LKU(fn->ref_fq_del);
621 return;
622 }
623 LKU(fn->ref_fq_add);
624 LKU(fn->ref_fq_del);
625#endif
626 EINA_LIST_FOREACH(fn->fonts, l, fi)
627 {
628 fi->references--;
629 if (fi->references == 0)
630 {
631 fonts_lru = eina_list_append(fonts_lru, fi);
632 evas_common_font_int_modify_cache_by(fi, 1);
633 }
634 }
635 evas_common_font_flush();
636 eina_list_free(fn->fonts);
637 if (fn->fash) fn->fash->freeme(fn->fash);
638 LKD(fn->lock);
639#ifdef EVAS_FRAME_QUEUING
640 LKD(fn->ref_fq_add);
641 LKD(fn->ref_fq_del);
642 eina_condition_free(&(fn->cond_fq_del));
643#endif
644 free(fn);
645}
646
647EAPI void
648evas_common_font_hinting_set(RGBA_Font *fn, Font_Hint_Flags hinting)
649{
650 Eina_List *l;
651 RGBA_Font_Int *fi;
652
653 if (!fn) return;
654 fn->hinting = hinting;
655 EINA_LIST_FOREACH(fn->fonts, l, fi)
656 {
657 fi->hinting = fn->hinting;
658 }
659}
660
661EAPI Eina_Bool
662evas_common_hinting_available(Font_Hint_Flags hinting)
663{
664 switch (hinting)
665 {
666 case FONT_NO_HINT:
667 case FONT_AUTO_HINT:
668 /* these two hinting modes are always available */
669 return EINA_TRUE;
670 case FONT_BYTECODE_HINT:
671 /* Only use the bytecode interpreter if support for the _patented_
672 * algorithms is available because the free bytecode
673 * interpreter's results are too crappy.
674 *
675 * On freetyp 2.2+, we can ask the library about support for
676 * the patented interpreter. On older versions, we need to use
677 * macros to check for it.
678 */
679#if FREETYPE_MINOR >= 2
680 return FT_Get_TrueType_Engine_Type(evas_ft_lib) >=
681 FT_TRUETYPE_ENGINE_TYPE_PATENTED;
682#else
683 /* we may not rely on TT_CONFIG_OPTION_BYTECODE_INTERPRETER
684 * here to find out whether it's supported.
685 *
686 * so, assume it is. o_O
687 */
688 return EINA_TRUE;
689#endif
690 }
691 /* shouldn't get here - need to add another case statement */
692 return EINA_FALSE;
693}
694
695EAPI RGBA_Font *
696evas_common_font_memory_hinting_load(const char *name, int size, const void *data, int data_size, Font_Hint_Flags hinting, Font_Rend_Flags wanted_rend)
697{
698 RGBA_Font *fn;
699
700 fn = evas_common_font_memory_load(name, size, data, data_size, wanted_rend);
701 if (fn) evas_common_font_hinting_set(fn, hinting);
702 return fn;
703}
704
705EAPI RGBA_Font *
706evas_common_font_hinting_load(const char *name, int size, Font_Hint_Flags hinting, Font_Rend_Flags wanted_rend)
707{
708 RGBA_Font *fn;
709
710 fn = evas_common_font_load(name, size, wanted_rend);
711 if (fn) evas_common_font_hinting_set(fn, hinting);
712 return fn;
713}
714
715EAPI RGBA_Font *
716evas_common_font_hinting_add(RGBA_Font *fn, const char *name, int size, Font_Hint_Flags hinting, Font_Rend_Flags wanted_rend)
717{
718 fn = evas_common_font_add(fn, name, size, wanted_rend);
719 if (fn) evas_common_font_hinting_set(fn, hinting);
720 return fn;
721}
722
723EAPI RGBA_Font *
724evas_common_font_memory_hinting_add(RGBA_Font *fn, const char *name, int size, const void *data, int data_size, Font_Hint_Flags hinting, Font_Rend_Flags wanted_rend)
725{
726 fn = evas_common_font_memory_add(fn, name, size, data, data_size,
727 wanted_rend);
728 if (fn) evas_common_font_hinting_set(fn, hinting);
729 return fn;
730}
731
732static void
733_evas_common_font_int_clear(RGBA_Font_Int *fi)
734{
735 int i, j, k;
736
737 LKL(fi->ft_mutex);
738 if (!fi->fash)
739 {
740 LKU(fi->ft_mutex);
741 return;
742 }
743 evas_common_font_int_modify_cache_by(fi, -1);
744 if (fi->fash)
745 {
746 for (k = 0; k <= 0xff; k++) // 24bits for unicode - v6 up to E01EF (chrs) & 10FFFD for private use (plane 16)
747 {
748 Fash_Glyph_Map2 *fmap2 = fi->fash->bucket[k];
749 if (fmap2)
750 {
751 for (j = 0; j <= 0xff; j++) // 24bits for unicode - v6 up to E01EF (chrs) & 10FFFD for private use (plane 16)
752 {
753 Fash_Glyph_Map *fmap = fmap2->bucket[j];
754 if (fmap)
755 {
756 for (i = 0; i <= 0xff; i++)
757 {
758 RGBA_Font_Glyph *fg = fmap->item[i];
759 if ((fg) && (fg != (void *)(-1)))
760 {
761 FT_Done_Glyph(fg->glyph);
762 /* extension calls */
763 if (fg->ext_dat_free) fg->ext_dat_free(fg->ext_dat);
764 free(fg);
765 fmap->item[i] = NULL;
766 }
767 }
768 }
769 }
770 }
771 }
772 fi->fash->freeme(fi->fash);
773 fi->fash = NULL;
774 }
775 if (fi->inuse) fonts_use_usage -= fi->usage;
776 fi->usage = 0;
777 LKU(fi->ft_mutex);
778}
779
780static Eina_Bool
781_evas_common_font_all_clear_cb(const Eina_Hash *hash __UNUSED__, const void *key __UNUSED__, void *data, void *fdata __UNUSED__)
782{
783 RGBA_Font_Int *fi = data;
784 _evas_common_font_int_clear(fi);
785 return 1;
786}
787
788EAPI void
789evas_common_font_all_clear(void)
790{
791 eina_hash_foreach(fonts, _evas_common_font_all_clear_cb, NULL);
792}
793
794void
795evas_common_font_int_promote(RGBA_Font_Int *fi)
796{
797 return;
798 if (fonts_use_lru == (Eina_Inlist *)fi) return;
799 if (!fi->inuse) return;
800 fonts_use_lru = eina_inlist_remove(fonts_use_lru, EINA_INLIST_GET(fi));
801 fonts_use_lru = eina_inlist_prepend(fonts_use_lru, EINA_INLIST_GET(fi));
802}
803
804void
805evas_common_font_int_use_increase(int size)
806{
807 fonts_use_usage += size;
808}
809
810void
811evas_common_font_int_use_trim(void)
812{
813 Eina_Inlist *l;
814
815 return;
816 if (fonts_use_usage <= (font_cache << 1)) return;
817 if (!fonts_use_lru) return;
818 l = fonts_use_lru->last;
819 while (l)
820 {
821 RGBA_Font_Int *fi = (RGBA_Font_Int *)l;
822 if (fonts_use_usage <= (font_cache << 1)) break;
823 // FIXME: del fi->kerning content
824 _evas_common_font_int_clear(fi);
825 evas_common_font_int_unload(fi);
826 evas_common_font_int_promote(fi);
827 l = l->prev;
828 }
829}
830
831void
832evas_common_font_int_unload(RGBA_Font_Int *fi)
833{
834 return;
835 if (!fi->src->ft.face) return;
836 _evas_common_font_int_clear(fi);
837 FT_Done_Size(fi->ft.size);
838 fi->ft.size = NULL;
839 evas_common_font_source_unload(fi->src);
840}
841
842void
843evas_common_font_int_reload(RGBA_Font_Int *fi)
844{
845 if (fi->src->ft.face) return;
846 evas_common_font_source_load_complete(fi->src);
847 return;
848 evas_common_font_source_reload(fi->src);
849 evas_common_font_int_load_complete(fi);
850}
851
852/* when the fi->references == 0 we increase this instead of really deleting
853 * we then check if the cache_useage size is larger than allowed
854 * !If the cache is NOT too large we dont delete font_int
855 * !If the cache is too large we really delete font_int */
856EAPI void
857evas_common_font_int_modify_cache_by(RGBA_Font_Int *fi, int dir)
858{
859 font_cache_usage += dir * (sizeof(RGBA_Font) + fi->usage +
860 sizeof(FT_FaceRec) + 16384); /* fudge values */
861}
862
863EAPI int
864evas_common_font_cache_get(void)
865{
866 return font_cache;
867}
868
869EAPI void
870evas_common_font_cache_set(int size)
871{
872 font_cache = size;
873 evas_common_font_flush();
874 evas_common_font_int_use_trim();
875}
876
877EAPI void
878evas_common_font_flush(void)
879{
880 if (font_cache_usage < font_cache) return;
881 while (font_cache_usage > font_cache)
882 {
883 int pfont_cache_usage;
884
885 pfont_cache_usage = font_cache_usage;
886 evas_common_font_flush_last();
887 if (pfont_cache_usage == font_cache_usage) break;
888 }
889}
890
891/* We run this when the cache gets larger than allowed size
892 * We check cache size each time a fi->references goes to 0
893 * PERFORMS: Find font_int(s) with references == 0 and delete them */
894EAPI void
895evas_common_font_flush_last(void)
896{
897 RGBA_Font_Int *fi = NULL;
898
899 if (!fonts_lru) return ;
900 fi = eina_list_data_get(fonts_lru);
901 fonts_lru = eina_list_remove_list(fonts_lru, fonts_lru);
902 eina_hash_del(fonts, fi, fi);
903}
904
905EAPI RGBA_Font_Int *
906evas_common_font_int_find(const char *name, int size,
907 Font_Rend_Flags wanted_rend)
908{
909 RGBA_Font_Int tmp_fi;
910 RGBA_Font_Source tmp_fn;
911 RGBA_Font_Int *fi;
912
913 tmp_fn.name = (char*) eina_stringshare_add(name);
914 tmp_fi.src = &tmp_fn;
915 tmp_fi.size = size;
916 tmp_fi.wanted_rend = wanted_rend;
917 fi = eina_hash_find(fonts, &tmp_fi);
918 if (fi)
919 {
920 if (fi->references == 0)
921 {
922 evas_common_font_int_modify_cache_by(fi, -1);
923 fonts_lru = eina_list_remove(fonts_lru, fi);
924 }
925 fi->references++;
926 }
927 eina_stringshare_del(tmp_fn.name);
928 return fi;
929}