From b5a4d08962cd8111ddce84c4a2dd0fe8a201595d Mon Sep 17 00:00:00 2001 From: Michael Goderbauer Date: Thu, 12 Nov 2020 10:19:03 -0800 Subject: [PATCH] Intrinsic Width fixes for RenderParagraph (#70236) --- .../flutter/lib/src/rendering/paragraph.dart | 24 ++++------- packages/flutter/test/widgets/text_test.dart | 42 +++++++++++++++++++ 2 files changed, 51 insertions(+), 15 deletions(-) diff --git a/packages/flutter/lib/src/rendering/paragraph.dart b/packages/flutter/lib/src/rendering/paragraph.dart index 41ca3ba6c80..0846bc88c69 100644 --- a/packages/flutter/lib/src/rendering/paragraph.dart +++ b/packages/flutter/lib/src/rendering/paragraph.dart @@ -395,42 +395,36 @@ class RenderParagraph extends RenderBox RenderBox? child = firstChild; final List placeholderDimensions = List.filled(childCount, PlaceholderDimensions.empty, growable: false); int childIndex = 0; - // Takes textScaleFactor into account because the content of the placeholder - // span will be scale up when it paints. - height = height / textScaleFactor; while (child != null) { // Height and baseline is irrelevant as all text will be laid - // out in a single line. + // out in a single line. Therefore, using 0.0 as a dummy for the height. placeholderDimensions[childIndex] = PlaceholderDimensions( - size: Size(child.getMaxIntrinsicWidth(height), height), + size: Size(child.getMaxIntrinsicWidth(double.infinity), 0.0), alignment: _placeholderSpans[childIndex].alignment, baseline: _placeholderSpans[childIndex].baseline, ); child = childAfter(child); childIndex += 1; } - _textPainter.setPlaceholderDimensions(placeholderDimensions.cast()); + _textPainter.setPlaceholderDimensions(placeholderDimensions); } void _computeChildrenWidthWithMinIntrinsics(double height) { RenderBox? child = firstChild; final List placeholderDimensions = List.filled(childCount, PlaceholderDimensions.empty, growable: false); int childIndex = 0; - // Takes textScaleFactor into account because the content of the placeholder - // span will be scale up when it paints. - height = height / textScaleFactor; while (child != null) { - final double intrinsicWidth = child.getMinIntrinsicWidth(height); - final double intrinsicHeight = child.getMinIntrinsicHeight(intrinsicWidth); + // Height and baseline is irrelevant; only looking for the widest word or + // placeholder. Therefore, using 0.0 as a dummy for height. placeholderDimensions[childIndex] = PlaceholderDimensions( - size: Size(intrinsicWidth, intrinsicHeight), + size: Size(child.getMinIntrinsicWidth(double.infinity), 0.0), alignment: _placeholderSpans[childIndex].alignment, baseline: _placeholderSpans[childIndex].baseline, ); child = childAfter(child); childIndex += 1; } - _textPainter.setPlaceholderDimensions(placeholderDimensions.cast()); + _textPainter.setPlaceholderDimensions(placeholderDimensions); } void _computeChildrenHeightWithMinIntrinsics(double width) { @@ -451,7 +445,7 @@ class RenderParagraph extends RenderBox child = childAfter(child); childIndex += 1; } - _textPainter.setPlaceholderDimensions(placeholderDimensions.cast()); + _textPainter.setPlaceholderDimensions(placeholderDimensions); } @override @@ -593,7 +587,7 @@ class RenderParagraph extends RenderBox child = childAfter(child); childIndex += 1; } - _placeholderDimensions = placeholderDimensions.cast(); + _placeholderDimensions = placeholderDimensions; } // Iterate through the laid-out children and set the parentData offsets based diff --git a/packages/flutter/test/widgets/text_test.dart b/packages/flutter/test/widgets/text_test.dart index 5065624e6e6..5402aeed163 100644 --- a/packages/flutter/test/widgets/text_test.dart +++ b/packages/flutter/test/widgets/text_test.dart @@ -4,6 +4,7 @@ import 'dart:ui' as ui; +import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; @@ -1209,6 +1210,47 @@ void main() { ignoreTransform: true, )); }, semanticsEnabled: true, skip: isBrowser); // Browser does not support widget span + + testWidgets('RenderParagraph intrinsic width', (WidgetTester tester) async { + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: Center( + child: Container( + height: 100, + child: IntrinsicWidth( + child: RichText( + text: TextSpan( + style: const TextStyle(fontSize: 16, height: 1), + children: [ + const TextSpan(text: 'S '), + WidgetSpan( + alignment: PlaceholderAlignment.top, + child: Wrap( + direction: Axis.vertical, + children: [ + Container(width: 200, height: 100), + Container(width: 200, height: 30), + ], + ), + ), + const TextSpan(text: ' E'), + ], + ), + ), + ), + ), + ), + ), + ); + + expect(tester.getSize(find.byType(RichText)).width, 200 + 4 * 16.0); + final RenderParagraph paragraph = tester.renderObject(find.byType(RichText)); + // The inline spans are rendered on one (horizontal) line, the sum of the widths is the max intrinsic width. + expect(paragraph.getMaxIntrinsicWidth(0.0), 200 + 4 * 16.0); + // The inline spans are rendered in one vertical run, the widest one determines the min intrinsic width. + expect(paragraph.getMinIntrinsicWidth(0.0), 200, skip: 'https://github.com/flutter/flutter/issues/70230'); + }); } Future _pumpTextWidget({