Index: chrome/renderer/resources/extensions/automation_custom_bindings.js |
diff --git a/chrome/renderer/resources/extensions/automation_custom_bindings.js b/chrome/renderer/resources/extensions/automation_custom_bindings.js |
index b2fc5c3b711d1b9dc49fb8c04648d91c33aef577..3f8e44680023a4d4a26841e19cc507db21cbec79 100644 |
--- a/chrome/renderer/resources/extensions/automation_custom_bindings.js |
+++ b/chrome/renderer/resources/extensions/automation_custom_bindings.js |
@@ -16,6 +16,11 @@ var logging = requireNative('logging'); |
var nativeAutomationInternal = requireNative('automationInternal'); |
var GetRoutingID = nativeAutomationInternal.GetRoutingID; |
var GetSchemaAdditions = nativeAutomationInternal.GetSchemaAdditions; |
+var DestroyAccessibilityTree = |
+ nativeAutomationInternal.DestroyAccessibilityTree; |
+var GetIntAttribute = nativeAutomationInternal.GetIntAttribute; |
+var StartCachingAccessibilityTrees = |
+ nativeAutomationInternal.StartCachingAccessibilityTrees; |
var schema = GetSchemaAdditions(); |
/** |
@@ -24,7 +29,6 @@ var schema = GetSchemaAdditions(); |
window.automationUtil = function() {}; |
// TODO(aboxhall): Look into using WeakMap |
-var idToAutomationRootNode = {}; |
var idToCallback = {}; |
var DESKTOP_TREE_ID = 0; |
@@ -33,7 +37,7 @@ automationUtil.storeTreeCallback = function(id, callback) { |
if (!callback) |
return; |
- var targetTree = idToAutomationRootNode[id]; |
+ var targetTree = AutomationRootNode.get(id); |
if (!targetTree) { |
// If we haven't cached the tree, hold the callback until the tree is |
// populated by the initial onAccessibilityEvent call. |
@@ -58,6 +62,7 @@ automation.registerCustomHook(function(bindingsAPI) { |
// TODO(aboxhall, dtseng): Make this return the speced AutomationRootNode obj. |
apiFunctions.setHandleRequest('getTree', function getTree(tabID, callback) { |
var routingID = GetRoutingID(); |
+ StartCachingAccessibilityTrees(); |
// enableTab() ensures the renderer for the active or specified tab has |
// accessibility enabled, and fetches its ax tree id to use as |
@@ -79,8 +84,8 @@ automation.registerCustomHook(function(bindingsAPI) { |
var desktopTree = null; |
apiFunctions.setHandleRequest('getDesktop', function(callback) { |
- desktopTree = |
- idToAutomationRootNode[DESKTOP_TREE_ID]; |
+ StartCachingAccessibilityTrees(); |
+ desktopTree = AutomationRootNode.get(DESKTOP_TREE_ID); |
if (!desktopTree) { |
if (DESKTOP_TREE_ID in idToCallback) |
idToCallback[DESKTOP_TREE_ID].push(callback); |
@@ -93,8 +98,7 @@ automation.registerCustomHook(function(bindingsAPI) { |
// scope. |
automationInternal.enableDesktop(routingID, function() { |
if (lastError.hasError(chrome)) { |
- delete idToAutomationRootNode[ |
- DESKTOP_TREE_ID]; |
+ AutomationRootNode.destroy(DESKTOP_TREE_ID); |
callback(); |
return; |
} |
@@ -125,19 +129,62 @@ automation.registerCustomHook(function(bindingsAPI) { |
}); |
+automationInternal.onTreeChange.addListener(function(treeID, |
+ nodeID, |
+ changeType) { |
+ var tree = AutomationRootNode.get(treeID); |
+ if (!tree) |
+ return; |
+ |
+ var node = privates(tree).impl.get(nodeID); |
+ if (!node) |
+ return; |
+ |
+ if (node.role == 'webView') { |
+ // A WebView in the desktop tree has a different AX tree as its child. |
+ // When we encounter a WebView with a child AX tree id that we don't |
+ // currently have cached, explicitly request that AX tree from the |
+ // browser process and set up a callback when it loads to attach that |
+ // tree as a child of this node and fire appropriate events. |
+ var childTreeID = GetIntAttribute(treeID, nodeID, 'childTreeId'); |
+ if (!AutomationRootNode.get(childTreeID)) { |
+ automationUtil.storeTreeCallback(childTreeID, function(root) { |
+ privates(root).impl.hostNode = node; |
not at google - send to devlin
2015/06/17 21:14:48
Glancing at this code (and not understanding it),
dmazzoni
2015/06/18 07:23:53
Done.
not at google - send to devlin
2015/06/18 17:34:38
Is there a semantically reasonable function that c
dmazzoni
2015/06/18 21:31:53
I'm not sure why - I consider automation_custom_bi
|
+ |
+ if (root.docLoaded) |
+ privates(root).impl.dispatchEvent(schema.EventType.loadComplete); |
+ |
+ privates(node).impl.dispatchEvent(schema.EventType.childrenChanged); |
+ }); |
+ |
+ automationInternal.enableFrame(childTreeID); |
+ } |
+ } |
+ |
+ var treeChange = {target: node, type: changeType}; |
+ var observers = automationUtil.treeChangeObservers; |
not at google - send to devlin
2015/06/17 21:14:48
I don't know where this code came from, but note t
dmazzoni
2015/06/18 07:23:53
Good idea. I changed it to make a copy of the arra
|
+ for (var i = 0; i < observers.length; i++) { |
+ try { |
+ observers[i](treeChange); |
+ } catch (e) { |
+ logging.WARNING('Error in tree change observer for ' + |
+ treeChange.type + ': ' + e.message + |
+ '\nStack trace: ' + e.stack); |
+ } |
+ } |
+ |
+ if (changeType == schema.TreeChangeType.nodeRemoved) { |
+ privates(tree).impl.remove(nodeID); |
+ } |
+}); |
+ |
// Listen to the automationInternal.onAccessibilityEvent event, which is |
// essentially a proxy for the AccessibilityHostMsg_Events IPC from the |
// renderer. |
automationInternal.onAccessibilityEvent.addListener(function(data) { |
var id = data.treeID; |
- var targetTree = idToAutomationRootNode[id]; |
- if (!targetTree) { |
- // If this is the first time we've gotten data for this tree, it will |
- // contain all of the tree's data, so create a new tree which will be |
- // bootstrapped from |data|. |
- targetTree = new AutomationRootNode(id); |
- idToAutomationRootNode[id] = targetTree; |
- } |
+ var targetTree = AutomationRootNode.getOrCreate(id); |
+ |
if (!privates(targetTree).impl.onAccessibilityEvent(data)) |
return; |
@@ -149,7 +196,7 @@ automationInternal.onAccessibilityEvent.addListener(function(data) { |
// attribute or child nodes. If we've got that, wait for the full tree before |
// calling the callback. |
// TODO(dmazzoni): Don't send down placeholder (crbug.com/397553) |
- if (id != DESKTOP_TREE_ID && !targetTree.attributes.url && |
+ if (id != DESKTOP_TREE_ID && !targetTree.url && |
targetTree.children.length == 0) { |
return; |
} |
@@ -158,7 +205,6 @@ automationInternal.onAccessibilityEvent.addListener(function(data) { |
// have been cached in idToCallback, so call and delete it now that we |
// have the complete tree. |
for (var i = 0; i < idToCallback[id].length; i++) { |
- console.log('calling getTree() callback'); |
var callback = idToCallback[id][i]; |
callback(targetTree); |
} |
@@ -166,14 +212,17 @@ automationInternal.onAccessibilityEvent.addListener(function(data) { |
}); |
automationInternal.onAccessibilityTreeDestroyed.addListener(function(id) { |
- var targetTree = idToAutomationRootNode[id]; |
+ // Destroy the AutomationRootNode. |
+ var targetTree = AutomationRootNode.get(id); |
if (targetTree) { |
privates(targetTree).impl.destroy(); |
- delete idToAutomationRootNode[id]; |
+ AutomationRootNode.destroy(id); |
} else { |
logging.WARNING('no targetTree to destroy'); |
} |
- delete idToAutomationRootNode[id]; |
+ |
+ // Destroy the native cache of the accessibility tree. |
+ DestroyAccessibilityTree(id); |
}); |
exports.binding = automation.generate(); |