Add long running gmail memory benchmark for background tab.
[chromium-blink-merge.git] / content / browser / accessibility / browser_accessibility_manager.cc
blob9a42dc169e7e897158a10536b0199d580b9c56f4
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 // tree_->root() can be null during AXTreeDelegate callbacks.
133 ui::AXNode* root = tree_->root();
134 return root ? GetFromAXNode(root) : nullptr;
137 BrowserAccessibility* BrowserAccessibilityManager::GetFromAXNode(
138 ui::AXNode* node) {
139 return GetFromID(node->id());
142 BrowserAccessibility* BrowserAccessibilityManager::GetFromID(int32 id) {
143 base::hash_map<int32, BrowserAccessibility*>::iterator iter =
144 id_wrapper_map_.find(id);
145 if (iter != id_wrapper_map_.end())
146 return iter->second;
147 return NULL;
150 void BrowserAccessibilityManager::OnWindowFocused() {
151 if (focus_)
152 NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, GetFromAXNode(focus_));
155 void BrowserAccessibilityManager::OnWindowBlurred() {
156 if (focus_)
157 NotifyAccessibilityEvent(ui::AX_EVENT_BLUR, GetFromAXNode(focus_));
160 void BrowserAccessibilityManager::UserIsNavigatingAway() {
161 user_is_navigating_away_ = true;
164 void BrowserAccessibilityManager::UserIsReloading() {
165 user_is_navigating_away_ = true;
168 void BrowserAccessibilityManager::NavigationSucceeded() {
169 user_is_navigating_away_ = false;
172 void BrowserAccessibilityManager::NavigationFailed() {
173 user_is_navigating_away_ = false;
176 void BrowserAccessibilityManager::GotMouseDown() {
177 osk_state_ = OSK_ALLOWED_WITHIN_FOCUSED_OBJECT;
178 NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, GetFromAXNode(focus_));
181 bool BrowserAccessibilityManager::UseRootScrollOffsetsWhenComputingBounds() {
182 return true;
185 void BrowserAccessibilityManager::OnAccessibilityEvents(
186 const std::vector<AccessibilityHostMsg_EventParams>& params) {
187 bool should_send_initial_focus = false;
189 // Process all changes to the accessibility tree first.
190 for (uint32 index = 0; index < params.size(); index++) {
191 const AccessibilityHostMsg_EventParams& param = params[index];
192 if (!tree_->Unserialize(param.update)) {
193 if (delegate_) {
194 LOG(ERROR) << tree_->error();
195 delegate_->AccessibilityFatalError();
196 } else {
197 CHECK(false) << tree_->error();
199 return;
202 // Set focus to the root if it's not anywhere else.
203 if (!focus_) {
204 SetFocus(tree_->root(), false);
205 should_send_initial_focus = true;
209 if (should_send_initial_focus &&
210 (!delegate_ || delegate_->AccessibilityViewHasFocus())) {
211 NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, GetFromAXNode(focus_));
214 // Now iterate over the events again and fire the events.
215 for (uint32 index = 0; index < params.size(); index++) {
216 const AccessibilityHostMsg_EventParams& param = params[index];
218 // Find the node corresponding to the id that's the target of the
219 // event (which may not be the root of the update tree).
220 ui::AXNode* node = tree_->GetFromId(param.id);
221 if (!node)
222 continue;
224 ui::AXEvent event_type = param.event_type;
225 if (event_type == ui::AX_EVENT_FOCUS ||
226 event_type == ui::AX_EVENT_BLUR) {
227 SetFocus(node, false);
229 if (osk_state_ != OSK_DISALLOWED_BECAUSE_TAB_HIDDEN &&
230 osk_state_ != OSK_DISALLOWED_BECAUSE_TAB_JUST_APPEARED)
231 osk_state_ = OSK_ALLOWED;
233 // Don't send a native focus event if the window itself doesn't
234 // have focus.
235 if (delegate_ && !delegate_->AccessibilityViewHasFocus())
236 continue;
239 // Send the event event to the operating system.
240 NotifyAccessibilityEvent(event_type, GetFromAXNode(node));
244 void BrowserAccessibilityManager::OnLocationChanges(
245 const std::vector<AccessibilityHostMsg_LocationChangeParams>& params) {
246 for (size_t i = 0; i < params.size(); ++i) {
247 BrowserAccessibility* obj = GetFromID(params[i].id);
248 if (!obj)
249 continue;
250 ui::AXNode* node = obj->node();
251 node->SetLocation(params[i].new_location);
252 obj->OnLocationChanged();
256 void BrowserAccessibilityManager::OnFindInPageResult(
257 int request_id, int match_index, int start_id, int start_offset,
258 int end_id, int end_offset) {
259 find_in_page_info_.request_id = request_id;
260 find_in_page_info_.match_index = match_index;
261 find_in_page_info_.start_id = start_id;
262 find_in_page_info_.start_offset = start_offset;
263 find_in_page_info_.end_id = end_id;
264 find_in_page_info_.end_offset = end_offset;
266 if (find_in_page_info_.active_request_id == request_id)
267 ActivateFindInPageResult(request_id);
270 void BrowserAccessibilityManager::ActivateFindInPageResult(
271 int request_id) {
272 find_in_page_info_.active_request_id = request_id;
273 if (find_in_page_info_.request_id != request_id)
274 return;
276 BrowserAccessibility* node = GetFromID(find_in_page_info_.start_id);
277 if (!node)
278 return;
280 // If an ancestor of this node is a leaf node, fire the notification on that.
281 BrowserAccessibility* ancestor = node->GetParent();
282 while (ancestor && ancestor != GetRoot()) {
283 if (ancestor->PlatformIsLeaf())
284 node = ancestor;
285 ancestor = ancestor->GetParent();
288 // The "scrolled to anchor" notification is a great way to get a
289 // screen reader to jump directly to a specific location in a document.
290 NotifyAccessibilityEvent(ui::AX_EVENT_SCROLLED_TO_ANCHOR, node);
293 BrowserAccessibility* BrowserAccessibilityManager::GetActiveDescendantFocus(
294 BrowserAccessibility* root) {
295 BrowserAccessibility* node = BrowserAccessibilityManager::GetFocus(root);
296 if (!node)
297 return NULL;
299 int active_descendant_id;
300 if (node->GetIntAttribute(ui::AX_ATTR_ACTIVEDESCENDANT_ID,
301 &active_descendant_id)) {
302 BrowserAccessibility* active_descendant =
303 node->manager()->GetFromID(active_descendant_id);
304 if (active_descendant)
305 return active_descendant;
307 return node;
310 BrowserAccessibility* BrowserAccessibilityManager::GetFocus(
311 BrowserAccessibility* root) {
312 if (!focus_)
313 return NULL;
315 if (root && !focus_->IsDescendantOf(root->node()))
316 return NULL;
318 BrowserAccessibility* obj = GetFromAXNode(focus_);
319 if (delegate() && obj->HasBoolAttribute(ui::AX_ATTR_IS_AX_TREE_HOST)) {
320 BrowserAccessibilityManager* child_manager =
321 delegate()->AccessibilityGetChildFrame(obj->GetId());
322 if (child_manager)
323 return child_manager->GetFocus(child_manager->GetRoot());
326 return obj;
329 void BrowserAccessibilityManager::SetFocus(ui::AXNode* node, bool notify) {
330 if (focus_ != node)
331 focus_ = node;
333 if (notify && node && delegate_)
334 delegate_->AccessibilitySetFocus(node->id());
337 void BrowserAccessibilityManager::SetFocus(
338 BrowserAccessibility* obj, bool notify) {
339 if (obj->node())
340 SetFocus(obj->node(), notify);
343 void BrowserAccessibilityManager::DoDefaultAction(
344 const BrowserAccessibility& node) {
345 if (delegate_)
346 delegate_->AccessibilityDoDefaultAction(node.GetId());
349 void BrowserAccessibilityManager::ScrollToMakeVisible(
350 const BrowserAccessibility& node, gfx::Rect subfocus) {
351 if (delegate_) {
352 delegate_->AccessibilityScrollToMakeVisible(node.GetId(), subfocus);
356 void BrowserAccessibilityManager::ScrollToPoint(
357 const BrowserAccessibility& node, gfx::Point point) {
358 if (delegate_) {
359 delegate_->AccessibilityScrollToPoint(node.GetId(), point);
363 void BrowserAccessibilityManager::SetScrollOffset(
364 const BrowserAccessibility& node, gfx::Point offset) {
365 if (delegate_) {
366 delegate_->AccessibilitySetScrollOffset(node.GetId(), offset);
370 void BrowserAccessibilityManager::SetValue(
371 const BrowserAccessibility& node,
372 const base::string16& value) {
373 if (delegate_)
374 delegate_->AccessibilitySetValue(node.GetId(), value);
377 void BrowserAccessibilityManager::SetTextSelection(
378 const BrowserAccessibility& node,
379 int start_offset,
380 int end_offset) {
381 if (delegate_) {
382 delegate_->AccessibilitySetTextSelection(
383 node.GetId(), start_offset, end_offset);
387 gfx::Rect BrowserAccessibilityManager::GetViewBounds() {
388 BrowserAccessibilityDelegate* delegate = GetDelegateFromRootManager();
389 if (delegate)
390 return delegate->AccessibilityGetViewBounds();
391 return gfx::Rect();
394 BrowserAccessibility* BrowserAccessibilityManager::NextInTreeOrder(
395 BrowserAccessibility* node) {
396 if (!node)
397 return NULL;
399 if (node->PlatformChildCount() > 0)
400 return node->PlatformGetChild(0);
401 while (node) {
402 if (node->GetParent() &&
403 node->GetIndexInParent() <
404 static_cast<int>(node->GetParent()->PlatformChildCount()) - 1) {
405 return node->GetParent()->PlatformGetChild(node->GetIndexInParent() + 1);
407 node = node->GetParent();
410 return NULL;
413 BrowserAccessibility* BrowserAccessibilityManager::PreviousInTreeOrder(
414 BrowserAccessibility* node) {
415 if (!node)
416 return NULL;
418 if (node->GetParent() && node->GetIndexInParent() > 0) {
419 node = node->GetParent()->PlatformGetChild(node->GetIndexInParent() - 1);
420 while (node->PlatformChildCount() > 0)
421 node = node->PlatformGetChild(node->PlatformChildCount() - 1);
422 return node;
425 return node->GetParent();
428 void BrowserAccessibilityManager::OnNodeWillBeDeleted(ui::AXTree* tree,
429 ui::AXNode* node) {
430 if (node == focus_ && tree_) {
431 if (node != tree_->root())
432 SetFocus(tree_->root(), false);
433 else
434 focus_ = NULL;
436 if (id_wrapper_map_.find(node->id()) == id_wrapper_map_.end())
437 return;
438 GetFromAXNode(node)->Destroy();
439 id_wrapper_map_.erase(node->id());
442 void BrowserAccessibilityManager::OnSubtreeWillBeDeleted(ui::AXTree* tree,
443 ui::AXNode* node) {
444 BrowserAccessibility* obj = GetFromAXNode(node);
445 if (obj)
446 obj->OnSubtreeWillBeDeleted();
449 void BrowserAccessibilityManager::OnNodeCreated(ui::AXTree* tree,
450 ui::AXNode* node) {
451 BrowserAccessibility* wrapper = factory_->Create();
452 wrapper->Init(this, node);
453 id_wrapper_map_[node->id()] = wrapper;
454 wrapper->OnDataChanged();
457 void BrowserAccessibilityManager::OnNodeChanged(ui::AXTree* tree,
458 ui::AXNode* node) {
459 GetFromAXNode(node)->OnDataChanged();
462 void BrowserAccessibilityManager::OnAtomicUpdateFinished(
463 ui::AXTree* tree,
464 bool root_changed,
465 const std::vector<ui::AXTreeDelegate::Change>& changes) {
468 BrowserAccessibilityDelegate*
469 BrowserAccessibilityManager::GetDelegateFromRootManager() {
470 BrowserAccessibilityManager* manager = this;
471 while (manager->delegate()) {
472 BrowserAccessibility* host_node_in_parent_frame =
473 manager->delegate()->AccessibilityGetParentFrame();
474 if (!host_node_in_parent_frame)
475 break;
476 manager = host_node_in_parent_frame->manager();
478 return manager->delegate();
481 ui::AXTreeUpdate BrowserAccessibilityManager::SnapshotAXTreeForTesting() {
482 scoped_ptr<ui::AXTreeSource<const ui::AXNode*> > tree_source(
483 tree_->CreateTreeSource());
484 ui::AXTreeSerializer<const ui::AXNode*> serializer(tree_source.get());
485 ui::AXTreeUpdate update;
486 serializer.SerializeChanges(tree_->root(), &update);
487 return update;
490 } // namespace content