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(
206 WebTestRunner::WebTestDelegate
* delegate
) {
207 delegate_
= delegate
;
210 void AccessibilityController::SetWebView(blink::WebView
* web_view
) {
211 web_view_
= web_view
;
214 void AccessibilityController::LogAccessibilityEvents() {
215 log_accessibility_events_
= true;
218 void AccessibilityController::SetNotificationListener(
219 v8::Handle
<v8::Function
> callback
) {
220 v8::Isolate
* isolate
= blink::mainThreadIsolate();
221 notification_callback_
.Reset(isolate
, callback
);
224 void AccessibilityController::UnsetNotificationListener() {
225 notification_callback_
.Reset();
228 v8::Handle
<v8::Object
> AccessibilityController::FocusedElement() {
229 if (focused_element_
.isNull())
230 focused_element_
= web_view_
->accessibilityObject();
231 return elements_
.GetOrCreate(focused_element_
);
234 v8::Handle
<v8::Object
> AccessibilityController::RootElement() {
235 if (root_element_
.isNull())
236 root_element_
= web_view_
->accessibilityObject();
237 return elements_
.CreateRoot(root_element_
);
240 v8::Handle
<v8::Object
>
241 AccessibilityController::AccessibleElementById(const std::string
& id
) {
242 if (root_element_
.isNull())
243 root_element_
= web_view_
->accessibilityObject();
245 if (!root_element_
.updateBackingStoreAndCheckValidity())
246 return v8::Handle
<v8::Object
>();
248 return FindAccessibleElementByIdRecursive(
249 root_element_
, blink::WebString::fromUTF8(id
.c_str()));
252 v8::Handle
<v8::Object
>
253 AccessibilityController::FindAccessibleElementByIdRecursive(
254 const blink::WebAXObject
& obj
, const blink::WebString
& id
) {
255 if (obj
.isNull() || obj
.isDetached())
256 return v8::Handle
<v8::Object
>();
258 blink::WebNode node
= obj
.node();
259 if (!node
.isNull() && node
.isElementNode()) {
260 blink::WebElement element
= node
.to
<blink::WebElement
>();
261 element
.getAttribute("id");
262 if (element
.getAttribute("id") == id
)
263 return elements_
.GetOrCreate(obj
);
266 unsigned childCount
= obj
.childCount();
267 for (unsigned i
= 0; i
< childCount
; i
++) {
268 v8::Handle
<v8::Object
> result
=
269 FindAccessibleElementByIdRecursive(obj
.childAt(i
), id
);
274 return v8::Handle
<v8::Object
>();
277 } // namespace content