elm: add elm_atspi_ewk_wrapper class
authorLukasz Stanislawski <l.stanislaws@samsung.com>
Thu, 7 Dec 2017 13:56:57 +0000 (19:26 +0530)
committerJiyoun Park <jy0703.park@samsung.com>
Thu, 21 Dec 2017 13:30:52 +0000 (22:30 +0900)
Create wrapper widget around Ewk_View Evas_Object in order to
integrate a11y frameworks from elementary and Chromium. Such wrapper
should be created on Chromium EFL port side, however currently will be
added on elementary side with hope to move it into chromium library.

@tizen_feature

orignal patch: 85d052b2e63dc7e0b5286cea61c0870a2f854dcc

Change-Id: I8e99a836e5c47d8e37100b5309c200fbfa20960d

src/Makefile_Elementary.am
src/lib/elementary/Elementary.h
src/lib/elementary/elm_atspi_ewk_wrapper.c [new file with mode: 0644]
src/lib/elementary/elm_atspi_ewk_wrapper.eo [new file with mode: 0644]
src/lib/elementary/elm_atspi_ewk_wrapper.h [new file with mode: 0644]
src/lib/elementary/elm_widget.c

index cf4a5b8..470e8dd 100644 (file)
@@ -3,8 +3,9 @@
 
 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 \
@@ -223,6 +224,7 @@ includesdir = $(includedir)/elementary-@VMAJ@
 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 \
@@ -571,7 +573,8 @@ lib_elementary_libelementary_la_SOURCES = \
        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 \
index eabcf66..78eb198 100644 (file)
@@ -185,6 +185,7 @@ EAPI extern Elm_Version *elm_version;
 #include <elm_app.h>
 #include <elm_atspi_app_object.h>
 #include <elm_atspi_bridge.h>
+#include <elm_atspi_ewk_wrapper.h>
 //TIZEN_ONLY(20171108): make atspi_proxy work
 #include <elm_atspi_proxy.h>
 //
diff --git a/src/lib/elementary/elm_atspi_ewk_wrapper.c b/src/lib/elementary/elm_atspi_ewk_wrapper.c
new file mode 100644 (file)
index 0000000..1f9e665
--- /dev/null
@@ -0,0 +1,211 @@
+#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"
diff --git a/src/lib/elementary/elm_atspi_ewk_wrapper.eo b/src/lib/elementary/elm_atspi_ewk_wrapper.eo
new file mode 100644 (file)
index 0000000..01a48ef
--- /dev/null
@@ -0,0 +1,36 @@
+class Elm.Atspi.Ewk_Wrapper (Efl.Object, Efl.Access, Efl.Access.Component)
+{
+   data: Elm_Atspi_Ewk_Wrapper_Data;
+   eo_prefix: elm_obj_atspi_ewk_wrapper;
+   legacy_prefix: elm_atspi_ewk_wrapper;
+   methods {
+      constructor {
+         params {
+             @in ewk: Efl.Object;
+         }
+      }
+      connection_init {
+      }
+      @property ewk_view {
+           get {
+           }
+           values {
+                ewk: Efl.Object;
+           }
+      }
+      a11y_init @class {
+            params {
+                @in parent: Efl.Object;
+                @in ewk: Efl.Object;
+            }
+      }
+   }
+   constructors {
+      .constructor;
+   }
+   implements {
+      Efl.Object.destructor;
+      Efl.Access.children { get; }
+      Efl.Access.Component.accessible_at_point_get;
+   }
+}
\ No newline at end of file
diff --git a/src/lib/elementary/elm_atspi_ewk_wrapper.h b/src/lib/elementary/elm_atspi_ewk_wrapper.h
new file mode 100644 (file)
index 0000000..03ffe2a
--- /dev/null
@@ -0,0 +1,8 @@
+#ifdef EFL_BETA_API_SUPPORT
+#ifdef EFL_EO_API_SUPPORT
+#include "elm_atspi_ewk_wrapper.eo.h"
+#endif
+#ifndef EFL_NOLEGACY_API_SUPPORT
+#include "elm_atspi_ewk_wrapper.eo.legacy.h"
+#endif
+#endif
index 88fbbc9..a50f726 100644 (file)
@@ -5619,26 +5619,6 @@ static Eina_List *_lines_split(Eina_List *children)
 
 //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;
@@ -5658,33 +5638,23 @@ _elm_widget_efl_access_children_get(Eo *obj, Elm_Widget_Smart_Data *pd)
 
    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)
@@ -6592,6 +6562,11 @@ _elm_widget_efl_access_component_accessible_at_point_get(Eo *obj, Elm_Widget_Sma
                   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;