Flutter macOS Embedder
accessibility_bridge.h
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 
5 #ifndef FLUTTER_SHELL_PLATFORM_COMMON_ACCESSIBILITY_BRIDGE_H_
6 #define FLUTTER_SHELL_PLATFORM_COMMON_ACCESSIBILITY_BRIDGE_H_
7 
8 #include <unordered_map>
9 
10 #include "flutter/fml/mapping.h"
11 #include "flutter/shell/platform/embedder/embedder.h"
12 
13 #include "flutter/third_party/accessibility/ax/ax_event_generator.h"
14 #include "flutter/third_party/accessibility/ax/ax_tree.h"
15 #include "flutter/third_party/accessibility/ax/ax_tree_observer.h"
16 #include "flutter/third_party/accessibility/ax/platform/ax_platform_node_delegate.h"
17 #include "flutter/third_party/accessibility/ax/platform/ax_platform_tree_manager.h"
18 
20 
21 namespace flutter {
22 
23 //------------------------------------------------------------------------------
24 /// Use this class to maintain an accessibility tree. This class consumes
25 /// semantics updates from the embedder API and produces an accessibility tree
26 /// in the native format.
27 ///
28 /// The bridge creates an AXTree to hold the semantics data that comes from
29 /// Flutter semantics updates. The tree holds AXNode[s] which contain the
30 /// semantics information for semantics node. The AXTree resemble the Flutter
31 /// semantics tree in the Flutter framework. The bridge also uses
32 /// FlutterPlatformNodeDelegate to wrap each AXNode in order to provide
33 /// an accessibility tree in the native format.
34 ///
35 /// To use this class, one must subclass this class and provide their own
36 /// implementation of FlutterPlatformNodeDelegate.
37 ///
38 /// AccessibilityBridge must be created as a shared_ptr, since some methods
39 /// acquires its weak_ptr.
41  : public std::enable_shared_from_this<AccessibilityBridge>,
43  public ui::AXPlatformTreeManager,
44  private ui::AXTreeObserver {
45  public:
46  //-----------------------------------------------------------------------------
47  /// @brief Creates a new instance of a accessibility bridge.
49  virtual ~AccessibilityBridge();
50 
51  //------------------------------------------------------------------------------
52  /// @brief Adds a semantics node update to the pending semantics update.
53  /// Calling this method alone will NOT update the semantics tree.
54  /// To flush the pending updates, call the CommitUpdates().
55  ///
56  /// @param[in] node A reference to the semantics node update.
57  void AddFlutterSemanticsNodeUpdate(const FlutterSemanticsNode2& node);
58 
59  //------------------------------------------------------------------------------
60  /// @brief Adds a custom semantics action update to the pending semantics
61  /// update. Calling this method alone will NOT update the
62  /// semantics tree. To flush the pending updates, call the
63  /// CommitUpdates().
64  ///
65  /// @param[in] action A reference to the custom semantics action
66  /// update.
68  const FlutterSemanticsCustomAction2& action);
69 
70  //------------------------------------------------------------------------------
71  /// @brief Flushes the pending updates and applies them to this
72  /// accessibility bridge. Calling this with no pending updates
73  /// does nothing, and callers should call this method at the end
74  /// of an atomic batch to avoid leaving the tree in a unstable
75  /// state. For example if a node reparents from A to B, callers
76  /// should only call this method when both removal from A and
77  /// addition to B are in the pending updates.
78  void CommitUpdates();
79 
80  //------------------------------------------------------------------------------
81  /// @brief Get the flutter platform node delegate with the given id from
82  /// this accessibility bridge. Returns expired weak_ptr if the
83  /// delegate associated with the id does not exist or has been
84  /// removed from the accessibility tree.
85  ///
86  /// @param[in] id The id of the flutter accessibility node you want
87  /// to retrieve.
88  std::weak_ptr<FlutterPlatformNodeDelegate>
90 
91  //------------------------------------------------------------------------------
92  /// @brief Get the ax tree data from this accessibility bridge. The tree
93  /// data contains information such as the id of the node that
94  /// has the keyboard focus or the text selection range.
95  const ui::AXTreeData& GetAXTreeData() const;
96 
97  //------------------------------------------------------------------------------
98  /// @brief Gets all pending accessibility events generated during
99  /// semantics updates. This is useful when deciding how to handle
100  /// events in AccessibilityBridgeDelegate::OnAccessibilityEvent in
101  /// case one may decide to handle an event differently based on
102  /// all pending events.
103  const std::vector<ui::AXEventGenerator::TargetedEvent> GetPendingEvents()
104  const;
105 
106  // |AXTreeManager|
107  ui::AXNode* GetNodeFromTree(const ui::AXTreeID tree_id,
108  const ui::AXNode::AXID node_id) const override;
109 
110  // |AXTreeManager|
111  ui::AXNode* GetNodeFromTree(const ui::AXNode::AXID node_id) const override;
112 
113  // |AXTreeManager|
114  ui::AXTreeID GetTreeID() const override;
115 
116  // |AXTreeManager|
117  ui::AXTreeID GetParentTreeID() const override;
118 
119  // |AXTreeManager|
120  ui::AXNode* GetRootAsAXNode() const override;
121 
122  // |AXTreeManager|
123  ui::AXNode* GetParentNodeFromParentTreeAsAXNode() const override;
124 
125  // |AXTreeManager|
126  ui::AXTree* GetTree() const override;
127 
128  // |AXPlatformTreeManager|
129  ui::AXPlatformNode* GetPlatformNodeFromTree(
130  const ui::AXNode::AXID node_id) const override;
131 
132  // |AXPlatformTreeManager|
133  ui::AXPlatformNode* GetPlatformNodeFromTree(
134  const ui::AXNode& node) const override;
135 
136  // |AXPlatformTreeManager|
137  ui::AXPlatformNodeDelegate* RootDelegate() const override;
138 
139  protected:
140  //---------------------------------------------------------------------------
141  /// @brief Handle accessibility events generated due to accessibility
142  /// tree changes. These events are needed to be sent to native
143  /// accessibility system. See ui::AXEventGenerator::Event for
144  /// possible events.
145  ///
146  /// @param[in] targeted_event The object that contains both the
147  /// generated event and the event target.
148  virtual void OnAccessibilityEvent(
149  ui::AXEventGenerator::TargetedEvent targeted_event) = 0;
150 
151  //---------------------------------------------------------------------------
152  /// @brief Creates a platform specific FlutterPlatformNodeDelegate.
153  /// Ownership passes to the caller. This method will be called
154  /// whenever a new AXNode is created in AXTree. Each platform
155  /// needs to implement this method in order to inject its
156  /// subclass into the accessibility bridge.
157  virtual std::shared_ptr<FlutterPlatformNodeDelegate>
159 
160  private:
161  // See FlutterSemanticsNode in embedder.h
162  typedef struct {
163  int32_t id;
164  FlutterSemanticsFlags* flags;
165  FlutterSemanticsAction actions;
166  int32_t text_selection_base;
167  int32_t text_selection_extent;
168  int32_t scroll_child_count;
169  int32_t scroll_index;
170  double scroll_position;
171  double scroll_extent_max;
172  double scroll_extent_min;
173  std::string label;
174  std::string hint;
175  std::string value;
176  std::string increased_value;
177  std::string decreased_value;
178  std::string tooltip;
179  FlutterTextDirection text_direction;
180  FlutterRect rect;
181  FlutterTransformation transform;
182  std::vector<int32_t> children_in_traversal_order;
183  std::vector<int32_t> custom_accessibility_actions;
184  int32_t heading_level;
185  } SemanticsNode;
186 
187  // See FlutterSemanticsCustomAction in embedder.h
188  typedef struct {
189  int32_t id;
190  FlutterSemanticsAction override_action;
191  std::string label;
192  std::string hint;
193  } SemanticsCustomAction;
194 
195  std::unordered_map<AccessibilityNodeId,
196  std::shared_ptr<FlutterPlatformNodeDelegate>>
197  id_wrapper_map_;
198  std::unique_ptr<ui::AXTree> tree_;
199  ui::AXEventGenerator event_generator_;
200  std::unordered_map<int32_t, SemanticsNode> pending_semantics_node_updates_;
201  std::unordered_map<int32_t, SemanticsCustomAction>
202  pending_semantics_custom_action_updates_;
203  AccessibilityNodeId last_focused_id_ = ui::AXNode::kInvalidAXID;
204 
205  void InitAXTree(const ui::AXTreeUpdate& initial_state);
206 
207  // Create an update that removes any nodes that will be reparented by
208  // pending_semantics_updates_. Returns std::nullopt if none are reparented.
209  std::optional<ui::AXTreeUpdate> CreateRemoveReparentedNodesUpdate();
210 
211  void GetSubTreeList(const SemanticsNode& target,
212  std::vector<SemanticsNode>& result);
213  void ConvertFlutterUpdate(const SemanticsNode& node,
214  ui::AXTreeUpdate& tree_update);
215  void SetRoleFromFlutterUpdate(ui::AXNodeData& node_data,
216  const SemanticsNode& node);
217  void SetStateFromFlutterUpdate(ui::AXNodeData& node_data,
218  const SemanticsNode& node);
219  void SetActionsFromFlutterUpdate(ui::AXNodeData& node_data,
220  const SemanticsNode& node);
221  void SetBooleanAttributesFromFlutterUpdate(ui::AXNodeData& node_data,
222  const SemanticsNode& node);
223  void SetIntAttributesFromFlutterUpdate(ui::AXNodeData& node_data,
224  const SemanticsNode& node);
225  void SetIntListAttributesFromFlutterUpdate(ui::AXNodeData& node_data,
226  const SemanticsNode& node);
227  void SetStringListAttributesFromFlutterUpdate(ui::AXNodeData& node_data,
228  const SemanticsNode& node);
229  void SetNameFromFlutterUpdate(ui::AXNodeData& node_data,
230  const SemanticsNode& node);
231  void SetValueFromFlutterUpdate(ui::AXNodeData& node_data,
232  const SemanticsNode& node);
233  void SetTooltipFromFlutterUpdate(ui::AXNodeData& node_data,
234  const SemanticsNode& node);
235  void SetTreeData(const SemanticsNode& node, ui::AXTreeUpdate& tree_update);
236  SemanticsNode FromFlutterSemanticsNode(
237  const FlutterSemanticsNode2& flutter_node);
238  SemanticsCustomAction FromFlutterSemanticsCustomAction(
239  const FlutterSemanticsCustomAction2& flutter_custom_action);
240 
241  // |AXTreeObserver|
242  void OnNodeWillBeDeleted(ui::AXTree* tree, ui::AXNode* node) override;
243 
244  // |AXTreeObserver|
245  void OnSubtreeWillBeDeleted(ui::AXTree* tree, ui::AXNode* node) override;
246 
247  // |AXTreeObserver|
248  void OnNodeCreated(ui::AXTree* tree, ui::AXNode* node) override;
249 
250  // |AXTreeObserver|
251  void OnNodeDeleted(ui::AXTree* tree, AccessibilityNodeId node_id) override;
252 
253  // |AXTreeObserver|
254  void OnNodeReparented(ui::AXTree* tree, ui::AXNode* node) override;
255 
256  // |AXTreeObserver|
257  void OnRoleChanged(ui::AXTree* tree,
258  ui::AXNode* node,
259  ax::mojom::Role old_role,
260  ax::mojom::Role new_role) override;
261 
262  // |AXTreeObserver|
263  void OnNodeDataChanged(ui::AXTree* tree,
264  const ui::AXNodeData& old_node_data,
265  const ui::AXNodeData& new_node_data) override;
266 
267  // |AXTreeObserver|
268  void OnAtomicUpdateFinished(
269  ui::AXTree* tree,
270  bool root_changed,
271  const std::vector<ui::AXTreeObserver::Change>& changes) override;
272 
273  // |FlutterPlatformNodeDelegate::OwnerBridge|
274  void SetLastFocusedId(AccessibilityNodeId node_id) override;
275 
276  // |FlutterPlatformNodeDelegate::OwnerBridge|
277  AccessibilityNodeId GetLastFocusedId() override;
278 
279  // |FlutterPlatformNodeDelegate::OwnerBridge|
280  gfx::NativeViewAccessible GetNativeAccessibleFromId(
281  AccessibilityNodeId id) override;
282 
283  // |FlutterPlatformNodeDelegate::OwnerBridge|
284  gfx::RectF RelativeToGlobalBounds(const ui::AXNode* node,
285  bool& offscreen,
286  bool clip_bounds) override;
287 
288  BASE_DISALLOW_COPY_AND_ASSIGN(AccessibilityBridge);
289 };
290 
291 } // namespace flutter
292 
293 #endif // FLUTTER_SHELL_PLATFORM_COMMON_ACCESSIBILITY_BRIDGE_H_
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
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
ui::AXNode::AXID AccessibilityNodeId