OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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.h" | 5 #include "content/browser/accessibility/browser_accessibility_manager.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
8 #include "content/browser/accessibility/browser_accessibility.h" | 8 #include "content/browser/accessibility/browser_accessibility.h" |
9 #include "content/common/view_messages.h" | 9 #include "content/common/view_messages.h" |
10 | 10 |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
54 | 54 |
55 BrowserAccessibilityManager::BrowserAccessibilityManager( | 55 BrowserAccessibilityManager::BrowserAccessibilityManager( |
56 gfx::NativeView parent_view, | 56 gfx::NativeView parent_view, |
57 const WebAccessibility& src, | 57 const WebAccessibility& src, |
58 BrowserAccessibilityDelegate* delegate, | 58 BrowserAccessibilityDelegate* delegate, |
59 BrowserAccessibilityFactory* factory) | 59 BrowserAccessibilityFactory* factory) |
60 : parent_view_(parent_view), | 60 : parent_view_(parent_view), |
61 delegate_(delegate), | 61 delegate_(delegate), |
62 factory_(factory), | 62 factory_(factory), |
63 focus_(NULL) { | 63 focus_(NULL) { |
64 root_ = CreateAccessibilityTree(NULL, src, 0); | 64 root_ = CreateAccessibilityTree(NULL, src, 0, false); |
65 if (!focus_) | 65 if (!focus_) |
66 SetFocus(root_, false); | 66 SetFocus(root_, false); |
67 } | 67 } |
68 | 68 |
69 // static | 69 // static |
70 int32 BrowserAccessibilityManager::GetNextChildID() { | 70 int32 BrowserAccessibilityManager::GetNextChildID() { |
71 // Get the next child ID, and wrap around when we get near the end | 71 // Get the next child ID, and wrap around when we get near the end |
72 // of a 32-bit integer range. It's okay to wrap around; we just want | 72 // of a 32-bit integer range. It's okay to wrap around; we just want |
73 // to avoid it as long as possible because clients may cache the ID of | 73 // to avoid it as long as possible because clients may cache the ID of |
74 // an object for a while to determine if they've seen it before. | 74 // an object for a while to determine if they've seen it before. |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
124 if (renderer_id_to_child_id_map_[renderer_id] == child_id) | 124 if (renderer_id_to_child_id_map_[renderer_id] == child_id) |
125 renderer_id_to_child_id_map_.erase(renderer_id); | 125 renderer_id_to_child_id_map_.erase(renderer_id); |
126 } | 126 } |
127 | 127 |
128 void BrowserAccessibilityManager::OnAccessibilityNotifications( | 128 void BrowserAccessibilityManager::OnAccessibilityNotifications( |
129 const std::vector<ViewHostMsg_AccessibilityNotification_Params>& params) { | 129 const std::vector<ViewHostMsg_AccessibilityNotification_Params>& params) { |
130 for (uint32 index = 0; index < params.size(); index++) { | 130 for (uint32 index = 0; index < params.size(); index++) { |
131 const ViewHostMsg_AccessibilityNotification_Params& param = params[index]; | 131 const ViewHostMsg_AccessibilityNotification_Params& param = params[index]; |
132 | 132 |
133 switch (param.notification_type) { | 133 switch (param.notification_type) { |
134 case ViewHostMsg_AccessibilityNotification_Type:: | 134 // Notifications where children are included. |
135 NOTIFICATION_TYPE_CHECK_STATE_CHANGED: | 135 case ViewHostMsg_AccEvent::CHILDREN_CHANGED: |
136 OnAccessibilityObjectStateChange(param.acc_obj); | 136 case ViewHostMsg_AccEvent::LIVE_REGION_CHANGED: |
137 OnSimpleAccessibilityNotification( | |
138 param.acc_obj, param.notification_type, true); | |
137 break; | 139 break; |
138 case ViewHostMsg_AccessibilityNotification_Type:: | 140 |
139 NOTIFICATION_TYPE_CHILDREN_CHANGED: | 141 case ViewHostMsg_AccEvent::FOCUS_CHANGED: |
140 OnAccessibilityObjectChildrenChange(param.acc_obj); | |
141 break; | |
142 case ViewHostMsg_AccessibilityNotification_Type:: | |
143 NOTIFICATION_TYPE_FOCUS_CHANGED: | |
144 OnAccessibilityObjectFocusChange(param.acc_obj); | 142 OnAccessibilityObjectFocusChange(param.acc_obj); |
145 break; | 143 break; |
146 case ViewHostMsg_AccessibilityNotification_Type:: | 144 |
147 NOTIFICATION_TYPE_LOAD_COMPLETE: | 145 case ViewHostMsg_AccEvent::LOAD_COMPLETE: |
148 OnAccessibilityObjectLoadComplete(param.acc_obj); | 146 OnAccessibilityObjectLoadComplete(param.acc_obj); |
149 break; | 147 break; |
150 case ViewHostMsg_AccessibilityNotification_Type:: | 148 |
151 NOTIFICATION_TYPE_VALUE_CHANGED: | 149 // All other notifications |
Chris Guillory
2011/08/31 02:14:53
Optional: Mention in comment that children are not
dmazzoni
2011/08/31 22:02:54
Done.
| |
152 OnAccessibilityObjectValueChange(param.acc_obj); | 150 case ViewHostMsg_AccEvent::ACTIVE_DESCENDANT_CHANGED: |
151 case ViewHostMsg_AccEvent::ALERT: | |
152 case ViewHostMsg_AccEvent::CHECK_STATE_CHANGED: | |
153 case ViewHostMsg_AccEvent::LAYOUT_COMPLETE: | |
154 case ViewHostMsg_AccEvent::MENU_LIST_VALUE_CHANGED: | |
155 case ViewHostMsg_AccEvent::OBJECT_HIDE: | |
156 case ViewHostMsg_AccEvent::OBJECT_SHOW: | |
157 case ViewHostMsg_AccEvent::ROW_COLLAPSED: | |
158 case ViewHostMsg_AccEvent::ROW_COUNT_CHANGED: | |
159 case ViewHostMsg_AccEvent::ROW_EXPANDED: | |
160 case ViewHostMsg_AccEvent::SCROLLED_TO_ANCHOR: | |
161 case ViewHostMsg_AccEvent::SELECTED_CHILDREN_CHANGED: | |
162 case ViewHostMsg_AccEvent::SELECTED_TEXT_CHANGED: | |
163 case ViewHostMsg_AccEvent::TEXT_INSERTED: | |
164 case ViewHostMsg_AccEvent::TEXT_REMOVED: | |
165 case ViewHostMsg_AccEvent::VALUE_CHANGED: | |
166 OnSimpleAccessibilityNotification( | |
167 param.acc_obj, param.notification_type, false); | |
153 break; | 168 break; |
154 case ViewHostMsg_AccessibilityNotification_Type:: | 169 |
155 NOTIFICATION_TYPE_SELECTED_TEXT_CHANGED: | |
156 OnAccessibilityObjectTextChange(param.acc_obj); | |
157 break; | |
158 default: | 170 default: |
159 DCHECK(0); | 171 DCHECK(0); |
160 break; | |
161 } | 172 } |
162 } | 173 } |
163 } | 174 } |
164 | 175 |
165 void BrowserAccessibilityManager::OnAccessibilityObjectStateChange( | 176 void BrowserAccessibilityManager::OnSimpleAccessibilityNotification( |
166 const WebAccessibility& acc_obj) { | 177 const WebAccessibility& acc_obj, |
167 BrowserAccessibility* new_browser_acc = UpdateNode(acc_obj, false); | 178 int notification_type, |
179 bool include_children) { | |
180 BrowserAccessibility* new_browser_acc = | |
181 UpdateNode(acc_obj, include_children); | |
168 if (!new_browser_acc) | 182 if (!new_browser_acc) |
169 return; | 183 return; |
170 | 184 |
171 NotifyAccessibilityEvent( | 185 NotifyAccessibilityEvent(notification_type, new_browser_acc); |
172 ViewHostMsg_AccessibilityNotification_Type:: | |
173 NOTIFICATION_TYPE_CHECK_STATE_CHANGED, | |
174 new_browser_acc); | |
175 } | |
176 | |
177 void BrowserAccessibilityManager::OnAccessibilityObjectChildrenChange( | |
178 const WebAccessibility& acc_obj) { | |
179 BrowserAccessibility* new_browser_acc = UpdateNode(acc_obj, true); | |
180 if (!new_browser_acc) | |
181 return; | |
182 | |
183 NotifyAccessibilityEvent( | |
184 ViewHostMsg_AccessibilityNotification_Type:: | |
185 NOTIFICATION_TYPE_CHILDREN_CHANGED, | |
186 new_browser_acc); | |
187 } | 186 } |
188 | 187 |
189 void BrowserAccessibilityManager::OnAccessibilityObjectFocusChange( | 188 void BrowserAccessibilityManager::OnAccessibilityObjectFocusChange( |
190 const WebAccessibility& acc_obj) { | 189 const WebAccessibility& acc_obj) { |
191 BrowserAccessibility* new_browser_acc = UpdateNode(acc_obj, false); | 190 BrowserAccessibility* new_browser_acc = UpdateNode(acc_obj, false); |
192 if (!new_browser_acc) | 191 if (!new_browser_acc) |
193 return; | 192 return; |
194 | 193 |
195 SetFocus(new_browser_acc, false); | 194 SetFocus(new_browser_acc, false); |
196 if (delegate_ && delegate_->HasFocus()) { | 195 if (delegate_ && delegate_->HasFocus()) { |
197 GotFocus(); | 196 GotFocus(); |
198 } else if (!delegate_) { | 197 } else if (!delegate_) { |
199 // Mac currently does not have a BrowserAccessibilityDelegate. | 198 // Mac currently does not have a BrowserAccessibilityDelegate. |
200 NotifyAccessibilityEvent( | 199 NotifyAccessibilityEvent(ViewHostMsg_AccEvent::FOCUS_CHANGED, focus_); |
201 ViewHostMsg_AccessibilityNotification_Type:: | |
202 NOTIFICATION_TYPE_FOCUS_CHANGED, | |
203 focus_); | |
204 } | 200 } |
205 } | 201 } |
206 | 202 |
207 void BrowserAccessibilityManager::OnAccessibilityObjectLoadComplete( | 203 void BrowserAccessibilityManager::OnAccessibilityObjectLoadComplete( |
208 const WebAccessibility& acc_obj) { | 204 const WebAccessibility& acc_obj) { |
209 SetFocus(NULL, false); | 205 SetFocus(NULL, false); |
210 | 206 |
211 root_ = UpdateNode(acc_obj, true); | 207 root_ = UpdateNode(acc_obj, true); |
212 if (!focus_) | 208 if (!focus_) |
213 SetFocus(root_, false); | 209 SetFocus(root_, false); |
214 | 210 |
215 NotifyAccessibilityEvent( | 211 NotifyAccessibilityEvent(ViewHostMsg_AccEvent::LOAD_COMPLETE, root_); |
216 ViewHostMsg_AccessibilityNotification_Type:: | |
217 NOTIFICATION_TYPE_LOAD_COMPLETE, | |
218 root_); | |
219 if (delegate_ && delegate_->HasFocus()) | 212 if (delegate_ && delegate_->HasFocus()) |
220 GotFocus(); | 213 GotFocus(); |
221 } | 214 } |
222 | 215 |
223 void BrowserAccessibilityManager::OnAccessibilityObjectValueChange( | |
224 const WebAccessibility& acc_obj) { | |
225 BrowserAccessibility* new_browser_acc = UpdateNode(acc_obj, false); | |
226 if (!new_browser_acc) | |
227 return; | |
228 | |
229 NotifyAccessibilityEvent( | |
230 ViewHostMsg_AccessibilityNotification_Type:: | |
231 NOTIFICATION_TYPE_VALUE_CHANGED, | |
232 new_browser_acc); | |
233 } | |
234 | |
235 void BrowserAccessibilityManager::OnAccessibilityObjectTextChange( | |
236 const WebAccessibility& acc_obj) { | |
237 BrowserAccessibility* new_browser_acc = UpdateNode(acc_obj, false); | |
238 if (!new_browser_acc) | |
239 return; | |
240 | |
241 NotifyAccessibilityEvent( | |
242 ViewHostMsg_AccessibilityNotification_Type:: | |
243 NOTIFICATION_TYPE_SELECTED_TEXT_CHANGED, | |
244 new_browser_acc); | |
245 } | |
246 | |
247 void BrowserAccessibilityManager::GotFocus() { | 216 void BrowserAccessibilityManager::GotFocus() { |
248 // TODO(ctguil): Remove when tree update logic handles focus changes. | 217 // TODO(ctguil): Remove when tree update logic handles focus changes. |
249 if (!focus_) | 218 if (!focus_) |
250 return; | 219 return; |
251 | 220 |
252 NotifyAccessibilityEvent( | 221 NotifyAccessibilityEvent(ViewHostMsg_AccEvent::FOCUS_CHANGED, focus_); |
253 ViewHostMsg_AccessibilityNotification_Type:: | |
254 NOTIFICATION_TYPE_FOCUS_CHANGED, | |
255 focus_); | |
256 } | 222 } |
257 | 223 |
258 gfx::NativeView BrowserAccessibilityManager::GetParentView() { | 224 gfx::NativeView BrowserAccessibilityManager::GetParentView() { |
259 return parent_view_; | 225 return parent_view_; |
260 } | 226 } |
261 | 227 |
262 BrowserAccessibility* BrowserAccessibilityManager::GetFocus( | 228 BrowserAccessibility* BrowserAccessibilityManager::GetFocus( |
263 BrowserAccessibility* root) { | 229 BrowserAccessibility* root) { |
264 if (focus_ && (!root || focus_->IsDescendantOf(root))) | 230 if (focus_ && (!root || focus_->IsDescendantOf(root))) |
265 return focus_; | 231 return focus_; |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
307 return NULL; | 273 return NULL; |
308 | 274 |
309 if (!include_children) { | 275 if (!include_children) { |
310 DCHECK_EQ(0U, src.children.size()); | 276 DCHECK_EQ(0U, src.children.size()); |
311 current->Initialize( | 277 current->Initialize( |
312 this, | 278 this, |
313 current->parent(), | 279 current->parent(), |
314 current->child_id(), | 280 current->child_id(), |
315 current->index_in_parent(), | 281 current->index_in_parent(), |
316 src); | 282 src); |
283 current->SendNodeUpdateEvents(); | |
317 return current; | 284 return current; |
318 } | 285 } |
319 | 286 |
320 BrowserAccessibility* current_parent = current->parent(); | 287 BrowserAccessibility* current_parent = current->parent(); |
321 int current_index_in_parent = current->index_in_parent(); | 288 int current_index_in_parent = current->index_in_parent(); |
322 | 289 |
323 // Detach all of the nodes in the old tree and get a single flat vector | 290 // Detach all of the nodes in the old tree and get a single flat vector |
324 // of all node pointers. | 291 // of all node pointers. |
325 std::vector<BrowserAccessibility*> old_tree_nodes; | 292 std::vector<BrowserAccessibility*> old_tree_nodes; |
326 current->DetachTree(&old_tree_nodes); | 293 current->DetachTree(&old_tree_nodes); |
327 | 294 |
328 // Build a new tree, reusing old nodes if possible. Each node that's | 295 // Build a new tree, reusing old nodes if possible. Each node that's |
329 // reused will have its reference count incremented by one. | 296 // reused will have its reference count incremented by one. |
330 current = | 297 current = CreateAccessibilityTree( |
331 CreateAccessibilityTree(current_parent, src, current_index_in_parent); | 298 current_parent, src, current_index_in_parent, true); |
332 | 299 |
333 // Decrement the reference count of all nodes in the old tree, which will | 300 // Decrement the reference count of all nodes in the old tree, which will |
334 // delete any nodes no longer needed. | 301 // delete any nodes no longer needed. |
335 for (int i = 0; i < static_cast<int>(old_tree_nodes.size()); i++) | 302 for (int i = 0; i < static_cast<int>(old_tree_nodes.size()); i++) |
336 old_tree_nodes[i]->InternalReleaseReference(false); | 303 old_tree_nodes[i]->InternalReleaseReference(false); |
337 | 304 |
338 if (!focus_ || !focus_->instance_active()) | 305 if (!focus_ || !focus_->instance_active()) |
339 SetFocus(root_, false); | 306 SetFocus(root_, false); |
340 | 307 |
341 return current; | 308 return current; |
342 } | 309 } |
343 | 310 |
344 BrowserAccessibility* BrowserAccessibilityManager::CreateAccessibilityTree( | 311 BrowserAccessibility* BrowserAccessibilityManager::CreateAccessibilityTree( |
345 BrowserAccessibility* parent, | 312 BrowserAccessibility* parent, |
346 const WebAccessibility& src, | 313 const WebAccessibility& src, |
347 int index_in_parent) { | 314 int index_in_parent, |
315 bool send_show_events) { | |
348 BrowserAccessibility* instance = NULL; | 316 BrowserAccessibility* instance = NULL; |
349 int32 child_id = 0; | 317 int32 child_id = 0; |
318 bool children_can_send_show_events = send_show_events; | |
350 base::hash_map<int32, int32>::iterator iter = | 319 base::hash_map<int32, int32>::iterator iter = |
351 renderer_id_to_child_id_map_.find(src.id); | 320 renderer_id_to_child_id_map_.find(src.id); |
352 | 321 |
353 // If a BrowserAccessibility instance for this ID already exists, add a | 322 // If a BrowserAccessibility instance for this ID already exists, add a |
354 // new reference to it and retrieve its children vector. | 323 // new reference to it and retrieve its children vector. |
355 if (iter != renderer_id_to_child_id_map_.end()) { | 324 if (iter != renderer_id_to_child_id_map_.end()) { |
356 child_id = iter->second; | 325 child_id = iter->second; |
357 instance = GetFromChildID(child_id); | 326 instance = GetFromChildID(child_id); |
358 } | 327 } |
359 | 328 |
360 // If the node has changed roles, don't reuse a BrowserAccessibility | 329 // If the node has changed roles, don't reuse a BrowserAccessibility |
361 // object, that could confuse a screen reader. | 330 // object, that could confuse a screen reader. |
362 // TODO(dtseng): Investigate when this gets hit; See crbug.com/93095. | 331 // TODO(dtseng): Investigate when this gets hit; See crbug.com/93095. |
363 DCHECK(!instance || instance->role() == src.role); | 332 DCHECK(!instance || instance->role() == src.role); |
364 | 333 |
365 // If we're reusing a node, it should already be detached from a parent | 334 // If we're reusing a node, it should already be detached from a parent |
366 // and any children. If not, that means we have a serious bug somewhere, | 335 // and any children. If not, that means we have a serious bug somewhere, |
367 // like the same child is reachable from two places in the same tree. | 336 // like the same child is reachable from two places in the same tree. |
368 if (instance && (instance->parent() != NULL || instance->child_count() > 0)) { | 337 if (instance && (instance->parent() != NULL || instance->child_count() > 0)) { |
369 NOTREACHED(); | 338 NOTREACHED(); |
370 instance = NULL; | 339 instance = NULL; |
371 } | 340 } |
372 | 341 |
373 if (instance) { | 342 if (instance) { |
374 // If we're reusing a node, update its parent and increment its | 343 // If we're reusing a node, update its parent and increment its |
375 // reference count. | 344 // reference count. |
376 instance->UpdateParent(parent, index_in_parent); | 345 instance->UpdateParent(parent, index_in_parent); |
377 instance->InternalAddReference(); | 346 instance->InternalAddReference(); |
347 send_show_events = false; | |
378 } else { | 348 } else { |
379 // Otherwise, create a new instance. | 349 // Otherwise, create a new instance. |
380 instance = factory_->Create(); | 350 instance = factory_->Create(); |
381 child_id = GetNextChildID(); | 351 child_id = GetNextChildID(); |
352 children_can_send_show_events = false; | |
382 } | 353 } |
383 | 354 |
384 instance->Initialize(this, parent, child_id, index_in_parent, src); | 355 instance->Initialize(this, parent, child_id, index_in_parent, src); |
385 child_id_map_[child_id] = instance; | 356 child_id_map_[child_id] = instance; |
386 renderer_id_to_child_id_map_[src.id] = child_id; | 357 renderer_id_to_child_id_map_[src.id] = child_id; |
387 if ((src.state >> WebAccessibility::STATE_FOCUSED) & 1) | 358 if ((src.state >> WebAccessibility::STATE_FOCUSED) & 1) |
388 SetFocus(instance, false); | 359 SetFocus(instance, false); |
389 for (int i = 0; i < static_cast<int>(src.children.size()); ++i) { | 360 for (int i = 0; i < static_cast<int>(src.children.size()); ++i) { |
390 BrowserAccessibility* child = CreateAccessibilityTree( | 361 BrowserAccessibility* child = CreateAccessibilityTree( |
391 instance, src.children[i], i); | 362 instance, src.children[i], i, children_can_send_show_events); |
392 instance->AddChild(child); | 363 instance->AddChild(child); |
393 } | 364 } |
394 | 365 |
366 // Note: the purpose of send_show_events and children_can_send_show_events | |
367 // is so that we send a single OBJECT_SHOW event for the root of a subtree | |
368 // that just appeared for the first time, but not on any descendant of | |
369 // that subtree. | |
370 if (send_show_events) | |
371 NotifyAccessibilityEvent(ViewHostMsg_AccEvent::OBJECT_SHOW, instance); | |
372 | |
373 instance->SendNodeUpdateEvents(); | |
374 | |
395 return instance; | 375 return instance; |
396 } | 376 } |
OLD | NEW |