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
3 // found in the LICENSE file.
5 #include "content/browser/accessibility/browser_accessibility_manager.h"
7 #include "base/logging.h"
8 #include "content/browser/accessibility/browser_accessibility.h"
9 #include "content/common/accessibility_messages.h"
13 BrowserAccessibility
* BrowserAccessibilityFactory::Create() {
14 return BrowserAccessibility::Create();
17 #if !defined(OS_MACOSX) && \
19 !defined(TOOLKIT_GTK) && \
20 !defined(OS_ANDROID) \
21 // We have subclassess of BrowserAccessibilityManager on Mac, Linux/GTK,
22 // and Win. For any other platform, instantiate the base class.
24 BrowserAccessibilityManager
* BrowserAccessibilityManager::Create(
25 const ui::AXNodeData
& src
,
26 BrowserAccessibilityDelegate
* delegate
,
27 BrowserAccessibilityFactory
* factory
) {
28 return new BrowserAccessibilityManager(src
, delegate
, factory
);
32 BrowserAccessibilityManager::BrowserAccessibilityManager(
33 BrowserAccessibilityDelegate
* delegate
,
34 BrowserAccessibilityFactory
* factory
)
35 : delegate_(delegate
),
39 osk_state_(OSK_ALLOWED
) {
42 BrowserAccessibilityManager::BrowserAccessibilityManager(
43 const ui::AXNodeData
& src
,
44 BrowserAccessibilityDelegate
* delegate
,
45 BrowserAccessibilityFactory
* factory
)
46 : delegate_(delegate
),
50 osk_state_(OSK_ALLOWED
) {
54 BrowserAccessibilityManager::~BrowserAccessibilityManager() {
59 void BrowserAccessibilityManager::Initialize(const ui::AXNodeData src
) {
60 std::vector
<ui::AXNodeData
> nodes
;
62 if (!UpdateNodes(nodes
))
65 SetFocus(root_
, false);
69 ui::AXNodeData
BrowserAccessibilityManager::GetEmptyDocument() {
70 ui::AXNodeData empty_document
;
71 empty_document
.id
= 0;
72 empty_document
.role
= ui::AX_ROLE_ROOT_WEB_AREA
;
73 return empty_document
;
76 BrowserAccessibility
* BrowserAccessibilityManager::GetRoot() {
80 BrowserAccessibility
* BrowserAccessibilityManager::GetFromRendererID(
82 base::hash_map
<int32
, BrowserAccessibility
*>::iterator iter
=
83 renderer_id_map_
.find(renderer_id
);
84 if (iter
!= renderer_id_map_
.end())
89 void BrowserAccessibilityManager::GotFocus(bool touch_event_context
) {
90 if (!touch_event_context
)
91 osk_state_
= OSK_DISALLOWED_BECAUSE_TAB_JUST_APPEARED
;
96 NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS
, focus_
);
99 void BrowserAccessibilityManager::WasHidden() {
100 osk_state_
= OSK_DISALLOWED_BECAUSE_TAB_HIDDEN
;
103 void BrowserAccessibilityManager::GotMouseDown() {
104 osk_state_
= OSK_ALLOWED_WITHIN_FOCUSED_OBJECT
;
105 NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS
, focus_
);
108 bool BrowserAccessibilityManager::IsOSKAllowed(const gfx::Rect
& bounds
) {
109 if (!delegate_
|| !delegate_
->HasFocus())
112 gfx::Point touch_point
= delegate_
->GetLastTouchEventLocation();
113 return bounds
.Contains(touch_point
);
116 bool BrowserAccessibilityManager::UseRootScrollOffsetsWhenComputingBounds() {
120 void BrowserAccessibilityManager::RemoveNode(BrowserAccessibility
* node
) {
122 SetFocus(root_
, false);
123 int renderer_id
= node
->renderer_id();
124 renderer_id_map_
.erase(renderer_id
);
127 void BrowserAccessibilityManager::OnAccessibilityEvents(
128 const std::vector
<AccessibilityHostMsg_EventParams
>& params
) {
129 bool should_send_initial_focus
= false;
131 // Process all changes to the accessibility tree first.
132 for (uint32 index
= 0; index
< params
.size(); index
++) {
133 const AccessibilityHostMsg_EventParams
& param
= params
[index
];
134 if (!UpdateNodes(param
.nodes
))
137 // Set initial focus when a page is loaded.
138 ui::AXEvent event_type
= param
.event_type
;
139 if (event_type
== ui::AX_EVENT_LOAD_COMPLETE
) {
141 SetFocus(root_
, false);
142 should_send_initial_focus
= true;
147 if (should_send_initial_focus
&&
148 (!delegate_
|| delegate_
->HasFocus())) {
149 NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS
, focus_
);
152 // Now iterate over the events again and fire the events.
153 for (uint32 index
= 0; index
< params
.size(); index
++) {
154 const AccessibilityHostMsg_EventParams
& param
= params
[index
];
156 // Find the node corresponding to the id that's the target of the
157 // event (which may not be the root of the update tree).
158 BrowserAccessibility
* node
= GetFromRendererID(param
.id
);
162 ui::AXEvent event_type
= param
.event_type
;
163 if (event_type
== ui::AX_EVENT_FOCUS
||
164 event_type
== ui::AX_EVENT_BLUR
) {
165 SetFocus(node
, false);
167 if (osk_state_
!= OSK_DISALLOWED_BECAUSE_TAB_HIDDEN
&&
168 osk_state_
!= OSK_DISALLOWED_BECAUSE_TAB_JUST_APPEARED
)
169 osk_state_
= OSK_ALLOWED
;
171 // Don't send a native focus event if the window itself doesn't
173 if (delegate_
&& !delegate_
->HasFocus())
177 // Send the event event to the operating system.
178 NotifyAccessibilityEvent(event_type
, node
);
182 void BrowserAccessibilityManager::OnLocationChanges(
183 const std::vector
<AccessibilityHostMsg_LocationChangeParams
>& params
) {
184 for (size_t i
= 0; i
< params
.size(); ++i
) {
185 BrowserAccessibility
* node
= GetFromRendererID(params
[i
].id
);
187 node
->SetLocation(params
[i
].new_location
);
191 BrowserAccessibility
* BrowserAccessibilityManager::GetFocus(
192 BrowserAccessibility
* root
) {
193 if (focus_
&& (!root
|| focus_
->IsDescendantOf(root
)))
199 void BrowserAccessibilityManager::SetFocus(
200 BrowserAccessibility
* node
, bool notify
) {
204 if (notify
&& node
&& delegate_
)
205 delegate_
->SetAccessibilityFocus(node
->renderer_id());
208 void BrowserAccessibilityManager::SetRoot(BrowserAccessibility
* node
) {
213 void BrowserAccessibilityManager::DoDefaultAction(
214 const BrowserAccessibility
& node
) {
216 delegate_
->AccessibilityDoDefaultAction(node
.renderer_id());
219 void BrowserAccessibilityManager::ScrollToMakeVisible(
220 const BrowserAccessibility
& node
, gfx::Rect subfocus
) {
222 delegate_
->AccessibilityScrollToMakeVisible(node
.renderer_id(), subfocus
);
226 void BrowserAccessibilityManager::ScrollToPoint(
227 const BrowserAccessibility
& node
, gfx::Point point
) {
229 delegate_
->AccessibilityScrollToPoint(node
.renderer_id(), point
);
233 void BrowserAccessibilityManager::SetTextSelection(
234 const BrowserAccessibility
& node
, int start_offset
, int end_offset
) {
236 delegate_
->AccessibilitySetTextSelection(
237 node
.renderer_id(), start_offset
, end_offset
);
241 gfx::Rect
BrowserAccessibilityManager::GetViewBounds() {
243 return delegate_
->GetViewBounds();
247 BrowserAccessibility
* BrowserAccessibilityManager::NextInTreeOrder(
248 BrowserAccessibility
* node
) {
252 if (node
->PlatformChildCount() > 0)
253 return node
->PlatformGetChild(0);
255 if (node
->parent() &&
256 node
->index_in_parent() <
257 static_cast<int>(node
->parent()->PlatformChildCount()) - 1) {
258 return node
->parent()->PlatformGetChild(node
->index_in_parent() + 1);
260 node
= node
->parent();
266 BrowserAccessibility
* BrowserAccessibilityManager::PreviousInTreeOrder(
267 BrowserAccessibility
* node
) {
271 if (node
->parent() && node
->index_in_parent() > 0) {
272 node
= node
->parent()->PlatformGetChild(node
->index_in_parent() - 1);
273 while (node
->PlatformChildCount() > 0)
274 node
= node
->PlatformGetChild(node
->PlatformChildCount() - 1);
278 return node
->parent();
281 void BrowserAccessibilityManager::UpdateNodesForTesting(
282 const ui::AXNodeData
& node1
,
283 const ui::AXNodeData
& node2
/* = ui::AXNodeData() */,
284 const ui::AXNodeData
& node3
/* = ui::AXNodeData() */,
285 const ui::AXNodeData
& node4
/* = ui::AXNodeData() */,
286 const ui::AXNodeData
& node5
/* = ui::AXNodeData() */,
287 const ui::AXNodeData
& node6
/* = ui::AXNodeData() */,
288 const ui::AXNodeData
& node7
/* = ui::AXNodeData() */) {
289 std::vector
<ui::AXNodeData
> nodes
;
290 nodes
.push_back(node1
);
291 if (node2
.id
!= ui::AXNodeData().id
)
292 nodes
.push_back(node2
);
293 if (node3
.id
!= ui::AXNodeData().id
)
294 nodes
.push_back(node3
);
295 if (node4
.id
!= ui::AXNodeData().id
)
296 nodes
.push_back(node4
);
297 if (node5
.id
!= ui::AXNodeData().id
)
298 nodes
.push_back(node5
);
299 if (node6
.id
!= ui::AXNodeData().id
)
300 nodes
.push_back(node6
);
301 if (node7
.id
!= ui::AXNodeData().id
)
302 nodes
.push_back(node7
);
306 bool BrowserAccessibilityManager::UpdateNodes(
307 const std::vector
<ui::AXNodeData
>& nodes
) {
310 // First, update all of the nodes in the tree.
311 for (size_t i
= 0; i
< nodes
.size() && success
; i
++) {
312 if (!UpdateNode(nodes
[i
]))
316 // In a second pass, call PostInitialize on each one - this must
317 // be called after all of each node's children are initialized too.
318 for (size_t i
= 0; i
< nodes
.size() && success
; i
++) {
319 // Note: it's not a bug for nodes[i].id to not be found in the tree.
320 // Consider this example:
334 // In this example, F is being reparented. The renderer scans the tree
335 // in order. If can't update "C" to add "F" as a child, when "F" is still
336 // a child of "E". So it first updates "E", to remove "F" as a child.
337 // Later, it ends up deleting "E". So when we get here, "E" was updated as
338 // part of this sequence but it no longer exists in the final tree, so
339 // there's nothing to postinitialize.
340 BrowserAccessibility
* instance
= GetFromRendererID(nodes
[i
].id
);
342 instance
->PostInitialize();
346 // A bad accessibility tree could lead to memory corruption.
347 // Ask the delegate to crash the renderer, or if not available,
348 // crash the browser.
350 delegate_
->FatalAccessibilityTreeError();
358 BrowserAccessibility
* BrowserAccessibilityManager::CreateNode(
359 BrowserAccessibility
* parent
,
361 int32 index_in_parent
) {
362 BrowserAccessibility
* node
= factory_
->Create();
363 node
->InitializeTreeStructure(
364 this, parent
, renderer_id
, index_in_parent
);
369 void BrowserAccessibilityManager::AddNodeToMap(BrowserAccessibility
* node
) {
370 renderer_id_map_
[node
->renderer_id()] = node
;
373 bool BrowserAccessibilityManager::UpdateNode(const ui::AXNodeData
& src
) {
374 // This method updates one node in the tree based on serialized data
375 // received from the renderer.
377 // Create a set of child ids in |src| for fast lookup. If a duplicate id is
378 // found, exit now with a fatal error before changing anything else.
379 std::set
<int32
> new_child_ids
;
380 for (size_t i
= 0; i
< src
.child_ids
.size(); ++i
) {
381 if (new_child_ids
.find(src
.child_ids
[i
]) != new_child_ids
.end())
383 new_child_ids
.insert(src
.child_ids
[i
]);
386 // Look up the node by id. If it's not found, then either the root
387 // of the tree is being swapped, or we're out of sync with the renderer
388 // and this is a serious error.
389 BrowserAccessibility
* instance
= GetFromRendererID(src
.id
);
391 if (src
.role
!= ui::AX_ROLE_ROOT_WEB_AREA
)
393 instance
= CreateNode(NULL
, src
.id
, 0);
396 // Update all of the node-specific data, like its role, state, name, etc.
397 instance
->InitializeData(src
);
400 // Update the children in three steps:
402 // 1. Iterate over the old children and delete nodes that are no longer
404 // 2. Build up a vector of new children, reusing children that haven't
405 // changed (but may have been reordered) and adding new empty
406 // objects for new children.
407 // 3. Swap in the new children vector for the old one.
409 // Delete any previous children of this instance that are no longer
410 // children first. We make a deletion-only pass first to prevent a
411 // node that's being reparented from being the child of both its old
412 // parent and new parent, which could lead to a double-free.
413 // If a node is reparented, the renderer will always send us a fresh
415 const std::vector
<BrowserAccessibility
*>& old_children
= instance
->children();
416 for (size_t i
= 0; i
< old_children
.size(); ++i
) {
417 int old_id
= old_children
[i
]->renderer_id();
418 if (new_child_ids
.find(old_id
) == new_child_ids
.end())
419 old_children
[i
]->Destroy();
422 // Now build a vector of new children, reusing objects that were already
423 // children of this node before.
424 std::vector
<BrowserAccessibility
*> new_children
;
426 for (size_t i
= 0; i
< src
.child_ids
.size(); i
++) {
427 int32 child_renderer_id
= src
.child_ids
[i
];
428 int32 index_in_parent
= static_cast<int32
>(i
);
429 BrowserAccessibility
* child
= GetFromRendererID(child_renderer_id
);
431 if (child
->parent() != instance
) {
432 // This is a serious error - nodes should never be reparented.
433 // If this case occurs, continue so this node isn't left in an
434 // inconsistent state, but return failure at the end.
438 child
->UpdateParent(instance
, index_in_parent
);
440 child
= CreateNode(instance
, child_renderer_id
, index_in_parent
);
442 new_children
.push_back(child
);
445 // Finally, swap in the new children vector for the old.
446 instance
->SwapChildren(new_children
);
448 // Handle the case where this node is the new root of the tree.
449 if (src
.role
== ui::AX_ROLE_ROOT_WEB_AREA
&&
450 (!root_
|| root_
->renderer_id() != src
.id
)) {
454 SetFocus(instance
, false);
458 // Keep track of what node is focused.
459 if (src
.role
!= ui::AX_ROLE_ROOT_WEB_AREA
&&
460 src
.role
!= ui::AX_ROLE_WEB_AREA
&&
461 (src
.state
>> ui::AX_STATE_FOCUSED
& 1)) {
462 SetFocus(instance
, false);
467 } // namespace content