summaryrefslogtreecommitdiffstats
path: root/content/browser/accessibility/browser_accessibility_manager.cc
diff options
context:
space:
mode:
Diffstat (limited to 'content/browser/accessibility/browser_accessibility_manager.cc')
-rw-r--r--content/browser/accessibility/browser_accessibility_manager.cc350
1 files changed, 121 insertions, 229 deletions
diff --git a/content/browser/accessibility/browser_accessibility_manager.cc b/content/browser/accessibility/browser_accessibility_manager.cc
index b91f3c1..abc5884 100644
--- a/content/browser/accessibility/browser_accessibility_manager.cc
+++ b/content/browser/accessibility/browser_accessibility_manager.cc
@@ -10,6 +10,40 @@
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();
}
@@ -21,10 +55,10 @@ BrowserAccessibility* BrowserAccessibilityFactory::Create() {
// other platform, instantiate the base class.
// static
BrowserAccessibilityManager* BrowserAccessibilityManager::Create(
- const ui::AXNodeData& src,
+ const ui::AXTreeUpdate& initial_tree,
BrowserAccessibilityDelegate* delegate,
BrowserAccessibilityFactory* factory) {
- return new BrowserAccessibilityManager(src, delegate, factory);
+ return new BrowserAccessibilityManager(initial_tree, delegate, factory);
}
#endif
@@ -33,71 +67,84 @@ BrowserAccessibilityManager::BrowserAccessibilityManager(
BrowserAccessibilityFactory* factory)
: delegate_(delegate),
factory_(factory),
- root_(NULL),
+ tree_(new ui::AXTree()),
focus_(NULL),
osk_state_(OSK_ALLOWED) {
+ tree_->SetDelegate(this);
}
BrowserAccessibilityManager::BrowserAccessibilityManager(
- const ui::AXNodeData& src,
+ const ui::AXTreeUpdate& initial_tree,
BrowserAccessibilityDelegate* delegate,
BrowserAccessibilityFactory* factory)
: delegate_(delegate),
factory_(factory),
- root_(NULL),
+ tree_(new ui::AXTree()),
focus_(NULL),
osk_state_(OSK_ALLOWED) {
- Initialize(src);
+ tree_->SetDelegate(this);
+ Initialize(initial_tree);
}
BrowserAccessibilityManager::~BrowserAccessibilityManager() {
- if (root_)
- root_->Destroy();
+ tree_.reset(NULL);
}
-void BrowserAccessibilityManager::Initialize(const ui::AXNodeData src) {
- std::vector<ui::AXNodeData> nodes;
- nodes.push_back(src);
- if (!UpdateNodes(nodes))
- return;
+void BrowserAccessibilityManager::Initialize(
+ const ui::AXTreeUpdate& initial_tree) {
+ if (!tree_->Unserialize(initial_tree)) {
+ if (delegate_) {
+ LOG(ERROR) << tree_->error();
+ delegate_->FatalAccessibilityTreeError();
+ } else {
+ LOG(FATAL) << tree_->error();
+ }
+ }
+
if (!focus_)
- SetFocus(root_, false);
+ SetFocus(tree_->GetRoot(), false);
}
// static
-ui::AXNodeData BrowserAccessibilityManager::GetEmptyDocument() {
+ui::AXTreeUpdate BrowserAccessibilityManager::GetEmptyDocument() {
ui::AXNodeData empty_document;
empty_document.id = 0;
empty_document.role = ui::AX_ROLE_ROOT_WEB_AREA;
- return empty_document;
+ ui::AXTreeUpdate update;
+ update.nodes.push_back(empty_document);
+ return update;
}
BrowserAccessibility* BrowserAccessibilityManager::GetRoot() {
- return root_;
+ return GetFromAXNode(tree_->GetRoot());
}
-BrowserAccessibility* BrowserAccessibilityManager::GetFromRendererID(
- int32 renderer_id) {
+BrowserAccessibility* BrowserAccessibilityManager::GetFromAXNode(
+ ui::AXNode* node) {
+ return GetFromID(node->id());
+}
+
+BrowserAccessibility* BrowserAccessibilityManager::GetFromID(int32 id) {
base::hash_map<int32, BrowserAccessibility*>::iterator iter =
- renderer_id_map_.find(renderer_id);
- if (iter != renderer_id_map_.end())
+ 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, focus_);
+ NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, GetFromAXNode(focus_));
}
void BrowserAccessibilityManager::OnWindowBlurred() {
if (focus_)
- NotifyAccessibilityEvent(ui::AX_EVENT_BLUR, focus_);
+ NotifyAccessibilityEvent(ui::AX_EVENT_BLUR, GetFromAXNode(focus_));
}
void BrowserAccessibilityManager::GotMouseDown() {
osk_state_ = OSK_ALLOWED_WITHIN_FOCUSED_OBJECT;
- NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, focus_);
+ NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, GetFromAXNode(focus_));
}
bool BrowserAccessibilityManager::IsOSKAllowed(const gfx::Rect& bounds) {
@@ -112,13 +159,6 @@ bool BrowserAccessibilityManager::UseRootScrollOffsetsWhenComputingBounds() {
return true;
}
-void BrowserAccessibilityManager::RemoveNode(BrowserAccessibility* node) {
- if (node == focus_)
- SetFocus(root_, false);
- int renderer_id = node->GetId();
- renderer_id_map_.erase(renderer_id);
-}
-
void BrowserAccessibilityManager::OnAccessibilityEvents(
const std::vector<AccessibilityHostMsg_EventParams>& params) {
bool should_send_initial_focus = false;
@@ -126,22 +166,26 @@ void BrowserAccessibilityManager::OnAccessibilityEvents(
// Process all changes to the accessibility tree first.
for (uint32 index = 0; index < params.size(); index++) {
const AccessibilityHostMsg_EventParams& param = params[index];
- if (!UpdateNodes(param.update.nodes))
+ if (!tree_->Unserialize(param.update)) {
+ if (delegate_) {
+ LOG(ERROR) << tree_->error();
+ delegate_->FatalAccessibilityTreeError();
+ } else {
+ CHECK(false) << tree_->error();
+ }
return;
+ }
- // Set initial focus when a page is loaded.
- ui::AXEvent event_type = param.event_type;
- if (event_type == ui::AX_EVENT_LOAD_COMPLETE) {
- if (!focus_) {
- SetFocus(root_, false);
- should_send_initial_focus = true;
- }
+ // Set focus to the root if it's not anywhere else.
+ if (!focus_) {
+ SetFocus(tree_->GetRoot(), false);
+ should_send_initial_focus = true;
}
}
if (should_send_initial_focus &&
(!delegate_ || delegate_->HasFocus())) {
- NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, focus_);
+ NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, GetFromAXNode(focus_));
}
// Now iterate over the events again and fire the events.
@@ -150,7 +194,7 @@ void BrowserAccessibilityManager::OnAccessibilityEvents(
// Find the node corresponding to the id that's the target of the
// event (which may not be the root of the update tree).
- BrowserAccessibility* node = GetFromRendererID(param.id);
+ ui::AXNode* node = tree_->GetFromId(param.id);
if (!node)
continue;
@@ -170,39 +214,42 @@ void BrowserAccessibilityManager::OnAccessibilityEvents(
}
// Send the event event to the operating system.
- NotifyAccessibilityEvent(event_type, node);
+ NotifyAccessibilityEvent(event_type, GetFromAXNode(node));
}
}
void BrowserAccessibilityManager::OnLocationChanges(
const std::vector<AccessibilityHostMsg_LocationChangeParams>& params) {
for (size_t i = 0; i < params.size(); ++i) {
- BrowserAccessibility* node = GetFromRendererID(params[i].id);
- if (node)
- node->SetLocation(params[i].new_location);
+ BrowserAccessibility* obj = GetFromID(params[i].id);
+ if (!obj)
+ continue;
+ ui::AXNode* node = obj->node();
+ node->SetLocation(params[i].new_location);
+ obj->OnLocationChanged();
}
}
BrowserAccessibility* BrowserAccessibilityManager::GetFocus(
BrowserAccessibility* root) {
- if (focus_ && (!root || focus_->IsDescendantOf(root)))
- return focus_;
+ if (focus_ && (!root || focus_->IsDescendantOf(root->node())))
+ return GetFromAXNode(focus_);
return NULL;
}
-void BrowserAccessibilityManager::SetFocus(
- BrowserAccessibility* node, bool notify) {
+void BrowserAccessibilityManager::SetFocus(ui::AXNode* node, bool notify) {
if (focus_ != node)
focus_ = node;
if (notify && node && delegate_)
- delegate_->SetAccessibilityFocus(node->GetId());
+ delegate_->SetAccessibilityFocus(node->id());
}
-void BrowserAccessibilityManager::SetRoot(BrowserAccessibility* node) {
- root_ = node;
- OnRootChanged();
+void BrowserAccessibilityManager::SetFocus(
+ BrowserAccessibility* obj, bool notify) {
+ if (obj->node())
+ SetFocus(obj->node(), notify);
}
void BrowserAccessibilityManager::DoDefaultAction(
@@ -273,191 +320,36 @@ BrowserAccessibility* BrowserAccessibilityManager::PreviousInTreeOrder(
return node->GetParent();
}
-void BrowserAccessibilityManager::UpdateNodesForTesting(
- 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() */) {
- std::vector<ui::AXNodeData> nodes;
- nodes.push_back(node1);
- if (node2.id != ui::AXNodeData().id)
- nodes.push_back(node2);
- if (node3.id != ui::AXNodeData().id)
- nodes.push_back(node3);
- if (node4.id != ui::AXNodeData().id)
- nodes.push_back(node4);
- if (node5.id != ui::AXNodeData().id)
- nodes.push_back(node5);
- if (node6.id != ui::AXNodeData().id)
- nodes.push_back(node6);
- if (node7.id != ui::AXNodeData().id)
- nodes.push_back(node7);
- UpdateNodes(nodes);
-}
-
-bool BrowserAccessibilityManager::UpdateNodes(
- const std::vector<ui::AXNodeData>& nodes) {
- bool success = true;
-
- // First, update all of the nodes in the tree.
- for (size_t i = 0; i < nodes.size() && success; i++) {
- if (!UpdateNode(nodes[i]))
- success = false;
- }
-
- // In a second pass, call PostInitialize on each one - this must
- // be called after all of each node's children are initialized too.
- for (size_t i = 0; i < nodes.size() && success; i++) {
- // Note: it's not a bug for nodes[i].id to not be found in the tree.
- // Consider this example:
- // Before:
- // A
- // B
- // C
- // D
- // E
- // F
- // After:
- // A
- // B
- // C
- // F
- // D
- // In this example, F is being reparented. The renderer scans the tree
- // in order. If can't update "C" to add "F" as a child, when "F" is still
- // a child of "E". So it first updates "E", to remove "F" as a child.
- // Later, it ends up deleting "E". So when we get here, "E" was updated as
- // part of this sequence but it no longer exists in the final tree, so
- // there's nothing to postinitialize.
- BrowserAccessibility* instance = GetFromRendererID(nodes[i].id);
- if (instance)
- instance->PostInitialize();
- }
-
- if (!success) {
- // A bad accessibility tree could lead to memory corruption.
- // Ask the delegate to crash the renderer, or if not available,
- // crash the browser.
- if (delegate_)
- delegate_->FatalAccessibilityTreeError();
+void BrowserAccessibilityManager::OnNodeWillBeDeleted(ui::AXNode* node) {
+ if (node == focus_ && tree_) {
+ if (node != tree_->GetRoot())
+ SetFocus(tree_->GetRoot(), false);
else
- CHECK(false);
+ focus_ = NULL;
}
-
- return success;
+ if (id_wrapper_map_.find(node->id()) == id_wrapper_map_.end())
+ return;
+ GetFromAXNode(node)->Destroy();
+ id_wrapper_map_.erase(node->id());
}
-BrowserAccessibility* BrowserAccessibilityManager::CreateNode(
- BrowserAccessibility* parent,
- int32 renderer_id,
- int32 index_in_parent) {
- BrowserAccessibility* node = factory_->Create();
- node->InitializeTreeStructure(
- this, parent, renderer_id, index_in_parent);
- AddNodeToMap(node);
- return node;
+void BrowserAccessibilityManager::OnNodeCreated(ui::AXNode* node) {
+ BrowserAccessibility* wrapper = factory_->Create();
+ wrapper->Init(this, node);
+ id_wrapper_map_[node->id()] = wrapper;
+ wrapper->OnDataChanged();
}
-void BrowserAccessibilityManager::AddNodeToMap(BrowserAccessibility* node) {
- renderer_id_map_[node->GetId()] = node;
+void BrowserAccessibilityManager::OnNodeChanged(ui::AXNode* node) {
+ GetFromAXNode(node)->OnDataChanged();
}
-bool BrowserAccessibilityManager::UpdateNode(const ui::AXNodeData& src) {
- // This method updates one node in the tree based on serialized data
- // received from the renderer.
-
- // Create a set of child ids in |src| for fast lookup. If a duplicate id is
- // found, exit now with a fatal error before changing anything else.
- std::set<int32> new_child_ids;
- for (size_t i = 0; i < src.child_ids.size(); ++i) {
- if (new_child_ids.find(src.child_ids[i]) != new_child_ids.end())
- return false;
- new_child_ids.insert(src.child_ids[i]);
- }
-
- // Look up the node by id. If it's not found, then either the root
- // of the tree is being swapped, or we're out of sync with the renderer
- // and this is a serious error.
- BrowserAccessibility* instance = GetFromRendererID(src.id);
- if (!instance) {
- if (src.role != ui::AX_ROLE_ROOT_WEB_AREA)
- return false;
- instance = CreateNode(NULL, src.id, 0);
- }
-
- // Update all of the node-specific data, like its role, state, name, etc.
- instance->InitializeData(src);
-
- //
- // Update the children in three steps:
- //
- // 1. Iterate over the old children and delete nodes that are no longer
- // in the tree.
- // 2. Build up a vector of new children, reusing children that haven't
- // changed (but may have been reordered) and adding new empty
- // objects for new children.
- // 3. Swap in the new children vector for the old one.
-
- // Delete any previous children of this instance that are no longer
- // children first. We make a deletion-only pass first to prevent a
- // node that's being reparented from being the child of both its old
- // parent and new parent, which could lead to a double-free.
- // If a node is reparented, the renderer will always send us a fresh
- // copy of the node.
- const std::vector<BrowserAccessibility*>& old_children =
- instance->deprecated_children();
- for (size_t i = 0; i < old_children.size(); ++i) {
- int old_id = old_children[i]->GetId();
- if (new_child_ids.find(old_id) == new_child_ids.end())
- old_children[i]->Destroy();
- }
-
- // Now build a vector of new children, reusing objects that were already
- // children of this node before.
- std::vector<BrowserAccessibility*> new_children;
- bool success = true;
- for (size_t i = 0; i < src.child_ids.size(); i++) {
- int32 child_renderer_id = src.child_ids[i];
- int32 index_in_parent = static_cast<int32>(i);
- BrowserAccessibility* child = GetFromRendererID(child_renderer_id);
- if (child) {
- if (child->GetParent() != instance) {
- // This is a serious error - nodes should never be reparented.
- // If this case occurs, continue so this node isn't left in an
- // inconsistent state, but return failure at the end.
- success = false;
- continue;
- }
- child->UpdateParent(instance, index_in_parent);
- } else {
- child = CreateNode(instance, child_renderer_id, index_in_parent);
- }
- new_children.push_back(child);
- }
-
- // Finally, swap in the new children vector for the old.
- instance->SwapChildren(new_children);
-
- // Handle the case where this node is the new root of the tree.
- if (src.role == ui::AX_ROLE_ROOT_WEB_AREA &&
- (!root_ || root_->GetId() != src.id)) {
- if (root_)
- root_->Destroy();
- if (focus_ == root_)
- SetFocus(instance, false);
- SetRoot(instance);
- }
+void BrowserAccessibilityManager::OnNodeCreationFinished(ui::AXNode* node) {
+ GetFromAXNode(node)->OnUpdateFinished();
+}
- // Keep track of what node is focused.
- if (src.role != ui::AX_ROLE_ROOT_WEB_AREA &&
- src.role != ui::AX_ROLE_WEB_AREA &&
- (src.state >> ui::AX_STATE_FOCUSED & 1)) {
- SetFocus(instance, false);
- }
- return success;
+void BrowserAccessibilityManager::OnNodeChangeFinished(ui::AXNode* node) {
+ GetFromAXNode(node)->OnUpdateFinished();
}
} // namespace content