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

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: Made test expectations approximate Created 5 years 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 <= end && end <= len) {
530 int start_offset = start > 0 ? character_offsets[start - 1] : 0;
531 int end_offset = end > 0 ? character_offsets[end - 1] : 0;
532
533 switch (node->data().GetIntAttribute(ui::AX_ATTR_TEXT_DIRECTION)) {
534 case ui::AX_TEXT_DIRECTION_LTR:
535 default:
536 location.set_x(location.x() + start_offset);
537 location.set_width(end_offset - start_offset);
538 break;
539 case ui::AX_TEXT_DIRECTION_RTL:
540 location.set_x(location.x() + location.width() - end_offset);
541 location.set_width(end_offset - start_offset);
542 break;
543 case ui::AX_TEXT_DIRECTION_TTB:
544 location.set_y(location.y() + start_offset);
545 location.set_height(end_offset - start_offset);
546 break;
547 case ui::AX_TEXT_DIRECTION_BTT:
548 location.set_y(location.y() + location.height() - end_offset);
549 location.set_height(end_offset - start_offset);
550 break;
551 }
552 }
553 }
554 result.Set(RectToV8Object(isolate, location));
555 });
556
557 // Bindings that take a Tree ID and Node ID and string attribute name
396 // and return a property of the node. 558 // and return a property of the node.
397 559
398 RouteNodeIDPlusAttributeFunction( 560 RouteNodeIDPlusAttributeFunction(
399 "GetStringAttribute", 561 "GetStringAttribute",
400 [](v8::Isolate* isolate, v8::ReturnValue<v8::Value> result, 562 [](v8::Isolate* isolate, v8::ReturnValue<v8::Value> result,
401 ui::AXNode* node, const std::string& attribute_name) { 563 ui::AXNode* node, const std::string& attribute_name) {
402 ui::AXStringAttribute attribute = 564 ui::AXStringAttribute attribute =
403 ui::ParseAXStringAttribute(attribute_name); 565 ui::ParseAXStringAttribute(attribute_name);
404 std::string attr_value; 566 std::string attr_value;
405 if (!node->data().GetStringAttribute(attribute, &attr_value)) 567 if (!node->data().GetStringAttribute(attribute, &attr_value))
(...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after
585 } 747 }
586 748
587 void AutomationInternalCustomBindings::RouteNodeIDPlusAttributeFunction( 749 void AutomationInternalCustomBindings::RouteNodeIDPlusAttributeFunction(
588 const std::string& name, 750 const std::string& name,
589 NodeIDPlusAttributeFunction callback) { 751 NodeIDPlusAttributeFunction callback) {
590 scoped_refptr<NodeIDPlusAttributeWrapper> wrapper = 752 scoped_refptr<NodeIDPlusAttributeWrapper> wrapper =
591 new NodeIDPlusAttributeWrapper(this, callback); 753 new NodeIDPlusAttributeWrapper(this, callback);
592 RouteFunction(name, base::Bind(&NodeIDPlusAttributeWrapper::Run, wrapper)); 754 RouteFunction(name, base::Bind(&NodeIDPlusAttributeWrapper::Run, wrapper));
593 } 755 }
594 756
757 void AutomationInternalCustomBindings::RouteNodeIDPlusRangeFunction(
758 const std::string& name,
759 NodeIDPlusRangeFunction callback) {
760 scoped_refptr<NodeIDPlusRangeWrapper> wrapper =
761 new NodeIDPlusRangeWrapper(this, callback);
762 RouteFunction(name, base::Bind(&NodeIDPlusRangeWrapper::Run, wrapper));
763 }
764
595 void AutomationInternalCustomBindings::GetChildIDAtIndex( 765 void AutomationInternalCustomBindings::GetChildIDAtIndex(
596 const v8::FunctionCallbackInfo<v8::Value>& args) { 766 const v8::FunctionCallbackInfo<v8::Value>& args) {
597 if (args.Length() < 3 || !args[2]->IsNumber()) { 767 if (args.Length() < 3 || !args[2]->IsNumber()) {
598 ThrowInvalidArgumentsException(this); 768 ThrowInvalidArgumentsException(this);
599 return; 769 return;
600 } 770 }
601 771
602 int tree_id = args[0]->Int32Value(); 772 int tree_id = args[0]->Int32Value();
603 int node_id = args[1]->Int32Value(); 773 int node_id = args[1]->Int32Value();
604 774
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after
749 v8::HandleScope handle_scope(isolate); 919 v8::HandleScope handle_scope(isolate);
750 v8::Context::Scope context_scope(context()->v8_context()); 920 v8::Context::Scope context_scope(context()->v8_context());
751 v8::Local<v8::Array> args(v8::Array::New(GetIsolate(), 3U)); 921 v8::Local<v8::Array> args(v8::Array::New(GetIsolate(), 3U));
752 args->Set(0U, v8::Integer::New(GetIsolate(), tree_id)); 922 args->Set(0U, v8::Integer::New(GetIsolate(), tree_id));
753 args->Set(1U, v8::Integer::New(GetIsolate(), node->id())); 923 args->Set(1U, v8::Integer::New(GetIsolate(), node->id()));
754 args->Set(2U, CreateV8String(isolate, ToString(change_type))); 924 args->Set(2U, CreateV8String(isolate, ToString(change_type)));
755 context()->DispatchEvent("automationInternal.onTreeChange", args); 925 context()->DispatchEvent("automationInternal.onTreeChange", args);
756 } 926 }
757 927
758 } // namespace extensions 928 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698