Add navigation helper functions for screen-reader and friends (part 2) 42/136142/1
authorRadoslaw Cybulski <r.cybulski@partner.samsung.com>
Fri, 24 Mar 2017 17:50:16 +0000 (18:50 +0100)
committerShinwoo Kim <cinoo.kim@samsung.com>
Wed, 28 Jun 2017 08:08:51 +0000 (17:08 +0900)
Change-Id: Ia9fd6d9743fddcb24801df596d2834b076408ea9

atk-adaptor/adaptors/accessible-adaptor.c
atk-adaptor/bridge.c
droute/droute.c

index a84052a..b0a7d8b 100644 (file)
 #include "introspection.h"
 #include <string.h>
 #include <stdint.h>
-
-
-
-
-
-
-
-
-
-
-
-
+#include <stdlib.h>
 
 // TIZEN_ONLY(20170310) - implementation of get object under coordinates for accessibility
-static AtspiRelationType spi_relation_type_from_atk_relation_type (AtkRelationType type);
+typedef struct {
+   void **objects;
+   unsigned int capacity;
+   unsigned int size;
+} vector;
+
+typedef enum {
+  NEIGHBOR_SEARCH_MODE_NORMAL = 0,
+  NEIGHBOR_SEARCH_MODE_RECURSE_FROM_ROOT = 1,
+  NEIGHBOR_SEARCH_MODE_CONTINUE_AFTER_FAILED_RECURSING = 2,
+} GetNeighborSearchMode;
+
+typedef struct accessibility_navigation_pointer_table {
+   AtspiRole (*object_get_role)(struct accessibility_navigation_pointer_table *t, void *ptr);
+   uint64_t (*object_get_state_set)(struct accessibility_navigation_pointer_table *t, void *ptr);
+   void *(*get_object_in_relation_by_type)(struct accessibility_navigation_pointer_table *t, void *ptr, AtspiRelationType type);
+   unsigned char (*object_is_zero_size)(struct accessibility_navigation_pointer_table *t, void *ptr);
+   void *(*get_parent)(struct accessibility_navigation_pointer_table *t, void *ptr);
+   unsigned char (*object_is_scrollable)(struct accessibility_navigation_pointer_table *t, void *ptr);
+   void *(*get_object_at_point)(struct accessibility_navigation_pointer_table *t, void *ptr, int x, int y, unsigned char coordinates_are_screen_based);
+   unsigned char (*object_contains)(struct accessibility_navigation_pointer_table *t, void *ptr, int x, int y, unsigned char coordinates_are_screen_based);
+   unsigned char (*object_is_proxy)(struct accessibility_navigation_pointer_table *t, void *ptr);
+   void (*get_children)(struct accessibility_navigation_pointer_table *t, void *ptr, vector *v);
+} accessibility_navigation_pointer_table;
 
-static AtspiRole _object_get_role_impl(void *ptr)
+static vector vector_init(void)
 {
-  AtkObject *obj = (AtkObject*)ptr;
-  AtkRole role = atk_object_get_role (obj);
-  AtspiRole rv = spi_accessible_role_from_atk_role (role);
-  return rv;
+   vector v;
+   v.objects = NULL;
+   v.capacity = 0;
+   v.size = 0;
+   return v;
 }
 
-static uint64_t _object_get_state_set_impl(void *ptr)
+static void vector_free(vector *v)
 {
-  dbus_uint32_t array[2];
-  spi_atk_state_to_dbus_array((AtkObject*)ptr, array);
-  uint64_t res = array[0] | ((uint64_t)array[1] << 32);
-  return res;
+   free(v->objects);
+   v->objects = NULL;
+   v->capacity = 0;
+   v->size = 0;
 }
