cc: Make picture pile base thread safe.
[chromium-blink-merge.git] / content / browser / accessibility / browser_accessibility_manager.cc
blobbd745cd12fe49baa667bb0591b29c9bb2300b778
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"
12 namespace content {
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);
45 return update;
48 BrowserAccessibility* BrowserAccessibilityFactory::Create() {
49 return BrowserAccessibility::Create();
52 #if !defined(OS_MACOSX) && \
53 !defined(OS_WIN) && \
54 !defined(OS_ANDROID) \
55 // We have subclassess of BrowserAccessibilityManager on Mac, and Win. For any
56 // other platform, instantiate the base class.
57 // static
58 BrowserAccessibilityManager* BrowserAccessibilityManager::Create(
59 const ui::AXTreeUpdate& initial_tree,
60 BrowserAccessibilityDelegate* delegate,
61 BrowserAccessibilityFactory* factory) {
62 return new BrowserAccessibilityManager(initial_tree, delegate, factory);
64 #endif
66 BrowserAccessibilityManager::BrowserAccessibilityManager(
67 BrowserAccessibilityDelegate* delegate,
68 BrowserAccessibilityFactory* factory)
69 : delegate_(delegate),
70 factory_(factory),
71 tree_(new ui::AXSerializableTree()),
72 focus_(NULL),
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),
82 factory_(factory),
83 tree_(new ui::AXSerializableTree()),
84 focus_(NULL),
85 osk_state_(OSK_ALLOWED) {
86 tree_->SetDelegate(this);
87 Initialize(initial_tree);
90 BrowserAccessibilityManager::~BrowserAccessibilityManager() {
91 tree_.reset(NULL);
94 void BrowserAccessibilityManager::Initialize(
95 const ui::AXTreeUpdate& initial_tree) {
96 if (!tree_->Unserialize(initial_tree)) {
97 if (delegate_) {
98 LOG(ERROR) << tree_->error();
99 delegate_->AccessibilityFatalError();
100 } else {
101 LOG(FATAL) << tree_->error();
105 if (!focus_)
106 SetFocus(tree_->GetRoot(), false);
109 // static
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);
116 return update;
119 BrowserAccessibility* BrowserAccessibilityManager::GetRoot() {
120 return GetFromAXNode(tree_->GetRoot());
123 BrowserAccessibility* BrowserAccessibilityManager::GetFromAXNode(
124 ui::AXNode* node) {
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())
132 return iter->second;
133 return NULL;
136 void BrowserAccessibilityManager::OnWindowFocused() {
137 if (focus_)
138 NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, GetFromAXNode(focus_));
141 void BrowserAccessibilityManager::OnWindowBlurred() {
142 if (focus_)
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() {
152 return true;
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)) {
163 if (delegate_) {
164 LOG(ERROR) << tree_->error();
165 delegate_->AccessibilityFatalError();
166 } else {
167 CHECK(false) << tree_->error();
169 return;
172 // Set focus to the root if it's not anywhere else.
173 if (!focus_) {
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);
193 if (!node)
194 continue;
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
206 // have focus.
207 if (delegate_ && !delegate_->AccessibilityViewHasFocus())
208 continue;
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);
220 if (!obj)
221 continue;
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);
231 if (!node)
232 return NULL;
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;
242 return node;
245 BrowserAccessibility* BrowserAccessibilityManager::GetFocus(
246 BrowserAccessibility* root) {
247 if (focus_ && (!root || focus_->IsDescendantOf(root->node())))
248 return GetFromAXNode(focus_);
250 return NULL;
253 void BrowserAccessibilityManager::SetFocus(ui::AXNode* node, bool notify) {
254 if (focus_ != node)
255 focus_ = node;
257 if (notify && node && delegate_)
258 delegate_->AccessibilitySetFocus(node->id());
261 void BrowserAccessibilityManager::SetFocus(
262 BrowserAccessibility* obj, bool notify) {
263 if (obj->node())
264 SetFocus(obj->node(), notify);
267 void BrowserAccessibilityManager::DoDefaultAction(
268 const BrowserAccessibility& node) {
269 if (delegate_)
270 delegate_->AccessibilityDoDefaultAction(node.GetId());
273 void BrowserAccessibilityManager::ScrollToMakeVisible(
274 const BrowserAccessibility& node, gfx::Rect subfocus) {
275 if (delegate_) {
276 delegate_->AccessibilityScrollToMakeVisible(node.GetId(), subfocus);
280 void BrowserAccessibilityManager::ScrollToPoint(
281 const BrowserAccessibility& node, gfx::Point point) {
282 if (delegate_) {
283 delegate_->AccessibilityScrollToPoint(node.GetId(), point);
287 void BrowserAccessibilityManager::SetTextSelection(
288 const BrowserAccessibility& node, int start_offset, int end_offset) {
289 if (delegate_) {
290 delegate_->AccessibilitySetTextSelection(
291 node.GetId(), start_offset, end_offset);
295 gfx::Rect BrowserAccessibilityManager::GetViewBounds() {
296 if (delegate_)
297 return delegate_->AccessibilityGetViewBounds();
298 return gfx::Rect();
301 BrowserAccessibility* BrowserAccessibilityManager::NextInTreeOrder(
302 BrowserAccessibility* node) {
303 if (!node)
304 return NULL;
306 if (node->PlatformChildCount() > 0)
307 return node->PlatformGetChild(0);
308 while (node) {
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();
317 return NULL;
320 BrowserAccessibility* BrowserAccessibilityManager::PreviousInTreeOrder(
321 BrowserAccessibility* node) {
322 if (!node)
323 return NULL;
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);
329 return node;
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);
339 else
340 focus_ = NULL;
342 if (id_wrapper_map_.find(node->id()) == id_wrapper_map_.end())
343 return;
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);
373 return update;
376 } // namespace content