From 3f43d9f3d4105d4190c839e087c42d79ebe092e8 Mon Sep 17 00:00:00 2001 From: xubaolin Date: Thu, 30 Jun 2022 05:57:16 +0800 Subject: [PATCH] Reland "Clipping if only one character text overflows (#99146)" (#102130) Fixes a text clipping edge case. --- .../flutter/lib/src/painting/text_painter.dart | 9 +++++++++ .../flutter/lib/src/rendering/paragraph.dart | 8 +++++++- .../flutter/test/rendering/paragraph_test.dart | 18 ++++++++++++++++++ 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/packages/flutter/lib/src/painting/text_painter.dart b/packages/flutter/lib/src/painting/text_painter.dart index 2cbf171eb449..f10d17d25eb0 100644 --- a/packages/flutter/lib/src/painting/text_painter.dart +++ b/packages/flutter/lib/src/painting/text_painter.dart @@ -599,6 +599,15 @@ class TextPainter { 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 fdd3f360a7d9..d47b028b0923 100644 --- a/packages/flutter/lib/src/rendering/paragraph.dart +++ b/packages/flutter/lib/src/rendering/paragraph.dart @@ -630,6 +630,12 @@ class RenderParagraph extends RenderBox @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 @@ class RenderParagraph extends RenderBox 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 deddef608757..0f7a24cfc9e1 100644 --- a/packages/flutter/test/rendering/paragraph_test.dart +++ b/packages/flutter/test/rendering/paragraph_test.dart @@ -326,6 +326,24 @@ void main() { 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(