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

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 nested event sending in AutomationManagerAura 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/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 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 = nullptr;
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 = nullptr;
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 = nullptr;
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 = nullptr;
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 = nullptr;
288 if (!GetNodeHelper(args, nullptr, &node))
289 return;
290
291 v8::Local<v8::Object> state(v8::Object::New(GetIsolate()));
292 uint32 state_pos = 0, state_shifter = node->data().state;
293 while (state_shifter) {
294 if (state_shifter & 1) {
295 std::string key = ToString(static_cast<ui::AXState>(state_pos));
296 state->Set(CreateV8String(key),
297 v8::Boolean::New(GetIsolate(), true));
298 }
299 state_shifter = state_shifter >> 1;
300 state_pos++;
301 }
302
303 args.GetReturnValue().Set(state);
304 }
305
306 void AutomationInternalCustomBindings::GetRole(
307 const v8::FunctionCallbackInfo<v8::Value>& args) {
308 ui::AXNode* node = nullptr;
309 if (!GetNodeHelper(args, nullptr, &node))
310 return;
311
312 std::string role_name = ui::ToString(node->data().role);
313 args.GetReturnValue().Set(
314 v8::String::NewFromUtf8(GetIsolate(), role_name.c_str()));
315 }
316
317 void AutomationInternalCustomBindings::GetLocation(
318 const v8::FunctionCallbackInfo<v8::Value>& args) {
319 TreeCache* cache;
320 ui::AXNode* node = nullptr;
321 if (!GetNodeHelper(args, &cache, &node))
322 return;
323
324 v8::Local<v8::Object> location_obj(v8::Object::New(GetIsolate()));
325 gfx::Rect location = node->data().location;
326 location.Offset(cache->location_offset);
327 location_obj->Set(CreateV8String("left"),
328 v8::Integer::New(GetIsolate(), location.x()));
329 location_obj->Set(CreateV8String("top"),
330 v8::Integer::New(GetIsolate(), location.y()));
331 location_obj->Set(CreateV8String("width"),
332 v8::Integer::New(GetIsolate(), location.width()));
333 location_obj->Set(CreateV8String("height"),
334 v8::Integer::New(GetIsolate(), location.height()));
335 args.GetReturnValue().Set(location_obj);
336 }
337
338 void AutomationInternalCustomBindings::GetStringAttribute(
339 const v8::FunctionCallbackInfo<v8::Value>& args) {
340 ui::AXNode* node = nullptr;
341 std::string attribute_name;
342 if (!GetAttributeHelper(args, &node, &attribute_name))
343 return;
344
345 ui::AXStringAttribute attribute = ui::ParseAXStringAttribute(attribute_name);
346 std::string attr_value;
347 if (!node->data().GetStringAttribute(attribute, &attr_value))
348 return;
349
350 args.GetReturnValue().Set(
351 v8::String::NewFromUtf8(GetIsolate(), attr_value.c_str()));
352 }
353
354 void AutomationInternalCustomBindings::GetBoolAttribute(
355 const v8::FunctionCallbackInfo<v8::Value>& args) {
356 ui::AXNode* node = nullptr;
357 std::string attribute_name;
358 if (!GetAttributeHelper(args, &node, &attribute_name))
359 return;
360
361 ui::AXBoolAttribute attribute = ui::ParseAXBoolAttribute(attribute_name);
362 bool attr_value;
363 if (!node->data().GetBoolAttribute(attribute, &attr_value))
364 return;
365
366 args.GetReturnValue().Set(v8::Boolean::New(GetIsolate(), attr_value));
367 }
368
369 void AutomationInternalCustomBindings::GetIntAttribute(
370 const v8::FunctionCallbackInfo<v8::Value>& args) {
371 ui::AXNode* node = nullptr;
372 std::string attribute_name;
373 if (!GetAttributeHelper(args, &node, &attribute_name))
374 return;
375
376 ui::AXIntAttribute attribute = ui::ParseAXIntAttribute(attribute_name);
377 int attr_value;
378 if (!node->data().GetIntAttribute(attribute, &attr_value))
379 return;
380
381 args.GetReturnValue().Set(v8::Integer::New(GetIsolate(), attr_value));
382 }
383
384 void AutomationInternalCustomBindings::GetFloatAttribute(
385 const v8::FunctionCallbackInfo<v8::Value>& args) {
386 ui::AXNode* node = nullptr;
387 std::string attribute_name;
388 if (!GetAttributeHelper(args, &node, &attribute_name))
389 return;
390
391 ui::AXFloatAttribute attribute = ui::ParseAXFloatAttribute(attribute_name);
392 float attr_value;
393
394 if (!node->data().GetFloatAttribute(attribute, &attr_value))
395 return;
396
397 args.GetReturnValue().Set(v8::Number::New(GetIsolate(), attr_value));
398 }
399
400 void AutomationInternalCustomBindings::GetIntListAttribute(
401 const v8::FunctionCallbackInfo<v8::Value>& args) {
402 ui::AXNode* node = nullptr;
403 std::string attribute_name;
404 if (!GetAttributeHelper(args, &node, &attribute_name))
405 return;
406
407 ui::AXIntListAttribute attribute =
408 ui::ParseAXIntListAttribute(attribute_name);
409 if (!node->data().HasIntListAttribute(attribute))
410 return;
411 const std::vector<int32>& attr_value =
412 node->data().GetIntListAttribute(attribute);
413
414 v8::Local<v8::Array> result(v8::Array::New(GetIsolate(), attr_value.size()));
415 for (size_t i = 0; i < attr_value.size(); ++i)
416 result->Set(static_cast<uint32>(i),
417 v8::Integer::New(GetIsolate(), attr_value[i]));
418 args.GetReturnValue().Set(result);
419 }
420
421 void AutomationInternalCustomBindings::GetHtmlAttribute(
422 const v8::FunctionCallbackInfo<v8::Value>& args) {
423 ui::AXNode* node = nullptr;
424 std::string attribute_name;
425 if (!GetAttributeHelper(args, &node, &attribute_name))
426 return;
427
428 std::string attr_value;
429 if (!node->data().GetHtmlAttribute(attribute_name.c_str(), &attr_value))
430 return;
431
432 args.GetReturnValue().Set(
433 v8::String::NewFromUtf8(GetIsolate(), attr_value.c_str()));
434 }
435
436 //
437 // Helper functions.
438 //
439
440 void AutomationInternalCustomBindings::ThrowInvalidArgumentsException(
441 const v8::FunctionCallbackInfo<v8::Value>& args) {
442 GetIsolate()->ThrowException(
443 v8::String::NewFromUtf8(
444 GetIsolate(),
445 "Invalid arguments to AutomationInternalCustomBindings function",
446 v8::NewStringType::kNormal).ToLocalChecked());
447
448 LOG(FATAL)
449 << "Invalid arguments to AutomationInternalCustomBindings function"
450 << context()->GetStackTraceAsString();
451 }
452
453 bool AutomationInternalCustomBindings::GetNodeHelper(
454 const v8::FunctionCallbackInfo<v8::Value>& args,
455 TreeCache** out_cache,
456 ui::AXNode** out_node) {
457 if (args.Length() < 2 || !args[0]->IsNumber() || !args[1]->IsNumber()) {
458 ThrowInvalidArgumentsException(args);
459 return false;
460 }
461
462 int tree_id = args[0]->Int32Value();
463 int node_id = args[1]->Int32Value();
464
465 const auto iter = tree_id_to_tree_cache_map_.find(tree_id);
466 if (iter == tree_id_to_tree_cache_map_.end())
467 return false;
468
469 TreeCache* cache = iter->second;
470 ui::AXNode* node = cache->tree.GetFromId(node_id);
471
472 if (out_cache)
473 *out_cache = cache;
474 if (out_node)
475 *out_node = node;
476
477 return node != nullptr;
478 }
479
480 bool AutomationInternalCustomBindings::GetAttributeHelper(
481 const v8::FunctionCallbackInfo<v8::Value>& args,
482 ui::AXNode** out_node,
483 std::string* out_attribute_name) {
484 if (args.Length() != 3 ||
485 !args[2]->IsString()) {
486 ThrowInvalidArgumentsException(args);
487 return false;
488 }
489
490 TreeCache* cache = nullptr;
491 if (!GetNodeHelper(args, &cache, out_node))
492 return false;
493
494 *out_attribute_name = *v8::String::Utf8Value(args[2]);
495 return true;
496 }
497
498 v8::Local<v8::Value> AutomationInternalCustomBindings::CreateV8String(
499 const char* str) {
500 return v8::String::NewFromUtf8(
501 GetIsolate(), str, v8::String::kNormalString, strlen(str));
502 }
503
504 v8::Local<v8::Value> AutomationInternalCustomBindings::CreateV8String(
505 const std::string& str) {
506 return v8::String::NewFromUtf8(
507 GetIsolate(), str.c_str(), v8::String::kNormalString, str.length());
508 }
509
510 //
511 // Handle accessibility events from the browser process.
512 //
513
162 void AutomationInternalCustomBindings::OnAccessibilityEvent( 514 void AutomationInternalCustomBindings::OnAccessibilityEvent(
163 const ExtensionMsg_AccessibilityEventParams& params) { 515 const ExtensionMsg_AccessibilityEventParams& params) {
164 // TODO(dmazzoni): finish implementing this. 516 int tree_id = params.tree_id;
517 TreeCache* cache;
518 auto iter = tree_id_to_tree_cache_map_.find(tree_id);
519 if (iter == tree_id_to_tree_cache_map_.end()) {
520 cache = new TreeCache();
521 cache->tab_id = -1;
522 cache->tree_id = params.tree_id;
523 cache->tree.SetDelegate(this);
524 tree_id_to_tree_cache_map_.insert(std::make_pair(tree_id, cache));
525 axtree_to_tree_cache_map_.insert(std::make_pair(&cache->tree, cache));
526 } else {
527 cache = iter->second;
528 }
529
530 cache->location_offset = params.location_offset;
531 if (!cache->tree.Unserialize(params.update)) {
532 LOG(FATAL) << cache->tree.error();
533 return;
534 }
535
536 v8::HandleScope handle_scope(GetIsolate());
537 v8::Context::Scope context_scope(context()->v8_context());
538 v8::Local<v8::Array> args(v8::Array::New(GetIsolate(), 1U));
539 v8::Local<v8::Object> event_params(v8::Object::New(GetIsolate()));
540 event_params->Set(CreateV8String("treeID"),
541 v8::Integer::New(GetIsolate(), params.tree_id));
542 event_params->Set(CreateV8String("targetID"),
543 v8::Integer::New(GetIsolate(), params.id));
544 event_params->Set(CreateV8String("eventType"),
545 CreateV8String(ToString(params.event_type)));
546 args->Set(0U, event_params);
547 context()->DispatchEvent("automationInternal.onAccessibilityEvent", args);
548 }
549
550 void AutomationInternalCustomBindings::OnNodeWillBeDeleted(ui::AXTree* tree,
551 ui::AXNode* node) {
552 SendTreeChangeEvent(
553 api::automation::TREE_CHANGE_TYPE_NODEREMOVED,
554 tree, node);
555 }
556
557 void AutomationInternalCustomBindings::OnSubtreeWillBeDeleted(
558 ui::AXTree* tree,
559 ui::AXNode* node) {
560 // This isn't strictly needed, as OnNodeWillBeDeleted will already be
561 // called. We could send a JS event for this only if it turns out to
562 // be needed for something.
563 }
564
565 void AutomationInternalCustomBindings::OnNodeCreated(ui::AXTree* tree,
566 ui::AXNode* node) {
567 // Not needed, this is called in the middle of an update so it's not
568 // safe to trigger JS from here. Wait for the notification in
569 // OnAtomicUpdateFinished instead.
570 }
571
572 void AutomationInternalCustomBindings::OnNodeChanged(ui::AXTree* tree,
573 ui::AXNode* node) {
574 // Not needed, this is called in the middle of an update so it's not
575 // safe to trigger JS from here. Wait for the notification in
576 // OnAtomicUpdateFinished instead.
577 }
578
579 void AutomationInternalCustomBindings::OnAtomicUpdateFinished(
580 ui::AXTree* tree,
581 bool root_changed,
582 const std::vector<ui::AXTreeDelegate::Change>& changes) {
583 auto iter = axtree_to_tree_cache_map_.find(tree);
584 if (iter == axtree_to_tree_cache_map_.end())
585 return;
586
587 for (auto change : changes) {
588 ui::AXNode* node = change.node;
589 switch (change.type) {
590 case NODE_CREATED:
591 SendTreeChangeEvent(
592 api::automation::TREE_CHANGE_TYPE_NODECREATED,
593 tree, node);
594 break;
595 case SUBTREE_CREATED:
596 SendTreeChangeEvent(
597 api::automation::TREE_CHANGE_TYPE_SUBTREECREATED,
598 tree, node);
599 break;
600 case NODE_CHANGED:
601 SendTreeChangeEvent(
602 api::automation::TREE_CHANGE_TYPE_NODECHANGED,
603 tree, node);
604 break;
605 }
606 }
607 }
608
609 void AutomationInternalCustomBindings::SendTreeChangeEvent(
610 api::automation::TreeChangeType change_type,
611 ui::AXTree* tree,
612 ui::AXNode* node) {
613 auto iter = axtree_to_tree_cache_map_.find(tree);
614 if (iter == axtree_to_tree_cache_map_.end())
615 return;
616
617 int tree_id = iter->second->tree_id;
618
619 v8::HandleScope handle_scope(GetIsolate());
620 v8::Context::Scope context_scope(context()->v8_context());
621 v8::Local<v8::Array> args(v8::Array::New(GetIsolate(), 3U));
622 args->Set(0U, v8::Integer::New(GetIsolate(), tree_id));
623 args->Set(1U, v8::Integer::New(GetIsolate(), node->id()));
624 args->Set(2U, CreateV8String(ToString(change_type)));
625 context()->DispatchEvent("automationInternal.onTreeChange", args);
165 } 626 }
166 627
167 } // namespace extensions 628 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698