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

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

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

Powered by Google App Engine
This is Rietveld 408576698