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 5824935f85f74a4dc990bb1db09c75be02863951..9a6edcd4d49ac5f0e96d3a4dd4a6688c7765c3d6 100644 |
--- a/chrome/renderer/resources/extensions/automation_custom_bindings.js |
+++ b/chrome/renderer/resources/extensions/automation_custom_bindings.js |
@@ -15,6 +15,9 @@ var lastError = require('lastError'); |
var logging = requireNative('logging'); |
var nativeAutomationInternal = requireNative('automationInternal'); |
var GetRoutingID = nativeAutomationInternal.GetRoutingID; |
+var DestroyAccessibilityTree = |
+ nativeAutomationInternal.DestroyAccessibilityTree; |
+var GetIntAttribute = nativeAutomationInternal.GetIntAttribute; |
var GetSchemaAdditions = nativeAutomationInternal.GetSchemaAdditions(); |
var schema = GetSchemaAdditions(); |
@@ -24,7 +27,6 @@ var schema = GetSchemaAdditions(); |
window.automationUtil = function() {}; |
// TODO(aboxhall): Look into using WeakMap |
-var idToAutomationRootNode = {}; |
var idToCallback = {}; |
var DESKTOP_TREE_ID = 0; |
@@ -33,7 +35,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. |
@@ -79,8 +81,7 @@ automation.registerCustomHook(function(bindingsAPI) { |
var desktopTree = null; |
apiFunctions.setHandleRequest('getDesktop', function(callback) { |
- desktopTree = |
- idToAutomationRootNode[DESKTOP_TREE_ID]; |
+ desktopTree = AutomationRootNode.get(DESKTOP_TREE_ID); |
if (!desktopTree) { |
if (DESKTOP_TREE_ID in idToCallback) |
idToCallback[DESKTOP_TREE_ID].push(callback); |
@@ -93,8 +94,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 +125,57 @@ 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') { |
+ var childTreeID = GetIntAttribute(treeID, nodeID, 'childTreeId'); |
+ if (!AutomationRootNode.get(childTreeID)) { |
+ automationUtil.storeTreeCallback(childTreeID, function(root) { |
+ privates(root).impl.hostNode = node; |
+ |
+ 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; |
+ for (var i = 0; i < observers.length; i++) { |
+ try { |
+ observers[i](treeChange); |
+ } catch (e) { |
+ console.error('Error in tree change observer for ' + |
+ treeChange.type + ': ' + e.message + |
+ '\nStack trace: ' + e.stack); |
+ } |
+ } |
+ |
+ // |
+ // TODO: delete AutomationNode if 'removeNode' event |
David Tseng
2015/06/10 17:48:16
?
dmazzoni
2015/06/12 17:51:35
Done. I needed to remove the mapping from the id t
|
+ // |
+}); |
+ |
// 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 +187,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 +196,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 +203,17 @@ automationInternal.onAccessibilityEvent.addListener(function(data) { |
}); |
automationInternal.onAccessibilityTreeDestroyed.addListener(function(id) { |
- var targetTree = idToAutomationRootNode[id]; |
+ // Destroy the native cache of the accessibility tree. |
+ DestroyAccessibilityTree(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]; |
}); |
exports.binding = automation.generate(); |