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 ui::AXTreeUpdate
MakeAXTreeUpdate(
14 const ui::AXNodeData
& node1
,
15 const ui::AXNodeData
& node2
/* = ui::AXNodeData() */,
16 const ui::AXNodeData
& node3
/* = ui::AXNodeData() */,
17 const ui::AXNodeData
& node4
/* = ui::AXNodeData() */,
18 const ui::AXNodeData
& node5
/* = ui::AXNodeData() */,
19 const ui::AXNodeData
& node6
/* = ui::AXNodeData() */,
20 const ui::AXNodeData
& node7
/* = ui::AXNodeData() */,
21 const ui::AXNodeData
& node8
/* = ui::AXNodeData() */,
22 const ui::AXNodeData
& node9
/* = ui::AXNodeData() */) {
23 CR_DEFINE_STATIC_LOCAL(ui::AXNodeData
, empty_data
, ());
24 int32 no_id
= empty_data
.id
;
26 ui::AXTreeUpdate update
;
27 update
.nodes
.push_back(node1
);
28 if (node2
.id
!= no_id
)
29 update
.nodes
.push_back(node2
);
30 if (node3
.id
!= no_id
)
31 update
.nodes
.push_back(node3
);
32 if (node4
.id
!= no_id
)
33 update
.nodes
.push_back(node4
);
34 if (node5
.id
!= no_id
)
35 update
.nodes
.push_back(node5
);
36 if (node6
.id
!= no_id
)
37 update
.nodes
.push_back(node6
);
38 if (node7
.id
!= no_id
)
39 update
.nodes
.push_back(node7
);
40 if (node8
.id
!= no_id
)
41 update
.nodes
.push_back(node8
);
42 if (node9
.id
!= no_id
)
43 update
.nodes
.push_back(node9
);
47 BrowserAccessibility
* BrowserAccessibilityFactory::Create() {
48 return BrowserAccessibility::Create();
51 #if !defined(OS_MACOSX) && \
53 !defined(OS_ANDROID) \
54 // We have subclassess of BrowserAccessibilityManager on Mac, and Win. For any
55 // other platform, instantiate the base class.
57 BrowserAccessibilityManager
* BrowserAccessibilityManager::Create(
58 const ui::AXTreeUpdate
& initial_tree
,
59 BrowserAccessibilityDelegate
* delegate
,
60 BrowserAccessibilityFactory
* factory
) {
61 return new BrowserAccessibilityManager(initial_tree
, delegate
, factory
);
65 BrowserAccessibilityManager::BrowserAccessibilityManager(
66 BrowserAccessibilityDelegate
* delegate
,
67 BrowserAccessibilityFactory
* factory
)
68 : delegate_(delegate
),
70 tree_(new ui::AXTree()),
72 osk_state_(OSK_ALLOWED
) {
73 tree_
->SetDelegate(this);
76 BrowserAccessibilityManager::BrowserAccessibilityManager(
77 const ui::AXTreeUpdate
& initial_tree
,
78 BrowserAccessibilityDelegate
* delegate
,
79 BrowserAccessibilityFactory
* factory
)
80 : delegate_(delegate
),
82 tree_(new ui::AXTree()),
84 osk_state_(OSK_ALLOWED
) {
85 tree_
->SetDelegate(this);
86 Initialize(initial_tree
);
89 BrowserAccessibilityManager::~BrowserAccessibilityManager() {
93 void BrowserAccessibilityManager::Initialize(
94 const ui::AXTreeUpdate
& initial_tree
) {
95 if (!tree_
->Unserialize(initial_tree
)) {
97 LOG(ERROR
) << tree_
->error();
98 delegate_
->AccessibilityFatalError();
100 LOG(FATAL
) << tree_
->error();
105 SetFocus(tree_
->GetRoot(), false);
109 ui::AXTreeUpdate
BrowserAccessibilityManager::GetEmptyDocument() {
110 ui::AXNodeData empty_document
;
111 empty_document
.id
= 0;
112 empty_document
.role
= ui::AX_ROLE_ROOT_WEB_AREA
;
113 ui::AXTreeUpdate update
;
114 update
.nodes
.push_back(empty_document
);
118 BrowserAccessibility
* BrowserAccessibilityManager::GetRoot() {
119 return GetFromAXNode(tree_
->GetRoot());
122 BrowserAccessibility
* BrowserAccessibilityManager::GetFromAXNode(
124 return GetFromID(node
->id());
127 BrowserAccessibility
* BrowserAccessibilityManager::GetFromID(int32 id
) {
128 base::hash_map
<int32
, BrowserAccessibility
*>::iterator iter
=
129 id_wrapper_map_
.find(id
);
130 if (iter
!= id_wrapper_map_
.end())
135 void BrowserAccessibilityManager::OnWindowFocused() {
137 NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS
, GetFromAXNode(focus_
));
140 void BrowserAccessibilityManager::OnWindowBlurred() {
142 NotifyAccessibilityEvent(ui::AX_EVENT_BLUR
, GetFromAXNode(focus_
));
145 void BrowserAccessibilityManager::GotMouseDown() {
146 osk_state_
= OSK_ALLOWED_WITHIN_FOCUSED_OBJECT
;
147 NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS
, GetFromAXNode(focus_
));
150 bool BrowserAccessibilityManager::UseRootScrollOffsetsWhenComputingBounds() {
154 void BrowserAccessibilityManager::OnAccessibilityEvents(
155 const std::vector
<AccessibilityHostMsg_EventParams
>& params
) {
156 bool should_send_initial_focus
= false;
158 // Process all changes to the accessibility tree first.
159 for (uint32 index
= 0; index
< params
.size(); index
++) {
160 const AccessibilityHostMsg_EventParams
& param
= params
[index
];
161 if (!tree_
->Unserialize(param
.update
)) {
163 LOG(ERROR
) << tree_
->error();
164 delegate_
->AccessibilityFatalError();
166 CHECK(false) << tree_
->error();
171 // Set focus to the root if it's not anywhere else.
173 SetFocus(tree_
->GetRoot(), false);
174 should_send_initial_focus
= true;
178 OnTreeUpdateFinished();
180 if (should_send_initial_focus
&&
181 (!delegate_
|| delegate_
->AccessibilityViewHasFocus())) {
182 NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS
, GetFromAXNode(focus_
));
185 // Now iterate over the events again and fire the events.
186 for (uint32 index
= 0; index
< params
.size(); index
++) {
187 const AccessibilityHostMsg_EventParams
& param
= params
[index
];
189 // Find the node corresponding to the id that's the target of the
190 // event (which may not be the root of the update tree).
191 ui::AXNode
* node
= tree_
->GetFromId(param
.id
);
195 ui::AXEvent event_type
= param
.event_type
;
196 if (event_type
== ui::AX_EVENT_FOCUS
||
197 event_type
== ui::AX_EVENT_BLUR
) {
198 SetFocus(node
, false);
200 if (osk_state_
!= OSK_DISALLOWED_BECAUSE_TAB_HIDDEN
&&
201 osk_state_
!= OSK_DISALLOWED_BECAUSE_TAB_JUST_APPEARED
)
202 osk_state_
= OSK_ALLOWED
;
204 // Don't send a native focus event if the window itself doesn't
206 if (delegate_
&& !delegate_
->AccessibilityViewHasFocus())
210 // Send the event event to the operating system.
211 NotifyAccessibilityEvent(event_type
, GetFromAXNode(node
));
215 void BrowserAccessibilityManager::OnLocationChanges(
216 const std::vector
<AccessibilityHostMsg_LocationChangeParams
>& params
) {
217 for (size_t i
= 0; i
< params
.size(); ++i
) {
218 BrowserAccessibility
* obj
= GetFromID(params
[i
].id
);
221 ui::AXNode
* node
= obj
->node();
222 node
->SetLocation(params
[i
].new_location
);
223 obj
->OnLocationChanged();
227 BrowserAccessibility
* BrowserAccessibilityManager::GetActiveDescendantFocus(
228 BrowserAccessibility
* root
) {
229 BrowserAccessibility
* node
= BrowserAccessibilityManager::GetFocus(root
);
233 int active_descendant_id
;
234 if (node
->GetIntAttribute(ui::AX_ATTR_ACTIVEDESCENDANT_ID
,
235 &active_descendant_id
)) {
236 BrowserAccessibility
* active_descendant
=
237 node
->manager()->GetFromID(active_descendant_id
);
238 if (active_descendant
)
239 return active_descendant
;
244 BrowserAccessibility
* BrowserAccessibilityManager::GetFocus(
245 BrowserAccessibility
* root
) {
246 if (focus_
&& (!root
|| focus_
->IsDescendantOf(root
->node())))
247 return GetFromAXNode(focus_
);
252 void BrowserAccessibilityManager::SetFocus(ui::AXNode
* node
, bool notify
) {
256 if (notify
&& node
&& delegate_
)
257 delegate_
->AccessibilitySetFocus(node
->id());
260 void BrowserAccessibilityManager::SetFocus(
261 BrowserAccessibility
* obj
, bool notify
) {
263 SetFocus(obj
->node(), notify
);
266 void BrowserAccessibilityManager::DoDefaultAction(
267 const BrowserAccessibility
& node
) {
269 delegate_
->AccessibilityDoDefaultAction(node
.GetId());
272 void BrowserAccessibilityManager::ScrollToMakeVisible(
273 const BrowserAccessibility
& node
, gfx::Rect subfocus
) {
275 delegate_
->AccessibilityScrollToMakeVisible(node
.GetId(), subfocus
);
279 void BrowserAccessibilityManager::ScrollToPoint(
280 const BrowserAccessibility
& node
, gfx::Point point
) {
282 delegate_
->AccessibilityScrollToPoint(node
.GetId(), point
);
286 void BrowserAccessibilityManager::SetTextSelection(
287 const BrowserAccessibility
& node
, int start_offset
, int end_offset
) {
289 delegate_
->AccessibilitySetTextSelection(
290 node
.GetId(), start_offset
, end_offset
);
294 gfx::Rect
BrowserAccessibilityManager::GetViewBounds() {
296 return delegate_
->AccessibilityGetViewBounds();
300 BrowserAccessibility
* BrowserAccessibilityManager::NextInTreeOrder(
301 BrowserAccessibility
* node
) {
305 if (node
->PlatformChildCount() > 0)
306 return node
->PlatformGetChild(0);
308 if (node
->GetParent() &&
309 node
->GetIndexInParent() <
310 static_cast<int>(node
->GetParent()->PlatformChildCount()) - 1) {
311 return node
->GetParent()->PlatformGetChild(node
->GetIndexInParent() + 1);
313 node
= node
->GetParent();
319 BrowserAccessibility
* BrowserAccessibilityManager::PreviousInTreeOrder(
320 BrowserAccessibility
* node
) {
324 if (node
->GetParent() && node
->GetIndexInParent() > 0) {
325 node
= node
->GetParent()->PlatformGetChild(node
->GetIndexInParent() - 1);
326 while (node
->PlatformChildCount() > 0)
327 node
= node
->PlatformGetChild(node
->PlatformChildCount() - 1);
331 return node
->GetParent();
334 void BrowserAccessibilityManager::OnNodeWillBeDeleted(ui::AXNode
* node
) {
335 if (node
== focus_
&& tree_
) {
336 if (node
!= tree_
->GetRoot())
337 SetFocus(tree_
->GetRoot(), false);
341 if (id_wrapper_map_
.find(node
->id()) == id_wrapper_map_
.end())
343 GetFromAXNode(node
)->Destroy();
344 id_wrapper_map_
.erase(node
->id());
347 void BrowserAccessibilityManager::OnNodeCreated(ui::AXNode
* node
) {
348 BrowserAccessibility
* wrapper
= factory_
->Create();
349 wrapper
->Init(this, node
);
350 id_wrapper_map_
[node
->id()] = wrapper
;
351 wrapper
->OnDataChanged();
354 void BrowserAccessibilityManager::OnNodeChanged(ui::AXNode
* node
) {
355 GetFromAXNode(node
)->OnDataChanged();
358 void BrowserAccessibilityManager::OnNodeCreationFinished(ui::AXNode
* node
) {
359 GetFromAXNode(node
)->OnUpdateFinished();
362 void BrowserAccessibilityManager::OnNodeChangeFinished(ui::AXNode
* node
) {
363 GetFromAXNode(node
)->OnUpdateFinished();
366 } // namespace content