Remove PlatformFile from profile_browsertest
[chromium-blink-merge.git] / content / browser / accessibility / browser_accessibility_manager.cc
blob8481b0776c42c9ee6df90e205de097b0e3a6db35
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 BrowserAccessibility* BrowserAccessibilityFactory::Create() {
14 return BrowserAccessibility::Create();
17 #if !defined(OS_MACOSX) && \
18 !defined(OS_WIN) && \
19 !defined(TOOLKIT_GTK) && \
20 !defined(OS_ANDROID) \
21 // We have subclassess of BrowserAccessibilityManager on Mac, Linux/GTK,
22 // and Win. For any other platform, instantiate the base class.
23 // static
24 BrowserAccessibilityManager* BrowserAccessibilityManager::Create(
25 const ui::AXNodeData& src,
26 BrowserAccessibilityDelegate* delegate,
27 BrowserAccessibilityFactory* factory) {
28 return new BrowserAccessibilityManager(src, delegate, factory);
30 #endif
32 BrowserAccessibilityManager::BrowserAccessibilityManager(
33 BrowserAccessibilityDelegate* delegate,
34 BrowserAccessibilityFactory* factory)
35 : delegate_(delegate),
36 factory_(factory),
37 root_(NULL),
38 focus_(NULL),
39 osk_state_(OSK_ALLOWED) {
42 BrowserAccessibilityManager::BrowserAccessibilityManager(
43 const ui::AXNodeData& src,
44 BrowserAccessibilityDelegate* delegate,
45 BrowserAccessibilityFactory* factory)
46 : delegate_(delegate),
47 factory_(factory),
48 root_(NULL),
49 focus_(NULL),
50 osk_state_(OSK_ALLOWED) {
51 Initialize(src);
54 BrowserAccessibilityManager::~BrowserAccessibilityManager() {
55 if (root_)
56 root_->Destroy();
59 void BrowserAccessibilityManager::Initialize(const ui::AXNodeData src) {
60 std::vector<ui::AXNodeData> nodes;
61 nodes.push_back(src);
62 if (!UpdateNodes(nodes))
63 return;
64 if (!focus_)
65 SetFocus(root_, false);
68 // static
69 ui::AXNodeData BrowserAccessibilityManager::GetEmptyDocument() {
70 ui::AXNodeData empty_document;
71 empty_document.id = 0;
72 empty_document.role = ui::AX_ROLE_ROOT_WEB_AREA;
73 return empty_document;
76 BrowserAccessibility* BrowserAccessibilityManager::GetRoot() {
77 return root_;
80 BrowserAccessibility* BrowserAccessibilityManager::GetFromRendererID(
81 int32 renderer_id) {
82 base::hash_map<int32, BrowserAccessibility*>::iterator iter =
83 renderer_id_map_.find(renderer_id);
84 if (iter != renderer_id_map_.end())
85 return iter->second;
86 return NULL;
89 void BrowserAccessibilityManager::GotFocus(bool touch_event_context) {
90 if (!touch_event_context)
91 osk_state_ = OSK_DISALLOWED_BECAUSE_TAB_JUST_APPEARED;
93 if (!focus_)
94 return;
96 NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, focus_);
99 void BrowserAccessibilityManager::WasHidden() {
100 osk_state_ = OSK_DISALLOWED_BECAUSE_TAB_HIDDEN;
103 void BrowserAccessibilityManager::GotMouseDown() {
104 osk_state_ = OSK_ALLOWED_WITHIN_FOCUSED_OBJECT;
105 NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, focus_);
108 bool BrowserAccessibilityManager::IsOSKAllowed(const gfx::Rect& bounds) {
109 if (!delegate_ || !delegate_->HasFocus())
110 return false;
112 gfx::Point touch_point = delegate_->GetLastTouchEventLocation();
113 return bounds.Contains(touch_point);
116 bool BrowserAccessibilityManager::UseRootScrollOffsetsWhenComputingBounds() {
117 return true;
120 void BrowserAccessibilityManager::RemoveNode(BrowserAccessibility* node) {
121 if (node == focus_)
122 SetFocus(root_, false);
123 int renderer_id = node->renderer_id();
124 renderer_id_map_.erase(renderer_id);
127 void BrowserAccessibilityManager::OnAccessibilityEvents(
128 const std::vector<AccessibilityHostMsg_EventParams>& params) {
129 bool should_send_initial_focus = false;
131 // Process all changes to the accessibility tree first.
132 for (uint32 index = 0; index < params.size(); index++) {
133 const AccessibilityHostMsg_EventParams& param = params[index];
134 if (!UpdateNodes(param.nodes))
135 return;
137 // Set initial focus when a page is loaded.
138 ui::AXEvent event_type = param.event_type;
139 if (event_type == ui::AX_EVENT_LOAD_COMPLETE) {
140 if (!focus_) {
141 SetFocus(root_, false);
142 should_send_initial_focus = true;
147 if (should_send_initial_focus &&
148 (!delegate_ || delegate_->HasFocus())) {
149 NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, focus_);
152 // Now iterate over the events again and fire the events.
153 for (uint32 index = 0; index < params.size(); index++) {
154 const AccessibilityHostMsg_EventParams& param = params[index];
156 // Find the node corresponding to the id that's the target of the
157 // event (which may not be the root of the update tree).
158 BrowserAccessibility* node = GetFromRendererID(param.id);
159 if (!node)
160 continue;
162 ui::AXEvent event_type = param.event_type;
163 if (event_type == ui::AX_EVENT_FOCUS ||
164 event_type == ui::AX_EVENT_BLUR) {
165 SetFocus(node, false);
167 if (osk_state_ != OSK_DISALLOWED_BECAUSE_TAB_HIDDEN &&
168 osk_state_ != OSK_DISALLOWED_BECAUSE_TAB_JUST_APPEARED)
169 osk_state_ = OSK_ALLOWED;
171 // Don't send a native focus event if the window itself doesn't
172 // have focus.
173 if (delegate_ && !delegate_->HasFocus())
174 continue;
177 // Send the event event to the operating system.
178 NotifyAccessibilityEvent(event_type, node);
182 void BrowserAccessibilityManager::OnLocationChanges(
183 const std::vector<AccessibilityHostMsg_LocationChangeParams>& params) {
184 for (size_t i = 0; i < params.size(); ++i) {
185 BrowserAccessibility* node = GetFromRendererID(params[i].id);
186 if (node)
187 node->SetLocation(params[i].new_location);
191 BrowserAccessibility* BrowserAccessibilityManager::GetFocus(
192 BrowserAccessibility* root) {
193 if (focus_ && (!root || focus_->IsDescendantOf(root)))
194 return focus_;
196 return NULL;
199 void BrowserAccessibilityManager::SetFocus(
200 BrowserAccessibility* node, bool notify) {
201 if (focus_ != node)
202 focus_ = node;
204 if (notify && node && delegate_)
205 delegate_->SetAccessibilityFocus(node->renderer_id());
208 void BrowserAccessibilityManager::SetRoot(BrowserAccessibility* node) {
209 root_ = node;
210 NotifyRootChanged();
213 void BrowserAccessibilityManager::DoDefaultAction(
214 const BrowserAccessibility& node) {
215 if (delegate_)
216 delegate_->AccessibilityDoDefaultAction(node.renderer_id());
219 void BrowserAccessibilityManager::ScrollToMakeVisible(
220 const BrowserAccessibility& node, gfx::Rect subfocus) {
221 if (delegate_) {
222 delegate_->AccessibilityScrollToMakeVisible(node.renderer_id(), subfocus);
226 void BrowserAccessibilityManager::ScrollToPoint(
227 const BrowserAccessibility& node, gfx::Point point) {
228 if (delegate_) {
229 delegate_->AccessibilityScrollToPoint(node.renderer_id(), point);
233 void BrowserAccessibilityManager::SetTextSelection(
234 const BrowserAccessibility& node, int start_offset, int end_offset) {
235 if (delegate_) {
236 delegate_->AccessibilitySetTextSelection(
237 node.renderer_id(), start_offset, end_offset);
241 gfx::Rect BrowserAccessibilityManager::GetViewBounds() {
242 if (delegate_)
243 return delegate_->GetViewBounds();
244 return gfx::Rect();
247 BrowserAccessibility* BrowserAccessibilityManager::NextInTreeOrder(
248 BrowserAccessibility* node) {
249 if (!node)
250 return NULL;
252 if (node->PlatformChildCount() > 0)
253 return node->PlatformGetChild(0);
254 while (node) {
255 if (node->parent() &&
256 node->index_in_parent() <
257 static_cast<int>(node->parent()->PlatformChildCount()) - 1) {
258 return node->parent()->PlatformGetChild(node->index_in_parent() + 1);
260 node = node->parent();
263 return NULL;
266 BrowserAccessibility* BrowserAccessibilityManager::PreviousInTreeOrder(
267 BrowserAccessibility* node) {
268 if (!node)
269 return NULL;
271 if (node->parent() && node->index_in_parent() > 0) {
272 node = node->parent()->PlatformGetChild(node->index_in_parent() - 1);
273 while (node->PlatformChildCount() > 0)
274 node = node->PlatformGetChild(node->PlatformChildCount() - 1);
275 return node;
278 return node->parent();
281 void BrowserAccessibilityManager::UpdateNodesForTesting(
282 const ui::AXNodeData& node1,
283 const ui::AXNodeData& node2 /* = ui::AXNodeData() */,
284 const ui::AXNodeData& node3 /* = ui::AXNodeData() */,
285 const ui::AXNodeData& node4 /* = ui::AXNodeData() */,
286 const ui::AXNodeData& node5 /* = ui::AXNodeData() */,
287 const ui::AXNodeData& node6 /* = ui::AXNodeData() */,
288 const ui::AXNodeData& node7 /* = ui::AXNodeData() */) {
289 std::vector<ui::AXNodeData> nodes;
290 nodes.push_back(node1);
291 if (node2.id != ui::AXNodeData().id)
292 nodes.push_back(node2);
293 if (node3.id != ui::AXNodeData().id)
294 nodes.push_back(node3);
295 if (node4.id != ui::AXNodeData().id)
296 nodes.push_back(node4);
297 if (node5.id != ui::AXNodeData().id)
298 nodes.push_back(node5);
299 if (node6.id != ui::AXNodeData().id)
300 nodes.push_back(node6);
301 if (node7.id != ui::AXNodeData().id)
302 nodes.push_back(node7);
303 UpdateNodes(nodes);
306 bool BrowserAccessibilityManager::UpdateNodes(
307 const std::vector<ui::AXNodeData>& nodes) {
308 bool success = true;
310 // First, update all of the nodes in the tree.
311 for (size_t i = 0; i < nodes.size() && success; i++) {
312 if (!UpdateNode(nodes[i]))
313 success = false;
316 // In a second pass, call PostInitialize on each one - this must
317 // be called after all of each node's children are initialized too.
318 for (size_t i = 0; i < nodes.size() && success; i++) {
319 // Note: it's not a bug for nodes[i].id to not be found in the tree.
320 // Consider this example:
321 // Before:
322 // A
323 // B
324 // C
325 // D
326 // E
327 // F
328 // After:
329 // A
330 // B
331 // C
332 // F
333 // D
334 // In this example, F is being reparented. The renderer scans the tree
335 // in order. If can't update "C" to add "F" as a child, when "F" is still
336 // a child of "E". So it first updates "E", to remove "F" as a child.
337 // Later, it ends up deleting "E". So when we get here, "E" was updated as
338 // part of this sequence but it no longer exists in the final tree, so
339 // there's nothing to postinitialize.
340 BrowserAccessibility* instance = GetFromRendererID(nodes[i].id);
341 if (instance)
342 instance->PostInitialize();
345 if (!success) {
346 // A bad accessibility tree could lead to memory corruption.
347 // Ask the delegate to crash the renderer, or if not available,
348 // crash the browser.
349 if (delegate_)
350 delegate_->FatalAccessibilityTreeError();
351 else
352 CHECK(false);
355 return success;
358 BrowserAccessibility* BrowserAccessibilityManager::CreateNode(
359 BrowserAccessibility* parent,
360 int32 renderer_id,
361 int32 index_in_parent) {
362 BrowserAccessibility* node = factory_->Create();
363 node->InitializeTreeStructure(
364 this, parent, renderer_id, index_in_parent);
365 AddNodeToMap(node);
366 return node;
369 void BrowserAccessibilityManager::AddNodeToMap(BrowserAccessibility* node) {
370 renderer_id_map_[node->renderer_id()] = node;
373 bool BrowserAccessibilityManager::UpdateNode(const ui::AXNodeData& src) {
374 // This method updates one node in the tree based on serialized data
375 // received from the renderer.
377 // Create a set of child ids in |src| for fast lookup. If a duplicate id is
378 // found, exit now with a fatal error before changing anything else.
379 std::set<int32> new_child_ids;
380 for (size_t i = 0; i < src.child_ids.size(); ++i) {
381 if (new_child_ids.find(src.child_ids[i]) != new_child_ids.end())
382 return false;
383 new_child_ids.insert(src.child_ids[i]);
386 // Look up the node by id. If it's not found, then either the root
387 // of the tree is being swapped, or we're out of sync with the renderer
388 // and this is a serious error.
389 BrowserAccessibility* instance = GetFromRendererID(src.id);
390 if (!instance) {
391 if (src.role != ui::AX_ROLE_ROOT_WEB_AREA)
392 return false;
393 instance = CreateNode(NULL, src.id, 0);
396 // Update all of the node-specific data, like its role, state, name, etc.
397 instance->InitializeData(src);
400 // Update the children in three steps:
402 // 1. Iterate over the old children and delete nodes that are no longer
403 // in the tree.
404 // 2. Build up a vector of new children, reusing children that haven't
405 // changed (but may have been reordered) and adding new empty
406 // objects for new children.
407 // 3. Swap in the new children vector for the old one.
409 // Delete any previous children of this instance that are no longer
410 // children first. We make a deletion-only pass first to prevent a
411 // node that's being reparented from being the child of both its old
412 // parent and new parent, which could lead to a double-free.
413 // If a node is reparented, the renderer will always send us a fresh
414 // copy of the node.
415 const std::vector<BrowserAccessibility*>& old_children = instance->children();
416 for (size_t i = 0; i < old_children.size(); ++i) {
417 int old_id = old_children[i]->renderer_id();
418 if (new_child_ids.find(old_id) == new_child_ids.end())
419 old_children[i]->Destroy();
422 // Now build a vector of new children, reusing objects that were already
423 // children of this node before.
424 std::vector<BrowserAccessibility*> new_children;
425 bool success = true;
426 for (size_t i = 0; i < src.child_ids.size(); i++) {
427 int32 child_renderer_id = src.child_ids[i];
428 int32 index_in_parent = static_cast<int32>(i);
429 BrowserAccessibility* child = GetFromRendererID(child_renderer_id);
430 if (child) {
431 if (child->parent() != instance) {
432 // This is a serious error - nodes should never be reparented.
433 // If this case occurs, continue so this node isn't left in an
434 // inconsistent state, but return failure at the end.
435 success = false;
436 continue;
438 child->UpdateParent(instance, index_in_parent);
439 } else {
440 child = CreateNode(instance, child_renderer_id, index_in_parent);
442 new_children.push_back(child);
445 // Finally, swap in the new children vector for the old.
446 instance->SwapChildren(new_children);
448 // Handle the case where this node is the new root of the tree.
449 if (src.role == ui::AX_ROLE_ROOT_WEB_AREA &&
450 (!root_ || root_->renderer_id() != src.id)) {
451 if (root_)
452 root_->Destroy();
453 if (focus_ == root_)
454 SetFocus(instance, false);
455 SetRoot(instance);
458 // Keep track of what node is focused.
459 if (src.role != ui::AX_ROLE_ROOT_WEB_AREA &&
460 src.role != ui::AX_ROLE_WEB_AREA &&
461 (src.state >> ui::AX_STATE_FOCUSED & 1)) {
462 SetFocus(instance, false);
464 return success;
467 } // namespace content