Index: content/browser/accessibility/#browser_accessibility_manager.cc# |
diff --git a/content/browser/accessibility/#browser_accessibility_manager.cc# b/content/browser/accessibility/#browser_accessibility_manager.cc# |
new file mode 100644 |
index 0000000000000000000000000000000000000000..b84ff231544b5e91d1365a9eb3dfe9cb8b59999d |
--- /dev/null |
+++ b/content/browser/accessibility/#browser_accessibility_manager.cc# |
@@ -0,0 +1,401 @@ |
+// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "content/browser/accessibility/browser_accessibility_manager.h" |
+ |
+#include "base/logging.h" |
+#include "content/browser/accessibility/browser_accessibility.h" |
+#include "content/common/accessibility_messages.h" |
+ |
+namespace content { |
+ |
+ui::AXTreeUpdate MakeAXTreeUpdate( |
+ const ui::AXNodeData& node1, |
+ const ui::AXNodeData& node2 /* = ui::AXNodeData() */, |
+ const ui::AXNodeData& node3 /* = ui::AXNodeData() */, |
+ const ui::AXNodeData& node4 /* = ui::AXNodeData() */, |
+ const ui::AXNodeData& node5 /* = ui::AXNodeData() */, |
+ const ui::AXNodeData& node6 /* = ui::AXNodeData() */, |
+ const ui::AXNodeData& node7 /* = ui::AXNodeData() */, |
+ const ui::AXNodeData& node8 /* = ui::AXNodeData() */, |
+ const ui::AXNodeData& node9 /* = ui::AXNodeData() */) { |
+ CR_DEFINE_STATIC_LOCAL(ui::AXNodeData, empty_data, ()); |
+ int32 no_id = empty_data.id; |
+ |
+ ui::AXTreeUpdate update; |
+ update.nodes.push_back(node1); |
+ if (node2.id != no_id) |
+ update.nodes.push_back(node2); |
+ if (node3.id != no_id) |
+ update.nodes.push_back(node3); |
+ if (node4.id != no_id) |
+ update.nodes.push_back(node4); |
+ if (node5.id != no_id) |
+ update.nodes.push_back(node5); |
+ if (node6.id != no_id) |
+ update.nodes.push_back(node6); |
+ if (node7.id != no_id) |
+ update.nodes.push_back(node7); |
+ if (node8.id != no_id) |
+ update.nodes.push_back(node8); |
+ if (node9.id != no_id) |
+ update.nodes.push_back(node9); |
+ return update; |
+} |
+ |
+BrowserAccessibility* BrowserAccessibilityFactory::Create() { |
+ return BrowserAccessibility::Create(); |
+} |
+ |
+#if !defined(OS_MACOSX) && \ |
+ !defined(OS_WIN) && \ |
+ !defined(OS_ANDROID) \ |
+// We have subclassess of BrowserAccessibilityManager on Mac, Win, and Android. |
+// These are the default implementations of these functions |
+ |
+// static |
+BrowserAccessibilityManager* BrowserAccessibilityManager::Create( |
+ const ui::AXTreeUpdate& initial_tree, |
+ BrowserAccessibilityDelegate* delegate, |
+ BrowserAccessibilityFactory* factory) { |
+ return new BrowserAccessibilityManager(initial_tree, delegate, factory); |
+} |
+ |
+// static |
+ui::AXTreeUpdate BrowserAccessibilityManager::GetEmptyDocument() { |
+ ui::AXNodeData empty_document; |
+ empty_document.id = 0; |
+ empty_document.role = ui::AX_ROLE_ROOT_WEB_AREA; |
+ ui::AXTreeUpdate update; |
+ update.nodes.push_back(empty_document); |
+ return update; |
+} |
+#endif |
+ |
+BrowserAccessibilityManager::BrowserAccessibilityManager( |
+ BrowserAccessibilityDelegate* delegate, |
+ BrowserAccessibilityFactory* factory) |
+ : delegate_(delegate), |
+ factory_(factory), |
+ tree_(new ui::AXTree()), |
+ focus_(NULL), |
+ osk_state_(OSK_ALLOWED) { |
+ tree_->SetDelegate(this); |
+} |
+ |
+BrowserAccessibilityManager::BrowserAccessibilityManager( |
+ const ui::AXTreeUpdate& initial_tree, |
+ BrowserAccessibilityDelegate* delegate, |
+ BrowserAccessibilityFactory* factory) |
+ : delegate_(delegate), |
+ factory_(factory), |
+ tree_(new ui::AXTree()), |
+ focus_(NULL), |
+ osk_state_(OSK_ALLOWED) { |
+ tree_->SetDelegate(this); |
+ Initialize(initial_tree); |
+} |
+ |
+BrowserAccessibilityManager::~BrowserAccessibilityManager() { |
+ tree_.reset(NULL); |
+} |
+ |
+void BrowserAccessibilityManager::Initialize( |
+ const ui::AXTreeUpdate& initial_tree) { |
+ if (!tree_->Unserialize(initial_tree)) { |
+ if (delegate_) { |
+ LOG(ERROR) << tree_->error(); |
+ delegate_->AccessibilityFatalError(); |
+ } else { |
+ LOG(FATAL) << tree_->error(); |
+ } |
+ } |
+ |
+ if (!focus_) |
+ SetFocus(tree_->GetRoot(), false); |
+} |
+ |
+BrowserAccessibility* BrowserAccessibilityManager::GetRoot() { |
+ return GetFromAXNode(tree_->GetRoot()); |
+} |
+ |
+BrowserAccessibility* BrowserAccessibilityManager::GetFromAXNode( |
+ ui::AXNode* node) { |
+ return GetFromID(node->id()); |
+} |
+ |
+BrowserAccessibility* BrowserAccessibilityManager::GetFromID(int32 id) { |
+ base::hash_map<int32, BrowserAccessibility*>::iterator iter = |
+ id_wrapper_map_.find(id); |
+ if (iter != id_wrapper_map_.end()) |
+ return iter->second; |
+ return NULL; |
+} |
+ |
+void BrowserAccessibilityManager::OnWindowFocused() { |
+ if (focus_) |
+ NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, GetFromAXNode(focus_)); |
+} |
+ |
+void BrowserAccessibilityManager::OnWindowBlurred() { |
+ if (focus_) |
+ NotifyAccessibilityEvent(ui::AX_EVENT_BLUR, GetFromAXNode(focus_)); |
+} |
+ |
+void BrowserAccessibilityManager::OnNavigation(bool is_reload) { |
+ // Exit if we don't even have the first document loaded yet. |
+ if (GetRoot()->GetId() == 0) |
+ return; |
+ |
+ LOG(ERROR) << "AX: BrowserAccessibilityManager::OnNavigation " << is_reload; |
+ // Create an update that replaces the current tree with an empty document |
+ // (which should be in the "busy" state by default) and apply it. |
+ ui::AXTreeUpdate update = GetEmptyDocument(); |
+ |
+ LOG(ERROR) << "AX: OnNavigation empty doc update state: " |
+ << update.nodes[0].state; |
+ |
+ update.nodes[0].id = GetRoot()->GetId(); |
+ |
+ LOG(ERROR) << "AX: State before unserializing the empty doc: " |
+ << GetRoot()->GetState(); |
+ LOG(ERROR) << "AX: Root id before unserializing the empty doc: " |
+ << GetRoot()->GetId(); |
+ LOG(ERROR) << "AX: Root children before: " |
+ << GetRoot()->PlatformChildCount(); |
+ |
+ LOG(ERROR) << "AX: State of first node in update: " |
+ << update.nodes[0].state; |
+ |
+ CHECK(tree_->Unserialize(update)); |
+ LOG(ERROR) << "AX: State after unserializing the empty doc: " |
+ << GetRoot()->GetState(); |
+ LOG(ERROR) << "AX: Root id after unserializing the empty doc: " |
+ << GetRoot()->GetId(); |
+ LOG(ERROR) << "AX: Root children after: " |
+ << GetRoot()->PlatformChildCount(); |
+} |
+ |
+void BrowserAccessibilityManager::GotMouseDown() { |
+ osk_state_ = OSK_ALLOWED_WITHIN_FOCUSED_OBJECT; |
+ NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, GetFromAXNode(focus_)); |
+} |
+ |
+bool BrowserAccessibilityManager::UseRootScrollOffsetsWhenComputingBounds() { |
+ return true; |
+} |
+ |
+void BrowserAccessibilityManager::OnAccessibilityEvents( |
+ const std::vector<AccessibilityHostMsg_EventParams>& params) { |
+ bool should_send_initial_focus = false; |
+ |
+ // Process all changes to the accessibility tree first. |
+ for (uint32 index = 0; index < params.size(); index++) { |
+ const AccessibilityHostMsg_EventParams& param = params[index]; |
+ if (!tree_->Unserialize(param.update)) { |
+ if (delegate_) { |
+ LOG(ERROR) << tree_->error(); |
+ delegate_->AccessibilityFatalError(); |
+ } else { |
+ CHECK(false) << tree_->error(); |
+ } |
+ return; |
+ } |
+ |
+ // Set focus to the root if it's not anywhere else. |
+ if (!focus_) { |
+ SetFocus(tree_->GetRoot(), false); |
+ should_send_initial_focus = true; |
+ } |
+ } |
+ |
+ OnTreeUpdateFinished(); |
+ |
+ if (should_send_initial_focus && |
+ (!delegate_ || delegate_->AccessibilityViewHasFocus())) { |
+ NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, GetFromAXNode(focus_)); |
+ } |
+ |
+ // Now iterate over the events again and fire the events. |
+ for (uint32 index = 0; index < params.size(); index++) { |
+ const AccessibilityHostMsg_EventParams& param = params[index]; |
+ |
+ // Find the node corresponding to the id that's the target of the |
+ // event (which may not be the root of the update tree). |
+ ui::AXNode* node = tree_->GetFromId(param.id); |
+ if (!node) |
+ continue; |
+ |
+ ui::AXEvent event_type = param.event_type; |
+ if (event_type == ui::AX_EVENT_FOCUS || |
+ event_type == ui::AX_EVENT_BLUR) { |
+ SetFocus(node, false); |
+ |
+ if (osk_state_ != OSK_DISALLOWED_BECAUSE_TAB_HIDDEN && |
+ osk_state_ != OSK_DISALLOWED_BECAUSE_TAB_JUST_APPEARED) |
+ osk_state_ = OSK_ALLOWED; |
+ |
+ // Don't send a native focus event if the window itself doesn't |
+ // have focus. |
+ if (delegate_ && !delegate_->AccessibilityViewHasFocus()) |
+ continue; |
+ } |
+ |
+ // Send the event event to the operating system. |
+ NotifyAccessibilityEvent(event_type, GetFromAXNode(node)); |
+ } |
+} |
+ |
+void BrowserAccessibilityManager::OnLocationChanges( |
+ const std::vector<AccessibilityHostMsg_LocationChangeParams>& params) { |
+ for (size_t i = 0; i < params.size(); ++i) { |
+ BrowserAccessibility* obj = GetFromID(params[i].id); |
+ if (!obj) |
+ continue; |
+ ui::AXNode* node = obj->node(); |
+ node->SetLocation(params[i].new_location); |
+ obj->OnLocationChanged(); |
+ } |
+} |
+ |
+BrowserAccessibility* BrowserAccessibilityManager::GetActiveDescendantFocus( |
+ BrowserAccessibility* root) { |
+ BrowserAccessibility* node = BrowserAccessibilityManager::GetFocus(root); |
+ if (!node) |
+ return NULL; |
+ |
+ int active_descendant_id; |
+ if (node->GetIntAttribute(ui::AX_ATTR_ACTIVEDESCENDANT_ID, |
+ &active_descendant_id)) { |
+ BrowserAccessibility* active_descendant = |
+ node->manager()->GetFromID(active_descendant_id); |
+ if (active_descendant) |
+ return active_descendant; |
+ } |
+ return node; |
+} |
+ |
+BrowserAccessibility* BrowserAccessibilityManager::GetFocus( |
+ BrowserAccessibility* root) { |
+ if (focus_ && (!root || focus_->IsDescendantOf(root->node()))) |
+ return GetFromAXNode(focus_); |
+ |
+ return NULL; |
+} |
+ |
+void BrowserAccessibilityManager::SetFocus(ui::AXNode* node, bool notify) { |
+ if (focus_ != node) |
+ focus_ = node; |
+ |
+ if (notify && node && delegate_) |
+ delegate_->AccessibilitySetFocus(node->id()); |
+} |
+ |
+void BrowserAccessibilityManager::SetFocus( |
+ BrowserAccessibility* obj, bool notify) { |
+ if (obj->node()) |
+ SetFocus(obj->node(), notify); |
+} |
+ |
+void BrowserAccessibilityManager::DoDefaultAction( |
+ const BrowserAccessibility& node) { |
+ if (delegate_) |
+ delegate_->AccessibilityDoDefaultAction(node.GetId()); |
+} |
+ |
+void BrowserAccessibilityManager::ScrollToMakeVisible( |
+ const BrowserAccessibility& node, gfx::Rect subfocus) { |
+ if (delegate_) { |
+ delegate_->AccessibilityScrollToMakeVisible(node.GetId(), subfocus); |
+ } |
+} |
+ |
+void BrowserAccessibilityManager::ScrollToPoint( |
+ const BrowserAccessibility& node, gfx::Point point) { |
+ if (delegate_) { |
+ delegate_->AccessibilityScrollToPoint(node.GetId(), point); |
+ } |
+} |
+ |
+void BrowserAccessibilityManager::SetTextSelection( |
+ const BrowserAccessibility& node, int start_offset, int end_offset) { |
+ if (delegate_) { |
+ delegate_->AccessibilitySetTextSelection( |
+ node.GetId(), start_offset, end_offset); |
+ } |
+} |
+ |
+gfx::Rect BrowserAccessibilityManager::GetViewBounds() { |
+ if (delegate_) |
+ return delegate_->AccessibilityGetViewBounds(); |
+ return gfx::Rect(); |
+} |
+ |
+BrowserAccessibility* BrowserAccessibilityManager::NextInTreeOrder( |
+ BrowserAccessibility* node) { |
+ if (!node) |
+ return NULL; |
+ |
+ if (node->PlatformChildCount() > 0) |
+ return node->PlatformGetChild(0); |
+ while (node) { |
+ if (node->GetParent() && |
+ node->GetIndexInParent() < |
+ static_cast<int>(node->GetParent()->PlatformChildCount()) - 1) { |
+ return node->GetParent()->PlatformGetChild(node->GetIndexInParent() + 1); |
+ } |
+ node = node->GetParent(); |
+ } |
+ |
+ return NULL; |
+} |
+ |
+BrowserAccessibility* BrowserAccessibilityManager::PreviousInTreeOrder( |
+ BrowserAccessibility* node) { |
+ if (!node) |
+ return NULL; |
+ |
+ if (node->GetParent() && node->GetIndexInParent() > 0) { |
+ node = node->GetParent()->PlatformGetChild(node->GetIndexInParent() - 1); |
+ while (node->PlatformChildCount() > 0) |
+ node = node->PlatformGetChild(node->PlatformChildCount() - 1); |
+ return node; |
+ } |
+ |
+ return node->GetParent(); |
+} |
+ |
+void BrowserAccessibilityManager::OnNodeWillBeDeleted(ui::AXNode* node) { |
+ if (node == focus_ && tree_) { |
+ if (node != tree_->GetRoot()) |
+ SetFocus(tree_->GetRoot(), false); |
+ else |
+ focus_ = NULL; |
+ } |
+ if (id_wrapper_map_.find(node->id()) == id_wrapper_map_.end()) |
+ return; |
+ GetFromAXNode(node)->Destroy(); |
+ id_wrapper_map_.erase(node->id()); |
+} |
+ |
+void BrowserAccessibilityManager::OnNodeCreated(ui::AXNode* node) { |
+ BrowserAccessibility* wrapper = factory_->Create(); |
+ wrapper->Init(this, node); |
+ id_wrapper_map_[node->id()] = wrapper; |
+ wrapper->OnDataChanged(); |
+} |
+ |
+void BrowserAccessibilityManager::OnNodeChanged(ui::AXNode* node) { |
+ GetFromAXNode(node)->OnDataChanged(); |
+} |
+ |
+void BrowserAccessibilityManager::OnNodeCreationFinished(ui::AXNode* node) { |
+ GetFromAXNode(node)->OnUpdateFinished(); |
+} |
+ |
+void BrowserAccessibilityManager::OnNodeChangeFinished(ui::AXNode* node) { |
+ GetFromAXNode(node)->OnUpdateFinished(); |
+} |
+ |
+} // namespace content |