From: JunsuChoi Date: Tue, 16 Jan 2018 05:50:52 +0000 (+0900) Subject: atspi: "GetNeighbor" is using deputy object X-Git-Tag: submit/sandbox/upgrade/efl120/20180319.053334~314 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F88%2F167188%2F4;p=platform%2Fupstream%2Fefl.git atspi: "GetNeighbor" is using deputy object A01 object is deputy object, and exists in embedding process. A02, A03 object exist in embedding process. B01, B02 objects exist in embedded process. The “GetNeighbor” method should return A02 object as “next” object of B02, and return B02 object as “prev” object of A02. The “next” object of A01 is B01. The “prev” object of B01 is A01. This is default implementation. The following is default order: A01 - B01 - B02 - A02 - A03 But more important thing is that the embedding process could use ELM_ATSPI_RELATION_FLOWS_TO/FROM for each objects A01, A02, and A03. So there are some cases should be considered. (1) If A01 is ELM_ATSPI_RELATION_FLOWS_FROM object of A03, then the “GetNeighbor” should find B02 first when it navigates backward from A03. (2) If A03 is ELM_ATSPI_RELATION_FLOWS_TO object of A01, then the “GetNeighbor” should find A03 first when it navigates backward from B02. (3) Even though the A01 has ELM_ATSPI_RELATION_FLOWS_TO relation information, the “GetNeighbor” should find B01 first. Because the ELM_ATSPI_RELATION_FLOWS_TO object is used when “GetNeighbor” finds next object of B02. Change-Id: I36dde39af3e99efcd7168c146b065fc6dfa5d104 --- diff --git a/src/lib/elementary/efl_ui_widget.c b/src/lib/elementary/efl_ui_widget.c index 436a894..9a32013 100644 --- a/src/lib/elementary/efl_ui_widget.c +++ b/src/lib/elementary/efl_ui_widget.c @@ -5797,6 +5797,7 @@ _efl_ui_widget_efl_access_children_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Dat // TIZEN_ONLY(20160824): Do not append a child, if its accessible parent is different with widget parent Eo *parent; // + Eo *proxy = NULL; EINA_LIST_FOREACH(pd->subobjs, l, widget) { @@ -5809,7 +5810,6 @@ _efl_ui_widget_efl_access_children_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Dat elm_atspi_ewk_wrapper_a11y_init(obj, widget); } } - Eo *proxy = NULL; EINA_LIST_FOREACH(pd->subobjs, l, widget) { // TIZEN_ONLY(20160824): Do not append a child, if its accessible parent is different with widget parent @@ -5852,6 +5852,31 @@ _efl_ui_widget_efl_access_children_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Dat EINA_LIST_FREE(lines, line) accs = eina_list_merge(accs, eina_list_sort(line, -1, _sort_horizontally)); // + + if (proxy) + { + Eo *deputy = NULL; + accs = eina_list_remove(accs, proxy); + EINA_LIST_FOREACH(accs, l, widget) + { + if (efl_isa(widget, ELM_ACCESS_CLASS)) + { + Elm_Access_Info *info = _elm_access_info_get(widget); + if (!info) continue; + if (obj == info->part_object) + { + deputy = widget; + break; + } + } + } + + if (deputy) + { + accs = eina_list_append_relative(accs, proxy, deputy); + } + } + return accs; } diff --git a/src/lib/elementary/elm_atspi_bridge.c b/src/lib/elementary/elm_atspi_bridge.c index 0ff3019..c19afeb 100644 --- a/src/lib/elementary/elm_atspi_bridge.c +++ b/src/lib/elementary/elm_atspi_bridge.c @@ -4226,6 +4226,7 @@ typedef enum { NEIGHBOR_SEARCH_MODE_NORMAL = 0, NEIGHBOR_SEARCH_MODE_RECURSE_FROM_ROOT = 1, NEIGHBOR_SEARCH_MODE_CONTINUE_AFTER_FAILED_RECURSING = 2, + NEIGHBOR_SEARCH_MODE_RECURSE_TO_OUTSIDE = 3, } GetNeighborSearchMode; typedef struct accessibility_navigation_pointer_table { @@ -4618,6 +4619,86 @@ unsigned char cycle_detection_check_if_in_cycle(cycle_detection_data *data, cons return 0; } +static Eina_Bool +_deputy_is(Eo *obj) +{ + if (efl_isa(obj, ELM_ACCESS_CLASS)) + { + Elm_Access_Info *info; + + info = _elm_access_info_get(obj); + if (info && efl_isa(info->part_object, EFL_UI_LAYOUT_CLASS)) + { + Eina_List *attrs, *l; + Efl_Access_Attribute *attr; + + attrs = efl_access_attributes_get(info->part_object); + EINA_LIST_FOREACH(attrs, l, attr) + { + if (!strcmp(attr->key, "___PlugID")) + { + efl_access_attributes_list_free(attrs); + return EINA_TRUE; + } + } + efl_access_attributes_list_free(attrs); + } + } + return EINA_FALSE; +} + +static Eo * +_proxy_in_parent_get(Eo *obj) +{ + Eina_List *l; + Eo *proxy = NULL; + Eina_List *children_list = NULL; + children_list = efl_access_children_get(obj); + + Evas_Object *child; + EINA_LIST_FOREACH(children_list, l, child) + { + if (efl_isa(child, ELM_ATSPI_PROXY_CLASS)) + { + proxy = child; + break; + } + } + eina_list_free(children_list); + + return proxy; +} + +static Eo * +_deputy_of_proxy_in_parent_get(Eo *obj) +{ + Eina_List *l; + Eo *deputy = NULL; + Eina_List *children_list = NULL; + children_list = efl_access_children_get(obj); + + unsigned int index = 0; + Evas_Object *child; + EINA_LIST_FOREACH(children_list, l, child) + { + if (efl_isa(child, ELM_ATSPI_PROXY_CLASS)) + { + if (index == 0) + { + WRN("Proxy does not have deputy object"); + break; + } + + deputy = eina_list_nth(children_list, index - 1); + break; + } + index++; + } + eina_list_free(children_list); + + return deputy; +} + 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; @@ -4626,6 +4707,14 @@ static void *_calculate_neighbor_impl(accessibility_navigation_pointer_table *ta start = NULL; forward = 1; } + + if (search_mode == NEIGHBOR_SEARCH_MODE_RECURSE_TO_OUTSIDE) + { + /* This only works if we navigate backward, and it is not possible to + find in embedded process. In this case the deputy should be used */ + return _deputy_of_proxy_in_parent_get(start); + } + void *node = start ? start : root; if (!node) return NULL; @@ -4675,11 +4764,48 @@ static void *_calculate_neighbor_impl(accessibility_navigation_pointer_table *ta void *next_related_in_direction = !force_next ? _get_object_in_relation_flow(table, node, forward) : NULL; + /* force_next means that the search_mode is NEIGHBOR_SEARCH_MODE_CONTINUE_AFTER_FAILED_RECURSING + in this case the node is elm_layout which is parent of proxy object. + There is an access object working for the proxy object, and the access + object could have relation information. This relation information should + be checked first before using the elm_layout as a node. */ + if (force_next && forward) + { + Eo *deputy; + deputy = _deputy_of_proxy_in_parent_get(node); + next_related_in_direction = + _get_object_in_relation_flow(table, deputy, forward); + } + 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) { + /* Check next_related_in_direction is deputy object */ + Eo *parent; + if (!forward) + { + /* If the prev object is deputy, then go to inside of its proxy first */ + if (_deputy_is(next_related_in_direction)) + { + parent = efl_ui_widget_parent_get(next_related_in_direction); + next_related_in_direction = + _proxy_in_parent_get(parent); + } + } + else + { + /* If current object is deputy, and it has relation next object, + then do not use the relation next object, and use proxy first */ + if (_deputy_is(node)) + { + parent = efl_ui_widget_parent_get(node); + next_related_in_direction = + _proxy_in_parent_get(parent); + } + } + node = next_related_in_direction; want_cycle_detection = 1; }