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.
5 #include "content/shell/renderer/test_runner/accessibility_controller.h"
7 #include "gin/handle.h"
8 #include "gin/object_template_builder.h"
9 #include "gin/wrappable.h"
10 #include "third_party/WebKit/public/web/WebElement.h"
11 #include "third_party/WebKit/public/web/WebFrame.h"
12 #include "third_party/WebKit/public/web/WebKit.h"
13 #include "third_party/WebKit/public/web/WebView.h"
17 class AccessibilityControllerBindings
18 : public gin::Wrappable<AccessibilityControllerBindings> {
20 static gin::WrapperInfo kWrapperInfo;
22 static void Install(base::WeakPtr<AccessibilityController> controller,
23 blink::WebFrame* frame);
26 explicit AccessibilityControllerBindings(
27 base::WeakPtr<AccessibilityController> controller);
28 virtual ~AccessibilityControllerBindings();
31 virtual gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
32 v8::Isolate* isolate) OVERRIDE;
34 void LogAccessibilityEvents();
35 void SetNotificationListener(v8::Handle<v8::Function> callback);
36 void UnsetNotificationListener();
37 v8::Handle<v8::Object> FocusedElement();
38 v8::Handle<v8::Object> RootElement();
39 v8::Handle<v8::Object> AccessibleElementById(const std::string& id);
41 base::WeakPtr<AccessibilityController> controller_;
43 DISALLOW_COPY_AND_ASSIGN(AccessibilityControllerBindings);
46 gin::WrapperInfo AccessibilityControllerBindings::kWrapperInfo = {
47 gin::kEmbedderNativeGin};
50 void AccessibilityControllerBindings::Install(
51 base::WeakPtr<AccessibilityController> controller,
52 blink::WebFrame* frame) {
53 v8::Isolate* isolate = blink::mainThreadIsolate();
54 v8::HandleScope handle_scope(isolate);
55 v8::Handle<v8::Context> context = frame->mainWorldScriptContext();
56 if (context.IsEmpty())
59 v8::Context::Scope context_scope(context);
61 gin::Handle<AccessibilityControllerBindings> bindings =
62 gin::CreateHandle(isolate,
63 new AccessibilityControllerBindings(controller));
64 if (bindings.IsEmpty())
66 v8::Handle<v8::Object> global = context->Global();
67 global->Set(gin::StringToV8(isolate, "accessibilityController"),
71 AccessibilityControllerBindings::AccessibilityControllerBindings(
72 base::WeakPtr<AccessibilityController> controller)
73 : controller_(controller) {
76 AccessibilityControllerBindings::~AccessibilityControllerBindings() {
79 gin::ObjectTemplateBuilder
80 AccessibilityControllerBindings::GetObjectTemplateBuilder(
81 v8::Isolate* isolate) {
82 return gin::Wrappable<AccessibilityControllerBindings>::
83 GetObjectTemplateBuilder(isolate)
84 .SetMethod("logAccessibilityEvents",
85 &AccessibilityControllerBindings::LogAccessibilityEvents)
86 .SetMethod("setNotificationListener",
87 &AccessibilityControllerBindings::SetNotificationListener)
88 .SetMethod("unsetNotificationListener",
89 &AccessibilityControllerBindings::UnsetNotificationListener)
90 .SetProperty("focusedElement",
91 &AccessibilityControllerBindings::FocusedElement)
92 .SetProperty("rootElement",
93 &AccessibilityControllerBindings::RootElement)
94 .SetMethod("accessibleElementById",
95 &AccessibilityControllerBindings::AccessibleElementById)
96 // TODO(hajimehoshi): These are for backward compatibility. Remove them.
97 .SetMethod("addNotificationListener",
98 &AccessibilityControllerBindings::SetNotificationListener)
99 .SetMethod("removeNotificationListener",
100 &AccessibilityControllerBindings::UnsetNotificationListener);
103 void AccessibilityControllerBindings::LogAccessibilityEvents() {
105 controller_->LogAccessibilityEvents();
108 void AccessibilityControllerBindings::SetNotificationListener(
109 v8::Handle<v8::Function> callback) {
111 controller_->SetNotificationListener(callback);
114 void AccessibilityControllerBindings::UnsetNotificationListener() {
116 controller_->UnsetNotificationListener();
119 v8::Handle<v8::Object> AccessibilityControllerBindings::FocusedElement() {
120 return controller_ ? controller_->FocusedElement() : v8::Handle<v8::Object>();
123 v8::Handle<v8::Object> AccessibilityControllerBindings::RootElement() {
124 return controller_ ? controller_->RootElement() : v8::Handle<v8::Object>();
127 v8::Handle<v8::Object> AccessibilityControllerBindings::AccessibleElementById(
128 const std::string& id) {
129 return controller_ ? controller_->AccessibleElementById(id)
130 : v8::Handle<v8::Object>();
133 AccessibilityController::AccessibilityController()
134 : log_accessibility_events_(false),
135 weak_factory_(this) {
138 AccessibilityController::~AccessibilityController() {}
140 void AccessibilityController::Reset() {
141 root_element_ = blink::WebAXObject();
142 focused_element_ = blink::WebAXObject();
144 notification_callback_.Reset();
145 log_accessibility_events_ = false;
148 void AccessibilityController::Install(blink::WebFrame* frame) {
149 blink::WebAXObject::enableAccessibility();
150 blink::WebAXObject::enableInlineTextBoxAccessibility();
151 AccessibilityControllerBindings::Install(weak_factory_.GetWeakPtr(), frame);
154 void AccessibilityController::SetFocusedElement(
155 const blink::WebAXObject& focused_element) {
156 focused_element_ = focused_element;
159 bool AccessibilityController::ShouldLogAccessibilityEvents() {
160 return log_accessibility_events_;
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);
168 blink::WebFrame* frame = web_view_->mainFrame();
172 v8::Handle<v8::Context> context = frame->mainWorldScriptContext();
173 if (context.IsEmpty())
176 v8::Context::Scope context_scope(context);
178 // Call notification listeners on the element.
179 v8::Handle<v8::Object> element_handle = elements_.GetOrCreate(target);
180 if (element_handle.IsEmpty())
183 WebAXObjectProxy* element;
184 bool result = gin::ConvertFromV8(isolate, element_handle, &element);
186 element->NotificationReceived(frame, notification_name);
188 if (notification_callback_.IsEmpty())
191 // Call global notification listeners.
192 v8::Handle<v8::Value> argv[] = {
194 v8::String::NewFromUtf8(isolate, notification_name.data(),
195 v8::String::kNormalString,
196 notification_name.size()),
198 frame->callFunctionEvenIfScriptDisabled(
199 v8::Local<v8::Function>::New(isolate, notification_callback_),
205 void AccessibilityController::SetDelegate(WebTestDelegate* delegate) {
206 delegate_ = delegate;
209 void AccessibilityController::SetWebView(blink::WebView* web_view) {
210 web_view_ = web_view;
213 void AccessibilityController::LogAccessibilityEvents() {
214 log_accessibility_events_ = true;
217 void AccessibilityController::SetNotificationListener(
218 v8::Handle<v8::Function> callback) {
219 v8::Isolate* isolate = blink::mainThreadIsolate();
220 notification_callback_.Reset(isolate, callback);
223 void AccessibilityController::UnsetNotificationListener() {
224 notification_callback_.Reset();
227 v8::Handle<v8::Object> AccessibilityController::FocusedElement() {
228 if (focused_element_.isNull())
229 focused_element_ = web_view_->accessibilityObject();
230 return elements_.GetOrCreate(focused_element_);
233 v8::Handle<v8::Object> AccessibilityController::RootElement() {
234 if (root_element_.isNull())
235 root_element_ = web_view_->accessibilityObject();
236 return elements_.CreateRoot(root_element_);
239 v8::Handle<v8::Object>
240 AccessibilityController::AccessibleElementById(const std::string& id) {
241 if (root_element_.isNull())
242 root_element_ = web_view_->accessibilityObject();
244 if (!root_element_.updateBackingStoreAndCheckValidity())
245 return v8::Handle<v8::Object>();
247 return FindAccessibleElementByIdRecursive(
248 root_element_, blink::WebString::fromUTF8(id.c_str()));
251 v8::Handle<v8::Object>
252 AccessibilityController::FindAccessibleElementByIdRecursive(
253 const blink::WebAXObject& obj, const blink::WebString& id) {
254 if (obj.isNull() || obj.isDetached())
255 return v8::Handle<v8::Object>();
257 blink::WebNode node = obj.node();
258 if (!node.isNull() && node.isElementNode()) {
259 blink::WebElement element = node.to<blink::WebElement>();
260 element.getAttribute("id");
261 if (element.getAttribute("id") == id)
262 return elements_.GetOrCreate(obj);
265 unsigned childCount = obj.childCount();
266 for (unsigned i = 0; i < childCount; i++) {
267 v8::Handle<v8::Object> result =
268 FindAccessibleElementByIdRecursive(obj.childAt(i), id);
273 return v8::Handle<v8::Object>();
276 } // namespace content