Chromium Code Reviews| 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 25 matching lines...) Expand all Loading... | |
| 36 return nullptr; | 36 return nullptr; |
| 37 } | 37 } |
| 38 | 38 |
| 39 } // namespace | 39 } // namespace |
| 40 | 40 |
| 41 // Map from AXTreeID to BrowserAccessibilityManager | 41 // Map from AXTreeID to BrowserAccessibilityManager |
| 42 using AXTreeIDMap = | 42 using AXTreeIDMap = |
| 43 base::hash_map<AXTreeIDRegistry::AXTreeID, BrowserAccessibilityManager*>; | 43 base::hash_map<AXTreeIDRegistry::AXTreeID, BrowserAccessibilityManager*>; |
| 44 base::LazyInstance<AXTreeIDMap> g_ax_tree_id_map = LAZY_INSTANCE_INITIALIZER; | 44 base::LazyInstance<AXTreeIDMap> g_ax_tree_id_map = LAZY_INSTANCE_INITIALIZER; |
| 45 | 45 |
| 46 // A function to call when focus changes, for testing only. | |
| 47 base::LazyInstance<base::Closure> g_focus_change_callback_for_testing = | |
| 48 LAZY_INSTANCE_INITIALIZER; | |
| 49 | |
| 46 ui::AXTreeUpdate MakeAXTreeUpdate( | 50 ui::AXTreeUpdate MakeAXTreeUpdate( |
| 47 const ui::AXNodeData& node1, | 51 const ui::AXNodeData& node1, |
| 48 const ui::AXNodeData& node2 /* = ui::AXNodeData() */, | 52 const ui::AXNodeData& node2 /* = ui::AXNodeData() */, |
| 49 const ui::AXNodeData& node3 /* = ui::AXNodeData() */, | 53 const ui::AXNodeData& node3 /* = ui::AXNodeData() */, |
| 50 const ui::AXNodeData& node4 /* = ui::AXNodeData() */, | 54 const ui::AXNodeData& node4 /* = ui::AXNodeData() */, |
| 51 const ui::AXNodeData& node5 /* = ui::AXNodeData() */, | 55 const ui::AXNodeData& node5 /* = ui::AXNodeData() */, |
| 52 const ui::AXNodeData& node6 /* = ui::AXNodeData() */, | 56 const ui::AXNodeData& node6 /* = ui::AXNodeData() */, |
| 53 const ui::AXNodeData& node7 /* = ui::AXNodeData() */, | 57 const ui::AXNodeData& node7 /* = ui::AXNodeData() */, |
| 54 const ui::AXNodeData& node8 /* = ui::AXNodeData() */, | 58 const ui::AXNodeData& node8 /* = ui::AXNodeData() */, |
| 55 const ui::AXNodeData& node9 /* = ui::AXNodeData() */, | 59 const ui::AXNodeData& node9 /* = ui::AXNodeData() */, |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 172 ui::AXNodeData empty_document; | 176 ui::AXNodeData empty_document; |
| 173 empty_document.id = 0; | 177 empty_document.id = 0; |
| 174 empty_document.role = ui::AX_ROLE_ROOT_WEB_AREA; | 178 empty_document.role = ui::AX_ROLE_ROOT_WEB_AREA; |
| 175 ui::AXTreeUpdate update; | 179 ui::AXTreeUpdate update; |
| 176 update.nodes.push_back(empty_document); | 180 update.nodes.push_back(empty_document); |
| 177 return update; | 181 return update; |
| 178 } | 182 } |
| 179 | 183 |
| 180 void BrowserAccessibilityManager::FireFocusEventsIfNeeded() { | 184 void BrowserAccessibilityManager::FireFocusEventsIfNeeded() { |
| 181 BrowserAccessibility* focus = GetFocus(); | 185 BrowserAccessibility* focus = GetFocus(); |
| 182 if (delegate_ && !delegate_->AccessibilityViewHasFocus()) | |
| 183 focus = nullptr; | |
| 184 | 186 |
| 185 if (!CanFireEvents()) | 187 // Don't fire focus events if the window itself doesn't have focus. |
| 186 focus = nullptr; | 188 // Bypass this check if a global focus listener was set up for testing |
| 189 // so that the test passes whether the window is active or not. | |
| 190 if (!g_focus_change_callback_for_testing.Pointer()) { | |
|
dcheng
2016/03/24 18:15:11
I wonder if it'd be possible to snoop IPC messages
dmazzoni
2016/03/25 05:02:22
That's how most of the tests in content/ work, we
| |
| 191 if (delegate_ &&!delegate_->AccessibilityViewHasFocus()) | |
| 192 focus = nullptr; | |
| 193 | |
| 194 if (!CanFireEvents()) | |
| 195 focus = nullptr; | |
| 196 } | |
| 187 | 197 |
| 188 // Don't allow the document to be focused if it has no children and | 198 // Don't allow the document to be focused if it has no children and |
| 189 // hasn't finished loading yet. Wait for at least a tiny bit of content, | 199 // hasn't finished loading yet. Wait for at least a tiny bit of content, |
| 190 // or for the document to actually finish loading. | 200 // or for the document to actually finish loading. |
| 191 if (focus && | 201 if (focus && |
| 192 focus == focus->manager()->GetRoot() && | 202 focus == focus->manager()->GetRoot() && |
| 193 focus->PlatformChildCount() == 0 && | 203 focus->PlatformChildCount() == 0 && |
| 194 !focus->HasState(ui::AX_STATE_BUSY) && | 204 !focus->HasState(ui::AX_STATE_BUSY) && |
| 195 !focus->manager()->GetTreeData().loaded) { | 205 !focus->manager()->GetTreeData().loaded) { |
| 196 focus = nullptr; | 206 focus = nullptr; |
| 197 } | 207 } |
| 198 | 208 |
| 199 if (focus && focus != last_focused_node_) | 209 if (focus && focus != last_focused_node_) |
| 200 FireFocusEvent(focus); | 210 FireFocusEvent(focus); |
| 201 | 211 |
| 202 last_focused_node_ = focus; | 212 last_focused_node_ = focus; |
| 203 last_focused_manager_ = focus ? focus->manager() : nullptr; | 213 last_focused_manager_ = focus ? focus->manager() : nullptr; |
| 204 } | 214 } |
| 205 | 215 |
| 206 bool BrowserAccessibilityManager::CanFireEvents() { | 216 bool BrowserAccessibilityManager::CanFireEvents() { |
| 207 return true; | 217 return true; |
| 208 } | 218 } |
| 209 | 219 |
| 210 void BrowserAccessibilityManager::FireFocusEvent(BrowserAccessibility* node) { | 220 void BrowserAccessibilityManager::FireFocusEvent(BrowserAccessibility* node) { |
| 211 NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, node); | 221 NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, node); |
| 222 if (g_focus_change_callback_for_testing.Pointer()) | |
| 223 g_focus_change_callback_for_testing.Get().Run(); | |
| 212 } | 224 } |
| 213 | 225 |
| 214 BrowserAccessibility* BrowserAccessibilityManager::GetRoot() { | 226 BrowserAccessibility* BrowserAccessibilityManager::GetRoot() { |
| 215 // tree_ can be null during destruction. | 227 // tree_ can be null during destruction. |
| 216 if (!tree_) | 228 if (!tree_) |
| 217 return nullptr; | 229 return nullptr; |
| 218 | 230 |
| 219 // tree_->root() can be null during AXTreeDelegate callbacks. | 231 // tree_->root() can be null during AXTreeDelegate callbacks. |
| 220 ui::AXNode* root = tree_->root(); | 232 ui::AXNode* root = tree_->root(); |
| 221 return root ? GetFromAXNode(root) : nullptr; | 233 return root ? GetFromAXNode(root) : nullptr; |
| (...skipping 227 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 449 if (!root_manager) | 461 if (!root_manager) |
| 450 root_manager = this; | 462 root_manager = this; |
| 451 int32_t focused_tree_id = root_manager->GetTreeData().focused_tree_id; | 463 int32_t focused_tree_id = root_manager->GetTreeData().focused_tree_id; |
| 452 | 464 |
| 453 BrowserAccessibilityManager* focused_manager = nullptr; | 465 BrowserAccessibilityManager* focused_manager = nullptr; |
| 454 if (focused_tree_id) | 466 if (focused_tree_id) |
| 455 focused_manager =BrowserAccessibilityManager::FromID(focused_tree_id); | 467 focused_manager =BrowserAccessibilityManager::FromID(focused_tree_id); |
| 456 if (!focused_manager) | 468 if (!focused_manager) |
| 457 focused_manager = root_manager; | 469 focused_manager = root_manager; |
| 458 | 470 |
| 459 int32_t focus_id = focused_manager->GetTreeData().focus_id; | 471 return focused_manager->GetFocusFromThisOrDescendantFrame(); |
| 460 BrowserAccessibility* obj = focused_manager->GetFromID(focus_id); | 472 } |
| 473 | |
| 474 BrowserAccessibility* | |
| 475 BrowserAccessibilityManager::GetFocusFromThisOrDescendantFrame() { | |
| 476 int32_t focus_id = GetTreeData().focus_id; | |
| 477 BrowserAccessibility* obj = GetFromID(focus_id); | |
| 461 if (!obj) | 478 if (!obj) |
| 462 return focused_manager->GetRoot(); | 479 return GetRoot(); |
| 463 | 480 |
| 464 if (obj->HasIntAttribute(ui::AX_ATTR_CHILD_TREE_ID)) { | 481 if (obj->HasIntAttribute(ui::AX_ATTR_CHILD_TREE_ID)) { |
| 465 BrowserAccessibilityManager* child_manager = | 482 BrowserAccessibilityManager* child_manager = |
| 466 BrowserAccessibilityManager::FromID( | 483 BrowserAccessibilityManager::FromID( |
| 467 obj->GetIntAttribute(ui::AX_ATTR_CHILD_TREE_ID)); | 484 obj->GetIntAttribute(ui::AX_ATTR_CHILD_TREE_ID)); |
| 468 if (child_manager) | 485 if (child_manager) |
| 469 return child_manager->GetFocus(); | 486 return child_manager->GetFocusFromThisOrDescendantFrame(); |
| 470 } | 487 } |
| 471 | 488 |
| 472 return obj; | 489 return obj; |
| 473 } | 490 } |
| 474 | 491 |
| 475 void BrowserAccessibilityManager::SetFocus(const BrowserAccessibility& node) { | 492 void BrowserAccessibilityManager::SetFocus(const BrowserAccessibility& node) { |
| 476 if (delegate_) | 493 if (delegate_) |
| 477 delegate_->AccessibilitySetFocus(node.GetId()); | 494 delegate_->AccessibilitySetFocus(node.GetId()); |
| 478 } | 495 } |
| 479 | 496 |
| 480 void BrowserAccessibilityManager::SetFocusLocallyForTesting( | 497 void BrowserAccessibilityManager::SetFocusLocallyForTesting( |
| 481 BrowserAccessibility* node) { | 498 BrowserAccessibility* node) { |
| 482 ui::AXTreeData data = GetTreeData(); | 499 ui::AXTreeData data = GetTreeData(); |
| 483 data.focus_id = node->GetId(); | 500 data.focus_id = node->GetId(); |
| 484 tree_->UpdateData(data); | 501 tree_->UpdateData(data); |
| 485 } | 502 } |
| 486 | 503 |
| 504 // static | |
| 505 void BrowserAccessibilityManager::SetFocusChangeCallbackForTesting( | |
| 506 base::Closure callback) { | |
| 507 g_focus_change_callback_for_testing.Get() = callback; | |
| 508 } | |
| 509 | |
| 487 void BrowserAccessibilityManager::DoDefaultAction( | 510 void BrowserAccessibilityManager::DoDefaultAction( |
| 488 const BrowserAccessibility& node) { | 511 const BrowserAccessibility& node) { |
| 489 if (delegate_) | 512 if (delegate_) |
| 490 delegate_->AccessibilityDoDefaultAction(node.GetId()); | 513 delegate_->AccessibilityDoDefaultAction(node.GetId()); |
| 491 } | 514 } |
| 492 | 515 |
| 493 void BrowserAccessibilityManager::ScrollToMakeVisible( | 516 void BrowserAccessibilityManager::ScrollToMakeVisible( |
| 494 const BrowserAccessibility& node, gfx::Rect subfocus) { | 517 const BrowserAccessibility& node, gfx::Rect subfocus) { |
| 495 if (delegate_) { | 518 if (delegate_) { |
| 496 delegate_->AccessibilityScrollToMakeVisible(node.GetId(), subfocus); | 519 delegate_->AccessibilityScrollToMakeVisible(node.GetId(), subfocus); |
| (...skipping 313 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 810 tree_->CreateTreeSource()); | 833 tree_->CreateTreeSource()); |
| 811 ui::AXTreeSerializer<const ui::AXNode*, | 834 ui::AXTreeSerializer<const ui::AXNode*, |
| 812 ui::AXNodeData, | 835 ui::AXNodeData, |
| 813 ui::AXTreeData> serializer(tree_source.get()); | 836 ui::AXTreeData> serializer(tree_source.get()); |
| 814 ui::AXTreeUpdate update; | 837 ui::AXTreeUpdate update; |
| 815 serializer.SerializeChanges(tree_->root(), &update); | 838 serializer.SerializeChanges(tree_->root(), &update); |
| 816 return update; | 839 return update; |
| 817 } | 840 } |
| 818 | 841 |
| 819 } // namespace content | 842 } // namespace content |
| OLD | NEW |