--- /dev/null
+#ifdef HAVE_CONFIG_H
+# include "elementary_config.h"
+#endif
+
+#define ELM_INTERFACE_ATSPI_ACCESSIBLE_PROTECTED
+#define ELM_INTERFACE_ATSPI_COMPONENT_PROTECTED
+
+#include <Elementary.h>
+#include "elm_widget.h"
+#include "elm_priv.h"
+
+#define EWK_A11Y_DATA_KEY "__a11y_wrapper"
+
+typedef struct _Elm_Atspi_Ewk_Wrapper_Data Elm_Atspi_Ewk_Wrapper_Data;
+
+struct _Elm_Atspi_Ewk_Wrapper_Data
+{
+ Elm_Atspi_Proxy *proxy;
+ Evas_Object *ewk_view;
+ char *plug_id;
+};
+
+static Eina_Bool
+_ewk_view_geometry_changed(void *data, Eo *obj EINA_UNUSED, const Eo_Event_Description *desc EINA_UNUSED, void *event_info EINA_UNUSED);
+
+EO_CALLBACKS_ARRAY_DEFINE(resize_watch,
+ { EVAS_OBJECT_EVENT_MOVE, _ewk_view_geometry_changed },
+ { EVAS_OBJECT_EVENT_RESIZE, _ewk_view_geometry_changed });
+
+static void
+_elm_atspi_ewk_wrapper_disconnect(Elm_Atspi_Ewk_Wrapper_Data *_pd)
+{
+ if (_pd->proxy) eo_del(_pd->proxy);
+ free(_pd->plug_id);
+ _pd->proxy = NULL;
+ _pd->plug_id = NULL;
+}
+
+static Eina_Bool
+_ewk_view_geometry_changed(void *data, Eo *obj EINA_UNUSED, const Eo_Event_Description *desc EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+ Evas_Coord x, y, w, h;
+ Elm_Atspi_Ewk_Wrapper *wrapper = data;
+
+ evas_object_geometry_get(obj, &x, &y, &w, &h);
+ evas_object_move(wrapper, x, y);
+ evas_object_resize(wrapper, w, h);
+ return EINA_TRUE;
+}
+
+EOLIAN static void
+_elm_atspi_ewk_wrapper_constructor(Elm_Atspi_Ewk_Wrapper *obj, Elm_Atspi_Ewk_Wrapper_Data *_pd, Evas_Object *ewk_view)
+{
+ Evas_Coord x, y, w, h;
+ _pd->ewk_view = ewk_view;
+
+ elm_widget_sub_object_parent_add(obj);
+ elm_atspi_accessible_role_set(obj, ELM_ATSPI_ROLE_EMBEDDED);
+
+ evas_object_geometry_get(ewk_view, &x, &y, &w, &h);
+ evas_object_move(obj, x, y);
+ evas_object_resize(obj, w, h);
+ evas_object_show(obj);
+ eo_do(ewk_view, eo_event_callback_array_add(resize_watch(), obj));
+
+ eo_do(obj, elm_obj_atspi_ewk_wrapper_connection_init());
+}
+
+static Eo*
+_elm_atspi_ewk_wrapper_proxy_create(const char *plugid, Eo *parent)
+{
+ Elm_Atspi_Proxy *proxy;
+ char *bus = NULL, *path = NULL;
+
+ if (!_elm_atspi_bridge_plug_id_split(plugid, &bus, &path)) {
+ ERR("_elm_atspi_bridge_plug_id_split failed");
+ return NULL;
+ }
+
+ proxy = eo_add(ELM_ATSPI_PROXY_CLASS, parent,
+ elm_obj_atspi_proxy_constructor(ELM_ATSPI_PROXY_TYPE_PLUG));
+ if (!proxy) {
+ ERR("Unable to create Elm_Atspi_Proxy object");
+ free(bus); free(path);
+ return NULL;
+ }
+
+ eo_do(proxy, elm_obj_atspi_proxy_address_set(bus, path));
+
+ free(bus);
+ free(path);
+
+ elm_atspi_bridge_utils_proxy_connect(proxy);
+ return proxy;
+}
+
+EOLIAN static void
+_elm_atspi_ewk_wrapper_connection_init(Elm_Atspi_Ewk_Wrapper *obj, Elm_Atspi_Ewk_Wrapper_Data *_pd)
+{
+ // PlugID is set by chromium
+ const char *plug_id = evas_object_data_get(_pd->ewk_view, "__PlugID");
+
+ // when plug_id is NULL, disconnect
+ if (!plug_id)
+ {
+ _elm_atspi_ewk_wrapper_disconnect(_pd);
+ return;
+ }
+
+ // check if already connected to atspi object referenced by plug_id
+ if (_pd->plug_id && !strcmp(_pd->plug_id, plug_id))
+ return;
+
+ // destroy current connection
+ _elm_atspi_ewk_wrapper_disconnect(_pd);
+
+ // make new connection using proxy object
+ _pd->proxy = _elm_atspi_ewk_wrapper_proxy_create(plug_id, obj);
+ if (!_pd->proxy) {
+ ERR("Failed connect to Ewk_View root accessible object");
+ return;
+ }
+ _pd->plug_id = strdup(plug_id);
+}
+
+EOLIAN static void
+_elm_atspi_ewk_wrapper_eo_base_destructor(Elm_Atspi_Ewk_Wrapper *obj EINA_UNUSED, Elm_Atspi_Ewk_Wrapper_Data *_pd)
+{
+ free(_pd->plug_id);
+ if (_pd->ewk_view)
+ eo_do(_pd->ewk_view, eo_event_callback_array_del(resize_watch(), obj));
+}
+
+EOLIAN static Eina_List*
+_elm_atspi_ewk_wrapper_elm_interface_atspi_accessible_children_get(Elm_Atspi_Ewk_Wrapper *obj EINA_UNUSED, Elm_Atspi_Ewk_Wrapper_Data *_pd)
+{
+ if (_pd->proxy)
+ return eina_list_append(NULL, _pd->proxy);
+ else
+ return NULL;
+}
+
+static Eina_Bool
+_wrapper_widget_del(void *data, Eo *obj EINA_UNUSED, const Eo_Event_Description *desc EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+ Evas_Object *ewk_view = data;
+ evas_object_data_set(ewk_view, EWK_A11Y_DATA_KEY, NULL);
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_ewk_view_widget_del(void *data, Eo *obj EINA_UNUSED, const Eo_Event_Description *desc EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+ Elm_Atspi_Ewk_Wrapper *wrapper = data;
+ eo_del(wrapper);
+ return EINA_TRUE;
+}
+
+EOLIAN void
+_elm_atspi_ewk_wrapper_a11y_init(Eo *class EINA_UNUSED, void *pd EINA_UNUSED,
+ Evas_Object *parent, Evas_Object *ewk_view)
+{
+ Evas_Object *wrapper = evas_object_data_get(ewk_view, EWK_A11Y_DATA_KEY);
+ if (!wrapper) {
+ wrapper = eo_add(ELM_ATSPI_EWK_WRAPPER_CLASS, parent, elm_obj_atspi_ewk_wrapper_constructor(ewk_view));
+ evas_object_data_set(ewk_view, EWK_A11Y_DATA_KEY, wrapper);
+ // make sure that wrapper will not outlive ewk_view
+ eo_do(wrapper, eo_event_callback_del(EO_EV_DEL, _wrapper_widget_del, ewk_view));
+ eo_do(ewk_view, eo_event_callback_del(EO_EV_DEL, _ewk_view_widget_del, wrapper));
+ } else {
+ // Check if reparenting occured on Ewk_View
+ // This may happen in case when ewk_view is taken out from layout and put into another one.
+ // In order to avoid situation when ewk a11y may be accessed from different
+ // a11y node we check if reparenting occured and reset wrapper parent
+ if (parent != elm_widget_parent_get(wrapper)) {
+ eo_do(parent, elm_obj_widget_sub_object_add(wrapper));
+ }
+ }
+ elm_atspi_ewk_wrapper_connection_init(wrapper);
+}
+
+EOLIAN static Eo *
+_elm_atspi_ewk_wrapper_elm_interface_atspi_component_accessible_at_point_get(Elm_Atspi_Ewk_Wrapper *obj EINA_UNUSED, Elm_Atspi_Ewk_Wrapper_Data *_pd, Eina_Bool screen_coords, int x, int y)
+{
+ Eina_Rectangle rect;
+ int ee_x, ee_y;
+
+ if (!_pd->ewk_view)
+ return NULL;
+
+ if (screen_coords)
+ {
+ Ecore_Evas *ee = ecore_evas_ecore_evas_get(evas_object_evas_get(_pd->ewk_view));
+ if (!ee) return NULL;
+ ecore_evas_geometry_get(ee, &ee_x, &ee_y, NULL, NULL);
+ x -= ee_x;
+ y -= ee_y;
+ }
+
+ evas_object_geometry_get(_pd->ewk_view, &rect.x, &rect.y, &rect.w, &rect.h);
+
+ if (eina_rectangle_coords_inside(&rect, x, y))
+ return _pd->proxy;
+ else
+ return NULL;
+}
+
+EOLIAN static Evas_Object *
+_elm_atspi_ewk_wrapper_ewk_view_get(Elm_Atspi_Ewk_Wrapper *obj EINA_UNUSED, Elm_Atspi_Ewk_Wrapper_Data *_pd)
+{
+ return _pd->ewk_view;
+}
+
+
+#include "elm_atspi_ewk_wrapper.eo.c"
}
//
-// TIZEN ONLY
-static void
-_ewk_view_load_finished(Eo *plug,
- Evas_Object *obj,
- const char *addr)
-{
- char *bus, *path;
-
- if (addr && !evas_object_data_get(obj, "__plug_connected"))
- {
- if (_elm_atspi_bridge_plug_id_split(addr, &bus, &path))
- {
- eo_do(plug, elm_obj_atspi_proxy_address_set(bus, path));
- elm_atspi_bridge_utils_proxy_connect(plug);
- evas_object_data_set(obj, "__plug_connected", (void*)1);
- free(bus);
- free(path);
- }
- }
-}
-
// TIZEN_ONLY(20160705) - enable atspi_proxy to work
static void
_proxy_widget_move_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
EINA_LIST_FOREACH(wd->subobjs, l, widget)
{
- // TIZEN_ONLY(20160824): Do not append a child, if its accessible parent is different with widget parent
- eo_do(widget, parent = elm_interface_atspi_accessible_parent_get());
- if (parent && (parent != obj)) continue;
- //
-
+ const char *type = evas_object_type_get(widget);
// TIZEN ONLY
- // Ugly Tizen hack to integrate AT-SPI2 accessibility provided by WebKit with
- // elementary one. Due to problematic cross dependencies between Webkit
- // and elementary, instead of directly using ewk API to integrate accessibility
- // we use evas_object_data_set with pre defined key to share data
- // between webkit and elemetary libraries.
- const char *plug_id;
- if ((plug_id = evas_object_data_get(widget, "__PlugID")) != NULL)
- {
- // TIZEN_ONLY(20160930) : endless recursion fix
- eo_do_super(obj, MY_CLASS, elm_interface_atspi_accessible_attribute_append("__PlugID", plug_id));
- //
- Eo *plug = evas_object_data_get(widget, "__ewk_proxy");
- if (!plug)
- {
- plug = eo_add(ELM_ATSPI_PROXY_CLASS, obj, elm_obj_atspi_proxy_constructor(ELM_ATSPI_PROXY_TYPE_PLUG));
- evas_object_data_set(widget, "__ewk_proxy", plug);
- eo_do(widget, eo_event_callback_add(EO_EV_DEL, _on_widget_del, plug));
- _ewk_view_load_finished(plug, widget, plug_id);
- }
- if (plug && evas_object_data_get(widget, "__plug_connected"))
- accs = eina_list_append(accs, plug);
- continue;
- }
+ // Ugly Tizen hack to integrate AT-SPI2 accessibility provided by WebKit/Chromium with elementary one.
+ // This wrapper class should be implemented in Webkit/Chromium EFL ports
+ if (type && (!strcmp(type, "EWebView") || !strcmp(type, "WebView"))) {
+ elm_atspi_ewk_wrapper_a11y_init(obj, widget);
+ }
+ }
+
+ EINA_LIST_FOREACH(wd->subobjs, l, widget)
+ {
+ // TIZEN_ONLY(20160824): Do not append a child, if its accessible parent is different with widget parent
+ if (eo_isa(widget, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN)) {
+ eo_do(widget, parent = elm_interface_atspi_accessible_parent_get());
+ if (parent && (parent != obj)) continue;
+ }
// TIZEN_ONLY(20160705) - enable atspi_proxy to work
const char *plug_id_2;
if ((plug_id_2 = evas_object_data_get(widget, "___PLUGID")) != NULL)
{
// TIZEN_ONLY(20160930) : endless recursion fix
- eo_do_super(obj, MY_CLASS, elm_interface_atspi_accessible_attribute_append("___PlugID", plug_id));
+ eo_do_super(obj, MY_CLASS, elm_interface_atspi_accessible_attribute_append("___PlugID", plug_id_2));
Eo *proxy;
char *svcname, *svcnum;
Elm_Access_Info *info = _elm_access_info_get(child);
compare_obj = info->part_object;
}
+
+ /* In case of ewk wrapper object compare with internal ewk_view evas_object */
+ if (eo_isa(child, ELM_ATSPI_EWK_WRAPPER_CLASS))
+ {
+ compare_obj = elm_atspi_ewk_wrapper_ewk_view_get(child);
+ }
+
/* If spacial eo children do not have backing evas_object continue with search */
if (!compare_obj)
continue;