Supervised user whitelists: Cleanup
[chromium-blink-merge.git] / content / browser / accessibility / browser_accessibility_manager.cc
blob9fe18ca30c34c4375e4aecb675711716f7f21a0b
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 BrowserAccessibilityFindInPageInfo::BrowserAccessibilityFindInPageInfo()
53 : request_id(-1),
54 match_index(-1),
55 start_id(-1),
56 start_offset(0),
57 end_id(-1),
58 end_offset(-1),
59 active_request_id(-1) {}
61 #if !defined(OS_MACOSX) && \
62 !defined(OS_WIN) && \
63 !defined(OS_ANDROID) \
64 // We have subclassess of BrowserAccessibilityManager on Mac, and Win. For any
65 // other platform, instantiate the base class.
66 // static
67 BrowserAccessibilityManager* BrowserAccessibilityManager::Create(
68 const ui::AXTreeUpdate& initial_tree,
69 BrowserAccessibilityDelegate* delegate,
70 BrowserAccessibilityFactory* factory) {
71 return new BrowserAccessibilityManager(initial_tree, delegate, factory);
73 #endif
75 BrowserAccessibilityManager::BrowserAccessibilityManager(
76 BrowserAccessibilityDelegate* delegate,
77 BrowserAccessibilityFactory* factory)
78 : delegate_(delegate),
79 factory_(factory),
80 tree_(new ui::AXSerializableTree()),
81 focus_(NULL),
82 user_is_navigating_away_(false),
83 osk_state_(OSK_ALLOWED) {
84 tree_->SetDelegate(this);
87 BrowserAccessibilityManager::BrowserAccessibilityManager(
88 const ui::AXTreeUpdate& initial_tree,
89 BrowserAccessibilityDelegate* delegate,
90 BrowserAccessibilityFactory* factory)
91 : delegate_(delegate),
92 factory_(factory),
93 tree_(new ui::AXSerializableTree()),
94 focus_(NULL),
95 user_is_navigating_away_(false),
96 osk_state_(OSK_ALLOWED) {
97 tree_->SetDelegate(this);
98 Initialize(initial_tree);
101 BrowserAccessibilityManager::~BrowserAccessibilityManager() {
102 tree_.reset(NULL);
105 void BrowserAccessibilityManager::Initialize(
106 const ui::AXTreeUpdate& initial_tree) {
107 if (!tree_->Unserialize(initial_tree)) {
108 if (delegate_) {
109 LOG(ERROR) << tree_->error();
110 delegate_->AccessibilityFatalError();
111 } else {
112 LOG(FATAL) << tree_->error();
116 if (!focus_)
117 SetFocus(tree_->root(), false);
120 // static
121 ui::AXTreeUpdate BrowserAccessibilityManager::GetEmptyDocument() {
122 ui::AXNodeData empty_document;
123 empty_document.id = 0;
124 empty_document.role = ui::AX_ROLE_ROOT_WEB_AREA;
125 ui::AXTreeUpdate update;
126 update.nodes.push_back(empty_document);
127 return update;
130 BrowserAccessibility* BrowserAccessibilityManager::GetRoot() {
131 return GetFromAXNode(tree_->root());
134 BrowserAccessibility* BrowserAccessibilityManager::GetFromAXNode(
135 ui::AXNode* node) {
136 return GetFromID(node->id());
139 BrowserAccessibility* BrowserAccessibilityManager::GetFromID(int32 id) {
140 base::hash_map<int32, BrowserAccessibility*>::iterator iter =
141 id_wrapper_map_.find(id);
142 if (iter != id_wrapper_map_.end())
143 return iter->second;
144 return NULL;
147 void BrowserAccessibilityManager::OnWindowFocused() {
148 if (focus_)
149 NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, GetFromAXNode(focus_));
152 void BrowserAccessibilityManager::OnWindowBlurred() {
153 if (focus_)
154 NotifyAccessibilityEvent(ui::AX_EVENT_BLUR, GetFromAXNode(focus_));
157 void BrowserAccessibilityManager::UserIsNavigatingAway() {
158 user_is_navigating_away_ = true;
161 void BrowserAccessibilityManager::UserIsReloading() {
162 user_is_navigating_away_ = true;
165 void BrowserAccessibilityManager::NavigationSucceeded() {
166 user_is_navigating_away_ = false;
169 void BrowserAccessibilityManager::NavigationFailed() {
170 user_is_navigating_away_ = false;
173 void BrowserAccessibilityManager::GotMouseDown() {
174 osk_state_ = OSK_ALLOWED_WITHIN_FOCUSED_OBJECT;
175 NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, GetFromAXNode(focus_));
178 bool BrowserAccessibilityManager::UseRootScrollOffsetsWhenComputingBounds() {
179 return true;
182 void BrowserAccessibilityManager::OnAccessibilityEvents(
183 const std::vector<AccessibilityHostMsg_EventParams>& params) {
184 bool should_send_initial_focus = false;
186 // Process all changes to the accessibility tree first.
187 for (uint32 index = 0; index < params.size(); index++) {
188 const AccessibilityHostMsg_EventParams& param = params[index];
189 if (!tree_->Unserialize(param.update)) {
190 if (delegate_) {
191 LOG(ERROR) << tree_->error();
192 delegate_->AccessibilityFatalError();
193 } else {
194 CHECK(false) << tree_->error();
196 return;
199 // Set focus to the root if it's not anywhere else.
200 if (!focus_) {
201 SetFocus(tree_->root(), false);
202 should_send_initial_focus = true;
206 if (should_send_initial_focus &&
207 (!delegate_ || delegate_->AccessibilityViewHasFocus())) {
208 NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, GetFromAXNode(focus_));
211 // Now iterate over the events again and fire the events.
212 for (uint32 index = 0; index < params.size(); index++) {
213 const AccessibilityHostMsg_EventParams& param = params[index];
215 // Find the node corresponding to the id that's the target of the
216 // event (which may not be the root of the update tree).
217 ui::AXNode* node = tree_->GetFromId(param.id);
218 if (!node)
219 continue;
221 ui::AXEvent event_type = param.event_type;
222 if (event_type == ui::AX_EVENT_FOCUS ||
223 event_type == ui::AX_EVENT_BLUR) {
224 SetFocus(node, false);
226 if (osk_state_ != OSK_DISALLOWED_BECAUSE_TAB_HIDDEN &&
227 osk_state_ != OSK_DISALLOWED_BECAUSE_TAB_JUST_APPEARED)
228 osk_state_ = OSK_ALLOWED;
230 // Don't send a native focus event if the window itself doesn't
231 // have focus.
232 if (delegate_ && !delegate_->AccessibilityViewHasFocus())
233 continue;
236 // Send the event event to the operating system.
237 NotifyAccessibilityEvent(event_type, GetFromAXNode(node));
241 void BrowserAccessibilityManager::OnLocationChanges(
242 const std::vector<AccessibilityHostMsg_LocationChangeParams>& params) {
243 for (size_t i = 0; i < params.size(); ++i) {
244 BrowserAccessibility* obj = GetFromID(params[i].id);
245 if (!obj)
246 continue;
247 ui::AXNode* node = obj->node();
248 node->SetLocation(params[i].new_location);
249 obj->OnLocationChanged();
253 void BrowserAccessibilityManager::OnFindInPageResult(
254 int request_id, int match_index, int start_id, int start_offset,
255 int end_id, int end_offset) {
256 find_in_page_info_.request_id = request_id;
257 find_in_page_info_.match_index = match_index;
258 find_in_page_info_.start_id = start_id;
259 find_in_page_info_.start_offset = start_offset;
260 find_in_page_info_.end_id = end_id;
261 find_in_page_info_.end_offset = end_offset;
263 if (find_in_page_info_.active_request_id == request_id)
264 ActivateFindInPageResult(request_id);
267 void BrowserAccessibilityManager::ActivateFindInPageResult(
268 int request_id) {
269 find_in_page_info_.active_request_id = request_id;
270 if (find_in_page_info_.request_id != request_id)
271 return;
273 BrowserAccessibility* node = GetFromID(find_in_page_info_.start_id);
274 if (!node)
275 return;
277 // If an ancestor of this node is a leaf node, fire the notification on that.
278 BrowserAccessibility* ancestor = node->GetParent();
279 while (ancestor && ancestor != GetRoot()) {
280 if (ancestor->PlatformIsLeaf())
281 node = ancestor;
282 ancestor = ancestor->GetParent();
285 // The "scrolled to anchor" notification is a great way to get a
286 // screen reader to jump directly to a specific location in a document.
287 NotifyAccessibilityEvent(ui::AX_EVENT_SCROLLED_TO_ANCHOR, node);
290 BrowserAccessibility* BrowserAccessibilityManager::GetActiveDescendantFocus(
291 BrowserAccessibility* root) {
292 BrowserAccessibility* node = BrowserAccessibilityManager::GetFocus(root);
293 if (!node)
294 return NULL;
296 int active_descendant_id;
297 if (node->GetIntAttribute(ui::AX_ATTR_ACTIVEDESCENDANT_ID,
298 &active_descendant_id)) {
299 BrowserAccessibility* active_descendant =
300 node->manager()->GetFromID(active_descendant_id);
301 if (active_descendant)
302 return active_descendant;
304 return node;
307 BrowserAccessibility* BrowserAccessibilityManager::GetFocus(
308 BrowserAccessibility* root) {
309 if (!focus_)
310 return NULL;
312 if (root && !focus_->IsDescendantOf(root->node()))
313 return NULL;
315 BrowserAccessibility* obj = GetFromAXNode(focus_);
316 if (delegate() && obj->HasBoolAttribute(ui::AX_ATTR_IS_AX_TREE_HOST)) {
317 BrowserAccessibilityManager* child_manager =
318 delegate()->AccessibilityGetChildFrame(obj->GetId());
319 if (child_manager)
320 return child_manager->GetFocus(child_manager->GetRoot());
323 return obj;
326 void BrowserAccessibilityManager::SetFocus(ui::AXNode* node, bool notify) {
327 if (focus_ != node)
328 focus_ = node;
330 if (notify && node && delegate_)
331 delegate_->AccessibilitySetFocus(node->id());
334 void BrowserAccessibilityManager::SetFocus(
335 BrowserAccessibility* obj, bool notify) {
336 if (obj->node())
337 SetFocus(obj->node(), notify);
340 void BrowserAccessibilityManager::DoDefaultAction(
341 const BrowserAccessibility& node) {
342 if (delegate_)
343 delegate_->AccessibilityDoDefaultAction(node.GetId());
346 void BrowserAccessibilityManager::ScrollToMakeVisible(
347 const BrowserAccessibility& node, gfx::Rect subfocus) {
348 if (delegate_) {
349 delegate_->AccessibilityScrollToMakeVisible(node.GetId(), subfocus);
353 void BrowserAccessibilityManager::ScrollToPoint(
354 const BrowserAccessibility& node, gfx::Point point) {
355 if (delegate_) {
356 delegate_->AccessibilityScrollToPoint(node.GetId(), point);
360 void BrowserAccessibilityManager::SetValue(
361 const BrowserAccessibility& node,
362 const base::string16& value) {
363 if (delegate_)
364 delegate_->AccessibilitySetValue(node.GetId(), value);
367 void BrowserAccessibilityManager::SetTextSelection(
368 const BrowserAccessibility& node,
369 int start_offset,
370 int end_offset) {
371 if (delegate_) {
372 delegate_->AccessibilitySetTextSelection(
373 node.GetId(), start_offset, end_offset);
377 gfx::Rect BrowserAccessibilityManager::GetViewBounds() {
378 BrowserAccessibilityDelegate* delegate = GetDelegateFromRootManager();
379 if (delegate)
380 return delegate->AccessibilityGetViewBounds();
381 return gfx::Rect();
384 BrowserAccessibility* BrowserAccessibilityManager::NextInTreeOrder(
385 BrowserAccessibility* node) {
386 if (!node)
387 return NULL;
389 if (node->PlatformChildCount() > 0)
390 return node->PlatformGetChild(0);
391 while (node) {
392 if (node->GetParent() &&
393 node->GetIndexInParent() <
394 static_cast<int>(node->GetParent()->PlatformChildCount()) - 1) {
395 return node->GetParent()->PlatformGetChild(node->GetIndexInParent() + 1);
397 node = node->GetParent();
400 return NULL;
403 BrowserAccessibility* BrowserAccessibilityManager::PreviousInTreeOrder(
404 BrowserAccessibility* node) {
405 if (!node)
406 return NULL;
408 if (node->GetParent() && node->GetIndexInParent() > 0) {
409 node = node->GetParent()->PlatformGetChild(node->GetIndexInParent() - 1);
410 while (node->PlatformChildCount() > 0)
411 node = node->PlatformGetChild(node->PlatformChildCount() - 1);
412 return node;
415 return node->GetParent();
418 void BrowserAccessibilityManager::OnNodeWillBeDeleted(ui::AXNode* node) {
419 if (node == focus_ && tree_) {
420 if (node != tree_->root())
421 SetFocus(tree_->root(), false);
422 else
423 focus_ = NULL;
425 if (id_wrapper_map_.find(node->id()) == id_wrapper_map_.end())
426 return;
427 GetFromAXNode(node)->Destroy();
428 id_wrapper_map_.erase(node->id());
431 void BrowserAccessibilityManager::OnSubtreeWillBeDeleted(ui::AXNode* node) {
432 BrowserAccessibility* obj = GetFromAXNode(node);
433 if (obj)
434 obj->OnSubtreeWillBeDeleted();
437 void BrowserAccessibilityManager::OnNodeCreated(ui::AXNode* node) {
438 BrowserAccessibility* wrapper = factory_->Create();
439 wrapper->Init(this, node);
440 id_wrapper_map_[node->id()] = wrapper;
441 wrapper->OnDataChanged();
444 void BrowserAccessibilityManager::OnNodeChanged(ui::AXNode* node) {
445 GetFromAXNode(node)->OnDataChanged();
448 void BrowserAccessibilityManager::OnAtomicUpdateFinished(
449 bool root_changed,
450 const std::vector<ui::AXTreeDelegate::Change>& changes) {
453 BrowserAccessibilityDelegate*
454 BrowserAccessibilityManager::GetDelegateFromRootManager() {
455 BrowserAccessibilityManager* manager = this;
456 while (manager->delegate()) {
457 BrowserAccessibility* host_node_in_parent_frame =
458 manager->delegate()->AccessibilityGetParentFrame();
459 if (!host_node_in_parent_frame)
460 break;
461 manager = host_node_in_parent_frame->manager();
463 return manager->delegate();
466 ui::AXTreeUpdate BrowserAccessibilityManager::SnapshotAXTreeForTesting() {
467 scoped_ptr<ui::AXTreeSource<const ui::AXNode*> > tree_source(
468 tree_->CreateTreeSource());
469 ui::AXTreeSerializer<const ui::AXNode*> serializer(tree_source.get());
470 ui::AXTreeUpdate update;
471 serializer.SerializeChanges(tree_->root(), &update);
472 return update;
475 } // namespace content