Give names to all utility processes.
[chromium-blink-merge.git] / chrome / renderer / resources / extensions / automation_custom_bindings.js
blob3d38afc4e0a5c427a40f93c8108a22a99e5aaede
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 // Custom bindings for the automation API.
6 var AutomationNode = require('automationNode').AutomationNode;
7 var AutomationRootNode = require('automationNode').AutomationRootNode;
8 var automation = require('binding').Binding.create('automation');
9 var automationInternal =
10 require('binding').Binding.create('automationInternal').generate();
11 var eventBindings = require('event_bindings');
12 var Event = eventBindings.Event;
13 var forEach = require('utils').forEach;
14 var lastError = require('lastError');
15 var logging = requireNative('logging');
16 var schema = requireNative('automationInternal').GetSchemaAdditions();
18 /**
19 * A namespace to export utility functions to other files in automation.
21 window.automationUtil = function() {};
23 // TODO(aboxhall): Look into using WeakMap
24 var idToAutomationRootNode = {};
25 var idToCallback = {};
27 var DESKTOP_TREE_ID = 0;
29 automationUtil.storeTreeCallback = function(id, callback) {
30 if (!callback)
31 return;
33 var targetTree = idToAutomationRootNode[id];
34 if (!targetTree) {
35 // If we haven't cached the tree, hold the callback until the tree is
36 // populated by the initial onAccessibilityEvent call.
37 if (id in idToCallback)
38 idToCallback[id].push(callback);
39 else
40 idToCallback[id] = [callback];
41 } else {
42 callback(targetTree);
46 /**
47 * Global list of tree change observers.
48 * @type {Array<TreeChangeObserver>}
50 automationUtil.treeChangeObservers = [];
52 automation.registerCustomHook(function(bindingsAPI) {
53 var apiFunctions = bindingsAPI.apiFunctions;
55 // TODO(aboxhall, dtseng): Make this return the speced AutomationRootNode obj.
56 apiFunctions.setHandleRequest('getTree', function getTree(tabId, callback) {
57 // enableTab() ensures the renderer for the active or specified tab has
58 // accessibility enabled, and fetches its ax tree id to use as
59 // a key in the idToAutomationRootNode map. The callback to
60 // enableTab is bound to the callback passed in to getTree(), so that once
61 // the tree is available (either due to having been cached earlier, or after
62 // an accessibility event occurs which causes the tree to be populated), the
63 // callback can be called.
64 automationInternal.enableTab(tabId, function onEnable(id) {
65 if (lastError.hasError(chrome)) {
66 callback();
67 return;
69 automationUtil.storeTreeCallback(id, callback);
70 });
71 });
73 var desktopTree = null;
74 apiFunctions.setHandleRequest('getDesktop', function(callback) {
75 desktopTree =
76 idToAutomationRootNode[DESKTOP_TREE_ID];
77 if (!desktopTree) {
78 if (DESKTOP_TREE_ID in idToCallback)
79 idToCallback[DESKTOP_TREE_ID].push(callback);
80 else
81 idToCallback[DESKTOP_TREE_ID] = [callback];
83 // TODO(dtseng): Disable desktop tree once desktop object goes out of
84 // scope.
85 automationInternal.enableDesktop(function() {
86 if (lastError.hasError(chrome)) {
87 delete idToAutomationRootNode[
88 DESKTOP_TREE_ID];
89 callback();
90 return;
92 });
93 } else {
94 callback(desktopTree);
96 });
98 function removeTreeChangeObserver(observer) {
99 var observers = automationUtil.treeChangeObservers;
100 for (var i = 0; i < observers.length; i++) {
101 if (observer == observers[i])
102 observers.splice(i, 1);
105 apiFunctions.setHandleRequest('removeTreeChangeObserver', function(observer) {
106 removeTreeChangeObserver(observer);
109 function addTreeChangeObserver(observer) {
110 removeTreeChangeObserver(observer);
111 automationUtil.treeChangeObservers.push(observer);
113 apiFunctions.setHandleRequest('addTreeChangeObserver', function(observer) {
114 addTreeChangeObserver(observer);
119 // Listen to the automationInternal.onAccessibilityEvent event, which is
120 // essentially a proxy for the AccessibilityHostMsg_Events IPC from the
121 // renderer.
122 automationInternal.onAccessibilityEvent.addListener(function(data) {
123 var id = data.treeID;
124 var targetTree = idToAutomationRootNode[id];
125 if (!targetTree) {
126 // If this is the first time we've gotten data for this tree, it will
127 // contain all of the tree's data, so create a new tree which will be
128 // bootstrapped from |data|.
129 targetTree = new AutomationRootNode(id);
130 idToAutomationRootNode[id] = targetTree;
132 if (!privates(targetTree).impl.onAccessibilityEvent(data))
133 return;
135 // If we're not waiting on a callback to getTree(), we can early out here.
136 if (!(id in idToCallback))
137 return;
139 // We usually get a 'placeholder' tree first, which doesn't have any url
140 // attribute or child nodes. If we've got that, wait for the full tree before
141 // calling the callback.
142 // TODO(dmazzoni): Don't send down placeholder (crbug.com/397553)
143 if (id != DESKTOP_TREE_ID && !targetTree.attributes.url &&
144 targetTree.children.length == 0) {
145 return;
148 // If the tree wasn't available when getTree() was called, the callback will
149 // have been cached in idToCallback, so call and delete it now that we
150 // have the complete tree.
151 for (var i = 0; i < idToCallback[id].length; i++) {
152 console.log('calling getTree() callback');
153 var callback = idToCallback[id][i];
154 callback(targetTree);
156 delete idToCallback[id];
159 automationInternal.onAccessibilityTreeDestroyed.addListener(function(id) {
160 var targetTree = idToAutomationRootNode[id];
161 if (targetTree) {
162 privates(targetTree).impl.destroy();
163 delete idToAutomationRootNode[id];
164 } else {
165 logging.WARNING('no targetTree to destroy');
167 delete idToAutomationRootNode[id];
170 exports.binding = automation.generate();
172 // Add additional accessibility bindings not specified in the automation IDL.
173 // Accessibility and automation share some APIs (see
174 // ui/accessibility/ax_enums.idl).
175 forEach(schema, function(k, v) {
176 exports.binding[k] = v;