[*]add ENV related with font dpi
[framework/uifw/evas.git] / src / lib / engines / common / evas_font_main.c
1 #include "evas_common.h"
2 #include "evas_private.h"
3
4 #include "evas_font_private.h"
5
6 #include FT_OUTLINE_H
7
8 FT_Library      evas_ft_lib = 0;
9 static int      initialised = 0;
10
11 LK(lock_font_draw); // for freetype2 API calls
12 LK(lock_bidi); // for evas bidi internal usage.
13 LK(lock_ot); // for evas bidi internal usage.
14
15 EAPI void
16 evas_common_font_init(void)
17 {
18    int error;
19    const char *s;
20
21    initialised++;
22    if (initialised != 1) return;
23    error = FT_Init_FreeType(&evas_ft_lib);
24    if (error) return;
25    evas_common_font_load_init();
26    evas_common_font_draw_init();
27    s = getenv("EVAS_FONT_DPI");
28    if (s)
29      {
30         int dpi = atoi(s);
31
32         if (dpi > 0) evas_common_font_dpi_set(dpi);
33      }
34    LKI(lock_font_draw);
35    LKI(lock_bidi);
36    LKI(lock_ot);
37 }
38
39 EAPI void
40 evas_common_font_shutdown(void)
41 {
42    int error;
43
44    if (initialised < 1) return;
45    initialised--;
46    if (initialised != 0) return;
47
48    LKD(lock_font_draw);
49    LKD(lock_bidi);
50    LKD(lock_ot);
51
52    evas_common_font_load_shutdown();
53    evas_common_font_cache_set(0);
54    evas_common_font_flush();
55
56    error = FT_Done_FreeType(evas_ft_lib);
57 #ifdef EVAS_FRAME_QUEUING
58    evas_common_font_draw_finish();
59 #endif
60    evas_ft_lib = 0;
61 }
62
63 EAPI void
64 evas_common_font_font_all_unload(void)
65 {
66    evas_common_font_all_clear();
67 }
68
69 EAPI int
70 evas_common_font_ascent_get(RGBA_Font *fn)
71 {
72    int val;
73    RGBA_Font_Int *fi;
74
75 //   evas_common_font_size_use(fn);
76 #if 0
77      {
78         Eina_List *l;
79         
80         EINA_LIST_FOREACH(fn->fonts, l, fi)
81           {
82              if (!fi->src->ft.face) continue;
83              if (fi->src->current_size != fi->size)
84                {
85                   FTLOCK();
86                   FT_Activate_Size(fi->ft.size);
87                   FTUNLOCK();
88                   fi->src->current_size = fi->size;
89                }
90              val = (int)fi->src->ft.face->size->metrics.ascender;
91              if (fi->src->ft.face->units_per_EM == 0)
92                return val;
93              dv = (fi->src->ft.orig_upem * 2048) / fi->src->ft.face->units_per_EM;
94              ret = (val * fi->src->ft.face->size->metrics.y_scale) / (dv * dv);
95              printf(" ==== %p: %i\n", fi, ret);
96           }
97      }
98 #endif
99    fi = fn->fonts->data;
100    evas_common_font_int_reload(fi);
101    if (fi->src->current_size != fi->size)
102      {
103         FTLOCK();
104         FT_Activate_Size(fi->ft.size);
105         FTUNLOCK();
106         fi->src->current_size = fi->size;
107      }
108    if (!FT_IS_SCALABLE(fi->src->ft.face))
109      {
110         WRN("NOT SCALABLE!");
111      }
112    val = (int)fi->src->ft.face->size->metrics.ascender;
113    return val >> 6;
114 //   printf("%i | %i\n", val, val >> 6);
115 //   if (fi->src->ft.face->units_per_EM == 0)
116 //     return val;
117 //   dv = (fi->src->ft.orig_upem * 2048) / fi->src->ft.face->units_per_EM;
118 //   ret = (val * fi->src->ft.face->size->metrics.y_scale) / (dv * dv);
119 //   return ret;
120 }
121
122 EAPI int
123 evas_common_font_descent_get(RGBA_Font *fn)
124 {
125    int val;
126    RGBA_Font_Int *fi;
127
128 //   evas_common_font_size_use(fn);
129    fi = fn->fonts->data;
130    evas_common_font_int_reload(fi);
131    if (fi->src->current_size != fi->size)
132      {
133         FTLOCK();
134         FT_Activate_Size(fi->ft.size);
135         FTUNLOCK();
136         fi->src->current_size = fi->size;
137      }
138    val = -(int)fi->src->ft.face->size->metrics.descender;
139    return val >> 6;
140 //   if (fi->src->ft.face->units_per_EM == 0)
141 //     return val;
142 //   dv = (fi->src->ft.orig_upem * 2048) / fi->src->ft.face->units_per_EM;
143 //   ret = (val * fi->src->ft.face->size->metrics.y_scale) / (dv * dv);
144 //   return ret;
145 }
146
147 EAPI int
148 evas_common_font_max_ascent_get(RGBA_Font *fn)
149 {
150    int val, dv;
151    int ret;
152    RGBA_Font_Int *fi;
153
154 //   evas_common_font_size_use(fn);
155    fi = fn->fonts->data;
156    evas_common_font_int_reload(fi);
157   if (fi->src->current_size != fi->size)
158      {
159         FTLOCK();
160         FT_Activate_Size(fi->ft.size);
161         FTUNLOCK();
162         fi->src->current_size = fi->size;
163      }
164    val = (int)fi->src->ft.face->bbox.yMax;
165    if (fi->src->ft.face->units_per_EM == 0)
166      return val;
167    dv = (fi->src->ft.orig_upem * 2048) / fi->src->ft.face->units_per_EM;
168    ret = (val * fi->src->ft.face->size->metrics.y_scale) / (dv * dv);
169    return ret;
170 }
171
172 EAPI int
173 evas_common_font_max_descent_get(RGBA_Font *fn)
174 {
175    int val, dv;
176    int ret;
177    RGBA_Font_Int *fi;
178
179 //   evas_common_font_size_use(fn);
180    fi = fn->fonts->data;
181    evas_common_font_int_reload(fi);
182    if (fi->src->current_size != fi->size)
183      {
184         FTLOCK();
185         FT_Activate_Size(fi->ft.size);
186         FTUNLOCK();
187         fi->src->current_size = fi->size;
188      }
189    val = -(int)fi->src->ft.face->bbox.yMin;
190    if (fi->src->ft.face->units_per_EM == 0)
191      return val;
192    dv = (fi->src->ft.orig_upem * 2048) / fi->src->ft.face->units_per_EM;
193    ret = (val * fi->src->ft.face->size->metrics.y_scale) / (dv * dv);
194    return ret;
195 }
196
197 EAPI int
198 evas_common_font_get_line_advance(RGBA_Font *fn)
199 {
200    int val;
201    RGBA_Font_Int *fi;
202
203 //   evas_common_font_size_use(fn);
204    fi = fn->fonts->data;
205    evas_common_font_int_reload(fi);
206    if (fi->src->current_size != fi->size)
207      {
208         FTLOCK();
209         FT_Activate_Size(fi->ft.size);
210         FTUNLOCK();
211         fi->src->current_size = fi->size;
212      }
213    val = (int)fi->src->ft.face->size->metrics.height;
214    if (fi->src->ft.face->units_per_EM == 0)
215      return val;
216    return val >> 6;
217 //   dv = (fi->src->ft.orig_upem * 2048) / fi->src->ft.face->units_per_EM;
218 //   ret = (val * fi->src->ft.face->size->metrics.y_scale) / (dv * dv);
219 //   return ret;
220 }
221
222 /* Set of common functions that are used in a couple of places. */
223
224 static void
225 _fash_int2_free(Fash_Int_Map2 *fash)
226 {
227    int i;
228
229    for (i = 0; i < 256; i++) if (fash->bucket[i]) free(fash->bucket[i]);
230    free(fash);
231 }
232
233 static void
234 _fash_int_free(Fash_Int *fash)
235 {
236    int i;
237
238    for (i = 0; i < 256; i++) if (fash->bucket[i]) _fash_int2_free(fash->bucket[i]);
239    free(fash);
240 }
241
242 static Fash_Int *
243 _fash_int_new(void)
244 {
245    Fash_Int *fash = calloc(1, sizeof(Fash_Int));
246    fash->freeme = _fash_int_free;
247    return fash;
248 }
249
250 static Fash_Item_Index_Map *
251 _fash_int_find(Fash_Int *fash, int item)
252 {
253    int grp, maj, min;
254
255    // 24bits for unicode - v6 up to E01EF (chrs) & 10FFFD for private use (plane 16)
256    grp = (item >> 16) & 0xff;
257    maj = (item >> 8) & 0xff;
258    min = item & 0xff;
259    if (!fash->bucket[grp]) return NULL;
260    if (!fash->bucket[grp]->bucket[maj]) return NULL;
261    return &(fash->bucket[grp]->bucket[maj]->item[min]);
262 }
263
264 static void
265 _fash_int_add(Fash_Int *fash, int item, RGBA_Font_Int *fint, int idx)
266 {
267    int grp, maj, min;
268
269    // 24bits for unicode - v6 up to E01EF (chrs) & 10FFFD for private use (plane 16)
270    grp = (item >> 16) & 0xff;
271    maj = (item >> 8) & 0xff;
272    min = item & 0xff;
273    if (!fash->bucket[grp])
274      fash->bucket[grp] = calloc(1, sizeof(Fash_Int_Map2));
275    EINA_SAFETY_ON_NULL_RETURN(fash->bucket[grp]);
276    if (!fash->bucket[grp]->bucket[maj])
277      fash->bucket[grp]->bucket[maj] = calloc(1, sizeof(Fash_Int_Map));
278    EINA_SAFETY_ON_NULL_RETURN(fash->bucket[grp]->bucket[maj]);
279    fash->bucket[grp]->bucket[maj]->item[min].fint = fint;
280    fash->bucket[grp]->bucket[maj]->item[min].index = idx;
281 }
282
283 static void
284 _fash_gl2_free(Fash_Glyph_Map2 *fash)
285 {
286    int i;
287
288    for (i = 0; i < 256; i++) if (fash->bucket[i]) free(fash->bucket[i]);
289    free(fash);
290 }
291
292 static void
293 _fash_gl_free(Fash_Glyph *fash)
294 {
295    int i;
296
297    for (i = 0; i < 256; i++) if (fash->bucket[i]) _fash_gl2_free(fash->bucket[i]);
298    free(fash);
299 }
300
301 static Fash_Glyph *
302 _fash_gl_new(void)
303 {
304    Fash_Glyph *fash = calloc(1, sizeof(Fash_Glyph));
305    fash->freeme = _fash_gl_free;
306    return fash;
307 }
308
309 static RGBA_Font_Glyph *
310 _fash_gl_find(Fash_Glyph *fash, int item)
311 {
312    int grp, maj, min;
313
314    // 24bits for unicode - v6 up to E01EF (chrs) & 10FFFD for private use (plane 16)
315    grp = (item >> 16) & 0xff;
316    maj = (item >> 8) & 0xff;
317    min = item & 0xff;
318    if (!fash->bucket[grp]) return NULL;
319    if (!fash->bucket[grp]->bucket[maj]) return NULL;
320    return fash->bucket[grp]->bucket[maj]->item[min];
321 }
322
323 static void
324 _fash_gl_add(Fash_Glyph *fash, int item, RGBA_Font_Glyph *glyph)
325 {
326    int grp, maj, min;
327
328    // 24bits for unicode - v6 up to E01EF (chrs) & 10FFFD for private use (plane 16)
329    grp = (item >> 16) & 0xff;
330    maj = (item >> 8) & 0xff;
331    min = item & 0xff;
332    if (!fash->bucket[grp])
333      fash->bucket[grp] = calloc(1, sizeof(Fash_Glyph_Map2));
334    EINA_SAFETY_ON_NULL_RETURN(fash->bucket[grp]);
335    if (!fash->bucket[grp]->bucket[maj])
336      fash->bucket[grp]->bucket[maj] = calloc(1, sizeof(Fash_Glyph_Map));
337    EINA_SAFETY_ON_NULL_RETURN(fash->bucket[grp]->bucket[maj]);
338    fash->bucket[grp]->bucket[maj]->item[min] = glyph;
339 }
340
341 EAPI RGBA_Font_Glyph *
342 evas_common_font_int_cache_glyph_get(RGBA_Font_Int *fi, FT_UInt idx)
343 {
344    RGBA_Font_Glyph *fg;
345    FT_UInt hindex;
346    FT_Error error;
347    int size;
348    const FT_Int32 hintflags[3] =
349      { FT_LOAD_NO_HINTING, FT_LOAD_FORCE_AUTOHINT, FT_LOAD_NO_AUTOHINT };
350    static FT_Matrix transform = {0x10000, 0x05000, 0x0000, 0x10000}; // about 12 degree.
351
352    evas_common_font_int_promote(fi);
353    if (fi->fash)
354      {
355         fg = _fash_gl_find(fi->fash, idx);
356         if (fg == (void *)(-1)) return NULL;
357         else if (fg) return fg;
358      }
359
360    hindex = idx + (fi->hinting * 500000000);
361
362 //   fg = eina_hash_find(fi->glyphs, &hindex);
363 //   if (fg) return fg;
364
365    evas_common_font_int_reload(fi);
366    FTLOCK();
367    error = FT_Load_Glyph(fi->src->ft.face, idx,
368                          FT_LOAD_DEFAULT | FT_LOAD_NO_BITMAP |
369                          hintflags[fi->hinting]);
370    FTUNLOCK();
371    if (error)
372      {
373         if (!fi->fash) fi->fash = _fash_gl_new();
374         if (fi->fash) _fash_gl_add(fi->fash, idx, (void *)(-1));
375         return NULL;
376      }
377
378    /* Transform the outline of Glyph according to runtime_rend. */
379    if (fi->runtime_rend & FONT_REND_SLANT)
380       FT_Outline_Transform(&fi->src->ft.face->glyph->outline, &transform);
381    /* Embolden the outline of Glyph according to rundtime_rend. */
382    if (fi->runtime_rend & FONT_REND_WEIGHT)
383       FT_Outline_Embolden(&fi->src->ft.face->glyph->outline,
384             (fi->src->ft.face->size->metrics.x_ppem * 5 * 64) / 100);
385
386    fg = malloc(sizeof(struct _RGBA_Font_Glyph));
387    if (!fg) return NULL;
388    memset(fg, 0, (sizeof(struct _RGBA_Font_Glyph)));
389
390    FTLOCK();
391    error = FT_Get_Glyph(fi->src->ft.face->glyph, &(fg->glyph));
392    FTUNLOCK();
393    if (error)
394      {
395         free(fg);
396         if (!fi->fash) fi->fash = _fash_gl_new();
397         if (fi->fash) _fash_gl_add(fi->fash, idx, (void *)(-1));
398         return NULL;
399      }
400
401    FTLOCK();
402    error = FT_Glyph_To_Bitmap(&(fg->glyph), FT_RENDER_MODE_NORMAL, 0, 1);
403    if (error)
404      {
405         FT_Done_Glyph(fg->glyph);
406         FTUNLOCK();
407         free(fg);
408         if (!fi->fash) fi->fash = _fash_gl_new();
409         if (fi->fash) _fash_gl_add(fi->fash, idx, (void *)(-1));
410         return NULL;
411      }
412    FTUNLOCK();
413
414    fg->glyph_out = (FT_BitmapGlyph)fg->glyph;
415    fg->index = hindex;
416    fg->fi = fi;
417
418    if (!fi->fash) fi->fash = _fash_gl_new();
419    if (fi->fash) _fash_gl_add(fi->fash, idx, fg);
420    /* This '+ 200' is just an estimation of how much memory freetype will use
421     * on it's size. This value is not really used anywhere in code - it's
422     * only for statistics. */
423    size = sizeof(RGBA_Font_Glyph) + sizeof(Eina_List) +
424     (fg->glyph_out->bitmap.width * fg->glyph_out->bitmap.rows) + 200;
425    fi->usage += size;
426    if (fi->inuse) evas_common_font_int_use_increase(size);
427
428 //   eina_hash_direct_add(fi->glyphs, &fg->index, fg);
429    return fg;
430 }
431
432 typedef struct _Font_Char_Index Font_Char_Index;
433 struct _Font_Char_Index
434 {
435    FT_UInt index;
436    Eina_Unicode gl;
437 };
438
439 EAPI FT_UInt
440 evas_common_get_char_index(RGBA_Font_Int* fi, Eina_Unicode gl)
441 {
442    Font_Char_Index result;
443    //FT_UInt ret;
444
445 #ifdef HAVE_PTHREAD
446 ///   pthread_mutex_lock(&fi->ft_mutex);
447 #endif
448
449 //   result = eina_hash_find(fi->indexes, &gl);
450 //   if (result) goto on_correct;
451 //
452 //   result = malloc(sizeof (Font_Char_Index));
453 //   if (!result)
454 //     {
455 //#ifdef HAVE_PTHREAD
456 //      pthread_mutex_unlock(&fi->ft_mutex);
457 //#endif
458 //      return FT_Get_Char_Index(fi->src->ft.face, gl);
459 //     }
460
461    evas_common_font_int_reload(fi);
462    FTLOCK();
463    result.index = FT_Get_Char_Index(fi->src->ft.face, gl);
464    FTUNLOCK();
465    result.gl = gl;
466
467 //   eina_hash_direct_add(fi->indexes, &result->gl, result);
468 //
469 // on_correct:
470 #ifdef HAVE_PTHREAD
471 //   pthread_mutex_unlock(&fi->ft_mutex);
472 #endif
473    return result.index;
474 }
475
476 EAPI int
477 evas_common_font_glyph_search(RGBA_Font *fn, RGBA_Font_Int **fi_ret, Eina_Unicode gl)
478 {
479    Eina_List *l;
480
481    if (fn->fash)
482      {
483         Fash_Item_Index_Map *fm = _fash_int_find(fn->fash, gl);
484         if (fm)
485           {
486              if (fm->fint)
487                {
488                   *fi_ret = fm->fint;
489                   return fm->index;
490                }
491              else if (fm->index == -1) return 0;
492           }
493      }
494
495    for (l = fn->fonts; l; l = l->next)
496      {
497         RGBA_Font_Int *fi;
498         int idx;
499
500         fi = l->data;
501
502 #if 0 /* FIXME: charmap user is disabled and use a deprecated data type. */
503 /*        
504         if (fi->src->charmap) // Charmap loaded, FI/FS blank
505           {
506              idx = evas_array_hash_search(fi->src->charmap, gl);
507              if (idx != 0)
508                {
509                   evas_common_font_source_load_complete(fi->src);
510                   evas_common_font_int_load_complete(fi);
511
512                   evas_array_hash_free(fi->src->charmap);
513                   fi->src->charmap = NULL;
514
515                   *fi_ret = fi;
516                   return idx;
517                }
518            }
519         else
520 */
521 #endif
522         if (!fi->src->ft.face) /* Charmap not loaded, FI/FS blank */
523           {
524              evas_common_font_int_reload(fi);
525           }
526         if (fi->src->ft.face)
527           {
528              idx = evas_common_get_char_index(fi, gl);
529              if (idx != 0)
530                {
531                   if (!fi->ft.size)
532                     evas_common_font_int_load_complete(fi);
533                   if (!fn->fash) fn->fash = _fash_int_new();
534                   if (fn->fash) _fash_int_add(fn->fash, gl, fi, idx);
535                   *fi_ret = fi;
536                   return idx;
537                }
538              else
539                {
540                   if (!fn->fash) fn->fash = _fash_int_new();
541                   if (fn->fash) _fash_int_add(fn->fash, gl, NULL, -1);
542                }
543           }
544      }
545    *fi_ret = NULL;
546    return 0;
547 }