From: Shinwoo Kim Date: Wed, 20 Sep 2017 04:14:27 +0000 (+0900) Subject: atspi: fix infinite loop issue X-Git-Tag: accepted/tizen/4.0/unified/20171012.225849~5 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=ec698adc80928b0658622f0109e3d3bb86a5680e;p=platform%2Fupstream%2Felementary.git atspi: fix infinite loop issue 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. Change-Id: I2edeefdc9a0c5955f1c28926321b74424c71bc40 --- diff --git a/src/lib/elm_atspi_bridge.c b/src/lib/elm_atspi_bridge.c index 56710b6..9625629 100644 --- a/src/lib/elm_atspi_bridge.c +++ b/src/lib/elm_atspi_bridge.c @@ -4301,16 +4301,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; + eo_do(root, parent = elm_interface_atspi_accessible_parent_get()); + + while (parent) + { + if (parent == target) return EINA_FALSE; + eo_do(parent, parent = elm_interface_atspi_accessible_parent_get()); + } + + 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; diff --git a/src/lib/elm_widget.c b/src/lib/elm_widget.c index 7502188..a5402c1 100644 --- a/src/lib/elm_widget.c +++ b/src/lib/elm_widget.c @@ -7330,20 +7330,28 @@ _child_object_at_point_get(Eo *obj, int x, int y) } static Eina_Bool -_is_acceptable_leaf(Eo *obj) +_acceptable_child_is(Eo *obj) { Elm_Atspi_Role role; Eina_List *children; + Elm_Atspi_State_Set ss; eo_do(obj, role = elm_interface_atspi_accessible_role_get()); switch (role) { case ELM_ATSPI_ROLE_IMAGE: case ELM_ATSPI_ROLE_ICON: + /* remove unacceptable leaf node */ eo_do(obj, children = elm_interface_atspi_accessible_children_get()); if (!children) return EINA_FALSE; break; + case ELM_ATSPI_ROLE_PANEL: + /* remove closed panel fron children list */ + eo_do(obj, ss = elm_interface_atspi_accessible_state_set_get()); + if (!STATE_TYPE_GET(ss, ELM_ATSPI_STATE_SHOWING)) return EINA_FALSE; + break; + default: break; } @@ -7369,7 +7377,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); } @@ -7537,6 +7545,11 @@ _elm_widget_elm_interface_atspi_component_accessible_at_point_get(Eo *obj, Elm_W 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;