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

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

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

Powered by Google App Engine
This is Rietveld 408576698