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 25 matching lines...) Expand all Loading... |
36 #endif | 36 #endif |
37 | 37 |
38 // static | 38 // static |
39 BrowserAccessibilityManager* BrowserAccessibilityManager::CreateEmptyDocument( | 39 BrowserAccessibilityManager* BrowserAccessibilityManager::CreateEmptyDocument( |
40 gfx::NativeView parent_view, | 40 gfx::NativeView parent_view, |
41 WebAccessibility::State state, | 41 WebAccessibility::State state, |
42 BrowserAccessibilityDelegate* delegate, | 42 BrowserAccessibilityDelegate* delegate, |
43 BrowserAccessibilityFactory* factory) { | 43 BrowserAccessibilityFactory* factory) { |
44 // Use empty document to process notifications | 44 // Use empty document to process notifications |
45 webkit_glue::WebAccessibility empty_document; | 45 webkit_glue::WebAccessibility empty_document; |
46 // Renderer id's always start at 1000 as determined by webkit. Boot strap | 46 empty_document.id = 0; |
47 // our ability to reuse BrowserAccessibility instances. | 47 empty_document.role = WebAccessibility::ROLE_ROOT_WEB_AREA; |
48 empty_document.id = 1000; | |
49 empty_document.role = WebAccessibility::ROLE_WEB_AREA; | |
50 empty_document.state = state; | 48 empty_document.state = state; |
51 return BrowserAccessibilityManager::Create( | 49 return BrowserAccessibilityManager::Create( |
52 parent_view, empty_document, delegate, factory); | 50 parent_view, empty_document, delegate, factory); |
53 } | 51 } |
54 | 52 |
55 BrowserAccessibilityManager::BrowserAccessibilityManager( | 53 BrowserAccessibilityManager::BrowserAccessibilityManager( |
56 gfx::NativeView parent_view, | 54 gfx::NativeView parent_view, |
57 const WebAccessibility& src, | 55 const WebAccessibility& src, |
58 BrowserAccessibilityDelegate* delegate, | 56 BrowserAccessibilityDelegate* delegate, |
59 BrowserAccessibilityFactory* factory) | 57 BrowserAccessibilityFactory* factory) |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
107 int32 renderer_id) { | 105 int32 renderer_id) { |
108 base::hash_map<int32, int32>::iterator iter = | 106 base::hash_map<int32, int32>::iterator iter = |
109 renderer_id_to_child_id_map_.find(renderer_id); | 107 renderer_id_to_child_id_map_.find(renderer_id); |
110 if (iter == renderer_id_to_child_id_map_.end()) | 108 if (iter == renderer_id_to_child_id_map_.end()) |
111 return NULL; | 109 return NULL; |
112 | 110 |
113 int32 child_id = iter->second; | 111 int32 child_id = iter->second; |
114 return GetFromChildID(child_id); | 112 return GetFromChildID(child_id); |
115 } | 113 } |
116 | 114 |
| 115 void BrowserAccessibilityManager::GotFocus() { |
| 116 if (!focus_) |
| 117 return; |
| 118 |
| 119 NotifyAccessibilityEvent(ViewHostMsg_AccEvent::FOCUS_CHANGED, focus_); |
| 120 } |
| 121 |
117 void BrowserAccessibilityManager::Remove(int32 child_id, int32 renderer_id) { | 122 void BrowserAccessibilityManager::Remove(int32 child_id, int32 renderer_id) { |
118 child_id_map_.erase(child_id); | 123 child_id_map_.erase(child_id); |
119 | 124 |
120 // TODO(ctguil): Investigate if hit. We should never have a newer entry. | 125 // TODO(ctguil): Investigate if hit. We should never have a newer entry. |
121 DCHECK(renderer_id_to_child_id_map_[renderer_id] == child_id); | 126 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 | 127 // Make sure we don't overwrite a newer entry (see UpdateNode for a possible |
123 // corner case). | 128 // corner case). |
124 if (renderer_id_to_child_id_map_[renderer_id] == child_id) | 129 if (renderer_id_to_child_id_map_[renderer_id] == child_id) |
125 renderer_id_to_child_id_map_.erase(renderer_id); | 130 renderer_id_to_child_id_map_.erase(renderer_id); |
126 } | 131 } |
127 | 132 |
128 void BrowserAccessibilityManager::OnAccessibilityNotifications( | 133 void BrowserAccessibilityManager::OnAccessibilityNotifications( |
129 const std::vector<ViewHostMsg_AccessibilityNotification_Params>& params) { | 134 const std::vector<ViewHostMsg_AccessibilityNotification_Params>& params) { |
130 for (uint32 index = 0; index < params.size(); index++) { | 135 for (uint32 index = 0; index < params.size(); index++) { |
131 const ViewHostMsg_AccessibilityNotification_Params& param = params[index]; | 136 const ViewHostMsg_AccessibilityNotification_Params& param = params[index]; |
132 | 137 |
133 switch (param.notification_type) { | 138 // Update the tree. |
134 // Notifications where children are included. | 139 UpdateNode(param.acc_tree, param.includes_children); |
135 case ViewHostMsg_AccEvent::CHILDREN_CHANGED: | |
136 case ViewHostMsg_AccEvent::LIVE_REGION_CHANGED: | |
137 OnSimpleAccessibilityNotification( | |
138 param.acc_obj, param.notification_type, true); | |
139 break; | |
140 | 140 |
141 case ViewHostMsg_AccEvent::FOCUS_CHANGED: | 141 // Find the node corresponding to the id that's the target of the |
142 OnAccessibilityObjectFocusChange(param.acc_obj); | 142 // notification (which may not be the root of the update tree). |
143 break; | 143 base::hash_map<int32, int32>::iterator iter = |
| 144 renderer_id_to_child_id_map_.find(param.id); |
| 145 if (iter == renderer_id_to_child_id_map_.end()) { |
| 146 continue; |
| 147 } |
| 148 int32 child_id = iter->second; |
| 149 BrowserAccessibility* node = GetFromChildID(child_id); |
| 150 if (!node) { |
| 151 NOTREACHED(); |
| 152 continue; |
| 153 } |
144 | 154 |
145 case ViewHostMsg_AccEvent::LOAD_COMPLETE: | 155 if (param.notification_type == ViewHostMsg_AccEvent::FOCUS_CHANGED) { |
146 OnAccessibilityObjectLoadComplete(param.acc_obj); | 156 SetFocus(node, false); |
147 break; | |
148 | 157 |
149 // All other notifications: the node is updated, but | 158 // Don't send a native focus event if the window itself doesn't |
150 // children are not included. | 159 // have focus. |
151 case ViewHostMsg_AccEvent::ACTIVE_DESCENDANT_CHANGED: | 160 if (delegate_ && !delegate_->HasFocus()) |
152 case ViewHostMsg_AccEvent::ALERT: | 161 continue; |
153 case ViewHostMsg_AccEvent::CHECK_STATE_CHANGED: | 162 } |
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); | |
169 break; | |
170 | 163 |
171 default: | 164 // Send the notification event to the operating system. |
172 DCHECK(0); | 165 NotifyAccessibilityEvent(param.notification_type, node); |
| 166 |
| 167 // Set initial focus when a page is loaded. |
| 168 if (param.notification_type == ViewHostMsg_AccEvent::LOAD_COMPLETE) { |
| 169 if (!focus_) |
| 170 SetFocus(root_, false); |
| 171 if (!delegate_ || delegate_->HasFocus()) |
| 172 NotifyAccessibilityEvent(ViewHostMsg_AccEvent::FOCUS_CHANGED, focus_); |
173 } | 173 } |
174 } | 174 } |
175 } | 175 } |
176 | 176 |
177 void BrowserAccessibilityManager::OnSimpleAccessibilityNotification( | |
178 const WebAccessibility& acc_obj, | |
179 int notification_type, | |
180 bool include_children) { | |
181 BrowserAccessibility* new_browser_acc = | |
182 UpdateNode(acc_obj, include_children); | |
183 if (!new_browser_acc) | |
184 return; | |
185 | |
186 NotifyAccessibilityEvent(notification_type, new_browser_acc); | |
187 } | |
188 | |
189 void BrowserAccessibilityManager::OnAccessibilityObjectFocusChange( | |
190 const WebAccessibility& acc_obj) { | |
191 BrowserAccessibility* new_browser_acc = UpdateNode(acc_obj, false); | |
192 if (!new_browser_acc) | |
193 return; | |
194 | |
195 SetFocus(new_browser_acc, false); | |
196 if (delegate_ && delegate_->HasFocus()) { | |
197 GotFocus(); | |
198 } else if (!delegate_) { | |
199 // Mac currently does not have a BrowserAccessibilityDelegate. | |
200 NotifyAccessibilityEvent(ViewHostMsg_AccEvent::FOCUS_CHANGED, focus_); | |
201 } | |
202 } | |
203 | |
204 void BrowserAccessibilityManager::OnAccessibilityObjectLoadComplete( | |
205 const WebAccessibility& acc_obj) { | |
206 SetFocus(NULL, false); | |
207 | |
208 root_ = UpdateNode(acc_obj, true); | |
209 if (!focus_) | |
210 SetFocus(root_, false); | |
211 | |
212 NotifyAccessibilityEvent(ViewHostMsg_AccEvent::LOAD_COMPLETE, root_); | |
213 if (delegate_ && delegate_->HasFocus()) | |
214 GotFocus(); | |
215 } | |
216 | |
217 void BrowserAccessibilityManager::GotFocus() { | |
218 // TODO(ctguil): Remove when tree update logic handles focus changes. | |
219 if (!focus_) | |
220 return; | |
221 | |
222 NotifyAccessibilityEvent(ViewHostMsg_AccEvent::FOCUS_CHANGED, focus_); | |
223 } | |
224 | |
225 gfx::NativeView BrowserAccessibilityManager::GetParentView() { | 177 gfx::NativeView BrowserAccessibilityManager::GetParentView() { |
226 return parent_view_; | 178 return parent_view_; |
227 } | 179 } |
228 | 180 |
229 BrowserAccessibility* BrowserAccessibilityManager::GetFocus( | 181 BrowserAccessibility* BrowserAccessibilityManager::GetFocus( |
230 BrowserAccessibility* root) { | 182 BrowserAccessibility* root) { |
231 if (focus_ && (!root || focus_->IsDescendantOf(root))) | 183 if (focus_ && (!root || focus_->IsDescendantOf(root))) |
232 return focus_; | 184 return focus_; |
233 | 185 |
234 return NULL; | 186 return NULL; |
(...skipping 18 matching lines...) Expand all Loading... |
253 if (delegate_) | 205 if (delegate_) |
254 delegate_->AccessibilityDoDefaultAction(node.renderer_id()); | 206 delegate_->AccessibilityDoDefaultAction(node.renderer_id()); |
255 } | 207 } |
256 | 208 |
257 gfx::Rect BrowserAccessibilityManager::GetViewBounds() { | 209 gfx::Rect BrowserAccessibilityManager::GetViewBounds() { |
258 if (delegate_) | 210 if (delegate_) |
259 return delegate_->GetViewBounds(); | 211 return delegate_->GetViewBounds(); |
260 return gfx::Rect(); | 212 return gfx::Rect(); |
261 } | 213 } |
262 | 214 |
263 BrowserAccessibility* BrowserAccessibilityManager::UpdateNode( | 215 void BrowserAccessibilityManager::UpdateNode( |
264 const WebAccessibility& src, | 216 const WebAccessibility& src, |
265 bool include_children) { | 217 bool include_children) { |
266 base::hash_map<int32, int32>::iterator iter = | 218 BrowserAccessibility* current = NULL; |
267 renderer_id_to_child_id_map_.find(src.id); | 219 if (src.role == WebAccessibility::ROLE_ROOT_WEB_AREA) { |
268 if (iter == renderer_id_to_child_id_map_.end()) | 220 // As an exceptional case, there can only be one root of the tree, so |
269 return NULL; | 221 // if we get a new root, replace the current root no matter what the |
| 222 // current root's renderer ID is. |
| 223 current = root_; |
| 224 renderer_id_to_child_id_map_.erase(current->renderer_id()); |
| 225 renderer_id_to_child_id_map_[src.id] = current->child_id(); |
| 226 } else { |
| 227 // Otherwise, replace the node based on its renderer ID. |
| 228 base::hash_map<int32, int32>::iterator iter = |
| 229 renderer_id_to_child_id_map_.find(src.id); |
| 230 if (iter != renderer_id_to_child_id_map_.end()) { |
| 231 int32 child_id = iter->second; |
| 232 current = GetFromChildID(child_id); |
| 233 } |
| 234 } |
270 | 235 |
271 int32 child_id = iter->second; | |
272 BrowserAccessibility* current = GetFromChildID(child_id); | |
273 if (!current) | 236 if (!current) |
274 return NULL; | 237 return; |
275 | 238 |
276 if (!include_children) { | 239 if (!include_children) { |
277 DCHECK_EQ(0U, src.children.size()); | 240 DCHECK_EQ(0U, src.children.size()); |
278 current->Initialize( | 241 current->Initialize( |
279 this, | 242 this, |
280 current->parent(), | 243 current->parent(), |
281 current->child_id(), | 244 current->child_id(), |
282 current->index_in_parent(), | 245 current->index_in_parent(), |
283 src); | 246 src); |
284 current->SendNodeUpdateEvents(); | 247 current->SendNodeUpdateEvents(); |
285 return current; | 248 return; |
286 } | 249 } |
287 | 250 |
288 BrowserAccessibility* current_parent = current->parent(); | 251 BrowserAccessibility* current_parent = current->parent(); |
289 int current_index_in_parent = current->index_in_parent(); | 252 int current_index_in_parent = current->index_in_parent(); |
290 | 253 |
291 // Detach all of the nodes in the old tree and get a single flat vector | 254 // Detach all of the nodes in the old tree and get a single flat vector |
292 // of all node pointers. | 255 // of all node pointers. |
293 std::vector<BrowserAccessibility*> old_tree_nodes; | 256 std::vector<BrowserAccessibility*> old_tree_nodes; |
294 current->DetachTree(&old_tree_nodes); | 257 current->DetachTree(&old_tree_nodes); |
295 | 258 |
296 // Build a new tree, reusing old nodes if possible. Each node that's | 259 // Build a new tree, reusing old nodes if possible. Each node that's |
297 // reused will have its reference count incremented by one. | 260 // reused will have its reference count incremented by one. |
298 current = CreateAccessibilityTree( | 261 current = CreateAccessibilityTree( |
299 current_parent, src, current_index_in_parent, true); | 262 current_parent, src, current_index_in_parent, true); |
300 | 263 |
301 // Decrement the reference count of all nodes in the old tree, which will | 264 // Decrement the reference count of all nodes in the old tree, which will |
302 // delete any nodes no longer needed. | 265 // delete any nodes no longer needed. |
303 for (int i = 0; i < static_cast<int>(old_tree_nodes.size()); i++) | 266 for (int i = 0; i < static_cast<int>(old_tree_nodes.size()); i++) |
304 old_tree_nodes[i]->InternalReleaseReference(false); | 267 old_tree_nodes[i]->InternalReleaseReference(false); |
305 | 268 |
306 if (!focus_ || !focus_->instance_active()) | 269 if (!focus_ || !focus_->instance_active()) |
307 SetFocus(root_, false); | 270 SetFocus(root_, false); |
308 | |
309 return current; | |
310 } | 271 } |
311 | 272 |
312 BrowserAccessibility* BrowserAccessibilityManager::CreateAccessibilityTree( | 273 BrowserAccessibility* BrowserAccessibilityManager::CreateAccessibilityTree( |
313 BrowserAccessibility* parent, | 274 BrowserAccessibility* parent, |
314 const WebAccessibility& src, | 275 const WebAccessibility& src, |
315 int index_in_parent, | 276 int index_in_parent, |
316 bool send_show_events) { | 277 bool send_show_events) { |
317 BrowserAccessibility* instance = NULL; | 278 BrowserAccessibility* instance = NULL; |
318 int32 child_id = 0; | 279 int32 child_id = 0; |
319 bool children_can_send_show_events = send_show_events; | 280 bool children_can_send_show_events = send_show_events; |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
368 // is so that we send a single OBJECT_SHOW event for the root of a subtree | 329 // 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 | 330 // that just appeared for the first time, but not on any descendant of |
370 // that subtree. | 331 // that subtree. |
371 if (send_show_events) | 332 if (send_show_events) |
372 NotifyAccessibilityEvent(ViewHostMsg_AccEvent::OBJECT_SHOW, instance); | 333 NotifyAccessibilityEvent(ViewHostMsg_AccEvent::OBJECT_SHOW, instance); |
373 | 334 |
374 instance->SendNodeUpdateEvents(); | 335 instance->SendNodeUpdateEvents(); |
375 | 336 |
376 return instance; | 337 return instance; |
377 } | 338 } |
OLD | NEW |