aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/evas/src/lib/engines/common/evas_font_query.c
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/evas/src/lib/engines/common/evas_font_query.c')
-rw-r--r--libraries/evas/src/lib/engines/common/evas_font_query.c789
1 files changed, 789 insertions, 0 deletions
diff --git a/libraries/evas/src/lib/engines/common/evas_font_query.c b/libraries/evas/src/lib/engines/common/evas_font_query.c
new file mode 100644
index 0000000..af2cc84
--- /dev/null
+++ b/libraries/evas/src/lib/engines/common/evas_font_query.c
@@ -0,0 +1,789 @@
1#include "evas_common.h"
2#include "language/evas_bidi_utils.h" /*defines BIDI_SUPPORT if possible */
3#include "evas_font_private.h" /* for Frame-Queuing support */
4#include "evas_font_ot.h"
5
6
7/* FIXME: Check coverage according to the font and not by actually loading */
8/**
9 * @internal
10 * Find the end of a run according to font coverage, and return the base script
11 * font and the current wanted font.
12 *
13 * @param[in] fn the font to use.
14 * @param script_fi The base font instance to be used with the script. If NULL, then it's calculated and returned in this variable, if not NULL, it's used and not modified.
15 * @param[out] cur_fi The font instance found for the current run.
16 * @param[in] script the base script
17 * @param[in] text the text to work on.
18 * @param[in] run_let the current run len, i.e "search limit".
19 * @return length of the run found.
20 */
21EAPI int
22evas_common_font_query_run_font_end_get(RGBA_Font *fn, RGBA_Font_Int **script_fi, RGBA_Font_Int **cur_fi, Evas_Script_Type script, const Eina_Unicode *text, int run_len)
23{
24 RGBA_Font_Int *fi = NULL;
25 const Eina_Unicode *run_end = text + run_len;
26 const Eina_Unicode *itr;
27
28 /* If there's no current script_fi, find it first */
29 if (!*script_fi)
30 {
31 const Eina_Unicode *base_char = NULL;
32 /* Skip common chars */
33 for (base_char = text ;
34 (base_char < run_end) &&
35 (evas_common_language_char_script_get(*base_char) != script) ;
36 base_char++)
37 ;
38 if (base_char == run_end) base_char = text;
39
40 /* Find the first renderable char */
41 while (base_char < run_end)
42 {
43 /* 0x1F is the last ASCII contral char, just a hack in
44 * the meanwhile. */
45 if ((*base_char > 0x1F) &&
46 evas_common_font_glyph_search(fn, &fi, *base_char))
47 break;
48 base_char++;
49 }
50
51
52 /* If everything else fails, at least try to find a font for the
53 * replacement char */
54 if (base_char == run_end)
55 evas_common_font_glyph_search(fn, &fi, REPLACEMENT_CHAR);
56
57 if (!fi)
58 fi = fn->fonts->data;
59
60 *script_fi = fi;
61 }
62 else
63 {
64 fi = *script_fi;
65 }
66
67 /* Find the longest run of the same font starting from the start position
68 * and update cur_fi accordingly. */
69 itr = text;
70 while (itr < run_end)
71 {
72 RGBA_Font_Int *tmp_fi;
73 /* Itr will end up being the first of the next run */
74 for ( ; itr < run_end ; itr++)
75 {
76 /* 0x1F is the last ASCII contral char, just a hack in
77 * the meanwhile. */
78 if (*itr <= 0x1F)
79 continue;
80 /* Break if either it's not in the font, or if it is in the
81 * script's font. */
82 if (fi == *script_fi)
83 {
84 if (!evas_common_get_char_index(fi, *itr))
85 break;
86 }
87 else
88 {
89 if (evas_common_get_char_index(*script_fi, *itr))
90 break;
91 }
92 }
93
94 /* Abort if we reached the end */
95 if (itr == run_end)
96 break;
97
98 /* If the script font doesn't fit even one char, find a new font. */
99 if (itr == text)
100 {
101 /* If we can find a font, use it. Otherwise, find the first
102 * char the run of chars that can't be rendered until the first
103 * one that can. */
104 if (evas_common_font_glyph_search(fn, &tmp_fi, *itr))
105 {
106 fi = tmp_fi;
107 }
108 else
109 {
110 itr++;
111 /* Go through all the chars that can't be rendered with any
112 * font */
113 for ( ; itr < run_end ; itr++)
114 {
115 tmp_fi = fi;
116 if (evas_common_get_char_index(fi, *itr) ||
117 evas_common_font_glyph_search(fn, &tmp_fi, *itr))
118 {
119 fi = tmp_fi;
120 break;
121 }
122 }
123
124 /* If we found a renderable character and the found font
125 * can render the replacement char, continue, otherwise
126 * find a font most suitable for the replacement char and
127 * break */
128 if ((itr == run_end) ||
129 !evas_common_get_char_index(fi, REPLACEMENT_CHAR))
130 {
131 evas_common_font_glyph_search(fn, &fi, REPLACEMENT_CHAR);
132 break;
133 }
134 }
135 itr++;
136 }
137 else
138 {
139 /* If this char is not renderable by any font, but the replacement
140 * char can be rendered using the currentfont, continue this
141 * run. */
142 if (!evas_common_font_glyph_search(fn, &tmp_fi, *itr) &&
143 evas_common_get_char_index(fi, REPLACEMENT_CHAR))
144 {
145 itr++;
146 }
147 else
148 {
149 /* Done, we did as much as possible */
150 break;
151 }
152 }
153 }
154
155 if (fi)
156 *cur_fi = fi;
157 else
158 *cur_fi = *script_fi;
159
160 return itr - text;
161}
162
163/**
164 * @internal
165 * Calculate the kerning between "left" and "right.
166 *
167 * @param fi the font instance to use
168 * @param left the left glyph index
169 * @param right the right glyph index
170 * @param[out] kerning the kerning calculated.
171 * @return FALSE on error, TRUE on success.
172 */
173EAPI int
174evas_common_font_query_kerning(RGBA_Font_Int *fi, FT_UInt left, FT_UInt right,
175 int *kerning)
176{
177 int *result;
178 FT_Vector delta;
179 int key[2];
180 int error = 1;
181
182 key[0] = left;
183 key[1] = right;
184
185 result = eina_hash_find(fi->kerning, key);
186 if (result)
187 {
188 *kerning = result[2];
189 goto on_correct;
190 }
191
192 /* NOTE: ft2 seems to have a bug. and sometimes returns bizarre
193 * values to kern by - given same font, same size and same
194 * prev_index and index. auto/bytecode or none hinting doesn't
195 * matter */
196 evas_common_font_int_reload(fi);
197 FTLOCK();
198 if (FT_Get_Kerning(fi->src->ft.face,
199 key[0], key[1],
200 FT_KERNING_DEFAULT, &delta) == 0)
201 {
202 int *push;
203
204 FTUNLOCK();
205 *kerning = delta.x;
206
207 push = malloc(sizeof (int) * 3);
208 if (!push) return 1;
209
210 push[0] = key[0];
211 push[1] = key[1];
212 push[2] = *kerning;
213
214 eina_hash_direct_add(fi->kerning, push, push);
215
216 goto on_correct;
217 }
218
219 FTUNLOCK();
220 error = 0;
221
222 on_correct:
223 return error;
224}
225
226/**
227 * @internal
228 * Calculate the inset of the text. Inset is the difference between the pen
229 * position of the first char in the string, and the first pixel drawn.
230 * (can be negative).
231 *
232 * @param fn the font set to use.
233 * @param text_props the string object.
234 * @return the calculated inset.
235 */
236EAPI int
237evas_common_font_query_inset(RGBA_Font *fn __UNUSED__, const Evas_Text_Props *text_props)
238{
239 if (!text_props->len) return 0;
240 return text_props->info->glyph[text_props->start].x_bear;
241}
242
243/**
244 * @internal
245 * Calculate the right inset of the text. This is the difference between the
246 * pen position of the glyph after the last glyph in the text, and the last
247 * pixel drawn in the text (essentially "advance - width" of the last char).
248 *
249 * @param fn the font set to use.
250 * @param text_props the string object.
251 * @return the calculated inset.
252 *
253 * @see evas_common_font_query_inset()
254 */
255EAPI int
256evas_common_font_query_right_inset(RGBA_Font *fn __UNUSED__, const Evas_Text_Props *text_props)
257{
258 const Evas_Font_Glyph_Info *gli;
259 if (!text_props->len) return 0;
260 gli = text_props->info->glyph + text_props->start + text_props->len - 1;
261
262 /* If the last char is a whitespace, we use the advance as the size,
263 * so the right_inset is 0. */
264 if (gli->width == 0)
265 return 0;
266
267 return ((gli > text_props->info->glyph) ?
268 gli->pen_after - (gli - 1)->pen_after : gli->pen_after) -
269 (gli->width + gli->x_bear
270#ifdef OT_SUPPORT
271 + EVAS_FONT_ROUND_26_6_TO_INT(EVAS_FONT_OT_X_OFF_GET(
272 text_props->info->ot[text_props->start + text_props->len - 1]))
273#endif
274 );
275}
276
277/**
278 * @internal
279 * Calculate the size of the string (width and height).
280 * The width is the disntance between the first pen position and the last pixel
281 * drawn.
282 * The height is the max ascent+descent of the font.
283 *
284 * @param fn the font set to use.
285 * @param text_props the string object.
286 * @param[out] w the calculated width
287 * @param[out] h the calculated height
288 */
289EAPI void
290evas_common_font_query_size(RGBA_Font *fn, const Evas_Text_Props *text_props, int *w, int *h)
291{
292 Evas_Coord ret_w = 0;
293
294 if (text_props->len > 0)
295 {
296 const Evas_Font_Glyph_Info *glyph = text_props->info->glyph +
297 text_props->start;
298 const Evas_Font_Glyph_Info *last_glyph = glyph;
299
300 if (text_props->len > 1)
301 {
302 last_glyph += text_props->len - 1;
303 ret_w = last_glyph[-1].pen_after;
304 if (text_props->start > 0)
305 ret_w -= glyph[-1].pen_after;
306 }
307#ifdef OT_SUPPORT
308 ret_w += EVAS_FONT_ROUND_26_6_TO_INT(EVAS_FONT_OT_X_OFF_GET(
309 text_props->info->ot[text_props->start + text_props->len - 1]));
310#endif
311 ret_w += last_glyph->width + last_glyph->x_bear;
312 }
313
314 if (w) *w = ret_w;
315 if (h) *h = evas_common_font_max_ascent_get(fn) + evas_common_font_max_descent_get(fn);
316}
317
318/**
319 * @internal
320 * Calculate the advance of the string. Advance is the distance between the
321 * first pen position and the pen position after the string.
322 *
323 * @param fn the font set to use.
324 * @param text_props the string object.
325 * @param[out] h_adv the calculated horizontal advance.
326 * @param[out] v_adv the calculated vertical advance.
327 */
328EAPI void
329evas_common_font_query_advance(RGBA_Font *fn, const Evas_Text_Props *text_props, int *h_adv, int *v_adv)
330{
331 Evas_Coord ret_adv = 0;
332 if (text_props->len > 0)
333 {
334 const Evas_Font_Glyph_Info *glyph = text_props->info->glyph +
335 text_props->start;
336 ret_adv = glyph[text_props->len - 1].pen_after;
337 if (text_props->start > 0)
338 ret_adv -= glyph[-1].pen_after;
339 }
340
341 if (h_adv) *h_adv = ret_adv;
342 if (v_adv) *v_adv = evas_common_font_get_line_advance(fn);
343}
344
345/**
346 * @internal
347 * Query the coordinates of the char at position pos. If the position is at the
348 * end of the string (i.e where the finishing null would be) it returns the
349 * coordinates of the position right after the last char. This is either on
350 * the left or on the right of the string, depending on BiDi direction. Returned
351 * width in this case is 0. It returns the x of the leftmost pixel drawn.
352 *
353 * @param fn the font set to use.
354 * @param text_props the string object.
355 * @param pos the position of the char in the string object (not actual position in the string object, but the position of the source character).
356 * @param[out] cx the calculated x - CAN BE NULL
357 * @param[out] cy the calculated y - CAN BE NULL
358 * @param[out] cw the calculated width - CAN BE NULL
359 * @param[out] ch the calculated height - CAN BE NULL
360 * @return TRUE on success, FALSE otherwise.
361 *
362 * @see evas_common_font_query_pen_coords()
363 */
364EAPI int
365evas_common_font_query_char_coords(RGBA_Font *fn, const Evas_Text_Props *text_props, int pos, int *cx, int *cy, int *cw, int *ch)
366{
367 int asc, desc;
368 size_t position = 0;
369 int ret_val = 0;
370 EVAS_FONT_WALK_TEXT_INIT();
371
372 asc = evas_common_font_max_ascent_get(fn);
373 desc = evas_common_font_max_descent_get(fn);
374
375 position = pos;
376 /* If it's the null, choose location according to the direction. */
377 if (position == text_props->text_len)
378 {
379 /* if it's rtl then the location is the left of the string,
380 * otherwise, the right. */
381#ifdef BIDI_SUPPORT
382 if (text_props->bidi.dir == EVAS_BIDI_DIRECTION_RTL)
383 {
384 if (cx) *cx = 0;
385 if (ch) *ch = asc + desc;
386 }
387 else
388#endif
389 {
390 evas_common_font_query_advance(fn, text_props, cx, ch);
391 }
392 if (cy) *cy = 0;
393 if (cw) *cw = 0;
394 ret_val = 1;
395 goto end;
396 }
397
398 Evas_Coord cluster_start = 0, last_end = 0;
399 int prev_cluster = -1;
400 int found = 0, items = 1, item_pos = 1;
401 int last_is_visible = 0;
402 EVAS_FONT_WALK_TEXT_START()
403 {
404 EVAS_FONT_WALK_TEXT_WORK();
405
406 if (prev_cluster != (int) EVAS_FONT_WALK_POS)
407 {
408 if (found)
409 {
410 break;
411 }
412 else
413 {
414 cluster_start = EVAS_FONT_WALK_PEN_X +
415 EVAS_FONT_WALK_X_OFF +
416 EVAS_FONT_WALK_X_BEAR;
417 }
418 }
419 last_is_visible = EVAS_FONT_WALK_IS_VISIBLE;
420 last_end = EVAS_FONT_WALK_PEN_X + EVAS_FONT_WALK_X_OFF +
421 EVAS_FONT_WALK_X_BEAR + EVAS_FONT_WALK_WIDTH;
422 /* we need to see if the char at the visual position is the char wanted */
423 if ((text_props->bidi.dir == EVAS_BIDI_DIRECTION_LTR) &&
424 (EVAS_FONT_WALK_POS <= (size_t) position) &&
425 ((((size_t) position) < EVAS_FONT_WALK_POS_NEXT) ||
426 (EVAS_FONT_WALK_IS_LAST)))
427 {
428 found = 1;
429#ifdef OT_SUPPORT
430 items = evas_common_font_ot_cluster_size_get(text_props,
431 char_index);
432#endif
433 item_pos = position - EVAS_FONT_WALK_POS + 1;
434 }
435 else if ((text_props->bidi.dir == EVAS_BIDI_DIRECTION_RTL) &&
436 ((EVAS_FONT_WALK_POS_PREV > (size_t) position) ||
437 (EVAS_FONT_WALK_IS_FIRST)) &&
438 (((size_t) position) >= EVAS_FONT_WALK_POS))
439 {
440 found = 1;
441#ifdef OT_SUPPORT
442 items = evas_common_font_ot_cluster_size_get(text_props,
443 char_index);
444#endif
445 item_pos = items - (position - EVAS_FONT_WALK_POS);
446 }
447
448 prev_cluster = EVAS_FONT_WALK_POS;
449 }
450 EVAS_FONT_WALK_TEXT_END();
451 if (found)
452 {
453 Evas_Coord cluster_w;
454 cluster_w = last_end - cluster_start;
455 if (cy) *cy = -asc;
456 if (ch) *ch = asc + desc;
457 if (last_is_visible)
458 {
459 if (cx) *cx = cluster_start +
460 (cluster_w / items) *
461 (item_pos - 1);
462 if (cw) *cw = (cluster_w / items);
463 }
464 else
465 {
466 if (cx) *cx = cluster_start;
467 if (cw) *cw = 0;
468 }
469 ret_val = 1;
470 goto end;
471 }
472end:
473
474 return ret_val;
475}
476
477/**
478 * @internal
479 * Query the coordinates of the char at position pos. If the position is at the
480 * end of the string (i.e where the finishing null would be) it returns the
481 * coordinates of the position right after the last char. This is either on
482 * the left or on the right of the string, depending on BiDi direction. Returned
483 * advance in this case is 0.
484 *
485 * This is the same as evas_common_font_query_char_coords() except that the
486 * advance of the character is returned instead of the width and the pen
487 * position is returned instead of the actual pixel position.
488 *
489 * @param fn the font set to use.
490 * @param text_props the string object.
491 * @param pos the position of the char in the string object (not actual position in the string object, but the position of the source character).
492 * @param[out] cpenx the calculated x - CAN BE NULL
493 * @param[out] cy the calculated y - CAN BE NULL
494 * @param[out] cadv the calculated advance - CAN BE NULL
495 * @param[out] ch the calculated height - CAN BE NULL
496 * @return TRUE on success, FALSE otherwise.
497 *
498 * @see evas_common_font_query_char_coords()
499 */
500EAPI int
501evas_common_font_query_pen_coords(RGBA_Font *fn, const Evas_Text_Props *text_props, int pos, int *cpen_x, int *cy, int *cadv, int *ch)
502{
503 int asc, desc;
504 size_t position;
505 int ret_val = 0;
506 EVAS_FONT_WALK_TEXT_INIT();
507
508 asc = evas_common_font_max_ascent_get(fn);
509 desc = evas_common_font_max_descent_get(fn);
510
511 position = pos;
512 /* If it's the null, choose location according to the direction. */
513 if (position == text_props->text_len)
514 {
515 /* if it's rtl then the location is the left of the string,
516 * otherwise, the right. */
517#ifdef BIDI_SUPPORT
518 if (text_props->bidi.dir == EVAS_BIDI_DIRECTION_RTL)
519 {
520 if (cpen_x) *cpen_x = 0;
521 if (ch) *ch = asc + desc;
522 }
523 else
524#endif
525 {
526 evas_common_font_query_advance(fn, text_props, cpen_x, ch);
527 }
528 if (cy) *cy = 0;
529 if (cadv) *cadv = 0;
530 ret_val = 1;
531 goto end;
532 }
533 Evas_Coord cluster_start = 0;
534 int prev_cluster = -1;
535 int found = 0, items = 1, item_pos = 1;
536 int last_is_visible = 0;
537 EVAS_FONT_WALK_TEXT_START()
538 {
539 EVAS_FONT_WALK_TEXT_WORK();
540
541 if (prev_cluster != (int) EVAS_FONT_WALK_POS)
542 {
543 if (found)
544 {
545 break;
546 }
547 else
548 {
549 cluster_start = EVAS_FONT_WALK_PEN_X;
550 }
551 }
552 last_is_visible = EVAS_FONT_WALK_IS_VISIBLE;
553
554 if ((text_props->bidi.dir == EVAS_BIDI_DIRECTION_LTR) &&
555 (EVAS_FONT_WALK_POS <= (size_t) position) &&
556 ((((size_t) position) < EVAS_FONT_WALK_POS_NEXT) ||
557 (EVAS_FONT_WALK_IS_LAST)))
558 {
559 found = 1;
560#ifdef OT_SUPPORT
561 items = evas_common_font_ot_cluster_size_get(text_props,
562 char_index);
563#endif
564 item_pos = position - EVAS_FONT_WALK_POS + 1;
565 }
566 else if ((text_props->bidi.dir == EVAS_BIDI_DIRECTION_RTL) &&
567 ((EVAS_FONT_WALK_POS_PREV > (size_t) position) ||
568 (EVAS_FONT_WALK_IS_FIRST)) &&
569 (((size_t) position) >= EVAS_FONT_WALK_POS))
570 {
571 found = 1;
572#ifdef OT_SUPPORT
573 items = evas_common_font_ot_cluster_size_get(text_props,
574 char_index);
575#endif
576 item_pos = items - (position - EVAS_FONT_WALK_POS);
577 }
578
579 prev_cluster = EVAS_FONT_WALK_POS;
580 }
581 EVAS_FONT_WALK_TEXT_END();
582
583 if (found)
584 {
585 Evas_Coord cluster_adv;
586 cluster_adv = EVAS_FONT_WALK_PEN_X - cluster_start;
587 if (cy) *cy = -asc;
588 if (ch) *ch = asc + desc;
589 if (last_is_visible)
590 {
591 if (cpen_x) *cpen_x = cluster_start +
592 (cluster_adv / items) *
593 (item_pos - 1);
594 if (cadv) *cadv = (cluster_adv / items);
595 }
596 else
597 {
598 if (cpen_x) *cpen_x = EVAS_FONT_WALK_PEN_X;
599 if (cadv) *cadv = 0;
600 }
601 ret_val = 1;
602 goto end;
603 }
604end:
605
606 return ret_val;
607}
608
609/**
610 * @internal
611 * Find the character at a specific x, y coordinates and return it's position
612 * in the text (not in the text object, but in the source text). Also calculate
613 * the char's geometry.
614 *
615 * @param fn the font set to use.
616 * @param text_props the string object.
617 * @param x the x to look at.
618 * @param y the y to look at.
619 * @param[out] cx the calculated x - CAN BE NULL
620 * @param[out] cy the calculated y - CAN BE NULL
621 * @param[out] cw the calculated width - CAN BE NULL
622 * @param[out] ch the calculated height - CAN BE NULL
623 * @return the position found, -1 on failure.
624 */
625EAPI int
626evas_common_font_query_char_at_coords(RGBA_Font *fn, const Evas_Text_Props *text_props, int x, int y, int *cx, int *cy, int *cw, int *ch)
627{
628 int asc, desc;
629 int ret_val = -1;
630 EVAS_FONT_WALK_TEXT_INIT();
631
632 asc = evas_common_font_max_ascent_get(fn);
633 desc = evas_common_font_max_descent_get(fn);
634 Evas_Coord cluster_start = 0;
635 int prev_cluster = -1;
636 int found = 0, items = 1;
637 EVAS_FONT_WALK_TEXT_START()
638 {
639 EVAS_FONT_WALK_TEXT_WORK();
640 if (prev_cluster != (int) EVAS_FONT_WALK_POS)
641 {
642 if (found)
643 {
644 break;
645 }
646 else
647 {
648 cluster_start = EVAS_FONT_WALK_PEN_X;
649 }
650 }
651
652 if (!EVAS_FONT_WALK_IS_VISIBLE) continue;
653
654 /* we need to see if the char at the visual position is the char,
655 * we check that by checking if it's before the current pen
656 * position and the next */
657 if ((x >= EVAS_FONT_WALK_PEN_X) &&
658 (x <= (EVAS_FONT_WALK_PEN_X_AFTER)) && (y >= -asc) && (y <= desc))
659 {
660#ifdef OT_SUPPORT
661 items = evas_common_font_ot_cluster_size_get(text_props,
662 char_index);
663#endif
664 found = 1;
665 }
666
667 prev_cluster = EVAS_FONT_WALK_POS;
668 }
669 EVAS_FONT_WALK_TEXT_END();
670 if (found)
671 {
672 int item_pos;
673 Evas_Coord cluster_adv;
674 cluster_adv = EVAS_FONT_WALK_PEN_X - cluster_start;
675
676 if (text_props->bidi.dir == EVAS_BIDI_DIRECTION_LTR)
677 {
678 double part;
679 part = cluster_adv / items;
680 item_pos = (int) ((x - cluster_start) / part);
681 }
682 else
683 {
684 double part;
685 part = cluster_adv / items;
686 item_pos = items - ((int) ((x - cluster_start) / part)) - 1;
687 }
688 if (cx) *cx = EVAS_FONT_WALK_PEN_X +
689 ((cluster_adv / items) * (item_pos - 1));
690 if (cy) *cy = -asc;
691 if (cw) *cw = (cluster_adv / items);
692 if (ch) *ch = asc + desc;
693 ret_val = prev_cluster + item_pos;
694 goto end;
695 }
696end:
697
698 return ret_val;
699}
700
701/**
702 * @internal
703 * Find one after the last character that fits until the boundaries set by x
704 * and y. I.e find the first char that doesn't fit.
705 * This LOGICALLY walks the string. This is needed for wrapping for example
706 * where we want the first part to be the first logical part.
707 *
708 * @param fn the font set to use.
709 * @param text_props the string object.
710 * @param x the x boundary.
711 * @param y the y boundary.
712 * @return the position found, -1 on failure.
713 */
714EAPI int
715evas_common_font_query_last_up_to_pos(RGBA_Font *fn, const Evas_Text_Props *text_props, int x, int y)
716{
717 int asc, desc;
718 int ret=-1;
719
720 asc = evas_common_font_max_ascent_get(fn);
721 desc = evas_common_font_max_descent_get(fn);
722
723#ifdef BIDI_SUPPORT
724 if (text_props->bidi.dir == EVAS_BIDI_DIRECTION_RTL)
725 {
726 Evas_Font_Glyph_Info *gli = NULL;
727 Evas_Coord full_adv = 0, pen_x = 0, start_pen = 0;
728 int i;
729
730 if ((text_props->info) && (text_props->len > 0))
731 {
732 gli = text_props->info->glyph + text_props->start;
733 full_adv = gli[text_props->len - 1].pen_after;
734 if (text_props->start > 0)
735 {
736 start_pen = gli[-1].pen_after;
737 full_adv -= start_pen;
738 }
739
740 gli += text_props->len - 1;
741
742 for (i = text_props->len - 1 ; i >= 0 ; i--, gli--)
743 {
744 pen_x = full_adv - (gli->pen_after - start_pen);
745 /* If invisible, skip */
746 if (gli->index == 0) continue;
747 if ((x >= pen_x) &&
748 (((i == 0) && (x <= full_adv)) ||
749 (x <= (full_adv - (gli[-1].pen_after - start_pen)))) &&
750 (y >= -asc) && (y <= desc))
751 {
752#ifdef OT_SUPPORT
753 ret = EVAS_FONT_OT_POS_GET(
754 text_props->info->ot[text_props->start + i]) -
755 text_props->text_offset;
756#else
757 ret = text_props->text_len - i - 1;
758#endif
759 goto end;
760 }
761 }
762 }
763 }
764 else
765#endif
766 {
767 EVAS_FONT_WALK_TEXT_INIT();
768 /* When text is not rtl, visual direction = logical direction */
769 EVAS_FONT_WALK_TEXT_START()
770 {
771 EVAS_FONT_WALK_TEXT_WORK();
772 if (!EVAS_FONT_WALK_IS_VISIBLE) continue;
773
774 if ((x >= EVAS_FONT_WALK_PEN_X) &&
775 (x <= (EVAS_FONT_WALK_PEN_X_AFTER)) &&
776 (y >= -asc) && (y <= desc))
777 {
778 ret = EVAS_FONT_WALK_POS;
779 goto end;
780 }
781 }
782 EVAS_FONT_WALK_TEXT_END();
783 }
784
785end:
786
787 return ret;
788}
789