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