| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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 #include "content/browser/accessibility/browser_accessibility_manager.h" | 5 #include "content/browser/accessibility/browser_accessibility_manager.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 | 8 |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "build/build_config.h" | 10 #include "build/build_config.h" |
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 176 ui::AXTreeUpdate | 176 ui::AXTreeUpdate |
| 177 BrowserAccessibilityManager::GetEmptyDocument() { | 177 BrowserAccessibilityManager::GetEmptyDocument() { |
| 178 ui::AXNodeData empty_document; | 178 ui::AXNodeData empty_document; |
| 179 empty_document.id = 0; | 179 empty_document.id = 0; |
| 180 empty_document.role = ui::AX_ROLE_ROOT_WEB_AREA; | 180 empty_document.role = ui::AX_ROLE_ROOT_WEB_AREA; |
| 181 ui::AXTreeUpdate update; | 181 ui::AXTreeUpdate update; |
| 182 update.nodes.push_back(empty_document); | 182 update.nodes.push_back(empty_document); |
| 183 return update; | 183 return update; |
| 184 } | 184 } |
| 185 | 185 |
| 186 void BrowserAccessibilityManager::FireFocusEventsIfNeeded() { | 186 void BrowserAccessibilityManager::NotifyAccessibilityEvent( |
| 187 BrowserAccessibilityEvent::Source source, |
| 188 ui::AXEvent event_type, |
| 189 BrowserAccessibility* node) { |
| 190 BrowserAccessibilityEvent::Create(source, event_type, node)->Fire(); |
| 191 } |
| 192 |
| 193 void BrowserAccessibilityManager::FireFocusEventsIfNeeded( |
| 194 BrowserAccessibilityEvent::Source source) { |
| 187 BrowserAccessibility* focus = GetFocus(); | 195 BrowserAccessibility* focus = GetFocus(); |
| 188 | 196 |
| 189 // Don't fire focus events if the window itself doesn't have focus. | 197 // Don't fire focus events if the window itself doesn't have focus. |
| 190 // Bypass this check if a global focus listener was set up for testing | 198 // Bypass this check if a global focus listener was set up for testing |
| 191 // so that the test passes whether the window is active or not. | 199 // so that the test passes whether the window is active or not. |
| 192 if (!g_focus_change_callback_for_testing.Pointer()) { | 200 if (!g_focus_change_callback_for_testing.Pointer()) { |
| 193 if (delegate_ && !delegate_->AccessibilityViewHasFocus()) | 201 if (delegate_ && !delegate_->AccessibilityViewHasFocus()) |
| 194 focus = nullptr; | 202 focus = nullptr; |
| 195 | 203 |
| 196 if (!CanFireEvents()) | 204 if (!CanFireEvents()) |
| 197 focus = nullptr; | 205 focus = nullptr; |
| 198 } | 206 } |
| 199 | 207 |
| 200 // Don't allow the document to be focused if it has no children and | 208 // Don't allow the document to be focused if it has no children and |
| 201 // hasn't finished loading yet. Wait for at least a tiny bit of content, | 209 // hasn't finished loading yet. Wait for at least a tiny bit of content, |
| 202 // or for the document to actually finish loading. | 210 // or for the document to actually finish loading. |
| 203 if (focus && | 211 if (focus && |
| 204 focus == focus->manager()->GetRoot() && | 212 focus == focus->manager()->GetRoot() && |
| 205 focus->PlatformChildCount() == 0 && | 213 focus->PlatformChildCount() == 0 && |
| 206 !focus->HasState(ui::AX_STATE_BUSY) && | 214 !focus->HasState(ui::AX_STATE_BUSY) && |
| 207 !focus->manager()->GetTreeData().loaded) { | 215 !focus->manager()->GetTreeData().loaded) { |
| 208 focus = nullptr; | 216 focus = nullptr; |
| 209 } | 217 } |
| 210 | 218 |
| 211 if (focus && focus != last_focused_node_) | 219 if (focus && focus != last_focused_node_) |
| 212 FireFocusEvent(focus); | 220 FireFocusEvent(source, focus); |
| 213 | 221 |
| 214 last_focused_node_ = focus; | 222 last_focused_node_ = focus; |
| 215 last_focused_manager_ = focus ? focus->manager() : nullptr; | 223 last_focused_manager_ = focus ? focus->manager() : nullptr; |
| 216 } | 224 } |
| 217 | 225 |
| 218 bool BrowserAccessibilityManager::CanFireEvents() { | 226 bool BrowserAccessibilityManager::CanFireEvents() { |
| 219 return true; | 227 return true; |
| 220 } | 228 } |
| 221 | 229 |
| 222 void BrowserAccessibilityManager::FireFocusEvent(BrowserAccessibility* node) { | 230 void BrowserAccessibilityManager::FireFocusEvent( |
| 223 NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, node); | 231 BrowserAccessibilityEvent::Source source, |
| 232 BrowserAccessibility* node) { |
| 233 NotifyAccessibilityEvent(source, ui::AX_EVENT_FOCUS, node); |
| 224 | 234 |
| 225 if (!g_focus_change_callback_for_testing.Get().is_null()) | 235 if (!g_focus_change_callback_for_testing.Get().is_null()) |
| 226 g_focus_change_callback_for_testing.Get().Run(); | 236 g_focus_change_callback_for_testing.Get().Run(); |
| 227 } | 237 } |
| 228 | 238 |
| 229 BrowserAccessibility* BrowserAccessibilityManager::GetRoot() { | 239 BrowserAccessibility* BrowserAccessibilityManager::GetRoot() { |
| 230 // tree_ can be null during destruction. | 240 // tree_ can be null during destruction. |
| 231 if (!tree_) | 241 if (!tree_) |
| 232 return nullptr; | 242 return nullptr; |
| 233 | 243 |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 285 | 295 |
| 286 return nullptr; | 296 return nullptr; |
| 287 } | 297 } |
| 288 | 298 |
| 289 const ui::AXTreeData& BrowserAccessibilityManager::GetTreeData() { | 299 const ui::AXTreeData& BrowserAccessibilityManager::GetTreeData() { |
| 290 return tree_->data(); | 300 return tree_->data(); |
| 291 } | 301 } |
| 292 | 302 |
| 293 void BrowserAccessibilityManager::OnWindowFocused() { | 303 void BrowserAccessibilityManager::OnWindowFocused() { |
| 294 if (this == GetRootManager()) | 304 if (this == GetRootManager()) |
| 295 FireFocusEventsIfNeeded(); | 305 FireFocusEventsIfNeeded(BrowserAccessibilityEvent::FromWindowFocusChange); |
| 296 } | 306 } |
| 297 | 307 |
| 298 void BrowserAccessibilityManager::OnWindowBlurred() { | 308 void BrowserAccessibilityManager::OnWindowBlurred() { |
| 299 if (this == GetRootManager()) { | 309 if (this == GetRootManager()) { |
| 300 last_focused_node_ = nullptr; | 310 last_focused_node_ = nullptr; |
| 301 last_focused_manager_ = nullptr; | 311 last_focused_manager_ = nullptr; |
| 302 } | 312 } |
| 303 } | 313 } |
| 304 | 314 |
| 305 void BrowserAccessibilityManager::UserIsNavigatingAway() { | 315 void BrowserAccessibilityManager::UserIsNavigatingAway() { |
| 306 user_is_navigating_away_ = true; | 316 user_is_navigating_away_ = true; |
| 307 } | 317 } |
| 308 | 318 |
| 309 void BrowserAccessibilityManager::UserIsReloading() { | 319 void BrowserAccessibilityManager::UserIsReloading() { |
| 310 user_is_navigating_away_ = true; | 320 user_is_navigating_away_ = true; |
| 311 } | 321 } |
| 312 | 322 |
| 313 void BrowserAccessibilityManager::NavigationSucceeded() { | 323 void BrowserAccessibilityManager::NavigationSucceeded() { |
| 314 user_is_navigating_away_ = false; | 324 user_is_navigating_away_ = false; |
| 315 } | 325 } |
| 316 | 326 |
| 317 void BrowserAccessibilityManager::NavigationFailed() { | 327 void BrowserAccessibilityManager::NavigationFailed() { |
| 318 user_is_navigating_away_ = false; | 328 user_is_navigating_away_ = false; |
| 319 } | 329 } |
| 320 | 330 |
| 321 void BrowserAccessibilityManager::GotMouseDown() { | |
| 322 BrowserAccessibility* focus = GetFocus(); | |
| 323 if (!focus) | |
| 324 return; | |
| 325 | |
| 326 osk_state_ = OSK_ALLOWED_WITHIN_FOCUSED_OBJECT; | |
| 327 NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, focus); | |
| 328 } | |
| 329 | |
| 330 bool BrowserAccessibilityManager::UseRootScrollOffsetsWhenComputingBounds() { | 331 bool BrowserAccessibilityManager::UseRootScrollOffsetsWhenComputingBounds() { |
| 331 return true; | 332 return true; |
| 332 } | 333 } |
| 333 | 334 |
| 334 void BrowserAccessibilityManager::OnAccessibilityEvents( | 335 void BrowserAccessibilityManager::OnAccessibilityEvents( |
| 335 const std::vector<AXEventNotificationDetails>& details) { | 336 const std::vector<AXEventNotificationDetails>& details) { |
| 336 // Process all changes to the accessibility tree first. | 337 // Process all changes to the accessibility tree first. |
| 337 for (uint32_t index = 0; index < details.size(); ++index) { | 338 for (uint32_t index = 0; index < details.size(); ++index) { |
| 338 const AXEventNotificationDetails& detail = details[index]; | 339 const AXEventNotificationDetails& detail = details[index]; |
| 339 if (!tree_->Unserialize(detail.update)) { | 340 if (!tree_->Unserialize(detail.update)) { |
| 340 if (delegate_) { | 341 if (delegate_) { |
| 341 LOG(ERROR) << tree_->error(); | 342 LOG(ERROR) << tree_->error(); |
| 342 delegate_->AccessibilityFatalError(); | 343 delegate_->AccessibilityFatalError(); |
| 343 } else { | 344 } else { |
| 344 CHECK(false) << tree_->error(); | 345 CHECK(false) << tree_->error(); |
| 345 } | 346 } |
| 346 return; | 347 return; |
| 347 } | 348 } |
| 348 } | 349 } |
| 349 | 350 |
| 350 // If the root's parent is in another accessibility tree but it wasn't | 351 // If the root's parent is in another accessibility tree but it wasn't |
| 351 // previously connected, post the proper notifications on the parent. | 352 // previously connected, post the proper notifications on the parent. |
| 352 BrowserAccessibility* parent = GetParentNodeFromParentTree(); | 353 BrowserAccessibility* parent = GetParentNodeFromParentTree(); |
| 353 if (parent) { | 354 if (parent) { |
| 354 if (!connected_to_parent_tree_node_) { | 355 if (!connected_to_parent_tree_node_) { |
| 355 parent->OnDataChanged(); | 356 parent->OnDataChanged(); |
| 356 parent->UpdatePlatformAttributes(); | 357 parent->UpdatePlatformAttributes(); |
| 357 parent->manager()->NotifyAccessibilityEvent( | 358 NotifyAccessibilityEvent( |
| 358 ui::AX_EVENT_CHILDREN_CHANGED, parent); | 359 BrowserAccessibilityEvent::FromChildFrameLoading, |
| 360 ui::AX_EVENT_CHILDREN_CHANGED, |
| 361 parent); |
| 359 connected_to_parent_tree_node_ = true; | 362 connected_to_parent_tree_node_ = true; |
| 360 } | 363 } |
| 361 } else { | 364 } else { |
| 362 connected_to_parent_tree_node_ = false; | 365 connected_to_parent_tree_node_ = false; |
| 363 } | 366 } |
| 364 | 367 |
| 365 // Based on the changes to the tree, first fire focus events if needed. | 368 // Based on the changes to the tree, first fire focus events if needed. |
| 366 // Screen readers might not do the right thing if they're not aware of what | 369 // Screen readers might not do the right thing if they're not aware of what |
| 367 // has focus, so always try that first. Nothing will be fired if the window | 370 // has focus, so always try that first. Nothing will be fired if the window |
| 368 // itself isn't focused or if focus hasn't changed. | 371 // itself isn't focused or if focus hasn't changed. |
| 369 GetRootManager()->FireFocusEventsIfNeeded(); | 372 GetRootManager()->FireFocusEventsIfNeeded( |
| 373 BrowserAccessibilityEvent::FromBlink); |
| 370 | 374 |
| 371 // Now iterate over the events again and fire the events other than focus | 375 // Now iterate over the events again and fire the events other than focus |
| 372 // events. | 376 // events. |
| 373 for (uint32_t index = 0; index < details.size(); index++) { | 377 for (uint32_t index = 0; index < details.size(); index++) { |
| 374 const AXEventNotificationDetails& detail = details[index]; | 378 const AXEventNotificationDetails& detail = details[index]; |
| 375 | 379 |
| 376 // Find the node corresponding to the id that's the target of the | 380 // Find the node corresponding to the id that's the target of the |
| 377 // event (which may not be the root of the update tree). | 381 // event (which may not be the root of the update tree). |
| 378 ui::AXNode* node = tree_->GetFromId(detail.id); | 382 ui::AXNode* node = tree_->GetFromId(detail.id); |
| 379 if (!node) | 383 if (!node) |
| (...skipping 11 matching lines...) Expand all Loading... |
| 391 | 395 |
| 392 // Skip all focus events other than ones on menu list options; | 396 // Skip all focus events other than ones on menu list options; |
| 393 // we've already handled them, above. Menu list options are a weird | 397 // we've already handled them, above. Menu list options are a weird |
| 394 // exception because the menu list itself has focus but we need to fire | 398 // exception because the menu list itself has focus but we need to fire |
| 395 // focus events on the individual options. | 399 // focus events on the individual options. |
| 396 if (!is_menu_list_option) | 400 if (!is_menu_list_option) |
| 397 continue; | 401 continue; |
| 398 } | 402 } |
| 399 | 403 |
| 400 // Fire the native event. | 404 // Fire the native event. |
| 401 NotifyAccessibilityEvent(event_type, GetFromAXNode(node)); | 405 BrowserAccessibility* event_target = GetFromAXNode(node); |
| 406 if (event_target) { |
| 407 NotifyAccessibilityEvent( |
| 408 BrowserAccessibilityEvent::FromBlink, |
| 409 event_type, |
| 410 event_target); |
| 411 } |
| 402 } | 412 } |
| 403 } | 413 } |
| 404 | 414 |
| 405 void BrowserAccessibilityManager::OnLocationChanges( | 415 void BrowserAccessibilityManager::OnLocationChanges( |
| 406 const std::vector<AccessibilityHostMsg_LocationChangeParams>& params) { | 416 const std::vector<AccessibilityHostMsg_LocationChangeParams>& params) { |
| 407 for (size_t i = 0; i < params.size(); ++i) { | 417 for (size_t i = 0; i < params.size(); ++i) { |
| 408 BrowserAccessibility* obj = GetFromID(params[i].id); | 418 BrowserAccessibility* obj = GetFromID(params[i].id); |
| 409 if (!obj) | 419 if (!obj) |
| 410 continue; | 420 continue; |
| 411 ui::AXNode* node = obj->node(); | 421 ui::AXNode* node = obj->node(); |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 466 // If an ancestor of this node is a leaf node, fire the notification on that. | 476 // If an ancestor of this node is a leaf node, fire the notification on that. |
| 467 BrowserAccessibility* ancestor = node->GetParent(); | 477 BrowserAccessibility* ancestor = node->GetParent(); |
| 468 while (ancestor && ancestor != GetRoot()) { | 478 while (ancestor && ancestor != GetRoot()) { |
| 469 if (ancestor->PlatformIsLeaf()) | 479 if (ancestor->PlatformIsLeaf()) |
| 470 node = ancestor; | 480 node = ancestor; |
| 471 ancestor = ancestor->GetParent(); | 481 ancestor = ancestor->GetParent(); |
| 472 } | 482 } |
| 473 | 483 |
| 474 // The "scrolled to anchor" notification is a great way to get a | 484 // The "scrolled to anchor" notification is a great way to get a |
| 475 // screen reader to jump directly to a specific location in a document. | 485 // screen reader to jump directly to a specific location in a document. |
| 476 NotifyAccessibilityEvent(ui::AX_EVENT_SCROLLED_TO_ANCHOR, node); | 486 NotifyAccessibilityEvent( |
| 487 BrowserAccessibilityEvent::FromFindInPageResult, |
| 488 ui::AX_EVENT_SCROLLED_TO_ANCHOR, |
| 489 node); |
| 477 } | 490 } |
| 478 | 491 |
| 479 BrowserAccessibility* BrowserAccessibilityManager::GetActiveDescendantFocus( | 492 BrowserAccessibility* BrowserAccessibilityManager::GetActiveDescendantFocus( |
| 480 BrowserAccessibility* focus) { | 493 BrowserAccessibility* focus) { |
| 481 if (!focus) | 494 if (!focus) |
| 482 return NULL; | 495 return NULL; |
| 483 | 496 |
| 484 int active_descendant_id; | 497 int active_descendant_id; |
| 485 if (focus->GetIntAttribute(ui::AX_ATTR_ACTIVEDESCENDANT_ID, | 498 if (focus->GetIntAttribute(ui::AX_ATTR_ACTIVEDESCENDANT_ID, |
| 486 &active_descendant_id)) { | 499 &active_descendant_id)) { |
| (...skipping 389 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 876 tree_source(tree_->CreateTreeSource()); | 889 tree_source(tree_->CreateTreeSource()); |
| 877 ui::AXTreeSerializer<const ui::AXNode*, | 890 ui::AXTreeSerializer<const ui::AXNode*, |
| 878 ui::AXNodeData, | 891 ui::AXNodeData, |
| 879 ui::AXTreeData> serializer(tree_source.get()); | 892 ui::AXTreeData> serializer(tree_source.get()); |
| 880 ui::AXTreeUpdate update; | 893 ui::AXTreeUpdate update; |
| 881 serializer.SerializeChanges(tree_->root(), &update); | 894 serializer.SerializeChanges(tree_->root(), &update); |
| 882 return update; | 895 return update; |
| 883 } | 896 } |
| 884 | 897 |
| 885 } // namespace content | 898 } // namespace content |
| OLD | NEW |