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

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

Issue 1458723002: Finish implementing ChromeVox Next active indicator. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@load_key_map
Patch Set: Created 5 years, 1 month 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/thread_task_runner_handle.h"
10 #include "base/values.h" 10 #include "base/values.h"
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
56 return v8::String::NewFromUtf8(isolate, str, v8::String::kNormalString, 56 return v8::String::NewFromUtf8(isolate, str, v8::String::kNormalString,
57 strlen(str)); 57 strlen(str));
58 } 58 }
59 59
60 v8::Local<v8::Value> CreateV8String(v8::Isolate* isolate, 60 v8::Local<v8::Value> CreateV8String(v8::Isolate* isolate,
61 const std::string& str) { 61 const std::string& str) {
62 return v8::String::NewFromUtf8(isolate, str.c_str(), 62 return v8::String::NewFromUtf8(isolate, str.c_str(),
63 v8::String::kNormalString, str.length()); 63 v8::String::kNormalString, str.length());
64 } 64 }
65 65
66 v8::Local<v8::Object> RectToV8Object(v8::Isolate* isolate,
67 const gfx::Rect& rect) {
68 v8::Local<v8::Object> result(v8::Object::New(isolate));
69 result->Set(CreateV8String(isolate, "left"),
70 v8::Integer::New(isolate, rect.x()));
71 result->Set(CreateV8String(isolate, "top"),
72 v8::Integer::New(isolate, rect.y()));
73 result->Set(CreateV8String(isolate, "width"),
74 v8::Integer::New(isolate, rect.width()));
75 result->Set(CreateV8String(isolate, "height"),
76 v8::Integer::New(isolate, rect.height()));
77 return result;
78 }
79
80 // Compute the bounding box of a node, fixing nodes with empty bounds by
81 // unioning the bounds of their children.
82 static gfx::Rect ComputeLocalNodeBounds(TreeCache* cache, ui::AXNode* node) {
83 gfx::Rect bounds = node->data().location;
84 if (bounds.width() > 0 && bounds.height() > 0)
85 return bounds;
86
87 // Compute the bounds of each child.
88 for (size_t i = 0; i < node->children().size(); i++) {
89 ui::AXNode* child = node->children()[i];
90 gfx::Rect child_bounds = ComputeLocalNodeBounds(cache, child);
91
92 // Ignore children that don't have valid bounds themselves.
93 if (child_bounds.width() == 0 || child_bounds.height() == 0)
94 continue;
95
96 // For the first valid child, just set the bounds to that child's bounds.
97 if (bounds.width() == 0 || bounds.height() == 0) {
98 bounds = child_bounds;
99 continue;
100 }
101
102 // Union each additional child's bounds.
103 bounds.Union(child_bounds);
104 }
105
106 return bounds;
107 }
108
109 // Compute the bounding box of a node in global coordinates, walking up the
110 // parent hierarchy to offset by frame offsets and scroll offsets.
111 static gfx::Rect ComputeGlobalNodeBounds(TreeCache* cache, ui::AXNode* node) {
112 gfx::Rect bounds = ComputeLocalNodeBounds(cache, node);
113 ui::AXNode* parent = node->parent();
114 bool need_to_offset_web_area = node->data().role == ui::AX_ROLE_WEB_AREA ||
115 node->data().role == ui::AX_ROLE_ROOT_WEB_AREA;
116 while (parent) {
117 if (bounds.IsEmpty()) {
118 bounds = parent->data().location;
119 } else if (need_to_offset_web_area && parent->data().location.width() > 0 &&
120 parent->data().location.height() > 0) {
121 bounds.Offset(parent->data().location.x(), parent->data().location.y());
122 need_to_offset_web_area = false;
123 }
124
125 if (parent->data().role == ui::AX_ROLE_WEB_AREA ||
126 parent->data().role == ui::AX_ROLE_ROOT_WEB_AREA) {
127 int sx = 0;
128 int sy = 0;
129 if (parent->data().GetIntAttribute(ui::AX_ATTR_SCROLL_X, &sx) &&
130 parent->data().GetIntAttribute(ui::AX_ATTR_SCROLL_Y, &sy)) {
131 bounds.Offset(-sx, -sy);
132 }
133 need_to_offset_web_area = true;
134 }
135 parent = parent->parent();
136 }
137
138 return bounds;
139 }
140
66 // 141 //
67 // Helper class that helps implement bindings for a JavaScript function 142 // Helper class that helps implement bindings for a JavaScript function
68 // that takes a single input argument consisting of a Tree ID. Looks up 143 // that takes a single input argument consisting of a Tree ID. Looks up
69 // the TreeCache and passes it to the function passed to the constructor. 144 // the TreeCache and passes it to the function passed to the constructor.
70 // 145 //
71 146
72 typedef void (*TreeIDFunction)(v8::Isolate* isolate, 147 typedef void (*TreeIDFunction)(v8::Isolate* isolate,
73 v8::ReturnValue<v8::Value> result, 148 v8::ReturnValue<v8::Value> result,
74 TreeCache* cache); 149 TreeCache* cache);
75 150
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after
195 270
196 private: 271 private:
197 virtual ~NodeIDPlusAttributeWrapper() {} 272 virtual ~NodeIDPlusAttributeWrapper() {}
198 273
199 friend class base::RefCountedThreadSafe<NodeIDPlusAttributeWrapper>; 274 friend class base::RefCountedThreadSafe<NodeIDPlusAttributeWrapper>;
200 275
201 AutomationInternalCustomBindings* automation_bindings_; 276 AutomationInternalCustomBindings* automation_bindings_;
202 NodeIDPlusAttributeFunction function_; 277 NodeIDPlusAttributeFunction function_;
203 }; 278 };
204 279
280 //
281 // Helper class that helps implement bindings for a JavaScript function
282 // that takes four input arguments: a tree ID, node ID, and integer start
283 // and end indices. Looks up the TreeCache and the AXNode and passes them
284 // to the function passed to the constructor.
285 //
286
287 typedef void (*NodeIDPlusRangeFunction)(v8::Isolate* isolate,
288 v8::ReturnValue<v8::Value> result,
289 TreeCache* cache,
290 ui::AXNode* node,
291 int start,
292 int end);
293
294 class NodeIDPlusRangeWrapper
295 : public base::RefCountedThreadSafe<NodeIDPlusRangeWrapper> {
296 public:
297 NodeIDPlusRangeWrapper(AutomationInternalCustomBindings* automation_bindings,
298 NodeIDPlusRangeFunction function)
299 : automation_bindings_(automation_bindings), function_(function) {}
300
301 void Run(const v8::FunctionCallbackInfo<v8::Value>& args) {
302 v8::Isolate* isolate = automation_bindings_->GetIsolate();
303 if (args.Length() < 4 || !args[0]->IsNumber() || !args[1]->IsNumber() ||
304 !args[2]->IsNumber() || !args[3]->IsNumber()) {
305 ThrowInvalidArgumentsException(automation_bindings_);
306 }
307
308 int tree_id = args[0]->Int32Value();
309 int node_id = args[1]->Int32Value();
310 int start = args[2]->Int32Value();
311 int end = args[3]->Int32Value();
312
313 TreeCache* cache = automation_bindings_->GetTreeCacheFromTreeID(tree_id);
314 if (!cache)
315 return;
316
317 ui::AXNode* node = cache->tree.GetFromId(node_id);
318 if (!node)
319 return;
320
321 function_(isolate, args.GetReturnValue(), cache, node, start, end);
322 }
323
324 private:
325 virtual ~NodeIDPlusRangeWrapper() {}
326
327 friend class base::RefCountedThreadSafe<NodeIDPlusRangeWrapper>;
328
329 AutomationInternalCustomBindings* automation_bindings_;
330 NodeIDPlusRangeFunction function_;
331 };
332
205 } // namespace 333 } // namespace
206 334
207 TreeCache::TreeCache() {} 335 TreeCache::TreeCache() {}
208 TreeCache::~TreeCache() {} 336 TreeCache::~TreeCache() {}
209 337
210 class AutomationMessageFilter : public IPC::MessageFilter { 338 class AutomationMessageFilter : public IPC::MessageFilter {
211 public: 339 public:
212 explicit AutomationMessageFilter(AutomationInternalCustomBindings* owner) 340 explicit AutomationMessageFilter(AutomationInternalCustomBindings* owner)
213 : owner_(owner), 341 : owner_(owner),
214 removed_(false) { 342 removed_(false) {
(...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after
371 }); 499 });
372 RouteNodeIDFunction( 500 RouteNodeIDFunction(
373 "GetRole", [](v8::Isolate* isolate, v8::ReturnValue<v8::Value> result, 501 "GetRole", [](v8::Isolate* isolate, v8::ReturnValue<v8::Value> result,
374 TreeCache* cache, ui::AXNode* node) { 502 TreeCache* cache, ui::AXNode* node) {
375 std::string role_name = ui::ToString(node->data().role); 503 std::string role_name = ui::ToString(node->data().role);
376 result.Set(v8::String::NewFromUtf8(isolate, role_name.c_str())); 504 result.Set(v8::String::NewFromUtf8(isolate, role_name.c_str()));
377 }); 505 });
378 RouteNodeIDFunction( 506 RouteNodeIDFunction(
379 "GetLocation", [](v8::Isolate* isolate, v8::ReturnValue<v8::Value> result, 507 "GetLocation", [](v8::Isolate* isolate, v8::ReturnValue<v8::Value> result,
380 TreeCache* cache, ui::AXNode* node) { 508 TreeCache* cache, ui::AXNode* node) {
381 v8::Local<v8::Object> location_obj(v8::Object::New(isolate)); 509 gfx::Rect location = ComputeGlobalNodeBounds(cache, node);
382 gfx::Rect location = node->data().location;
383 location.Offset(cache->location_offset); 510 location.Offset(cache->location_offset);
384 location_obj->Set(CreateV8String(isolate, "left"), 511 result.Set(RectToV8Object(isolate, location));
385 v8::Integer::New(isolate, location.x()));
386 location_obj->Set(CreateV8String(isolate, "top"),
387 v8::Integer::New(isolate, location.y()));
388 location_obj->Set(CreateV8String(isolate, "width"),
389 v8::Integer::New(isolate, location.width()));
390 location_obj->Set(CreateV8String(isolate, "height"),
391 v8::Integer::New(isolate, location.height()));
392 result.Set(location_obj);
393 }); 512 });
394 513
395 // Bindings that take a Tree ID and Node ID and string attribute name 514 // Bindings that take a Tree ID and Node ID and string attribute name
515 // and return a property of the node.
516
517 RouteNodeIDPlusRangeFunction(
518 "GetBoundsForRange",
519 [](v8::Isolate* isolate, v8::ReturnValue<v8::Value> result,
520 TreeCache* cache, ui::AXNode* node, int start, int end) {
521 gfx::Rect location = ComputeGlobalNodeBounds(cache, node);
522 location.Offset(cache->location_offset);
523 if (node->data().role == ui::AX_ROLE_INLINE_TEXT_BOX) {
524 std::string name = node->data().GetStringAttribute(ui::AX_ATTR_NAME);
525 std::vector<int> character_offsets =
526 node->data().GetIntListAttribute(ui::AX_ATTR_CHARACTER_OFFSETS);
527 int len =
528 static_cast<int>(std::min(name.size(), character_offsets.size()));
529 if (start >= 0 && start <= len && end >= 0 && end <= len &&
530 end >= start) {
531 int start_offset = start > 0 ? character_offsets[start - 1] : 0;
532 int end_offset = end > 0 ? character_offsets[end - 1] : 0;
533 location.set_x(location.x() + start_offset);
Peter Lundblad 2015/11/20 11:15:03 Could this need to be extended for top-to-bottom t
dmazzoni 2015/11/20 23:35:14 Yes! We were already exposing this info, wasn't ha
534 location.set_width(end_offset - start_offset);
535 }
536 }
537 result.Set(RectToV8Object(isolate, location));
538 });
539
540 // Bindings that take a Tree ID and Node ID and string attribute name
396 // and return a property of the node. 541 // and return a property of the node.
397 542
398 RouteNodeIDPlusAttributeFunction( 543 RouteNodeIDPlusAttributeFunction(
399 "GetStringAttribute", 544 "GetStringAttribute",
400 [](v8::Isolate* isolate, v8::ReturnValue<v8::Value> result, 545 [](v8::Isolate* isolate, v8::ReturnValue<v8::Value> result,
401 ui::AXNode* node, const std::string& attribute_name) { 546 ui::AXNode* node, const std::string& attribute_name) {
402 ui::AXStringAttribute attribute = 547 ui::AXStringAttribute attribute =
403 ui::ParseAXStringAttribute(attribute_name); 548 ui::ParseAXStringAttribute(attribute_name);
404 std::string attr_value; 549 std::string attr_value;
405 if (!node->data().GetStringAttribute(attribute, &attr_value)) 550 if (!node->data().GetStringAttribute(attribute, &attr_value))
(...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after
585 } 730 }
586 731
587 void AutomationInternalCustomBindings::RouteNodeIDPlusAttributeFunction( 732 void AutomationInternalCustomBindings::RouteNodeIDPlusAttributeFunction(
588 const std::string& name, 733 const std::string& name,
589 NodeIDPlusAttributeFunction callback) { 734 NodeIDPlusAttributeFunction callback) {
590 scoped_refptr<NodeIDPlusAttributeWrapper> wrapper = 735 scoped_refptr<NodeIDPlusAttributeWrapper> wrapper =
591 new NodeIDPlusAttributeWrapper(this, callback); 736 new NodeIDPlusAttributeWrapper(this, callback);
592 RouteFunction(name, base::Bind(&NodeIDPlusAttributeWrapper::Run, wrapper)); 737 RouteFunction(name, base::Bind(&NodeIDPlusAttributeWrapper::Run, wrapper));
593 } 738 }
594 739
740 void AutomationInternalCustomBindings::RouteNodeIDPlusRangeFunction(
741 const std::string& name,
742 NodeIDPlusRangeFunction callback) {
743 scoped_refptr<NodeIDPlusRangeWrapper> wrapper =
744 new NodeIDPlusRangeWrapper(this, callback);
745 RouteFunction(name, base::Bind(&NodeIDPlusRangeWrapper::Run, wrapper));
746 }
747
595 void AutomationInternalCustomBindings::GetChildIDAtIndex( 748 void AutomationInternalCustomBindings::GetChildIDAtIndex(
596 const v8::FunctionCallbackInfo<v8::Value>& args) { 749 const v8::FunctionCallbackInfo<v8::Value>& args) {
597 if (args.Length() < 3 || !args[2]->IsNumber()) { 750 if (args.Length() < 3 || !args[2]->IsNumber()) {
598 ThrowInvalidArgumentsException(this); 751 ThrowInvalidArgumentsException(this);
599 return; 752 return;
600 } 753 }
601 754
602 int tree_id = args[0]->Int32Value(); 755 int tree_id = args[0]->Int32Value();
603 int node_id = args[1]->Int32Value(); 756 int node_id = args[1]->Int32Value();
604 757
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after
749 v8::HandleScope handle_scope(isolate); 902 v8::HandleScope handle_scope(isolate);
750 v8::Context::Scope context_scope(context()->v8_context()); 903 v8::Context::Scope context_scope(context()->v8_context());
751 v8::Local<v8::Array> args(v8::Array::New(GetIsolate(), 3U)); 904 v8::Local<v8::Array> args(v8::Array::New(GetIsolate(), 3U));
752 args->Set(0U, v8::Integer::New(GetIsolate(), tree_id)); 905 args->Set(0U, v8::Integer::New(GetIsolate(), tree_id));
753 args->Set(1U, v8::Integer::New(GetIsolate(), node->id())); 906 args->Set(1U, v8::Integer::New(GetIsolate(), node->id()));
754 args->Set(2U, CreateV8String(isolate, ToString(change_type))); 907 args->Set(2U, CreateV8String(isolate, ToString(change_type)));
755 context()->DispatchEvent("automationInternal.onTreeChange", args); 908 context()->DispatchEvent("automationInternal.onTreeChange", args);
756 } 909 }
757 910
758 } // namespace extensions 911 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698