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(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 Loading... |
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 |
OLD | NEW |