OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 <stddef.h> | 7 #include <stddef.h> |
8 | 8 |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "build/build_config.h" | 10 #include "build/build_config.h" |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
118 } | 118 } |
119 | 119 |
120 BrowserAccessibilityManager::BrowserAccessibilityManager( | 120 BrowserAccessibilityManager::BrowserAccessibilityManager( |
121 BrowserAccessibilityDelegate* delegate, | 121 BrowserAccessibilityDelegate* delegate, |
122 BrowserAccessibilityFactory* factory) | 122 BrowserAccessibilityFactory* factory) |
123 : delegate_(delegate), | 123 : delegate_(delegate), |
124 factory_(factory), | 124 factory_(factory), |
125 tree_(new ui::AXSerializableTree()), | 125 tree_(new ui::AXSerializableTree()), |
126 user_is_navigating_away_(false), | 126 user_is_navigating_away_(false), |
127 osk_state_(OSK_ALLOWED), | 127 osk_state_(OSK_ALLOWED), |
128 last_focused_node_(nullptr), | |
129 last_focused_manager_(nullptr), | |
128 ax_tree_id_(AXTreeIDRegistry::kNoAXTreeID), | 130 ax_tree_id_(AXTreeIDRegistry::kNoAXTreeID), |
129 parent_node_id_from_parent_tree_(0) { | 131 parent_node_id_from_parent_tree_(0) { |
130 tree_->SetDelegate(this); | 132 tree_->SetDelegate(this); |
131 } | 133 } |
132 | 134 |
133 BrowserAccessibilityManager::BrowserAccessibilityManager( | 135 BrowserAccessibilityManager::BrowserAccessibilityManager( |
134 const ui::AXTreeUpdate& initial_tree, | 136 const ui::AXTreeUpdate& initial_tree, |
135 BrowserAccessibilityDelegate* delegate, | 137 BrowserAccessibilityDelegate* delegate, |
136 BrowserAccessibilityFactory* factory) | 138 BrowserAccessibilityFactory* factory) |
137 : delegate_(delegate), | 139 : delegate_(delegate), |
(...skipping 28 matching lines...) Expand all Loading... | |
166 ui::AXTreeUpdate | 168 ui::AXTreeUpdate |
167 BrowserAccessibilityManager::GetEmptyDocument() { | 169 BrowserAccessibilityManager::GetEmptyDocument() { |
168 ui::AXNodeData empty_document; | 170 ui::AXNodeData empty_document; |
169 empty_document.id = 0; | 171 empty_document.id = 0; |
170 empty_document.role = ui::AX_ROLE_ROOT_WEB_AREA; | 172 empty_document.role = ui::AX_ROLE_ROOT_WEB_AREA; |
171 ui::AXTreeUpdate update; | 173 ui::AXTreeUpdate update; |
172 update.nodes.push_back(empty_document); | 174 update.nodes.push_back(empty_document); |
173 return update; | 175 return update; |
174 } | 176 } |
175 | 177 |
178 void BrowserAccessibilityManager::FireFocusEventsIfNeeded() { | |
179 BrowserAccessibility* focus = GetFocus(); | |
180 if (delegate_ && !delegate_->AccessibilityViewHasFocus()) | |
181 focus = nullptr; | |
182 | |
183 if (!CanFireEvents()) | |
184 focus = nullptr; | |
185 | |
186 // Don't allow the document to be focused if it has no children and | |
187 // hasn't finished loading yet. Wait for at least a tiny bit of content, | |
188 // or for the document to actually finish loading. | |
189 if (focus && | |
190 focus == focus->manager()->GetRoot() && | |
191 focus->PlatformChildCount() == 0 && | |
192 !focus->HasState(ui::AX_STATE_BUSY) && | |
193 !focus->manager()->GetTreeData().loaded) { | |
David Tseng
2016/03/04 16:50:20
Why do we want to exclude focus for this case?
dmazzoni
2016/03/07 21:35:32
I moved this from Windows-specific code to cross-p
| |
194 focus = nullptr; | |
195 } | |
196 | |
197 if (focus && focus != last_focused_node_) | |
198 FireFocusEvent(focus); | |
199 | |
200 last_focused_node_ = focus; | |
David Tseng
2016/03/04 16:50:20
This would set nullptr for the conditions above. I
dmazzoni
2016/03/07 21:35:32
Yes, definitely intentional. Every single event we
| |
201 last_focused_manager_ = focus ? focus->manager() : nullptr; | |
David Tseng
2016/03/04 16:50:20
Why not remove the FocusManager member pointer and
dmazzoni
2016/03/07 21:35:32
Because we don't have an easy way of clearing last
| |
202 } | |
203 | |
204 bool BrowserAccessibilityManager::CanFireEvents() { | |
205 return true; | |
206 } | |
207 | |
208 void BrowserAccessibilityManager::FireFocusEvent(BrowserAccessibility* node) { | |
209 NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, node); | |
210 } | |
211 | |
176 BrowserAccessibility* BrowserAccessibilityManager::GetRoot() { | 212 BrowserAccessibility* BrowserAccessibilityManager::GetRoot() { |
177 // tree_ can be null during destruction. | 213 // tree_ can be null during destruction. |
178 if (!tree_) | 214 if (!tree_) |
179 return nullptr; | 215 return nullptr; |
180 | 216 |
181 // tree_->root() can be null during AXTreeDelegate callbacks. | 217 // tree_->root() can be null during AXTreeDelegate callbacks. |
182 ui::AXNode* root = tree_->root(); | 218 ui::AXNode* root = tree_->root(); |
183 return root ? GetFromAXNode(root) : nullptr; | 219 return root ? GetFromAXNode(root) : nullptr; |
184 } | 220 } |
185 | 221 |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
231 } | 267 } |
232 | 268 |
233 return nullptr; | 269 return nullptr; |
234 } | 270 } |
235 | 271 |
236 const ui::AXTreeData& BrowserAccessibilityManager::GetTreeData() { | 272 const ui::AXTreeData& BrowserAccessibilityManager::GetTreeData() { |
237 return tree_->data(); | 273 return tree_->data(); |
238 } | 274 } |
239 | 275 |
240 void BrowserAccessibilityManager::OnWindowFocused() { | 276 void BrowserAccessibilityManager::OnWindowFocused() { |
241 BrowserAccessibility* focus = GetFocus(); | 277 if (this == GetRootManager()) |
242 if (focus) | 278 FireFocusEventsIfNeeded(); |
243 NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, focus); | |
244 } | 279 } |
245 | 280 |
246 void BrowserAccessibilityManager::OnWindowBlurred() { | 281 void BrowserAccessibilityManager::OnWindowBlurred() { |
247 BrowserAccessibility* focus = GetFocus(); | 282 if (this == GetRootManager()) { |
248 if (focus) | 283 last_focused_node_ = nullptr; |
249 NotifyAccessibilityEvent(ui::AX_EVENT_BLUR, focus); | 284 last_focused_manager_ = nullptr; |
285 } | |
250 } | 286 } |
251 | 287 |
252 void BrowserAccessibilityManager::UserIsNavigatingAway() { | 288 void BrowserAccessibilityManager::UserIsNavigatingAway() { |
253 user_is_navigating_away_ = true; | 289 user_is_navigating_away_ = true; |
254 } | 290 } |
255 | 291 |
256 void BrowserAccessibilityManager::UserIsReloading() { | 292 void BrowserAccessibilityManager::UserIsReloading() { |
257 user_is_navigating_away_ = true; | 293 user_is_navigating_away_ = true; |
258 } | 294 } |
259 | 295 |
(...skipping 27 matching lines...) Expand all Loading... | |
287 if (delegate_) { | 323 if (delegate_) { |
288 LOG(ERROR) << tree_->error(); | 324 LOG(ERROR) << tree_->error(); |
289 delegate_->AccessibilityFatalError(); | 325 delegate_->AccessibilityFatalError(); |
290 } else { | 326 } else { |
291 CHECK(false) << tree_->error(); | 327 CHECK(false) << tree_->error(); |
292 } | 328 } |
293 return; | 329 return; |
294 } | 330 } |
295 } | 331 } |
296 | 332 |
297 // Now iterate over the events again and fire the events. | 333 // Based on the changes to the tree, first fire focus events if needed. |
334 // Screen readers might not do the right thing if they're not aware of what | |
335 // has focus, so always try that first. Nothing will be fired if the window | |
336 // itself isn't focused or if focus hasn't changed. | |
337 GetRootManager()->FireFocusEventsIfNeeded(); | |
338 | |
339 // Now iterate over the events again and fire the events other than focus | |
340 // events. | |
298 for (uint32_t index = 0; index < details.size(); index++) { | 341 for (uint32_t index = 0; index < details.size(); index++) { |
299 const AXEventNotificationDetails& detail = details[index]; | 342 const AXEventNotificationDetails& detail = details[index]; |
300 | 343 |
301 // Find the node corresponding to the id that's the target of the | 344 // Find the node corresponding to the id that's the target of the |
302 // event (which may not be the root of the update tree). | 345 // event (which may not be the root of the update tree). |
303 ui::AXNode* node = tree_->GetFromId(detail.id); | 346 ui::AXNode* node = tree_->GetFromId(detail.id); |
304 if (!node) | 347 if (!node) |
305 continue; | 348 continue; |
306 | 349 |
307 ui::AXEvent event_type = detail.event_type; | 350 ui::AXEvent event_type = detail.event_type; |
308 if (event_type == ui::AX_EVENT_FOCUS || | 351 if (event_type == ui::AX_EVENT_FOCUS || |
309 event_type == ui::AX_EVENT_BLUR) { | 352 event_type == ui::AX_EVENT_BLUR) { |
310 if (osk_state_ != OSK_DISALLOWED_BECAUSE_TAB_HIDDEN && | 353 if (osk_state_ != OSK_DISALLOWED_BECAUSE_TAB_HIDDEN && |
311 osk_state_ != OSK_DISALLOWED_BECAUSE_TAB_JUST_APPEARED) | 354 osk_state_ != OSK_DISALLOWED_BECAUSE_TAB_JUST_APPEARED) |
312 osk_state_ = OSK_ALLOWED; | 355 osk_state_ = OSK_ALLOWED; |
313 | 356 |
314 // Don't send a native focus event if the window itself doesn't | 357 bool is_menu_list_option = |
315 // have focus. | 358 node->data().role == ui::AX_ROLE_MENU_LIST_OPTION; |
316 if (!NativeViewHasFocus()) | 359 |
360 // Skip all focus events other than ones on menu list options; | |
361 // we've already handled them, above. Menu list options are a weird | |
362 // exception because the menu list itself has focus but we need to fire | |
363 // focus events on the individual options. | |
364 if (!is_menu_list_option) | |
317 continue; | 365 continue; |
318 } | 366 } |
319 | 367 |
320 // Send the event event to the operating system. | 368 // Fire the native event. |
321 NotifyAccessibilityEvent(event_type, GetFromAXNode(node)); | 369 NotifyAccessibilityEvent(event_type, GetFromAXNode(node)); |
322 } | 370 } |
323 } | 371 } |
324 | 372 |
325 void BrowserAccessibilityManager::OnLocationChanges( | 373 void BrowserAccessibilityManager::OnLocationChanges( |
326 const std::vector<AccessibilityHostMsg_LocationChangeParams>& params) { | 374 const std::vector<AccessibilityHostMsg_LocationChangeParams>& params) { |
327 for (size_t i = 0; i < params.size(); ++i) { | 375 for (size_t i = 0; i < params.size(); ++i) { |
328 BrowserAccessibility* obj = GetFromID(params[i].id); | 376 BrowserAccessibility* obj = GetFromID(params[i].id); |
329 if (!obj) | 377 if (!obj) |
330 continue; | 378 continue; |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
388 } | 436 } |
389 | 437 |
390 bool BrowserAccessibilityManager::NativeViewHasFocus() { | 438 bool BrowserAccessibilityManager::NativeViewHasFocus() { |
391 BrowserAccessibilityDelegate* delegate = GetDelegateFromRootManager(); | 439 BrowserAccessibilityDelegate* delegate = GetDelegateFromRootManager(); |
392 if (delegate) | 440 if (delegate) |
393 return delegate->AccessibilityViewHasFocus(); | 441 return delegate->AccessibilityViewHasFocus(); |
394 return false; | 442 return false; |
395 } | 443 } |
396 | 444 |
397 BrowserAccessibility* BrowserAccessibilityManager::GetFocus() { | 445 BrowserAccessibility* BrowserAccessibilityManager::GetFocus() { |
398 int32_t focus_id = GetTreeData().focus_id; | 446 BrowserAccessibilityManager* root_manager = GetRootManager(); |
399 BrowserAccessibility* obj = GetFromID(focus_id); | 447 if (!root_manager) |
448 root_manager = this; | |
449 int32_t focused_tree_id = root_manager->GetTreeData().focused_tree_id; | |
450 | |
451 BrowserAccessibilityManager* focused_manager = nullptr; | |
452 if (focused_tree_id) | |
453 focused_manager =BrowserAccessibilityManager::FromID(focused_tree_id); | |
454 if (!focused_manager) | |
455 focused_manager = root_manager; | |
456 | |
457 int32_t focus_id = focused_manager->GetTreeData().focus_id; | |
458 BrowserAccessibility* obj = focused_manager->GetFromID(focus_id); | |
400 if (!obj) | 459 if (!obj) |
401 return GetRoot(); | 460 return focused_manager->GetRoot(); |
402 | 461 |
403 if (obj->HasIntAttribute(ui::AX_ATTR_CHILD_TREE_ID)) { | 462 if (obj->HasIntAttribute(ui::AX_ATTR_CHILD_TREE_ID)) { |
404 BrowserAccessibilityManager* child_manager = | 463 BrowserAccessibilityManager* child_manager = |
405 BrowserAccessibilityManager::FromID( | 464 BrowserAccessibilityManager::FromID( |
406 obj->GetIntAttribute(ui::AX_ATTR_CHILD_TREE_ID)); | 465 obj->GetIntAttribute(ui::AX_ATTR_CHILD_TREE_ID)); |
407 if (child_manager) | 466 if (child_manager) |
408 return child_manager->GetFocus(); | 467 return child_manager->GetFocus(); |
409 } | 468 } |
410 | 469 |
411 return obj; | 470 return obj; |
(...skipping 337 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
749 tree_->CreateTreeSource()); | 808 tree_->CreateTreeSource()); |
750 ui::AXTreeSerializer<const ui::AXNode*, | 809 ui::AXTreeSerializer<const ui::AXNode*, |
751 ui::AXNodeData, | 810 ui::AXNodeData, |
752 ui::AXTreeData> serializer(tree_source.get()); | 811 ui::AXTreeData> serializer(tree_source.get()); |
753 ui::AXTreeUpdate update; | 812 ui::AXTreeUpdate update; |
754 serializer.SerializeChanges(tree_->root(), &update); | 813 serializer.SerializeChanges(tree_->root(), &update); |
755 return update; | 814 return update; |
756 } | 815 } |
757 | 816 |
758 } // namespace content | 817 } // namespace content |
OLD | NEW |