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