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

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: the node is updated, but
152 OnAccessibilityObjectValueChange(param.acc_obj); 150 // children are not included.
151 case ViewHostMsg_AccEvent::ACTIVE_DESCENDANT_CHANGED:
152 case ViewHostMsg_AccEvent::ALERT:
153 case ViewHostMsg_AccEvent::CHECK_STATE_CHANGED:
154 case ViewHostMsg_AccEvent::LAYOUT_COMPLETE:
155 case ViewHostMsg_AccEvent::MENU_LIST_VALUE_CHANGED:
156 case ViewHostMsg_AccEvent::OBJECT_HIDE:
157 case ViewHostMsg_AccEvent::OBJECT_SHOW:
158 case ViewHostMsg_AccEvent::ROW_COLLAPSED:
159 case ViewHostMsg_AccEvent::ROW_COUNT_CHANGED:
160 case ViewHostMsg_AccEvent::ROW_EXPANDED:
161 case ViewHostMsg_AccEvent::SCROLLED_TO_ANCHOR:
162 case ViewHostMsg_AccEvent::SELECTED_CHILDREN_CHANGED:
163 case ViewHostMsg_AccEvent::SELECTED_TEXT_CHANGED:
164 case ViewHostMsg_AccEvent::TEXT_INSERTED:
165 case ViewHostMsg_AccEvent::TEXT_REMOVED:
166 case ViewHostMsg_AccEvent::VALUE_CHANGED:
167 OnSimpleAccessibilityNotification(
168 param.acc_obj, param.notification_type, false);
153 break; 169 break;
154 case ViewHostMsg_AccessibilityNotification_Type:: 170
155 NOTIFICATION_TYPE_SELECTED_TEXT_CHANGED:
156 OnAccessibilityObjectTextChange(param.acc_obj);
157 break;
158 default: 171 default:
159 DCHECK(0); 172 DCHECK(0);
160 break;
161 } 173 }
162 } 174 }
163 } 175 }
164 176
165 void BrowserAccessibilityManager::OnAccessibilityObjectStateChange( 177 void BrowserAccessibilityManager::OnSimpleAccessibilityNotification(
166 const WebAccessibility& acc_obj) { 178 const WebAccessibility& acc_obj,
167 BrowserAccessibility* new_browser_acc = UpdateNode(acc_obj, false); 179 int notification_type,
180 bool include_children) {
181 BrowserAccessibility* new_browser_acc =
182 UpdateNode(acc_obj, include_children);
168 if (!new_browser_acc) 183 if (!new_browser_acc)
169 return; 184 return;
170 185
171 NotifyAccessibilityEvent( 186 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 } 187 }
188 188
189 void BrowserAccessibilityManager::OnAccessibilityObjectFocusChange( 189 void BrowserAccessibilityManager::OnAccessibilityObjectFocusChange(
190 const WebAccessibility& acc_obj) { 190 const WebAccessibility& acc_obj) {
191 BrowserAccessibility* new_browser_acc = UpdateNode(acc_obj, false); 191 BrowserAccessibility* new_browser_acc = UpdateNode(acc_obj, false);
192 if (!new_browser_acc) 192 if (!new_browser_acc)
193 return; 193 return;
194 194
195 SetFocus(new_browser_acc, false); 195 SetFocus(new_browser_acc, false);
196 if (delegate_ && delegate_->HasFocus()) { 196 if (delegate_ && delegate_->HasFocus()) {
197 GotFocus(); 197 GotFocus();
198 } else if (!delegate_) { 198 } else if (!delegate_) {
199 // Mac currently does not have a BrowserAccessibilityDelegate. 199 // Mac currently does not have a BrowserAccessibilityDelegate.
200 NotifyAccessibilityEvent( 200 NotifyAccessibilityEvent(ViewHostMsg_AccEvent::FOCUS_CHANGED, focus_);
201 ViewHostMsg_AccessibilityNotification_Type::
202 NOTIFICATION_TYPE_FOCUS_CHANGED,
203 focus_);
204 } 201 }
205 } 202 }
206 203
207 void BrowserAccessibilityManager::OnAccessibilityObjectLoadComplete( 204 void BrowserAccessibilityManager::OnAccessibilityObjectLoadComplete(
208 const WebAccessibility& acc_obj) { 205 const WebAccessibility& acc_obj) {
209 SetFocus(NULL, false); 206 SetFocus(NULL, false);
210 207
211 root_ = UpdateNode(acc_obj, true); 208 root_ = UpdateNode(acc_obj, true);
212 if (!focus_) 209 if (!focus_)
213 SetFocus(root_, false); 210 SetFocus(root_, false);
214 211
215 NotifyAccessibilityEvent( 212 NotifyAccessibilityEvent(ViewHostMsg_AccEvent::LOAD_COMPLETE, root_);
216 ViewHostMsg_AccessibilityNotification_Type::
217 NOTIFICATION_TYPE_LOAD_COMPLETE,
218 root_);
219 if (delegate_ && delegate_->HasFocus()) 213 if (delegate_ && delegate_->HasFocus())
220 GotFocus(); 214 GotFocus();
221 } 215 }
222 216
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() { 217 void BrowserAccessibilityManager::GotFocus() {
248 // TODO(ctguil): Remove when tree update logic handles focus changes. 218 // TODO(ctguil): Remove when tree update logic handles focus changes.
249 if (!focus_) 219 if (!focus_)
250 return; 220 return;
251 221
252 NotifyAccessibilityEvent( 222 NotifyAccessibilityEvent(ViewHostMsg_AccEvent::FOCUS_CHANGED, focus_);
253 ViewHostMsg_AccessibilityNotification_Type::
254 NOTIFICATION_TYPE_FOCUS_CHANGED,
255 focus_);
256 } 223 }
257 224
258 gfx::NativeView BrowserAccessibilityManager::GetParentView() { 225 gfx::NativeView BrowserAccessibilityManager::GetParentView() {
259 return parent_view_; 226 return parent_view_;
260 } 227 }
261 228
262 BrowserAccessibility* BrowserAccessibilityManager::GetFocus( 229 BrowserAccessibility* BrowserAccessibilityManager::GetFocus(
263 BrowserAccessibility* root) { 230 BrowserAccessibility* root) {
264 if (focus_ && (!root || focus_->IsDescendantOf(root))) 231 if (focus_ && (!root || focus_->IsDescendantOf(root)))
265 return focus_; 232 return focus_;
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
307 return NULL; 274 return NULL;
308 275
309 if (!include_children) { 276 if (!include_children) {
310 DCHECK_EQ(0U, src.children.size()); 277 DCHECK_EQ(0U, src.children.size());
311 current->Initialize( 278 current->Initialize(
312 this, 279 this,
313 current->parent(), 280 current->parent(),
314 current->child_id(), 281 current->child_id(),
315 current->index_in_parent(), 282 current->index_in_parent(),
316 src); 283 src);
284 current->SendNodeUpdateEvents();
317 return current; 285 return current;
318 } 286 }
319 287
320 BrowserAccessibility* current_parent = current->parent(); 288 BrowserAccessibility* current_parent = current->parent();
321 int current_index_in_parent = current->index_in_parent(); 289 int current_index_in_parent = current->index_in_parent();
322 290
323 // Detach all of the nodes in the old tree and get a single flat vector 291 // Detach all of the nodes in the old tree and get a single flat vector
324 // of all node pointers. 292 // of all node pointers.
325 std::vector<BrowserAccessibility*> old_tree_nodes; 293 std::vector<BrowserAccessibility*> old_tree_nodes;
326 current->DetachTree(&old_tree_nodes); 294 current->DetachTree(&old_tree_nodes);
327 295
328 // Build a new tree, reusing old nodes if possible. Each node that's 296 // Build a new tree, reusing old nodes if possible. Each node that's
329 // reused will have its reference count incremented by one. 297 // reused will have its reference count incremented by one.
330 current = 298 current = CreateAccessibilityTree(
331 CreateAccessibilityTree(current_parent, src, current_index_in_parent); 299 current_parent, src, current_index_in_parent, true);
332 300
333 // Decrement the reference count of all nodes in the old tree, which will 301 // Decrement the reference count of all nodes in the old tree, which will
334 // delete any nodes no longer needed. 302 // delete any nodes no longer needed.
335 for (int i = 0; i < static_cast<int>(old_tree_nodes.size()); i++) 303 for (int i = 0; i < static_cast<int>(old_tree_nodes.size()); i++)
336 old_tree_nodes[i]->InternalReleaseReference(false); 304 old_tree_nodes[i]->InternalReleaseReference(false);
337 305
338 if (!focus_ || !focus_->instance_active()) 306 if (!focus_ || !focus_->instance_active())
339 SetFocus(root_, false); 307 SetFocus(root_, false);
340 308
341 return current; 309 return current;
342 } 310 }
343 311
344 BrowserAccessibility* BrowserAccessibilityManager::CreateAccessibilityTree( 312 BrowserAccessibility* BrowserAccessibilityManager::CreateAccessibilityTree(
345 BrowserAccessibility* parent, 313 BrowserAccessibility* parent,
346 const WebAccessibility& src, 314 const WebAccessibility& src,
347 int index_in_parent) { 315 int index_in_parent,
316 bool send_show_events) {
348 BrowserAccessibility* instance = NULL; 317 BrowserAccessibility* instance = NULL;
349 int32 child_id = 0; 318 int32 child_id = 0;
319 bool children_can_send_show_events = send_show_events;
350 base::hash_map<int32, int32>::iterator iter = 320 base::hash_map<int32, int32>::iterator iter =
351 renderer_id_to_child_id_map_.find(src.id); 321 renderer_id_to_child_id_map_.find(src.id);
352 322
353 // If a BrowserAccessibility instance for this ID already exists, add a 323 // If a BrowserAccessibility instance for this ID already exists, add a
354 // new reference to it and retrieve its children vector. 324 // new reference to it and retrieve its children vector.
355 if (iter != renderer_id_to_child_id_map_.end()) { 325 if (iter != renderer_id_to_child_id_map_.end()) {
356 child_id = iter->second; 326 child_id = iter->second;
357 instance = GetFromChildID(child_id); 327 instance = GetFromChildID(child_id);
358 } 328 }
359 329
360 // If the node has changed roles, don't reuse a BrowserAccessibility 330 // If the node has changed roles, don't reuse a BrowserAccessibility
361 // object, that could confuse a screen reader. 331 // object, that could confuse a screen reader.
362 // TODO(dtseng): Investigate when this gets hit; See crbug.com/93095. 332 // TODO(dtseng): Investigate when this gets hit; See crbug.com/93095.
363 DCHECK(!instance || instance->role() == src.role); 333 DCHECK(!instance || instance->role() == src.role);
364 334
365 // If we're reusing a node, it should already be detached from a parent 335 // 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, 336 // 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. 337 // like the same child is reachable from two places in the same tree.
368 if (instance && (instance->parent() != NULL || instance->child_count() > 0)) { 338 if (instance && (instance->parent() != NULL || instance->child_count() > 0)) {
369 NOTREACHED(); 339 NOTREACHED();
370 instance = NULL; 340 instance = NULL;
371 } 341 }
372 342
373 if (instance) { 343 if (instance) {
374 // If we're reusing a node, update its parent and increment its 344 // If we're reusing a node, update its parent and increment its
375 // reference count. 345 // reference count.
376 instance->UpdateParent(parent, index_in_parent); 346 instance->UpdateParent(parent, index_in_parent);
377 instance->InternalAddReference(); 347 instance->InternalAddReference();
348 send_show_events = false;
378 } else { 349 } else {
379 // Otherwise, create a new instance. 350 // Otherwise, create a new instance.
380 instance = factory_->Create(); 351 instance = factory_->Create();
381 child_id = GetNextChildID(); 352 child_id = GetNextChildID();
353 children_can_send_show_events = false;
382 } 354 }
383 355
384 instance->Initialize(this, parent, child_id, index_in_parent, src); 356 instance->Initialize(this, parent, child_id, index_in_parent, src);
385 child_id_map_[child_id] = instance; 357 child_id_map_[child_id] = instance;
386 renderer_id_to_child_id_map_[src.id] = child_id; 358 renderer_id_to_child_id_map_[src.id] = child_id;
387 if ((src.state >> WebAccessibility::STATE_FOCUSED) & 1) 359 if ((src.state >> WebAccessibility::STATE_FOCUSED) & 1)
388 SetFocus(instance, false); 360 SetFocus(instance, false);
389 for (int i = 0; i < static_cast<int>(src.children.size()); ++i) { 361 for (int i = 0; i < static_cast<int>(src.children.size()); ++i) {
390 BrowserAccessibility* child = CreateAccessibilityTree( 362 BrowserAccessibility* child = CreateAccessibilityTree(
391 instance, src.children[i], i); 363 instance, src.children[i], i, children_can_send_show_events);
392 instance->AddChild(child); 364 instance->AddChild(child);
393 } 365 }
394 366
367 // Note: the purpose of send_show_events and children_can_send_show_events
368 // is so that we send a single OBJECT_SHOW event for the root of a subtree
369 // that just appeared for the first time, but not on any descendant of
370 // that subtree.
371 if (send_show_events)
372 NotifyAccessibilityEvent(ViewHostMsg_AccEvent::OBJECT_SHOW, instance);
373
374 instance->SendNodeUpdateEvents();
375
395 return instance; 376 return instance;
396 } 377 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698