Chromium Code Reviews| 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..f548e6aa57c4666df1d931bc7752dcf5b787da6a 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,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'); |
|
aboxhall
2015/06/11 17:42:46
Can you add a comment explaining what's going on i
dmazzoni
2015/06/12 17:51:36
Done. This code used to be in automation_node.js.
|
| + 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 ' + |
|
aboxhall
2015/06/11 17:42:46
Maybe use logging.WARNING - logs to stderr. https:
dmazzoni
2015/06/12 17:51:36
This is intended for extension developers. Which i
|
| + treeChange.type + ': ' + e.message + |
| + '\nStack trace: ' + e.stack); |
| + } |
| + } |
| + |
| + // |
| + // TODO: delete AutomationNode if 'removeNode' event |
| + // |
| +}); |
| + |
| // 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 +191,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 +200,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 +207,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(); |