Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
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_FUCHSIA_FLUTTER_ACCESSIBILITY_BRIDGE_H_
6#define FLUTTER_SHELL_PLATFORM_FUCHSIA_FLUTTER_ACCESSIBILITY_BRIDGE_H_
7
8// Work around symbol conflicts with ICU.
9#undef TRUE
10#undef FALSE
11
12#include <fuchsia/accessibility/semantics/cpp/fidl.h>
13#include <fuchsia/ui/gfx/cpp/fidl.h>
14#include <lib/fidl/cpp/binding_set.h>
15#include <lib/inspect/component/cpp/component.h>
16#include <zircon/types.h>
17
18#include <memory>
19#include <optional>
20#include <queue>
21#include <unordered_map>
22#include <unordered_set>
23#include <vector>
24
25#include "flutter/fml/macros.h"
26#include "flutter/lib/ui/semantics/semantics_node.h"
27
28namespace flutter_runner {
29
30// Accessibility bridge.
31//
32// This class intermediates accessibility-related calls between Fuchsia and
33// Flutter. It serves to resolve the impedance mismatch between Flutter's
34// platform-agnostic accessibility APIs and Fuchsia's APIs and behaviour.
35//
36// This bridge performs the following functions, among others:
37//
38// * Translates Flutter's semantics node updates to events Fuchsia requires
39// (e.g. Flutter only sends updates for changed nodes, but Fuchsia requires
40// the entire flattened subtree to be sent when a node changes.
42 : public fuchsia::accessibility::semantics::SemanticListener {
43 public:
44 using SetSemanticsEnabledCallback = std::function<void(bool)>;
46 std::function<void(int32_t, flutter::SemanticsAction)>;
47
48 // TODO(MI4-2531, FIDL-718): Remove this. We shouldn't be worried about
49 // batching messages at this level.
50 // FIDL may encode a C++ struct as larger than the sizeof the C++ struct.
51 // This is to make sure we don't send updates that are too large.
52 static constexpr uint32_t kMaxMessageSize = ZX_CHANNEL_MAX_MSG_BYTES / 2;
53
54 static_assert(fuchsia::accessibility::semantics::MAX_LABEL_SIZE <
55 kMaxMessageSize - 1);
56
57 // Flutter uses signed 32 bit integers for node IDs, while Fuchsia uses
58 // unsigned 32 bit integers. A change in the size on either one would break
59 // casts and size tracking logic in the implementation.
60 static constexpr size_t kNodeIdSize = sizeof(flutter::SemanticsNode::id);
61 static_assert(
63 sizeof(fuchsia::accessibility::semantics::Node().node_id()),
64 "flutter::SemanticsNode::id and "
65 "fuchsia::accessibility::semantics::Node::node_id differ in size.");
66
67 // Maximum number of node ids to be deleted through the Semantics API.
68 static constexpr size_t kMaxDeletionsPerUpdate =
70
72 SetSemanticsEnabledCallback set_semantics_enabled_callback,
73 DispatchSemanticsActionCallback dispatch_semantics_action_callback,
74 fuchsia::accessibility::semantics::SemanticsManagerHandle
75 semantics_manager,
76 fuchsia::ui::views::ViewRef view_ref,
77 inspect::Node inspect_node);
78
79 // Returns true if accessible navigation is enabled.
80 bool GetSemanticsEnabled() const;
81
82 // Enables Flutter accessibility navigation features.
83 //
84 // Once enabled, any semantics updates in the Flutter application will
85 // trigger |FuchsiaAccessibility::DispatchAccessibilityEvent| callbacks
86 // to send events back to the Fuchsia SemanticsManager.
87 void SetSemanticsEnabled(bool enabled);
88
89 // Adds a semantics node update to the buffer of node updates to apply.
91 float view_pixel_ratio);
92
93 // Requests a message announcement from the accessibility TTS system.
94 void RequestAnnounce(const std::string message);
95
96 // Notifies the bridge of a 'hover move' touch exploration event.
97 zx_status_t OnHoverMove(double x, double y);
98
99 // |fuchsia::accessibility::semantics::SemanticListener|
100 void HitTest(
101 fuchsia::math::PointF local_point,
102 fuchsia::accessibility::semantics::SemanticListener::HitTestCallback
103 callback) override;
104
105 // |fuchsia::accessibility::semantics::SemanticListener|
107 uint32_t node_id,
108 fuchsia::accessibility::semantics::Action action,
109 fuchsia::accessibility::semantics::SemanticListener::
110 OnAccessibilityActionRequestedCallback callback) override;
111
112 private:
113 // Fuchsia's default root semantic node id.
114 static constexpr int32_t kRootNodeId = 0;
115
116 // Represents an atomic semantic update to Fuchsia, which can contain deletes
117 // and updates of semantic nodes.
118 //
119 // An atomic update is a set of operations that take a semantic tree in a
120 // valid state to another valid state. Please check the semantics FIDL
121 // documentation for details.
122 struct FuchsiaAtomicUpdate {
123 FuchsiaAtomicUpdate() = default;
124 ~FuchsiaAtomicUpdate() = default;
125 FuchsiaAtomicUpdate(FuchsiaAtomicUpdate&&) = default;
126
127 // Adds a node to be updated. |size| contains the
128 // size in bytes of the node to be updated.
129 void AddNodeUpdate(fuchsia::accessibility::semantics::Node node,
130 size_t size);
131
132 // Adds a node to be deleted.
133 void AddNodeDeletion(uint32_t id);
134
135 std::vector<std::pair<fuchsia::accessibility::semantics::Node, size_t>>
136 updates;
137 std::vector<uint32_t> deletions;
138 };
139
140 // Holds a flutter semantic node and some extra info.
141 // In particular, it adds a screen_rect field to flutter::SemanticsNode.
142 struct SemanticsNode {
144 SkRect screen_rect;
145 };
146
147 fuchsia::accessibility::semantics::Node GetRootNodeUpdate(size_t& node_size);
148
149 // Derives the BoundingBox of a Flutter semantics node from its
150 // rect and elevation.
151 fuchsia::ui::gfx::BoundingBox GetNodeLocation(
152 const flutter::SemanticsNode& node) const;
153
154 // Gets mat4 transformation from a Flutter semantics node.
155 fuchsia::ui::gfx::mat4 GetNodeTransform(
156 const flutter::SemanticsNode& node) const;
157
158 // Converts a Flutter semantics node's transformation to a mat4.
159 fuchsia::ui::gfx::mat4 ConvertSkiaTransformToMat4(
160 const SkM44 transform) const;
161
162 // Derives the attributes for a Fuchsia semantics node from a Flutter
163 // semantics node.
164 fuchsia::accessibility::semantics::Attributes GetNodeAttributes(
165 const flutter::SemanticsNode& node,
166 size_t* added_size) const;
167
168 // Derives the states for a Fuchsia semantics node from a Flutter semantics
169 // node.
170 fuchsia::accessibility::semantics::States GetNodeStates(
171 const flutter::SemanticsNode& node,
172 size_t* additional_size) const;
173
174 // Derives the set of supported actions for a Fuchsia semantics node from
175 // a Flutter semantics node.
176 std::vector<fuchsia::accessibility::semantics::Action> GetNodeActions(
177 const flutter::SemanticsNode& node,
178 size_t* additional_size) const;
179
180 // Derives the role for a Fuchsia semantics node from a Flutter
181 // semantics node.
182 fuchsia::accessibility::semantics::Role GetNodeRole(
183 const flutter::SemanticsNode& node) const;
184
185 // Gets the set of reachable descendants from the given node id.
186 std::unordered_set<int32_t> GetDescendants(int32_t node_id) const;
187
188 // Removes internal references to any dangling nodes from previous
189 // updates, and adds the nodes to be deleted to the current |atomic_update|.
190 //
191 // The node ids to be deleted are only collected at this point, and will be
192 // committed in the next call to |Apply()|.
193 void PruneUnreachableNodes(FuchsiaAtomicUpdate* atomic_update);
194
195 // Updates the on-screen positions of accessibility elements,
196 // starting from the root element with an identity matrix.
197 //
198 // This should be called from Update.
199 void UpdateScreenRects();
200
201 // Updates the on-screen positions of accessibility elements, starting
202 // from node_id and using the specified transform.
203 //
204 // Update calls this via UpdateScreenRects().
205 void UpdateScreenRects(int32_t node_id,
206 SkM44 parent_transform,
207 std::unordered_set<int32_t>* visited_nodes);
208
209 // Traverses the semantics tree to find the node_id hit by the given x,y
210 // point.
211 //
212 // Assumes that SemanticsNode::screen_rect is up to date.
213 std::optional<int32_t> GetHitNode(int32_t node_id, float x, float y);
214
215 // Returns whether the node is considered focusable.
216 bool IsFocusable(const flutter::SemanticsNode& node) const;
217
218 // Converts a fuchsia::accessibility::semantics::Action to a
219 // flutter::SemanticsAction.
220 //
221 // The node_id parameter is used for printing warnings about unsupported
222 // action types.
223 std::optional<flutter::SemanticsAction> GetFlutterSemanticsAction(
224 fuchsia::accessibility::semantics::Action fuchsia_action,
225 uint32_t node_id);
226
227 // Applies the updates and deletions in |atomic_update|, sending them via
228 // |tree_ptr|.
229 void Apply(FuchsiaAtomicUpdate* atomic_update);
230
231 // |fuchsia::accessibility::semantics::SemanticListener|
232 void OnSemanticsModeChanged(bool enabled,
233 OnSemanticsModeChangedCallback callback) override;
234
235#if !FLUTTER_RELEASE
236 // Fills the inspect tree with debug information about the semantic tree.
237 void FillInspectTree(int32_t flutter_node_id,
238 int32_t current_level,
239 inspect::Node inspect_node,
240 inspect::Inspector* inspector) const;
241#endif // !FLUTTER_RELEASE
242
243 SetSemanticsEnabledCallback set_semantics_enabled_callback_;
244 DispatchSemanticsActionCallback dispatch_semantics_action_callback_;
245 flutter::SemanticsNode root_flutter_semantics_node_;
246 float last_seen_view_pixel_ratio_ = 1.f;
247
248 fidl::Binding<fuchsia::accessibility::semantics::SemanticListener> binding_;
249 fuchsia::accessibility::semantics::SemanticsManagerPtr
250 fuchsia_semantics_manager_;
251 fuchsia::accessibility::semantics::SemanticTreePtr tree_ptr_;
252
253 // This is the cache of all nodes we've sent to Fuchsia's SemanticsManager.
254 // Assists with pruning unreachable nodes and hit testing.
255 std::unordered_map<int32_t, SemanticsNode> nodes_;
256 bool semantics_enabled_;
257
258 // Queue of atomic updates to be sent to Fuchsia.
259 std::shared_ptr<std::queue<FuchsiaAtomicUpdate>> atomic_updates_;
260
261 // Node to publish inspect data.
262 inspect::Node inspect_node_;
263
264#if !FLUTTER_RELEASE
265 // Inspect node to store a dump of the semantic tree. Note that this only gets
266 // computed if requested, so it does not use memory to store the dump unless
267 // an explicit request is made.
268 inspect::LazyNode inspect_node_tree_dump_;
269#endif // !FLUTTER_RELEASE
270
271 FML_DISALLOW_COPY_AND_ASSIGN(AccessibilityBridge);
272};
273} // namespace flutter_runner
274
275#endif // FLUTTER_SHELL_PLATFORM_FUCHSIA_FLUTTER_ACCESSIBILITY_BRIDGE_H_
Definition SkM44.h:150
void AddSemanticsNodeUpdate(const flutter::SemanticsNodeUpdates update, float view_pixel_ratio)
std::function< void(bool)> SetSemanticsEnabledCallback
void OnSemanticsModeChanged(bool enabled, OnSemanticsModeChangedCallback callback) override
void OnAccessibilityActionRequested(uint32_t node_id, fuchsia::accessibility::semantics::Action action, fuchsia::accessibility::semantics::SemanticListener::OnAccessibilityActionRequestedCallback callback) override
static constexpr uint32_t kMaxMessageSize
void RequestAnnounce(const std::string message)
std::function< void(int32_t, flutter::SemanticsAction)> DispatchSemanticsActionCallback
zx_status_t OnHoverMove(double x, double y)
static constexpr size_t kMaxDeletionsPerUpdate
FlKeyEvent uint64_t FlKeyResponderAsyncCallback callback
#define FML_DISALLOW_COPY_AND_ASSIGN(TypeName)
Definition macros.h:27
Win32Message message
double y
double x
std::unordered_map< int32_t, SemanticsNode > SemanticsNodeUpdates
static SkColor4f transform(SkColor4f c, SkColorSpace *src, SkColorSpace *dst)
Definition p3.cpp:47