elm_public_eolian_files = \
lib/elementary/elm_atspi_bridge.eo \
+ lib/elementary/elm_atspi_ewk_wrapper.eo \
lib/elementary/elm_atspi_app_object.eo \
- lib/elementary/elm_atspi_proxy.eo \
+ lib/elementary/elm_atspi_proxy.eo \
lib/elementary/elm_bg.eo \
lib/elementary/efl_ui_button.eo \
lib/elementary/elm_calendar.eo \
includesunstable_HEADERS = \
lib/elementary/elm_gen_common.h \
lib/elementary/elm_atspi_bridge.h \
+ lib/elementary/elm_atspi_ewk_wrapper.h \
lib/elementary/efl_access.h \
lib/elementary/efl_access_legacy.h \
lib/elementary/efl_access_text.h \
lib/elementary/elm_actionslider.c \
lib/elementary/elm_atspi_app_object.c \
lib/elementary/elm_atspi_bridge.c \
- lib/elementary/elm_atspi_proxy.c \
+ lib/elementary/elm_atspi_ewk_wrapper.c \
+ lib/elementary/elm_atspi_proxy.c \
lib/elementary/elm_bg.c \
lib/elementary/elm_box.c \
lib/elementary/elm_bubble.c \
--- /dev/null
+#ifdef HAVE_CONFIG_H
+# include "elementary_config.h"
+#endif
+
+#define EFL_ACCESS_PROTECTED
+#define EFL_ACCESS_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 void
+_ewk_view_geometry_changed(void *data, const Efl_Event *event);
+
+EFL_CALLBACKS_ARRAY_DEFINE(resize_watch,
+ { EFL_GFX_EVENT_MOVE, _ewk_view_geometry_changed },
+ { EFL_GFX_EVENT_RESIZE, _ewk_view_geometry_changed });
+
+static void
+_elm_atspi_ewk_wrapper_disconnect(Elm_Atspi_Ewk_Wrapper_Data *_pd)
+{
+ if (_pd->proxy) efl_del(_pd->proxy);
+ free(_pd->plug_id);
+ _pd->proxy = NULL;
+ _pd->plug_id = NULL;
+}
+
+static void
+_ewk_view_geometry_changed(void *data, const Efl_Event *event)
+{
+ Evas_Coord x, y, w, h;
+ Elm_Atspi_Ewk_Wrapper *wrapper = data;
+
+ evas_object_geometry_get(event->object, &x, &y, &w, &h);
+ evas_object_move(wrapper, x, y);
+ evas_object_resize(wrapper, w, h);
+}
+
+EOLIAN static void
+_elm_atspi_ewk_wrapper_constructor(Eo *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);
+ efl_access_role_set(obj, EFL_ACCESS_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);
+ efl_event_callback_array_add(ewk_view, resize_watch(), obj);
+
+ elm_obj_atspi_ewk_wrapper_connection_init(obj);
+}
+
+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 = efl_add(ELM_ATSPI_PROXY_CLASS, parent, elm_obj_atspi_proxy_constructor(parent, ELM_ATSPI_PROXY_TYPE_PLUG));
+ if (!proxy) {
+ ERR("Unable to create Elm_Atspi_Proxy object");
+ free(bus); free(path);
+ return NULL;
+ }
+
+ elm_obj_atspi_proxy_address_set(proxy, bus, path);
+
+ free(bus);
+ free(path);
+
+ elm_atspi_bridge_utils_proxy_connect(proxy);
+ return proxy;
+}
+
+EOLIAN static void
+_elm_atspi_ewk_wrapper_connection_init(Eo *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_efl_object_destructor(Eo *obj EINA_UNUSED, Elm_Atspi_Ewk_Wrapper_Data *_pd)
+{
+ free(_pd->plug_id);
+ if (_pd->ewk_view)
+ efl_event_callback_array_del(_pd->ewk_view, resize_watch(), obj);
+}
+
+EOLIAN static Eina_List*
+_elm_atspi_ewk_wrapper_efl_access_children_get(Eo *obj EINA_UNUSED, Elm_Atspi_Ewk_Wrapper_Data *_pd)
+{
+ if (_pd->proxy)
+ return eina_list_append(NULL, _pd->proxy);
+ else
+ return NULL;
+}
+
+static void
+_wrapper_widget_del(void *data, const Efl_Event *event EINA_UNUSED)
+{
+ Evas_Object *ewk_view = data;
+ evas_object_data_set(ewk_view, EWK_A11Y_DATA_KEY, NULL);
+}
+
+static void
+_ewk_view_widget_del(void *data, const Efl_Event *event EINA_UNUSED)
+{
+ Elm_Atspi_Ewk_Wrapper *wrapper = data;
+ efl_del(wrapper);
+}
+
+EOLIAN void
+_elm_atspi_ewk_wrapper_a11y_init(Eo *obj 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 = efl_add(ELM_ATSPI_EWK_WRAPPER_CLASS, parent, elm_obj_atspi_ewk_wrapper_constructor(obj, ewk_view));
+ evas_object_data_set(ewk_view, EWK_A11Y_DATA_KEY, wrapper);
+ // make sure that wrapper will not outlive ewk_view
+ efl_event_callback_del(wrapper, EFL_EVENT_DEL, _wrapper_widget_del, ewk_view);
+ efl_event_callback_del(ewk_view, EFL_EVENT_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)) {
+ elm_obj_widget_sub_object_add(parent, wrapper);
+ }
+ }
+ elm_atspi_ewk_wrapper_connection_init(wrapper);
+}
+
+EOLIAN static Eo *
+_elm_atspi_ewk_wrapper_efl_access_component_accessible_at_point_get(Eo *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(Eo *obj EINA_UNUSED, Elm_Atspi_Ewk_Wrapper_Data *_pd)
+{
+ return _pd->ewk_view;
+}
+
+
+#include "elm_atspi_ewk_wrapper.eo.c"
//TIZEN_ONLY(20171114) atspi: integrate ewk_view with elementary accessibility
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))
- {
- elm_obj_atspi_proxy_address_set(plug, bus, path);
- elm_atspi_bridge_utils_proxy_connect(plug);
- evas_object_data_set(obj, "__plug_connected", (void*)1);
- free(bus);
- free(path);
- }
- }
-}
-
-static void
_on_ewk_del(void *data, const Efl_Event *desc EINA_UNUSED)
{
Eo *plug = data;
EINA_LIST_FOREACH(pd->subobjs, l, widget)
{
- //TIZEN_ONLY(20160824): Do not append a child, if its accessible parent is different with widget parent
- parent = efl_access_parent_get(widget);
- if (parent && (parent != obj)) continue;
-
- //TIZEN_ONLY(20171114) atspi: integrate ewk_view with elementary accessibility
- // 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)
+ const char *type = evas_object_type_get(widget);
+ // TIZEN ONLY
+ // 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")))
{
- Eo *plug = evas_object_data_get(widget, "__ewk_proxy");
- if (!plug)
- {
- plug = efl_add(ELM_ATSPI_PROXY_CLASS, obj, elm_obj_atspi_proxy_constructor(efl_added, ELM_ATSPI_PROXY_TYPE_PLUG));
- evas_object_data_set(widget, "__ewk_proxy", plug);
- efl_event_callback_add(widget, EFL_EVENT_DEL, _on_ewk_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;
+ elm_atspi_ewk_wrapper_a11y_init(obj, widget);
+ }
+ }
+ EINA_LIST_FOREACH(pd->subobjs, l, widget)
+ {
+ // TIZEN_ONLY(20160824): Do not append a child, if its accessible parent is different with widget parent
+ if (efl_isa(widget, EFL_ACCESS_MIXIN))
+ {
+ parent = efl_access_parent_get(widget);
+ if (parent && (parent != obj)) continue;
}
- //
-
//TIZEN_ONLY(20171108): make atspi_proxy work
const char *plug_id_2;
if ((plug_id_2 = evas_object_data_get(widget, "___PLUGID")) != NULL)
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 (efl_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;