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

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: Add support for input type html attribute 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);
126 ROUTE_FUNCTION(GetHtmlAttribute);
127
128 #undef ROUTE_FUNCTION
105 } 129 }
106 130
107 AutomationInternalCustomBindings::~AutomationInternalCustomBindings() { 131 AutomationInternalCustomBindings::~AutomationInternalCustomBindings() {
108 message_filter_->Detach(); 132 if (message_filter_)
133 message_filter_->Detach();
134 STLDeleteContainerPairSecondPointers(tree_id_to_tree_cache_map_.begin(),
135 tree_id_to_tree_cache_map_.end());
109 } 136 }
110 137
111 bool AutomationInternalCustomBindings::OnMessageReceived( 138 bool AutomationInternalCustomBindings::OnMessageReceived(
112 const IPC::Message& message) { 139 const IPC::Message& message) {
not at google - send to devlin 2015/06/17 21:14:48 1. There doesn't seem much point this method imita
dmazzoni 2015/06/18 07:23:53 Good call, done.
113 IPC_BEGIN_MESSAGE_MAP(AutomationInternalCustomBindings, message) 140 IPC_BEGIN_MESSAGE_MAP(AutomationInternalCustomBindings, message)
114 IPC_MESSAGE_HANDLER(ExtensionMsg_AccessibilityEvent, OnAccessibilityEvent) 141 IPC_MESSAGE_HANDLER(ExtensionMsg_AccessibilityEvent, OnAccessibilityEvent)
115 IPC_END_MESSAGE_MAP() 142 IPC_END_MESSAGE_MAP()
116 143
117 // Always return false in case there are multiple 144 // Always return false in case there are multiple
118 // AutomationInternalCustomBindings instances attached to the same thread. 145 // AutomationInternalCustomBindings instances attached to the same thread.
119 return false; 146 return false;
120 } 147 }
121 148
122 void AutomationInternalCustomBindings::IsInteractPermitted( 149 void AutomationInternalCustomBindings::IsInteractPermitted(
123 const v8::FunctionCallbackInfo<v8::Value>& args) { 150 const v8::FunctionCallbackInfo<v8::Value>& args) {
124 const Extension* extension = context()->extension(); 151 const Extension* extension = context()->extension();
125 CHECK(extension); 152 CHECK(extension);
126 const AutomationInfo* automation_info = AutomationInfo::Get(extension); 153 const AutomationInfo* automation_info = AutomationInfo::Get(extension);
127 CHECK(automation_info); 154 CHECK(automation_info);
128 args.GetReturnValue().Set( 155 args.GetReturnValue().Set(
129 v8::Boolean::New(GetIsolate(), automation_info->interact)); 156 v8::Boolean::New(GetIsolate(), automation_info->interact));
130 } 157 }
131 158
132 void AutomationInternalCustomBindings::GetRoutingID( 159 void AutomationInternalCustomBindings::GetRoutingID(
133 const v8::FunctionCallbackInfo<v8::Value>& args) { 160 const v8::FunctionCallbackInfo<v8::Value>& args) {
134 int routing_id = context()->GetRenderView()->GetRoutingID(); 161 int routing_id = context()->GetRenderView()->GetRoutingID();
135 args.GetReturnValue().Set(v8::Integer::New(GetIsolate(), routing_id)); 162 args.GetReturnValue().Set(v8::Integer::New(GetIsolate(), routing_id));
136 } 163 }
137 164
165 void AutomationInternalCustomBindings::StartCachingAccessibilityTrees(
166 const v8::FunctionCallbackInfo<v8::Value>& args) {
167 if (!message_filter_)
168 message_filter_ = new AutomationMessageFilter(this);
169 }
170
138 void AutomationInternalCustomBindings::GetSchemaAdditions( 171 void AutomationInternalCustomBindings::GetSchemaAdditions(
139 const v8::FunctionCallbackInfo<v8::Value>& args) { 172 const v8::FunctionCallbackInfo<v8::Value>& args) {
140 v8::Local<v8::Object> additions = v8::Object::New(GetIsolate()); 173 v8::Local<v8::Object> additions = v8::Object::New(GetIsolate());
141 174
142 additions->Set( 175 additions->Set(
143 v8::String::NewFromUtf8(GetIsolate(), "EventType"), 176 v8::String::NewFromUtf8(GetIsolate(), "EventType"),
144 ToEnumObject(GetIsolate(), ui::AX_EVENT_NONE, ui::AX_EVENT_LAST)); 177 ToEnumObject(GetIsolate(), ui::AX_EVENT_NONE, ui::AX_EVENT_LAST));
145 178
146 additions->Set( 179 additions->Set(
147 v8::String::NewFromUtf8(GetIsolate(), "RoleType"), 180 v8::String::NewFromUtf8(GetIsolate(), "RoleType"),
148 ToEnumObject(GetIsolate(), ui::AX_ROLE_NONE, ui::AX_ROLE_LAST)); 181 ToEnumObject(GetIsolate(), ui::AX_ROLE_NONE, ui::AX_ROLE_LAST));
149 182
150 additions->Set( 183 additions->Set(
151 v8::String::NewFromUtf8(GetIsolate(), "StateType"), 184 v8::String::NewFromUtf8(GetIsolate(), "StateType"),
152 ToEnumObject(GetIsolate(), ui::AX_STATE_NONE, ui::AX_STATE_LAST)); 185 ToEnumObject(GetIsolate(), ui::AX_STATE_NONE, ui::AX_STATE_LAST));
153 186
154 additions->Set( 187 additions->Set(
155 v8::String::NewFromUtf8(GetIsolate(), "TreeChangeType"), 188 v8::String::NewFromUtf8(GetIsolate(), "TreeChangeType"),
156 ToEnumObject(GetIsolate(), ui::AX_MUTATION_NONE, ui::AX_MUTATION_LAST)); 189 ToEnumObject(GetIsolate(), ui::AX_MUTATION_NONE, ui::AX_MUTATION_LAST));
157 190
158 args.GetReturnValue().Set(additions); 191 args.GetReturnValue().Set(additions);
159 } 192 }
160 193
194 void AutomationInternalCustomBindings::DestroyAccessibilityTree(
195 const v8::FunctionCallbackInfo<v8::Value>& args) {
196 if (args.Length() != 1 || !args[0]->IsNumber()) {
197 ThrowInvalidArgumentsException(args);
198 return;
199 }
200
201 int tree_id = args[0]->Int32Value();
202 auto iter = tree_id_to_tree_cache_map_.find(tree_id);
203 if (iter == tree_id_to_tree_cache_map_.end())
204 return;
205
206 TreeCache* cache = iter->second;
207 tree_id_to_tree_cache_map_.erase(tree_id);
208 axtree_to_tree_cache_map_.erase(&cache->tree);
209 delete cache;
210 }
211
212 //
213 // Access the cached accessibility trees and properties of their nodes.
214 //
215
216 void AutomationInternalCustomBindings::GetRootID(
217 const v8::FunctionCallbackInfo<v8::Value>& args) {
218 if (args.Length() != 1 || !args[0]->IsNumber()) {
219 ThrowInvalidArgumentsException(args);
220 return;
221 }
222
223 int tree_id = args[0]->Int32Value();
224 const auto& iter = tree_id_to_tree_cache_map_.find(tree_id);
not at google - send to devlin 2015/06/17 21:14:47 I think this shouldn't be a const reference, just
dmazzoni 2015/06/18 07:23:53 Done.
225 if (iter == tree_id_to_tree_cache_map_.end())
226 return;
227
228 TreeCache* cache = iter->second;
229 int root_id = cache->tree.root()->id();
230 args.GetReturnValue().Set(v8::Integer::New(GetIsolate(), root_id));
231 }
232
233 void AutomationInternalCustomBindings::GetParentID(
234 const v8::FunctionCallbackInfo<v8::Value>& args) {
235 ui::AXNode* node;
not at google - send to devlin 2015/06/17 21:14:48 Always nice to initialise pointers to null.
dmazzoni 2015/06/18 07:23:53 Done.
236 if (!GetNodeHelper(args, nullptr, &node))
237 return;
238
239 if (!node->parent())
240 return;
241
242 int parent_id = node->parent()->id();
243 args.GetReturnValue().Set(v8::Integer::New(GetIsolate(), parent_id));
244 }
245
246 void AutomationInternalCustomBindings::GetChildCount(
247 const v8::FunctionCallbackInfo<v8::Value>& args) {
248 ui::AXNode* node;
249 if (!GetNodeHelper(args, nullptr, &node))
250 return;
251
252 int child_count = node->child_count();
253 args.GetReturnValue().Set(v8::Integer::New(GetIsolate(), child_count));
254 }
255
256 void AutomationInternalCustomBindings::GetChildIDAtIndex(
257 const v8::FunctionCallbackInfo<v8::Value>& args) {
258 if (args.Length() < 3 || !args[2]->IsNumber()) {
259 ThrowInvalidArgumentsException(args);
260 return;
261 }
262
263 ui::AXNode* node;
264 if (!GetNodeHelper(args, nullptr, &node))
265 return;
266
267 int index = args[2]->Int32Value();
268 if (index < 0 || index >= node->child_count())
269 return;
270
271 int child_id = node->children()[index]->id();
272 args.GetReturnValue().Set(v8::Integer::New(GetIsolate(), child_id));
273 }
274
275 void AutomationInternalCustomBindings::GetIndexInParent(
276 const v8::FunctionCallbackInfo<v8::Value>& args) {
277 ui::AXNode* node;
278 if (!GetNodeHelper(args, nullptr, &node))
279 return;
280
281 int index_in_parent = node->index_in_parent();
282 args.GetReturnValue().Set(v8::Integer::New(GetIsolate(), index_in_parent));
283 }
284
285 void AutomationInternalCustomBindings::GetState(
286 const v8::FunctionCallbackInfo<v8::Value>& args) {
287 ui::AXNode* node;
288 if (!GetNodeHelper(args, nullptr, &node))
289 return;
290
291 base::DictionaryValue state_dict;
292 uint32 state_pos = 0, state_shifter = node->data().state;
293 while (state_shifter) {
294 if (state_shifter & 1) {
295 state_dict.SetBoolean(
296 ToString(static_cast<ui::AXState>(state_pos)), true);
297 }
298 state_shifter = state_shifter >> 1;
299 state_pos++;
300 }
301
302 SetReturnValueFromBaseValue(args, state_dict);
303 }
304
305 void AutomationInternalCustomBindings::GetRole(
306 const v8::FunctionCallbackInfo<v8::Value>& args) {
307 ui::AXNode* node;
308 if (!GetNodeHelper(args, nullptr, &node))
309 return;
310
311 std::string role_name = ui::ToString(node->data().role);
312 args.GetReturnValue().Set(
313 v8::String::NewFromUtf8(GetIsolate(), role_name.c_str()));
314 }
315
316 void AutomationInternalCustomBindings::GetLocation(
317 const v8::FunctionCallbackInfo<v8::Value>& args) {
318 TreeCache* cache;
319 ui::AXNode* node;
320 if (!GetNodeHelper(args, &cache, &node))
321 return;
322
323 base::DictionaryValue location_dict;
324 gfx::Rect location = node->data().location;
325 location.Offset(cache->location_offset);
326 location_dict.SetInteger("left", location.x());
327 location_dict.SetInteger("top", location.y());
328 location_dict.SetInteger("width", location.width());
329 location_dict.SetInteger("height", location.height());
330
331 SetReturnValueFromBaseValue(args, location_dict);
332 }
333
334 void AutomationInternalCustomBindings::GetStringAttribute(
335 const v8::FunctionCallbackInfo<v8::Value>& args) {
336 ui::AXNode* node;
337 std::string attribute_name;
338 if (!GetAttributeHelper(args, &node, &attribute_name))
339 return;
340
341 ui::AXStringAttribute attribute = ui::ParseAXStringAttribute(attribute_name);
342 std::string attr_value;
343 if (!node->data().GetStringAttribute(attribute, &attr_value))
344 return;
345
346 args.GetReturnValue().Set(
347 v8::String::NewFromUtf8(GetIsolate(), attr_value.c_str()));
348 }
349
350 void AutomationInternalCustomBindings::GetBoolAttribute(
351 const v8::FunctionCallbackInfo<v8::Value>& args) {
352 ui::AXNode* node;
353 std::string attribute_name;
354 if (!GetAttributeHelper(args, &node, &attribute_name))
355 return;
356
357 ui::AXBoolAttribute attribute = ui::ParseAXBoolAttribute(attribute_name);
358 bool attr_value;
359 if (!node->data().GetBoolAttribute(attribute, &attr_value))
360 return;
361
362 args.GetReturnValue().Set(v8::Boolean::New(GetIsolate(), attr_value));
363 }
364
365 void AutomationInternalCustomBindings::GetIntAttribute(
366 const v8::FunctionCallbackInfo<v8::Value>& args) {
367 ui::AXNode* node;
368 std::string attribute_name;
369 if (!GetAttributeHelper(args, &node, &attribute_name))
370 return;
371
372 ui::AXIntAttribute attribute = ui::ParseAXIntAttribute(attribute_name);
373 int attr_value;
374 if (!node->data().GetIntAttribute(attribute, &attr_value))
375 return;
376
377 args.GetReturnValue().Set(v8::Integer::New(GetIsolate(), attr_value));
378 }
379
380 void AutomationInternalCustomBindings::GetFloatAttribute(
381 const v8::FunctionCallbackInfo<v8::Value>& args) {
382 ui::AXNode* node;
383 std::string attribute_name;
384 if (!GetAttributeHelper(args, &node, &attribute_name))
385 return;
386
387 ui::AXFloatAttribute attribute = ui::ParseAXFloatAttribute(attribute_name);
388 float attr_value;
389
390 if (!node->data().GetFloatAttribute(attribute, &attr_value))
391 return;
392
393 args.GetReturnValue().Set(v8::Number::New(GetIsolate(), attr_value));
394 }
395
396 void AutomationInternalCustomBindings::GetIntListAttribute(
397 const v8::FunctionCallbackInfo<v8::Value>& args) {
398 ui::AXNode* node;
399 std::string attribute_name;
400 if (!GetAttributeHelper(args, &node, &attribute_name))
401 return;
402
403 ui::AXIntListAttribute attribute =
404 ui::ParseAXIntListAttribute(attribute_name);
405 if (!node->data().HasIntListAttribute(attribute))
406 return;
407 const std::vector<int32>& attr_value =
408 node->data().GetIntListAttribute(attribute);
409
410 base::ListValue list;
411 for (int32 i : attr_value)
412 list.AppendInteger(i);
413 SetReturnValueFromBaseValue(args, list);
414 }
415
416 void AutomationInternalCustomBindings::GetHtmlAttribute(
417 const v8::FunctionCallbackInfo<v8::Value>& args) {
418 ui::AXNode* node;
419 std::string attribute_name;
420 if (!GetAttributeHelper(args, &node, &attribute_name))
421 return;
422
423 std::string attr_value;
424 if (!node->data().GetHtmlAttribute(attribute_name.c_str(), &attr_value))
425 return;
426
427 args.GetReturnValue().Set(
428 v8::String::NewFromUtf8(GetIsolate(), attr_value.c_str()));
429 }
430
431 //
432 // Helper functions.
433 //
434
435 void AutomationInternalCustomBindings::ThrowInvalidArgumentsException(
436 const v8::FunctionCallbackInfo<v8::Value>& args) {
437 GetIsolate()->ThrowException(
438 v8::String::NewFromUtf8(
439 GetIsolate(),
440 "Invalid arguments to AutomationInternalCustomBindings function",
441 v8::NewStringType::kNormal).ToLocalChecked());
442
443 std::string trace;
not at google - send to devlin 2015/06/17 21:14:48 This stringify-stack-trace utility looks handy. In
dmazzoni 2015/06/18 07:23:53 Done.
444 v8::Local<v8::StackTrace> stack_trace =
445 v8::StackTrace::CurrentStackTrace(GetIsolate(), 10);
446 for (size_t i = 0; i < (size_t)stack_trace->GetFrameCount(); ++i) {
not at google - send to devlin 2015/06/17 21:14:48 static_cast<size_t> not (size_t)?
dcheng 2015/06/17 22:55:09 How about just using int instead of casting?
dmazzoni 2015/06/18 07:23:53 Done.
447 v8::Local<v8::StackFrame> frame = stack_trace->GetFrame(i);
448 CHECK(!frame.IsEmpty());
449 trace += base::StringPrintf(
450 "\n at %s (%s:%d:%d)",
451 *v8::String::Utf8Value(frame->GetFunctionName()),
452 *v8::String::Utf8Value(frame->GetScriptName()),
453 frame->GetLineNumber(),
454 frame->GetColumn());
455 }
456 LOG(FATAL)
457 << "Invalid arguments to AutomationInternalCustomBindings function"
458 << trace;
459 }
460
461 bool AutomationInternalCustomBindings::GetNodeHelper(
462 const v8::FunctionCallbackInfo<v8::Value>& args,
463 TreeCache** out_cache,
464 ui::AXNode** out_node) {
465 if (args.Length() < 2 || !args[0]->IsNumber() || !args[1]->IsNumber()) {
466 ThrowInvalidArgumentsException(args);
467 return false;
468 }
469
470 int tree_id = args[0]->Int32Value();
471 int node_id = args[1]->Int32Value();
472
473 const auto& iter = tree_id_to_tree_cache_map_.find(tree_id);
474 if (iter == tree_id_to_tree_cache_map_.end())
475 return false;
476
477 TreeCache* cache = iter->second;
478 ui::AXNode* node = cache->tree.GetFromId(node_id);
479
480 if (out_cache)
481 *out_cache = cache;
482 if (out_node)
483 *out_node = node;
484
485 return node != nullptr;
486 }
487
488 bool AutomationInternalCustomBindings::GetAttributeHelper(
489 const v8::FunctionCallbackInfo<v8::Value>& args,
490 ui::AXNode** out_node,
491 std::string* out_attribute_name) {
492 if (args.Length() != 3 ||
493 !args[2]->IsString()) {
494 ThrowInvalidArgumentsException(args);
495 return false;
496 }
497
498 TreeCache* cache = nullptr;
499 if (!GetNodeHelper(args, &cache, out_node))
500 return false;
501
502 *out_attribute_name = *v8::String::Utf8Value(args[2]);
503 return true;
504 }
505
506 void AutomationInternalCustomBindings::SetReturnValueFromBaseValue(
507 const v8::FunctionCallbackInfo<v8::Value>& args,
508 const base::Value& value) {
509 v8::HandleScope handle_scope(GetIsolate());
510 v8::Context::Scope context_scope(context()->v8_context());
511 scoped_ptr<content::V8ValueConverter> converter(
512 content::V8ValueConverter::create());
513 v8::Local<v8::Value> v8_value =
514 converter->ToV8Value(&value, context()->v8_context());
515 args.GetReturnValue().Set(v8_value);
516 }
517
518 //
519 // Handle accessibility events from the browser process.
520 //
521
161 void AutomationInternalCustomBindings::OnAccessibilityEvent( 522 void AutomationInternalCustomBindings::OnAccessibilityEvent(
162 const ExtensionMsg_AccessibilityEventParams& params) { 523 const ExtensionMsg_AccessibilityEventParams& params) {
163 // TODO(dmazzoni): finish implementing this. 524 int tree_id = params.tree_id;
525 TreeCache* cache;
526 auto iter = tree_id_to_tree_cache_map_.find(tree_id);
527 if (iter == tree_id_to_tree_cache_map_.end()) {
528 cache = new TreeCache();
529 cache->tab_id = -1;
530 cache->tree_id = params.tree_id;
531 cache->tree.SetDelegate(this);
532 tree_id_to_tree_cache_map_.insert(std::make_pair(tree_id, cache));
533 axtree_to_tree_cache_map_.insert(std::make_pair(&cache->tree, cache));
534 } else {
535 cache = iter->second;
536 }
537
538 cache->location_offset = params.location_offset;
539 if (!cache->tree.Unserialize(params.update)) {
540 LOG(FATAL) << cache->tree.error();
541 return;
542 }
543
544 api::automation_internal::AXEventParams event_params;
545 event_params.tree_id = params.tree_id;
546 event_params.target_id = params.id;
547 event_params.event_type = ToString(params.event_type);
548 base::ListValue args;
549 args.Append(event_params.ToValue());
550
551 v8::HandleScope handle_scope(GetIsolate());
552 v8::Context::Scope context_scope(context()->v8_context());
553 scoped_ptr<content::V8ValueConverter> converter(
554 content::V8ValueConverter::create());
555 v8::Local<v8::Value> v8_args =
556 converter->ToV8Value(&args, context()->v8_context());
557
558 DCHECK(v8_args->IsArray());
559 v8::Local<v8::Array> v8_args_array = v8_args.As<v8::Array>();
560 context()->DispatchEvent("automationInternal.onAccessibilityEvent",
561 v8_args_array);
562 }
563
564 void AutomationInternalCustomBindings::OnNodeWillBeDeleted(ui::AXTree* tree,
565 ui::AXNode* node) {
566 SendTreeChangeEvent(
567 api::automation::TREE_CHANGE_TYPE_NODEREMOVED,
568 tree, node);
569 }
570
571 void AutomationInternalCustomBindings::OnSubtreeWillBeDeleted(
572 ui::AXTree* tree,
573 ui::AXNode* node) {
574 // This isn't strictly needed, as OnNodeWillBeDeleted will already be
575 // called. We could send a JS event for this only if it turns out to
576 // be needed for something.
577 }
578
579 void AutomationInternalCustomBindings::OnNodeCreated(ui::AXTree* tree,
580 ui::AXNode* node) {
581 // Not needed, this is called in the middle of an update so it's not
582 // safe to trigger JS from here. Wait for the notification in
583 // OnAtomicUpdateFinished instead.
584 }
585
586 void AutomationInternalCustomBindings::OnNodeChanged(ui::AXTree* tree,
587 ui::AXNode* node) {
588 // Not needed, this is called in the middle of an update so it's not
589 // safe to trigger JS from here. Wait for the notification in
590 // OnAtomicUpdateFinished instead.
591 }
592
593 void AutomationInternalCustomBindings::OnAtomicUpdateFinished(
594 ui::AXTree* tree,
595 bool root_changed,
596 const std::vector<ui::AXTreeDelegate::Change>& changes) {
597 auto iter = axtree_to_tree_cache_map_.find(tree);
598 if (iter == axtree_to_tree_cache_map_.end())
599 return;
600
601 for (auto change : changes) {
602 ui::AXNode* node = change.node;
603 switch (change.type) {
604 case NODE_CREATED:
605 SendTreeChangeEvent(
606 api::automation::TREE_CHANGE_TYPE_NODECREATED,
607 tree, node);
608 break;
609 case SUBTREE_CREATED:
610 SendTreeChangeEvent(
611 api::automation::TREE_CHANGE_TYPE_SUBTREECREATED,
612 tree, node);
613 break;
614 case NODE_CHANGED:
615 SendTreeChangeEvent(
616 api::automation::TREE_CHANGE_TYPE_NODECHANGED,
617 tree, node);
618 break;
619 }
620 }
621 }
622
623 void AutomationInternalCustomBindings::SendTreeChangeEvent(
624 api::automation::TreeChangeType change_type,
625 ui::AXTree* tree,
626 ui::AXNode* node) {
627 auto iter = axtree_to_tree_cache_map_.find(tree);
628 if (iter == axtree_to_tree_cache_map_.end())
629 return;
630
631 int tree_id = iter->second->tree_id;
632 base::ListValue args;
633 args.AppendInteger(tree_id);
634 args.AppendInteger(node->id());
635 args.AppendString(ToString(change_type).c_str());
636
637 v8::HandleScope handle_scope(GetIsolate());
638 v8::Context::Scope context_scope(context()->v8_context());
639 scoped_ptr<content::V8ValueConverter> converter(
640 content::V8ValueConverter::create());
not at google - send to devlin 2015/06/17 21:14:47 You should avoid dealing with base::Values as much
dmazzoni 2015/06/18 07:23:53 OK, done. I got rid of all uses of V8ValueConverte
641 v8::Local<v8::Value> v8_args =
642 converter->ToV8Value(&args, context()->v8_context());
643
644 DCHECK(v8_args->IsArray());
645 v8::Local<v8::Array> v8_args_array = v8_args.As<v8::Array>();
646 context()->DispatchEvent("automationInternal.onTreeChange",
647 v8_args_array);
164 } 648 }
165 649
166 } // namespace extensions 650 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698