Commit 2cfc6040 authored by Aaron Leventhal's avatar Aaron Leventhal Committed by Commit Bot

Announce autofill menu option selections in VoiceOver

Bug: 846570
Change-Id: I60e851b4e09658424de11b2f978dfd9dfcd1b67d
Reviewed-on: https://chromium-review.googlesource.com/1099880
Commit-Queue: Aaron Leventhal <aleventhal@chromium.org>
Reviewed-by: default avatarAlexei Svitkine <asvitkine@chromium.org>
Reviewed-by: default avatarDominic Mazzoni <dmazzoni@chromium.org>
Reviewed-by: default avatarElly Fong-Jones <ellyjones@chromium.org>
Cr-Commit-Position: refs/heads/master@{#568222}
parent 0c91664f
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include "content/browser/renderer_host/render_widget_host_view_mac.h" #include "content/browser/renderer_host/render_widget_host_view_mac.h"
#import "content/browser/renderer_host/render_widget_host_view_mac_editcommand_helper.h" #import "content/browser/renderer_host/render_widget_host_view_mac_editcommand_helper.h"
#import "content/public/browser/render_widget_host_view_mac_delegate.h" #import "content/public/browser/render_widget_host_view_mac_delegate.h"
#include "ui/accessibility/platform/ax_platform_node.h"
#import "ui/base/clipboard/clipboard_util_mac.h" #import "ui/base/clipboard/clipboard_util_mac.h"
#import "ui/base/cocoa/appkit_utils.h" #import "ui/base/cocoa/appkit_utils.h"
#include "ui/base/cocoa/cocoa_base_utils.h" #include "ui/base/cocoa/cocoa_base_utils.h"
...@@ -1383,6 +1384,16 @@ void ExtractUnderlines(NSAttributedString* string, ...@@ -1383,6 +1384,16 @@ void ExtractUnderlines(NSAttributedString* string,
} }
- (id)accessibilityFocusedUIElement { - (id)accessibilityFocusedUIElement {
// If content is overlayed with a focused popup from native UI code, this
// getter must return the current menu item as the focused element, rather
// than the focus within the content. An example of this occurs with the
// Autofill feature, where focus is actually still in the textbox although
// the UX acts as if focus is in the popup.
gfx::NativeViewAccessible popup_focus_override =
ui::AXPlatformNode::GetPopupFocusOverride();
if (popup_focus_override)
return popup_focus_override;
BrowserAccessibilityManager* manager = BrowserAccessibilityManager* manager =
client_->GetRootBrowserAccessibilityManager(); client_->GetRootBrowserAccessibilityManager();
if (manager) { if (manager) {
......
...@@ -27,6 +27,9 @@ AXMode AXPlatformNode::ax_mode_; ...@@ -27,6 +27,9 @@ AXMode AXPlatformNode::ax_mode_;
// static // static
bool AXPlatformNode::has_input_suggestions_ = false; bool AXPlatformNode::has_input_suggestions_ = false;
// static
gfx::NativeViewAccessible AXPlatformNode::popup_focus_override_ = nullptr;
// static // static
AXPlatformNode* AXPlatformNode::FromNativeWindow( AXPlatformNode* AXPlatformNode::FromNativeWindow(
gfx::NativeWindow native_window) { gfx::NativeWindow native_window) {
...@@ -94,4 +97,15 @@ bool AXPlatformNode::HasInputSuggestions() { ...@@ -94,4 +97,15 @@ bool AXPlatformNode::HasInputSuggestions() {
return has_input_suggestions_; return has_input_suggestions_;
} }
// static
void AXPlatformNode::SetPopupFocusOverride(
gfx::NativeViewAccessible popup_focus_override) {
popup_focus_override_ = popup_focus_override;
}
// static
gfx::NativeViewAccessible AXPlatformNode::GetPopupFocusOverride() {
return popup_focus_override_;
}
} // namespace ui } // namespace ui
...@@ -70,6 +70,14 @@ class AX_EXPORT AXPlatformNode { ...@@ -70,6 +70,14 @@ class AX_EXPORT AXPlatformNode {
static bool HasInputSuggestions(); static bool HasInputSuggestions();
// Return the focused object in any UI popup overlaying content, or null.
static gfx::NativeViewAccessible GetPopupFocusOverride();
// Set the focused object withn any UI popup overlaying content, or null.
// The focus override is the perceived focus within the popup, and it changes
// each time a user navigates to a new item within the popup.
static void SetPopupFocusOverride(gfx::NativeViewAccessible focus_override);
// Call Destroy rather than deleting this, because the subclass may // Call Destroy rather than deleting this, because the subclass may
// use reference counting. // use reference counting.
virtual void Destroy(); virtual void Destroy();
...@@ -105,6 +113,11 @@ class AX_EXPORT AXPlatformNode { ...@@ -105,6 +113,11 @@ class AX_EXPORT AXPlatformNode {
static bool has_input_suggestions_; static bool has_input_suggestions_;
// This allows UI menu popups like to act as if they are focused in the
// exposed platform accessibility API, even though actual focus remains in
// underlying content.
static gfx::NativeViewAccessible popup_focus_override_;
DISALLOW_COPY_AND_ASSIGN(AXPlatformNode); DISALLOW_COPY_AND_ASSIGN(AXPlatformNode);
}; };
......
...@@ -959,6 +959,13 @@ void AXPlatformNodeMac::NotifyAccessibilityEvent(ax::mojom::Event event_type) { ...@@ -959,6 +959,13 @@ void AXPlatformNodeMac::NotifyAccessibilityEvent(ax::mojom::Event event_type) {
return; return;
} }
break; break;
case ax::mojom::Event::kSelection:
// On Mac, map menu item selection to a focus event.
if (GetData().role == ax::mojom::Role::kMenuItem) {
NotifyMacEvent(native_node_, ax::mojom::Event::kFocus);
return;
}
break;
default: default:
break; break;
} }
......
...@@ -100,7 +100,6 @@ void FlushQueue() { ...@@ -100,7 +100,6 @@ void FlushQueue() {
// static // static
int NativeViewAccessibilityBase::menu_depth_ = 0; int NativeViewAccessibilityBase::menu_depth_ = 0;
int32_t NativeViewAccessibilityBase::fake_focus_view_id_ = 0;
NativeViewAccessibilityBase::NativeViewAccessibilityBase(View* view) NativeViewAccessibilityBase::NativeViewAccessibilityBase(View* view)
: ViewAccessibility(view) { : ViewAccessibility(view) {
...@@ -118,6 +117,9 @@ NativeViewAccessibilityBase::NativeViewAccessibilityBase(View* view) ...@@ -118,6 +117,9 @@ NativeViewAccessibilityBase::NativeViewAccessibilityBase(View* view)
} }
NativeViewAccessibilityBase::~NativeViewAccessibilityBase() { NativeViewAccessibilityBase::~NativeViewAccessibilityBase() {
if (ui::AXPlatformNode::GetPopupFocusOverride() == GetNativeObject())
ui::AXPlatformNode::SetPopupFocusOverride(nullptr);
g_unique_id_to_ax_platform_node.Get().erase(GetUniqueId().Get()); g_unique_id_to_ax_platform_node.Get().erase(GetUniqueId().Get());
ax_node_->Destroy(); ax_node_->Destroy();
} }
...@@ -166,7 +168,8 @@ void NativeViewAccessibilityBase::OnMenuItemActive() { ...@@ -166,7 +168,8 @@ void NativeViewAccessibilityBase::OnMenuItemActive() {
// When a native menu is shown and has an item selected, treat it and the // When a native menu is shown and has an item selected, treat it and the
// currently selected item as focused, even though the actual focus is in the // currently selected item as focused, even though the actual focus is in the
// browser's currently focused textfield. // browser's currently focused textfield.
fake_focus_view_id_ = GetUniqueId().Get(); ui::AXPlatformNode::SetPopupFocusOverride(
ax_node_->GetNativeViewAccessible());
} }
void NativeViewAccessibilityBase::OnMenuStart() { void NativeViewAccessibilityBase::OnMenuStart() {
...@@ -179,7 +182,7 @@ void NativeViewAccessibilityBase::OnMenuEnd() { ...@@ -179,7 +182,7 @@ void NativeViewAccessibilityBase::OnMenuEnd() {
DCHECK_GE(menu_depth_, 1); DCHECK_GE(menu_depth_, 1);
--menu_depth_; --menu_depth_;
if (menu_depth_ == 0) if (menu_depth_ == 0)
fake_focus_view_id_ = 0; ui::AXPlatformNode::SetPopupFocusOverride(nullptr);
} }
// ui::AXPlatformNodeDelegate // ui::AXPlatformNodeDelegate
...@@ -319,14 +322,15 @@ gfx::NativeViewAccessible NativeViewAccessibilityBase::HitTestSync(int x, ...@@ -319,14 +322,15 @@ gfx::NativeViewAccessible NativeViewAccessibilityBase::HitTestSync(int x,
} }
gfx::NativeViewAccessible NativeViewAccessibilityBase::GetFocus() { gfx::NativeViewAccessible NativeViewAccessibilityBase::GetFocus() {
gfx::NativeViewAccessible focus_override =
ui::AXPlatformNode::GetPopupFocusOverride();
if (focus_override)
return focus_override;
FocusManager* focus_manager = view()->GetFocusManager(); FocusManager* focus_manager = view()->GetFocusManager();
View* focused_view = View* focused_view =
focus_manager ? focus_manager->GetFocusedView() : nullptr; focus_manager ? focus_manager->GetFocusedView() : nullptr;
if (fake_focus_view_id_) {
ui::AXPlatformNode* ax_node = PlatformNodeFromNodeID(fake_focus_view_id_);
if (ax_node)
return ax_node->GetNativeViewAccessible();
}
return focused_view ? focused_view->GetNativeViewAccessible() : nullptr; return focused_view ? focused_view->GetNativeViewAccessible() : nullptr;
} }
......
...@@ -88,11 +88,6 @@ class VIEWS_EXPORT NativeViewAccessibilityBase ...@@ -88,11 +88,6 @@ class VIEWS_EXPORT NativeViewAccessibilityBase
// Levels of menu are currently open, e.g. 0: none, 1: top, 2: submenu ... // Levels of menu are currently open, e.g. 0: none, 1: top, 2: submenu ...
static int32_t menu_depth_; static int32_t menu_depth_;
// This allows UI menu popups like to act as if they are focused in the
// exposed platform accessibility API, even though true focus remains in
// underlying content.
static int32_t fake_focus_view_id_;
DISALLOW_COPY_AND_ASSIGN(NativeViewAccessibilityBase); DISALLOW_COPY_AND_ASSIGN(NativeViewAccessibilityBase);
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment