Evas font/textblock/text: Started using string objects instead of
[framework/uifw/evas.git] / src / lib / engines / common / evas_font_ot.c
1 #include "evas_font_ot.h"
2
3 #ifdef OT_SUPPORT
4 # include <hb.h>
5 # include <hb-ft.h>
6 #endif
7
8 #include "evas_common.h"
9
10 #include <Eina.h>
11 #include "evas_font_private.h"
12
13 #ifdef OT_SUPPORT
14 /* FIXME: doc. returns #items */
15 EAPI int
16 evas_common_font_ot_cluster_size_get(const Evas_Text_Props *props, size_t char_index)
17 {
18    int i;
19    int items;
20    int left_bound, right_bound;
21    size_t base_cluster = EVAS_FONT_OT_POS_GET(props->info->ot[char_index]);
22    for (i = (int) char_index ;
23          (i >= (int) props->start) &&
24          (EVAS_FONT_OT_POS_GET(props->info->ot[i]) == base_cluster) ;
25          i--)
26      ;
27    left_bound = i;
28    for (i = (int) char_index + 1;
29          (i < (int) (props->start + props->len)) &&
30          (EVAS_FONT_OT_POS_GET(props->info->ot[i]) == base_cluster) ;
31          i++)
32      ;
33    right_bound = i;
34    if (left_bound < 0)
35       left_bound = 0;
36    if (right_bound >= (int) (props->start + props->len))
37       right_bound = props->start + props->len - 1;
38
39    if (right_bound == left_bound)
40      {
41         items = 1;
42      }
43    else if (props->bidi.dir == EVAS_BIDI_DIRECTION_RTL)
44      {
45         if (left_bound < 0)
46           {
47              items = props->start + props->len -
48                 props->info->ot[left_bound + 1].source_cluster;
49           }
50         else
51           {
52              items = props->info->ot[left_bound].source_cluster -
53                 props->info->ot[left_bound + 1].source_cluster;
54           }
55      }
56    else
57      {
58         if (right_bound == (int) (props->start + props->len))
59           {
60              items = props->start + props->len -
61                 props->info->ot[right_bound - 1].source_cluster;
62           }
63         else
64           {
65              items = props->info->ot[right_bound].source_cluster -
66                 props->info->ot[right_bound - 1].source_cluster;
67           }
68      }
69    return (items > 0) ? items : 1;
70 }
71
72 EAPI void
73 evas_common_font_ot_load_face(void *_font)
74 {
75    RGBA_Font_Source *font = (RGBA_Font_Source *) _font;
76    /* Unload the face if by any chance it's already loaded */
77    evas_common_font_ot_unload_face(font);
78    font->hb.face = hb_ft_face_create(font->ft.face, NULL);
79 }
80
81 EAPI void
82 evas_common_font_ot_unload_face(void *_font)
83 {
84    RGBA_Font_Source *font = (RGBA_Font_Source *) _font;
85    if (!font->hb.face) return;
86    hb_face_destroy(font->hb.face);
87    font->hb.face = NULL;
88 }
89
90 static void
91 _evas_common_font_ot_shape(hb_buffer_t *buffer, RGBA_Font_Source *src)
92 {
93    hb_font_t   *hb_font;
94
95    hb_font = hb_ft_font_create(src->ft.face, NULL);
96
97    hb_shape(hb_font, src->hb.face, buffer, NULL, 0);
98    hb_font_destroy(hb_font);
99 }
100
101 EAPI Eina_Bool
102 evas_common_font_ot_populate_text_props(void *_fn, const Eina_Unicode *text,
103       Evas_Text_Props *props, int len)
104 {
105    RGBA_Font *fn = (RGBA_Font *) _fn;
106    RGBA_Font_Int *fi;
107    hb_buffer_t *buffer;
108    hb_glyph_position_t *positions;
109    hb_glyph_info_t *infos;
110    int slen;
111    unsigned int i;
112
113    fi = fn->fonts->data;
114    /* Load the font needed for this script */
115      {
116         /* Skip common chars */
117         const Eina_Unicode *tmp;
118         for (tmp = text ;
119               *tmp &&
120               evas_common_language_char_script_get(*tmp) == EVAS_SCRIPT_COMMON ;
121               tmp++)
122           ;
123         if (!*tmp && (tmp > text)) tmp--;
124         evas_common_font_glyph_search(fn, &fi, *tmp);
125      }
126    evas_common_font_int_reload(fi);
127    if (fi->src->current_size != fi->size)
128      {
129         FTLOCK();
130         FT_Activate_Size(fi->ft.size);
131         FTUNLOCK();
132         fi->src->current_size = fi->size;
133      }
134
135    if (len < 0)
136      {
137         slen = eina_unicode_strlen(text);
138      }
139    else
140      {
141         slen = len;
142      }
143
144    buffer = hb_buffer_create(slen);
145    hb_buffer_set_unicode_funcs(buffer, evas_common_language_unicode_funcs_get());
146    hb_buffer_set_language(buffer, hb_language_from_string(
147             evas_common_language_from_locale_get()));
148    hb_buffer_set_script(buffer, props->script);
149    hb_buffer_set_direction(buffer,
150          (props->bidi.dir == EVAS_BIDI_DIRECTION_RTL) ?
151          HB_DIRECTION_RTL : HB_DIRECTION_LTR);
152    /* FIXME: add run-time conversions if needed, which is very unlikely */
153    hb_buffer_add_utf32(buffer, (const uint32_t *) text, slen, 0, slen);
154
155    _evas_common_font_ot_shape(buffer, fi->src);
156
157    props->len = hb_buffer_get_length(buffer);
158    props->info->ot = calloc(props->len,
159          sizeof(Evas_Font_OT_Info));
160    props->info->glyph = calloc(props->len,
161               sizeof(Evas_Font_Glyph_Info));
162    positions = hb_buffer_get_glyph_positions(buffer);
163    infos = hb_buffer_get_glyph_infos(buffer);
164    for (i = 0 ; i < props->len ; i++)
165      {
166         props->info->ot[i].source_cluster = infos[i].cluster;
167         props->info->ot[i].x_offset = positions[i].x_offset;
168         props->info->ot[i].y_offset = positions[i].y_offset;
169         props->info->glyph[i].index = infos[i].codepoint;
170         props->info->glyph[i].advance = positions[i].x_advance;
171      }
172
173    hb_buffer_destroy(buffer);
174    evas_common_font_int_use_trim();
175
176    return EINA_FALSE;
177 }
178
179 #endif
180