-
-static void *_get_object_in_relation_by_type_impl(void *ptr, AtspiRelationType expected_relation_type)
+static void vector_reserve(vector *v, unsigned int s)
 {
-  if (ptr) {
-    g_return_val_if_fail (ATK_IS_OBJECT (ptr), NULL);
-    AtkRelationSet *set = atk_object_ref_relation_set (ptr);
-    if (!set)
-      return NULL;
-    gint count = atk_relation_set_get_n_relations (set), i;
-    for (i = 0; i < count; i++)
-    {
-      AtkRelation *r = atk_relation_set_get_relation (set, i);
-      if (!r)
-        continue;
-      AtkRelationType rt = atk_relation_get_relation_type (r);
-      AtspiRelationType type = spi_relation_type_from_atk_relation_type (rt);
-      if (expected_relation_type == type)
-      {
-        GPtrArray *target = atk_relation_get_target (r);
-        if (target && target->len > 0)
-          return target->pdata[0];
-      }
-    }
-    g_object_unref (set);
-  }
-  return NULL;
+   if (s > v->capacity)
+     {
+       v->objects = (void**)realloc(v->objects, sizeof(v->objects[0]) * s);
+       v->capacity = s;
+     }
 }
 
-static unsigned char _object_is_zero_size_impl(void *ptr)
+static void vector_resize(vector *v, unsigned int s)
 {
-  AtkObject *obj = (AtkObject*)obj;
-  g_return_val_if_fail(ATK_IS_COMPONENT (obj), 0);
-  gint x, y, w, h;
-  atk_component_get_extents (ATK_COMPONENT(obj), &x, &y, &w, &h, ATSPI_COORD_TYPE_SCREEN);
-  return w == 0 || h == 0;
+   vector_reserve(v, s);
+   v->size = s;
 }
 
-unsigned char _object_is_scrollable_impl(void *ptr)
+static void *vector_get(vector *v, unsigned int index)
 {
-  AtspiRole role = _object_get_role_impl(ptr);
-  switch (role) {
-  case ATSPI_ROLE_SCROLL_PANE:    //scroller
-  case ATSPI_ROLE_LIST:           //genlist, list
-  case ATSPI_ROLE_TREE_TABLE:     //gengrid
-  case ATSPI_ROLE_TOOL_BAR:       //toolbar
-      return 1;
-  default:
-      break;
-  }
-  return 0;
+   return v->objects[index];
 }
 
-void *_get_parent_impl(void *ptr)
+static void vector_set(vector *v, unsigned int index, void *data)
 {
-  return atk_object_get_parent((AtkObject*)ptr);
+   v->objects[index] = data;
 }
 
-void *_object_at_point_get_impl(void *ptr, int x, int y, unsigned char coordinates_are_screen_based)
+static unsigned int vector_size(vector *v)
 {
-  AtkObject *obj = (AtkObject*)ptr;
-  g_return_val_if_fail(ATK_IS_COMPONENT (obj), 0);
-  return atk_component_ref_accessible_at_point (ATK_COMPONENT(obj), x, y,
-          coordinates_are_screen_based ? ATSPI_COORD_TYPE_SCREEN : ATSPI_COORD_TYPE_WINDOW);
+   return v->size;
 }
 
