| 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 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 118 } | 118 } |
| 119 | 119 |
| 120 BrowserAccessibilityManager::BrowserAccessibilityManager( | 120 BrowserAccessibilityManager::BrowserAccessibilityManager( |
| 121 BrowserAccessibilityDelegate* delegate, | 121 BrowserAccessibilityDelegate* delegate, |
| 122 BrowserAccessibilityFactory* factory) | 122 BrowserAccessibilityFactory* factory) |
| 123 : delegate_(delegate), | 123 : delegate_(delegate), |
| 124 factory_(factory), | 124 factory_(factory), |
| 125 tree_(new ui::AXSerializableTree()), | 125 tree_(new ui::AXSerializableTree()), |
| 126 user_is_navigating_away_(false), | 126 user_is_navigating_away_(false), |
| 127 osk_state_(OSK_ALLOWED), | 127 osk_state_(OSK_ALLOWED), |
| 128 last_focused_node_(nullptr), |
| 129 last_focused_manager_(nullptr), |
| 128 ax_tree_id_(AXTreeIDRegistry::kNoAXTreeID), | 130 ax_tree_id_(AXTreeIDRegistry::kNoAXTreeID), |
| 129 parent_node_id_from_parent_tree_(0) { | 131 parent_node_id_from_parent_tree_(0) { |
| 130 tree_->SetDelegate(this); | 132 tree_->SetDelegate(this); |
| 131 } | 133 } |
| 132 | 134 |
| 133 BrowserAccessibilityManager::BrowserAccessibilityManager( | 135 BrowserAccessibilityManager::BrowserAccessibilityManager( |
| 134 const ui::AXTreeUpdate& initial_tree, | 136 const ui::AXTreeUpdate& initial_tree, |
| 135 BrowserAccessibilityDelegate* delegate, | 137 BrowserAccessibilityDelegate* delegate, |
| 136 BrowserAccessibilityFactory* factory) | 138 BrowserAccessibilityFactory* factory) |
| 137 : delegate_(delegate), | 139 : delegate_(delegate), |
| (...skipping 28 matching lines...) Expand all Loading... |
| 166 ui::AXTreeUpdate | 168 ui::AXTreeUpdate |
| 167 BrowserAccessibilityManager::GetEmptyDocument() { | 169 BrowserAccessibilityManager::GetEmptyDocument() { |
| 168 ui::AXNodeData empty_document; | 170 ui::AXNodeData empty_document; |
| 169 empty_document.id = 0; | 171 empty_document.id = 0; |
| 170 empty_document.role = ui::AX_ROLE_ROOT_WEB_AREA; | 172 empty_document.role = ui::AX_ROLE_ROOT_WEB_AREA; |
| 171 ui::AXTreeUpdate update; | 173 ui::AXTreeUpdate update; |
| 172 update.nodes.push_back(empty_document); | 174 update.nodes.push_back(empty_document); |
| 173 return update; | 175 return update; |
| 174 } | 176 } |
| 175 | 177 |
| 178 void BrowserAccessibilityManager::FireFocusEventsIfNeeded() { |
| 179 BrowserAccessibility* focus = GetFocus(); |
| 180 if (delegate_ && !delegate_->AccessibilityViewHasFocus()) |
| 181 focus = nullptr; |
| 182 |
| 183 if (!CanFireEvents()) |
| 184 focus = nullptr; |
| 185 |
| 186 // Don't allow the document to be focused if it has no children and |
| 187 // hasn't finished loading yet. Wait for at least a tiny bit of content, |
| 188 // or for the document to actually finish loading. |
| 189 if (focus && |
| 190 focus == focus->manager()->GetRoot() && |
| 191 focus->PlatformChildCount() == 0 && |
| 192 !focus->HasState(ui::AX_STATE_BUSY) && |
| 193 !focus->manager()->GetTreeData().loaded) { |
| 194 focus = nullptr; |
| 195 } |
| 196 |
| 197 if (focus && focus != last_focused_node_) |
| 198 FireFocusEvent(focus); |
| 199 |
| 200 last_focused_node_ = focus; |
| 201 last_focused_manager_ = focus ? focus->manager() : nullptr; |
| 202 } |
| 203 |
| 204 bool BrowserAccessibilityManager::CanFireEvents() { |
| 205 return true; |
| 206 } |
| 207 |
| 208 void BrowserAccessibilityManager::FireFocusEvent(BrowserAccessibility* node) { |
| 209 NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, node); |
| 210 } |
| 211 |
| 176 BrowserAccessibility* BrowserAccessibilityManager::GetRoot() { | 212 BrowserAccessibility* BrowserAccessibilityManager::GetRoot() { |
| 177 // tree_ can be null during destruction. | 213 // tree_ can be null during destruction. |
| 178 if (!tree_) | 214 if (!tree_) |
| 179 return nullptr; | 215 return nullptr; |
| 180 | 216 |
| 181 // tree_->root() can be null during AXTreeDelegate callbacks. | 217 // tree_->root() can be null during AXTreeDelegate callbacks. |
| 182 ui::AXNode* root = tree_->root(); | 218 ui::AXNode* root = tree_->root(); |
| 183 return root ? GetFromAXNode(root) : nullptr; | 219 return root ? GetFromAXNode(root) : nullptr; |
| 184 } | 220 } |
| 185 | 221 |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 231 } | 267 } |
| 232 | 268 |
| 233 return nullptr; | 269 return nullptr; |
| 234 } | 270 } |
| 235 | 271 |
| 236 const ui::AXTreeData& BrowserAccessibilityManager::GetTreeData() { | 272 const ui::AXTreeData& BrowserAccessibilityManager::GetTreeData() { |
| 237 return tree_->data(); | 273 return tree_->data(); |
| 238 } | 274 } |
| 239 | 275 |
| 240 void BrowserAccessibilityManager::OnWindowFocused() { | 276 void BrowserAccessibilityManager::OnWindowFocused() { |
| 241 BrowserAccessibility* focus = GetFocus(); | 277 if (this == GetRootManager()) |
| 242 if (focus) | 278 FireFocusEventsIfNeeded(); |
| 243 NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, focus); | |
| 244 } | 279 } |
| 245 | 280 |
| 246 void BrowserAccessibilityManager::OnWindowBlurred() { | 281 void BrowserAccessibilityManager::OnWindowBlurred() { |
| 247 BrowserAccessibility* focus = GetFocus(); | 282 if (this == GetRootManager()) { |
| 248 if (focus) | 283 last_focused_node_ = nullptr; |
| 249 NotifyAccessibilityEvent(ui::AX_EVENT_BLUR, focus); | 284 last_focused_manager_ = nullptr; |
| 285 } |
| 250 } | 286 } |
| 251 | 287 |
| 252 void BrowserAccessibilityManager::UserIsNavigatingAway() { | 288 void BrowserAccessibilityManager::UserIsNavigatingAway() { |
| 253 user_is_navigating_away_ = true; | 289 user_is_navigating_away_ = true; |
| 254 } | 290 } |
| 255 | 291 |
| 256 void BrowserAccessibilityManager::UserIsReloading() { | 292 void BrowserAccessibilityManager::UserIsReloading() { |
| 257 user_is_navigating_away_ = true; | 293 user_is_navigating_away_ = true; |
| 258 } | 294 } |
| 259 | 295 |
| (...skipping 27 matching lines...) Expand all Loading... |
| 287 if (delegate_) { | 323 if (delegate_) { |
| 288 LOG(ERROR) << tree_->error(); | 324 LOG(ERROR) << tree_->error(); |
| 289 delegate_->AccessibilityFatalError(); | 325 delegate_->AccessibilityFatalError(); |
| 290 } else { | 326 } else { |
| 291 CHECK(false) << tree_->error(); | 327 CHECK(false) << tree_->error(); |
| 292 } | 328 } |
| 293 return; | 329 return; |
| 294 } | 330 } |
| 295 } | 331 } |
| 296 | 332 |
| 297 // Now iterate over the events again and fire the events. | 333 // Based on the changes to the tree, first fire focus events if needed. |
| 334 // Screen readers might not do the right thing if they're not aware of what |
| 335 // has focus, so always try that first. Nothing will be fired if the window |
| 336 // itself isn't focused or if focus hasn't changed. |
| 337 GetRootManager()->FireFocusEventsIfNeeded(); |
| 338 |
| 339 // Now iterate over the events again and fire the events other than focus |
| 340 // events. |
| 298 for (uint32_t index = 0; index < details.size(); index++) { | 341 for (uint32_t index = 0; index < details.size(); index++) { |
| 299 const AXEventNotificationDetails& detail = details[index]; | 342 const AXEventNotificationDetails& detail = details[index]; |
| 300 | 343 |
| 301 // Find the node corresponding to the id that's the target of the | 344 // Find the node corresponding to the id that's the target of the |
| 302 // event (which may not be the root of the update tree). | 345 // event (which may not be the root of the update tree). |
| 303 ui::AXNode* node = tree_->GetFromId(detail.id); | 346 ui::AXNode* node = tree_->GetFromId(detail.id); |
| 304 if (!node) | 347 if (!node) |
| 305 continue; | 348 continue; |
| 306 | 349 |
| 307 ui::AXEvent event_type = detail.event_type; | 350 ui::AXEvent event_type = detail.event_type; |
| 308 if (event_type == ui::AX_EVENT_FOCUS || | 351 if (event_type == ui::AX_EVENT_FOCUS || |
| 309 event_type == ui::AX_EVENT_BLUR) { | 352 event_type == ui::AX_EVENT_BLUR) { |
| 310 if (osk_state_ != OSK_DISALLOWED_BECAUSE_TAB_HIDDEN && | 353 if (osk_state_ != OSK_DISALLOWED_BECAUSE_TAB_HIDDEN && |
| 311 osk_state_ != OSK_DISALLOWED_BECAUSE_TAB_JUST_APPEARED) | 354 osk_state_ != OSK_DISALLOWED_BECAUSE_TAB_JUST_APPEARED) |
| 312 osk_state_ = OSK_ALLOWED; | 355 osk_state_ = OSK_ALLOWED; |
| 313 | 356 |
| 314 // Don't send a native focus event if the window itself doesn't | 357 bool is_menu_list_option = |
| 315 // have focus. | 358 node->data().role == ui::AX_ROLE_MENU_LIST_OPTION; |
| 316 if (!NativeViewHasFocus()) | 359 |
| 360 // Skip all focus events other than ones on menu list options; |
| 361 // we've already handled them, above. Menu list options are a weird |
| 362 // exception because the menu list itself has focus but we need to fire |
| 363 // focus events on the individual options. |
| 364 if (!is_menu_list_option) |
| 317 continue; | 365 continue; |
| 318 } | 366 } |
| 319 | 367 |
| 320 // Send the event event to the operating system. | 368 // Fire the native event. |
| 321 NotifyAccessibilityEvent(event_type, GetFromAXNode(node)); | 369 NotifyAccessibilityEvent(event_type, GetFromAXNode(node)); |
| 322 } | 370 } |
| 323 } | 371 } |
| 324 | 372 |
| 325 void BrowserAccessibilityManager::OnLocationChanges( | 373 void BrowserAccessibilityManager::OnLocationChanges( |
| 326 const std::vector<AccessibilityHostMsg_LocationChangeParams>& params) { | 374 const std::vector<AccessibilityHostMsg_LocationChangeParams>& params) { |
| 327 for (size_t i = 0; i < params.size(); ++i) { | 375 for (size_t i = 0; i < params.size(); ++i) { |
| 328 BrowserAccessibility* obj = GetFromID(params[i].id); | 376 BrowserAccessibility* obj = GetFromID(params[i].id); |
| 329 if (!obj) | 377 if (!obj) |
| 330 continue; | 378 continue; |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 388 } | 436 } |
| 389 | 437 |
| 390 bool BrowserAccessibilityManager::NativeViewHasFocus() { | 438 bool BrowserAccessibilityManager::NativeViewHasFocus() { |
| 391 BrowserAccessibilityDelegate* delegate = GetDelegateFromRootManager(); | 439 BrowserAccessibilityDelegate* delegate = GetDelegateFromRootManager(); |
| 392 if (delegate) | 440 if (delegate) |
| 393 return delegate->AccessibilityViewHasFocus(); | 441 return delegate->AccessibilityViewHasFocus(); |
| 394 return false; | 442 return false; |
| 395 } | 443 } |
| 396 | 444 |
| 397 BrowserAccessibility* BrowserAccessibilityManager::GetFocus() { | 445 BrowserAccessibility* BrowserAccessibilityManager::GetFocus() { |
| 398 int32_t focus_id = GetTreeData().focus_id; | 446 BrowserAccessibilityManager* root_manager = GetRootManager(); |
| 399 BrowserAccessibility* obj = GetFromID(focus_id); | 447 if (!root_manager) |
| 448 root_manager = this; |
| 449 int32_t focused_tree_id = root_manager->GetTreeData().focused_tree_id; |
| 450 |
| 451 BrowserAccessibilityManager* focused_manager = nullptr; |
| 452 if (focused_tree_id) |
| 453 focused_manager =BrowserAccessibilityManager::FromID(focused_tree_id); |
| 454 if (!focused_manager) |
| 455 focused_manager = root_manager; |
| 456 |
| 457 int32_t focus_id = focused_manager->GetTreeData().focus_id; |
| 458 BrowserAccessibility* obj = focused_manager->GetFromID(focus_id); |
| 400 if (!obj) | 459 if (!obj) |
| 401 return GetRoot(); | 460 return focused_manager->GetRoot(); |
| 402 | 461 |
| 403 if (obj->HasIntAttribute(ui::AX_ATTR_CHILD_TREE_ID)) { | 462 if (obj->HasIntAttribute(ui::AX_ATTR_CHILD_TREE_ID)) { |
| 404 BrowserAccessibilityManager* child_manager = | 463 BrowserAccessibilityManager* child_manager = |
| 405 BrowserAccessibilityManager::FromID( | 464 BrowserAccessibilityManager::FromID( |
| 406 obj->GetIntAttribute(ui::AX_ATTR_CHILD_TREE_ID)); | 465 obj->GetIntAttribute(ui::AX_ATTR_CHILD_TREE_ID)); |
| 407 if (child_manager) | 466 if (child_manager) |
| 408 return child_manager->GetFocus(); | 467 return child_manager->GetFocus(); |
| 409 } | 468 } |
| 410 | 469 |
| 411 return obj; | 470 return obj; |
| (...skipping 337 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 749 tree_->CreateTreeSource()); | 808 tree_->CreateTreeSource()); |
| 750 ui::AXTreeSerializer<const ui::AXNode*, | 809 ui::AXTreeSerializer<const ui::AXNode*, |
| 751 ui::AXNodeData, | 810 ui::AXNodeData, |
| 752 ui::AXTreeData> serializer(tree_source.get()); | 811 ui::AXTreeData> serializer(tree_source.get()); |
| 753 ui::AXTreeUpdate update; | 812 ui::AXTreeUpdate update; |
| 754 serializer.SerializeChanges(tree_->root(), &update); | 813 serializer.SerializeChanges(tree_->root(), &update); |
| 755 return update; | 814 return update; |
| 756 } | 815 } |
| 757 | 816 |
| 758 } // namespace content | 817 } // namespace content |
| OLD | NEW |