Flutter Engine
 
Loading...
Searching...
No Matches
embedder_semantics_update.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
7namespace {
8FlutterCheckState ToFlutterCheckState(flutter::SemanticsCheckState state) {
9 switch (state) {
18 }
19}
20
21FlutterTristate ToFlutterTristate(flutter::SemanticsTristate state) {
22 switch (state) {
29 }
30}
31
32std::unique_ptr<FlutterSemanticsFlags> ConvertToFlutterSemanticsFlags(
33 const flutter::SemanticsFlags& source) {
34 return std::make_unique<FlutterSemanticsFlags>(FlutterSemanticsFlags{
35 .is_checked = ToFlutterCheckState(source.isChecked),
36 .is_selected = ToFlutterTristate(source.isSelected),
37 .is_enabled = ToFlutterTristate(source.isEnabled),
38 .is_toggled = ToFlutterTristate(source.isToggled),
39 .is_expanded = ToFlutterTristate(source.isExpanded),
40 .is_required = ToFlutterTristate(source.isRequired),
41 .is_focused = ToFlutterTristate(source.isFocused),
42 .is_button = source.isButton,
43 .is_text_field = source.isTextField,
44 .is_in_mutually_exclusive_group = source.isInMutuallyExclusiveGroup,
45 .is_header = source.isHeader,
46 .is_obscured = source.isObscured,
47 .scopes_route = source.scopesRoute,
48 .names_route = source.namesRoute,
49 .is_hidden = source.isHidden,
50 .is_image = source.isImage,
51 .is_live_region = source.isLiveRegion,
52 .has_implicit_scrolling = source.hasImplicitScrolling,
53 .is_multiline = source.isMultiline,
54 .is_read_only = source.isReadOnly,
55 .is_link = source.isLink,
56 .is_slider = source.isSlider,
57 .is_keyboard_key = source.isKeyboardKey,
58 .is_accessibility_focus_blocked = source.isAccessibilityFocusBlocked,
59 });
60}
61
62} // namespace
63
64namespace flutter {
65
67 const SemanticsNodeUpdates& nodes,
68 const CustomAccessibilityActionUpdates& actions) {
69 for (const auto& value : nodes) {
70 AddNode(value.second);
71 }
72
73 for (const auto& value : actions) {
74 AddAction(value.second);
75 }
76
77 update_ = {
79 .nodes_count = nodes_.size(),
80 .nodes = nodes_.data(),
81 .custom_actions_count = actions_.size(),
82 .custom_actions = actions_.data(),
83 };
84}
85
86// This function is for backward compatibility and contains only a subset of
87// the flags. New flags will be added only to `FlutterSemanticsFlags`, not
88// `FlutterSemanticsFlag`.
90 int result = 0;
91
93 result |= (1 << 0);
94 }
96 result |= (1 << 1);
97 }
99 result |= (1 << 2);
100 }
101 if (flags.isButton) {
102 result |= (1 << 3);
103 }
104 if (flags.isTextField) {
105 result |= (1 << 4);
106 }
107 if (flags.isFocused == SemanticsTristate::kTrue) {
108 result |= (1 << 5);
109 }
110 if (flags.isEnabled != SemanticsTristate::kNone) {
111 result |= (1 << 6);
112 }
113 if (flags.isEnabled == SemanticsTristate::kTrue) {
114 result |= (1 << 7);
115 }
116 if (flags.isInMutuallyExclusiveGroup) {
117 result |= (1 << 8);
118 }
119 if (flags.isHeader) {
120 result |= (1 << 9);
121 }
122 if (flags.isObscured) {
123 result |= (1 << 10);
124 }
125 if (flags.scopesRoute) {
126 result |= (1 << 11);
127 }
128 if (flags.namesRoute) {
129 result |= (1 << 12);
130 }
131 if (flags.isHidden) {
132 result |= (1 << 13);
133 }
134 if (flags.isImage) {
135 result |= (1 << 14);
136 }
137 if (flags.isLiveRegion) {
138 result |= (1 << 15);
139 }
140 if (flags.isToggled != SemanticsTristate::kNone) {
141 result |= (1 << 16);
142 }
143 if (flags.isToggled == SemanticsTristate::kTrue) {
144 result |= (1 << 17);
145 }
146 if (flags.hasImplicitScrolling) {
147 result |= (1 << 18);
148 }
149 if (flags.isMultiline) {
150 result |= (1 << 19);
151 }
152 if (flags.isReadOnly) {
153 result |= (1 << 20);
154 }
155 if (flags.isFocused != SemanticsTristate::kNone) {
156 result |= (1 << 21);
157 }
158 if (flags.isLink) {
159 result |= (1 << 22);
160 }
161 if (flags.isSlider) {
162 result |= (1 << 23);
163 }
164 if (flags.isKeyboardKey) {
165 result |= (1 << 24);
166 }
168 result |= (1 << 25);
169 }
171 result |= (1 << 26);
172 }
174 result |= (1 << 27);
175 }
177 result |= (1 << 28);
178 }
180 result |= (1 << 29);
181 }
183 result |= (1 << 30);
184 }
185
186 return static_cast<FlutterSemanticsFlag>(result);
187}
188
189void EmbedderSemanticsUpdate::AddNode(const SemanticsNode& node) {
190 SkMatrix transform = node.transform.asM33();
191 FlutterTransformation flutter_transform{
192 transform.get(SkMatrix::kMScaleX), transform.get(SkMatrix::kMSkewX),
193 transform.get(SkMatrix::kMTransX), transform.get(SkMatrix::kMSkewY),
194 transform.get(SkMatrix::kMScaleY), transform.get(SkMatrix::kMTransY),
195 transform.get(SkMatrix::kMPersp0), transform.get(SkMatrix::kMPersp1),
196 transform.get(SkMatrix::kMPersp2)};
197
198 // Do not add new members to FlutterSemanticsNode.
199 // This would break the forward compatibility of FlutterSemanticsUpdate.
200 // All new members must be added to FlutterSemanticsNode2 instead.
201 nodes_.push_back({
202 sizeof(FlutterSemanticsNode),
203 node.id,
204 SemanticsFlagsToInt(node.flags),
205 static_cast<FlutterSemanticsAction>(node.actions),
206 node.textSelectionBase,
207 node.textSelectionExtent,
208 node.scrollChildren,
209 node.scrollIndex,
210 node.scrollPosition,
211 node.scrollExtentMax,
212 node.scrollExtentMin,
213 0.0,
214 0.0,
215 node.label.c_str(),
216 node.hint.c_str(),
217 node.value.c_str(),
218 node.increasedValue.c_str(),
219 node.decreasedValue.c_str(),
220 static_cast<FlutterTextDirection>(node.textDirection),
221 FlutterRect{node.rect.fLeft, node.rect.fTop, node.rect.fRight,
222 node.rect.fBottom},
223 flutter_transform,
224 node.childrenInTraversalOrder.size(),
225 node.childrenInTraversalOrder.data(),
226 node.childrenInHitTestOrder.data(),
227 node.customAccessibilityActions.size(),
228 node.customAccessibilityActions.data(),
229 node.platformViewId,
230 node.tooltip.c_str(),
231 });
232}
233
234void EmbedderSemanticsUpdate::AddAction(
235 const CustomAccessibilityAction& action) {
236 // Do not add new members to FlutterSemanticsCustomAction.
237 // This would break the forward compatibility of FlutterSemanticsUpdate.
238 // All new members must be added to FlutterSemanticsCustomAction2 instead.
239 actions_.push_back({
241 action.id,
242 static_cast<FlutterSemanticsAction>(action.overrideId),
243 action.label.c_str(),
244 action.hint.c_str(),
245 });
246}
247
249
251 int64_t view_id,
252 const SemanticsNodeUpdates& nodes,
253 const CustomAccessibilityActionUpdates& actions) {
254 nodes_.reserve(nodes.size());
255 flags_.reserve(nodes.size());
256 node_pointers_.reserve(nodes.size());
257 actions_.reserve(actions.size());
258 action_pointers_.reserve(actions.size());
259
260 for (const auto& value : nodes) {
261 AddNode(value.second);
262 }
263
264 for (const auto& value : actions) {
265 AddAction(value.second);
266 }
267
268 for (size_t i = 0; i < nodes_.size(); i++) {
269 node_pointers_.push_back(&nodes_[i]);
270 }
271
272 for (size_t i = 0; i < actions_.size(); i++) {
273 action_pointers_.push_back(&actions_[i]);
274 }
275
276 update_ = {.struct_size = sizeof(FlutterSemanticsUpdate2),
277 .node_count = node_pointers_.size(),
278 .nodes = node_pointers_.data(),
279 .custom_action_count = action_pointers_.size(),
280 .custom_actions = action_pointers_.data(),
281 .view_id = view_id};
282}
283
285
286void EmbedderSemanticsUpdate2::AddNode(const SemanticsNode& node) {
287 SkMatrix transform = node.transform.asM33();
288 FlutterTransformation flutter_transform{
289 transform.get(SkMatrix::kMScaleX), transform.get(SkMatrix::kMSkewX),
290 transform.get(SkMatrix::kMTransX), transform.get(SkMatrix::kMSkewY),
291 transform.get(SkMatrix::kMScaleY), transform.get(SkMatrix::kMTransY),
292 transform.get(SkMatrix::kMPersp0), transform.get(SkMatrix::kMPersp1),
293 transform.get(SkMatrix::kMPersp2)};
294
295 auto label_attributes = CreateStringAttributes(node.labelAttributes);
296 auto hint_attributes = CreateStringAttributes(node.hintAttributes);
297 auto value_attributes = CreateStringAttributes(node.valueAttributes);
298 auto increased_value_attributes =
299 CreateStringAttributes(node.increasedValueAttributes);
300 auto decreased_value_attributes =
301 CreateStringAttributes(node.decreasedValueAttributes);
302 flags_.emplace_back(ConvertToFlutterSemanticsFlags(node.flags));
303
304 nodes_.push_back({
305 sizeof(FlutterSemanticsNode2),
306 node.id,
308 static_cast<FlutterSemanticsAction>(node.actions),
311 node.scrollChildren,
312 node.scrollIndex,
313 node.scrollPosition,
314 node.scrollExtentMax,
315 node.scrollExtentMin,
316 0.0,
317 0.0,
318 node.label.c_str(),
319 node.hint.c_str(),
320 node.value.c_str(),
321 node.increasedValue.c_str(),
322 node.decreasedValue.c_str(),
323 static_cast<FlutterTextDirection>(node.textDirection),
324 FlutterRect{node.rect.fLeft, node.rect.fTop, node.rect.fRight,
325 node.rect.fBottom},
326 flutter_transform,
327 node.childrenInTraversalOrder.size(),
328 node.childrenInTraversalOrder.data(),
329 node.childrenInHitTestOrder.data(),
330 node.customAccessibilityActions.size(),
331 node.customAccessibilityActions.data(),
332 node.platformViewId,
333 node.tooltip.c_str(),
334 label_attributes.count,
335 label_attributes.attributes,
336 hint_attributes.count,
337 hint_attributes.attributes,
338 value_attributes.count,
339 value_attributes.attributes,
340 increased_value_attributes.count,
341 increased_value_attributes.attributes,
342 decreased_value_attributes.count,
343 decreased_value_attributes.attributes,
344 flags_.back().get(),
345 node.headingLevel,
346 node.identifier.c_str(),
347 });
348}
349
350void EmbedderSemanticsUpdate2::AddAction(
351 const CustomAccessibilityAction& action) {
352 actions_.push_back({
354 action.id,
355 static_cast<FlutterSemanticsAction>(action.overrideId),
356 action.label.c_str(),
357 action.hint.c_str(),
358 });
359}
360
361EmbedderSemanticsUpdate2::EmbedderStringAttributes
362EmbedderSemanticsUpdate2::CreateStringAttributes(
363 const StringAttributes& attributes) {
364 // Minimize allocations if attributes are empty.
365 if (attributes.empty()) {
366 return {.count = 0, .attributes = nullptr};
367 }
368
369 // Translate the engine attributes to embedder attributes.
370 // The result vector's data is returned by this method.
371 // The result vector will be owned by |node_string_attributes_|
372 // so that the embedder attributes are cleaned up at the end of the
373 // semantics update callback when when the |EmbedderSemanticsUpdate2|
374 // is destroyed.
375 auto result = std::make_unique<std::vector<const FlutterStringAttribute*>>();
376 result->reserve(attributes.size());
377
378 for (const auto& attribute : attributes) {
379 auto embedder_attribute = std::make_unique<FlutterStringAttribute>();
380 embedder_attribute->struct_size = sizeof(FlutterStringAttribute);
381 embedder_attribute->start = attribute->start;
382 embedder_attribute->end = attribute->end;
383
384 switch (attribute->type) {
386 std::shared_ptr<flutter::LocaleStringAttribute> locale_attribute =
387 std::static_pointer_cast<flutter::LocaleStringAttribute>(attribute);
388
389 auto embedder_locale = std::make_unique<FlutterLocaleStringAttribute>();
390 embedder_locale->struct_size = sizeof(FlutterLocaleStringAttribute);
391 embedder_locale->locale = locale_attribute->locale.c_str();
392 locale_attributes_.push_back(std::move(embedder_locale));
393
394 embedder_attribute->type = FlutterStringAttributeType::kLocale;
395 embedder_attribute->locale = locale_attributes_.back().get();
396 break;
397 }
399 // All spell out attributes are identical and share a lazily created
400 // instance.
401 if (!spell_out_attribute_) {
402 auto spell_out_attribute_ =
403 std::make_unique<FlutterSpellOutStringAttribute>();
404 spell_out_attribute_->struct_size =
406 }
407
408 embedder_attribute->type = FlutterStringAttributeType::kSpellOut;
409 embedder_attribute->spell_out = spell_out_attribute_.get();
410 break;
411 }
412 }
413
414 string_attributes_.push_back(std::move(embedder_attribute));
415 result->push_back(string_attributes_.back().get());
416 }
417
418 node_string_attributes_.push_back(std::move(result));
419
420 return {
421 .count = node_string_attributes_.back()->size(),
422 .attributes = node_string_attributes_.back()->data(),
423 };
424}
425
426} // namespace flutter
EmbedderSemanticsUpdate2(int64_t view_id, const SemanticsNodeUpdates &nodes, const CustomAccessibilityActionUpdates &actions)
EmbedderSemanticsUpdate(const SemanticsNodeUpdates &nodes, const CustomAccessibilityActionUpdates &actions)
int32_t value
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
@ kFlutterCheckStateFalse
The semantics node is not checked.
Definition embedder.h:286
@ kFlutterCheckStateMixed
The semantics node represents a checkbox in mixed state.
Definition embedder.h:288
FlutterSemanticsAction
Definition embedder.h:115
@ kSpellOut
Definition embedder.h:1474
@ kLocale
Definition embedder.h:1476
FlutterTristate
Definition embedder.h:271
@ 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
FlutterTextDirection
Definition embedder.h:359
FlutterSemanticsFlag
Definition embedder.h:185
G_BEGIN_DECLS FlutterViewId view_id
std::unordered_map< int32_t, SemanticsNode > SemanticsNodeUpdates
FlutterSemanticsFlag SemanticsFlagsToInt(const SemanticsFlags &flags)
std::unordered_map< int32_t, CustomAccessibilityAction > CustomAccessibilityActionUpdates
std::vector< StringAttributePtr > StringAttributes
A structure to represent a rectangle.
Definition embedder.h:641
FlutterCheckState is_checked
Whether a semantics node is checked.
Definition embedder.h:295
A batch of updates to semantics nodes and custom actions.
Definition embedder.h:1796
size_t struct_size
The size of the struct. Must be sizeof(FlutterSemanticsUpdate2).
Definition embedder.h:1798
size_t struct_size
The size of the struct. Must be sizeof(FlutterSemanticsUpdate).
Definition embedder.h:1784
SemanticsTristate isExpanded
SemanticsCheckState isChecked
SemanticsTristate isRequired
SemanticsTristate isFocused
SemanticsTristate isSelected
SemanticsTristate isToggled
SemanticsTristate isEnabled
StringAttributes decreasedValueAttributes
StringAttributes hintAttributes
StringAttributes increasedValueAttributes
StringAttributes valueAttributes
StringAttributes labelAttributes
std::vector< int32_t > childrenInHitTestOrder
std::vector< int32_t > customAccessibilityActions
std::vector< int32_t > childrenInTraversalOrder