-unsigned char _object_contains_impl(void *ptr, int x, int y, unsigned char coordinates_are_screen_based)
-{
-  AtkObject *obj = (AtkObject*)ptr;
-  g_return_val_if_fail(ATK_IS_COMPONENT (obj), 0);
-
-  return atk_component_contains (ATK_COMPONENT(obj), x, y,
-        coordinates_are_screen_based ? ATSPI_COORD_TYPE_SCREEN : ATSPI_COORD_TYPE_WINDOW);
-}
-
-unsigned char _object_is_proxy_impl(void *ptr)
-{
-  return 0;
-}
-
-typedef struct {
-   AtspiRole (*object_get_role)(void *ptr);
-   uint64_t (*object_get_state_set)(void *ptr);
-   void *(*get_object_in_relation_by_type)(void *ptr, AtspiRelationType type);
-   unsigned char (*object_is_zero_size)(void *ptr);
-   void *(*get_parent)(void *ptr);
-   unsigned char (*object_is_scrollable)(void *ptr);
-   void *(*object_at_point_get)(void *ptr, int x, int y, unsigned char coordinates_are_screen_based);
-   unsigned char (*object_contains)(void *ptr, int x, int y, unsigned char coordinates_are_screen_based);
-   unsigned char (*object_is_proxy)(void *ptr);
-} accessibility_navigation_pointer_table;
-
+#define CALL(fncname, ...) table->fncname(table, __VA_ARGS__)
 static unsigned char _accept_object_check_role(accessibility_navigation_pointer_table *table, void *obj)
 {
-   AtspiRole role = table->object_get_role(obj);
+   AtspiRole role = CALL(object_get_role, obj);
    switch (role)
      {
        case ATSPI_ROLE_APPLICATION:
@@ -193,27 +146,44 @@ static unsigned char _state_set_is_set(uint64_t state_set, AtspiStateType state)
    return (state_set & ((uint64_t)1 << (unsigned int)state)) != 0;
 }
 
+static unsigned char _object_is_defunct(accessibility_navigation_pointer_table *table, void *ptr)
+{
+   uint64_t states = CALL(object_get_state_set, ptr);
+   return _state_set_is_set(states, ATSPI_STATE_DEFUNCT);
+}
+
+static unsigned char _object_role_is_acceptable_when_navigating_next_prev(accessibility_navigation_pointer_table *table, void *obj)
+{
+   AtspiRole role = CALL(object_get_role, obj);
+   return role != ATSPI_ROLE_POPUP_MENU && role != ATSPI_ROLE_DIALOG;
+}
+
+static void *_get_object_in_relation_flow(accessibility_navigation_pointer_table *table, void *source, unsigned char forward)
+{
+    return CALL(get_object_in_relation_by_type, source, forward ? ATSPI_RELATION_FLOWS_TO : ATSPI_RELATION_FLOWS_FROM);
+}
+
 static unsigned char _object_is_item(accessibility_navigation_pointer_table *table, void *obj)
 {
-   AtspiRole role = table->object_get_role(obj);
+   AtspiRole role = CALL(object_get_role, obj);
    return role == ATSPI_ROLE_LIST_ITEM || role == ATSPI_ROLE_MENU_ITEM;
 }
 
 static unsigned char _object_is_highlightable(accessibility_navigation_pointer_table *table, void *obj)
 {
-   uint64_t state_set = table->object_get_state_set(obj);
+   uint64_t state_set = CALL(object_get_state_set, obj);
    return _state_set_is_set(state_set, ATSPI_STATE_HIGHLIGHTABLE);
 }
 
 static unsigned char _object_is_showing(accessibility_navigation_pointer_table *table, void *obj)
 {
-   uint64_t state_set = table->object_get_state_set(obj);
+   uint64_t state_set = CALL(object_get_state_set, obj);
    return _state_set_is_set(state_set, ATSPI_STATE_SHOWING);
 }
 
 static unsigned char _object_is_collapsed(accessibility_navigation_pointer_table *table, void *obj)
 {
-   uint64_t state_set = table->object_get_state_set(obj);
+   uint64_t state_set = CALL(object_get_state_set, obj);
    return
       _state_set_is_set(state_set, ATSPI_STATE_EXPANDABLE) &&
       !_state_set_is_set(state_set, ATSPI_STATE_EXPANDED);
@@ -221,21 +191,21 @@ static unsigned char _object_is_collapsed(accessibility_navigation_pointer_table
 
 static unsigned char _object_has_modal_state(accessibility_navigation_pointer_table *table, void *obj)
 {
-   uint64_t state_set = table->object_get_state_set(obj);
+   uint64_t state_set = CALL(object_get_state_set, obj);
    return _state_set_is_set(state_set, ATSPI_STATE_MODAL);
 }
 
 static unsigned char _object_is_zero_size(accessibility_navigation_pointer_table *table, void *obj)
 {
-   return table->object_is_zero_size(obj);
+   return CALL(object_is_zero_size, obj);
 }
 
 static void *_get_scrollable_parent(accessibility_navigation_pointer_table *table, void *obj)
 {
    while(obj)
      {
-       obj = table->get_parent(obj);
-       if (obj && table->object_is_scrollable(obj)) return obj;
+       obj = CALL(get_parent, obj);
+       if (obj && CALL(object_is_scrollable, obj)) return obj;
      }
    return NULL;
 }
@@ -243,12 +213,12 @@ static unsigned char _accept_object(accessibility_navigation_pointer_table *tabl
 {
    if (!obj) return 0;
    if (!_accept_object_check_role(table, obj)) return 0;
-   if (table->get_object_in_relation_by_type(obj, ATSPI_RELATION_CONTROLLED_BY) != NULL) return 0;
+   if (CALL(get_object_in_relation_by_type, obj, ATSPI_RELATION_CONTROLLED_BY) != NULL) return 0;
    if (!_object_is_highlightable(table, obj)) return 0;
 
    if (_get_scrollable_parent(table, obj) != NULL)
      {
-       void *parent = table->get_parent(obj);
+       void *parent = CALL(get_parent, obj);
 
        if (parent)
          {
@@ -271,18 +241,18 @@ static void *_calculate_navigable_accessible_at_point_impl(accessibility_navigat
    void *return_value = NULL;
    while (1)
      {
-       void *target = table->object_at_point_get(root, x, y, coordinates_are_screen_based);
+       void *target = CALL(get_object_at_point, root, x, y, coordinates_are_screen_based);
        if (!target) break;
 
        // always return proxy, so atspi lib can call on it again
-       if (table->object_is_proxy(target)) return target;
+       if (CALL(object_is_proxy, target)) return target;
 
        root = target;
-       void *relation_obj = table->get_object_in_relation_by_type(root, ATSPI_RELATION_CONTROLLED_BY);
+       void *relation_obj = CALL(get_object_in_relation_by_type, root, ATSPI_RELATION_CONTROLLED_BY);
        unsigned char contains = 0;
        if (relation_obj)
          {
-           contains = table->object_contains(relation_obj, x, y, coordinates_are_screen_based);
+           contains = CALL(object_contains, relation_obj, x, y, coordinates_are_screen_based);
            if (contains) root = relation_obj;
          }
 
@@ -297,6 +267,329 @@ static void *_calculate_navigable_accessible_at_point_impl(accessibility_navigat
    return return_value;
 }
 
+
+
+
+
+
+
+static void *_find_non_defunct_child(accessibility_navigation_pointer_table *table,
+            vector *objects, unsigned int current_index, unsigned char forward)
+{
+   for(; current_index < vector_size(objects); forward ? ++current_index : --current_index)
+     {
+       void *n = vector_get(objects, current_index);
+       if (n && !_object_is_defunct(table, n)) return n;
+     }
+   return NULL;
+}
+
+static void *_directional_depth_first_search_try_non_defunct_child(accessibility_navigation_pointer_table *table,
+            void *node, vector *children, unsigned char forward)
+{
+   if (vector_size(children) > 0)
+     {
+       unsigned char is_showing = _get_scrollable_parent(table, node) == NULL ? _object_is_showing(table, node) : 1;
+       if (is_showing)
+         {
+           return _find_non_defunct_child(table, children, forward ? 0 : vector_size(children) - 1, forward);
+         }
+     }
+   return NULL;
+}
+
+static void *_get_next_non_defunct_sibling(accessibility_navigation_pointer_table *table,
+            void *obj, unsigned char forward)
+{
+   if (!obj) return NULL;
+   void *parent = CALL(get_parent, obj);
+   if (!parent) return NULL;
+
+   vector children = vector_init();
+   CALL(get_children, parent, &children);
+   if (vector_size(&children) == 0)
+     {
+       vector_free(&children);
+       return NULL;
+     }
+   unsigned int current = 0;
+   for(; current < vector_size(&children) && vector_get(&children, current) != obj; ++current) ;
+   if (current >= vector_size(&children))
+     {
+       vector_free(&children);
+       return NULL;
+     }
+   forward ? ++current : --current;
+   void *ret = _find_non_defunct_child(table, &children, current, forward);
+   vector_free(&children);
+   return ret;
+}
+
+static void *_directional_depth_first_search_try_non_defunct_sibling(accessibility_navigation_pointer_table *table,
+            unsigned char *all_children_visited_ptr, void *node, void *root, unsigned char forward)
+{
+   while(1)
+     {
+       void *sibling = _get_next_non_defunct_sibling(table, node, forward);
+       if (sibling != NULL)
+         {
+           node = sibling;
+           *all_children_visited_ptr = 0;
+           break;
+         }
+
+       // walk up...
+       node = CALL(get_parent, node);
+       if (node == NULL || node == root) return NULL;
+
+       // in backward traversing stop the walk up on parent
+       if (!forward) break;
+     }
+   return node;
+}
+
+typedef struct {
+    const void *key;
+    unsigned int current_search_size;
+    unsigned int counter;
+} cycle_detection_data;
+
+void cycle_detection_initialize(cycle_detection_data *data, const void *key)
+{
+   if (!data) return;
+   data->key = key;
+   data->current_search_size = 1;
+   data->counter = 1;
+}
+
+unsigned char cycle_detection_check_if_in_cycle(cycle_detection_data *data, const void *key)
+{
+   if (!data) return 1;
+   if (data->key == key) return 1;
+   if (--data->counter == 0)
+     {
+       data->current_search_size <<= 1;
+       if (data->current_search_size == 0) return 1;
+       data->counter = data->current_search_size;
+       data->key = key;
+     }
+   return 0;
+}
+
+static void *_calculate_neighbor_impl(accessibility_navigation_pointer_table *table, void *root, void *start, unsigned char forward, GetNeighborSearchMode search_mode)
+{
+   if (root && _object_is_defunct(table, root)) return NULL;
+   if (start && _object_is_defunct(table, start))
+     {
+       start = root;
+       forward = 1;
+     }
+   void *node = start;
+   if (!node) return NULL;
+
+   // initialization of all-children-visiten flag for start node - we assume
+   // that when we begin at start node and we navigate backward, then all children
+   // are visited, so navigation will ignore start's children and go to
+   // previous sibling available.
+   unsigned char all_children_visited = search_mode != NEIGHBOR_SEARCH_MODE_RECURSE_FROM_ROOT && !forward;
+   unsigned char force_next = search_mode == NEIGHBOR_SEARCH_MODE_CONTINUE_AFTER_FAILED_RECURSING;
+
+   cycle_detection_data cycle_detection;
+   cycle_detection_initialize(&cycle_detection, node);
+   while (node)
+     {
+       if (_object_is_defunct(table, node)) return NULL;
+
+       // always accept proxy object from different world
+       if (!force_next && CALL(object_is_proxy, node)) return node;
+
+       vector children = vector_init();
+       CALL(get_children, node, &children);
+
+       // do accept:
+       // 1. not start node
+       // 2. parent after all children in backward traversing
+       // 3. Nodes with roles: ATSPI_ROLE_PAGE_TAB, ATSPI_ROLE_POPUP_MENU and ATSPI_ROLE_DIALOG, only when looking for first or last element.
+       //    Objects with those roles shouldnt be reachable, when navigating next / prev.
+       unsigned char all_children_visited_or_moving_forward = (vector_size(&children) == 0 || forward || all_children_visited);
+       if (!force_next && node != start && all_children_visited_or_moving_forward && _accept_object(table, node))
+         {
+           if (start == NULL || _object_role_is_acceptable_when_navigating_next_prev(table, node))
+             {
+               vector_free(&children);
+               return node;
+             }
+         }
+
+       void *next_related_in_direction = !force_next ? _get_object_in_relation_flow(table, node, forward) : NULL;
+
+       if (next_related_in_direction && _object_is_defunct(table, next_related_in_direction))
+           next_related_in_direction = NULL;
+       unsigned char want_cycle_detection = 0;
+       if (next_related_in_direction)
+         {
+           node = next_related_in_direction;
+           want_cycle_detection = 1;
+         }
+       else {
+           void *child = !force_next && !all_children_visited ?
+                          _directional_depth_first_search_try_non_defunct_child(table, node, &children, forward) : NULL;
+           if (child != NULL) want_cycle_detection = 1;
+           else
+             {
+               if (!force_next && node == root)
+                 {
+                   vector_free(&children);
+                   return NULL;
+                 }
+               all_children_visited = 1;
+               child = _directional_depth_first_search_try_non_defunct_sibling(table, &all_children_visited, node, root, forward);
+             }
+           node = child;
+       }
+
+       force_next = 0;
+       if (want_cycle_detection && cycle_detection_check_if_in_cycle(&cycle_detection, node))
+         {
+           vector_free(&children);
+           return NULL;
+         }
+       vector_free(&children);
+     }
+   return NULL;
+}
+
+
+
+
+static AtspiRelationType spi_relation_type_from_atk_relation_type (AtkRelationType type);
+#define MARK_AS_UNUSED(v) do { (void)(v); } while(0)
+
+static AtspiRole _object_get_role_impl(accessibility_navigation_pointer_table *table, void *ptr)
+{
+  MARK_AS_UNUSED(table);
+  AtkObject *obj = (AtkObject*)ptr;
+  AtkRole role = atk_object_get_role (obj);
+  AtspiRole rv = spi_accessible_role_from_atk_role (role);
+  return rv;
+}
+
+static uint64_t _object_get_state_set_impl(accessibility_navigation_pointer_table *table, void *ptr)
+{
+  MARK_AS_UNUSED(table);
+  dbus_uint32_t array[2];
+  spi_atk_state_to_dbus_array((AtkObject*)ptr, array);
+  uint64_t res = array[0] | ((uint64_t)array[1] << 32);
+  return res;
+}
+
+static void *_get_object_in_relation_by_type_impl(accessibility_navigation_pointer_table *table, void *ptr, AtspiRelationType expected_relation_type)
+{
+  MARK_AS_UNUSED(table);
+  if (ptr) {
+    g_return_val_if_fail (ATK_IS_OBJECT (ptr), NULL);
+    AtkRelationSet *set = atk_object_ref_relation_set (ptr);
+    if (!set)
+      return NULL;
+    gint count = atk_relation_set_get_n_relations (set), i;
+    for (i = 0; i < count; i++)
+    {
+      AtkRelation *r = atk_relation_set_get_relation (set, i);
+      if (!r)
+        continue;
+      AtkRelationType rt = atk_relation_get_relation_type (r);
+      AtspiRelationType type = spi_relation_type_from_atk_relation_type (rt);
+      if (expected_relation_type == type)
+      {
+        GPtrArray *target = atk_relation_get_target (r);
+        if (target && target->len > 0)
+          return target->pdata[0];
+      }
+    }
+    g_object_unref (set);
+  }
+  return NULL;
+}
+
+static unsigned char _object_is_zero_size_impl(accessibility_navigation_pointer_table *table, void *ptr)
+{
+  MARK_AS_UNUSED(table);
+  AtkObject *obj = (AtkObject*)ptr;
+  g_return_val_if_fail(ATK_IS_COMPONENT (obj), 0);
+  gint x, y, w, h;
+  atk_component_get_extents (ATK_COMPONENT(obj), &x, &y, &w, &h, ATSPI_COORD_TYPE_SCREEN);
+  return w == 0 || h == 0;
+}
+
+unsigned char _object_is_scrollable_impl(accessibility_navigation_pointer_table *table, void *ptr)
+{
+  AtspiRole role = _object_get_role_impl(table, ptr);
+  switch (role) {
+  case ATSPI_ROLE_SCROLL_PANE:    //scroller
+  case ATSPI_ROLE_LIST:           //genlist, list
+  case ATSPI_ROLE_TREE_TABLE:     //gengrid
+  case ATSPI_ROLE_TOOL_BAR:       //toolbar
+      return 1;
+  default:
+      break;
+  }
+  return 0;
+}
+
+void *_get_parent_impl(accessibility_navigation_pointer_table *table, void *ptr)
+{
+  MARK_AS_UNUSED(table);
+  return atk_object_get_parent((AtkObject*)ptr);
+}
+
+void *_get_object_at_point_impl(accessibility_navigation_pointer_table *table, void *ptr, int x, int y, unsigned char coordinates_are_screen_based)
+{
+  MARK_AS_UNUSED(table);
+  AtkObject *obj = (AtkObject*)ptr;
+  g_return_val_if_fail(ATK_IS_COMPONENT (obj), 0);
+  return atk_component_ref_accessible_at_point (ATK_COMPONENT(obj), x, y,
+          coordinates_are_screen_based ? ATSPI_COORD_TYPE_SCREEN : ATSPI_COORD_TYPE_WINDOW);
+}
+
+unsigned char _object_contains_impl(accessibility_navigation_pointer_table *table, void *ptr, int x, int y, unsigned char coordinates_are_screen_based)
+{
+  MARK_AS_UNUSED(table);
+  AtkObject *obj = (AtkObject*)ptr;
+  g_return_val_if_fail(ATK_IS_COMPONENT (obj), 0);
+
+  return atk_component_contains (ATK_COMPONENT(obj), x, y,
+        coordinates_are_screen_based ? ATSPI_COORD_TYPE_SCREEN : ATSPI_COORD_TYPE_WINDOW);
+}
+
+unsigned char _object_is_proxy_impl(accessibility_navigation_pointer_table *table, void *ptr)
+{
+  MARK_AS_UNUSED(table);
+  return 0;
+}
+
+void _get_children_impl(accessibility_navigation_pointer_table *table, void *ptr, vector *v)
+{
+  MARK_AS_UNUSED(table);
+    AtkObject *obj = (AtkObject*)ptr;
+    gint count = atk_object_get_n_accessible_children (obj);
+    vector_resize(v, (unsigned int)count);
+
+    gint i, index = 0;
+    for (i = 0; i < count; i++) {
+        AtkObject *child = atk_object_ref_accessible_child (obj, i);
+        if (child) {
+            vector_set(v, index, child);
+            ++index;
+            g_object_unref (child);
+        }
+    }
+    vector_resize(v, index);
+}
+
+
+
+
+
 accessibility_navigation_pointer_table construct_accessibility_navigation_pointer_table(void)
 {
    accessibility_navigation_pointer_table table;
@@ -307,12 +600,16 @@ accessibility_navigation_pointer_table construct_accessibility_navigation_pointe
    INIT(object_is_zero_size);
    INIT(get_parent);
    INIT(object_is_scrollable);
-   INIT(object_at_point_get);
+   INIT(get_object_at_point);
    INIT(object_contains);
    INIT(object_is_proxy);
+   INIT(get_children);
 #undef INIT
    return table;
 }
+
+
+
 static AtkObject *_calculate_navigable_accessible_at_point(AtkObject *root, unsigned char coord_type, int x, int y)
 {
    accessibility_navigation_pointer_table table = construct_accessibility_navigation_pointer_table();
@@ -320,6 +617,35 @@ static AtkObject *_calculate_navigable_accessible_at_point(AtkObject *root, unsi
    return result;
 }
 
+static AtkObject *_calculate_neighbor(AtkObject *root, AtkObject *start, unsigned char forward, GetNeighborSearchMode search_mode)
+{
+   accessibility_navigation_pointer_table table = construct_accessibility_navigation_pointer_table();
+   AtkObject *result = (AtkObject*)_calculate_neighbor_impl(&table, root, start, forward ? 1 : 0, search_mode);
+   return result;
+}
+
+static DBusMessage *
+impl_GetNeighbor (DBusConnection * bus, DBusMessage * message, void *user_data)
+{
+  AtkObject *start = (AtkObject *) user_data;
+  dbus_uint32_t direction, search_mode;
+  const char *root_path = NULL;
+  DBusMessage *reply;
+  AtkObject *child;
+
+  if (!dbus_message_get_args
+      (message, NULL, DBUS_TYPE_STRING, &root_path, DBUS_TYPE_INT32, &direction, DBUS_TYPE_INT32, &search_mode, DBUS_TYPE_INVALID))
+    {
+      return droute_invalid_arguments_error (message);
+    }
+
+  AtkObject *root_object = (AtkObject*)spi_global_register_path_to_object(root_path);
+  child = _calculate_neighbor (root_object, start, direction == 1, search_mode);
+  reply = spi_object_return_reference_and_recurse_flag (message, child, 0);
+
+  return reply;
+}
+
 static DBusMessage *
 impl_GetNavigableAtPoint (DBusConnection * bus, DBusMessage * message,
                            void *user_data)
@@ -330,21 +656,14 @@ impl_GetNavigableAtPoint (DBusConnection * bus, DBusMessage * message,
   DBusMessage *reply;
   AtkObject *child;
 
-  g_return_val_if_fail (ATK_IS_COMPONENT (object),
-                        droute_not_yet_handled_error (message));
-
   if (!dbus_message_get_args
       (message, NULL, DBUS_TYPE_INT32, &x, DBUS_TYPE_INT32, &y,
        DBUS_TYPE_UINT32, &coord_type, DBUS_TYPE_INVALID))
     {
       return droute_invalid_arguments_error (message);
     }
-  child = (AtkObject*)
-      _calculate_navigable_accessible_at_point (object, coord_type == ATSPI_COORD_TYPE_SCREEN, x, y);
-
+  child = _calculate_navigable_accessible_at_point (object, coord_type == ATSPI_COORD_TYPE_SCREEN, x, y);
   reply = spi_object_return_reference_and_recurse_flag (message, child, 0);
-  if (child)
-    g_object_unref (child);
 
   return reply;
 }
@@ -843,6 +1162,7 @@ impl_GetInterfaces (DBusConnection * bus,
 static DRouteMethod methods[] = {
 // TIZEN_ONLY(20170310) - implementation of get object under coordinates for accessibility
   {impl_GetNavigableAtPoint, "GetNavigableAtPoint"},
+  {impl_GetNeighbor, "GetNeighbor"},
 //
   {impl_GetChildAtIndex, "GetChildAtIndex"},
   {impl_GetChildren, "GetChildren"},
index c40ef38..d39a8e9 100644 (file)
@@ -429,7 +429,7 @@ register_application (SpiBridge * app)
 
   dbus_message_iter_init_append (message, &iter);
   spi_object_append_reference (&iter, app->root);
-  
+
     if (!dbus_connection_send_with_reply (app->bus, message, &pending, -1)
         || !pending)
     {
@@ -753,7 +753,6 @@ remove_events (const char *bus_name, const char *event)
           g_strfreev (evdata->data);
           g_free (evdata->bus_name);
           g_slist_free_full (evdata->properties, free_property_definition);
-          g_free (evdata);
           if (list->prev)
             {
               GList *next = list->next;
@@ -765,6 +764,7 @@ remove_events (const char *bus_name, const char *event)
               spi_global_app_data->events = g_list_remove (events, evdata);
               list = spi_global_app_data->events;
             }
+          g_free (evdata);
         }
       else
         {
@@ -1047,7 +1047,7 @@ atk_bridge_adaptor_init (gint * argc, gchar ** argv[])
   /* Hook our plug-and socket functions */
   install_plug_hooks ();
 
-  /* 
+  /*
    * Create the leasing, register and cache objects.
    * The order is important here, the cache depends on the
    * register object.
index 838aacd..fa6d353 100644 (file)
@@ -353,7 +353,7 @@ impl_prop_GetSet (DBusMessage *message,
 
     if (get && prop_funcs->get)
       {
-        
+
         DBusMessageIter iter;
 
         _DROUTE_DEBUG ("DRoute (handle prop Get): %s|%s on %s\n", pair.one, pair.two, pathstr);
@@ -602,7 +602,7 @@ handle_message (DBusConnection *bus, DBusMessage *message, void *user_data)
     if (result == DBUS_HANDLER_RESULT_NOT_YET_HANDLED)
         g_print ("DRoute | Unhandled message: %s|%s of type %d on %s\n", member, iface, type, pathstr);
 #endif
-      
+
     return result;
 }