OLD | NEW |
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 Loading... |
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( | 76 void BrowserAccessibilityManagerWin::MaybeCallNotifyWinEvent(DWORD event, |
77 DWORD event, BrowserAccessibility* node) { | 77 LONG child_id) { |
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 | |
85 HWND hwnd = delegate->AccessibilityGetAcceleratedWidget(); | 82 HWND hwnd = delegate->AccessibilityGetAcceleratedWidget(); |
86 if (!hwnd) | 83 if (!hwnd) |
87 return; | 84 return; |
88 | 85 |
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(); | |
126 ::NotifyWinEvent(event, hwnd, OBJID_CLIENT, child_id); | 86 ::NotifyWinEvent(event, hwnd, OBJID_CLIENT, child_id); |
127 } | 87 } |
128 | 88 |
129 void BrowserAccessibilityManagerWin::OnNodeCreated(ui::AXNode* node) { | 89 void BrowserAccessibilityManagerWin::OnNodeCreated(ui::AXNode* node) { |
130 BrowserAccessibilityManager::OnNodeCreated(node); | 90 BrowserAccessibilityManager::OnNodeCreated(node); |
131 BrowserAccessibility* obj = GetFromAXNode(node); | 91 BrowserAccessibility* obj = GetFromAXNode(node); |
132 if (!obj) | |
133 return; | |
134 if (!obj->IsNative()) | |
135 return; | |
136 LONG unique_id_win = obj->ToBrowserAccessibilityWin()->unique_id_win(); | 92 LONG unique_id_win = obj->ToBrowserAccessibilityWin()->unique_id_win(); |
137 unique_id_to_ax_id_map_[unique_id_win] = obj->GetId(); | 93 unique_id_to_ax_id_map_[unique_id_win] = obj->GetId(); |
138 } | 94 } |
139 | 95 |
140 void BrowserAccessibilityManagerWin::OnNodeWillBeDeleted(ui::AXNode* node) { | 96 void BrowserAccessibilityManagerWin::OnNodeWillBeDeleted(ui::AXNode* node) { |
141 BrowserAccessibilityManager::OnNodeWillBeDeleted(node); | 97 BrowserAccessibilityManager::OnNodeWillBeDeleted(node); |
142 BrowserAccessibility* obj = GetFromAXNode(node); | 98 BrowserAccessibility* obj = GetFromAXNode(node); |
143 if (!obj) | 99 if (!obj) |
144 return; | 100 return; |
145 if (!obj->IsNative()) | |
146 return; | |
147 unique_id_to_ax_id_map_.erase( | 101 unique_id_to_ax_id_map_.erase( |
148 obj->ToBrowserAccessibilityWin()->unique_id_win()); | 102 obj->ToBrowserAccessibilityWin()->unique_id_win()); |
149 if (obj == tracked_scroll_object_) { | 103 if (obj == tracked_scroll_object_) { |
150 tracked_scroll_object_->Release(); | 104 tracked_scroll_object_->Release(); |
151 tracked_scroll_object_ = NULL; | 105 tracked_scroll_object_ = NULL; |
152 } | 106 } |
153 } | 107 } |
154 | 108 |
155 void BrowserAccessibilityManagerWin::OnWindowFocused() { | 109 void BrowserAccessibilityManagerWin::OnWindowFocused() { |
156 // This is called either when this web frame gets focused, or when | 110 // This is called either when this web frame gets focused, or when |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
212 OnWindowFocused(); | 166 OnWindowFocused(); |
213 | 167 |
214 LONG event_id = EVENT_MIN; | 168 LONG event_id = EVENT_MIN; |
215 switch (event_type) { | 169 switch (event_type) { |
216 case ui::AX_EVENT_ACTIVEDESCENDANTCHANGED: | 170 case ui::AX_EVENT_ACTIVEDESCENDANTCHANGED: |
217 event_id = IA2_EVENT_ACTIVE_DESCENDANT_CHANGED; | 171 event_id = IA2_EVENT_ACTIVE_DESCENDANT_CHANGED; |
218 break; | 172 break; |
219 case ui::AX_EVENT_ALERT: | 173 case ui::AX_EVENT_ALERT: |
220 event_id = EVENT_SYSTEM_ALERT; | 174 event_id = EVENT_SYSTEM_ALERT; |
221 break; | 175 break; |
| 176 case ui::AX_EVENT_ARIA_ATTRIBUTE_CHANGED: |
| 177 event_id = IA2_EVENT_OBJECT_ATTRIBUTE_CHANGED; |
| 178 break; |
222 case ui::AX_EVENT_AUTOCORRECTION_OCCURED: | 179 case ui::AX_EVENT_AUTOCORRECTION_OCCURED: |
223 event_id = IA2_EVENT_OBJECT_ATTRIBUTE_CHANGED; | 180 event_id = IA2_EVENT_OBJECT_ATTRIBUTE_CHANGED; |
224 break; | 181 break; |
225 case ui::AX_EVENT_BLUR: | 182 case ui::AX_EVENT_BLUR: |
226 // Equivalent to focus on the root. | 183 // Equivalent to focus on the root. |
227 event_id = EVENT_OBJECT_FOCUS; | 184 event_id = EVENT_OBJECT_FOCUS; |
228 node = GetRoot(); | 185 node = GetRoot(); |
229 break; | 186 break; |
| 187 case ui::AX_EVENT_CHECKED_STATE_CHANGED: |
| 188 event_id = EVENT_OBJECT_STATECHANGE; |
| 189 break; |
230 case ui::AX_EVENT_CHILDREN_CHANGED: | 190 case ui::AX_EVENT_CHILDREN_CHANGED: |
231 event_id = EVENT_OBJECT_REORDER; | 191 event_id = EVENT_OBJECT_REORDER; |
232 break; | 192 break; |
233 case ui::AX_EVENT_FOCUS: | 193 case ui::AX_EVENT_FOCUS: |
234 event_id = EVENT_OBJECT_FOCUS; | 194 event_id = EVENT_OBJECT_FOCUS; |
235 break; | 195 break; |
| 196 case ui::AX_EVENT_INVALID_STATUS_CHANGED: |
| 197 event_id = EVENT_OBJECT_STATECHANGE; |
| 198 break; |
236 case ui::AX_EVENT_LIVE_REGION_CHANGED: | 199 case ui::AX_EVENT_LIVE_REGION_CHANGED: |
237 if (node->GetBoolAttribute(ui::AX_ATTR_CONTAINER_LIVE_BUSY)) | 200 if (node->GetBoolAttribute(ui::AX_ATTR_CONTAINER_LIVE_BUSY)) |
238 return; | 201 return; |
239 event_id = EVENT_OBJECT_LIVEREGIONCHANGED; | 202 event_id = EVENT_OBJECT_LIVEREGIONCHANGED; |
240 break; | 203 break; |
241 case ui::AX_EVENT_LOAD_COMPLETE: | 204 case ui::AX_EVENT_LOAD_COMPLETE: |
242 event_id = IA2_EVENT_DOCUMENT_LOAD_COMPLETE; | 205 event_id = IA2_EVENT_DOCUMENT_LOAD_COMPLETE; |
243 break; | 206 break; |
244 case ui::AX_EVENT_MENU_LIST_ITEM_SELECTED: | 207 case ui::AX_EVENT_MENU_LIST_ITEM_SELECTED: |
245 event_id = EVENT_OBJECT_FOCUS; | 208 event_id = EVENT_OBJECT_FOCUS; |
246 break; | 209 break; |
247 case ui::AX_EVENT_MENU_LIST_VALUE_CHANGED: | 210 case ui::AX_EVENT_MENU_LIST_VALUE_CHANGED: |
248 event_id = EVENT_OBJECT_VALUECHANGE; | 211 event_id = EVENT_OBJECT_VALUECHANGE; |
249 break; | 212 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; |
250 case ui::AX_EVENT_SCROLL_POSITION_CHANGED: | 219 case ui::AX_EVENT_SCROLL_POSITION_CHANGED: |
251 event_id = EVENT_SYSTEM_SCROLLINGEND; | 220 event_id = EVENT_SYSTEM_SCROLLINGEND; |
252 break; | 221 break; |
253 case ui::AX_EVENT_SCROLLED_TO_ANCHOR: | 222 case ui::AX_EVENT_SCROLLED_TO_ANCHOR: |
254 event_id = EVENT_SYSTEM_SCROLLINGSTART; | 223 event_id = EVENT_SYSTEM_SCROLLINGSTART; |
255 break; | 224 break; |
256 case ui::AX_EVENT_SELECTED_CHILDREN_CHANGED: | 225 case ui::AX_EVENT_SELECTED_CHILDREN_CHANGED: |
257 event_id = EVENT_OBJECT_SELECTIONWITHIN; | 226 event_id = EVENT_OBJECT_SELECTIONWITHIN; |
258 break; | 227 break; |
| 228 case ui::AX_EVENT_TEXT_CHANGED: |
| 229 event_id = EVENT_OBJECT_NAMECHANGE; |
| 230 break; |
259 case ui::AX_EVENT_TEXT_SELECTION_CHANGED: | 231 case ui::AX_EVENT_TEXT_SELECTION_CHANGED: |
260 event_id = IA2_EVENT_TEXT_CARET_MOVED; | 232 event_id = IA2_EVENT_TEXT_CARET_MOVED; |
261 break; | 233 break; |
| 234 case ui::AX_EVENT_VALUE_CHANGED: |
| 235 event_id = EVENT_OBJECT_VALUECHANGE; |
| 236 break; |
262 default: | 237 default: |
263 // Not all WebKit accessibility events result in a Windows | 238 // Not all WebKit accessibility events result in a Windows |
264 // accessibility notification. | 239 // accessibility notification. |
265 break; | 240 break; |
266 } | 241 } |
267 | 242 |
268 if (event_id != EVENT_MIN) { | 243 if (event_id != EVENT_MIN) { |
269 // Pass the node's unique id in the |child_id| argument to NotifyWinEvent; | 244 // Pass the node's unique id in the |child_id| argument to NotifyWinEvent; |
270 // the AT client will then call get_accChild on the HWND's accessibility | 245 // the AT client will then call get_accChild on the HWND's accessibility |
271 // object and pass it that same id, which we can use to retrieve the | 246 // object and pass it that same id, which we can use to retrieve the |
272 // IAccessible for this node. | 247 // IAccessible for this node. |
273 MaybeCallNotifyWinEvent(event_id, node); | 248 LONG child_id = node->ToBrowserAccessibilityWin()->unique_id_win(); |
| 249 MaybeCallNotifyWinEvent(event_id, child_id); |
274 } | 250 } |
275 | 251 |
276 // If this is a layout complete notification (sent when a container scrolls) | 252 // If this is a layout complete notification (sent when a container scrolls) |
277 // and there is a descendant tracked object, send a notification on it. | 253 // and there is a descendant tracked object, send a notification on it. |
278 // TODO(dmazzoni): remove once http://crbug.com/113483 is fixed. | 254 // TODO(dmazzoni): remove once http://crbug.com/113483 is fixed. |
279 if (event_type == ui::AX_EVENT_LAYOUT_COMPLETE && | 255 if (event_type == ui::AX_EVENT_LAYOUT_COMPLETE && |
280 tracked_scroll_object_ && | 256 tracked_scroll_object_ && |
281 tracked_scroll_object_->IsDescendantOf(node)) { | 257 tracked_scroll_object_->IsDescendantOf(node)) { |
282 MaybeCallNotifyWinEvent( | 258 MaybeCallNotifyWinEvent( |
283 IA2_EVENT_VISIBLE_DATA_CHANGED, tracked_scroll_object_); | 259 IA2_EVENT_VISIBLE_DATA_CHANGED, |
| 260 tracked_scroll_object_->ToBrowserAccessibilityWin()->unique_id_win()); |
284 tracked_scroll_object_->Release(); | 261 tracked_scroll_object_->Release(); |
285 tracked_scroll_object_ = NULL; | 262 tracked_scroll_object_ = NULL; |
286 } | 263 } |
287 } | 264 } |
288 | 265 |
289 void BrowserAccessibilityManagerWin::OnAtomicUpdateFinished( | 266 void BrowserAccessibilityManagerWin::OnAtomicUpdateFinished( |
290 bool root_changed, | 267 bool root_changed, |
291 const std::vector<ui::AXTreeDelegate::Change>& changes) { | 268 const std::vector<ui::AXTreeDelegate::Change>& changes) { |
292 BrowserAccessibilityManager::OnAtomicUpdateFinished(root_changed, changes); | 269 BrowserAccessibilityManager::OnAtomicUpdateFinished(root_changed, changes); |
293 | 270 |
294 if (root_changed) { | 271 if (root_changed) { |
295 // In order to make screen readers aware of the new accessibility root, | 272 // In order to make screen readers aware of the new accessibility root, |
296 // we need to fire a focus event on it. | 273 // we need to fire a focus event on it. |
297 OnWindowFocused(); | 274 OnWindowFocused(); |
298 } | 275 } |
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 } | |
312 } | 276 } |
313 | 277 |
314 void BrowserAccessibilityManagerWin::TrackScrollingObject( | 278 void BrowserAccessibilityManagerWin::TrackScrollingObject( |
315 BrowserAccessibilityWin* node) { | 279 BrowserAccessibilityWin* node) { |
316 if (tracked_scroll_object_) | 280 if (tracked_scroll_object_) |
317 tracked_scroll_object_->Release(); | 281 tracked_scroll_object_->Release(); |
318 tracked_scroll_object_ = node; | 282 tracked_scroll_object_ = node; |
319 tracked_scroll_object_->AddRef(); | 283 tracked_scroll_object_->AddRef(); |
320 } | 284 } |
321 | 285 |
322 BrowserAccessibilityWin* BrowserAccessibilityManagerWin::GetFromUniqueIdWin( | 286 BrowserAccessibilityWin* BrowserAccessibilityManagerWin::GetFromUniqueIdWin( |
323 LONG unique_id_win) { | 287 LONG unique_id_win) { |
324 base::hash_map<LONG, int32>::iterator iter = | 288 base::hash_map<LONG, int32>::iterator iter = |
325 unique_id_to_ax_id_map_.find(unique_id_win); | 289 unique_id_to_ax_id_map_.find(unique_id_win); |
326 if (iter != unique_id_to_ax_id_map_.end()) { | 290 if (iter != unique_id_to_ax_id_map_.end()) { |
327 BrowserAccessibility* result = GetFromID(iter->second); | 291 BrowserAccessibility* result = GetFromID(iter->second); |
328 if (result && result->IsNative()) | 292 if (result) |
329 return result->ToBrowserAccessibilityWin(); | 293 return result->ToBrowserAccessibilityWin(); |
330 } | 294 } |
331 | 295 |
332 // Also search all child frames, such as out-of-process iframes or | 296 // Also search all child frames, such as out-of-process iframes or |
333 // guest browser plugins. | 297 // guest browser plugins. |
334 if (delegate()) { | 298 if (delegate()) { |
335 std::vector<BrowserAccessibilityManager*> child_frames; | 299 std::vector<BrowserAccessibilityManager*> child_frames; |
336 delegate()->AccessibilityGetAllChildFrames(&child_frames); | 300 delegate()->AccessibilityGetAllChildFrames(&child_frames); |
337 for (size_t i = 0; i < child_frames.size(); ++i) { | 301 for (size_t i = 0; i < child_frames.size(); ++i) { |
338 BrowserAccessibilityManagerWin* child_manager = | 302 BrowserAccessibilityManagerWin* child_manager = |
339 child_frames[i]->ToBrowserAccessibilityManagerWin(); | 303 child_frames[i]->ToBrowserAccessibilityManagerWin(); |
340 BrowserAccessibilityWin* result = | 304 BrowserAccessibilityWin* result = |
341 child_manager->GetFromUniqueIdWin(unique_id_win); | 305 child_manager->GetFromUniqueIdWin(unique_id_win); |
342 if (result) | 306 if (result) |
343 return result; | 307 return result; |
344 } | 308 } |
345 } | 309 } |
346 | 310 |
347 return NULL; | 311 return NULL; |
348 } | 312 } |
349 | 313 |
350 } // namespace content | 314 } // namespace content |
OLD | NEW |