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 for (
size_t i = 0; i < node.custom_accessibility_actions.size(); i++) {
500 custom_action_ids.push_back(node.custom_accessibility_actions[i]);
502 node_data.AddIntListAttribute(ax::mojom::IntListAttribute::kCustomActionIds,
507 void AccessibilityBridge::SetStringListAttributesFromFlutterUpdate(
508 ui::AXNodeData& node_data,
509 const SemanticsNode& node) {
510 FlutterSemanticsAction actions = node.actions;
511 if (actions & FlutterSemanticsAction::kFlutterSemanticsActionCustomAction) {
512 std::vector<std::string> custom_action_description;
513 for (
size_t i = 0; i < node.custom_accessibility_actions.size(); i++) {
514 auto iter = pending_semantics_custom_action_updates_.find(
515 node.custom_accessibility_actions[i]);
516 BASE_DCHECK(iter != pending_semantics_custom_action_updates_.end());
517 custom_action_description.push_back(iter->second.label);
519 node_data.AddStringListAttribute(
520 ax::mojom::StringListAttribute::kCustomActionDescriptions,
521 custom_action_description);
525 void AccessibilityBridge::SetNameFromFlutterUpdate(ui::AXNodeData& node_data,
526 const SemanticsNode& node) {
527 node_data.SetName(node.label);
530 void AccessibilityBridge::SetValueFromFlutterUpdate(ui::AXNodeData& node_data,
531 const SemanticsNode& node) {
532 node_data.SetValue(node.value);
535 void AccessibilityBridge::SetTooltipFromFlutterUpdate(
536 ui::AXNodeData& node_data,
537 const SemanticsNode& node) {
538 node_data.SetTooltip(node.tooltip);
541 void AccessibilityBridge::SetTreeData(
const SemanticsNode& node,
542 ui::AXTreeUpdate& tree_update) {
543 const FlutterSemanticsFlags* flags = node.flags;
548 if (flags->is_text_field &&
549 flags->is_focused == FlutterTristate::kFlutterTristateTrue) {
550 if (node.text_selection_base != -1) {
551 tree_update.tree_data.sel_anchor_object_id = node.id;
552 tree_update.tree_data.sel_anchor_offset = node.text_selection_base;
553 tree_update.tree_data.sel_focus_object_id = node.id;
554 tree_update.tree_data.sel_focus_offset = node.text_selection_extent;
555 tree_update.has_tree_data =
true;
556 }
else if (tree_update.tree_data.sel_anchor_object_id == node.id) {
557 tree_update.tree_data.sel_anchor_object_id = ui::AXNode::kInvalidAXID;
558 tree_update.tree_data.sel_anchor_offset = -1;
559 tree_update.tree_data.sel_focus_object_id = ui::AXNode::kInvalidAXID;
560 tree_update.tree_data.sel_focus_offset = -1;
561 tree_update.has_tree_data =
true;
565 if (flags->is_focused == FlutterTristate::kFlutterTristateTrue &&
566 tree_update.tree_data.focus_id != node.id) {
567 tree_update.tree_data.focus_id = node.id;
568 tree_update.has_tree_data =
true;
569 }
else if (flags->is_focused != FlutterTristate::kFlutterTristateTrue &&
570 tree_update.tree_data.focus_id == node.id) {
571 tree_update.tree_data.focus_id = ui::AXNode::kInvalidAXID;
572 tree_update.has_tree_data =
true;
576 AccessibilityBridge::SemanticsNode
577 AccessibilityBridge::FromFlutterSemanticsNode(
578 const FlutterSemanticsNode2& flutter_node) {
579 SemanticsNode result;
580 result.id = flutter_node.id;
581 FML_DCHECK(flutter_node.flags2)
582 <<
"FlutterSemanticsNode2::flags2 must not be null";
584 result.flags = flutter_node.flags2;
585 result.actions = flutter_node.actions;
586 result.text_selection_base = flutter_node.text_selection_base;
587 result.text_selection_extent = flutter_node.text_selection_extent;
588 result.scroll_child_count = flutter_node.scroll_child_count;
589 result.scroll_index = flutter_node.scroll_index;
590 result.scroll_position = flutter_node.scroll_position;
591 result.scroll_extent_max = flutter_node.scroll_extent_max;
592 result.scroll_extent_min = flutter_node.scroll_extent_min;
593 if (flutter_node.label) {
594 result.label = std::string(flutter_node.label);
596 if (flutter_node.hint) {
597 result.hint = std::string(flutter_node.hint);
599 if (flutter_node.value) {
600 result.value = std::string(flutter_node.value);
602 if (flutter_node.increased_value) {
603 result.increased_value = std::string(flutter_node.increased_value);
605 if (flutter_node.decreased_value) {
606 result.decreased_value = std::string(flutter_node.decreased_value);
608 if (flutter_node.tooltip) {
609 result.tooltip = std::string(flutter_node.tooltip);
611 result.text_direction = flutter_node.text_direction;
612 result.rect = flutter_node.rect;
613 result.transform = flutter_node.transform;
614 if (flutter_node.child_count > 0) {
615 result.children_in_traversal_order = std::vector<int32_t>(
616 flutter_node.children_in_traversal_order,
617 flutter_node.children_in_traversal_order + flutter_node.child_count);
619 if (flutter_node.custom_accessibility_actions_count > 0) {
620 result.custom_accessibility_actions = std::vector<int32_t>(
621 flutter_node.custom_accessibility_actions,
622 flutter_node.custom_accessibility_actions +
623 flutter_node.custom_accessibility_actions_count);
628 AccessibilityBridge::SemanticsCustomAction
629 AccessibilityBridge::FromFlutterSemanticsCustomAction(
630 const FlutterSemanticsCustomAction2& flutter_custom_action) {
631 SemanticsCustomAction result;
632 result.id = flutter_custom_action.id;
633 result.override_action = flutter_custom_action.override_action;
634 if (flutter_custom_action.label) {
635 result.label = std::string(flutter_custom_action.label);
637 if (flutter_custom_action.hint) {
638 result.hint = std::string(flutter_custom_action.hint);
644 if (last_focused_id_ != node_id) {
645 auto last_focused_child =
647 if (!last_focused_child.expired()) {
650 FlutterSemanticsAction::
651 kFlutterSemanticsActionDidLoseAccessibilityFocus,
654 last_focused_id_ = node_id;
659 return last_focused_id_;
662 gfx::NativeViewAccessible AccessibilityBridge::GetNativeAccessibleFromId(
665 if (!platform_node_delegate) {
668 return platform_node_delegate->GetNativeViewAccessible();
671 gfx::RectF AccessibilityBridge::RelativeToGlobalBounds(
const ui::AXNode* node,
674 return tree_->RelativeToTreeBounds(node, gfx::RectF(), &offscreen,
679 ui::AXTreeID tree_id,
680 ui::AXNode::AXID node_id)
const {
685 ui::AXNode::AXID node_id)
const {
686 return tree_->GetFromId(node_id);
690 return tree_->GetAXTreeID();
694 return ui::AXTreeIDUnknown();
698 return tree_->root();
710 const ui::AXNode::AXID node_id)
const {
712 auto platform_delegate = platform_delegate_weak.lock();
713 if (!platform_delegate) {
716 return platform_delegate->GetPlatformNode();
720 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