From 7016872619b7b84e46688de29b133997c43f95ed Mon Sep 17 00:00:00 2001 From: Yakov Goldberg Date: Wed, 10 Apr 2013 14:54:37 +0300 Subject: [PATCH] Efl textblock/entry: additions to split BiDi cursor - handling multiple runs, multiple lines, last char of line/par - tests added Signed-off-by: Yakov Goldberg --- ChangeLog | 3 + NEWS | 1 + src/lib/edje/edje_entry.c | 6 +- src/lib/evas/Evas.h | 26 +- src/lib/evas/canvas/evas_object_textblock.c | 213 +++++++++---- src/tests/evas/evas_test_textblock.c | 327 ++++++++++++++++++++ 6 files changed, 518 insertions(+), 58 deletions(-) diff --git a/ChangeLog b/ChangeLog index 04fc489a6a..779bf02487 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,6 @@ +2013-04-10 Tom Hacohen (Tasn) Yakov Goldberg + * Evas textblock : Added split cursor for BiDi text + 2013-04-10 WooHyun Jung * Edje: When cursor is located to each edge, entry now doesn't grab events for cursor movement. diff --git a/NEWS b/NEWS index cf24cf20d3..3735e3891a 100644 --- a/NEWS +++ b/NEWS @@ -144,6 +144,7 @@ Improvements: * Use the right macro to disable fcntl. * Edje: use Eina_Cow to reduce memory usage. * Embryo: use eina_file_mkstemp(). + * Evas textblock : Added split cursor for BiDi text Fixes: * Fix a memory leak in ecore_con_dns when using ecore_con_server_connect diff --git a/src/lib/edje/edje_entry.c b/src/lib/edje/edje_entry.c index d7b0f771c6..b324d97b9f 100644 --- a/src/lib/edje/edje_entry.c +++ b/src/lib/edje/edje_entry.c @@ -2409,14 +2409,14 @@ _edje_entry_real_part_init(Edje *ed, Edje_Real_Part *rp) /* A proxy to the main cursor. */ if (rp->part->cursor_mode == EDJE_ENTRY_CURSOR_MODE_BEFORE) { - en->cursor_fg2 = evas_object_image_add(rp->edje->base->evas); + en->cursor_fg2 = evas_object_image_add(ed->base->evas); evas_object_image_source_set(en->cursor_fg2, en->cursor_fg); evas_object_image_fill_set(en->cursor_fg2, 0, 0, 1, 1); - evas_object_smart_member_add(en->cursor_fg2, rp->edje->obj); + evas_object_smart_member_add(en->cursor_fg2, ed->obj); evas_object_stack_above(en->cursor_fg2, rp->object); evas_object_clip_set(en->cursor_fg2, evas_object_clip_get(rp->object)); evas_object_pass_events_set(en->cursor_fg2, EINA_TRUE); - _edje_subobj_register(en->rp->edje, en->cursor_fg2); + _edje_subobj_register(en->ed, en->cursor_fg2); } evas_object_textblock_legacy_newline_set(rp->object, EINA_TRUE); diff --git a/src/lib/evas/Evas.h b/src/lib/evas/Evas.h index 9d3603b06b..86d0beb8c5 100644 --- a/src/lib/evas/Evas.h +++ b/src/lib/evas/Evas.h @@ -11628,8 +11628,30 @@ EAPI char *evas_textblock_cursor_range_text_g */ EAPI char *evas_textblock_cursor_content_get(const Evas_Textblock_Cursor *cur) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_MALLOC; -/** FIXME: doc. - * The cw2 and etc are not valid if false is returned. */ +/** + * Returns the geometry of two cursors ("split cursor"), if logical cursor is + * between LTR/RTL text, also considering paragraph direction. + * Upper cursor is shown for the text of the same direction as paragraph, + * lower cursor - for opposite. + * + * Split cursor geometry is valid only in '|' cursor mode. + * In this case @c EINA_TRUE is returned and cx2, cy2, cw2, ch2 are set, + * otherwise it behaves like cursor_geometry_get. + * + * @param[in] cur the cursor. + * @param[out] cx the x of the cursor (or upper cursor) + * @param[out] cy the y of the cursor (or upper cursor) + * @param[out] cw the width of the cursor (or upper cursor) + * @param[out] ch the height of the cursor (or upper cursor) + * @param[out] cx2 the x of the lower cursor + * @param[out] cy2 the y of the lower cursor + * @param[out] cw2 the width of the lower cursor + * @param[out] ch2 the height of the lower cursor + * @param[in] dir the direction of the cursor, can be NULL. + * @param[in] ctype the type of the cursor. + * @return @c EINA_TRUE for split cursor, @c EINA_FALSE otherwise + * @since 1.8 + */ EAPI Eina_Bool evas_textblock_cursor_geometry_bidi_get(const Evas_Textblock_Cursor *cur, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch, Evas_Coord *cx2, Evas_Coord *cy2, Evas_Coord *cw2, Evas_Coord *ch2, Evas_Textblock_Cursor_Type ctype); diff --git a/src/lib/evas/canvas/evas_object_textblock.c b/src/lib/evas/canvas/evas_object_textblock.c index 994b258a65..a274319446 100644 --- a/src/lib/evas/canvas/evas_object_textblock.c +++ b/src/lib/evas/canvas/evas_object_textblock.c @@ -8950,21 +8950,43 @@ evas_textblock_cursor_format_is_visible_get(const Evas_Textblock_Cursor *cur) return EVAS_TEXTBLOCK_IS_VISIBLE_FORMAT_CHAR(text[cur->pos]); } +#ifdef BIDI_SUPPORT +static Evas_Object_Textblock_Line* +_find_layout_line_by_item(Evas_Object_Textblock_Paragraph *par, Evas_Object_Textblock_Item *_it) +{ + Evas_Object_Textblock_Line *ln; + + EINA_INLIST_FOREACH(par->lines, ln) + { + Evas_Object_Textblock_Item *it; + + EINA_INLIST_FOREACH(ln->items, it) + { + if (_it == it) + return ln; + } + } + return NULL; +} +#endif + EAPI Eina_Bool evas_textblock_cursor_geometry_bidi_get(const Evas_Textblock_Cursor *cur, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch, Evas_Coord *cx2, Evas_Coord *cy2, Evas_Coord *cw2, Evas_Coord *ch2, Evas_Textblock_Cursor_Type ctype) { - const Evas_Textblock_Cursor *dir_cur; - Evas_Textblock_Cursor cur2; if (!cur) return EINA_FALSE; Evas_Object_Textblock *o = eo_data_get(cur->obj, MY_CLASS); if (!o->formatted.valid) _relayout(cur->obj); - dir_cur = cur; if (ctype == EVAS_TEXTBLOCK_CURSOR_UNDER) { evas_textblock_cursor_pen_geometry_get(cur, cx, cy, cw, ch); return EINA_FALSE; } + +#ifdef BIDI_SUPPORT +#define IS_RTL(par) ((par) % 2) +#define IS_DIFFERENT_DIR(l1, l2) ((IS_RTL(l1) && (!IS_RTL(l2))) || \ + ((!IS_RTL(l1)) && IS_RTL(l2))) else { Evas_Object_Textblock_Line *ln = NULL; @@ -8972,74 +8994,159 @@ evas_textblock_cursor_geometry_bidi_get(const Evas_Textblock_Cursor *cur, Evas_C _find_layout_item_match(cur, &ln, &it); if (ln && it) { - if (cw) *cw = 0; - if (cw2) *cw2 = 0; - /* If we are at the start or the end of the item there's a chance - * we'll want a split cursor. - * FIXME: Handle the last char of the last paragraph. - * FIXME: Handle multiple items of the same direction. - * FIXME: Handle items across different lines.. */ - if (cur->pos == it->text_pos) + if (ln->par->is_bidi) { - Evas_BiDi_Direction itdir = (it->type == EVAS_TEXTBLOCK_ITEM_TEXT) ? - _ITEM_TEXT(it)->text_props.bidi_dir : _ITEM_FORMAT(it)->bidi_dir; + if (cw) *cw = 0; + if (cw2) *cw2 = 0; + + /* If we are at the start or the end of the item there's a chance + * we'll want a split cursor. */ Evas_Object_Textblock_Item *previt = NULL; - Evas_BiDi_Direction previtdir = EVAS_BIDI_DIRECTION_NEUTRAL; - /* Get the logically previous item. */ + Evas_Object_Textblock_Item *it1 = NULL, *it2 = NULL; + Evas_Coord adv1 = 0, adv2 = 0; + + if (cur->pos == it->text_pos) { - Eina_List *itr; - Evas_Object_Textblock_Item *ititr; - EINA_LIST_FOREACH(ln->par->logical_items, itr, ititr) + EvasBiDiLevel par_level, it_level, previt_level; + + _layout_update_bidi_props(o, ln->par); + par_level = *(ln->par->bidi_props->embedding_levels); + it_level = ln->par->bidi_props->embedding_levels[it->text_pos]; + /* Get the logically previous item. */ { - if (ititr == it) - break; - previt = ititr; + Eina_List *itr; + Evas_Object_Textblock_Item *ititr; + + EINA_LIST_FOREACH(ln->par->logical_items, itr, ititr) + { + if (ititr == it) + break; + previt = ititr; + } + + if (previt) + { + previt_level = ln->par->bidi_props->embedding_levels[previt->text_pos]; + } } - if (previt) + if (previt && (it_level != previt_level)) { - previtdir = (previt->type == EVAS_TEXTBLOCK_ITEM_TEXT) ? - _ITEM_TEXT(previt)->text_props.bidi_dir : _ITEM_FORMAT(previt)->bidi_dir; + Evas_Object_Textblock_Item *curit = NULL, *curit_opp = NULL; + EvasBiDiLevel cur_level; + + if (it_level > previt_level) + { + curit = it; + curit_opp = previt; + cur_level = it_level; + } + else + { + curit = previt; + curit_opp = it; + cur_level = previt_level; + } + + if (((curit == it) && (!IS_RTL(par_level))) || + ((curit == previt) && (IS_RTL(par_level)))) + { + adv1 = (IS_DIFFERENT_DIR(cur_level, par_level)) ? + curit_opp->adv : 0; + adv2 = curit->adv; + } + else if (((curit == previt) && (!IS_RTL(par_level))) || + ((curit == it) && (IS_RTL(par_level)))) + { + adv1 = (IS_DIFFERENT_DIR(cur_level, par_level)) ? + 0 : curit->adv; + adv2 = 0; + } + + if (!IS_DIFFERENT_DIR(cur_level, par_level)) + curit_opp = curit; + + it1 = curit_opp; + it2 = curit; } + /* Clear the bidi props because we don't need them anymore. */ + evas_bidi_paragraph_props_unref(ln->par->bidi_props); + ln->par->bidi_props = NULL; + } + /* Handling last char in line (or in paragraph). + * T.e. prev condition didn't work, so we are not standing in the beginning of item, + * but in the end of line or paragraph. */ + else if (evas_textblock_cursor_eol_get(cur)) + { + EvasBiDiLevel par_level, it_level; + + _layout_update_bidi_props(o, ln->par); + par_level = *(ln->par->bidi_props->embedding_levels); + it_level = ln->par->bidi_props->embedding_levels[it->text_pos]; + + if (it_level > par_level) + { + Evas_Object_Textblock_Item *lastit = it; + + if (IS_RTL(par_level)) /* RTL par*/ + { + /* We know, that all the items before current are of the same or bigger embedding level. + * So search backwards for the first one. */ + while (EINA_INLIST_GET(lastit)->prev) + { + lastit = _EINA_INLIST_CONTAINER(it, EINA_INLIST_GET(lastit)->prev); + } + + adv1 = 0; + adv2 = it->adv; + } + else /* LTR par */ + { + /* We know, that all the items after current are of bigger or same embedding level. + * So search forward for the last one. */ + while (EINA_INLIST_GET(lastit)->next) + { + lastit = _EINA_INLIST_CONTAINER(it, EINA_INLIST_GET(lastit)->next); + } + + adv1 = lastit->adv; + adv2 = 0; + } + + it1 = lastit; + it2 = it; + } + /* Clear the bidi props because we don't need them anymore. */ + evas_bidi_paragraph_props_unref(ln->par->bidi_props); + ln->par->bidi_props = NULL; } - if (previt && (itdir != previtdir)) + if (it1 && it2) { - Evas_Object_Textblock_Item *curit = NULL; - /* If the current dir is different than the paragraph dir - * this is our item. */ - if (itdir != ln->par->direction) - { - curit = it; - } - else - { - curit = previt; - } + Evas_Object_Textblock_Line *ln1 = NULL, *ln2 = NULL; + ln1 = _find_layout_line_by_item(ln->par, it1); + if (cx) *cx = ln1->x + it1->x + adv1; + if (cy) *cy = ln1->par->y + ln1->y; + if (ch) *ch = ln1->h; - if (((curit == it) && (ln->par->direction == EVAS_BIDI_DIRECTION_LTR)) || - ((curit == previt) && (ln->par->direction == EVAS_BIDI_DIRECTION_RTL))) - { - if (cx) *cx = ln->x + curit->x; - if (cx2) *cx2 = ln->x + curit->x + curit->w; - } - else - { - if (cx) *cx = ln->x + curit->x + curit->w; - if (cx2) *cx2 = ln->x + curit->x; - } + ln2 = _find_layout_line_by_item(ln->par, it2); + if (cx2) *cx2 = ln2->x + it2->x + adv2; + if (cy2) *cy2 = ln2->par->y + ln2->y; + if (ch2) *ch2 = ln2->h; - if (cy) *cy = ln->par->y + ln->y; - if (ch) *ch = curit->h; - - if (cy2) *cy2 = ln->par->y + ln->y; - if (ch2) *ch2 = curit->h; return EINA_TRUE; } } } } - +#undef IS_DIFFERENT_DIR +#undef IS_RTL +#else + (void) cx2; + (void) cy2; + (void) cw2; + (void) ch2; +#endif evas_textblock_cursor_geometry_get(cur, cx, cy, cw, ch, NULL, ctype); return EINA_FALSE; } diff --git a/src/tests/evas/evas_test_textblock.c b/src/tests/evas/evas_test_textblock.c index ed16077e16..b1dcacc029 100644 --- a/src/tests/evas/evas_test_textblock.c +++ b/src/tests/evas/evas_test_textblock.c @@ -648,6 +648,332 @@ START_TEST(evas_textblock_cursor) } END_TEST +START_TEST(evas_textblock_split_cursor) +{ +#ifdef HAVE_FRIBIDI + START_TB_TEST(); + Evas_Coord x, w, x2, w2; + Evas_Coord nw, nh; + Evas_Coord cx, cy, cx2, cy2; + + /* Split cursor in LTR paragraph. */ + /*0123456789 10 123 14 5678901234 */ + evas_object_textblock_text_markup_set(tb, "test נסיון\u202babc\u202cנסיון bang"); + evas_object_textblock_size_native_get(tb, &nw, &nh); + evas_object_resize(tb, nw, nh); + + /* Logical cursor after "test " */ + evas_textblock_cursor_pos_set(cur, 5); + fail_if(!evas_textblock_cursor_geometry_bidi_get(cur, &cx, NULL, NULL, + NULL, &cx2, NULL, NULL, NULL, + EVAS_TEXTBLOCK_CURSOR_BEFORE)); + evas_textblock_cursor_pos_set(cur, 4); + evas_textblock_cursor_pen_geometry_get(cur, &x, NULL, &w, NULL); + evas_textblock_cursor_pos_set(cur, 5); + evas_textblock_cursor_pen_geometry_get(cur, &x2, NULL, &w2, NULL); + fail_if(cx != (x + w)); + fail_if(cx2 != (x2 + w2)); + + /* Logical cursor before " bang" */ + evas_textblock_cursor_pos_set(cur, 20); + evas_textblock_cursor_pen_geometry_get(cur, &x, NULL, NULL, NULL); + fail_if(!evas_textblock_cursor_geometry_bidi_get(cur, &cx, NULL, NULL, + NULL, &cx2, NULL, NULL, NULL, + EVAS_TEXTBLOCK_CURSOR_BEFORE)); + evas_textblock_cursor_pos_set(cur, 19); + evas_textblock_cursor_pen_geometry_get(cur, &x2, NULL, NULL, NULL); + fail_if(cx != x); + fail_if(cx2 != x2); + + /* Logical cursor before "a" */ + evas_textblock_cursor_pos_set(cur, 11); + evas_textblock_cursor_pen_geometry_get(cur, &x, NULL, NULL, NULL); + fail_if(!evas_textblock_cursor_geometry_bidi_get(cur, &cx, NULL, NULL, + NULL, &cx2, NULL, NULL, NULL, + EVAS_TEXTBLOCK_CURSOR_BEFORE)); + evas_textblock_cursor_pos_set(cur, 9); + evas_textblock_cursor_pen_geometry_get(cur, &x2, NULL, NULL, NULL); + fail_if(cx != x); + fail_if(cx2 != x2); + + /* Logical cursor after "c" */ + evas_textblock_cursor_pos_set(cur, 15); + evas_textblock_cursor_pen_geometry_get(cur, &x2, NULL, &w2, NULL); + fail_if(!evas_textblock_cursor_geometry_bidi_get(cur, &cx, NULL, NULL, + NULL, &cx2, NULL, NULL, NULL, + EVAS_TEXTBLOCK_CURSOR_BEFORE)); + evas_textblock_cursor_pos_set(cur, 13); + evas_textblock_cursor_pen_geometry_get(cur, &x, NULL, &w, NULL); + fail_if(cx != (x + w)); + fail_if(cx2 != (x2 + w2)); + + /* Logical cursor in the beginning */ + evas_textblock_cursor_line_char_first(cur); + fail_if(evas_textblock_cursor_geometry_bidi_get(cur, &cx, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, + EVAS_TEXTBLOCK_CURSOR_BEFORE)); + evas_textblock_cursor_pen_geometry_get(cur, &x, NULL, NULL, NULL); + fail_if(cx != x); + + /* Logical cursor in the end */ + evas_textblock_cursor_line_char_last(cur); + fail_if(evas_textblock_cursor_geometry_bidi_get(cur, &cx, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, + EVAS_TEXTBLOCK_CURSOR_BEFORE)); + evas_textblock_cursor_pos_set(cur, 24); + evas_textblock_cursor_pen_geometry_get(cur, &x, NULL, &w, NULL); + fail_if(cx != (x + w)); + + /* Logical cursor on the first pos */ + evas_textblock_cursor_pos_set(cur, 1); + fail_if(evas_textblock_cursor_geometry_bidi_get(cur, &cx, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, + EVAS_TEXTBLOCK_CURSOR_BEFORE)); + evas_textblock_cursor_pen_geometry_get(cur, &x, NULL, NULL, NULL); + fail_if(cx != x); + + /* Split cursor in RTL paragraph. */ + /* 1 2 + 0123456789 0 12345 6 7890123456 */ + evas_object_textblock_text_markup_set(tb, "שלום test \u202aעברית\u202c efl נסיון"); + evas_object_textblock_size_native_get(tb, &nw, &nh); + evas_object_resize(tb, nw, nh); + + /* Logical cursor before "test" */ + evas_textblock_cursor_pos_set(cur, 4); + evas_textblock_cursor_pen_geometry_get(cur, &x, NULL, &w, NULL); + evas_textblock_cursor_pos_set(cur, 5); + + fail_if(!evas_textblock_cursor_geometry_bidi_get(cur, &cx, NULL, NULL, + NULL, &cx2, NULL, NULL, NULL, + EVAS_TEXTBLOCK_CURSOR_BEFORE)); + evas_textblock_cursor_pos_set(cur, 5); + evas_textblock_cursor_pen_geometry_get(cur, &x2, NULL, NULL, NULL); + fail_if(cx != x); + fail_if(cx2 != x2); + + /* Logical cursor after " efl" */ + evas_textblock_cursor_pos_set(cur, 21); + evas_textblock_cursor_pen_geometry_get(cur, &x, NULL, &w, NULL); + + fail_if(!evas_textblock_cursor_geometry_bidi_get(cur, &cx, NULL, NULL, + NULL, &cx2, NULL, NULL, NULL, + EVAS_TEXTBLOCK_CURSOR_BEFORE)); + evas_textblock_cursor_pos_set(cur, 20); + evas_textblock_cursor_pen_geometry_get(cur, &x2, NULL, &w2, NULL); + fail_if(cx != (x + w)); + fail_if(cx2 != (x2 + w2)); + + /* Logical cursor before " efl" */ + evas_textblock_cursor_pos_set(cur, 17); + evas_textblock_cursor_pen_geometry_get(cur, &x, NULL, &w, NULL); + + fail_if(!evas_textblock_cursor_geometry_bidi_get(cur, &cx, NULL, NULL, + NULL, &cx2, NULL, NULL, NULL, + EVAS_TEXTBLOCK_CURSOR_BEFORE)); + evas_textblock_cursor_pos_set(cur, 15); + evas_textblock_cursor_pen_geometry_get(cur, &x2, NULL, NULL, NULL); + fail_if(cx != x2); + fail_if(cx2 != x); + + /* Logical cursor after "test " */ + evas_textblock_cursor_pos_set(cur, 11); + evas_textblock_cursor_pen_geometry_get(cur, &x, NULL, &w, NULL); + + fail_if(!evas_textblock_cursor_geometry_bidi_get(cur, &cx, NULL, NULL, + NULL, &cx2, NULL, NULL, NULL, + EVAS_TEXTBLOCK_CURSOR_BEFORE)); + evas_textblock_cursor_pos_set(cur, 9); + evas_textblock_cursor_pen_geometry_get(cur, &x2, NULL, &w2, NULL); + fail_if(cx != (x + w)); + fail_if(cx2 != (x2 + w2)); + + /* Logical cursor in the beginning */ + evas_textblock_cursor_line_char_first(cur); + fail_if(evas_textblock_cursor_geometry_bidi_get(cur, &cx, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, + EVAS_TEXTBLOCK_CURSOR_BEFORE)); + evas_textblock_cursor_pen_geometry_get(cur, &x, NULL, &w, NULL); + fail_if(cx != (x + w)); + + /* Logical cursor in the end */ + evas_textblock_cursor_line_char_last(cur); + fail_if(evas_textblock_cursor_geometry_bidi_get(cur, &cx, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, + EVAS_TEXTBLOCK_CURSOR_BEFORE)); + evas_textblock_cursor_pos_set(cur, 26); + evas_textblock_cursor_pen_geometry_get(cur, &x, NULL, NULL, NULL); + fail_if(cx != x); + + /* Corner cases for split cursor. */ + + /* End of line in LTR paragraph */ + /* 1 + 01234567890123 4 567 */ + evas_object_textblock_text_markup_set(tb, "test נסיוןشسيب\u202babc"); + evas_textblock_cursor_line_char_last(cur); + evas_textblock_cursor_pen_geometry_get(cur, &x2, NULL, &w2, NULL); + evas_object_textblock_size_native_get(tb, &nw, &nh); + evas_object_resize(tb, nw, nh); + + evas_textblock_cursor_line_char_last(cur); + fail_if(!evas_textblock_cursor_geometry_bidi_get(cur, &cx, NULL, NULL, + NULL, &cx2, NULL, NULL, NULL, + EVAS_TEXTBLOCK_CURSOR_BEFORE)); + evas_textblock_cursor_pos_set(cur, 4); + evas_textblock_cursor_pen_geometry_get(cur, &x2, NULL, &w2, NULL); + evas_textblock_cursor_pos_set(cur, 5); + evas_textblock_cursor_pen_geometry_get(cur, &x, NULL, &w, NULL); + fail_if(cx != (x + w)); + fail_if(cx2 != (x2 + w2)); + + /* End of line in RTL paragraph */ + /* 1 2 + 0123456789012345678 9 0123 */ + evas_object_textblock_text_markup_set(tb, "נסיוןشسي testпривет\u202aשלום"); + evas_object_textblock_size_native_get(tb, &nw, &nh); + evas_object_resize(tb, nw, nh); + + evas_textblock_cursor_line_char_last(cur); + fail_if(!evas_textblock_cursor_geometry_bidi_get(cur, &cx, NULL, NULL, + NULL, &cx2, NULL, NULL, NULL, + EVAS_TEXTBLOCK_CURSOR_BEFORE)); + evas_textblock_cursor_pos_set(cur, 8); + evas_textblock_cursor_pen_geometry_get(cur, &x2, NULL, NULL, NULL); + evas_textblock_cursor_pos_set(cur, 9); + evas_textblock_cursor_pen_geometry_get(cur, &x, NULL, NULL, NULL); + fail_if(cx != x); + fail_if(cx2 != x2); + + /* Cursor is between items of the same direction */ + evas_textblock_cursor_pos_set(cur, 13); + fail_if(evas_textblock_cursor_geometry_bidi_get(cur, &cx, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, + EVAS_TEXTBLOCK_CURSOR_BEFORE)); + evas_textblock_cursor_pen_geometry_get(cur, &x, NULL, NULL, NULL); + fail_if(cx != x); + + /* Cursor type is UNDER */ + evas_textblock_cursor_pos_set(cur, 0); + fail_if(evas_textblock_cursor_geometry_bidi_get(cur, &cx, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, + EVAS_TEXTBLOCK_CURSOR_UNDER)); + evas_textblock_cursor_pen_geometry_get(cur, &x, NULL, NULL, NULL); + fail_if(cx != x); + + /* Multiline */ + Evas_Coord ly; + int i; + /* 012345678901234 */ + evas_object_textblock_text_markup_set(tb, "testשלוםشسيبefl"); + evas_object_textblock_size_native_get(tb, &nw, &nh); + nh = nh * 15; + evas_object_resize(tb, nw, nh); + + for (i = 0; i < nw; i++) + { + evas_object_resize(tb, i, nh); + + evas_textblock_cursor_pos_set(cur, 12); + fail_if(!evas_textblock_cursor_geometry_bidi_get(cur, &cx, &cy, NULL, + NULL, &cx2, &cy2, NULL, NULL, + EVAS_TEXTBLOCK_CURSOR_BEFORE)); + evas_textblock_cursor_line_geometry_get(cur, NULL, &ly, NULL, NULL); + fail_if(cy != ly); + evas_textblock_cursor_pen_geometry_get(cur, &x, NULL, NULL, NULL); + fail_if(cx != x); + evas_textblock_cursor_pos_set(cur, 11); + evas_textblock_cursor_line_geometry_get(cur, NULL, &ly, NULL, NULL); + fail_if(cy2 != ly); + evas_textblock_cursor_pen_geometry_get(cur, &x2, NULL, NULL, NULL); + fail_if(cx2 != x2); + } + /* 01234567890123456789 */ + evas_object_textblock_text_markup_set(tb, "נסיוןhelloприветשלום"); + evas_object_textblock_size_native_get(tb, &nw, &nh); + nh = nh * 20; + evas_object_resize(tb, nw, nh); + + for (i = 0; i < nw; i++) + { + evas_object_resize(tb, i, nh); + + evas_textblock_cursor_pos_set(cur, 16); + fail_if(!evas_textblock_cursor_geometry_bidi_get(cur, &cx, &cy, NULL, + NULL, &cx2, &cy2, NULL, NULL, + EVAS_TEXTBLOCK_CURSOR_BEFORE)); + evas_textblock_cursor_line_geometry_get(cur, NULL, &ly, NULL, NULL); + fail_if(cy != ly); + evas_textblock_cursor_pen_geometry_get(cur, &x, NULL, &w, NULL); + fail_if(cx != (x + w)); + evas_textblock_cursor_pos_set(cur, 15); + evas_textblock_cursor_line_geometry_get(cur, NULL, &ly, NULL, NULL); + fail_if(cy2 != ly); + evas_textblock_cursor_pen_geometry_get(cur, &x2, NULL, &w2, NULL); + fail_if(cx2 != (x2 + w2)); + } + + /* Testing multiline, when only RTL item is in the line. */ + /* 012345678901234567890123 */ + evas_object_textblock_text_markup_set(tb, "testtesttestтестשלוםشسيب"); + evas_object_textblock_size_native_get(tb, &nw, &nh); + nh = nh * 23; + evas_object_resize(tb, nw, nh); + + evas_textblock_cursor_pos_set(cur, 15); + evas_textblock_cursor_pen_geometry_get(cur, &x, NULL, &w, NULL); + /* Resizing textblock, so RTL item will be on the next line.*/ + evas_object_resize(tb, x + w, nh); + + evas_textblock_cursor_pos_set(cur, 24); + fail_if(!evas_textblock_cursor_geometry_bidi_get(cur, &cx, &cy, NULL, + NULL, &cx2, &cy2, NULL, NULL, + EVAS_TEXTBLOCK_CURSOR_BEFORE)); + evas_textblock_cursor_pos_set(cur, 16); + evas_textblock_cursor_pen_geometry_get(cur, &x, NULL, &w, NULL); + fail_if(cx != (x + w)); + evas_textblock_cursor_line_geometry_get(cur, NULL, &ly, NULL, NULL); + fail_if(cy != ly); + + evas_textblock_cursor_pos_set(cur, 23); + evas_textblock_cursor_pen_geometry_get(cur, &x2, NULL, NULL, NULL); + fail_if(cx2 != x2); + evas_textblock_cursor_line_geometry_get(cur, NULL, &ly, NULL, NULL); + fail_if(cy2 != ly); + + /* Testing multiline, when only LTR item is in the line. */ + /* 012345678901234567890123 */ + evas_object_textblock_text_markup_set(tb, "שלוםשלוםשלוםشسيبtestтест"); + evas_object_textblock_size_native_get(tb, &nw, &nh); + nh = nh * 23; + evas_object_resize(tb, nw, nh); + + evas_textblock_cursor_pos_set(cur, 15); + evas_textblock_cursor_pen_geometry_get(cur, &x, NULL, &w, NULL); + /* Resizing textblock, so LTR item will be on the next line.*/ + evas_object_resize(tb, nw - x, nh); + + evas_textblock_cursor_pos_set(cur, 24); + fail_if(!evas_textblock_cursor_geometry_bidi_get(cur, &cx, &cy, NULL, + NULL, &cx2, &cy2, NULL, NULL, + EVAS_TEXTBLOCK_CURSOR_BEFORE)); + evas_textblock_cursor_pos_set(cur, 16); + evas_textblock_cursor_pen_geometry_get(cur, &x, NULL, NULL, NULL); + fail_if(cx != x); + evas_textblock_cursor_line_geometry_get(cur, NULL, &ly, NULL, NULL); + fail_if(cy != ly); + + evas_textblock_cursor_pos_set(cur, 23); + evas_textblock_cursor_pen_geometry_get(cur, &x2, NULL, &w2, NULL); + fail_if(cx2 != (x2 + w2)); + evas_textblock_cursor_line_geometry_get(cur, NULL, &ly, NULL, NULL); + fail_if(cy2 != ly); + + END_TB_TEST(); +#endif +} +END_TEST + START_TEST(evas_textblock_format_removal) { START_TB_TEST(); @@ -2318,6 +2644,7 @@ void evas_test_textblock(TCase *tc) { tcase_add_test(tc, evas_textblock_simple); tcase_add_test(tc, evas_textblock_cursor); + tcase_add_test(tc, evas_textblock_split_cursor); tcase_add_test(tc, evas_textblock_size); tcase_add_test(tc, evas_textblock_editing); tcase_add_test(tc, evas_textblock_style);