[ATK] Missing WTR AccessibilityUIElement::addNotificationListener implementation
[WebKit-https.git] / Tools / WebKitTestRunner / InjectedBundle / atk / AccessibilityControllerAtk.cpp
1 /*
2  * Copyright (C) 2012 Igalia S.L.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27
28 #include "config.h"
29 #include "AccessibilityController.h"
30
31 #include "InjectedBundle.h"
32 #include "InjectedBundlePage.h"
33
34 #include <WebKit2/WKBundlePagePrivate.h>
35 #include <atk/atk.h>
36 #include <cstdio>
37 #include <wtf/gobject/GOwnPtr.h>
38 #include <wtf/text/StringBuilder.h>
39
40 namespace WTR {
41
42 void AccessibilityController::logAccessibilityEvents()
43 {
44     // Ensure no callbacks are connected before.
45     resetToConsistentState();
46
47     // Ensure that accessibility is initialized for the WebView by querying for
48     // the root accessible object, which will create the full hierarchy.
49     rootElement();
50
51     if (!m_globalNotificationHandler)
52         m_globalNotificationHandler = AccessibilityNotificationHandler::create();
53     m_globalNotificationHandler->logAccessibilityEvents();
54
55     // Ensure the Atk interface types are registered, otherwise
56     // the AtkDocument signal handlers below won't get registered.
57     GObject* dummyAxObject = G_OBJECT(g_object_new(ATK_TYPE_OBJECT, 0));
58     AtkObject* dummyNoOpAxObject = atk_no_op_object_new(dummyAxObject);
59     g_object_unref(G_OBJECT(dummyNoOpAxObject));
60     g_object_unref(dummyAxObject);
61 }
62
63 void AccessibilityController::resetToConsistentState()
64 {
65     m_globalNotificationHandler = 0;
66 }
67
68 static AtkObject* childElementById(AtkObject* parent, const char* id)
69 {
70     if (!ATK_IS_OBJECT(parent))
71         return 0;
72
73     bool parentFound = false;
74     AtkAttributeSet* attributeSet = atk_object_get_attributes(parent);
75     for (AtkAttributeSet* attributes = attributeSet; attributes; attributes = attributes->next) {
76         AtkAttribute* attribute = static_cast<AtkAttribute*>(attributes->data);
77         if (!strcmp(attribute->name, "html-id")) {
78             if (!strcmp(attribute->value, id))
79                 parentFound = true;
80             break;
81         }
82     }
83     atk_attribute_set_free(attributeSet);
84
85     if (parentFound)
86         return parent;
87
88     int childCount = atk_object_get_n_accessible_children(parent);
89     for (int i = 0; i < childCount; i++) {
90         AtkObject* result = childElementById(atk_object_ref_accessible_child(parent, i), id);
91         if (ATK_IS_OBJECT(result))
92             return result;
93     }
94
95     return 0;
96 }
97
98 PassRefPtr<AccessibilityUIElement> AccessibilityController::accessibleElementById(JSStringRef id)
99 {
100     AtkObject* root = ATK_OBJECT(WKAccessibilityRootObject(InjectedBundle::shared().page()->page()));
101     if (!root)
102         return 0;
103
104     size_t bufferSize = JSStringGetMaximumUTF8CStringSize(id);
105     GOwnPtr<gchar> idBuffer(static_cast<gchar*>(g_malloc(bufferSize)));
106     JSStringGetUTF8CString(id, idBuffer.get(), bufferSize);
107
108     AtkObject* result = childElementById(root, idBuffer.get());
109     if (ATK_IS_OBJECT(result))
110         return AccessibilityUIElement::create(result);
111
112     return 0;
113 }
114
115 PassRefPtr<AccessibilityUIElement> AccessibilityController::rootElement()
116 {
117     WKBundlePageRef page = InjectedBundle::shared().page()->page();
118     void* root = WKAccessibilityRootObject(page);
119
120     return AccessibilityUIElement::create(static_cast<AtkObject*>(root));
121 }
122
123 PassRefPtr<AccessibilityUIElement> AccessibilityController::focusedElement()
124 {
125     WKBundlePageRef page = InjectedBundle::shared().page()->page();
126     void* root = WKAccessibilityFocusedObject(page);
127
128     return AccessibilityUIElement::create(static_cast<AtkObject*>(root));
129 }
130
131 } // namespace WTR