Skip to content

Commit

Permalink
Revert "Fix text.rich to merge widget span (flutter#113461)" (flutter…
Browse files Browse the repository at this point in the history
…#121562)

This reverts commit 660992a.
  • Loading branch information
chunhtai committed Feb 27, 2023
1 parent 22cbe6e commit c8d8016
Show file tree
Hide file tree
Showing 4 changed files with 21 additions and 312 deletions.
87 changes: 10 additions & 77 deletions packages/flutter/lib/src/rendering/object.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import 'package:flutter/semantics.dart';

import 'debug.dart';
import 'layer.dart';
import 'proxy_box.dart';

export 'package:flutter/foundation.dart' show
DiagnosticPropertiesBuilder,
Expand Down Expand Up @@ -3228,15 +3227,14 @@ abstract class RenderObject extends AbstractNode with DiagnosticableTreeMixin im
final SemanticsConfiguration config = _semanticsConfiguration;
bool dropSemanticsOfPreviousSiblings = config.isBlockingSemanticsOfPreviouslyPaintedNodes;

bool producesForkingFragment = !config.hasBeenAnnotated && !config.isSemanticBoundary;
final bool producesForkingFragment = !config.hasBeenAnnotated && !config.isSemanticBoundary;
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>>[];
final bool hasTags = config.tagsForChildren?.isNotEmpty ?? false;
visitChildrenForSemantics((RenderObject renderChild) {
assert(!_needsLayout);
final _SemanticsFragment parentFragment = renderChild._getSemanticsForParent(
Expand All @@ -3252,9 +3250,7 @@ abstract class RenderObject extends AbstractNode with DiagnosticableTreeMixin im
}
for (final _InterestingSemanticsFragment fragment in parentFragment.mergeUpFragments) {
fragment.addAncestor(this);
if (hasTags) {
fragment.addTags(config.tagsForChildren!);
}
fragment.addTags(config.tagsForChildren);
if (hasChildConfigurationsDelegate && fragment.config != null) {
// This fragment need to go through delegate to determine whether it
// merge up or not.
Expand All @@ -3270,9 +3266,7 @@ abstract class RenderObject extends AbstractNode with DiagnosticableTreeMixin im
for (final List<_InterestingSemanticsFragment> siblingMergeGroup in parentFragment.siblingMergeGroups) {
for (final _InterestingSemanticsFragment siblingMergingFragment in siblingMergeGroup) {
siblingMergingFragment.addAncestor(this);
if (hasTags) {
siblingMergingFragment.addTags(config.tagsForChildren!);
}
siblingMergingFragment.addTags(config.tagsForChildren);
}
siblingMergeFragmentGroups.add(siblingMergeGroup);
}
Expand All @@ -3285,25 +3279,14 @@ abstract class RenderObject extends AbstractNode with DiagnosticableTreeMixin im
for (final _InterestingSemanticsFragment fragment in mergeUpFragments) {
fragment.markAsExplicit();
}
} else if (hasChildConfigurationsDelegate) {
} else if (hasChildConfigurationsDelegate && childConfigurations.isNotEmpty) {
final ChildSemanticsConfigurationsResult result = config.childConfigurationsDelegate!(childConfigurations);
mergeUpFragments.addAll(
result.mergeUp.map<_InterestingSemanticsFragment>((SemanticsConfiguration config) {
final _InterestingSemanticsFragment? fragment = configToFragment[config];
if (fragment == null) {
// Parent fragment of Incomplete fragments can't be a forking
// fragment since they need to be merged.
producesForkingFragment = false;
return _IncompleteSemanticsFragment(config: config, owner: this);
}
return fragment;
}),
result.mergeUp.map<_InterestingSemanticsFragment>((SemanticsConfiguration config) => configToFragment[config]!),
);
for (final Iterable<SemanticsConfiguration> group in result.siblingMergeGroups) {
siblingMergeFragmentGroups.add(
group.map<_InterestingSemanticsFragment>((SemanticsConfiguration config) {
return configToFragment[config] ?? _IncompleteSemanticsFragment(config: config, owner: this);
}).toList(),
group.map<_InterestingSemanticsFragment>((SemanticsConfiguration config) => configToFragment[config]!).toList()
);
}
}
Expand Down Expand Up @@ -4184,10 +4167,10 @@ abstract class _InterestingSemanticsFragment extends _SemanticsFragment {
Set<SemanticsTag>? _tagsForChildren;

/// Tag all children produced by [compileChildren] with `tags`.
///
/// `tags` must not be empty.
void addTags(Iterable<SemanticsTag> tags) {
assert(tags.isNotEmpty);
void addTags(Iterable<SemanticsTag>? tags) {
if (tags == null || tags.isEmpty) {
return;
}
_tagsForChildren ??= <SemanticsTag>{};
_tagsForChildren!.addAll(tags);
}
Expand Down Expand Up @@ -4281,48 +4264,6 @@ class _RootSemanticsFragment extends _InterestingSemanticsFragment {
}
}

/// A fragment with partial information that must not form an explicit
/// semantics node without merging into another _SwitchableSemanticsFragment.
///
/// This fragment is generated from synthetic SemanticsConfiguration returned from
/// [SemanticsConfiguration.childConfigurationsDelegate].
class _IncompleteSemanticsFragment extends _InterestingSemanticsFragment {
_IncompleteSemanticsFragment({
required this.config,
required super.owner,
}) : super(dropsSemanticsOfPreviousSiblings: false);

@override
void addAll(Iterable<_InterestingSemanticsFragment> fragments) {
assert(false, 'This fragment must be a leaf node');
}

@override
void compileChildren({
required Rect? parentSemanticsClipRect,
required Rect? parentPaintClipRect,
required double elevationAdjustment,
required List<SemanticsNode> result,
required List<SemanticsNode> siblingNodes,
}) {
// There is nothing to do because this fragment must be a leaf node and
// must not be explicit.
}

@override
final SemanticsConfiguration config;

@override
void markAsExplicit() {
assert(
false,
'SemanticsConfiguration created in '
'SemanticsConfiguration.childConfigurationsDelegate must not produce '
'its own semantics node'
);
}
}

/// An [_InterestingSemanticsFragment] that can be told to only add explicit
/// [SemanticsNode]s to the parent.
///
Expand Down Expand Up @@ -4601,14 +4542,6 @@ class _SwitchableSemanticsFragment extends _InterestingSemanticsFragment {
}
}

@override
void addTags(Iterable<SemanticsTag> tags) {
super.addTags(tags);
// _ContainerSemanticsFragments add their tags to child fragments through
// this method. This fragment must make sure its _config is in sync.
tags.forEach(_config.addTagForChildren);
}

void _ensureConfigIsWritable() {
if (!_isConfigWritable) {
_config = _config.copy();
Expand Down
87 changes: 9 additions & 78 deletions packages/flutter/lib/src/rendering/paragraph.dart
Original file line number Diff line number Diff line change
Expand Up @@ -119,9 +119,7 @@ class RenderParagraph extends RenderBox

static final String _placeholderCharacter = String.fromCharCode(PlaceholderSpan.placeholderCodeUnit);
final TextPainter _textPainter;

List<AttributedString>? _cachedAttributedLabels;

AttributedString? _cachedAttributedLabel;
List<InlineSpanSemanticsInformation>? _cachedCombinedSemanticsInfos;

/// The text to display.
Expand All @@ -137,7 +135,7 @@ class RenderParagraph extends RenderBox
break;
case RenderComparison.paint:
_textPainter.text = value;
_cachedAttributedLabels = null;
_cachedAttributedLabel = null;
_cachedCombinedSemanticsInfos = null;
_extractPlaceholderSpans(value);
markNeedsPaint();
Expand All @@ -146,7 +144,7 @@ class RenderParagraph extends RenderBox
case RenderComparison.layout:
_textPainter.text = value;
_overflowShader = null;
_cachedAttributedLabels = null;
_cachedAttributedLabel = null;
_cachedCombinedSemanticsInfos = null;
_extractPlaceholderSpans(value);
markNeedsLayout();
Expand Down Expand Up @@ -1037,23 +1035,12 @@ class RenderParagraph extends RenderBox
void describeSemanticsConfiguration(SemanticsConfiguration config) {
super.describeSemanticsConfiguration(config);
_semanticsInfo = text.getSemanticsInformation();
bool needsAssembleSemanticsNode = false;
bool needsChildConfigrationsDelegate = false;
for (final InlineSpanSemanticsInformation info in _semanticsInfo!) {
if (info.recognizer != null) {
needsAssembleSemanticsNode = true;
break;
}
needsChildConfigrationsDelegate = needsChildConfigrationsDelegate || info.isPlaceholder;
}

if (needsAssembleSemanticsNode) {
if (_semanticsInfo!.any((InlineSpanSemanticsInformation info) => info.recognizer != null)) {
config.explicitChildNodes = true;
config.isSemanticBoundary = true;
} else if (needsChildConfigrationsDelegate) {
config.childConfigurationsDelegate = _childSemanticsConfigurationsDelegate;
} else {
if (_cachedAttributedLabels == null) {
if (_cachedAttributedLabel == null) {
final StringBuffer buffer = StringBuffer();
int offset = 0;
final List<StringAttribute> attributes = <StringAttribute>[];
Expand All @@ -1063,77 +1050,21 @@ class RenderParagraph extends RenderBox
final TextRange originalRange = infoAttribute.range;
attributes.add(
infoAttribute.copy(
range: TextRange(
start: offset + originalRange.start,
end: offset + originalRange.end,
),
range: TextRange(start: offset + originalRange.start,
end: offset + originalRange.end)
),
);
}
buffer.write(label);
offset += label.length;
}
_cachedAttributedLabels = <AttributedString>[AttributedString(buffer.toString(), attributes: attributes)];
_cachedAttributedLabel = AttributedString(buffer.toString(), attributes: attributes);
}
config.attributedLabel = _cachedAttributedLabels![0];
config.attributedLabel = _cachedAttributedLabel!;
config.textDirection = textDirection;
}
}

ChildSemanticsConfigurationsResult _childSemanticsConfigurationsDelegate(List<SemanticsConfiguration> childConfigs) {
final ChildSemanticsConfigurationsResultBuilder builder = ChildSemanticsConfigurationsResultBuilder();
int placeholderIndex = 0;
int childConfigsIndex = 0;
int attributedLabelCacheIndex = 0;
InlineSpanSemanticsInformation? seenTextInfo;
_cachedCombinedSemanticsInfos ??= combineSemanticsInfo(_semanticsInfo!);
for (final InlineSpanSemanticsInformation info in _cachedCombinedSemanticsInfos!) {
if (info.isPlaceholder) {
if (seenTextInfo != null) {
builder.markAsMergeUp(_createSemanticsConfigForTextInfo(seenTextInfo, attributedLabelCacheIndex));
attributedLabelCacheIndex += 1;
}
// Mark every childConfig belongs to this placeholder to merge up group.
while (childConfigsIndex < childConfigs.length &&
childConfigs[childConfigsIndex].tagsChildrenWith(PlaceholderSpanIndexSemanticsTag(placeholderIndex))) {
builder.markAsMergeUp(childConfigs[childConfigsIndex]);
childConfigsIndex += 1;
}
placeholderIndex += 1;
} else {
seenTextInfo = info;
}
}

// Handle plain text info at the end.
if (seenTextInfo != null) {
builder.markAsMergeUp(_createSemanticsConfigForTextInfo(seenTextInfo, attributedLabelCacheIndex));
}
return builder.build();
}

SemanticsConfiguration _createSemanticsConfigForTextInfo(InlineSpanSemanticsInformation textInfo, int cacheIndex) {
assert(!textInfo.requiresOwnNode);
final List<AttributedString> cachedStrings = _cachedAttributedLabels ??= <AttributedString>[];
assert(cacheIndex <= cachedStrings.length);
final bool hasCache = cacheIndex < cachedStrings.length;

late AttributedString attributedLabel;
if (hasCache) {
attributedLabel = cachedStrings[cacheIndex];
} else {
assert(cachedStrings.length == cacheIndex);
attributedLabel = AttributedString(
textInfo.semanticsLabel ?? textInfo.text,
attributes: textInfo.stringAttributes,
);
cachedStrings.add(attributedLabel);
}
return SemanticsConfiguration()
..textDirection = textDirection
..attributedLabel = attributedLabel;
}

// Caches [SemanticsNode]s created during [assembleSemanticsNode] so they
// can be re-used when [assembleSemanticsNode] is called again. This ensures
// stable ids for the [SemanticsNode]s of [TextSpan]s across
Expand Down
5 changes: 2 additions & 3 deletions packages/flutter/lib/src/semantics/semantics.dart
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,7 @@ class AttributedString {
}

@override
int get hashCode => Object.hash(string, attributes);
int get hashCode => Object.hash(string, attributes,);

@override
String toString() {
Expand Down Expand Up @@ -3805,8 +3805,7 @@ class SemanticsConfiguration {
/// 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 or child rendering
/// objects do not contribute to the semantics.
/// object of this semantics configuration is a leaf node.
ChildSemanticsConfigurationsDelegate? get childConfigurationsDelegate => _childConfigurationsDelegate;
ChildSemanticsConfigurationsDelegate? _childConfigurationsDelegate;
set childConfigurationsDelegate(ChildSemanticsConfigurationsDelegate? value) {
Expand Down
Loading

0 comments on commit c8d8016

Please sign in to comment.