1 // Copyright (c) 2012 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. 4 5 #include "content/browser/accessibility/browser_accessibility_manager.h" 6 7 #include "base/logging.h" 8 #include "content/browser/accessibility/browser_accessibility.h" 9 #include "content/common/accessibility_messages.h" 10 11 namespace content { 12 13 BrowserAccessibility* BrowserAccessibilityFactory::Create() { 14 return BrowserAccessibility::Create(); 15 } 16 17 #if !defined(OS_MACOSX) && \ 18 !defined(OS_WIN) && \ 19 !defined(TOOLKIT_GTK) && \ 20 !defined(OS_ANDROID) \ 21 // We have subclassess of BrowserAccessibilityManager on Mac, Linux/GTK, 22 // and Win. For any other platform, instantiate the base class. 23 // static 24 BrowserAccessibilityManager* BrowserAccessibilityManager::Create( 25 const AccessibilityNodeData& src, 26 BrowserAccessibilityDelegate* delegate, 27 BrowserAccessibilityFactory* factory) { 28 return new BrowserAccessibilityManager(src, delegate, factory); 29 } 30 #endif 31 32 BrowserAccessibilityManager::BrowserAccessibilityManager( 33 BrowserAccessibilityDelegate* delegate, 34 BrowserAccessibilityFactory* factory) 35 : delegate_(delegate), 36 factory_(factory), 37 root_(NULL), 38 focus_(NULL), 39 osk_state_(OSK_ALLOWED) { 40 } 41 42 BrowserAccessibilityManager::BrowserAccessibilityManager( 43 const AccessibilityNodeData& src, 44 BrowserAccessibilityDelegate* delegate, 45 BrowserAccessibilityFactory* factory) 46 : delegate_(delegate), 47 factory_(factory), 48 root_(NULL), 49 focus_(NULL), 50 osk_state_(OSK_ALLOWED) { 51 Initialize(src); 52 } 53 54 BrowserAccessibilityManager::~BrowserAccessibilityManager() { 55 if (root_) 56 root_->Destroy(); 57 } 58 59 void BrowserAccessibilityManager::Initialize(const AccessibilityNodeData src) { 60 std::vector<AccessibilityNodeData> nodes; 61 nodes.push_back(src); 62 if (!UpdateNodes(nodes)) 63 return; 64 if (!focus_) 65 SetFocus(root_, false); 66 } 67 68 // static 69 AccessibilityNodeData BrowserAccessibilityManager::GetEmptyDocument() { 70 AccessibilityNodeData empty_document; 71 empty_document.id = 0; 72 empty_document.role = AccessibilityNodeData::ROLE_ROOT_WEB_AREA; 73 return empty_document; 74 } 75 76 BrowserAccessibility* BrowserAccessibilityManager::GetRoot() { 77 return root_; 78 } 79 80 BrowserAccessibility* BrowserAccessibilityManager::GetFromRendererID( 81 int32 renderer_id) { 82 base::hash_map<int32, BrowserAccessibility*>::iterator iter = 83 renderer_id_map_.find(renderer_id); 84 if (iter != renderer_id_map_.end()) 85 return iter->second; 86 return NULL; 87 } 88 89 void BrowserAccessibilityManager::GotFocus(bool touch_event_context) { 90 if (!touch_event_context) 91 osk_state_ = OSK_DISALLOWED_BECAUSE_TAB_JUST_APPEARED; 92 93 if (!focus_) 94 return; 95 96 NotifyAccessibilityEvent(AccessibilityNotificationFocusChanged, focus_); 97 } 98 99 void BrowserAccessibilityManager::WasHidden() { 100 osk_state_ = OSK_DISALLOWED_BECAUSE_TAB_HIDDEN; 101 } 102 103 void BrowserAccessibilityManager::GotMouseDown() { 104 osk_state_ = OSK_ALLOWED_WITHIN_FOCUSED_OBJECT; 105 NotifyAccessibilityEvent(AccessibilityNotificationFocusChanged, focus_); 106 } 107 108 bool BrowserAccessibilityManager::IsOSKAllowed(const gfx::Rect& bounds) { 109 if (!delegate_ || !delegate_->HasFocus()) 110 return false; 111 112 gfx::Point touch_point = delegate_->GetLastTouchEventLocation(); 113 return bounds.Contains(touch_point); 114 } 115 116 bool BrowserAccessibilityManager::UseRootScrollOffsetsWhenComputingBounds() { 117 return true; 118 } 119 120 void BrowserAccessibilityManager::RemoveNode(BrowserAccessibility* node) { 121 if (node == focus_) 122 SetFocus(root_, false); 123 int renderer_id = node->renderer_id(); 124 renderer_id_map_.erase(renderer_id); 125 } 126 127 void BrowserAccessibilityManager::OnAccessibilityNotifications( 128 const std::vector<AccessibilityHostMsg_NotificationParams>& params) { 129 for (uint32 index = 0; index < params.size(); index++) { 130 const AccessibilityHostMsg_NotificationParams& param = params[index]; 131 132 // Update nodes that changed. 133 if (!UpdateNodes(param.nodes)) 134 return; 135 136 // Find the node corresponding to the id that's the target of the 137 // notification (which may not be the root of the update tree). 138 BrowserAccessibility* node = GetFromRendererID(param.id); 139 if (!node) 140 continue; 141 142 int notification_type = param.notification_type; 143 if (notification_type == AccessibilityNotificationFocusChanged || 144 notification_type == AccessibilityNotificationBlur) { 145 SetFocus(node, false); 146 147 if (osk_state_ != OSK_DISALLOWED_BECAUSE_TAB_HIDDEN && 148 osk_state_ != OSK_DISALLOWED_BECAUSE_TAB_JUST_APPEARED) 149 osk_state_ = OSK_ALLOWED; 150 151 // Don't send a native focus event if the window itself doesn't 152 // have focus. 153 if (delegate_ && !delegate_->HasFocus()) 154 continue; 155 } 156 157 // Send the notification event to the operating system. 158 NotifyAccessibilityEvent(notification_type, node); 159 160 // Set initial focus when a page is loaded. 161 if (notification_type == AccessibilityNotificationLoadComplete) { 162 if (!focus_) 163 SetFocus(root_, false); 164 if (!delegate_ || delegate_->HasFocus()) 165 NotifyAccessibilityEvent(AccessibilityNotificationFocusChanged, focus_); 166 } 167 } 168 } 169 170 BrowserAccessibility* BrowserAccessibilityManager::GetFocus( 171 BrowserAccessibility* root) { 172 if (focus_ && (!root || focus_->IsDescendantOf(root))) 173 return focus_; 174 175 return NULL; 176 } 177 178 void BrowserAccessibilityManager::SetFocus( 179 BrowserAccessibility* node, bool notify) { 180 if (focus_ != node) 181 focus_ = node; 182 183 if (notify && node && delegate_) 184 delegate_->SetAccessibilityFocus(node->renderer_id()); 185 } 186 187 void BrowserAccessibilityManager::SetRoot(BrowserAccessibility* node) { 188 root_ = node; 189 NotifyRootChanged(); 190 } 191 192 void BrowserAccessibilityManager::DoDefaultAction( 193 const BrowserAccessibility& node) { 194 if (delegate_) 195 delegate_->AccessibilityDoDefaultAction(node.renderer_id()); 196 } 197 198 void BrowserAccessibilityManager::ScrollToMakeVisible( 199 const BrowserAccessibility& node, gfx::Rect subfocus) { 200 if (delegate_) { 201 delegate_->AccessibilityScrollToMakeVisible(node.renderer_id(), subfocus); 202 } 203 } 204 205 void BrowserAccessibilityManager::ScrollToPoint( 206 const BrowserAccessibility& node, gfx::Point point) { 207 if (delegate_) { 208 delegate_->AccessibilityScrollToPoint(node.renderer_id(), point); 209 } 210 } 211 212 void BrowserAccessibilityManager::SetTextSelection( 213 const BrowserAccessibility& node, int start_offset, int end_offset) { 214 if (delegate_) { 215 delegate_->AccessibilitySetTextSelection( 216 node.renderer_id(), start_offset, end_offset); 217 } 218 } 219 220 gfx::Rect BrowserAccessibilityManager::GetViewBounds() { 221 if (delegate_) 222 return delegate_->GetViewBounds(); 223 return gfx::Rect(); 224 } 225 226 void BrowserAccessibilityManager::UpdateNodesForTesting( 227 const AccessibilityNodeData& node1, 228 const AccessibilityNodeData& node2 /* = AccessibilityNodeData() */, 229 const AccessibilityNodeData& node3 /* = AccessibilityNodeData() */, 230 const AccessibilityNodeData& node4 /* = AccessibilityNodeData() */, 231 const AccessibilityNodeData& node5 /* = AccessibilityNodeData() */, 232 const AccessibilityNodeData& node6 /* = AccessibilityNodeData() */, 233 const AccessibilityNodeData& node7 /* = AccessibilityNodeData() */) { 234 std::vector<AccessibilityNodeData> nodes; 235 nodes.push_back(node1); 236 if (node2.id != AccessibilityNodeData().id) 237 nodes.push_back(node2); 238 if (node3.id != AccessibilityNodeData().id) 239 nodes.push_back(node3); 240 if (node4.id != AccessibilityNodeData().id) 241 nodes.push_back(node4); 242 if (node5.id != AccessibilityNodeData().id) 243 nodes.push_back(node5); 244 if (node6.id != AccessibilityNodeData().id) 245 nodes.push_back(node6); 246 if (node7.id != AccessibilityNodeData().id) 247 nodes.push_back(node7); 248 UpdateNodes(nodes); 249 } 250 251 bool BrowserAccessibilityManager::UpdateNodes( 252 const std::vector<AccessibilityNodeData>& nodes) { 253 bool success = true; 254 255 // First, update all of the nodes in the tree. 256 for (size_t i = 0; i < nodes.size() && success; i++) { 257 if (!UpdateNode(nodes[i])) 258 success = false; 259 } 260 261 // In a second pass, call PostInitialize on each one - this must 262 // be called after all of each node's children are initialized too. 263 for (size_t i = 0; i < nodes.size() && success; i++) { 264 // Note: it's not a bug for nodes[i].id to not be found in the tree. 265 // Consider this example: 266 // Before: 267 // A 268 // B 269 // C 270 // D 271 // E 272 // F 273 // After: 274 // A 275 // B 276 // C 277 // F 278 // D 279 // In this example, F is being reparented. The renderer scans the tree 280 // in order. If can't update "C" to add "F" as a child, when "F" is still 281 // a child of "E". So it first updates "E", to remove "F" as a child. 282 // Later, it ends up deleting "E". So when we get here, "E" was updated as 283 // part of this sequence but it no longer exists in the final tree, so 284 // there's nothing to postinitialize. 285 BrowserAccessibility* instance = GetFromRendererID(nodes[i].id); 286 if (instance) 287 instance->PostInitialize(); 288 } 289 290 if (!success) { 291 // A bad accessibility tree could lead to memory corruption. 292 // Ask the delegate to crash the renderer, or if not available, 293 // crash the browser. 294 if (delegate_) 295 delegate_->FatalAccessibilityTreeError(); 296 else 297 CHECK(false); 298 } 299 300 return success; 301 } 302 303 BrowserAccessibility* BrowserAccessibilityManager::CreateNode( 304 BrowserAccessibility* parent, 305 int32 renderer_id, 306 int32 index_in_parent) { 307 BrowserAccessibility* node = factory_->Create(); 308 node->InitializeTreeStructure( 309 this, parent, renderer_id, index_in_parent); 310 AddNodeToMap(node); 311 return node; 312 } 313 314 void BrowserAccessibilityManager::AddNodeToMap(BrowserAccessibility* node) { 315 renderer_id_map_[node->renderer_id()] = node; 316 } 317 318 bool BrowserAccessibilityManager::UpdateNode(const AccessibilityNodeData& src) { 319 // This method updates one node in the tree based on serialized data 320 // received from the renderer. 321 322 // Create a set of child ids in |src| for fast lookup. If a duplicate id is 323 // found, exit now with a fatal error before changing anything else. 324 std::set<int32> new_child_ids; 325 for (size_t i = 0; i < src.child_ids.size(); ++i) { 326 if (new_child_ids.find(src.child_ids[i]) != new_child_ids.end()) 327 return false; 328 new_child_ids.insert(src.child_ids[i]); 329 } 330 331 // Look up the node by id. If it's not found, then either the root 332 // of the tree is being swapped, or we're out of sync with the renderer 333 // and this is a serious error. 334 BrowserAccessibility* instance = GetFromRendererID(src.id); 335 if (!instance) { 336 if (src.role != AccessibilityNodeData::ROLE_ROOT_WEB_AREA) 337 return false; 338 instance = CreateNode(NULL, src.id, 0); 339 } 340 341 if (src.bool_attributes.find( 342 AccessibilityNodeData::ATTR_UPDATE_LOCATION_ONLY) != 343 src.bool_attributes.end()) { 344 instance->SetLocation(src.location); 345 return true; 346 } 347 348 // Update all of the node-specific data, like its role, state, name, etc. 349 instance->InitializeData(src); 350 351 // 352 // Update the children in three steps: 353 // 354 // 1. Iterate over the old children and delete nodes that are no longer 355 // in the tree. 356 // 2. Build up a vector of new children, reusing children that haven't 357 // changed (but may have been reordered) and adding new empty 358 // objects for new children. 359 // 3. Swap in the new children vector for the old one. 360 361 // Delete any previous children of this instance that are no longer 362 // children first. We make a deletion-only pass first to prevent a 363 // node that's being reparented from being the child of both its old 364 // parent and new parent, which could lead to a double-free. 365 // If a node is reparented, the renderer will always send us a fresh 366 // copy of the node. 367 const std::vector<BrowserAccessibility*>& old_children = instance->children(); 368 for (size_t i = 0; i < old_children.size(); ++i) { 369 int old_id = old_children[i]->renderer_id(); 370 if (new_child_ids.find(old_id) == new_child_ids.end()) 371 old_children[i]->Destroy(); 372 } 373 374 // Now build a vector of new children, reusing objects that were already 375 // children of this node before. 376 std::vector<BrowserAccessibility*> new_children; 377 bool success = true; 378 for (size_t i = 0; i < src.child_ids.size(); i++) { 379 int32 child_renderer_id = src.child_ids[i]; 380 int32 index_in_parent = static_cast<int32>(i); 381 BrowserAccessibility* child = GetFromRendererID(child_renderer_id); 382 if (child) { 383 if (child->parent() != instance) { 384 // This is a serious error - nodes should never be reparented. 385 // If this case occurs, continue so this node isn't left in an 386 // inconsistent state, but return failure at the end. 387 success = false; 388 continue; 389 } 390 child->UpdateParent(instance, index_in_parent); 391 } else { 392 child = CreateNode(instance, child_renderer_id, index_in_parent); 393 } 394 new_children.push_back(child); 395 } 396 397 // Finally, swap in the new children vector for the old. 398 instance->SwapChildren(new_children); 399 400 // Handle the case where this node is the new root of the tree. 401 if (src.role == AccessibilityNodeData::ROLE_ROOT_WEB_AREA && 402 (!root_ || root_->renderer_id() != src.id)) { 403 if (root_) 404 root_->Destroy(); 405 if (focus_ == root_) 406 SetFocus(instance, false); 407 SetRoot(instance); 408 } 409 410 // Keep track of what node is focused. 411 if (src.role != AccessibilityNodeData::ROLE_ROOT_WEB_AREA && 412 src.role != AccessibilityNodeData::ROLE_WEB_AREA && 413 (src.state >> AccessibilityNodeData::STATE_FOCUSED & 1)) { 414 SetFocus(instance, false); 415 } 416 return success; 417 } 418 419 } // namespace content 420