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();
65 FML_LOG(ERROR) <<
"Failed to update ui::AXTree, error: " <<
error;
83 std::vector<std::vector<SemanticsNode>> results;
84 while (!pending_semantics_node_updates_.empty()) {
85 auto begin = pending_semantics_node_updates_.begin();
86 SemanticsNode
target = begin->second;
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()) {
114 FML_LOG(ERROR) <<
"Failed to update ui::AXTree, error: " <<
error;
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());
152void AccessibilityBridge::OnNodeWillBeDeleted(
ui::AXTree* tree,
155void AccessibilityBridge::OnSubtreeWillBeDeleted(
ui::AXTree* tree,
161void AccessibilityBridge::OnRoleChanged(
ui::AXTree* tree,
166void AccessibilityBridge::OnNodeDataChanged(
173 platform_view->NodeDataChanged(old_node_data, new_node_data);
180 id_wrapper_map_[node->
id()]->Init(
181 std::static_pointer_cast<FlutterPlatformNodeDelegate::OwnerBridge>(
186void AccessibilityBridge::OnNodeDeleted(
ui::AXTree* tree,
189 if (id_wrapper_map_.find(node_id) != id_wrapper_map_.end()) {
190 id_wrapper_map_.erase(node_id);
194void AccessibilityBridge::OnAtomicUpdateFinished(
197 const std::vector<ui::AXTreeObserver::Change>& changes) {
201 for (
const auto& change : changes) {
206 offset_container_id = node->
parent()->
id();
209 data.relative_bounds.transform.get());
213std::optional<ui::AXTreeUpdate>
214AccessibilityBridge::CreateRemoveReparentedNodesUpdate() {
215 std::unordered_map<int32_t, ui::AXNodeData> updates;
217 for (
const auto& node_update : pending_semantics_node_updates_) {
218 for (int32_t child_id : node_update.second.children_in_traversal_order) {
220 ui::AXNode* child = tree_->GetFromId(child_id);
229 if (child->
parent()->
id() == node_update.second.id) {
235 assert(pending_semantics_node_updates_.find(child_id) !=
236 pending_semantics_node_updates_.end());
239 int32_t parent_id = child->
parent()->
id();
240 if (updates.find(parent_id) == updates.end()) {
241 updates[parent_id] = tree_->GetFromId(parent_id)->data();
253 if (updates.empty()) {
259 .nodes = std::vector<ui::AXNodeData>(),
262 for (std::pair<int32_t, ui::AXNodeData>
data : updates) {
263 update.nodes.push_back(std::move(
data.second));
270void AccessibilityBridge::GetSubTreeList(
const SemanticsNode&
target,
271 std::vector<SemanticsNode>& result) {
273 for (int32_t child :
target.children_in_traversal_order) {
274 auto iter = pending_semantics_node_updates_.find(child);
275 if (iter != pending_semantics_node_updates_.end()) {
276 SemanticsNode node = iter->second;
277 GetSubTreeList(node, result);
278 pending_semantics_node_updates_.erase(iter);
283void AccessibilityBridge::ConvertFlutterUpdate(
const SemanticsNode& node,
286 node_data.
id = node.id;
287 SetRoleFromFlutterUpdate(node_data, node);
288 SetStateFromFlutterUpdate(node_data, node);
289 SetActionsFromFlutterUpdate(node_data, node);
290 SetBooleanAttributesFromFlutterUpdate(node_data, node);
291 SetIntAttributesFromFlutterUpdate(node_data, node);
292 SetIntListAttributesFromFlutterUpdate(node_data, node);
293 SetStringListAttributesFromFlutterUpdate(node_data, node);
294 SetIdentifierFromFlutterUpdate(node_data, node);
295 SetNameFromFlutterUpdate(node_data, node);
296 SetValueFromFlutterUpdate(node_data, node);
297 SetTooltipFromFlutterUpdate(node_data, node);
299 node.rect.right - node.rect.left,
300 node.rect.bottom - node.rect.top);
302 node.transform.scaleX, node.transform.skewX, node.transform.transX, 0,
303 node.transform.skewY, node.transform.scaleY, node.transform.transY, 0,
304 node.transform.pers0, node.transform.pers1, node.transform.pers2, 0, 0, 0,
306 for (
auto child : node.children_in_traversal_order) {
309 SetTreeData(node, tree_update);
310 tree_update.
nodes.push_back(node_data);
313void AccessibilityBridge::SetRoleFromFlutterUpdate(
ui::AXNodeData& node_data,
314 const SemanticsNode& node) {
316 FML_DCHECK(flags) <<
"SemanticsNode::flags must not be null";
357 if (node.children_in_traversal_order.empty()) {
364void AccessibilityBridge::SetStateFromFlutterUpdate(
ui::AXNodeData& node_data,
365 const SemanticsNode& node) {
378 node.label.empty() && node.hint.empty()) {
388void AccessibilityBridge::SetActionsFromFlutterUpdate(
390 const SemanticsNode& node) {
432void AccessibilityBridge::SetBooleanAttributesFromFlutterUpdate(
434 const SemanticsNode& node) {
444 !node.children_in_traversal_order.empty());
457void AccessibilityBridge::SetIntAttributesFromFlutterUpdate(
459 const SemanticsNode& node) {
462 node.text_direction);
464 int sel_start = node.text_selection_base;
465 int sel_end = node.text_selection_extent;
468 sel_start = sel_start == -1 ? node.value.length() : sel_start;
469 sel_end = sel_end == -1 ? node.value.length() : sel_end;
478 static_cast<int32_t
>(
487 static_cast<int32_t
>(
494void AccessibilityBridge::SetIntListAttributesFromFlutterUpdate(
496 const SemanticsNode& node) {
499 std::vector<int32_t> custom_action_ids;
500 custom_action_ids.reserve(node.custom_accessibility_actions.size());
501 for (
size_t i = 0;
i < node.custom_accessibility_actions.size();
i++) {
502 custom_action_ids.push_back(node.custom_accessibility_actions[
i]);
509void AccessibilityBridge::SetStringListAttributesFromFlutterUpdate(
511 const SemanticsNode& node) {
514 std::vector<std::string> custom_action_description;
515 for (
size_t i = 0;
i < node.custom_accessibility_actions.size();
i++) {
516 auto iter = pending_semantics_custom_action_updates_.find(
517 node.custom_accessibility_actions[
i]);
518 BASE_DCHECK(iter != pending_semantics_custom_action_updates_.end());
519 custom_action_description.push_back(iter->second.label);
523 custom_action_description);
527void AccessibilityBridge::SetIdentifierFromFlutterUpdate(
529 const SemanticsNode& node) {
534void AccessibilityBridge::SetNameFromFlutterUpdate(
ui::AXNodeData& node_data,
535 const SemanticsNode& node) {
539void AccessibilityBridge::SetValueFromFlutterUpdate(
ui::AXNodeData& node_data,
540 const SemanticsNode& node) {
544void AccessibilityBridge::SetTooltipFromFlutterUpdate(
546 const SemanticsNode& node) {
550void AccessibilityBridge::SetTreeData(
const SemanticsNode& node,
559 if (node.text_selection_base != -1) {
585AccessibilityBridge::SemanticsNode
586AccessibilityBridge::FromFlutterSemanticsNode(
588 SemanticsNode result;
589 result.id = flutter_node.
id;
591 <<
"FlutterSemanticsNode2::flags2 must not be null";
593 result.flags = flutter_node.
flags2;
594 result.actions = flutter_node.
actions;
603 if (flutter_node.
label) {
604 result.label = std::string(flutter_node.
label);
606 if (flutter_node.
hint) {
607 result.hint = std::string(flutter_node.
hint);
609 if (flutter_node.
value) {
610 result.value = std::string(flutter_node.
value);
619 result.tooltip = std::string(flutter_node.
tooltip);
622 result.rect = flutter_node.
rect;
623 result.transform = flutter_node.
transform;
625 result.children_in_traversal_order = std::vector<int32_t>(
630 result.custom_accessibility_actions = std::vector<int32_t>(
636 result.identifier = std::string(flutter_node.
identifier);
641AccessibilityBridge::SemanticsCustomAction
642AccessibilityBridge::FromFlutterSemanticsCustomAction(
644 SemanticsCustomAction result;
645 result.id = flutter_custom_action.
id;
647 if (flutter_custom_action.
label) {
648 result.label = std::string(flutter_custom_action.
label);
650 if (flutter_custom_action.
hint) {
651 result.hint = std::string(flutter_custom_action.
hint);
657 if (last_focused_id_ != node_id) {
658 auto last_focused_child =
660 if (!last_focused_child.expired()) {
667 last_focused_id_ = node_id;
672 return last_focused_id_;
678 if (!platform_node_delegate) {
681 return platform_node_delegate->GetNativeViewAccessible();
687 return tree_->RelativeToTreeBounds(node,
gfx::RectF(), &offscreen,
699 return tree_->GetFromId(node_id);
703 return tree_->GetAXTreeID();
711 return tree_->root();
725 auto platform_delegate = platform_delegate_weak.lock();
726 if (!platform_delegate) {
729 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 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()
@ kFlutterCheckStateNone
The semantics node does not have check state.
@ kFlutterCheckStateTrue
The semantics node is checked.
@ kFlutterCheckStateMixed
The semantics node represents a checkbox in mixed state.
@ 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
@ kFlutterTristateTrue
The property is applicable and its state is "true" or "on".
@ kFlutterTristateFalse
The property is applicable and its state is "false" or "off".
@ kFlutterTristateNone
The property is not applicable to this semantics node.
static gboolean is_checked(FlutterSemanticsFlags 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.
bool is_link
Whether the semantics node represents a link.
bool is_image
Whether the semantics node represents an image.
bool is_slider
Whether the semantics node represents a slider.
bool is_header
Whether a semantic node is a header that divides content into sections.
FlutterTristate is_selected
Whether a semantics node is selected.
bool is_in_mutually_exclusive_group
Whether a semantic node is in a mutually exclusive group.
FlutterTristate is_toggled
FlutterTristate is_focused
Whether the semantic node currently holds the user's focus.
FlutterTristate is_expanded
Whether a semantic node that is currently expanded.
bool is_text_field
Whether the semantic node represents a text field.
FlutterCheckState is_checked
Whether a semantics node is checked.
bool is_button
Whether the semantic node represents a button.
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.
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.
FlutterSemanticsFlags * flags2
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.
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 AddStringAttribute(ax::mojom::StringAttribute attribute, const std::string &value)
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)