[release] Revert "Adds API in semanticsconfiguration to decide how to merge child semanticsConfigurations (#110730)" (#116839) (#116845)
This reverts commit 352ad3a9efccc8c54deb72eb0d7164bfb42b2a49.
diff --git a/packages/flutter/lib/src/material/input_decorator.dart b/packages/flutter/lib/src/material/input_decorator.dart
index 773eb23..4685d88 100644
--- a/packages/flutter/lib/src/material/input_decorator.dart
+++ b/packages/flutter/lib/src/material/input_decorator.dart
@@ -1326,35 +1326,6 @@
return Size.zero;
}
- ChildSemanticsConfigurationsResult _childSemanticsConfigurationDelegate(List<SemanticsConfiguration> childConfigs) {
- final ChildSemanticsConfigurationsResultBuilder builder = ChildSemanticsConfigurationsResultBuilder();
- List<SemanticsConfiguration>? prefixMergeGroup;
- List<SemanticsConfiguration>? suffixMergeGroup;
- for (final SemanticsConfiguration childConfig in childConfigs) {
- if (childConfig.tagsChildrenWith(_InputDecoratorState._kPrefixSemanticsTag)) {
- prefixMergeGroup ??= <SemanticsConfiguration>[];
- prefixMergeGroup.add(childConfig);
- } else if (childConfig.tagsChildrenWith(_InputDecoratorState._kSuffixSemanticsTag)) {
- suffixMergeGroup ??= <SemanticsConfiguration>[];
- suffixMergeGroup.add(childConfig);
- } else {
- builder.markAsMergeUp(childConfig);
- }
- }
- if (prefixMergeGroup != null) {
- builder.markAsSiblingMergeGroup(prefixMergeGroup);
- }
- if (suffixMergeGroup != null) {
- builder.markAsSiblingMergeGroup(suffixMergeGroup);
- }
- return builder.build();
- }
-
- @override
- void describeSemanticsConfiguration(SemanticsConfiguration config) {
- config.childConfigurationsDelegate = _childSemanticsConfigurationDelegate;
- }
-
@override
void performLayout() {
final BoxConstraints constraints = this.constraints;
@@ -1742,16 +1713,12 @@
this.text,
this.style,
this.child,
- this.semanticsSortKey,
- required this.semanticsTag,
});
final bool labelIsFloating;
final String? text;
final TextStyle? style;
final Widget? child;
- final SemanticsSortKey? semanticsSortKey;
- final SemanticsTag semanticsTag;
@override
Widget build(BuildContext context) {
@@ -1761,11 +1728,7 @@
duration: _kTransitionDuration,
curve: _kTransitionCurve,
opacity: labelIsFloating ? 1.0 : 0.0,
- child: Semantics(
- sortKey: semanticsSortKey,
- tagForChildren: semanticsTag,
- child: child ?? (text == null ? null : Text(text!, style: style)),
- ),
+ child: child ?? (text == null ? null : Text(text!, style: style)),
),
);
}
@@ -1936,11 +1899,6 @@
late AnimationController _floatingLabelController;
late AnimationController _shakingLabelController;
final _InputBorderGap _borderGap = _InputBorderGap();
- static const OrdinalSortKey _kPrefixSemanticsSortOrder = OrdinalSortKey(0);
- static const OrdinalSortKey _kInputSemanticsSortOrder = OrdinalSortKey(1);
- static const OrdinalSortKey _kSuffixSemanticsSortOrder = OrdinalSortKey(2);
- static const SemanticsTag _kPrefixSemanticsTag = SemanticsTag('_InputDecoratorState.prefix');
- static const SemanticsTag _kSuffixSemanticsTag = SemanticsTag('_InputDecoratorState.suffix');
@override
void initState() {
@@ -2260,42 +2218,22 @@
),
);
- final bool hasPrefix = decoration.prefix != null || decoration.prefixText != null;
- final bool hasSuffix = decoration.suffix != null || decoration.suffixText != null;
-
- Widget? input = widget.child;
- // If at least two out of the three are visible, it needs semantics sort
- // order.
- final bool needsSemanticsSortOrder = widget._labelShouldWithdraw && (input != null ? (hasPrefix || hasSuffix) : (hasPrefix && hasSuffix));
-
- final Widget? prefix = hasPrefix
- ? _AffixText(
- labelIsFloating: widget._labelShouldWithdraw,
- text: decoration.prefixText,
- style: MaterialStateProperty.resolveAs(decoration.prefixStyle, materialState) ?? hintStyle,
- semanticsSortKey: needsSemanticsSortOrder ? _kPrefixSemanticsSortOrder : null,
- semanticsTag: _kPrefixSemanticsTag,
- child: decoration.prefix,
- )
- : null;
-
- final Widget? suffix = hasSuffix
- ? _AffixText(
- labelIsFloating: widget._labelShouldWithdraw,
- text: decoration.suffixText,
- style: MaterialStateProperty.resolveAs(decoration.suffixStyle, materialState) ?? hintStyle,
- semanticsSortKey: needsSemanticsSortOrder ? _kSuffixSemanticsSortOrder : null,
- semanticsTag: _kSuffixSemanticsTag,
- child: decoration.suffix,
- )
- : null;
-
- if (input != null && needsSemanticsSortOrder) {
- input = Semantics(
- sortKey: _kInputSemanticsSortOrder,
- child: input,
+ final Widget? prefix = decoration.prefix == null && decoration.prefixText == null ? null :
+ _AffixText(
+ labelIsFloating: widget._labelShouldWithdraw,
+ text: decoration.prefixText,
+ style: MaterialStateProperty.resolveAs(decoration.prefixStyle, materialState) ?? hintStyle,
+ child: decoration.prefix,
);
- }
+
+ final Widget? suffix = decoration.suffix == null && decoration.suffixText == null ? null :
+ _AffixText(
+ labelIsFloating: widget._labelShouldWithdraw,
+ text: decoration.suffixText,
+ style: MaterialStateProperty.resolveAs(decoration.suffixStyle, materialState) ?? hintStyle,
+ child: decoration.suffix,
+ );
+
final bool decorationIsDense = decoration.isDense ?? false;
final double iconSize = decorationIsDense ? 18.0 : 24.0;
@@ -2334,9 +2272,7 @@
color: _getPrefixIconColor(themeData, defaults),
size: iconSize,
),
- child: Semantics(
- child: decoration.prefixIcon,
- ),
+ child: decoration.prefixIcon!,
),
),
),
@@ -2361,9 +2297,7 @@
color: _getSuffixIconColor(themeData, defaults),
size: iconSize,
),
- child: Semantics(
- child: decoration.suffixIcon,
- ),
+ child: decoration.suffixIcon!,
),
),
),
@@ -2440,7 +2374,7 @@
isDense: decoration.isDense,
visualDensity: themeData.visualDensity,
icon: icon,
- input: input,
+ input: widget.child,
label: label,
hint: hint,
prefix: prefix,
diff --git a/packages/flutter/lib/src/rendering/object.dart b/packages/flutter/lib/src/rendering/object.dart
index 7449016..c3aa820 100644
--- a/packages/flutter/lib/src/rendering/object.dart
+++ b/packages/flutter/lib/src/rendering/object.dart
@@ -3100,10 +3100,6 @@
if (_cachedSemanticsConfiguration == null) {
_cachedSemanticsConfiguration = SemanticsConfiguration();
describeSemanticsConfiguration(_cachedSemanticsConfiguration!);
- assert(
- !_cachedSemanticsConfiguration!.explicitChildNodes || _cachedSemanticsConfiguration!.childConfigurationsDelegate == null,
- 'A SemanticsConfiguration with explicitChildNode set to true cannot have a non-null childConfigsDelegate.',
- );
}
return _cachedSemanticsConfiguration!;
}
@@ -3165,13 +3161,7 @@
final bool wasSemanticsBoundary = _semantics != null && (_cachedSemanticsConfiguration?.isSemanticBoundary ?? false);
_cachedSemanticsConfiguration = null;
- // The childConfigurationsDelegate may produce sibling nodes to be attached
- // to the parent of this semantics node, thus it can't be a semantics
- // boundary.
- bool isEffectiveSemanticsBoundary =
- _semanticsConfiguration.childConfigurationsDelegate == null &&
- _semanticsConfiguration.isSemanticBoundary &&
- wasSemanticsBoundary;
+ bool isEffectiveSemanticsBoundary = _semanticsConfiguration.isSemanticBoundary && wasSemanticsBoundary;
RenderObject node = this;
while (!isEffectiveSemanticsBoundary && node.parent is RenderObject) {
@@ -3223,13 +3213,11 @@
assert(fragment is _InterestingSemanticsFragment);
final _InterestingSemanticsFragment interestingFragment = fragment as _InterestingSemanticsFragment;
final List<SemanticsNode> result = <SemanticsNode>[];
- final List<SemanticsNode> siblingNodes = <SemanticsNode>[];
interestingFragment.compileChildren(
parentSemanticsClipRect: _semantics?.parentSemanticsClipRect,
parentPaintClipRect: _semantics?.parentPaintClipRect,
elevationAdjustment: _semantics?.elevationAdjustment ?? 0.0,
result: result,
- siblingNodes: siblingNodes,
);
final SemanticsNode node = result.single;
// Fragment only wants to add this node's SemanticsNode to the parent.
@@ -3247,94 +3235,70 @@
bool dropSemanticsOfPreviousSiblings = config.isBlockingSemanticsOfPreviouslyPaintedNodes;
final bool producesForkingFragment = !config.hasBeenAnnotated && !config.isSemanticBoundary;
+ final List<_InterestingSemanticsFragment> fragments = <_InterestingSemanticsFragment>[];
+ final Set<_InterestingSemanticsFragment> toBeMarkedExplicit = <_InterestingSemanticsFragment>{};
final bool childrenMergeIntoParent = mergeIntoParent || config.isMergingSemanticsOfDescendants;
- final List<SemanticsConfiguration> childConfigurations = <SemanticsConfiguration>[];
- final bool explicitChildNode = config.explicitChildNodes || parent is! RenderObject;
- final bool hasChildConfigurationsDelegate = config.childConfigurationsDelegate != null;
- final Map<SemanticsConfiguration, _InterestingSemanticsFragment> configToFragment = <SemanticsConfiguration, _InterestingSemanticsFragment>{};
- final List<_InterestingSemanticsFragment> mergeUpFragments = <_InterestingSemanticsFragment>[];
- final List<List<_InterestingSemanticsFragment>> siblingMergeFragmentGroups = <List<_InterestingSemanticsFragment>>[];
+
visitChildrenForSemantics((RenderObject renderChild) {
assert(!_needsLayout);
final _SemanticsFragment parentFragment = renderChild._getSemanticsForParent(
mergeIntoParent: childrenMergeIntoParent,
);
if (parentFragment.dropsSemanticsOfPreviousSiblings) {
- childConfigurations.clear();
- mergeUpFragments.clear();
- siblingMergeFragmentGroups.clear();
+ fragments.clear();
+ toBeMarkedExplicit.clear();
if (!config.isSemanticBoundary) {
dropSemanticsOfPreviousSiblings = true;
}
}
- for (final _InterestingSemanticsFragment fragment in parentFragment.mergeUpFragments) {
+ // Figure out which child fragments are to be made explicit.
+ for (final _InterestingSemanticsFragment fragment in parentFragment.interestingFragments) {
+ fragments.add(fragment);
fragment.addAncestor(this);
fragment.addTags(config.tagsForChildren);
- if (hasChildConfigurationsDelegate && fragment.config != null) {
- // This fragment need to go through delegate to determine whether it
- // merge up or not.
- childConfigurations.add(fragment.config!);
- configToFragment[fragment.config!] = fragment;
- } else {
- mergeUpFragments.add(fragment);
+ if (config.explicitChildNodes || parent is! RenderObject) {
+ fragment.markAsExplicit();
+ continue;
}
- }
- if (parentFragment is _ContainerSemanticsFragment) {
- // Container fragments needs to propagate sibling merge group to be
- // compiled by _SwitchableSemanticsFragment.
- for (final List<_InterestingSemanticsFragment> siblingMergeGroup in parentFragment.siblingMergeGroups) {
- for (final _InterestingSemanticsFragment siblingMergingFragment in siblingMergeGroup) {
- siblingMergingFragment.addAncestor(this);
- siblingMergingFragment.addTags(config.tagsForChildren);
+ if (!fragment.hasConfigForParent || producesForkingFragment) {
+ continue;
+ }
+ if (!config.isCompatibleWith(fragment.config)) {
+ toBeMarkedExplicit.add(fragment);
+ }
+ final int siblingLength = fragments.length - 1;
+ for (int i = 0; i < siblingLength; i += 1) {
+ final _InterestingSemanticsFragment siblingFragment = fragments[i];
+ if (!fragment.config!.isCompatibleWith(siblingFragment.config)) {
+ toBeMarkedExplicit.add(fragment);
+ toBeMarkedExplicit.add(siblingFragment);
}
- siblingMergeFragmentGroups.add(siblingMergeGroup);
}
}
});
- assert(hasChildConfigurationsDelegate || configToFragment.isEmpty);
-
- if (explicitChildNode) {
- for (final _InterestingSemanticsFragment fragment in mergeUpFragments) {
- fragment.markAsExplicit();
- }
- } else if (hasChildConfigurationsDelegate && childConfigurations.isNotEmpty) {
- final ChildSemanticsConfigurationsResult result = config.childConfigurationsDelegate!(childConfigurations);
- mergeUpFragments.addAll(
- result.mergeUp.map<_InterestingSemanticsFragment>((SemanticsConfiguration config) => configToFragment[config]!),
- );
- for (final Iterable<SemanticsConfiguration> group in result.siblingMergeGroups) {
- siblingMergeFragmentGroups.add(
- group.map<_InterestingSemanticsFragment>((SemanticsConfiguration config) => configToFragment[config]!).toList()
- );
- }
+ for (final _InterestingSemanticsFragment fragment in toBeMarkedExplicit) {
+ fragment.markAsExplicit();
}
_needsSemanticsUpdate = false;
- final _SemanticsFragment result;
+ _SemanticsFragment result;
if (parent is! RenderObject) {
assert(!config.hasBeenAnnotated);
assert(!mergeIntoParent);
- assert(siblingMergeFragmentGroups.isEmpty);
- _marksExplicitInMergeGroup(mergeUpFragments, isMergeUp: true);
- siblingMergeFragmentGroups.forEach(_marksExplicitInMergeGroup);
result = _RootSemanticsFragment(
owner: this,
dropsSemanticsOfPreviousSiblings: dropSemanticsOfPreviousSiblings,
);
} else if (producesForkingFragment) {
result = _ContainerSemanticsFragment(
- siblingMergeGroups: siblingMergeFragmentGroups,
dropsSemanticsOfPreviousSiblings: dropSemanticsOfPreviousSiblings,
);
} else {
- _marksExplicitInMergeGroup(mergeUpFragments, isMergeUp: true);
- siblingMergeFragmentGroups.forEach(_marksExplicitInMergeGroup);
result = _SwitchableSemanticsFragment(
config: config,
mergeIntoParent: mergeIntoParent,
- siblingMergeGroups: siblingMergeFragmentGroups,
owner: this,
dropsSemanticsOfPreviousSiblings: dropSemanticsOfPreviousSiblings,
);
@@ -3343,32 +3307,10 @@
fragment.markAsExplicit();
}
}
- result.addAll(mergeUpFragments);
- return result;
- }
- void _marksExplicitInMergeGroup(List<_InterestingSemanticsFragment> mergeGroup, {bool isMergeUp = false}) {
- final Set<_InterestingSemanticsFragment> toBeExplicit = <_InterestingSemanticsFragment>{};
- for (int i = 0; i < mergeGroup.length; i += 1) {
- final _InterestingSemanticsFragment fragment = mergeGroup[i];
- if (!fragment.hasConfigForParent) {
- continue;
- }
- if (isMergeUp && !_semanticsConfiguration.isCompatibleWith(fragment.config)) {
- toBeExplicit.add(fragment);
- }
- final int siblingLength = i;
- for (int j = 0; j < siblingLength; j += 1) {
- final _InterestingSemanticsFragment siblingFragment = mergeGroup[j];
- if (!fragment.config!.isCompatibleWith(siblingFragment.config)) {
- toBeExplicit.add(fragment);
- toBeExplicit.add(siblingFragment);
- }
- }
- }
- for (final _InterestingSemanticsFragment fragment in toBeExplicit) {
- fragment.markAsExplicit();
- }
+ result.addAll(fragments);
+
+ return result;
}
/// Called when collecting the semantics of this node.
@@ -4043,9 +3985,8 @@
/// * [_ContainerSemanticsFragment]: a container class to transport the semantic
/// information of multiple [_InterestingSemanticsFragment] to a parent.
abstract class _SemanticsFragment {
- _SemanticsFragment({
- required this.dropsSemanticsOfPreviousSiblings,
- }) : assert (dropsSemanticsOfPreviousSiblings != null);
+ _SemanticsFragment({ required this.dropsSemanticsOfPreviousSiblings })
+ : assert (dropsSemanticsOfPreviousSiblings != null);
/// Incorporate the fragments of children into this fragment.
void addAll(Iterable<_InterestingSemanticsFragment> fragments);
@@ -4061,29 +4002,25 @@
/// Returns [_InterestingSemanticsFragment] describing the actual semantic
/// information that this fragment wants to add to the parent.
- List<_InterestingSemanticsFragment> get mergeUpFragments;
+ List<_InterestingSemanticsFragment> get interestingFragments;
}
/// A container used when a [RenderObject] wants to add multiple independent
/// [_InterestingSemanticsFragment] to its parent.
///
/// The [_InterestingSemanticsFragment] to be added to the parent can be
-/// obtained via [mergeUpFragments].
+/// obtained via [interestingFragments].
class _ContainerSemanticsFragment extends _SemanticsFragment {
- _ContainerSemanticsFragment({
- required super.dropsSemanticsOfPreviousSiblings,
- required this.siblingMergeGroups,
- });
- final List<List<_InterestingSemanticsFragment>> siblingMergeGroups;
+ _ContainerSemanticsFragment({ required super.dropsSemanticsOfPreviousSiblings });
@override
void addAll(Iterable<_InterestingSemanticsFragment> fragments) {
- mergeUpFragments.addAll(fragments);
+ interestingFragments.addAll(fragments);
}
@override
- final List<_InterestingSemanticsFragment> mergeUpFragments = <_InterestingSemanticsFragment>[];
+ final List<_InterestingSemanticsFragment> interestingFragments = <_InterestingSemanticsFragment>[];
}
/// A [_SemanticsFragment] that describes which concrete semantic information
@@ -4120,7 +4057,6 @@
required Rect? parentPaintClipRect,
required double elevationAdjustment,
required List<SemanticsNode> result,
- required List<SemanticsNode> siblingNodes,
});
/// The [SemanticsConfiguration] the child wants to merge into the parent's
@@ -4150,7 +4086,7 @@
bool get hasConfigForParent => config != null;
@override
- List<_InterestingSemanticsFragment> get mergeUpFragments => <_InterestingSemanticsFragment>[this];
+ List<_InterestingSemanticsFragment> get interestingFragments => <_InterestingSemanticsFragment>[this];
Set<SemanticsTag>? _tagsForChildren;
@@ -4188,13 +4124,7 @@
});
@override
- void compileChildren({
- Rect? parentSemanticsClipRect,
- Rect? parentPaintClipRect,
- required double elevationAdjustment,
- required List<SemanticsNode> result,
- required List<SemanticsNode> siblingNodes,
- }) {
+ void compileChildren({ Rect? parentSemanticsClipRect, Rect? parentPaintClipRect, required double elevationAdjustment, required List<SemanticsNode> result }) {
assert(_tagsForChildren == null || _tagsForChildren!.isEmpty);
assert(parentSemanticsClipRect == null);
assert(parentPaintClipRect == null);
@@ -4220,11 +4150,8 @@
parentPaintClipRect: parentPaintClipRect,
elevationAdjustment: 0.0,
result: children,
- siblingNodes: siblingNodes,
);
}
- // Root node does not have a parent and thus can't attach sibling nodes.
- assert(siblingNodes.isEmpty);
node.updateWith(config: null, childrenInInversePaintOrder: children);
// The root node is the only semantics node allowed to be invisible. This
@@ -4274,11 +4201,9 @@
_SwitchableSemanticsFragment({
required bool mergeIntoParent,
required SemanticsConfiguration config,
- required List<List<_InterestingSemanticsFragment>> siblingMergeGroups,
required super.owner,
required super.dropsSemanticsOfPreviousSiblings,
- }) : _siblingMergeGroups = siblingMergeGroups,
- _mergeIntoParent = mergeIntoParent,
+ }) : _mergeIntoParent = mergeIntoParent,
_config = config,
assert(mergeIntoParent != null),
assert(config != null);
@@ -4286,126 +4211,14 @@
final bool _mergeIntoParent;
SemanticsConfiguration _config;
bool _isConfigWritable = false;
- bool _mergesToSibling = false;
-
- final List<List<_InterestingSemanticsFragment>> _siblingMergeGroups;
-
- void _mergeSiblingGroup(Rect? parentSemanticsClipRect, Rect? parentPaintClipRect, List<SemanticsNode> result, Set<int> usedSemanticsIds) {
- for (final List<_InterestingSemanticsFragment> group in _siblingMergeGroups) {
- Rect? rect;
- Rect? semanticsClipRect;
- Rect? paintClipRect;
- SemanticsConfiguration? configuration;
- // Use empty set because the _tagsForChildren may not contains all of the
- // tags if this fragment is not explicit. The _tagsForChildren are added
- // to sibling nodes at the end of compileChildren if this fragment is
- // explicit.
- final Set<SemanticsTag> tags = <SemanticsTag>{};
- SemanticsNode? node;
- for (final _InterestingSemanticsFragment fragment in group) {
- if (fragment.config != null) {
- final _SwitchableSemanticsFragment switchableFragment = fragment as _SwitchableSemanticsFragment;
- switchableFragment._mergesToSibling = true;
- node ??= fragment.owner._semantics;
- if (configuration == null) {
- switchableFragment._ensureConfigIsWritable();
- configuration = switchableFragment.config;
- } else {
- configuration.absorb(switchableFragment.config!);
- }
- // It is a child fragment of a _SwitchableFragment, it must have a
- // geometry.
- final _SemanticsGeometry geometry = switchableFragment._computeSemanticsGeometry(
- parentSemanticsClipRect: parentSemanticsClipRect,
- parentPaintClipRect: parentPaintClipRect,
- )!;
- final Rect fragmentRect = MatrixUtils.transformRect(geometry.transform, geometry.rect);
- if (rect == null) {
- rect = fragmentRect;
- } else {
- rect = rect.expandToInclude(fragmentRect);
- }
- if (geometry.semanticsClipRect != null) {
- final Rect rect = MatrixUtils.transformRect(geometry.transform, geometry.semanticsClipRect!);
- if (semanticsClipRect == null) {
- semanticsClipRect = rect;
- } else {
- semanticsClipRect = semanticsClipRect.intersect(rect);
- }
- }
- if (geometry.paintClipRect != null) {
- final Rect rect = MatrixUtils.transformRect(geometry.transform, geometry.paintClipRect!);
- if (paintClipRect == null) {
- paintClipRect = rect;
- } else {
- paintClipRect = paintClipRect.intersect(rect);
- }
- }
- if (switchableFragment._tagsForChildren != null) {
- tags.addAll(switchableFragment._tagsForChildren!);
- }
- }
- }
- // Can be null if all fragments in group are marked as explicit.
- if (configuration != null && !rect!.isEmpty) {
- if (node == null || usedSemanticsIds.contains(node.id)) {
- node = SemanticsNode(showOnScreen: owner.showOnScreen);
- }
- usedSemanticsIds.add(node.id);
- node
- ..tags = tags
- ..rect = rect
- ..transform = null // Will be set when compiling immediate parent node.
- ..parentSemanticsClipRect = semanticsClipRect
- ..parentPaintClipRect = paintClipRect;
- for (final _InterestingSemanticsFragment fragment in group) {
- if (fragment.config != null) {
- fragment.owner._semantics = node;
- }
- }
- node.updateWith(config: configuration);
- result.add(node);
- }
- }
- }
-
final List<_InterestingSemanticsFragment> _children = <_InterestingSemanticsFragment>[];
@override
- void compileChildren({
- Rect? parentSemanticsClipRect,
- Rect? parentPaintClipRect,
- required double elevationAdjustment,
- required List<SemanticsNode> result,
- required List<SemanticsNode> siblingNodes,
- }) {
- final Set<int> usedSemanticsIds = <int>{};
- Iterable<_InterestingSemanticsFragment> compilingFragments = _children;
- for (final List<_InterestingSemanticsFragment> siblingGroup in _siblingMergeGroups) {
- compilingFragments = compilingFragments.followedBy(siblingGroup);
- }
+ void compileChildren({ Rect? parentSemanticsClipRect, Rect? parentPaintClipRect, required double elevationAdjustment, required List<SemanticsNode> result }) {
if (!_isExplicit) {
- if (!_mergesToSibling) {
- owner._semantics = null;
- }
- _mergeSiblingGroup(
- parentSemanticsClipRect,
- parentPaintClipRect,
- siblingNodes,
- usedSemanticsIds,
- );
- for (final _InterestingSemanticsFragment fragment in compilingFragments) {
+ owner._semantics = null;
+ for (final _InterestingSemanticsFragment fragment in _children) {
assert(_ancestorChain.first == fragment._ancestorChain.last);
- if (fragment is _SwitchableSemanticsFragment) {
- // Cached semantics node may be part of sibling merging group prior
- // to this update. In this case, the semantics node may continue to
- // be reused in that sibling merging group.
- if (fragment._isExplicit &&
- fragment.owner._semantics != null &&
- usedSemanticsIds.contains(fragment.owner._semantics!.id)) {
- fragment.owner._semantics = null;
- }
- }
fragment._ancestorChain.addAll(_ancestorChain.skip(1));
fragment.compileChildren(
parentSemanticsClipRect: parentSemanticsClipRect,
@@ -4415,16 +4228,14 @@
// its children are placed at the elevation dictated by this config.
elevationAdjustment: elevationAdjustment + _config.elevation,
result: result,
- siblingNodes: siblingNodes,
);
}
return;
}
- final _SemanticsGeometry? geometry = _computeSemanticsGeometry(
- parentSemanticsClipRect: parentSemanticsClipRect,
- parentPaintClipRect: parentPaintClipRect,
- );
+ final _SemanticsGeometry? geometry = _needsGeometryUpdate
+ ? _SemanticsGeometry(parentSemanticsClipRect: parentSemanticsClipRect, parentPaintClipRect: parentPaintClipRect, ancestors: _ancestorChain)
+ : null;
if (!_mergeIntoParent && (geometry?.dropFromTree ?? false)) {
return; // Drop the node, it's not going to be visible.
@@ -4453,66 +4264,22 @@
_config.isHidden = true;
}
}
+
final List<SemanticsNode> children = <SemanticsNode>[];
- _mergeSiblingGroup(
- node.parentSemanticsClipRect,
- node.parentPaintClipRect,
- siblingNodes,
- usedSemanticsIds,
- );
- for (final _InterestingSemanticsFragment fragment in compilingFragments) {
- if (fragment is _SwitchableSemanticsFragment) {
- // Cached semantics node may be part of sibling merging group prior
- // to this update. In this case, the semantics node may continue to
- // be reused in that sibling merging group.
- if (fragment._isExplicit &&
- fragment.owner._semantics != null &&
- usedSemanticsIds.contains(fragment.owner._semantics!.id)) {
- fragment.owner._semantics = null;
- }
- }
- final List<SemanticsNode> childSiblingNodes = <SemanticsNode>[];
+ for (final _InterestingSemanticsFragment fragment in _children) {
fragment.compileChildren(
parentSemanticsClipRect: node.parentSemanticsClipRect,
parentPaintClipRect: node.parentPaintClipRect,
elevationAdjustment: 0.0,
result: children,
- siblingNodes: childSiblingNodes,
);
- siblingNodes.addAll(childSiblingNodes);
}
-
if (_config.isSemanticBoundary) {
owner.assembleSemanticsNode(node, _config, children);
} else {
node.updateWith(config: _config, childrenInInversePaintOrder: children);
}
result.add(node);
- // Sibling node needs to attach to the parent of an explicit node.
- for (final SemanticsNode siblingNode in siblingNodes) {
- // sibling nodes are in the same coordinate of the immediate explicit node.
- // They need to share the same transform if they are going to attach to the
- // parent of the immediate explicit node.
- assert(siblingNode.transform == null);
- siblingNode
- ..transform = node.transform
- ..isMergedIntoParent = node.isMergedIntoParent;
- if (_tagsForChildren != null) {
- siblingNode.tags ??= <SemanticsTag>{};
- siblingNode.tags!.addAll(_tagsForChildren!);
- }
- }
- result.addAll(siblingNodes);
- siblingNodes.clear();
- }
-
- _SemanticsGeometry? _computeSemanticsGeometry({
- required Rect? parentSemanticsClipRect,
- required Rect? parentPaintClipRect,
- }) {
- return _needsGeometryUpdate
- ? _SemanticsGeometry(parentSemanticsClipRect: parentSemanticsClipRect, parentPaintClipRect: parentPaintClipRect, ancestors: _ancestorChain)
- : null;
}
@override
diff --git a/packages/flutter/lib/src/semantics/semantics.dart b/packages/flutter/lib/src/semantics/semantics.dart
index 041c70d..bed9eea 100644
--- a/packages/flutter/lib/src/semantics/semantics.dart
+++ b/packages/flutter/lib/src/semantics/semantics.dart
@@ -6,7 +6,6 @@
import 'dart:ui' as ui;
import 'dart:ui' show Offset, Rect, SemanticsAction, SemanticsFlag, StringAttribute, TextDirection;
-import 'package:collection/collection.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/painting.dart' show MatrixUtils, TransformProperty;
import 'package:flutter/services.dart';
@@ -54,20 +53,6 @@
/// Used by [SemanticsOwner.onSemanticsUpdate].
typedef SemanticsUpdateCallback = void Function(ui.SemanticsUpdate update);
-/// Signature for the [SemanticsConfiguration.childConfigurationsDelegate].
-///
-/// The input list contains all [SemanticsConfiguration]s that rendering
-/// children want to merge upward. One can tag a render child with a
-/// [SemanticsTag] and look up its [SemanticsConfiguration]s through
-/// [SemanticsConfiguration.tagsChildrenWith].
-///
-/// The return value is the arrangement of these configs, including which
-/// configs continue to merge upward and which configs form sibling merge group.
-///
-/// Use [ChildSemanticsConfigurationsResultBuilder] to generate the return
-/// value.
-typedef ChildSemanticsConfigurationsDelegate = ChildSemanticsConfigurationsResult Function(List<SemanticsConfiguration>);
-
/// A tag for a [SemanticsNode].
///
/// Tags can be interpreted by the parent of a [SemanticsNode]
@@ -100,89 +85,6 @@
String toString() => '${objectRuntimeType(this, 'SemanticsTag')}($name)';
}
-/// The result that contains the arrangement for the child
-/// [SemanticsConfiguration]s.
-///
-/// When the [PipelineOwner] builds the semantics tree, it uses the returned
-/// [ChildSemanticsConfigurationsResult] from
-/// [SemanticsConfiguration.childConfigurationsDelegate] to decide how semantics nodes
-/// should form.
-///
-/// Use [ChildSemanticsConfigurationsResultBuilder] to build the result.
-class ChildSemanticsConfigurationsResult {
- ChildSemanticsConfigurationsResult._(this.mergeUp, this.siblingMergeGroups);
-
- /// Returns the [SemanticsConfiguration]s that are supposed to be merged into
- /// the parent semantics node.
- ///
- /// [SemanticsConfiguration]s that are either semantics boundaries or are
- /// conflicting with other [SemanticsConfiguration]s will form explicit
- /// semantics nodes. All others will be merged into the parent.
- final List<SemanticsConfiguration> mergeUp;
-
- /// The groups of child semantics configurations that want to merge together
- /// and form a sibling [SemanticsNode].
- ///
- /// All the [SemanticsConfiguration]s in a given group that are either
- /// semantics boundaries or are conflicting with other
- /// [SemanticsConfiguration]s of the same group will be excluded from the
- /// sibling merge group and form independent semantics nodes as usual.
- ///
- /// The result [SemanticsNode]s from the merges are attached as the sibling
- /// nodes of the immediate parent semantics node. For example, a `RenderObjectA`
- /// has a rendering child, `RenderObjectB`. If both of them form their own
- /// semantics nodes, `SemanticsNodeA` and `SemanticsNodeB`, any semantics node
- /// created from sibling merge groups of `RenderObjectB` will be attach to
- /// `SemanticsNodeA` as a sibling of `SemanticsNodeB`.
- final List<List<SemanticsConfiguration>> siblingMergeGroups;
-}
-
-/// The builder to build a [ChildSemanticsConfigurationsResult] based on its
-/// annotations.
-///
-/// To use this builder, one can use [markAsMergeUp] and
-/// [markAsSiblingMergeGroup] to annotate the arrangement of
-/// [SemanticsConfiguration]s. Once all the configs are annotated, use [build]
-/// to generate the [ChildSemanticsConfigurationsResult].
-class ChildSemanticsConfigurationsResultBuilder {
- /// Creates a [ChildSemanticsConfigurationsResultBuilder].
- ChildSemanticsConfigurationsResultBuilder();
-
- final List<SemanticsConfiguration> _mergeUp = <SemanticsConfiguration>[];
- final List<List<SemanticsConfiguration>> _siblingMergeGroups = <List<SemanticsConfiguration>>[];
-
- /// Marks the [SemanticsConfiguration] to be merged into the parent semantics
- /// node.
- ///
- /// The [SemanticsConfiguration] will be added to the
- /// [ChildSemanticsConfigurationsResult.mergeUp] that this builder builds.
- void markAsMergeUp(SemanticsConfiguration config) => _mergeUp.add(config);
-
- /// Marks a group of [SemanticsConfiguration]s to merge together
- /// and form a sibling [SemanticsNode].
- ///
- /// The group of [SemanticsConfiguration]s will be added to the
- /// [ChildSemanticsConfigurationsResult.siblingMergeGroups] that this builder builds.
- void markAsSiblingMergeGroup(List<SemanticsConfiguration> configs) => _siblingMergeGroups.add(configs);
-
- /// Builds a [ChildSemanticsConfigurationsResult] contains the arrangement.
- ChildSemanticsConfigurationsResult build() {
- assert((){
- final Set<SemanticsConfiguration> seenConfigs = <SemanticsConfiguration>{};
- for (final SemanticsConfiguration config in <SemanticsConfiguration>[..._mergeUp, ..._siblingMergeGroups.flattened]) {
- assert(
- seenConfigs.add(config),
- 'Duplicated SemanticsConfigurations. This can happen if the same '
- 'SemanticsConfiguration was marked twice in markAsMergeUp and/or '
- 'markAsSiblingMergeGroup'
- );
- }
- return true;
- }());
- return ChildSemanticsConfigurationsResult._(_mergeUp, _siblingMergeGroups);
- }
-}
-
/// An identifier of a custom semantics action.
///
/// Custom semantics actions can be provided to make complex user
@@ -3822,25 +3724,6 @@
_onDidLoseAccessibilityFocus = value;
}
- /// A delegate that decides how to handle [SemanticsConfiguration]s produced
- /// in the widget subtree.
- ///
- /// The [SemanticsConfiguration]s are produced by rendering objects in the
- /// subtree and want to merge up to their parent. This delegate can decide
- /// which of these should be merged together to form sibling SemanticsNodes and
- /// which of them should be merged upwards into the parent SemanticsNode.
- ///
- /// The input list of [SemanticsConfiguration]s can be empty if the rendering
- /// object of this semantics configuration is a leaf node.
- ChildSemanticsConfigurationsDelegate? get childConfigurationsDelegate => _childConfigurationsDelegate;
- ChildSemanticsConfigurationsDelegate? _childConfigurationsDelegate;
- set childConfigurationsDelegate(ChildSemanticsConfigurationsDelegate? value) {
- assert(value != null);
- _childConfigurationsDelegate = value;
- // Setting the childConfigsDelegate does not annotate any meaningful
- // semantics information of the config.
- }
-
/// Returns the action handler registered for [action] or null if none was
/// registered.
SemanticsActionHandler? getActionHandler(SemanticsAction action) => _actions[action];
@@ -4565,11 +4448,6 @@
/// * [addTagForChildren] to add a tag and for more information about their
/// usage.
Iterable<SemanticsTag>? get tagsForChildren => _tagsForChildren;
-
- /// Whether this configuration will tag the child semantics nodes with a
- /// given [SemanticsTag].
- bool tagsChildrenWith(SemanticsTag tag) => _tagsForChildren?.contains(tag) ?? false;
-
Set<SemanticsTag>? _tagsForChildren;
/// Specifies a [SemanticsTag] that this configuration wants to apply to all
diff --git a/packages/flutter/test/material/text_field_test.dart b/packages/flutter/test/material/text_field_test.dart
index 1cf7a24..944e444 100644
--- a/packages/flutter/test/material/text_field_test.dart
+++ b/packages/flutter/test/material/text_field_test.dart
@@ -4375,47 +4375,6 @@
expect(prefixText.style, prefixStyle);
});
- testWidgets('TextField prefix and suffix create a sibling node', (WidgetTester tester) async {
- final SemanticsTester semantics = SemanticsTester(tester);
- await tester.pumpWidget(
- overlay(
- child: TextField(
- controller: TextEditingController(text: 'some text'),
- decoration: const InputDecoration(
- prefixText: 'Prefix',
- suffixText: 'Suffix',
- ),
- ),
- ),
- );
-
- expect(semantics, hasSemantics(TestSemantics.root(
- children: <TestSemantics>[
- TestSemantics.rootChild(
- id: 2,
- textDirection: TextDirection.ltr,
- label: 'Prefix',
- ),
- TestSemantics.rootChild(
- id: 1,
- textDirection: TextDirection.ltr,
- value: 'some text',
- actions: <SemanticsAction>[
- SemanticsAction.tap,
- ],
- flags: <SemanticsFlag>[
- SemanticsFlag.isTextField,
- ],
- ),
- TestSemantics.rootChild(
- id: 3,
- textDirection: TextDirection.ltr,
- label: 'Suffix',
- ),
- ],
- ), ignoreTransform: true, ignoreRect: true));
- });
-
testWidgets('TextField with specified suffixStyle', (WidgetTester tester) async {
final TextStyle suffixStyle = TextStyle(
color: Colors.pink[500],
diff --git a/packages/flutter/test/widgets/scrollable_test.dart b/packages/flutter/test/widgets/scrollable_test.dart
index 4b5e379..12b1839 100644
--- a/packages/flutter/test/widgets/scrollable_test.dart
+++ b/packages/flutter/test/widgets/scrollable_test.dart
@@ -1429,51 +1429,6 @@
handle.dispose();
});
- testWidgets('Two panel semantics is added to the sibling nodes of direct children', (WidgetTester tester) async {
- final SemanticsHandle handle = tester.ensureSemantics();
- final UniqueKey key = UniqueKey();
- await tester.pumpWidget(MaterialApp(
- home: Scaffold(
- body: ListView(
- key: key,
- children: const <Widget>[
- TextField(
- autofocus: true,
- decoration: InputDecoration(
- prefixText: 'prefix',
- ),
- ),
- ],
- ),
- ),
- ));
- // Wait for focus.
- await tester.pumpAndSettle();
-
- final SemanticsNode scrollableNode = tester.getSemantics(find.byKey(key));
- SemanticsNode? intermediateNode;
- scrollableNode.visitChildren((SemanticsNode node) {
- intermediateNode = node;
- return true;
- });
- SemanticsNode? syntheticScrollableNode;
- intermediateNode!.visitChildren((SemanticsNode node) {
- syntheticScrollableNode = node;
- return true;
- });
- expect(syntheticScrollableNode!.hasFlag(ui.SemanticsFlag.hasImplicitScrolling), isTrue);
-
- int numberOfChild = 0;
- syntheticScrollableNode!.visitChildren((SemanticsNode node) {
- expect(node.isTagged(RenderViewport.useTwoPaneSemantics), isTrue);
- numberOfChild += 1;
- return true;
- });
- expect(numberOfChild, 2);
-
- handle.dispose();
- });
-
testWidgets('Scroll inertia cancel event', (WidgetTester tester) async {
await pumpTest(tester, null);
await tester.fling(find.byType(Scrollable), const Offset(0.0, -dragOffset), 1000.0);
diff --git a/packages/flutter/test/widgets/semantics_child_configs_delegate_test.dart b/packages/flutter/test/widgets/semantics_child_configs_delegate_test.dart
deleted file mode 100644
index b09c4cd..0000000
--- a/packages/flutter/test/widgets/semantics_child_configs_delegate_test.dart
+++ /dev/null
@@ -1,259 +0,0 @@
-// Copyright 2014 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import 'package:flutter/rendering.dart';
-import 'package:flutter/widgets.dart';
-import 'package:flutter_test/flutter_test.dart';
-
-import 'semantics_tester.dart';
-
-void main() {
- testWidgets('Semantics can merge sibling group', (WidgetTester tester) async {
- final SemanticsTester semantics = SemanticsTester(tester);
- const SemanticsTag first = SemanticsTag('1');
- const SemanticsTag second = SemanticsTag('2');
- const SemanticsTag third = SemanticsTag('3');
- ChildSemanticsConfigurationsResult delegate(List<SemanticsConfiguration> configs) {
- expect(configs.length, 3);
- final ChildSemanticsConfigurationsResultBuilder builder = ChildSemanticsConfigurationsResultBuilder();
- final List<SemanticsConfiguration> sibling = <SemanticsConfiguration>[];
- // Merge first and third
- for (final SemanticsConfiguration config in configs) {
- if (config.tagsChildrenWith(first) || config.tagsChildrenWith(third)) {
- sibling.add(config);
- } else {
- builder.markAsMergeUp(config);
- }
- }
- builder.markAsSiblingMergeGroup(sibling);
- return builder.build();
- }
- await tester.pumpWidget(
- Directionality(
- textDirection: TextDirection.ltr,
- child: Semantics(
- label: 'parent',
- child: TestConfigDelegate(
- delegate: delegate,
- child: Column(
- children: <Widget>[
- Semantics(
- label: '1',
- tagForChildren: first,
- child: const SizedBox(width: 100, height: 100),
- // this tests that empty nodes disappear
- ),
- Semantics(
- label: '2',
- tagForChildren: second,
- child: const SizedBox(width: 100, height: 100),
- ),
- Semantics(
- label: '3',
- tagForChildren: third,
- child: const SizedBox(width: 100, height: 100),
- ),
- ],
- ),
- ),
- ),
- ),
- );
-
- expect(semantics, hasSemantics(TestSemantics.root(
- children: <TestSemantics>[
- TestSemantics.rootChild(
- label: 'parent\n2',
- ),
- TestSemantics.rootChild(
- label: '1\n3',
- ),
- ],
- ), ignoreId: true, ignoreRect: true, ignoreTransform: true));
- });
-
- testWidgets('Semantics can drop semantics config', (WidgetTester tester) async {
- final SemanticsTester semantics = SemanticsTester(tester);
- const SemanticsTag first = SemanticsTag('1');
- const SemanticsTag second = SemanticsTag('2');
- const SemanticsTag third = SemanticsTag('3');
- ChildSemanticsConfigurationsResult delegate(List<SemanticsConfiguration> configs) {
- final ChildSemanticsConfigurationsResultBuilder builder = ChildSemanticsConfigurationsResultBuilder();
- // Merge first and third
- for (final SemanticsConfiguration config in configs) {
- if (config.tagsChildrenWith(first) || config.tagsChildrenWith(third)) {
- continue;
- }
- builder.markAsMergeUp(config);
- }
- return builder.build();
- }
- await tester.pumpWidget(
- Directionality(
- textDirection: TextDirection.ltr,
- child: Semantics(
- label: 'parent',
- child: TestConfigDelegate(
- delegate: delegate,
- child: Column(
- children: <Widget>[
- Semantics(
- label: '1',
- tagForChildren: first,
- child: const SizedBox(width: 100, height: 100),
- // this tests that empty nodes disappear
- ),
- Semantics(
- label: '2',
- tagForChildren: second,
- child: const SizedBox(width: 100, height: 100),
- ),
- Semantics(
- label: '3',
- tagForChildren: third,
- child: const SizedBox(width: 100, height: 100),
- ),
- ],
- ),
- ),
- ),
- ),
- );
-
- expect(semantics, hasSemantics(TestSemantics.root(
- children: <TestSemantics>[
- TestSemantics.rootChild(
- label: 'parent\n2',
- ),
- ],
- ), ignoreId: true, ignoreRect: true, ignoreTransform: true));
- });
-
- testWidgets('Semantics throws when mark the same config twice case 1', (WidgetTester tester) async {
- const SemanticsTag first = SemanticsTag('1');
- const SemanticsTag second = SemanticsTag('2');
- const SemanticsTag third = SemanticsTag('3');
- ChildSemanticsConfigurationsResult delegate(List<SemanticsConfiguration> configs) {
- final ChildSemanticsConfigurationsResultBuilder builder = ChildSemanticsConfigurationsResultBuilder();
- // Marks the same one twice.
- builder.markAsMergeUp(configs.first);
- builder.markAsMergeUp(configs.first);
- return builder.build();
- }
- await tester.pumpWidget(
- Directionality(
- textDirection: TextDirection.ltr,
- child: Semantics(
- label: 'parent',
- child: TestConfigDelegate(
- delegate: delegate,
- child: Column(
- children: <Widget>[
- Semantics(
- label: '1',
- tagForChildren: first,
- child: const SizedBox(width: 100, height: 100),
- // this tests that empty nodes disappear
- ),
- Semantics(
- label: '2',
- tagForChildren: second,
- child: const SizedBox(width: 100, height: 100),
- ),
- Semantics(
- label: '3',
- tagForChildren: third,
- child: const SizedBox(width: 100, height: 100),
- ),
- ],
- ),
- ),
- ),
- ),
- );
-
- expect(tester.takeException(), isAssertionError);
- });
-
- testWidgets('Semantics throws when mark the same config twice case 2', (WidgetTester tester) async {
- const SemanticsTag first = SemanticsTag('1');
- const SemanticsTag second = SemanticsTag('2');
- const SemanticsTag third = SemanticsTag('3');
- ChildSemanticsConfigurationsResult delegate(List<SemanticsConfiguration> configs) {
- final ChildSemanticsConfigurationsResultBuilder builder = ChildSemanticsConfigurationsResultBuilder();
- // Marks the same one twice.
- builder.markAsMergeUp(configs.first);
- builder.markAsSiblingMergeGroup(<SemanticsConfiguration>[configs.first]);
- return builder.build();
- }
- await tester.pumpWidget(
- Directionality(
- textDirection: TextDirection.ltr,
- child: Semantics(
- label: 'parent',
- child: TestConfigDelegate(
- delegate: delegate,
- child: Column(
- children: <Widget>[
- Semantics(
- label: '1',
- tagForChildren: first,
- child: const SizedBox(width: 100, height: 100),
- // this tests that empty nodes disappear
- ),
- Semantics(
- label: '2',
- tagForChildren: second,
- child: const SizedBox(width: 100, height: 100),
- ),
- Semantics(
- label: '3',
- tagForChildren: third,
- child: const SizedBox(width: 100, height: 100),
- ),
- ],
- ),
- ),
- ),
- ),
- );
-
- expect(tester.takeException(), isAssertionError);
- });
-}
-
-class TestConfigDelegate extends SingleChildRenderObjectWidget {
- const TestConfigDelegate({super.key, required this.delegate, super.child});
- final ChildSemanticsConfigurationsDelegate delegate;
-
- @override
- RenderTestConfigDelegate createRenderObject(BuildContext context) => RenderTestConfigDelegate(
- delegate: delegate,
- );
-
- @override
- void updateRenderObject(BuildContext context, RenderTestConfigDelegate renderObject) {
- renderObject.delegate = delegate;
- }
-}
-
-class RenderTestConfigDelegate extends RenderProxyBox {
- RenderTestConfigDelegate({
- ChildSemanticsConfigurationsDelegate? delegate,
- }) : _delegate = delegate;
-
- ChildSemanticsConfigurationsDelegate? get delegate => _delegate;
- ChildSemanticsConfigurationsDelegate? _delegate;
- set delegate(ChildSemanticsConfigurationsDelegate? value) {
- if (value != _delegate) {
- markNeedsSemanticsUpdate();
- }
- _delegate = value;
- }
-
- @override
- void describeSemanticsConfiguration(SemanticsConfiguration config) {
- config.childConfigurationsDelegate = _delegate;
- }
-}