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_
->FatalAccessibilityTreeError();
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::IsOSKAllowed(const gfx::Rect
& bounds
) {
151 if (!delegate_
|| !delegate_
->HasFocus())
154 gfx::Point touch_point
= delegate_
->GetLastTouchEventLocation();
155 return bounds
.Contains(touch_point
);
158 bool BrowserAccessibilityManager::UseRootScrollOffsetsWhenComputingBounds() {
162 void BrowserAccessibilityManager::OnAccessibilityEvents(
163 const std::vector
<AccessibilityHostMsg_EventParams
>& params
) {
164 bool should_send_initial_focus
= false;
166 // Process all changes to the accessibility tree first.
167 for (uint32 index
= 0; index
< params
.size(); index
++) {
168 const AccessibilityHostMsg_EventParams
& param
= params
[index
];
169 if (!tree_
->Unserialize(param
.update
)) {
171 LOG(ERROR
) << tree_
->error();
172 delegate_
->FatalAccessibilityTreeError();
174 CHECK(false) << tree_
->error();
179 // Set focus to the root if it's not anywhere else.
181 SetFocus(tree_
->GetRoot(), false);
182 should_send_initial_focus
= true;
186 if (should_send_initial_focus
&&
187 (!delegate_
|| delegate_
->HasFocus())) {
188 NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS
, GetFromAXNode(focus_
));
191 // Now iterate over the events again and fire the events.
192 for (uint32 index
= 0; index
< params
.size(); index
++) {
193 const AccessibilityHostMsg_EventParams
& param
= params
[index
];
195 // Find the node corresponding to the id that's the target of the
196 // event (which may not be the root of the update tree).
197 ui::AXNode
* node
= tree_
->GetFromId(param
.id
);
201 ui::AXEvent event_type
= param
.event_type
;
202 if (event_type
== ui::AX_EVENT_FOCUS
||
203 event_type
== ui::AX_EVENT_BLUR
) {
204 SetFocus(node
, false);
206 if (osk_state_
!= OSK_DISALLOWED_BECAUSE_TAB_HIDDEN
&&
207 osk_state_
!= OSK_DISALLOWED_BECAUSE_TAB_JUST_APPEARED
)
208 osk_state_
= OSK_ALLOWED
;
210 // Don't send a native focus event if the window itself doesn't
212 if (delegate_
&& !delegate_
->HasFocus())
216 // Send the event event to the operating system.
217 NotifyAccessibilityEvent(event_type
, GetFromAXNode(node
));
221 void BrowserAccessibilityManager::OnLocationChanges(
222 const std::vector
<AccessibilityHostMsg_LocationChangeParams
>& params
) {
223 for (size_t i
= 0; i
< params
.size(); ++i
) {
224 BrowserAccessibility
* obj
= GetFromID(params
[i
].id
);
227 ui::AXNode
* node
= obj
->node();
228 node
->SetLocation(params
[i
].new_location
);
229 obj
->OnLocationChanged();
233 BrowserAccessibility
* BrowserAccessibilityManager::GetFocus(
234 BrowserAccessibility
* root
) {
235 if (focus_
&& (!root
|| focus_
->IsDescendantOf(root
->node())))
236 return GetFromAXNode(focus_
);
241 void BrowserAccessibilityManager::SetFocus(ui::AXNode
* node
, bool notify
) {
245 if (notify
&& node
&& delegate_
)
246 delegate_
->SetAccessibilityFocus(node
->id());
249 void BrowserAccessibilityManager::SetFocus(
250 BrowserAccessibility
* obj
, bool notify
) {
252 SetFocus(obj
->node(), notify
);
255 void BrowserAccessibilityManager::DoDefaultAction(
256 const BrowserAccessibility
& node
) {
258 delegate_
->AccessibilityDoDefaultAction(node
.GetId());
261 void BrowserAccessibilityManager::ScrollToMakeVisible(
262 const BrowserAccessibility
& node
, gfx::Rect subfocus
) {
264 delegate_
->AccessibilityScrollToMakeVisible(node
.GetId(), subfocus
);
268 void BrowserAccessibilityManager::ScrollToPoint(
269 const BrowserAccessibility
& node
, gfx::Point point
) {
271 delegate_
->AccessibilityScrollToPoint(node
.GetId(), point
);
275 void BrowserAccessibilityManager::SetTextSelection(
276 const BrowserAccessibility
& node
, int start_offset
, int end_offset
) {
278 delegate_
->AccessibilitySetTextSelection(
279 node
.GetId(), start_offset
, end_offset
);
283 gfx::Rect
BrowserAccessibilityManager::GetViewBounds() {
285 return delegate_
->GetViewBounds();
289 BrowserAccessibility
* BrowserAccessibilityManager::NextInTreeOrder(
290 BrowserAccessibility
* node
) {
294 if (node
->PlatformChildCount() > 0)
295 return node
->PlatformGetChild(0);
297 if (node
->GetParent() &&
298 node
->GetIndexInParent() <
299 static_cast<int>(node
->GetParent()->PlatformChildCount()) - 1) {
300 return node
->GetParent()->PlatformGetChild(node
->GetIndexInParent() + 1);
302 node
= node
->GetParent();
308 BrowserAccessibility
* BrowserAccessibilityManager::PreviousInTreeOrder(
309 BrowserAccessibility
* node
) {
313 if (node
->GetParent() && node
->GetIndexInParent() > 0) {
314 node
= node
->GetParent()->PlatformGetChild(node
->GetIndexInParent() - 1);
315 while (node
->PlatformChildCount() > 0)
316 node
= node
->PlatformGetChild(node
->PlatformChildCount() - 1);
320 return node
->GetParent();
323 void BrowserAccessibilityManager::OnNodeWillBeDeleted(ui::AXNode
* node
) {
324 if (node
== focus_
&& tree_
) {
325 if (node
!= tree_
->GetRoot())
326 SetFocus(tree_
->GetRoot(), false);
330 if (id_wrapper_map_
.find(node
->id()) == id_wrapper_map_
.end())
332 GetFromAXNode(node
)->Destroy();
333 id_wrapper_map_
.erase(node
->id());
336 void BrowserAccessibilityManager::OnNodeCreated(ui::AXNode
* node
) {
337 BrowserAccessibility
* wrapper
= factory_
->Create();
338 wrapper
->Init(this, node
);
339 id_wrapper_map_
[node
->id()] = wrapper
;
340 wrapper
->OnDataChanged();
343 void BrowserAccessibilityManager::OnNodeChanged(ui::AXNode
* node
) {
344 GetFromAXNode(node
)->OnDataChanged();
347 void BrowserAccessibilityManager::OnNodeCreationFinished(ui::AXNode
* node
) {
348 GetFromAXNode(node
)->OnUpdateFinished();
351 void BrowserAccessibilityManager::OnNodeChangeFinished(ui::AXNode
* node
) {
352 GetFromAXNode(node
)->OnUpdateFinished();
355 } // namespace content