diff --git a/shell/platform/common/accessibility_bridge.cc b/shell/platform/common/accessibility_bridge.cc index f95998d15b167..4b1ea03563815 100644 --- a/shell/platform/common/accessibility_bridge.cc +++ b/shell/platform/common/accessibility_bridge.cc @@ -7,6 +7,7 @@ #include #include +#include "flutter/third_party/accessibility/ax/ax_tree_manager_map.h" #include "flutter/third_party/accessibility/ax/ax_tree_update.h" #include "flutter/third_party/accessibility/base/logging.h" @@ -19,14 +20,20 @@ constexpr int kHasScrollingAction = FlutterSemanticsAction::kFlutterSemanticsActionScrollDown; // AccessibilityBridge -AccessibilityBridge::AccessibilityBridge() { - event_generator_.SetTree(&tree_); - tree_.AddObserver(static_cast(this)); +AccessibilityBridge::AccessibilityBridge() + : tree_(std::make_unique()) { + event_generator_.SetTree(tree_.get()); + tree_->AddObserver(static_cast(this)); + ui::AXTreeData data = tree_->data(); + data.tree_id = ui::AXTreeID::CreateNewAXTreeID(); + tree_->UpdateData(data); + ui::AXTreeManagerMap::GetInstance().AddTreeManager(tree_->GetAXTreeID(), + this); } AccessibilityBridge::~AccessibilityBridge() { event_generator_.ReleaseTree(); - tree_.RemoveObserver(static_cast(this)); + tree_->RemoveObserver(static_cast(this)); } void AccessibilityBridge::AddFlutterSemanticsNodeUpdate( @@ -51,9 +58,9 @@ void AccessibilityBridge::CommitUpdates() { std::optional remove_reparented = CreateRemoveReparentedNodesUpdate(); if (remove_reparented.has_value()) { - tree_.Unserialize(remove_reparented.value()); + tree_->Unserialize(remove_reparented.value()); - std::string error = tree_.error(); + std::string error = tree_->error(); if (!error.empty()) { FML_LOG(ERROR) << "Failed to update ui::AXTree, error: " << error; assert(false); @@ -63,7 +70,7 @@ void AccessibilityBridge::CommitUpdates() { // Second, apply the pending node updates. This also moves reparented nodes to // their new parents if needed. - ui::AXTreeUpdate update{.tree_data = tree_.data()}; + ui::AXTreeUpdate update{.tree_data = tree_->data()}; // Figure out update order, ui::AXTree only accepts update in tree order, // where parent node must come before the child node in @@ -88,11 +95,11 @@ void AccessibilityBridge::CommitUpdates() { } } - tree_.Unserialize(update); + tree_->Unserialize(update); pending_semantics_node_updates_.clear(); pending_semantics_custom_action_updates_.clear(); - std::string error = tree_.error(); + std::string error = tree_->error(); if (!error.empty()) { FML_LOG(ERROR) << "Failed to update ui::AXTree, error: " << error; return; @@ -122,7 +129,7 @@ AccessibilityBridge::GetFlutterPlatformNodeDelegateFromID( } const ui::AXTreeData& AccessibilityBridge::GetAXTreeData() const { - return tree_.data(); + return tree_->data(); } const std::vector @@ -201,7 +208,7 @@ AccessibilityBridge::CreateRemoveReparentedNodesUpdate() { for (auto node_update : pending_semantics_node_updates_) { for (int32_t child_id : node_update.second.children_in_traversal_order) { // Skip nodes that don't exist or have a parent in the current tree. - ui::AXNode* child = tree_.GetFromId(child_id); + ui::AXNode* child = tree_->GetFromId(child_id); if (!child) { continue; } @@ -222,7 +229,7 @@ AccessibilityBridge::CreateRemoveReparentedNodesUpdate() { // Create an update to remove the child from its previous parent. int32_t parent_id = child->parent()->id(); if (updates.find(parent_id) == updates.end()) { - updates[parent_id] = tree_.GetFromId(parent_id)->data(); + updates[parent_id] = tree_->GetFromId(parent_id)->data(); } ui::AXNodeData* parent = &updates[parent_id]; @@ -239,7 +246,7 @@ AccessibilityBridge::CreateRemoveReparentedNodesUpdate() { } ui::AXTreeUpdate update{ - .tree_data = tree_.data(), + .tree_data = tree_->data(), .nodes = std::vector(), }; @@ -649,8 +656,60 @@ gfx::NativeViewAccessible AccessibilityBridge::GetNativeAccessibleFromId( gfx::RectF AccessibilityBridge::RelativeToGlobalBounds(const ui::AXNode* node, bool& offscreen, bool clip_bounds) { - return tree_.RelativeToTreeBounds(node, gfx::RectF(), &offscreen, - clip_bounds); + return tree_->RelativeToTreeBounds(node, gfx::RectF(), &offscreen, + clip_bounds); +} + +ui::AXNode* AccessibilityBridge::GetNodeFromTree( + ui::AXTreeID tree_id, + ui::AXNode::AXID node_id) const { + return GetNodeFromTree(node_id); +} + +ui::AXNode* AccessibilityBridge::GetNodeFromTree( + ui::AXNode::AXID node_id) const { + return tree_->GetFromId(node_id); +} + +ui::AXTreeID AccessibilityBridge::GetTreeID() const { + return tree_->GetAXTreeID(); +} + +ui::AXTreeID AccessibilityBridge::GetParentTreeID() const { + return ui::AXTreeIDUnknown(); +} + +ui::AXNode* AccessibilityBridge::GetRootAsAXNode() const { + return tree_->root(); +} + +ui::AXNode* AccessibilityBridge::GetParentNodeFromParentTreeAsAXNode() const { + return nullptr; +} + +ui::AXTree* AccessibilityBridge::GetTree() const { + return tree_.get(); +} + +ui::AXPlatformNode* AccessibilityBridge::GetPlatformNodeFromTree( + const ui::AXNode::AXID node_id) const { + auto platform_delegate_weak = GetFlutterPlatformNodeDelegateFromID(node_id); + auto platform_delegate = platform_delegate_weak.lock(); + if (!platform_delegate) { + return nullptr; + } + return platform_delegate->GetPlatformNode(); +} + +ui::AXPlatformNode* AccessibilityBridge::GetPlatformNodeFromTree( + const ui::AXNode& node) const { + return GetPlatformNodeFromTree(node.id()); +} + +ui::AXPlatformNodeDelegate* AccessibilityBridge::RootDelegate() const { + return GetFlutterPlatformNodeDelegateFromID(GetRootAsAXNode()->id()) + .lock() + .get(); } } // namespace flutter diff --git a/shell/platform/common/accessibility_bridge.h b/shell/platform/common/accessibility_bridge.h index fe88f27fa91e1..eb913f6b5c7bf 100644 --- a/shell/platform/common/accessibility_bridge.h +++ b/shell/platform/common/accessibility_bridge.h @@ -14,6 +14,7 @@ #include "flutter/third_party/accessibility/ax/ax_tree.h" #include "flutter/third_party/accessibility/ax/ax_tree_observer.h" #include "flutter/third_party/accessibility/ax/platform/ax_platform_node_delegate.h" +#include "flutter/third_party/accessibility/ax/platform/ax_platform_tree_manager.h" #include "flutter_platform_node_delegate.h" @@ -39,6 +40,7 @@ namespace flutter { class AccessibilityBridge : public std::enable_shared_from_this, public FlutterPlatformNodeDelegate::OwnerBridge, + public ui::AXPlatformTreeManager, private ui::AXTreeObserver { public: //----------------------------------------------------------------------------- @@ -106,6 +108,39 @@ class AccessibilityBridge const std::vector GetPendingEvents() const; + // |AXTreeManager| + ui::AXNode* GetNodeFromTree(const ui::AXTreeID tree_id, + const ui::AXNode::AXID node_id) const override; + + // |AXTreeManager| + ui::AXNode* GetNodeFromTree(const ui::AXNode::AXID node_id) const override; + + // |AXTreeManager| + ui::AXTreeID GetTreeID() const override; + + // |AXTreeManager| + ui::AXTreeID GetParentTreeID() const override; + + // |AXTreeManager| + ui::AXNode* GetRootAsAXNode() const override; + + // |AXTreeManager| + ui::AXNode* GetParentNodeFromParentTreeAsAXNode() const override; + + // |AXTreeManager| + ui::AXTree* GetTree() const override; + + // |AXPlatformTreeManager| + ui::AXPlatformNode* GetPlatformNodeFromTree( + const ui::AXNode::AXID node_id) const override; + + // |AXPlatformTreeManager| + ui::AXPlatformNode* GetPlatformNodeFromTree( + const ui::AXNode& node) const override; + + // |AXPlatformTreeManager| + ui::AXPlatformNodeDelegate* RootDelegate() const override; + protected: //--------------------------------------------------------------------------- /// @brief Handle accessibility events generated due to accessibility @@ -176,7 +211,7 @@ class AccessibilityBridge std::unordered_map> id_wrapper_map_; - ui::AXTree tree_; + std::unique_ptr tree_; ui::AXEventGenerator event_generator_; std::unordered_map pending_semantics_node_updates_; std::unordered_map diff --git a/shell/platform/common/accessibility_bridge_unittests.cc b/shell/platform/common/accessibility_bridge_unittests.cc index 5dc52393ec737..e6a72f98d4d21 100644 --- a/shell/platform/common/accessibility_bridge_unittests.cc +++ b/shell/platform/common/accessibility_bridge_unittests.cc @@ -7,6 +7,7 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" +#include "flutter/third_party/accessibility/ax/ax_tree_manager_map.h" #include "test_accessibility_bridge.h" namespace flutter { @@ -483,5 +484,15 @@ TEST(AccessibilityBridgeTest, CanReparentNodeWithChild) { Contains(ui::AXEventGenerator::Event::ROLE_CHANGED).Times(1)); } +TEST(AccessibilityBridgeTest, AXTreeManagerTest) { + std::shared_ptr bridge = + std::make_shared(); + + ui::AXTreeID tree_id = bridge->GetTreeID(); + ui::AXTreeManager* manager = + ui::AXTreeManagerMap::GetInstance().GetManager(tree_id); + ASSERT_EQ(manager, static_cast(bridge.get())); +} + } // namespace testing } // namespace flutter diff --git a/shell/platform/common/flutter_platform_node_delegate.cc b/shell/platform/common/flutter_platform_node_delegate.cc index cf5464fc861ba..d45bf96dc2098 100644 --- a/shell/platform/common/flutter_platform_node_delegate.cc +++ b/shell/platform/common/flutter_platform_node_delegate.cc @@ -114,4 +114,8 @@ FlutterPlatformNodeDelegate::GetOwnerBridge() const { return bridge_; } +ui::AXPlatformNode* FlutterPlatformNodeDelegate::GetPlatformNode() const { + return nullptr; +} + } // namespace flutter diff --git a/shell/platform/common/flutter_platform_node_delegate.h b/shell/platform/common/flutter_platform_node_delegate.h index 2878fe45afe92..a22fa3e97fa9c 100644 --- a/shell/platform/common/flutter_platform_node_delegate.h +++ b/shell/platform/common/flutter_platform_node_delegate.h @@ -144,6 +144,9 @@ class FlutterPlatformNodeDelegate : public ui::AXPlatformNodeDelegateBase { /// platform thread. std::weak_ptr GetOwnerBridge() const; + // Get the platform node represented by this delegate. + virtual ui::AXPlatformNode* GetPlatformNode() const; + private: ui::AXNode* ax_node_; std::weak_ptr bridge_; diff --git a/shell/platform/windows/flutter_platform_node_delegate_windows.cc b/shell/platform/windows/flutter_platform_node_delegate_windows.cc index a7c972be10a62..0e2ce94c7a7e2 100644 --- a/shell/platform/windows/flutter_platform_node_delegate_windows.cc +++ b/shell/platform/windows/flutter_platform_node_delegate_windows.cc @@ -107,4 +107,9 @@ FlutterPlatformNodeDelegateWindows::GetTargetForNativeAccessibilityEvent() { return view_->GetPlatformWindow(); } +ui::AXPlatformNode* FlutterPlatformNodeDelegateWindows::GetPlatformNode() + const { + return ax_platform_node_; +} + } // namespace flutter diff --git a/shell/platform/windows/flutter_platform_node_delegate_windows.h b/shell/platform/windows/flutter_platform_node_delegate_windows.h index 364411cfffeab..489ae4884daa5 100644 --- a/shell/platform/windows/flutter_platform_node_delegate_windows.h +++ b/shell/platform/windows/flutter_platform_node_delegate_windows.h @@ -51,6 +51,9 @@ class FlutterPlatformNodeDelegateWindows : public FlutterPlatformNodeDelegate { // | AXPlatformNodeDelegate | gfx::AcceleratedWidget GetTargetForNativeAccessibilityEvent() override; + // | FlutterPlatformNodeDelegate | + ui::AXPlatformNode* GetPlatformNode() const override; + private: ui::AXPlatformNode* ax_platform_node_; std::weak_ptr bridge_;