1 /*
2 * Copyright (C) 2010 Google Inc. All rights reserved.
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 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include "AccessibilityController.h"
32
33 #include "public/platform/WebCString.h"
34 #include "public/testing/WebTestDelegate.h"
35 #include "public/web/WebAXObject.h"
36 #include "public/web/WebElement.h"
37 #include "public/web/WebFrame.h"
38 #include "public/web/WebNode.h"
39 #include "public/web/WebView.h"
40
41 using namespace blink;
42
43 namespace WebTestRunner {
44
AccessibilityController()45 AccessibilityController::AccessibilityController()
46 : m_logAccessibilityEvents(false)
47 {
48
49 bindMethod("logAccessibilityEvents", &AccessibilityController::logAccessibilityEventsCallback);
50 bindMethod("addNotificationListener", &AccessibilityController::addNotificationListenerCallback);
51 bindMethod("removeNotificationListener", &AccessibilityController::removeNotificationListenerCallback);
52
53 bindProperty("focusedElement", &AccessibilityController::focusedElementGetterCallback);
54 bindProperty("rootElement", &AccessibilityController::rootElementGetterCallback);
55
56 bindMethod("accessibleElementById", &AccessibilityController::accessibleElementByIdGetterCallback);
57
58 bindFallbackMethod(&AccessibilityController::fallbackCallback);
59 }
60
bindToJavascript(WebFrame * frame,const WebString & classname)61 void AccessibilityController::bindToJavascript(WebFrame* frame, const WebString& classname)
62 {
63 WebAXObject::enableAccessibility();
64 WebAXObject::enableInlineTextBoxAccessibility();
65 CppBoundClass::bindToJavascript(frame, classname);
66 }
67
reset()68 void AccessibilityController::reset()
69 {
70 m_rootElement = WebAXObject();
71 m_focusedElement = WebAXObject();
72 m_elements.clear();
73 m_notificationCallbacks.clear();
74
75 m_logAccessibilityEvents = false;
76 }
77
setFocusedElement(const WebAXObject & focusedElement)78 void AccessibilityController::setFocusedElement(const WebAXObject& focusedElement)
79 {
80 m_focusedElement = focusedElement;
81 }
82
getFocusedElement()83 WebAXObjectProxy* AccessibilityController::getFocusedElement()
84 {
85 if (m_focusedElement.isNull())
86 m_focusedElement = m_webView->accessibilityObject();
87 return m_elements.getOrCreate(m_focusedElement);
88 }
89
getRootElement()90 WebAXObjectProxy* AccessibilityController::getRootElement()
91 {
92 if (m_rootElement.isNull())
93 m_rootElement = m_webView->accessibilityObject();
94 return m_elements.createRoot(m_rootElement);
95 }
96
findAccessibleElementByIdRecursive(const WebAXObject & obj,const WebString & id)97 WebAXObjectProxy* AccessibilityController::findAccessibleElementByIdRecursive(const WebAXObject& obj, const WebString& id)
98 {
99 if (obj.isNull() || obj.isDetached())
100 return 0;
101
102 WebNode node = obj.node();
103 if (!node.isNull() && node.isElementNode()) {
104 WebElement element = node.to<WebElement>();
105 element.getAttribute("id");
106 if (element.getAttribute("id") == id)
107 return m_elements.getOrCreate(obj);
108 }
109
110 unsigned childCount = obj.childCount();
111 for (unsigned i = 0; i < childCount; i++) {
112 if (WebAXObjectProxy* result = findAccessibleElementByIdRecursive(obj.childAt(i), id))
113 return result;
114 }
115
116 return 0;
117 }
118
getAccessibleElementById(const std::string & id)119 WebAXObjectProxy* AccessibilityController::getAccessibleElementById(const std::string& id)
120 {
121 if (m_rootElement.isNull())
122 m_rootElement = m_webView->accessibilityObject();
123
124 if (!m_rootElement.updateBackingStoreAndCheckValidity())
125 return 0;
126
127 return findAccessibleElementByIdRecursive(m_rootElement, WebString::fromUTF8(id.c_str()));
128 }
129
shouldLogAccessibilityEvents()130 bool AccessibilityController::shouldLogAccessibilityEvents()
131 {
132 return m_logAccessibilityEvents;
133 }
134
notificationReceived(const blink::WebAXObject & target,const char * notificationName)135 void AccessibilityController::notificationReceived(const blink::WebAXObject& target, const char* notificationName)
136 {
137 // Call notification listeners on the element.
138 WebAXObjectProxy* element = m_elements.getOrCreate(target);
139 element->notificationReceived(notificationName);
140
141 // Call global notification listeners.
142 size_t callbackCount = m_notificationCallbacks.size();
143 for (size_t i = 0; i < callbackCount; i++) {
144 CppVariant arguments[2];
145 arguments[0].set(*element->getAsCppVariant());
146 arguments[1].set(notificationName);
147 CppVariant invokeResult;
148 m_notificationCallbacks[i].invokeDefault(arguments, 2, invokeResult);
149 }
150 }
151
logAccessibilityEventsCallback(const CppArgumentList &,CppVariant * result)152 void AccessibilityController::logAccessibilityEventsCallback(const CppArgumentList&, CppVariant* result)
153 {
154 m_logAccessibilityEvents = true;
155 result->setNull();
156 }
157
addNotificationListenerCallback(const CppArgumentList & arguments,CppVariant * result)158 void AccessibilityController::addNotificationListenerCallback(const CppArgumentList& arguments, CppVariant* result)
159 {
160 if (arguments.size() < 1 || !arguments[0].isObject()) {
161 result->setNull();
162 return;
163 }
164
165 m_notificationCallbacks.push_back(arguments[0]);
166 result->setNull();
167 }
168
removeNotificationListenerCallback(const CppArgumentList &,CppVariant * result)169 void AccessibilityController::removeNotificationListenerCallback(const CppArgumentList&, CppVariant* result)
170 {
171 // FIXME: Implement this.
172 result->setNull();
173 }
174
focusedElementGetterCallback(CppVariant * result)175 void AccessibilityController::focusedElementGetterCallback(CppVariant* result)
176 {
177 result->set(*(getFocusedElement()->getAsCppVariant()));
178 }
179
rootElementGetterCallback(CppVariant * result)180 void AccessibilityController::rootElementGetterCallback(CppVariant* result)
181 {
182 result->set(*(getRootElement()->getAsCppVariant()));
183 }
184
accessibleElementByIdGetterCallback(const CppArgumentList & arguments,CppVariant * result)185 void AccessibilityController::accessibleElementByIdGetterCallback(const CppArgumentList& arguments, CppVariant* result)
186 {
187 result->setNull();
188
189 if (arguments.size() < 1 || !arguments[0].isString())
190 return;
191
192 std::string id = arguments[0].toString();
193 WebAXObjectProxy* foundElement = getAccessibleElementById(id);
194 if (!foundElement)
195 return;
196
197 result->set(*(foundElement->getAsCppVariant()));
198 }
199
fallbackCallback(const CppArgumentList &,CppVariant * result)200 void AccessibilityController::fallbackCallback(const CppArgumentList&, CppVariant* result)
201 {
202 m_delegate->printMessage("CONSOLE MESSAGE: JavaScript ERROR: unknown method called on AccessibilityController\n");
203 result->setNull();
204 }
205
206 }
207