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