diff --git a/shell/platform/common/flutter_platform_node_delegate.cc b/shell/platform/common/flutter_platform_node_delegate.cc index d45bf96dc2098..9e4e8a4a2b111 100644 --- a/shell/platform/common/flutter_platform_node_delegate.cc +++ b/shell/platform/common/flutter_platform_node_delegate.cc @@ -6,7 +6,9 @@ #include +#include "flutter/shell/platform/common/accessibility_bridge.h" #include "flutter/third_party/accessibility/ax/ax_action_data.h" +#include "flutter/third_party/accessibility/ax/ax_tree_manager_map.h" #include "flutter/third_party/accessibility/gfx/geometry/rect_conversions.h" namespace flutter { @@ -118,4 +120,46 @@ ui::AXPlatformNode* FlutterPlatformNodeDelegate::GetPlatformNode() const { return nullptr; } +gfx::NativeViewAccessible +FlutterPlatformNodeDelegate::GetLowestPlatformAncestor() const { + auto bridge_ptr = bridge_.lock(); + BASE_DCHECK(bridge_ptr); + auto lowest_platform_ancestor = ax_node_->GetLowestPlatformAncestor(); + if (lowest_platform_ancestor) { + return bridge_ptr->GetNativeAccessibleFromId( + ax_node_->GetLowestPlatformAncestor()->id()); + } + return nullptr; +} + +ui::AXNodePosition::AXPositionInstance +FlutterPlatformNodeDelegate::CreateTextPositionAt(int offset) const { + return ui::AXNodePosition::CreatePosition(*ax_node_, offset); +} + +ui::AXPlatformNode* FlutterPlatformNodeDelegate::GetFromNodeID( + int32_t node_id) { + ui::AXTreeManager* tree_manager = + ui::AXTreeManagerMap::GetInstance().GetManager( + ax_node_->tree()->GetAXTreeID()); + AccessibilityBridge* platform_manager = + static_cast(tree_manager); + return platform_manager->GetPlatformNodeFromTree(node_id); +} + +ui::AXPlatformNode* FlutterPlatformNodeDelegate::GetFromTreeIDAndNodeID( + const ui::AXTreeID& tree_id, + int32_t node_id) { + ui::AXTreeManager* tree_manager = + ui::AXTreeManagerMap::GetInstance().GetManager(tree_id); + AccessibilityBridge* platform_manager = + static_cast(tree_manager); + return platform_manager->GetPlatformNodeFromTree(node_id); +} + +const ui::AXTree::Selection FlutterPlatformNodeDelegate::GetUnignoredSelection() + const { + return ax_node_->GetUnignoredSelection(); +} + } // namespace flutter diff --git a/shell/platform/common/flutter_platform_node_delegate.h b/shell/platform/common/flutter_platform_node_delegate.h index a22fa3e97fa9c..6172f4f86b9f2 100644 --- a/shell/platform/common/flutter_platform_node_delegate.h +++ b/shell/platform/common/flutter_platform_node_delegate.h @@ -125,6 +125,13 @@ class FlutterPlatformNodeDelegate : public ui::AXPlatformNodeDelegateBase { const ui::AXClippingBehavior clipping_behavior, ui::AXOffscreenResult* offscreen_result) const override; + // |ui::AXPlatformNodeDelegateBase| + gfx::NativeViewAccessible GetLowestPlatformAncestor() const override; + + // |ui::AXPlatformNodeDelegateBase| + ui::AXNodePosition::AXPositionInstance CreateTextPositionAt( + int offset) const override; + //------------------------------------------------------------------------------ /// @brief Called only once, immediately after construction. The /// constructor doesn't take any arguments because in the Windows @@ -147,6 +154,17 @@ class FlutterPlatformNodeDelegate : public ui::AXPlatformNodeDelegateBase { // Get the platform node represented by this delegate. virtual ui::AXPlatformNode* GetPlatformNode() const; + // |ui::AXPlatformNodeDelegateBase| + virtual ui::AXPlatformNode* GetFromNodeID(int32_t id) override; + + // |ui::AXPlatformNodeDelegateBase| + virtual ui::AXPlatformNode* GetFromTreeIDAndNodeID( + const ui::AXTreeID& tree_id, + int32_t node_id) override; + + // |ui::AXPlatformNodeDelegateBase| + virtual const ui::AXTree::Selection GetUnignoredSelection() const override; + private: ui::AXNode* ax_node_; std::weak_ptr bridge_; diff --git a/shell/platform/common/flutter_platform_node_delegate_unittests.cc b/shell/platform/common/flutter_platform_node_delegate_unittests.cc index cc91ae0506736..d9fe80c211c3b 100644 --- a/shell/platform/common/flutter_platform_node_delegate_unittests.cc +++ b/shell/platform/common/flutter_platform_node_delegate_unittests.cc @@ -246,5 +246,63 @@ TEST(FlutterPlatformNodeDelegateTest, canUseOwnerBridge) { EXPECT_EQ(result, false); } +TEST(FlutterPlatformNodeDelegateTest, selfIsLowestPlatformAncestor) { + std::shared_ptr bridge = + std::make_shared(); + FlutterSemanticsNode root; + root.id = 0; + root.label = "root"; + root.hint = ""; + root.value = ""; + root.increased_value = ""; + root.decreased_value = ""; + root.tooltip = ""; + root.child_count = 0; + root.children_in_traversal_order = nullptr; + root.custom_accessibility_actions_count = 0; + bridge->AddFlutterSemanticsNodeUpdate(&root); + + bridge->CommitUpdates(); + auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock(); + auto lowest_platform_ancestor = root_node->GetLowestPlatformAncestor(); + EXPECT_EQ(root_node->GetNativeViewAccessible(), lowest_platform_ancestor); +} + +TEST(FlutterPlatformNodeDelegateTest, canGetFromNodeID) { + std::shared_ptr bridge = + std::make_shared(); + FlutterSemanticsNode root; + root.id = 0; + root.label = "root"; + root.hint = ""; + root.value = ""; + root.increased_value = ""; + root.decreased_value = ""; + root.tooltip = ""; + root.child_count = 1; + int32_t children[] = {1}; + root.children_in_traversal_order = children; + root.custom_accessibility_actions_count = 0; + bridge->AddFlutterSemanticsNodeUpdate(&root); + + FlutterSemanticsNode child1; + child1.id = 1; + child1.label = "child 1"; + child1.hint = ""; + child1.value = ""; + child1.increased_value = ""; + child1.decreased_value = ""; + child1.tooltip = ""; + child1.child_count = 0; + child1.custom_accessibility_actions_count = 0; + bridge->AddFlutterSemanticsNodeUpdate(&child1); + + bridge->CommitUpdates(); + auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock(); + auto child1_node = bridge->GetFlutterPlatformNodeDelegateFromID(1).lock(); + auto node_by_id = root_node->GetFromNodeID(1); + EXPECT_EQ(child1_node->GetPlatformNode(), node_by_id); +} + } // namespace testing } // namespace flutter