| 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 1d8c13f4bf5d7b401569793d6f92ba93ae21e5a8..c09243ae6219431b151093548a5859ca84a1698f 100644
|
| --- a/chrome/renderer/resources/extensions/automation_custom_bindings.js
|
| +++ b/chrome/renderer/resources/extensions/automation_custom_bindings.js
|
| @@ -22,6 +22,9 @@ var DestroyAccessibilityTree =
|
| var GetIntAttribute = nativeAutomationInternal.GetIntAttribute;
|
| var StartCachingAccessibilityTrees =
|
| nativeAutomationInternal.StartCachingAccessibilityTrees;
|
| +var AddTreeChangeObserver = nativeAutomationInternal.AddTreeChangeObserver;
|
| +var RemoveTreeChangeObserver =
|
| + nativeAutomationInternal.RemoveTreeChangeObserver;
|
| var schema = GetSchemaAdditions();
|
|
|
| /**
|
| @@ -53,9 +56,15 @@ automationUtil.storeTreeCallback = function(id, callback) {
|
|
|
| /**
|
| * Global list of tree change observers.
|
| - * @type {Array<TreeChangeObserver>}
|
| + * @type {Object<number, TreeChangeObserver>}
|
| */
|
| -automationUtil.treeChangeObservers = [];
|
| +automationUtil.treeChangeObserverMap = {};
|
| +
|
| +/**
|
| + * The id of the next tree change observer.
|
| + * @type {number}
|
| + */
|
| +automationUtil.nextTreeChangeObserverId = 1;
|
|
|
| automation.registerCustomHook(function(bindingsAPI) {
|
| var apiFunctions = bindingsAPI.apiFunctions;
|
| @@ -110,22 +119,27 @@ automation.registerCustomHook(function(bindingsAPI) {
|
| });
|
|
|
| function removeTreeChangeObserver(observer) {
|
| - var observers = automationUtil.treeChangeObservers;
|
| - for (var i = 0; i < observers.length; i++) {
|
| - if (observer == observers[i])
|
| - observers.splice(i, 1);
|
| + for (var id in automationUtil.treeChangeObserverMap) {
|
| + if (automationUtil.treeChangeObserverMap[id] == observer) {
|
| + RemoveTreeChangeObserver(id);
|
| + delete automationUtil.treeChangeObserverMap[id];
|
| + return;
|
| + }
|
| }
|
| }
|
| apiFunctions.setHandleRequest('removeTreeChangeObserver', function(observer) {
|
| removeTreeChangeObserver(observer);
|
| });
|
|
|
| - function addTreeChangeObserver(observer) {
|
| + function addTreeChangeObserver(filter, observer) {
|
| removeTreeChangeObserver(observer);
|
| - automationUtil.treeChangeObservers.push(observer);
|
| + var id = automationUtil.nextTreeChangeObserverId++;
|
| + AddTreeChangeObserver(id, filter);
|
| + automationUtil.treeChangeObserverMap[id] = observer;
|
| }
|
| - apiFunctions.setHandleRequest('addTreeChangeObserver', function(observer) {
|
| - addTreeChangeObserver(observer);
|
| + apiFunctions.setHandleRequest('addTreeChangeObserver',
|
| + function(filter, observer) {
|
| + addTreeChangeObserver(filter, observer);
|
| });
|
|
|
| apiFunctions.setHandleRequest('setDocumentSelection', function(params) {
|
| @@ -147,7 +161,44 @@ automation.registerCustomHook(function(bindingsAPI) {
|
|
|
| });
|
|
|
| -automationInternal.onTreeChange.addListener(function(treeID,
|
| +automationInternal.onChildTreeID.addListener(function(treeID,
|
| + nodeID) {
|
| + var tree = AutomationRootNode.getOrCreate(treeID);
|
| + if (!tree)
|
| + return;
|
| +
|
| + var node = privates(tree).impl.get(nodeID);
|
| + if (!node)
|
| + return;
|
| +
|
| + // 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 (!childTreeID)
|
| + return;
|
| +
|
| + var subroot = AutomationRootNode.get(childTreeID);
|
| + if (!subroot) {
|
| + automationUtil.storeTreeCallback(childTreeID, function(root) {
|
| + privates(root).impl.setHostNode(node);
|
| +
|
| + if (root.docLoaded)
|
| + privates(root).impl.dispatchEvent(schema.EventType.loadComplete);
|
| +
|
| + privates(node).impl.dispatchEvent(schema.EventType.childrenChanged);
|
| + });
|
| +
|
| + automationInternal.enableFrame(childTreeID);
|
| + } else {
|
| + privates(subroot).impl.setHostNode(node);
|
| + }
|
| +});
|
| +
|
| +automationInternal.onTreeChange.addListener(function(observerID,
|
| + treeID,
|
| nodeID,
|
| changeType) {
|
| var tree = AutomationRootNode.getOrCreate(treeID);
|
| @@ -158,49 +209,25 @@ automationInternal.onTreeChange.addListener(function(treeID,
|
| if (!node)
|
| return;
|
|
|
| - if (node.role == 'webView' || node.role == 'embeddedObject') {
|
| - // 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 (!childTreeID)
|
| - return;
|
| -
|
| - var subroot = AutomationRootNode.get(childTreeID);
|
| - if (!subroot) {
|
| - automationUtil.storeTreeCallback(childTreeID, function(root) {
|
| - privates(root).impl.setHostNode(node);
|
| -
|
| - if (root.docLoaded)
|
| - privates(root).impl.dispatchEvent(schema.EventType.loadComplete);
|
| -
|
| - privates(node).impl.dispatchEvent(schema.EventType.childrenChanged);
|
| - });
|
| + var observer = automationUtil.treeChangeObserverMap[observerID];
|
| + if (!observer)
|
| + return;
|
|
|
| - automationInternal.enableFrame(childTreeID);
|
| - } else {
|
| - privates(subroot).impl.setHostNode(node);
|
| - }
|
| + try {
|
| + observer({target: node, type: changeType});
|
| + } catch (e) {
|
| + exceptionHandler.handle('Error in tree change observer for ' +
|
| + treeChange.type, e);
|
| }
|
| +});
|
|
|
| - var treeChange = {target: node, type: changeType};
|
| -
|
| - // Make a copy of the observers in case one of these callbacks tries
|
| - // to change the list of observers.
|
| - var observers = automationUtil.treeChangeObservers.slice();
|
| - for (var i = 0; i < observers.length; i++) {
|
| - try {
|
| - observers[i](treeChange);
|
| - } catch (e) {
|
| - exceptionHandler.handle('Error in tree change observer for ' +
|
| - treeChange.type, e);
|
| - }
|
| - }
|
| +automationInternal.onNodesRemoved.addListener(function(treeID, nodeIDs) {
|
| + var tree = AutomationRootNode.getOrCreate(treeID);
|
| + if (!tree)
|
| + return;
|
|
|
| - if (changeType == schema.TreeChangeType.nodeRemoved) {
|
| - privates(tree).impl.remove(nodeID);
|
| + for (var i = 0; i < nodeIDs.length; i++) {
|
| + privates(tree).impl.remove(nodeIDs[i]);
|
| }
|
| });
|
|
|
|
|