diff options
Diffstat (limited to 'content/browser')
17 files changed, 487 insertions, 628 deletions
diff --git a/content/browser/accessibility/accessibility_ipc_error_browsertest.cc b/content/browser/accessibility/accessibility_ipc_error_browsertest.cc index 7ff3d27..6c47f94 100644 --- a/content/browser/accessibility/accessibility_ipc_error_browsertest.cc +++ b/content/browser/accessibility/accessibility_ipc_error_browsertest.cc @@ -4,7 +4,7 @@ #include "content/browser/frame_host/render_frame_host_impl.h" #include "content/browser/web_contents/web_contents_impl.h" -#include "content/common/accessibility_messages.h" +#include "content/public/browser/ax_event_notification_details.h" #include "content/public/test/browser_test_utils.h" #include "content/public/test/content_browser_test.h" #include "content/public/test/content_browser_test_utils.h" @@ -153,8 +153,8 @@ IN_PROC_BROWSER_TEST_F(AccessibilityIpcErrorBrowserTest, // Construct a bad accessibility message that BrowserAccessibilityManager // will reject. - std::vector<AccessibilityHostMsg_EventParams> bad_accessibility_event_list; - bad_accessibility_event_list.push_back(AccessibilityHostMsg_EventParams()); + std::vector<AXEventNotificationDetails> bad_accessibility_event_list; + bad_accessibility_event_list.push_back(AXEventNotificationDetails()); bad_accessibility_event_list[0].update.node_id_to_clear = -2; // We should be able to reset accessibility |max_iterations-1| times diff --git a/content/browser/accessibility/ax_tree_id_registry.cc b/content/browser/accessibility/ax_tree_id_registry.cc new file mode 100644 index 0000000..5973cbf --- /dev/null +++ b/content/browser/accessibility/ax_tree_id_registry.cc @@ -0,0 +1,61 @@ +// Copyright 2014 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/ax_tree_id_registry.h" + +#include "base/memory/singleton.h" + +namespace content { + +// static +const AXTreeIDRegistry::AXTreeID AXTreeIDRegistry::kNoAXTreeID = -1; + +// static +AXTreeIDRegistry* AXTreeIDRegistry::GetInstance() { + return Singleton<AXTreeIDRegistry>::get(); +} + +AXTreeIDRegistry::AXTreeID AXTreeIDRegistry::GetOrCreateAXTreeID( + int process_id, int routing_id) { + FrameID frame_id(process_id, routing_id); + std::map<FrameID, AXTreeID>::iterator it; + it = frame_to_ax_tree_id_map_.find(frame_id); + if (it != frame_to_ax_tree_id_map_.end()) + return it->second; + + AXTreeID new_id = ++ax_tree_id_counter_; + frame_to_ax_tree_id_map_[frame_id] = new_id; + ax_tree_to_frame_id_map_[new_id] = frame_id; + + return new_id; +} + +AXTreeIDRegistry::FrameID AXTreeIDRegistry::GetFrameID( + AXTreeIDRegistry::AXTreeID ax_tree_id) { + std::map<AXTreeID, FrameID>::iterator it; + it = ax_tree_to_frame_id_map_.find(ax_tree_id); + if (it != ax_tree_to_frame_id_map_.end()) + return it->second; + + return FrameID(-1, -1); +} + +void AXTreeIDRegistry::RemoveAXTreeID(AXTreeIDRegistry::AXTreeID ax_tree_id) { + std::map<AXTreeID, FrameID>::iterator it; + it = ax_tree_to_frame_id_map_.find(ax_tree_id); + if (it != ax_tree_to_frame_id_map_.end()) { + frame_to_ax_tree_id_map_.erase(it->second); + ax_tree_to_frame_id_map_.erase(it); + } +} + +AXTreeIDRegistry::AXTreeIDRegistry() : ax_tree_id_counter_(-1) { + // Always populate default desktop tree value (0 -> 0, 0). + GetOrCreateAXTreeID(0, 0); +} + +AXTreeIDRegistry::~AXTreeIDRegistry() { +} + +} // namespace content diff --git a/content/browser/accessibility/ax_tree_id_registry.h b/content/browser/accessibility/ax_tree_id_registry.h new file mode 100644 index 0000000..e3ffca9 --- /dev/null +++ b/content/browser/accessibility/ax_tree_id_registry.h @@ -0,0 +1,55 @@ +// Copyright 2014 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. + +#ifndef CONTENT_BROWSER_ACCESSIBILITY_AX_TREE_ID_REGISTRY_H_ +#define CONTENT_BROWSER_ACCESSIBILITY_AX_TREE_ID_REGISTRY_H_ + +#include <map> + +#include "base/stl_util.h" + +template <typename T> +struct DefaultSingletonTraits; + +namespace content { + +// A class which generates a unique id given a process id and frame routing id. +class AXTreeIDRegistry { + public: + typedef std::pair<int, int> FrameID; + + typedef int AXTreeID; + + static const AXTreeID kNoAXTreeID; + + // Get the single instance of this class. + static AXTreeIDRegistry* GetInstance(); + + // Obtains a unique id given a |process_id| and |routing_id|. Placeholder + // for full implementation once out of process iframe accessibility finalizes. + AXTreeID GetOrCreateAXTreeID(int process_id, int routing_id); + FrameID GetFrameID(AXTreeID ax_tree_id); + void RemoveAXTreeID(AXTreeID ax_tree_id); + + private: + friend struct DefaultSingletonTraits<AXTreeIDRegistry>; + + AXTreeIDRegistry(); + virtual ~AXTreeIDRegistry(); + + // Tracks the current unique ax frame id. + AXTreeID ax_tree_id_counter_; + + // Maps an accessibility tree to its frame via ids. + std::map<AXTreeID, FrameID> ax_tree_to_frame_id_map_; + + // Maps frames to an accessibility tree via ids. + std::map<FrameID, AXTreeID> frame_to_ax_tree_id_map_; + + DISALLOW_COPY_AND_ASSIGN(AXTreeIDRegistry); +}; + +} // namespace content + +#endif // CONTENT_BROWSER_ACCESSIBILITY_AX_TREE_ID_REGISTRY_H_ diff --git a/content/browser/accessibility/browser_accessibility.cc b/content/browser/accessibility/browser_accessibility.cc index f3cf377..6b32ef2 100644 --- a/content/browser/accessibility/browser_accessibility.cc +++ b/content/browser/accessibility/browser_accessibility.cc @@ -61,9 +61,11 @@ bool BrowserAccessibility::PlatformIsLeaf() const { } uint32 BrowserAccessibility::PlatformChildCount() const { - if (GetBoolAttribute(ui::AX_ATTR_IS_AX_TREE_HOST)) { - // Check if the child frame currently exists. - if (manager_->delegate()->AccessibilityGetChildFrame(GetId())) + if (HasIntAttribute(ui::AX_ATTR_CHILD_TREE_ID)) { + BrowserAccessibilityManager* child_manager = + BrowserAccessibilityManager::FromID( + GetIntAttribute(ui::AX_ATTR_CHILD_TREE_ID)); + if (child_manager) return 1; return 0; @@ -92,9 +94,10 @@ BrowserAccessibility* BrowserAccessibility::PlatformGetChild( DCHECK(child_index < PlatformChildCount()); BrowserAccessibility* result = nullptr; - if (GetBoolAttribute(ui::AX_ATTR_IS_AX_TREE_HOST)) { + if (HasIntAttribute(ui::AX_ATTR_CHILD_TREE_ID)) { BrowserAccessibilityManager* child_manager = - manager_->delegate()->AccessibilityGetChildFrame(GetId()); + BrowserAccessibilityManager::FromID( + GetIntAttribute(ui::AX_ATTR_CHILD_TREE_ID)); if (child_manager) result = child_manager->GetRoot(); } else { @@ -153,15 +156,7 @@ BrowserAccessibility* BrowserAccessibility::GetParent() const { if (parent) return manager_->GetFromAXNode(parent); - if (!manager_->delegate()) - return NULL; - - BrowserAccessibility* host_node = - manager_->delegate()->AccessibilityGetParentFrame(); - if (!host_node) - return NULL; - - return host_node; + return manager_->GetParentNodeFromParentTree(); } int32 BrowserAccessibility::GetIndexInParent() const { @@ -693,20 +688,6 @@ int BrowserAccessibility::GetStaticTextLenRecursive() const { return len; } -BrowserAccessibility* BrowserAccessibility::GetParentForBoundsCalculation() - const { - if (!node_ || !manager_) - return NULL; - ui::AXNode* parent = node_->parent(); - if (parent) - return manager_->GetFromAXNode(parent); - - if (!manager_->delegate()) - return NULL; - - return manager_->delegate()->AccessibilityGetParentFrame(); -} - void BrowserAccessibility::FixEmptyBounds(gfx::Rect* bounds) const { if (bounds->width() > 0 && bounds->height() > 0) @@ -738,7 +719,7 @@ gfx::Rect BrowserAccessibility::ElementBoundsToLocalBounds(gfx::Rect bounds) // Walk up the parent chain. Every time we encounter a Web Area, offset // based on the scroll bars and then offset based on the origin of that // nested web area. - BrowserAccessibility* parent = GetParentForBoundsCalculation(); + BrowserAccessibility* parent = GetParent(); bool need_to_offset_web_area = (GetRole() == ui::AX_ROLE_WEB_AREA || GetRole() == ui::AX_ROLE_ROOT_WEB_AREA); @@ -767,7 +748,7 @@ gfx::Rect BrowserAccessibility::ElementBoundsToLocalBounds(gfx::Rect bounds) } need_to_offset_web_area = true; } - parent = parent->GetParentForBoundsCalculation(); + parent = parent->GetParent(); } return bounds; diff --git a/content/browser/accessibility/browser_accessibility.h b/content/browser/accessibility/browser_accessibility.h index 17297ba..679becf 100644 --- a/content/browser/accessibility/browser_accessibility.h +++ b/content/browser/accessibility/browser_accessibility.h @@ -282,11 +282,6 @@ class CONTENT_EXPORT BrowserAccessibility { // including this object if it's static text. int GetStaticTextLenRecursive() const; - // Similar to GetParent(), but includes nodes that are the host of a - // subtree rather than skipping over them - because they contain important - // bounds offsets. - BrowserAccessibility* GetParentForBoundsCalculation() const; - // If a bounding rectangle is empty, compute it based on the union of its // children, since most accessibility APIs don't like elements with no // bounds, but "virtual" elements in the accessibility tree that don't diff --git a/content/browser/accessibility/browser_accessibility_auralinux.cc b/content/browser/accessibility/browser_accessibility_auralinux.cc index c754880..9fb8e4b 100644 --- a/content/browser/accessibility/browser_accessibility_auralinux.cc +++ b/content/browser/accessibility/browser_accessibility_auralinux.cc @@ -763,6 +763,11 @@ void BrowserAccessibilityAuraLinux::OnDataChanged() { if (!atk_object_) { interface_mask_ = GetInterfaceMaskFromObject(this); atk_object_ = ATK_OBJECT(browser_accessibility_new(this)); + if (this->GetParent()) { + atk_object_set_parent( + atk_object_, + this->GetParent()->ToBrowserAccessibilityAuraLinux()->GetAtkObject()); + } } } diff --git a/content/browser/accessibility/browser_accessibility_manager.cc b/content/browser/accessibility/browser_accessibility_manager.cc index f20cce9..4ccca0e 100644 --- a/content/browser/accessibility/browser_accessibility_manager.cc +++ b/content/browser/accessibility/browser_accessibility_manager.cc @@ -11,6 +11,35 @@ namespace content { +namespace { + +// Search the tree recursively from |node| and return any node that has +// a child tree ID of |ax_tree_id|. +BrowserAccessibility* FindNodeWithChildTreeId(BrowserAccessibility* node, + int ax_tree_id) { + if (!node) + return nullptr; + + if (node->GetIntAttribute(ui::AX_ATTR_CHILD_TREE_ID) == ax_tree_id) + return node; + + for (unsigned int i = 0; i < node->InternalChildCount(); ++i) { + BrowserAccessibility* child = node->InternalGetChild(i); + BrowserAccessibility* result = FindNodeWithChildTreeId(child, ax_tree_id); + if (result) + return result; + } + + return nullptr; +} + +} // namespace + +// Map from AXTreeID to BrowserAccessibilityManager +using AXTreeIDMap = + base::hash_map<AXTreeIDRegistry::AXTreeID, BrowserAccessibilityManager*>; +base::LazyInstance<AXTreeIDMap> g_ax_tree_id_map = LAZY_INSTANCE_INITIALIZER; + SimpleAXTreeUpdate MakeAXTreeUpdate( const ui::AXNodeData& node1, const ui::AXNodeData& node2 /* = ui::AXNodeData() */, @@ -73,6 +102,14 @@ BrowserAccessibilityManager* BrowserAccessibilityManager::Create( } #endif +// static +BrowserAccessibilityManager* BrowserAccessibilityManager::FromID( + AXTreeIDRegistry::AXTreeID ax_tree_id) { + AXTreeIDMap* ax_tree_id_map = g_ax_tree_id_map.Pointer(); + auto iter = ax_tree_id_map->find(ax_tree_id); + return iter == ax_tree_id_map->end() ? nullptr : iter->second; +} + BrowserAccessibilityManager::BrowserAccessibilityManager( BrowserAccessibilityDelegate* delegate, BrowserAccessibilityFactory* factory) @@ -81,7 +118,9 @@ BrowserAccessibilityManager::BrowserAccessibilityManager( tree_(new ui::AXSerializableTree()), focus_(NULL), user_is_navigating_away_(false), - osk_state_(OSK_ALLOWED) { + osk_state_(OSK_ALLOWED), + ax_tree_id_(AXTreeIDRegistry::kNoAXTreeID), + parent_node_id_from_parent_tree_(0) { tree_->SetDelegate(this); } @@ -148,6 +187,41 @@ BrowserAccessibility* BrowserAccessibilityManager::GetFromID(int32 id) { return NULL; } +BrowserAccessibility* +BrowserAccessibilityManager::GetParentNodeFromParentTree() { + if (!GetRoot()) + return nullptr; + + int parent_tree_id = GetRoot()->GetIntAttribute(ui::AX_ATTR_PARENT_TREE_ID); + BrowserAccessibilityManager* parent_manager = + BrowserAccessibilityManager::FromID(parent_tree_id); + if (!parent_manager) + return nullptr; + + // Try to use the cached parent node from the most recent time this + // was called. + if (parent_node_id_from_parent_tree_) { + BrowserAccessibility* parent_node = parent_manager->GetFromID( + parent_node_id_from_parent_tree_); + if (parent_node) { + int parent_child_tree_id = + parent_node->GetIntAttribute(ui::AX_ATTR_CHILD_TREE_ID); + if (parent_child_tree_id == ax_tree_id_) + return parent_node; + } + } + + // If that fails, search for it and cache it for next time. + BrowserAccessibility* parent_node = FindNodeWithChildTreeId( + parent_manager->GetRoot(), ax_tree_id_); + if (parent_node) { + parent_node_id_from_parent_tree_ = parent_node->GetId(); + return parent_node; + } + + return nullptr; +} + void BrowserAccessibilityManager::OnWindowFocused() { if (focus_) NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, GetFromAXNode(focus_)); @@ -184,13 +258,13 @@ bool BrowserAccessibilityManager::UseRootScrollOffsetsWhenComputingBounds() { } void BrowserAccessibilityManager::OnAccessibilityEvents( - const std::vector<AccessibilityHostMsg_EventParams>& params) { + const std::vector<AXEventNotificationDetails>& details) { 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)) { + for (uint32 index = 0; index < details.size(); ++index) { + const AXEventNotificationDetails& detail = details[index]; + if (!tree_->Unserialize(detail.update)) { if (delegate_) { LOG(ERROR) << tree_->error(); delegate_->AccessibilityFatalError(); @@ -213,16 +287,16 @@ void BrowserAccessibilityManager::OnAccessibilityEvents( } // Now iterate over the events again and fire the events. - for (uint32 index = 0; index < params.size(); index++) { - const AccessibilityHostMsg_EventParams& param = params[index]; + for (uint32 index = 0; index < details.size(); index++) { + const AXEventNotificationDetails& detail = details[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); + ui::AXNode* node = tree_->GetFromId(detail.id); if (!node) continue; - ui::AXEvent event_type = param.event_type; + ui::AXEvent event_type = detail.event_type; if (event_type == ui::AX_EVENT_FOCUS || event_type == ui::AX_EVENT_BLUR) { SetFocus(node, false); @@ -317,9 +391,10 @@ BrowserAccessibility* BrowserAccessibilityManager::GetFocus( return NULL; BrowserAccessibility* obj = GetFromAXNode(focus_); - if (delegate() && obj->HasBoolAttribute(ui::AX_ATTR_IS_AX_TREE_HOST)) { + if (obj->HasIntAttribute(ui::AX_ATTR_CHILD_TREE_ID)) { BrowserAccessibilityManager* child_manager = - delegate()->AccessibilityGetChildFrame(obj->GetId()); + BrowserAccessibilityManager::FromID( + obj->GetIntAttribute(ui::AX_ATTR_CHILD_TREE_ID)); if (child_manager) return child_manager->GetFocus(child_manager->GetRoot()); } @@ -464,19 +539,24 @@ void BrowserAccessibilityManager::OnAtomicUpdateFinished( ui::AXTree* tree, bool root_changed, const std::vector<ui::AXTreeDelegate::Change>& changes) { + if (GetRoot()->HasIntAttribute(ui::AX_ATTR_TREE_ID) && + GetRoot()->GetIntAttribute(ui::AX_ATTR_TREE_ID) != ax_tree_id_) { + g_ax_tree_id_map.Get().erase(ax_tree_id_); + ax_tree_id_ = GetRoot()->GetIntAttribute(ui::AX_ATTR_TREE_ID); + g_ax_tree_id_map.Get().insert(std::make_pair(ax_tree_id_, this)); + } } BrowserAccessibilityDelegate* BrowserAccessibilityManager::GetDelegateFromRootManager() { - BrowserAccessibilityManager* manager = this; - while (manager->delegate()) { - BrowserAccessibility* host_node_in_parent_frame = - manager->delegate()->AccessibilityGetParentFrame(); - if (!host_node_in_parent_frame) - break; - manager = host_node_in_parent_frame->manager(); - } - return manager->delegate(); + if (!GetRoot()) + return nullptr; + int parent_tree_id = GetRoot()->GetIntAttribute(ui::AX_ATTR_PARENT_TREE_ID); + BrowserAccessibilityManager* parent_manager = + BrowserAccessibilityManager::FromID(parent_tree_id); + if (parent_manager) + return parent_manager->GetDelegateFromRootManager(); + return delegate(); } SimpleAXTreeUpdate diff --git a/content/browser/accessibility/browser_accessibility_manager.h b/content/browser/accessibility/browser_accessibility_manager.h index e04d757..865b51f 100644 --- a/content/browser/accessibility/browser_accessibility_manager.h +++ b/content/browser/accessibility/browser_accessibility_manager.h @@ -10,14 +10,15 @@ #include "base/containers/hash_tables.h" #include "base/memory/scoped_ptr.h" #include "build/build_config.h" +#include "content/browser/accessibility/ax_tree_id_registry.h" #include "content/common/content_export.h" +#include "content/public/browser/ax_event_notification_details.h" #include "third_party/WebKit/public/web/WebAXEnums.h" #include "ui/accessibility/ax_node_data.h" #include "ui/accessibility/ax_serializable_tree.h" #include "ui/accessibility/ax_tree_update.h" #include "ui/gfx/native_widget_types.h" -struct AccessibilityHostMsg_EventParams; struct AccessibilityHostMsg_LocationChangeParams; namespace content { @@ -78,11 +79,6 @@ class CONTENT_EXPORT BrowserAccessibilityDelegate { virtual void AccessibilityFatalError() = 0; virtual gfx::AcceleratedWidget AccessibilityGetAcceleratedWidget() = 0; virtual gfx::NativeViewAccessible AccessibilityGetNativeViewAccessible() = 0; - virtual BrowserAccessibilityManager* AccessibilityGetChildFrame( - int accessibility_node_id) = 0; - virtual void AccessibilityGetAllChildFrames( - std::vector<BrowserAccessibilityManager*>* child_frames) = 0; - virtual BrowserAccessibility* AccessibilityGetParentFrame() = 0; }; class CONTENT_EXPORT BrowserAccessibilityFactory { @@ -124,6 +120,9 @@ class CONTENT_EXPORT BrowserAccessibilityManager : public ui::AXTreeDelegate { BrowserAccessibilityDelegate* delegate, BrowserAccessibilityFactory* factory = new BrowserAccessibilityFactory()); + static BrowserAccessibilityManager* FromID( + AXTreeIDRegistry::AXTreeID ax_tree_id); + ~BrowserAccessibilityManager() override; void Initialize(const SimpleAXTreeUpdate& initial_tree); @@ -143,6 +142,9 @@ class CONTENT_EXPORT BrowserAccessibilityManager : public ui::AXTreeDelegate { // does not make a new reference. BrowserAccessibility* GetFromID(int32 id); + // If this tree has a parent tree, return the parent node in that tree. + BrowserAccessibility* GetParentNodeFromParentTree(); + // Called to notify the accessibility manager that its associated native // view got focused. virtual void OnWindowFocused(); @@ -203,7 +205,7 @@ class CONTENT_EXPORT BrowserAccessibilityManager : public ui::AXTreeDelegate { // Called when the renderer process has notified us of about tree changes. void OnAccessibilityEvents( - const std::vector<AccessibilityHostMsg_EventParams>& params); + const std::vector<AXEventNotificationDetails>& details); // Called when the renderer process updates the location of accessibility // objects. @@ -333,6 +335,14 @@ class CONTENT_EXPORT BrowserAccessibilityManager : public ui::AXTreeDelegate { BrowserAccessibilityFindInPageInfo find_in_page_info_; + // The global ID of this accessibility tree. + AXTreeIDRegistry::AXTreeID ax_tree_id_; + + // If this tree has a parent tree, this is the cached ID of the parent + // node within that parent tree. It's computed as needed and cached for + // speed so that it can be accessed quickly if it hasn't changed. + int parent_node_id_from_parent_tree_; + DISALLOW_COPY_AND_ASSIGN(BrowserAccessibilityManager); }; diff --git a/content/browser/accessibility/browser_accessibility_manager_unittest.cc b/content/browser/accessibility/browser_accessibility_manager_unittest.cc index a5f89ff..1be3c64 100644 --- a/content/browser/accessibility/browser_accessibility_manager_unittest.cc +++ b/content/browser/accessibility/browser_accessibility_manager_unittest.cc @@ -9,7 +9,7 @@ #if defined(OS_WIN) #include "content/browser/accessibility/browser_accessibility_win.h" #endif -#include "content/common/accessibility_messages.h" +#include "content/public/browser/ax_event_notification_details.h" #include "testing/gtest/include/gtest/gtest.h" namespace content { @@ -92,15 +92,6 @@ class TestBrowserAccessibilityDelegate gfx::NativeViewAccessible AccessibilityGetNativeViewAccessible() override { return nullptr; } - BrowserAccessibilityManager* AccessibilityGetChildFrame( - int accessibility_node_id) override { - return nullptr; - } - BrowserAccessibility* AccessibilityGetParentFrame() override { - return nullptr; - } - void AccessibilityGetAllChildFrames( - std::vector<BrowserAccessibilityManager*>* child_frames) override {} bool got_fatal_error() const { return got_fatal_error_; } void reset_got_fatal_error() { got_fatal_error_ = false; } @@ -275,9 +266,9 @@ TEST(BrowserAccessibilityManagerTest, TestReuseBrowserAccessibilityObjects) { EXPECT_EQ(2, child3_accessible->GetIndexInParent()); // Process a notification containing the changed subtree. - std::vector<AccessibilityHostMsg_EventParams> params; - params.push_back(AccessibilityHostMsg_EventParams()); - AccessibilityHostMsg_EventParams* msg = ¶ms[0]; + std::vector<AXEventNotificationDetails> params; + params.push_back(AXEventNotificationDetails()); + AXEventNotificationDetails* msg = ¶ms[0]; msg->event_type = ui::AX_EVENT_CHILDREN_CHANGED; msg->update.nodes.push_back(tree2_root); msg->update.nodes.push_back(tree2_child0); @@ -451,9 +442,9 @@ TEST(BrowserAccessibilityManagerTest, TestReuseBrowserAccessibilityObjects2) { // Process a notification containing the changed subtree rooted at // the container. - std::vector<AccessibilityHostMsg_EventParams> params; - params.push_back(AccessibilityHostMsg_EventParams()); - AccessibilityHostMsg_EventParams* msg = ¶ms[0]; + std::vector<AXEventNotificationDetails> params; + params.push_back(AXEventNotificationDetails()); + AXEventNotificationDetails* msg = ¶ms[0]; msg->event_type = ui::AX_EVENT_CHILDREN_CHANGED; msg->update.nodes.push_back(tree2_container); msg->update.nodes.push_back(tree2_child0); @@ -557,9 +548,9 @@ TEST(BrowserAccessibilityManagerTest, TestMoveChildUp) { ASSERT_EQ(4, CountedBrowserAccessibility::global_obj_count_); // Process a notification containing the changed subtree. - std::vector<AccessibilityHostMsg_EventParams> params; - params.push_back(AccessibilityHostMsg_EventParams()); - AccessibilityHostMsg_EventParams* msg = ¶ms[0]; + std::vector<AXEventNotificationDetails> params; + params.push_back(AXEventNotificationDetails()); + AXEventNotificationDetails* msg = ¶ms[0]; msg->event_type = ui::AX_EVENT_CHILDREN_CHANGED; msg->update.nodes.push_back(tree2_1); msg->update.nodes.push_back(tree2_4); @@ -1013,8 +1004,8 @@ TEST(BrowserAccessibilityManagerTest, DeletingFocusedNodeDoesNotCrash) { ASSERT_EQ(1, manager->GetFocus(manager->GetRoot())->GetId()); // Send the focus event for node 2. - std::vector<AccessibilityHostMsg_EventParams> events; - events.push_back(AccessibilityHostMsg_EventParams()); + std::vector<AXEventNotificationDetails> events; + events.push_back(AXEventNotificationDetails()); events[0].update = MakeAXTreeUpdate(node2); events[0].id = 2; events[0].event_type = ui::AX_EVENT_FOCUS; @@ -1029,8 +1020,8 @@ TEST(BrowserAccessibilityManagerTest, DeletingFocusedNodeDoesNotCrash) { root2.role = ui::AX_ROLE_ROOT_WEB_AREA; root2.state = 0; - std::vector<AccessibilityHostMsg_EventParams> events2; - events2.push_back(AccessibilityHostMsg_EventParams()); + std::vector<AXEventNotificationDetails> events2; + events2.push_back(AXEventNotificationDetails()); events2[0].update = MakeAXTreeUpdate(root2); events2[0].id = -1; events2[0].event_type = ui::AX_EVENT_NONE; @@ -1074,8 +1065,8 @@ TEST(BrowserAccessibilityManagerTest, DeletingFocusedNodeDoesNotCrash2) { ASSERT_EQ(1, manager->GetFocus(manager->GetRoot())->GetId()); // Send the focus event for node 2. - std::vector<AccessibilityHostMsg_EventParams> events; - events.push_back(AccessibilityHostMsg_EventParams()); + std::vector<AXEventNotificationDetails> events; + events.push_back(AXEventNotificationDetails()); events[0].update = MakeAXTreeUpdate(node2); events[0].id = 2; events[0].event_type = ui::AX_EVENT_FOCUS; @@ -1091,8 +1082,8 @@ TEST(BrowserAccessibilityManagerTest, DeletingFocusedNodeDoesNotCrash2) { root2.state = 0; // Make an update the explicitly clears the previous root. - std::vector<AccessibilityHostMsg_EventParams> events2; - events2.push_back(AccessibilityHostMsg_EventParams()); + std::vector<AXEventNotificationDetails> events2; + events2.push_back(AXEventNotificationDetails()); events2[0].update = MakeAXTreeUpdate(root2); events2[0].update.node_id_to_clear = 1; events2[0].id = -1; diff --git a/content/browser/accessibility/browser_accessibility_manager_win.cc b/content/browser/accessibility/browser_accessibility_manager_win.cc index dcc60bf..d28423b 100644 --- a/content/browser/accessibility/browser_accessibility_manager_win.cc +++ b/content/browser/accessibility/browser_accessibility_manager_win.cc @@ -298,6 +298,7 @@ void BrowserAccessibilityManagerWin::OnNodeCreated(ui::AXTree* tree, return; LONG unique_id_win = obj->ToBrowserAccessibilityWin()->unique_id_win(); unique_id_to_ax_id_map_[unique_id_win] = obj->GetId(); + unique_id_to_ax_tree_id_map_[unique_id_win] = ax_tree_id_; } void BrowserAccessibilityManagerWin::OnNodeWillBeDeleted(ui::AXTree* tree, @@ -310,6 +311,8 @@ void BrowserAccessibilityManagerWin::OnNodeWillBeDeleted(ui::AXTree* tree, return; unique_id_to_ax_id_map_.erase( obj->ToBrowserAccessibilityWin()->unique_id_win()); + unique_id_to_ax_tree_id_map_.erase( + obj->ToBrowserAccessibilityWin()->unique_id_win()); if (obj == tracked_scroll_object_) { tracked_scroll_object_->Release(); tracked_scroll_object_ = NULL; @@ -375,30 +378,31 @@ void BrowserAccessibilityManagerWin::TrackScrollingObject( BrowserAccessibilityWin* BrowserAccessibilityManagerWin::GetFromUniqueIdWin( LONG unique_id_win) { - base::hash_map<LONG, int32>::iterator iter = - unique_id_to_ax_id_map_.find(unique_id_win); - if (iter != unique_id_to_ax_id_map_.end()) { - BrowserAccessibility* result = GetFromID(iter->second); - if (result && result->IsNative()) - return result->ToBrowserAccessibilityWin(); + auto tree_iter = unique_id_to_ax_tree_id_map_.find(unique_id_win); + if (tree_iter == unique_id_to_ax_tree_id_map_.end()) + return nullptr; + + int tree_id = tree_iter->second; + if (tree_id != ax_tree_id_) { + BrowserAccessibilityManagerWin* manager = + BrowserAccessibilityManager::FromID(tree_id) + ->ToBrowserAccessibilityManagerWin(); + if (!manager) + return nullptr; + if (manager != this) + return manager->GetFromUniqueIdWin(unique_id_win); + return nullptr; } - // Also search all child frames, such as out-of-process iframes or - // guest browser plugins. - if (delegate()) { - std::vector<BrowserAccessibilityManager*> child_frames; - delegate()->AccessibilityGetAllChildFrames(&child_frames); - for (size_t i = 0; i < child_frames.size(); ++i) { - BrowserAccessibilityManagerWin* child_manager = - child_frames[i]->ToBrowserAccessibilityManagerWin(); - BrowserAccessibilityWin* result = - child_manager->GetFromUniqueIdWin(unique_id_win); - if (result) - return result; - } - } + auto iter = unique_id_to_ax_id_map_.find(unique_id_win); + if (iter == unique_id_to_ax_id_map_.end()) + return nullptr; + + BrowserAccessibility* result = GetFromID(iter->second); + if (result && result->IsNative()) + return result->ToBrowserAccessibilityWin(); - return NULL; + return nullptr; } } // namespace content diff --git a/content/browser/accessibility/browser_accessibility_manager_win.h b/content/browser/accessibility/browser_accessibility_manager_win.h index 1fdf486..f1cb688 100644 --- a/content/browser/accessibility/browser_accessibility_manager_win.h +++ b/content/browser/accessibility/browser_accessibility_manager_win.h @@ -76,6 +76,10 @@ class CONTENT_EXPORT BrowserAccessibilityManagerWin // browser process) to accessibility ids within this page. base::hash_map<long, int32> unique_id_to_ax_id_map_; + // A mapping from the Windows-specific unique IDs (unique within the + // browser process) to the AXTreeID that contains this unique ID. + base::hash_map<long, AXTreeIDRegistry::AXTreeID> unique_id_to_ax_tree_id_map_; + // Set to true if we need to fire a focus event on the root as soon as // possible. bool focus_event_on_root_needed_; diff --git a/content/browser/accessibility/browser_accessibility_win_unittest.cc b/content/browser/accessibility/browser_accessibility_win_unittest.cc index 501490e..2a3ebde 100644 --- a/content/browser/accessibility/browser_accessibility_win_unittest.cc +++ b/content/browser/accessibility/browser_accessibility_win_unittest.cc @@ -231,16 +231,16 @@ TEST_F(BrowserAccessibilityTest, TestChildrenChange) { text_accessible.Release(); // Notify the BrowserAccessibilityManager that the text child has changed. - ui::AXNodeData text2; + AXContentNodeData text2; text2.id = 2; text2.role = ui::AX_ROLE_STATIC_TEXT; text2.SetName("new text"); text2.SetName("old text"); - AccessibilityHostMsg_EventParams param; + AXEventNotificationDetails param; param.event_type = ui::AX_EVENT_CHILDREN_CHANGED; param.update.nodes.push_back(text2); param.id = text2.id; - std::vector<AccessibilityHostMsg_EventParams> events; + std::vector<AXEventNotificationDetails> events; events.push_back(param); manager->OnAccessibilityEvents(events); @@ -308,11 +308,11 @@ TEST_F(BrowserAccessibilityTest, TestChildrenChangeNoLeaks) { // Notify the BrowserAccessibilityManager that the div node and its children // were removed and ensure that only one BrowserAccessibility instance exists. root.child_ids.clear(); - AccessibilityHostMsg_EventParams param; + AXEventNotificationDetails param; param.event_type = ui::AX_EVENT_CHILDREN_CHANGED; param.update.nodes.push_back(root); param.id = root.id; - std::vector<AccessibilityHostMsg_EventParams> events; + std::vector<AXEventNotificationDetails> events; events.push_back(param); manager->OnAccessibilityEvents(events); ASSERT_EQ(1, CountedBrowserAccessibility::num_instances()); @@ -693,9 +693,9 @@ TEST_F(BrowserAccessibilityTest, TestCreateEmptyDocument) { tree1_2.role = ui::AX_ROLE_TEXT_FIELD; // Process a load complete. - std::vector<AccessibilityHostMsg_EventParams> params; - params.push_back(AccessibilityHostMsg_EventParams()); - AccessibilityHostMsg_EventParams* msg = ¶ms[0]; + std::vector<AXEventNotificationDetails> params; + params.push_back(AXEventNotificationDetails()); + AXEventNotificationDetails* msg = ¶ms[0]; msg->event_type = ui::AX_EVENT_LOAD_COMPLETE; msg->update.nodes.push_back(tree1_1); msg->update.nodes.push_back(tree1_2); diff --git a/content/browser/accessibility/site_per_process_accessibility_browsertest.cc b/content/browser/accessibility/site_per_process_accessibility_browsertest.cc index 75abf1a..192b11c 100644 --- a/content/browser/accessibility/site_per_process_accessibility_browsertest.cc +++ b/content/browser/accessibility/site_per_process_accessibility_browsertest.cc @@ -38,6 +38,18 @@ class SitePerProcessAccessibilityBrowserTest SitePerProcessAccessibilityBrowserTest() {} }; +bool AccessibilityTreeContainsDocTitle( + BrowserAccessibility* node, + const std::string& title) { + if (node->GetStringAttribute(ui::AX_ATTR_DOC_TITLE) == title) + return true; + for (unsigned i = 0; i < node->PlatformChildCount(); i++) { + if (AccessibilityTreeContainsDocTitle(node->PlatformGetChild(i), title)) + return true; + } + return false; +} + // Utility function to determine if an accessibility tree has finished loading // or if the tree represents a page that hasn't finished loading yet. bool AccessibilityTreeIsLoaded(BrowserAccessibilityManager* manager) { @@ -96,25 +108,16 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessAccessibilityBrowserTest, main_frame->browser_accessibility_manager(); VLOG(1) << "Main frame accessibility tree:\n" << main_frame_manager->SnapshotAXTreeForTesting().ToString(); - EXPECT_TRUE(AccessibilityTreeIsLoaded(main_frame_manager)); - // Next, wait for the accessibility tree from the cross-process iframe - // to load. Since accessibility was enabled at the time this frame was - // created, we need to check to see if it's already loaded first, and - // only create an AccessibilityNotificationWaiter if it's not. RenderFrameHostImpl* child_frame = static_cast<RenderFrameHostImpl*>( child->current_frame_host()); - BrowserAccessibilityManager* child_frame_manager = - child_frame->browser_accessibility_manager(); - if (!AccessibilityTreeIsLoaded(child_frame_manager)) { - VLOG(1) << "Child frame accessibility tree is not loaded, waiting..."; - AccessibilityNotificationWaiter child_frame_accessibility_waiter( - child_frame, ui::AX_EVENT_LOAD_COMPLETE); - child_frame_accessibility_waiter.WaitForNotification(); + while (!AccessibilityTreeContainsDocTitle(main_frame_manager->GetRoot(), + "Title Of Awesomeness")) { + AccessibilityNotificationWaiter accessibility_waiter(main_frame, + ui::AX_EVENT_NONE); + accessibility_waiter.ListenToAdditionalFrame(child_frame); + accessibility_waiter.WaitForNotification(); } - EXPECT_TRUE(AccessibilityTreeIsLoaded(child_frame_manager)); - VLOG(1) << "Child frame accessibility tree:\n" - << child_frame_manager->SnapshotAXTreeForTesting().ToString(); // Assert that we can walk from the main frame down into the child frame // directly, getting correct roles and data along the way. diff --git a/content/browser/frame_host/frame_accessibility.cc b/content/browser/frame_host/frame_accessibility.cc deleted file mode 100644 index b046167..0000000 --- a/content/browser/frame_host/frame_accessibility.cc +++ /dev/null @@ -1,229 +0,0 @@ -// Copyright 2014 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/frame_host/frame_accessibility.h" - -#include "content/browser/frame_host/frame_tree.h" -#include "content/browser/frame_host/frame_tree_node.h" -#include "content/browser/frame_host/render_frame_host_delegate.h" -#include "content/browser/frame_host/render_frame_host_impl.h" -#include "content/public/browser/browser_context.h" - -namespace content { - -// static -FrameAccessibility* FrameAccessibility::GetInstance() { - return Singleton<FrameAccessibility>::get(); -} - -FrameAccessibility::ChildFrameMapping::ChildFrameMapping() - : parent_frame_host(nullptr), - accessibility_node_id(0), - child_frame_tree_node_id(0), - browser_plugin_instance_id(0) {} - -FrameAccessibility::FrameAccessibility() {} - -FrameAccessibility::~FrameAccessibility() {} - -void FrameAccessibility::AddChildFrame( - RenderFrameHostImpl* parent_frame_host, - int accessibility_node_id, - int child_frame_tree_node_id) { - for (std::vector<ChildFrameMapping>::iterator iter = mappings_.begin(); - iter != mappings_.end(); - ++iter) { - // TODO(dmazzoni): the renderer should keep track of these mappings - // and clear an existing mapping before setting a new one, that would - // be safer than just updating existing mappings. http://crbug.com/413464 - if (iter->parent_frame_host == parent_frame_host && - (iter->accessibility_node_id == accessibility_node_id || - iter->child_frame_tree_node_id == child_frame_tree_node_id)) { - iter->accessibility_node_id = accessibility_node_id; - iter->child_frame_tree_node_id = child_frame_tree_node_id; - return; - } - } - - ChildFrameMapping new_mapping; - new_mapping.parent_frame_host = parent_frame_host; - new_mapping.accessibility_node_id = accessibility_node_id; - new_mapping.child_frame_tree_node_id = child_frame_tree_node_id; - mappings_.push_back(new_mapping); -} - -void FrameAccessibility::AddGuestWebContents( - RenderFrameHostImpl* parent_frame_host, - int accessibility_node_id, - int browser_plugin_instance_id) { - for (std::vector<ChildFrameMapping>::iterator iter = mappings_.begin(); - iter != mappings_.end(); - ++iter) { - // TODO(dmazzoni): the renderer should keep track of these mappings - // and clear an existing mapping before setting a new one, that would - // be safer than just updating existing mappings. http://crbug.com/413464 - if (iter->parent_frame_host == parent_frame_host && - (iter->accessibility_node_id == accessibility_node_id || - iter->browser_plugin_instance_id == browser_plugin_instance_id)) { - iter->accessibility_node_id = accessibility_node_id; - iter->browser_plugin_instance_id = browser_plugin_instance_id; - return; - } - } - - ChildFrameMapping new_mapping; - new_mapping.parent_frame_host = parent_frame_host; - new_mapping.accessibility_node_id = accessibility_node_id; - new_mapping.browser_plugin_instance_id = browser_plugin_instance_id; - mappings_.push_back(new_mapping); -} - -void FrameAccessibility::OnRenderFrameHostDestroyed( - RenderFrameHostImpl* render_frame_host) { - // Since the order doesn't matter, the fastest way to remove all items - // with this render_frame_host is to iterate over the vector backwards, - // swapping each one with the back element if we need to delete it. - int initial_len = static_cast<int>(mappings_.size()); - for (int i = initial_len - 1; i >= 0; i--) { - if (mappings_[i].parent_frame_host == render_frame_host) { - mappings_[i] = mappings_.back(); - mappings_.pop_back(); - } - } -} - -RenderFrameHostImpl* FrameAccessibility::GetChild( - RenderFrameHostImpl* parent_frame_host, - int accessibility_node_id) { - for (std::vector<ChildFrameMapping>::iterator iter = mappings_.begin(); - iter != mappings_.end(); - ++iter) { - if (iter->parent_frame_host != parent_frame_host || - iter->accessibility_node_id != accessibility_node_id) { - continue; - } - - if (iter->child_frame_tree_node_id) { - return GetRFHIFromFrameTreeNodeId( - parent_frame_host, iter->child_frame_tree_node_id); - } - - if (iter->browser_plugin_instance_id) { - RenderFrameHost* guest = - parent_frame_host->delegate()->GetGuestByInstanceID( - iter->parent_frame_host, - iter->browser_plugin_instance_id); - if (guest) - return static_cast<RenderFrameHostImpl*>(guest); - } - } - - return nullptr; -} - -void FrameAccessibility::GetAllChildFrames( - RenderFrameHostImpl* parent_frame_host, - std::vector<RenderFrameHostImpl*>* child_frame_hosts) { - CHECK(child_frame_hosts); - - for (std::vector<ChildFrameMapping>::iterator iter = mappings_.begin(); - iter != mappings_.end(); - ++iter) { - if (iter->parent_frame_host != parent_frame_host) - continue; - - if (iter->child_frame_tree_node_id) { - RenderFrameHostImpl* child_frame_host = GetRFHIFromFrameTreeNodeId( - parent_frame_host, iter->child_frame_tree_node_id); - if (child_frame_host) - child_frame_hosts->push_back(child_frame_host); - } - - if (iter->browser_plugin_instance_id) { - RenderFrameHost* guest = - parent_frame_host->delegate()->GetGuestByInstanceID( - iter->parent_frame_host, - iter->browser_plugin_instance_id); - if (guest) - child_frame_hosts->push_back(static_cast<RenderFrameHostImpl*>(guest)); - } - } -} - -bool FrameAccessibility::GetParent( - RenderFrameHostImpl* child_frame_host, - RenderFrameHostImpl** out_parent_frame_host, - int* out_accessibility_node_id) { - for (std::vector<ChildFrameMapping>::iterator iter = mappings_.begin(); - iter != mappings_.end(); - ++iter) { - if (iter->child_frame_tree_node_id) { - FrameTreeNode* child_node = - FrameTreeNode::GloballyFindByID(iter->child_frame_tree_node_id); - if (child_node && - child_node->current_frame_host() == child_frame_host) { - // Assert that the child node is a descendant of the parent frame in - // the frame tree. It may not be a direct descendant because the - // parent frame's accessibility tree may span multiple frames from the - // same origin. - FrameTreeNode* parent_node = iter->parent_frame_host->frame_tree_node(); - FrameTreeNode* child_node_ancestor = child_node->parent(); - while (child_node_ancestor && child_node_ancestor != parent_node) - child_node_ancestor = child_node_ancestor->parent(); - if (child_node_ancestor != parent_node) { - NOTREACHED(); - return false; - } - - if (out_parent_frame_host) - *out_parent_frame_host = iter->parent_frame_host; - if (out_accessibility_node_id) - *out_accessibility_node_id = iter->accessibility_node_id; - return true; - } - } - - if (iter->browser_plugin_instance_id) { - RenderFrameHost* guest = - iter->parent_frame_host->delegate()->GetGuestByInstanceID( - iter->parent_frame_host, - iter->browser_plugin_instance_id); - if (guest == child_frame_host) { - if (out_parent_frame_host) - *out_parent_frame_host = iter->parent_frame_host; - if (out_accessibility_node_id) - *out_accessibility_node_id = iter->accessibility_node_id; - return true; - } - } - } - - return false; -} - -RenderFrameHostImpl* FrameAccessibility::GetRFHIFromFrameTreeNodeId( - RenderFrameHostImpl* parent_frame_host, - int child_frame_tree_node_id) { - FrameTreeNode* child_node = - FrameTreeNode::GloballyFindByID(child_frame_tree_node_id); - if (!child_node) - return nullptr; - - // Assert that the child node is a descendant of the parent frame in - // the frame tree. It may not be a direct descendant because the - // parent frame's accessibility tree may span multiple frames from the - // same origin. - FrameTreeNode* parent_node = parent_frame_host->frame_tree_node(); - FrameTreeNode* child_node_ancestor = child_node->parent(); - while (child_node_ancestor && child_node_ancestor != parent_node) - child_node_ancestor = child_node_ancestor->parent(); - if (child_node_ancestor != parent_node) { - NOTREACHED(); - return nullptr; - } - - return child_node->current_frame_host(); -} - -} // namespace content diff --git a/content/browser/frame_host/frame_accessibility.h b/content/browser/frame_host/frame_accessibility.h deleted file mode 100644 index d97a5c0..0000000 --- a/content/browser/frame_host/frame_accessibility.h +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright 2014 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. - -#ifndef CONTENT_BROWSER_FRAME_HOST_FRAME_ACCESSIBILITY_H_ -#define CONTENT_BROWSER_FRAME_HOST_FRAME_ACCESSIBILITY_H_ - -#include <vector> - -#include "base/basictypes.h" -#include "base/memory/singleton.h" -#include "content/common/content_export.h" - -namespace content { - -class RenderFrameHostImpl; - -// This singleton class maintains the mappings necessary to link child frames -// and guest frames into a single tree for accessibility. This class is only -// used if accessibility is enabled. -class CONTENT_EXPORT FrameAccessibility { - public: - static FrameAccessibility* GetInstance(); - - // Add a mapping between an accessibility node of |parent_frame_host| - // and the child frame with the given frame tree node id, in the same - // frame tree. - void AddChildFrame(RenderFrameHostImpl* parent_frame_host, - int accessibility_node_id, - int child_frame_tree_node_id); - - // Add a mapping between an accessibility node of |parent_frame_host| - // and the main frame of the guest Webcontents with the given - // browser plugin instance id. - void AddGuestWebContents(RenderFrameHostImpl* parent_frame_host, - int accessibility_node_id, - int browser_plugin_instance_id); - - // This is called when a RenderFrameHostImpl is deleted, so invalid - // mappings can be removed from this data structure. - void OnRenderFrameHostDestroyed(RenderFrameHostImpl* render_frame_host); - - // Given a parent RenderFrameHostImpl and an accessibility node id, look up - // a child frame or guest frame that was previously associated with this - // frame and node id. If a mapping exists, return the resulting frame if - // it's valid. If it doesn't resolve to a valid RenderFrameHostImpl, - // returns NULL. - RenderFrameHostImpl* GetChild(RenderFrameHostImpl* parent_frame_host, - int accessibility_node_id); - - // Given a parent RenderFrameHostImpl and an accessibility node id, look up - // all child frames or guest frames that were previously associated with this - // frame, and populate |child_frame_hosts| with all of them that resolve - // to a valid RenderFrameHostImpl. - void GetAllChildFrames(RenderFrameHostImpl* parent_frame_host, - std::vector<RenderFrameHostImpl*>* child_frame_hosts); - - // Given a RenderFrameHostImpl, check the mapping table to see if it's - // the child of a node in some other frame. If so, return true and - // set the parent frame and accessibility node id in the parent frame, - // otherwise return false. - bool GetParent(RenderFrameHostImpl* child_frame_host, - RenderFrameHostImpl** out_parent_frame_host, - int* out_accessibility_node_id); - - private: - FrameAccessibility(); - virtual ~FrameAccessibility(); - - RenderFrameHostImpl* GetRFHIFromFrameTreeNodeId( - RenderFrameHostImpl* parent_frame_host, - int child_frame_tree_node_id); - - // This structure stores the parent-child relationship between an - // accessibility node in a parent frame and its child frame, where the - // child frame may be an iframe or the main frame of a guest browser - // plugin. It allows the accessibility code to walk both down and up - // the "composed" accessibility tree. - struct ChildFrameMapping { - ChildFrameMapping(); - - // The parent frame host. Required. - RenderFrameHostImpl* parent_frame_host; - - // The id of the accessibility node that's the host of the child frame, - // for example the accessibility node for the <iframe> element or the - // <embed> element. - int accessibility_node_id; - - // If the child frame is an iframe, this is the iframe's FrameTreeNode id, - // otherwise 0. - int child_frame_tree_node_id; - - // If the child frame is a browser plugin, this is its instance id, - // otherwise 0. - int browser_plugin_instance_id; - }; - - std::vector<ChildFrameMapping> mappings_; - - friend struct DefaultSingletonTraits<FrameAccessibility>; -}; - -} // namespace content - -#endif // CONTENT_BROWSER_FRAME_HOST_FRAME_ACCESSIBILITY_H_ diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc index 331f152..a25fc59 100644 --- a/content/browser/frame_host/render_frame_host_impl.cc +++ b/content/browser/frame_host/render_frame_host_impl.cc @@ -12,13 +12,13 @@ #include "base/process/kill.h" #include "base/time/time.h" #include "content/browser/accessibility/accessibility_mode_helper.h" +#include "content/browser/accessibility/ax_tree_id_registry.h" #include "content/browser/accessibility/browser_accessibility_manager.h" #include "content/browser/accessibility/browser_accessibility_state_impl.h" #include "content/browser/bad_message.h" #include "content/browser/child_process_security_policy_impl.h" #include "content/browser/frame_host/cross_process_frame_connector.h" #include "content/browser/frame_host/cross_site_transferring_request.h" -#include "content/browser/frame_host/frame_accessibility.h" #include "content/browser/frame_host/frame_mojo_shell.h" #include "content/browser/frame_host/frame_tree.h" #include "content/browser/frame_host/frame_tree_node.h" @@ -147,6 +147,21 @@ RenderFrameHostImpl* RenderFrameHostImpl::FromID(int process_id, return it == frames->end() ? NULL : it->second; } +// static +RenderFrameHost* RenderFrameHost::FromAXTreeID( + int ax_tree_id) { + return RenderFrameHostImpl::FromAXTreeID(ax_tree_id); +} + +// static +RenderFrameHostImpl* RenderFrameHostImpl::FromAXTreeID( + AXTreeIDRegistry::AXTreeID ax_tree_id) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + AXTreeIDRegistry::FrameID frame_id = + AXTreeIDRegistry::GetInstance()->GetFrameID(ax_tree_id); + return RenderFrameHostImpl::FromID(frame_id.first, frame_id.second); +} + RenderFrameHostImpl::RenderFrameHostImpl(SiteInstance* site_instance, RenderViewHostImpl* render_view_host, RenderFrameHostDelegate* delegate, @@ -209,8 +224,6 @@ RenderFrameHostImpl::~RenderFrameHostImpl() { if (delegate_ && render_frame_created_) delegate_->RenderFrameDeleted(this); - FrameAccessibility::GetInstance()->OnRenderFrameHostDestroyed(this); - // If this was swapped out, it already decremented the active frame count of // the SiteInstance it belongs to. if (IsRFHStateActive(rfh_state_)) @@ -238,6 +251,11 @@ int RenderFrameHostImpl::GetRoutingID() { return routing_id_; } +AXTreeIDRegistry::AXTreeID RenderFrameHostImpl::GetAXTreeID() { + return AXTreeIDRegistry::GetInstance()->GetOrCreateAXTreeID( + GetProcess()->GetID(), routing_id_); +} + SiteInstanceImpl* RenderFrameHostImpl::GetSiteInstance() { return site_instance_.get(); } @@ -580,57 +598,6 @@ gfx::NativeViewAccessible return NULL; } -BrowserAccessibilityManager* RenderFrameHostImpl::AccessibilityGetChildFrame( - int accessibility_node_id) { - RenderFrameHostImpl* child_frame = - FrameAccessibility::GetInstance()->GetChild(this, accessibility_node_id); - if (!child_frame || IsSameSiteInstance(child_frame)) - return nullptr; - - return child_frame->GetOrCreateBrowserAccessibilityManager(); -} - -void RenderFrameHostImpl::AccessibilityGetAllChildFrames( - std::vector<BrowserAccessibilityManager*>* child_frames) { - std::vector<RenderFrameHostImpl*> child_frame_hosts; - FrameAccessibility::GetInstance()->GetAllChildFrames( - this, &child_frame_hosts); - for (size_t i = 0; i < child_frame_hosts.size(); ++i) { - RenderFrameHostImpl* child_frame_host = child_frame_hosts[i]; - if (!child_frame_host || IsSameSiteInstance(child_frame_host)) - continue; - - BrowserAccessibilityManager* manager = - child_frame_host->GetOrCreateBrowserAccessibilityManager(); - if (manager) - child_frames->push_back(manager); - } -} - -BrowserAccessibility* RenderFrameHostImpl::AccessibilityGetParentFrame() { - RenderFrameHostImpl* parent_frame = NULL; - int parent_node_id = 0; - if (!FrameAccessibility::GetInstance()->GetParent( - this, &parent_frame, &parent_node_id)) { - return NULL; - } - - // As a sanity check, make sure the frame we're going to return belongs - // to the same BrowserContext. - if (GetSiteInstance()->GetBrowserContext() != - parent_frame->GetSiteInstance()->GetBrowserContext()) { - NOTREACHED(); - return NULL; - } - - BrowserAccessibilityManager* manager = - parent_frame->browser_accessibility_manager(); - if (!manager) - return NULL; - - return manager->GetFromID(parent_node_id); -} - bool RenderFrameHostImpl::CreateRenderFrame(int parent_routing_id, int previous_sibling_routing_id, int proxy_routing_id) { @@ -1425,72 +1392,61 @@ void RenderFrameHostImpl::OnAccessibilityEvents( AccessibilityMode accessibility_mode = delegate_->GetAccessibilityMode(); if ((accessibility_mode != AccessibilityModeOff) && view && RenderFrameHostImpl::IsRFHStateActive(rfh_state())) { - if (browser_accessibility_manager_) { - // Get the frame routing ids from out-of-process iframes and - // browser plugin instance ids from guests and update the mappings in - // FrameAccessibility. - for (size_t i = 0; i < params.size(); ++i) { - const AccessibilityHostMsg_EventParams& param = params[i]; - UpdateCrossProcessIframeAccessibility( - param.node_to_frame_routing_id_map); - UpdateGuestFrameAccessibility( - param.node_to_browser_plugin_instance_id_map); - } - } - - if (accessibility_mode & AccessibilityModeFlagPlatform) { + if (accessibility_mode & AccessibilityModeFlagPlatform) GetOrCreateBrowserAccessibilityManager(); - if (browser_accessibility_manager_) - browser_accessibility_manager_->OnAccessibilityEvents(params); - } - // Send the updates to the automation extension API. std::vector<AXEventNotificationDetails> details; details.reserve(params.size()); for (size_t i = 0; i < params.size(); ++i) { const AccessibilityHostMsg_EventParams& param = params[i]; - AXEventNotificationDetails detail( - param.update.node_id_to_clear, - param.update.nodes, - param.event_type, - param.id, - param.node_to_browser_plugin_instance_id_map, - GetProcess()->GetID(), - routing_id_); + AXEventNotificationDetails detail; + detail.event_type = param.event_type; + detail.id = param.id; + detail.ax_tree_id = GetAXTreeID(); + detail.update.node_id_to_clear = param.update.node_id_to_clear; + detail.update.nodes.resize(param.update.nodes.size()); + for (size_t i = 0; i < param.update.nodes.size(); ++i) { + AXContentNodeDataToAXNodeData(param.update.nodes[i], + &detail.update.nodes[i]); + } details.push_back(detail); } - delegate_->AccessibilityEventReceived(details); - } - - // Always send an ACK or the renderer can be in a bad state. - Send(new AccessibilityMsg_Events_ACK(routing_id_)); - - // The rest of this code is just for testing; bail out if we're not - // in that mode. - if (accessibility_testing_callback_.is_null()) - return; + if (accessibility_mode & AccessibilityModeFlagPlatform) { + if (browser_accessibility_manager_) + browser_accessibility_manager_->OnAccessibilityEvents(details); + } - for (size_t i = 0; i < params.size(); i++) { - const AccessibilityHostMsg_EventParams& param = params[i]; - if (static_cast<int>(param.event_type) < 0) - continue; + // Send the updates to the automation extension API. + delegate_->AccessibilityEventReceived(details); - if (!ax_tree_for_testing_) { - if (browser_accessibility_manager_) { - ax_tree_for_testing_.reset(new ui::AXTree( - browser_accessibility_manager_->SnapshotAXTreeForTesting())); - } else { - ax_tree_for_testing_.reset(new ui::AXTree()); - CHECK(ax_tree_for_testing_->Unserialize(param.update)) - << ax_tree_for_testing_->error(); + // For testing only. + if (!accessibility_testing_callback_.is_null()) { + for (size_t i = 0; i < details.size(); i++) { + const AXEventNotificationDetails& detail = details[i]; + if (static_cast<int>(detail.event_type) < 0) + continue; + + if (!ax_tree_for_testing_) { + if (browser_accessibility_manager_) { + ax_tree_for_testing_.reset(new ui::AXTree( + browser_accessibility_manager_->SnapshotAXTreeForTesting())); + } else { + ax_tree_for_testing_.reset(new ui::AXTree()); + CHECK(ax_tree_for_testing_->Unserialize(detail.update)) + << ax_tree_for_testing_->error(); + } + } else { + CHECK(ax_tree_for_testing_->Unserialize(detail.update)) + << ax_tree_for_testing_->error(); + } + accessibility_testing_callback_.Run(detail.event_type, detail.id); } - } else { - CHECK(ax_tree_for_testing_->Unserialize(param.update)) - << ax_tree_for_testing_->error(); } - accessibility_testing_callback_.Run(param.event_type, param.id); } + + // Always send an ACK or the renderer can be in a bad state. + Send(new AccessibilityMsg_Events_ACK(routing_id_)); } void RenderFrameHostImpl::OnAccessibilityLocationChanges( @@ -1528,10 +1484,16 @@ void RenderFrameHostImpl::OnAccessibilityFindInPageResult( void RenderFrameHostImpl::OnAccessibilitySnapshotResponse( int callback_id, - const ui::AXTreeUpdate<ui::AXNodeData>& snapshot) { + const ui::AXTreeUpdate<AXContentNodeData>& snapshot) { const auto& it = ax_tree_snapshot_callbacks_.find(callback_id); if (it != ax_tree_snapshot_callbacks_.end()) { - it->second.Run(snapshot); + ui::AXTreeUpdate<ui::AXNodeData> dst_snapshot; + dst_snapshot.nodes.resize(snapshot.nodes.size()); + for (size_t i = 0; i < snapshot.nodes.size(); ++i) { + AXContentNodeDataToAXNodeData(snapshot.nodes[i], + &dst_snapshot.nodes[i]); + } + it->second.Run(dst_snapshot); ax_tree_snapshot_callbacks_.erase(it); } else { NOTREACHED() << "Received AX tree snapshot response for unknown id"; @@ -1972,37 +1934,6 @@ RenderFrameHostImpl::GetMojoImageDownloader() { return mojo_image_downloader_; } -void RenderFrameHostImpl::UpdateCrossProcessIframeAccessibility( - const std::map<int32, int>& node_to_frame_routing_id_map) { - for (const auto& iter : node_to_frame_routing_id_map) { - // This is the id of the accessibility node that has a child frame. - int32 node_id = iter.first; - // The routing id from either a RenderFrame or a RenderFrameProxy. - int frame_routing_id = iter.second; - - FrameTree* frame_tree = frame_tree_node()->frame_tree(); - FrameTreeNode* child_frame_tree_node = frame_tree->FindByRoutingID( - GetProcess()->GetID(), frame_routing_id); - - if (child_frame_tree_node) { - FrameAccessibility::GetInstance()->AddChildFrame( - this, node_id, child_frame_tree_node->frame_tree_node_id()); - } - } -} - -void RenderFrameHostImpl::UpdateGuestFrameAccessibility( - const std::map<int32, int>& node_to_browser_plugin_instance_id_map) { - for (const auto& iter : node_to_browser_plugin_instance_id_map) { - // This is the id of the accessibility node that hosts a plugin. - int32 node_id = iter.first; - // The id of the browser plugin. - int browser_plugin_instance_id = iter.second; - FrameAccessibility::GetInstance()->AddGuestWebContents( - this, node_id, browser_plugin_instance_id); - } -} - bool RenderFrameHostImpl::IsSameSiteInstance( RenderFrameHostImpl* other_render_frame_host) { // As a sanity check, make sure the frame belongs to the same BrowserContext. @@ -2216,4 +2147,78 @@ bool RenderFrameHostImpl::CanExecuteJavaScript() { (delegate_->GetAsWebContents() == nullptr); } +AXTreeIDRegistry::AXTreeID RenderFrameHostImpl::RoutingIDToAXTreeID( + int routing_id) { + RenderFrameHostImpl* rfh = nullptr; + RenderFrameProxyHost* rfph = RenderFrameProxyHost::FromID( + GetProcess()->GetID(), routing_id); + if (rfph) { + FrameTree* frame_tree = frame_tree_node()->frame_tree(); + FrameTreeNode* frame_tree_node = frame_tree->FindByRoutingID( + GetProcess()->GetID(), routing_id); + rfh = frame_tree_node->render_manager()->current_frame_host(); + } else { + rfh = RenderFrameHostImpl::FromID(GetProcess()->GetID(), routing_id); + } + + if (!rfh) + return AXTreeIDRegistry::kNoAXTreeID; + + // As a sanity check, make sure we're within the same frame tree and + // crash the renderer if not. + if (rfh->frame_tree_node()->frame_tree() != frame_tree_node()->frame_tree()) { + AccessibilityFatalError(); + return AXTreeIDRegistry::kNoAXTreeID; + } + + return rfh->GetAXTreeID(); +} + +AXTreeIDRegistry::AXTreeID +RenderFrameHostImpl::BrowserPluginInstanceIDToAXTreeID( + int instance_id) { + RenderFrameHost* guest = delegate()->GetGuestByInstanceID( + this, instance_id); + if (!guest) + return AXTreeIDRegistry::kNoAXTreeID; + + return guest->GetAXTreeID(); +} + +void RenderFrameHostImpl::AXContentNodeDataToAXNodeData( + const AXContentNodeData& src, + ui::AXNodeData* dst) { + // Copy the common fields. + *dst = src; + + // Map content-specific attributes based on routing IDs or browser plugin + // instance IDs to generic attributes with global AXTreeIDs. + for (auto iter : src.content_int_attributes) { + AXContentIntAttribute attr = iter.first; + int32 value = iter.second; + switch (attr) { + case AX_CONTENT_ATTR_ROUTING_ID: + dst->int_attributes.push_back(std::make_pair( + ui::AX_ATTR_TREE_ID, RoutingIDToAXTreeID(value))); + break; + case AX_CONTENT_ATTR_PARENT_ROUTING_ID: + dst->int_attributes.push_back(std::make_pair( + ui::AX_ATTR_PARENT_TREE_ID, RoutingIDToAXTreeID(value))); + break; + case AX_CONTENT_ATTR_CHILD_ROUTING_ID: + dst->int_attributes.push_back(std::make_pair( + ui::AX_ATTR_CHILD_TREE_ID, RoutingIDToAXTreeID(value))); + break; + case AX_CONTENT_ATTR_CHILD_BROWSER_PLUGIN_INSTANCE_ID: + dst->int_attributes.push_back(std::make_pair( + ui::AX_ATTR_CHILD_TREE_ID, + BrowserPluginInstanceIDToAXTreeID(value))); + break; + case AX_CONTENT_INT_ATTRIBUTE_LAST: + NOTREACHED(); + break; + } + } +} + } // namespace content diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h index 772cdeb..a36899d 100644 --- a/content/browser/frame_host/render_frame_host_impl.h +++ b/content/browser/frame_host/render_frame_host_impl.h @@ -17,6 +17,7 @@ #include "content/browser/accessibility/browser_accessibility_manager.h" #include "content/browser/site_instance_impl.h" #include "content/common/accessibility_mode_enums.h" +#include "content/common/ax_content_node_data.h" #include "content/common/content_export.h" #include "content/common/frame_message_enums.h" #include "content/common/frame_replication_state.h" @@ -123,11 +124,14 @@ class CONTENT_EXPORT RenderFrameHostImpl static const int kMaxAccessibilityResets = 5; static RenderFrameHostImpl* FromID(int process_id, int routing_id); + static RenderFrameHostImpl* FromAXTreeID( + AXTreeIDRegistry::AXTreeID ax_tree_id); ~RenderFrameHostImpl() override; // RenderFrameHost int GetRoutingID() override; + AXTreeIDRegistry::AXTreeID GetAXTreeID() override; SiteInstanceImpl* GetSiteInstance() override; RenderProcessHost* GetProcess() override; RenderFrameHost* GetParent() override; @@ -188,11 +192,6 @@ class CONTENT_EXPORT RenderFrameHostImpl void AccessibilityFatalError() override; gfx::AcceleratedWidget AccessibilityGetAcceleratedWidget() override; gfx::NativeViewAccessible AccessibilityGetNativeViewAccessible() override; - BrowserAccessibilityManager* AccessibilityGetChildFrame( - int accessibility_node_id) override; - void AccessibilityGetAllChildFrames( - std::vector<BrowserAccessibilityManager*>* child_frames) override; - BrowserAccessibility* AccessibilityGetParentFrame() override; // Creates a RenderFrame in the renderer process. Only called for // cross-process subframe navigations in --site-per-process. @@ -559,7 +558,7 @@ class CONTENT_EXPORT RenderFrameHostImpl const AccessibilityHostMsg_FindInPageResultParams& params); void OnAccessibilitySnapshotResponse( int callback_id, - const ui::AXTreeUpdate<ui::AXNodeData>& snapshot); + const ui::AXTreeUpdate<AXContentNodeData>& snapshot); void OnToggleFullscreen(bool enter_fullscreen); void OnDidStartLoading(bool to_different_document); void OnDidStopLoading(); @@ -582,18 +581,6 @@ class CONTENT_EXPORT RenderFrameHostImpl // it will be used to kill processes that commit unauthorized URLs. bool CanCommitURL(const GURL& url); - // Update the the singleton FrameAccessibility instance with a map - // from accessibility node id to the frame routing id of a cross-process - // iframe. - void UpdateCrossProcessIframeAccessibility( - const std::map<int32, int>& node_to_frame_routing_id_map); - - // Update the the singleton FrameAccessibility instance with a map - // from accessibility node id to the browser plugin instance id of a - // guest WebContents. - void UpdateGuestFrameAccessibility( - const std::map<int32, int>& node_to_browser_plugin_instance_id_map); - // Asserts that the given RenderFrameHostImpl is part of the same browser // context (and crashes if not), then returns whether the given frame is // part of the same site instance. @@ -609,6 +596,19 @@ class CONTENT_EXPORT RenderFrameHostImpl // Returns true if the ExecuteJavaScript() API can be used on this host. bool CanExecuteJavaScript(); + // Map a routing ID from a frame in the same frame tree to a globally + // unique AXTreeID. + AXTreeIDRegistry::AXTreeID RoutingIDToAXTreeID(int routing_id); + + // Map a browser plugin instance ID to the AXTreeID of the plugin's + // main frame. + AXTreeIDRegistry::AXTreeID BrowserPluginInstanceIDToAXTreeID(int routing_id); + + // Convert the content-layer-specific AXContentNodeData to a general-purpose + // AXNodeData structure. + void AXContentNodeDataToAXNodeData(const AXContentNodeData& src, + ui::AXNodeData* dst); + // For now, RenderFrameHosts indirectly keep RenderViewHosts alive via a // refcount that calls Shutdown when it reaches zero. This allows each // RenderFrameHostManager to just care about RenderFrameHosts, while ensuring |