| 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 exceptionHandler = require('uncaught_exception_handler'); | 13 var exceptionHandler = require('uncaught_exception_handler'); |
| 14 var forEach = require('utils').forEach; | 14 var forEach = require('utils').forEach; |
| 15 var lastError = require('lastError'); | 15 var lastError = require('lastError'); |
| 16 var logging = requireNative('logging'); | 16 var logging = requireNative('logging'); |
| 17 var nativeAutomationInternal = requireNative('automationInternal'); | 17 var nativeAutomationInternal = requireNative('automationInternal'); |
| 18 var GetRoutingID = nativeAutomationInternal.GetRoutingID; | 18 var GetRoutingID = nativeAutomationInternal.GetRoutingID; |
| 19 var GetSchemaAdditions = nativeAutomationInternal.GetSchemaAdditions; | 19 var GetSchemaAdditions = nativeAutomationInternal.GetSchemaAdditions; |
| 20 var DestroyAccessibilityTree = | 20 var DestroyAccessibilityTree = |
| 21 nativeAutomationInternal.DestroyAccessibilityTree; | 21 nativeAutomationInternal.DestroyAccessibilityTree; |
| 22 var GetIntAttribute = nativeAutomationInternal.GetIntAttribute; | 22 var GetIntAttribute = nativeAutomationInternal.GetIntAttribute; |
| 23 var StartCachingAccessibilityTrees = | 23 var StartCachingAccessibilityTrees = |
| 24 nativeAutomationInternal.StartCachingAccessibilityTrees; | 24 nativeAutomationInternal.StartCachingAccessibilityTrees; |
| 25 var AddTreeChangeObserver = nativeAutomationInternal.AddTreeChangeObserver; | 25 var AddTreeChangeObserver = nativeAutomationInternal.AddTreeChangeObserver; |
| 26 var RemoveTreeChangeObserver = | 26 var RemoveTreeChangeObserver = |
| 27 nativeAutomationInternal.RemoveTreeChangeObserver; | 27 nativeAutomationInternal.RemoveTreeChangeObserver; |
| 28 var GetFocus = nativeAutomationInternal.GetFocus; |
| 28 var schema = GetSchemaAdditions(); | 29 var schema = GetSchemaAdditions(); |
| 29 | 30 |
| 30 /** | 31 /** |
| 31 * A namespace to export utility functions to other files in automation. | 32 * A namespace to export utility functions to other files in automation. |
| 32 */ | 33 */ |
| 33 window.automationUtil = function() {}; | 34 window.automationUtil = function() {}; |
| 34 | 35 |
| 35 // TODO(aboxhall): Look into using WeakMap | 36 // TODO(aboxhall): Look into using WeakMap |
| 36 var idToCallback = {}; | 37 var idToCallback = {}; |
| 37 | 38 |
| (...skipping 21 matching lines...) Expand all Loading... |
| 59 * @type {Object<number, TreeChangeObserver>} | 60 * @type {Object<number, TreeChangeObserver>} |
| 60 */ | 61 */ |
| 61 automationUtil.treeChangeObserverMap = {}; | 62 automationUtil.treeChangeObserverMap = {}; |
| 62 | 63 |
| 63 /** | 64 /** |
| 64 * The id of the next tree change observer. | 65 * The id of the next tree change observer. |
| 65 * @type {number} | 66 * @type {number} |
| 66 */ | 67 */ |
| 67 automationUtil.nextTreeChangeObserverId = 1; | 68 automationUtil.nextTreeChangeObserverId = 1; |
| 68 | 69 |
| 70 /** |
| 71 * @type {AutomationNode} The current focused node. This is only updated |
| 72 * when calling automationUtil.updateFocusedNode. |
| 73 */ |
| 74 automationUtil.focusedNode = null; |
| 75 |
| 76 /** |
| 77 * Update automationUtil.focusedNode to be the node that currently has focus. |
| 78 */ |
| 79 automationUtil.updateFocusedNode = function() { |
| 80 automationUtil.focusedNode = null; |
| 81 var focusedNodeInfo = GetFocus(DESKTOP_TREE_ID); |
| 82 if (!focusedNodeInfo) |
| 83 return; |
| 84 var tree = AutomationRootNode.getOrCreate(focusedNodeInfo.treeId); |
| 85 if (tree) { |
| 86 automationUtil.focusedNode = |
| 87 privates(tree).impl.get(focusedNodeInfo.nodeId); |
| 88 } |
| 89 }; |
| 90 |
| 69 automation.registerCustomHook(function(bindingsAPI) { | 91 automation.registerCustomHook(function(bindingsAPI) { |
| 70 var apiFunctions = bindingsAPI.apiFunctions; | 92 var apiFunctions = bindingsAPI.apiFunctions; |
| 71 | 93 |
| 72 // TODO(aboxhall, dtseng): Make this return the speced AutomationRootNode obj. | 94 // TODO(aboxhall, dtseng): Make this return the speced AutomationRootNode obj. |
| 73 apiFunctions.setHandleRequest('getTree', function getTree(tabID, callback) { | 95 apiFunctions.setHandleRequest('getTree', function getTree(tabID, callback) { |
| 74 var routingID = GetRoutingID(); | 96 var routingID = GetRoutingID(); |
| 75 StartCachingAccessibilityTrees(); | 97 StartCachingAccessibilityTrees(); |
| 76 | 98 |
| 77 // enableTab() ensures the renderer for the active or specified tab has | 99 // enableTab() ensures the renderer for the active or specified tab has |
| 78 // accessibility enabled, and fetches its ax tree id to use as | 100 // accessibility enabled, and fetches its ax tree id to use as |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 111 AutomationRootNode.destroy(DESKTOP_TREE_ID); | 133 AutomationRootNode.destroy(DESKTOP_TREE_ID); |
| 112 callback(); | 134 callback(); |
| 113 return; | 135 return; |
| 114 } | 136 } |
| 115 }); | 137 }); |
| 116 } else { | 138 } else { |
| 117 callback(desktopTree); | 139 callback(desktopTree); |
| 118 } | 140 } |
| 119 }); | 141 }); |
| 120 | 142 |
| 143 apiFunctions.setHandleRequest('getFocus', function() { |
| 144 automationUtil.updateFocusedNode(); |
| 145 return automationUtil.focusedNode; |
| 146 }); |
| 147 |
| 121 function removeTreeChangeObserver(observer) { | 148 function removeTreeChangeObserver(observer) { |
| 122 for (var id in automationUtil.treeChangeObserverMap) { | 149 for (var id in automationUtil.treeChangeObserverMap) { |
| 123 if (automationUtil.treeChangeObserverMap[id] == observer) { | 150 if (automationUtil.treeChangeObserverMap[id] == observer) { |
| 124 RemoveTreeChangeObserver(id); | 151 RemoveTreeChangeObserver(id); |
| 125 delete automationUtil.treeChangeObserverMap[id]; | 152 delete automationUtil.treeChangeObserverMap[id]; |
| 126 return; | 153 return; |
| 127 } | 154 } |
| 128 } | 155 } |
| 129 } | 156 } |
| 130 apiFunctions.setHandleRequest('removeTreeChangeObserver', function(observer) { | 157 apiFunctions.setHandleRequest('removeTreeChangeObserver', function(observer) { |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 224 automationInternal.onNodesRemoved.addListener(function(treeID, nodeIDs) { | 251 automationInternal.onNodesRemoved.addListener(function(treeID, nodeIDs) { |
| 225 var tree = AutomationRootNode.getOrCreate(treeID); | 252 var tree = AutomationRootNode.getOrCreate(treeID); |
| 226 if (!tree) | 253 if (!tree) |
| 227 return; | 254 return; |
| 228 | 255 |
| 229 for (var i = 0; i < nodeIDs.length; i++) { | 256 for (var i = 0; i < nodeIDs.length; i++) { |
| 230 privates(tree).impl.remove(nodeIDs[i]); | 257 privates(tree).impl.remove(nodeIDs[i]); |
| 231 } | 258 } |
| 232 }); | 259 }); |
| 233 | 260 |
| 234 // Listen to the automationInternal.onAccessibilityEvent event, which is | 261 /** |
| 235 // essentially a proxy for the AccessibilityHostMsg_Events IPC from the | 262 * Dispatch accessibility events fired on individual nodes to its |
| 236 // renderer. | 263 * corresponding AutomationNode. Handle focus events specially |
| 237 automationInternal.onAccessibilityEvent.addListener(function(data) { | 264 * (see below). |
| 238 var id = data.treeID; | 265 */ |
| 266 automationInternal.onAccessibilityEvent.addListener(function(eventParams) { |
| 267 var id = eventParams.treeID; |
| 239 var targetTree = AutomationRootNode.getOrCreate(id); | 268 var targetTree = AutomationRootNode.getOrCreate(id); |
| 240 | 269 |
| 241 if (!privates(targetTree).impl.onAccessibilityEvent(data)) | 270 // When we get a focus event, ignore the actual event target, and instead |
| 271 // check what node has focus globally. If that represents a focus change, |
| 272 // fire a focus event on the correct target. |
| 273 if (eventParams.eventType == schema.EventType.focus) { |
| 274 var previousFocusedNode = automationUtil.focusedNode; |
| 275 automationUtil.updateFocusedNode(); |
| 276 if (automationUtil.focusedNode == previousFocusedNode) |
| 277 return; |
| 278 |
| 279 if (automationUtil.focusedNode == null) |
| 280 return; |
| 281 |
| 282 targetTree = automationUtil.focusedNode.root; |
| 283 eventParams.treeID = privates(targetTree).impl.treeID; |
| 284 eventParams.targetID = privates(automationUtil.focusedNode).impl.id; |
| 285 } |
| 286 |
| 287 if (!privates(targetTree).impl.onAccessibilityEvent(eventParams)) |
| 242 return; | 288 return; |
| 243 | 289 |
| 244 // If we're not waiting on a callback to getTree(), we can early out here. | 290 // If we're not waiting on a callback to getTree(), we can early out here. |
| 245 if (!(id in idToCallback)) | 291 if (!(id in idToCallback)) |
| 246 return; | 292 return; |
| 247 | 293 |
| 248 // We usually get a 'placeholder' tree first, which doesn't have any url | 294 // We usually get a 'placeholder' tree first, which doesn't have any url |
| 249 // attribute or child nodes. If we've got that, wait for the full tree before | 295 // attribute or child nodes. If we've got that, wait for the full tree before |
| 250 // calling the callback. | 296 // calling the callback. |
| 251 // TODO(dmazzoni): Don't send down placeholder (crbug.com/397553) | 297 // TODO(dmazzoni): Don't send down placeholder (crbug.com/397553) |
| (...skipping 26 matching lines...) Expand all Loading... |
| 278 }); | 324 }); |
| 279 | 325 |
| 280 exports.binding = automation.generate(); | 326 exports.binding = automation.generate(); |
| 281 | 327 |
| 282 // Add additional accessibility bindings not specified in the automation IDL. | 328 // Add additional accessibility bindings not specified in the automation IDL. |
| 283 // Accessibility and automation share some APIs (see | 329 // Accessibility and automation share some APIs (see |
| 284 // ui/accessibility/ax_enums.idl). | 330 // ui/accessibility/ax_enums.idl). |
| 285 forEach(schema, function(k, v) { | 331 forEach(schema, function(k, v) { |
| 286 exports.binding[k] = v; | 332 exports.binding[k] = v; |
| 287 }); | 333 }); |
| OLD | NEW |