Reland "Clipping if only one character text overflows (#99146)" (#102130)
Fixes a text clipping edge case.
diff --git a/packages/flutter/lib/src/painting/text_painter.dart b/packages/flutter/lib/src/painting/text_painter.dart
index 2cbf171..f10d17d 100644
--- a/packages/flutter/lib/src/painting/text_painter.dart
+++ b/packages/flutter/lib/src/painting/text_painter.dart
@@ -599,6 +599,15 @@
return _paragraph!.didExceedMaxLines;
}
+ /// The distance from the left edge of the leftmost glyph to the right edge of
+ /// the rightmost glyph in the paragraph.
+ ///
+ /// Valid only after [layout] has been called.
+ double get longestLine {
+ assert(!_debugNeedsLayout);
+ return _paragraph!.longestLine;
+ }
+
double? _lastMinWidth;
double? _lastMaxWidth;
diff --git a/packages/flutter/lib/src/rendering/paragraph.dart b/packages/flutter/lib/src/rendering/paragraph.dart
index fdd3f36..d47b028 100644
--- a/packages/flutter/lib/src/rendering/paragraph.dart
+++ b/packages/flutter/lib/src/rendering/paragraph.dart
@@ -630,6 +630,12 @@
@visibleForTesting
bool get debugHasOverflowShader => _overflowShader != null;
+ /// Whether this paragraph currently has overflow and needs clipping.
+ ///
+ /// Used to test this object. Not for use in production.
+ @visibleForTesting
+ bool get debugNeedsClipping => _needsClipping;
+
void _layoutText({ double minWidth = 0.0, double maxWidth = double.infinity }) {
final bool widthMatters = softWrap || overflow == TextOverflow.ellipsis;
_textPainter.layout(
@@ -781,7 +787,7 @@
size = constraints.constrain(textSize);
final bool didOverflowHeight = size.height < textSize.height || textDidExceedMaxLines;
- final bool didOverflowWidth = size.width < textSize.width;
+ final bool didOverflowWidth = size.width < textSize.width || size.width < _textPainter.longestLine;
// TODO(abarth): We're only measuring the sizes of the line boxes here. If
// the glyphs draw outside the line boxes, we might think that there isn't
// visual overflow when there actually is visual overflow. This can become
diff --git a/packages/flutter/test/rendering/paragraph_test.dart b/packages/flutter/test/rendering/paragraph_test.dart
index deddef6..0f7a24c 100644
--- a/packages/flutter/test/rendering/paragraph_test.dart
+++ b/packages/flutter/test/rendering/paragraph_test.dart
@@ -326,6 +326,24 @@
expect(paragraph.debugHasOverflowShader, isFalse);
}, skip: isBrowser); // https://github.com/flutter/flutter/issues/61018
+ test('one character clip test', () {
+ // Regressing test for https://github.com/flutter/flutter/issues/99140
+ final RenderParagraph paragraph = RenderParagraph(
+ const TextSpan(
+ text: '7',
+ style: TextStyle(fontFamily: 'Ahem', fontSize: 60.0),
+ ),
+ textDirection: TextDirection.ltr,
+ maxLines: 1,
+ );
+
+ // Lay out in a narrow box to force clipping.
+ // The text width is 60 bigger than the constraints width.
+ layout(paragraph, constraints: BoxConstraints.tight(const Size(50.0, 200.0)));
+
+ expect(paragraph.debugNeedsClipping, true);
+ }, skip: isBrowser); // https://github.com/flutter/flutter/issues/61018
+
test('maxLines', () {
final RenderParagraph paragraph = RenderParagraph(
const TextSpan(