OLD | NEW |
| (Empty) |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "components/test_runner/accessibility_controller.h" | |
6 | |
7 #include "base/macros.h" | |
8 #include "components/test_runner/web_view_test_proxy.h" | |
9 #include "gin/handle.h" | |
10 #include "gin/object_template_builder.h" | |
11 #include "gin/wrappable.h" | |
12 #include "third_party/WebKit/public/web/WebDocument.h" | |
13 #include "third_party/WebKit/public/web/WebElement.h" | |
14 #include "third_party/WebKit/public/web/WebFrame.h" | |
15 #include "third_party/WebKit/public/web/WebKit.h" | |
16 #include "third_party/WebKit/public/web/WebLocalFrame.h" | |
17 #include "third_party/WebKit/public/web/WebSettings.h" | |
18 #include "third_party/WebKit/public/web/WebView.h" | |
19 | |
20 namespace test_runner { | |
21 | |
22 class AccessibilityControllerBindings | |
23 : public gin::Wrappable<AccessibilityControllerBindings> { | |
24 public: | |
25 static gin::WrapperInfo kWrapperInfo; | |
26 | |
27 static void Install(base::WeakPtr<AccessibilityController> controller, | |
28 blink::WebLocalFrame* frame); | |
29 | |
30 private: | |
31 explicit AccessibilityControllerBindings( | |
32 base::WeakPtr<AccessibilityController> controller); | |
33 ~AccessibilityControllerBindings() override; | |
34 | |
35 // gin::Wrappable: | |
36 gin::ObjectTemplateBuilder GetObjectTemplateBuilder( | |
37 v8::Isolate* isolate) override; | |
38 | |
39 void LogAccessibilityEvents(); | |
40 void SetNotificationListener(v8::Local<v8::Function> callback); | |
41 void UnsetNotificationListener(); | |
42 v8::Local<v8::Object> FocusedElement(); | |
43 v8::Local<v8::Object> RootElement(); | |
44 v8::Local<v8::Object> AccessibleElementById(const std::string& id); | |
45 | |
46 base::WeakPtr<AccessibilityController> controller_; | |
47 | |
48 DISALLOW_COPY_AND_ASSIGN(AccessibilityControllerBindings); | |
49 }; | |
50 | |
51 gin::WrapperInfo AccessibilityControllerBindings::kWrapperInfo = { | |
52 gin::kEmbedderNativeGin}; | |
53 | |
54 // static | |
55 void AccessibilityControllerBindings::Install( | |
56 base::WeakPtr<AccessibilityController> controller, | |
57 blink::WebLocalFrame* frame) { | |
58 v8::Isolate* isolate = blink::mainThreadIsolate(); | |
59 v8::HandleScope handle_scope(isolate); | |
60 v8::Local<v8::Context> context = frame->mainWorldScriptContext(); | |
61 if (context.IsEmpty()) | |
62 return; | |
63 | |
64 v8::Context::Scope context_scope(context); | |
65 | |
66 gin::Handle<AccessibilityControllerBindings> bindings = | |
67 gin::CreateHandle(isolate, | |
68 new AccessibilityControllerBindings(controller)); | |
69 if (bindings.IsEmpty()) | |
70 return; | |
71 v8::Local<v8::Object> global = context->Global(); | |
72 global->Set(gin::StringToV8(isolate, "accessibilityController"), | |
73 bindings.ToV8()); | |
74 } | |
75 | |
76 AccessibilityControllerBindings::AccessibilityControllerBindings( | |
77 base::WeakPtr<AccessibilityController> controller) | |
78 : controller_(controller) { | |
79 } | |
80 | |
81 AccessibilityControllerBindings::~AccessibilityControllerBindings() { | |
82 } | |
83 | |
84 gin::ObjectTemplateBuilder | |
85 AccessibilityControllerBindings::GetObjectTemplateBuilder( | |
86 v8::Isolate* isolate) { | |
87 return gin::Wrappable<AccessibilityControllerBindings>:: | |
88 GetObjectTemplateBuilder(isolate) | |
89 .SetMethod("logAccessibilityEvents", | |
90 &AccessibilityControllerBindings::LogAccessibilityEvents) | |
91 .SetMethod("setNotificationListener", | |
92 &AccessibilityControllerBindings::SetNotificationListener) | |
93 .SetMethod("unsetNotificationListener", | |
94 &AccessibilityControllerBindings::UnsetNotificationListener) | |
95 .SetProperty("focusedElement", | |
96 &AccessibilityControllerBindings::FocusedElement) | |
97 .SetProperty("rootElement", | |
98 &AccessibilityControllerBindings::RootElement) | |
99 .SetMethod("accessibleElementById", | |
100 &AccessibilityControllerBindings::AccessibleElementById) | |
101 // TODO(hajimehoshi): These are for backward compatibility. Remove them. | |
102 .SetMethod("addNotificationListener", | |
103 &AccessibilityControllerBindings::SetNotificationListener) | |
104 .SetMethod("removeNotificationListener", | |
105 &AccessibilityControllerBindings::UnsetNotificationListener); | |
106 } | |
107 | |
108 void AccessibilityControllerBindings::LogAccessibilityEvents() { | |
109 if (controller_) | |
110 controller_->LogAccessibilityEvents(); | |
111 } | |
112 | |
113 void AccessibilityControllerBindings::SetNotificationListener( | |
114 v8::Local<v8::Function> callback) { | |
115 if (controller_) | |
116 controller_->SetNotificationListener(callback); | |
117 } | |
118 | |
119 void AccessibilityControllerBindings::UnsetNotificationListener() { | |
120 if (controller_) | |
121 controller_->UnsetNotificationListener(); | |
122 } | |
123 | |
124 v8::Local<v8::Object> AccessibilityControllerBindings::FocusedElement() { | |
125 return controller_ ? controller_->FocusedElement() : v8::Local<v8::Object>(); | |
126 } | |
127 | |
128 v8::Local<v8::Object> AccessibilityControllerBindings::RootElement() { | |
129 return controller_ ? controller_->RootElement() : v8::Local<v8::Object>(); | |
130 } | |
131 | |
132 v8::Local<v8::Object> AccessibilityControllerBindings::AccessibleElementById( | |
133 const std::string& id) { | |
134 return controller_ ? controller_->AccessibleElementById(id) | |
135 : v8::Local<v8::Object>(); | |
136 } | |
137 | |
138 AccessibilityController::AccessibilityController( | |
139 WebViewTestProxyBase* web_view_test_proxy_base) | |
140 : log_accessibility_events_(false), | |
141 web_view_test_proxy_base_(web_view_test_proxy_base), | |
142 weak_factory_(this) {} | |
143 | |
144 AccessibilityController::~AccessibilityController() {} | |
145 | |
146 void AccessibilityController::Reset() { | |
147 elements_.Clear(); | |
148 notification_callback_.Reset(); | |
149 log_accessibility_events_ = false; | |
150 } | |
151 | |
152 void AccessibilityController::Install(blink::WebLocalFrame* frame) { | |
153 frame->view()->settings()->setAccessibilityEnabled(true); | |
154 frame->view()->settings()->setInlineTextBoxAccessibilityEnabled(true); | |
155 | |
156 AccessibilityControllerBindings::Install(weak_factory_.GetWeakPtr(), frame); | |
157 } | |
158 | |
159 bool AccessibilityController::ShouldLogAccessibilityEvents() { | |
160 return log_accessibility_events_; | |
161 } | |
162 | |
163 void AccessibilityController::NotificationReceived( | |
164 const blink::WebAXObject& target, const std::string& notification_name) { | |
165 v8::Isolate* isolate = blink::mainThreadIsolate(); | |
166 v8::HandleScope handle_scope(isolate); | |
167 | |
168 blink::WebFrame* frame = web_view()->mainFrame(); | |
169 if (!frame || frame->isWebRemoteFrame()) | |
170 return; | |
171 | |
172 v8::Local<v8::Context> context = frame->mainWorldScriptContext(); | |
173 if (context.IsEmpty()) | |
174 return; | |
175 | |
176 v8::Context::Scope context_scope(context); | |
177 | |
178 // Call notification listeners on the element. | |
179 v8::Local<v8::Object> element_handle = elements_.GetOrCreate(target); | |
180 if (element_handle.IsEmpty()) | |
181 return; | |
182 | |
183 WebAXObjectProxy* element; | |
184 bool result = gin::ConvertFromV8(isolate, element_handle, &element); | |
185 DCHECK(result); | |
186 element->NotificationReceived(frame, notification_name); | |
187 | |
188 if (notification_callback_.IsEmpty()) | |
189 return; | |
190 | |
191 // Call global notification listeners. | |
192 v8::Local<v8::Value> argv[] = { | |
193 element_handle, | |
194 v8::String::NewFromUtf8(isolate, notification_name.data(), | |
195 v8::String::kNormalString, | |
196 notification_name.size()), | |
197 }; | |
198 frame->callFunctionEvenIfScriptDisabled( | |
199 v8::Local<v8::Function>::New(isolate, notification_callback_), | |
200 context->Global(), | |
201 arraysize(argv), | |
202 argv); | |
203 } | |
204 | |
205 void AccessibilityController::LogAccessibilityEvents() { | |
206 log_accessibility_events_ = true; | |
207 } | |
208 | |
209 void AccessibilityController::SetNotificationListener( | |
210 v8::Local<v8::Function> callback) { | |
211 v8::Isolate* isolate = blink::mainThreadIsolate(); | |
212 notification_callback_.Reset(isolate, callback); | |
213 } | |
214 | |
215 void AccessibilityController::UnsetNotificationListener() { | |
216 notification_callback_.Reset(); | |
217 } | |
218 | |
219 v8::Local<v8::Object> AccessibilityController::FocusedElement() { | |
220 blink::WebFrame* frame = web_view()->mainFrame(); | |
221 if (!frame) | |
222 return v8::Local<v8::Object>(); | |
223 | |
224 blink::WebAXObject focused_element = | |
225 frame->document().focusedAccessibilityObject(); | |
226 if (focused_element.isNull()) | |
227 focused_element = web_view()->accessibilityObject(); | |
228 return elements_.GetOrCreate(focused_element); | |
229 } | |
230 | |
231 v8::Local<v8::Object> AccessibilityController::RootElement() { | |
232 blink::WebAXObject root_element = web_view()->accessibilityObject(); | |
233 return elements_.GetOrCreate(root_element); | |
234 } | |
235 | |
236 v8::Local<v8::Object> | |
237 AccessibilityController::AccessibleElementById(const std::string& id) { | |
238 blink::WebAXObject root_element = web_view()->accessibilityObject(); | |
239 | |
240 if (!root_element.updateLayoutAndCheckValidity()) | |
241 return v8::Local<v8::Object>(); | |
242 | |
243 return FindAccessibleElementByIdRecursive( | |
244 root_element, blink::WebString::fromUTF8(id.c_str())); | |
245 } | |
246 | |
247 v8::Local<v8::Object> | |
248 AccessibilityController::FindAccessibleElementByIdRecursive( | |
249 const blink::WebAXObject& obj, const blink::WebString& id) { | |
250 if (obj.isNull() || obj.isDetached()) | |
251 return v8::Local<v8::Object>(); | |
252 | |
253 blink::WebNode node = obj.node(); | |
254 if (!node.isNull() && node.isElementNode()) { | |
255 blink::WebElement element = node.to<blink::WebElement>(); | |
256 element.getAttribute("id"); | |
257 if (element.getAttribute("id") == id) | |
258 return elements_.GetOrCreate(obj); | |
259 } | |
260 | |
261 unsigned childCount = obj.childCount(); | |
262 for (unsigned i = 0; i < childCount; i++) { | |
263 v8::Local<v8::Object> result = | |
264 FindAccessibleElementByIdRecursive(obj.childAt(i), id); | |
265 if (*result) | |
266 return result; | |
267 } | |
268 | |
269 return v8::Local<v8::Object>(); | |
270 } | |
271 | |
272 blink::WebView* AccessibilityController::web_view() { | |
273 return web_view_test_proxy_base_->web_view(); | |
274 } | |
275 | |
276 } // namespace test_runner | |
OLD | NEW |