Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(140)

Side by Side Diff: content/browser/accessibility/browser_accessibility_manager_win.cc

Issue 344573003: More NVDA browse mode fixes (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@x64_2
Patch Set: Address feedback Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « content/browser/accessibility/browser_accessibility_manager_win.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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_win.h" 5 #include "content/browser/accessibility/browser_accessibility_manager_win.h"
6 6
7 #include "base/command_line.h" 7 #include "base/command_line.h"
8 #include "base/win/scoped_comptr.h" 8 #include "base/win/scoped_comptr.h"
9 #include "base/win/windows_version.h" 9 #include "base/win/windows_version.h"
10 #include "content/browser/accessibility/browser_accessibility_state_impl.h" 10 #include "content/browser/accessibility/browser_accessibility_state_impl.h"
(...skipping 22 matching lines...) Expand all
33 BrowserAccessibilityManagerWin::BrowserAccessibilityManagerWin( 33 BrowserAccessibilityManagerWin::BrowserAccessibilityManagerWin(
34 LegacyRenderWidgetHostHWND* accessible_hwnd, 34 LegacyRenderWidgetHostHWND* accessible_hwnd,
35 IAccessible* parent_iaccessible, 35 IAccessible* parent_iaccessible,
36 const ui::AXTreeUpdate& initial_tree, 36 const ui::AXTreeUpdate& initial_tree,
37 BrowserAccessibilityDelegate* delegate, 37 BrowserAccessibilityDelegate* delegate,
38 BrowserAccessibilityFactory* factory) 38 BrowserAccessibilityFactory* factory)
39 : BrowserAccessibilityManager(initial_tree, delegate, factory), 39 : BrowserAccessibilityManager(initial_tree, delegate, factory),
40 parent_hwnd_(NULL), 40 parent_hwnd_(NULL),
41 parent_iaccessible_(parent_iaccessible), 41 parent_iaccessible_(parent_iaccessible),
42 tracked_scroll_object_(NULL), 42 tracked_scroll_object_(NULL),
43 accessible_hwnd_(accessible_hwnd) { 43 accessible_hwnd_(accessible_hwnd),
44 focus_event_on_root_needed_(false) {
44 ui::win::CreateATLModuleIfNeeded(); 45 ui::win::CreateATLModuleIfNeeded();
45 if (accessible_hwnd_) { 46 if (accessible_hwnd_) {
46 accessible_hwnd_->set_browser_accessibility_manager(this); 47 accessible_hwnd_->set_browser_accessibility_manager(this);
47 parent_hwnd_ = accessible_hwnd_->GetParent(); 48 parent_hwnd_ = accessible_hwnd_->GetParent();
48 } 49 }
49 } 50 }
50 51
51 BrowserAccessibilityManagerWin::~BrowserAccessibilityManagerWin() { 52 BrowserAccessibilityManagerWin::~BrowserAccessibilityManagerWin() {
52 if (tracked_scroll_object_) { 53 if (tracked_scroll_object_) {
53 tracked_scroll_object_->Release(); 54 tracked_scroll_object_->Release();
(...skipping 22 matching lines...) Expand all
76 LegacyRenderWidgetHostHWND* accessible_hwnd) { 77 LegacyRenderWidgetHostHWND* accessible_hwnd) {
77 accessible_hwnd_ = accessible_hwnd; 78 accessible_hwnd_ = accessible_hwnd;
78 if (accessible_hwnd_) { 79 if (accessible_hwnd_) {
79 accessible_hwnd_->set_browser_accessibility_manager(this); 80 accessible_hwnd_->set_browser_accessibility_manager(this);
80 parent_hwnd_ = accessible_hwnd_->GetParent(); 81 parent_hwnd_ = accessible_hwnd_->GetParent();
81 } 82 }
82 } 83 }
83 84
84 void BrowserAccessibilityManagerWin::MaybeCallNotifyWinEvent(DWORD event, 85 void BrowserAccessibilityManagerWin::MaybeCallNotifyWinEvent(DWORD event,
85 LONG child_id) { 86 LONG child_id) {
86 // Don't fire events if this view isn't hooked up to its parent.
87 if (!parent_iaccessible() || !parent_hwnd())
88 return;
89
90 // If on Win 7 and complete accessibility is enabled, use the fake child HWND 87 // If on Win 7 and complete accessibility is enabled, use the fake child HWND
91 // to use as the root of the accessibility tree. See comments above 88 // to use as the root of the accessibility tree. See comments above
92 // LegacyRenderWidgetHostHWND for details. 89 // LegacyRenderWidgetHostHWND for details.
93 if (BrowserAccessibilityStateImpl::GetInstance()->IsAccessibleBrowser()) { 90 if (accessible_hwnd_ &&
94 DCHECK(accessible_hwnd_); 91 BrowserAccessibilityStateImpl::GetInstance()->IsAccessibleBrowser()) {
95 parent_hwnd_ = accessible_hwnd_->hwnd(); 92 parent_hwnd_ = accessible_hwnd_->hwnd();
96 parent_iaccessible_ = accessible_hwnd_->window_accessible(); 93 parent_iaccessible_ = accessible_hwnd_->window_accessible();
97 } 94 }
98 ::NotifyWinEvent(event, parent_hwnd(), OBJID_CLIENT, child_id); 95
96 // Only fire events if this view is hooked up to its parent.
97 if (parent_iaccessible() && parent_hwnd())
98 ::NotifyWinEvent(event, parent_hwnd(), OBJID_CLIENT, child_id);
99 } 99 }
100 100
101 101
102 void BrowserAccessibilityManagerWin::OnNodeCreated(ui::AXNode* node) { 102 void BrowserAccessibilityManagerWin::OnNodeCreated(ui::AXNode* node) {
103 BrowserAccessibilityManager::OnNodeCreated(node); 103 BrowserAccessibilityManager::OnNodeCreated(node);
104 BrowserAccessibility* obj = GetFromAXNode(node); 104 BrowserAccessibility* obj = GetFromAXNode(node);
105 LONG unique_id_win = obj->ToBrowserAccessibilityWin()->unique_id_win(); 105 LONG unique_id_win = obj->ToBrowserAccessibilityWin()->unique_id_win();
106 unique_id_to_ax_id_map_[unique_id_win] = obj->GetId(); 106 unique_id_to_ax_id_map_[unique_id_win] = obj->GetId();
107 } 107 }
108 108
109 void BrowserAccessibilityManagerWin::OnNodeWillBeDeleted(ui::AXNode* node) { 109 void BrowserAccessibilityManagerWin::OnNodeWillBeDeleted(ui::AXNode* node) {
110 BrowserAccessibilityManager::OnNodeWillBeDeleted(node); 110 BrowserAccessibilityManager::OnNodeWillBeDeleted(node);
111 BrowserAccessibility* obj = GetFromAXNode(node); 111 BrowserAccessibility* obj = GetFromAXNode(node);
112 if (!obj) 112 if (!obj)
113 return; 113 return;
114 unique_id_to_ax_id_map_.erase( 114 unique_id_to_ax_id_map_.erase(
115 obj->ToBrowserAccessibilityWin()->unique_id_win()); 115 obj->ToBrowserAccessibilityWin()->unique_id_win());
116 if (obj == tracked_scroll_object_) { 116 if (obj == tracked_scroll_object_) {
117 tracked_scroll_object_->Release(); 117 tracked_scroll_object_->Release();
118 tracked_scroll_object_ = NULL; 118 tracked_scroll_object_ = NULL;
119 } 119 }
120 } 120 }
121 121
122 void BrowserAccessibilityManagerWin::OnWindowFocused() { 122 void BrowserAccessibilityManagerWin::OnWindowFocused() {
123 // Fire a focus event on the root first and then the focused node. 123 // This is called either when this web frame gets focused, or when
124 // the root of the accessibility tree changes. In both cases, we need
125 // to fire a focus event on the root and then on the focused element
126 // within the page, if different.
127
128 // Set this flag so that we'll keep trying to fire these focus events
129 // if they're not successful this time.
130 focus_event_on_root_needed_ = true;
131
132 if (!delegate_ || !delegate_->AccessibilityViewHasFocus())
133 return;
134
135 // Try to fire a focus event on the root first and then the focused node.
136 // This will clear focus_event_on_root_needed_ if successful.
124 if (focus_ != tree_->GetRoot()) 137 if (focus_ != tree_->GetRoot())
125 NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, GetRoot()); 138 NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, GetRoot());
126 BrowserAccessibilityManager::OnWindowFocused(); 139 BrowserAccessibilityManager::OnWindowFocused();
127 } 140 }
128 141
129 void BrowserAccessibilityManagerWin::OnWindowBlurred() {
130 // Fire a blur event on the focused node first and then the root.
131 BrowserAccessibilityManager::OnWindowBlurred();
132 if (focus_ != tree_->GetRoot())
133 NotifyAccessibilityEvent(ui::AX_EVENT_BLUR, GetRoot());
134 }
135
136 void BrowserAccessibilityManagerWin::NotifyAccessibilityEvent( 142 void BrowserAccessibilityManagerWin::NotifyAccessibilityEvent(
137 ui::AXEvent event_type, 143 ui::AXEvent event_type,
138 BrowserAccessibility* node) { 144 BrowserAccessibility* node) {
139 if (node->GetRole() == ui::AX_ROLE_INLINE_TEXT_BOX) 145 if (node->GetRole() == ui::AX_ROLE_INLINE_TEXT_BOX)
140 return; 146 return;
141 147
148 // Don't fire focus, blur, or load complete notifications if the
149 // window isn't focused, because that can confuse screen readers into
150 // entering their "browse" mode.
151 if ((event_type == ui::AX_EVENT_FOCUS ||
152 event_type == ui::AX_EVENT_BLUR ||
153 event_type == ui::AX_EVENT_LOAD_COMPLETE) &&
154 (!delegate_ || !delegate_->AccessibilityViewHasFocus())) {
155 return;
156 }
157
142 // NVDA gets confused if we focus the main document element when it hasn't 158 // NVDA gets confused if we focus the main document element when it hasn't
143 // finished loading and it has no children at all, so suppress that event. 159 // finished loading and it has no children at all, so suppress that event.
144 if (event_type == ui::AX_EVENT_FOCUS && 160 if (event_type == ui::AX_EVENT_FOCUS &&
145 node == GetRoot() && 161 node == GetRoot() &&
146 node->PlatformChildCount() == 0 && 162 node->PlatformChildCount() == 0 &&
163 !node->HasState(ui::AX_STATE_BUSY) &&
147 !node->GetBoolAttribute(ui::AX_ATTR_DOC_LOADED)) { 164 !node->GetBoolAttribute(ui::AX_ATTR_DOC_LOADED)) {
148 return; 165 return;
149 } 166 }
150 167
168 // If a focus event is needed on the root, fire that first before
169 // this event.
170 if (event_type == ui::AX_EVENT_FOCUS && node == GetRoot())
171 focus_event_on_root_needed_ = false;
172 else if (focus_event_on_root_needed_)
173 OnWindowFocused();
174
151 LONG event_id = EVENT_MIN; 175 LONG event_id = EVENT_MIN;
152 switch (event_type) { 176 switch (event_type) {
153 case ui::AX_EVENT_ACTIVEDESCENDANTCHANGED: 177 case ui::AX_EVENT_ACTIVEDESCENDANTCHANGED:
154 event_id = IA2_EVENT_ACTIVE_DESCENDANT_CHANGED; 178 event_id = IA2_EVENT_ACTIVE_DESCENDANT_CHANGED;
155 break; 179 break;
156 case ui::AX_EVENT_ALERT: 180 case ui::AX_EVENT_ALERT:
157 event_id = EVENT_SYSTEM_ALERT; 181 event_id = EVENT_SYSTEM_ALERT;
158 break; 182 break;
159 case ui::AX_EVENT_ARIA_ATTRIBUTE_CHANGED: 183 case ui::AX_EVENT_ARIA_ATTRIBUTE_CHANGED:
160 event_id = IA2_EVENT_OBJECT_ATTRIBUTE_CHANGED; 184 event_id = IA2_EVENT_OBJECT_ATTRIBUTE_CHANGED;
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
228 // accessibility notification. 252 // accessibility notification.
229 break; 253 break;
230 } 254 }
231 255
232 if (event_id != EVENT_MIN) { 256 if (event_id != EVENT_MIN) {
233 // Pass the node's unique id in the |child_id| argument to NotifyWinEvent; 257 // Pass the node's unique id in the |child_id| argument to NotifyWinEvent;
234 // the AT client will then call get_accChild on the HWND's accessibility 258 // the AT client will then call get_accChild on the HWND's accessibility
235 // object and pass it that same id, which we can use to retrieve the 259 // object and pass it that same id, which we can use to retrieve the
236 // IAccessible for this node. 260 // IAccessible for this node.
237 LONG child_id = node->ToBrowserAccessibilityWin()->unique_id_win(); 261 LONG child_id = node->ToBrowserAccessibilityWin()->unique_id_win();
238
239 // Always send a focus before a load complete.
240 if (event_type == ui::AX_EVENT_LOAD_COMPLETE)
241 MaybeCallNotifyWinEvent(EVENT_OBJECT_FOCUS, child_id);
242 MaybeCallNotifyWinEvent(event_id, child_id); 262 MaybeCallNotifyWinEvent(event_id, child_id);
243 } 263 }
244 264
245 // If this is a layout complete notification (sent when a container scrolls) 265 // If this is a layout complete notification (sent when a container scrolls)
246 // and there is a descendant tracked object, send a notification on it. 266 // and there is a descendant tracked object, send a notification on it.
247 // TODO(dmazzoni): remove once http://crbug.com/113483 is fixed. 267 // TODO(dmazzoni): remove once http://crbug.com/113483 is fixed.
248 if (event_type == ui::AX_EVENT_LAYOUT_COMPLETE && 268 if (event_type == ui::AX_EVENT_LAYOUT_COMPLETE &&
249 tracked_scroll_object_ && 269 tracked_scroll_object_ &&
250 tracked_scroll_object_->IsDescendantOf(node)) { 270 tracked_scroll_object_->IsDescendantOf(node)) {
251 MaybeCallNotifyWinEvent( 271 MaybeCallNotifyWinEvent(
252 IA2_EVENT_VISIBLE_DATA_CHANGED, 272 IA2_EVENT_VISIBLE_DATA_CHANGED,
253 tracked_scroll_object_->ToBrowserAccessibilityWin()->unique_id_win()); 273 tracked_scroll_object_->ToBrowserAccessibilityWin()->unique_id_win());
254 tracked_scroll_object_->Release(); 274 tracked_scroll_object_->Release();
255 tracked_scroll_object_ = NULL; 275 tracked_scroll_object_ = NULL;
256 } 276 }
257 } 277 }
258 278
259 void BrowserAccessibilityManagerWin::OnRootChanged(ui::AXNode* new_root) { 279 void BrowserAccessibilityManagerWin::OnRootChanged(ui::AXNode* new_root) {
260 if (delegate_ && delegate_->AccessibilityViewHasFocus()) 280 // In order to make screen readers aware of the new accessibility root,
261 NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, GetRoot()); 281 // we need to fire a focus event on it.
282 OnWindowFocused();
262 } 283 }
263 284
264 void BrowserAccessibilityManagerWin::TrackScrollingObject( 285 void BrowserAccessibilityManagerWin::TrackScrollingObject(
265 BrowserAccessibilityWin* node) { 286 BrowserAccessibilityWin* node) {
266 if (tracked_scroll_object_) 287 if (tracked_scroll_object_)
267 tracked_scroll_object_->Release(); 288 tracked_scroll_object_->Release();
268 tracked_scroll_object_ = node; 289 tracked_scroll_object_ = node;
269 tracked_scroll_object_->AddRef(); 290 tracked_scroll_object_->AddRef();
270 } 291 }
271 292
(...skipping 14 matching lines...) Expand all
286 // |parent_iaccessible_| are no longer valid either, since they were 307 // |parent_iaccessible_| are no longer valid either, since they were
287 // derived from AccessibleHWND. We don't have to restore them to 308 // derived from AccessibleHWND. We don't have to restore them to
288 // previous values, though, because this should only happen 309 // previous values, though, because this should only happen
289 // during the destruct sequence for this window. 310 // during the destruct sequence for this window.
290 accessible_hwnd_ = NULL; 311 accessible_hwnd_ = NULL;
291 parent_hwnd_ = NULL; 312 parent_hwnd_ = NULL;
292 parent_iaccessible_ = NULL; 313 parent_iaccessible_ = NULL;
293 } 314 }
294 315
295 } // namespace content 316 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/accessibility/browser_accessibility_manager_win.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698