Flutter Engine
 
Loading...
Searching...
No Matches
accessibility_bridge.cc
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
6
7#include <functional>
8#include <utility>
9
13
14namespace flutter { // namespace
15
16constexpr int kHasScrollingAction =
21
22// AccessibilityBridge
24 : tree_(std::make_unique<ui::AXTree>()) {
25 event_generator_.SetTree(tree_.get());
26 tree_->AddObserver(static_cast<ui::AXTreeObserver*>(this));
27 ui::AXTreeData data = tree_->data();
29 tree_->UpdateData(data);
31 this);
32}
33
35 event_generator_.ReleaseTree();
36 tree_->RemoveObserver(static_cast<ui::AXTreeObserver*>(this));
37}
38
40 const FlutterSemanticsNode2& node) {
41 pending_semantics_node_updates_[node.id] = FromFlutterSemanticsNode(node);
42}
43
46 pending_semantics_custom_action_updates_[action.id] =
47 FromFlutterSemanticsCustomAction(action);
48}
49
51 // AXTree cannot move a node in a single update.
52 // This must be split across two updates:
53 //
54 // * Update 1: remove nodes from their old parents.
55 // * Update 2: re-add nodes (including their children) to their new parents.
56 //
57 // First, start by removing nodes if necessary.
58 std::optional<ui::AXTreeUpdate> remove_reparented =
59 CreateRemoveReparentedNodesUpdate();
60 if (remove_reparented.has_value()) {
61 tree_->Unserialize(remove_reparented.value());
62
63 std::string error = tree_->error();
64 if (!error.empty()) {
65 FML_LOG(ERROR) << "Failed to update ui::AXTree, error: " << error;
66 assert(false);
67 return;
68 }
69 }
70
71 // Second, apply the pending node updates. This also moves reparented nodes to
72 // their new parents if needed.
73 ui::AXTreeUpdate update{.tree_data = tree_->data()};
74
75 // Figure out update order, ui::AXTree only accepts update in tree order,
76 // where parent node must come before the child node in
77 // ui::AXTreeUpdate.nodes. We start with picking a random node and turn the
78 // entire subtree into a list. We pick another node from the remaining update,
79 // and keep doing so until the update map is empty. We then concatenate the
80 // lists in the reversed order, this guarantees parent updates always come
81 // before child updates. If the root is in the update, it is guaranteed to
82 // be the first node of the last list.
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);
91 }
92
93 for (size_t i = results.size(); i > 0; i--) {
94 for (const SemanticsNode& node : results[i - 1]) {
95 ConvertFlutterUpdate(node, update);
96 }
97 }
98
99 // The first update must set the tree's root, which is guaranteed to be the
100 // last list's first node. A tree's root node never changes, though it can be
101 // modified.
102 if (!results.empty() && GetRootAsAXNode()->id() == ui::AXNode::kInvalidAXID) {
103 FML_DCHECK(!results.back().empty());
104
105 update.root_id = results.back().front().id;
106 }
107
108 tree_->Unserialize(update);
109 pending_semantics_node_updates_.clear();
110 pending_semantics_custom_action_updates_.clear();
111
112 std::string error = tree_->error();
113 if (!error.empty()) {
114 FML_LOG(ERROR) << "Failed to update ui::AXTree, error: " << error;
115 return;
116 }
117 // Handles accessibility events as the result of the semantics update.
118 for (const auto& targeted_event : event_generator_) {
119 auto event_target =
120 GetFlutterPlatformNodeDelegateFromID(targeted_event.node->id());
121 if (event_target.expired()) {
122 continue;
123 }
124
125 OnAccessibilityEvent(targeted_event);
126 }
127 event_generator_.ClearEvents();
128}
129
130std::weak_ptr<FlutterPlatformNodeDelegate>
132 AccessibilityNodeId id) const {
133 const auto iter = id_wrapper_map_.find(id);
134 if (iter != id_wrapper_map_.end()) {
135 return iter->second;
136 }
137
138 return std::weak_ptr<FlutterPlatformNodeDelegate>();
139}
140
142 return tree_->data();
143}
144
145const std::vector<ui::AXEventGenerator::TargetedEvent>
147 std::vector<ui::AXEventGenerator::TargetedEvent> result(
148 event_generator_.begin(), event_generator_.end());
149 return result;
150}
151
152void AccessibilityBridge::OnNodeWillBeDeleted(ui::AXTree* tree,
153 ui::AXNode* node) {}
154
155void AccessibilityBridge::OnSubtreeWillBeDeleted(ui::AXTree* tree,
156 ui::AXNode* node) {}
157
158void AccessibilityBridge::OnNodeReparented(ui::AXTree* tree, ui::AXNode* node) {
159}
160
161void AccessibilityBridge::OnRoleChanged(ui::AXTree* tree,
162 ui::AXNode* node,
163 ax::mojom::Role old_role,
164 ax::mojom::Role new_role) {}
165
166void AccessibilityBridge::OnNodeDataChanged(
167 ui::AXTree* tree,
168 const ui::AXNodeData& old_node_data,
169 const ui::AXNodeData& new_node_data) {
170 auto platform_view =
171 GetFlutterPlatformNodeDelegateFromID(new_node_data.id).lock();
172 if (platform_view) {
173 platform_view->NodeDataChanged(old_node_data, new_node_data);
174 }
175}
176
177void AccessibilityBridge::OnNodeCreated(ui::AXTree* tree, ui::AXNode* node) {
178 BASE_DCHECK(node);
179 id_wrapper_map_[node->id()] = CreateFlutterPlatformNodeDelegate();
180 id_wrapper_map_[node->id()]->Init(
181 std::static_pointer_cast<FlutterPlatformNodeDelegate::OwnerBridge>(
182 shared_from_this()),
183 node);
184}
185
186void AccessibilityBridge::OnNodeDeleted(ui::AXTree* tree,
187 AccessibilityNodeId node_id) {
189 if (id_wrapper_map_.find(node_id) != id_wrapper_map_.end()) {
190 id_wrapper_map_.erase(node_id);
191 }
192}
193
194void AccessibilityBridge::OnAtomicUpdateFinished(
195 ui::AXTree* tree,
196 bool root_changed,
197 const std::vector<ui::AXTreeObserver::Change>& changes) {
198 // The Flutter semantics update does not include child->parent relationship
199 // We have to update the relative bound offset container id here in order
200 // to calculate the screen bound correctly.
201 for (const auto& change : changes) {
202 ui::AXNode* node = change.node;
203 const ui::AXNodeData& data = node->data();
204 AccessibilityNodeId offset_container_id = -1;
205 if (node->parent()) {
206 offset_container_id = node->parent()->id();
207 }
208 node->SetLocation(offset_container_id, data.relative_bounds.bounds,
209 data.relative_bounds.transform.get());
210 }
211}
212
213std::optional<ui::AXTreeUpdate>
214AccessibilityBridge::CreateRemoveReparentedNodesUpdate() {
215 std::unordered_map<int32_t, ui::AXNodeData> updates;
216
217 for (const auto& node_update : pending_semantics_node_updates_) {
218 for (int32_t child_id : node_update.second.children_in_traversal_order) {
219 // Skip nodes that don't exist or have a parent in the current tree.
220 ui::AXNode* child = tree_->GetFromId(child_id);
221 if (!child) {
222 continue;
223 }
224
225 // Flutter's root node should never be reparented.
226 assert(child->parent());
227
228 // Skip nodes whose parents are unchanged.
229 if (child->parent()->id() == node_update.second.id) {
230 continue;
231 }
232
233 // This pending update moves the current child node.
234 // That new child must have a corresponding pending update.
235 assert(pending_semantics_node_updates_.find(child_id) !=
236 pending_semantics_node_updates_.end());
237
238 // Create an update to remove the child from its previous parent.
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();
242 }
243
244 ui::AXNodeData* parent = &updates[parent_id];
245 auto iter = std::find(parent->child_ids.begin(), parent->child_ids.end(),
246 child_id);
247
248 assert(iter != parent->child_ids.end());
249 parent->child_ids.erase(iter);
250 }
251 }
252
253 if (updates.empty()) {
254 return std::nullopt;
255 }
256
257 ui::AXTreeUpdate update{
258 .tree_data = tree_->data(),
259 .nodes = std::vector<ui::AXNodeData>(),
260 };
261
262 for (std::pair<int32_t, ui::AXNodeData> data : updates) {
263 update.nodes.push_back(std::move(data.second));
264 }
265
266 return update;
267}
268
269// Private method.
270void AccessibilityBridge::GetSubTreeList(const SemanticsNode& target,
271 std::vector<SemanticsNode>& result) {
272 result.push_back(target);
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);
279 }
280 }
281}
282
283void AccessibilityBridge::ConvertFlutterUpdate(const SemanticsNode& node,
284 ui::AXTreeUpdate& tree_update) {
285 ui::AXNodeData node_data;
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);
298 node_data.relative_bounds.bounds.SetRect(node.rect.left, node.rect.top,
299 node.rect.right - node.rect.left,
300 node.rect.bottom - node.rect.top);
301 node_data.relative_bounds.transform = std::make_unique<gfx::Transform>(
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,
305 0, 0);
306 for (auto child : node.children_in_traversal_order) {
307 node_data.child_ids.push_back(child);
308 }
309 SetTreeData(node, tree_update);
310 tree_update.nodes.push_back(node_data);
311}
312
313void AccessibilityBridge::SetRoleFromFlutterUpdate(ui::AXNodeData& node_data,
314 const SemanticsNode& node) {
315 const FlutterSemanticsFlags* flags = node.flags;
316 FML_DCHECK(flags) << "SemanticsNode::flags must not be null";
317 if (flags->is_button) {
318 node_data.role = ax::mojom::Role::kButton;
319 return;
320 }
321 if (flags->is_text_field && !flags->is_read_only) {
323 return;
324 }
325 if (flags->is_header) {
326 node_data.role = ax::mojom::Role::kHeader;
327 return;
328 }
329 if (flags->is_image) {
330 node_data.role = ax::mojom::Role::kImage;
331 return;
332 }
333 if (flags->is_link) {
334 node_data.role = ax::mojom::Role::kLink;
335 return;
336 }
337
341 return;
342 }
345 return;
346 }
348 node_data.role = ax::mojom::Role::kSwitch;
349 return;
350 }
351 if (flags->is_slider) {
352 node_data.role = ax::mojom::Role::kSlider;
353 return;
354 }
355 // If the state cannot be derived from the flutter flags, we fallback to group
356 // or static text.
357 if (node.children_in_traversal_order.empty()) {
359 } else {
360 node_data.role = ax::mojom::Role::kGroup;
361 }
362}
363
364void AccessibilityBridge::SetStateFromFlutterUpdate(ui::AXNodeData& node_data,
365 const SemanticsNode& node) {
366 const FlutterSemanticsFlags* flags = node.flags;
367 FlutterSemanticsAction actions = node.actions;
372 }
373 if (flags->is_text_field && !flags->is_read_only) {
375 }
376 if (node_data.role == ax::mojom::Role::kStaticText &&
377 (actions & kHasScrollingAction) == 0 && node.value.empty() &&
378 node.label.empty() && node.hint.empty()) {
380 } else {
381 // kFlutterSemanticsFlagIsFocusable means a keyboard focusable, it is
382 // different from semantics focusable.
383 // TODO(chunhtai): figure out whether something is not semantics focusable.
385 }
386}
387
388void AccessibilityBridge::SetActionsFromFlutterUpdate(
389 ui::AXNodeData& node_data,
390 const SemanticsNode& node) {
391 FlutterSemanticsAction actions = node.actions;
394 }
397 }
400 }
403 }
406 }
409 }
412 }
413 // Every node has show on screen action.
415
418 }
419 if (actions & FlutterSemanticsAction::
422 }
423 if (actions & FlutterSemanticsAction::
426 }
429 }
430}
431
432void AccessibilityBridge::SetBooleanAttributesFromFlutterUpdate(
433 ui::AXNodeData& node_data,
434 const SemanticsNode& node) {
435 FlutterSemanticsAction actions = node.actions;
436 const FlutterSemanticsFlags* flags = node.flags;
438 actions & kHasScrollingAction);
439 node_data.AddBoolAttribute(
442 // TODO(chunhtai): figure out if there is a node that does not clip overflow.
444 !node.children_in_traversal_order.empty());
446 flags->is_selected);
448 flags->is_text_field && !flags->is_read_only);
449 // Mark nodes as line breaking so that screen readers don't
450 // merge all consecutive objects into one.
451 // TODO(schectman): When should a node have this attribute set?
452 // https://github.com/flutter/flutter/issues/118184
454 true);
455}
456
457void AccessibilityBridge::SetIntAttributesFromFlutterUpdate(
458 ui::AXNodeData& node_data,
459 const SemanticsNode& node) {
460 const FlutterSemanticsFlags* flags = node.flags;
462 node.text_direction);
463
464 int sel_start = node.text_selection_base;
465 int sel_end = node.text_selection_extent;
466 if (flags->is_text_field && !flags->is_read_only && !node.value.empty()) {
467 // By default the text field selection should be at the end.
468 sel_start = sel_start == -1 ? node.value.length() : sel_start;
469 sel_end = sel_end == -1 ? node.value.length() : sel_end;
470 }
473
474 if (node_data.role == ax::mojom::Role::kRadioButton ||
475 node_data.role == ax::mojom::Role::kCheckBox) {
476 node_data.AddIntAttribute(
478 static_cast<int32_t>(
482 ? ax::mojom::CheckedState::kTrue
483 : ax::mojom::CheckedState::kFalse));
484 } else if (node_data.role == ax::mojom::Role::kSwitch) {
485 node_data.AddIntAttribute(
487 static_cast<int32_t>(
490 : ax::mojom::CheckedState::kFalse));
491 }
492}
493
494void AccessibilityBridge::SetIntListAttributesFromFlutterUpdate(
495 ui::AXNodeData& node_data,
496 const SemanticsNode& node) {
497 FlutterSemanticsAction actions = node.actions;
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]);
503 }
505 custom_action_ids);
506 }
507}
508
509void AccessibilityBridge::SetStringListAttributesFromFlutterUpdate(
510 ui::AXNodeData& node_data,
511 const SemanticsNode& node) {
512 FlutterSemanticsAction actions = node.actions;
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);
520 }
521 node_data.AddStringListAttribute(
523 custom_action_description);
524 }
525}
526
527void AccessibilityBridge::SetIdentifierFromFlutterUpdate(
528 ui::AXNodeData& node_data,
529 const SemanticsNode& node) {
531 node.identifier);
532}
533
534void AccessibilityBridge::SetNameFromFlutterUpdate(ui::AXNodeData& node_data,
535 const SemanticsNode& node) {
536 node_data.SetName(node.label);
537}
538
539void AccessibilityBridge::SetValueFromFlutterUpdate(ui::AXNodeData& node_data,
540 const SemanticsNode& node) {
541 node_data.SetValue(node.value);
542}
543
544void AccessibilityBridge::SetTooltipFromFlutterUpdate(
545 ui::AXNodeData& node_data,
546 const SemanticsNode& node) {
547 node_data.SetTooltip(node.tooltip);
548}
549
550void AccessibilityBridge::SetTreeData(const SemanticsNode& node,
551 ui::AXTreeUpdate& tree_update) {
552 const FlutterSemanticsFlags* flags = node.flags;
553 // Set selection of the focused node if:
554 // 1. this text field has a valid selection
555 // 2. this text field doesn't have a valid selection but had selection stored
556 // in the tree.
557 if (flags->is_text_field &&
559 if (node.text_selection_base != -1) {
560 tree_update.tree_data.sel_anchor_object_id = node.id;
561 tree_update.tree_data.sel_anchor_offset = node.text_selection_base;
562 tree_update.tree_data.sel_focus_object_id = node.id;
563 tree_update.tree_data.sel_focus_offset = node.text_selection_extent;
564 tree_update.has_tree_data = true;
565 } else if (tree_update.tree_data.sel_anchor_object_id == node.id) {
567 tree_update.tree_data.sel_anchor_offset = -1;
569 tree_update.tree_data.sel_focus_offset = -1;
570 tree_update.has_tree_data = true;
571 }
572 }
573
575 tree_update.tree_data.focus_id != node.id) {
576 tree_update.tree_data.focus_id = node.id;
577 tree_update.has_tree_data = true;
579 tree_update.tree_data.focus_id == node.id) {
581 tree_update.has_tree_data = true;
582 }
583}
584
585AccessibilityBridge::SemanticsNode
586AccessibilityBridge::FromFlutterSemanticsNode(
587 const FlutterSemanticsNode2& flutter_node) {
588 SemanticsNode result;
589 result.id = flutter_node.id;
590 FML_DCHECK(flutter_node.flags2)
591 << "FlutterSemanticsNode2::flags2 must not be null";
592
593 result.flags = flutter_node.flags2;
594 result.actions = flutter_node.actions;
595 result.heading_level = flutter_node.heading_level;
596 result.text_selection_base = flutter_node.text_selection_base;
597 result.text_selection_extent = flutter_node.text_selection_extent;
598 result.scroll_child_count = flutter_node.scroll_child_count;
599 result.scroll_index = flutter_node.scroll_index;
600 result.scroll_position = flutter_node.scroll_position;
601 result.scroll_extent_max = flutter_node.scroll_extent_max;
602 result.scroll_extent_min = flutter_node.scroll_extent_min;
603 if (flutter_node.label) {
604 result.label = std::string(flutter_node.label);
605 }
606 if (flutter_node.hint) {
607 result.hint = std::string(flutter_node.hint);
608 }
609 if (flutter_node.value) {
610 result.value = std::string(flutter_node.value);
611 }
612 if (flutter_node.increased_value) {
613 result.increased_value = std::string(flutter_node.increased_value);
614 }
615 if (flutter_node.decreased_value) {
616 result.decreased_value = std::string(flutter_node.decreased_value);
617 }
618 if (flutter_node.tooltip) {
619 result.tooltip = std::string(flutter_node.tooltip);
620 }
621 result.text_direction = flutter_node.text_direction;
622 result.rect = flutter_node.rect;
623 result.transform = flutter_node.transform;
624 if (flutter_node.child_count > 0) {
625 result.children_in_traversal_order = std::vector<int32_t>(
626 flutter_node.children_in_traversal_order,
627 flutter_node.children_in_traversal_order + flutter_node.child_count);
628 }
629 if (flutter_node.custom_accessibility_actions_count > 0) {
630 result.custom_accessibility_actions = std::vector<int32_t>(
631 flutter_node.custom_accessibility_actions,
632 flutter_node.custom_accessibility_actions +
634 }
635 if (flutter_node.identifier) {
636 result.identifier = std::string(flutter_node.identifier);
637 }
638 return result;
639}
640
641AccessibilityBridge::SemanticsCustomAction
642AccessibilityBridge::FromFlutterSemanticsCustomAction(
643 const FlutterSemanticsCustomAction2& flutter_custom_action) {
644 SemanticsCustomAction result;
645 result.id = flutter_custom_action.id;
646 result.override_action = flutter_custom_action.override_action;
647 if (flutter_custom_action.label) {
648 result.label = std::string(flutter_custom_action.label);
649 }
650 if (flutter_custom_action.hint) {
651 result.hint = std::string(flutter_custom_action.hint);
652 }
653 return result;
654}
655
656void AccessibilityBridge::SetLastFocusedId(AccessibilityNodeId node_id) {
657 if (last_focused_id_ != node_id) {
658 auto last_focused_child =
659 GetFlutterPlatformNodeDelegateFromID(last_focused_id_);
660 if (!last_focused_child.expired()) {
662 last_focused_id_,
665 {});
666 }
667 last_focused_id_ = node_id;
668 }
669}
670
671AccessibilityNodeId AccessibilityBridge::GetLastFocusedId() {
672 return last_focused_id_;
673}
674
675gfx::NativeViewAccessible AccessibilityBridge::GetNativeAccessibleFromId(
677 auto platform_node_delegate = GetFlutterPlatformNodeDelegateFromID(id).lock();
678 if (!platform_node_delegate) {
679 return nullptr;
680 }
681 return platform_node_delegate->GetNativeViewAccessible();
682}
683
684gfx::RectF AccessibilityBridge::RelativeToGlobalBounds(const ui::AXNode* node,
685 bool& offscreen,
686 bool clip_bounds) {
687 return tree_->RelativeToTreeBounds(node, gfx::RectF(), &offscreen,
688 clip_bounds);
689}
690
692 ui::AXTreeID tree_id,
693 ui::AXNode::AXID node_id) const {
694 return GetNodeFromTree(node_id);
695}
696
698 ui::AXNode::AXID node_id) const {
699 return tree_->GetFromId(node_id);
700}
701
703 return tree_->GetAXTreeID();
704}
705
709
711 return tree_->root();
712}
713
717
719 return tree_.get();
720}
721
723 const ui::AXNode::AXID node_id) const {
724 auto platform_delegate_weak = GetFlutterPlatformNodeDelegateFromID(node_id);
725 auto platform_delegate = platform_delegate_weak.lock();
726 if (!platform_delegate) {
727 return nullptr;
728 }
729 return platform_delegate->GetPlatformNode();
730}
731
736
742
743} // namespace flutter
std::unique_ptr< flutter::PlatformViewIOS > platform_view
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
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
virtual void DispatchAccessibilityAction(AccessibilityNodeId target, FlutterSemanticsAction action, fml::MallocMapping data)=0
Dispatch accessibility action back to the Flutter framework. These actions are generated in the nativ...
void SetRect(float x, float y, float width, float height)
Definition rect_f.h:79
void SetTree(AXTree *new_tree)
AXID id() const
Definition ax_node.h:110
int32_t AXID
Definition ax_node.h:36
static constexpr AXID kInvalidAXID
Definition ax_node.h:41
void SetLocation(int32_t offset_container_id, const gfx::RectF &location, gfx::Transform *transform)
Definition ax_node.cc:377
AXNode * parent() const
Definition ax_node.h:111
const AXNodeData & data() const
Definition ax_node.h:112
static AXTreeID CreateNewAXTreeID()
Definition ax_tree_id.cc:47
void AddTreeManager(AXTreeID tree_id, AXTreeManager *manager)
static AXTreeManagerMap & GetInstance()
FlutterCheckState
Definition embedder.h:280
@ kFlutterCheckStateNone
The semantics node does not have check state.
Definition embedder.h:282
@ kFlutterCheckStateTrue
The semantics node is checked.
Definition embedder.h:284
@ kFlutterCheckStateMixed
The semantics node represents a checkbox in mixed state.
Definition embedder.h:288
FlutterSemanticsAction
Definition embedder.h:115
@ kFlutterSemanticsActionDidLoseAccessibilityFocus
Indicate that the node has lost accessibility focus.
Definition embedder.h:156
@ kFlutterSemanticsActionDecrease
Decrease the value represented by the semantics node.
Definition embedder.h:138
@ kFlutterSemanticsActionScrollDown
Definition embedder.h:134
@ kFlutterSemanticsActionScrollRight
Definition embedder.h:128
@ kFlutterSemanticsActionSetSelection
Set the text selection to the given range.
Definition embedder.h:146
@ kFlutterSemanticsActionScrollUp
Definition embedder.h:131
@ kFlutterSemanticsActionCustomAction
Indicate that the user has invoked a custom accessibility action.
Definition embedder.h:158
@ kFlutterSemanticsActionIncrease
Increase the value represented by the semantics node.
Definition embedder.h:136
@ kFlutterSemanticsActionScrollLeft
Definition embedder.h:124
@ kFlutterSemanticsActionDidGainAccessibilityFocus
Indicate that the node has gained accessibility focus.
Definition embedder.h:154
@ kFlutterSemanticsActionTap
Definition embedder.h:118
@ kFlutterTristateTrue
The property is applicable and its state is "true" or "on".
Definition embedder.h:275
@ kFlutterTristateFalse
The property is applicable and its state is "false" or "off".
Definition embedder.h:277
@ kFlutterTristateNone
The property is not applicable to this semantics node.
Definition embedder.h:273
static gboolean is_checked(FlutterSemanticsFlags flags)
const uint8_t uint32_t uint32_t GError ** error
uint32_t * target
#define FML_LOG(severity)
Definition logging.h:101
#define FML_DCHECK(condition)
Definition logging.h:122
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot data
Definition switch_defs.h:36
constexpr int kHasScrollingAction
ui::AXNode::AXID AccessibilityNodeId
UnimplementedNativeViewAccessible * NativeViewAccessible
Definition ref_ptr.h:261
const AXTreeID & AXTreeIDUnknown()
const char * hint
The hint description of this custom semantics action.
Definition embedder.h:1774
const char * label
The user-readable name of this custom semantics action.
Definition embedder.h:1772
FlutterSemanticsAction override_action
Definition embedder.h:1770
int32_t id
The unique custom action or action override ID.
Definition embedder.h:1767
bool is_link
Whether the semantics node represents a link.
Definition embedder.h:350
bool is_image
Whether the semantics node represents an image.
Definition embedder.h:328
bool is_slider
Whether the semantics node represents a slider.
Definition embedder.h:352
bool is_header
Whether a semantic node is a header that divides content into sections.
Definition embedder.h:317
FlutterTristate is_selected
Whether a semantics node is selected.
Definition embedder.h:297
bool is_in_mutually_exclusive_group
Whether a semantic node is in a mutually exclusive group.
Definition embedder.h:315
FlutterTristate is_toggled
Definition embedder.h:302
FlutterTristate is_focused
Whether the semantic node currently holds the user's focus.
Definition embedder.h:309
FlutterTristate is_expanded
Whether a semantic node that is currently expanded.
Definition embedder.h:304
bool is_text_field
Whether the semantic node represents a text field.
Definition embedder.h:313
FlutterCheckState is_checked
Whether a semantics node is checked.
Definition embedder.h:295
bool is_button
Whether the semantic node represents a button.
Definition embedder.h:311
const char * identifier
Definition embedder.h:1714
const char * increased_value
Definition embedder.h:1650
const char * tooltip
A textual tooltip attached to the node.
Definition embedder.h:1677
int32_t scroll_index
The index of the first visible semantic child of a scroll node.
Definition embedder.h:1629
size_t custom_accessibility_actions_count
The number of custom accessibility action associated with this node.
Definition embedder.h:1669
const int32_t * children_in_traversal_order
Array of child node IDs in traversal order. Has length child_count.
Definition embedder.h:1665
double scroll_extent_min
The minimum in-range value for scrollPosition if the node is scrollable.
Definition embedder.h:1636
int32_t text_selection_extent
The position at which the text selection terminates.
Definition embedder.h:1625
FlutterTextDirection text_direction
Definition embedder.h:1656
FlutterSemanticsAction actions
The set of semantics actions applicable to this node.
Definition embedder.h:1621
const int32_t * custom_accessibility_actions
Definition embedder.h:1672
int32_t id
The unique identifier for this node.
Definition embedder.h:1613
FlutterRect rect
The bounding box for this node in its coordinate system.
Definition embedder.h:1658
FlutterTransformation transform
Definition embedder.h:1661
size_t child_count
The number of children this node has.
Definition embedder.h:1663
double scroll_extent_max
The maximum in-range value for scrollPosition if the node is scrollable.
Definition embedder.h:1634
const char * decreased_value
Definition embedder.h:1653
const char * label
A textual description of the node.
Definition embedder.h:1643
int32_t text_selection_base
The position at which the text selection originates.
Definition embedder.h:1623
const char * hint
A brief description of the result of performing an action on the node.
Definition embedder.h:1645
FlutterSemanticsFlags * flags2
Definition embedder.h:1705
const char * value
A textual description of the current value of the node.
Definition embedder.h:1647
int32_t scroll_child_count
The total number of scrollable children that contribute to semantics.
Definition embedder.h:1627
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)
ax::mojom::Role role
void AddAction(ax::mojom::Action action)
std::unique_ptr< gfx::Transform > transform
AXNode::AXID sel_anchor_object_id
AXNode::AXID sel_focus_object_id
AXNode::AXID focus_id
int32_t sel_focus_offset
int32_t sel_anchor_offset
std::vector< AXNodeData > nodes
#define BASE_DCHECK(condition)
Definition logging.h:63