[atspi] try bottom-up search first for getting accessible object at x,y point
authorShinwoo Kim <cinoo.kim@samsung.com>
Thu, 17 Nov 2016 12:17:16 +0000 (21:17 +0900)
committerTaehyub Kim <taehyub.kim@samsung.com>
Tue, 29 Nov 2016 12:32:36 +0000 (21:32 +0900)
Change-Id: Iaa77a9c86886cb3771cf66080234d8fcc1cac8fd

src/lib/elm_widget.c

index 6f8b16e..337c046 100644 (file)
@@ -6743,10 +6743,86 @@ _elm_widget_elm_interface_atspi_accessible_name_set(Eo *obj EINA_UNUSED, Elm_Wid
 //
 
 //TIZEN_ONLY(20160329): widget: improve accessibile_at_point getter (a8aff0423202b9a55dbb3843205875226678fbd6)
-EOLIAN static Eo *
-_elm_widget_elm_interface_atspi_component_accessible_at_point_get(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED, Eina_Bool screen_coords, int x, int y)
+static void
+_coordinate_system_based_point_translate(Eo *obj, Eina_Bool screen_coords, int *x, int *y)
+{
+   Ecore_Evas *ee;
+   int ee_x = 0;
+   int ee_y = 0;
+
+   if (screen_coords)
+     {
+        ee = ecore_evas_ecore_evas_get(evas_object_evas_get(obj));
+        if (!ee) return;
+
+        ecore_evas_geometry_get(ee, &ee_x, &ee_y, NULL, NULL);
+        *x -= ee_x;
+        *y -= ee_y;
+     }
+}
+
+static Evas_Object *
+_parent_get(Evas_Object *obj)
+{
+   Evas_Object *parent;
+
+   parent = evas_object_smart_parent_get(obj);
+   if (!parent)
+     {
+        if (strcmp("Elm_Win", eo_class_name_get(eo_class_get(obj))))
+          parent = elm_widget_parent_get(obj);
+     }
+
+   return parent;
+}
+
+static Eina_Bool
+_is_inside(Evas_Object *obj, int x, int y)
+{
+   Eina_Bool ret = EINA_TRUE;
+   Evas_Coord cx = 0;
+   Evas_Coord cy = 0;
+   Evas_Coord cw = 0;
+   Evas_Coord ch = 0;
+   if (eo_isa(obj, ELM_WIDGET_ITEM_CLASS))
+     {
+        Elm_Widget_Item_Data *id = eo_data_scope_get(obj, ELM_WIDGET_ITEM_CLASS);
+        evas_object_geometry_get(id->view, &cx, &cy, &cw, &ch);
+     }
+   else
+     evas_object_geometry_get(obj, &cx, &cy, &cw, &ch);
+
+   /* check the point is out of bound */
+   if (x < cx || x > cx + cw || y < cy || y > cy + ch)
+     {
+        ret = EINA_FALSE;
+     }
+   return ret;
+}
+
+static Eina_Bool
+_is_ancestor_of(Evas_Object *smart_parent, Evas_Object *obj)
+{
+   Eina_Bool ret = EINA_FALSE;
+   Evas_Object *parent = elm_widget_parent_get(obj);
+   while (parent)
+     {
+        /* No need to check more, the smart_parent is parent of obj */
+        if (smart_parent == parent)
+          {
+             ret = EINA_TRUE;
+             break;
+          }
+        parent = elm_widget_parent_get(parent);
+     }
+
+   return ret;
+}
+
+static Eo *
+_accessible_at_point_top_down_get(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED, Eina_Bool screen_coords, int x, int y)
 {
-   Eina_List *l, *l2, *children;
+   Eina_List *l, *l2, *children, *valid_children = NULL;
    Eo *child;
    Evas_Object *stack_item;
    Eo *compare_obj;
@@ -6754,26 +6830,23 @@ _elm_widget_elm_interface_atspi_component_accessible_at_point_get(Eo *obj, Elm_W
    Eo *proxy;
    Evas_Coord px, py, pw, ph;
    //
-   int ee_x, ee_y;
 
-   if (screen_coords)
-     {
-        Ecore_Evas *ee = ecore_evas_ecore_evas_get(evas_object_evas_get(obj));
-        if (!ee) return NULL;
-        ecore_evas_geometry_get(ee, &ee_x, &ee_y, NULL, NULL);
-        x -= ee_x;
-        y -= ee_y;
-     }
+   _coordinate_system_based_point_translate(obj, screen_coords, &x, &y);
 
    eo_do(obj, children = elm_interface_atspi_accessible_children_get());
 
+   EINA_LIST_FOREACH(children, l2, child)
+     {
+        if (_is_inside(child, x, y))
+          valid_children = eina_list_append(valid_children, child);
+     }
    /* Get evas_object stacked at given x,y coordinates starting from top */
    Eina_List *stack = evas_tree_objects_at_xy_get(evas_object_evas_get(obj), NULL, x, y);
    /* Foreach stacked object starting from top */
    EINA_LIST_FOREACH(stack, l, stack_item)
      {
-        /* Foreach at-spi children traverse stack_item evas_objects hierarchy */
-        EINA_LIST_FOREACH(children, l2, child)
+        /* Foreach at-spi valid children traverse stack_item evas_objects hierarchy */
+        EINA_LIST_FOREACH(valid_children, l2, child)
           {
              Elm_Atspi_Role role;
              eo_do(child, role = elm_interface_atspi_accessible_role_get());
@@ -6793,7 +6866,13 @@ _elm_widget_elm_interface_atspi_component_accessible_at_point_get(Eo *obj, Elm_W
              /* In case of access object compare should be 'wrapped' evas_object */
              if (eo_isa(child, ELM_ACCESS_CLASS))
                {
-                  Elm_Access_Info *info = _elm_access_info_get(child);
+                   Elm_Access_Info *info = _elm_access_info_get(child);
+                   compare_obj = info->part_object;
+                }
+             /* In case of widget is registerd by elm_access_object_register */
+             Elm_Access_Info *info = _elm_access_info_get(child);
+             if (info && info->part_object)
+               {
                   compare_obj = info->part_object;
                }
 
@@ -6830,7 +6909,9 @@ _elm_widget_elm_interface_atspi_component_accessible_at_point_get(Eo *obj, Elm_W
                           }
                      }
                    //
-                   smart_parent = evas_object_smart_parent_get(smart_parent);
+
+                   smart_parent = _parent_get(smart_parent);
+                   if (_is_ancestor_of(smart_parent, obj)) break;
                }
           }
      }
@@ -6839,6 +6920,69 @@ _elm_widget_elm_interface_atspi_component_accessible_at_point_get(Eo *obj, Elm_W
    eina_list_free(stack);
    return NULL;
 }
+
+static int _sort_by_repeat_events(const void *data1, const void *data2)
+{
+   Eina_Bool repeat1, repeat2;
+
+   repeat1 = evas_object_repeat_events_get(data1);
+   repeat2 = evas_object_repeat_events_get(data2);
+
+   if (repeat1 != repeat2 && repeat1 == EINA_TRUE) return 1;
+   return -1;
+}
+
+EOLIAN static Eo *
+_elm_widget_elm_interface_atspi_component_accessible_at_point_get(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED, Eina_Bool screen_coords, int x, int y)
+{
+   Eina_List *l;
+   Evas_Object *stack_item;
+
+   if(strcmp("Elm_Win", eo_class_name_get(eo_class_get(obj))))
+     return _accessible_at_point_top_down_get(obj, _pd, screen_coords, x, y);
+
+   _coordinate_system_based_point_translate(obj, screen_coords, &x, &y);
+
+   Eina_List *stack = evas_tree_objects_at_xy_get(evas_object_evas_get(obj), NULL, x, y);
+   stack = eina_list_sort(stack, -1, _sort_by_repeat_events);
+
+   EINA_LIST_FOREACH(stack, l, stack_item)
+     {
+        Evas_Object *smart_parent = stack_item;
+        while (smart_parent)
+          {
+             Evas_Object *ao = elm_access_object_get(smart_parent);
+             if (ao) return ao;
+
+             if (eo_isa(smart_parent, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN))
+               {
+                  Eina_Bool acceptable = EINA_FALSE;
+
+                  Elm_Atspi_Role role;
+                  eo_do(smart_parent, role = elm_interface_atspi_accessible_role_get());
+                  switch (role)
+                    {
+                     case ELM_ATSPI_ROLE_FILLER: /* ex: View of colorselector item is layout */
+                     case ELM_ATSPI_ROLE_ICON:
+                     case ELM_ATSPI_ROLE_IMAGE:
+                     case ELM_ATSPI_ROLE_REDUNDANT_OBJECT:
+                     case ELM_ATSPI_ROLE_WINDOW:
+                       DBG("Go for parent: %s (%p)\n", evas_object_type_get(smart_parent), smart_parent);
+                       break;
+
+                     default:
+                       acceptable = EINA_TRUE;
+                       break;
+                    }
+
+                    if (acceptable) return smart_parent;
+               }
+
+             smart_parent = _parent_get(smart_parent);
+          }
+     }
+   return NULL;
+}
 //
 
 //TIZEN_ONLY(20150709) add relations atpi