| Index: chrome/renderer/extensions/automation_internal_custom_bindings.cc
|
| diff --git a/chrome/renderer/extensions/automation_internal_custom_bindings.cc b/chrome/renderer/extensions/automation_internal_custom_bindings.cc
|
| index 3a05d188a739a69f1cb5d5ffedf60d255fdde848..826859edb42390cdf33ddb20fa405a2085ebf4ae 100644
|
| --- a/chrome/renderer/extensions/automation_internal_custom_bindings.cc
|
| +++ b/chrome/renderer/extensions/automation_internal_custom_bindings.cc
|
| @@ -416,6 +416,8 @@ AutomationInternalCustomBindings::AutomationInternalCustomBindings(
|
| ROUTE_FUNCTION(AddTreeChangeObserver);
|
| ROUTE_FUNCTION(RemoveTreeChangeObserver);
|
| ROUTE_FUNCTION(GetChildIDAtIndex);
|
| + ROUTE_FUNCTION(GetFocus);
|
| + ROUTE_FUNCTION(GetState);
|
| #undef ROUTE_FUNCTION
|
|
|
| // Bindings that take a Tree ID and return a property of the tree.
|
| @@ -491,22 +493,6 @@ AutomationInternalCustomBindings::AutomationInternalCustomBindings(
|
| result.Set(v8::Integer::New(isolate, node->index_in_parent()));
|
| });
|
| RouteNodeIDFunction(
|
| - "GetState", [](v8::Isolate* isolate, v8::ReturnValue<v8::Value> result,
|
| - TreeCache* cache, ui::AXNode* node) {
|
| - v8::Local<v8::Object> state(v8::Object::New(isolate));
|
| - uint32_t state_pos = 0, state_shifter = node->data().state;
|
| - while (state_shifter) {
|
| - if (state_shifter & 1) {
|
| - std::string key = ToString(static_cast<ui::AXState>(state_pos));
|
| - state->Set(CreateV8String(isolate, key),
|
| - v8::Boolean::New(isolate, true));
|
| - }
|
| - state_shifter = state_shifter >> 1;
|
| - state_pos++;
|
| - }
|
| - result.Set(state);
|
| - });
|
| - RouteNodeIDFunction(
|
| "GetRole", [](v8::Isolate* isolate, v8::ReturnValue<v8::Value> result,
|
| TreeCache* cache, ui::AXNode* node) {
|
| std::string role_name = ui::ToString(node->data().role);
|
| @@ -777,6 +763,112 @@ void AutomationInternalCustomBindings::RemoveTreeChangeObserver(
|
| UpdateOverallTreeChangeObserverFilter();
|
| }
|
|
|
| +bool AutomationInternalCustomBindings::GetFocusInternal(TreeCache* cache,
|
| + TreeCache** out_cache,
|
| + ui::AXNode** out_node) {
|
| + int focus_id = cache->tree.data().focus_id;
|
| + ui::AXNode* focus = cache->tree.GetFromId(focus_id);
|
| + if (!focus)
|
| + return false;
|
| +
|
| + while (focus->data().HasIntAttribute(ui::AX_ATTR_CHILD_TREE_ID)) {
|
| + // Try to keep following focus recursively, by letting |tree_id| be the
|
| + // new subtree to search in, while keeping |focus_tree_id| set to the tree
|
| + // where we know we found a focused node.
|
| + int child_tree_id =
|
| + focus->data().GetIntAttribute(ui::AX_ATTR_CHILD_TREE_ID);
|
| +
|
| + TreeCache* child_cache = GetTreeCacheFromTreeID(child_tree_id);
|
| + if (!child_cache)
|
| + break;
|
| +
|
| + int child_focus_id = child_cache->tree.data().focus_id;
|
| + ui::AXNode* child_focus = child_cache->tree.GetFromId(child_focus_id);
|
| + if (!child_focus)
|
| + break;
|
| +
|
| + focus = child_focus;
|
| + cache = child_cache;
|
| + }
|
| +
|
| + *out_cache = cache;
|
| + *out_node = focus;
|
| + return true;
|
| +}
|
| +
|
| +void AutomationInternalCustomBindings::GetFocus(
|
| + const v8::FunctionCallbackInfo<v8::Value>& args) {
|
| + if (args.Length() != 1 || !args[0]->IsNumber()) {
|
| + ThrowInvalidArgumentsException(this);
|
| + return;
|
| + }
|
| +
|
| + int tree_id = args[0]->Int32Value();
|
| + TreeCache* cache = GetTreeCacheFromTreeID(tree_id);
|
| + if (!cache)
|
| + return;
|
| +
|
| + TreeCache* focused_tree_cache = nullptr;
|
| + ui::AXNode* focused_node = nullptr;
|
| + if (!GetFocusInternal(cache, &focused_tree_cache, &focused_node))
|
| + return;
|
| +
|
| + v8::Isolate* isolate = GetIsolate();
|
| + v8::Local<v8::Object> result(v8::Object::New(isolate));
|
| + result->Set(CreateV8String(isolate, "treeId"),
|
| + v8::Integer::New(isolate, focused_tree_cache->tree_id));
|
| + result->Set(CreateV8String(isolate, "nodeId"),
|
| + v8::Integer::New(isolate, focused_node->id()));
|
| + args.GetReturnValue().Set(result);
|
| +}
|
| +
|
| +void AutomationInternalCustomBindings::GetState(
|
| + const v8::FunctionCallbackInfo<v8::Value>& args) {
|
| + v8::Isolate* isolate = GetIsolate();
|
| + if (args.Length() < 2 || !args[0]->IsNumber() || !args[1]->IsNumber())
|
| + ThrowInvalidArgumentsException(this);
|
| +
|
| + int tree_id = args[0]->Int32Value();
|
| + int node_id = args[1]->Int32Value();
|
| +
|
| + TreeCache* cache = GetTreeCacheFromTreeID(tree_id);
|
| + if (!cache)
|
| + return;
|
| +
|
| + ui::AXNode* node = cache->tree.GetFromId(node_id);
|
| + if (!node)
|
| + return;
|
| +
|
| + v8::Local<v8::Object> state(v8::Object::New(isolate));
|
| + uint32_t state_pos = 0, state_shifter = node->data().state;
|
| + while (state_shifter) {
|
| + if (state_shifter & 1) {
|
| + std::string key = ToString(static_cast<ui::AXState>(state_pos));
|
| + state->Set(CreateV8String(isolate, key), v8::Boolean::New(isolate, true));
|
| + }
|
| + state_shifter = state_shifter >> 1;
|
| + state_pos++;
|
| + }
|
| +
|
| + TreeCache* top_cache = GetTreeCacheFromTreeID(0);
|
| + if (!top_cache)
|
| + top_cache = cache;
|
| + TreeCache* focused_cache = nullptr;
|
| + ui::AXNode* focused_node = nullptr;
|
| + if (GetFocusInternal(top_cache, &focused_cache, &focused_node)) {
|
| + if (focused_cache == cache && focused_node == node) {
|
| + state->Set(CreateV8String(isolate, "focused"),
|
| + v8::Boolean::New(isolate, true));
|
| + }
|
| + }
|
| + if (cache->tree.data().focus_id == node->id()) {
|
| + state->Set(CreateV8String(isolate, "focused"),
|
| + v8::Boolean::New(isolate, true));
|
| + }
|
| +
|
| + args.GetReturnValue().Set(state);
|
| +}
|
| +
|
| void AutomationInternalCustomBindings::UpdateOverallTreeChangeObserverFilter() {
|
| tree_change_observer_overall_filter_ =
|
| api::automation::TREE_CHANGE_OBSERVER_FILTER_NOTREECHANGES;
|
|
|