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

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 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698