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"
10 #include "ui/accessibility/ax_tree_serializer.h"
14 ui::AXTreeUpdate
MakeAXTreeUpdate(
15 const ui::AXNodeData
& node1
,
16 const ui::AXNodeData
& node2
/* = ui::AXNodeData() */,
17 const ui::AXNodeData
& node3
/* = ui::AXNodeData() */,
18 const ui::AXNodeData
& node4
/* = ui::AXNodeData() */,
19 const ui::AXNodeData
& node5
/* = ui::AXNodeData() */,
20 const ui::AXNodeData
& node6
/* = ui::AXNodeData() */,
21 const ui::AXNodeData
& node7
/* = ui::AXNodeData() */,
22 const ui::AXNodeData
& node8
/* = ui::AXNodeData() */,
23 const ui::AXNodeData
& node9
/* = ui::AXNodeData() */) {
24 CR_DEFINE_STATIC_LOCAL(ui::AXNodeData
, empty_data
, ());
25 int32 no_id
= empty_data
.id
;
27 ui::AXTreeUpdate update
;
28 update
.nodes
.push_back(node1
);
29 if (node2
.id
!= no_id
)
30 update
.nodes
.push_back(node2
);
31 if (node3
.id
!= no_id
)
32 update
.nodes
.push_back(node3
);
33 if (node4
.id
!= no_id
)
34 update
.nodes
.push_back(node4
);
35 if (node5
.id
!= no_id
)
36 update
.nodes
.push_back(node5
);
37 if (node6
.id
!= no_id
)
38 update
.nodes
.push_back(node6
);
39 if (node7
.id
!= no_id
)
40 update
.nodes
.push_back(node7
);
41 if (node8
.id
!= no_id
)
42 update
.nodes
.push_back(node8
);
43 if (node9
.id
!= no_id
)
44 update
.nodes
.push_back(node9
);
48 BrowserAccessibility
* BrowserAccessibilityFactory::Create() {
49 return BrowserAccessibility::Create();
52 #if !defined(OS_MACOSX) && \
54 !defined(OS_ANDROID) \
55 // We have subclassess of BrowserAccessibilityManager on Mac, and Win. For any
56 // other platform, instantiate the base class.
58 BrowserAccessibilityManager
* BrowserAccessibilityManager::Create(
59 const ui::AXTreeUpdate
& initial_tree
,
60 BrowserAccessibilityDelegate
* delegate
,
61 BrowserAccessibilityFactory
* factory
) {
62 return new BrowserAccessibilityManager(initial_tree
, delegate
, factory
);
66 BrowserAccessibilityManager::BrowserAccessibilityManager(
67 BrowserAccessibilityDelegate
* delegate
,
68 BrowserAccessibilityFactory
* factory
)
69 : delegate_(delegate
),
71 tree_(new ui::AXSerializableTree()),
73 osk_state_(OSK_ALLOWED
) {
74 tree_
->SetDelegate(this);
77 BrowserAccessibilityManager::BrowserAccessibilityManager(
78 const ui::AXTreeUpdate
& initial_tree
,
79 BrowserAccessibilityDelegate
* delegate
,
80 BrowserAccessibilityFactory
* factory
)
81 : delegate_(delegate
),
83 tree_(new ui::AXSerializableTree()),
85 osk_state_(OSK_ALLOWED
) {
86 tree_
->SetDelegate(this);
87 Initialize(initial_tree
);
90 BrowserAccessibilityManager::~BrowserAccessibilityManager() {
94 void BrowserAccessibilityManager::Initialize(
95 const ui::AXTreeUpdate
& initial_tree
) {
96 if (!tree_
->Unserialize(initial_tree
)) {
98 LOG(ERROR
) << tree_
->error();
99 delegate_
->AccessibilityFatalError();
101 LOG(FATAL
) << tree_
->error();
106 SetFocus(tree_
->GetRoot(), false);
110 ui::AXTreeUpdate
BrowserAccessibilityManager::GetEmptyDocument() {
111 ui::AXNodeData empty_document
;
112 empty_document
.id
= 0;
113 empty_document
.role
= ui::AX_ROLE_ROOT_WEB_AREA
;
114 ui::AXTreeUpdate update
;
115 update
.nodes
.push_back(empty_document
);
119 BrowserAccessibility
* BrowserAccessibilityManager::GetRoot() {
120 return GetFromAXNode(tree_
->GetRoot());
123 BrowserAccessibility
* BrowserAccessibilityManager::GetFromAXNode(
125 return GetFromID(node
->id());
128 BrowserAccessibility
* BrowserAccessibilityManager::GetFromID(int32 id
) {
129 base::hash_map
<int32
, BrowserAccessibility
*>::iterator iter
=
130 id_wrapper_map_
.find(id
);
131 if (iter
!= id_wrapper_map_
.end())
136 void BrowserAccessibilityManager::OnWindowFocused() {
138 NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS
, GetFromAXNode(focus_
));
141 void BrowserAccessibilityManager::OnWindowBlurred() {
143 NotifyAccessibilityEvent(ui::AX_EVENT_BLUR
, GetFromAXNode(focus_
));
146 void BrowserAccessibilityManager::GotMouseDown() {
147 osk_state_
= OSK_ALLOWED_WITHIN_FOCUSED_OBJECT
;
148 NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS
, GetFromAXNode(focus_
));
151 bool BrowserAccessibilityManager::UseRootScrollOffsetsWhenComputingBounds() {
155 void BrowserAccessibilityManager::OnAccessibilityEvents(
156 const std::vector
<AccessibilityHostMsg_EventParams
>& params
) {
157 bool should_send_initial_focus
= false;
159 // Process all changes to the accessibility tree first.
160 for (uint32 index
= 0; index
< params
.size(); index
++) {
161 const AccessibilityHostMsg_EventParams
& param
= params
[index
];
162 if (!tree_
->Unserialize(param
.update
)) {
164 LOG(ERROR
) << tree_
->error();
165 delegate_
->AccessibilityFatalError();
167 CHECK(false) << tree_
->error();
172 // Set focus to the root if it's not anywhere else.
174 SetFocus(tree_
->GetRoot(), false);
175 should_send_initial_focus
= true;
179 OnTreeUpdateFinished();
181 if (should_send_initial_focus
&&
182 (!delegate_
|| delegate_
->AccessibilityViewHasFocus())) {
183 NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS
, GetFromAXNode(focus_
));
186 // Now iterate over the events again and fire the events.
187 for (uint32 index
= 0; index
< params
.size(); index
++) {
188 const AccessibilityHostMsg_EventParams
& param
= params
[index
];
190 // Find the node corresponding to the id that's the target of the
191 // event (which may not be the root of the update tree).
192 ui::AXNode
* node
= tree_
->GetFromId(param
.id
);
196 ui::AXEvent event_type
= param
.event_type
;
197 if (event_type
== ui::AX_EVENT_FOCUS
||
198 event_type
== ui::AX_EVENT_BLUR
) {
199 SetFocus(node
, false);
201 if (osk_state_
!= OSK_DISALLOWED_BECAUSE_TAB_HIDDEN
&&
202 osk_state_
!= OSK_DISALLOWED_BECAUSE_TAB_JUST_APPEARED
)
203 osk_state_
= OSK_ALLOWED
;
205 // Don't send a native focus event if the window itself doesn't
207 if (delegate_
&& !delegate_
->AccessibilityViewHasFocus())
211 // Send the event event to the operating system.
212 NotifyAccessibilityEvent(event_type
, GetFromAXNode(node
));
216 void BrowserAccessibilityManager::OnLocationChanges(
217 const std::vector
<AccessibilityHostMsg_LocationChangeParams
>& params
) {
218 for (size_t i
= 0; i
< params
.size(); ++i
) {
219 BrowserAccessibility
* obj
= GetFromID(params
[i
].id
);
222 ui::AXNode
* node
= obj
->node();
223 node
->SetLocation(params
[i
].new_location
);
224 obj
->OnLocationChanged();
228 BrowserAccessibility
* BrowserAccessibilityManager::GetActiveDescendantFocus(
229 BrowserAccessibility
* root
) {
230 BrowserAccessibility
* node
= BrowserAccessibilityManager::GetFocus(root
);
234 int active_descendant_id
;
235 if (node
->GetIntAttribute(ui::AX_ATTR_ACTIVEDESCENDANT_ID
,
236 &active_descendant_id
)) {
237 BrowserAccessibility
* active_descendant
=
238 node
->manager()->GetFromID(active_descendant_id
);
239 if (active_descendant
)
240 return active_descendant
;
245 BrowserAccessibility
* BrowserAccessibilityManager::GetFocus(
246 BrowserAccessibility
* root
) {
247 if (focus_
&& (!root
|| focus_
->IsDescendantOf(root
->node())))
248 return GetFromAXNode(focus_
);
253 void BrowserAccessibilityManager::SetFocus(ui::AXNode
* node
, bool notify
) {
257 if (notify
&& node
&& delegate_
)
258 delegate_
->AccessibilitySetFocus(node
->id());
261 void BrowserAccessibilityManager::SetFocus(
262 BrowserAccessibility
* obj
, bool notify
) {
264 SetFocus(obj
->node(), notify
);
267 void BrowserAccessibilityManager::DoDefaultAction(
268 const BrowserAccessibility
& node
) {
270 delegate_
->AccessibilityDoDefaultAction(node
.GetId());
273 void BrowserAccessibilityManager::ScrollToMakeVisible(
274 const BrowserAccessibility
& node
, gfx::Rect subfocus
) {
276 delegate_
->AccessibilityScrollToMakeVisible(node
.GetId(), subfocus
);
280 void BrowserAccessibilityManager::ScrollToPoint(
281 const BrowserAccessibility
& node
, gfx::Point point
) {
283 delegate_
->AccessibilityScrollToPoint(node
.GetId(), point
);
287 void BrowserAccessibilityManager::SetTextSelection(
288 const BrowserAccessibility
& node
, int start_offset
, int end_offset
) {
290 delegate_
->AccessibilitySetTextSelection(
291 node
.GetId(), start_offset
, end_offset
);
295 gfx::Rect
BrowserAccessibilityManager::GetViewBounds() {
297 return delegate_
->AccessibilityGetViewBounds();
301 BrowserAccessibility
* BrowserAccessibilityManager::NextInTreeOrder(
302 BrowserAccessibility
* node
) {
306 if (node
->PlatformChildCount() > 0)
307 return node
->PlatformGetChild(0);
309 if (node
->GetParent() &&
310 node
->GetIndexInParent() <
311 static_cast<int>(node
->GetParent()->PlatformChildCount()) - 1) {
312 return node
->GetParent()->PlatformGetChild(node
->GetIndexInParent() + 1);
314 node
= node
->GetParent();
320 BrowserAccessibility
* BrowserAccessibilityManager::PreviousInTreeOrder(
321 BrowserAccessibility
* node
) {
325 if (node
->GetParent() && node
->GetIndexInParent() > 0) {
326 node
= node
->GetParent()->PlatformGetChild(node
->GetIndexInParent() - 1);
327 while (node
->PlatformChildCount() > 0)
328 node
= node
->PlatformGetChild(node
->PlatformChildCount() - 1);
332 return node
->GetParent();
335 void BrowserAccessibilityManager::OnNodeWillBeDeleted(ui::AXNode
* node
) {
336 if (node
== focus_
&& tree_
) {
337 if (node
!= tree_
->GetRoot())
338 SetFocus(tree_
->GetRoot(), false);
342 if (id_wrapper_map_
.find(node
->id()) == id_wrapper_map_
.end())
344 GetFromAXNode(node
)->Destroy();
345 id_wrapper_map_
.erase(node
->id());
348 void BrowserAccessibilityManager::OnNodeCreated(ui::AXNode
* node
) {
349 BrowserAccessibility
* wrapper
= factory_
->Create();
350 wrapper
->Init(this, node
);
351 id_wrapper_map_
[node
->id()] = wrapper
;
352 wrapper
->OnDataChanged();
355 void BrowserAccessibilityManager::OnNodeChanged(ui::AXNode
* node
) {
356 GetFromAXNode(node
)->OnDataChanged();
359 void BrowserAccessibilityManager::OnNodeCreationFinished(ui::AXNode
* node
) {
360 GetFromAXNode(node
)->OnUpdateFinished();
363 void BrowserAccessibilityManager::OnNodeChangeFinished(ui::AXNode
* node
) {
364 GetFromAXNode(node
)->OnUpdateFinished();
367 ui::AXTreeUpdate
BrowserAccessibilityManager::SnapshotAXTreeForTesting() {
368 scoped_ptr
<ui::AXTreeSource
<const ui::AXNode
*> > tree_source(
369 tree_
->CreateTreeSource());
370 ui::AXTreeSerializer
<const ui::AXNode
*> serializer(tree_source
.get());
371 ui::AXTreeUpdate update
;
372 serializer
.SerializeChanges(tree_
->GetRoot(), &update
);
376 } // namespace content