| Index: content/browser/accessibility/browser_accessibility_manager.cc
|
| diff --git a/content/browser/accessibility/browser_accessibility_manager.cc b/content/browser/accessibility/browser_accessibility_manager.cc
|
| index c6b65e6b732e25d227c21c411d989b6b473f1076..ebf3a99e8a5f65aba3acd77bdae4b813c64838bd 100644
|
| --- a/content/browser/accessibility/browser_accessibility_manager.cc
|
| +++ b/content/browser/accessibility/browser_accessibility_manager.cc
|
| @@ -125,6 +125,8 @@ BrowserAccessibilityManager::BrowserAccessibilityManager(
|
| tree_(new ui::AXSerializableTree()),
|
| user_is_navigating_away_(false),
|
| osk_state_(OSK_ALLOWED),
|
| + last_focused_node_(nullptr),
|
| + last_focused_manager_(nullptr),
|
| ax_tree_id_(AXTreeIDRegistry::kNoAXTreeID),
|
| parent_node_id_from_parent_tree_(0) {
|
| tree_->SetDelegate(this);
|
| @@ -173,6 +175,40 @@ BrowserAccessibilityManager::GetEmptyDocument() {
|
| return update;
|
| }
|
|
|
| +void BrowserAccessibilityManager::FireFocusEventsIfNeeded() {
|
| + BrowserAccessibility* focus = GetFocus();
|
| + if (delegate_ && !delegate_->AccessibilityViewHasFocus())
|
| + focus = nullptr;
|
| +
|
| + if (!CanFireEvents())
|
| + focus = nullptr;
|
| +
|
| + // Don't allow the document to be focused if it has no children and
|
| + // hasn't finished loading yet. Wait for at least a tiny bit of content,
|
| + // or for the document to actually finish loading.
|
| + if (focus &&
|
| + focus == focus->manager()->GetRoot() &&
|
| + focus->PlatformChildCount() == 0 &&
|
| + !focus->HasState(ui::AX_STATE_BUSY) &&
|
| + !focus->manager()->GetTreeData().loaded) {
|
| + focus = nullptr;
|
| + }
|
| +
|
| + if (focus && focus != last_focused_node_)
|
| + FireFocusEvent(focus);
|
| +
|
| + last_focused_node_ = focus;
|
| + last_focused_manager_ = focus ? focus->manager() : nullptr;
|
| +}
|
| +
|
| +bool BrowserAccessibilityManager::CanFireEvents() {
|
| + return true;
|
| +}
|
| +
|
| +void BrowserAccessibilityManager::FireFocusEvent(BrowserAccessibility* node) {
|
| + NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, node);
|
| +}
|
| +
|
| BrowserAccessibility* BrowserAccessibilityManager::GetRoot() {
|
| // tree_ can be null during destruction.
|
| if (!tree_)
|
| @@ -238,15 +274,15 @@ const ui::AXTreeData& BrowserAccessibilityManager::GetTreeData() {
|
| }
|
|
|
| void BrowserAccessibilityManager::OnWindowFocused() {
|
| - BrowserAccessibility* focus = GetFocus();
|
| - if (focus)
|
| - NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, focus);
|
| + if (this == GetRootManager())
|
| + FireFocusEventsIfNeeded();
|
| }
|
|
|
| void BrowserAccessibilityManager::OnWindowBlurred() {
|
| - BrowserAccessibility* focus = GetFocus();
|
| - if (focus)
|
| - NotifyAccessibilityEvent(ui::AX_EVENT_BLUR, focus);
|
| + if (this == GetRootManager()) {
|
| + last_focused_node_ = nullptr;
|
| + last_focused_manager_ = nullptr;
|
| + }
|
| }
|
|
|
| void BrowserAccessibilityManager::UserIsNavigatingAway() {
|
| @@ -294,7 +330,14 @@ void BrowserAccessibilityManager::OnAccessibilityEvents(
|
| }
|
| }
|
|
|
| - // Now iterate over the events again and fire the events.
|
| + // Based on the changes to the tree, first fire focus events if needed.
|
| + // Screen readers might not do the right thing if they're not aware of what
|
| + // has focus, so always try that first. Nothing will be fired if the window
|
| + // itself isn't focused or if focus hasn't changed.
|
| + GetRootManager()->FireFocusEventsIfNeeded();
|
| +
|
| + // Now iterate over the events again and fire the events other than focus
|
| + // events.
|
| for (uint32_t index = 0; index < details.size(); index++) {
|
| const AXEventNotificationDetails& detail = details[index];
|
|
|
| @@ -311,13 +354,18 @@ void BrowserAccessibilityManager::OnAccessibilityEvents(
|
| osk_state_ != OSK_DISALLOWED_BECAUSE_TAB_JUST_APPEARED)
|
| osk_state_ = OSK_ALLOWED;
|
|
|
| - // Don't send a native focus event if the window itself doesn't
|
| - // have focus.
|
| - if (!NativeViewHasFocus())
|
| + bool is_menu_list_option =
|
| + node->data().role == ui::AX_ROLE_MENU_LIST_OPTION;
|
| +
|
| + // Skip all focus events other than ones on menu list options;
|
| + // we've already handled them, above. Menu list options are a weird
|
| + // exception because the menu list itself has focus but we need to fire
|
| + // focus events on the individual options.
|
| + if (!is_menu_list_option)
|
| continue;
|
| }
|
|
|
| - // Send the event event to the operating system.
|
| + // Fire the native event.
|
| NotifyAccessibilityEvent(event_type, GetFromAXNode(node));
|
| }
|
| }
|
| @@ -395,10 +443,21 @@ bool BrowserAccessibilityManager::NativeViewHasFocus() {
|
| }
|
|
|
| BrowserAccessibility* BrowserAccessibilityManager::GetFocus() {
|
| - int32_t focus_id = GetTreeData().focus_id;
|
| - BrowserAccessibility* obj = GetFromID(focus_id);
|
| + BrowserAccessibilityManager* root_manager = GetRootManager();
|
| + if (!root_manager)
|
| + root_manager = this;
|
| + int32_t focused_tree_id = root_manager->GetTreeData().focused_tree_id;
|
| +
|
| + BrowserAccessibilityManager* focused_manager = nullptr;
|
| + if (focused_tree_id)
|
| + focused_manager =BrowserAccessibilityManager::FromID(focused_tree_id);
|
| + if (!focused_manager)
|
| + focused_manager = root_manager;
|
| +
|
| + int32_t focus_id = focused_manager->GetTreeData().focus_id;
|
| + BrowserAccessibility* obj = focused_manager->GetFromID(focus_id);
|
| if (!obj)
|
| - return GetRoot();
|
| + return focused_manager->GetRoot();
|
|
|
| if (obj->HasIntAttribute(ui::AX_ATTR_CHILD_TREE_ID)) {
|
| BrowserAccessibilityManager* child_manager =
|
|
|