@@ -15,6 +15,7 @@ import 'package:flutter/semantics.dart';
15
15
16
16
import 'debug.dart' ;
17
17
import 'layer.dart' ;
18
+ import 'proxy_box.dart' ;
18
19
19
20
export 'package:flutter/foundation.dart' show
20
21
DiagnosticPropertiesBuilder,
@@ -3244,14 +3245,15 @@ abstract class RenderObject extends AbstractNode with DiagnosticableTreeMixin im
3244
3245
final SemanticsConfiguration config = _semanticsConfiguration;
3245
3246
bool dropSemanticsOfPreviousSiblings = config.isBlockingSemanticsOfPreviouslyPaintedNodes;
3246
3247
3247
- final bool producesForkingFragment = ! config.hasBeenAnnotated && ! config.isSemanticBoundary;
3248
+ bool producesForkingFragment = ! config.hasBeenAnnotated && ! config.isSemanticBoundary;
3248
3249
final bool childrenMergeIntoParent = mergeIntoParent || config.isMergingSemanticsOfDescendants;
3249
3250
final List <SemanticsConfiguration > childConfigurations = < SemanticsConfiguration > [];
3250
3251
final bool explicitChildNode = config.explicitChildNodes || parent is ! RenderObject ;
3251
3252
final bool hasChildConfigurationsDelegate = config.childConfigurationsDelegate != null ;
3252
3253
final Map <SemanticsConfiguration , _InterestingSemanticsFragment > configToFragment = < SemanticsConfiguration , _InterestingSemanticsFragment > {};
3253
3254
final List <_InterestingSemanticsFragment > mergeUpFragments = < _InterestingSemanticsFragment > [];
3254
3255
final List <List <_InterestingSemanticsFragment >> siblingMergeFragmentGroups = < List <_InterestingSemanticsFragment >> [];
3256
+ final bool hasTags = config.tagsForChildren? .isNotEmpty ?? false ;
3255
3257
visitChildrenForSemantics ((RenderObject renderChild) {
3256
3258
assert (! _needsLayout);
3257
3259
final _SemanticsFragment parentFragment = renderChild._getSemanticsForParent (
@@ -3267,7 +3269,9 @@ abstract class RenderObject extends AbstractNode with DiagnosticableTreeMixin im
3267
3269
}
3268
3270
for (final _InterestingSemanticsFragment fragment in parentFragment.mergeUpFragments) {
3269
3271
fragment.addAncestor (this );
3270
- fragment.addTags (config.tagsForChildren);
3272
+ if (hasTags) {
3273
+ fragment.addTags (config.tagsForChildren! );
3274
+ }
3271
3275
if (hasChildConfigurationsDelegate && fragment.config != null ) {
3272
3276
// This fragment need to go through delegate to determine whether it
3273
3277
// merge up or not.
@@ -3283,7 +3287,9 @@ abstract class RenderObject extends AbstractNode with DiagnosticableTreeMixin im
3283
3287
for (final List <_InterestingSemanticsFragment > siblingMergeGroup in parentFragment.siblingMergeGroups) {
3284
3288
for (final _InterestingSemanticsFragment siblingMergingFragment in siblingMergeGroup) {
3285
3289
siblingMergingFragment.addAncestor (this );
3286
- siblingMergingFragment.addTags (config.tagsForChildren);
3290
+ if (hasTags) {
3291
+ siblingMergingFragment.addTags (config.tagsForChildren! );
3292
+ }
3287
3293
}
3288
3294
siblingMergeFragmentGroups.add (siblingMergeGroup);
3289
3295
}
@@ -3296,14 +3302,25 @@ abstract class RenderObject extends AbstractNode with DiagnosticableTreeMixin im
3296
3302
for (final _InterestingSemanticsFragment fragment in mergeUpFragments) {
3297
3303
fragment.markAsExplicit ();
3298
3304
}
3299
- } else if (hasChildConfigurationsDelegate && childConfigurations.isNotEmpty ) {
3305
+ } else if (hasChildConfigurationsDelegate) {
3300
3306
final ChildSemanticsConfigurationsResult result = config.childConfigurationsDelegate !(childConfigurations);
3301
3307
mergeUpFragments.addAll (
3302
- result.mergeUp.map <_InterestingSemanticsFragment >((SemanticsConfiguration config) => configToFragment[config]! ),
3308
+ result.mergeUp.map <_InterestingSemanticsFragment >((SemanticsConfiguration config) {
3309
+ final _InterestingSemanticsFragment ? fragment = configToFragment[config];
3310
+ if (fragment == null ) {
3311
+ // Parent fragment of Incomplete fragments can't be a forking
3312
+ // fragment since they need to be merged.
3313
+ producesForkingFragment = false ;
3314
+ return _IncompleteSemanticsFragment (config: config, owner: this );
3315
+ }
3316
+ return fragment;
3317
+ }),
3303
3318
);
3304
3319
for (final Iterable <SemanticsConfiguration > group in result.siblingMergeGroups) {
3305
3320
siblingMergeFragmentGroups.add (
3306
- group.map <_InterestingSemanticsFragment >((SemanticsConfiguration config) => configToFragment[config]! ).toList ()
3321
+ group.map <_InterestingSemanticsFragment >((SemanticsConfiguration config) {
3322
+ return configToFragment[config] ?? _IncompleteSemanticsFragment (config: config, owner: this );
3323
+ }).toList (),
3307
3324
);
3308
3325
}
3309
3326
}
@@ -4184,10 +4201,10 @@ abstract class _InterestingSemanticsFragment extends _SemanticsFragment {
4184
4201
Set <SemanticsTag >? _tagsForChildren;
4185
4202
4186
4203
/// Tag all children produced by [compileChildren] with `tags` .
4187
- void addTags ( Iterable < SemanticsTag > ? tags) {
4188
- if ( tags == null || tags.isEmpty) {
4189
- return ;
4190
- }
4204
+ ///
4205
+ /// ` tags` must not be empty.
4206
+ void addTags ( Iterable < SemanticsTag > tags) {
4207
+ assert (tags.isNotEmpty);
4191
4208
_tagsForChildren ?? = < SemanticsTag > {};
4192
4209
_tagsForChildren! .addAll (tags);
4193
4210
}
@@ -4281,6 +4298,48 @@ class _RootSemanticsFragment extends _InterestingSemanticsFragment {
4281
4298
}
4282
4299
}
4283
4300
4301
+ /// A fragment with partial information that must not form an explicit
4302
+ /// semantics node without merging into another _SwitchableSemanticsFragment.
4303
+ ///
4304
+ /// This fragment is generated from synthetic SemanticsConfiguration returned from
4305
+ /// [SemanticsConfiguration.childConfigurationsDelegate] .
4306
+ class _IncompleteSemanticsFragment extends _InterestingSemanticsFragment {
4307
+ _IncompleteSemanticsFragment ({
4308
+ required this .config,
4309
+ required super .owner,
4310
+ }) : super (dropsSemanticsOfPreviousSiblings: false );
4311
+
4312
+ @override
4313
+ void addAll (Iterable <_InterestingSemanticsFragment > fragments) {
4314
+ assert (false , 'This fragment must be a leaf node' );
4315
+ }
4316
+
4317
+ @override
4318
+ void compileChildren ({
4319
+ required Rect ? parentSemanticsClipRect,
4320
+ required Rect ? parentPaintClipRect,
4321
+ required double elevationAdjustment,
4322
+ required List <SemanticsNode > result,
4323
+ required List <SemanticsNode > siblingNodes,
4324
+ }) {
4325
+ // There is nothing to do because this fragment must be a leaf node and
4326
+ // must not be explicit.
4327
+ }
4328
+
4329
+ @override
4330
+ final SemanticsConfiguration config;
4331
+
4332
+ @override
4333
+ void markAsExplicit () {
4334
+ assert (
4335
+ false ,
4336
+ 'SemanticsConfiguration created in '
4337
+ 'SemanticsConfiguration.childConfigurationsDelegate must not produce '
4338
+ 'its own semantics node'
4339
+ );
4340
+ }
4341
+ }
4342
+
4284
4343
/// An [_InterestingSemanticsFragment] that can be told to only add explicit
4285
4344
/// [SemanticsNode] s to the parent.
4286
4345
///
@@ -4559,6 +4618,14 @@ class _SwitchableSemanticsFragment extends _InterestingSemanticsFragment {
4559
4618
}
4560
4619
}
4561
4620
4621
+ @override
4622
+ void addTags (Iterable <SemanticsTag > tags) {
4623
+ super .addTags (tags);
4624
+ // _ContainerSemanticsFragments add their tags to child fragments through
4625
+ // this method. This fragment must make sure its _config is in sync.
4626
+ tags.forEach (_config.addTagForChildren);
4627
+ }
4628
+
4562
4629
void _ensureConfigIsWritable () {
4563
4630
if (! _isConfigWritable) {
4564
4631
_config = _config.copy ();
0 commit comments