10#include "flutter/third_party/accessibility/ax/ax_tree_manager_map.h"
11#include "flutter/third_party/accessibility/ax/ax_tree_update.h"
12#include "flutter/third_party/accessibility/base/logging.h"
24 : tree_(
std::make_unique<
ui::AXTree>()) {
25 event_generator_.
SetTree(tree_.get());
29 tree_->UpdateData(
data);
41 pending_semantics_node_updates_[node.
id] = FromFlutterSemanticsNode(node);
46 pending_semantics_custom_action_updates_[
action.id] =
47 FromFlutterSemanticsCustomAction(
action);
58 std::optional<ui::AXTreeUpdate> remove_reparented =
59 CreateRemoveReparentedNodesUpdate();
60 if (remove_reparented.has_value()) {
61 tree_->Unserialize(remove_reparented.value());
63 std::string
error = tree_->error();
83 std::vector<std::vector<SemanticsNode>> results;
84 while (!pending_semantics_node_updates_.empty()) {
85 auto begin = pending_semantics_node_updates_.begin();
87 std::vector<SemanticsNode> sub_tree_list;
88 GetSubTreeList(
target, sub_tree_list);
89 results.push_back(sub_tree_list);
90 pending_semantics_node_updates_.erase(
begin);
93 for (
size_t i = results.size(); i > 0; i--) {
94 for (
const SemanticsNode& node : results[i - 1]) {
95 ConvertFlutterUpdate(node,
update);
105 update.root_id = results.back().front().id;
108 tree_->Unserialize(
update);
109 pending_semantics_node_updates_.clear();
110 pending_semantics_custom_action_updates_.clear();
112 std::string
error = tree_->error();
113 if (!
error.empty()) {
118 for (
const auto& targeted_event : event_generator_) {
121 if (event_target.expired()) {
130std::weak_ptr<FlutterPlatformNodeDelegate>
133 const auto iter = id_wrapper_map_.find(
id);
134 if (iter != id_wrapper_map_.end()) {
138 return std::weak_ptr<FlutterPlatformNodeDelegate>();
142 return tree_->data();
145const std::vector<ui::AXEventGenerator::TargetedEvent>
147 std::vector<ui::AXEventGenerator::TargetedEvent>
result(
148 event_generator_.
begin(), event_generator_.
end());
169 id_wrapper_map_[node->
id()]->Init(
170 std::static_pointer_cast<FlutterPlatformNodeDelegate::OwnerBridge>(
178 if (id_wrapper_map_.find(node_id) != id_wrapper_map_.end()) {
179 id_wrapper_map_.erase(node_id);
186 const std::vector<ui::AXTreeObserver::Change>& changes) {
190 for (
const auto& change : changes) {
195 offset_container_id = node->
parent()->
id();
198 data.relative_bounds.transform.get());
202std::optional<ui::AXTreeUpdate>
203AccessibilityBridge::CreateRemoveReparentedNodesUpdate() {
204 std::unordered_map<int32_t, ui::AXNodeData> updates;
206 for (
const auto& node_update : pending_semantics_node_updates_) {
207 for (int32_t child_id : node_update.second.children_in_traversal_order) {
209 ui::AXNode* child = tree_->GetFromId(child_id);
218 if (child->
parent()->
id() == node_update.second.id) {
224 assert(pending_semantics_node_updates_.find(child_id) !=
225 pending_semantics_node_updates_.end());
228 int32_t parent_id = child->
parent()->
id();
229 if (updates.find(parent_id) == updates.end()) {
230 updates[parent_id] = tree_->GetFromId(parent_id)->data();
242 if (updates.empty()) {
247 .tree_data = tree_->data(),
248 .nodes = std::vector<ui::AXNodeData>(),
251 for (std::pair<int32_t, ui::AXNodeData>
data : updates) {
252 update.nodes.push_back(std::move(
data.second));
259void AccessibilityBridge::GetSubTreeList(
const SemanticsNode&
target,
260 std::vector<SemanticsNode>&
result) {
262 for (int32_t child :
target.children_in_traversal_order) {
263 auto iter = pending_semantics_node_updates_.find(child);
264 if (iter != pending_semantics_node_updates_.end()) {
265 SemanticsNode node = iter->second;
266 GetSubTreeList(node,
result);
267 pending_semantics_node_updates_.erase(iter);
272void AccessibilityBridge::ConvertFlutterUpdate(
const SemanticsNode& node,
275 node_data.
id = node.id;
276 SetRoleFromFlutterUpdate(node_data, node);
277 SetStateFromFlutterUpdate(node_data, node);
278 SetActionsFromFlutterUpdate(node_data, node);
279 SetBooleanAttributesFromFlutterUpdate(node_data, node);
280 SetIntAttributesFromFlutterUpdate(node_data, node);
281 SetIntListAttributesFromFlutterUpdate(node_data, node);
282 SetStringListAttributesFromFlutterUpdate(node_data, node);
283 SetNameFromFlutterUpdate(node_data, node);
284 SetValueFromFlutterUpdate(node_data, node);
285 SetTooltipFromFlutterUpdate(node_data, node);
287 node.rect.right - node.rect.left,
288 node.rect.bottom - node.rect.top);
290 node.transform.scaleX, node.transform.skewX, node.transform.transX, 0,
291 node.transform.skewY, node.transform.scaleY, node.transform.transY, 0,
292 node.transform.pers0, node.transform.pers1, node.transform.pers2, 0, 0, 0,
294 for (
auto child : node.children_in_traversal_order) {
297 SetTreeData(node, tree_update);
298 tree_update.
nodes.push_back(node_data);
301void AccessibilityBridge::SetRoleFromFlutterUpdate(
ui::AXNodeData& node_data,
302 const SemanticsNode& node) {
345 if (node.children_in_traversal_order.empty()) {
352void AccessibilityBridge::SetStateFromFlutterUpdate(
ui::AXNodeData& node_data,
353 const SemanticsNode& node) {
369 node.label.empty() && node.hint.empty()) {
379void AccessibilityBridge::SetActionsFromFlutterUpdate(
381 const SemanticsNode& node) {
423void AccessibilityBridge::SetBooleanAttributesFromFlutterUpdate(
425 const SemanticsNode& node) {
435 !node.children_in_traversal_order.empty());
451void AccessibilityBridge::SetIntAttributesFromFlutterUpdate(
453 const SemanticsNode& node) {
456 node.text_direction);
458 int sel_start = node.text_selection_base;
459 int sel_end = node.text_selection_extent;
462 !node.value.empty()) {
464 sel_start = sel_start == -1 ? node.value.length() : sel_start;
465 sel_end = sel_end == -1 ? node.value.length() : sel_end;
474 static_cast<int32_t
>(
483 static_cast<int32_t
>(
490void AccessibilityBridge::SetIntListAttributesFromFlutterUpdate(
492 const SemanticsNode& node) {
495 std::vector<int32_t> custom_action_ids;
496 for (
size_t i = 0; i < node.custom_accessibility_actions.size(); i++) {
497 custom_action_ids.push_back(node.custom_accessibility_actions[i]);
504void AccessibilityBridge::SetStringListAttributesFromFlutterUpdate(
506 const SemanticsNode& node) {
509 std::vector<std::string> custom_action_description;
510 for (
size_t i = 0; i < node.custom_accessibility_actions.size(); i++) {
511 auto iter = pending_semantics_custom_action_updates_.find(
512 node.custom_accessibility_actions[i]);
513 BASE_DCHECK(iter != pending_semantics_custom_action_updates_.end());
514 custom_action_description.push_back(iter->second.label);
518 custom_action_description);
522void AccessibilityBridge::SetNameFromFlutterUpdate(
ui::AXNodeData& node_data,
523 const SemanticsNode& node) {
527void AccessibilityBridge::SetValueFromFlutterUpdate(
ui::AXNodeData& node_data,
528 const SemanticsNode& node) {
532void AccessibilityBridge::SetTooltipFromFlutterUpdate(
534 const SemanticsNode& node) {
538void AccessibilityBridge::SetTreeData(
const SemanticsNode& node,
547 if (node.text_selection_base != -1) {
574AccessibilityBridge::SemanticsNode
575AccessibilityBridge::FromFlutterSemanticsNode(
590 if (flutter_node.
label) {
593 if (flutter_node.
hint) {
596 if (flutter_node.
value) {
612 result.children_in_traversal_order = std::vector<int32_t>(
617 result.custom_accessibility_actions = std::vector<int32_t>(
625AccessibilityBridge::SemanticsCustomAction
626AccessibilityBridge::FromFlutterSemanticsCustomAction(
628 SemanticsCustomAction
result;
629 result.id = flutter_custom_action.
id;
631 if (flutter_custom_action.
label) {
632 result.label = std::string(flutter_custom_action.
label);
634 if (flutter_custom_action.
hint) {
635 result.hint = std::string(flutter_custom_action.
hint);
641 if (last_focused_id_ != node_id) {
642 auto last_focused_child =
644 if (!last_focused_child.expired()) {
651 last_focused_id_ = node_id;
656 return last_focused_id_;
662 if (!platform_node_delegate) {
665 return platform_node_delegate->GetNativeViewAccessible();
671 return tree_->RelativeToTreeBounds(node,
gfx::RectF(), &offscreen,
683 return tree_->GetFromId(node_id);
687 return tree_->GetAXTreeID();
695 return tree_->root();
709 auto platform_delegate = platform_delegate_weak.lock();
710 if (!platform_delegate) {
713 return platform_delegate->GetPlatformNode();
ui::AXTree * GetTree() const override
ui::AXPlatformNodeDelegate * RootDelegate() const override
std::weak_ptr< FlutterPlatformNodeDelegate > GetFlutterPlatformNodeDelegateFromID(AccessibilityNodeId id) const
Get the flutter platform node delegate with the given id from this accessibility bridge....
void OnNodeCreated(ui::AXTree *tree, ui::AXNode *node) override
AccessibilityNodeId GetLastFocusedId() override
Get the last id of the node that received accessibility focus.
void AddFlutterSemanticsNodeUpdate(const FlutterSemanticsNode2 &node)
Adds a semantics node update to the pending semantics update. Calling this method alone will NOT upda...
void OnSubtreeWillBeDeleted(ui::AXTree *tree, ui::AXNode *node) override
virtual std::shared_ptr< FlutterPlatformNodeDelegate > CreateFlutterPlatformNodeDelegate()=0
Creates a platform specific FlutterPlatformNodeDelegate. Ownership passes to the caller....
void AddFlutterSemanticsCustomActionUpdate(const FlutterSemanticsCustomAction2 &action)
Adds a custom semantics action update to the pending semantics update. Calling this method alone will...
ui::AXPlatformNode * GetPlatformNodeFromTree(const ui::AXNode::AXID node_id) const override
gfx::RectF RelativeToGlobalBounds(const ui::AXNode *node, bool &offscreen, bool clip_bounds) override
Gets the rectangular bounds of the ax node relative to global coordinate.
const ui::AXTreeData & GetAXTreeData() const
Get the ax tree data from this accessibility bridge. The tree data contains information such as the i...
ui::AXTreeID GetParentTreeID() const override
ui::AXNode * GetRootAsAXNode() const override
void SetLastFocusedId(AccessibilityNodeId node_id) override
Update the id of the node that is currently foucsed by the native accessibility system.
virtual ~AccessibilityBridge()
gfx::NativeViewAccessible GetNativeAccessibleFromId(AccessibilityNodeId id) override
Get the native accessibility node with the given id.
ui::AXNode * GetParentNodeFromParentTreeAsAXNode() const override
void OnAtomicUpdateFinished(ui::AXTree *tree, bool root_changed, const std::vector< ui::AXTreeObserver::Change > &changes) override
AccessibilityBridge()
Creates a new instance of a accessibility bridge.
virtual void OnAccessibilityEvent(ui::AXEventGenerator::TargetedEvent targeted_event)=0
Handle accessibility events generated due to accessibility tree changes. These events are needed to b...
ui::AXTreeID GetTreeID() const override
void OnNodeWillBeDeleted(ui::AXTree *tree, ui::AXNode *node) override
void OnNodeDeleted(ui::AXTree *tree, AccessibilityNodeId node_id) override
const std::vector< ui::AXEventGenerator::TargetedEvent > GetPendingEvents() const
Gets all pending accessibility events generated during semantics updates. This is useful when decidin...
void OnRoleChanged(ui::AXTree *tree, ui::AXNode *node, ax::mojom::Role old_role, ax::mojom::Role new_role) override
void CommitUpdates()
Flushes the pending updates and applies them to this accessibility bridge. Calling this with no pendi...
void OnNodeReparented(ui::AXTree *tree, ui::AXNode *node) override
ui::AXNode * GetNodeFromTree(const ui::AXTreeID tree_id, const ui::AXNode::AXID node_id) const override
void SetRect(float x, float y, float width, float height)
void SetTree(AXTree *new_tree)
static constexpr AXID kInvalidAXID
void SetLocation(int32_t offset_container_id, const gfx::RectF &location, gfx::Transform *transform)
const AXNodeData & data() const
static AXTreeID CreateNewAXTreeID()
void AddTreeManager(AXTreeID tree_id, AXTreeManager *manager)
static AXTreeManagerMap & GetInstance()
static const char * begin(const StringSlice &s)
@ kFlutterSemanticsActionDidLoseAccessibilityFocus
Indicate that the node has lost accessibility focus.
@ kFlutterSemanticsActionDecrease
Decrease the value represented by the semantics node.
@ kFlutterSemanticsActionScrollDown
@ kFlutterSemanticsActionScrollRight
@ kFlutterSemanticsActionSetSelection
Set the text selection to the given range.
@ kFlutterSemanticsActionScrollUp
@ kFlutterSemanticsActionCustomAction
Indicate that the user has invoked a custom accessibility action.
@ kFlutterSemanticsActionIncrease
Increase the value represented by the semantics node.
@ kFlutterSemanticsActionScrollLeft
@ kFlutterSemanticsActionDidGainAccessibilityFocus
Indicate that the node has gained accessibility focus.
@ kFlutterSemanticsActionTap
@ kFlutterSemanticsFlagIsHeader
Whether a semantic node is a header that divides content into sections.
@ kFlutterSemanticsFlagIsSlider
Whether the semantics node represents a slider.
@ kFlutterSemanticsFlagHasToggledState
The semantics node has the quality of either being "on" or "off".
@ kFlutterSemanticsFlagIsSelected
Whether a semantics node is selected.
@ kFlutterSemanticsFlagIsInMutuallyExclusiveGroup
Whether a semantic node is in a mutually exclusive group.
@ kFlutterSemanticsFlagIsChecked
Whether a semantics node is checked.
@ kFlutterSemanticsFlagHasExpandedState
@ kFlutterSemanticsFlagIsCheckStateMixed
Whether the semantics node represents a tristate checkbox in mixed state.
@ kFlutterSemanticsFlagIsToggled
@ kFlutterSemanticsFlagIsButton
Whether the semantic node represents a button.
@ kFlutterSemanticsFlagIsReadOnly
@ kFlutterSemanticsFlagIsLink
Whether the semantics node represents a link.
@ kFlutterSemanticsFlagIsFocused
Whether the semantic node currently holds the user's focus.
@ kFlutterSemanticsFlagIsImage
Whether the semantics node represents an image.
@ kFlutterSemanticsFlagIsTextField
Whether the semantic node represents a text field.
@ kFlutterSemanticsFlagHasCheckedState
@ kFlutterSemanticsFlagIsExpanded
Whether a semantic node that hasExpandedState is currently expanded.
FlutterSemanticsFlag flags
const uint8_t uint32_t uint32_t GError ** error
#define FML_LOG(severity)
#define FML_DCHECK(condition)
@ kCustomActionDescriptions
@ kClearAccessibilityFocus
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot data
constexpr int kHasScrollingAction
ui::AXNode::AXID AccessibilityNodeId
UnimplementedNativeViewAccessible * NativeViewAccessible
const AXTreeID & AXTreeIDUnknown()
const char * hint
The hint description of this custom semantics action.
const char * label
The user-readable name of this custom semantics action.
FlutterSemanticsAction override_action
int32_t id
The unique custom action or action override ID.
const char * increased_value
const char * tooltip
A textual tooltip attached to the node.
int32_t scroll_index
The index of the first visible semantic child of a scroll node.
size_t custom_accessibility_actions_count
The number of custom accessibility action associated with this node.
const int32_t * children_in_traversal_order
Array of child node IDs in traversal order. Has length child_count.
double scroll_extent_min
The minimum in-range value for scrollPosition if the node is scrollable.
double thickness
Describes how much space the semantics node takes up along the z-axis.
int32_t text_selection_extent
The position at which the text selection terminates.
FlutterTextDirection text_direction
FlutterSemanticsAction actions
The set of semantics actions applicable to this node.
const int32_t * custom_accessibility_actions
int32_t id
The unique identifier for this node.
FlutterRect rect
The bounding box for this node in its coordinate system.
FlutterTransformation transform
size_t child_count
The number of children this node has.
double scroll_extent_max
The maximum in-range value for scrollPosition if the node is scrollable.
const char * decreased_value
const char * label
A textual description of the node.
int32_t text_selection_base
The position at which the text selection originates.
const char * hint
A brief description of the result of performing an action on the node.
const char * value
A textual description of the current value of the node.
int32_t scroll_child_count
The total number of scrollable children that contribute to semantics.
FlutterSemanticsFlag flags
The set of semantics flags associated with this node.
AXRelativeBounds relative_bounds
void AddIntListAttribute(ax::mojom::IntListAttribute attribute, const std::vector< int32_t > &value)
void AddState(ax::mojom::State state)
void AddIntAttribute(ax::mojom::IntAttribute attribute, int32_t value)
std::vector< int32_t > child_ids
void SetValue(const std::string &value)
void AddStringListAttribute(ax::mojom::StringListAttribute attribute, const std::vector< std::string > &value)
void SetName(const std::string &name)
void SetTooltip(const std::string &value)
void AddBoolAttribute(ax::mojom::BoolAttribute attribute, bool value)
void AddAction(ax::mojom::Action action)
std::unique_ptr< gfx::Transform > transform
AXNode::AXID sel_anchor_object_id
AXNode::AXID sel_focus_object_id
int32_t sel_anchor_offset
std::vector< AXNodeData > nodes
#define BASE_DCHECK(condition)