Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / content / browser / accessibility / browser_accessibility_manager.cc
blob6aaf25575c926e45dda8026e5b6519a93dbd7bb0
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_WIN) && \
62 !defined(OS_MACOSX) && \
63 !defined(OS_ANDROID) && \
64 !(defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_X11))
65 // We have subclassess of BrowserAccessibility on some platforms.
66 // For other platforms, instantiate the base class.
67 // static
68 BrowserAccessibilityManager* BrowserAccessibilityManager::Create(
69 const ui::AXTreeUpdate& initial_tree,
70 BrowserAccessibilityDelegate* delegate,
71 BrowserAccessibilityFactory* factory) {
72 return new BrowserAccessibilityManager(initial_tree, delegate, factory);
74 #endif
76 BrowserAccessibilityManager::BrowserAccessibilityManager(
77 BrowserAccessibilityDelegate* delegate,
78 BrowserAccessibilityFactory* factory)
79 : delegate_(delegate),
80 factory_(factory),
81 tree_(new ui::AXSerializableTree()),
82 focus_(NULL),
83 user_is_navigating_away_(false),
84 osk_state_(OSK_ALLOWED) {
85 tree_->SetDelegate(this);
88 BrowserAccessibilityManager::BrowserAccessibilityManager(
89 const ui::AXTreeUpdate& initial_tree,
90 BrowserAccessibilityDelegate* delegate,
91 BrowserAccessibilityFactory* factory)
92 : delegate_(delegate),
93 factory_(factory),
94 tree_(new ui::AXSerializableTree()),
95 focus_(NULL),
96 user_is_navigating_away_(false),
97 osk_state_(OSK_ALLOWED) {
98 tree_->SetDelegate(this);
99 Initialize(initial_tree);
102 BrowserAccessibilityManager::~BrowserAccessibilityManager() {
103 tree_.reset(NULL);
106 void BrowserAccessibilityManager::Initialize(
107 const ui::AXTreeUpdate& initial_tree) {
108 if (!tree_->Unserialize(initial_tree)) {
109 if (delegate_) {
110 LOG(ERROR) << tree_->error();
111 delegate_->AccessibilityFatalError();
112 } else {
113 LOG(FATAL) << tree_->error();
117 if (!focus_)
118 SetFocus(tree_->root(), false);
121 // static
122 ui::AXTreeUpdate BrowserAccessibilityManager::GetEmptyDocument() {
123 ui::AXNodeData empty_document;
124 empty_document.id = 0;
125 empty_document.role = ui::AX_ROLE_ROOT_WEB_AREA;
126 ui::AXTreeUpdate update;
127 update.nodes.push_back(empty_document);
128 return update;
131 BrowserAccessibility* BrowserAccessibilityManager::GetRoot() {
132 return GetFromAXNode(tree_->root());
135 BrowserAccessibility* BrowserAccessibilityManager::GetFromAXNode(
136 ui::AXNode* node) {
137 return GetFromID(node->id());
140 BrowserAccessibility* BrowserAccessibilityManager::GetFromID(int32 id) {
141 base::hash_map<int32, BrowserAccessibility*>::iterator iter =
142 id_wrapper_map_.find(id);
143 if (iter != id_wrapper_map_.end())
144 return iter->second;
145 return NULL;
148 void BrowserAccessibilityManager::OnWindowFocused() {
149 if (focus_)
150 NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, GetFromAXNode(focus_));
153 void BrowserAccessibilityManager::OnWindowBlurred() {
154 if (focus_)
155 NotifyAccessibilityEvent(ui::AX_EVENT_BLUR, GetFromAXNode(focus_));
158 void BrowserAccessibilityManager::UserIsNavigatingAway() {
159 user_is_navigating_away_ = true;
162 void BrowserAccessibilityManager::UserIsReloading() {
163 user_is_navigating_away_ = true;
166 void BrowserAccessibilityManager::NavigationSucceeded() {
167 user_is_navigating_away_ = false;
170 void BrowserAccessibilityManager::NavigationFailed() {
171 user_is_navigating_away_ = false;
174 void BrowserAccessibilityManager::GotMouseDown() {
175 osk_state_ = OSK_ALLOWED_WITHIN_FOCUSED_OBJECT;
176 NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, GetFromAXNode(focus_));
179 bool BrowserAccessibilityManager::UseRootScrollOffsetsWhenComputingBounds() {
180 return true;
183 void BrowserAccessibilityManager::OnAccessibilityEvents(
184 const std::vector<AccessibilityHostMsg_EventParams>& params) {
185 bool should_send_initial_focus = false;
187 // Process all changes to the accessibility tree first.
188 for (uint32 index = 0; index < params.size(); index++) {
189 const AccessibilityHostMsg_EventParams& param = params[index];
190 if (!tree_->Unserialize(param.update)) {
191 if (delegate_) {
192 LOG(ERROR) << tree_->error();
193 delegate_->AccessibilityFatalError();
194 } else {
195 CHECK(false) << tree_->error();
197 return;
200 // Set focus to the root if it's not anywhere else.
201 if (!focus_) {
202 SetFocus(tree_->root(), false);
203 should_send_initial_focus = true;
207 if (should_send_initial_focus &&
208 (!delegate_ || delegate_->AccessibilityViewHasFocus())) {
209 NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, GetFromAXNode(focus_));
212 // Now iterate over the events again and fire the events.
213 for (uint32 index = 0; index < params.size(); index++) {
214 const AccessibilityHostMsg_EventParams& param = params[index];
216 // Find the node corresponding to the id that's the target of the
217 // event (which may not be the root of the update tree).
218 ui::AXNode* node = tree_->GetFromId(param.id);
219 if (!node)
220 continue;
222 ui::AXEvent event_type = param.event_type;
223 if (event_type == ui::AX_EVENT_FOCUS ||
224 event_type == ui::AX_EVENT_BLUR) {
225 SetFocus(node, false);
227 if (osk_state_ != OSK_DISALLOWED_BECAUSE_TAB_HIDDEN &&
228 osk_state_ != OSK_DISALLOWED_BECAUSE_TAB_JUST_APPEARED)
229 osk_state_ = OSK_ALLOWED;
231 // Don't send a native focus event if the window itself doesn't
232 // have focus.
233 if (delegate_ && !delegate_->AccessibilityViewHasFocus())
234 continue;
237 // Send the event event to the operating system.
238 NotifyAccessibilityEvent(event_type, GetFromAXNode(node));
242 void BrowserAccessibilityManager::OnLocationChanges(
243 const std::vector<AccessibilityHostMsg_LocationChangeParams>& params) {
244 for (size_t i = 0; i < params.size(); ++i) {
245 BrowserAccessibility* obj = GetFromID(params[i].id);
246 if (!obj)
247 continue;
248 ui::AXNode* node = obj->node();
249 node->SetLocation(params[i].new_location);
250 obj->OnLocationChanged();
254 void BrowserAccessibilityManager::OnFindInPageResult(
255 int request_id, int match_index, int start_id, int start_offset,
256 int end_id, int end_offset) {
257 find_in_page_info_.request_id = request_id;
258 find_in_page_info_.match_index = match_index;
259 find_in_page_info_.start_id = start_id;
260 find_in_page_info_.start_offset = start_offset;
261 find_in_page_info_.end_id = end_id;
262 find_in_page_info_.end_offset = end_offset;
264 if (find_in_page_info_.active_request_id == request_id)
265 ActivateFindInPageResult(request_id);
268 void BrowserAccessibilityManager::ActivateFindInPageResult(
269 int request_id) {
270 find_in_page_info_.active_request_id = request_id;
271 if (find_in_page_info_.request_id != request_id)
272 return;
274 BrowserAccessibility* node = GetFromID(find_in_page_info_.start_id);
275 if (!node)
276 return;
278 // If an ancestor of this node is a leaf node, fire the notification on that.
279 BrowserAccessibility* ancestor = node->GetParent();
280 while (ancestor && ancestor != GetRoot()) {
281 if (ancestor->PlatformIsLeaf())
282 node = ancestor;
283 ancestor = ancestor->GetParent();
286 // The "scrolled to anchor" notification is a great way to get a
287 // screen reader to jump directly to a specific location in a document.
288 NotifyAccessibilityEvent(ui::AX_EVENT_SCROLLED_TO_ANCHOR, node);
291 BrowserAccessibility* BrowserAccessibilityManager::GetActiveDescendantFocus(
292 BrowserAccessibility* root) {
293 BrowserAccessibility* node = BrowserAccessibilityManager::GetFocus(root);
294 if (!node)
295 return NULL;
297 int active_descendant_id;
298 if (node->GetIntAttribute(ui::AX_ATTR_ACTIVEDESCENDANT_ID,
299 &active_descendant_id)) {
300 BrowserAccessibility* active_descendant =
301 node->manager()->GetFromID(active_descendant_id);
302 if (active_descendant)
303 return active_descendant;
305 return node;
308 BrowserAccessibility* BrowserAccessibilityManager::GetFocus(
309 BrowserAccessibility* root) {
310 if (!focus_)
311 return NULL;
313 if (root && !focus_->IsDescendantOf(root->node()))
314 return NULL;
316 BrowserAccessibility* obj = GetFromAXNode(focus_);
317 if (delegate() && obj->HasBoolAttribute(ui::AX_ATTR_IS_AX_TREE_HOST)) {
318 BrowserAccessibilityManager* child_manager =
319 delegate()->AccessibilityGetChildFrame(obj->GetId());
320 if (child_manager)
321 return child_manager->GetFocus(child_manager->GetRoot());
324 return obj;
327 void BrowserAccessibilityManager::SetFocus(ui::AXNode* node, bool notify) {
328 if (focus_ != node)
329 focus_ = node;
331 if (notify && node && delegate_)
332 delegate_->AccessibilitySetFocus(node->id());
335 void BrowserAccessibilityManager::SetFocus(
336 BrowserAccessibility* obj, bool notify) {
337 if (obj->node())
338 SetFocus(obj->node(), notify);
341 void BrowserAccessibilityManager::DoDefaultAction(
342 const BrowserAccessibility& node) {
343 if (delegate_)
344 delegate_->AccessibilityDoDefaultAction(node.GetId());
347 void BrowserAccessibilityManager::ScrollToMakeVisible(
348 const BrowserAccessibility& node, gfx::Rect subfocus) {
349 if (delegate_) {
350 delegate_->AccessibilityScrollToMakeVisible(node.GetId(), subfocus);
354 void BrowserAccessibilityManager::ScrollToPoint(
355 const BrowserAccessibility& node, gfx::Point point) {
356 if (delegate_) {
357 delegate_->AccessibilityScrollToPoint(node.GetId(), point);
361 void BrowserAccessibilityManager::SetScrollOffset(
362 const BrowserAccessibility& node, gfx::Point offset) {
363 if (delegate_) {
364 delegate_->AccessibilitySetScrollOffset(node.GetId(), offset);
368 void BrowserAccessibilityManager::SetValue(
369 const BrowserAccessibility& node,
370 const base::string16& value) {
371 if (delegate_)
372 delegate_->AccessibilitySetValue(node.GetId(), value);
375 void BrowserAccessibilityManager::SetTextSelection(
376 const BrowserAccessibility& node,
377 int start_offset,
378 int end_offset) {
379 if (delegate_) {
380 delegate_->AccessibilitySetTextSelection(
381 node.GetId(), start_offset, end_offset);
385 gfx::Rect BrowserAccessibilityManager::GetViewBounds() {
386 BrowserAccessibilityDelegate* delegate = GetDelegateFromRootManager();
387 if (delegate)
388 return delegate->AccessibilityGetViewBounds();
389 return gfx::Rect();
392 BrowserAccessibility* BrowserAccessibilityManager::NextInTreeOrder(
393 BrowserAccessibility* node) {
394 if (!node)
395 return NULL;
397 if (node->PlatformChildCount() > 0)
398 return node->PlatformGetChild(0);
399 while (node) {
400 if (node->GetParent() &&
401 node->GetIndexInParent() <
402 static_cast<int>(node->GetParent()->PlatformChildCount()) - 1) {
403 return node->GetParent()->PlatformGetChild(node->GetIndexInParent() + 1);
405 node = node->GetParent();
408 return NULL;
411 BrowserAccessibility* BrowserAccessibilityManager::PreviousInTreeOrder(
412 BrowserAccessibility* node) {
413 if (!node)
414 return NULL;
416 if (node->GetParent() && node->GetIndexInParent() > 0) {
417 node = node->GetParent()->PlatformGetChild(node->GetIndexInParent() - 1);
418 while (node->PlatformChildCount() > 0)
419 node = node->PlatformGetChild(node->PlatformChildCount() - 1);
420 return node;
423 return node->GetParent();
426 void BrowserAccessibilityManager::OnNodeWillBeDeleted(ui::AXTree* tree,
427 ui::AXNode* node) {
428 if (node == focus_ && tree_) {
429 if (node != tree_->root())
430 SetFocus(tree_->root(), false);
431 else
432 focus_ = NULL;
434 if (id_wrapper_map_.find(node->id()) == id_wrapper_map_.end())
435 return;
436 GetFromAXNode(node)->Destroy();
437 id_wrapper_map_.erase(node->id());
440 void BrowserAccessibilityManager::OnSubtreeWillBeDeleted(ui::AXTree* tree,
441 ui::AXNode* node) {
442 BrowserAccessibility* obj = GetFromAXNode(node);
443 if (obj)
444 obj->OnSubtreeWillBeDeleted();
447 void BrowserAccessibilityManager::OnNodeCreated(ui::AXTree* tree,
448 ui::AXNode* node) {
449 BrowserAccessibility* wrapper = factory_->Create();
450 wrapper->Init(this, node);
451 id_wrapper_map_[node->id()] = wrapper;
452 wrapper->OnDataChanged();
455 void BrowserAccessibilityManager::OnNodeChanged(ui::AXTree* tree,
456 ui::AXNode* node) {
457 GetFromAXNode(node)->OnDataChanged();
460 void BrowserAccessibilityManager::OnAtomicUpdateFinished(
461 ui::AXTree* tree,
462 bool root_changed,
463 const std::vector<ui::AXTreeDelegate::Change>& changes) {
466 BrowserAccessibilityDelegate*
467 BrowserAccessibilityManager::GetDelegateFromRootManager() {
468 BrowserAccessibilityManager* manager = this;
469 while (manager->delegate()) {
470 BrowserAccessibility* host_node_in_parent_frame =
471 manager->delegate()->AccessibilityGetParentFrame();
472 if (!host_node_in_parent_frame)
473 break;
474 manager = host_node_in_parent_frame->manager();
476 return manager->delegate();
479 ui::AXTreeUpdate BrowserAccessibilityManager::SnapshotAXTreeForTesting() {
480 scoped_ptr<ui::AXTreeSource<const ui::AXNode*> > tree_source(
481 tree_->CreateTreeSource());
482 ui::AXTreeSerializer<const ui::AXNode*> serializer(tree_source.get());
483 ui::AXTreeUpdate update;
484 serializer.SerializeChanges(tree_->root(), &update);
485 return update;
488 } // namespace content