Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make AccessibilityBridge a AXPlatformTreeManager #38610

Merged
merged 5 commits into from
Jan 3, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 77 additions & 15 deletions shell/platform/common/accessibility_bridge.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <functional>
#include <utility>

#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"

Expand All @@ -19,14 +20,20 @@ constexpr int kHasScrollingAction =
FlutterSemanticsAction::kFlutterSemanticsActionScrollDown;

// AccessibilityBridge
AccessibilityBridge::AccessibilityBridge() {
event_generator_.SetTree(&tree_);
tree_.AddObserver(static_cast<ui::AXTreeObserver*>(this));
AccessibilityBridge::AccessibilityBridge()
: tree_(std::make_unique<ui::AXTree>()) {
event_generator_.SetTree(tree_.get());
tree_->AddObserver(static_cast<ui::AXTreeObserver*>(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<ui::AXTreeObserver*>(this));
tree_->RemoveObserver(static_cast<ui::AXTreeObserver*>(this));
}

void AccessibilityBridge::AddFlutterSemanticsNodeUpdate(
Expand All @@ -51,9 +58,9 @@ void AccessibilityBridge::CommitUpdates() {
std::optional<ui::AXTreeUpdate> 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);
Expand All @@ -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
Expand All @@ -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;
Expand Down Expand Up @@ -122,7 +129,7 @@ AccessibilityBridge::GetFlutterPlatformNodeDelegateFromID(
}

const ui::AXTreeData& AccessibilityBridge::GetAXTreeData() const {
return tree_.data();
return tree_->data();
}

const std::vector<ui::AXEventGenerator::TargetedEvent>
Expand Down Expand Up @@ -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;
}
Expand All @@ -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];
Expand All @@ -239,7 +246,7 @@ AccessibilityBridge::CreateRemoveReparentedNodesUpdate() {
}

ui::AXTreeUpdate update{
.tree_data = tree_.data(),
.tree_data = tree_->data(),
.nodes = std::vector<ui::AXNodeData>(),
};

Expand Down Expand Up @@ -649,8 +656,63 @@ 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);
if (platform_delegate_weak.expired()) {
return nullptr;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this case unnecessary due to lock check below? See: https://en.cppreference.com/w/cpp/memory/weak_ptr/lock

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably

}
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
37 changes: 36 additions & 1 deletion shell/platform/common/accessibility_bridge.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand All @@ -39,6 +40,7 @@ namespace flutter {
class AccessibilityBridge
: public std::enable_shared_from_this<AccessibilityBridge>,
public FlutterPlatformNodeDelegate::OwnerBridge,
public ui::AXPlatformTreeManager,
private ui::AXTreeObserver {
public:
//-----------------------------------------------------------------------------
Expand Down Expand Up @@ -106,6 +108,39 @@ class AccessibilityBridge
const std::vector<ui::AXEventGenerator::TargetedEvent> 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
Expand Down Expand Up @@ -176,7 +211,7 @@ class AccessibilityBridge
std::unordered_map<AccessibilityNodeId,
std::shared_ptr<FlutterPlatformNodeDelegate>>
id_wrapper_map_;
ui::AXTree tree_;
std::unique_ptr<ui::AXTree> tree_;
ui::AXEventGenerator event_generator_;
std::unordered_map<int32_t, SemanticsNode> pending_semantics_node_updates_;
std::unordered_map<int32_t, SemanticsCustomAction>
Expand Down
11 changes: 11 additions & 0 deletions shell/platform/common/accessibility_bridge_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -483,5 +484,15 @@ TEST(AccessibilityBridgeTest, CanReparentNodeWithChild) {
Contains(ui::AXEventGenerator::Event::ROLE_CHANGED).Times(1));
}

TEST(AccessibilityBridgeTest, AXTreeManagerTest) {
std::shared_ptr<TestAccessibilityBridge> bridge =
std::make_shared<TestAccessibilityBridge>();

ui::AXTreeID tree_id = bridge->GetTreeID();
ui::AXTreeManager* manager =
ui::AXTreeManagerMap::GetInstance().GetManager(tree_id);
ASSERT_EQ(manager, static_cast<ui::AXTreeManager*>(bridge.get()));
}

} // namespace testing
} // namespace flutter
4 changes: 4 additions & 0 deletions shell/platform/common/flutter_platform_node_delegate.cc
Original file line number Diff line number Diff line change
Expand Up @@ -114,4 +114,8 @@ FlutterPlatformNodeDelegate::GetOwnerBridge() const {
return bridge_;
}

ui::AXPlatformNode* FlutterPlatformNodeDelegate::GetPlatformNode() const {
return nullptr;
}

} // namespace flutter
3 changes: 3 additions & 0 deletions shell/platform/common/flutter_platform_node_delegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,9 @@ class FlutterPlatformNodeDelegate : public ui::AXPlatformNodeDelegateBase {
/// platform thread.
std::weak_ptr<OwnerBridge> GetOwnerBridge() const;

// Get the platform node represented by this delegate.
virtual ui::AXPlatformNode* GetPlatformNode() const;

private:
ui::AXNode* ax_node_;
std::weak_ptr<OwnerBridge> bridge_;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,4 +107,9 @@ FlutterPlatformNodeDelegateWindows::GetTargetForNativeAccessibilityEvent() {
return view_->GetPlatformWindow();
}

ui::AXPlatformNode* FlutterPlatformNodeDelegateWindows::GetPlatformNode()
const {
return ax_platform_node_;
}

} // namespace flutter
Original file line number Diff line number Diff line change
Expand Up @@ -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<AccessibilityBridge> bridge_;
Expand Down