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