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