Commit d2b32fde authored by dmazzoni@chromium.org's avatar dmazzoni@chromium.org

More NVDA browse mode fixes

The previous change (https://codereview.chromium.org/332893004/) wasn't quite right. To avoid errors, we need to only fire focus and load events when the web view itself has focus, not say when the location bar has focus. And because there are transient periods when we can't fire events, we need to keep track of whether we need to fire a focus event with a flag and fire it later.

BUG=368549
NOTRY=true

Review URL: https://codereview.chromium.org/344573003

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@278303 0039d316-1c4b-4281-b951-d872f2087c98
parent 61e469f9
......@@ -40,7 +40,8 @@ BrowserAccessibilityManagerWin::BrowserAccessibilityManagerWin(
parent_hwnd_(NULL),
parent_iaccessible_(parent_iaccessible),
tracked_scroll_object_(NULL),
accessible_hwnd_(accessible_hwnd) {
accessible_hwnd_(accessible_hwnd),
focus_event_on_root_needed_(false) {
ui::win::CreateATLModuleIfNeeded();
if (accessible_hwnd_) {
accessible_hwnd_->set_browser_accessibility_manager(this);
......@@ -83,19 +84,18 @@ void BrowserAccessibilityManagerWin::SetAccessibleHWND(
void BrowserAccessibilityManagerWin::MaybeCallNotifyWinEvent(DWORD event,
LONG child_id) {
// Don't fire events if this view isn't hooked up to its parent.
if (!parent_iaccessible() || !parent_hwnd())
return;
// If on Win 7 and complete accessibility is enabled, use the fake child HWND
// to use as the root of the accessibility tree. See comments above
// LegacyRenderWidgetHostHWND for details.
if (BrowserAccessibilityStateImpl::GetInstance()->IsAccessibleBrowser()) {
DCHECK(accessible_hwnd_);
if (accessible_hwnd_ &&
BrowserAccessibilityStateImpl::GetInstance()->IsAccessibleBrowser()) {
parent_hwnd_ = accessible_hwnd_->hwnd();
parent_iaccessible_ = accessible_hwnd_->window_accessible();
}
::NotifyWinEvent(event, parent_hwnd(), OBJID_CLIENT, child_id);
// Only fire events if this view is hooked up to its parent.
if (parent_iaccessible() && parent_hwnd())
::NotifyWinEvent(event, parent_hwnd(), OBJID_CLIENT, child_id);
}
......@@ -120,34 +120,58 @@ void BrowserAccessibilityManagerWin::OnNodeWillBeDeleted(ui::AXNode* node) {
}
void BrowserAccessibilityManagerWin::OnWindowFocused() {
// Fire a focus event on the root first and then the focused node.
// This is called either when this web frame gets focused, or when
// the root of the accessibility tree changes. In both cases, we need
// to fire a focus event on the root and then on the focused element
// within the page, if different.
// Set this flag so that we'll keep trying to fire these focus events
// if they're not successful this time.
focus_event_on_root_needed_ = true;
if (!delegate_ || !delegate_->AccessibilityViewHasFocus())
return;
// Try to fire a focus event on the root first and then the focused node.
// This will clear focus_event_on_root_needed_ if successful.
if (focus_ != tree_->GetRoot())
NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, GetRoot());
BrowserAccessibilityManager::OnWindowFocused();
}
void BrowserAccessibilityManagerWin::OnWindowBlurred() {
// Fire a blur event on the focused node first and then the root.
BrowserAccessibilityManager::OnWindowBlurred();
if (focus_ != tree_->GetRoot())
NotifyAccessibilityEvent(ui::AX_EVENT_BLUR, GetRoot());
}
void BrowserAccessibilityManagerWin::NotifyAccessibilityEvent(
ui::AXEvent event_type,
BrowserAccessibility* node) {
if (node->GetRole() == ui::AX_ROLE_INLINE_TEXT_BOX)
return;
// Don't fire focus, blur, or load complete notifications if the
// window isn't focused, because that can confuse screen readers into
// entering their "browse" mode.
if ((event_type == ui::AX_EVENT_FOCUS ||
event_type == ui::AX_EVENT_BLUR ||
event_type == ui::AX_EVENT_LOAD_COMPLETE) &&
(!delegate_ || !delegate_->AccessibilityViewHasFocus())) {
return;
}
// NVDA gets confused if we focus the main document element when it hasn't
// finished loading and it has no children at all, so suppress that event.
if (event_type == ui::AX_EVENT_FOCUS &&
node == GetRoot() &&
node->PlatformChildCount() == 0 &&
!node->HasState(ui::AX_STATE_BUSY) &&
!node->GetBoolAttribute(ui::AX_ATTR_DOC_LOADED)) {
return;
}
// If a focus event is needed on the root, fire that first before
// this event.
if (event_type == ui::AX_EVENT_FOCUS && node == GetRoot())
focus_event_on_root_needed_ = false;
else if (focus_event_on_root_needed_)
OnWindowFocused();
LONG event_id = EVENT_MIN;
switch (event_type) {
case ui::AX_EVENT_ACTIVEDESCENDANTCHANGED:
......@@ -235,10 +259,6 @@ void BrowserAccessibilityManagerWin::NotifyAccessibilityEvent(
// object and pass it that same id, which we can use to retrieve the
// IAccessible for this node.
LONG child_id = node->ToBrowserAccessibilityWin()->unique_id_win();
// Always send a focus before a load complete.
if (event_type == ui::AX_EVENT_LOAD_COMPLETE)
MaybeCallNotifyWinEvent(EVENT_OBJECT_FOCUS, child_id);
MaybeCallNotifyWinEvent(event_id, child_id);
}
......@@ -257,8 +277,9 @@ void BrowserAccessibilityManagerWin::NotifyAccessibilityEvent(
}
void BrowserAccessibilityManagerWin::OnRootChanged(ui::AXNode* new_root) {
if (delegate_ && delegate_->AccessibilityViewHasFocus())
NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, GetRoot());
// In order to make screen readers aware of the new accessibility root,
// we need to fire a focus event on it.
OnWindowFocused();
}
void BrowserAccessibilityManagerWin::TrackScrollingObject(
......
......@@ -51,7 +51,6 @@ class CONTENT_EXPORT BrowserAccessibilityManagerWin
// BrowserAccessibilityManager methods
virtual void OnWindowFocused() OVERRIDE;
virtual void OnWindowBlurred() OVERRIDE;
virtual void NotifyAccessibilityEvent(
ui::AXEvent event_type, BrowserAccessibility* node) OVERRIDE;
......@@ -93,6 +92,10 @@ class CONTENT_EXPORT BrowserAccessibilityManagerWin
// Owned by its parent; OnAccessibleHwndDeleted gets called upon deletion.
LegacyRenderWidgetHostHWND* accessible_hwnd_;
// Set to true if we need to fire a focus event on the root as soon as
// possible.
bool focus_event_on_root_needed_;
DISALLOW_COPY_AND_ASSIGN(BrowserAccessibilityManagerWin);
};
......
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