atspi: fix infinite loop issue
authorShinwoo Kim <cinoo.kim@samsung.com>
Wed, 13 Dec 2017 09:13:16 +0000 (14:43 +0530)
committerJiyoun Park <jy0703.park@samsung.com>
Thu, 21 Dec 2017 13:34:07 +0000 (22:34 +0900)
It is possilbe to get a target object as a return value of
get_object_at_point. In this case _elm_widget_elm_interface_atspi_component_accessible_at_point_get
works again with the target which is same with root object.

[Enhanced]
- We do not have to go parent if the bottom up logic meets root object.
- Visiblity of panel is always true. So we are checking its SHOWING state.
  If the panel is not SHOWING, remove it from valid children list.

orignal patch: 680532bd4dff4ca12f9ec0958fcb65ac67a89256

@tizen_fix

Change-Id: I9b18a6fda915f4958c3b965454c6bb2ba9663fa6

src/lib/elementary/elm_atspi_bridge.c
src/lib/elementary/elm_widget.c

index 8dfd54f..de055a0 100644 (file)
@@ -4362,16 +4362,34 @@ static unsigned char _accept_object(accessibility_navigation_pointer_table *tabl
    return 1;
 }
 
+/* The target cannot be a parent of root */
+static Eina_Bool _target_validation_check(Eo *target, Eo *root)
+{
+   Eo *parent;
+   parent = efl_access_parent_get(root);
+
+   while (parent)
+     {
+        if (parent == target) return EINA_FALSE;
+        parent = efl_access_parent_get(parent);
+     }
+
+   return EINA_TRUE;
+}
+
 static void *_calculate_navigable_accessible_at_point_impl(accessibility_navigation_pointer_table *table,
           void *root, int x, int y, unsigned char coordinates_are_screen_based)
 {
    if (!root) return NULL;
+   void *prev_root = root;
 
    void *return_value = NULL;
    while (1)
      {
        void *target = CALL(get_object_at_point, root, x, y, coordinates_are_screen_based);
        if (!target) break;
+       if (target == root || target == prev_root) break;
+       if (!_target_validation_check(target, root)) break;
 
        // always return proxy, so atspi lib can call on it again
        if (CALL(object_is_proxy, target)) return target;
index 0286244..9c5ce87 100644 (file)
@@ -6557,20 +6557,28 @@ _is_ancestor_of(Evas_Object *smart_parent, Evas_Object *obj)
 }
 
 static Eina_Bool
-_is_acceptable_leaf(Eo *obj)
+_acceptable_child_is(Eo *obj)
 {
    Efl_Access_Role role;
    Eina_List *children;
+   Efl_Access_State_Set ss;
 
    role = efl_access_role_get(obj);
    switch (role)
      {
        case EFL_ACCESS_ROLE_IMAGE:
        case EFL_ACCESS_ROLE_ICON:
+       /* remove unacceptable leaf node */
          children = efl_access_children_get(obj);
          if (!children) return EINA_FALSE;
          break;
 
+       case EFL_ACCESS_ROLE_PANEL:
+         /* remove closed panel fron children list */
+         ss = efl_access_state_set_get(obj);
+         if (!STATE_TYPE_GET(ss, EFL_ACCESS_STATE_SHOWING)) return EINA_FALSE;
+         break;
+
        default:
          break;
      }
@@ -6596,7 +6604,7 @@ _accessible_at_point_top_down_get(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSE
 
    EINA_LIST_FOREACH(children, l2, child)
      {
-        if (_is_inside(child, x, y) && _is_acceptable_leaf(child))
+        if (_is_inside(child, x, y) && _acceptable_child_is(child))
           valid_children = eina_list_append(valid_children, child);
      }
 
@@ -6734,6 +6742,11 @@ _elm_widget_efl_access_component_accessible_at_point_get(Eo *obj, Elm_Widget_Sma
         Evas_Object *smart_parent = stack_item;
         while (smart_parent)
           {
+             /* If parent equals to obj, it is not necessary to go upper.
+                So the top down logic would be better than NULL return. */
+             if (smart_parent == obj)
+               return _accessible_at_point_top_down_get(obj, _pd, screen_coords, x, y);
+
              Evas_Object *ao = elm_access_object_get(smart_parent);
              if (ao) return ao;