From a9b4be11e1e7525d98c08a5bb04b1f29ea8b0d4f Mon Sep 17 00:00:00 2001 From: Youngbok Shin Date: Thu, 19 Nov 2015 11:37:07 +0000 Subject: [PATCH] Evas object: Add paragraph_direciton APIs Summary: It adds evas_object_paragraph_direction_set, get APIs. The APIs set or get paragraph direction to/from the given object. It changes BiDi calculations and affect the direction and aligning of text. It doesn't have any effect to text without Fribidi library. The default paragraph direction is EVAS_BIDI_DIRECTION_INHERIT. If dir is EVAS_BIDI_DIRECTION_INHERIT, paragraph direction is changed according to smart parent object. If there is no smart parent object, paragraph direction works as EVAS_BIDI_DIRECTION_NEUTRAL. @feature Test Plan: Test cases included to the following files. - evas_test_textblock.c - evas_test_text.c - evas_test_object_smart.c Run "make check". Reviewers: woohyun, raster, herdsman, tasn Subscribers: c, raster, cedric Differential Revision: https://phab.enlightenment.org/D1690 --- src/Makefile_Evas.am | 1 + src/lib/edje/edje_object.eo | 1 + src/lib/edje/edje_smart.c | 11 + src/lib/evas/canvas/evas_object.eo | 13 ++ src/lib/evas/canvas/evas_object_main.c | 12 ++ src/lib/evas/canvas/evas_object_smart.c | 106 ++++++++++ src/lib/evas/canvas/evas_object_smart.eo | 2 + src/lib/evas/canvas/evas_object_text.c | 126 +++++++++++- src/lib/evas/canvas/evas_object_textblock.c | 112 +++++++++- src/lib/evas/canvas/evas_text.eo | 2 + src/lib/evas/canvas/evas_textblock.eo | 2 + src/lib/evas/canvas/evas_types.eot | 3 +- .../evas/common/language/evas_bidi_utils.c | 13 +- .../evas/common/language/evas_bidi_utils.h | 2 +- src/tests/evas/evas_suite.c | 1 + src/tests/evas/evas_suite.h | 1 + src/tests/evas/evas_test_object_smart.c | 180 ++++++++++++++++ src/tests/evas/evas_test_text.c | 9 + src/tests/evas/evas_test_textblock.c | 194 +++++++++++++++++- 19 files changed, 775 insertions(+), 16 deletions(-) create mode 100644 src/tests/evas/evas_test_object_smart.c diff --git a/src/Makefile_Evas.am b/src/Makefile_Evas.am index 11ebd43242..e5abebc3d8 100644 --- a/src/Makefile_Evas.am +++ b/src/Makefile_Evas.am @@ -2121,6 +2121,7 @@ tests_evas_evas_suite_SOURCES = \ tests/evas/evas_suite.c \ tests/evas/evas_test_init.c \ tests/evas/evas_test_object.c \ +tests/evas/evas_test_object_smart.c \ tests/evas/evas_test_textblock.c \ tests/evas/evas_test_text.c \ tests/evas/evas_test_callbacks.c \ diff --git a/src/lib/edje/edje_object.eo b/src/lib/edje/edje_object.eo index 31e4affd00..ff80ef3b7e 100644 --- a/src/lib/edje/edje_object.eo +++ b/src/lib/edje/edje_object.eo @@ -2138,6 +2138,7 @@ class Edje.Object (Evas.Smart_Clipped, Efl.File) Eo.Base.constructor; Eo.Base.destructor; Eo.Base.dbg_info_get; + Evas.Object.paragraph_direction.set; Evas.Object_Smart.hide; Evas.Object_Smart.calculate; Evas.Object_Smart.show; diff --git a/src/lib/edje/edje_smart.c b/src/lib/edje/edje_smart.c index 5bd5ce2830..43227a0764 100644 --- a/src/lib/edje/edje_smart.c +++ b/src/lib/edje/edje_smart.c @@ -389,4 +389,15 @@ edje_object_file_get(const Edje_Object *obj, const char **file, const char **gro eo_do((Edje_Object *)obj, efl_file_get(file, group)); } +EOLIAN static void +_edje_object_evas_object_paragraph_direction_set(Eo *obj, Edje *ed, Evas_BiDi_Direction dir) +{ + eo_do_super(obj, MY_CLASS, evas_obj_paragraph_direction_set(dir)); + + /* Make it dirty to recalculate edje. + It needs to move text objects according to new paragraph direction */ + ed->dirty = EINA_TRUE; + eo_do(obj, evas_obj_smart_need_recalculate_set(1)); +} + #include "edje_object.eo.c" diff --git a/src/lib/evas/canvas/evas_object.eo b/src/lib/evas/canvas/evas_object.eo index 0639af214b..af5b85375c 100644 --- a/src/lib/evas/canvas/evas_object.eo +++ b/src/lib/evas/canvas/evas_object.eo @@ -976,6 +976,19 @@ abstract Evas.Object (Eo.Base, Evas.Common_Interface, Efl.Gfx.Base, Efl.Gfx.Stac dispmode: Evas.Display_Mode; [[Display mode hint.]] } } + @property paragraph_direction { + [[This handles text paragraph direction of the given object. + Even if the given object is not textblock or text, its smart child objects + can inherit the paragraph direction from the given object. + The default paragraph direction is @Evas.BiDi_Direction.inherit.]] + set { + } + get { + } + values { + dir: Evas.BiDi_Direction; [[Paragraph direction for the given object.]] + } + } clipees_has @const { [[Test if any object is clipped by $obj. diff --git a/src/lib/evas/canvas/evas_object_main.c b/src/lib/evas/canvas/evas_object_main.c index 3517bcd79c..1fd2348e6d 100644 --- a/src/lib/evas/canvas/evas_object_main.c +++ b/src/lib/evas/canvas/evas_object_main.c @@ -2013,5 +2013,17 @@ _evas_object_smart_type_check_ptr(const Eo *eo_obj EINA_UNUSED, Evas_Object_Prot return EINA_FALSE; } +EOLIAN static void +_evas_object_paragraph_direction_set(Eo *eo_obj EINA_UNUSED, Evas_Object_Protected_Data *obj EINA_UNUSED, Evas_BiDi_Direction dir EINA_UNUSED) +{ + return; +} + +EOLIAN static Evas_BiDi_Direction +_evas_object_paragraph_direction_get(Eo *eo_obj EINA_UNUSED, Evas_Object_Protected_Data *obj EINA_UNUSED) +{ + return EVAS_BIDI_DIRECTION_NEUTRAL; +} + #include "canvas/evas_object.eo.c" diff --git a/src/lib/evas/canvas/evas_object_smart.c b/src/lib/evas/canvas/evas_object_smart.c index 451c073b14..d9f8a89a7a 100644 --- a/src/lib/evas/canvas/evas_object_smart.c +++ b/src/lib/evas/canvas/evas_object_smart.c @@ -35,6 +35,8 @@ struct _Evas_Smart_Data unsigned char recalculate_cycle; + Evas_BiDi_Direction paragraph_direction : 2; + Eina_Bool inherit_paragraph_direction : 1; Eina_Bool deletions_waiting : 1; Eina_Bool need_recalculate : 1; Eina_Bool update_boundingbox_needed : 1; @@ -83,6 +85,8 @@ static void evas_object_smart_render_post(Evas_Object *eo_obj, static unsigned int evas_object_smart_id_get(Evas_Object *eo_obj); static unsigned int evas_object_smart_visual_id_get(Evas_Object *eo_obj); static void *evas_object_smart_engine_data_get(Evas_Object *eo_obj); +static void _evas_object_smart_paragraph_direction_set_internal(Eo *eo_obj, + Evas_BiDi_Direction dir); static const Evas_Object_Func object_func = { @@ -209,6 +213,7 @@ _evas_object_smart_member_add(Eo *smart_obj, Evas_Smart_Data *o, Evas_Object *eo Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS); Evas_Object_Protected_Data *smart = eo_data_scope_get(smart_obj, EVAS_OBJECT_CLASS); + Evas_Smart_Data *member_o; if (obj->delete_me) { @@ -257,6 +262,19 @@ _evas_object_smart_member_add(Eo *smart_obj, Evas_Smart_Data *o, Evas_Object *eo evas_object_smart_member_cache_invalidate(eo_obj, EINA_TRUE, EINA_TRUE, EINA_TRUE); obj->restack = 1; + + if (obj->is_smart) + { + member_o = eo_data_scope_get(eo_obj, EVAS_OBJECT_SMART_CLASS); + + if ((member_o->inherit_paragraph_direction) && + (member_o->paragraph_direction != o->paragraph_direction)) + { + member_o->paragraph_direction = o->paragraph_direction; + _evas_object_smart_paragraph_direction_set_internal(eo_obj, o->paragraph_direction); + } + } + evas_object_change(eo_obj, obj); evas_object_mapped_clip_across_mark(eo_obj, obj); if (smart->smart.smart && smart->smart.smart->smart_class->member_add) @@ -282,6 +300,7 @@ EOLIAN static void _evas_object_smart_member_del(Eo *smart_obj, Evas_Smart_Data *_pd EINA_UNUSED, Evas_Object *eo_obj) { Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS); + Evas_Smart_Data *member_o; if (!obj->smart.parent) return; @@ -304,6 +323,18 @@ _evas_object_smart_member_del(Eo *smart_obj, Evas_Smart_Data *_pd EINA_UNUSED, E } EINA_COW_STATE_WRITE_END(obj, state_write, cur); + if (obj->is_smart) + { + member_o = eo_data_scope_get(eo_obj, EVAS_OBJECT_SMART_CLASS); + + if ((member_o->inherit_paragraph_direction) && + (member_o->paragraph_direction != EVAS_BIDI_DIRECTION_NEUTRAL)) + { + member_o->paragraph_direction = EVAS_BIDI_DIRECTION_NEUTRAL; + _evas_object_smart_paragraph_direction_set_internal(eo_obj, EVAS_BIDI_DIRECTION_NEUTRAL); + } + } + evas_object_inject(eo_obj, obj, obj->layer->evas->evas); obj->restack = 1; evas_object_change(eo_obj, obj); @@ -551,6 +582,7 @@ _evas_object_smart_eo_base_constructor(Eo *eo_obj, Evas_Smart_Data *class_data E smart = class_data; smart->object = eo_obj; + smart->inherit_paragraph_direction = EINA_TRUE; eo_obj = eo_do_super_ret(eo_obj, MY_CLASS, eo_obj, eo_constructor()); evas_object_smart_init(eo_obj); @@ -1469,4 +1501,78 @@ _evas_object_smart_class_destructor(Eo_Class *klass EINA_UNUSED) eina_hash_free(_evas_smart_class_names_hash_table); } +static void +_evas_object_smart_paragraph_direction_set_internal(Eo *eo_obj, + Evas_BiDi_Direction dir) +{ + Evas_Object_Protected_Data *o; + Evas_Smart_Data *member_o; + + EINA_INLIST_FOREACH(evas_object_smart_members_get_direct(eo_obj), o) + { + evas_object_change(o->object, o); + + if (o->is_smart) + { + member_o = eo_data_scope_get(o->object, EVAS_OBJECT_SMART_CLASS); + + if ((member_o->inherit_paragraph_direction) && + (member_o->paragraph_direction != dir)) + { + member_o->paragraph_direction = dir; + _evas_object_smart_paragraph_direction_set_internal(o->object, dir); + } + } + } +} + +EOLIAN static void +_evas_object_smart_evas_object_paragraph_direction_set(Eo *eo_obj, Evas_Smart_Data *o, Evas_BiDi_Direction dir) +{ + Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS); + Evas_Smart_Data *parent; + + MAGIC_CHECK(eo_obj, Evas_Object, MAGIC_OBJ); + return; + MAGIC_CHECK_END(); + + if ((!(o->inherit_paragraph_direction) && (o->paragraph_direction == dir)) || + (o->inherit_paragraph_direction && (dir == EVAS_BIDI_DIRECTION_INHERIT))) + return; + + if (dir == EVAS_BIDI_DIRECTION_INHERIT) + { + o->inherit_paragraph_direction = EINA_TRUE; + Evas_BiDi_Direction parent_dir = EVAS_BIDI_DIRECTION_NEUTRAL; + + if (obj->smart.parent) + { + parent = eo_data_scope_get(obj->smart.parent, EVAS_OBJECT_SMART_CLASS); + + if (parent) + parent_dir = parent->paragraph_direction; + } + + if (parent_dir != o->paragraph_direction) + { + o->paragraph_direction = parent_dir; + evas_object_change(eo_obj, obj); + } + } + else + { + o->inherit_paragraph_direction = EINA_FALSE; + o->paragraph_direction = dir; + evas_object_change(eo_obj, obj); + } + + _evas_object_smart_paragraph_direction_set_internal(eo_obj, o->paragraph_direction); +} + +EOLIAN static Evas_BiDi_Direction +_evas_object_smart_evas_object_paragraph_direction_get(Eo *eo_obj EINA_UNUSED, Evas_Smart_Data *o) +{ + return o->paragraph_direction; +} + #include "canvas/evas_object_smart.eo.c" diff --git a/src/lib/evas/canvas/evas_object_smart.eo b/src/lib/evas/canvas/evas_object_smart.eo index 56eb8f54da..3ecab659e2 100644 --- a/src/lib/evas/canvas/evas_object_smart.eo +++ b/src/lib/evas/canvas/evas_object_smart.eo @@ -300,5 +300,7 @@ class Evas.Object_Smart (Evas.Object, Evas.Signal_Interface) Evas.Object.smart_type_check_ptr; Evas.Object.smart_type_check; Evas.Object.smart_data.get; + Evas.Object.paragraph_direction.set; + Evas.Object.paragraph_direction.get; } } diff --git a/src/lib/evas/canvas/evas_object_text.c b/src/lib/evas/canvas/evas_object_text.c index f650048d38..08aa27050b 100644 --- a/src/lib/evas/canvas/evas_object_text.c +++ b/src/lib/evas/canvas/evas_object_text.c @@ -68,6 +68,9 @@ struct _Evas_Text_Data float max_ascent, max_descent; Evas_BiDi_Direction bidi_dir : 2; + Evas_BiDi_Direction paragraph_direction : 2; + Eina_Bool inherit_paragraph_direction : 1; + Eina_Bool changed_paragraph_direction : 1; Eina_Bool changed : 1; Eina_Bool has_filter : 1; }; @@ -696,7 +699,8 @@ _evas_object_text_layout(Evas_Object *eo_obj, Evas_Text_Data *o, Eina_Unicode *t o->cur.text == text && obj->cur->scale == obj->prev->scale && ((o->last_computed.advance <= obj->cur->geometry.w && !o->last_computed.ellipsis) || - o->last_computed.w == obj->cur->geometry.w)) + (o->last_computed.w == obj->cur->geometry.w)) && + !o->changed_paragraph_direction) return; o->last_computed.ellipsis = EINA_FALSE; @@ -717,7 +721,28 @@ _evas_object_text_layout(Evas_Object *eo_obj, Evas_Text_Data *o, Eina_Unicode *t } evas_bidi_paragraph_props_unref(o->bidi_par_props); if (text) - o->bidi_par_props = evas_bidi_paragraph_props_get(text, len, segment_idxs); + { + Evas_BiDi_Direction par_dir; + EvasBiDiParType bidi_par_type; + + par_dir = o->paragraph_direction; + + switch (par_dir) + { + case EVAS_BIDI_DIRECTION_LTR: + bidi_par_type = EVAS_BIDI_PARAGRAPH_LTR; + break; + case EVAS_BIDI_DIRECTION_RTL: + bidi_par_type = EVAS_BIDI_PARAGRAPH_RTL; + break; + case EVAS_BIDI_DIRECTION_NEUTRAL: + default: + bidi_par_type = EVAS_BIDI_PARAGRAPH_NEUTRAL; + break; + } + + o->bidi_par_props = evas_bidi_paragraph_props_get(text, len, segment_idxs, bidi_par_type); + } if (o->bidi_par_props) o->bidi_dir = EVAS_BIDI_PAR_TYPE_TO_DIRECTION(o->bidi_par_props->direction); @@ -1056,8 +1081,33 @@ _evas_text_efl_text_text_get(Eo *eo_obj EINA_UNUSED, Evas_Text_Data *o) } EOLIAN static Evas_BiDi_Direction -_evas_text_direction_get(Eo *eo_obj EINA_UNUSED, Evas_Text_Data *o) +_evas_text_direction_get(Eo *eo_obj, Evas_Text_Data *o) { +#ifdef BIDI_SUPPORT + Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS); + + if (o->inherit_paragraph_direction) + { + Evas_BiDi_Direction parent_dir = EVAS_BIDI_DIRECTION_NEUTRAL; + + if (obj->smart.parent) + parent_dir = evas_object_paragraph_direction_get(obj->smart.parent); + + if (parent_dir != o->paragraph_direction) + { + o->paragraph_direction = parent_dir; + o->changed_paragraph_direction = EINA_TRUE; + } + } + + if (o->changed_paragraph_direction) + { + _evas_object_text_recalc(eo_obj, o->cur.text); + evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, + eo_obj, obj); + } +#endif + return o->bidi_dir; } @@ -1537,6 +1587,7 @@ evas_object_text_init(Evas_Object *eo_obj) o->prev = o->cur; #ifdef BIDI_SUPPORT o->bidi_par_props = evas_bidi_paragraph_props_new(); + o->inherit_paragraph_direction = EINA_TRUE; #endif eo_do(eo_obj, evas_filter_constructor()); @@ -1925,12 +1976,30 @@ evas_object_text_render_pre(Evas_Object *eo_obj, obj->cur->clipper, obj->cur->clipper->private_data); } + +#ifdef BIDI_SUPPORT + if (o->inherit_paragraph_direction) + { + Evas_BiDi_Direction parent_dir = EVAS_BIDI_DIRECTION_NEUTRAL; + + if (obj->smart.parent) + parent_dir = evas_object_paragraph_direction_get(obj->smart.parent); + + if (parent_dir != o->paragraph_direction) + { + o->paragraph_direction = parent_dir; + o->changed_paragraph_direction = EINA_TRUE; + } + } +#endif + /* If object size changed and ellipsis is set */ if (((o->cur.ellipsis >= 0.0 || o->cur.ellipsis != o->prev.ellipsis) && ((obj->cur->geometry.w != o->last_computed.w) || (obj->cur->geometry.h != o->last_computed.h))) || - (obj->cur->scale != obj->prev->scale)) + (obj->cur->scale != obj->prev->scale) || + (o->changed_paragraph_direction)) { _evas_object_text_recalc(eo_obj, o->cur.text); evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, @@ -2199,6 +2268,9 @@ _evas_object_text_recalc(Evas_Object *eo_obj, Eina_Unicode *text) } o->last_computed.w = obj->cur->geometry.w; o->last_computed.h = obj->cur->geometry.h; +#ifdef BIDI_SUPPORT + o->changed_paragraph_direction = EINA_FALSE; +#endif } EAPI void @@ -2247,4 +2319,50 @@ _evas_text_efl_gfx_filter_program_set(Eo *obj, Evas_Text_Data *pd EINA_UNUSED, c eo_do_super(obj, MY_CLASS, efl_gfx_filter_program_set(code, name)); } +EOLIAN static void +_evas_text_evas_object_paragraph_direction_set(Eo *eo_obj, Evas_Text_Data *o, Evas_BiDi_Direction dir) +{ +#ifdef BIDI_SUPPORT + Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS); + + if ((!(o->inherit_paragraph_direction) && (o->paragraph_direction == dir)) || + (o->inherit_paragraph_direction && (dir == EVAS_BIDI_DIRECTION_INHERIT))) + return; + + if (dir == EVAS_BIDI_DIRECTION_INHERIT) + { + o->inherit_paragraph_direction = EINA_TRUE; + Evas_BiDi_Direction parent_dir = EVAS_BIDI_DIRECTION_NEUTRAL; + + if (obj->smart.parent) + parent_dir = evas_object_paragraph_direction_get(obj->smart.parent); + + if (parent_dir != o->paragraph_direction) + { + o->paragraph_direction = parent_dir; + o->changed_paragraph_direction = EINA_TRUE; + evas_object_change(eo_obj, obj); + } + } + else + { + o->inherit_paragraph_direction = EINA_FALSE; + o->paragraph_direction = dir; + o->changed_paragraph_direction = EINA_TRUE; + evas_object_change(eo_obj, obj); + } +#else + (void) eo_obj; + (void) o; + (void) dir; +#endif +} + +EOLIAN static Evas_BiDi_Direction +_evas_text_evas_object_paragraph_direction_get(Eo *eo_obj EINA_UNUSED, + Evas_Text_Data *o) +{ + return o->paragraph_direction; +} + #include "canvas/evas_text.eo.c" diff --git a/src/lib/evas/canvas/evas_object_textblock.c b/src/lib/evas/canvas/evas_object_textblock.c index 4bc0e8ee46..c559ed2fa1 100644 --- a/src/lib/evas/canvas/evas_object_textblock.c +++ b/src/lib/evas/canvas/evas_object_textblock.c @@ -507,6 +507,7 @@ struct _Evas_Object_Textblock void *engine_data; const char *repch; const char *bidi_delimiters; + Evas_BiDi_Direction paragraph_direction : 2; struct { int w, h, oneline_h; Eina_Bool valid : 1; @@ -518,6 +519,8 @@ struct _Evas_Object_Textblock Eina_Bool format_changed : 1; Eina_Bool have_ellipsis : 1; Eina_Bool legacy_newline : 1; + Eina_Bool inherit_paragraph_direction : 1; + Eina_Bool changed_paragraph_direction : 1; }; struct _Evas_Textblock_Selection_Iterator @@ -2882,15 +2885,34 @@ _layout_update_bidi_props(const Evas_Textblock_Data *o, { const Eina_Unicode *text; int *segment_idxs = NULL; + Evas_BiDi_Direction par_dir; + EvasBiDiParType bidi_par_type; + text = eina_ustrbuf_string_get(par->text_node->unicode); if (o->bidi_delimiters) segment_idxs = evas_bidi_segment_idxs_get(text, o->bidi_delimiters); + par_dir = o->paragraph_direction; + + switch (par_dir) + { + case EVAS_BIDI_DIRECTION_LTR: + bidi_par_type = EVAS_BIDI_PARAGRAPH_LTR; + break; + case EVAS_BIDI_DIRECTION_RTL: + bidi_par_type = EVAS_BIDI_PARAGRAPH_RTL; + break; + case EVAS_BIDI_DIRECTION_NEUTRAL: + default: + bidi_par_type = EVAS_BIDI_PARAGRAPH_NEUTRAL; + break; + } + evas_bidi_paragraph_props_unref(par->bidi_props); par->bidi_props = evas_bidi_paragraph_props_get(text, eina_ustrbuf_length_get(par->text_node->unicode), - segment_idxs); + segment_idxs, bidi_par_type); par->direction = EVAS_BIDI_PARAGRAPH_DIRECTION_IS_RTL(par->bidi_props) ? EVAS_BIDI_DIRECTION_RTL : EVAS_BIDI_DIRECTION_LTR; par->is_bidi = !!par->bidi_props; @@ -5801,6 +5823,9 @@ _relayout(const Evas_Object *eo_obj) o->content_changed = 0; o->format_changed = EINA_FALSE; o->redraw = 1; +#ifdef BIDI_SUPPORT + o->changed_paragraph_direction = EINA_FALSE; +#endif } /* @@ -11502,6 +11527,9 @@ evas_object_textblock_init(Evas_Object *eo_obj) evas_object_textblock_text_markup_set(eo_obj, ""); o->legacy_newline = EINA_TRUE; +#ifdef BIDI_SUPPORT + o->inherit_paragraph_direction = EINA_TRUE; +#endif } EOLIAN static void @@ -12045,12 +12073,30 @@ evas_object_textblock_render(Evas_Object *eo_obj EINA_UNUSED, } static void -evas_object_textblock_coords_recalc(Evas_Object *eo_obj EINA_UNUSED, +evas_object_textblock_coords_recalc(Evas_Object *eo_obj, Evas_Object_Protected_Data *obj, void *type_private_data) { Evas_Textblock_Data *o = type_private_data; +#ifdef BIDI_SUPPORT + if (o->inherit_paragraph_direction) + { + Evas_BiDi_Direction parent_dir = EVAS_BIDI_DIRECTION_NEUTRAL; + + if (obj->smart.parent) + { + parent_dir = evas_object_paragraph_direction_get(obj->smart.parent); + } + + if (parent_dir != o->paragraph_direction) + { + o->paragraph_direction = parent_dir; + o->changed_paragraph_direction = EINA_TRUE; + } + } +#endif + if ( // width changed thus we may have to re-wrap or change centering etc. (obj->cur->geometry.w != o->last_w) || @@ -12068,10 +12114,18 @@ evas_object_textblock_coords_recalc(Evas_Object *eo_obj EINA_UNUSED, (o->content_changed) || // if format changed (eg styles) we need to re-format/match tags etc. (o->format_changed) || - (o->obstacle_changed) + (o->obstacle_changed) || + (o->changed_paragraph_direction) ) { - LYDBG("ZZ: invalidate 2 %p ## %i != %i || %3.3f || %i && %i != %i | %i %i\n", eo_obj, obj->cur->geometry.w, o->last_w, o->valign, o->have_ellipsis, obj->cur->geometry.h, o->last_h, o->content_changed, o->format_changed); + LYDBG("ZZ: invalidate 2 %p ## %i != %i || %3.3f || %i && %i != %i | %i %i || %d\n", eo_obj, obj->cur->geometry.w, o->last_w, o->valign, o->have_ellipsis, obj->cur->geometry.h, o->last_h, o->content_changed, o->format_changed, o->changed_paragraph_direction); + + if (o->changed_paragraph_direction) + { + _evas_textblock_invalidate_all(o); + _evas_textblock_changed(o, eo_obj); + } + o->formatted.valid = 0; o->changed = 1; } @@ -12291,6 +12345,56 @@ _evas_object_textblock_rehint(Evas_Object *eo_obj) _evas_textblock_changed(o, eo_obj); } +EOLIAN static void +_evas_textblock_evas_object_paragraph_direction_set(Eo *eo_obj, + Evas_Textblock_Data *o, + Evas_BiDi_Direction dir) +{ +#ifdef BIDI_SUPPORT + Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS); + + if ((!(o->inherit_paragraph_direction) && (o->paragraph_direction == dir)) || + (o->inherit_paragraph_direction && (dir == EVAS_BIDI_DIRECTION_INHERIT))) + return; + + if (dir == EVAS_BIDI_DIRECTION_INHERIT) + { + o->inherit_paragraph_direction = EINA_TRUE; + Evas_BiDi_Direction parent_dir = EVAS_BIDI_DIRECTION_NEUTRAL; + + if (obj->smart.parent) + parent_dir = evas_object_paragraph_direction_get(obj->smart.parent); + + if (parent_dir != o->paragraph_direction) + { + o->paragraph_direction = parent_dir; + o->changed_paragraph_direction = EINA_TRUE; + _evas_textblock_invalidate_all(o); + _evas_textblock_changed(o, eo_obj); + } + } + else + { + o->inherit_paragraph_direction = EINA_FALSE; + o->paragraph_direction = dir; + o->changed_paragraph_direction = EINA_TRUE; + _evas_textblock_invalidate_all(o); + _evas_textblock_changed(o, eo_obj); + } +#else + (void) eo_obj; + (void) o; + (void) dir; +#endif +} + +EOLIAN static Evas_BiDi_Direction +_evas_textblock_evas_object_paragraph_direction_get(Eo *eo_obj EINA_UNUSED, + Evas_Textblock_Data *o) +{ + return o->paragraph_direction; +} + /** * @} */ diff --git a/src/lib/evas/canvas/evas_text.eo b/src/lib/evas/canvas/evas_text.eo index b063d6b435..e26c56162c 100644 --- a/src/lib/evas/canvas/evas_text.eo +++ b/src/lib/evas/canvas/evas_text.eo @@ -264,5 +264,7 @@ class Evas.Text (Evas.Object, Efl.Text, Efl.Text_Properties, Evas.Filter) Evas.Filter.input_alpha; Evas.Filter.input_render; Evas.Filter.dirty; + Evas.Object.paragraph_direction.set; + Evas.Object.paragraph_direction.get; } } diff --git a/src/lib/evas/canvas/evas_textblock.eo b/src/lib/evas/canvas/evas_textblock.eo index 6c5231b061..a087400414 100644 --- a/src/lib/evas/canvas/evas_textblock.eo +++ b/src/lib/evas/canvas/evas_textblock.eo @@ -325,5 +325,7 @@ class Evas.Textblock (Evas.Object) Eo.Base.constructor; Eo.Base.destructor; Eo.Base.dbg_info_get; + Evas.Object.paragraph_direction.set; + Evas.Object.paragraph_direction.get; } } diff --git a/src/lib/evas/canvas/evas_types.eot b/src/lib/evas/canvas/evas_types.eot index eb4b042895..818aa6a452 100644 --- a/src/lib/evas/canvas/evas_types.eot +++ b/src/lib/evas/canvas/evas_types.eot @@ -72,7 +72,8 @@ enum Evas.BiDi_Direction { natural = 0, neutral = 0, ltr, - rtl + rtl, + inherit } enum Evas.Text_Style_Type { diff --git a/src/lib/evas/common/language/evas_bidi_utils.c b/src/lib/evas/common/language/evas_bidi_utils.c index e3ae361c81..f04c825701 100644 --- a/src/lib/evas/common/language/evas_bidi_utils.c +++ b/src/lib/evas/common/language/evas_bidi_utils.c @@ -222,11 +222,12 @@ evas_bidi_segment_idxs_get(const Eina_Unicode *str, const char *delim) * @param ustr The string to update according to. * @param len The length of the string * @param segment_idxs A -1 terminated array of points to start a new bidi analysis at (used for section high level bidi overrides). - NULL means none. + * @param base_bidi The base BiDi direction of paragraph. * @return returns allocated paragraph props on success, NULL otherwise. */ Evas_BiDi_Paragraph_Props * evas_bidi_paragraph_props_get(const Eina_Unicode *eina_ustr, size_t len, - int *segment_idxs) + int *segment_idxs, EvasBiDiParType base_bidi) { Evas_BiDi_Paragraph_Props *bidi_props = NULL; EvasBiDiCharType *char_types = NULL; @@ -237,8 +238,9 @@ evas_bidi_paragraph_props_get(const Eina_Unicode *eina_ustr, size_t len, if (!eina_ustr) return NULL; - - if (!evas_bidi_is_rtl_str(eina_ustr)) /* No need to handle bidi */ + /* No need to handle bidi */ + if (!evas_bidi_is_rtl_str(eina_ustr) && + (base_bidi != EVAS_BIDI_PARAGRAPH_RTL)) { len = -1; goto cleanup; @@ -255,6 +257,7 @@ evas_bidi_paragraph_props_get(const Eina_Unicode *eina_ustr, size_t len, #endif bidi_props = evas_bidi_paragraph_props_new(); + bidi_props->direction = base_bidi; /* Prep work for reordering */ char_types = (EvasBiDiCharType *) malloc(sizeof(EvasBiDiCharType) * len); @@ -281,7 +284,7 @@ evas_bidi_paragraph_props_get(const Eina_Unicode *eina_ustr, size_t len, for (itr = segment_idxs ; *itr > 0 ; itr++) { - direction = EVAS_BIDI_PARAGRAPH_NEUTRAL; + direction = base_bidi; if (!fribidi_get_par_embedding_levels(char_types + pos, *itr - pos, &direction, @@ -308,7 +311,7 @@ evas_bidi_paragraph_props_get(const Eina_Unicode *eina_ustr, size_t len, pos = *itr + 1; } - direction = EVAS_BIDI_PARAGRAPH_NEUTRAL; + direction = base_bidi; if (!fribidi_get_par_embedding_levels(char_types + pos, len - pos, &direction, diff --git a/src/lib/evas/common/language/evas_bidi_utils.h b/src/lib/evas/common/language/evas_bidi_utils.h index 37a4e65964..dfccec8166 100644 --- a/src/lib/evas/common/language/evas_bidi_utils.h +++ b/src/lib/evas/common/language/evas_bidi_utils.h @@ -143,7 +143,7 @@ Eina_Bool evas_bidi_props_reorder_line(Eina_Unicode *eina_ustr, size_t start, size_t len, const Evas_BiDi_Paragraph_Props *props, EvasBiDiStrIndex **_v_to_l); Evas_BiDi_Paragraph_Props * -evas_bidi_paragraph_props_get(const Eina_Unicode *eina_ustr, size_t len, int *segment_idxs) EINA_ARG_NONNULL(1) EINA_MALLOC EINA_WARN_UNUSED_RESULT; +evas_bidi_paragraph_props_get(const Eina_Unicode *eina_ustr, size_t len, int *segment_idxs, EvasBiDiParType base_bidi) EINA_ARG_NONNULL(1) EINA_MALLOC EINA_WARN_UNUSED_RESULT; void evas_bidi_props_copy_and_ref(const Evas_BiDi_Props *src, Evas_BiDi_Props *dst); diff --git a/src/tests/evas/evas_suite.c b/src/tests/evas/evas_suite.c index 242215f65d..10a8d2732c 100644 --- a/src/tests/evas/evas_suite.c +++ b/src/tests/evas/evas_suite.c @@ -29,6 +29,7 @@ static const Evas_Test_Case etc[] = { { "Meshes", evas_test_mesh }, { "Masking", evas_test_mask }, { "Evas GL", evas_test_evasgl }, + { "Object Smart", evas_test_object_smart }, { NULL, NULL } }; diff --git a/src/tests/evas/evas_suite.h b/src/tests/evas/evas_suite.h index 574bdc2969..bf77aee056 100644 --- a/src/tests/evas/evas_suite.h +++ b/src/tests/evas/evas_suite.h @@ -14,5 +14,6 @@ void evas_test_image_object(TCase *tc); void evas_test_mesh(TCase *tc); void evas_test_mask(TCase *tc); void evas_test_evasgl(TCase *tc); +void evas_test_object_smart(TCase *tc); #endif /* _EVAS_SUITE_H */ diff --git a/src/tests/evas/evas_test_object_smart.c b/src/tests/evas/evas_test_object_smart.c new file mode 100644 index 0000000000..6f31197220 --- /dev/null +++ b/src/tests/evas/evas_test_object_smart.c @@ -0,0 +1,180 @@ +/* + * TODO: + * * Test different font lodaing mechanisms. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include + +#include "evas_suite.h" +#include "Evas.h" +#include "evas_tests_helpers.h" + +#define TEST_FONT_SOURCE TESTS_SRC_DIR "/TestFont.eet" +#define TEST_TEXTBLOCK_FONT "font=DejaVuSans font_source=" TEST_FONT_SOURCE +#define TEST_TEXTBLOCK_FONT_SIZE "14" +#define TEST_TEXT_FONT "DejaVuSans,UnDotum" +#define TEST_TEXT_FONT_SIZE 14 + +static const char *style_buf = + "DEFAULT='" TEST_TEXTBLOCK_FONT " font_size="TEST_TEXTBLOCK_FONT_SIZE" color=#000 text_class=entry'" + "newline='br'" + "b='+ font_weight=bold'"; + +#define START_EVAS_OBJECT_SMART_TEST() \ + Evas *evas; \ + Evas_Object *smart_obj; \ + evas = EVAS_TEST_INIT_EVAS(); \ + smart_obj = evas_object_box_add(evas); \ + fail_if(!smart_obj); \ +do \ +{ \ +} \ +while (0) + +#define END_EVAS_OBJECT_SMART_TEST() \ +do \ +{ \ + evas_object_del(smart_obj); \ + evas_free(evas); \ + evas_shutdown(); \ +} \ +while (0) + +#define ADD_EVAS_TEXTBLOCK() \ + Evas_Object *tb; \ + Evas_Textblock_Style *st; \ + Evas_Textblock_Cursor *cur; \ + evas_font_hinting_set(evas, EVAS_FONT_HINTING_AUTO); \ + tb = evas_object_textblock_add(evas); \ + fail_if(!tb); \ + evas_object_textblock_legacy_newline_set(tb, EINA_FALSE); \ + st = evas_textblock_style_new(); \ + fail_if(!st); \ + evas_textblock_style_set(st, style_buf); \ + fail_if(strcmp(style_buf, evas_textblock_style_get(st))); \ + evas_object_textblock_style_set(tb, st); \ + cur = evas_object_textblock_cursor_new(tb); \ +do \ +{ \ +} \ +while (0) + +#define ADD_EVAS_TEXT() \ + Evas_Object *to; \ + evas_font_hinting_set(evas, EVAS_FONT_HINTING_AUTO); \ + to = evas_object_text_add(evas); \ + fail_if(!to); \ + evas_object_text_font_source_set(to, TEST_FONT_SOURCE); \ + evas_object_text_font_set(to, TEST_TEXT_FONT, TEST_TEXT_FONT_SIZE); \ +do \ +{ \ +} \ +while (0) + +#define DELETE_EVAS_TEXTBLOCK() \ +do \ +{ \ + evas_textblock_cursor_free(cur); \ + evas_object_del(tb); \ + evas_textblock_style_free(st); \ +} \ +while (0) + +#define DELETE_EVAS_TEXT() \ +do \ +{ \ + evas_object_del(to); \ +} \ +while (0) + +START_TEST(evas_object_smart_paragraph_direction) +{ + START_EVAS_OBJECT_SMART_TEST(); + + ADD_EVAS_TEXTBLOCK(); + evas_object_resize(tb, 500, 500); + evas_object_textblock_text_markup_set(tb, "%^&"); + fail_if(strcmp(evas_object_textblock_text_markup_get(tb), "%^&")); + evas_object_paragraph_direction_set(tb, EVAS_BIDI_DIRECTION_INHERIT); + + ADD_EVAS_TEXT(); + evas_object_text_text_set(to, "%^&"); + fail_if(strcmp(evas_object_text_text_get(to), "%^&")); + evas_object_paragraph_direction_set(to, EVAS_BIDI_DIRECTION_INHERIT); + + /* Test evas_object_paragraph_direction_set API with smart objects. */ + Evas_Object *smart_child = evas_object_box_add(evas); + Evas_BiDi_Direction dir; + Evas_Coord x, y, w, h; + Evas_Coord xx, yy, ww, hh; + + evas_object_smart_member_add(smart_child, smart_obj); + evas_object_smart_member_add(tb, smart_child); + evas_object_smart_member_add(to, smart_child); + + dir = EVAS_BIDI_DIRECTION_RTL; + evas_textblock_cursor_geometry_get(cur, &x, &y, &w, &h, &dir, + EVAS_TEXTBLOCK_CURSOR_UNDER); + fail_if(dir == EVAS_BIDI_DIRECTION_RTL); + fail_if(evas_object_text_direction_get(to) == EVAS_BIDI_DIRECTION_RTL); + + /* Change paragraph direction of smart parent object */ + evas_object_paragraph_direction_set(smart_obj, EVAS_BIDI_DIRECTION_RTL); + dir = EVAS_BIDI_DIRECTION_LTR; + evas_textblock_cursor_geometry_get(cur, &xx, &yy, &ww, &hh, &dir, + EVAS_TEXTBLOCK_CURSOR_UNDER); + fail_if(dir != EVAS_BIDI_DIRECTION_RTL); + fail_if((x >= xx) || (y != yy) || (w != ww) || (h != hh)); + fail_if(evas_object_text_direction_get(to) != EVAS_BIDI_DIRECTION_RTL); + + /* The paragraph direction of smart member object has to be reset + if smart member object is removed from smart parent. */ + evas_object_smart_member_del(smart_child); + + dir = EVAS_BIDI_DIRECTION_RTL; + evas_textblock_cursor_geometry_get(cur, &x, &y, &w, &h, &dir, + EVAS_TEXTBLOCK_CURSOR_UNDER); + fail_if(dir == EVAS_BIDI_DIRECTION_RTL); + fail_if((x >= xx) || (y != yy) || (w != ww) || (h != hh)); + fail_if(evas_object_text_direction_get(to) == EVAS_BIDI_DIRECTION_RTL); + + /* The paragraph direction of smart member object has to be changed + if smart member object is appended to smart parent. */ + evas_object_smart_member_add(smart_child, smart_obj); + + dir = EVAS_BIDI_DIRECTION_LTR; + evas_textblock_cursor_geometry_get(cur, &xx, &yy, &ww, &hh, &dir, + EVAS_TEXTBLOCK_CURSOR_UNDER); + fail_if(dir != EVAS_BIDI_DIRECTION_RTL); + fail_if((x >= xx) || (y != yy) || (w != ww) || (h != hh)); + fail_if(evas_object_text_direction_get(to) != EVAS_BIDI_DIRECTION_RTL); + + /* Ignore smart parent's paragraph direction */ + evas_object_paragraph_direction_set(tb, EVAS_BIDI_DIRECTION_NEUTRAL); + evas_object_paragraph_direction_set(to, EVAS_BIDI_DIRECTION_NEUTRAL); + dir = EVAS_BIDI_DIRECTION_RTL; + evas_textblock_cursor_geometry_get(cur, &x, &y, &w, &h, &dir, + EVAS_TEXTBLOCK_CURSOR_UNDER); + fail_if(dir == EVAS_BIDI_DIRECTION_RTL); + fail_if((x >= xx) || (y != yy) || (w != ww) || (h != hh)); + fail_if(evas_object_text_direction_get(to) == EVAS_BIDI_DIRECTION_RTL); + + evas_object_smart_member_del(tb); + evas_object_smart_member_del(to); + evas_object_del(smart_child); + + DELETE_EVAS_TEXTBLOCK(); + DELETE_EVAS_TEXT(); + END_EVAS_OBJECT_SMART_TEST(); +} +END_TEST + +void evas_test_object_smart(TCase *tc) +{ + tcase_add_test(tc, evas_object_smart_paragraph_direction); +} diff --git a/src/tests/evas/evas_test_text.c b/src/tests/evas/evas_test_text.c index 90ce19dcc8..128e8ac743 100644 --- a/src/tests/evas/evas_test_text.c +++ b/src/tests/evas/evas_test_text.c @@ -362,6 +362,15 @@ START_TEST(evas_text_set_get) fail_if(evas_object_text_direction_get(to) != EVAS_BIDI_DIRECTION_LTR); #endif +#ifdef HAVE_FRIBIDI + /* Check direction with evas_object_paragraph_direction_set API */ + evas_object_text_text_set(to, "12345"); + fail_if(evas_object_text_direction_get(to) == EVAS_BIDI_DIRECTION_RTL); + evas_object_paragraph_direction_set(to, EVAS_BIDI_DIRECTION_RTL); + fail_if(evas_object_text_direction_get(to) != EVAS_BIDI_DIRECTION_RTL); + evas_object_paragraph_direction_set(to, EVAS_BIDI_DIRECTION_NEUTRAL); +#endif + END_TEXT_TEST(); } END_TEST diff --git a/src/tests/evas/evas_test_textblock.c b/src/tests/evas/evas_test_textblock.c index 44b7de238e..61f1431a2a 100644 --- a/src/tests/evas/evas_test_textblock.c +++ b/src/tests/evas/evas_test_textblock.c @@ -421,6 +421,7 @@ START_TEST(evas_textblock_cursor) fail_if(evas_textblock_cursor_compare(main_cur, cur)); } +#ifdef HAVE_FRIBIDI /* Check direction */ evas_object_textblock_text_markup_set(tb, "test"); fail_if(strcmp(evas_object_textblock_text_markup_get(tb), "test")); @@ -442,8 +443,199 @@ START_TEST(evas_textblock_cursor) evas_textblock_cursor_geometry_get(cur, NULL, NULL, NULL, NULL, &dir, EVAS_TEXTBLOCK_CURSOR_BEFORE); fail_if(dir != EVAS_BIDI_DIRECTION_RTL); + evas_object_textblock_text_markup_set(tb, "123"); + fail_if(strcmp(evas_object_textblock_text_markup_get(tb), "123")); + dir = EVAS_BIDI_DIRECTION_RTL; + evas_textblock_cursor_geometry_get(cur, NULL, NULL, NULL, NULL, &dir, + EVAS_TEXTBLOCK_CURSOR_UNDER); + fail_if(dir != EVAS_BIDI_DIRECTION_LTR); + dir = EVAS_BIDI_DIRECTION_RTL; + evas_textblock_cursor_geometry_get(cur, NULL, NULL, NULL, NULL, &dir, + EVAS_TEXTBLOCK_CURSOR_BEFORE); + fail_if(dir != EVAS_BIDI_DIRECTION_LTR); + evas_object_textblock_text_markup_set(tb, "%^&"); + fail_if(strcmp(evas_object_textblock_text_markup_get(tb), "%^&")); + dir = EVAS_BIDI_DIRECTION_RTL; + evas_textblock_cursor_geometry_get(cur, NULL, NULL, NULL, NULL, &dir, + EVAS_TEXTBLOCK_CURSOR_UNDER); + fail_if(dir != EVAS_BIDI_DIRECTION_LTR); + dir = EVAS_BIDI_DIRECTION_RTL; + evas_textblock_cursor_geometry_get(cur, NULL, NULL, NULL, NULL, &dir, + EVAS_TEXTBLOCK_CURSOR_BEFORE); + fail_if(dir != EVAS_BIDI_DIRECTION_LTR); + + /* Check direction with evas_object_paragraph_direction_set API */ + { + Evas_Coord xx, yy, ww, hh; + + /* LTR text case */ + evas_object_textblock_text_markup_set(tb, "test"); + fail_if(strcmp(evas_object_textblock_text_markup_get(tb), "test")); + + /* EVAS_TEXTBLOCK_CURSOR_UNDER */ + evas_object_paragraph_direction_set(tb, EVAS_BIDI_DIRECTION_NEUTRAL); + dir = EVAS_BIDI_DIRECTION_RTL; + evas_textblock_cursor_geometry_get(cur, &x, &y, &w, &h, &dir, + EVAS_TEXTBLOCK_CURSOR_UNDER); + fail_if(dir == EVAS_BIDI_DIRECTION_RTL); + evas_object_paragraph_direction_set(tb, EVAS_BIDI_DIRECTION_RTL); + dir = EVAS_BIDI_DIRECTION_RTL; + evas_textblock_cursor_geometry_get(cur, &xx, &yy, &ww, &hh, &dir, + EVAS_TEXTBLOCK_CURSOR_UNDER); + fail_if(dir == EVAS_BIDI_DIRECTION_RTL); + fail_if((x >= xx) || (y != yy) || (w != ww) || (h != hh)); + evas_object_paragraph_direction_set(tb, EVAS_BIDI_DIRECTION_LTR); + dir = EVAS_BIDI_DIRECTION_RTL; + evas_textblock_cursor_geometry_get(cur, &xx, &yy, &ww, &hh, &dir, + EVAS_TEXTBLOCK_CURSOR_UNDER); + fail_if(dir == EVAS_BIDI_DIRECTION_RTL); + fail_if((x != xx) || (y != yy) || (w != ww) || (h != hh)); + + /* EVAS_TEXTBLOCK_CURSOR_BEFORE */ + evas_object_paragraph_direction_set(tb, EVAS_BIDI_DIRECTION_NEUTRAL); + dir = EVAS_BIDI_DIRECTION_RTL; + evas_textblock_cursor_geometry_get(cur, &x, &y, &w, &h, &dir, + EVAS_TEXTBLOCK_CURSOR_BEFORE); + fail_if(dir == EVAS_BIDI_DIRECTION_RTL); + evas_object_paragraph_direction_set(tb, EVAS_BIDI_DIRECTION_RTL); + dir = EVAS_BIDI_DIRECTION_RTL; + evas_textblock_cursor_geometry_get(cur, &xx, &yy, &ww, &hh, &dir, + EVAS_TEXTBLOCK_CURSOR_BEFORE); + fail_if(dir == EVAS_BIDI_DIRECTION_RTL); + fail_if((x >= xx) || (y != yy) || (w != ww) || (h != hh)); + evas_object_paragraph_direction_set(tb, EVAS_BIDI_DIRECTION_LTR); + dir = EVAS_BIDI_DIRECTION_RTL; + evas_textblock_cursor_geometry_get(cur, &xx, &yy, &ww, &hh, &dir, + EVAS_TEXTBLOCK_CURSOR_BEFORE); + fail_if(dir == EVAS_BIDI_DIRECTION_RTL); + fail_if((x != xx) || (y != yy) || (w != ww) || (h != hh)); + + /* RTL text case */ + evas_object_textblock_text_markup_set(tb, "עוד פסקה"); + fail_if(strcmp(evas_object_textblock_text_markup_get(tb), "עוד פסקה")); + + evas_object_paragraph_direction_set(tb, EVAS_BIDI_DIRECTION_NEUTRAL); + dir = EVAS_BIDI_DIRECTION_LTR; + evas_textblock_cursor_geometry_get(cur, &x, &y, &w, &h, &dir, + EVAS_TEXTBLOCK_CURSOR_UNDER); + fail_if(dir != EVAS_BIDI_DIRECTION_RTL); + evas_object_paragraph_direction_set(tb, EVAS_BIDI_DIRECTION_LTR); + dir = EVAS_BIDI_DIRECTION_LTR; + evas_textblock_cursor_geometry_get(cur, &xx, &yy, &ww, &hh, &dir, + EVAS_TEXTBLOCK_CURSOR_UNDER); + fail_if(dir != EVAS_BIDI_DIRECTION_RTL); + fail_if((x <= xx) || (y != yy) || (w != ww) || (h != hh)); + evas_object_paragraph_direction_set(tb, EVAS_BIDI_DIRECTION_RTL); + dir = EVAS_BIDI_DIRECTION_LTR; + evas_textblock_cursor_geometry_get(cur, &xx, &yy, &ww, &hh, &dir, + EVAS_TEXTBLOCK_CURSOR_UNDER); + fail_if(dir != EVAS_BIDI_DIRECTION_RTL); + fail_if((x != xx) || (y != yy) || (w != ww) || (h != hh)); + + evas_object_paragraph_direction_set(tb, EVAS_BIDI_DIRECTION_NEUTRAL); + dir = EVAS_BIDI_DIRECTION_LTR; + evas_textblock_cursor_geometry_get(cur, &x, &y, &w, &h, &dir, + EVAS_TEXTBLOCK_CURSOR_BEFORE); + fail_if(dir != EVAS_BIDI_DIRECTION_RTL); + evas_object_paragraph_direction_set(tb, EVAS_BIDI_DIRECTION_LTR); + dir = EVAS_BIDI_DIRECTION_LTR; + evas_textblock_cursor_geometry_get(cur, &xx, &yy, &ww, &hh, &dir, + EVAS_TEXTBLOCK_CURSOR_BEFORE); + fail_if(dir != EVAS_BIDI_DIRECTION_RTL); + fail_if((x <= xx) || (y != yy) || (w != ww) || (h != hh)); + evas_object_paragraph_direction_set(tb, EVAS_BIDI_DIRECTION_RTL); + dir = EVAS_BIDI_DIRECTION_LTR; + evas_textblock_cursor_geometry_get(cur, &xx, &yy, &ww, &hh, &dir, + EVAS_TEXTBLOCK_CURSOR_BEFORE); + fail_if(dir != EVAS_BIDI_DIRECTION_RTL); + fail_if((x != xx) || (y != yy) || (w != ww) || (h != hh)); + + /* NEUTRAL(European Number) text case */ + /* It doesn't change characters sequence. */ + evas_object_textblock_text_markup_set(tb, "123"); + fail_if(strcmp(evas_object_textblock_text_markup_get(tb), "123")); + + evas_object_paragraph_direction_set(tb, EVAS_BIDI_DIRECTION_NEUTRAL); + dir = EVAS_BIDI_DIRECTION_RTL; + evas_textblock_cursor_geometry_get(cur, &x, &y, &w, &h, &dir, + EVAS_TEXTBLOCK_CURSOR_UNDER); + fail_if(dir == EVAS_BIDI_DIRECTION_RTL); + evas_object_paragraph_direction_set(tb, EVAS_BIDI_DIRECTION_RTL); + dir = EVAS_BIDI_DIRECTION_RTL; + evas_textblock_cursor_geometry_get(cur, &xx, &yy, &ww, &hh, &dir, + EVAS_TEXTBLOCK_CURSOR_UNDER); + fail_if(dir == EVAS_BIDI_DIRECTION_RTL); + fail_if((x >= xx) || (y != yy) || (w != ww) || (h != hh)); + evas_object_paragraph_direction_set(tb, EVAS_BIDI_DIRECTION_LTR); + dir = EVAS_BIDI_DIRECTION_RTL; + evas_textblock_cursor_geometry_get(cur, &xx, &yy, &ww, &hh, &dir, + EVAS_TEXTBLOCK_CURSOR_UNDER); + fail_if(dir == EVAS_BIDI_DIRECTION_RTL); + fail_if((x != xx) || (y != yy) || (w != ww) || (h != hh)); + + evas_object_paragraph_direction_set(tb, EVAS_BIDI_DIRECTION_NEUTRAL); + dir = EVAS_BIDI_DIRECTION_RTL; + evas_textblock_cursor_geometry_get(cur, &x, &y, &w, &h, &dir, + EVAS_TEXTBLOCK_CURSOR_BEFORE); + fail_if(dir == EVAS_BIDI_DIRECTION_RTL); + evas_object_paragraph_direction_set(tb, EVAS_BIDI_DIRECTION_RTL); + dir = EVAS_BIDI_DIRECTION_RTL; + evas_textblock_cursor_geometry_get(cur, &xx, &yy, &ww, &hh, &dir, + EVAS_TEXTBLOCK_CURSOR_BEFORE); + fail_if(dir == EVAS_BIDI_DIRECTION_RTL); + fail_if((x >= xx) || (y != yy) || (w != ww) || (h != hh)); + evas_object_paragraph_direction_set(tb, EVAS_BIDI_DIRECTION_LTR); + dir = EVAS_BIDI_DIRECTION_RTL; + evas_textblock_cursor_geometry_get(cur, &xx, &yy, &ww, &hh, &dir, + EVAS_TEXTBLOCK_CURSOR_BEFORE); + fail_if(dir == EVAS_BIDI_DIRECTION_RTL); + fail_if((x != xx) || (y != yy) || (w != ww) || (h != hh)); + + /* NEUTRAL(Other Neutrals) text case */ + /* It changes characters sequence. */ + evas_object_textblock_text_markup_set(tb, "%^&"); + fail_if(strcmp(evas_object_textblock_text_markup_get(tb), "%^&")); + + evas_object_paragraph_direction_set(tb, EVAS_BIDI_DIRECTION_NEUTRAL); + dir = EVAS_BIDI_DIRECTION_RTL; + evas_textblock_cursor_geometry_get(cur, &x, &y, &w, &h, &dir, + EVAS_TEXTBLOCK_CURSOR_UNDER); + fail_if(dir == EVAS_BIDI_DIRECTION_RTL); + evas_object_paragraph_direction_set(tb, EVAS_BIDI_DIRECTION_RTL); + dir = EVAS_BIDI_DIRECTION_LTR; + evas_textblock_cursor_geometry_get(cur, &xx, &yy, &ww, &hh, &dir, + EVAS_TEXTBLOCK_CURSOR_UNDER); + fail_if(dir != EVAS_BIDI_DIRECTION_RTL); + fail_if((x >= xx) || (y != yy) || (w != ww) || (h != hh)); + evas_object_paragraph_direction_set(tb, EVAS_BIDI_DIRECTION_LTR); + dir = EVAS_BIDI_DIRECTION_RTL; + evas_textblock_cursor_geometry_get(cur, &xx, &yy, &ww, &hh, &dir, + EVAS_TEXTBLOCK_CURSOR_UNDER); + fail_if(dir == EVAS_BIDI_DIRECTION_RTL); + fail_if((x != xx) || (y != yy) || (w != ww) || (h != hh)); + + evas_object_paragraph_direction_set(tb, EVAS_BIDI_DIRECTION_NEUTRAL); + dir = EVAS_BIDI_DIRECTION_RTL; + evas_textblock_cursor_geometry_get(cur, &x, &y, &w, &h, &dir, + EVAS_TEXTBLOCK_CURSOR_BEFORE); + fail_if(dir == EVAS_BIDI_DIRECTION_RTL); + evas_object_paragraph_direction_set(tb, EVAS_BIDI_DIRECTION_RTL); + dir = EVAS_BIDI_DIRECTION_LTR; + evas_textblock_cursor_geometry_get(cur, &xx, &yy, &ww, &hh, &dir, + EVAS_TEXTBLOCK_CURSOR_BEFORE); + fail_if(dir != EVAS_BIDI_DIRECTION_RTL); + fail_if((x >= xx) || (y != yy) || (w != ww) || (h != hh)); + evas_object_paragraph_direction_set(tb, EVAS_BIDI_DIRECTION_LTR); + dir = EVAS_BIDI_DIRECTION_RTL; + evas_textblock_cursor_geometry_get(cur, &xx, &yy, &ww, &hh, &dir, + EVAS_TEXTBLOCK_CURSOR_BEFORE); + fail_if(dir == EVAS_BIDI_DIRECTION_RTL); + fail_if((x != xx) || (y != yy) || (w != ww) || (h != hh)); + + /* Reset paragraph direction */ + evas_object_paragraph_direction_set(tb, EVAS_BIDI_DIRECTION_NEUTRAL); + } -#ifdef HAVE_FRIBIDI evas_object_textblock_text_markup_set(tb, "testנסיוןtestנסיון" "נסיוןtestנסיוןtest"