1 #include "evas_common.h"
2 #include "evas_font_private.h"
3 #include "evas_text_utils.h"
4 #include "language/evas_bidi_utils.h"
5 #include "language/evas_language_utils.h"
6 #include "evas_font_ot.h"
8 #define PROPS_CHANGE(Props) Props->changed = EINA_TRUE;
11 evas_common_text_props_bidi_set(Evas_Text_Props *props,
12 Evas_BiDi_Paragraph_Props *bidi_par_props, size_t start)
15 props->bidi.dir = (evas_bidi_is_rtl_char(
18 start)) ? EVAS_BIDI_DIRECTION_RTL : EVAS_BIDI_DIRECTION_LTR;
21 (void) bidi_par_props;
22 props->bidi.dir = EVAS_BIDI_DIRECTION_LTR;
28 evas_common_text_props_script_set(Evas_Text_Props *props, Evas_Script_Type scr)
35 evas_common_text_props_content_copy_and_ref(Evas_Text_Props *dst,
36 const Evas_Text_Props *src)
38 memcpy(dst, src, sizeof(Evas_Text_Props));
39 evas_common_text_props_content_ref(dst);
43 evas_common_text_props_content_ref(Evas_Text_Props *props)
45 /* No content in this case */
49 props->info->refcount++;
53 evas_common_text_props_content_unref(Evas_Text_Props *props)
55 /* No content in this case */
59 if (--(props->info->refcount) == 0)
61 if (props->info->glyph)
62 free(props->info->glyph);
65 free(props->info->ot);
73 _evas_common_text_props_cluster_move(const Evas_Text_Props *props, int pos,
76 int prop_pos = evas_common_text_props_index_find(props, pos);
77 if (!right && (prop_pos > 0))
80 return props->info->ot[props->start + prop_pos - 1].source_cluster -
83 return props->start + prop_pos - 1 - props->text_offset;
86 else if (right && (prop_pos < (int) (props->len - 1)))
89 return props->info->ot[props->start + prop_pos + 1].source_cluster -
92 return props->start + prop_pos + 1 - props->text_offset;
100 evas_common_text_props_cluster_next(const Evas_Text_Props *props, int pos)
103 /* Move right if we are in a non-rtl text */
104 right = (props->bidi.dir != EVAS_BIDI_DIRECTION_RTL);
105 return _evas_common_text_props_cluster_move(props, pos, right);
109 evas_common_text_props_cluster_prev(const Evas_Text_Props *props, int pos)
112 /* Move right if we are in an rtl text */
113 right = (props->bidi.dir == EVAS_BIDI_DIRECTION_RTL);
114 return _evas_common_text_props_cluster_move(props, pos, right);
117 /* Returns the index of the logical char in the props. */
119 evas_common_text_props_index_find(const Evas_Text_Props *props, int _cutoff)
122 Evas_Font_OT_Info *ot_info;
124 int max = props->len - 1;
127 _cutoff += props->text_offset;
128 ot_info = props->info->ot + props->start;
129 /* Should get us closer to the right place. */
130 if ((min <= _cutoff) && (_cutoff <= max))
133 mid = (min + max) / 2;
135 if (props->bidi.dir == EVAS_BIDI_DIRECTION_RTL)
137 /* Monotonic in a descending order */
140 if (_cutoff > (int) ot_info[mid].source_cluster)
142 else if (_cutoff < (int) ot_info[mid].source_cluster)
147 mid = (min + max) / 2;
153 /* Monotonic in an ascending order */
156 if (_cutoff < (int) ot_info[mid].source_cluster)
158 else if (_cutoff > (int) ot_info[mid].source_cluster)
163 mid = (min + max) / 2;
168 /* If we didn't find, abort */
173 if (props->bidi.dir == EVAS_BIDI_DIRECTION_RTL)
175 /* Walk to the last one of the same cluster */
176 for ( ; mid < (int) props->len ; mid++, ot_info++)
178 if (ot_info->source_cluster != (size_t) _cutoff)
185 /* Walk to the last one of the same cluster */
186 for ( ; mid >= 0 ; mid--, ot_info--)
188 if (ot_info->source_cluster != (size_t) _cutoff)
201 /* Won't work in the middle of ligatures, assumes cutoff < len.
202 * Also won't work in the middle of indic words, should handle that in a
205 evas_common_text_props_split(Evas_Text_Props *base,
206 Evas_Text_Props *ext, int _cutoff)
210 /* Translate text cutoff pos to string object cutoff point */
212 _cutoff = evas_common_text_props_index_find(base, _cutoff);
216 cutoff = (size_t) _cutoff;
220 ERR("Couldn't find the cutoff position. Is it inside a cluster?");
224 cutoff = (size_t) _cutoff;
227 evas_common_text_props_content_copy_and_ref(ext, base);
228 if (base->bidi.dir == EVAS_BIDI_DIRECTION_RTL)
230 ext->start = base->start;
231 ext->len = cutoff + 1;
232 base->start = base->start + ext->len;
233 base->len = base->len - ext->len;
237 ext->info->ot[ext->start + ext->len - 1].source_cluster;
239 ext->text_offset = base->text_offset + base->len;
244 ext->start = base->start + cutoff;
245 ext->len = base->len - cutoff;
249 ext->text_offset = ext->info->ot[ext->start].source_cluster;
251 ext->text_offset = base->text_offset + base->len;
254 ext->text_len = base->text_len - (ext->text_offset - base->text_offset);
255 base->text_len = (ext->text_offset - base->text_offset);
260 /* Won't work in the middle of ligatures */
262 evas_common_text_props_merge(Evas_Text_Props *item1,
263 const Evas_Text_Props *item2)
265 if (item1->info != item2->info)
267 ERR("tried merge back items that weren't together in the first place.");
270 if (item1->bidi.dir == EVAS_BIDI_DIRECTION_RTL)
272 item1->start = item2->start;
275 item1->len += item2->len;
276 item1->text_len += item2->text_len;
281 evas_common_text_props_content_create(void *_fi, const Eina_Unicode *text,
282 Evas_Text_Props *text_props, const Evas_BiDi_Paragraph_Props *par_props,
283 size_t par_pos, int len)
285 RGBA_Font_Int *fi = (RGBA_Font_Int *) _fi;
287 if (text_props->info)
289 evas_common_text_props_content_unref(text_props);
293 text_props->info = NULL;
294 text_props->start = text_props->len = text_props->text_offset = 0;
296 text_props->info = calloc(1, sizeof(Evas_Text_Props_Info));
298 text_props->font_instance = fi;
300 evas_common_font_int_reload(fi);
301 if (fi->src->current_size != fi->size)
304 FT_Activate_Size(fi->ft.size);
306 fi->src->current_size = fi->size;
309 text_props->changed = EINA_TRUE;
313 Evas_Font_Glyph_Info *gl_itr;
314 Evas_Coord pen_x = 0, adjust_x = 0;
318 evas_common_font_ot_populate_text_props(text, text_props, len);
320 gl_itr = text_props->info->glyph;
321 for (char_index = 0 ; char_index < text_props->len ; char_index++)
325 Eina_Bool is_replacement = EINA_FALSE;
326 /* If we got a malformed index, show the replacement char instead */
327 if (gl_itr->index == 0)
329 gl_itr->index = evas_common_get_char_index(fi, REPLACEMENT_CHAR);
330 is_replacement = EINA_TRUE;
334 fg = evas_common_font_int_cache_glyph_get(fi, idx);
342 gl_itr->x_bear = fg->x_bear;
343 gl_itr->width = fg->width;
344 /* text_props->info->glyph[char_index].advance =
345 * text_props->info->glyph[char_index].index =
346 * already done by the ot function */
347 if (EVAS_FONT_CHARACTER_IS_INVISIBLE(
348 text[text_props->info->ot[char_index].source_cluster]))
351 /* Reduce the current advance */
352 if (gl_itr > text_props->info->glyph)
354 adjust_x -= gl_itr->pen_after - (gl_itr - 1)->pen_after;
358 adjust_x -= gl_itr->pen_after;
365 /* Update the advance accordingly */
366 adjust_x += (pen_x + (fg->glyph->advance.x >> 16)) -
369 pen_x = gl_itr->pen_after;
371 gl_itr->pen_after += adjust_x;
373 fi = text_props->font_instance;
377 /* We are walking the string in visual ordering */
378 Evas_Font_Glyph_Info *gl_itr;
379 Eina_Bool use_kerning;
381 FT_Face pface = NULL;
382 Evas_Coord pen_x = 0;
384 #if !defined(OT_SUPPORT) && defined(BIDI_SUPPORT)
385 Eina_Unicode *base_str = NULL;
386 if (text_props->bidi.dir == EVAS_BIDI_DIRECTION_RTL)
388 text = base_str = eina_unicode_strndup(text, len);
389 evas_bidi_shape_string(base_str, par_props, par_pos, len);
397 use_kerning = FT_HAS_KERNING(fi->src->ft.face);
402 text_props->info->glyph = calloc(len,
403 sizeof(Evas_Font_Glyph_Info));
405 if (text_props->bidi.dir == EVAS_BIDI_DIRECTION_RTL)
415 gl_itr = text_props->info->glyph;
416 for ( ; i > 0 ; gl_itr++, text += adv_d, i--)
425 idx = evas_common_get_char_index(fi, _gl);
428 idx = evas_common_get_char_index(fi, REPLACEMENT_CHAR);
431 fg = evas_common_font_int_cache_glyph_get(fi, idx);
435 if ((use_kerning) && (prev_index) && (idx) &&
436 (pface == fi->src->ft.face))
438 if (evas_common_font_query_kerning(fi, prev_index, idx, &kern))
441 (gl_itr - 1)->pen_after +=
442 EVAS_FONT_ROUND_26_6_TO_INT(kern);
446 pface = fi->src->ft.face;
449 gl_itr->x_bear = fg->x_bear;
450 adv = fg->glyph->advance.x >> 10;
451 gl_itr->width = fg->width;
453 if (EVAS_FONT_CHARACTER_IS_INVISIBLE(_gl))
462 gl_itr->pen_after = EVAS_FONT_ROUND_26_6_TO_INT(pen_x);
466 text_props->len = len;
467 # if !defined(OT_SUPPORT) && defined(BIDI_SUPPORT)
472 text_props->text_len = len;
473 text_props->info->refcount = 1;