From 35b85c8953dcf3017e2ca6399c387c7e57234769 Mon Sep 17 00:00:00 2001 From: Tomasz Gucio Date: Fri, 29 Jul 2022 16:31:51 +0200 Subject: [PATCH 1/4] PlaceholderDimensions equality operator --- packages/flutter/lib/src/painting/text_painter.dart | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/packages/flutter/lib/src/painting/text_painter.dart b/packages/flutter/lib/src/painting/text_painter.dart index 2cbf171eb4490..cff51bbbb7a3d 100644 --- a/packages/flutter/lib/src/painting/text_painter.dart +++ b/packages/flutter/lib/src/painting/text_painter.dart @@ -98,6 +98,18 @@ class PlaceholderDimensions { /// * [ui.PlaceholderAlignment.middle] final TextBaseline? baseline; + @override + bool operator ==(Object other) { + return other is PlaceholderDimensions + && other.size == size + && other.alignment == alignment + && other.baseline == baseline + && other.baselineOffset == baselineOffset; + } + + @override + int get hashCode => Object.hash(size, alignment, baseline, baselineOffset); + @override String toString() { return 'PlaceholderDimensions($size, $baseline)'; From ec3f046c54158bce2c93816fad5396a7e669b719 Mon Sep 17 00:00:00 2001 From: Tomasz Gucio Date: Fri, 29 Jul 2022 16:32:29 +0200 Subject: [PATCH 2/4] Add tests --- .../test/painting/text_painter_test.dart | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/packages/flutter/test/painting/text_painter_test.dart b/packages/flutter/test/painting/text_painter_test.dart index c27e443946861..07debc854b803 100644 --- a/packages/flutter/test/painting/text_painter_test.dart +++ b/packages/flutter/test/painting/text_painter_test.dart @@ -1034,6 +1034,81 @@ void main() { lines = painter.computeLineMetrics(); expect(lines.length, 1); }, skip: kIsWeb && !isCanvasKit); // https://github.com/flutter/flutter/issues/62819 + + test('TextPainter requires layout after providing different placeholder dimensions', () { + final TextPainter painter = TextPainter() + ..textDirection = TextDirection.ltr; + + painter.text = const TextSpan(children: [ + TextSpan(text: 'before'), + WidgetSpan(child: Text('widget1')), + WidgetSpan(child: Text('widget2')), + WidgetSpan(child: Text('widget3')), + TextSpan(text: 'after'), + ]); + + painter.setPlaceholderDimensions(const [ + PlaceholderDimensions(size: Size(30, 30), alignment: ui.PlaceholderAlignment.bottom), + PlaceholderDimensions(size: Size(40, 30), alignment: ui.PlaceholderAlignment.bottom), + PlaceholderDimensions(size: Size(50, 30), alignment: ui.PlaceholderAlignment.bottom), + ]); + painter.layout(); + + painter.setPlaceholderDimensions(const [ + PlaceholderDimensions(size: Size(30, 30), alignment: ui.PlaceholderAlignment.bottom), + PlaceholderDimensions(size: Size(40, 20), alignment: ui.PlaceholderAlignment.bottom), + PlaceholderDimensions(size: Size(50, 30), alignment: ui.PlaceholderAlignment.bottom), + ]); + + Object? e; + try { + painter.paint(MockCanvas(), Offset.zero); + } catch (exception) { + e = exception; + } + expect( + e.toString(), + contains('TextPainter.paint called when text geometry was not yet calculated'), + ); + }, skip: isBrowser && !isCanvasKit); // https://github.com/flutter/flutter/issues/56308 + + test('TextPainter does not require layout after providing identical placeholder dimensions', () { + final TextPainter painter = TextPainter() + ..textDirection = TextDirection.ltr; + + painter.text = const TextSpan(children: [ + TextSpan(text: 'before'), + WidgetSpan(child: Text('widget1')), + WidgetSpan(child: Text('widget2')), + WidgetSpan(child: Text('widget3')), + TextSpan(text: 'after'), + ]); + + painter.setPlaceholderDimensions(const [ + PlaceholderDimensions(size: Size(30, 30), alignment: ui.PlaceholderAlignment.bottom), + PlaceholderDimensions(size: Size(40, 30), alignment: ui.PlaceholderAlignment.bottom), + PlaceholderDimensions(size: Size(50, 30), alignment: ui.PlaceholderAlignment.bottom), + ]); + painter.layout(); + + painter.setPlaceholderDimensions(const [ + PlaceholderDimensions(size: Size(30, 30), alignment: ui.PlaceholderAlignment.bottom), + PlaceholderDimensions(size: Size(40, 30), alignment: ui.PlaceholderAlignment.bottom), + PlaceholderDimensions(size: Size(50, 30), alignment: ui.PlaceholderAlignment.bottom), + ]); + + Object? e; + try { + painter.paint(MockCanvas(), Offset.zero); + } catch (exception) { + e = exception; + } + // In tests, paint() will throw an UnimplementedError due to missing drawParagraph method. + expect( + e.toString(), + isNot(contains('TextPainter.paint called when text geometry was not yet calculated')), + ); + }, skip: isBrowser && !isCanvasKit); // https://github.com/flutter/flutter/issues/56308 } class MockCanvas extends Fake implements Canvas { From 5532213a11d4fb8244a5740f6b8ba971172e02e4 Mon Sep 17 00:00:00 2001 From: Tomasz Gucio <72562119+tgucio@users.noreply.github.com> Date: Sat, 30 Jul 2022 11:41:56 +0200 Subject: [PATCH 3/4] Remove extra newline --- packages/flutter/test/painting/text_painter_test.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/flutter/test/painting/text_painter_test.dart b/packages/flutter/test/painting/text_painter_test.dart index 92e71dd62a50b..0c0c67abc221a 100644 --- a/packages/flutter/test/painting/text_painter_test.dart +++ b/packages/flutter/test/painting/text_painter_test.dart @@ -1070,7 +1070,6 @@ void main() { exception = null; }); - test('TextPainter requires layout after providing different placeholder dimensions', () { final TextPainter painter = TextPainter() ..textDirection = TextDirection.ltr; From dc73b3f61a9f1eb6d64526758567fee48207793a Mon Sep 17 00:00:00 2001 From: Tomasz Gucio Date: Mon, 1 Aug 2022 12:10:05 +0200 Subject: [PATCH 4/4] Check for identical object first --- packages/flutter/lib/src/painting/text_painter.dart | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/flutter/lib/src/painting/text_painter.dart b/packages/flutter/lib/src/painting/text_painter.dart index 86f7ac2c693e6..515249ad5916c 100644 --- a/packages/flutter/lib/src/painting/text_painter.dart +++ b/packages/flutter/lib/src/painting/text_painter.dart @@ -110,6 +110,9 @@ class PlaceholderDimensions { @override bool operator ==(Object other) { + if (identical(this, other)) { + return true; + } return other is PlaceholderDimensions && other.size == size && other.alignment == alignment