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

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

Powered by Google App Engine
This is Rietveld 408576698