Battery Status API: add UMA logging for Linux.
[chromium-blink-merge.git] / content / browser / accessibility / browser_accessibility_manager.cc
blob6bdce2d907a503186a04788d2ba7731723866923
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"
11 namespace content {
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);
44 return update;
47 BrowserAccessibility* BrowserAccessibilityFactory::Create() {
48 return BrowserAccessibility::Create();
51 #if !defined(OS_MACOSX) && \
52 !defined(OS_WIN) && \
53 !defined(OS_ANDROID) \
54 // We have subclassess of BrowserAccessibilityManager on Mac, and Win. For any
55 // other platform, instantiate the base class.
56 // static
57 BrowserAccessibilityManager* BrowserAccessibilityManager::Create(
58 const ui::AXTreeUpdate& initial_tree,
59 BrowserAccessibilityDelegate* delegate,
60 BrowserAccessibilityFactory* factory) {
61 return new BrowserAccessibilityManager(initial_tree, delegate, factory);
63 #endif
65 BrowserAccessibilityManager::BrowserAccessibilityManager(
66 BrowserAccessibilityDelegate* delegate,
67 BrowserAccessibilityFactory* factory)
68 : delegate_(delegate),
69 factory_(factory),
70 tree_(new ui::AXTree()),
71 focus_(NULL),
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),
81 factory_(factory),
82 tree_(new ui::AXTree()),
83 focus_(NULL),
84 osk_state_(OSK_ALLOWED) {
85 tree_->SetDelegate(this);
86 Initialize(initial_tree);
89 BrowserAccessibilityManager::~BrowserAccessibilityManager() {
90 tree_.reset(NULL);
93 void BrowserAccessibilityManager::Initialize(
94 const ui::AXTreeUpdate& initial_tree) {
95 if (!tree_->Unserialize(initial_tree)) {
96 if (delegate_) {
97 LOG(ERROR) << tree_->error();
98 delegate_->AccessibilityFatalError();
99 } else {
100 LOG(FATAL) << tree_->error();
104 if (!focus_)
105 SetFocus(tree_->GetRoot(), false);
108 // static
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);
115 return update;
118 BrowserAccessibility* BrowserAccessibilityManager::GetRoot() {
119 return GetFromAXNode(tree_->GetRoot());
122 BrowserAccessibility* BrowserAccessibilityManager::GetFromAXNode(
123 ui::AXNode* node) {
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())
131 return iter->second;
132 return NULL;
135 void BrowserAccessibilityManager::OnWindowFocused() {
136 if (focus_)
137 NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, GetFromAXNode(focus_));
140 void BrowserAccessibilityManager::OnWindowBlurred() {
141 if (focus_)
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::UseRootScrollOffsetsWhenComputingBounds() {
151 return true;
154 void BrowserAccessibilityManager::OnAccessibilityEvents(
155 const std::vector<AccessibilityHostMsg_EventParams>& params) {
156 bool should_send_initial_focus = false;
158 // Process all changes to the accessibility tree first.
159 for (uint32 index = 0; index < params.size(); index++) {
160 const AccessibilityHostMsg_EventParams& param = params[index];
161 if (!tree_->Unserialize(param.update)) {
162 if (delegate_) {
163 LOG(ERROR) << tree_->error();
164 delegate_->AccessibilityFatalError();
165 } else {
166 CHECK(false) << tree_->error();
168 return;
171 // Set focus to the root if it's not anywhere else.
172 if (!focus_) {
173 SetFocus(tree_->GetRoot(), false);
174 should_send_initial_focus = true;
178 OnTreeUpdateFinished();
180 if (should_send_initial_focus &&
181 (!delegate_ || delegate_->AccessibilityViewHasFocus())) {
182 NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, GetFromAXNode(focus_));
185 // Now iterate over the events again and fire the events.
186 for (uint32 index = 0; index < params.size(); index++) {
187 const AccessibilityHostMsg_EventParams& param = params[index];
189 // Find the node corresponding to the id that's the target of the
190 // event (which may not be the root of the update tree).
191 ui::AXNode* node = tree_->GetFromId(param.id);
192 if (!node)
193 continue;
195 ui::AXEvent event_type = param.event_type;
196 if (event_type == ui::AX_EVENT_FOCUS ||
197 event_type == ui::AX_EVENT_BLUR) {
198 SetFocus(node, false);
200 if (osk_state_ != OSK_DISALLOWED_BECAUSE_TAB_HIDDEN &&
201 osk_state_ != OSK_DISALLOWED_BECAUSE_TAB_JUST_APPEARED)
202 osk_state_ = OSK_ALLOWED;
204 // Don't send a native focus event if the window itself doesn't
205 // have focus.
206 if (delegate_ && !delegate_->AccessibilityViewHasFocus())
207 continue;
210 // Send the event event to the operating system.
211 NotifyAccessibilityEvent(event_type, GetFromAXNode(node));
215 void BrowserAccessibilityManager::OnLocationChanges(
216 const std::vector<AccessibilityHostMsg_LocationChangeParams>& params) {
217 for (size_t i = 0; i < params.size(); ++i) {
218 BrowserAccessibility* obj = GetFromID(params[i].id);
219 if (!obj)
220 continue;
221 ui::AXNode* node = obj->node();
222 node->SetLocation(params[i].new_location);
223 obj->OnLocationChanged();
227 BrowserAccessibility* BrowserAccessibilityManager::GetActiveDescendantFocus(
228 BrowserAccessibility* root) {
229 BrowserAccessibility* node = BrowserAccessibilityManager::GetFocus(root);
230 if (!node)
231 return NULL;
233 int active_descendant_id;
234 if (node->GetIntAttribute(ui::AX_ATTR_ACTIVEDESCENDANT_ID,
235 &active_descendant_id)) {
236 BrowserAccessibility* active_descendant =
237 node->manager()->GetFromID(active_descendant_id);
238 if (active_descendant)
239 return active_descendant;
241 return node;
244 BrowserAccessibility* BrowserAccessibilityManager::GetFocus(
245 BrowserAccessibility* root) {
246 if (focus_ && (!root || focus_->IsDescendantOf(root->node())))
247 return GetFromAXNode(focus_);
249 return NULL;
252 void BrowserAccessibilityManager::SetFocus(ui::AXNode* node, bool notify) {
253 if (focus_ != node)
254 focus_ = node;
256 if (notify && node && delegate_)
257 delegate_->AccessibilitySetFocus(node->id());
260 void BrowserAccessibilityManager::SetFocus(
261 BrowserAccessibility* obj, bool notify) {
262 if (obj->node())
263 SetFocus(obj->node(), notify);
266 void BrowserAccessibilityManager::DoDefaultAction(
267 const BrowserAccessibility& node) {
268 if (delegate_)
269 delegate_->AccessibilityDoDefaultAction(node.GetId());
272 void BrowserAccessibilityManager::ScrollToMakeVisible(
273 const BrowserAccessibility& node, gfx::Rect subfocus) {
274 if (delegate_) {
275 delegate_->AccessibilityScrollToMakeVisible(node.GetId(), subfocus);
279 void BrowserAccessibilityManager::ScrollToPoint(
280 const BrowserAccessibility& node, gfx::Point point) {
281 if (delegate_) {
282 delegate_->AccessibilityScrollToPoint(node.GetId(), point);
286 void BrowserAccessibilityManager::SetTextSelection(
287 const BrowserAccessibility& node, int start_offset, int end_offset) {
288 if (delegate_) {
289 delegate_->AccessibilitySetTextSelection(
290 node.GetId(), start_offset, end_offset);
294 gfx::Rect BrowserAccessibilityManager::GetViewBounds() {
295 if (delegate_)
296 return delegate_->AccessibilityGetViewBounds();
297 return gfx::Rect();
300 BrowserAccessibility* BrowserAccessibilityManager::NextInTreeOrder(
301 BrowserAccessibility* node) {
302 if (!node)
303 return NULL;
305 if (node->PlatformChildCount() > 0)
306 return node->PlatformGetChild(0);
307 while (node) {
308 if (node->GetParent() &&
309 node->GetIndexInParent() <
310 static_cast<int>(node->GetParent()->PlatformChildCount()) - 1) {
311 return node->GetParent()->PlatformGetChild(node->GetIndexInParent() + 1);
313 node = node->GetParent();
316 return NULL;
319 BrowserAccessibility* BrowserAccessibilityManager::PreviousInTreeOrder(
320 BrowserAccessibility* node) {
321 if (!node)
322 return NULL;
324 if (node->GetParent() && node->GetIndexInParent() > 0) {
325 node = node->GetParent()->PlatformGetChild(node->GetIndexInParent() - 1);
326 while (node->PlatformChildCount() > 0)
327 node = node->PlatformGetChild(node->PlatformChildCount() - 1);
328 return node;
331 return node->GetParent();
334 void BrowserAccessibilityManager::OnNodeWillBeDeleted(ui::AXNode* node) {
335 if (node == focus_ && tree_) {
336 if (node != tree_->GetRoot())
337 SetFocus(tree_->GetRoot(), false);
338 else
339 focus_ = NULL;
341 if (id_wrapper_map_.find(node->id()) == id_wrapper_map_.end())
342 return;
343 GetFromAXNode(node)->Destroy();
344 id_wrapper_map_.erase(node->id());
347 void BrowserAccessibilityManager::OnNodeCreated(ui::AXNode* node) {
348 BrowserAccessibility* wrapper = factory_->Create();
349 wrapper->Init(this, node);
350 id_wrapper_map_[node->id()] = wrapper;
351 wrapper->OnDataChanged();
354 void BrowserAccessibilityManager::OnNodeChanged(ui::AXNode* node) {
355 GetFromAXNode(node)->OnDataChanged();
358 void BrowserAccessibilityManager::OnNodeCreationFinished(ui::AXNode* node) {
359 GetFromAXNode(node)->OnUpdateFinished();
362 void BrowserAccessibilityManager::OnNodeChangeFinished(ui::AXNode* node) {
363 GetFromAXNode(node)->OnUpdateFinished();
366 } // namespace content