1 #include "evas_font_private.h"
2 #include "evas_font_draw.h"
3
4 #include FT_OUTLINE_H
5 #include FT_SYNTHESIS_H
6 #include FT_BITMAP_H
7 #include FT_TRUETYPE_DRIVER_H
8
9 FT_Library evas_ft_lib = 0;
10 static int initialised = 0;
11
12 LK(lock_font_draw); // for freetype2 API calls
13 LK(lock_bidi); // for evas bidi internal usage.
14 LK(lock_ot); // for evas bidi internal usage.
15
16 int _evas_font_log_dom_global = -1;
17 int _evas_font_texture_cache = -1;
18
19 EAPI void
evas_common_font_init(void)20 evas_common_font_init(void)
21 {
22 int error;
23 const char *s;
24 FT_UInt interpreter_version =
25 #ifndef TT_INTERPRETER_VERSION_35
26 TT_INTERPRETER_VERSION_35;
27 #else
28 35;
29 #endif
30 _evas_font_log_dom_global = eina_log_domain_register
31 ("evas_font_main", EVAS_FONT_DEFAULT_LOG_COLOR);
32 if (_evas_font_log_dom_global < 0)
33 {
34 EINA_LOG_ERR("Can not create a module log domain.");
35 }
36
37 initialised++;
38 if (initialised != 1) return;
39 error = FT_Init_FreeType(&evas_ft_lib);
40 if (error) return;
41 FT_Property_Set(evas_ft_lib, "truetype", "interpreter-version",
42 &interpreter_version);
43 evas_common_font_load_init();
44 evas_common_font_draw_init();
45 s = getenv("EVAS_FONT_DPI");
46 if (s)
47 {
48 int dpi_h = 75, dpi_v = 0;
49
50 if (sscanf(s, "%dx%d", &dpi_h, &dpi_v) < 2)
51 dpi_h = dpi_v = atoi(s);
52
53 if (dpi_h > 0) evas_common_font_dpi_set(dpi_h, dpi_v);
54 }
55 LKI(lock_font_draw);
56 LKI(lock_bidi);
57 LKI(lock_ot);
58 }
59
60 EAPI void
evas_common_font_shutdown(void)61 evas_common_font_shutdown(void)
62 {
63 if (initialised < 1) return;
64 initialised--;
65 if (initialised != 0) return;
66
67 evas_common_font_load_shutdown();
68 evas_common_font_cache_set(0);
69 evas_common_font_flush();
70
71 FT_Done_FreeType(evas_ft_lib);
72 evas_ft_lib = 0;
73
74 LKD(lock_font_draw);
75 LKD(lock_bidi);
76 LKD(lock_ot);
77 eina_log_domain_unregister(_evas_font_log_dom_global);
78 }
79
80 EAPI void
evas_common_font_font_all_unload(void)81 evas_common_font_font_all_unload(void)
82 {
83 evas_common_font_all_clear();
84 }
85
86 /* FIXME: This function should not be used. It's a short-cut fix that is meant
87 * to improve font fallback for in-theme fonts. It will break if we stop using
88 * freetype (unlikely) or do anything else fancy. */
89 void *
evas_common_font_freetype_face_get(RGBA_Font * font)90 evas_common_font_freetype_face_get(RGBA_Font *font)
91 {
92 RGBA_Font_Int *fi = font->fonts->data;
93
94 if (!fi)
95 return NULL;
96
97 evas_common_font_int_reload(fi);
98
99 return fi->src->ft.face;
100 }
101
102 EAPI int
evas_common_font_instance_ascent_get(RGBA_Font_Int * fi)103 evas_common_font_instance_ascent_get(RGBA_Font_Int *fi)
104 {
105 int val;
106 evas_common_font_int_reload(fi);
107 if (fi->src->current_size != fi->size)
108 {
109 FTLOCK();
110 FT_Activate_Size(fi->ft.size);
111 FTUNLOCK();
112 fi->src->current_size = fi->size;
113 }
114 if (!FT_IS_SCALABLE(fi->src->ft.face))
115 {
116 WRN("NOT SCALABLE!");
117 }
118 val = (int)fi->src->ft.face->size->metrics.ascender;
119
120 if (FT_HAS_FIXED_SIZES(fi->src->ft.face))
121 {
122 if (FT_HAS_COLOR(fi->src->ft.face) &&
123 fi->bitmap_scalable & EFL_TEXT_FONT_BITMAP_SCALABLE_COLOR)
124 val *= fi->scale_factor;
125 }
126
127 return FONT_METRIC_ROUNDUP(val);
128 // printf("%i | %i\n", val, val >> 6);
129 // if (fi->src->ft.face->units_per_EM == 0)
130 // return val;
131 // dv = (fi->src->ft.orig_upem * 2048) / fi->src->ft.face->units_per_EM;
132 // ret = (val * fi->src->ft.face->size->metrics.y_scale) / (dv * dv);
133 // return ret;
134 }
135
136 EAPI int
evas_common_font_instance_descent_get(RGBA_Font_Int * fi)137 evas_common_font_instance_descent_get(RGBA_Font_Int *fi)
138 {
139 int val;
140 evas_common_font_int_reload(fi);
141 if (fi->src->current_size != fi->size)
142 {
143 FTLOCK();
144 FT_Activate_Size(fi->ft.size);
145 FTUNLOCK();
146 fi->src->current_size = fi->size;
147 }
148 val = -(int)fi->src->ft.face->size->metrics.descender;
149
150 if (FT_HAS_FIXED_SIZES(fi->src->ft.face))
151 {
152 if (FT_HAS_COLOR(fi->src->ft.face) &&
153 fi->bitmap_scalable & EFL_TEXT_FONT_BITMAP_SCALABLE_COLOR)
154 val *= fi->scale_factor;
155 }
156
157 return FONT_METRIC_ROUNDUP(val);
158 // if (fi->src->ft.face->units_per_EM == 0)
159 // return val;
160 // dv = (fi->src->ft.orig_upem * 2048) / fi->src->ft.face->units_per_EM;
161 // ret = (val * fi->src->ft.face->size->metrics.y_scale) / (dv * dv);
162 // return ret;
163 }
164
165 EAPI int
evas_common_font_instance_max_ascent_get(RGBA_Font_Int * fi)166 evas_common_font_instance_max_ascent_get(RGBA_Font_Int *fi)
167 {
168 int val, dv;
169 int ret;
170
171 evas_common_font_int_reload(fi);
172 if (fi->src->current_size != fi->size)
173 {
174 FTLOCK();
175 FT_Activate_Size(fi->ft.size);
176 FTUNLOCK();
177 fi->src->current_size = fi->size;
178 }
179 if ((fi->src->ft.face->bbox.yMax == 0) &&
180 (fi->src->ft.face->bbox.yMin == 0) &&
181 (fi->src->ft.face->units_per_EM == 0))
182 val = FONT_METRIC_ROUNDUP((int)fi->src->ft.face->size->metrics.ascender);
183 else
184 val = (int)fi->src->ft.face->bbox.yMax;
185
186 if (FT_HAS_FIXED_SIZES(fi->src->ft.face))
187 {
188 if (FT_HAS_COLOR(fi->src->ft.face) &&
189 fi->bitmap_scalable & EFL_TEXT_FONT_BITMAP_SCALABLE_COLOR)
190 val *= fi->scale_factor;
191 }
192
193 if (fi->src->ft.face->units_per_EM == 0)
194 return val;
195 dv = (fi->src->ft.orig_upem * 2048) / fi->src->ft.face->units_per_EM;
196 ret = FONT_METRIC_CONV(val, dv, fi->src->ft.face->size->metrics.y_scale);
197 return ret;
198 }
199
200 EAPI int
evas_common_font_instance_max_descent_get(RGBA_Font_Int * fi)201 evas_common_font_instance_max_descent_get(RGBA_Font_Int *fi)
202 {
203 int val, dv;
204 int ret;
205
206 evas_common_font_int_reload(fi);
207 if (fi->src->current_size != fi->size)
208 {
209 FTLOCK();
210 FT_Activate_Size(fi->ft.size);
211 FTUNLOCK();
212 fi->src->current_size = fi->size;
213 }
214 if ((fi->src->ft.face->bbox.yMax == 0) &&
215 (fi->src->ft.face->bbox.yMin == 0) &&
216 (fi->src->ft.face->units_per_EM == 0))
217 val = FONT_METRIC_ROUNDUP(-(int)fi->src->ft.face->size->metrics.descender);
218 else
219 val = -(int)fi->src->ft.face->bbox.yMin;
220
221 if (FT_HAS_FIXED_SIZES(fi->src->ft.face))
222 {
223 if (FT_HAS_COLOR(fi->src->ft.face) &&
224 fi->bitmap_scalable & EFL_TEXT_FONT_BITMAP_SCALABLE_COLOR)
225 val *= fi->scale_factor;
226 }
227
228 if (fi->src->ft.face->units_per_EM == 0)
229 return val;
230 dv = (fi->src->ft.orig_upem * 2048) / fi->src->ft.face->units_per_EM;
231 ret = FONT_METRIC_CONV(val, dv, fi->src->ft.face->size->metrics.y_scale);
232 return ret;
233 }
234
235 EAPI int
evas_common_font_ascent_get(RGBA_Font * fn)236 evas_common_font_ascent_get(RGBA_Font *fn)
237 {
238 // evas_common_font_size_use(fn);
239 return evas_common_font_instance_ascent_get(fn->fonts->data);
240 }
241
242 EAPI int
evas_common_font_descent_get(RGBA_Font * fn)243 evas_common_font_descent_get(RGBA_Font *fn)
244 {
245 // evas_common_font_size_use(fn);
246 return evas_common_font_instance_descent_get(fn->fonts->data);
247 }
248
249 EAPI int
evas_common_font_max_ascent_get(RGBA_Font * fn)250 evas_common_font_max_ascent_get(RGBA_Font *fn)
251 {
252 // evas_common_font_size_use(fn);
253 return evas_common_font_instance_max_ascent_get(fn->fonts->data);
254 }
255
256 EAPI int
evas_common_font_max_descent_get(RGBA_Font * fn)257 evas_common_font_max_descent_get(RGBA_Font *fn)
258 {
259 // evas_common_font_size_use(fn);
260 return evas_common_font_instance_max_descent_get(fn->fonts->data);
261 }
262
263 EAPI int
evas_common_font_get_line_advance(RGBA_Font * fn)264 evas_common_font_get_line_advance(RGBA_Font *fn)
265 {
266 int val;
267 RGBA_Font_Int *fi;
268
269 // evas_common_font_size_use(fn);
270 fi = fn->fonts->data;
271 evas_common_font_int_reload(fi);
272 if (fi->src->current_size != fi->size)
273 {
274 FTLOCK();
275 FT_Activate_Size(fi->ft.size);
276 FTUNLOCK();
277 fi->src->current_size = fi->size;
278 }
279 val = (int)fi->src->ft.face->size->metrics.height;
280
281 if (FT_HAS_FIXED_SIZES(fi->src->ft.face))
282 {
283 if ((fi->bitmap_scalable & EFL_TEXT_FONT_BITMAP_SCALABLE_COLOR) &&
284 FT_HAS_COLOR(fi->src->ft.face))
285 val *= fi->scale_factor;
286 }
287
288 if ((fi->src->ft.face->bbox.yMax == 0) &&
289 (fi->src->ft.face->bbox.yMin == 0) &&
290 (fi->src->ft.face->units_per_EM == 0))
291 return FONT_METRIC_ROUNDUP(val);
292 else if (fi->src->ft.face->units_per_EM == 0)
293 return val;
294 return FONT_METRIC_ROUNDUP(val);
295 // dv = (fi->src->ft.orig_upem * 2048) / fi->src->ft.face->units_per_EM;
296 // ret = (val * fi->src->ft.face->size->metrics.y_scale) / (dv * dv);
297 // return ret;
298 }
299
300 EAPI int
evas_common_font_instance_underline_position_get(RGBA_Font_Int * fi)301 evas_common_font_instance_underline_position_get(RGBA_Font_Int *fi)
302 {
303 int position = 0;
304
305 if (!fi) goto end;
306
307 evas_common_font_int_reload(fi);
308 if (fi->src->current_size != fi->size)
309 {
310 FTLOCK();
311 FT_Activate_Size(fi->ft.size);
312 FTUNLOCK();
313 fi->src->current_size = fi->size;
314 }
315
316 position = FT_MulFix(fi->src->ft.face->underline_position,
317 fi->src->ft.face->size->metrics.x_scale);
318 position = FONT_METRIC_ROUNDUP(abs(position));
319
320 end:
321 /* This almost surely means a broken font, offset at least by one pixel. */
322 if (position == 0)
323 position = 1;
324
325 return position;
326 }
327
328 EAPI int
evas_common_font_instance_underline_thickness_get(RGBA_Font_Int * fi)329 evas_common_font_instance_underline_thickness_get(RGBA_Font_Int *fi)
330 {
331 int thickness = 0;
332
333 if (!fi) goto end;
334
335 evas_common_font_int_reload(fi);
336 if (fi->src->current_size != fi->size)
337 {
338 FTLOCK();
339 FT_Activate_Size(fi->ft.size);
340 FTUNLOCK();
341 fi->src->current_size = fi->size;
342 }
343
344 thickness = FT_MulFix(fi->src->ft.face->underline_thickness,
345 fi->src->ft.face->size->metrics.x_scale);
346 thickness = FONT_METRIC_ROUNDUP(thickness);
347
348 end:
349 /* This almost surely means a broken font, make it at least one pixel. */
350 if (thickness == 0)
351 thickness = 1;
352
353 return thickness;
354 }
355
356 /* Set of common functions that are used in a couple of places. */
357
358 static void
_fash_int_map_and_variations_free(Fash_Int_Map * map)359 _fash_int_map_and_variations_free(Fash_Int_Map *map)
360 {
361 if(!map)
362 return;
363 int i;
364
365 for (i = 0; i < 256; i++)
366 {
367 if (map->items[i].variations)
368 {
369 if (map->items[i].variations->list)
370 {
371 free(map->items[i].variations->list);
372 map->items[i].variations->list = NULL;
373 map->items[i].variations->capacity = 0;
374 map->items[i].variations->length = 0;
375 }
376 free(map->items[i].variations);
377 map->items[i].variations = NULL;
378 }
379 }
380
381 free(map);
382 }
383
384 static void
_fash_int2_free(Fash_Int_Map2 * fash)385 _fash_int2_free(Fash_Int_Map2 *fash)
386 {
387 int i;
388 if (fash)
389 {
390 for (i = 0; i < 256; i++)
391 if (fash->bucket[i])
392 {
393 _fash_int_map_and_variations_free(fash->bucket[i]);
394 fash->bucket[i] = NULL;
395 }
396 free(fash);
397 fash = NULL;
398 }
399 }
400
401 static void
_fash_int_free(Fash_Int * fash)402 _fash_int_free(Fash_Int *fash)
403 {
404 int i;
405 if (fash)
406 {
407 if (fash->MAGIC != FASH_INT_MAGIC)
408 {
409 return;
410 }
411
412 for (i = 0; i < 256; i++)
413 {
414 if (fash->bucket[i])
415 {
416 _fash_int2_free(fash->bucket[i]);
417 fash->bucket[i] = NULL;
418 }
419 }
420 free(fash);
421 }
422 }
423
424 static Fash_Int *
_fash_int_new(void)425 _fash_int_new(void)
426 {
427 Fash_Int *fash = calloc(1, sizeof(Fash_Int));
428 EINA_SAFETY_ON_NULL_RETURN_VAL(fash, NULL);
429 fash->MAGIC = FASH_INT_MAGIC;
430 fash->freeme = _fash_int_free;
431 return fash;
432 }
433
434 static Fash_Item_variation_List *
_variations_list_new(void)435 _variations_list_new(void)
436 {
437 Fash_Item_variation_List *variations = calloc(1, sizeof(Fash_Item_variation_List));
438 EINA_SAFETY_ON_NULL_RETURN_VAL(variations, NULL);
439 variations->capacity = 0;
440 variations->length = 0;
441 variations->list = 0;
442 return variations;
443 }
444
445 static void
_variations_list_add(Fash_Item_variation_List * variations,RGBA_Font_Int * fint,int index,Eina_Unicode variation_sequence)446 _variations_list_add(Fash_Item_variation_List *variations,RGBA_Font_Int *fint, int index, Eina_Unicode variation_sequence)
447 {
448 Fash_Item_variation_Index_Item *list = variations->list;
449 if (variations->capacity == variations->length)
450 {
451 list = (Fash_Item_variation_Index_Item *) realloc(list, (variations->capacity + 4) * sizeof(Fash_Item_variation_Index_Item));
452 if (list)
453 {
454 variations->list = list;
455 variations->capacity += 4;
456 }
457 }
458
459 EINA_SAFETY_ON_NULL_RETURN(list);
460
461 int start = 0;
462 int end = variations->length;
463 if (end == 0)
464 {
465 // if only on element just add it in 0 index
466 variations->list[0].item.fint = fint;
467 variations->list[0].item.index = index;
468 variations->list[0].variation_sequence = variation_sequence;
469 variations->length++;
470 }
471 else
472 {
473 // find lower bound
474 while (end > start)
475 {
476 int middle = start + (end - start) / 2;
477 if (variations->list[middle].variation_sequence >= variation_sequence)
478 end = middle;
479 else
480 start = middle + 1;
481 }
482
483 // if passed value founded in list, just replace it
484 if (start < (int)variations->length && variations->list[start].variation_sequence == variation_sequence)
485 {
486 variations->list[start].item.fint = fint;
487 variations->list[start].item.index = index;
488 variations->list[start].variation_sequence = variation_sequence;
489 return;
490 }
491
492 // shift array to insert item
493 for (int i = (variations->length - 1) ; i >= start; i--)
494 {
495 variations->list[i + 1] = variations->list[i];
496 }
497
498 // insert new item and keep array sorted
499 variations->list[start].item.fint = fint;
500 variations->list[start].item.index = index;
501 variations->list[start].variation_sequence = variation_sequence;
502 variations->length++;
503 }
504 }
505
506
507 static Fash_Item_Index_Map *
_variations_list_find(Fash_Item_variation_List * variations,Eina_Unicode variation_sequence)508 _variations_list_find(Fash_Item_variation_List * variations, Eina_Unicode variation_sequence)
509 {
510 if (!variations)
511 return NULL;
512
513 if (!variations->list)
514 return NULL;
515
516 int start = 0;
517 int end = variations->length;
518
519 while(end > start)
520 {
521 int middle = start + (end - start) / 2;
522 if (variations->list[middle].variation_sequence == variation_sequence)
523 return &(variations->list[middle].item);
524 else if (variations->list[middle].variation_sequence < variation_sequence)
525 start = middle + 1;
526 else
527 end = middle - 1;
528 }
529
530 return NULL;
531 }
532
533 static const Fash_Item_Index_Map *
_fash_int_find(Fash_Int * fash,int item,Eina_Unicode variation_sequence)534 _fash_int_find(Fash_Int *fash, int item, Eina_Unicode variation_sequence)
535 {
536 int grp, maj, min;
537
538 // 24bits for unicode - v6 up to E01EF (chrs) & 10FFFD for private use (plane 16)
539 grp = (item >> 16) & 0xff;
540 maj = (item >> 8) & 0xff;
541 min = item & 0xff;
542 if (!fash->bucket[grp]) return NULL;
543 if (!fash->bucket[grp]->bucket[maj]) return NULL;
544 if (!variation_sequence)
545 return &(fash->bucket[grp]->bucket[maj]->items[min].item);
546 else
547 return _variations_list_find(fash->bucket[grp]->bucket[maj]->items[min].variations, variation_sequence);
548 }
549
550 static void
_fash_int_add(Fash_Int * fash,int item,RGBA_Font_Int * fint,int idx,Eina_Unicode variation_sequence)551 _fash_int_add(Fash_Int *fash, int item, RGBA_Font_Int *fint, int idx, Eina_Unicode variation_sequence)
552 {
553 int grp, maj, min;
554
555 // If we already have cached passed item, skip adding it again
556 const Fash_Item_Index_Map *fm = _fash_int_find(fash, item, variation_sequence);
557 if (fm && fm->fint)
558 return;
559
560 // 24bits for unicode - v6 up to E01EF (chrs) & 10FFFD for private use (plane 16)
561 grp = (item >> 16) & 0xff;
562 maj = (item >> 8) & 0xff;
563 min = item & 0xff;
564 if (!fash->bucket[grp])
565 fash->bucket[grp] = calloc(1, sizeof(Fash_Int_Map2));
566 EINA_SAFETY_ON_NULL_RETURN(fash->bucket[grp]);
567 if (!fash->bucket[grp]->bucket[maj])
568 fash->bucket[grp]->bucket[maj] = calloc(1, sizeof(Fash_Int_Map));
569 EINA_SAFETY_ON_NULL_RETURN(fash->bucket[grp]->bucket[maj]);
570 if (variation_sequence)
571 {
572 if (!fash->bucket[grp]->bucket[maj]->items[min].variations)
573 {
574 fash->bucket[grp]->bucket[maj]->items[min].variations =_variations_list_new();
575 EINA_SAFETY_ON_NULL_RETURN(fash->bucket[grp]->bucket[maj]->items[min].variations);
576 }
577 _variations_list_add(fash->bucket[grp]->bucket[maj]->items[min].variations, fint, idx, variation_sequence);
578 }
579 else
580 {
581 fash->bucket[grp]->bucket[maj]->items[min].item.fint = fint;
582 fash->bucket[grp]->bucket[maj]->items[min].item.index = idx;
583 }
584 }
585
586 static void
_glyph_free(RGBA_Font_Glyph * fg)587 _glyph_free(RGBA_Font_Glyph *fg)
588 {
589 if ((!fg) || (fg == (void *)(-1))) return;
590
591 if (fg->glyph_out)
592 {
593 if ((!fg->glyph_out->rle) && (!fg->glyph_out->bitmap.rle_alloc))
594 {
595 FT_BitmapGlyph fbg = (FT_BitmapGlyph)fg->glyph;
596 FT_Bitmap_Done(evas_ft_lib, &(fbg->bitmap));
597 }
598
599 if ((fg->glyph_out->rle) && (fg->glyph_out->bitmap.rle_alloc))
600 free(fg->glyph_out->rle);
601 else if ((fg->glyph_out->bitmap.buffer) && (fg->glyph_out->bitmap.rle_alloc))
602 {
603 free(fg->glyph_out->bitmap.buffer);
604 fg->glyph_out->bitmap.buffer = NULL;
605 }
606 fg->glyph_out->rle = NULL;
607 if (!fg->glyph_out->bitmap.no_free_glout) free(fg->glyph_out);
608 fg->glyph_out = NULL;
609 }
610 FT_Done_Glyph(fg->glyph);
611 /* extension calls */
612 if (fg->ext_dat_free) fg->ext_dat_free(fg->ext_dat);
613 if (fg->col_dat) evas_cache_image_drop(fg->col_dat);
614 free(fg);
615 }
616
617 static void
_fash_glyph_free(Fash_Glyph_Map * fmap)618 _fash_glyph_free(Fash_Glyph_Map *fmap)
619 {
620 int i;
621
622 for (i = 0; i <= 0xff; i++)
623 {
624 RGBA_Font_Glyph *fg = fmap->item[i];
625 if ((fg) && (fg != (void *)(-1)))
626 {
627 _glyph_free(fg);
628 fmap->item[i] = NULL;
629 }
630 }
631 free(fmap);
632 }
633
634 static void
_fash_gl2_free(Fash_Glyph_Map2 * fash)635 _fash_gl2_free(Fash_Glyph_Map2 *fash)
636 {
637 int i;
638
639 // 24bits for unicode - v6 up to E01EF (chrs) & 10FFFD for private use (plane 16)
640 for (i = 0; i < 256; i++)
641 {
642 if (fash->bucket[i])
643 {
644 _fash_glyph_free(fash->bucket[i]);
645 fash->bucket[i] = NULL;
646 }
647 }
648 free(fash);
649 }
650
651 static void
_fash_gl_free(Fash_Glyph * fash)652 _fash_gl_free(Fash_Glyph *fash)
653 {
654 if (fash)
655 {
656 if (fash->MAGIC != FASH_GLYPH_MAGIC)
657 return;
658
659 int i;
660 // 24bits for unicode - v6 up to E01EF (chrs) & 10FFFD for private use (plane 16)
661 for (i = 0; i < 256; i++)
662 {
663 if (fash->bucket[i])
664 {
665 _fash_gl2_free(fash->bucket[i]);
666 fash->bucket[i] = NULL;
667 }
668 }
669 free(fash);
670 }
671 }
672
673 static Fash_Glyph *
_fash_gl_new(void)674 _fash_gl_new(void)
675 {
676 Fash_Glyph *fash = calloc(1, sizeof(Fash_Glyph));
677 EINA_SAFETY_ON_NULL_RETURN_VAL(fash, NULL);
678 fash->MAGIC = FASH_GLYPH_MAGIC;
679 fash->freeme = _fash_gl_free;
680 return fash;
681 }
682
683 static RGBA_Font_Glyph *
_fash_gl_find(Fash_Glyph * fash,int item)684 _fash_gl_find(Fash_Glyph *fash, int item)
685 {
686 int grp, maj, min;
687
688 // 24bits for unicode - v6 up to E01EF (chrs) & 10FFFD for private use (plane 16)
689 grp = (item >> 16) & 0xff;
690 maj = (item >> 8) & 0xff;
691 min = item & 0xff;
692 if (!fash->bucket[grp]) return NULL;
693 if (!fash->bucket[grp]->bucket[maj]) return NULL;
694 return fash->bucket[grp]->bucket[maj]->item[min];
695 }
696
697 static void
_fash_gl_add(Fash_Glyph * fash,int item,RGBA_Font_Glyph * glyph)698 _fash_gl_add(Fash_Glyph *fash, int item, RGBA_Font_Glyph *glyph)
699 {
700 int grp, maj, min;
701
702 // 24bits for unicode - v6 up to E01EF (chrs) & 10FFFD for private use (plane 16)
703 grp = (item >> 16) & 0xff;
704 maj = (item >> 8) & 0xff;
705 min = item & 0xff;
706 if (!fash->bucket[grp])
707 fash->bucket[grp] = calloc(1, sizeof(Fash_Glyph_Map2));
708 EINA_SAFETY_ON_NULL_RETURN(fash->bucket[grp]);
709 if (!fash->bucket[grp]->bucket[maj])
710 fash->bucket[grp]->bucket[maj] = calloc(1, sizeof(Fash_Glyph_Map));
711 EINA_SAFETY_ON_NULL_RETURN(fash->bucket[grp]->bucket[maj]);
712 fash->bucket[grp]->bucket[maj]->item[min] = glyph;
713 }
714
evas_font_glyph_load(RGBA_Font_Glyph * fg)715 static void evas_font_glyph_load(RGBA_Font_Glyph *fg)
716 {
717 if(fg->glyph) return;
718
719 RGBA_Font_Int *fi = fg->fi;
720 FT_UInt idx = fg->index;
721 FT_Error error;
722
723 const FT_Int32 hintflags[3] =
724 { FT_LOAD_NO_HINTING, FT_LOAD_FORCE_AUTOHINT, FT_LOAD_NO_AUTOHINT };
725 static FT_Matrix transform = {0x10000, _EVAS_FONT_SLANT_TAN * 0x10000,
726 0x00000, 0x10000};
727
728 evas_common_font_int_reload(fi);
729 FTLOCK();
730 error = FT_Load_Glyph(fi->src->ft.face, idx,
731 (FT_HAS_COLOR(fi->src->ft.face) ?
732 (FT_LOAD_COLOR | hintflags[fi->hinting]) :
733 (FT_LOAD_DEFAULT | FT_LOAD_NO_BITMAP | hintflags[fi->hinting])));
734
735 FTUNLOCK();
736 if (error)
737 {
738 return;
739 }
740
741 /* Transform the outline of Glyph according to runtime_rend. */
742 if (fi->runtime_rend & FONT_REND_SLANT)
743 FT_Outline_Transform(&fi->src->ft.face->glyph->outline, &transform);
744 /* Embolden the outline of Glyph according to rundtime_rend. */
745 if (fi->runtime_rend & FONT_REND_WEIGHT)
746 FT_GlyphSlot_Embolden(fi->src->ft.face->glyph);
747
748 FTLOCK();
749 error = FT_Get_Glyph(fi->src->ft.face->glyph, &(fg->glyph));
750 FTUNLOCK();
751
752 return;
753 }
754
755 EAPI RGBA_Font_Glyph *
evas_common_font_int_cache_glyph_get(RGBA_Font_Int * fi,FT_UInt idx)756 evas_common_font_int_cache_glyph_get(RGBA_Font_Int *fi, FT_UInt idx)
757 {
758 RGBA_Font_Glyph *fg;
759 FT_Error error;
760 const FT_Int32 hintflags[3] =
761 { FT_LOAD_NO_HINTING, FT_LOAD_FORCE_AUTOHINT, FT_LOAD_NO_AUTOHINT };
762 static FT_Matrix transform = {0x10000, _EVAS_FONT_SLANT_TAN * 0x10000,
763 0x00000, 0x10000};
764
765 evas_common_font_int_promote(fi);
766 if (fi->fash)
767 {
768 fg = _fash_gl_find(fi->fash, idx);
769 if (fg == (void *)(-1)) return NULL;
770 else if (fg)
771 return fg;
772 }
773 // fg = eina_hash_find(fi->glyphs, &hindex);
774 // if (fg) return fg;
775
776 evas_common_font_int_reload(fi);
777 FTLOCK();
778 error = FT_Load_Glyph(fi->src->ft.face, idx,
779 (FT_HAS_COLOR(fi->src->ft.face) ?
780 (FT_LOAD_COLOR | hintflags[fi->hinting]) :
781 (FT_LOAD_DEFAULT | FT_LOAD_NO_BITMAP | hintflags[fi->hinting])));
782
783 FTUNLOCK();
784 if (error)
785 {
786 if (!fi->fash) fi->fash = _fash_gl_new();
787 if (fi->fash) _fash_gl_add(fi->fash, idx, (void *)(-1));
788 return NULL;
789 }
790
791 /* Transform the outline of Glyph according to runtime_rend. */
792 if (fi->runtime_rend & FONT_REND_SLANT)
793 FT_Outline_Transform(&fi->src->ft.face->glyph->outline, &transform);
794 /* Embolden the outline of Glyph according to rundtime_rend. */
795 if (fi->runtime_rend & FONT_REND_WEIGHT)
796 FT_GlyphSlot_Embolden(fi->src->ft.face->glyph);
797
798 fg = calloc(1, sizeof(RGBA_Font_Glyph));
799 if (!fg) return NULL;
800
801 if (FT_HAS_COLOR(fi->src->ft.face))
802 {
803 fg->advance.x = fi->src->ft.face->glyph->advance.x * 1024;
804 fg->advance.y = fi->src->ft.face->glyph->advance.y * 1024;
805
806 FT_GlyphSlot slot = fi->src->ft.face->glyph;
807 fg->width = EVAS_FONT_ROUND_26_6_TO_INT(slot->metrics.width);
808 fg->x_bear = EVAS_FONT_ROUND_26_6_TO_INT(slot->metrics.horiBearingX);
809 fg->y_bear = EVAS_FONT_ROUND_26_6_TO_INT(slot->metrics.horiBearingY);
810
811 if (FT_HAS_FIXED_SIZES(fi->src->ft.face))
812 {
813 if (fi->bitmap_scalable & EFL_TEXT_FONT_BITMAP_SCALABLE_COLOR)
814 {
815 fg->advance.x *= fi->scale_factor;
816 fg->advance.y *= fi->scale_factor;
817 fg->width *= fi->scale_factor;
818 fg->x_bear *= fi->scale_factor;
819 fg->y_bear *= fi->scale_factor;
820 }
821 }
822 }
823 else
824 {
825 FTLOCK();
826 error = FT_Get_Glyph(fi->src->ft.face->glyph, &(fg->glyph));
827 FTUNLOCK();
828 if (error)
829 {
830 free(fg);
831 if (!fi->fash) fi->fash = _fash_gl_new();
832 if (fi->fash) _fash_gl_add(fi->fash, idx, (void *)(-1));
833 return NULL;
834 }
835 fg->advance.x = fg->glyph->advance.x;
836 fg->advance.y = fg->glyph->advance.y;
837
838 FT_BBox outbox;
839 FT_Glyph_Get_CBox(fg->glyph,
840 ((fi->hinting == 0) ? FT_GLYPH_BBOX_UNSCALED :
841 FT_GLYPH_BBOX_GRIDFIT),
842 &outbox);
843 fg->width = EVAS_FONT_ROUND_26_6_TO_INT(outbox.xMax - outbox.xMin);
844 fg->x_bear = EVAS_FONT_ROUND_26_6_TO_INT(outbox.xMin);
845 fg->y_bear = EVAS_FONT_ROUND_26_6_TO_INT(outbox.yMax);
846 }
847
848 fg->index = idx;
849 fg->fi = fi;
850
851 if (!fi->fash) fi->fash = _fash_gl_new();
852 if (fi->fash) _fash_gl_add(fi->fash, idx, fg);
853
854 // eina_hash_direct_add(fi->glyphs, &fg->index, fg);
855 return fg;
856 }
857
858 EAPI void
evas_font_data_cache_set(Evas_Font_Data_Cache options,int bytes)859 evas_font_data_cache_set(Evas_Font_Data_Cache options, int bytes)
860 {
861 if ((options & EVAS_FONT_DATA_CACHE_TEXTURE) == EVAS_FONT_DATA_CACHE_TEXTURE)
862 {
863 _evas_font_texture_cache = bytes;
864 //FIXME No direct free happend until next render call
865 }
866 }
867
868 EAPI int
evas_font_data_cache_get(Evas_Font_Data_Cache options)869 evas_font_data_cache_get(Evas_Font_Data_Cache options)
870 {
871 if ((options & EVAS_FONT_DATA_CACHE_TEXTURE) == EVAS_FONT_DATA_CACHE_TEXTURE)
872 return _evas_font_texture_cache;
873 else
874 return -1;
875 }
876
877 EAPI Eina_Bool
evas_common_font_int_cache_glyph_render(RGBA_Font_Glyph * fg)878 evas_common_font_int_cache_glyph_render(RGBA_Font_Glyph *fg)
879 {
880 int size;
881 FT_Error error;
882 RGBA_Font_Int *fi = fg->fi;
883 FT_BitmapGlyph fbg;
884
885 /* no cserve2 case */
886 if (fg->glyph_out)
887 return EINA_TRUE;
888 evas_font_glyph_load(fg);
889 FTLOCK();
890 error = FT_Glyph_To_Bitmap(&(fg->glyph), FT_RENDER_MODE_NORMAL, 0, 1);
891 if (error)
892 {
893 FT_Done_Glyph(fg->glyph);
894 FTUNLOCK();
895 if (!fi->fash) fi->fash = _fash_gl_new();
896 if (fi->fash) _fash_gl_add(fi->fash, fg->index, (void *)(-1));
897 free(fg);
898 return EINA_FALSE;
899 }
900 FTUNLOCK();
901
902 fbg = (FT_BitmapGlyph)fg->glyph;
903
904 fg->glyph_out = calloc(1, sizeof(RGBA_Font_Glyph_Out));
905 fg->glyph_out->bitmap.rows = fbg->bitmap.rows;
906 fg->glyph_out->bitmap.width = fbg->bitmap.width;
907 fg->glyph_out->bitmap.pitch = fbg->bitmap.pitch;
908 fg->glyph_out->bitmap.buffer = fbg->bitmap.buffer;
909 fg->glyph_out->bitmap.rle_alloc = EINA_TRUE;
910
911 /* This '+ 100' is just an estimation of how much memory freetype will use
912 * on it's size. This value is not really used anywhere in code - it's
913 * only for statistics. */
914 size = sizeof(RGBA_Font_Glyph) + sizeof(Eina_List) +
915 (fg->glyph_out->bitmap.width * fg->glyph_out->bitmap.rows / 2) + 100;
916 fi->usage += size;
917 if (fi->inuse) evas_common_font_int_use_increase(size);
918
919 if (!FT_HAS_COLOR(fi->src->ft.face))
920 {
921 fg->glyph_out->rle = evas_common_font_glyph_compress
922 (fbg->bitmap.buffer, fbg->bitmap.num_grays, fbg->bitmap.pixel_mode,
923 fbg->bitmap.pitch, fbg->bitmap.width, fbg->bitmap.rows,
924 &(fg->glyph_out->rle_size));
925 fg->glyph_out->bitmap.rle_alloc = EINA_TRUE;
926
927 fg->glyph_out->bitmap.buffer = NULL;
928
929 // this may be technically incorrect as we go and free a bitmap buffer
930 // behind the ftglyph's back...
931 FT_Bitmap_Done(evas_ft_lib, &(fbg->bitmap));
932 }
933 else
934 {
935 fg->glyph_out->rle = NULL;
936 fg->glyph_out->bitmap.rle_alloc = EINA_FALSE;
937 if (fi->is_resized)
938 {
939 int w = fbg->bitmap.width;
940 int h = fbg->bitmap.rows;
941
942 RGBA_Image src = {0};
943 src.image.data = (DATA32 *) fbg->bitmap.buffer;
944 src.cache_entry.w = w;
945 src.cache_entry.h = h;
946 src.cache_entry.flags.alpha = 1;
947
948 RGBA_Image dst = {0};
949 dst.cache_entry.w = w * fi->scale_factor;
950 dst.cache_entry.h = h * fi->scale_factor;
951 dst.image.data = malloc(dst.cache_entry.w * dst.cache_entry.h * 4);
952 dst.cache_entry.flags.alpha = 1;
953
954 evas_common_scale_rgba_smooth_draw(&src, &dst,
955 0, 0, src.cache_entry.w , src.cache_entry.h,
956 0xffffffff, EVAS_RENDER_COPY,
957 0, 0, src.cache_entry.w , src.cache_entry.h,
958 0, 0, dst.cache_entry.w, dst.cache_entry.h,
959 NULL, 0, 0);
960
961 fg->glyph_out->bitmap.rows = dst.cache_entry.h;
962 fg->glyph_out->bitmap.width = dst.cache_entry.w;
963 fg->glyph_out->bitmap.buffer = (unsigned char *) dst.image.data;
964 fg->glyph_out->bitmap.pitch = dst.cache_entry.w * 4;
965
966 fg->glyph_out->rle = NULL;
967 fg->glyph_out->bitmap.rle_alloc = EINA_TRUE;
968 // this may be technically incorrect as we go and free a bitmap buffer
969 // behind the ftglyph's back...
970 FT_Bitmap_Done(evas_ft_lib, &(fbg->bitmap));
971 }
972 }
973
974 return EINA_TRUE;
975 }
976
977 typedef struct _Font_Char_Index Font_Char_Index;
978 struct _Font_Char_Index
979 {
980 FT_UInt index;
981 Eina_Unicode gl;
982 };
983
984 EAPI FT_UInt
evas_common_get_char_index(RGBA_Font_Int * fi,Eina_Unicode gl,Eina_Unicode variation_sequence)985 evas_common_get_char_index(RGBA_Font_Int* fi, Eina_Unicode gl, Eina_Unicode variation_sequence)
986 {
987 static const unsigned short mapfix[] =
988 {
989 0x00b0, 0x7,
990 0x00b1, 0x8,
991 0x00b7, 0x1f,
992 0x03c0, 0x1c,
993 0x20a4, 0xa3,
994 0x2260, 0x1d,
995 0x2264, 0x1a,
996 0x2265, 0x1b,
997 0x23ba, 0x10,
998 0x23bb, 0x11,
999 0x23bc, 0x13,
1000 0x23bd, 0x14,
1001 0x2409, 0x3,
1002 0x240a, 0x6,
1003 0x240b, 0xa,
1004 0x240c, 0x4,
1005 0x240d, 0x5,
1006 0x2424, 0x9,
1007 0x2500, 0x12,
1008 0x2502, 0x19,
1009 0x250c, 0xd,
1010 0x2510, 0xc,
1011 0x2514, 0xe,
1012 0x2518, 0xb,
1013 0x251c, 0x15,
1014 0x2524, 0x16,
1015 0x252c, 0x18,
1016 0x2534, 0x17,
1017 0x253c, 0xf,
1018 0x2592, 0x2,
1019 0x25c6, 0x1,
1020 };
1021 Font_Char_Index result;
1022 //FT_UInt ret;
1023
1024 #ifdef HAVE_PTHREAD
1025 /// pthread_mutex_lock(&fi->ft_mutex);
1026 #endif
1027
1028 // result = eina_hash_find(fi->indexes, &gl);
1029 // if (result) goto on_correct;
1030 //
1031 // result = malloc(sizeof (Font_Char_Index));
1032 // if (!result)
1033 // {
1034 //#ifdef HAVE_PTHREAD
1035 // pthread_mutex_unlock(&fi->ft_mutex);
1036 //#endif
1037 // return FT_Get_Char_Index(fi->src->ft.face, gl);
1038 // }
1039
1040 evas_common_font_int_reload(fi);
1041 /*
1042 * There is no point in locking FreeType at this point as all caller
1043 * are running in the main loop at a time where there is zero chance
1044 * that something else try to use it.
1045 */
1046 /* FTLOCK(); */
1047 if (variation_sequence)
1048 result.index = FT_Face_GetCharVariantIndex(fi->src->ft.face, gl, variation_sequence);
1049 else
1050 result.index = FT_Get_Char_Index(fi->src->ft.face, gl);
1051 /* FTUNLOCK(); */
1052 result.gl = gl;
1053
1054 // eina_hash_direct_add(fi->indexes, &result->gl, result);
1055 //
1056 // on_correct:
1057 #ifdef HAVE_PTHREAD
1058 // pthread_mutex_unlock(&fi->ft_mutex);
1059 #endif
1060 // this is a workaround freetype bugs where for a bitmap old style font
1061 // even if it has unicode information and mappings, they are not used
1062 // to find terminal line/drawing chars, so do this by hand with a table
1063 if ((result.index <= 0) && (fi->src->ft.face->num_fixed_sizes == 1) &&
1064 (fi->src->ft.face->num_glyphs < 512))
1065 {
1066 int i, min = 0, max;
1067
1068 // binary search through sorted table of codepoints to new
1069 // codepoints with a guess that bitmap font is playing the old
1070 // game of putting line drawing chars in specific ranges
1071 max = sizeof(mapfix) / (sizeof(mapfix[0]) * 2);
1072 i = (min + max) / 2;
1073 for (;;)
1074 {
1075 unsigned short v;
1076
1077 v = mapfix[i << 1];
1078 if (gl == v)
1079 {
1080 gl = mapfix[(i << 1) + 1];
1081 FTLOCK();
1082 if (variation_sequence)
1083 result.index = FT_Face_GetCharVariantIndex(fi->src->ft.face, gl, variation_sequence);
1084 else
1085 result.index = FT_Get_Char_Index(fi->src->ft.face, gl);
1086 FTUNLOCK();
1087 break;
1088 }
1089 // failure to find at all
1090 if ((max - min) <= 2) break;
1091 // if glyph above out position...
1092 if (gl > v)
1093 {
1094 min = i;
1095 if ((max - min) == 1) i = max;
1096 else i = (min + max) / 2;
1097 }
1098 // if glyph below out position
1099 else if (gl < v)
1100 {
1101 max = i;
1102 if ((max - min) == 1) i = min;
1103 else i = (min + max) / 2;
1104 }
1105 }
1106 }
1107 return result.index;
1108 }
1109
1110
1111 /*
1112 * @internal
1113 * Search for unicode glyph inside all font files, and return font and glyph index
1114 *
1115 * @param[in] fn the font to use.
1116 * @param[out] fi_ret founded font.
1117 * @param[in] gl unicode glyph to search for
1118 * @param[in] variation_sequence for the gl glyph
1119 * @param[in] evas_font_search_options search options when searching font files
1120 *
1121 */
1122
1123 EAPI int
evas_common_font_glyph_search(RGBA_Font * fn,RGBA_Font_Int ** fi_ret,Eina_Unicode gl,Eina_Unicode variation_sequence,uint32_t evas_font_search_options)1124 evas_common_font_glyph_search(RGBA_Font *fn, RGBA_Font_Int **fi_ret, Eina_Unicode gl, Eina_Unicode variation_sequence, uint32_t evas_font_search_options)
1125 {
1126 Eina_List *l;
1127
1128 if (fn->fash)
1129 {
1130 const Fash_Item_Index_Map *fm = _fash_int_find(fn->fash, gl, variation_sequence);
1131 if (fm)
1132 {
1133 if (fm->fint)
1134 {
1135 if (evas_font_search_options == EVAS_FONT_SEARCH_OPTION_NONE)
1136 {
1137 *fi_ret = fm->fint;
1138 return fm->index;
1139 }
1140 else if( (evas_font_search_options & EVAS_FONT_SEARCH_OPTION_SKIP_COLOR) == EVAS_FONT_SEARCH_OPTION_SKIP_COLOR)
1141 {
1142 if (!fm->fint->src->ft.face)
1143 {
1144 evas_common_font_int_reload(fm->fint);
1145 }
1146
1147 if (fm->fint->src->ft.face && !FT_HAS_COLOR(fm->fint->src->ft.face))
1148 {
1149 *fi_ret = fm->fint;
1150 return fm->index;
1151 }
1152 }
1153 }
1154 else if (fm->index == -1) return 0;
1155 }
1156 }
1157
1158 for (l = fn->fonts; l; l = l->next)
1159 {
1160 RGBA_Font_Int *fi;
1161 int idx;
1162
1163 fi = l->data;
1164
1165 #if 0 /* FIXME: charmap user is disabled and use a deprecated data type. */
1166 /*
1167 if (fi->src->charmap) // Charmap loaded, FI/FS blank
1168 {
1169 idx = evas_array_hash_search(fi->src->charmap, gl);
1170 if (idx != 0)
1171 {
1172 evas_common_font_source_load_complete(fi->src);
1173 evas_common_font_int_load_complete(fi);
1174
1175 evas_array_hash_free(fi->src->charmap);
1176 fi->src->charmap = NULL;
1177
1178 *fi_ret = fi;
1179 return idx;
1180 }
1181 }
1182 else
1183 */
1184 #endif
1185 if (!fi->src->ft.face) /* Charmap not loaded, FI/FS blank */
1186 {
1187 evas_common_font_int_reload(fi);
1188 }
1189 if (fi->src->ft.face)
1190 {
1191 Eina_Bool is_color_only = (evas_font_search_options & EVAS_FONT_SEARCH_OPTION_SKIP_COLOR) == EVAS_FONT_SEARCH_OPTION_SKIP_COLOR &&
1192 FT_HAS_COLOR(fi->src->ft.face);
1193
1194 if (is_color_only)
1195 {
1196 /* This is color font ignore it */
1197 continue;
1198 }
1199
1200 idx = (int) evas_common_get_char_index(fi, gl, variation_sequence);
1201 if (idx != 0)
1202 {
1203 if (!fi->ft.size)
1204 evas_common_font_int_load_complete(fi);
1205 if (!is_color_only)
1206 {
1207 if (!fn->fash) fn->fash = _fash_int_new();
1208 if (fn->fash) _fash_int_add(fn->fash, gl, fi, idx, variation_sequence);
1209 }
1210 *fi_ret = fi;
1211 return idx;
1212 }
1213 else
1214 {
1215 if (!is_color_only)
1216 {
1217 if (!fn->fash) fn->fash = _fash_int_new();
1218 if (fn->fash) _fash_int_add(fn->fash, gl, NULL, -1, variation_sequence);
1219 }
1220 }
1221 }
1222 }
1223 *fi_ret = NULL;
1224 return 0;
1225 }
1226