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()) {
127 event_generator_.ClearEvents();
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());
152void AccessibilityBridge::OnNodeWillBeDeleted(
ui::AXTree* tree,
155void AccessibilityBridge::OnSubtreeWillBeDeleted(
ui::AXTree* tree,
161void AccessibilityBridge::OnRoleChanged(
ui::AXTree* tree,
169 id_wrapper_map_[node->
id()]->Init(
170 std::static_pointer_cast<FlutterPlatformNodeDelegate::OwnerBridge>(
175void AccessibilityBridge::OnNodeDeleted(
ui::AXTree* tree,
178 if (id_wrapper_map_.find(node_id) != id_wrapper_map_.end()) {
179 id_wrapper_map_.erase(node_id);
183void AccessibilityBridge::OnAtomicUpdateFinished(
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();
int find(T *array, int N, T item)
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 AddFlutterSemanticsNodeUpdate(const FlutterSemanticsNode2 &node)
Adds a semantics node update to the pending semantics update. Calling this method alone will NOT upda...
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
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
virtual ~AccessibilityBridge()
ui::AXNode * GetParentNodeFromParentTreeAsAXNode() const 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
const std::vector< ui::AXEventGenerator::TargetedEvent > GetPendingEvents() const
Gets all pending accessibility events generated during semantics updates. This is useful when decidin...
void CommitUpdates()
Flushes the pending updates and applies them to this accessibility bridge. Calling this with no pendi...
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)