Diff
Modified: trunk/Tools/ChangeLog (156163 => 156164)
--- trunk/Tools/ChangeLog 2013-09-20 15:04:07 UTC (rev 156163)
+++ trunk/Tools/ChangeLog 2013-09-20 15:15:22 UTC (rev 156164)
@@ -1,3 +1,75 @@
+2013-09-20 Denis Nomiyama <[email protected]>
+
+ [ATK] Missing WTR AccessibilityUIElement::addNotificationListener implementation
+ https://bugs.webkit.org/show_bug.cgi?id=120421
+
+ Reviewed by Mario Sanchez Prada.
+
+ Implemented the notification listener for AccessibilityUIElement for
+ WebKitTestRunner. The signal is generated by
+ AXObjectCache::postPlatformNotification() and received by
+ axObjectEventListener(). axObjectEventListener() will then invoke
+ JSObjectCallAsFunction() with the respective callback function. The
+ notification handlers are stored in HashMap in
+ AccessibilityNotificationHandlerAtk.cpp.
+
+ Moved ATK signal handling (printAccessibilityEvent and
+ axObjectEventListener) to AccessibilityNotificationHandlerAtk.cpp.
+
+ * WebKitTestRunner/CMakeLists.txt: Added InjectedBundle/atk to the
+ include path.
+ * WebKitTestRunner/GNUmakefile.am:
+ Added AccessibilityNotificationHandlerAtk.cpp/h.
+ * WebKitTestRunner/InjectedBundle/AccessibilityController.cpp: Moved
+ listener IDs to AccessibilityNotificationHandlerAtk.cpp.
+ * WebKitTestRunner/InjectedBundle/AccessibilityController.h: Moved
+ listener IDs to AccessibilityNotificationHandlerAtk.cpp.
+ * WebKitTestRunner/InjectedBundle/AccessibilityUIElement.h: Added a
+ notification handler for GTK+ and EFL.
+ * WebKitTestRunner/InjectedBundle/atk/AccessibilityControllerAtk.cpp:
+ Moved printAccessibilityEvent and axObjectEventListener to
+ AccessibilityNotificationHandlerAtk.cpp.
+ (WTR::AccessibilityController::logAccessibilityEvents): Moved listener
+ IDs to AccessibilityNotificationHandlerAtk.cpp.
+ (WTR::AccessibilityController::resetToConsistentState): Moved listener
+ IDs to AccessibilityNotificationHandlerAtk.cpp.
+ * WebKitTestRunner/InjectedBundle/atk/AccessibilityNotificationHandlerAtk.cpp: Added.
+ (WTR::printAccessibilityEvent): Prints accessibility events. This
+ function was moved from AccessibilityControllerAtk.cpp.
+ (WTR::axObjectEventListener): Callback for signals. This function was
+ moved from AccessibilityControllerAtk.cpp.
+ (WTR::AccessibilityNotificationHandler::AccessibilityNotificationHandler):
+ Initialize element and function callback.
+ (WTR::AccessibilityNotificationHandler::~AccessibilityNotificationHandler):
+ Removes handler from HashMap and disconnects callbacks if necessary.
+ (WTR::AccessibilityNotificationHandler::logAccessibilityEvents): Sets
+ logging mode and connects callbacks.
+ (WTR::AccessibilityNotificationHandler::setNotificationFunctionCallback):
+ Sets the notification callback and connects callback to signals.
+ (WTR::AccessibilityNotificationHandler::removeAccessibilityNotificationHandler):
+ Removes the notification callback from HashMap.
+ (WTR::AccessibilityNotificationHandler::connectAccessibilityCallbacks):
+ Connects axObjectEventListener to ATK signals.
+ (WTR::AccessibilityNotificationHandler::disconnectAccessibilityCallbacks):
+ Disconnects callback.
+ * WebKitTestRunner/InjectedBundle/atk/AccessibilityNotificationHandlerAtk.h: Added.
+ (WTR::AccessibilityNotificationHandler::create): Creates a new instance
+ of AccessibilityNotificationHandler.
+ (WTR::AccessibilityNotificationHandler::setPlatformElement): Sets the
+ element.
+ (WTR::AccessibilityNotificationHandler::platformElement): Gets the
+ element.
+ (WTR::AccessibilityNotificationHandler::notificationFunctionCallback):
+ Gets the notification callback.
+ * WebKitTestRunner/InjectedBundle/atk/AccessibilityUIElementAtk.cpp:
+ (WTR::AccessibilityUIElement::addNotificationListener): Creates
+ notification handler, set the platform element and the notification
+ callback.
+ (WTR::AccessibilityUIElement::removeNotificationListener): Deletes the
+ notification handler.
+ * WebKitTestRunner/PlatformEfl.cmake:
+ Added AccessibilityNotificationHandlerAtk.cpp.
+
2013-09-20 Allan Sandfeld Jensen <[email protected]>
Update features.pri
Modified: trunk/Tools/WebKitTestRunner/CMakeLists.txt (156163 => 156164)
--- trunk/Tools/WebKitTestRunner/CMakeLists.txt 2013-09-20 15:04:07 UTC (rev 156163)
+++ trunk/Tools/WebKitTestRunner/CMakeLists.txt 2013-09-20 15:15:22 UTC (rev 156164)
@@ -24,6 +24,7 @@
${WEBKIT_TESTRUNNER_DIR}
${WEBKIT_TESTRUNNER_DIR}/InjectedBundle
${WEBKIT_TESTRUNNER_DIR}/InjectedBundle/Bindings
+ ${WEBKIT_TESTRUNNER_DIR}/InjectedBundle/atk
${_javascript_CORE_DIR}
${_javascript_CORE_DIR}/ForwardingHeaders
${WEBCORE_DIR}/editing
Modified: trunk/Tools/WebKitTestRunner/GNUmakefile.am (156163 => 156164)
--- trunk/Tools/WebKitTestRunner/GNUmakefile.am 2013-09-20 15:04:07 UTC (rev 156163)
+++ trunk/Tools/WebKitTestRunner/GNUmakefile.am 2013-09-20 15:15:22 UTC (rev 156164)
@@ -93,6 +93,8 @@
Tools/WebKitTestRunner/InjectedBundle/AccessibilityUIElement.h \
Tools/WebKitTestRunner/InjectedBundle/ActivateFonts.h \
Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityControllerAtk.cpp \
+ Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityNotificationHandlerAtk.cpp \
+ Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityNotificationHandlerAtk.h \
Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityUIElementAtk.cpp \
Tools/WebKitTestRunner/InjectedBundle/Bindings/JSWrappable.h \
Tools/WebKitTestRunner/InjectedBundle/Bindings/JSWrapper.cpp \
@@ -132,6 +134,7 @@
-I$(srcdir)/Tools/WebKitTestRunner \
-I$(srcdir)/Tools/WebKitTestRunner/InjectedBundle \
-I$(srcdir)/Tools/WebKitTestRunner/InjectedBundle/Bindings \
+ -I$(srcdir)/Tools/WebKitTestRunner/InjectedBundle/atk \
-I$(srcdir)/Source/WebCore/testing/js \
-I$(top_builddir)/DerivedSources/InjectedBundle \
-I$(top_builddir)/DerivedSources/WebKit2/include \
Modified: trunk/Tools/WebKitTestRunner/InjectedBundle/AccessibilityController.cpp (156163 => 156164)
--- trunk/Tools/WebKitTestRunner/InjectedBundle/AccessibilityController.cpp 2013-09-20 15:04:07 UTC (rev 156163)
+++ trunk/Tools/WebKitTestRunner/InjectedBundle/AccessibilityController.cpp 2013-09-20 15:15:22 UTC (rev 156164)
@@ -44,14 +44,6 @@
}
AccessibilityController::AccessibilityController()
-#if PLATFORM(GTK) || PLATFORM(EFL)
- : m_stateChangeListenerId(0)
- , m_focusEventListenerId(0)
- , m_activeDescendantChangedListenerId(0)
- , m_childrenChangedListenerId(0)
- , m_propertyChangedListenerId(0)
- , m_visibleDataChangedListenerId(0)
-#endif
{
}
Modified: trunk/Tools/WebKitTestRunner/InjectedBundle/AccessibilityController.h (156163 => 156164)
--- trunk/Tools/WebKitTestRunner/InjectedBundle/AccessibilityController.h 2013-09-20 15:04:07 UTC (rev 156163)
+++ trunk/Tools/WebKitTestRunner/InjectedBundle/AccessibilityController.h 2013-09-20 15:15:22 UTC (rev 156164)
@@ -33,6 +33,9 @@
#if PLATFORM(WIN)
#include <windows.h>
#endif
+#if PLATFORM(GTK) || (PLATFORM(EFL) && HAVE(ACCESSIBILITY))
+#include "AccessibilityNotificationHandlerAtk.h"
+#endif
namespace WTR {
@@ -68,13 +71,8 @@
RetainPtr<NotificationHandler> m_globalNotificationHandler;
#endif
-#if PLATFORM(GTK) || PLATFORM(EFL)
- unsigned m_stateChangeListenerId;
- unsigned m_focusEventListenerId;
- unsigned m_activeDescendantChangedListenerId;
- unsigned m_childrenChangedListenerId;
- unsigned m_propertyChangedListenerId;
- unsigned m_visibleDataChangedListenerId;
+#if PLATFORM(GTK) || (PLATFORM(EFL) && HAVE(ACCESSIBILITY))
+ RefPtr<AccessibilityNotificationHandler> m_globalNotificationHandler;
#endif
};
Modified: trunk/Tools/WebKitTestRunner/InjectedBundle/AccessibilityUIElement.h (156163 => 156164)
--- trunk/Tools/WebKitTestRunner/InjectedBundle/AccessibilityUIElement.h 2013-09-20 15:04:07 UTC (rev 156163)
+++ trunk/Tools/WebKitTestRunner/InjectedBundle/AccessibilityUIElement.h 2013-09-20 15:15:22 UTC (rev 156164)
@@ -50,6 +50,7 @@
typedef COMPtr<IAccessible> PlatformUIElement;
#elif PLATFORM(GTK) || (PLATFORM(EFL) && HAVE(ACCESSIBILITY))
+#include "AccessibilityNotificationHandlerAtk.h"
#include <atk/atk.h>
#include <wtf/gobject/GRefPtr.h>
typedef GRefPtr<AtkObject> PlatformUIElement;
@@ -262,6 +263,10 @@
void getChildren(Vector<RefPtr<AccessibilityUIElement> >&);
void getChildrenWithRange(Vector<RefPtr<AccessibilityUIElement> >&, unsigned location, unsigned length);
#endif
+
+#if PLATFORM(GTK) || (PLATFORM(EFL) && HAVE(ACCESSIBILITY))
+ RefPtr<AccessibilityNotificationHandler> m_notificationHandler;
+#endif
};
} // namespace WTR
Modified: trunk/Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityControllerAtk.cpp (156163 => 156164)
--- trunk/Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityControllerAtk.cpp 2013-09-20 15:04:07 UTC (rev 156163)
+++ trunk/Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityControllerAtk.cpp 2013-09-20 15:15:22 UTC (rev 156164)
@@ -39,63 +39,6 @@
namespace WTR {
-static void printAccessibilityEvent(AtkObject* accessible, const gchar* signalName, const gchar* signalValue)
-{
- // Do not handle state-change:defunct signals, as the AtkObject
- // associated to them will not be valid at this point already.
- if (!signalName || !g_strcmp0(signalName, "state-change:defunct"))
- return;
-
- if (!accessible || !ATK_IS_OBJECT(accessible))
- return;
-
- const gchar* objectName = atk_object_get_name(accessible);
- AtkRole objectRole = atk_object_get_role(accessible);
-
- // Try to always provide a name to be logged for the object.
- if (!objectName || *objectName == '\0')
- objectName = "(No name)";
-
- GOwnPtr<gchar> signalNameAndValue(signalValue ? g_strdup_printf("%s = %s", signalName, signalValue) : g_strdup(signalName));
- GOwnPtr<gchar> accessibilityEventString(g_strdup_printf("Accessibility object emitted \"%s\" / Name: \"%s\" / Role: %d\n", signalNameAndValue.get(), objectName, objectRole));
- InjectedBundle::shared().outputText(String::fromUTF8(accessibilityEventString.get()));
-}
-
-static gboolean axObjectEventListener(GSignalInvocationHint *signalHint, guint numParamValues, const GValue *paramValues, gpointer data)
-{
- // At least we should receive the instance emitting the signal.
- if (numParamValues < 1)
- return TRUE;
-
- AtkObject* accessible = ATK_OBJECT(g_value_get_object(¶mValues[0]));
- if (!accessible || !ATK_IS_OBJECT(accessible))
- return TRUE;
-
- GSignalQuery signalQuery;
- GOwnPtr<gchar> signalName;
- GOwnPtr<gchar> signalValue;
-
- g_signal_query(signalHint->signal_id, &signalQuery);
-
- if (!g_strcmp0(signalQuery.signal_name, "state-change")) {
- signalName.set(g_strdup_printf("state-change:%s", g_value_get_string(¶mValues[1])));
- signalValue.set(g_strdup_printf("%d", g_value_get_boolean(¶mValues[2])));
- } else if (!g_strcmp0(signalQuery.signal_name, "focus-event")) {
- signalName.set(g_strdup("focus-event"));
- signalValue.set(g_strdup_printf("%d", g_value_get_boolean(¶mValues[1])));
- } else if (!g_strcmp0(signalQuery.signal_name, "children-changed")) {
- signalName.set(g_strdup("children-changed"));
- signalValue.set(g_strdup_printf("%d", g_value_get_uint(¶mValues[1])));
- } else if (!g_strcmp0(signalQuery.signal_name, "property-change"))
- signalName.set(g_strdup_printf("property-change:%s", g_quark_to_string(signalHint->detail)));
- else
- signalName.set(g_strdup(signalQuery.signal_name));
-
- printAccessibilityEvent(accessible, signalName.get(), signalValue.get());
-
- return TRUE;
-}
-
void AccessibilityController::logAccessibilityEvents()
{
// Ensure no callbacks are connected before.
@@ -105,13 +48,9 @@
// the root accessible object, which will create the full hierarchy.
rootElement();
- // Add global listeners for AtkObject's signals.
- m_stateChangeListenerId = atk_add_global_event_listener(axObjectEventListener, "ATK:AtkObject:state-change");
- m_focusEventListenerId = atk_add_global_event_listener(axObjectEventListener, "ATK:AtkObject:focus-event");
- m_activeDescendantChangedListenerId = atk_add_global_event_listener(axObjectEventListener, "ATK:AtkObject:active-descendant-changed");
- m_childrenChangedListenerId = atk_add_global_event_listener(axObjectEventListener, "ATK:AtkObject:children-changed");
- m_propertyChangedListenerId = atk_add_global_event_listener(axObjectEventListener, "ATK:AtkObject:property-change");
- m_visibleDataChangedListenerId = atk_add_global_event_listener(axObjectEventListener, "ATK:AtkObject:visible-data-changed");
+ if (!m_globalNotificationHandler)
+ m_globalNotificationHandler = AccessibilityNotificationHandler::create();
+ m_globalNotificationHandler->logAccessibilityEvents();
// Ensure the Atk interface types are registered, otherwise
// the AtkDocument signal handlers below won't get registered.
@@ -123,31 +62,7 @@
void AccessibilityController::resetToConsistentState()
{
- // AtkObject signals.
- if (m_stateChangeListenerId) {
- atk_remove_global_event_listener(m_stateChangeListenerId);
- m_stateChangeListenerId = 0;
- }
- if (m_focusEventListenerId) {
- atk_remove_global_event_listener(m_focusEventListenerId);
- m_focusEventListenerId = 0;
- }
- if (m_activeDescendantChangedListenerId) {
- atk_remove_global_event_listener(m_activeDescendantChangedListenerId);
- m_activeDescendantChangedListenerId = 0;
- }
- if (m_childrenChangedListenerId) {
- atk_remove_global_event_listener(m_childrenChangedListenerId);
- m_childrenChangedListenerId = 0;
- }
- if (m_propertyChangedListenerId) {
- atk_remove_global_event_listener(m_propertyChangedListenerId);
- m_propertyChangedListenerId = 0;
- }
- if (m_visibleDataChangedListenerId) {
- atk_remove_global_event_listener(m_visibleDataChangedListenerId);
- m_visibleDataChangedListenerId = 0;
- }
+ m_globalNotificationHandler = 0;
}
static AtkObject* childElementById(AtkObject* parent, const char* id)
Added: trunk/Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityNotificationHandlerAtk.cpp (0 => 156164)
--- trunk/Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityNotificationHandlerAtk.cpp (rev 0)
+++ trunk/Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityNotificationHandlerAtk.cpp 2013-09-20 15:15:22 UTC (rev 156164)
@@ -0,0 +1,280 @@
+/*
+ * Copyright (C) 2013 Samsung Electronics Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "AccessibilityNotificationHandlerAtk.h"
+
+#include "InjectedBundle.h"
+#include "InjectedBundlePage.h"
+#include "JSWrapper.h"
+#include <WebKit2/WKBundleFrame.h>
+#include <WebKit2/WKBundlePage.h>
+#include <WebKit2/WKBundlePagePrivate.h>
+#include <wtf/HashMap.h>
+#include <wtf/gobject/GOwnPtr.h>
+#include <wtf/text/CString.h>
+#include <wtf/text/WTFString.h>
+
+namespace WTR {
+
+namespace {
+
+typedef HashMap<AtkObject*, AccessibilityNotificationHandler*> NotificationHandlersMap;
+
+unsigned stateChangeListenerId = 0;
+unsigned focusEventListenerId = 0;
+unsigned activeDescendantChangedListenerId = 0;
+unsigned childrenChangedListenerId = 0;
+unsigned propertyChangedListenerId = 0;
+unsigned visibleDataChangedListenerId = 0;
+NotificationHandlersMap notificationHandlers;
+AccessibilityNotificationHandler* globalNotificationHandler = 0;
+bool loggingAccessibilityEvents = false;
+
+void printAccessibilityEvent(AtkObject* accessible, const char* signalName, const char* signalValue)
+{
+ // Do not handle state-change:defunct signals, as the AtkObject
+ // associated to them will not be valid at this point already.
+ if (!signalName || !g_strcmp0(signalName, "state-change:defunct"))
+ return;
+
+ if (!accessible || !ATK_IS_OBJECT(accessible))
+ return;
+
+ const char* objectName = atk_object_get_name(accessible);
+ AtkRole objectRole = atk_object_get_role(accessible);
+
+ // Try to always provide a name to be logged for the object.
+ if (!objectName || *objectName == '\0')
+ objectName = "(No name)";
+
+ GOwnPtr<char> signalNameAndValue(signalValue ? g_strdup_printf("%s = %s", signalName, signalValue) : g_strdup(signalName));
+ GOwnPtr<char> accessibilityEventString(g_strdup_printf("Accessibility object emitted \"%s\" / Name: \"%s\" / Role: %d\n", signalNameAndValue.get(), objectName, objectRole));
+ InjectedBundle::shared().outputText(String::fromUTF8(accessibilityEventString.get()));
+}
+
+gboolean axObjectEventListener(GSignalInvocationHint* signalHint, unsigned numParamValues, const GValue* paramValues, gpointer data)
+{
+ // At least we should receive the instance emitting the signal.
+ if (!numParamValues)
+ return true;
+
+ AtkObject* accessible = ATK_OBJECT(g_value_get_object(¶mValues[0]));
+ if (!accessible || !ATK_IS_OBJECT(accessible))
+ return true;
+
+ GSignalQuery signalQuery;
+ GOwnPtr<char> signalName;
+ GOwnPtr<char> signalValue;
+ const char* notificationName = 0;
+
+ g_signal_query(signalHint->signal_id, &signalQuery);
+
+ if (!g_strcmp0(signalQuery.signal_name, "state-change")) {
+ signalName.set(g_strdup_printf("state-change:%s", g_value_get_string(¶mValues[1])));
+ signalValue.set(g_strdup_printf("%d", g_value_get_boolean(¶mValues[2])));
+ if (!g_strcmp0(g_value_get_string(¶mValues[1]), "checked"))
+ notificationName = "CheckedStateChanged";
+ else if (!g_strcmp0(g_value_get_string(¶mValues[1]), "invalid-entry"))
+ notificationName = "AXInvalidStatusChanged";
+ else if (!g_strcmp0(g_value_get_string(¶mValues[1]), "layout-complete"))
+ notificationName = "AXLayoutComplete";
+ } else if (!g_strcmp0(signalQuery.signal_name, "focus-event")) {
+ signalName.set(g_strdup("focus-event"));
+ signalValue.set(g_strdup_printf("%d", g_value_get_boolean(¶mValues[1])));
+ if (g_value_get_boolean(¶mValues[1]))
+ notificationName = "AXFocusedUIElementChanged";
+ } else if (!g_strcmp0(signalQuery.signal_name, "children-changed")) {
+ signalName.set(g_strdup("children-changed"));
+ signalValue.set(g_strdup_printf("%d", g_value_get_uint(¶mValues[1])));
+ } else if (!g_strcmp0(signalQuery.signal_name, "property-change")) {
+ signalName.set(g_strdup_printf("property-change:%s", g_quark_to_string(signalHint->detail)));
+ if (!g_strcmp0(g_quark_to_string(signalHint->detail), "accessible-value"))
+ notificationName = "AXValueChanged";
+ } else
+ signalName.set(g_strdup(signalQuery.signal_name));
+
+ if (loggingAccessibilityEvents)
+ printAccessibilityEvent(accessible, signalName.get(), signalValue.get());
+
+#if PLATFORM(GTK)
+ WKBundlePageRef page = InjectedBundle::shared().page()->page();
+ WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(page);
+ JSContextRef jsContext = WKBundleFrameGetJavaScriptContext(mainFrame);
+#else
+ JSContextRef jsContext = 0;
+#endif
+ if (!jsContext)
+ return true;
+
+ if (notificationName) {
+ JSRetainPtr<JSStringRef> jsNotificationEventName(Adopt, JSStringCreateWithUTF8CString(notificationName));
+ JSValueRef notificationNameArgument = JSValueMakeString(jsContext, jsNotificationEventName.get());
+ NotificationHandlersMap::iterator elementNotificationHandler = notificationHandlers.find(accessible);
+ if (elementNotificationHandler != notificationHandlers.end()) {
+ // Listener for one element just gets one argument, the notification name.
+ JSObjectCallAsFunction(jsContext, const_cast<JSObjectRef>(elementNotificationHandler->value->notificationFunctionCallback()), 0, 1, ¬ificationNameArgument, 0);
+ }
+
+ if (globalNotificationHandler) {
+ // A global listener gets the element and the notification name as arguments.
+ JSValueRef arguments[2];
+ arguments[0] = toJS(jsContext, WTF::getPtr(WTR::AccessibilityUIElement::create(accessible)));
+ arguments[1] = notificationNameArgument;
+ JSObjectCallAsFunction(jsContext, const_cast<JSObjectRef>(globalNotificationHandler->notificationFunctionCallback()), 0, 2, arguments, 0);
+ }
+ }
+
+ return true;
+}
+
+} // namespace
+
+AccessibilityNotificationHandler::AccessibilityNotificationHandler()
+ : m_platformElement(0)
+ , m_notificationFunctionCallback(0)
+{
+}
+
+AccessibilityNotificationHandler::~AccessibilityNotificationHandler()
+{
+ removeAccessibilityNotificationHandler();
+ disconnectAccessibilityCallbacks();
+}
+
+void AccessibilityNotificationHandler::logAccessibilityEvents()
+{
+ connectAccessibilityCallbacks();
+ loggingAccessibilityEvents = true;
+}
+
+void AccessibilityNotificationHandler::setNotificationFunctionCallback(JSValueRef notificationFunctionCallback)
+{
+ if (!notificationFunctionCallback) {
+ removeAccessibilityNotificationHandler();
+ disconnectAccessibilityCallbacks();
+ return;
+ }
+
+ m_notificationFunctionCallback = notificationFunctionCallback;
+
+#if PLATFORM(GTK)
+ WKBundlePageRef page = InjectedBundle::shared().page()->page();
+ WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(page);
+ JSContextRef jsContext = WKBundleFrameGetJavaScriptContext(mainFrame);
+#else
+ JSContextRef jsContext = 0;
+#endif
+ if (!jsContext)
+ return;
+
+ connectAccessibilityCallbacks();
+
+ JSValueProtect(jsContext, m_notificationFunctionCallback);
+ // Check if this notification handler is related to a specific element.
+ if (m_platformElement) {
+ NotificationHandlersMap::iterator currentNotificationHandler = notificationHandlers.find(m_platformElement.get());
+ if (currentNotificationHandler != notificationHandlers.end()) {
+ ASSERT(currentNotificationHandler->value->platformElement());
+ JSValueUnprotect(jsContext, currentNotificationHandler->value->notificationFunctionCallback());
+ notificationHandlers.remove(currentNotificationHandler->value->platformElement().get());
+ }
+ notificationHandlers.add(m_platformElement.get(), this);
+ } else {
+ if (globalNotificationHandler)
+ JSValueUnprotect(jsContext, globalNotificationHandler->notificationFunctionCallback());
+ globalNotificationHandler = this;
+ }
+}
+
+void AccessibilityNotificationHandler::removeAccessibilityNotificationHandler()
+{
+#if PLATFORM(GTK)
+ WKBundlePageRef page = InjectedBundle::shared().page()->page();
+ WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(page);
+ JSContextRef jsContext = WKBundleFrameGetJavaScriptContext(mainFrame);
+#else
+ JSContextRef jsContext = 0;
+#endif
+ if (!jsContext)
+ return;
+
+ if (globalNotificationHandler == this) {
+ JSValueUnprotect(jsContext, globalNotificationHandler->notificationFunctionCallback());
+ globalNotificationHandler = 0;
+ } else if (m_platformElement.get()) {
+ NotificationHandlersMap::iterator removeNotificationHandler = notificationHandlers.find(m_platformElement.get());
+ if (removeNotificationHandler != notificationHandlers.end()) {
+ JSValueUnprotect(jsContext, removeNotificationHandler->value->notificationFunctionCallback());
+ notificationHandlers.remove(removeNotificationHandler);
+ }
+ }
+}
+
+void AccessibilityNotificationHandler::connectAccessibilityCallbacks()
+{
+ // Ensure no callbacks are connected before.
+ if (!disconnectAccessibilityCallbacks())
+ return;
+
+ // Add global listeners for AtkObject's signals.
+ stateChangeListenerId = atk_add_global_event_listener(axObjectEventListener, "ATK:AtkObject:state-change");
+ focusEventListenerId = atk_add_global_event_listener(axObjectEventListener, "ATK:AtkObject:focus-event");
+ activeDescendantChangedListenerId = atk_add_global_event_listener(axObjectEventListener, "ATK:AtkObject:active-descendant-changed");
+ childrenChangedListenerId = atk_add_global_event_listener(axObjectEventListener, "ATK:AtkObject:children-changed");
+ propertyChangedListenerId = atk_add_global_event_listener(axObjectEventListener, "ATK:AtkObject:property-change");
+ visibleDataChangedListenerId = atk_add_global_event_listener(axObjectEventListener, "ATK:AtkObject:visible-data-changed");
+}
+
+bool AccessibilityNotificationHandler::disconnectAccessibilityCallbacks()
+{
+ // Only disconnect if logging is off and there is no notification handler.
+ if (loggingAccessibilityEvents || !notificationHandlers.isEmpty() || globalNotificationHandler)
+ return false;
+
+ // AtkObject signals.
+ if (stateChangeListenerId) {
+ atk_remove_global_event_listener(stateChangeListenerId);
+ stateChangeListenerId = 0;
+ }
+ if (focusEventListenerId) {
+ atk_remove_global_event_listener(focusEventListenerId);
+ focusEventListenerId = 0;
+ }
+ if (activeDescendantChangedListenerId) {
+ atk_remove_global_event_listener(activeDescendantChangedListenerId);
+ activeDescendantChangedListenerId = 0;
+ }
+ if (childrenChangedListenerId) {
+ atk_remove_global_event_listener(childrenChangedListenerId);
+ childrenChangedListenerId = 0;
+ }
+ if (propertyChangedListenerId) {
+ atk_remove_global_event_listener(propertyChangedListenerId);
+ propertyChangedListenerId = 0;
+ }
+ if (visibleDataChangedListenerId) {
+ atk_remove_global_event_listener(visibleDataChangedListenerId);
+ visibleDataChangedListenerId = 0;
+ }
+
+ return true;
+}
+
+} // namespace WTR
Added: trunk/Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityNotificationHandlerAtk.h (0 => 156164)
--- trunk/Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityNotificationHandlerAtk.h (rev 0)
+++ trunk/Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityNotificationHandlerAtk.h 2013-09-20 15:15:22 UTC (rev 156164)
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2013 Samsung Electronics Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef AccessibilityNotificationHandlerAtk_h
+#define AccessibilityNotificationHandlerAtk_h
+
+#include <_javascript_Core/JSObjectRef.h>
+#include <atk/atk.h>
+#include <atk/atkobject.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/gobject/GRefPtr.h>
+
+namespace WTR {
+
+class AccessibilityNotificationHandler : public RefCounted<AccessibilityNotificationHandler> {
+public:
+ static PassRefPtr<AccessibilityNotificationHandler> create()
+ {
+ return adoptRef(new AccessibilityNotificationHandler());
+ }
+ ~AccessibilityNotificationHandler();
+ void setPlatformElement(GRefPtr<AtkObject> platformElement) { m_platformElement = platformElement; }
+ GRefPtr<AtkObject> platformElement() const { return m_platformElement; }
+ void setNotificationFunctionCallback(JSValueRef);
+ JSValueRef notificationFunctionCallback() const { return m_notificationFunctionCallback; }
+ void logAccessibilityEvents();
+
+private:
+ AccessibilityNotificationHandler();
+ void connectAccessibilityCallbacks();
+ bool disconnectAccessibilityCallbacks();
+ void removeAccessibilityNotificationHandler();
+
+ GRefPtr<AtkObject> m_platformElement;
+ JSValueRef m_notificationFunctionCallback;
+};
+
+} // namespace WTR
+
+#endif // AccessibilityNotificationHandlerAtk_h
Modified: trunk/Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityUIElementAtk.cpp (156163 => 156164)
--- trunk/Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityUIElementAtk.cpp 2013-09-20 15:04:07 UTC (rev 156163)
+++ trunk/Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityUIElementAtk.cpp 2013-09-20 15:15:22 UTC (rev 156164)
@@ -1119,13 +1119,26 @@
bool AccessibilityUIElement::addNotificationListener(JSValueRef functionCallback)
{
- // FIXME: implement
+ if (!functionCallback)
+ return false;
+
+ // Only one notification listener per element.
+ if (m_notificationHandler)
+ return false;
+
+ m_notificationHandler = AccessibilityNotificationHandler::create();
+ m_notificationHandler->setPlatformElement(platformUIElement());
+ m_notificationHandler->setNotificationFunctionCallback(functionCallback);
+
return true;
}
bool AccessibilityUIElement::removeNotificationListener()
{
- // FIXME: implement
+ // Programmers should not be trying to remove a listener that's already removed.
+ ASSERT(m_notificationHandler);
+ m_notificationHandler = 0;
+
return true;
}
Modified: trunk/Tools/WebKitTestRunner/PlatformEfl.cmake (156163 => 156164)
--- trunk/Tools/WebKitTestRunner/PlatformEfl.cmake 2013-09-20 15:04:07 UTC (rev 156163)
+++ trunk/Tools/WebKitTestRunner/PlatformEfl.cmake 2013-09-20 15:15:22 UTC (rev 156164)
@@ -70,6 +70,7 @@
if (ENABLE_ACCESSIBILITY)
list(APPEND WebKitTestRunnerInjectedBundle_SOURCES
${WEBKIT_TESTRUNNER_INJECTEDBUNDLE_DIR}/atk/AccessibilityControllerAtk.cpp
+ ${WEBKIT_TESTRUNNER_INJECTEDBUNDLE_DIR}/atk/AccessibilityNotificationHandlerAtk.cpp
${WEBKIT_TESTRUNNER_INJECTEDBUNDLE_DIR}/atk/AccessibilityUIElementAtk.cpp
)
list(APPEND WebKitTestRunner_INCLUDE_DIRECTORIES