Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(443)

Side by Side Diff: chrome/renderer/extensions/automation_internal_custom_bindings.cc

Issue 1155183006: Reimplement automation API on top of C++-backed AXTree. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@automation_faster_2
Patch Set: Copy observers Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/renderer/extensions/automation_internal_custom_bindings.h" 5 #include "chrome/renderer/extensions/automation_internal_custom_bindings.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/memory/scoped_ptr.h" 8 #include "base/memory/scoped_ptr.h"
9 #include "base/values.h" 9 #include "base/values.h"
10 #include "chrome/common/extensions/chrome_extension_messages.h" 10 #include "chrome/common/extensions/chrome_extension_messages.h"
11 #include "chrome/common/extensions/manifest_handlers/automation.h" 11 #include "chrome/common/extensions/manifest_handlers/automation.h"
12 #include "content/public/child/v8_value_converter.h"
13 #include "content/public/renderer/render_thread.h" 12 #include "content/public/renderer/render_thread.h"
14 #include "content/public/renderer/render_view.h" 13 #include "content/public/renderer/render_view.h"
15 #include "extensions/common/extension.h" 14 #include "extensions/common/extension.h"
16 #include "extensions/common/manifest.h" 15 #include "extensions/common/manifest.h"
17 #include "extensions/renderer/script_context.h" 16 #include "extensions/renderer/script_context.h"
18 #include "ipc/message_filter.h" 17 #include "ipc/message_filter.h"
19 #include "ui/accessibility/ax_enums.h" 18 #include "ui/accessibility/ax_enums.h"
20 #include "ui/accessibility/ax_node.h" 19 #include "ui/accessibility/ax_node.h"
21 20
22 namespace { 21 namespace {
23 22
24 // Helper to convert an enum to a V8 object. 23 // Helper to convert an enum to a V8 object.
25 template <typename EnumType> 24 template <typename EnumType>
26 v8::Local<v8::Object> ToEnumObject(v8::Isolate* isolate, 25 v8::Local<v8::Object> ToEnumObject(v8::Isolate* isolate,
27 EnumType start_after, 26 EnumType start_after,
28 EnumType end_at) { 27 EnumType end_at) {
29 v8::Local<v8::Object> object = v8::Object::New(isolate); 28 v8::Local<v8::Object> object = v8::Object::New(isolate);
30 for (int i = start_after + 1; i <= end_at; ++i) { 29 for (int i = start_after + 1; i <= end_at; ++i) {
31 v8::Local<v8::String> value = v8::String::NewFromUtf8( 30 v8::Local<v8::String> value = v8::String::NewFromUtf8(
32 isolate, ui::ToString(static_cast<EnumType>(i)).c_str()); 31 isolate, ui::ToString(static_cast<EnumType>(i)).c_str());
33 object->Set(value, value); 32 object->Set(value, value);
34 } 33 }
35 return object; 34 return object;
36 } 35 }
37 36
38 } // namespace 37 } // namespace
39 38
40 namespace extensions { 39 namespace extensions {
41 40
41 TreeCache::TreeCache() {}
42 TreeCache::~TreeCache() {}
43
42 class AutomationMessageFilter : public IPC::MessageFilter { 44 class AutomationMessageFilter : public IPC::MessageFilter {
43 public: 45 public:
44 explicit AutomationMessageFilter(AutomationInternalCustomBindings* owner) 46 explicit AutomationMessageFilter(AutomationInternalCustomBindings* owner)
45 : owner_(owner), 47 : owner_(owner),
46 removed_(false) { 48 removed_(false) {
47 DCHECK(owner); 49 DCHECK(owner);
48 content::RenderThread::Get()->AddFilter(this); 50 content::RenderThread::Get()->AddFilter(this);
51 task_runner_ = content::RenderThread::Get()->GetTaskRunner();
49 } 52 }
50 53
51 void Detach() { 54 void Detach() {
52 owner_ = nullptr; 55 owner_ = nullptr;
53 Remove(); 56 Remove();
54 } 57 }
55 58
56 // IPC::MessageFilter 59 // IPC::MessageFilter
57 bool OnMessageReceived(const IPC::Message& message) override { 60 bool OnMessageReceived(const IPC::Message& message) override {
58 if (owner_) 61 task_runner_->PostTask(
59 return owner_->OnMessageReceived(message); 62 FROM_HERE,
60 else 63 base::Bind(
61 return false; 64 &AutomationMessageFilter::OnMessageReceivedOnRenderThread,
65 this, message));
66
67 // Always return false in case there are multiple
68 // AutomationInternalCustomBindings instances attached to the same thread.
69 return false;
62 } 70 }
63 71
64 void OnFilterRemoved() override { 72 void OnFilterRemoved() override {
65 removed_ = true; 73 removed_ = true;
66 } 74 }
67 75
68 private: 76 private:
77 void OnMessageReceivedOnRenderThread(const IPC::Message& message) {
78 if (owner_)
79 owner_->OnMessageReceived(message);
80 }
81
69 ~AutomationMessageFilter() override { 82 ~AutomationMessageFilter() override {
70 Remove(); 83 Remove();
71 } 84 }
72 85
73 void Remove() { 86 void Remove() {
74 if (!removed_) { 87 if (!removed_) {
75 removed_ = true; 88 removed_ = true;
76 content::RenderThread::Get()->RemoveFilter(this); 89 content::RenderThread::Get()->RemoveFilter(this);
77 } 90 }
78 } 91 }
79 92
80 AutomationInternalCustomBindings* owner_; 93 AutomationInternalCustomBindings* owner_;
81 bool removed_; 94 bool removed_;
95 scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
82 96
83 DISALLOW_COPY_AND_ASSIGN(AutomationMessageFilter); 97 DISALLOW_COPY_AND_ASSIGN(AutomationMessageFilter);
84 }; 98 };
85 99
86 AutomationInternalCustomBindings::AutomationInternalCustomBindings( 100 AutomationInternalCustomBindings::AutomationInternalCustomBindings(
87 ScriptContext* context) : ObjectBackedNativeHandler(context) { 101 ScriptContext* context) : ObjectBackedNativeHandler(context) {
88 // It's safe to use base::Unretained(this) here because these bindings 102 // It's safe to use base::Unretained(this) here because these bindings
89 // will only be called on a valid AutomationInternalCustomBindings instance 103 // will only be called on a valid AutomationInternalCustomBindings instance
90 // and none of the functions have any side effects. 104 // and none of the functions have any side effects.
91 RouteFunction( 105 #define ROUTE_FUNCTION(FN) \
92 "IsInteractPermitted", 106 RouteFunction(#FN, \
93 base::Bind(&AutomationInternalCustomBindings::IsInteractPermitted, 107 base::Bind(&AutomationInternalCustomBindings::FN, \
94 base::Unretained(this))); 108 base::Unretained(this)))
95 RouteFunction(
96 "GetSchemaAdditions",
97 base::Bind(&AutomationInternalCustomBindings::GetSchemaAdditions,
98 base::Unretained(this)));
99 RouteFunction(
100 "GetRoutingID",
101 base::Bind(&AutomationInternalCustomBindings::GetRoutingID,
102 base::Unretained(this)));
103 109
104 message_filter_ = new AutomationMessageFilter(this); 110 ROUTE_FUNCTION(IsInteractPermitted);
111 ROUTE_FUNCTION(GetSchemaAdditions);
112 ROUTE_FUNCTION(GetRoutingID);
113 ROUTE_FUNCTION(StartCachingAccessibilityTrees);
114 ROUTE_FUNCTION(DestroyAccessibilityTree);
115 ROUTE_FUNCTION(GetRootID);
116 ROUTE_FUNCTION(GetParentID);
117 ROUTE_FUNCTION(GetChildCount);
118 ROUTE_FUNCTION(GetChildIDAtIndex);
119 ROUTE_FUNCTION(GetIndexInParent);
120 ROUTE_FUNCTION(GetState);
121 ROUTE_FUNCTION(GetRole);
122 ROUTE_FUNCTION(GetLocation);
123 ROUTE_FUNCTION(GetStringAttribute);
124 ROUTE_FUNCTION(GetBoolAttribute);
125 ROUTE_FUNCTION(GetIntAttribute);
126 ROUTE_FUNCTION(GetFloatAttribute);
127 ROUTE_FUNCTION(GetIntListAttribute);
128 ROUTE_FUNCTION(GetHtmlAttribute);
129
130 #undef ROUTE_FUNCTION
105 } 131 }
106 132
107 AutomationInternalCustomBindings::~AutomationInternalCustomBindings() { 133 AutomationInternalCustomBindings::~AutomationInternalCustomBindings() {
108 message_filter_->Detach(); 134 if (message_filter_)
135 message_filter_->Detach();
136 STLDeleteContainerPairSecondPointers(tree_id_to_tree_cache_map_.begin(),
137 tree_id_to_tree_cache_map_.end());
109 } 138 }
110 139
111 bool AutomationInternalCustomBindings::OnMessageReceived( 140 void AutomationInternalCustomBindings::OnMessageReceived(
112 const IPC::Message& message) { 141 const IPC::Message& message) {
113 IPC_BEGIN_MESSAGE_MAP(AutomationInternalCustomBindings, message) 142 IPC_BEGIN_MESSAGE_MAP(AutomationInternalCustomBindings, message)
114 IPC_MESSAGE_HANDLER(ExtensionMsg_AccessibilityEvent, OnAccessibilityEvent) 143 IPC_MESSAGE_HANDLER(ExtensionMsg_AccessibilityEvent, OnAccessibilityEvent)
115 IPC_END_MESSAGE_MAP() 144 IPC_END_MESSAGE_MAP()
116
117 // Always return false in case there are multiple
118 // AutomationInternalCustomBindings instances attached to the same thread.
119 return false;
120 } 145 }
121 146
122 void AutomationInternalCustomBindings::IsInteractPermitted( 147 void AutomationInternalCustomBindings::IsInteractPermitted(
123 const v8::FunctionCallbackInfo<v8::Value>& args) { 148 const v8::FunctionCallbackInfo<v8::Value>& args) {
124 const Extension* extension = context()->extension(); 149 const Extension* extension = context()->extension();
125 CHECK(extension); 150 CHECK(extension);
126 const AutomationInfo* automation_info = AutomationInfo::Get(extension); 151 const AutomationInfo* automation_info = AutomationInfo::Get(extension);
127 CHECK(automation_info); 152 CHECK(automation_info);
128 args.GetReturnValue().Set( 153 args.GetReturnValue().Set(
129 v8::Boolean::New(GetIsolate(), automation_info->interact)); 154 v8::Boolean::New(GetIsolate(), automation_info->interact));
130 } 155 }
131 156
132 void AutomationInternalCustomBindings::GetRoutingID( 157 void AutomationInternalCustomBindings::GetRoutingID(
133 const v8::FunctionCallbackInfo<v8::Value>& args) { 158 const v8::FunctionCallbackInfo<v8::Value>& args) {
134 int routing_id = context()->GetRenderView()->GetRoutingID(); 159 int routing_id = context()->GetRenderView()->GetRoutingID();
135 args.GetReturnValue().Set(v8::Integer::New(GetIsolate(), routing_id)); 160 args.GetReturnValue().Set(v8::Integer::New(GetIsolate(), routing_id));
136 } 161 }
137 162
163 void AutomationInternalCustomBindings::StartCachingAccessibilityTrees(
164 const v8::FunctionCallbackInfo<v8::Value>& args) {
165 if (!message_filter_)
166 message_filter_ = new AutomationMessageFilter(this);
167 }
168
138 void AutomationInternalCustomBindings::GetSchemaAdditions( 169 void AutomationInternalCustomBindings::GetSchemaAdditions(
139 const v8::FunctionCallbackInfo<v8::Value>& args) { 170 const v8::FunctionCallbackInfo<v8::Value>& args) {
140 v8::Local<v8::Object> additions = v8::Object::New(GetIsolate()); 171 v8::Local<v8::Object> additions = v8::Object::New(GetIsolate());
141 172
142 additions->Set( 173 additions->Set(
143 v8::String::NewFromUtf8(GetIsolate(), "EventType"), 174 v8::String::NewFromUtf8(GetIsolate(), "EventType"),
144 ToEnumObject(GetIsolate(), ui::AX_EVENT_NONE, ui::AX_EVENT_LAST)); 175 ToEnumObject(GetIsolate(), ui::AX_EVENT_NONE, ui::AX_EVENT_LAST));
145 176
146 additions->Set( 177 additions->Set(
147 v8::String::NewFromUtf8(GetIsolate(), "RoleType"), 178 v8::String::NewFromUtf8(GetIsolate(), "RoleType"),
148 ToEnumObject(GetIsolate(), ui::AX_ROLE_NONE, ui::AX_ROLE_LAST)); 179 ToEnumObject(GetIsolate(), ui::AX_ROLE_NONE, ui::AX_ROLE_LAST));
149 180
150 additions->Set( 181 additions->Set(
151 v8::String::NewFromUtf8(GetIsolate(), "StateType"), 182 v8::String::NewFromUtf8(GetIsolate(), "StateType"),
152 ToEnumObject(GetIsolate(), ui::AX_STATE_NONE, ui::AX_STATE_LAST)); 183 ToEnumObject(GetIsolate(), ui::AX_STATE_NONE, ui::AX_STATE_LAST));
153 184
154 additions->Set( 185 additions->Set(
155 v8::String::NewFromUtf8(GetIsolate(), "TreeChangeType"), 186 v8::String::NewFromUtf8(GetIsolate(), "TreeChangeType"),
156 ToEnumObject(GetIsolate(), ui::AX_MUTATION_NONE, ui::AX_MUTATION_LAST)); 187 ToEnumObject(GetIsolate(), ui::AX_MUTATION_NONE, ui::AX_MUTATION_LAST));
157 188
158 args.GetReturnValue().Set(additions); 189 args.GetReturnValue().Set(additions);
159 } 190 }
160 191
192 void AutomationInternalCustomBindings::DestroyAccessibilityTree(
193 const v8::FunctionCallbackInfo<v8::Value>& args) {
194 if (args.Length() != 1 || !args[0]->IsNumber()) {
195 ThrowInvalidArgumentsException(args);
196 return;
197 }
198
199 int tree_id = args[0]->Int32Value();
200 auto iter = tree_id_to_tree_cache_map_.find(tree_id);
201 if (iter == tree_id_to_tree_cache_map_.end())
202 return;
203
204 TreeCache* cache = iter->second;
205 tree_id_to_tree_cache_map_.erase(tree_id);
206 axtree_to_tree_cache_map_.erase(&cache->tree);
207 delete cache;
208 }
209
210 //
211 // Access the cached accessibility trees and properties of their nodes.
212 //
213
214 void AutomationInternalCustomBindings::GetRootID(
215 const v8::FunctionCallbackInfo<v8::Value>& args) {
216 if (args.Length() != 1 || !args[0]->IsNumber()) {
217 ThrowInvalidArgumentsException(args);
218 return;
219 }
220
221 int tree_id = args[0]->Int32Value();
222 const auto iter = tree_id_to_tree_cache_map_.find(tree_id);
223 if (iter == tree_id_to_tree_cache_map_.end())
224 return;
225
226 TreeCache* cache = iter->second;
227 int root_id = cache->tree.root()->id();
228 args.GetReturnValue().Set(v8::Integer::New(GetIsolate(), root_id));
229 }
230
231 void AutomationInternalCustomBindings::GetParentID(
232 const v8::FunctionCallbackInfo<v8::Value>& args) {
233 ui::AXNode* node = nullptr;
234 if (!GetNodeHelper(args, nullptr, &node))
235 return;
236
237 if (!node->parent())
238 return;
239
240 int parent_id = node->parent()->id();
241 args.GetReturnValue().Set(v8::Integer::New(GetIsolate(), parent_id));
242 }
243
244 void AutomationInternalCustomBindings::GetChildCount(
245 const v8::FunctionCallbackInfo<v8::Value>& args) {
246 ui::AXNode* node = nullptr;
247 if (!GetNodeHelper(args, nullptr, &node))
248 return;
249
250 int child_count = node->child_count();
251 args.GetReturnValue().Set(v8::Integer::New(GetIsolate(), child_count));
252 }
253
254 void AutomationInternalCustomBindings::GetChildIDAtIndex(
255 const v8::FunctionCallbackInfo<v8::Value>& args) {
256 if (args.Length() < 3 || !args[2]->IsNumber()) {
257 ThrowInvalidArgumentsException(args);
258 return;
259 }
260
261 ui::AXNode* node = nullptr;
262 if (!GetNodeHelper(args, nullptr, &node))
263 return;
264
265 int index = args[2]->Int32Value();
266 if (index < 0 || index >= node->child_count())
267 return;
268
269 int child_id = node->children()[index]->id();
270 args.GetReturnValue().Set(v8::Integer::New(GetIsolate(), child_id));
271 }
272
273 void AutomationInternalCustomBindings::GetIndexInParent(
274 const v8::FunctionCallbackInfo<v8::Value>& args) {
275 ui::AXNode* node = nullptr;
276 if (!GetNodeHelper(args, nullptr, &node))
277 return;
278
279 int index_in_parent = node->index_in_parent();
280 args.GetReturnValue().Set(v8::Integer::New(GetIsolate(), index_in_parent));
281 }
282
283 void AutomationInternalCustomBindings::GetState(
284 const v8::FunctionCallbackInfo<v8::Value>& args) {
285 ui::AXNode* node = nullptr;
286 if (!GetNodeHelper(args, nullptr, &node))
287 return;
288
289 v8::Local<v8::Object> state(v8::Object::New(GetIsolate()));
290 uint32 state_pos = 0, state_shifter = node->data().state;
291 while (state_shifter) {
292 if (state_shifter & 1) {
293 std::string key = ToString(static_cast<ui::AXState>(state_pos));
294 state->Set(CreateV8String(key),
295 v8::Boolean::New(GetIsolate(), true));
296 }
297 state_shifter = state_shifter >> 1;
298 state_pos++;
299 }
300
301 args.GetReturnValue().Set(state);
302 }
303
304 void AutomationInternalCustomBindings::GetRole(
305 const v8::FunctionCallbackInfo<v8::Value>& args) {
306 ui::AXNode* node = nullptr;
307 if (!GetNodeHelper(args, nullptr, &node))
308 return;
309
310 std::string role_name = ui::ToString(node->data().role);
311 args.GetReturnValue().Set(
312 v8::String::NewFromUtf8(GetIsolate(), role_name.c_str()));
313 }
314
315 void AutomationInternalCustomBindings::GetLocation(
316 const v8::FunctionCallbackInfo<v8::Value>& args) {
317 TreeCache* cache;
318 ui::AXNode* node = nullptr;
319 if (!GetNodeHelper(args, &cache, &node))
320 return;
321
322 v8::Local<v8::Object> location_obj(v8::Object::New(GetIsolate()));
323 gfx::Rect location = node->data().location;
324 location.Offset(cache->location_offset);
325 location_obj->Set(CreateV8String("left"),
326 v8::Integer::New(GetIsolate(), location.x()));
327 location_obj->Set(CreateV8String("top"),
328 v8::Integer::New(GetIsolate(), location.y()));
329 location_obj->Set(CreateV8String("width"),
330 v8::Integer::New(GetIsolate(), location.width()));
331 location_obj->Set(CreateV8String("height"),
332 v8::Integer::New(GetIsolate(), location.height()));
333 args.GetReturnValue().Set(location_obj);
334 }
335
336 void AutomationInternalCustomBindings::GetStringAttribute(
337 const v8::FunctionCallbackInfo<v8::Value>& args) {
338 ui::AXNode* node = nullptr;
339 std::string attribute_name;
340 if (!GetAttributeHelper(args, &node, &attribute_name))
341 return;
342
343 ui::AXStringAttribute attribute = ui::ParseAXStringAttribute(attribute_name);
344 std::string attr_value;
345 if (!node->data().GetStringAttribute(attribute, &attr_value))
346 return;
347
348 args.GetReturnValue().Set(
349 v8::String::NewFromUtf8(GetIsolate(), attr_value.c_str()));
350 }
351
352 void AutomationInternalCustomBindings::GetBoolAttribute(
353 const v8::FunctionCallbackInfo<v8::Value>& args) {
354 ui::AXNode* node = nullptr;
355 std::string attribute_name;
356 if (!GetAttributeHelper(args, &node, &attribute_name))
357 return;
358
359 ui::AXBoolAttribute attribute = ui::ParseAXBoolAttribute(attribute_name);
360 bool attr_value;
361 if (!node->data().GetBoolAttribute(attribute, &attr_value))
362 return;
363
364 args.GetReturnValue().Set(v8::Boolean::New(GetIsolate(), attr_value));
365 }
366
367 void AutomationInternalCustomBindings::GetIntAttribute(
368 const v8::FunctionCallbackInfo<v8::Value>& args) {
369 ui::AXNode* node = nullptr;
370 std::string attribute_name;
371 if (!GetAttributeHelper(args, &node, &attribute_name))
372 return;
373
374 ui::AXIntAttribute attribute = ui::ParseAXIntAttribute(attribute_name);
375 int attr_value;
376 if (!node->data().GetIntAttribute(attribute, &attr_value))
377 return;
378
379 args.GetReturnValue().Set(v8::Integer::New(GetIsolate(), attr_value));
380 }
381
382 void AutomationInternalCustomBindings::GetFloatAttribute(
383 const v8::FunctionCallbackInfo<v8::Value>& args) {
384 ui::AXNode* node = nullptr;
385 std::string attribute_name;
386 if (!GetAttributeHelper(args, &node, &attribute_name))
387 return;
388
389 ui::AXFloatAttribute attribute = ui::ParseAXFloatAttribute(attribute_name);
390 float attr_value;
391
392 if (!node->data().GetFloatAttribute(attribute, &attr_value))
393 return;
394
395 args.GetReturnValue().Set(v8::Number::New(GetIsolate(), attr_value));
396 }
397
398 void AutomationInternalCustomBindings::GetIntListAttribute(
399 const v8::FunctionCallbackInfo<v8::Value>& args) {
400 ui::AXNode* node = nullptr;
401 std::string attribute_name;
402 if (!GetAttributeHelper(args, &node, &attribute_name))
403 return;
404
405 ui::AXIntListAttribute attribute =
406 ui::ParseAXIntListAttribute(attribute_name);
407 if (!node->data().HasIntListAttribute(attribute))
408 return;
409 const std::vector<int32>& attr_value =
410 node->data().GetIntListAttribute(attribute);
411
412 v8::Local<v8::Array> result(v8::Array::New(GetIsolate(), attr_value.size()));
413 for (size_t i = 0; i < attr_value.size(); ++i)
414 result->Set(static_cast<uint32>(i),
415 v8::Integer::New(GetIsolate(), attr_value[i]));
416 args.GetReturnValue().Set(result);
417 }
418
419 void AutomationInternalCustomBindings::GetHtmlAttribute(
420 const v8::FunctionCallbackInfo<v8::Value>& args) {
421 ui::AXNode* node = nullptr;
422 std::string attribute_name;
423 if (!GetAttributeHelper(args, &node, &attribute_name))
424 return;
425
426 std::string attr_value;
427 if (!node->data().GetHtmlAttribute(attribute_name.c_str(), &attr_value))
428 return;
429
430 args.GetReturnValue().Set(
431 v8::String::NewFromUtf8(GetIsolate(), attr_value.c_str()));
432 }
433
434 //
435 // Helper functions.
436 //
437
438 void AutomationInternalCustomBindings::ThrowInvalidArgumentsException(
439 const v8::FunctionCallbackInfo<v8::Value>& args) {
440 GetIsolate()->ThrowException(
441 v8::String::NewFromUtf8(
442 GetIsolate(),
443 "Invalid arguments to AutomationInternalCustomBindings function",
444 v8::NewStringType::kNormal).ToLocalChecked());
445
446 LOG(FATAL)
447 << "Invalid arguments to AutomationInternalCustomBindings function"
448 << context()->GetStackTraceAsString();
449 }
450
451 bool AutomationInternalCustomBindings::GetNodeHelper(
452 const v8::FunctionCallbackInfo<v8::Value>& args,
453 TreeCache** out_cache,
454 ui::AXNode** out_node) {
455 if (args.Length() < 2 || !args[0]->IsNumber() || !args[1]->IsNumber()) {
456 ThrowInvalidArgumentsException(args);
457 return false;
458 }
459
460 int tree_id = args[0]->Int32Value();
461 int node_id = args[1]->Int32Value();
462
463 const auto iter = tree_id_to_tree_cache_map_.find(tree_id);
464 if (iter == tree_id_to_tree_cache_map_.end())
465 return false;
466
467 TreeCache* cache = iter->second;
468 ui::AXNode* node = cache->tree.GetFromId(node_id);
469
470 if (out_cache)
471 *out_cache = cache;
472 if (out_node)
473 *out_node = node;
474
475 return node != nullptr;
476 }
477
478 bool AutomationInternalCustomBindings::GetAttributeHelper(
479 const v8::FunctionCallbackInfo<v8::Value>& args,
480 ui::AXNode** out_node,
481 std::string* out_attribute_name) {
482 if (args.Length() != 3 ||
483 !args[2]->IsString()) {
484 ThrowInvalidArgumentsException(args);
485 return false;
486 }
487
488 TreeCache* cache = nullptr;
489 if (!GetNodeHelper(args, &cache, out_node))
490 return false;
491
492 *out_attribute_name = *v8::String::Utf8Value(args[2]);
493 return true;
494 }
495
496 v8::Local<v8::Value> AutomationInternalCustomBindings::CreateV8String(
497 const char* str) {
498 return v8::String::NewFromUtf8(
499 GetIsolate(), str, v8::String::kNormalString, strlen(str));
500 }
501
502 v8::Local<v8::Value> AutomationInternalCustomBindings::CreateV8String(
503 const std::string& str) {
504 return v8::String::NewFromUtf8(
505 GetIsolate(), str.c_str(), v8::String::kNormalString, str.length());
506 }
507
508 //
509 // Handle accessibility events from the browser process.
510 //
511
161 void AutomationInternalCustomBindings::OnAccessibilityEvent( 512 void AutomationInternalCustomBindings::OnAccessibilityEvent(
162 const ExtensionMsg_AccessibilityEventParams& params) { 513 const ExtensionMsg_AccessibilityEventParams& params) {
163 // TODO(dmazzoni): finish implementing this. 514 int tree_id = params.tree_id;
515 TreeCache* cache;
516 auto iter = tree_id_to_tree_cache_map_.find(tree_id);
517 if (iter == tree_id_to_tree_cache_map_.end()) {
518 cache = new TreeCache();
519 cache->tab_id = -1;
520 cache->tree_id = params.tree_id;
521 cache->tree.SetDelegate(this);
522 tree_id_to_tree_cache_map_.insert(std::make_pair(tree_id, cache));
523 axtree_to_tree_cache_map_.insert(std::make_pair(&cache->tree, cache));
524 } else {
525 cache = iter->second;
526 }
527
528 cache->location_offset = params.location_offset;
529 if (!cache->tree.Unserialize(params.update)) {
530 LOG(FATAL) << cache->tree.error();
531 return;
532 }
533
534 v8::HandleScope handle_scope(GetIsolate());
535 v8::Context::Scope context_scope(context()->v8_context());
536 v8::Local<v8::Array> args(v8::Array::New(GetIsolate(), 1U));
537 v8::Local<v8::Object> event_params(v8::Object::New(GetIsolate()));
538 event_params->Set(CreateV8String("treeID"),
539 v8::Integer::New(GetIsolate(), params.tree_id));
540 event_params->Set(CreateV8String("targetID"),
541 v8::Integer::New(GetIsolate(), params.id));
542 event_params->Set(CreateV8String("eventType"),
543 CreateV8String(ToString(params.event_type)));
544 args->Set(0U, event_params);
545 context()->DispatchEvent("automationInternal.onAccessibilityEvent", args);
546 }
547
548 void AutomationInternalCustomBindings::OnNodeWillBeDeleted(ui::AXTree* tree,
549 ui::AXNode* node) {
550 SendTreeChangeEvent(
551 api::automation::TREE_CHANGE_TYPE_NODEREMOVED,
552 tree, node);
553 }
554
555 void AutomationInternalCustomBindings::OnSubtreeWillBeDeleted(
556 ui::AXTree* tree,
557 ui::AXNode* node) {
558 // This isn't strictly needed, as OnNodeWillBeDeleted will already be
559 // called. We could send a JS event for this only if it turns out to
560 // be needed for something.
561 }
562
563 void AutomationInternalCustomBindings::OnNodeCreated(ui::AXTree* tree,
564 ui::AXNode* node) {
565 // Not needed, this is called in the middle of an update so it's not
566 // safe to trigger JS from here. Wait for the notification in
567 // OnAtomicUpdateFinished instead.
568 }
569
570 void AutomationInternalCustomBindings::OnNodeChanged(ui::AXTree* tree,
571 ui::AXNode* node) {
572 // Not needed, this is called in the middle of an update so it's not
573 // safe to trigger JS from here. Wait for the notification in
574 // OnAtomicUpdateFinished instead.
575 }
576
577 void AutomationInternalCustomBindings::OnAtomicUpdateFinished(
578 ui::AXTree* tree,
579 bool root_changed,
580 const std::vector<ui::AXTreeDelegate::Change>& changes) {
581 auto iter = axtree_to_tree_cache_map_.find(tree);
582 if (iter == axtree_to_tree_cache_map_.end())
583 return;
584
585 for (auto change : changes) {
586 ui::AXNode* node = change.node;
587 switch (change.type) {
588 case NODE_CREATED:
589 SendTreeChangeEvent(
590 api::automation::TREE_CHANGE_TYPE_NODECREATED,
591 tree, node);
592 break;
593 case SUBTREE_CREATED:
594 SendTreeChangeEvent(
595 api::automation::TREE_CHANGE_TYPE_SUBTREECREATED,
596 tree, node);
597 break;
598 case NODE_CHANGED:
599 SendTreeChangeEvent(
600 api::automation::TREE_CHANGE_TYPE_NODECHANGED,
601 tree, node);
602 break;
603 }
604 }
605 }
606
607 void AutomationInternalCustomBindings::SendTreeChangeEvent(
608 api::automation::TreeChangeType change_type,
609 ui::AXTree* tree,
610 ui::AXNode* node) {
611 auto iter = axtree_to_tree_cache_map_.find(tree);
612 if (iter == axtree_to_tree_cache_map_.end())
613 return;
614
615 int tree_id = iter->second->tree_id;
616
617 v8::HandleScope handle_scope(GetIsolate());
618 v8::Context::Scope context_scope(context()->v8_context());
619 v8::Local<v8::Array> args(v8::Array::New(GetIsolate(), 3U));
620 args->Set(0U, v8::Integer::New(GetIsolate(), tree_id));
621 args->Set(1U, v8::Integer::New(GetIsolate(), node->id()));
622 args->Set(2U, CreateV8String(ToString(change_type)));
623 context()->DispatchEvent("automationInternal.onTreeChange", args);
164 } 624 }
165 625
166 } // namespace extensions 626 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698