diff options
Diffstat (limited to 'content/browser/accessibility/browser_accessibility_manager.cc')
-rw-r--r-- | content/browser/accessibility/browser_accessibility_manager.cc | 350 |
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 |