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

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

Issue 7745035: Add a big grab bag of missing web accessibility functionality... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 9 years, 3 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 | Annotate | Revision Log
OLDNEW
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
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 25 matching lines...) Expand all
100 return iter->second; 100 return iter->second;
101 } else { 101 } else {
102 return NULL; 102 return NULL;
103 } 103 }
104 } 104 }
105 105
106 BrowserAccessibility* BrowserAccessibilityManager::GetFromRendererID( 106 BrowserAccessibility* BrowserAccessibilityManager::GetFromRendererID(
107 int32 renderer_id) { 107 int32 renderer_id) {
108 base::hash_map<int32, int32>::iterator iter = 108 base::hash_map<int32, int32>::iterator iter =
109 renderer_id_to_child_id_map_.find(renderer_id); 109 renderer_id_to_child_id_map_.find(renderer_id);
110 if (iter == renderer_id_to_child_id_map_.end()) 110 if (iter == renderer_id_to_child_id_map_.end()) {
David Tseng 2011/08/26 16:14:37 nit: Do we need the braces?
dmazzoni 2011/08/29 18:08:51 Done.
111 return NULL; 111 return NULL;
112 }
112 113
113 int32 child_id = iter->second; 114 int32 child_id = iter->second;
114 return GetFromChildID(child_id); 115 return GetFromChildID(child_id);
115 } 116 }
116 117
117 void BrowserAccessibilityManager::Remove(int32 child_id, int32 renderer_id) { 118 void BrowserAccessibilityManager::Remove(int32 child_id, int32 renderer_id) {
118 child_id_map_.erase(child_id); 119 child_id_map_.erase(child_id);
119 120
120 // TODO(ctguil): Investigate if hit. We should never have a newer entry. 121 // TODO(ctguil): Investigate if hit. We should never have a newer entry.
121 DCHECK(renderer_id_to_child_id_map_[renderer_id] == child_id); 122 DCHECK(renderer_id_to_child_id_map_[renderer_id] == child_id);
122 // Make sure we don't overwrite a newer entry (see UpdateNode for a possible 123 // Make sure we don't overwrite a newer entry (see UpdateNode for a possible
123 // corner case). 124 // corner case).
124 if (renderer_id_to_child_id_map_[renderer_id] == child_id) 125 if (renderer_id_to_child_id_map_[renderer_id] == child_id)
125 renderer_id_to_child_id_map_.erase(renderer_id); 126 renderer_id_to_child_id_map_.erase(renderer_id);
126 } 127 }
127 128
128 void BrowserAccessibilityManager::OnAccessibilityNotifications( 129 void BrowserAccessibilityManager::OnAccessibilityNotifications(
129 const std::vector<ViewHostMsg_AccessibilityNotification_Params>& params) { 130 const std::vector<ViewHostMsg_AccessibilityNotification_Params>& params) {
130 for (uint32 index = 0; index < params.size(); index++) { 131 for (uint32 index = 0; index < params.size(); index++) {
131 const ViewHostMsg_AccessibilityNotification_Params& param = params[index]; 132 const ViewHostMsg_AccessibilityNotification_Params& param = params[index];
132 133
133 switch (param.notification_type) { 134 switch (param.notification_type) {
134 case ViewHostMsg_AccessibilityNotification_Type:: 135 case ViewHostMsg_AccessibilityNotification_Type::
135 NOTIFICATION_TYPE_CHECK_STATE_CHANGED: 136 NOTIFICATION_TYPE_LIVE_REGION_CHANGED:
David Tseng 2011/08/26 16:14:37 nit: sort alphabetically.
dmazzoni 2011/08/29 18:08:51 Done.
136 OnAccessibilityObjectStateChange(param.acc_obj);
137 break;
138 case ViewHostMsg_AccessibilityNotification_Type:: 137 case ViewHostMsg_AccessibilityNotification_Type::
139 NOTIFICATION_TYPE_CHILDREN_CHANGED: 138 NOTIFICATION_TYPE_CHILDREN_CHANGED:
140 OnAccessibilityObjectChildrenChange(param.acc_obj); 139 // Notifications where children are included.
140 OnSimpleAccessibilityNotification(
141 param.acc_obj, param.notification_type, true);
141 break; 142 break;
142 case ViewHostMsg_AccessibilityNotification_Type:: 143 case ViewHostMsg_AccessibilityNotification_Type::
143 NOTIFICATION_TYPE_FOCUS_CHANGED: 144 NOTIFICATION_TYPE_FOCUS_CHANGED:
144 OnAccessibilityObjectFocusChange(param.acc_obj); 145 OnAccessibilityObjectFocusChange(param.acc_obj);
145 break; 146 break;
146 case ViewHostMsg_AccessibilityNotification_Type:: 147 case ViewHostMsg_AccessibilityNotification_Type::
147 NOTIFICATION_TYPE_LOAD_COMPLETE: 148 NOTIFICATION_TYPE_LOAD_COMPLETE:
148 OnAccessibilityObjectLoadComplete(param.acc_obj); 149 OnAccessibilityObjectLoadComplete(param.acc_obj);
149 break; 150 break;
150 case ViewHostMsg_AccessibilityNotification_Type::
151 NOTIFICATION_TYPE_VALUE_CHANGED:
152 OnAccessibilityObjectValueChange(param.acc_obj);
153 break;
154 case ViewHostMsg_AccessibilityNotification_Type::
155 NOTIFICATION_TYPE_SELECTED_TEXT_CHANGED:
156 OnAccessibilityObjectTextChange(param.acc_obj);
157 break;
158 default: 151 default:
159 DCHECK(0); 152 // For all other notifications, children are not included.
David Tseng 2011/08/26 16:14:37 Either remove the DCHECK above or explicitly list
dmazzoni 2011/08/29 18:08:51 Done.
153 OnSimpleAccessibilityNotification(
154 param.acc_obj, param.notification_type, false);
160 break; 155 break;
161 } 156 }
162 } 157 }
163 } 158 }
164 159
165 void BrowserAccessibilityManager::OnAccessibilityObjectStateChange( 160 void BrowserAccessibilityManager::OnSimpleAccessibilityNotification(
166 const WebAccessibility& acc_obj) { 161 const WebAccessibility& acc_obj,
167 BrowserAccessibility* new_browser_acc = UpdateNode(acc_obj, false); 162 int notification_type,
163 bool include_children) {
164 BrowserAccessibility* new_browser_acc =
165 UpdateNode(acc_obj, include_children);
168 if (!new_browser_acc) 166 if (!new_browser_acc)
169 return; 167 return;
170 168
171 NotifyAccessibilityEvent( 169 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 } 170 }
188 171
189 void BrowserAccessibilityManager::OnAccessibilityObjectFocusChange( 172 void BrowserAccessibilityManager::OnAccessibilityObjectFocusChange(
190 const WebAccessibility& acc_obj) { 173 const WebAccessibility& acc_obj) {
191 BrowserAccessibility* new_browser_acc = UpdateNode(acc_obj, false); 174 BrowserAccessibility* new_browser_acc = UpdateNode(acc_obj, false);
192 if (!new_browser_acc) 175 if (!new_browser_acc)
193 return; 176 return;
194 177
195 SetFocus(new_browser_acc, false); 178 SetFocus(new_browser_acc, false);
196 if (delegate_ && delegate_->HasFocus()) { 179 if (delegate_ && delegate_->HasFocus()) {
(...skipping 16 matching lines...) Expand all
213 SetFocus(root_, false); 196 SetFocus(root_, false);
214 197
215 NotifyAccessibilityEvent( 198 NotifyAccessibilityEvent(
216 ViewHostMsg_AccessibilityNotification_Type:: 199 ViewHostMsg_AccessibilityNotification_Type::
217 NOTIFICATION_TYPE_LOAD_COMPLETE, 200 NOTIFICATION_TYPE_LOAD_COMPLETE,
218 root_); 201 root_);
219 if (delegate_ && delegate_->HasFocus()) 202 if (delegate_ && delegate_->HasFocus())
220 GotFocus(); 203 GotFocus();
221 } 204 }
222 205
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() { 206 void BrowserAccessibilityManager::GotFocus() {
248 // TODO(ctguil): Remove when tree update logic handles focus changes. 207 // TODO(ctguil): Remove when tree update logic handles focus changes.
249 if (!focus_) 208 if (!focus_)
250 return; 209 return;
251 210
252 NotifyAccessibilityEvent( 211 NotifyAccessibilityEvent(
253 ViewHostMsg_AccessibilityNotification_Type:: 212 ViewHostMsg_AccessibilityNotification_Type::
254 NOTIFICATION_TYPE_FOCUS_CHANGED, 213 NOTIFICATION_TYPE_FOCUS_CHANGED,
255 focus_); 214 focus_);
256 } 215 }
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
307 return NULL; 266 return NULL;
308 267
309 if (!include_children) { 268 if (!include_children) {
310 DCHECK_EQ(0U, src.children.size()); 269 DCHECK_EQ(0U, src.children.size());
311 current->Initialize( 270 current->Initialize(
312 this, 271 this,
313 current->parent(), 272 current->parent(),
314 current->child_id(), 273 current->child_id(),
315 current->index_in_parent(), 274 current->index_in_parent(),
316 src); 275 src);
276 current->SendNodeUpdateEvents();
317 return current; 277 return current;
318 } 278 }
319 279
320 BrowserAccessibility* current_parent = current->parent(); 280 BrowserAccessibility* current_parent = current->parent();
321 int current_index_in_parent = current->index_in_parent(); 281 int current_index_in_parent = current->index_in_parent();
322 282
323 // Detach all of the nodes in the old tree and get a single flat vector 283 // Detach all of the nodes in the old tree and get a single flat vector
324 // of all node pointers. 284 // of all node pointers.
325 std::vector<BrowserAccessibility*> old_tree_nodes; 285 std::vector<BrowserAccessibility*> old_tree_nodes;
326 current->DetachTree(&old_tree_nodes); 286 current->DetachTree(&old_tree_nodes);
327 287
328 // Build a new tree, reusing old nodes if possible. Each node that's 288 // Build a new tree, reusing old nodes if possible. Each node that's
329 // reused will have its reference count incremented by one. 289 // reused will have its reference count incremented by one.
330 current = 290 current = CreateAccessibilityTree(
331 CreateAccessibilityTree(current_parent, src, current_index_in_parent); 291 current_parent, src, current_index_in_parent, true);
332 292
333 // Decrement the reference count of all nodes in the old tree, which will 293 // Decrement the reference count of all nodes in the old tree, which will
334 // delete any nodes no longer needed. 294 // delete any nodes no longer needed.
335 for (int i = 0; i < static_cast<int>(old_tree_nodes.size()); i++) 295 for (int i = 0; i < static_cast<int>(old_tree_nodes.size()); i++) {
David Tseng 2011/08/26 16:14:37 nit: braces necessary?
dmazzoni 2011/08/29 18:08:51 Done.
336 old_tree_nodes[i]->InternalReleaseReference(false); 296 old_tree_nodes[i]->InternalReleaseReference(false);
297 }
337 298
338 if (!focus_ || !focus_->instance_active()) 299 if (!focus_ || !focus_->instance_active())
339 SetFocus(root_, false); 300 SetFocus(root_, false);
340 301
341 return current; 302 return current;
342 } 303 }
343 304
344 BrowserAccessibility* BrowserAccessibilityManager::CreateAccessibilityTree( 305 BrowserAccessibility* BrowserAccessibilityManager::CreateAccessibilityTree(
345 BrowserAccessibility* parent, 306 BrowserAccessibility* parent,
346 const WebAccessibility& src, 307 const WebAccessibility& src,
347 int index_in_parent) { 308 int index_in_parent,
309 bool send_show_events) {
348 BrowserAccessibility* instance = NULL; 310 BrowserAccessibility* instance = NULL;
349 int32 child_id = 0; 311 int32 child_id = 0;
312 bool children_can_send_show_events = send_show_events;
350 base::hash_map<int32, int32>::iterator iter = 313 base::hash_map<int32, int32>::iterator iter =
351 renderer_id_to_child_id_map_.find(src.id); 314 renderer_id_to_child_id_map_.find(src.id);
352 315
353 // If a BrowserAccessibility instance for this ID already exists, add a 316 // If a BrowserAccessibility instance for this ID already exists, add a
354 // new reference to it and retrieve its children vector. 317 // new reference to it and retrieve its children vector.
355 if (iter != renderer_id_to_child_id_map_.end()) { 318 if (iter != renderer_id_to_child_id_map_.end()) {
356 child_id = iter->second; 319 child_id = iter->second;
357 instance = GetFromChildID(child_id); 320 instance = GetFromChildID(child_id);
358 } 321 }
359 322
360 // If the node has changed roles, don't reuse a BrowserAccessibility 323 // If the node has changed roles, don't reuse a BrowserAccessibility
361 // object, that could confuse a screen reader. 324 // object, that could confuse a screen reader.
362 // TODO(dtseng): Investigate when this gets hit; See crbug.com/93095. 325 // TODO(dtseng): Investigate when this gets hit; See crbug.com/93095.
363 DCHECK(!instance || instance->role() == src.role); 326 DCHECK(!instance || instance->role() == src.role);
364 327
365 // If we're reusing a node, it should already be detached from a parent 328 // 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, 329 // 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. 330 // like the same child is reachable from two places in the same tree.
368 if (instance && (instance->parent() != NULL || instance->child_count() > 0)) { 331 if (instance && (instance->parent() != NULL || instance->child_count() > 0)) {
369 NOTREACHED(); 332 NOTREACHED();
370 instance = NULL; 333 instance = NULL;
371 } 334 }
372 335
373 if (instance) { 336 if (instance) {
374 // If we're reusing a node, update its parent and increment its 337 // If we're reusing a node, update its parent and increment its
375 // reference count. 338 // reference count.
376 instance->UpdateParent(parent, index_in_parent); 339 instance->UpdateParent(parent, index_in_parent);
377 instance->InternalAddReference(); 340 instance->InternalAddReference();
341 send_show_events = false;
378 } else { 342 } else {
379 // Otherwise, create a new instance. 343 // Otherwise, create a new instance.
380 instance = factory_->Create(); 344 instance = factory_->Create();
381 child_id = GetNextChildID(); 345 child_id = GetNextChildID();
346 children_can_send_show_events = false;
382 } 347 }
383 348
384 instance->Initialize(this, parent, child_id, index_in_parent, src); 349 instance->Initialize(this, parent, child_id, index_in_parent, src);
385 child_id_map_[child_id] = instance; 350 child_id_map_[child_id] = instance;
386 renderer_id_to_child_id_map_[src.id] = child_id; 351 renderer_id_to_child_id_map_[src.id] = child_id;
387 if ((src.state >> WebAccessibility::STATE_FOCUSED) & 1) 352 if ((src.state >> WebAccessibility::STATE_FOCUSED) & 1)
388 SetFocus(instance, false); 353 SetFocus(instance, false);
389 for (int i = 0; i < static_cast<int>(src.children.size()); ++i) { 354 for (int i = 0; i < static_cast<int>(src.children.size()); ++i) {
390 BrowserAccessibility* child = CreateAccessibilityTree( 355 BrowserAccessibility* child = CreateAccessibilityTree(
391 instance, src.children[i], i); 356 instance, src.children[i], i, children_can_send_show_events);
392 instance->AddChild(child); 357 instance->AddChild(child);
393 } 358 }
359 if (send_show_events) {
David Tseng 2011/08/26 16:14:37 Any chance we could move this up to UpdateNode?
dmazzoni 2011/08/29 18:08:51 It'd be pretty hard, we need to update children_ca
360 NotifyAccessibilityEvent(
361 ViewHostMsg_AccessibilityNotification_Type::
362 NOTIFICATION_TYPE_OBJECT_SHOW,
363 instance);
David Tseng 2011/08/26 16:14:37 nit: align with "ViewHostMsg_AccessibilityNotifica
dmazzoni 2011/08/29 18:08:51 Done.
364 }
365 instance->SendNodeUpdateEvents();
394 366
395 return instance; 367 return instance;
396 } 368 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698