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