From 1efe8793da85ee6e25185175047c077adfe8e55c Mon Sep 17 00:00:00 2001 From: dmazzoni Date: Thu, 6 Aug 2015 18:02:15 -0700 Subject: Get rid of FrameAccessibility using AXTreeIDs Depends on: https://codereview.chromium.org/1257093005/ Instead of keeping track of the relationship between frames in FrameAccessibility, create a subclass of AXNodeData that's only allowed to be used within the content module, and once an AX tree is received in the browser process, convert routing IDs to global AXTreeIDs that can be stored AXNodeData. BUG=368298 Review URL: https://codereview.chromium.org/1267663002 Cr-Commit-Position: refs/heads/master@{#342251} --- .../browser/accessibility/ax_tree_id_registry.cc | 52 ---- chrome/browser/accessibility/ax_tree_id_registry.h | 50 ---- .../api/automation/automation_apitest.cc | 1 - .../automation_internal/automation_event_router.cc | 1 - .../automation_internal/automation_internal_api.cc | 53 +--- .../ui/aura/accessibility/ax_tree_source_aura.cc | 6 +- chrome/chrome_browser.gypi | 2 - .../common/extensions/chrome_extension_messages.h | 19 ++ .../accessibility_ipc_error_browsertest.cc | 6 +- .../browser/accessibility/ax_tree_id_registry.cc | 61 +++++ .../browser/accessibility/ax_tree_id_registry.h | 55 ++++ .../browser/accessibility/browser_accessibility.cc | 41 +-- .../browser/accessibility/browser_accessibility.h | 5 - .../browser_accessibility_auralinux.cc | 5 + .../accessibility/browser_accessibility_manager.cc | 120 +++++++-- .../accessibility/browser_accessibility_manager.h | 24 +- .../browser_accessibility_manager_unittest.cc | 45 ++-- .../browser_accessibility_manager_win.cc | 46 ++-- .../browser_accessibility_manager_win.h | 4 + .../browser_accessibility_win_unittest.cc | 16 +- .../site_per_process_accessibility_browsertest.cc | 33 +-- content/browser/frame_host/frame_accessibility.cc | 229 ----------------- content/browser/frame_host/frame_accessibility.h | 106 -------- .../browser/frame_host/render_frame_host_impl.cc | 283 +++++++++++---------- .../browser/frame_host/render_frame_host_impl.h | 36 +-- content/common/accessibility_messages.h | 45 ++-- content/common/ax_content_node_data.cc | 93 +++++++ content/common/ax_content_node_data.h | 51 ++++ content/content_browser.gypi | 4 +- content/content_common.gypi | 2 + .../browser/ax_event_notification_details.cc | 20 +- .../public/browser/ax_event_notification_details.h | 20 +- content/public/browser/render_frame_host.h | 6 + content/public/common/common_param_traits_macros.h | 20 -- .../renderer/accessibility/blink_ax_tree_source.cc | 57 +++-- .../renderer/accessibility/blink_ax_tree_source.h | 15 +- .../accessibility/renderer_accessibility.cc | 6 +- .../accessibility/renderer_accessibility.h | 8 +- .../renderer_accessibility_browsertest.cc | 1 + content/renderer/render_frame_impl.cc | 3 +- content/test/accessibility_browser_test_utils.cc | 7 + content/test/accessibility_browser_test_utils.h | 2 + ui/accessibility/ax_enums.idl | 10 +- ui/accessibility/ax_node_data.cc | 6 +- 44 files changed, 765 insertions(+), 910 deletions(-) delete mode 100644 chrome/browser/accessibility/ax_tree_id_registry.cc delete mode 100644 chrome/browser/accessibility/ax_tree_id_registry.h create mode 100644 content/browser/accessibility/ax_tree_id_registry.cc create mode 100644 content/browser/accessibility/ax_tree_id_registry.h delete mode 100644 content/browser/frame_host/frame_accessibility.cc delete mode 100644 content/browser/frame_host/frame_accessibility.h create mode 100644 content/common/ax_content_node_data.cc create mode 100644 content/common/ax_content_node_data.h diff --git a/chrome/browser/accessibility/ax_tree_id_registry.cc b/chrome/browser/accessibility/ax_tree_id_registry.cc deleted file mode 100644 index 4314ea4..0000000 --- a/chrome/browser/accessibility/ax_tree_id_registry.cc +++ /dev/null @@ -1,52 +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 "chrome/browser/accessibility/ax_tree_id_registry.h" - -#include "base/memory/singleton.h" - -// static -AXTreeIDRegistry* AXTreeIDRegistry::GetInstance() { - return Singleton::get(); -} - -int AXTreeIDRegistry::GetOrCreateAXTreeID(int process_id, int routing_id) { - FrameID frame_id(process_id, routing_id); - std::map::iterator it; - it = frame_to_ax_tree_id_map_.find(frame_id); - if (it != frame_to_ax_tree_id_map_.end()) - return it->second; - - int 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(int ax_tree_id) { - std::map::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(int ax_tree_id) { - std::map::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() { -} diff --git a/chrome/browser/accessibility/ax_tree_id_registry.h b/chrome/browser/accessibility/ax_tree_id_registry.h deleted file mode 100644 index bdcf72c..0000000 --- a/chrome/browser/accessibility/ax_tree_id_registry.h +++ /dev/null @@ -1,50 +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 CHROME_BROWSER_ACCESSIBILITY_AX_TREE_ID_REGISTRY_H_ -#define CHROME_BROWSER_ACCESSIBILITY_AX_TREE_ID_REGISTRY_H_ - -#include - -#include "base/stl_util.h" - -template -struct DefaultSingletonTraits; - -// A class which generates a unique id given a process id and routing id. -// Currently, placeholder implementation pending finalization of out of process -// iframes. -class AXTreeIDRegistry { - public: - typedef int AXTreeID; - typedef std::pair FrameID; - - // 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. - int GetOrCreateAXTreeID(int process_id, int routing_id); - FrameID GetFrameID(int ax_tree_id); - void RemoveAXTreeID(int ax_tree_id); - - private: - friend struct DefaultSingletonTraits; - - AXTreeIDRegistry(); - virtual ~AXTreeIDRegistry(); - - // Tracks the current unique ax frame id. - int ax_tree_id_counter_; - - // Maps an accessibility tree to its frame via ids. - std::map ax_tree_to_frame_id_map_; - - // Maps frames to an accessibility tree via ids. - std::map frame_to_ax_tree_id_map_; - - DISALLOW_COPY_AND_ASSIGN(AXTreeIDRegistry); -}; - -#endif // CHROME_BROWSER_ACCESSIBILITY_AX_TREE_ID_REGISTRY_H_ diff --git a/chrome/browser/extensions/api/automation/automation_apitest.cc b/chrome/browser/extensions/api/automation/automation_apitest.cc index 739424d..f63998e 100644 --- a/chrome/browser/extensions/api/automation/automation_apitest.cc +++ b/chrome/browser/extensions/api/automation/automation_apitest.cc @@ -8,7 +8,6 @@ #include "base/single_thread_task_runner.h" #include "base/strings/string_number_conversions.h" #include "base/thread_task_runner_handle.h" -#include "chrome/browser/accessibility/ax_tree_id_registry.h" #include "chrome/browser/extensions/api/automation_internal/automation_event_router.h" #include "chrome/browser/extensions/chrome_extension_function.h" #include "chrome/browser/extensions/extension_apitest.h" diff --git a/chrome/browser/extensions/api/automation_internal/automation_event_router.cc b/chrome/browser/extensions/api/automation_internal/automation_event_router.cc index 7be3332..3e4539d 100644 --- a/chrome/browser/extensions/api/automation_internal/automation_event_router.cc +++ b/chrome/browser/extensions/api/automation_internal/automation_event_router.cc @@ -10,7 +10,6 @@ #include "base/stl_util.h" #include "base/values.h" -#include "chrome/browser/accessibility/ax_tree_id_registry.h" #include "chrome/common/extensions/api/automation_internal.h" #include "chrome/common/extensions/chrome_extension_messages.h" #include "content/public/browser/notification_service.h" diff --git a/chrome/browser/extensions/api/automation_internal/automation_internal_api.cc b/chrome/browser/extensions/api/automation_internal/automation_internal_api.cc index 58efba5..dc10f2c 100644 --- a/chrome/browser/extensions/api/automation_internal/automation_internal_api.cc +++ b/chrome/browser/extensions/api/automation_internal/automation_internal_api.cc @@ -9,7 +9,6 @@ #include "base/strings/string16.h" #include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" -#include "chrome/browser/accessibility/ax_tree_id_registry.h" #include "chrome/browser/extensions/api/automation_internal/automation_action_adapter.h" #include "chrome/browser/extensions/api/automation_internal/automation_event_router.h" #include "chrome/browser/extensions/api/tabs/tabs_constants.h" @@ -201,42 +200,14 @@ class AutomationWebContentsObserver details.begin(); for (; iter != details.end(); ++iter) { const content::AXEventNotificationDetails& event = *iter; - int tree_id = AXTreeIDRegistry::GetInstance()->GetOrCreateAXTreeID( - event.process_id, event.routing_id); ExtensionMsg_AccessibilityEventParams params; - params.tree_id = tree_id; + params.tree_id = event.ax_tree_id; params.id = event.id; params.event_type = event.event_type; - params.update.node_id_to_clear = event.node_id_to_clear; - params.update.nodes = event.nodes; + params.update = event.update; params.location_offset = web_contents()->GetContainerBounds().OffsetFromOrigin(); - for (size_t i = 0; i < params.update.nodes.size(); ++i) { - ui::AXNodeData& node = params.update.nodes[i]; - if (node.HasBoolAttribute(ui::AX_ATTR_IS_AX_TREE_HOST)) { - const auto& iter = event.node_to_browser_plugin_instance_id_map.find( - node.id); - if (iter != event.node_to_browser_plugin_instance_id_map.end()) { - int instance_id = iter->second; - content::BrowserPluginGuestManager* guest_manager = - browser_context_->GetGuestManager(); - content::WebContents* guest_web_contents = - guest_manager->GetGuestByInstanceID(event.process_id, - instance_id); - if (guest_web_contents) { - content::RenderFrameHost* guest_rfh = - guest_web_contents->GetMainFrame(); - int guest_tree_id = - AXTreeIDRegistry::GetInstance()->GetOrCreateAXTreeID( - guest_rfh->GetProcess()->GetID(), - guest_rfh->GetRoutingID()); - node.AddIntAttribute(ui::AX_ATTR_CHILD_TREE_ID, guest_tree_id); - } - } - } - } - AutomationEventRouter* router = AutomationEventRouter::GetInstance(); router->DispatchAccessibilityEvent(params); } @@ -244,10 +215,7 @@ class AutomationWebContentsObserver void RenderFrameDeleted( content::RenderFrameHost* render_frame_host) override { - int tree_id = AXTreeIDRegistry::GetInstance()->GetOrCreateAXTreeID( - render_frame_host->GetProcess()->GetID(), - render_frame_host->GetRoutingID()); - AXTreeIDRegistry::GetInstance()->RemoveAXTreeID(tree_id); + int tree_id = render_frame_host->GetAXTreeID(); AutomationEventRouter::GetInstance()->DispatchTreeDestroyedEvent( tree_id, browser_context_); @@ -304,8 +272,7 @@ AutomationInternalEnableTabFunction::Run() { AutomationWebContentsObserver::CreateForWebContents(contents); contents->EnableTreeOnlyAccessibilityMode(); - int ax_tree_id = AXTreeIDRegistry::GetInstance()->GetOrCreateAXTreeID( - rfh->GetProcess()->GetID(), rfh->GetRoutingID()); + int ax_tree_id = rfh->GetAXTreeID(); // This gets removed when the extension process dies. AutomationEventRouter::GetInstance()->RegisterListenerForOneTree( @@ -324,10 +291,8 @@ ExtensionFunction::ResponseAction AutomationInternalEnableFrameFunction::Run() { scoped_ptr params(Params::Create(*args_)); EXTENSION_FUNCTION_VALIDATE(params.get()); - AXTreeIDRegistry::FrameID frame_id = - AXTreeIDRegistry::GetInstance()->GetFrameID(params->tree_id); content::RenderFrameHost* rfh = - content::RenderFrameHost::FromID(frame_id.first, frame_id.second); + content::RenderFrameHost::FromAXTreeID(params->tree_id); if (!rfh) return RespondNow(Error("unable to load tab")); @@ -358,10 +323,8 @@ AutomationInternalPerformActionFunction::Run() { " platform does not support desktop automation")); #endif // defined(USE_AURA) } - AXTreeIDRegistry::FrameID frame_id = - AXTreeIDRegistry::GetInstance()->GetFrameID(params->args.tree_id); content::RenderFrameHost* rfh = - content::RenderFrameHost::FromID(frame_id.first, frame_id.second); + content::RenderFrameHost::FromAXTreeID(params->args.tree_id); if (!rfh) return RespondNow(Error("Ignoring action on destroyed node")); @@ -450,10 +413,8 @@ AutomationInternalQuerySelectorFunction::Run() { return RespondNow( Error("domQuerySelector queries may not be used on the desktop.")); } - AXTreeIDRegistry::FrameID frame_id = - AXTreeIDRegistry::GetInstance()->GetFrameID(params->args.tree_id); content::RenderFrameHost* rfh = - content::RenderFrameHost::FromID(frame_id.first, frame_id.second); + content::RenderFrameHost::FromAXTreeID(params->args.tree_id); if (!rfh) return RespondNow(Error("domQuerySelector query sent on destroyed tree.")); diff --git a/chrome/browser/ui/aura/accessibility/ax_tree_source_aura.cc b/chrome/browser/ui/aura/accessibility/ax_tree_source_aura.cc index 9ab3f3e..6c6a585 100644 --- a/chrome/browser/ui/aura/accessibility/ax_tree_source_aura.cc +++ b/chrome/browser/ui/aura/accessibility/ax_tree_source_aura.cc @@ -6,7 +6,6 @@ #include -#include "chrome/browser/accessibility/ax_tree_id_registry.h" #include "chrome/browser/ui/aura/accessibility/automation_manager_aura.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_process_host.h" @@ -110,10 +109,7 @@ void AXTreeSourceAura::SerializeNode(AXAuraObjWrapper* node, static_cast(view)->GetWebContents(); content::RenderFrameHost* rfh = contents->GetMainFrame(); if (rfh) { - int process_id = rfh->GetProcess()->GetID(); - int routing_id = rfh->GetRoutingID(); - int ax_tree_id = AXTreeIDRegistry::GetInstance()->GetOrCreateAXTreeID( - process_id, routing_id); + int ax_tree_id = rfh->GetAXTreeID(); out_data->AddIntAttribute(ui::AX_ATTR_CHILD_TREE_ID, ax_tree_id); } } diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 33a7d82..8cf1e3e 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -980,8 +980,6 @@ ], # Everything but Android and iOS. 'chrome_browser_non_mobile_sources': [ - 'browser/accessibility/ax_tree_id_registry.cc', - 'browser/accessibility/ax_tree_id_registry.h', 'browser/accessibility/invert_bubble_prefs.cc', 'browser/accessibility/invert_bubble_prefs.h', 'browser/auto_launch_trial.cc', diff --git a/chrome/common/extensions/chrome_extension_messages.h b/chrome/common/extensions/chrome_extension_messages.h index 6ca1b75..3865f3e 100644 --- a/chrome/common/extensions/chrome_extension_messages.h +++ b/chrome/common/extensions/chrome_extension_messages.h @@ -54,6 +54,25 @@ IPC_MESSAGE_ROUTED4(ExtensionMsg_InlineWebstoreInstallResponse, std::string /* error */, extensions::webstore_install::Result /* result */) +IPC_STRUCT_TRAITS_BEGIN(ui::AXNodeData) + IPC_STRUCT_TRAITS_MEMBER(id) + IPC_STRUCT_TRAITS_MEMBER(role) + IPC_STRUCT_TRAITS_MEMBER(state) + IPC_STRUCT_TRAITS_MEMBER(location) + IPC_STRUCT_TRAITS_MEMBER(string_attributes) + IPC_STRUCT_TRAITS_MEMBER(int_attributes) + IPC_STRUCT_TRAITS_MEMBER(float_attributes) + IPC_STRUCT_TRAITS_MEMBER(bool_attributes) + IPC_STRUCT_TRAITS_MEMBER(intlist_attributes) + IPC_STRUCT_TRAITS_MEMBER(html_attributes) + IPC_STRUCT_TRAITS_MEMBER(child_ids) +IPC_STRUCT_TRAITS_END() + +IPC_STRUCT_TRAITS_BEGIN(ui::AXTreeUpdate) + IPC_STRUCT_TRAITS_MEMBER(node_id_to_clear) + IPC_STRUCT_TRAITS_MEMBER(nodes) +IPC_STRUCT_TRAITS_END() + IPC_STRUCT_BEGIN(ExtensionMsg_AccessibilityEventParams) // ID of the accessibility tree that this event applies to. IPC_STRUCT_MEMBER(int, tree_id) 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 bad_accessibility_event_list; - bad_accessibility_event_list.push_back(AccessibilityHostMsg_EventParams()); + std::vector 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::get(); +} + +AXTreeIDRegistry::AXTreeID AXTreeIDRegistry::GetOrCreateAXTreeID( + int process_id, int routing_id) { + FrameID frame_id(process_id, routing_id); + std::map::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::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::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 + +#include "base/stl_util.h" + +template +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 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(); + 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 ax_tree_to_frame_id_map_; + + // Maps frames to an accessibility tree via ids. + std::map 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; +base::LazyInstance 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& params) { + const std::vector& 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& 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* 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& params); + const std::vector& 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* 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 params; - params.push_back(AccessibilityHostMsg_EventParams()); - AccessibilityHostMsg_EventParams* msg = ¶ms[0]; + std::vector 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 params; - params.push_back(AccessibilityHostMsg_EventParams()); - AccessibilityHostMsg_EventParams* msg = ¶ms[0]; + std::vector 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 params; - params.push_back(AccessibilityHostMsg_EventParams()); - AccessibilityHostMsg_EventParams* msg = ¶ms[0]; + std::vector 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 events; - events.push_back(AccessibilityHostMsg_EventParams()); + std::vector 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 events2; - events2.push_back(AccessibilityHostMsg_EventParams()); + std::vector 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 events; - events.push_back(AccessibilityHostMsg_EventParams()); + std::vector 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 events2; - events2.push_back(AccessibilityHostMsg_EventParams()); + std::vector 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::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 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 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 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 events; + std::vector 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 events; + std::vector 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 params; - params.push_back(AccessibilityHostMsg_EventParams()); - AccessibilityHostMsg_EventParams* msg = ¶ms[0]; + std::vector 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( 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::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::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::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(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::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(guest); - } - } - - return nullptr; -} - -void FrameAccessibility::GetAllChildFrames( - RenderFrameHostImpl* parent_frame_host, - std::vector* child_frame_hosts) { - CHECK(child_frame_hosts); - - for (std::vector::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(guest)); - } - } -} - -bool FrameAccessibility::GetParent( - RenderFrameHostImpl* child_frame_host, - RenderFrameHostImpl** out_parent_frame_host, - int* out_accessibility_node_id) { - for (std::vector::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 - -#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* 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