OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // Custom bindings for the automation API. | 5 // Custom bindings for the automation API. |
6 var AutomationNode = require('automationNode').AutomationNode; | 6 var AutomationNode = require('automationNode').AutomationNode; |
7 var AutomationRootNode = require('automationNode').AutomationRootNode; | 7 var AutomationRootNode = require('automationNode').AutomationRootNode; |
8 var automation = require('binding').Binding.create('automation'); | 8 var automation = require('binding').Binding.create('automation'); |
9 var automationInternal = | 9 var automationInternal = |
10 require('binding').Binding.create('automationInternal').generate(); | 10 require('binding').Binding.create('automationInternal').generate(); |
11 var eventBindings = require('event_bindings'); | 11 var eventBindings = require('event_bindings'); |
12 var Event = eventBindings.Event; | 12 var Event = eventBindings.Event; |
13 var forEach = require('utils').forEach; | 13 var forEach = require('utils').forEach; |
14 var lastError = require('lastError'); | 14 var lastError = require('lastError'); |
15 var schema = requireNative('automationInternal').GetSchemaAdditions(); | 15 var schema = requireNative('automationInternal').GetSchemaAdditions(); |
16 var logging = requireNative('logging'); | |
17 | 16 |
18 // TODO(aboxhall): Look into using WeakMap | 17 // TODO(aboxhall): Look into using WeakMap |
19 var idToAutomationRootNode = {}; | 18 var idToAutomationRootNode = {}; |
20 var idToCallback = {}; | 19 var idToCallback = {}; |
21 | 20 |
22 // TODO(dtseng): Move out to automation/automation_util.js or as a static member | 21 // TODO(dtseng): Move out to automation/automation_util.js or as a static member |
23 // of AutomationRootNode to keep this file clean. | 22 // of AutomationRootNode to keep this file clean. |
24 /* | 23 /* |
25 * Creates an id associated with a particular AutomationRootNode based upon a | 24 * Creates an id associated with a particular AutomationRootNode based upon a |
26 * renderer/renderer host pair's process and routing id. | 25 * renderer/renderer host pair's process and routing id. |
27 */ | 26 */ |
28 var createAutomationRootNodeID = function(pid, rid) { | 27 var createAutomationRootNodeID = function(pid, rid) { |
29 return pid + '_' + rid; | 28 return pid + '_' + rid; |
30 }; | 29 }; |
31 | 30 |
32 var DESKTOP_TREE_ID = createAutomationRootNodeID(0, 0); | 31 var DESKTOP_TREE_ID = createAutomationRootNodeID(0, 0); |
33 | 32 |
34 automation.registerCustomHook(function(bindingsAPI) { | 33 automation.registerCustomHook(function(bindingsAPI) { |
35 var apiFunctions = bindingsAPI.apiFunctions; | 34 var apiFunctions = bindingsAPI.apiFunctions; |
36 | 35 |
| 36 // TODO(aboxhall, dtseng): Make this return the speced AutomationRootNode obj. |
37 apiFunctions.setHandleRequest('getTree', function getTree(tabId, callback) { | 37 apiFunctions.setHandleRequest('getTree', function getTree(tabId, callback) { |
38 // enableTab() ensures the renderer for the active or specified tab has | 38 // enableTab() ensures the renderer for the active or specified tab has |
39 // accessibility enabled, and fetches its process and routing ids to use as | 39 // accessibility enabled, and fetches its process and routing ids to use as |
40 // a key in the idToAutomationRootNode map. The callback to enableTab is is | 40 // a key in the idToAutomationRootNode map. The callback to enableTab is is |
41 // bound to the callback passed in to getTree(), so that once the tree is | 41 // bound to the callback passed in to getTree(), so that once the tree is |
42 // available (either due to having been cached earlier, or after an | 42 // available (either due to having been cached earlier, or after an |
43 // accessibility event occurs which causes the tree to be populated), the | 43 // accessibility event occurs which causes the tree to be populated), the |
44 // callback can be called. | 44 // callback can be called. |
45 automationInternal.enableTab(tabId, function onEnable(pid, rid) { | 45 automationInternal.enableTab(tabId, function onEnable(pid, rid) { |
46 if (lastError.hasError(chrome)) { | 46 if (lastError.hasError(chrome)) { |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
85 } | 85 } |
86 }); | 86 }); |
87 }); | 87 }); |
88 | 88 |
89 // Listen to the automationInternal.onAccessibilityEvent event, which is | 89 // Listen to the automationInternal.onAccessibilityEvent event, which is |
90 // essentially a proxy for the AccessibilityHostMsg_Events IPC from the | 90 // essentially a proxy for the AccessibilityHostMsg_Events IPC from the |
91 // renderer. | 91 // renderer. |
92 automationInternal.onAccessibilityEvent.addListener(function(data) { | 92 automationInternal.onAccessibilityEvent.addListener(function(data) { |
93 var pid = data.processID; | 93 var pid = data.processID; |
94 var rid = data.routingID; | 94 var rid = data.routingID; |
95 logging.LOG('onAccessibilityEvent { processID: ' + pid + ', routingID: ' + | |
96 rid + ', eventType: ' + data.eventType + ' }'); | |
97 var id = createAutomationRootNodeID(pid, rid); | 95 var id = createAutomationRootNodeID(pid, rid); |
98 var targetTree = idToAutomationRootNode[id]; | 96 var targetTree = idToAutomationRootNode[id]; |
99 if (!targetTree) { | 97 if (!targetTree) { |
100 // If this is the first time we've gotten data for this tree, it will | 98 // If this is the first time we've gotten data for this tree, it will |
101 // contain all of the tree's data, so create a new tree which will be | 99 // contain all of the tree's data, so create a new tree which will be |
102 // bootstrapped from |data|. | 100 // bootstrapped from |data|. |
103 targetTree = new AutomationRootNode(pid, rid); | 101 targetTree = new AutomationRootNode(pid, rid); |
104 idToAutomationRootNode[id] = targetTree; | 102 idToAutomationRootNode[id] = targetTree; |
105 } | 103 } |
106 | |
107 if (!privates(targetTree).impl.onAccessibilityEvent(data)) | 104 if (!privates(targetTree).impl.onAccessibilityEvent(data)) |
108 return; | 105 return; |
109 | 106 |
110 // If we're not waiting on a callback to getTree(), we can early out here. | 107 // If we're not waiting on a callback to getTree(), we can early out here. |
111 if (!(id in idToCallback)) | 108 if (!(id in idToCallback)) |
112 return; | 109 return; |
113 | 110 |
114 // We usually get a 'placeholder' tree first, which doesn't have any url | 111 // We usually get a 'placeholder' tree first, which doesn't have any url |
115 // attribute or child nodes. If we've got that, wait for the full tree before | 112 // attribute or child nodes. If we've got that, wait for the full tree before |
116 // calling the callback. | 113 // calling the callback. |
117 // TODO(dmazzoni): Don't send down placeholder (crbug.com/397553) | 114 // TODO(dmazzoni): Don't send down placeholder (crbug.com/397553) |
118 if (id != DESKTOP_TREE_ID && !targetTree.attributes.url && | 115 if (id != DESKTOP_TREE_ID && !targetTree.attributes.url && |
119 targetTree.children.length == 0) { | 116 targetTree.children.length == 0) { |
120 return; | 117 return; |
121 } | 118 } |
122 | 119 |
123 // If the tree wasn't available when getTree() was called, the callback will | 120 // If the tree wasn't available when getTree() was called, the callback will |
124 // have been cached in idToCallback, so call and delete it now that we | 121 // have been cached in idToCallback, so call and delete it now that we |
125 // have the complete tree. | 122 // have the complete tree. |
126 for (var i = 0; i < idToCallback[id].length; i++) { | 123 for (var i = 0; i < idToCallback[id].length; i++) { |
127 logging.LOG('calling getTree() callback'); | 124 console.log('calling getTree() callback'); |
128 var callback = idToCallback[id][i]; | 125 var callback = idToCallback[id][i]; |
129 callback(targetTree); | 126 callback(targetTree); |
130 } | 127 } |
131 delete idToCallback[id]; | 128 delete idToCallback[id]; |
132 }); | 129 }); |
133 | 130 |
134 automationInternal.onAccessibilityTreeDestroyed.addListener(function(pid, rid) { | 131 automationInternal.onAccessibilityTreeDestroyed.addListener(function(pid, rid) { |
135 var id = createAutomationRootNodeID(pid, rid); | 132 var id = createAutomationRootNodeID(pid, rid); |
136 var targetTree = idToAutomationRootNode[id]; | 133 var targetTree = idToAutomationRootNode[id]; |
137 if (targetTree) { | 134 if (targetTree) { |
138 privates(targetTree).impl.destroy(); | 135 privates(targetTree).impl.destroy(); |
139 delete idToAutomationRootNode[id]; | 136 delete idToAutomationRootNode[id]; |
140 } else { | 137 } else { |
141 logging.WARNING('no targetTree to destroy'); | 138 logging.WARNING('no targetTree to destroy'); |
142 } | 139 } |
143 delete idToAutomationRootNode[id]; | 140 delete idToAutomationRootNode[id]; |
144 }); | 141 }); |
145 | 142 |
146 exports.binding = automation.generate(); | 143 exports.binding = automation.generate(); |
147 | 144 |
148 // Add additional accessibility bindings not specified in the automation IDL. | 145 // Add additional accessibility bindings not specified in the automation IDL. |
149 // Accessibility and automation share some APIs (see | 146 // Accessibility and automation share some APIs (see |
150 // ui/accessibility/ax_enums.idl). | 147 // ui/accessibility/ax_enums.idl). |
151 forEach(schema, function(k, v) { | 148 forEach(schema, function(k, v) { |
152 exports.binding[k] = v; | 149 exports.binding[k] = v; |
153 }); | 150 }); |
OLD | NEW |