Evas object: Add paragraph_direciton APIs 74/59674/1
authorYoungbok Shin <youngb.shin@samsung.com>
Thu, 19 Nov 2015 11:37:07 +0000 (11:37 +0000)
committerYoungbok Shin <youngb.shin@samsung.com>
Wed, 17 Feb 2016 08:55:37 +0000 (17:55 +0900)
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

Conflicts:
src/lib/evas/canvas/evas_object_text.c

Change-Id: Ie97eab545f487bdd817156b18fd434f814159183

19 files changed:
src/Makefile_Evas.am
src/lib/edje/edje_object.eo
src/lib/edje/edje_smart.c
src/lib/evas/canvas/evas_object.eo
src/lib/evas/canvas/evas_object_main.c
src/lib/evas/canvas/evas_object_smart.c
src/lib/evas/canvas/evas_object_smart.eo
src/lib/evas/canvas/evas_object_text.c
src/lib/evas/canvas/evas_object_textblock.c
src/lib/evas/canvas/evas_text.eo
src/lib/evas/canvas/evas_textblock.eo
src/lib/evas/canvas/evas_types.eot
src/lib/evas/common/language/evas_bidi_utils.c
src/lib/evas/common/language/evas_bidi_utils.h
src/tests/evas/evas_suite.c
src/tests/evas/evas_suite.h
src/tests/evas/evas_test_object_smart.c [new file with mode: 0644]
src/tests/evas/evas_test_text.c
src/tests/evas/evas_test_textblock.c

index c062f58..1d1a79e 100644 (file)
@@ -2138,6 +2138,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 \
index 31e4aff..ff80ef3 100644 (file)
@@ -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;
index 5bd5ce2..43227a0 100644 (file)
@@ -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"
index 0639af2..af5b853 100644 (file)
@@ -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.
 
index 3517bcd..1fd2348 100644 (file)
@@ -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"
 
index 451c073..d9f8a89 100644 (file)
@@ -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"
index 56eb8f5..3ecab65 100644 (file)
@@ -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;
    }
 }
index 48a09f3..6fe711a 100644 (file)
@@ -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;
 };
@@ -700,7 +703,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;
@@ -721,7 +725,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);
@@ -1069,8 +1094,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;
 }
 
@@ -1550,6 +1600,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());
@@ -1946,12 +1997,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,
@@ -2220,6 +2289,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
@@ -2280,4 +2352,50 @@ evas_object_text_filter_source_set(Eo *obj, const char *name, Evas_Object *eo_so
    eo_do(obj, efl_gfx_filter_source_set(name, (Efl_Gfx_Base *)eo_source));
 }
 
+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"
index 271f344..ef9db67 100644 (file)
@@ -525,6 +525,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;
@@ -537,6 +538,8 @@ struct _Evas_Object_Textblock
    Eina_Bool                           have_ellipsis : 1;
    Eina_Bool                           hyphenating : 1;
    Eina_Bool                           legacy_newline : 1;
+   Eina_Bool                           inherit_paragraph_direction : 1;
+   Eina_Bool                           changed_paragraph_direction : 1;
 };
 
 struct _Evas_Textblock_Selection_Iterator
@@ -2935,15 +2938,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;
@@ -6122,6 +6144,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
 }
 
 /*
@@ -12547,6 +12572,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
@@ -13126,12 +13154,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) ||
@@ -13149,10 +13195,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;
      }
@@ -13372,6 +13426,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;
+}
+
 /**
  * @}
  */
index b063d6b..e26c561 100644 (file)
@@ -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;
    }
 }
index 6c5231b..a087400 100644 (file)
@@ -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;
    }
 }
index eb4b042..818aa6a 100644 (file)
@@ -72,7 +72,8 @@ enum Evas.BiDi_Direction {
    natural = 0,
    neutral = 0,
    ltr,
-   rtl
+   rtl,
+   inherit
 }
 
 enum Evas.Text_Style_Type {
index e3ae361..f04c825 100644 (file)
@@ -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,
index 37a4e65..dfccec8 100644 (file)
@@ -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);
index 242215f..10a8d27 100644 (file)
@@ -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 }
 };
 
index 574bdc2..bf77aee 100644 (file)
@@ -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 (file)
index 0000000..6f31197
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ * TODO:
+ * * Test different font lodaing mechanisms.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+#include <Eina.h>
+
+#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, "%^&amp;");
+   fail_if(strcmp(evas_object_textblock_text_markup_get(tb), "%^&amp;"));
+   evas_object_paragraph_direction_set(tb, EVAS_BIDI_DIRECTION_INHERIT);
+
+   ADD_EVAS_TEXT();
+   evas_object_text_text_set(to, "%^&amp;");
+   fail_if(strcmp(evas_object_text_text_get(to), "%^&amp;"));
+   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);
+}
index d6417cd..fe5644a 100644 (file)
@@ -397,6 +397,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
index d7d3fef..400175e 100644 (file)
@@ -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, "%^&amp;");
+   fail_if(strcmp(evas_object_textblock_text_markup_get(tb), "%^&amp;"));
+   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, "%^&amp;");
+        fail_if(strcmp(evas_object_textblock_text_markup_get(tb), "%^&amp;"));
+
+        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נסיון<ps/>"
          "נסיוןtestנסיוןtest<ps/>"