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"
17 FlutterSemanticsAction::kFlutterSemanticsActionScrollLeft |
18 FlutterSemanticsAction::kFlutterSemanticsActionScrollRight |
19 FlutterSemanticsAction::kFlutterSemanticsActionScrollUp |
20 FlutterSemanticsAction::kFlutterSemanticsActionScrollDown;
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();
28 data.tree_id = ui::AXTreeID::CreateNewAXTreeID();
29 tree_->UpdateData(data);
30 ui::AXTreeManagerMap::GetInstance().AddTreeManager(tree_->GetAXTreeID(),
35 event_generator_.ReleaseTree();
36 tree_->RemoveObserver(
static_cast<ui::AXTreeObserver*
>(
this));
40 const FlutterSemanticsNode2& node) {
41 pending_semantics_node_updates_[node.id] = FromFlutterSemanticsNode(node);
45 const FlutterSemanticsCustomAction2&
action) {
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;
73 ui::AXTreeUpdate update{.tree_data = tree_->data()};
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);
102 if (!results.empty() &&
GetRootAsAXNode()->
id() == ui::AXNode::kInvalidAXID) {
103 FML_DCHECK(!results.back().empty());
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()) {
127 event_generator_.ClearEvents();
130 std::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();
145 const std::vector<ui::AXEventGenerator::TargetedEvent>
147 std::vector<ui::AXEventGenerator::TargetedEvent> result(
148 event_generator_.begin(), event_generator_.end());
152 void AccessibilityBridge::OnNodeWillBeDeleted(ui::AXTree* tree,
155 void AccessibilityBridge::OnSubtreeWillBeDeleted(ui::AXTree* tree,
158 void AccessibilityBridge::OnNodeReparented(ui::AXTree* tree, ui::AXNode* node) {
161 void AccessibilityBridge::OnRoleChanged(ui::AXTree* tree,
163 ax::mojom::Role old_role,
164 ax::mojom::Role new_role) {}
166 void AccessibilityBridge::OnNodeDataChanged(
168 const ui::AXNodeData& old_node_data,
169 const ui::AXNodeData& new_node_data) {
173 platform_view->NodeDataChanged(old_node_data, new_node_data);
177 void AccessibilityBridge::OnNodeCreated(ui::AXTree* tree, ui::AXNode* node) {
180 id_wrapper_map_[node->id()]->Init(
181 std::static_pointer_cast<FlutterPlatformNodeDelegate::OwnerBridge>(
186 void AccessibilityBridge::OnNodeDeleted(ui::AXTree* tree,
188 BASE_DCHECK(node_id != ui::AXNode::kInvalidAXID);
189 if (id_wrapper_map_.find(node_id) != id_wrapper_map_.end()) {
190 id_wrapper_map_.erase(node_id);
194 void AccessibilityBridge::OnAtomicUpdateFinished(
197 const std::vector<ui::AXTreeObserver::Change>& changes) {
201 for (
const auto& change : changes) {
202 ui::AXNode* node = change.node;
203 const ui::AXNodeData& data = node->data();
205 if (node->parent()) {
206 offset_container_id = node->parent()->id();
208 node->SetLocation(offset_container_id, data.relative_bounds.bounds,
209 data.relative_bounds.transform.get());
213 std::optional<ui::AXTreeUpdate>
214 AccessibilityBridge::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);
226 assert(child->parent());
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();
244 ui::AXNodeData* parent = &updates[parent_id];
245 auto iter = std::find(parent->child_ids.begin(), parent->child_ids.end(),
248 assert(iter != parent->child_ids.end());
249 parent->child_ids.erase(iter);
253 if (updates.empty()) {
257 ui::AXTreeUpdate update{
258 .tree_data = tree_->data(),
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));
270 void 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);
283 void 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 SetNameFromFlutterUpdate(node_data, node);
295 SetValueFromFlutterUpdate(node_data, node);
296 SetTooltipFromFlutterUpdate(node_data, node);
297 node_data.relative_bounds.bounds.SetRect(node.rect.left, node.rect.top,
298 node.rect.right - node.rect.left,
299 node.rect.bottom - node.rect.top);
300 node_data.relative_bounds.transform = std::make_unique<gfx::Transform>(
301 node.transform.scaleX, node.transform.skewX, node.transform.transX, 0,
302 node.transform.skewY, node.transform.scaleY, node.transform.transY, 0,
303 node.transform.pers0, node.transform.pers1, node.transform.pers2, 0, 0, 0,
305 for (
auto child : node.children_in_traversal_order) {
306 node_data.child_ids.push_back(child);
308 SetTreeData(node, tree_update);
309 tree_update.nodes.push_back(node_data);
312 void AccessibilityBridge::SetRoleFromFlutterUpdate(ui::AXNodeData& node_data,
313 const SemanticsNode& node) {
314 const FlutterSemanticsFlags* flags = node.flags;
315 FML_DCHECK(flags) <<
"SemanticsNode::flags must not be null";
316 if (flags->is_button) {
317 node_data.role = ax::mojom::Role::kButton;
320 if (flags->is_text_field && !flags->is_read_only) {
321 node_data.role = ax::mojom::Role::kTextField;
324 if (flags->is_header) {
325 node_data.role = ax::mojom::Role::kHeader;
328 if (flags->is_image) {
329 node_data.role = ax::mojom::Role::kImage;
332 if (flags->is_link) {
333 node_data.role = ax::mojom::Role::kLink;
337 if (flags->is_in_mutually_exclusive_group &&
338 flags->is_checked != FlutterCheckState::kFlutterCheckStateNone) {
339 node_data.role = ax::mojom::Role::kRadioButton;
342 if (flags->is_checked != FlutterCheckState::kFlutterCheckStateNone) {
343 node_data.role = ax::mojom::Role::kCheckBox;
346 if (flags->is_toggled != FlutterTristate::kFlutterTristateNone) {
347 node_data.role = ax::mojom::Role::kSwitch;
350 if (flags->is_slider) {
351 node_data.role = ax::mojom::Role::kSlider;
356 if (node.children_in_traversal_order.empty()) {
357 node_data.role = ax::mojom::Role::kStaticText;
359 node_data.role = ax::mojom::Role::kGroup;
363 void AccessibilityBridge::SetStateFromFlutterUpdate(ui::AXNodeData& node_data,
364 const SemanticsNode& node) {
365 const FlutterSemanticsFlags* flags = node.flags;
366 FlutterSemanticsAction actions = node.actions;
367 if (flags->is_expanded == FlutterTristate::kFlutterTristateTrue) {
368 node_data.AddState(ax::mojom::State::kExpanded);
369 }
else if (flags->is_expanded == FlutterTristate::kFlutterTristateFalse) {
370 node_data.AddState(ax::mojom::State::kCollapsed);
372 if (flags->is_text_field && !flags->is_read_only) {
373 node_data.AddState(ax::mojom::State::kEditable);
375 if (node_data.role == ax::mojom::Role::kStaticText &&
377 node.label.empty() && node.hint.empty()) {
378 node_data.AddState(ax::mojom::State::kIgnored);
383 node_data.AddState(ax::mojom::State::kFocusable);
387 void AccessibilityBridge::SetActionsFromFlutterUpdate(
388 ui::AXNodeData& node_data,
389 const SemanticsNode& node) {
390 FlutterSemanticsAction actions = node.actions;
391 if (actions & FlutterSemanticsAction::kFlutterSemanticsActionTap) {
392 node_data.AddAction(ax::mojom::Action::kDoDefault);
394 if (actions & FlutterSemanticsAction::kFlutterSemanticsActionScrollLeft) {
395 node_data.AddAction(ax::mojom::Action::kScrollLeft);
397 if (actions & FlutterSemanticsAction::kFlutterSemanticsActionScrollRight) {
398 node_data.AddAction(ax::mojom::Action::kScrollRight);
400 if (actions & FlutterSemanticsAction::kFlutterSemanticsActionScrollUp) {
401 node_data.AddAction(ax::mojom::Action::kScrollUp);
403 if (actions & FlutterSemanticsAction::kFlutterSemanticsActionScrollDown) {
404 node_data.AddAction(ax::mojom::Action::kScrollDown);
406 if (actions & FlutterSemanticsAction::kFlutterSemanticsActionIncrease) {
407 node_data.AddAction(ax::mojom::Action::kIncrement);
409 if (actions & FlutterSemanticsAction::kFlutterSemanticsActionDecrease) {
410 node_data.AddAction(ax::mojom::Action::kDecrement);
413 node_data.AddAction(ax::mojom::Action::kScrollToMakeVisible);
415 if (actions & FlutterSemanticsAction::kFlutterSemanticsActionSetSelection) {
416 node_data.AddAction(ax::mojom::Action::kSetSelection);
418 if (actions & FlutterSemanticsAction::
419 kFlutterSemanticsActionDidGainAccessibilityFocus) {
420 node_data.AddAction(ax::mojom::Action::kSetAccessibilityFocus);
422 if (actions & FlutterSemanticsAction::
423 kFlutterSemanticsActionDidLoseAccessibilityFocus) {
424 node_data.AddAction(ax::mojom::Action::kClearAccessibilityFocus);
426 if (actions & FlutterSemanticsAction::kFlutterSemanticsActionCustomAction) {
427 node_data.AddAction(ax::mojom::Action::kCustomAction);
431 void AccessibilityBridge::SetBooleanAttributesFromFlutterUpdate(
432 ui::AXNodeData& node_data,
433 const SemanticsNode& node) {
434 FlutterSemanticsAction actions = node.actions;
435 const FlutterSemanticsFlags* flags = node.flags;
436 node_data.AddBoolAttribute(ax::mojom::BoolAttribute::kScrollable,
438 node_data.AddBoolAttribute(
439 ax::mojom::BoolAttribute::kClickable,
440 actions & FlutterSemanticsAction::kFlutterSemanticsActionTap);
442 node_data.AddBoolAttribute(ax::mojom::BoolAttribute::kClipsChildren,
443 !node.children_in_traversal_order.empty());
444 node_data.AddBoolAttribute(ax::mojom::BoolAttribute::kSelected,
446 node_data.AddBoolAttribute(ax::mojom::BoolAttribute::kEditableRoot,
447 flags->is_text_field && !flags->is_read_only);
452 node_data.AddBoolAttribute(ax::mojom::BoolAttribute::kIsLineBreakingObject,
456 void AccessibilityBridge::SetIntAttributesFromFlutterUpdate(
457 ui::AXNodeData& node_data,
458 const SemanticsNode& node) {
459 const FlutterSemanticsFlags* flags = node.flags;
460 node_data.AddIntAttribute(ax::mojom::IntAttribute::kTextDirection,
461 node.text_direction);
463 int sel_start = node.text_selection_base;
464 int sel_end = node.text_selection_extent;
465 if (flags->is_text_field && !flags->is_read_only && !node.value.empty()) {
467 sel_start = sel_start == -1 ? node.value.length() : sel_start;
468 sel_end = sel_end == -1 ? node.value.length() : sel_end;
470 node_data.AddIntAttribute(ax::mojom::IntAttribute::kTextSelStart, sel_start);
471 node_data.AddIntAttribute(ax::mojom::IntAttribute::kTextSelEnd, sel_end);
473 if (node_data.role == ax::mojom::Role::kRadioButton ||
474 node_data.role == ax::mojom::Role::kCheckBox) {
475 node_data.AddIntAttribute(
476 ax::mojom::IntAttribute::kCheckedState,
477 static_cast<int32_t
>(
478 (flags->is_checked == FlutterCheckState::kFlutterCheckStateMixed)
479 ? ax::mojom::CheckedState::kMixed
480 : (flags->is_checked == FlutterCheckState::kFlutterCheckStateTrue)
481 ? ax::mojom::CheckedState::kTrue
482 : ax::mojom::CheckedState::kFalse));
483 }
else if (node_data.role == ax::mojom::Role::kSwitch) {
484 node_data.AddIntAttribute(
485 ax::mojom::IntAttribute::kCheckedState,
486 static_cast<int32_t
>(
487 (flags->is_toggled == FlutterTristate::kFlutterTristateTrue)
488 ? ax::mojom::CheckedState::kTrue
489 : ax::mojom::CheckedState::kFalse));
493 void AccessibilityBridge::SetIntListAttributesFromFlutterUpdate(
494 ui::AXNodeData& node_data,
495 const SemanticsNode& node) {
496 FlutterSemanticsAction actions = node.actions;
497 if (actions & FlutterSemanticsAction::kFlutterSemanticsActionCustomAction) {
498 std::vector<int32_t> custom_action_ids;
499 custom_action_ids.reserve(node.custom_accessibility_actions.size());
500 for (
size_t i = 0; i < node.custom_accessibility_actions.size(); i++) {
501 custom_action_ids.push_back(node.custom_accessibility_actions[i]);
503 node_data.AddIntListAttribute(ax::mojom::IntListAttribute::kCustomActionIds,
508 void AccessibilityBridge::SetStringListAttributesFromFlutterUpdate(
509 ui::AXNodeData& node_data,
510 const SemanticsNode& node) {
511 FlutterSemanticsAction actions = node.actions;
512 if (actions & FlutterSemanticsAction::kFlutterSemanticsActionCustomAction) {
513 std::vector<std::string> custom_action_description;
514 for (
size_t i = 0; i < node.custom_accessibility_actions.size(); i++) {
515 auto iter = pending_semantics_custom_action_updates_.find(
516 node.custom_accessibility_actions[i]);
517 BASE_DCHECK(iter != pending_semantics_custom_action_updates_.end());
518 custom_action_description.push_back(iter->second.label);
520 node_data.AddStringListAttribute(
521 ax::mojom::StringListAttribute::kCustomActionDescriptions,
522 custom_action_description);
526 void AccessibilityBridge::SetNameFromFlutterUpdate(ui::AXNodeData& node_data,
527 const SemanticsNode& node) {
528 node_data.SetName(node.label);
531 void AccessibilityBridge::SetValueFromFlutterUpdate(ui::AXNodeData& node_data,
532 const SemanticsNode& node) {
533 node_data.SetValue(node.value);
536 void AccessibilityBridge::SetTooltipFromFlutterUpdate(
537 ui::AXNodeData& node_data,
538 const SemanticsNode& node) {
539 node_data.SetTooltip(node.tooltip);
542 void AccessibilityBridge::SetTreeData(
const SemanticsNode& node,
543 ui::AXTreeUpdate& tree_update) {
544 const FlutterSemanticsFlags* flags = node.flags;
549 if (flags->is_text_field &&
550 flags->is_focused == FlutterTristate::kFlutterTristateTrue) {
551 if (node.text_selection_base != -1) {
552 tree_update.tree_data.sel_anchor_object_id = node.id;
553 tree_update.tree_data.sel_anchor_offset = node.text_selection_base;
554 tree_update.tree_data.sel_focus_object_id = node.id;
555 tree_update.tree_data.sel_focus_offset = node.text_selection_extent;
556 tree_update.has_tree_data =
true;
557 }
else if (tree_update.tree_data.sel_anchor_object_id == node.id) {
558 tree_update.tree_data.sel_anchor_object_id = ui::AXNode::kInvalidAXID;
559 tree_update.tree_data.sel_anchor_offset = -1;
560 tree_update.tree_data.sel_focus_object_id = ui::AXNode::kInvalidAXID;
561 tree_update.tree_data.sel_focus_offset = -1;
562 tree_update.has_tree_data =
true;
566 if (flags->is_focused == FlutterTristate::kFlutterTristateTrue &&
567 tree_update.tree_data.focus_id != node.id) {
568 tree_update.tree_data.focus_id = node.id;
569 tree_update.has_tree_data =
true;
570 }
else if (flags->is_focused != FlutterTristate::kFlutterTristateTrue &&
571 tree_update.tree_data.focus_id == node.id) {
572 tree_update.tree_data.focus_id = ui::AXNode::kInvalidAXID;
573 tree_update.has_tree_data =
true;
577 AccessibilityBridge::SemanticsNode
578 AccessibilityBridge::FromFlutterSemanticsNode(
579 const FlutterSemanticsNode2& flutter_node) {
580 SemanticsNode result;
581 result.id = flutter_node.id;
582 FML_DCHECK(flutter_node.flags2)
583 <<
"FlutterSemanticsNode2::flags2 must not be null";
585 result.flags = flutter_node.flags2;
586 result.actions = flutter_node.actions;
587 result.heading_level = flutter_node.heading_level;
588 result.text_selection_base = flutter_node.text_selection_base;
589 result.text_selection_extent = flutter_node.text_selection_extent;
590 result.scroll_child_count = flutter_node.scroll_child_count;
591 result.scroll_index = flutter_node.scroll_index;
592 result.scroll_position = flutter_node.scroll_position;
593 result.scroll_extent_max = flutter_node.scroll_extent_max;
594 result.scroll_extent_min = flutter_node.scroll_extent_min;
595 if (flutter_node.label) {
596 result.label = std::string(flutter_node.label);
598 if (flutter_node.hint) {
599 result.hint = std::string(flutter_node.hint);
601 if (flutter_node.value) {
602 result.value = std::string(flutter_node.value);
604 if (flutter_node.increased_value) {
605 result.increased_value = std::string(flutter_node.increased_value);
607 if (flutter_node.decreased_value) {
608 result.decreased_value = std::string(flutter_node.decreased_value);
610 if (flutter_node.tooltip) {
611 result.tooltip = std::string(flutter_node.tooltip);
613 result.text_direction = flutter_node.text_direction;
614 result.rect = flutter_node.rect;
615 result.transform = flutter_node.transform;
616 if (flutter_node.child_count > 0) {
617 result.children_in_traversal_order = std::vector<int32_t>(
618 flutter_node.children_in_traversal_order,
619 flutter_node.children_in_traversal_order + flutter_node.child_count);
621 if (flutter_node.custom_accessibility_actions_count > 0) {
622 result.custom_accessibility_actions = std::vector<int32_t>(
623 flutter_node.custom_accessibility_actions,
624 flutter_node.custom_accessibility_actions +
625 flutter_node.custom_accessibility_actions_count);
630 AccessibilityBridge::SemanticsCustomAction
631 AccessibilityBridge::FromFlutterSemanticsCustomAction(
632 const FlutterSemanticsCustomAction2& flutter_custom_action) {
633 SemanticsCustomAction result;
634 result.id = flutter_custom_action.id;
635 result.override_action = flutter_custom_action.override_action;
636 if (flutter_custom_action.label) {
637 result.label = std::string(flutter_custom_action.label);
639 if (flutter_custom_action.hint) {
640 result.hint = std::string(flutter_custom_action.hint);
646 if (last_focused_id_ != node_id) {
647 auto last_focused_child =
649 if (!last_focused_child.expired()) {
652 FlutterSemanticsAction::
653 kFlutterSemanticsActionDidLoseAccessibilityFocus,
656 last_focused_id_ = node_id;
661 return last_focused_id_;
664 gfx::NativeViewAccessible AccessibilityBridge::GetNativeAccessibleFromId(
667 if (!platform_node_delegate) {
670 return platform_node_delegate->GetNativeViewAccessible();
673 gfx::RectF AccessibilityBridge::RelativeToGlobalBounds(
const ui::AXNode* node,
676 return tree_->RelativeToTreeBounds(node, gfx::RectF(), &offscreen,
681 ui::AXTreeID tree_id,
682 ui::AXNode::AXID node_id)
const {
687 ui::AXNode::AXID node_id)
const {
688 return tree_->GetFromId(node_id);
692 return tree_->GetAXTreeID();
696 return ui::AXTreeIDUnknown();
700 return tree_->root();
712 const ui::AXNode::AXID node_id)
const {
714 auto platform_delegate = platform_delegate_weak.lock();
715 if (!platform_delegate) {
718 return platform_delegate->GetPlatformNode();
722 const ui::AXNode& node)
const {
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....
virtual std::shared_ptr< FlutterPlatformNodeDelegate > CreateFlutterPlatformNodeDelegate()=0
Creates a platform specific FlutterPlatformNodeDelegate. Ownership passes to the caller....
void AddFlutterSemanticsNodeUpdate(const FlutterSemanticsNode2 &node)
Adds a semantics node update to the pending semantics update. Calling this method alone will NOT upda...
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
constexpr int kHasScrollingAction
ui::AXNode::AXID AccessibilityNodeId