Evas font-engine: Fixed walking to use ptrs instead of indexes.
[profile/ivi/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;
22    char_index += props->start;
23    base_cluster = EVAS_FONT_OT_POS_GET(props->info->ot[char_index]);
24    for (i = (int) char_index ;
25          (i >= (int) props->start) &&
26          (EVAS_FONT_OT_POS_GET(props->info->ot[i]) == base_cluster) ;
27          i--)
28      ;
29    left_bound = i;
30    for (i = (int) char_index + 1;
31          (i < (int) (props->start + props->len)) &&
32          (EVAS_FONT_OT_POS_GET(props->info->ot[i]) == base_cluster) ;
33          i++)
34      ;
35    right_bound = i;
36
37    if (right_bound == left_bound)
38      {
39         items = 1;
40      }
41    else if (props->bidi.dir == EVAS_BIDI_DIRECTION_RTL)
42      {
43         if (left_bound < 0)
44           {
45              items = props->text_offset + props->text_len - base_cluster;
46           }
47         else
48           {
49              items = props->info->ot[left_bound].source_cluster - base_cluster;
50           }
51      }
52    else
53      {
54         if (right_bound >= (int) (props->text_offset + props->text_len))
55           {
56              items = props->text_offset + props->text_len - base_cluster;
57           }
58         else
59           {
60              items = props->info->ot[right_bound].source_cluster - base_cluster;
61           }
62      }
63    return (items > 0) ? items : 1;
64 }
65
66 EAPI void
67 evas_common_font_ot_load_face(void *_font)
68 {
69    RGBA_Font_Source *font = (RGBA_Font_Source *) _font;
70    /* Unload the face if by any chance it's already loaded */
71    evas_common_font_ot_unload_face(font);
72    font->hb.face = hb_ft_face_create(font->ft.face, NULL);
73 }
74
75 EAPI void
76 evas_common_font_ot_unload_face(void *_font)
77 {
78    RGBA_Font_Source *font = (RGBA_Font_Source *) _font;
79    if (!font->hb.face) return;
80    hb_face_destroy(font->hb.face);
81    font->hb.face = NULL;
82 }
83
84 /* Harfbuzz font functions */
85 static hb_font_funcs_t *_ft_font_funcs = NULL;
86
87 static hb_codepoint_t
88 _evas_common_font_ot_hb_get_glyph(hb_font_t *font, hb_face_t *face,
89     const void *user_data, hb_codepoint_t unicode,
90     hb_codepoint_t variation_selector)
91 {
92    RGBA_Font_Int *fi = (RGBA_Font_Int *) user_data;
93    return hb_font_funcs_get_glyph_func(_ft_font_funcs)(font, face,
94       fi->src->ft.face, unicode, variation_selector);
95 }
96
97 static void
98 _evas_common_font_ot_hb_get_glyph_advance(hb_font_t *font, hb_face_t *face,
99    const void *user_data, hb_codepoint_t glyph,
100    hb_position_t *x_advance, hb_position_t *y_advance)
101 {
102    /* Use our cache*/
103    RGBA_Font_Int *fi = (RGBA_Font_Int *) user_data;
104    RGBA_Font_Glyph *fg;
105    (void) font;
106    (void) face;
107    fg = evas_common_font_int_cache_glyph_get(fi, glyph);
108    if (fg)
109      {
110         *x_advance = fg->glyph->advance.x >> 10;
111         *y_advance = fg->glyph->advance.y >> 10;
112      }
113 }
114
115 static void
116 _evas_common_font_ot_hb_get_glyph_extents(hb_font_t *font, hb_face_t *face,
117    const void *user_data, hb_codepoint_t glyph, hb_glyph_extents_t *extents)
118 {
119    RGBA_Font_Int *fi = (RGBA_Font_Int *) user_data;
120    hb_font_funcs_get_glyph_extents_func(_ft_font_funcs)(font, face,
121       fi->src->ft.face, glyph, extents);
122 }
123
124 static hb_bool_t
125 _evas_common_font_ot_hb_get_contour_point(hb_font_t *font, hb_face_t *face,
126    const void *user_data, unsigned int point_index, hb_codepoint_t glyph,
127    hb_position_t *x, hb_position_t *y)
128 {
129    RGBA_Font_Int *fi = (RGBA_Font_Int *) user_data;
130    return hb_font_funcs_get_contour_point_func(_ft_font_funcs)(font, face,
131       fi->src->ft.face, point_index, glyph, x, y);
132 }
133
134 static hb_position_t
135 _evas_common_font_ot_hb_get_kerning(hb_font_t *font, hb_face_t *face,
136    const void *user_data, hb_codepoint_t first_glyph,
137    hb_codepoint_t second_glyph)
138 {
139    RGBA_Font_Int *fi = (RGBA_Font_Int *) user_data;
140    int kern;
141    (void) font;
142    (void) face;
143    if (evas_common_font_query_kerning(fi, first_glyph, second_glyph, &kern))
144       return kern;
145    else
146       return 0;
147 }
148
149 /* End of harfbuzz font funcs */
150
151 static hb_font_funcs_t *
152 _evas_common_font_ot_font_funcs_get(void)
153 {
154    static hb_font_funcs_t *font_funcs = NULL;
155    if (!font_funcs)
156      {
157         _ft_font_funcs = hb_ft_get_font_funcs();
158         font_funcs = hb_font_funcs_create();
159         hb_font_funcs_set_glyph_func(font_funcs,
160             _evas_common_font_ot_hb_get_glyph);
161         hb_font_funcs_set_glyph_advance_func(font_funcs,
162             _evas_common_font_ot_hb_get_glyph_advance);
163         hb_font_funcs_set_glyph_extents_func(font_funcs,
164             _evas_common_font_ot_hb_get_glyph_extents);
165         hb_font_funcs_set_contour_point_func(font_funcs,
166             _evas_common_font_ot_hb_get_contour_point);
167         hb_font_funcs_set_kerning_func(font_funcs,
168             _evas_common_font_ot_hb_get_kerning);
169      }
170
171    return font_funcs;
172 }
173
174 static void
175 _evas_common_font_ot_shape(hb_buffer_t *buffer, RGBA_Font_Int *fi)
176 {
177    hb_font_t   *hb_font;
178
179    hb_font = hb_ft_font_create(fi->src->ft.face, NULL);
180    hb_font_set_funcs(hb_font, _evas_common_font_ot_font_funcs_get(), NULL, fi);
181
182    hb_shape(hb_font, fi->src->hb.face, buffer, NULL, 0);
183    hb_font_destroy(hb_font);
184 }
185
186 EAPI Eina_Bool
187 evas_common_font_ot_populate_text_props(void *_fn, const Eina_Unicode *text,
188       Evas_Text_Props *props, int len)
189 {
190    RGBA_Font *fn = (RGBA_Font *) _fn;
191    RGBA_Font_Int *fi;
192    hb_buffer_t *buffer;
193    hb_glyph_position_t *positions;
194    hb_glyph_info_t *infos;
195    int slen;
196    unsigned int i;
197
198    fi = fn->fonts->data;
199    /* Load the font needed for this script */
200      {
201         /* Skip common chars */
202         const Eina_Unicode *tmp;
203         for (tmp = text ;
204               *tmp &&
205               evas_common_language_char_script_get(*tmp) == EVAS_SCRIPT_COMMON ;
206               tmp++)
207           ;
208         if (!*tmp && (tmp > text)) tmp--;
209         evas_common_font_glyph_search(fn, &fi, *tmp);
210      }
211    evas_common_font_int_reload(fi);
212    if (fi->src->current_size != fi->size)
213      {
214         FTLOCK();
215         FT_Activate_Size(fi->ft.size);
216         FTUNLOCK();
217         fi->src->current_size = fi->size;
218      }
219
220    if (len < 0)
221      {
222         slen = eina_unicode_strlen(text);
223      }
224    else
225      {
226         slen = len;
227      }
228
229    buffer = hb_buffer_create(slen);
230    hb_buffer_set_unicode_funcs(buffer, evas_common_language_unicode_funcs_get());
231    hb_buffer_set_language(buffer, hb_language_from_string(
232             evas_common_language_from_locale_get()));
233    hb_buffer_set_script(buffer, props->script);
234    hb_buffer_set_direction(buffer,
235          (props->bidi.dir == EVAS_BIDI_DIRECTION_RTL) ?
236          HB_DIRECTION_RTL : HB_DIRECTION_LTR);
237    /* FIXME: add run-time conversions if needed, which is very unlikely */
238    hb_buffer_add_utf32(buffer, (const uint32_t *) text, slen, 0, slen);
239
240    _evas_common_font_ot_shape(buffer, fi);
241
242    props->len = hb_buffer_get_length(buffer);
243    props->info->ot = calloc(props->len,
244          sizeof(Evas_Font_OT_Info));
245    props->info->glyph = calloc(props->len,
246               sizeof(Evas_Font_Glyph_Info));
247    positions = hb_buffer_get_glyph_positions(buffer);
248    infos = hb_buffer_get_glyph_infos(buffer);
249    for (i = 0 ; i < props->len ; i++)
250      {
251         props->info->ot[i].source_cluster = infos[i].cluster;
252         props->info->ot[i].x_offset = positions[i].x_offset;
253         props->info->ot[i].y_offset = positions[i].y_offset;
254         props->info->glyph[i].index = infos[i].codepoint;
255         props->info->glyph[i].advance = positions[i].x_advance;
256      }
257
258    hb_buffer_destroy(buffer);
259    evas_common_font_int_use_trim();
260
261    return EINA_FALSE;
262 }
263
264 #endif
265