Chromium Code Reviews| Index: chrome/renderer/resources/extensions/automation/automation_node.js |
| diff --git a/chrome/renderer/resources/extensions/automation/automation_node.js b/chrome/renderer/resources/extensions/automation/automation_node.js |
| index fb851690585913880b3ba70de3c1a2f1ea4dbd09..fd2ddd84f14d8361fecf4916d685e5287e9373be 100644 |
| --- a/chrome/renderer/resources/extensions/automation/automation_node.js |
| +++ b/chrome/renderer/resources/extensions/automation/automation_node.js |
| @@ -14,6 +14,12 @@ var schema = requireNative('automationInternal').GetSchemaAdditions(); |
| var utils = require('utils'); |
| /** |
| + * Maps an accessibility tree id to an AutomationNode with role type webView. |
| + * @type {!Object.<string, string>} |
| + */ |
| +var idToWebView_ = {}; |
| + |
| +/** |
| * A single node in the Automation tree. |
| * @param {AutomationRootNodeImpl} root The root of the tree. |
| * @constructor |
| @@ -40,18 +46,21 @@ AutomationNodeImpl.prototype = { |
| }, |
| parent: function() { |
| + if (this.role == schema.RoleType.rootWebArea) { |
| + if (idToWebView_[this.treeID]) |
| + return idToWebView_[this.treeID]; |
| + } |
| return this.rootImpl.get(this.parentID); |
| }, |
| firstChild: function() { |
| - var node = this.rootImpl.get(this.childIds[0]); |
| - return node; |
| + return this.lookupWebViewChild_() || this.rootImpl.get(this.childIds[0]); |
| }, |
| lastChild: function() { |
| var childIds = this.childIds; |
| - var node = this.rootImpl.get(childIds[childIds.length - 1]); |
| - return node; |
| + return this.lookupWebViewChild_() || |
| + this.rootImpl.get(childIds[childIds.length - 1]); |
| }, |
| children: function() { |
| @@ -118,7 +127,6 @@ AutomationNodeImpl.prototype = { |
| var parent = this.parent(); |
| while (parent) { |
| path.push(parent); |
| - // TODO(aboxhall/dtseng): handle unloaded parent node |
| parent = parent.parent(); |
| } |
| var event = new AutomationEvent(eventType, this.wrapper); |
| @@ -144,6 +152,13 @@ AutomationNodeImpl.prototype = { |
| ' attributes=' + $JSON.stringify(this.attributes); |
| }, |
| + lookupWebViewChild_: function() { |
| + if (this.role != schema.RoleType.webView) |
| + return null; |
| + |
| + return automationUtil.idToAutomationRootNode[this.childTreeID]; |
| + }, |
| + |
| dispatchEventAtCapturing_: function(event, path) { |
| privates(event).impl.eventPhase = Event.CAPTURING_PHASE; |
| for (var i = path.length - 1; i >= 0; i--) { |
| @@ -194,8 +209,7 @@ AutomationNodeImpl.prototype = { |
| performAction_: function(actionType, opt_args) { |
| // Not yet initialized. |
| - if (this.rootImpl.processID === undefined || |
| - this.rootImpl.routingID === undefined || |
| + if (this.rootImpl.treeID === undefined || |
| this.id === undefined) { |
| return; |
| } |
| @@ -206,8 +220,7 @@ AutomationNodeImpl.prototype = { |
| ' {"interact": true} in the "automation" manifest key.'); |
| } |
| - automationInternal.performAction({ processID: this.rootImpl.processID, |
| - routingID: this.rootImpl.routingID, |
| + automationInternal.performAction({ treeID: this.rootImpl.treeID, |
| automationNodeID: this.id, |
| actionType: actionType }, |
| opt_args || {}); |
| @@ -255,6 +268,7 @@ var ATTRIBUTE_NAME_TO_ATTRIBUTE_ID = { |
| * @const |
| */ |
| var ATTRIBUTE_BLACKLIST = {'activedescendantId': true, |
| + 'childTreeId': true, |
| 'controlsIds': true, |
| 'describedbyIds': true, |
| 'flowtoIds': true, |
| @@ -276,14 +290,13 @@ var ATTRIBUTE_BLACKLIST = {'activedescendantId': true, |
| * AutomationNode object. |
| * Thus, tree traversals amount to a lookup in our hash. |
| * |
| - * The tree itself is identified by the process id and routing id of the |
| + * The tree itself is identified by the accessibility tree id of the |
| * renderer widget host. |
| * @constructor |
| */ |
| -function AutomationRootNodeImpl(processID, routingID) { |
| +function AutomationRootNodeImpl(treeID) { |
| AutomationNodeImpl.call(this, this); |
| - this.processID = processID; |
| - this.routingID = routingID; |
| + this.treeID = treeID; |
| this.axNodeDataCache_ = {}; |
| } |
| @@ -292,6 +305,8 @@ AutomationRootNodeImpl.prototype = { |
| isRootNode: true, |
| + role: 'rootWebArea', |
|
aboxhall
2014/11/03 17:15:49
Why is this necessary? Won't this come down in the
David Tseng
2014/11/03 19:31:53
It was (if we give callers the placeholder node) w
|
| + |
| get: function(id) { |
| if (id == undefined) |
| return undefined; |
| @@ -353,6 +368,7 @@ AutomationRootNodeImpl.prototype = { |
| destroy: function() { |
| this.dispatchEvent(schema.EventType.destroyed); |
| this.invalidate_(this.wrapper); |
| + idToWebView_[this.treeID] = undefined; |
|
aboxhall
2014/11/03 17:15:49
delete idToWebView_[this.treeID] does the same thi
David Tseng
2014/11/03 19:31:52
Obsolete.
|
| }, |
| onAccessibilityEvent: function(eventParams) { |
| @@ -406,19 +422,10 @@ AutomationRootNodeImpl.prototype = { |
| nodeImpl[key] = AutomationAttributeDefaults[key]; |
| } |
| nodeImpl.childIds = []; |
| - nodeImpl.loaded = false; |
| nodeImpl.id = id; |
| delete this.axNodeDataCache_[id]; |
| }, |
| - load: function(callback) { |
| - // TODO(dtseng/aboxhall): Implement. |
| - if (!this.loaded) |
| - throw 'Unsupported state: root node is not loaded.'; |
| - |
| - setTimeout(callback, 0); |
| - }, |
| - |
| deleteOldChildren_: function(node, newChildIds) { |
| // Create a set of child ids in |src| for fast lookup, and return false |
| // if a duplicate is found; |
| @@ -457,6 +464,7 @@ AutomationRootNodeImpl.prototype = { |
| createNewChildren_: function(node, newChildIds, updateState) { |
| logging.CHECK(node); |
| var success = true; |
| + |
| for (var i = 0; i < newChildIds.length; i++) { |
| var childId = newChildIds[i]; |
| var childNode = this.axNodeDataCache_[childId]; |
| @@ -495,6 +503,21 @@ AutomationRootNodeImpl.prototype = { |
| setData_: function(node, nodeData) { |
| var nodeImpl = privates(node).impl; |
| + |
| + if (nodeData.role == schema.RoleType.webView) { |
|
aboxhall
2014/11/03 17:15:49
I think we should have a set of roles which can be
David Tseng
2014/11/03 19:31:53
Added TODO since that seems a bit early at this po
|
| + if (nodeImpl.pendingChildFrame === undefined) |
| + nodeImpl.pendingChildFrame = true; |
|
aboxhall
2014/11/03 17:15:49
Do we want to expose the pendingChildFrame propert
David Tseng
2014/11/03 19:31:52
I'd prefer for the caller to check if there are ch
|
| + |
| + if (nodeImpl.pendingChildFrame) { |
| + nodeImpl.childTreeID = nodeData.intAttributes.childTreeId; |
| + idToWebView_[nodeImpl.childTreeID] = node; |
|
aboxhall
2014/11/03 17:15:49
So the id in idToWebView is the ID of the frame it
David Tseng
2014/11/03 19:31:52
Obsolete with other change.
|
| + automationInternal.enableFrame(nodeImpl.childTreeID); |
| + automationUtil.storeTreeCallback(nodeImpl.childTreeID, function(root) { |
|
aboxhall
2014/11/03 17:15:49
What's preventing us from setting root.id as the s
David Tseng
2014/11/03 19:31:52
I'm pretty sure node ids are not globally unique a
aboxhall
2014/11/03 19:40:18
Ah of course, they won't be unique if they're in d
|
| + nodeImpl.pendingChildFrame = false; |
| + nodeImpl.dispatchEvent(schema.EventType.childrenChanged); |
| + }); |
| + } |
| + } |
| for (var key in AutomationAttributeDefaults) { |
| if (key in nodeData) |
| nodeImpl[key] = nodeData[key]; |
| @@ -609,9 +632,7 @@ var AutomationNode = utils.expose('AutomationNode', |
| var AutomationRootNode = utils.expose('AutomationRootNode', |
|
aboxhall
2014/11/03 17:15:49
Do we still need to expose this type at all?
David Tseng
2014/11/03 19:31:52
Still seems useful at least for testing.
|
| AutomationRootNodeImpl, |
| - { superclass: AutomationNode, |
| - functions: ['load'], |
| - readonly: ['loaded'] }); |
| + { superclass: AutomationNode }); |
| exports.AutomationNode = AutomationNode; |
| exports.AutomationRootNode = AutomationRootNode; |