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

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

Issue 848653002: Re-land: Send Windows accessibility events based on tree updates. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@implicit_1_tests
Patch Set: Rebase Created 5 years, 10 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
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 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
66 return NULL; 66 return NULL;
67 return delegate_->AccessibilityGetAcceleratedWidget(); 67 return delegate_->AccessibilityGetAcceleratedWidget();
68 } 68 }
69 69
70 IAccessible* BrowserAccessibilityManagerWin::GetParentIAccessible() { 70 IAccessible* BrowserAccessibilityManagerWin::GetParentIAccessible() {
71 if (!delegate_) 71 if (!delegate_)
72 return NULL; 72 return NULL;
73 return delegate_->AccessibilityGetNativeViewAccessible(); 73 return delegate_->AccessibilityGetNativeViewAccessible();
74 } 74 }
75 75
76 void BrowserAccessibilityManagerWin::MaybeCallNotifyWinEvent(DWORD event, 76 void BrowserAccessibilityManagerWin::MaybeCallNotifyWinEvent(
77 LONG child_id) { 77 DWORD event, BrowserAccessibility* node) {
78 BrowserAccessibilityDelegate* delegate = GetDelegateFromRootManager(); 78 BrowserAccessibilityDelegate* delegate = GetDelegateFromRootManager();
79 if (!delegate) 79 if (!delegate)
80 return; 80 return;
81 81
82 if (!node->IsNative())
83 return;
84
82 HWND hwnd = delegate->AccessibilityGetAcceleratedWidget(); 85 HWND hwnd = delegate->AccessibilityGetAcceleratedWidget();
83 if (!hwnd) 86 if (!hwnd)
84 return; 87 return;
85 88
89 // Inline text boxes are an internal implementation detail, we don't
90 // expose them to Windows.
91 if (node->GetRole() == ui::AX_ROLE_INLINE_TEXT_BOX)
92 return;
93
94 // It doesn't make sense to fire a REORDER event on a leaf node; that
95 // happens when the node has internal children line inline text boxes.
96 if (event == EVENT_OBJECT_REORDER && node->PlatformIsLeaf())
97 return;
98
99 // Don't fire focus, or load complete notifications if the
100 // window isn't focused, because that can confuse screen readers into
101 // entering their "browse" mode.
102 if ((event == EVENT_OBJECT_FOCUS ||
103 event == IA2_EVENT_DOCUMENT_LOAD_COMPLETE) &&
104 (!delegate_->AccessibilityViewHasFocus())) {
105 return;
106 }
107
108 // NVDA gets confused if we focus the main document element when it hasn't
109 // finished loading and it has no children at all, so suppress that event.
110 if (event == EVENT_OBJECT_FOCUS &&
111 node == GetRoot() &&
112 node->PlatformChildCount() == 0 &&
113 !node->HasState(ui::AX_STATE_BUSY) &&
114 !node->GetBoolAttribute(ui::AX_ATTR_DOC_LOADED)) {
115 return;
116 }
117
118 // If a focus event is needed on the root, fire that first before
119 // this event.
120 if (event == EVENT_OBJECT_FOCUS && node == GetRoot())
121 focus_event_on_root_needed_ = false;
122 else if (focus_event_on_root_needed_)
123 OnWindowFocused();
124
125 LONG child_id = node->ToBrowserAccessibilityWin()->unique_id_win();
86 ::NotifyWinEvent(event, hwnd, OBJID_CLIENT, child_id); 126 ::NotifyWinEvent(event, hwnd, OBJID_CLIENT, child_id);
87 } 127 }
88 128
89 void BrowserAccessibilityManagerWin::OnNodeCreated(ui::AXNode* node) { 129 void BrowserAccessibilityManagerWin::OnNodeCreated(ui::AXNode* node) {
90 BrowserAccessibilityManager::OnNodeCreated(node); 130 BrowserAccessibilityManager::OnNodeCreated(node);
91 BrowserAccessibility* obj = GetFromAXNode(node); 131 BrowserAccessibility* obj = GetFromAXNode(node);
132 if (!obj)
133 return;
134 if (!obj->IsNative())
135 return;
92 LONG unique_id_win = obj->ToBrowserAccessibilityWin()->unique_id_win(); 136 LONG unique_id_win = obj->ToBrowserAccessibilityWin()->unique_id_win();
93 unique_id_to_ax_id_map_[unique_id_win] = obj->GetId(); 137 unique_id_to_ax_id_map_[unique_id_win] = obj->GetId();
94 } 138 }
95 139
96 void BrowserAccessibilityManagerWin::OnNodeWillBeDeleted(ui::AXNode* node) { 140 void BrowserAccessibilityManagerWin::OnNodeWillBeDeleted(ui::AXNode* node) {
97 BrowserAccessibilityManager::OnNodeWillBeDeleted(node); 141 BrowserAccessibilityManager::OnNodeWillBeDeleted(node);
98 BrowserAccessibility* obj = GetFromAXNode(node); 142 BrowserAccessibility* obj = GetFromAXNode(node);
99 if (!obj) 143 if (!obj)
100 return; 144 return;
145 if (!obj->IsNative())
146 return;
101 unique_id_to_ax_id_map_.erase( 147 unique_id_to_ax_id_map_.erase(
102 obj->ToBrowserAccessibilityWin()->unique_id_win()); 148 obj->ToBrowserAccessibilityWin()->unique_id_win());
103 if (obj == tracked_scroll_object_) { 149 if (obj == tracked_scroll_object_) {
104 tracked_scroll_object_->Release(); 150 tracked_scroll_object_->Release();
105 tracked_scroll_object_ = NULL; 151 tracked_scroll_object_ = NULL;
106 } 152 }
107 } 153 }
108 154
109 void BrowserAccessibilityManagerWin::OnWindowFocused() { 155 void BrowserAccessibilityManagerWin::OnWindowFocused() {
110 // This is called either when this web frame gets focused, or when 156 // This is called either when this web frame gets focused, or when
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
166 OnWindowFocused(); 212 OnWindowFocused();
167 213
168 LONG event_id = EVENT_MIN; 214 LONG event_id = EVENT_MIN;
169 switch (event_type) { 215 switch (event_type) {
170 case ui::AX_EVENT_ACTIVEDESCENDANTCHANGED: 216 case ui::AX_EVENT_ACTIVEDESCENDANTCHANGED:
171 event_id = IA2_EVENT_ACTIVE_DESCENDANT_CHANGED; 217 event_id = IA2_EVENT_ACTIVE_DESCENDANT_CHANGED;
172 break; 218 break;
173 case ui::AX_EVENT_ALERT: 219 case ui::AX_EVENT_ALERT:
174 event_id = EVENT_SYSTEM_ALERT; 220 event_id = EVENT_SYSTEM_ALERT;
175 break; 221 break;
176 case ui::AX_EVENT_ARIA_ATTRIBUTE_CHANGED:
177 event_id = IA2_EVENT_OBJECT_ATTRIBUTE_CHANGED;
178 break;
179 case ui::AX_EVENT_AUTOCORRECTION_OCCURED: 222 case ui::AX_EVENT_AUTOCORRECTION_OCCURED:
180 event_id = IA2_EVENT_OBJECT_ATTRIBUTE_CHANGED; 223 event_id = IA2_EVENT_OBJECT_ATTRIBUTE_CHANGED;
181 break; 224 break;
182 case ui::AX_EVENT_BLUR: 225 case ui::AX_EVENT_BLUR:
183 // Equivalent to focus on the root. 226 // Equivalent to focus on the root.
184 event_id = EVENT_OBJECT_FOCUS; 227 event_id = EVENT_OBJECT_FOCUS;
185 node = GetRoot(); 228 node = GetRoot();
186 break; 229 break;
187 case ui::AX_EVENT_CHECKED_STATE_CHANGED:
188 event_id = EVENT_OBJECT_STATECHANGE;
189 break;
190 case ui::AX_EVENT_CHILDREN_CHANGED: 230 case ui::AX_EVENT_CHILDREN_CHANGED:
191 event_id = EVENT_OBJECT_REORDER; 231 event_id = EVENT_OBJECT_REORDER;
192 break; 232 break;
193 case ui::AX_EVENT_FOCUS: 233 case ui::AX_EVENT_FOCUS:
194 event_id = EVENT_OBJECT_FOCUS; 234 event_id = EVENT_OBJECT_FOCUS;
195 break; 235 break;
196 case ui::AX_EVENT_INVALID_STATUS_CHANGED:
197 event_id = EVENT_OBJECT_STATECHANGE;
198 break;
199 case ui::AX_EVENT_LIVE_REGION_CHANGED: 236 case ui::AX_EVENT_LIVE_REGION_CHANGED:
200 if (node->GetBoolAttribute(ui::AX_ATTR_CONTAINER_LIVE_BUSY)) 237 if (node->GetBoolAttribute(ui::AX_ATTR_CONTAINER_LIVE_BUSY))
201 return; 238 return;
202 event_id = EVENT_OBJECT_LIVEREGIONCHANGED; 239 event_id = EVENT_OBJECT_LIVEREGIONCHANGED;
203 break; 240 break;
204 case ui::AX_EVENT_LOAD_COMPLETE: 241 case ui::AX_EVENT_LOAD_COMPLETE:
205 event_id = IA2_EVENT_DOCUMENT_LOAD_COMPLETE; 242 event_id = IA2_EVENT_DOCUMENT_LOAD_COMPLETE;
206 break; 243 break;
207 case ui::AX_EVENT_MENU_LIST_ITEM_SELECTED: 244 case ui::AX_EVENT_MENU_LIST_ITEM_SELECTED:
208 event_id = EVENT_OBJECT_FOCUS; 245 event_id = EVENT_OBJECT_FOCUS;
209 break; 246 break;
210 case ui::AX_EVENT_MENU_LIST_VALUE_CHANGED: 247 case ui::AX_EVENT_MENU_LIST_VALUE_CHANGED:
211 event_id = EVENT_OBJECT_VALUECHANGE; 248 event_id = EVENT_OBJECT_VALUECHANGE;
212 break; 249 break;
213 case ui::AX_EVENT_HIDE:
214 event_id = EVENT_OBJECT_HIDE;
215 break;
216 case ui::AX_EVENT_SHOW:
217 event_id = EVENT_OBJECT_SHOW;
218 break;
219 case ui::AX_EVENT_SCROLL_POSITION_CHANGED: 250 case ui::AX_EVENT_SCROLL_POSITION_CHANGED:
220 event_id = EVENT_SYSTEM_SCROLLINGEND; 251 event_id = EVENT_SYSTEM_SCROLLINGEND;
221 break; 252 break;
222 case ui::AX_EVENT_SCROLLED_TO_ANCHOR: 253 case ui::AX_EVENT_SCROLLED_TO_ANCHOR:
223 event_id = EVENT_SYSTEM_SCROLLINGSTART; 254 event_id = EVENT_SYSTEM_SCROLLINGSTART;
224 break; 255 break;
225 case ui::AX_EVENT_SELECTED_CHILDREN_CHANGED: 256 case ui::AX_EVENT_SELECTED_CHILDREN_CHANGED:
226 event_id = EVENT_OBJECT_SELECTIONWITHIN; 257 event_id = EVENT_OBJECT_SELECTIONWITHIN;
227 break; 258 break;
228 case ui::AX_EVENT_TEXT_CHANGED:
229 event_id = EVENT_OBJECT_NAMECHANGE;
230 break;
231 case ui::AX_EVENT_TEXT_SELECTION_CHANGED: 259 case ui::AX_EVENT_TEXT_SELECTION_CHANGED:
232 event_id = IA2_EVENT_TEXT_CARET_MOVED; 260 event_id = IA2_EVENT_TEXT_CARET_MOVED;
233 break; 261 break;
234 case ui::AX_EVENT_VALUE_CHANGED:
235 event_id = EVENT_OBJECT_VALUECHANGE;
236 break;
237 default: 262 default:
238 // Not all WebKit accessibility events result in a Windows 263 // Not all WebKit accessibility events result in a Windows
239 // accessibility notification. 264 // accessibility notification.
240 break; 265 break;
241 } 266 }
242 267
243 if (event_id != EVENT_MIN) { 268 if (event_id != EVENT_MIN) {
244 // Pass the node's unique id in the |child_id| argument to NotifyWinEvent; 269 // Pass the node's unique id in the |child_id| argument to NotifyWinEvent;
245 // the AT client will then call get_accChild on the HWND's accessibility 270 // the AT client will then call get_accChild on the HWND's accessibility
246 // object and pass it that same id, which we can use to retrieve the 271 // object and pass it that same id, which we can use to retrieve the
247 // IAccessible for this node. 272 // IAccessible for this node.
248 LONG child_id = node->ToBrowserAccessibilityWin()->unique_id_win(); 273 MaybeCallNotifyWinEvent(event_id, node);
249 MaybeCallNotifyWinEvent(event_id, child_id);
250 } 274 }
251 275
252 // If this is a layout complete notification (sent when a container scrolls) 276 // If this is a layout complete notification (sent when a container scrolls)
253 // and there is a descendant tracked object, send a notification on it. 277 // and there is a descendant tracked object, send a notification on it.
254 // TODO(dmazzoni): remove once http://crbug.com/113483 is fixed. 278 // TODO(dmazzoni): remove once http://crbug.com/113483 is fixed.
255 if (event_type == ui::AX_EVENT_LAYOUT_COMPLETE && 279 if (event_type == ui::AX_EVENT_LAYOUT_COMPLETE &&
256 tracked_scroll_object_ && 280 tracked_scroll_object_ &&
257 tracked_scroll_object_->IsDescendantOf(node)) { 281 tracked_scroll_object_->IsDescendantOf(node)) {
258 MaybeCallNotifyWinEvent( 282 MaybeCallNotifyWinEvent(
259 IA2_EVENT_VISIBLE_DATA_CHANGED, 283 IA2_EVENT_VISIBLE_DATA_CHANGED, tracked_scroll_object_);
260 tracked_scroll_object_->ToBrowserAccessibilityWin()->unique_id_win());
261 tracked_scroll_object_->Release(); 284 tracked_scroll_object_->Release();
262 tracked_scroll_object_ = NULL; 285 tracked_scroll_object_ = NULL;
263 } 286 }
264 } 287 }
265 288
266 void BrowserAccessibilityManagerWin::OnAtomicUpdateFinished( 289 void BrowserAccessibilityManagerWin::OnAtomicUpdateFinished(
267 bool root_changed, 290 bool root_changed,
268 const std::vector<ui::AXTreeDelegate::Change>& changes) { 291 const std::vector<ui::AXTreeDelegate::Change>& changes) {
269 BrowserAccessibilityManager::OnAtomicUpdateFinished(root_changed, changes); 292 BrowserAccessibilityManager::OnAtomicUpdateFinished(root_changed, changes);
270 293
271 if (root_changed) { 294 if (root_changed) {
272 // In order to make screen readers aware of the new accessibility root, 295 // In order to make screen readers aware of the new accessibility root,
273 // we need to fire a focus event on it. 296 // we need to fire a focus event on it.
274 OnWindowFocused(); 297 OnWindowFocused();
275 } 298 }
299
300 // BrowserAccessibilityManager::OnAtomicUpdateFinished calls
301 // OnUpdateFinished() on each node in |changes|. However, the
302 // IAccessibleText text for a node is a concatenatenation of all of its child
303 // text nodes, so we can't compute a node's IAccessibleText in
304 // OnUpdateFinished because its children may not have been updated yet.
305 //
306 // So we make a second pass here to update IAccessibleText.
307 for (size_t i = 0; i < changes.size(); ++i) {
308 BrowserAccessibility* obj = GetFromAXNode(changes[i].node);
309 if (obj && obj->IsNative())
310 obj->ToBrowserAccessibilityWin()->UpdateIAccessibleText();
311 }
276 } 312 }
277 313
278 void BrowserAccessibilityManagerWin::TrackScrollingObject( 314 void BrowserAccessibilityManagerWin::TrackScrollingObject(
279 BrowserAccessibilityWin* node) { 315 BrowserAccessibilityWin* node) {
280 if (tracked_scroll_object_) 316 if (tracked_scroll_object_)
281 tracked_scroll_object_->Release(); 317 tracked_scroll_object_->Release();
282 tracked_scroll_object_ = node; 318 tracked_scroll_object_ = node;
283 tracked_scroll_object_->AddRef(); 319 tracked_scroll_object_->AddRef();
284 } 320 }
285 321
286 BrowserAccessibilityWin* BrowserAccessibilityManagerWin::GetFromUniqueIdWin( 322 BrowserAccessibilityWin* BrowserAccessibilityManagerWin::GetFromUniqueIdWin(
287 LONG unique_id_win) { 323 LONG unique_id_win) {
288 base::hash_map<LONG, int32>::iterator iter = 324 base::hash_map<LONG, int32>::iterator iter =
289 unique_id_to_ax_id_map_.find(unique_id_win); 325 unique_id_to_ax_id_map_.find(unique_id_win);
290 if (iter != unique_id_to_ax_id_map_.end()) { 326 if (iter != unique_id_to_ax_id_map_.end()) {
291 BrowserAccessibility* result = GetFromID(iter->second); 327 BrowserAccessibility* result = GetFromID(iter->second);
292 if (result) 328 if (result && result->IsNative())
293 return result->ToBrowserAccessibilityWin(); 329 return result->ToBrowserAccessibilityWin();
294 } 330 }
295 331
296 // Also search all child frames, such as out-of-process iframes or 332 // Also search all child frames, such as out-of-process iframes or
297 // guest browser plugins. 333 // guest browser plugins.
298 if (delegate()) { 334 if (delegate()) {
299 std::vector<BrowserAccessibilityManager*> child_frames; 335 std::vector<BrowserAccessibilityManager*> child_frames;
300 delegate()->AccessibilityGetAllChildFrames(&child_frames); 336 delegate()->AccessibilityGetAllChildFrames(&child_frames);
301 for (size_t i = 0; i < child_frames.size(); ++i) { 337 for (size_t i = 0; i < child_frames.size(); ++i) {
302 BrowserAccessibilityManagerWin* child_manager = 338 BrowserAccessibilityManagerWin* child_manager =
303 child_frames[i]->ToBrowserAccessibilityManagerWin(); 339 child_frames[i]->ToBrowserAccessibilityManagerWin();
304 BrowserAccessibilityWin* result = 340 BrowserAccessibilityWin* result =
305 child_manager->GetFromUniqueIdWin(unique_id_win); 341 child_manager->GetFromUniqueIdWin(unique_id_win);
306 if (result) 342 if (result)
307 return result; 343 return result;
308 } 344 }
309 } 345 }
310 346
311 return NULL; 347 return NULL;
312 } 348 }
313 349
314 } // namespace content 350 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698