"Fossies" - the Fresh Open Source Software Archive

Member "flutter-1.22.4/packages/flutter/lib/src/semantics/semantics.dart" (13 Nov 2020, 159100 Bytes) of package /linux/misc/flutter-1.22.4.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Dart source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 // Copyright 2014 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 
    6 import 'dart:math' as math;
    7 import 'dart:typed_data';
    8 import 'dart:ui' as ui;
    9 import 'dart:ui' show Offset, Rect, SemanticsAction, SemanticsFlag,
   10        TextDirection;
   11 
   12 import 'package:flutter/foundation.dart';
   13 import 'package:flutter/painting.dart' show MatrixUtils, TransformProperty;
   14 import 'package:flutter/services.dart';
   15 import 'package:vector_math/vector_math_64.dart';
   16 
   17 import 'binding.dart' show SemanticsBinding;
   18 import 'semantics_event.dart';
   19 
   20 export 'dart:ui' show SemanticsAction;
   21 export 'semantics_event.dart';
   22 
   23 /// Signature for a function that is called for each [SemanticsNode].
   24 ///
   25 /// Return false to stop visiting nodes.
   26 ///
   27 /// Used by [SemanticsNode.visitChildren].
   28 typedef SemanticsNodeVisitor = bool Function(SemanticsNode node);
   29 
   30 /// Signature for [SemanticsAction]s that move the cursor.
   31 ///
   32 /// If `extendSelection` is set to true the cursor movement should extend the
   33 /// current selection or (if nothing is currently selected) start a selection.
   34 typedef MoveCursorHandler = void Function(bool extendSelection);
   35 
   36 /// Signature for the [SemanticsAction.setSelection] handlers to change the
   37 /// text selection (or re-position the cursor) to `selection`.
   38 typedef SetSelectionHandler = void Function(TextSelection selection);
   39 
   40 typedef _SemanticsActionHandler = void Function(dynamic args);
   41 
   42 /// A tag for a [SemanticsNode].
   43 ///
   44 /// Tags can be interpreted by the parent of a [SemanticsNode]
   45 /// and depending on the presence of a tag the parent can for example decide
   46 /// how to add the tagged node as a child. Tags are not sent to the engine.
   47 ///
   48 /// As an example, the [RenderSemanticsGestureHandler] uses tags to determine
   49 /// if a child node should be excluded from the scrollable area for semantic
   50 /// purposes.
   51 ///
   52 /// The provided [name] is only used for debugging. Two tags created with the
   53 /// same [name] and the `new` operator are not considered identical. However,
   54 /// two tags created with the same [name] and the `const` operator are always
   55 /// identical.
   56 class SemanticsTag {
   57   /// Creates a [SemanticsTag].
   58   ///
   59   /// The provided [name] is only used for debugging. Two tags created with the
   60   /// same [name] and the `new` operator are not considered identical. However,
   61   /// two tags created with the same [name] and the `const` operator are always
   62   /// identical.
   63   const SemanticsTag(this.name);
   64 
   65   /// A human-readable name for this tag used for debugging.
   66   ///
   67   /// This string is not used to determine if two tags are identical.
   68   final String name;
   69 
   70   @override
   71   String toString() => '${objectRuntimeType(this, 'SemanticsTag')}($name)';
   72 }
   73 
   74 /// An identifier of a custom semantics action.
   75 ///
   76 /// Custom semantics actions can be provided to make complex user
   77 /// interactions more accessible. For instance, if an application has a
   78 /// drag-and-drop list that requires the user to press and hold an item
   79 /// to move it, users interacting with the application using a hardware
   80 /// switch may have difficulty. This can be made accessible by creating custom
   81 /// actions and pairing them with handlers that move a list item up or down in
   82 /// the list.
   83 ///
   84 /// In Android, these actions are presented in the local context menu. In iOS,
   85 /// these are presented in the radial context menu.
   86 ///
   87 /// Localization and text direction do not automatically apply to the provided
   88 /// label or hint.
   89 ///
   90 /// Instances of this class should either be instantiated with const or
   91 /// new instances cached in static fields.
   92 ///
   93 /// See also:
   94 ///
   95 ///  * [SemanticsProperties], where the handler for a custom action is provided.
   96 @immutable
   97 class CustomSemanticsAction {
   98   /// Creates a new [CustomSemanticsAction].
   99   ///
  100   /// The [label] must not be null or the empty string.
  101   const CustomSemanticsAction({required String this.label})
  102     : assert(label != null),
  103       assert(label != ''),
  104       hint = null,
  105       action = null;
  106 
  107   /// Creates a new [CustomSemanticsAction] that overrides a standard semantics
  108   /// action.
  109   ///
  110   /// The [hint] must not be null or the empty string.
  111   const CustomSemanticsAction.overridingAction({required String this.hint, required SemanticsAction this.action})
  112     : assert(hint != null),
  113       assert(hint != ''),
  114       assert(action != null),
  115       label = null;
  116 
  117   /// The user readable name of this custom semantics action.
  118   final String? label;
  119 
  120   /// The hint description of this custom semantics action.
  121   final String? hint;
  122 
  123   /// The standard semantics action this action replaces.
  124   final SemanticsAction? action;
  125 
  126   @override
  127   int get hashCode => ui.hashValues(label, hint, action);
  128 
  129   @override
  130   bool operator ==(Object other) {
  131     if (other.runtimeType != runtimeType)
  132       return false;
  133     return other is CustomSemanticsAction
  134         && other.label == label
  135         && other.hint == hint
  136         && other.action == action;
  137   }
  138 
  139   @override
  140   String toString() {
  141     return 'CustomSemanticsAction(${_ids[this]}, label:$label, hint:$hint, action:$action)';
  142   }
  143 
  144   // Logic to assign a unique id to each custom action without requiring
  145   // user specification.
  146   static int _nextId = 0;
  147   static final Map<int, CustomSemanticsAction> _actions = <int, CustomSemanticsAction>{};
  148   static final Map<CustomSemanticsAction, int> _ids = <CustomSemanticsAction, int>{};
  149 
  150   /// Get the identifier for a given `action`.
  151   static int getIdentifier(CustomSemanticsAction action) {
  152     int? result = _ids[action];
  153     if (result == null) {
  154       result = _nextId++;
  155       _ids[action] = result;
  156       _actions[result] = action;
  157     }
  158     return result;
  159   }
  160 
  161   /// Get the `action` for a given identifier.
  162   static CustomSemanticsAction? getAction(int id) {
  163     return _actions[id];
  164   }
  165 }
  166 
  167 /// Summary information about a [SemanticsNode] object.
  168 ///
  169 /// A semantics node might [SemanticsNode.mergeAllDescendantsIntoThisNode],
  170 /// which means the individual fields on the semantics node don't fully describe
  171 /// the semantics at that node. This data structure contains the full semantics
  172 /// for the node.
  173 ///
  174 /// Typically obtained from [SemanticsNode.getSemanticsData].
  175 @immutable
  176 class SemanticsData with Diagnosticable {
  177   /// Creates a semantics data object.
  178   ///
  179   /// The [flags], [actions], [label], and [Rect] arguments must not be null.
  180   ///
  181   /// If [label] is not empty, then [textDirection] must also not be null.
  182   const SemanticsData({
  183     required this.flags,
  184     required this.actions,
  185     required this.label,
  186     required this.increasedValue,
  187     required this.value,
  188     required this.decreasedValue,
  189     required this.hint,
  190     required this.textDirection,
  191     required this.rect,
  192     required this.elevation,
  193     required this.thickness,
  194     required this.textSelection,
  195     required this.scrollIndex,
  196     required this.scrollChildCount,
  197     required this.scrollPosition,
  198     required this.scrollExtentMax,
  199     required this.scrollExtentMin,
  200     required this.platformViewId,
  201     required this.maxValueLength,
  202     required this.currentValueLength,
  203     this.tags,
  204     this.transform,
  205     this.customSemanticsActionIds,
  206   }) : assert(flags != null),
  207        assert(actions != null),
  208        assert(label != null),
  209        assert(value != null),
  210        assert(decreasedValue != null),
  211        assert(increasedValue != null),
  212        assert(hint != null),
  213        assert(label == '' || textDirection != null, 'A SemanticsData object with label "$label" had a null textDirection.'),
  214        assert(value == '' || textDirection != null, 'A SemanticsData object with value "$value" had a null textDirection.'),
  215        assert(hint == '' || textDirection != null, 'A SemanticsData object with hint "$hint" had a null textDirection.'),
  216        assert(decreasedValue == '' || textDirection != null, 'A SemanticsData object with decreasedValue "$decreasedValue" had a null textDirection.'),
  217        assert(increasedValue == '' || textDirection != null, 'A SemanticsData object with increasedValue "$increasedValue" had a null textDirection.'),
  218        assert(rect != null);
  219 
  220   /// A bit field of [SemanticsFlag]s that apply to this node.
  221   final int flags;
  222 
  223   /// A bit field of [SemanticsAction]s that apply to this node.
  224   final int actions;
  225 
  226   /// A textual description of this node.
  227   ///
  228   /// The reading direction is given by [textDirection].
  229   final String label;
  230 
  231   /// A textual description for the current value of the node.
  232   ///
  233   /// The reading direction is given by [textDirection].
  234   final String value;
  235 
  236   /// The value that [value] will become after performing a
  237   /// [SemanticsAction.increase] action.
  238   ///
  239   /// The reading direction is given by [textDirection].
  240   final String increasedValue;
  241 
  242   /// The value that [value] will become after performing a
  243   /// [SemanticsAction.decrease] action.
  244   ///
  245   /// The reading direction is given by [textDirection].
  246   final String decreasedValue;
  247 
  248   /// A brief description of the result of performing an action on this node.
  249   ///
  250   /// The reading direction is given by [textDirection].
  251   final String hint;
  252 
  253   /// The reading direction for the text in [label], [value], [hint],
  254   /// [increasedValue], and [decreasedValue].
  255   final TextDirection? textDirection;
  256 
  257   /// The currently selected text (or the position of the cursor) within [value]
  258   /// if this node represents a text field.
  259   final TextSelection? textSelection;
  260 
  261   /// The total number of scrollable children that contribute to semantics.
  262   ///
  263   /// If the number of children are unknown or unbounded, this value will be
  264   /// null.
  265   final int? scrollChildCount;
  266 
  267   /// The index of the first visible semantic child of a scroll node.
  268   final int? scrollIndex;
  269 
  270   /// Indicates the current scrolling position in logical pixels if the node is
  271   /// scrollable.
  272   ///
  273   /// The properties [scrollExtentMin] and [scrollExtentMax] indicate the valid
  274   /// in-range values for this property. The value for [scrollPosition] may
  275   /// (temporarily) be outside that range, e.g. during an overscroll.
  276   ///
  277   /// See also:
  278   ///
  279   ///  * [ScrollPosition.pixels], from where this value is usually taken.
  280   final double? scrollPosition;
  281 
  282   /// Indicates the maximum in-range value for [scrollPosition] if the node is
  283   /// scrollable.
  284   ///
  285   /// This value may be infinity if the scroll is unbound.
  286   ///
  287   /// See also:
  288   ///
  289   ///  * [ScrollPosition.maxScrollExtent], from where this value is usually taken.
  290   final double? scrollExtentMax;
  291 
  292   /// Indicates the minimum in-range value for [scrollPosition] if the node is
  293   /// scrollable.
  294   ///
  295   /// This value may be infinity if the scroll is unbound.
  296   ///
  297   /// See also:
  298   ///
  299   ///  * [ScrollPosition.minScrollExtent], from where this value is usually taken.
  300   final double? scrollExtentMin;
  301 
  302   /// The id of the platform view, whose semantics nodes will be added as
  303   /// children to this node.
  304   ///
  305   /// If this value is non-null, the SemanticsNode must not have any children
  306   /// as those would be replaced by the semantics nodes of the referenced
  307   /// platform view.
  308   ///
  309   /// See also:
  310   ///
  311   ///  * [AndroidView], which is the platform view for Android.
  312   ///  * [UiKitView], which is the platform view for iOS.
  313   final int? platformViewId;
  314 
  315   /// The maximum number of characters that can be entered into an editable
  316   /// text field.
  317   ///
  318   /// For the purpose of this function a character is defined as one Unicode
  319   /// scalar value.
  320   ///
  321   /// This should only be set when [SemanticsFlag.isTextField] is set. Defaults
  322   /// to null, which means no limit is imposed on the text field.
  323   final int? maxValueLength;
  324 
  325   /// The current number of characters that have been entered into an editable
  326   /// text field.
  327   ///
  328   /// For the purpose of this function a character is defined as one Unicode
  329   /// scalar value.
  330   ///
  331   /// This should only be set when [SemanticsFlag.isTextField] is set. This must
  332   /// be set when [maxValueLength] is set.
  333   final int? currentValueLength;
  334 
  335   /// The bounding box for this node in its coordinate system.
  336   final Rect rect;
  337 
  338   /// The set of [SemanticsTag]s associated with this node.
  339   final Set<SemanticsTag>? tags;
  340 
  341   /// The transform from this node's coordinate system to its parent's coordinate system.
  342   ///
  343   /// By default, the transform is null, which represents the identity
  344   /// transformation (i.e., that this node has the same coordinate system as its
  345   /// parent).
  346   final Matrix4? transform;
  347 
  348   /// The elevation of this node relative to the parent semantics node.
  349   ///
  350   /// See also:
  351   ///
  352   ///  * [SemanticsConfiguration.elevation] for a detailed discussion regarding
  353   ///    elevation and semantics.
  354   final double elevation;
  355 
  356   /// The extent of this node along the z-axis beyond its [elevation]
  357   ///
  358   /// See also:
  359   ///
  360   ///  * [SemanticsConfiguration.thickness] for a more detailed definition.
  361   final double thickness;
  362 
  363   /// The identifiers for the custom semantics actions and standard action
  364   /// overrides for this node.
  365   ///
  366   /// The list must be sorted in increasing order.
  367   ///
  368   /// See also:
  369   ///
  370   ///  * [CustomSemanticsAction], for an explanation of custom actions.
  371   final List<int>? customSemanticsActionIds;
  372 
  373   /// Whether [flags] contains the given flag.
  374   bool hasFlag(SemanticsFlag flag) => (flags & flag.index) != 0;
  375 
  376   /// Whether [actions] contains the given action.
  377   bool hasAction(SemanticsAction action) => (actions & action.index) != 0;
  378 
  379   @override
  380   String toStringShort() => objectRuntimeType(this, 'SemanticsData');
  381 
  382   @override
  383   void debugFillProperties(DiagnosticPropertiesBuilder properties) {
  384     super.debugFillProperties(properties);
  385     properties.add(DiagnosticsProperty<Rect>('rect', rect, showName: false));
  386     properties.add(TransformProperty('transform', transform, showName: false, defaultValue: null));
  387     properties.add(DoubleProperty('elevation', elevation, defaultValue: 0.0));
  388     properties.add(DoubleProperty('thickness', thickness, defaultValue: 0.0));
  389     final List<String> actionSummary = <String>[
  390       for (final SemanticsAction action in SemanticsAction.values.values)
  391         if ((actions & action.index) != 0)
  392           describeEnum(action),
  393     ];
  394     final List<String?> customSemanticsActionSummary = customSemanticsActionIds!
  395       .map<String?>((int actionId) => CustomSemanticsAction.getAction(actionId)!.label)
  396       .toList();
  397     properties.add(IterableProperty<String>('actions', actionSummary, ifEmpty: null));
  398     properties.add(IterableProperty<String?>('customActions', customSemanticsActionSummary, ifEmpty: null));
  399 
  400     final List<String> flagSummary = <String>[
  401       for (final SemanticsFlag flag in SemanticsFlag.values.values)
  402         if ((flags & flag.index) != 0)
  403           describeEnum(flag),
  404     ];
  405     properties.add(IterableProperty<String>('flags', flagSummary, ifEmpty: null));
  406     properties.add(StringProperty('label', label, defaultValue: ''));
  407     properties.add(StringProperty('value', value, defaultValue: ''));
  408     properties.add(StringProperty('increasedValue', increasedValue, defaultValue: ''));
  409     properties.add(StringProperty('decreasedValue', decreasedValue, defaultValue: ''));
  410     properties.add(StringProperty('hint', hint, defaultValue: ''));
  411     properties.add(EnumProperty<TextDirection>('textDirection', textDirection, defaultValue: null));
  412     if (textSelection?.isValid == true)
  413       properties.add(MessageProperty('textSelection', '[${textSelection!.start}, ${textSelection!.end}]'));
  414     properties.add(IntProperty('platformViewId', platformViewId, defaultValue: null));
  415     properties.add(IntProperty('maxValueLength', maxValueLength, defaultValue: null));
  416     properties.add(IntProperty('currentValueLength', currentValueLength, defaultValue: null));
  417     properties.add(IntProperty('scrollChildren', scrollChildCount, defaultValue: null));
  418     properties.add(IntProperty('scrollIndex', scrollIndex, defaultValue: null));
  419     properties.add(DoubleProperty('scrollExtentMin', scrollExtentMin, defaultValue: null));
  420     properties.add(DoubleProperty('scrollPosition', scrollPosition, defaultValue: null));
  421     properties.add(DoubleProperty('scrollExtentMax', scrollExtentMax, defaultValue: null));
  422   }
  423 
  424   @override
  425   bool operator ==(Object other) {
  426     return other is SemanticsData
  427         && other.flags == flags
  428         && other.actions == actions
  429         && other.label == label
  430         && other.value == value
  431         && other.increasedValue == increasedValue
  432         && other.decreasedValue == decreasedValue
  433         && other.hint == hint
  434         && other.textDirection == textDirection
  435         && other.rect == rect
  436         && setEquals(other.tags, tags)
  437         && other.scrollChildCount == scrollChildCount
  438         && other.scrollIndex == scrollIndex
  439         && other.textSelection == textSelection
  440         && other.scrollPosition == scrollPosition
  441         && other.scrollExtentMax == scrollExtentMax
  442         && other.scrollExtentMin == scrollExtentMin
  443         && other.platformViewId == platformViewId
  444         && other.maxValueLength == maxValueLength
  445         && other.currentValueLength == currentValueLength
  446         && other.transform == transform
  447         && other.elevation == elevation
  448         && other.thickness == thickness
  449         && _sortedListsEqual(other.customSemanticsActionIds, customSemanticsActionIds);
  450   }
  451 
  452   @override
  453   int get hashCode {
  454     return ui.hashValues(
  455       ui.hashValues(
  456         flags,
  457         actions,
  458         label,
  459         value,
  460         increasedValue,
  461         decreasedValue,
  462         hint,
  463         textDirection,
  464         rect,
  465         tags,
  466         textSelection,
  467         scrollChildCount,
  468         scrollIndex,
  469         scrollPosition,
  470         scrollExtentMax,
  471         scrollExtentMin,
  472         platformViewId,
  473         maxValueLength,
  474         currentValueLength,
  475         transform,
  476       ),
  477       elevation,
  478       thickness,
  479       ui.hashList(customSemanticsActionIds),
  480     );
  481   }
  482 
  483   static bool _sortedListsEqual(List<int>? left, List<int>? right) {
  484     if (left == null && right == null)
  485       return true;
  486     if (left != null && right != null) {
  487       if (left.length != right.length)
  488         return false;
  489       for (int i = 0; i < left.length; i++)
  490         if (left[i] != right[i])
  491           return false;
  492       return true;
  493     }
  494     return false;
  495   }
  496 }
  497 
  498 class _SemanticsDiagnosticableNode extends DiagnosticableNode<SemanticsNode> {
  499   _SemanticsDiagnosticableNode({
  500     String? name,
  501     required SemanticsNode value,
  502     required DiagnosticsTreeStyle? style,
  503     required this.childOrder,
  504   }) : super(
  505     name: name,
  506     value: value,
  507     style: style,
  508   );
  509 
  510   final DebugSemanticsDumpOrder childOrder;
  511 
  512   @override
  513   List<DiagnosticsNode> getChildren() {
  514     if (value != null)
  515       return value.debugDescribeChildren(childOrder: childOrder);
  516 
  517     // `value` has a non-nullable return type, but might be null when
  518     // running with weak checking, so we need to null check it above (and
  519     // ignore the warning below that the null-handling logic is dead code).
  520     return const <DiagnosticsNode>[]; // ignore: dead_code
  521   }
  522 }
  523 
  524 /// Provides hint values which override the default hints on supported
  525 /// platforms.
  526 ///
  527 /// On iOS, these values are always ignored.
  528 @immutable
  529 class SemanticsHintOverrides extends DiagnosticableTree {
  530   /// Creates a semantics hint overrides.
  531   const SemanticsHintOverrides({
  532     this.onTapHint,
  533     this.onLongPressHint,
  534   }) : assert(onTapHint != ''),
  535        assert(onLongPressHint != '');
  536 
  537   /// The hint text for a tap action.
  538   ///
  539   /// If null, the standard hint is used instead.
  540   ///
  541   /// The hint should describe what happens when a tap occurs, not the
  542   /// manner in which a tap is accomplished.
  543   ///
  544   /// Bad: 'Double tap to show movies'.
  545   /// Good: 'show movies'.
  546   final String? onTapHint;
  547 
  548   /// The hint text for a long press action.
  549   ///
  550   /// If null, the standard hint is used instead.
  551   ///
  552   /// The hint should describe what happens when a long press occurs, not
  553   /// the manner in which the long press is accomplished.
  554   ///
  555   /// Bad: 'Double tap and hold to show tooltip'.
  556   /// Good: 'show tooltip'.
  557   final String? onLongPressHint;
  558 
  559   /// Whether there are any non-null hint values.
  560   bool get isNotEmpty => onTapHint != null || onLongPressHint != null;
  561 
  562   @override
  563   int get hashCode => ui.hashValues(onTapHint, onLongPressHint);
  564 
  565   @override
  566   bool operator ==(Object other) {
  567     if (other.runtimeType != runtimeType)
  568       return false;
  569     return other is SemanticsHintOverrides
  570         && other.onTapHint == onTapHint
  571         && other.onLongPressHint == onLongPressHint;
  572   }
  573 
  574   @override
  575   void debugFillProperties(DiagnosticPropertiesBuilder properties) {
  576     super.debugFillProperties(properties);
  577     properties.add(StringProperty('onTapHint', onTapHint, defaultValue: null));
  578     properties.add(StringProperty('onLongPressHint', onLongPressHint, defaultValue: null));
  579   }
  580 }
  581 
  582 /// Contains properties used by assistive technologies to make the application
  583 /// more accessible.
  584 ///
  585 /// The properties of this class are used to generate a [SemanticsNode]s in the
  586 /// semantics tree.
  587 @immutable
  588 class SemanticsProperties extends DiagnosticableTree {
  589   /// Creates a semantic annotation.
  590   const SemanticsProperties({
  591     this.enabled,
  592     this.checked,
  593     this.selected,
  594     this.toggled,
  595     this.button,
  596     this.link,
  597     this.header,
  598     this.textField,
  599     this.readOnly,
  600     this.focusable,
  601     this.focused,
  602     this.inMutuallyExclusiveGroup,
  603     this.hidden,
  604     this.obscured,
  605     this.multiline,
  606     this.scopesRoute,
  607     this.namesRoute,
  608     this.image,
  609     this.liveRegion,
  610     this.maxValueLength,
  611     this.currentValueLength,
  612     this.label,
  613     this.value,
  614     this.increasedValue,
  615     this.decreasedValue,
  616     this.hint,
  617     this.hintOverrides,
  618     this.textDirection,
  619     this.sortKey,
  620     this.onTap,
  621     this.onLongPress,
  622     this.onScrollLeft,
  623     this.onScrollRight,
  624     this.onScrollUp,
  625     this.onScrollDown,
  626     this.onIncrease,
  627     this.onDecrease,
  628     this.onCopy,
  629     this.onCut,
  630     this.onPaste,
  631     this.onMoveCursorForwardByCharacter,
  632     this.onMoveCursorBackwardByCharacter,
  633     this.onMoveCursorForwardByWord,
  634     this.onMoveCursorBackwardByWord,
  635     this.onSetSelection,
  636     this.onDidGainAccessibilityFocus,
  637     this.onDidLoseAccessibilityFocus,
  638     this.onDismiss,
  639     this.customSemanticsActions,
  640   });
  641 
  642   /// If non-null, indicates that this subtree represents something that can be
  643   /// in an enabled or disabled state.
  644   ///
  645   /// For example, a button that a user can currently interact with would set
  646   /// this field to true. A button that currently does not respond to user
  647   /// interactions would set this field to false.
  648   final bool? enabled;
  649 
  650   /// If non-null, indicates that this subtree represents a checkbox
  651   /// or similar widget with a "checked" state, and what its current
  652   /// state is.
  653   ///
  654   /// This is mutually exclusive with [toggled].
  655   final bool? checked;
  656 
  657   /// If non-null, indicates that this subtree represents a toggle switch
  658   /// or similar widget with an "on" state, and what its current
  659   /// state is.
  660   ///
  661   /// This is mutually exclusive with [checked].
  662   final bool? toggled;
  663 
  664   /// If non-null indicates that this subtree represents something that can be
  665   /// in a selected or unselected state, and what its current state is.
  666   ///
  667   /// The active tab in a tab bar for example is considered "selected", whereas
  668   /// all other tabs are unselected.
  669   final bool? selected;
  670 
  671   /// If non-null, indicates that this subtree represents a button.
  672   ///
  673   /// TalkBack/VoiceOver provides users with the hint "button" when a button
  674   /// is focused.
  675   final bool? button;
  676 
  677   /// If non-null, indicates that this subtree represents a link.
  678   ///
  679   /// iOS's VoiceOver provides users with a unique hint when a link is focused.
  680   /// Android's Talkback will announce a link hint the same way it does a
  681   /// button.
  682   final bool? link;
  683 
  684   /// If non-null, indicates that this subtree represents a header.
  685   ///
  686   /// A header divides into sections. For example, an address book application
  687   /// might define headers A, B, C, etc. to divide the list of alphabetically
  688   /// sorted contacts into sections.
  689   final bool? header;
  690 
  691   /// If non-null, indicates that this subtree represents a text field.
  692   ///
  693   /// TalkBack/VoiceOver provide special affordances to enter text into a
  694   /// text field.
  695   final bool? textField;
  696 
  697   /// If non-null, indicates that this subtree is read only.
  698   ///
  699   /// Only applicable when [textField] is true.
  700   ///
  701   /// TalkBack/VoiceOver will treat it as non-editable text field.
  702   final bool? readOnly;
  703 
  704   /// If non-null, whether the node is able to hold input focus.
  705   ///
  706   /// If [focusable] is set to false, then [focused] must not be true.
  707   ///
  708   /// Input focus indicates that the node will receive keyboard events. It is not
  709   /// to be confused with accessibility focus. Accessibility focus is the
  710   /// green/black rectangular highlight that TalkBack/VoiceOver draws around the
  711   /// element it is reading, and is separate from input focus.
  712   final bool? focusable;
  713 
  714   /// If non-null, whether the node currently holds input focus.
  715   ///
  716   /// At most one node in the tree should hold input focus at any point in time,
  717   /// and it should not be set to true if [focusable] is false.
  718   ///
  719   /// Input focus indicates that the node will receive keyboard events. It is not
  720   /// to be confused with accessibility focus. Accessibility focus is the
  721   /// green/black rectangular highlight that TalkBack/VoiceOver draws around the
  722   /// element it is reading, and is separate from input focus.
  723   final bool? focused;
  724 
  725   /// If non-null, whether a semantic node is in a mutually exclusive group.
  726   ///
  727   /// For example, a radio button is in a mutually exclusive group because only
  728   /// one radio button in that group can be marked as [checked].
  729   final bool? inMutuallyExclusiveGroup;
  730 
  731   /// If non-null, whether the node is considered hidden.
  732   ///
  733   /// Hidden elements are currently not visible on screen. They may be covered
  734   /// by other elements or positioned outside of the visible area of a viewport.
  735   ///
  736   /// Hidden elements cannot gain accessibility focus though regular touch. The
  737   /// only way they can be focused is by moving the focus to them via linear
  738   /// navigation.
  739   ///
  740   /// Platforms are free to completely ignore hidden elements and new platforms
  741   /// are encouraged to do so.
  742   ///
  743   /// Instead of marking an element as hidden it should usually be excluded from
  744   /// the semantics tree altogether. Hidden elements are only included in the
  745   /// semantics tree to work around platform limitations and they are mainly
  746   /// used to implement accessibility scrolling on iOS.
  747   final bool? hidden;
  748 
  749   /// If non-null, whether [value] should be obscured.
  750   ///
  751   /// This option is usually set in combination with [textField] to indicate
  752   /// that the text field contains a password (or other sensitive information).
  753   /// Doing so instructs screen readers to not read out the [value].
  754   final bool? obscured;
  755 
  756   /// Whether the [value] is coming from a field that supports multiline text
  757   /// editing.
  758   ///
  759   /// This option is only meaningful when [textField] is true to indicate
  760   /// whether it's a single-line or multiline text field.
  761   ///
  762   /// This option is null when [textField] is false.
  763   final bool? multiline;
  764 
  765   /// If non-null, whether the node corresponds to the root of a subtree for
  766   /// which a route name should be announced.
  767   ///
  768   /// Generally, this is set in combination with
  769   /// [SemanticsConfiguration.explicitChildNodes], since nodes with this flag
  770   /// are not considered focusable by Android or iOS.
  771   ///
  772   /// See also:
  773   ///
  774   ///  * [SemanticsFlag.scopesRoute] for a description of how the announced
  775   ///    value is selected.
  776   final bool? scopesRoute;
  777 
  778   /// If non-null, whether the node contains the semantic label for a route.
  779   ///
  780   /// See also:
  781   ///
  782   ///  * [SemanticsFlag.namesRoute] for a description of how the name is used.
  783   final bool? namesRoute;
  784 
  785   /// If non-null, whether the node represents an image.
  786   ///
  787   /// See also:
  788   ///
  789   ///  * [SemanticsFlag.isImage], for the flag this setting controls.
  790   final bool? image;
  791 
  792   /// If non-null, whether the node should be considered a live region.
  793   ///
  794   /// On Android, when the label changes on a live region semantics node,
  795   /// TalkBack will make a polite announcement of the current label. This
  796   /// announcement occurs even if the node is not focused, but only if the label
  797   /// has changed since the last update.
  798   ///
  799   /// On iOS, no announcements are made but the node is marked as
  800   /// `UIAccessibilityTraitUpdatesFrequently`.
  801   ///
  802   /// An example of a live region is the [SnackBar] widget. When it appears
  803   /// on the screen it may be difficult to focus to read the label. A live
  804   /// region causes an initial polite announcement to be generated
  805   /// automatically.
  806   ///
  807   /// See also:
  808   ///
  809   ///  * [SemanticsFlag.isLiveRegion], the semantics flag this setting controls.
  810   ///  * [SemanticsConfiguration.liveRegion], for a full description of a live region.
  811   final bool? liveRegion;
  812 
  813   /// The maximum number of characters that can be entered into an editable
  814   /// text field.
  815   ///
  816   /// For the purpose of this function a character is defined as one Unicode
  817   /// scalar value.
  818   ///
  819   /// This should only be set when [textField] is true. Defaults to null,
  820   /// which means no limit is imposed on the text field.
  821   final int? maxValueLength;
  822 
  823   /// The current number of characters that have been entered into an editable
  824   /// text field.
  825   ///
  826   /// For the purpose of this function a character is defined as one Unicode
  827   /// scalar value.
  828   ///
  829   /// This should only be set when [textField] is true. Must be set when
  830   /// [maxValueLength] is set.
  831   final int? currentValueLength;
  832 
  833   /// Provides a textual description of the widget.
  834   ///
  835   /// If a label is provided, there must either by an ambient [Directionality]
  836   /// or an explicit [textDirection] should be provided.
  837   ///
  838   /// See also:
  839   ///
  840   ///  * [SemanticsConfiguration.label] for a description of how this is exposed
  841   ///    in TalkBack and VoiceOver.
  842   final String? label;
  843 
  844   /// Provides a textual description of the value of the widget.
  845   ///
  846   /// If a value is provided, there must either by an ambient [Directionality]
  847   /// or an explicit [textDirection] should be provided.
  848   ///
  849   /// See also:
  850   ///
  851   ///  * [SemanticsConfiguration.value] for a description of how this is exposed
  852   ///    in TalkBack and VoiceOver.
  853   final String? value;
  854 
  855   /// The value that [value] will become after a [SemanticsAction.increase]
  856   /// action has been performed on this widget.
  857   ///
  858   /// If a value is provided, [onIncrease] must also be set and there must
  859   /// either be an ambient [Directionality] or an explicit [textDirection]
  860   /// must be provided.
  861   ///
  862   /// See also:
  863   ///
  864   ///  * [SemanticsConfiguration.increasedValue] for a description of how this
  865   ///    is exposed in TalkBack and VoiceOver.
  866   final String? increasedValue;
  867 
  868   /// The value that [value] will become after a [SemanticsAction.decrease]
  869   /// action has been performed on this widget.
  870   ///
  871   /// If a value is provided, [onDecrease] must also be set and there must
  872   /// either be an ambient [Directionality] or an explicit [textDirection]
  873   /// must be provided.
  874   ///
  875   /// See also:
  876   ///
  877   ///  * [SemanticsConfiguration.decreasedValue] for a description of how this
  878   ///    is exposed in TalkBack and VoiceOver.
  879   final String? decreasedValue;
  880 
  881   /// Provides a brief textual description of the result of an action performed
  882   /// on the widget.
  883   ///
  884   /// If a hint is provided, there must either be an ambient [Directionality]
  885   /// or an explicit [textDirection] should be provided.
  886   ///
  887   /// See also:
  888   ///
  889   ///  * [SemanticsConfiguration.hint] for a description of how this is exposed
  890   ///    in TalkBack and VoiceOver.
  891   final String? hint;
  892 
  893   /// Provides hint values which override the default hints on supported
  894   /// platforms.
  895   ///
  896   /// On Android, If no hint overrides are used then default [hint] will be
  897   /// combined with the [label]. Otherwise, the [hint] will be ignored as long
  898   /// as there as at least one non-null hint override.
  899   ///
  900   /// On iOS, these are always ignored and the default [hint] is used instead.
  901   final SemanticsHintOverrides? hintOverrides;
  902 
  903   /// The reading direction of the [label], [value], [hint], [increasedValue],
  904   /// and [decreasedValue].
  905   ///
  906   /// Defaults to the ambient [Directionality].
  907   final TextDirection? textDirection;
  908 
  909   /// Determines the position of this node among its siblings in the traversal
  910   /// sort order.
  911   ///
  912   /// This is used to describe the order in which the semantic node should be
  913   /// traversed by the accessibility services on the platform (e.g. VoiceOver
  914   /// on iOS and TalkBack on Android).
  915   final SemanticsSortKey? sortKey;
  916 
  917   /// The handler for [SemanticsAction.tap].
  918   ///
  919   /// This is the semantic equivalent of a user briefly tapping the screen with
  920   /// the finger without moving it. For example, a button should implement this
  921   /// action.
  922   ///
  923   /// VoiceOver users on iOS and TalkBack users on Android can trigger this
  924   /// action by double-tapping the screen while an element is focused.
  925   final VoidCallback? onTap;
  926 
  927   /// The handler for [SemanticsAction.longPress].
  928   ///
  929   /// This is the semantic equivalent of a user pressing and holding the screen
  930   /// with the finger for a few seconds without moving it.
  931   ///
  932   /// VoiceOver users on iOS and TalkBack users on Android can trigger this
  933   /// action by double-tapping the screen without lifting the finger after the
  934   /// second tap.
  935   final VoidCallback? onLongPress;
  936 
  937   /// The handler for [SemanticsAction.scrollLeft].
  938   ///
  939   /// This is the semantic equivalent of a user moving their finger across the
  940   /// screen from right to left. It should be recognized by controls that are
  941   /// horizontally scrollable.
  942   ///
  943   /// VoiceOver users on iOS can trigger this action by swiping left with three
  944   /// fingers. TalkBack users on Android can trigger this action by swiping
  945   /// right and then left in one motion path. On Android, [onScrollUp] and
  946   /// [onScrollLeft] share the same gesture. Therefore, only on of them should
  947   /// be provided.
  948   final VoidCallback? onScrollLeft;
  949 
  950   /// The handler for [SemanticsAction.scrollRight].
  951   ///
  952   /// This is the semantic equivalent of a user moving their finger across the
  953   /// screen from left to right. It should be recognized by controls that are
  954   /// horizontally scrollable.
  955   ///
  956   /// VoiceOver users on iOS can trigger this action by swiping right with three
  957   /// fingers. TalkBack users on Android can trigger this action by swiping
  958   /// left and then right in one motion path. On Android, [onScrollDown] and
  959   /// [onScrollRight] share the same gesture. Therefore, only on of them should
  960   /// be provided.
  961   final VoidCallback? onScrollRight;
  962 
  963   /// The handler for [SemanticsAction.scrollUp].
  964   ///
  965   /// This is the semantic equivalent of a user moving their finger across the
  966   /// screen from bottom to top. It should be recognized by controls that are
  967   /// vertically scrollable.
  968   ///
  969   /// VoiceOver users on iOS can trigger this action by swiping up with three
  970   /// fingers. TalkBack users on Android can trigger this action by swiping
  971   /// right and then left in one motion path. On Android, [onScrollUp] and
  972   /// [onScrollLeft] share the same gesture. Therefore, only on of them should
  973   /// be provided.
  974   final VoidCallback? onScrollUp;
  975 
  976   /// The handler for [SemanticsAction.scrollDown].
  977   ///
  978   /// This is the semantic equivalent of a user moving their finger across the
  979   /// screen from top to bottom. It should be recognized by controls that are
  980   /// vertically scrollable.
  981   ///
  982   /// VoiceOver users on iOS can trigger this action by swiping down with three
  983   /// fingers. TalkBack users on Android can trigger this action by swiping
  984   /// left and then right in one motion path. On Android, [onScrollDown] and
  985   /// [onScrollRight] share the same gesture. Therefore, only on of them should
  986   /// be provided.
  987   final VoidCallback? onScrollDown;
  988 
  989   /// The handler for [SemanticsAction.increase].
  990   ///
  991   /// This is a request to increase the value represented by the widget. For
  992   /// example, this action might be recognized by a slider control.
  993   ///
  994   /// If a [value] is set, [increasedValue] must also be provided and
  995   /// [onIncrease] must ensure that [value] will be set to [increasedValue].
  996   ///
  997   /// VoiceOver users on iOS can trigger this action by swiping up with one
  998   /// finger. TalkBack users on Android can trigger this action by pressing the
  999   /// volume up button.
 1000   final VoidCallback? onIncrease;
 1001 
 1002   /// The handler for [SemanticsAction.decrease].
 1003   ///
 1004   /// This is a request to decrease the value represented by the widget. For
 1005   /// example, this action might be recognized by a slider control.
 1006   ///
 1007   /// If a [value] is set, [decreasedValue] must also be provided and
 1008   /// [onDecrease] must ensure that [value] will be set to [decreasedValue].
 1009   ///
 1010   /// VoiceOver users on iOS can trigger this action by swiping down with one
 1011   /// finger. TalkBack users on Android can trigger this action by pressing the
 1012   /// volume down button.
 1013   final VoidCallback? onDecrease;
 1014 
 1015   /// The handler for [SemanticsAction.copy].
 1016   ///
 1017   /// This is a request to copy the current selection to the clipboard.
 1018   ///
 1019   /// TalkBack users on Android can trigger this action from the local context
 1020   /// menu of a text field, for example.
 1021   final VoidCallback? onCopy;
 1022 
 1023   /// The handler for [SemanticsAction.cut].
 1024   ///
 1025   /// This is a request to cut the current selection and place it in the
 1026   /// clipboard.
 1027   ///
 1028   /// TalkBack users on Android can trigger this action from the local context
 1029   /// menu of a text field, for example.
 1030   final VoidCallback? onCut;
 1031 
 1032   /// The handler for [SemanticsAction.paste].
 1033   ///
 1034   /// This is a request to paste the current content of the clipboard.
 1035   ///
 1036   /// TalkBack users on Android can trigger this action from the local context
 1037   /// menu of a text field, for example.
 1038   final VoidCallback? onPaste;
 1039 
 1040   /// The handler for [SemanticsAction.moveCursorForwardByCharacter].
 1041   ///
 1042   /// This handler is invoked when the user wants to move the cursor in a
 1043   /// text field forward by one character.
 1044   ///
 1045   /// TalkBack users can trigger this by pressing the volume up key while the
 1046   /// input focus is in a text field.
 1047   final MoveCursorHandler? onMoveCursorForwardByCharacter;
 1048 
 1049   /// The handler for [SemanticsAction.moveCursorBackwardByCharacter].
 1050   ///
 1051   /// This handler is invoked when the user wants to move the cursor in a
 1052   /// text field backward by one character.
 1053   ///
 1054   /// TalkBack users can trigger this by pressing the volume down key while the
 1055   /// input focus is in a text field.
 1056   final MoveCursorHandler? onMoveCursorBackwardByCharacter;
 1057 
 1058   /// The handler for [SemanticsAction.moveCursorForwardByWord].
 1059   ///
 1060   /// This handler is invoked when the user wants to move the cursor in a
 1061   /// text field backward by one word.
 1062   ///
 1063   /// TalkBack users can trigger this by pressing the volume down key while the
 1064   /// input focus is in a text field.
 1065   final MoveCursorHandler? onMoveCursorForwardByWord;
 1066 
 1067   /// The handler for [SemanticsAction.moveCursorBackwardByWord].
 1068   ///
 1069   /// This handler is invoked when the user wants to move the cursor in a
 1070   /// text field backward by one word.
 1071   ///
 1072   /// TalkBack users can trigger this by pressing the volume down key while the
 1073   /// input focus is in a text field.
 1074   final MoveCursorHandler? onMoveCursorBackwardByWord;
 1075 
 1076   /// The handler for [SemanticsAction.setSelection].
 1077   ///
 1078   /// This handler is invoked when the user either wants to change the currently
 1079   /// selected text in a text field or change the position of the cursor.
 1080   ///
 1081   /// TalkBack users can trigger this handler by selecting "Move cursor to
 1082   /// beginning/end" or "Select all" from the local context menu.
 1083   final SetSelectionHandler? onSetSelection;
 1084 
 1085   /// The handler for [SemanticsAction.didGainAccessibilityFocus].
 1086   ///
 1087   /// This handler is invoked when the node annotated with this handler gains
 1088   /// the accessibility focus. The accessibility focus is the
 1089   /// green (on Android with TalkBack) or black (on iOS with VoiceOver)
 1090   /// rectangle shown on screen to indicate what element an accessibility
 1091   /// user is currently interacting with.
 1092   ///
 1093   /// The accessibility focus is different from the input focus. The input focus
 1094   /// is usually held by the element that currently responds to keyboard inputs.
 1095   /// Accessibility focus and input focus can be held by two different nodes!
 1096   ///
 1097   /// See also:
 1098   ///
 1099   ///  * [onDidLoseAccessibilityFocus], which is invoked when the accessibility
 1100   ///    focus is removed from the node.
 1101   ///  * [FocusNode], [FocusScope], [FocusManager], which manage the input focus.
 1102   final VoidCallback? onDidGainAccessibilityFocus;
 1103 
 1104   /// The handler for [SemanticsAction.didLoseAccessibilityFocus].
 1105   ///
 1106   /// This handler is invoked when the node annotated with this handler
 1107   /// loses the accessibility focus. The accessibility focus is
 1108   /// the green (on Android with TalkBack) or black (on iOS with VoiceOver)
 1109   /// rectangle shown on screen to indicate what element an accessibility
 1110   /// user is currently interacting with.
 1111   ///
 1112   /// The accessibility focus is different from the input focus. The input focus
 1113   /// is usually held by the element that currently responds to keyboard inputs.
 1114   /// Accessibility focus and input focus can be held by two different nodes!
 1115   ///
 1116   /// See also:
 1117   ///
 1118   ///  * [onDidGainAccessibilityFocus], which is invoked when the node gains
 1119   ///    accessibility focus.
 1120   ///  * [FocusNode], [FocusScope], [FocusManager], which manage the input focus.
 1121   final VoidCallback? onDidLoseAccessibilityFocus;
 1122 
 1123   /// The handler for [SemanticsAction.dismiss].
 1124   ///
 1125   /// This is a request to dismiss the currently focused node.
 1126   ///
 1127   /// TalkBack users on Android can trigger this action in the local context
 1128   /// menu, and VoiceOver users on iOS can trigger this action with a standard
 1129   /// gesture or menu option.
 1130   final VoidCallback? onDismiss;
 1131 
 1132   /// A map from each supported [CustomSemanticsAction] to a provided handler.
 1133   ///
 1134   /// The handler associated with each custom action is called whenever a
 1135   /// semantics action of type [SemanticsAction.customAction] is received. The
 1136   /// provided argument will be an identifier used to retrieve an instance of
 1137   /// a custom action which can then retrieve the correct handler from this map.
 1138   ///
 1139   /// See also:
 1140   ///
 1141   ///  * [CustomSemanticsAction], for an explanation of custom actions.
 1142   final Map<CustomSemanticsAction, VoidCallback>? customSemanticsActions;
 1143 
 1144   @override
 1145   void debugFillProperties(DiagnosticPropertiesBuilder properties) {
 1146     super.debugFillProperties(properties);
 1147     properties.add(DiagnosticsProperty<bool>('checked', checked, defaultValue: null));
 1148     properties.add(DiagnosticsProperty<bool>('selected', selected, defaultValue: null));
 1149     properties.add(StringProperty('label', label, defaultValue: ''));
 1150     properties.add(StringProperty('value', value));
 1151     properties.add(StringProperty('hint', hint));
 1152     properties.add(EnumProperty<TextDirection>('textDirection', textDirection, defaultValue: null));
 1153     properties.add(DiagnosticsProperty<SemanticsSortKey>('sortKey', sortKey, defaultValue: null));
 1154     properties.add(DiagnosticsProperty<SemanticsHintOverrides>('hintOverrides', hintOverrides));
 1155   }
 1156 
 1157   @override
 1158   String toStringShort() => objectRuntimeType(this, 'SemanticsProperties'); // the hashCode isn't important since we're immutable
 1159 }
 1160 
 1161 /// In tests use this function to reset the counter used to generate
 1162 /// [SemanticsNode.id].
 1163 void debugResetSemanticsIdCounter() {
 1164   SemanticsNode._lastIdentifier = 0;
 1165 }
 1166 
 1167 /// A node that represents some semantic data.
 1168 ///
 1169 /// The semantics tree is maintained during the semantics phase of the pipeline
 1170 /// (i.e., during [PipelineOwner.flushSemantics]), which happens after
 1171 /// compositing. The semantics tree is then uploaded into the engine for use
 1172 /// by assistive technology.
 1173 class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin {
 1174   /// Creates a semantic node.
 1175   ///
 1176   /// Each semantic node has a unique identifier that is assigned when the node
 1177   /// is created.
 1178   SemanticsNode({
 1179     this.key,
 1180     VoidCallback? showOnScreen,
 1181   }) : id = _generateNewId(),
 1182        _showOnScreen = showOnScreen;
 1183 
 1184   /// Creates a semantic node to represent the root of the semantics tree.
 1185   ///
 1186   /// The root node is assigned an identifier of zero.
 1187   SemanticsNode.root({
 1188     this.key,
 1189     VoidCallback? showOnScreen,
 1190     required SemanticsOwner owner,
 1191   }) : id = 0,
 1192        _showOnScreen = showOnScreen {
 1193     attach(owner);
 1194   }
 1195 
 1196 
 1197   // The maximal semantic node identifier generated by the framework.
 1198   //
 1199   // The identifier range for semantic node IDs is split into 2, the least significant 16 bits are
 1200   // reserved for framework generated IDs(generated with _generateNewId), and most significant 32
 1201   // bits are reserved for engine generated IDs.
 1202   static const int _maxFrameworkAccessibilityIdentifier = (1<<16) - 1;
 1203 
 1204   static int _lastIdentifier = 0;
 1205   static int _generateNewId() {
 1206     _lastIdentifier = (_lastIdentifier + 1) % _maxFrameworkAccessibilityIdentifier;
 1207     return _lastIdentifier;
 1208   }
 1209 
 1210   /// Uniquely identifies this node in the list of sibling nodes.
 1211   ///
 1212   /// Keys are used during the construction of the semantics tree. They are not
 1213   /// transferred to the engine.
 1214   final Key? key;
 1215 
 1216   /// The unique identifier for this node.
 1217   ///
 1218   /// The root node has an id of zero. Other nodes are given a unique id when
 1219   /// they are created.
 1220   final int id;
 1221 
 1222   final VoidCallback? _showOnScreen;
 1223 
 1224   // GEOMETRY
 1225 
 1226   /// The transform from this node's coordinate system to its parent's coordinate system.
 1227   ///
 1228   /// By default, the transform is null, which represents the identity
 1229   /// transformation (i.e., that this node has the same coordinate system as its
 1230   /// parent).
 1231   Matrix4? get transform => _transform;
 1232   Matrix4? _transform;
 1233   set transform(Matrix4? value) {
 1234     if (!MatrixUtils.matrixEquals(_transform, value)) {
 1235       _transform = value == null || MatrixUtils.isIdentity(value) ? null : value;
 1236       _markDirty();
 1237     }
 1238   }
 1239 
 1240   /// The bounding box for this node in its coordinate system.
 1241   Rect get rect => _rect;
 1242   Rect _rect = Rect.zero;
 1243   set rect(Rect value) {
 1244     assert(value != null);
 1245     assert(value.isFinite, '$this (with $owner) tried to set a non-finite rect.');
 1246     if (_rect != value) {
 1247       _rect = value;
 1248       _markDirty();
 1249     }
 1250   }
 1251 
 1252   /// The semantic clip from an ancestor that was applied to this node.
 1253   ///
 1254   /// Expressed in the coordinate system of the node. May be null if no clip has
 1255   /// been applied.
 1256   ///
 1257   /// Descendant [SemanticsNode]s that are positioned outside of this rect will
 1258   /// be excluded from the semantics tree. Descendant [SemanticsNode]s that are
 1259   /// overlapping with this rect, but are outside of [parentPaintClipRect] will
 1260   /// be included in the tree, but they will be marked as hidden because they
 1261   /// are assumed to be not visible on screen.
 1262   ///
 1263   /// If this rect is null, all descendant [SemanticsNode]s outside of
 1264   /// [parentPaintClipRect] will be excluded from the tree.
 1265   ///
 1266   /// If this rect is non-null it has to completely enclose
 1267   /// [parentPaintClipRect]. If [parentPaintClipRect] is null this property is
 1268   /// also null.
 1269   Rect? parentSemanticsClipRect;
 1270 
 1271   /// The paint clip from an ancestor that was applied to this node.
 1272   ///
 1273   /// Expressed in the coordinate system of the node. May be null if no clip has
 1274   /// been applied.
 1275   ///
 1276   /// Descendant [SemanticsNode]s that are positioned outside of this rect will
 1277   /// either be excluded from the semantics tree (if they have no overlap with
 1278   /// [parentSemanticsClipRect]) or they will be included and marked as hidden
 1279   /// (if they are overlapping with [parentSemanticsClipRect]).
 1280   ///
 1281   /// This rect is completely enclosed by [parentSemanticsClipRect].
 1282   ///
 1283   /// If this rect is null [parentSemanticsClipRect] also has to be null.
 1284   Rect? parentPaintClipRect;
 1285 
 1286   /// The elevation adjustment that the parent imposes on this node.
 1287   ///
 1288   /// The [elevation] property is relative to the elevation of the parent
 1289   /// [SemanticsNode]. However, as [SemanticsConfiguration]s from various
 1290   /// ascending [RenderObject]s are merged into each other to form that
 1291   /// [SemanticsNode] the parent’s elevation may change. This requires an
 1292   /// adjustment of the child’s relative elevation which is represented by this
 1293   /// value.
 1294   ///
 1295   /// The value is rarely accessed directly. Instead, for most use cases the
 1296   /// [elevation] value should be used, which includes this adjustment.
 1297   ///
 1298   /// See also:
 1299   ///
 1300   ///  * [elevation], the actual elevation of this [SemanticsNode].
 1301   double? elevationAdjustment;
 1302 
 1303   /// The index of this node within the parent's list of semantic children.
 1304   ///
 1305   /// This includes all semantic nodes, not just those currently in the
 1306   /// child list. For example, if a scrollable has five children but the first
 1307   /// two are not visible (and thus not included in the list of children), then
 1308   /// the index of the last node will still be 4.
 1309   int? indexInParent;
 1310 
 1311   /// Whether the node is invisible.
 1312   ///
 1313   /// A node whose [rect] is outside of the bounds of the screen and hence not
 1314   /// reachable for users is considered invisible if its semantic information
 1315   /// is not merged into a (partially) visible parent as indicated by
 1316   /// [isMergedIntoParent].
 1317   ///
 1318   /// An invisible node can be safely dropped from the semantic tree without
 1319   /// loosing semantic information that is relevant for describing the content
 1320   /// currently shown on screen.
 1321   bool get isInvisible => !isMergedIntoParent && rect.isEmpty;
 1322 
 1323   // MERGING
 1324 
 1325   /// Whether this node merges its semantic information into an ancestor node.
 1326   bool get isMergedIntoParent => _isMergedIntoParent;
 1327   bool _isMergedIntoParent = false;
 1328   set isMergedIntoParent(bool value) {
 1329     assert(value != null);
 1330     if (_isMergedIntoParent == value)
 1331       return;
 1332     _isMergedIntoParent = value;
 1333     _markDirty();
 1334   }
 1335 
 1336   /// Whether this node is taking part in a merge of semantic information.
 1337   ///
 1338   /// This returns true if the node is either merged into an ancestor node or if
 1339   /// decedent nodes are merged into this node.
 1340   ///
 1341   /// See also:
 1342   ///
 1343   ///  * [isMergedIntoParent]
 1344   ///  * [mergeAllDescendantsIntoThisNode]
 1345   bool get isPartOfNodeMerging => mergeAllDescendantsIntoThisNode || isMergedIntoParent;
 1346 
 1347   /// Whether this node and all of its descendants should be treated as one logical entity.
 1348   bool get mergeAllDescendantsIntoThisNode => _mergeAllDescendantsIntoThisNode;
 1349   bool _mergeAllDescendantsIntoThisNode = _kEmptyConfig.isMergingSemanticsOfDescendants;
 1350 
 1351 
 1352   // CHILDREN
 1353 
 1354   /// Contains the children in inverse hit test order (i.e. paint order).
 1355   List<SemanticsNode>? _children;
 1356 
 1357   /// A snapshot of `newChildren` passed to [_replaceChildren] that we keep in
 1358   /// debug mode. It supports the assertion that user does not mutate the list
 1359   /// of children.
 1360   late List<SemanticsNode> _debugPreviousSnapshot;
 1361 
 1362   void _replaceChildren(List<SemanticsNode> newChildren) {
 1363     assert(!newChildren.any((SemanticsNode child) => child == this));
 1364     assert(() {
 1365       if (identical(newChildren, _children)) {
 1366         final List<DiagnosticsNode> mutationErrors = <DiagnosticsNode>[];
 1367         if (newChildren.length != _debugPreviousSnapshot.length) {
 1368           mutationErrors.add(ErrorDescription(
 1369             "The list's length has changed from ${_debugPreviousSnapshot.length} "
 1370             'to ${newChildren.length}.'
 1371           ));
 1372         } else {
 1373           for (int i = 0; i < newChildren.length; i++) {
 1374             if (!identical(newChildren[i], _debugPreviousSnapshot[i])) {
 1375               if (mutationErrors.isNotEmpty) {
 1376                 mutationErrors.add(ErrorSpacer());
 1377               }
 1378               mutationErrors.add(ErrorDescription('Child node at position $i was replaced:'));
 1379               mutationErrors.add(newChildren[i].toDiagnosticsNode(name: 'Previous child', style: DiagnosticsTreeStyle.singleLine));
 1380               mutationErrors.add(_debugPreviousSnapshot[i].toDiagnosticsNode(name: 'New child', style: DiagnosticsTreeStyle.singleLine));
 1381             }
 1382           }
 1383         }
 1384         if (mutationErrors.isNotEmpty) {
 1385           throw FlutterError.fromParts(<DiagnosticsNode>[
 1386             ErrorSummary('Failed to replace child semantics nodes because the list of `SemanticsNode`s was mutated.'),
 1387             ErrorHint('Instead of mutating the existing list, create a new list containing the desired `SemanticsNode`s.'),
 1388             ErrorDescription('Error details:'),
 1389             ...mutationErrors,
 1390           ]);
 1391         }
 1392       }
 1393       assert(!newChildren.any((SemanticsNode node) => node.isMergedIntoParent) || isPartOfNodeMerging);
 1394 
 1395       _debugPreviousSnapshot = List<SemanticsNode>.from(newChildren);
 1396 
 1397       SemanticsNode ancestor = this;
 1398       while (ancestor.parent is SemanticsNode)
 1399         ancestor = ancestor.parent!;
 1400       assert(!newChildren.any((SemanticsNode child) => child == ancestor));
 1401       return true;
 1402     }());
 1403     assert(() {
 1404       final Set<SemanticsNode> seenChildren = <SemanticsNode>{};
 1405       for (final SemanticsNode child in newChildren)
 1406         assert(seenChildren.add(child)); // check for duplicate adds
 1407       return true;
 1408     }());
 1409 
 1410     // The goal of this function is updating sawChange.
 1411     if (_children != null) {
 1412       for (final SemanticsNode child in _children!)
 1413         child._dead = true;
 1414     }
 1415     if (newChildren != null) {
 1416       for (final SemanticsNode child in newChildren) {
 1417         assert(!child.isInvisible, 'Child $child is invisible and should not be added as a child of $this.');
 1418         child._dead = false;
 1419       }
 1420     }
 1421     bool sawChange = false;
 1422     if (_children != null) {
 1423       for (final SemanticsNode child in _children!) {
 1424         if (child._dead) {
 1425           if (child.parent == this) {
 1426             // we might have already had our child stolen from us by
 1427             // another node that is deeper in the tree.
 1428             dropChild(child);
 1429           }
 1430           sawChange = true;
 1431         }
 1432       }
 1433     }
 1434     if (newChildren != null) {
 1435       for (final SemanticsNode child in newChildren) {
 1436         if (child.parent != this) {
 1437           if (child.parent != null) {
 1438             // we're rebuilding the tree from the bottom up, so it's possible
 1439             // that our child was, in the last pass, a child of one of our
 1440             // ancestors. In that case, we drop the child eagerly here.
 1441             // TODO(ianh): Find a way to assert that the same node didn't
 1442             // actually appear in the tree in two places.
 1443             child.parent?.dropChild(child);
 1444           }
 1445           assert(!child.attached);
 1446           adoptChild(child);
 1447           sawChange = true;
 1448         }
 1449       }
 1450     }
 1451     if (!sawChange && _children != null) {
 1452       assert(newChildren != null);
 1453       assert(newChildren.length == _children!.length);
 1454       // Did the order change?
 1455       for (int i = 0; i < _children!.length; i++) {
 1456         if (_children![i].id != newChildren[i].id) {
 1457           sawChange = true;
 1458           break;
 1459         }
 1460       }
 1461     }
 1462     _children = newChildren;
 1463     if (sawChange)
 1464       _markDirty();
 1465   }
 1466 
 1467   /// Whether this node has a non-zero number of children.
 1468   bool get hasChildren => _children?.isNotEmpty ?? false;
 1469   bool _dead = false;
 1470 
 1471   /// The number of children this node has.
 1472   int get childrenCount => hasChildren ? _children!.length : 0;
 1473 
 1474   /// Visits the immediate children of this node.
 1475   ///
 1476   /// This function calls visitor for each immediate child until visitor returns
 1477   /// false. Returns true if all the visitor calls returned true, otherwise
 1478   /// returns false.
 1479   void visitChildren(SemanticsNodeVisitor visitor) {
 1480     if (_children != null) {
 1481       for (final SemanticsNode child in _children!) {
 1482         if (!visitor(child))
 1483           return;
 1484       }
 1485     }
 1486   }
 1487 
 1488   /// Visit all the descendants of this node.
 1489   ///
 1490   /// This function calls visitor for each descendant in a pre-order traversal
 1491   /// until visitor returns false. Returns true if all the visitor calls
 1492   /// returned true, otherwise returns false.
 1493   bool _visitDescendants(SemanticsNodeVisitor visitor) {
 1494     if (_children != null) {
 1495       for (final SemanticsNode child in _children!) {
 1496         if (!visitor(child) || !child._visitDescendants(visitor))
 1497           return false;
 1498       }
 1499     }
 1500     return true;
 1501   }
 1502 
 1503   // AbstractNode OVERRIDES
 1504 
 1505   @override
 1506   SemanticsOwner? get owner => super.owner as SemanticsOwner?;
 1507 
 1508   @override
 1509   SemanticsNode? get parent => super.parent as SemanticsNode?;
 1510 
 1511   @override
 1512   void redepthChildren() {
 1513     _children?.forEach(redepthChild);
 1514   }
 1515 
 1516   @override
 1517   void attach(SemanticsOwner owner) {
 1518     super.attach(owner);
 1519     assert(!owner._nodes.containsKey(id));
 1520     owner._nodes[id] = this;
 1521     owner._detachedNodes.remove(this);
 1522     if (_dirty) {
 1523       _dirty = false;
 1524       _markDirty();
 1525     }
 1526     if (_children != null) {
 1527       for (final SemanticsNode child in _children!)
 1528         child.attach(owner);
 1529     }
 1530   }
 1531 
 1532   @override
 1533   void detach() {
 1534     assert(owner!._nodes.containsKey(id));
 1535     assert(!owner!._detachedNodes.contains(this));
 1536     owner!._nodes.remove(id);
 1537     owner!._detachedNodes.add(this);
 1538     super.detach();
 1539     assert(owner == null);
 1540     if (_children != null) {
 1541       for (final SemanticsNode child in _children!) {
 1542         // The list of children may be stale and may contain nodes that have
 1543         // been assigned to a different parent.
 1544         if (child.parent == this)
 1545           child.detach();
 1546       }
 1547     }
 1548     // The other side will have forgotten this node if we ever send
 1549     // it again, so make sure to mark it dirty so that it'll get
 1550     // sent if it is resurrected.
 1551     _markDirty();
 1552   }
 1553 
 1554   // DIRTY MANAGEMENT
 1555 
 1556   bool _dirty = false;
 1557   void _markDirty() {
 1558     if (_dirty)
 1559       return;
 1560     _dirty = true;
 1561     if (attached) {
 1562       assert(!owner!._detachedNodes.contains(this));
 1563       owner!._dirtyNodes.add(this);
 1564     }
 1565   }
 1566 
 1567   bool _isDifferentFromCurrentSemanticAnnotation(SemanticsConfiguration config) {
 1568     return _label != config.label ||
 1569         _hint != config.hint ||
 1570         _elevation != config.elevation ||
 1571         _thickness != config.thickness ||
 1572         _decreasedValue != config.decreasedValue ||
 1573         _value != config.value ||
 1574         _increasedValue != config.increasedValue ||
 1575         _flags != config._flags ||
 1576         _textDirection != config.textDirection ||
 1577         _sortKey != config._sortKey ||
 1578         _textSelection != config._textSelection ||
 1579         _scrollPosition != config._scrollPosition ||
 1580         _scrollExtentMax != config._scrollExtentMax ||
 1581         _scrollExtentMin != config._scrollExtentMin ||
 1582         _actionsAsBits != config._actionsAsBits ||
 1583         indexInParent != config.indexInParent ||
 1584         platformViewId != config.platformViewId ||
 1585         _maxValueLength != config._maxValueLength ||
 1586         _currentValueLength != config._currentValueLength ||
 1587         _mergeAllDescendantsIntoThisNode != config.isMergingSemanticsOfDescendants;
 1588   }
 1589 
 1590   // TAGS, LABELS, ACTIONS
 1591 
 1592   Map<SemanticsAction, _SemanticsActionHandler> _actions = _kEmptyConfig._actions;
 1593   Map<CustomSemanticsAction, VoidCallback> _customSemanticsActions = _kEmptyConfig._customSemanticsActions;
 1594 
 1595   int _actionsAsBits = _kEmptyConfig._actionsAsBits;
 1596 
 1597   /// The [SemanticsTag]s this node is tagged with.
 1598   ///
 1599   /// Tags are used during the construction of the semantics tree. They are not
 1600   /// transferred to the engine.
 1601   Set<SemanticsTag>? tags;
 1602 
 1603   /// Whether this node is tagged with `tag`.
 1604   bool isTagged(SemanticsTag tag) => tags != null && tags!.contains(tag);
 1605 
 1606   int _flags = _kEmptyConfig._flags;
 1607 
 1608   /// Whether this node currently has a given [SemanticsFlag].
 1609   bool hasFlag(SemanticsFlag flag) => _flags & flag.index != 0;
 1610 
 1611   /// A textual description of this node.
 1612   ///
 1613   /// The reading direction is given by [textDirection].
 1614   String get label => _label;
 1615   String _label = _kEmptyConfig.label;
 1616 
 1617   /// A textual description for the current value of the node.
 1618   ///
 1619   /// The reading direction is given by [textDirection].
 1620   String get value => _value;
 1621   String _value = _kEmptyConfig.value;
 1622 
 1623   /// The value that [value] will have after a [SemanticsAction.decrease] action
 1624   /// has been performed.
 1625   ///
 1626   /// This property is only valid if the [SemanticsAction.decrease] action is
 1627   /// available on this node.
 1628   ///
 1629   /// The reading direction is given by [textDirection].
 1630   String get decreasedValue => _decreasedValue;
 1631   String _decreasedValue = _kEmptyConfig.decreasedValue;
 1632 
 1633   /// The value that [value] will have after a [SemanticsAction.increase] action
 1634   /// has been performed.
 1635   ///
 1636   /// This property is only valid if the [SemanticsAction.increase] action is
 1637   /// available on this node.
 1638   ///
 1639   /// The reading direction is given by [textDirection].
 1640   String get increasedValue => _increasedValue;
 1641   String _increasedValue = _kEmptyConfig.increasedValue;
 1642 
 1643   /// A brief description of the result of performing an action on this node.
 1644   ///
 1645   /// The reading direction is given by [textDirection].
 1646   String get hint => _hint;
 1647   String _hint = _kEmptyConfig.hint;
 1648 
 1649   /// The elevation along the z-axis at which the [rect] of this [SemanticsNode]
 1650   /// is located above its parent.
 1651   ///
 1652   /// The value is relative to the parent's [elevation]. The sum of the
 1653   /// [elevation]s of all ancestor node plus this value determines the absolute
 1654   /// elevation of this [SemanticsNode].
 1655   ///
 1656   /// See also:
 1657   ///
 1658   ///  * [thickness], which describes how much space in z-direction this
 1659   ///    [SemanticsNode] occupies starting at this [elevation].
 1660   ///  * [elevationAdjustment], which has been used to calculate this value.
 1661   double get elevation => _elevation;
 1662   double _elevation = _kEmptyConfig.elevation;
 1663 
 1664   /// Describes how much space the [SemanticsNode] takes up along the z-axis.
 1665   ///
 1666   /// A [SemanticsNode] represents multiple [RenderObject]s, which can be
 1667   /// located at various elevations in 3D. The [thickness] is the difference
 1668   /// between the absolute elevations of the lowest and highest [RenderObject]
 1669   /// represented by this [SemanticsNode]. In other words, the thickness
 1670   /// describes how high the box is that this [SemanticsNode] occupies in three
 1671   /// dimensional space. The two other dimensions are defined by [rect].
 1672   ///
 1673   /// {@tool snippet}
 1674   /// The following code stacks three [PhysicalModel]s on top of each other
 1675   /// separated by non-zero elevations.
 1676   ///
 1677   /// [PhysicalModel] C is elevated 10.0 above [PhysicalModel] B, which in turn
 1678   /// is elevated 5.0 above [PhysicalModel] A. The side view of this
 1679   /// constellation looks as follows:
 1680   ///
 1681   /// ![A diagram illustrating the elevations of three PhysicalModels and their
 1682   /// corresponding SemanticsNodes.](https://flutter.github.io/assets-for-api-docs/assets/semantics/SemanticsNode.thickness.png)
 1683   ///
 1684   /// In this example the [RenderObject]s for [PhysicalModel] C and B share one
 1685   /// [SemanticsNode] Y. Given the elevations of those [RenderObject]s, this
 1686   /// [SemanticsNode] has a [thickness] of 10.0 and an elevation of 5.0 over
 1687   /// its parent [SemanticsNode] X.
 1688   /// ```dart
 1689   /// PhysicalModel( // A
 1690   ///   color: Colors.amber,
 1691   ///   elevation: 0.0,
 1692   ///   child: Semantics(
 1693   ///     explicitChildNodes: true,
 1694   ///     child: PhysicalModel( // B
 1695   ///       color: Colors.brown,
 1696   ///       elevation: 5.0,
 1697   ///       child: PhysicalModel( // C
 1698   ///         color: Colors.cyan,
 1699   ///         elevation: 10.0,
 1700   ///         child: Placeholder(),
 1701   ///       ),
 1702   ///     ),
 1703   ///   ),
 1704   /// )
 1705   /// ```
 1706   /// {@end-tool}
 1707   ///
 1708   /// See also:
 1709   ///
 1710   ///  * [elevation], which describes the elevation of the box defined by
 1711   ///    [thickness] and [rect] relative to the parent of this [SemanticsNode].
 1712   double get thickness => _thickness;
 1713   double _thickness = _kEmptyConfig.thickness;
 1714 
 1715   /// Provides hint values which override the default hints on supported
 1716   /// platforms.
 1717   SemanticsHintOverrides? get hintOverrides => _hintOverrides;
 1718   SemanticsHintOverrides? _hintOverrides;
 1719 
 1720   /// The reading direction for [label], [value], [hint], [increasedValue], and
 1721   /// [decreasedValue].
 1722   TextDirection? get textDirection => _textDirection;
 1723   TextDirection? _textDirection = _kEmptyConfig.textDirection;
 1724 
 1725   /// Determines the position of this node among its siblings in the traversal
 1726   /// sort order.
 1727   ///
 1728   /// This is used to describe the order in which the semantic node should be
 1729   /// traversed by the accessibility services on the platform (e.g. VoiceOver
 1730   /// on iOS and TalkBack on Android).
 1731   SemanticsSortKey? get sortKey => _sortKey;
 1732   SemanticsSortKey? _sortKey;
 1733 
 1734   /// The currently selected text (or the position of the cursor) within [value]
 1735   /// if this node represents a text field.
 1736   TextSelection? get textSelection => _textSelection;
 1737   TextSelection? _textSelection;
 1738 
 1739   /// If this node represents a text field, this indicates whether or not it's
 1740   /// a multiline text field.
 1741   bool? get isMultiline => _isMultiline;
 1742   bool? _isMultiline;
 1743 
 1744   /// The total number of scrollable children that contribute to semantics.
 1745   ///
 1746   /// If the number of children are unknown or unbounded, this value will be
 1747   /// null.
 1748   int? get scrollChildCount => _scrollChildCount;
 1749   int? _scrollChildCount;
 1750 
 1751   /// The index of the first visible semantic child of a scroll node.
 1752   int? get scrollIndex => _scrollIndex;
 1753   int? _scrollIndex;
 1754 
 1755   /// Indicates the current scrolling position in logical pixels if the node is
 1756   /// scrollable.
 1757   ///
 1758   /// The properties [scrollExtentMin] and [scrollExtentMax] indicate the valid
 1759   /// in-range values for this property. The value for [scrollPosition] may
 1760   /// (temporarily) be outside that range, e.g. during an overscroll.
 1761   ///
 1762   /// See also:
 1763   ///
 1764   ///  * [ScrollPosition.pixels], from where this value is usually taken.
 1765   double? get scrollPosition => _scrollPosition;
 1766   double? _scrollPosition;
 1767 
 1768   /// Indicates the maximum in-range value for [scrollPosition] if the node is
 1769   /// scrollable.
 1770   ///
 1771   /// This value may be infinity if the scroll is unbound.
 1772   ///
 1773   /// See also:
 1774   ///
 1775   ///  * [ScrollPosition.maxScrollExtent], from where this value is usually taken.
 1776   double? get scrollExtentMax => _scrollExtentMax;
 1777   double? _scrollExtentMax;
 1778 
 1779   /// Indicates the minimum in-range value for [scrollPosition] if the node is
 1780   /// scrollable.
 1781   ///
 1782   /// This value may be infinity if the scroll is unbound.
 1783   ///
 1784   /// See also:
 1785   ///
 1786   ///  * [ScrollPosition.minScrollExtent] from where this value is usually taken.
 1787   double? get scrollExtentMin => _scrollExtentMin;
 1788   double? _scrollExtentMin;
 1789 
 1790   /// The id of the platform view, whose semantics nodes will be added as
 1791   /// children to this node.
 1792   ///
 1793   /// If this value is non-null, the SemanticsNode must not have any children
 1794   /// as those would be replaced by the semantics nodes of the referenced
 1795   /// platform view.
 1796   ///
 1797   /// See also:
 1798   ///
 1799   ///  * [AndroidView], which is the platform view for Android.
 1800   ///  * [UiKitView], which is the platform view for iOS.
 1801   int? get platformViewId => _platformViewId;
 1802   int? _platformViewId;
 1803 
 1804   /// The maximum number of characters that can be entered into an editable
 1805   /// text field.
 1806   ///
 1807   /// For the purpose of this function a character is defined as one Unicode
 1808   /// scalar value.
 1809   ///
 1810   /// This should only be set when [SemanticsFlag.isTextField] is set. Defaults
 1811   /// to null, which means no limit is imposed on the text field.
 1812   int? get maxValueLength => _maxValueLength;
 1813   int? _maxValueLength;
 1814 
 1815   /// The current number of characters that have been entered into an editable
 1816   /// text field.
 1817   ///
 1818   /// For the purpose of this function a character is defined as one Unicode
 1819   /// scalar value.
 1820   ///
 1821   /// This should only be set when [SemanticsFlag.isTextField] is set. Must be
 1822   /// set when [maxValueLength] is set.
 1823   int? get currentValueLength => _currentValueLength;
 1824   int? _currentValueLength;
 1825 
 1826   bool _canPerformAction(SemanticsAction action) => _actions.containsKey(action);
 1827 
 1828   static final SemanticsConfiguration _kEmptyConfig = SemanticsConfiguration();
 1829 
 1830   /// Reconfigures the properties of this object to describe the configuration
 1831   /// provided in the `config` argument and the children listed in the
 1832   /// `childrenInInversePaintOrder` argument.
 1833   ///
 1834   /// The arguments may be null; this represents an empty configuration (all
 1835   /// values at their defaults, no children).
 1836   ///
 1837   /// No reference is kept to the [SemanticsConfiguration] object, but the child
 1838   /// list is used as-is and should therefore not be changed after this call.
 1839   void updateWith({
 1840     required SemanticsConfiguration? config,
 1841     List<SemanticsNode>? childrenInInversePaintOrder,
 1842   }) {
 1843     config ??= _kEmptyConfig;
 1844     if (_isDifferentFromCurrentSemanticAnnotation(config))
 1845       _markDirty();
 1846 
 1847     assert(
 1848       config.platformViewId == null || childrenInInversePaintOrder == null || childrenInInversePaintOrder.isEmpty,
 1849       'SemanticsNodes with children must not specify a platformViewId.'
 1850     );
 1851 
 1852     _label = config.label;
 1853     _decreasedValue = config.decreasedValue;
 1854     _value = config.value;
 1855     _increasedValue = config.increasedValue;
 1856     _hint = config.hint;
 1857     _hintOverrides = config.hintOverrides;
 1858     _elevation = config.elevation;
 1859     _thickness = config.thickness;
 1860     _flags = config._flags;
 1861     _textDirection = config.textDirection;
 1862     _sortKey = config.sortKey;
 1863     _actions = Map<SemanticsAction, _SemanticsActionHandler>.from(config._actions);
 1864     _customSemanticsActions = Map<CustomSemanticsAction, VoidCallback>.from(config._customSemanticsActions);
 1865     _actionsAsBits = config._actionsAsBits;
 1866     _textSelection = config._textSelection;
 1867     _isMultiline = config.isMultiline;
 1868     _scrollPosition = config._scrollPosition;
 1869     _scrollExtentMax = config._scrollExtentMax;
 1870     _scrollExtentMin = config._scrollExtentMin;
 1871     _mergeAllDescendantsIntoThisNode = config.isMergingSemanticsOfDescendants;
 1872     _scrollChildCount = config.scrollChildCount;
 1873     _scrollIndex = config.scrollIndex;
 1874     indexInParent = config.indexInParent;
 1875     _platformViewId = config._platformViewId;
 1876     _maxValueLength = config._maxValueLength;
 1877     _currentValueLength = config._currentValueLength;
 1878     _replaceChildren(childrenInInversePaintOrder ?? const <SemanticsNode>[]);
 1879 
 1880     assert(
 1881       !_canPerformAction(SemanticsAction.increase) || (_value == '') == (_increasedValue == ''),
 1882       'A SemanticsNode with action "increase" needs to be annotated with either both "value" and "increasedValue" or neither',
 1883     );
 1884     assert(
 1885       !_canPerformAction(SemanticsAction.decrease) || (_value == '') == (_decreasedValue == ''),
 1886       'A SemanticsNode with action "increase" needs to be annotated with either both "value" and "decreasedValue" or neither',
 1887     );
 1888   }
 1889 
 1890 
 1891   /// Returns a summary of the semantics for this node.
 1892   ///
 1893   /// If this node has [mergeAllDescendantsIntoThisNode], then the returned data
 1894   /// includes the information from this node's descendants. Otherwise, the
 1895   /// returned data matches the data on this node.
 1896   SemanticsData getSemanticsData() {
 1897     int flags = _flags;
 1898     int actions = _actionsAsBits;
 1899     String label = _label;
 1900     String hint = _hint;
 1901     String value = _value;
 1902     String increasedValue = _increasedValue;
 1903     String decreasedValue = _decreasedValue;
 1904     TextDirection? textDirection = _textDirection;
 1905     Set<SemanticsTag>? mergedTags = tags == null ? null : Set<SemanticsTag>.from(tags!);
 1906     TextSelection? textSelection = _textSelection;
 1907     int? scrollChildCount = _scrollChildCount;
 1908     int? scrollIndex = _scrollIndex;
 1909     double? scrollPosition = _scrollPosition;
 1910     double? scrollExtentMax = _scrollExtentMax;
 1911     double? scrollExtentMin = _scrollExtentMin;
 1912     int? platformViewId = _platformViewId;
 1913     int? maxValueLength = _maxValueLength;
 1914     int? currentValueLength = _currentValueLength;
 1915     final double elevation = _elevation;
 1916     double thickness = _thickness;
 1917     final Set<int> customSemanticsActionIds = <int>{};
 1918     for (final CustomSemanticsAction action in _customSemanticsActions.keys)
 1919       customSemanticsActionIds.add(CustomSemanticsAction.getIdentifier(action));
 1920     if (hintOverrides != null) {
 1921       if (hintOverrides!.onTapHint != null) {
 1922         final CustomSemanticsAction action = CustomSemanticsAction.overridingAction(
 1923           hint: hintOverrides!.onTapHint!,
 1924           action: SemanticsAction.tap,
 1925         );
 1926         customSemanticsActionIds.add(CustomSemanticsAction.getIdentifier(action));
 1927       }
 1928       if (hintOverrides!.onLongPressHint != null) {
 1929         final CustomSemanticsAction action = CustomSemanticsAction.overridingAction(
 1930           hint: hintOverrides!.onLongPressHint!,
 1931           action: SemanticsAction.longPress,
 1932         );
 1933         customSemanticsActionIds.add(CustomSemanticsAction.getIdentifier(action));
 1934       }
 1935     }
 1936 
 1937     if (mergeAllDescendantsIntoThisNode) {
 1938       _visitDescendants((SemanticsNode node) {
 1939         assert(node.isMergedIntoParent);
 1940         flags |= node._flags;
 1941         actions |= node._actionsAsBits;
 1942         textDirection ??= node._textDirection;
 1943         textSelection ??= node._textSelection;
 1944         scrollChildCount ??= node._scrollChildCount;
 1945         scrollIndex ??= node._scrollIndex;
 1946         scrollPosition ??= node._scrollPosition;
 1947         scrollExtentMax ??= node._scrollExtentMax;
 1948         scrollExtentMin ??= node._scrollExtentMin;
 1949         platformViewId ??= node._platformViewId;
 1950         maxValueLength ??= node._maxValueLength;
 1951         currentValueLength ??= node._currentValueLength;
 1952         if (value == '' || value == null)
 1953           value = node._value;
 1954         if (increasedValue == '' || increasedValue == null)
 1955           increasedValue = node._increasedValue;
 1956         if (decreasedValue == '' || decreasedValue == null)
 1957           decreasedValue = node._decreasedValue;
 1958         if (node.tags != null) {
 1959           mergedTags ??= <SemanticsTag>{};
 1960           mergedTags!.addAll(node.tags!);
 1961         }
 1962         if (node._customSemanticsActions != null) {
 1963           for (final CustomSemanticsAction action in _customSemanticsActions.keys)
 1964             customSemanticsActionIds.add(CustomSemanticsAction.getIdentifier(action));
 1965         }
 1966         if (node.hintOverrides != null) {
 1967           if (node.hintOverrides!.onTapHint != null) {
 1968             final CustomSemanticsAction action = CustomSemanticsAction.overridingAction(
 1969               hint: node.hintOverrides!.onTapHint!,
 1970               action: SemanticsAction.tap,
 1971             );
 1972             customSemanticsActionIds.add(CustomSemanticsAction.getIdentifier(action));
 1973           }
 1974           if (node.hintOverrides!.onLongPressHint != null) {
 1975             final CustomSemanticsAction action = CustomSemanticsAction.overridingAction(
 1976               hint: node.hintOverrides!.onLongPressHint!,
 1977               action: SemanticsAction.longPress,
 1978             );
 1979             customSemanticsActionIds.add(CustomSemanticsAction.getIdentifier(action));
 1980           }
 1981         }
 1982         label = _concatStrings(
 1983           thisString: label,
 1984           thisTextDirection: textDirection,
 1985           otherString: node._label,
 1986           otherTextDirection: node._textDirection,
 1987         );
 1988         hint = _concatStrings(
 1989           thisString: hint,
 1990           thisTextDirection: textDirection,
 1991           otherString: node._hint,
 1992           otherTextDirection: node._textDirection,
 1993         );
 1994 
 1995         thickness = math.max(thickness, node._thickness + node._elevation);
 1996 
 1997         return true;
 1998       });
 1999     }
 2000 
 2001     return SemanticsData(
 2002       flags: flags,
 2003       actions: actions,
 2004       label: label,
 2005       value: value,
 2006       increasedValue: increasedValue,
 2007       decreasedValue: decreasedValue,
 2008       hint: hint,
 2009       textDirection: textDirection,
 2010       rect: rect,
 2011       transform: transform,
 2012       elevation: elevation,
 2013       thickness: thickness,
 2014       tags: mergedTags,
 2015       textSelection: textSelection,
 2016       scrollChildCount: scrollChildCount,
 2017       scrollIndex: scrollIndex,
 2018       scrollPosition: scrollPosition,
 2019       scrollExtentMax: scrollExtentMax,
 2020       scrollExtentMin: scrollExtentMin,
 2021       platformViewId: platformViewId,
 2022       maxValueLength: maxValueLength,
 2023       currentValueLength: currentValueLength,
 2024       customSemanticsActionIds: customSemanticsActionIds.toList()..sort(),
 2025     );
 2026   }
 2027 
 2028   static Float64List _initIdentityTransform() {
 2029     return Matrix4.identity().storage;
 2030   }
 2031 
 2032   static final Int32List _kEmptyChildList = Int32List(0);
 2033   static final Int32List _kEmptyCustomSemanticsActionsList = Int32List(0);
 2034   static final Float64List _kIdentityTransform = _initIdentityTransform();
 2035 
 2036   void _addToUpdate(ui.SemanticsUpdateBuilder builder, Set<int> customSemanticsActionIdsUpdate) {
 2037     assert(_dirty);
 2038     final SemanticsData data = getSemanticsData();
 2039     Int32List childrenInTraversalOrder;
 2040     Int32List childrenInHitTestOrder;
 2041     if (!hasChildren || mergeAllDescendantsIntoThisNode) {
 2042       childrenInTraversalOrder = _kEmptyChildList;
 2043       childrenInHitTestOrder = _kEmptyChildList;
 2044     } else {
 2045       final int childCount = _children!.length;
 2046       final List<SemanticsNode> sortedChildren = _childrenInTraversalOrder();
 2047       childrenInTraversalOrder = Int32List(childCount);
 2048       for (int i = 0; i < childCount; i += 1) {
 2049         childrenInTraversalOrder[i] = sortedChildren[i].id;
 2050       }
 2051       // _children is sorted in paint order, so we invert it to get the hit test
 2052       // order.
 2053       childrenInHitTestOrder = Int32List(childCount);
 2054       for (int i = childCount - 1; i >= 0; i -= 1) {
 2055         childrenInHitTestOrder[i] = _children![childCount - i - 1].id;
 2056       }
 2057     }
 2058     Int32List? customSemanticsActionIds;
 2059     if (data.customSemanticsActionIds?.isNotEmpty == true) {
 2060       customSemanticsActionIds = Int32List(data.customSemanticsActionIds!.length);
 2061       for (int i = 0; i < data.customSemanticsActionIds!.length; i++) {
 2062         customSemanticsActionIds[i] = data.customSemanticsActionIds![i];
 2063         customSemanticsActionIdsUpdate.add(data.customSemanticsActionIds![i]);
 2064       }
 2065     }
 2066     builder.updateNode(
 2067       id: id,
 2068       flags: data.flags,
 2069       actions: data.actions,
 2070       rect: data.rect,
 2071       label: data.label,
 2072       value: data.value,
 2073       decreasedValue: data.decreasedValue,
 2074       increasedValue: data.increasedValue,
 2075       hint: data.hint,
 2076       textDirection: data.textDirection,
 2077       textSelectionBase: data.textSelection != null ? data.textSelection!.baseOffset : -1,
 2078       textSelectionExtent: data.textSelection != null ? data.textSelection!.extentOffset : -1,
 2079       platformViewId: data.platformViewId ?? -1,
 2080       maxValueLength: data.maxValueLength ?? -1,
 2081       currentValueLength: data.currentValueLength ?? -1,
 2082       scrollChildren: data.scrollChildCount ?? 0,
 2083       scrollIndex: data.scrollIndex ?? 0 ,
 2084       scrollPosition: data.scrollPosition ?? double.nan,
 2085       scrollExtentMax: data.scrollExtentMax ?? double.nan,
 2086       scrollExtentMin: data.scrollExtentMin ?? double.nan,
 2087       transform: data.transform?.storage ?? _kIdentityTransform,
 2088       elevation: data.elevation,
 2089       thickness: data.thickness,
 2090       childrenInTraversalOrder: childrenInTraversalOrder,
 2091       childrenInHitTestOrder: childrenInHitTestOrder,
 2092       additionalActions: customSemanticsActionIds ?? _kEmptyCustomSemanticsActionsList,
 2093     );
 2094     _dirty = false;
 2095   }
 2096 
 2097   /// Builds a new list made of [_children] sorted in semantic traversal order.
 2098   List<SemanticsNode> _childrenInTraversalOrder() {
 2099     TextDirection? inheritedTextDirection = textDirection;
 2100     SemanticsNode? ancestor = parent;
 2101     while (inheritedTextDirection == null && ancestor != null) {
 2102       inheritedTextDirection = ancestor.textDirection;
 2103       ancestor = ancestor.parent;
 2104     }
 2105 
 2106     List<SemanticsNode>? childrenInDefaultOrder;
 2107     if (inheritedTextDirection != null) {
 2108       childrenInDefaultOrder = _childrenInDefaultOrder(_children!, inheritedTextDirection);
 2109     } else {
 2110       // In the absence of text direction default to paint order.
 2111       childrenInDefaultOrder = _children;
 2112     }
 2113 
 2114     // List.sort does not guarantee stable sort order. Therefore, children are
 2115     // first partitioned into groups that have compatible sort keys, i.e. keys
 2116     // in the same group can be compared to each other. These groups stay in
 2117     // the same place. Only children within the same group are sorted.
 2118     final List<_TraversalSortNode> everythingSorted = <_TraversalSortNode>[];
 2119     final List<_TraversalSortNode> sortNodes = <_TraversalSortNode>[];
 2120     SemanticsSortKey? lastSortKey;
 2121     for (int position = 0; position < childrenInDefaultOrder!.length; position += 1) {
 2122       final SemanticsNode child = childrenInDefaultOrder[position];
 2123       final SemanticsSortKey? sortKey = child.sortKey;
 2124       lastSortKey = position > 0
 2125           ? childrenInDefaultOrder[position - 1].sortKey
 2126           : null;
 2127       final bool isCompatibleWithPreviousSortKey = position == 0 ||
 2128           sortKey.runtimeType == lastSortKey.runtimeType &&
 2129           (sortKey == null || sortKey.name == lastSortKey!.name);
 2130       if (!isCompatibleWithPreviousSortKey && sortNodes.isNotEmpty) {
 2131         // Do not sort groups with null sort keys. List.sort does not guarantee
 2132         // a stable sort order.
 2133         if (lastSortKey != null) {
 2134           sortNodes.sort();
 2135         }
 2136         everythingSorted.addAll(sortNodes);
 2137         sortNodes.clear();
 2138       }
 2139 
 2140       sortNodes.add(_TraversalSortNode(
 2141         node: child,
 2142         sortKey: sortKey,
 2143         position: position,
 2144       ));
 2145     }
 2146 
 2147     // Do not sort groups with null sort keys. List.sort does not guarantee
 2148     // a stable sort order.
 2149     if (lastSortKey != null) {
 2150       sortNodes.sort();
 2151     }
 2152     everythingSorted.addAll(sortNodes);
 2153 
 2154     return everythingSorted
 2155       .map<SemanticsNode>((_TraversalSortNode sortNode) => sortNode.node)
 2156       .toList();
 2157   }
 2158 
 2159   /// Sends a [SemanticsEvent] associated with this [SemanticsNode].
 2160   ///
 2161   /// Semantics events should be sent to inform interested parties (like
 2162   /// the accessibility system of the operating system) about changes to the UI.
 2163   void sendEvent(SemanticsEvent event) {
 2164     if (!attached)
 2165       return;
 2166     SystemChannels.accessibility.send(event.toMap(nodeId: id));
 2167   }
 2168 
 2169   @override
 2170   String toStringShort() => '${objectRuntimeType(this, 'SemanticsNode')}#$id';
 2171 
 2172   @override
 2173   void debugFillProperties(DiagnosticPropertiesBuilder properties) {
 2174     super.debugFillProperties(properties);
 2175     bool hideOwner = true;
 2176     if (_dirty) {
 2177       final bool inDirtyNodes = owner != null && owner!._dirtyNodes.contains(this);
 2178       properties.add(FlagProperty('inDirtyNodes', value: inDirtyNodes, ifTrue: 'dirty', ifFalse: 'STALE'));
 2179       hideOwner = inDirtyNodes;
 2180     }
 2181     properties.add(DiagnosticsProperty<SemanticsOwner>('owner', owner, level: hideOwner ? DiagnosticLevel.hidden : DiagnosticLevel.info));
 2182     properties.add(FlagProperty('isMergedIntoParent', value: isMergedIntoParent, ifTrue: 'merged up ⬆️'));
 2183     properties.add(FlagProperty('mergeAllDescendantsIntoThisNode', value: mergeAllDescendantsIntoThisNode, ifTrue: 'merge boundary ⛔️'));
 2184     final Offset? offset = transform != null ? MatrixUtils.getAsTranslation(transform!) : null;
 2185     if (offset != null) {
 2186       properties.add(DiagnosticsProperty<Rect>('rect', rect.shift(offset), showName: false));
 2187     } else {
 2188       final double? scale = transform != null ? MatrixUtils.getAsScale(transform!) : null;
 2189       String? description;
 2190       if (scale != null) {
 2191         description = '$rect scaled by ${scale.toStringAsFixed(1)}x';
 2192       } else if (transform != null && !MatrixUtils.isIdentity(transform!)) {
 2193         final String matrix = transform.toString().split('\n').take(4).map<String>((String line) => line.substring(4)).join('; ');
 2194         description = '$rect with transform [$matrix]';
 2195       }
 2196       properties.add(DiagnosticsProperty<Rect>('rect', rect, description: description, showName: false));
 2197     }
 2198     properties.add(IterableProperty<String>('tags', tags?.map((SemanticsTag tag) => tag.name), defaultValue: null));
 2199     final List<String> actions = _actions.keys.map<String>((SemanticsAction action) => describeEnum(action)).toList()..sort();
 2200     final List<String?> customSemanticsActions = _customSemanticsActions.keys
 2201       .map<String?>((CustomSemanticsAction action) => action.label)
 2202       .toList();
 2203     properties.add(IterableProperty<String>('actions', actions, ifEmpty: null));
 2204     properties.add(IterableProperty<String?>('customActions', customSemanticsActions, ifEmpty: null));
 2205     final List<String> flags = SemanticsFlag.values.values.where((SemanticsFlag flag) => hasFlag(flag)).map((SemanticsFlag flag) => flag.toString().substring('SemanticsFlag.'.length)).toList();
 2206     properties.add(IterableProperty<String>('flags', flags, ifEmpty: null));
 2207     properties.add(FlagProperty('isInvisible', value: isInvisible, ifTrue: 'invisible'));
 2208     properties.add(FlagProperty('isHidden', value: hasFlag(SemanticsFlag.isHidden), ifTrue: 'HIDDEN'));
 2209     properties.add(StringProperty('label', _label, defaultValue: ''));
 2210     properties.add(StringProperty('value', _value, defaultValue: ''));
 2211     properties.add(StringProperty('increasedValue', _increasedValue, defaultValue: ''));
 2212     properties.add(StringProperty('decreasedValue', _decreasedValue, defaultValue: ''));
 2213     properties.add(StringProperty('hint', _hint, defaultValue: ''));
 2214     properties.add(EnumProperty<TextDirection>('textDirection', _textDirection, defaultValue: null));
 2215     properties.add(DiagnosticsProperty<SemanticsSortKey>('sortKey', sortKey, defaultValue: null));
 2216     if (_textSelection?.isValid == true)
 2217       properties.add(MessageProperty('text selection', '[${_textSelection!.start}, ${_textSelection!.end}]'));
 2218     properties.add(IntProperty('platformViewId', platformViewId, defaultValue: null));
 2219     properties.add(IntProperty('maxValueLength', maxValueLength, defaultValue: null));
 2220     properties.add(IntProperty('currentValueLength', currentValueLength, defaultValue: null));
 2221     properties.add(IntProperty('scrollChildren', scrollChildCount, defaultValue: null));
 2222     properties.add(IntProperty('scrollIndex', scrollIndex, defaultValue: null));
 2223     properties.add(DoubleProperty('scrollExtentMin', scrollExtentMin, defaultValue: null));
 2224     properties.add(DoubleProperty('scrollPosition', scrollPosition, defaultValue: null));
 2225     properties.add(DoubleProperty('scrollExtentMax', scrollExtentMax, defaultValue: null));
 2226     properties.add(DoubleProperty('elevation', elevation, defaultValue: 0.0));
 2227     properties.add(DoubleProperty('thickness', thickness, defaultValue: 0.0));
 2228   }
 2229 
 2230   /// Returns a string representation of this node and its descendants.
 2231   ///
 2232   /// The order in which the children of the [SemanticsNode] will be printed is
 2233   /// controlled by the [childOrder] parameter.
 2234   @override
 2235   String toStringDeep({
 2236     String prefixLineOne = '',
 2237     String? prefixOtherLines,
 2238     DiagnosticLevel minLevel = DiagnosticLevel.debug,
 2239     DebugSemanticsDumpOrder childOrder = DebugSemanticsDumpOrder.traversalOrder,
 2240   }) {
 2241     assert(childOrder != null);
 2242     return toDiagnosticsNode(childOrder: childOrder).toStringDeep(prefixLineOne: prefixLineOne, prefixOtherLines: prefixOtherLines, minLevel: minLevel);
 2243   }
 2244 
 2245   @override
 2246   DiagnosticsNode toDiagnosticsNode({
 2247     String? name,
 2248     DiagnosticsTreeStyle? style = DiagnosticsTreeStyle.sparse,
 2249     DebugSemanticsDumpOrder childOrder = DebugSemanticsDumpOrder.traversalOrder,
 2250   }) {
 2251     return _SemanticsDiagnosticableNode(
 2252       name: name,
 2253       value: this,
 2254       style: style,
 2255       childOrder: childOrder,
 2256     );
 2257   }
 2258 
 2259   @override
 2260   List<DiagnosticsNode> debugDescribeChildren({ DebugSemanticsDumpOrder childOrder = DebugSemanticsDumpOrder.inverseHitTest }) {
 2261     return debugListChildrenInOrder(childOrder)
 2262       .map<DiagnosticsNode>((SemanticsNode node) => node.toDiagnosticsNode(childOrder: childOrder))
 2263       .toList();
 2264   }
 2265 
 2266   /// Returns the list of direct children of this node in the specified order.
 2267   List<SemanticsNode> debugListChildrenInOrder(DebugSemanticsDumpOrder childOrder) {
 2268     assert(childOrder != null);
 2269     if (_children == null)
 2270       return const <SemanticsNode>[];
 2271 
 2272     switch (childOrder) {
 2273       case DebugSemanticsDumpOrder.inverseHitTest:
 2274         return _children!;
 2275       case DebugSemanticsDumpOrder.traversalOrder:
 2276         return _childrenInTraversalOrder();
 2277     }
 2278   }
 2279 }
 2280 
 2281 /// An edge of a box, such as top, bottom, left or right, used to compute
 2282 /// [SemanticsNode]s that overlap vertically or horizontally.
 2283 ///
 2284 /// For computing horizontal overlap in an LTR setting we create two [_BoxEdge]
 2285 /// objects for each [SemanticsNode]: one representing the left edge (marked
 2286 /// with [isLeadingEdge] equal to true) and one for the right edge (with [isLeadingEdge]
 2287 /// equal to false). Similarly, for vertical overlap we also create two objects
 2288 /// for each [SemanticsNode], one for the top and one for the bottom edge.
 2289 class _BoxEdge implements Comparable<_BoxEdge> {
 2290   _BoxEdge({
 2291     required this.isLeadingEdge,
 2292     required this.offset,
 2293     required this.node,
 2294   }) : assert(isLeadingEdge != null),
 2295        assert(offset != null),
 2296        assert(offset.isFinite),
 2297        assert(node != null);
 2298 
 2299   /// True if the edge comes before the seconds edge along the traversal
 2300   /// direction, and false otherwise.
 2301   ///
 2302   /// This field is never null.
 2303   ///
 2304   /// For example, in LTR traversal the left edge's [isLeadingEdge] is set to true,
 2305   /// the right edge's [isLeadingEdge] is set to false. When considering vertical
 2306   /// ordering of boxes, the top edge is the start edge, and the bottom edge is
 2307   /// the end edge.
 2308   final bool isLeadingEdge;
 2309 
 2310   /// The offset from the start edge of the parent [SemanticsNode] in the
 2311   /// direction of the traversal.
 2312   final double offset;
 2313 
 2314   /// The node whom this edge belongs.
 2315   final SemanticsNode node;
 2316 
 2317   @override
 2318   int compareTo(_BoxEdge other) {
 2319     return (offset - other.offset).sign.toInt();
 2320   }
 2321 }
 2322 
 2323 /// A group of [nodes] that are disjoint vertically or horizontally from other
 2324 /// nodes that share the same [SemanticsNode] parent.
 2325 ///
 2326 /// The [nodes] are sorted among each other separately from other nodes.
 2327 class _SemanticsSortGroup extends Comparable<_SemanticsSortGroup> {
 2328   _SemanticsSortGroup({
 2329     required this.startOffset,
 2330     required this.textDirection,
 2331   }) : assert(startOffset != null);
 2332 
 2333   /// The offset from the start edge of the parent [SemanticsNode] in the
 2334   /// direction of the traversal.
 2335   ///
 2336   /// This value is equal to the [_BoxEdge.offset] of the first node in the
 2337   /// [nodes] list being considered.
 2338   final double startOffset;
 2339 
 2340   final TextDirection textDirection;
 2341 
 2342   /// The nodes that are sorted among each other.
 2343   final List<SemanticsNode> nodes = <SemanticsNode>[];
 2344 
 2345   @override
 2346   int compareTo(_SemanticsSortGroup other) {
 2347     return (startOffset - other.startOffset).sign.toInt();
 2348   }
 2349 
 2350   /// Sorts this group assuming that [nodes] belong to the same vertical group.
 2351   ///
 2352   /// This method breaks up this group into horizontal [_SemanticsSortGroup]s
 2353   /// then sorts them using [sortedWithinKnot].
 2354   List<SemanticsNode> sortedWithinVerticalGroup() {
 2355     final List<_BoxEdge> edges = <_BoxEdge>[];
 2356     for (final SemanticsNode child in nodes) {
 2357       // Using a small delta to shrink child rects removes overlapping cases.
 2358       final Rect childRect = child.rect.deflate(0.1);
 2359       edges.add(_BoxEdge(
 2360         isLeadingEdge: true,
 2361         offset: _pointInParentCoordinates(child, childRect.topLeft).dx,
 2362         node: child,
 2363       ));
 2364       edges.add(_BoxEdge(
 2365         isLeadingEdge: false,
 2366         offset: _pointInParentCoordinates(child, childRect.bottomRight).dx,
 2367         node: child,
 2368       ));
 2369     }
 2370     edges.sort();
 2371 
 2372     List<_SemanticsSortGroup> horizontalGroups = <_SemanticsSortGroup>[];
 2373     _SemanticsSortGroup? group;
 2374     int depth = 0;
 2375     for (final _BoxEdge edge in edges) {
 2376       if (edge.isLeadingEdge) {
 2377         depth += 1;
 2378         group ??= _SemanticsSortGroup(
 2379           startOffset: edge.offset,
 2380           textDirection: textDirection,
 2381         );
 2382         group.nodes.add(edge.node);
 2383       } else {
 2384         depth -= 1;
 2385       }
 2386       if (depth == 0) {
 2387         horizontalGroups.add(group!);
 2388         group = null;
 2389       }
 2390     }
 2391     horizontalGroups.sort();
 2392 
 2393     if (textDirection == TextDirection.rtl) {
 2394       horizontalGroups = horizontalGroups.reversed.toList();
 2395     }
 2396 
 2397     return horizontalGroups
 2398       .expand((_SemanticsSortGroup group) => group.sortedWithinKnot())
 2399       .toList();
 2400   }
 2401 
 2402   /// Sorts [nodes] where nodes intersect both vertically and horizontally.
 2403   ///
 2404   /// In the special case when [nodes] contains one or less nodes, this method
 2405   /// returns [nodes] unchanged.
 2406   ///
 2407   /// This method constructs a graph, where vertices are [SemanticsNode]s and
 2408   /// edges are "traversed before" relation between pairs of nodes. The sort
 2409   /// order is the topological sorting of the graph, with the original order of
 2410   /// [nodes] used as the tie breaker.
 2411   ///
 2412   /// Whether a node is traversed before another node is determined by the
 2413   /// vector that connects the two nodes' centers. If the vector "points to the
 2414   /// right or down", defined as the [Offset.direction] being between `-pi/4`
 2415   /// and `3*pi/4`), then the semantics node whose center is at the end of the
 2416   /// vector is said to be traversed after.
 2417   List<SemanticsNode> sortedWithinKnot() {
 2418     if (nodes.length <= 1) {
 2419       // Trivial knot. Nothing to do.
 2420       return nodes;
 2421     }
 2422     final Map<int, SemanticsNode> nodeMap = <int, SemanticsNode>{};
 2423     final Map<int, int> edges = <int, int>{};
 2424     for (final SemanticsNode node in nodes) {
 2425       nodeMap[node.id] = node;
 2426       final Offset center = _pointInParentCoordinates(node, node.rect.center);
 2427       for (final SemanticsNode nextNode in nodes) {
 2428         if (identical(node, nextNode) || edges[nextNode.id] == node.id) {
 2429           // Skip self or when we've already established that the next node
 2430           // points to current node.
 2431           continue;
 2432         }
 2433 
 2434         final Offset nextCenter = _pointInParentCoordinates(nextNode, nextNode.rect.center);
 2435         final Offset centerDelta = nextCenter - center;
 2436         // When centers coincide, direction is 0.0.
 2437         final double direction = centerDelta.direction;
 2438         final bool isLtrAndForward = textDirection == TextDirection.ltr &&
 2439             -math.pi / 4 < direction && direction < 3 * math.pi / 4;
 2440         final bool isRtlAndForward = textDirection == TextDirection.rtl &&
 2441             (direction < -3 * math.pi / 4 || direction > 3 * math.pi / 4);
 2442         if (isLtrAndForward || isRtlAndForward) {
 2443           edges[node.id] = nextNode.id;
 2444         }
 2445       }
 2446     }
 2447 
 2448     final List<int> sortedIds = <int>[];
 2449     final Set<int> visitedIds = <int>{};
 2450     final List<SemanticsNode> startNodes = nodes.toList()..sort((SemanticsNode a, SemanticsNode b) {
 2451       final Offset aTopLeft = _pointInParentCoordinates(a, a.rect.topLeft);
 2452       final Offset bTopLeft = _pointInParentCoordinates(b, b.rect.topLeft);
 2453       final int verticalDiff = aTopLeft.dy.compareTo(bTopLeft.dy);
 2454       if (verticalDiff != 0) {
 2455         return -verticalDiff;
 2456       }
 2457       return -aTopLeft.dx.compareTo(bTopLeft.dx);
 2458     });
 2459 
 2460     void search(int id) {
 2461       if (visitedIds.contains(id)) {
 2462         return;
 2463       }
 2464       visitedIds.add(id);
 2465       if (edges.containsKey(id)) {
 2466         search(edges[id]!);
 2467       }
 2468       sortedIds.add(id);
 2469     }
 2470 
 2471     startNodes.map<int>((SemanticsNode node) => node.id).forEach(search);
 2472     return sortedIds.map<SemanticsNode>((int id) => nodeMap[id]!).toList().reversed.toList();
 2473   }
 2474 }
 2475 
 2476 /// Converts `point` to the `node`'s parent's coordinate system.
 2477 Offset _pointInParentCoordinates(SemanticsNode node, Offset point) {
 2478   if (node.transform == null) {
 2479     return point;
 2480   }
 2481   final Vector3 vector = Vector3(point.dx, point.dy, 0.0);
 2482   node.transform!.transform3(vector);
 2483   return Offset(vector.x, vector.y);
 2484 }
 2485 
 2486 /// Sorts `children` using the default sorting algorithm, and returns them as a
 2487 /// new list.
 2488 ///
 2489 /// The algorithm first breaks up children into groups such that no two nodes
 2490 /// from different groups overlap vertically. These groups are sorted vertically
 2491 /// according to their [_SemanticsSortGroup.startOffset].
 2492 ///
 2493 /// Within each group, the nodes are sorted using
 2494 /// [_SemanticsSortGroup.sortedWithinVerticalGroup].
 2495 ///
 2496 /// For an illustration of the algorithm see http://bit.ly/flutter-default-traversal.
 2497 List<SemanticsNode> _childrenInDefaultOrder(List<SemanticsNode> children, TextDirection textDirection) {
 2498   final List<_BoxEdge> edges = <_BoxEdge>[];
 2499   for (final SemanticsNode child in children) {
 2500     assert(child.rect.isFinite);
 2501     // Using a small delta to shrink child rects removes overlapping cases.
 2502     final Rect childRect = child.rect.deflate(0.1);
 2503     edges.add(_BoxEdge(
 2504       isLeadingEdge: true,
 2505       offset: _pointInParentCoordinates(child, childRect.topLeft).dy,
 2506       node: child,
 2507     ));
 2508     edges.add(_BoxEdge(
 2509       isLeadingEdge: false,
 2510       offset: _pointInParentCoordinates(child, childRect.bottomRight).dy,
 2511       node: child,
 2512     ));
 2513   }
 2514   edges.sort();
 2515 
 2516   final List<_SemanticsSortGroup> verticalGroups = <_SemanticsSortGroup>[];
 2517   _SemanticsSortGroup? group;
 2518   int depth = 0;
 2519   for (final _BoxEdge edge in edges) {
 2520     if (edge.isLeadingEdge) {
 2521       depth += 1;
 2522       group ??= _SemanticsSortGroup(
 2523         startOffset: edge.offset,
 2524         textDirection: textDirection,
 2525       );
 2526       group.nodes.add(edge.node);
 2527     } else {
 2528       depth -= 1;
 2529     }
 2530     if (depth == 0) {
 2531       verticalGroups.add(group!);
 2532       group = null;
 2533     }
 2534   }
 2535   verticalGroups.sort();
 2536 
 2537   return verticalGroups
 2538     .expand((_SemanticsSortGroup group) => group.sortedWithinVerticalGroup())
 2539     .toList();
 2540 }
 2541 
 2542 /// The implementation of [Comparable] that implements the ordering of
 2543 /// [SemanticsNode]s in the accessibility traversal.
 2544 ///
 2545 /// [SemanticsNode]s are sorted prior to sending them to the engine side.
 2546 ///
 2547 /// This implementation considers a [node]'s [sortKey] and its position within
 2548 /// the list of its siblings. [sortKey] takes precedence over position.
 2549 class _TraversalSortNode implements Comparable<_TraversalSortNode> {
 2550   _TraversalSortNode({
 2551     required this.node,
 2552     this.sortKey,
 2553     required this.position,
 2554   })
 2555     : assert(node != null),
 2556       assert(position != null);
 2557 
 2558   /// The node whose position this sort node determines.
 2559   final SemanticsNode node;
 2560 
 2561   /// Determines the position of this node among its siblings.
 2562   ///
 2563   /// Sort keys take precedence over other attributes, such as
 2564   /// [position].
 2565   final SemanticsSortKey? sortKey;
 2566 
 2567   /// Position within the list of siblings as determined by the default sort
 2568   /// order.
 2569   final int position;
 2570 
 2571   @override
 2572   int compareTo(_TraversalSortNode other) {
 2573     if (sortKey == null || other.sortKey == null) {
 2574       return position - other.position;
 2575     }
 2576     return sortKey!.compareTo(other.sortKey!);
 2577   }
 2578 }
 2579 
 2580 /// Owns [SemanticsNode] objects and notifies listeners of changes to the
 2581 /// render tree semantics.
 2582 ///
 2583 /// To listen for semantic updates, call [PipelineOwner.ensureSemantics] to
 2584 /// obtain a [SemanticsHandle]. This will create a [SemanticsOwner] if
 2585 /// necessary.
 2586 class SemanticsOwner extends ChangeNotifier {
 2587   final Set<SemanticsNode> _dirtyNodes = <SemanticsNode>{};
 2588   final Map<int, SemanticsNode> _nodes = <int, SemanticsNode>{};
 2589   final Set<SemanticsNode> _detachedNodes = <SemanticsNode>{};
 2590 
 2591   /// The root node of the semantics tree, if any.
 2592   ///
 2593   /// If the semantics tree is empty, returns null.
 2594   SemanticsNode? get rootSemanticsNode => _nodes[0];
 2595 
 2596   @override
 2597   void dispose() {
 2598     _dirtyNodes.clear();
 2599     _nodes.clear();
 2600     _detachedNodes.clear();
 2601     super.dispose();
 2602   }
 2603 
 2604   /// Update the semantics using [Window.updateSemantics].
 2605   void sendSemanticsUpdate() {
 2606     if (_dirtyNodes.isEmpty)
 2607       return;
 2608     final Set<int> customSemanticsActionIds = <int>{};
 2609     final List<SemanticsNode> visitedNodes = <SemanticsNode>[];
 2610     while (_dirtyNodes.isNotEmpty) {
 2611       final List<SemanticsNode> localDirtyNodes = _dirtyNodes.where((SemanticsNode node) => !_detachedNodes.contains(node)).toList();
 2612       _dirtyNodes.clear();
 2613       _detachedNodes.clear();
 2614       localDirtyNodes.sort((SemanticsNode a, SemanticsNode b) => a.depth - b.depth);
 2615       visitedNodes.addAll(localDirtyNodes);
 2616       for (final SemanticsNode node in localDirtyNodes) {
 2617         assert(node._dirty);
 2618         assert(node.parent == null || !node.parent!.isPartOfNodeMerging || node.isMergedIntoParent);
 2619         if (node.isPartOfNodeMerging) {
 2620           assert(node.mergeAllDescendantsIntoThisNode || node.parent != null);
 2621           // if we're merged into our parent, make sure our parent is added to the dirty list
 2622           if (node.parent != null && node.parent!.isPartOfNodeMerging) {
 2623             node.parent!._markDirty(); // this can add the node to the dirty list
 2624             node._dirty = false; // We don't want to send update for this node.
 2625           }
 2626         }
 2627       }
 2628     }
 2629     visitedNodes.sort((SemanticsNode a, SemanticsNode b) => a.depth - b.depth);
 2630     final ui.SemanticsUpdateBuilder builder = SemanticsBinding.instance!.createSemanticsUpdateBuilder();
 2631     for (final SemanticsNode node in visitedNodes) {
 2632       assert(node.parent?._dirty != true); // could be null (no parent) or false (not dirty)
 2633       // The _serialize() method marks the node as not dirty, and
 2634       // recurses through the tree to do a deep serialization of all
 2635       // contiguous dirty nodes. This means that when we return here,
 2636       // it's quite possible that subsequent nodes are no longer
 2637       // dirty. We skip these here.
 2638       // We also skip any nodes that were reset and subsequently
 2639       // dropped entirely (RenderObject.markNeedsSemanticsUpdate()
 2640       // calls reset() on its SemanticsNode if onlyChanges isn't set,
 2641       // which happens e.g. when the node is no longer contributing
 2642       // semantics).
 2643       if (node._dirty && node.attached)
 2644         node._addToUpdate(builder, customSemanticsActionIds);
 2645     }
 2646     _dirtyNodes.clear();
 2647     for (final int actionId in customSemanticsActionIds) {
 2648       final CustomSemanticsAction action = CustomSemanticsAction.getAction(actionId)!;
 2649       builder.updateCustomAction(id: actionId, label: action.label, hint: action.hint, overrideId: action.action?.index ?? -1);
 2650     }
 2651     SemanticsBinding.instance!.window.updateSemantics(builder.build());
 2652     notifyListeners();
 2653   }
 2654 
 2655   _SemanticsActionHandler? _getSemanticsActionHandlerForId(int id, SemanticsAction action) {
 2656     SemanticsNode? result = _nodes[id];
 2657     if (result != null && result.isPartOfNodeMerging && !result._canPerformAction(action)) {
 2658       result._visitDescendants((SemanticsNode node) {
 2659         if (node._canPerformAction(action)) {
 2660           result = node;
 2661           return false; // found node, abort walk
 2662         }
 2663         return true; // continue walk
 2664       });
 2665     }
 2666     if (result == null || !result!._canPerformAction(action))
 2667       return null;
 2668     return result!._actions[action];
 2669   }
 2670 
 2671   /// Asks the [SemanticsNode] with the given id to perform the given action.
 2672   ///
 2673   /// If the [SemanticsNode] has not indicated that it can perform the action,
 2674   /// this function does nothing.
 2675   ///
 2676   /// If the given `action` requires arguments they need to be passed in via
 2677   /// the `args` parameter.
 2678   void performAction(int id, SemanticsAction action, [ dynamic args ]) {
 2679     assert(action != null);
 2680     final _SemanticsActionHandler? handler = _getSemanticsActionHandlerForId(id, action);
 2681     if (handler != null) {
 2682       handler(args);
 2683       return;
 2684     }
 2685 
 2686     // Default actions if no [handler] was provided.
 2687     if (action == SemanticsAction.showOnScreen && _nodes[id]!._showOnScreen != null)
 2688       _nodes[id]!._showOnScreen!();
 2689   }
 2690 
 2691   _SemanticsActionHandler? _getSemanticsActionHandlerForPosition(SemanticsNode node, Offset position, SemanticsAction action) {
 2692     if (node.transform != null) {
 2693       final Matrix4 inverse = Matrix4.identity();
 2694       if (inverse.copyInverse(node.transform!) == 0.0)
 2695         return null;
 2696       position = MatrixUtils.transformPoint(inverse, position);
 2697     }
 2698     if (!node.rect.contains(position))
 2699       return null;
 2700     if (node.mergeAllDescendantsIntoThisNode) {
 2701       SemanticsNode? result;
 2702       node._visitDescendants((SemanticsNode child) {
 2703         if (child._canPerformAction(action)) {
 2704           result = child;
 2705           return false;
 2706         }
 2707         return true;
 2708       });
 2709       return result?._actions[action];
 2710     }
 2711     if (node.hasChildren) {
 2712       for (final SemanticsNode child in node._children!.reversed) {
 2713         final _SemanticsActionHandler? handler = _getSemanticsActionHandlerForPosition(child, position, action);
 2714         if (handler != null)
 2715           return handler;
 2716       }
 2717     }
 2718     return node._actions[action];
 2719   }
 2720 
 2721   /// Asks the [SemanticsNode] at the given position to perform the given action.
 2722   ///
 2723   /// If the [SemanticsNode] has not indicated that it can perform the action,
 2724   /// this function does nothing.
 2725   ///
 2726   /// If the given `action` requires arguments they need to be passed in via
 2727   /// the `args` parameter.
 2728   void performActionAt(Offset position, SemanticsAction action, [ dynamic args ]) {
 2729     assert(action != null);
 2730     final SemanticsNode? node = rootSemanticsNode;
 2731     if (node == null)
 2732       return;
 2733     final _SemanticsActionHandler? handler = _getSemanticsActionHandlerForPosition(node, position, action);
 2734     if (handler != null)
 2735       handler(args);
 2736   }
 2737 
 2738   @override
 2739   String toString() => describeIdentity(this);
 2740 }
 2741 
 2742 /// Describes the semantic information associated with the owning
 2743 /// [RenderObject].
 2744 ///
 2745 /// The information provided in the configuration is used to generate the
 2746 /// semantics tree.
 2747 class SemanticsConfiguration {
 2748 
 2749   // SEMANTIC BOUNDARY BEHAVIOR
 2750 
 2751   /// Whether the [RenderObject] owner of this configuration wants to own its
 2752   /// own [SemanticsNode].
 2753   ///
 2754   /// When set to true semantic information associated with the [RenderObject]
 2755   /// owner of this configuration or any of its descendants will not leak into
 2756   /// parents. The [SemanticsNode] generated out of this configuration will
 2757   /// act as a boundary.
 2758   ///
 2759   /// Whether descendants of the owning [RenderObject] can add their semantic
 2760   /// information to the [SemanticsNode] introduced by this configuration
 2761   /// is controlled by [explicitChildNodes].
 2762   ///
 2763   /// This has to be true if [isMergingSemanticsOfDescendants] is also true.
 2764   bool get isSemanticBoundary => _isSemanticBoundary;
 2765   bool _isSemanticBoundary = false;
 2766   set isSemanticBoundary(bool value) {
 2767     assert(!isMergingSemanticsOfDescendants || value);
 2768     _isSemanticBoundary = value;
 2769   }
 2770 
 2771   /// Whether the configuration forces all children of the owning [RenderObject]
 2772   /// that want to contribute semantic information to the semantics tree to do
 2773   /// so in the form of explicit [SemanticsNode]s.
 2774   ///
 2775   /// When set to false children of the owning [RenderObject] are allowed to
 2776   /// annotate [SemanticsNode]s of their parent with the semantic information
 2777   /// they want to contribute to the semantic tree.
 2778   /// When set to true the only way for children of the owning [RenderObject]
 2779   /// to contribute semantic information to the semantic tree is to introduce
 2780   /// new explicit [SemanticsNode]s to the tree.
 2781   ///
 2782   /// This setting is often used in combination with [isSemanticBoundary] to
 2783   /// create semantic boundaries that are either writable or not for children.
 2784   bool explicitChildNodes = false;
 2785 
 2786   /// Whether the owning [RenderObject] makes other [RenderObject]s previously
 2787   /// painted within the same semantic boundary unreachable for accessibility
 2788   /// purposes.
 2789   ///
 2790   /// If set to true, the semantic information for all siblings and cousins of
 2791   /// this node, that are earlier in a depth-first pre-order traversal, are
 2792   /// dropped from the semantics tree up until a semantic boundary (as defined
 2793   /// by [isSemanticBoundary]) is reached.
 2794   ///
 2795   /// If [isSemanticBoundary] and [isBlockingSemanticsOfPreviouslyPaintedNodes]
 2796   /// is set on the same node, all previously painted siblings and cousins up
 2797   /// until the next ancestor that is a semantic boundary are dropped.
 2798   ///
 2799   /// Paint order as established by [RenderObject.visitChildrenForSemantics] is
 2800   /// used to determine if a node is previous to this one.
 2801   bool isBlockingSemanticsOfPreviouslyPaintedNodes = false;
 2802 
 2803   // SEMANTIC ANNOTATIONS
 2804   // These will end up on [SemanticsNode]s generated from
 2805   // [SemanticsConfiguration]s.
 2806 
 2807   /// Whether this configuration is empty.
 2808   ///
 2809   /// An empty configuration doesn't contain any semantic information that it
 2810   /// wants to contribute to the semantics tree.
 2811   bool get hasBeenAnnotated => _hasBeenAnnotated;
 2812   bool _hasBeenAnnotated = false;
 2813 
 2814   /// The actions (with associated action handlers) that this configuration
 2815   /// would like to contribute to the semantics tree.
 2816   ///
 2817   /// See also:
 2818   ///
 2819   ///  * [addAction] to add an action.
 2820   final Map<SemanticsAction, _SemanticsActionHandler> _actions = <SemanticsAction, _SemanticsActionHandler>{};
 2821 
 2822   int _actionsAsBits = 0;
 2823 
 2824   /// Adds an `action` to the semantics tree.
 2825   ///
 2826   /// The provided `handler` is called to respond to the user triggered
 2827   /// `action`.
 2828   void _addAction(SemanticsAction action, _SemanticsActionHandler handler) {
 2829     assert(handler != null);
 2830     _actions[action] = handler;
 2831     _actionsAsBits |= action.index;
 2832     _hasBeenAnnotated = true;
 2833   }
 2834 
 2835   /// Adds an `action` to the semantics tree, whose `handler` does not expect
 2836   /// any arguments.
 2837   ///
 2838   /// The provided `handler` is called to respond to the user triggered
 2839   /// `action`.
 2840   void _addArgumentlessAction(SemanticsAction action, VoidCallback handler) {
 2841     assert(handler != null);
 2842     _addAction(action, (dynamic args) {
 2843       assert(args == null);
 2844       handler();
 2845     });
 2846   }
 2847 
 2848   /// The handler for [SemanticsAction.tap].
 2849   ///
 2850   /// This is the semantic equivalent of a user briefly tapping the screen with
 2851   /// the finger without moving it. For example, a button should implement this
 2852   /// action.
 2853   ///
 2854   /// VoiceOver users on iOS and TalkBack users on Android can trigger this
 2855   /// action by double-tapping the screen while an element is focused.
 2856   ///
 2857   /// On Android prior to Android Oreo a double-tap on the screen while an
 2858   /// element with an [onTap] handler is focused will not call the registered
 2859   /// handler. Instead, Android will simulate a pointer down and up event at the
 2860   /// center of the focused element. Those pointer events will get dispatched
 2861   /// just like a regular tap with TalkBack disabled would: The events will get
 2862   /// processed by any [GestureDetector] listening for gestures in the center of
 2863   /// the focused element. Therefore, to ensure that [onTap] handlers work
 2864   /// properly on Android versions prior to Oreo, a [GestureDetector] with an
 2865   /// onTap handler should always be wrapping an element that defines a
 2866   /// semantic [onTap] handler. By default a [GestureDetector] will register its
 2867   /// own semantic [onTap] handler that follows this principle.
 2868   VoidCallback? get onTap => _onTap;
 2869   VoidCallback? _onTap;
 2870   set onTap(VoidCallback? value) {
 2871     _addArgumentlessAction(SemanticsAction.tap, value!);
 2872     _onTap = value;
 2873   }
 2874 
 2875   /// The handler for [SemanticsAction.longPress].
 2876   ///
 2877   /// This is the semantic equivalent of a user pressing and holding the screen
 2878   /// with the finger for a few seconds without moving it.
 2879   ///
 2880   /// VoiceOver users on iOS and TalkBack users on Android can trigger this
 2881   /// action by double-tapping the screen without lifting the finger after the
 2882   /// second tap.
 2883   VoidCallback? get onLongPress => _onLongPress;
 2884   VoidCallback? _onLongPress;
 2885   set onLongPress(VoidCallback? value) {
 2886     _addArgumentlessAction(SemanticsAction.longPress, value!);
 2887     _onLongPress = value;
 2888   }
 2889 
 2890   /// The handler for [SemanticsAction.scrollLeft].
 2891   ///
 2892   /// This is the semantic equivalent of a user moving their finger across the
 2893   /// screen from right to left. It should be recognized by controls that are
 2894   /// horizontally scrollable.
 2895   ///
 2896   /// VoiceOver users on iOS can trigger this action by swiping left with three
 2897   /// fingers. TalkBack users on Android can trigger this action by swiping
 2898   /// right and then left in one motion path. On Android, [onScrollUp] and
 2899   /// [onScrollLeft] share the same gesture. Therefore, only on of them should
 2900   /// be provided.
 2901   VoidCallback? get onScrollLeft => _onScrollLeft;
 2902   VoidCallback? _onScrollLeft;
 2903   set onScrollLeft(VoidCallback? value) {
 2904     _addArgumentlessAction(SemanticsAction.scrollLeft, value!);
 2905     _onScrollLeft = value;
 2906   }
 2907 
 2908   /// The handler for [SemanticsAction.dismiss].
 2909   ///
 2910   /// This is a request to dismiss the currently focused node.
 2911   ///
 2912   /// TalkBack users on Android can trigger this action in the local context
 2913   /// menu, and VoiceOver users on iOS can trigger this action with a standard
 2914   /// gesture or menu option.
 2915   VoidCallback? get onDismiss => _onDismiss;
 2916   VoidCallback? _onDismiss;
 2917   set onDismiss(VoidCallback? value) {
 2918     _addArgumentlessAction(SemanticsAction.dismiss, value!);
 2919     _onDismiss = value;
 2920   }
 2921 
 2922   /// The handler for [SemanticsAction.scrollRight].
 2923   ///
 2924   /// This is the semantic equivalent of a user moving their finger across the
 2925   /// screen from left to right. It should be recognized by controls that are
 2926   /// horizontally scrollable.
 2927   ///
 2928   /// VoiceOver users on iOS can trigger this action by swiping right with three
 2929   /// fingers. TalkBack users on Android can trigger this action by swiping
 2930   /// left and then right in one motion path. On Android, [onScrollDown] and
 2931   /// [onScrollRight] share the same gesture. Therefore, only on of them should
 2932   /// be provided.
 2933   VoidCallback? get onScrollRight => _onScrollRight;
 2934   VoidCallback? _onScrollRight;
 2935   set onScrollRight(VoidCallback? value) {
 2936     _addArgumentlessAction(SemanticsAction.scrollRight, value!);
 2937     _onScrollRight = value;
 2938   }
 2939 
 2940   /// The handler for [SemanticsAction.scrollUp].
 2941   ///
 2942   /// This is the semantic equivalent of a user moving their finger across the
 2943   /// screen from bottom to top. It should be recognized by controls that are
 2944   /// vertically scrollable.
 2945   ///
 2946   /// VoiceOver users on iOS can trigger this action by swiping up with three
 2947   /// fingers. TalkBack users on Android can trigger this action by swiping
 2948   /// right and then left in one motion path. On Android, [onScrollUp] and
 2949   /// [onScrollLeft] share the same gesture. Therefore, only on of them should
 2950   /// be provided.
 2951   VoidCallback? get onScrollUp => _onScrollUp;
 2952   VoidCallback? _onScrollUp;
 2953   set onScrollUp(VoidCallback? value) {
 2954     _addArgumentlessAction(SemanticsAction.scrollUp, value!);
 2955     _onScrollUp = value;
 2956   }
 2957 
 2958   /// The handler for [SemanticsAction.scrollDown].
 2959   ///
 2960   /// This is the semantic equivalent of a user moving their finger across the
 2961   /// screen from top to bottom. It should be recognized by controls that are
 2962   /// vertically scrollable.
 2963   ///
 2964   /// VoiceOver users on iOS can trigger this action by swiping down with three
 2965   /// fingers. TalkBack users on Android can trigger this action by swiping
 2966   /// left and then right in one motion path. On Android, [onScrollDown] and
 2967   /// [onScrollRight] share the same gesture. Therefore, only on of them should
 2968   /// be provided.
 2969   VoidCallback? get onScrollDown => _onScrollDown;
 2970   VoidCallback? _onScrollDown;
 2971   set onScrollDown(VoidCallback? value) {
 2972     _addArgumentlessAction(SemanticsAction.scrollDown, value!);
 2973     _onScrollDown = value;
 2974   }
 2975 
 2976   /// The handler for [SemanticsAction.increase].
 2977   ///
 2978   /// This is a request to increase the value represented by the widget. For
 2979   /// example, this action might be recognized by a slider control.
 2980   ///
 2981   /// If a [value] is set, [increasedValue] must also be provided and
 2982   /// [onIncrease] must ensure that [value] will be set to [increasedValue].
 2983   ///
 2984   /// VoiceOver users on iOS can trigger this action by swiping up with one
 2985   /// finger. TalkBack users on Android can trigger this action by pressing the
 2986   /// volume up button.
 2987   VoidCallback? get onIncrease => _onIncrease;
 2988   VoidCallback? _onIncrease;
 2989   set onIncrease(VoidCallback? value) {
 2990     _addArgumentlessAction(SemanticsAction.increase, value!);
 2991     _onIncrease = value;
 2992   }
 2993 
 2994   /// The handler for [SemanticsAction.decrease].
 2995   ///
 2996   /// This is a request to decrease the value represented by the widget. For
 2997   /// example, this action might be recognized by a slider control.
 2998   ///
 2999   /// If a [value] is set, [decreasedValue] must also be provided and
 3000   /// [onDecrease] must ensure that [value] will be set to [decreasedValue].
 3001   ///
 3002   /// VoiceOver users on iOS can trigger this action by swiping down with one
 3003   /// finger. TalkBack users on Android can trigger this action by pressing the
 3004   /// volume down button.
 3005   VoidCallback? get onDecrease => _onDecrease;
 3006   VoidCallback? _onDecrease;
 3007   set onDecrease(VoidCallback? value) {
 3008     _addArgumentlessAction(SemanticsAction.decrease, value!);
 3009     _onDecrease = value;
 3010   }
 3011 
 3012   /// The handler for [SemanticsAction.copy].
 3013   ///
 3014   /// This is a request to copy the current selection to the clipboard.
 3015   ///
 3016   /// TalkBack users on Android can trigger this action from the local context
 3017   /// menu of a text field, for example.
 3018   VoidCallback? get onCopy => _onCopy;
 3019   VoidCallback? _onCopy;
 3020   set onCopy(VoidCallback? value) {
 3021     _addArgumentlessAction(SemanticsAction.copy, value!);
 3022     _onCopy = value;
 3023   }
 3024 
 3025   /// The handler for [SemanticsAction.cut].
 3026   ///
 3027   /// This is a request to cut the current selection and place it in the
 3028   /// clipboard.
 3029   ///
 3030   /// TalkBack users on Android can trigger this action from the local context
 3031   /// menu of a text field, for example.
 3032   VoidCallback? get onCut => _onCut;
 3033   VoidCallback? _onCut;
 3034   set onCut(VoidCallback? value) {
 3035     _addArgumentlessAction(SemanticsAction.cut, value!);
 3036     _onCut = value;
 3037   }
 3038 
 3039   /// The handler for [SemanticsAction.paste].
 3040   ///
 3041   /// This is a request to paste the current content of the clipboard.
 3042   ///
 3043   /// TalkBack users on Android can trigger this action from the local context
 3044   /// menu of a text field, for example.
 3045   VoidCallback? get onPaste => _onPaste;
 3046   VoidCallback? _onPaste;
 3047   set onPaste(VoidCallback? value) {
 3048     _addArgumentlessAction(SemanticsAction.paste, value!);
 3049     _onPaste = value;
 3050   }
 3051 
 3052   /// The handler for [SemanticsAction.showOnScreen].
 3053   ///
 3054   /// A request to fully show the semantics node on screen. For example, this
 3055   /// action might be send to a node in a scrollable list that is partially off
 3056   /// screen to bring it on screen.
 3057   ///
 3058   /// For elements in a scrollable list the framework provides a default
 3059   /// implementation for this action and it is not advised to provide a
 3060   /// custom one via this setter.
 3061   VoidCallback? get onShowOnScreen => _onShowOnScreen;
 3062   VoidCallback? _onShowOnScreen;
 3063   set onShowOnScreen(VoidCallback? value) {
 3064     _addArgumentlessAction(SemanticsAction.showOnScreen, value!);
 3065     _onShowOnScreen = value;
 3066   }
 3067 
 3068   /// The handler for [SemanticsAction.moveCursorForwardByCharacter].
 3069   ///
 3070   /// This handler is invoked when the user wants to move the cursor in a
 3071   /// text field forward by one character.
 3072   ///
 3073   /// TalkBack users can trigger this by pressing the volume up key while the
 3074   /// input focus is in a text field.
 3075   MoveCursorHandler? get onMoveCursorForwardByCharacter => _onMoveCursorForwardByCharacter;
 3076   MoveCursorHandler? _onMoveCursorForwardByCharacter;
 3077   set onMoveCursorForwardByCharacter(MoveCursorHandler? value) {
 3078     assert(value != null);
 3079     _addAction(SemanticsAction.moveCursorForwardByCharacter, (dynamic args) {
 3080       final bool extentSelection = args as bool;
 3081       assert(extentSelection != null);
 3082       value!(extentSelection);
 3083     });
 3084     _onMoveCursorForwardByCharacter = value;
 3085   }
 3086 
 3087   /// The handler for [SemanticsAction.moveCursorBackwardByCharacter].
 3088   ///
 3089   /// This handler is invoked when the user wants to move the cursor in a
 3090   /// text field backward by one character.
 3091   ///
 3092   /// TalkBack users can trigger this by pressing the volume down key while the
 3093   /// input focus is in a text field.
 3094   MoveCursorHandler? get onMoveCursorBackwardByCharacter => _onMoveCursorBackwardByCharacter;
 3095   MoveCursorHandler? _onMoveCursorBackwardByCharacter;
 3096   set onMoveCursorBackwardByCharacter(MoveCursorHandler? value) {
 3097     assert(value != null);
 3098     _addAction(SemanticsAction.moveCursorBackwardByCharacter, (dynamic args) {
 3099       final bool extentSelection = args as bool;
 3100       assert(extentSelection != null);
 3101       value!(extentSelection);
 3102     });
 3103     _onMoveCursorBackwardByCharacter = value;
 3104   }
 3105 
 3106   /// The handler for [SemanticsAction.moveCursorForwardByWord].
 3107   ///
 3108   /// This handler is invoked when the user wants to move the cursor in a
 3109   /// text field backward by one word.
 3110   ///
 3111   /// TalkBack users can trigger this by pressing the volume down key while the
 3112   /// input focus is in a text field.
 3113   MoveCursorHandler? get onMoveCursorForwardByWord => _onMoveCursorForwardByWord;
 3114   MoveCursorHandler? _onMoveCursorForwardByWord;
 3115   set onMoveCursorForwardByWord(MoveCursorHandler? value) {
 3116     assert(value != null);
 3117     _addAction(SemanticsAction.moveCursorForwardByWord, (dynamic args) {
 3118       final bool extentSelection = args as bool;
 3119       assert(extentSelection != null);
 3120       value!(extentSelection);
 3121     });
 3122     _onMoveCursorForwardByCharacter = value;
 3123   }
 3124 
 3125   /// The handler for [SemanticsAction.moveCursorBackwardByWord].
 3126   ///
 3127   /// This handler is invoked when the user wants to move the cursor in a
 3128   /// text field backward by one word.
 3129   ///
 3130   /// TalkBack users can trigger this by pressing the volume down key while the
 3131   /// input focus is in a text field.
 3132   MoveCursorHandler? get onMoveCursorBackwardByWord => _onMoveCursorBackwardByWord;
 3133   MoveCursorHandler? _onMoveCursorBackwardByWord;
 3134   set onMoveCursorBackwardByWord(MoveCursorHandler? value) {
 3135     assert(value != null);
 3136     _addAction(SemanticsAction.moveCursorBackwardByWord, (dynamic args) {
 3137       final bool extentSelection = args as bool;
 3138       assert(extentSelection != null);
 3139       value!(extentSelection);
 3140     });
 3141     _onMoveCursorBackwardByCharacter = value;
 3142   }
 3143 
 3144   /// The handler for [SemanticsAction.setSelection].
 3145   ///
 3146   /// This handler is invoked when the user either wants to change the currently
 3147   /// selected text in a text field or change the position of the cursor.
 3148   ///
 3149   /// TalkBack users can trigger this handler by selecting "Move cursor to
 3150   /// beginning/end" or "Select all" from the local context menu.
 3151   SetSelectionHandler? get onSetSelection => _onSetSelection;
 3152   SetSelectionHandler? _onSetSelection;
 3153   set onSetSelection(SetSelectionHandler? value) {
 3154     assert(value != null);
 3155     _addAction(SemanticsAction.setSelection, (dynamic args) {
 3156       assert(args != null && args is Map);
 3157       final Map<String, int> selection = (args as Map<dynamic, dynamic>).cast<String, int>();
 3158       assert(selection != null && selection['base'] != null && selection['extent'] != null);
 3159       value!(TextSelection(
 3160         baseOffset: selection['base']!,
 3161         extentOffset: selection['extent']!,
 3162       ));
 3163     });
 3164     _onSetSelection = value;
 3165   }
 3166 
 3167   /// The handler for [SemanticsAction.didGainAccessibilityFocus].
 3168   ///
 3169   /// This handler is invoked when the node annotated with this handler gains
 3170   /// the accessibility focus. The accessibility focus is the
 3171   /// green (on Android with TalkBack) or black (on iOS with VoiceOver)
 3172   /// rectangle shown on screen to indicate what element an accessibility
 3173   /// user is currently interacting with.
 3174   ///
 3175   /// The accessibility focus is different from the input focus. The input focus
 3176   /// is usually held by the element that currently responds to keyboard inputs.
 3177   /// Accessibility focus and input focus can be held by two different nodes!
 3178   ///
 3179   /// See also:
 3180   ///
 3181   ///  * [onDidLoseAccessibilityFocus], which is invoked when the accessibility
 3182   ///    focus is removed from the node.
 3183   ///  * [FocusNode], [FocusScope], [FocusManager], which manage the input focus.
 3184   VoidCallback? get onDidGainAccessibilityFocus => _onDidGainAccessibilityFocus;
 3185   VoidCallback? _onDidGainAccessibilityFocus;
 3186   set onDidGainAccessibilityFocus(VoidCallback? value) {
 3187     _addArgumentlessAction(SemanticsAction.didGainAccessibilityFocus, value!);
 3188     _onDidGainAccessibilityFocus = value;
 3189   }
 3190 
 3191   /// The handler for [SemanticsAction.didLoseAccessibilityFocus].
 3192   ///
 3193   /// This handler is invoked when the node annotated with this handler
 3194   /// loses the accessibility focus. The accessibility focus is
 3195   /// the green (on Android with TalkBack) or black (on iOS with VoiceOver)
 3196   /// rectangle shown on screen to indicate what element an accessibility
 3197   /// user is currently interacting with.
 3198   ///
 3199   /// The accessibility focus is different from the input focus. The input focus
 3200   /// is usually held by the element that currently responds to keyboard inputs.
 3201   /// Accessibility focus and input focus can be held by two different nodes!
 3202   ///
 3203   /// See also:
 3204   ///
 3205   ///  * [onDidGainAccessibilityFocus], which is invoked when the node gains
 3206   ///    accessibility focus.
 3207   ///  * [FocusNode], [FocusScope], [FocusManager], which manage the input focus.
 3208   VoidCallback? get onDidLoseAccessibilityFocus => _onDidLoseAccessibilityFocus;
 3209   VoidCallback? _onDidLoseAccessibilityFocus;
 3210   set onDidLoseAccessibilityFocus(VoidCallback? value) {
 3211     _addArgumentlessAction(SemanticsAction.didLoseAccessibilityFocus, value!);
 3212     _onDidLoseAccessibilityFocus = value;
 3213   }
 3214 
 3215   /// Returns the action handler registered for [action] or null if none was
 3216   /// registered.
 3217   _SemanticsActionHandler? getActionHandler(SemanticsAction action) => _actions[action];
 3218 
 3219   /// Determines the position of this node among its siblings in the traversal
 3220   /// sort order.
 3221   ///
 3222   /// This is used to describe the order in which the semantic node should be
 3223   /// traversed by the accessibility services on the platform (e.g. VoiceOver
 3224   /// on iOS and TalkBack on Android).
 3225   ///
 3226   /// Whether this sort key has an effect on the [SemanticsNode] sort order is
 3227   /// subject to how this configuration is used. For example, the [absorb]
 3228   /// method may decide to not use this key when it combines multiple
 3229   /// [SemanticsConfiguration] objects.
 3230   SemanticsSortKey? get sortKey => _sortKey;
 3231   SemanticsSortKey? _sortKey;
 3232   set sortKey(SemanticsSortKey? value) {
 3233     assert(value != null);
 3234     _sortKey = value;
 3235     _hasBeenAnnotated = true;
 3236   }
 3237 
 3238   /// The index of this node within the parent's list of semantic children.
 3239   ///
 3240   /// This includes all semantic nodes, not just those currently in the
 3241   /// child list. For example, if a scrollable has five children but the first
 3242   /// two are not visible (and thus not included in the list of children), then
 3243   /// the index of the last node will still be 4.
 3244   int? get indexInParent => _indexInParent;
 3245   int? _indexInParent;
 3246   set indexInParent(int? value) {
 3247     _indexInParent = value;
 3248     _hasBeenAnnotated = true;
 3249   }
 3250 
 3251   /// The total number of scrollable children that contribute to semantics.
 3252   ///
 3253   /// If the number of children are unknown or unbounded, this value will be
 3254   /// null.
 3255   int? get scrollChildCount => _scrollChildCount;
 3256   int? _scrollChildCount;
 3257   set scrollChildCount(int? value) {
 3258     if (value == scrollChildCount)
 3259       return;
 3260     _scrollChildCount = value;
 3261     _hasBeenAnnotated = true;
 3262   }
 3263 
 3264   /// The index of the first visible scrollable child that contributes to
 3265   /// semantics.
 3266   int? get scrollIndex => _scrollIndex;
 3267   int? _scrollIndex;
 3268   set scrollIndex(int? value) {
 3269     if (value == scrollIndex)
 3270       return;
 3271     _scrollIndex = value;
 3272     _hasBeenAnnotated = true;
 3273   }
 3274 
 3275   /// The id of the platform view, whose semantics nodes will be added as
 3276   /// children to this node.
 3277   int? get platformViewId => _platformViewId;
 3278   int? _platformViewId;
 3279   set platformViewId(int? value) {
 3280     if (value == platformViewId)
 3281       return;
 3282     _platformViewId = value;
 3283     _hasBeenAnnotated = true;
 3284   }
 3285 
 3286   /// The maximum number of characters that can be entered into an editable
 3287   /// text field.
 3288   ///
 3289   /// For the purpose of this function a character is defined as one Unicode
 3290   /// scalar value.
 3291   ///
 3292   /// This should only be set when [isTextField] is true. Defaults to null,
 3293   /// which means no limit is imposed on the text field.
 3294   int? get maxValueLength => _maxValueLength;
 3295   int? _maxValueLength;
 3296   set maxValueLength(int? value) {
 3297     if (value == maxValueLength)
 3298       return;
 3299     _maxValueLength = value;
 3300     _hasBeenAnnotated = true;
 3301   }
 3302 
 3303   /// The current number of characters that have been entered into an editable
 3304   /// text field.
 3305   ///
 3306   /// For the purpose of this function a character is defined as one Unicode
 3307   /// scalar value.
 3308   ///
 3309   /// This should only be set when [isTextField] is true. Must be set when
 3310   /// [maxValueLength] is set.
 3311   int? get currentValueLength => _currentValueLength;
 3312   int? _currentValueLength;
 3313   set currentValueLength(int? value) {
 3314     if (value == currentValueLength)
 3315       return;
 3316     _currentValueLength = value;
 3317     _hasBeenAnnotated = true;
 3318   }
 3319 
 3320   /// Whether the semantic information provided by the owning [RenderObject] and
 3321   /// all of its descendants should be treated as one logical entity.
 3322   ///
 3323   /// If set to true, the descendants of the owning [RenderObject]'s
 3324   /// [SemanticsNode] will merge their semantic information into the
 3325   /// [SemanticsNode] representing the owning [RenderObject].
 3326   ///
 3327   /// Setting this to true requires that [isSemanticBoundary] is also true.
 3328   bool get isMergingSemanticsOfDescendants => _isMergingSemanticsOfDescendants;
 3329   bool _isMergingSemanticsOfDescendants = false;
 3330   set isMergingSemanticsOfDescendants(bool value) {
 3331     assert(isSemanticBoundary);
 3332     _isMergingSemanticsOfDescendants = value;
 3333     _hasBeenAnnotated = true;
 3334   }
 3335 
 3336   /// The handlers for each supported [CustomSemanticsAction].
 3337   ///
 3338   /// Whenever a custom accessibility action is added to a node, the action
 3339   /// [SemanticsAction.customAction] is automatically added. A handler is
 3340   /// created which uses the passed argument to lookup the custom action
 3341   /// handler from this map and invoke it, if present.
 3342   Map<CustomSemanticsAction, VoidCallback> get customSemanticsActions => _customSemanticsActions;
 3343   Map<CustomSemanticsAction, VoidCallback> _customSemanticsActions = <CustomSemanticsAction, VoidCallback>{};
 3344   set customSemanticsActions(Map<CustomSemanticsAction, VoidCallback> value) {
 3345     _hasBeenAnnotated = true;
 3346     _actionsAsBits |= SemanticsAction.customAction.index;
 3347     _customSemanticsActions = value;
 3348     _actions[SemanticsAction.customAction] = _onCustomSemanticsAction;
 3349   }
 3350 
 3351   void _onCustomSemanticsAction(dynamic args) {
 3352     final CustomSemanticsAction? action = CustomSemanticsAction.getAction(args as int);
 3353     if (action == null)
 3354       return;
 3355     final VoidCallback? callback = _customSemanticsActions[action];
 3356     if (callback != null)
 3357       callback();
 3358   }
 3359 
 3360   /// A textual description of the owning [RenderObject].
 3361   ///
 3362   /// On iOS this is used for the `accessibilityLabel` property defined in the
 3363   /// `UIAccessibility` Protocol. On Android it is concatenated together with
 3364   /// [value] and [hint] in the following order: [value], [label], [hint].
 3365   /// The concatenated value is then used as the `Text` description.
 3366   ///
 3367   /// The reading direction is given by [textDirection].
 3368   String get label => _label;
 3369   String _label = '';
 3370   set label(String label) {
 3371     assert(label != null);
 3372     _label = label;
 3373     _hasBeenAnnotated = true;
 3374   }
 3375 
 3376   /// A textual description for the current value of the owning [RenderObject].
 3377   ///
 3378   /// On iOS this is used for the `accessibilityValue` property defined in the
 3379   /// `UIAccessibility` Protocol. On Android it is concatenated together with
 3380   /// [label] and [hint] in the following order: [value], [label], [hint].
 3381   /// The concatenated value is then used as the `Text` description.
 3382   ///
 3383   /// The reading direction is given by [textDirection].
 3384   ///
 3385   /// See also:
 3386   ///
 3387   ///  * [decreasedValue], describes what [value] will be after performing
 3388   ///    [SemanticsAction.decrease].
 3389   ///  * [increasedValue], describes what [value] will be after performing
 3390   ///    [SemanticsAction.increase].
 3391   String get value => _value;
 3392   String _value = '';
 3393   set value(String value) {
 3394     assert(value != null);
 3395     _value = value;
 3396     _hasBeenAnnotated = true;
 3397   }
 3398 
 3399   /// The value that [value] will have after performing a
 3400   /// [SemanticsAction.decrease] action.
 3401   ///
 3402   /// This must be set if a handler for [SemanticsAction.decrease] is provided
 3403   /// and [value] is set.
 3404   ///
 3405   /// The reading direction is given by [textDirection].
 3406   String get decreasedValue => _decreasedValue;
 3407   String _decreasedValue = '';
 3408   set decreasedValue(String decreasedValue) {
 3409     assert(decreasedValue != null);
 3410     _decreasedValue = decreasedValue;
 3411     _hasBeenAnnotated = true;
 3412   }
 3413 
 3414   /// The value that [value] will have after performing a
 3415   /// [SemanticsAction.increase] action.
 3416   ///
 3417   /// This must be set if a handler for [SemanticsAction.increase] is provided
 3418   /// and [value] is set.
 3419   ///
 3420   /// The reading direction is given by [textDirection].
 3421   String get increasedValue => _increasedValue;
 3422   String _increasedValue = '';
 3423   set increasedValue(String increasedValue) {
 3424     assert(increasedValue != null);
 3425     _increasedValue = increasedValue;
 3426     _hasBeenAnnotated = true;
 3427   }
 3428 
 3429   /// A brief description of the result of performing an action on this node.
 3430   ///
 3431   /// On iOS this is used for the `accessibilityHint` property defined in the
 3432   /// `UIAccessibility` Protocol. On Android it is concatenated together with
 3433   /// [label] and [value] in the following order: [value], [label], [hint].
 3434   /// The concatenated value is then used as the `Text` description.
 3435   ///
 3436   /// The reading direction is given by [textDirection].
 3437   String get hint => _hint;
 3438   String _hint = '';
 3439   set hint(String hint) {
 3440     assert(hint != null);
 3441     _hint = hint;
 3442     _hasBeenAnnotated = true;
 3443   }
 3444 
 3445   /// Provides hint values which override the default hints on supported
 3446   /// platforms.
 3447   SemanticsHintOverrides? get hintOverrides => _hintOverrides;
 3448   SemanticsHintOverrides? _hintOverrides;
 3449   set hintOverrides(SemanticsHintOverrides? value) {
 3450     if (value == null)
 3451       return;
 3452     _hintOverrides = value;
 3453     _hasBeenAnnotated = true;
 3454   }
 3455 
 3456   /// The elevation in z-direction at which the owning [RenderObject] is
 3457   /// located relative to its parent.
 3458   double get elevation => _elevation;
 3459   double _elevation = 0.0;
 3460   set elevation(double value) {
 3461     assert(value != null && value >= 0.0);
 3462     if (value == _elevation) {
 3463       return;
 3464     }
 3465     _elevation = value;
 3466     _hasBeenAnnotated = true;
 3467   }
 3468 
 3469   /// The extend that the owning [RenderObject] occupies in z-direction starting
 3470   /// at [elevation].
 3471   ///
 3472   /// It's extremely rare to set this value directly. Instead, it is calculated
 3473   /// implicitly when other [SemanticsConfiguration]s are merged into this one
 3474   /// via [absorb].
 3475   double get thickness => _thickness;
 3476   double _thickness = 0.0;
 3477   set thickness(double value) {
 3478     assert(value != null && value >= 0.0);
 3479     if (value == _thickness) {
 3480       return;
 3481     }
 3482     _thickness = value;
 3483     _hasBeenAnnotated = true;
 3484   }
 3485 
 3486   /// Whether the semantics node is the root of a subtree for which values
 3487   /// should be announced.
 3488   ///
 3489   /// See also:
 3490   ///
 3491   ///  * [SemanticsFlag.scopesRoute], for a full description of route scoping.
 3492   bool get scopesRoute => _hasFlag(SemanticsFlag.scopesRoute);
 3493   set scopesRoute(bool value) {
 3494     _setFlag(SemanticsFlag.scopesRoute, value);
 3495   }
 3496 
 3497   /// Whether the semantics node contains the label of a route.
 3498   ///
 3499   /// See also:
 3500   ///
 3501   ///  * [SemanticsFlag.namesRoute], for a full description of route naming.
 3502   bool get namesRoute => _hasFlag(SemanticsFlag.namesRoute);
 3503   set namesRoute(bool value) {
 3504     _setFlag(SemanticsFlag.namesRoute, value);
 3505   }
 3506 
 3507   /// Whether the semantics node represents an image.
 3508   bool get isImage => _hasFlag(SemanticsFlag.isImage);
 3509   set isImage(bool value) {
 3510     _setFlag(SemanticsFlag.isImage, value);
 3511   }
 3512 
 3513   /// Whether the semantics node is a live region.
 3514   ///
 3515   /// On Android, when the label changes on a live region semantics node,
 3516   /// TalkBack will make a polite announcement of the current label. This
 3517   /// announcement occurs even if the node is not focused, but only if the label
 3518   /// has changed since the last update.
 3519   ///
 3520   /// An example of a live region is the [SnackBar] widget. When it appears
 3521   /// on the screen it may be difficult to focus to read the label. A live
 3522   /// region causes an initial polite announcement to be generated
 3523   /// automatically.
 3524   ///
 3525   /// See also:
 3526   ///
 3527   ///  * [SemanticsFlag.isLiveRegion], the semantics flag that this setting controls.
 3528   bool get liveRegion => _hasFlag(SemanticsFlag.isLiveRegion);
 3529   set liveRegion(bool value) {
 3530     _setFlag(SemanticsFlag.isLiveRegion, value);
 3531   }
 3532 
 3533   /// The reading direction for the text in [label], [value], [hint],
 3534   /// [increasedValue], and [decreasedValue].
 3535   TextDirection? get textDirection => _textDirection;
 3536   TextDirection? _textDirection;
 3537   set textDirection(TextDirection? textDirection) {
 3538     _textDirection = textDirection;
 3539     _hasBeenAnnotated = true;
 3540   }
 3541 
 3542   /// Whether the owning [RenderObject] is selected (true) or not (false).
 3543   ///
 3544   /// This is different from having accessibility focus. The element that is
 3545   /// accessibility focused may or may not be selected; e.g. a [ListTile] can have
 3546   /// accessibility focus but have its [ListTile.selected] property set to false,
 3547   /// in which case it will not be flagged as selected.
 3548   bool get isSelected => _hasFlag(SemanticsFlag.isSelected);
 3549   set isSelected(bool value) {
 3550     _setFlag(SemanticsFlag.isSelected, value);
 3551   }
 3552 
 3553   /// Whether the owning [RenderObject] is currently enabled.
 3554   ///
 3555   /// A disabled object does not respond to user interactions. Only objects that
 3556   /// usually respond to user interactions, but which currently do not (like a
 3557   /// disabled button) should be marked as disabled.
 3558   ///
 3559   /// The setter should not be called for objects (like static text) that never
 3560   /// respond to user interactions.
 3561   ///
 3562   /// The getter will return null if the owning [RenderObject] doesn't support
 3563   /// the concept of being enabled/disabled.
 3564   ///
 3565   /// This property does not control whether semantics are enabled. If you wish to
 3566   /// disable semantics for a particular widget, you should use an [ExcludeSemantics]
 3567   /// widget.
 3568   bool? get isEnabled => _hasFlag(SemanticsFlag.hasEnabledState) ? _hasFlag(SemanticsFlag.isEnabled) : null;
 3569   set isEnabled(bool? value) {
 3570     _setFlag(SemanticsFlag.hasEnabledState, true);
 3571     _setFlag(SemanticsFlag.isEnabled, value!);
 3572   }
 3573 
 3574   /// If this node has Boolean state that can be controlled by the user, whether
 3575   /// that state is checked or unchecked, corresponding to true and false,
 3576   /// respectively.
 3577   ///
 3578   /// Do not call the setter for this field if the owning [RenderObject] doesn't
 3579   /// have checked/unchecked state that can be controlled by the user.
 3580   ///
 3581   /// The getter returns null if the owning [RenderObject] does not have
 3582   /// checked/unchecked state.
 3583   bool? get isChecked => _hasFlag(SemanticsFlag.hasCheckedState) ? _hasFlag(SemanticsFlag.isChecked) : null;
 3584   set isChecked(bool? value) {
 3585     _setFlag(SemanticsFlag.hasCheckedState, true);
 3586     _setFlag(SemanticsFlag.isChecked, value!);
 3587   }
 3588 
 3589   /// If this node has Boolean state that can be controlled by the user, whether
 3590   /// that state is on or off, corresponding to true and false, respectively.
 3591   ///
 3592   /// Do not call the setter for this field if the owning [RenderObject] doesn't
 3593   /// have on/off state that can be controlled by the user.
 3594   ///
 3595   /// The getter returns null if the owning [RenderObject] does not have
 3596   /// on/off state.
 3597   bool? get isToggled => _hasFlag(SemanticsFlag.hasToggledState) ? _hasFlag(SemanticsFlag.isToggled) : null;
 3598   set isToggled(bool? value) {
 3599     _setFlag(SemanticsFlag.hasToggledState, true);
 3600     _setFlag(SemanticsFlag.isToggled, value!);
 3601   }
 3602 
 3603   /// Whether the owning RenderObject corresponds to UI that allows the user to
 3604   /// pick one of several mutually exclusive options.
 3605   ///
 3606   /// For example, a [Radio] button is in a mutually exclusive group because
 3607   /// only one radio button in that group can be marked as [isChecked].
 3608   bool get isInMutuallyExclusiveGroup => _hasFlag(SemanticsFlag.isInMutuallyExclusiveGroup);
 3609   set isInMutuallyExclusiveGroup(bool value) {
 3610     _setFlag(SemanticsFlag.isInMutuallyExclusiveGroup, value);
 3611   }
 3612 
 3613   /// Whether the owning [RenderObject] can hold the input focus.
 3614   bool get isFocusable => _hasFlag(SemanticsFlag.isFocusable);
 3615   set isFocusable(bool value) {
 3616     _setFlag(SemanticsFlag.isFocusable, value);
 3617   }
 3618 
 3619   /// Whether the owning [RenderObject] currently holds the input focus.
 3620   bool get isFocused => _hasFlag(SemanticsFlag.isFocused);
 3621   set isFocused(bool value) {
 3622     _setFlag(SemanticsFlag.isFocused, value);
 3623   }
 3624 
 3625   /// Whether the owning [RenderObject] is a button (true) or not (false).
 3626   bool get isButton => _hasFlag(SemanticsFlag.isButton);
 3627   set isButton(bool value) {
 3628     _setFlag(SemanticsFlag.isButton, value);
 3629   }
 3630 
 3631   /// Whether the owning [RenderObject] is a link (true) or not (false).
 3632   bool get isLink => _hasFlag(SemanticsFlag.isLink);
 3633   set isLink(bool value) {
 3634     _setFlag(SemanticsFlag.isLink, value);
 3635   }
 3636 
 3637   /// Whether the owning [RenderObject] is a header (true) or not (false).
 3638   bool get isHeader => _hasFlag(SemanticsFlag.isHeader);
 3639   set isHeader(bool value) {
 3640     _setFlag(SemanticsFlag.isHeader, value);
 3641   }
 3642 
 3643   /// Whether the owning [RenderObject] is considered hidden.
 3644   ///
 3645   /// Hidden elements are currently not visible on screen. They may be covered
 3646   /// by other elements or positioned outside of the visible area of a viewport.
 3647   ///
 3648   /// Hidden elements cannot gain accessibility focus though regular touch. The
 3649   /// only way they can be focused is by moving the focus to them via linear
 3650   /// navigation.
 3651   ///
 3652   /// Platforms are free to completely ignore hidden elements and new platforms
 3653   /// are encouraged to do so.
 3654   ///
 3655   /// Instead of marking an element as hidden it should usually be excluded from
 3656   /// the semantics tree altogether. Hidden elements are only included in the
 3657   /// semantics tree to work around platform limitations and they are mainly
 3658   /// used to implement accessibility scrolling on iOS.
 3659   bool get isHidden => _hasFlag(SemanticsFlag.isHidden);
 3660   set isHidden(bool value) {
 3661     _setFlag(SemanticsFlag.isHidden, value);
 3662   }
 3663 
 3664   /// Whether the owning [RenderObject] is a text field.
 3665   bool get isTextField => _hasFlag(SemanticsFlag.isTextField);
 3666   set isTextField(bool value) {
 3667     _setFlag(SemanticsFlag.isTextField, value);
 3668   }
 3669 
 3670   /// Whether the owning [RenderObject] is read only.
 3671   ///
 3672   /// Only applicable when [isTextField] is true.
 3673   bool get isReadOnly => _hasFlag(SemanticsFlag.isReadOnly);
 3674   set isReadOnly(bool value) {
 3675     _setFlag(SemanticsFlag.isReadOnly, value);
 3676   }
 3677 
 3678   /// Whether the [value] should be obscured.
 3679   ///
 3680   /// This option is usually set in combination with [isTextField] to indicate
 3681   /// that the text field contains a password (or other sensitive information).
 3682   /// Doing so instructs screen readers to not read out the [value].
 3683   bool get isObscured => _hasFlag(SemanticsFlag.isObscured);
 3684   set isObscured(bool value) {
 3685     _setFlag(SemanticsFlag.isObscured, value);
 3686   }
 3687 
 3688   /// Whether the text field is multiline.
 3689   ///
 3690   /// This option is usually set in combination with [isTextField] to indicate
 3691   /// that the text field is configured to be multiline.
 3692   bool get isMultiline => _hasFlag(SemanticsFlag.isMultiline);
 3693   set isMultiline(bool value) {
 3694     _setFlag(SemanticsFlag.isMultiline, value);
 3695   }
 3696 
 3697   /// Whether the platform can scroll the semantics node when the user attempts
 3698   /// to move focus to an offscreen child.
 3699   ///
 3700   /// For example, a [ListView] widget has implicit scrolling so that users can
 3701   /// easily move to the next visible set of children. A [TabBar] widget does
 3702   /// not have implicit scrolling, so that users can navigate into the tab
 3703   /// body when reaching the end of the tab bar.
 3704   bool get hasImplicitScrolling => _hasFlag(SemanticsFlag.hasImplicitScrolling);
 3705   set hasImplicitScrolling(bool value) {
 3706     _setFlag(SemanticsFlag.hasImplicitScrolling, value);
 3707   }
 3708 
 3709   /// The currently selected text (or the position of the cursor) within [value]
 3710   /// if this node represents a text field.
 3711   TextSelection? get textSelection => _textSelection;
 3712   TextSelection? _textSelection;
 3713   set textSelection(TextSelection? value) {
 3714     assert(value != null);
 3715     _textSelection = value;
 3716     _hasBeenAnnotated = true;
 3717   }
 3718 
 3719   /// Indicates the current scrolling position in logical pixels if the node is
 3720   /// scrollable.
 3721   ///
 3722   /// The properties [scrollExtentMin] and [scrollExtentMax] indicate the valid
 3723   /// in-range values for this property. The value for [scrollPosition] may
 3724   /// (temporarily) be outside that range, e.g. during an overscroll.
 3725   ///
 3726   /// See also:
 3727   ///
 3728   ///  * [ScrollPosition.pixels], from where this value is usually taken.
 3729   double? get scrollPosition => _scrollPosition;
 3730   double? _scrollPosition;
 3731   set scrollPosition(double? value) {
 3732     assert(value != null);
 3733     _scrollPosition = value;
 3734     _hasBeenAnnotated = true;
 3735   }
 3736 
 3737   /// Indicates the maximum in-range value for [scrollPosition] if the node is
 3738   /// scrollable.
 3739   ///
 3740   /// This value may be infinity if the scroll is unbound.
 3741   ///
 3742   /// See also:
 3743   ///
 3744   ///  * [ScrollPosition.maxScrollExtent], from where this value is usually taken.
 3745   double? get scrollExtentMax => _scrollExtentMax;
 3746   double? _scrollExtentMax;
 3747   set scrollExtentMax(double? value) {
 3748     assert(value != null);
 3749     _scrollExtentMax = value;
 3750     _hasBeenAnnotated = true;
 3751   }
 3752 
 3753   /// Indicates the minimum in-range value for [scrollPosition] if the node is
 3754   /// scrollable.
 3755   ///
 3756   /// This value may be infinity if the scroll is unbound.
 3757   ///
 3758   /// See also:
 3759   ///
 3760   ///  * [ScrollPosition.minScrollExtent], from where this value is usually taken.
 3761   double? get scrollExtentMin => _scrollExtentMin;
 3762   double? _scrollExtentMin;
 3763   set scrollExtentMin(double? value) {
 3764     assert(value != null);
 3765     _scrollExtentMin = value;
 3766     _hasBeenAnnotated = true;
 3767   }
 3768 
 3769   // TAGS
 3770 
 3771   /// The set of tags that this configuration wants to add to all child
 3772   /// [SemanticsNode]s.
 3773   ///
 3774   /// See also:
 3775   ///
 3776   ///  * [addTagForChildren] to add a tag and for more information about their
 3777   ///    usage.
 3778   Iterable<SemanticsTag>? get tagsForChildren => _tagsForChildren;
 3779   Set<SemanticsTag>? _tagsForChildren;
 3780 
 3781   /// Specifies a [SemanticsTag] that this configuration wants to apply to all
 3782   /// child [SemanticsNode]s.
 3783   ///
 3784   /// The tag is added to all [SemanticsNode] that pass through the
 3785   /// [RenderObject] owning this configuration while looking to be attached to a
 3786   /// parent [SemanticsNode].
 3787   ///
 3788   /// Tags are used to communicate to a parent [SemanticsNode] that a child
 3789   /// [SemanticsNode] was passed through a particular [RenderObject]. The parent
 3790   /// can use this information to determine the shape of the semantics tree.
 3791   ///
 3792   /// See also:
 3793   ///
 3794   ///  * [RenderViewport.excludeFromScrolling] for an example of
 3795   ///    how tags are used.
 3796   void addTagForChildren(SemanticsTag tag) {
 3797     _tagsForChildren ??= <SemanticsTag>{};
 3798     _tagsForChildren!.add(tag);
 3799   }
 3800 
 3801   // INTERNAL FLAG MANAGEMENT
 3802 
 3803   int _flags = 0;
 3804   void _setFlag(SemanticsFlag flag, bool value) {
 3805     if (value) {
 3806       _flags |= flag.index;
 3807     } else {
 3808       _flags &= ~flag.index;
 3809     }
 3810     _hasBeenAnnotated = true;
 3811   }
 3812 
 3813   bool _hasFlag(SemanticsFlag flag) => (_flags & flag.index) != 0;
 3814 
 3815   // CONFIGURATION COMBINATION LOGIC
 3816 
 3817   /// Whether this configuration is compatible with the provided `other`
 3818   /// configuration.
 3819   ///
 3820   /// Two configurations are said to be compatible if they can be added to the
 3821   /// same [SemanticsNode] without losing any semantics information.
 3822   bool isCompatibleWith(SemanticsConfiguration? other) {
 3823     if (other == null || !other.hasBeenAnnotated || !hasBeenAnnotated)
 3824       return true;
 3825     if (_actionsAsBits & other._actionsAsBits != 0)
 3826       return false;
 3827     if ((_flags & other._flags) != 0)
 3828       return false;
 3829     if (_platformViewId != null && other._platformViewId != null) {
 3830       return false;
 3831     }
 3832     if (_maxValueLength != null && other._maxValueLength != null) {
 3833       return false;
 3834     }
 3835     if (_currentValueLength != null && other._currentValueLength != null) {
 3836       return false;
 3837     }
 3838     if (_value != null && _value.isNotEmpty && other._value != null && other._value.isNotEmpty)
 3839       return false;
 3840     return true;
 3841   }
 3842 
 3843   /// Absorb the semantic information from `child` into this configuration.
 3844   ///
 3845   /// This adds the semantic information of both configurations and saves the
 3846   /// result in this configuration.
 3847   ///
 3848   /// The [RenderObject] owning the `child` configuration must be a descendant
 3849   /// of the [RenderObject] that owns this configuration.
 3850   ///
 3851   /// Only configurations that have [explicitChildNodes] set to false can
 3852   /// absorb other configurations and it is recommended to only absorb compatible
 3853   /// configurations as determined by [isCompatibleWith].
 3854   void absorb(SemanticsConfiguration child) {
 3855     assert(!explicitChildNodes);
 3856 
 3857     if (!child.hasBeenAnnotated)
 3858       return;
 3859 
 3860     _actions.addAll(child._actions);
 3861     _customSemanticsActions.addAll(child._customSemanticsActions);
 3862     _actionsAsBits |= child._actionsAsBits;
 3863     _flags |= child._flags;
 3864     _textSelection ??= child._textSelection;
 3865     _scrollPosition ??= child._scrollPosition;
 3866     _scrollExtentMax ??= child._scrollExtentMax;
 3867     _scrollExtentMin ??= child._scrollExtentMin;
 3868     _hintOverrides ??= child._hintOverrides;
 3869     _indexInParent ??= child.indexInParent;
 3870     _scrollIndex ??= child._scrollIndex;
 3871     _scrollChildCount ??= child._scrollChildCount;
 3872     _platformViewId ??= child._platformViewId;
 3873     _maxValueLength ??= child._maxValueLength;
 3874     _currentValueLength ??= child._currentValueLength;
 3875 
 3876     textDirection ??= child.textDirection;
 3877     _sortKey ??= child._sortKey;
 3878     _label = _concatStrings(
 3879       thisString: _label,
 3880       thisTextDirection: textDirection,
 3881       otherString: child._label,
 3882       otherTextDirection: child.textDirection,
 3883     );
 3884     if (_decreasedValue == '' || _decreasedValue == null)
 3885       _decreasedValue = child._decreasedValue;
 3886     if (_value == '' || _value == null)
 3887       _value = child._value;
 3888     if (_increasedValue == '' || _increasedValue == null)
 3889       _increasedValue = child._increasedValue;
 3890     _hint = _concatStrings(
 3891       thisString: _hint,
 3892       thisTextDirection: textDirection,
 3893       otherString: child._hint,
 3894       otherTextDirection: child.textDirection,
 3895     );
 3896 
 3897     _thickness = math.max(_thickness, child._thickness + child._elevation);
 3898 
 3899     _hasBeenAnnotated = _hasBeenAnnotated || child._hasBeenAnnotated;
 3900   }
 3901 
 3902   /// Returns an exact copy of this configuration.
 3903   SemanticsConfiguration copy() {
 3904     return SemanticsConfiguration()
 3905       .._isSemanticBoundary = _isSemanticBoundary
 3906       ..explicitChildNodes = explicitChildNodes
 3907       ..isBlockingSemanticsOfPreviouslyPaintedNodes = isBlockingSemanticsOfPreviouslyPaintedNodes
 3908       .._hasBeenAnnotated = _hasBeenAnnotated
 3909       .._isMergingSemanticsOfDescendants = _isMergingSemanticsOfDescendants
 3910       .._textDirection = _textDirection
 3911       .._sortKey = _sortKey
 3912       .._label = _label
 3913       .._increasedValue = _increasedValue
 3914       .._value = _value
 3915       .._decreasedValue = _decreasedValue
 3916       .._hint = _hint
 3917       .._hintOverrides = _hintOverrides
 3918       .._elevation = _elevation
 3919       .._thickness = _thickness
 3920       .._flags = _flags
 3921       .._tagsForChildren = _tagsForChildren
 3922       .._textSelection = _textSelection
 3923       .._scrollPosition = _scrollPosition
 3924       .._scrollExtentMax = _scrollExtentMax
 3925       .._scrollExtentMin = _scrollExtentMin
 3926       .._actionsAsBits = _actionsAsBits
 3927       .._indexInParent = indexInParent
 3928       .._scrollIndex = _scrollIndex
 3929       .._scrollChildCount = _scrollChildCount
 3930       .._platformViewId = _platformViewId
 3931       .._maxValueLength = _maxValueLength
 3932       .._currentValueLength = _currentValueLength
 3933       .._actions.addAll(_actions)
 3934       .._customSemanticsActions.addAll(_customSemanticsActions);
 3935   }
 3936 }
 3937 
 3938 /// Used by [debugDumpSemanticsTree] to specify the order in which child nodes
 3939 /// are printed.
 3940 enum DebugSemanticsDumpOrder {
 3941   /// Print nodes in inverse hit test order.
 3942   ///
 3943   /// In inverse hit test order, the last child of a [SemanticsNode] will be
 3944   /// asked first if it wants to respond to a user's interaction, followed by
 3945   /// the second last, etc. until a taker is found.
 3946   inverseHitTest,
 3947 
 3948   /// Print nodes in semantic traversal order.
 3949   ///
 3950   /// This is the order in which a user would navigate the UI using the "next"
 3951   /// and "previous" gestures.
 3952   traversalOrder,
 3953 }
 3954 
 3955 String _concatStrings({
 3956   required String thisString,
 3957   required String otherString,
 3958   required TextDirection? thisTextDirection,
 3959   required TextDirection? otherTextDirection,
 3960 }) {
 3961   if (otherString.isEmpty)
 3962     return thisString;
 3963   String nestedLabel = otherString;
 3964   if (thisTextDirection != otherTextDirection && otherTextDirection != null) {
 3965     switch (otherTextDirection) {
 3966       case TextDirection.rtl:
 3967         nestedLabel = '${Unicode.RLE}$nestedLabel${Unicode.PDF}';
 3968         break;
 3969       case TextDirection.ltr:
 3970         nestedLabel = '${Unicode.LRE}$nestedLabel${Unicode.PDF}';
 3971         break;
 3972     }
 3973   }
 3974   if (thisString.isEmpty)
 3975     return nestedLabel;
 3976   return '$thisString\n$nestedLabel';
 3977 }
 3978 
 3979 /// Base class for all sort keys for [SemanticsProperties.sortKey] accessibility
 3980 /// traversal order sorting.
 3981 ///
 3982 /// Sort keys are sorted by [name], then by the comparison that the subclass
 3983 /// implements. If [SemanticsProperties.sortKey] is specified, sort keys within
 3984 /// the same semantic group must all be of the same type.
 3985 ///
 3986 /// Keys with no [name] are compared to other keys with no [name], and will
 3987 /// be traversed before those with a [name].
 3988 ///
 3989 /// If no sort key is applied to a semantics node, then it will be ordered using
 3990 /// a platform dependent default algorithm.
 3991 ///
 3992 /// See also:
 3993 ///
 3994 ///  * [OrdinalSortKey] for a sort key that sorts using an ordinal.
 3995 abstract class SemanticsSortKey with Diagnosticable implements Comparable<SemanticsSortKey> {
 3996   /// Abstract const constructor. This constructor enables subclasses to provide
 3997   /// const constructors so that they can be used in const expressions.
 3998   const SemanticsSortKey({this.name});
 3999 
 4000   /// An optional name that will group this sort key with other sort keys of the
 4001   /// same [name].
 4002   ///
 4003   /// Sort keys must have the same `runtimeType` when compared.
 4004   ///
 4005   /// Keys with no [name] are compared to other keys with no [name], and will
 4006   /// be traversed before those with a [name].
 4007   final String? name;
 4008 
 4009   @override
 4010   int compareTo(SemanticsSortKey other) {
 4011     // Sort by name first and then subclass ordering.
 4012     assert(runtimeType == other.runtimeType, 'Semantics sort keys can only be compared to other sort keys of the same type.');
 4013 
 4014     // Defer to the subclass implementation for ordering only if the names are
 4015     // identical (or both null).
 4016     if (name == other.name) {
 4017       return doCompare(other);
 4018     }
 4019 
 4020     // Keys that don't have a name are sorted together and come before those with
 4021     // a name.
 4022     if (name == null && other.name != null) {
 4023       return -1;
 4024     } else if (name != null && other.name == null) {
 4025       return 1;
 4026     }
 4027 
 4028     return name!.compareTo(other.name!);
 4029   }
 4030 
 4031   /// The implementation of [compareTo].
 4032   ///
 4033   /// The argument is guaranteed to be of the same type as this object and have
 4034   /// the same [name].
 4035   ///
 4036   /// The method should return a negative number if this object comes earlier in
 4037   /// the sort order than the argument; and a positive number if it comes later
 4038   /// in the sort order. Returning zero causes the system to use default sort
 4039   /// order.
 4040   @protected
 4041   int doCompare(covariant SemanticsSortKey other);
 4042 
 4043   @override
 4044   void debugFillProperties(DiagnosticPropertiesBuilder properties) {
 4045     super.debugFillProperties(properties);
 4046     properties.add(StringProperty('name', name, defaultValue: null));
 4047   }
 4048 }
 4049 
 4050 /// A [SemanticsSortKey] that sorts simply based on the `double` value it is
 4051 /// given.
 4052 ///
 4053 /// The [OrdinalSortKey] compares itself with other [OrdinalSortKey]s
 4054 /// to sort based on the order it is given.
 4055 ///
 4056 /// [OrdinalSortKey]s are sorted by the optional [name], then by their [order].
 4057 /// If [SemanticsProperties.sortKey] is a [OrdinalSortKey], then all the other
 4058 /// specified sort keys in the same semantics group must also be
 4059 /// [OrdinalSortKey]s.
 4060 ///
 4061 /// Keys with no [name] are compared to other keys with no [name], and will
 4062 /// be traversed before those with a [name].
 4063 ///
 4064 /// The ordinal value [order] is typically a whole number, though it can be
 4065 /// fractional, e.g. in order to fit between two other consecutive whole
 4066 /// numbers. The value must be finite (it cannot be [double.nan],
 4067 /// [double.infinity], or [double.negativeInfinity]).
 4068 class OrdinalSortKey extends SemanticsSortKey {
 4069   /// Creates a const semantics sort key that uses a [double] as its key value.
 4070   ///
 4071   /// The [order] must be a finite number, and must not be null.
 4072   const OrdinalSortKey(
 4073     this.order, {
 4074     String? name,
 4075   }) : assert(order != null),
 4076        assert(order != double.nan),
 4077        assert(order > double.negativeInfinity),
 4078        assert(order < double.infinity),
 4079        super(name: name);
 4080 
 4081   /// Determines the placement of this key in a sequence of keys that defines
 4082   /// the order in which this node is traversed by the platform's accessibility
 4083   /// services.
 4084   ///
 4085   /// Lower values will be traversed first. Keys with the same [name] will be
 4086   /// grouped together and sorted by name first, and then sorted by [order].
 4087   final double order;
 4088 
 4089   @override
 4090   int doCompare(OrdinalSortKey other) {
 4091     if (other.order == null || order == null || other.order == order)
 4092       return 0;
 4093     return order.compareTo(other.order);
 4094   }
 4095 
 4096   @override
 4097   void debugFillProperties(DiagnosticPropertiesBuilder properties) {
 4098     super.debugFillProperties(properties);
 4099     properties.add(DoubleProperty('order', order, defaultValue: null));
 4100   }
 4101 }