Flutter Engine
SemanticsObject.mm
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 #import "flutter/shell/platform/darwin/ios/framework/Source/SemanticsObject.h"
6 
7 #include "flutter/fml/platform/darwin/scoped_nsobject.h"
8 #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h"
9 
10 namespace {
11 
12 flutter::SemanticsAction GetSemanticsActionForScrollDirection(
13  UIAccessibilityScrollDirection direction) {
14  // To describe the vertical scroll direction, UIAccessibilityScrollDirection uses the
15  // direction the scroll bar moves in and SemanticsAction uses the direction the finger
16  // moves in. However, the horizontal scroll direction matches the SemanticsAction direction.
17  // That is way the following maps vertical opposite of the SemanticsAction, but the horizontal
18  // maps directly.
19  switch (direction) {
20  case UIAccessibilityScrollDirectionRight:
21  case UIAccessibilityScrollDirectionPrevious: // TODO(abarth): Support RTL using
22  // _node.textDirection.
24  case UIAccessibilityScrollDirectionLeft:
25  case UIAccessibilityScrollDirectionNext: // TODO(abarth): Support RTL using
26  // _node.textDirection.
28  case UIAccessibilityScrollDirectionUp:
30  case UIAccessibilityScrollDirectionDown:
32  }
33  FML_DCHECK(false); // Unreachable
35 }
36 
37 } // namespace
38 
39 @implementation FlutterSwitchSemanticsObject {
40  SemanticsObject* _semanticsObject;
41 }
42 
43 - (instancetype)initWithSemanticsObject:(SemanticsObject*)semanticsObject {
44  self = [super init];
45  if (self) {
46  _semanticsObject = [semanticsObject retain];
47  }
48  return self;
49 }
50 
51 - (void)dealloc {
52  [_semanticsObject release];
53  [super dealloc];
54 }
55 
56 - (NSMethodSignature*)methodSignatureForSelector:(SEL)sel {
57  NSMethodSignature* result = [super methodSignatureForSelector:sel];
58  if (!result) {
59  result = [_semanticsObject methodSignatureForSelector:sel];
60  }
61  return result;
62 }
63 
64 - (void)forwardInvocation:(NSInvocation*)anInvocation {
65  [anInvocation setTarget:_semanticsObject];
66  [anInvocation invoke];
67 }
68 
69 - (CGRect)accessibilityFrame {
70  return [_semanticsObject accessibilityFrame];
71 }
72 
73 - (id)accessibilityContainer {
74  return [_semanticsObject accessibilityContainer];
75 }
76 
77 - (NSString*)accessibilityLabel {
78  return [_semanticsObject accessibilityLabel];
79 }
80 
81 - (NSString*)accessibilityHint {
82  return [_semanticsObject accessibilityHint];
83 }
84 
85 - (NSString*)accessibilityValue {
86  if ([_semanticsObject node].HasFlag(flutter::SemanticsFlags::kIsToggled) ||
87  [_semanticsObject node].HasFlag(flutter::SemanticsFlags::kIsChecked)) {
88  self.on = YES;
89  } else {
90  self.on = NO;
91  }
92 
93  if (![_semanticsObject isAccessibilityBridgeAlive]) {
94  return nil;
95  } else {
96  return [super accessibilityValue];
97  }
98 }
99 
100 @end // FlutterSwitchSemanticsObject
101 
102 @implementation FlutterCustomAccessibilityAction {
103 }
104 @end
105 
106 @interface SemanticsObject ()
107 /** Should only be called in conjunction with setting child/parent relationship. */
108 - (void)privateSetParent:(SemanticsObject*)parent;
109 @end
110 
111 @implementation SemanticsObject {
113  NSMutableArray<SemanticsObject*>* _children;
114 }
115 
116 #pragma mark - Override base class designated initializers
117 
118 // Method declared as unavailable in the interface
119 - (instancetype)init {
120  [self release];
121  [super doesNotRecognizeSelector:_cmd];
122  return nil;
123 }
124 
125 #pragma mark - Designated initializers
126 
127 - (instancetype)initWithBridge:(fml::WeakPtr<flutter::AccessibilityBridgeIos>)bridge
128  uid:(int32_t)uid {
129  FML_DCHECK(bridge) << "bridge must be set";
130  FML_DCHECK(uid >= kRootNodeId);
131  // Initialize with the UIView as the container.
132  // The UIView will not necessarily be accessibility parent for this object.
133  // The bridge informs the OS of the actual structure via
134  // `accessibilityContainer` and `accessibilityElementAtIndex`.
135  self = [super initWithAccessibilityContainer:bridge->view()];
136 
137  if (self) {
138  _bridge = bridge;
139  _uid = uid;
140  _children = [[NSMutableArray alloc] init];
141  }
142 
143  return self;
144 }
145 
146 - (void)dealloc {
147  for (SemanticsObject* child in _children) {
148  [child privateSetParent:nil];
149  }
150  [_children removeAllObjects];
151  [_children release];
152  _parent = nil;
153  _container.get().semanticsObject = nil;
154  [_platformViewSemanticsContainer release];
155  [super dealloc];
156 }
157 
158 #pragma mark - Semantic object methods
159 
160 - (BOOL)isAccessibilityBridgeAlive {
161  return [self bridge].get() != nil;
162 }
163 
164 - (void)setSemanticsNode:(const flutter::SemanticsNode*)node {
165  _node = *node;
166 }
167 
168 /**
169  * Whether calling `setSemanticsNode:` with `node` would cause a layout change.
170  */
171 - (BOOL)nodeWillCauseLayoutChange:(const flutter::SemanticsNode*)node {
172  return [self node].rect != node->rect || [self node].transform != node->transform;
173 }
174 
175 /**
176  * Whether calling `setSemanticsNode:` with `node` would cause a scroll event.
177  */
178 - (BOOL)nodeWillCauseScroll:(const flutter::SemanticsNode*)node {
179  return !isnan([self node].scrollPosition) && !isnan(node->scrollPosition) &&
180  [self node].scrollPosition != node->scrollPosition;
181 }
182 
183 /**
184  * Whether calling `setSemanticsNode:` with `node` should trigger an
185  * announcement.
186  */
187 - (BOOL)nodeShouldTriggerAnnouncement:(const flutter::SemanticsNode*)node {
188  // The node dropped the live region flag, if it ever had one.
189  if (!node || !node->HasFlag(flutter::SemanticsFlags::kIsLiveRegion)) {
190  return NO;
191  }
192 
193  // The node has gained a new live region flag, always announce.
194  if (![self node].HasFlag(flutter::SemanticsFlags::kIsLiveRegion)) {
195  return YES;
196  }
197 
198  // The label has updated, and the new node has a live region flag.
199  return [self node].label != node->label;
200 }
201 
202 - (BOOL)hasChildren {
203  if (_node.IsPlatformViewNode()) {
204  return YES;
205  }
206  return [self.children count] != 0;
207 }
208 
209 - (void)privateSetParent:(SemanticsObject*)parent {
210  _parent = parent;
211 }
212 
213 - (void)setChildren:(NSArray<SemanticsObject*>*)children {
214  for (SemanticsObject* child in _children) {
215  [child privateSetParent:nil];
216  }
217  [_children release];
218  _children = [[NSMutableArray alloc] initWithArray:children];
219  for (SemanticsObject* child in _children) {
220  [child privateSetParent:self];
221  }
222 }
223 
224 - (void)replaceChildAtIndex:(NSInteger)index withChild:(SemanticsObject*)child {
225  SemanticsObject* oldChild = _children[index];
226  [oldChild privateSetParent:nil];
227  [child privateSetParent:self];
228  [_children replaceObjectAtIndex:index withObject:child];
229 }
230 
231 #pragma mark - UIAccessibility overrides
232 
233 - (BOOL)isAccessibilityElement {
234  if (![self isAccessibilityBridgeAlive])
235  return false;
236 
237  // Note: hit detection will only apply to elements that report
238  // -isAccessibilityElement of YES. The framework will continue scanning the
239  // entire element tree looking for such a hit.
240 
241  // We enforce in the framework that no other useful semantics are merged with these nodes.
242  if ([self node].HasFlag(flutter::SemanticsFlags::kScopesRoute))
243  return false;
244 
245  // If the only flag(s) set are scrolling related AND
246  // The only flags set are not kIsHidden OR
247  // The node doesn't have a label, value, or hint OR
248  // The only actions set are scrolling related actions.
249  //
250  // The kIsHidden flag set with any other flag just means this node is now
251  // hidden but still is a valid target for a11y focus in the tree, e.g. a list
252  // item that is currently off screen but the a11y navigation needs to know
253  // about.
254  return (([self node].flags & ~flutter::kScrollableSemanticsFlags) != 0 &&
255  [self node].flags != static_cast<int32_t>(flutter::SemanticsFlags::kIsHidden)) ||
256  ![self node].label.empty() || ![self node].value.empty() || ![self node].hint.empty() ||
257  ([self node].actions & ~flutter::kScrollableSemanticsActions) != 0;
258 }
259 
260 - (void)collectRoutes:(NSMutableArray<SemanticsObject*>*)edges {
261  if ([self node].HasFlag(flutter::SemanticsFlags::kScopesRoute))
262  [edges addObject:self];
263  if ([self hasChildren]) {
264  for (SemanticsObject* child in self.children) {
265  [child collectRoutes:edges];
266  }
267  }
268 }
269 
270 - (BOOL)onCustomAccessibilityAction:(FlutterCustomAccessibilityAction*)action {
271  if (![self node].HasAction(flutter::SemanticsAction::kCustomAction))
272  return NO;
273  int32_t action_id = action.uid;
274  std::vector<uint8_t> args;
275  args.push_back(3); // type=int32.
276  args.push_back(action_id);
277  args.push_back(action_id >> 8);
278  args.push_back(action_id >> 16);
279  args.push_back(action_id >> 24);
280  [self bridge]->DispatchSemanticsAction([self uid], flutter::SemanticsAction::kCustomAction,
281  std::move(args));
282  return YES;
283 }
284 
285 - (NSString*)routeName {
286  // Returns the first non-null and non-empty semantic label of a child
287  // with an NamesRoute flag. Otherwise returns nil.
288  if ([self node].HasFlag(flutter::SemanticsFlags::kNamesRoute)) {
289  NSString* newName = [self accessibilityLabel];
290  if (newName != nil && [newName length] > 0) {
291  return newName;
292  }
293  }
294  if ([self hasChildren]) {
295  for (SemanticsObject* child in self.children) {
296  NSString* newName = [child routeName];
297  if (newName != nil && [newName length] > 0) {
298  return newName;
299  }
300  }
301  }
302  return nil;
303 }
304 
305 - (NSString*)accessibilityLabel {
306  if (![self isAccessibilityBridgeAlive])
307  return nil;
308 
309  if ([self node].label.empty())
310  return nil;
311  return @([self node].label.data());
312 }
313 
314 - (NSString*)accessibilityHint {
315  if (![self isAccessibilityBridgeAlive])
316  return nil;
317 
318  if ([self node].hint.empty())
319  return nil;
320  return @([self node].hint.data());
321 }
322 
323 - (NSString*)accessibilityValue {
324  if (![self isAccessibilityBridgeAlive])
325  return nil;
326 
327  if (![self node].value.empty()) {
328  return @([self node].value.data());
329  }
330 
331  // FlutterSwitchSemanticsObject should supercede these conditionals.
332  if ([self node].HasFlag(flutter::SemanticsFlags::kHasToggledState) ||
334  if ([self node].HasFlag(flutter::SemanticsFlags::kIsToggled) ||
335  [self node].HasFlag(flutter::SemanticsFlags::kIsChecked)) {
336  return @"1";
337  } else {
338  return @"0";
339  }
340  }
341 
342  return nil;
343 }
344 
345 - (CGRect)accessibilityFrame {
346  if (![self isAccessibilityBridgeAlive])
347  return CGRectMake(0, 0, 0, 0);
348 
349  if ([self node].HasFlag(flutter::SemanticsFlags::kIsHidden)) {
350  return [super accessibilityFrame];
351  }
352  return [self globalRect];
353 }
354 
355 - (CGRect)globalRect {
356  SkM44 globalTransform = [self node].transform;
357  for (SemanticsObject* parent = [self parent]; parent; parent = parent.parent) {
358  globalTransform = parent.node.transform * globalTransform;
359  }
360 
361  SkPoint quad[4];
362  [self node].rect.toQuad(quad);
363  for (auto& point : quad) {
364  SkV4 vector = globalTransform.map(point.x(), point.y(), 0, 1);
365  point.set(vector.x / vector.w, vector.y / vector.w);
366  }
367  SkRect rect;
368  rect.setBounds(quad, 4);
369 
370  // `rect` is in the physical pixel coordinate system. iOS expects the accessibility frame in
371  // the logical pixel coordinate system. Therefore, we divide by the `scale` (pixel ratio) to
372  // convert.
373  CGFloat scale = [[[self bridge]->view() window] screen].scale;
374  auto result =
375  CGRectMake(rect.x() / scale, rect.y() / scale, rect.width() / scale, rect.height() / scale);
376  return UIAccessibilityConvertFrameToScreenCoordinates(result, [self bridge]->view());
377 }
378 
379 #pragma mark - UIAccessibilityElement protocol
380 
381 - (void)setAccessibilityContainer:(id)container {
382  // Explicit noop. The containers are calculated lazily in `accessibilityContainer`.
383  // See also: https://github.com/flutter/flutter/issues/54366
384 }
385 
386 - (id)accessibilityContainer {
387  if ([self hasChildren] || [self uid] == kRootNodeId) {
388  if (_container == nil)
389  _container.reset([[SemanticsObjectContainer alloc] initWithSemanticsObject:self
390  bridge:[self bridge]]);
391  return _container.get();
392  }
393  if ([self parent] == nil) {
394  // This can happen when we have released the accessibility tree but iOS is
395  // still holding onto our objects. iOS can take some time before it
396  // realizes that the tree has changed.
397  return nil;
398  }
399  return [[self parent] accessibilityContainer];
400 }
401 
402 #pragma mark - UIAccessibilityAction overrides
403 
404 - (BOOL)accessibilityActivate {
405  if (![self isAccessibilityBridgeAlive])
406  return NO;
407  if (![self node].HasAction(flutter::SemanticsAction::kTap))
408  return NO;
409  [self bridge]->DispatchSemanticsAction([self uid], flutter::SemanticsAction::kTap);
410  return YES;
411 }
412 
413 - (void)accessibilityIncrement {
414  if (![self isAccessibilityBridgeAlive])
415  return;
416  if ([self node].HasAction(flutter::SemanticsAction::kIncrease)) {
417  [self node].value = [self node].increasedValue;
418  [self bridge]->DispatchSemanticsAction([self uid], flutter::SemanticsAction::kIncrease);
419  }
420 }
421 
422 - (void)accessibilityDecrement {
423  if (![self isAccessibilityBridgeAlive])
424  return;
425  if ([self node].HasAction(flutter::SemanticsAction::kDecrease)) {
426  [self node].value = [self node].decreasedValue;
427  [self bridge]->DispatchSemanticsAction([self uid], flutter::SemanticsAction::kDecrease);
428  }
429 }
430 
431 - (BOOL)accessibilityScroll:(UIAccessibilityScrollDirection)direction {
432  if (![self isAccessibilityBridgeAlive])
433  return NO;
434  flutter::SemanticsAction action = GetSemanticsActionForScrollDirection(direction);
435  if (![self node].HasAction(action))
436  return NO;
437  [self bridge]->DispatchSemanticsAction([self uid], action);
438  return YES;
439 }
440 
441 - (BOOL)accessibilityPerformEscape {
442  if (![self isAccessibilityBridgeAlive])
443  return NO;
444  if (![self node].HasAction(flutter::SemanticsAction::kDismiss))
445  return NO;
446  [self bridge]->DispatchSemanticsAction([self uid], flutter::SemanticsAction::kDismiss);
447  return YES;
448 }
449 
450 #pragma mark UIAccessibilityFocus overrides
451 
452 - (void)accessibilityElementDidBecomeFocused {
453  if (![self isAccessibilityBridgeAlive])
454  return;
455  [self bridge]->AccessibilityObjectDidBecomeFocused([self uid]);
456  if ([self node].HasFlag(flutter::SemanticsFlags::kIsHidden) ||
457  [self node].HasFlag(flutter::SemanticsFlags::kIsHeader)) {
458  [self bridge]->DispatchSemanticsAction([self uid], flutter::SemanticsAction::kShowOnScreen);
459  }
460  if ([self node].HasAction(flutter::SemanticsAction::kDidGainAccessibilityFocus)) {
461  [self bridge]->DispatchSemanticsAction([self uid],
463  }
464 }
465 
466 - (void)accessibilityElementDidLoseFocus {
467  if (![self isAccessibilityBridgeAlive])
468  return;
469  [self bridge]->AccessibilityObjectDidLoseFocus([self uid]);
470  if ([self node].HasAction(flutter::SemanticsAction::kDidLoseAccessibilityFocus)) {
471  [self bridge]->DispatchSemanticsAction([self uid],
473  }
474 }
475 
476 @end
477 
478 @implementation FlutterSemanticsObject {
479 }
480 
481 #pragma mark - Override base class designated initializers
482 
483 // Method declared as unavailable in the interface
484 - (instancetype)init {
485  [self release];
486  [super doesNotRecognizeSelector:_cmd];
487  return nil;
488 }
489 
490 #pragma mark - Designated initializers
491 
492 - (instancetype)initWithBridge:(fml::WeakPtr<flutter::AccessibilityBridgeIos>)bridge
493  uid:(int32_t)uid {
494  self = [super initWithBridge:bridge uid:uid];
495  return self;
496 }
497 
498 #pragma mark - UIAccessibility overrides
499 
500 - (UIAccessibilityTraits)accessibilityTraits {
501  UIAccessibilityTraits traits = UIAccessibilityTraitNone;
502  if ([self node].HasAction(flutter::SemanticsAction::kIncrease) ||
503  [self node].HasAction(flutter::SemanticsAction::kDecrease)) {
504  traits |= UIAccessibilityTraitAdjustable;
505  }
506  // FlutterSwitchSemanticsObject should supercede these conditionals.
507  if ([self node].HasFlag(flutter::SemanticsFlags::kHasToggledState) ||
509  traits |= UIAccessibilityTraitButton;
510  }
511  if ([self node].HasFlag(flutter::SemanticsFlags::kIsSelected)) {
512  traits |= UIAccessibilityTraitSelected;
513  }
514  if ([self node].HasFlag(flutter::SemanticsFlags::kIsButton)) {
515  traits |= UIAccessibilityTraitButton;
516  }
517  if ([self node].HasFlag(flutter::SemanticsFlags::kHasEnabledState) &&
518  ![self node].HasFlag(flutter::SemanticsFlags::kIsEnabled)) {
519  traits |= UIAccessibilityTraitNotEnabled;
520  }
521  if ([self node].HasFlag(flutter::SemanticsFlags::kIsHeader)) {
522  traits |= UIAccessibilityTraitHeader;
523  }
524  if ([self node].HasFlag(flutter::SemanticsFlags::kIsImage)) {
525  traits |= UIAccessibilityTraitImage;
526  }
527  if ([self node].HasFlag(flutter::SemanticsFlags::kIsLiveRegion)) {
528  traits |= UIAccessibilityTraitUpdatesFrequently;
529  }
530  if ([self node].HasFlag(flutter::SemanticsFlags::kIsLink)) {
531  traits |= UIAccessibilityTraitLink;
532  }
533  return traits;
534 }
535 
536 @end
537 
539 @property(nonatomic, assign) SemanticsObject* semanticsObject;
540 @property(nonatomic, strong) UIView* platformView;
541 @end
542 
544 
545 // Method declared as unavailable in the interface
546 - (instancetype)init {
547  [self release];
548  [super doesNotRecognizeSelector:_cmd];
549  return nil;
550 }
551 
552 - (instancetype)initWithSemanticsObject:(SemanticsObject*)object {
553  FML_CHECK(object);
554  // Initialize with the UIView as the container.
555  // The UIView will not necessarily be accessibility parent for this object.
556  // The bridge informs the OS of the actual structure via
557  // `accessibilityContainer` and `accessibilityElementAtIndex`.
558  if (self = [super initWithAccessibilityContainer:object.bridge->view()]) {
559  _semanticsObject = object;
561  object.bridge->GetPlatformViewsController();
562  if (controller) {
563  _platformView = [[controller->GetPlatformViewByID(object.node.platformViewId) view] retain];
564  }
565  }
566  return self;
567 }
568 
569 - (void)dealloc {
570  [_platformView release];
571  _platformView = nil;
572  [super dealloc];
573 }
574 
575 - (NSArray*)accessibilityElements {
576  return @[ _semanticsObject, _platformView ];
577 }
578 
579 - (CGRect)accessibilityFrame {
580  return _semanticsObject.accessibilityFrame;
581 }
582 
583 - (BOOL)isAccessibilityElement {
584  return NO;
585 }
586 
587 - (id)accessibilityContainer {
588  return [_semanticsObject accessibilityContainer];
589 }
590 
591 - (BOOL)accessibilityScroll:(UIAccessibilityScrollDirection)direction {
592  return [_platformView accessibilityScroll:direction];
593 }
594 
595 @end
596 
597 @implementation SemanticsObjectContainer {
598  SemanticsObject* _semanticsObject;
600 }
601 
602 #pragma mark - initializers
603 
604 // Method declared as unavailable in the interface
605 - (instancetype)init {
606  [self release];
607  [super doesNotRecognizeSelector:_cmd];
608  return nil;
609 }
610 
611 - (instancetype)initWithSemanticsObject:(SemanticsObject*)semanticsObject
612  bridge:(fml::WeakPtr<flutter::AccessibilityBridgeIos>)bridge {
613  FML_DCHECK(semanticsObject) << "semanticsObject must be set";
614  // Initialize with the UIView as the container.
615  // The UIView will not necessarily be accessibility parent for this object.
616  // The bridge informs the OS of the actual structure via
617  // `accessibilityContainer` and `accessibilityElementAtIndex`.
618  self = [super initWithAccessibilityContainer:bridge->view()];
619 
620  if (self) {
621  _semanticsObject = semanticsObject;
622  _bridge = bridge;
623  }
624 
625  return self;
626 }
627 
628 #pragma mark - UIAccessibilityContainer overrides
629 
630 - (NSInteger)accessibilityElementCount {
631  NSInteger count = [[_semanticsObject children] count] + 1;
632  return count;
633 }
634 
635 - (nullable id)accessibilityElementAtIndex:(NSInteger)index {
636  if (index < 0 || index >= [self accessibilityElementCount])
637  return nil;
638  if (index == 0) {
639  return _semanticsObject;
640  }
641 
642  SemanticsObject* child = [_semanticsObject children][index - 1];
643 
644  // Swap the original `SemanticsObject` to a `PlatformViewSemanticsContainer`
645  if (child.node.IsPlatformViewNode()) {
647  return child.platformViewSemanticsContainer;
648  }
649 
650  if ([child hasChildren])
651  return [child accessibilityContainer];
652  return child;
653 }
654 
655 - (NSInteger)indexOfAccessibilityElement:(id)element {
656  if (element == _semanticsObject)
657  return 0;
658 
659  // FlutterPlatformViewSemanticsContainer is always the last element of its parent.
660  if ([element isKindOfClass:[FlutterPlatformViewSemanticsContainer class]]) {
661  return ((FlutterPlatformViewSemanticsContainer*)element).index;
662  }
663 
664  NSArray<SemanticsObject*>* children = [_semanticsObject children];
665  for (size_t i = 0; i < [children count]; i++) {
666  SemanticsObject* child = children[i];
667  if ((![child hasChildren] && child == element) ||
668  ([child hasChildren] && [child accessibilityContainer] == element))
669  return i + 1;
670  }
671  return NSNotFound;
672 }
673 
674 #pragma mark - UIAccessibilityElement protocol
675 
676 - (BOOL)isAccessibilityElement {
677  return NO;
678 }
679 
680 - (CGRect)accessibilityFrame {
681  return [_semanticsObject accessibilityFrame];
682 }
683 
684 - (id)accessibilityContainer {
685  if (!_bridge) {
686  return nil;
687  }
688  return ([_semanticsObject uid] == kRootNodeId)
689  ? _bridge->view()
690  : [[_semanticsObject parent] accessibilityContainer];
691 }
692 
693 #pragma mark - UIAccessibilityAction overrides
694 
695 - (BOOL)accessibilityScroll:(UIAccessibilityScrollDirection)direction {
696  return [_semanticsObject accessibilityScroll:direction];
697 }
698 
699 @end
G_BEGIN_DECLS FlValue * args
fml::WeakPtr< flutter::AccessibilityBridgeIos > _bridge
bool IsPlatformViewNode() const
#define FML_DCHECK(condition)
Definition: logging.h:86
FlutterPlatformViewSemanticsContainer * platformViewSemanticsContainer
auto WeakPtr(std::shared_ptr< T > pointer)
const int kScrollableSemanticsFlags
void collectRoutes:(NSMutableArray< SemanticsObject * > *edges)
Definition: ascii_trie.cc:9
const int kScrollableSemanticsActions
uint8_t value
fml::WeakPtr< flutter::AccessibilityBridgeIos > bridge
size_t length
SemanticsObject * parent
constexpr int32_t kRootNodeId
#define FML_CHECK(condition)
Definition: logging.h:68
NSMutableArray< SemanticsObject * > * _children
SemanticsObject * semanticsObject
flutter::SemanticsNode node
NSString * routeName()
int32_t id
virtual UIView * view() const =0
DEF_SWITCHES_START snapshot asset Path to the directory containing the four files specified by VmSnapshotInstructions and IsolateSnapshotInstructions vm snapshot The VM instructions snapshot that will be memory mapped as read and executable SnapshotAssetPath must be present isolate snapshot The isolate instructions snapshot that will be memory mapped as read and executable SnapshotAssetPath must be present icu symbol Prefix for the symbols representing ICU data linked into the Flutter library dart flags
Definition: switches.h:66