diff --git a/flutter_frontend_server/test/to_string_test.dart b/flutter_frontend_server/test/to_string_test.dart index fc21f4cdea34f..92a0a2a554584 100644 --- a/flutter_frontend_server/test/to_string_test.dart +++ b/flutter_frontend_server/test/to_string_test.dart @@ -60,8 +60,7 @@ void main() { ])); final runResult = io.Process.runSync(dart, [regularDill]); checkProcessResult(runResult); - var paintString = - '"Paint.toString":"Paint(Color(alpha: 1.0000, red: 1.0000, green: 1.0000, blue: 1.0000, colorSpace: ColorSpace.sRGB))"'; + var paintString = '"Paint.toString":"Paint(Color(0xffffffff))"'; if (buildDir.contains('release')) { paintString = '"Paint.toString":"Instance of \'Paint\'"'; } diff --git a/lib/ui/lerp.dart b/lib/ui/lerp.dart index b90e8a7738c51..5b17fe86756e3 100644 --- a/lib/ui/lerp.dart +++ b/lib/ui/lerp.dart @@ -37,3 +37,15 @@ double _lerpDouble(double a, double b, double t) { double _lerpInt(int a, int b, double t) { return a + (b - a) * t; } + +/// Same as [num.clamp] but specialized for non-null [int]. +int _clampInt(int value, int min, int max) { + assert(min <= max); + if (value < min) { + return min; + } else if (value > max) { + return max; + } else { + return value; + } +} diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index 6a171e79a94b0..202f4991d352f 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -48,8 +48,8 @@ bool _radiusIsValid(Radius radius) { return true; } -Color _scaleAlpha(Color x, double factor) { - return x.withValues(alpha: clampDouble(x.a * factor, 0, 1)); +Color _scaleAlpha(Color a, double factor) { + return a.withAlpha((a.alpha * factor).round().clamp(0, 255)); } /// An immutable 32 bit color value in ARGB format. @@ -310,11 +310,10 @@ class Color { /// /// See . double computeLuminance() { - assert(colorSpace != ColorSpace.extendedSRGB); // See - final double R = _linearizeColorComponent(r); - final double G = _linearizeColorComponent(g); - final double B = _linearizeColorComponent(b); + final double R = _linearizeColorComponent(red / 0xFF); + final double G = _linearizeColorComponent(green / 0xFF); + final double B = _linearizeColorComponent(blue / 0xFF); return 0.2126 * R + 0.7152 * G + 0.0722 * B; } @@ -340,26 +339,28 @@ class Color { /// /// Values for `t` are usually obtained from an [Animation], such as /// an [AnimationController]. - static Color? lerp(Color? x, Color? y, double t) { - assert(x?.colorSpace != ColorSpace.extendedSRGB); - assert(y?.colorSpace != ColorSpace.extendedSRGB); - if (y == null) { - if (x == null) { + static Color? lerp(Color? a, Color? b, double t) { + // TODO(gaaclarke): Update math to use floats. This was already attempted + // but it leads to subtle changes that change test results. + assert(a?.colorSpace != ColorSpace.extendedSRGB); + assert(b?.colorSpace != ColorSpace.extendedSRGB); + if (b == null) { + if (a == null) { return null; } else { - return _scaleAlpha(x, 1.0 - t); + return _scaleAlpha(a, 1.0 - t); } } else { - if (x == null) { - return _scaleAlpha(y, t); + if (a == null) { + return _scaleAlpha(b, t); } else { - assert(x.colorSpace == y.colorSpace); - return Color.from( - alpha: clampDouble(_lerpDouble(x.a, y.a, t), 0, 1), - red: clampDouble(_lerpDouble(x.r, y.r, t), 0, 1), - green: clampDouble(_lerpDouble(x.g, y.g, t), 0, 1), - blue: clampDouble(_lerpDouble(x.b, y.b, t), 0, 1), - colorSpace: x.colorSpace, + assert(a.colorSpace == b.colorSpace); + return Color._fromARGBC( + _clampInt(_lerpInt(a.alpha, b.alpha, t).toInt(), 0, 255), + _clampInt(_lerpInt(a.red, b.red, t).toInt(), 0, 255), + _clampInt(_lerpInt(a.green, b.green, t).toInt(), 0, 255), + _clampInt(_lerpInt(a.blue, b.blue, t).toInt(), 0, 255), + a.colorSpace, ); } } @@ -376,30 +377,32 @@ class Color { static Color alphaBlend(Color foreground, Color background) { assert(foreground.colorSpace == background.colorSpace); assert(foreground.colorSpace != ColorSpace.extendedSRGB); - final double alpha = foreground.a; - if (alpha == 0) { // Foreground completely transparent. + // TODO(gaaclarke): Update math to use floats. This was already attempted + // but it leads to subtle changes that change test results. + final int alpha = foreground.alpha; + if (alpha == 0x00) { // Foreground completely transparent. return background; } - final double invAlpha = 1 - alpha; - double backAlpha = background.a; - if (backAlpha == 1) { // Opaque background case - return Color.from( - alpha: 1, - red: alpha * foreground.r + invAlpha * background.r, - green: alpha * foreground.g + invAlpha * background.g, - blue: alpha * foreground.b + invAlpha * background.b, - colorSpace: foreground.colorSpace, + final int invAlpha = 0xff - alpha; + int backAlpha = background.alpha; + if (backAlpha == 0xff) { // Opaque background case + return Color._fromARGBC( + 0xff, + (alpha * foreground.red + invAlpha * background.red) ~/ 0xff, + (alpha * foreground.green + invAlpha * background.green) ~/ 0xff, + (alpha * foreground.blue + invAlpha * background.blue) ~/ 0xff, + foreground.colorSpace, ); } else { // General case - backAlpha = backAlpha * invAlpha; - final double outAlpha = alpha + backAlpha; - assert(outAlpha != 0); - return Color.from( - alpha: outAlpha, - red: (foreground.r * alpha + background.r * backAlpha) / outAlpha, - green: (foreground.g * alpha + background.g * backAlpha) / outAlpha, - blue: (foreground.b * alpha + background.b * backAlpha) / outAlpha, - colorSpace: foreground.colorSpace, + backAlpha = (backAlpha * invAlpha) ~/ 0xff; + final int outAlpha = alpha + backAlpha; + assert(outAlpha != 0x00); + return Color._fromARGBC( + outAlpha, + (foreground.red * alpha + background.red * backAlpha) ~/ outAlpha, + (foreground.green * alpha + background.green * backAlpha) ~/ outAlpha, + (foreground.blue * alpha + background.blue * backAlpha) ~/ outAlpha, + foreground.colorSpace, ); } } @@ -420,19 +423,16 @@ class Color { return false; } return other is Color && - other.a == a && - other.r == r && - other.g == g && - other.b == b && + other.value == value && other.colorSpace == colorSpace; } @override - int get hashCode => Object.hash(a, r, g, b, colorSpace); + int get hashCode => Object.hash(value, colorSpace); + // TODO(gaaclarke): Make toString() print out float values. @override - String toString() => - 'Color(alpha: ${a.toStringAsFixed(4)}, red: ${r.toStringAsFixed(4)}, green: ${g.toStringAsFixed(4)}, blue: ${b.toStringAsFixed(4)}, colorSpace: $colorSpace)'; + String toString() => 'Color(0x${value.toRadixString(16).padLeft(8, '0')})'; } /// Algorithms to use when painting on the canvas. diff --git a/lib/web_ui/lib/lerp.dart b/lib/web_ui/lib/lerp.dart index 80a941f7890e8..ff70c354e308f 100644 --- a/lib/web_ui/lib/lerp.dart +++ b/lib/web_ui/lib/lerp.dart @@ -28,3 +28,10 @@ double? lerpDouble(num? a, num? b, double t) { double _lerpDouble(double a, double b, double t) { return a * (1.0 - t) + b * t; } + +/// Linearly interpolate between two integers. +/// +/// Same as [lerpDouble] but specialized for non-null `int` type. +double _lerpInt(int a, int b, double t) { + return a * (1.0 - t) + b * t; +} diff --git a/lib/web_ui/lib/painting.dart b/lib/web_ui/lib/painting.dart index 7bdd746633328..113cabadca1e9 100644 --- a/lib/web_ui/lib/painting.dart +++ b/lib/web_ui/lib/painting.dart @@ -17,8 +17,8 @@ void _validateColorStops(List colors, List? colorStops) { } } -Color _scaleAlpha(Color x, double factor) { - return x.withValues(alpha: (x.a * factor).clamp(0, 1)); +Color _scaleAlpha(Color a, double factor) { + return a.withAlpha(engine.clampInt((a.alpha * factor).round(), 0, 255)); } class Color { @@ -141,32 +141,32 @@ class Color { double computeLuminance() { // See - final double R = _linearizeColorComponent(r); - final double G = _linearizeColorComponent(g); - final double B = _linearizeColorComponent(b); + final double R = _linearizeColorComponent(red / 0xFF); + final double G = _linearizeColorComponent(green / 0xFF); + final double B = _linearizeColorComponent(blue / 0xFF); return 0.2126 * R + 0.7152 * G + 0.0722 * B; } - static Color? lerp(Color? x, Color? y, double t) { - assert(x?.colorSpace != ColorSpace.extendedSRGB); - assert(y?.colorSpace != ColorSpace.extendedSRGB); - if (y == null) { - if (x == null) { + static Color? lerp(Color? a, Color? b, double t) { + assert(a?.colorSpace != ColorSpace.extendedSRGB); + assert(b?.colorSpace != ColorSpace.extendedSRGB); + if (b == null) { + if (a == null) { return null; } else { - return _scaleAlpha(x, 1.0 - t); + return _scaleAlpha(a, 1.0 - t); } } else { - if (x == null) { - return _scaleAlpha(y, t); + if (a == null) { + return _scaleAlpha(b, t); } else { - assert(x.colorSpace == y.colorSpace); - return Color.from( - alpha: _lerpDouble(x.a, y.a, t).clamp(0, 1), - red: _lerpDouble(x.r, y.r, t).clamp(0, 1), - green: _lerpDouble(x.g, y.g, t).clamp(0, 1), - blue: _lerpDouble(x.b, y.b, t).clamp(0, 1), - colorSpace: x.colorSpace, + assert(a.colorSpace == b.colorSpace); + return Color._fromARGBC( + engine.clampInt(_lerpInt(a.alpha, b.alpha, t).toInt(), 0, 255), + engine.clampInt(_lerpInt(a.red, b.red, t).toInt(), 0, 255), + engine.clampInt(_lerpInt(a.green, b.green, t).toInt(), 0, 255), + engine.clampInt(_lerpInt(a.blue, b.blue, t).toInt(), 0, 255), + a.colorSpace, ); } } @@ -175,30 +175,30 @@ class Color { static Color alphaBlend(Color foreground, Color background) { assert(foreground.colorSpace == background.colorSpace); assert(foreground.colorSpace != ColorSpace.extendedSRGB); - final double alpha = foreground.a; - if (alpha == 0) { // Foreground completely transparent. + final int alpha = foreground.alpha; + if (alpha == 0x00) { return background; } - final double invAlpha = 1 - alpha; - double backAlpha = background.a; - if (backAlpha == 1) { // Opaque background case - return Color.from( - alpha: 1, - red: alpha * foreground.r + invAlpha * background.r, - green: alpha * foreground.g + invAlpha * background.g, - blue: alpha * foreground.b + invAlpha * background.b, - colorSpace: foreground.colorSpace, + final int invAlpha = 0xff - alpha; + int backAlpha = background.alpha; + if (backAlpha == 0xff) { + return Color._fromARGBC( + 0xff, + (alpha * foreground.red + invAlpha * background.red) ~/ 0xff, + (alpha * foreground.green + invAlpha * background.green) ~/ 0xff, + (alpha * foreground.blue + invAlpha * background.blue) ~/ 0xff, + foreground.colorSpace, ); - } else { // General case - backAlpha = backAlpha * invAlpha; - final double outAlpha = alpha + backAlpha; - assert(outAlpha != 0); - return Color.from( - alpha: outAlpha, - red: (foreground.r * alpha + background.r * backAlpha) / outAlpha, - green: (foreground.g * alpha + background.g * backAlpha) / outAlpha, - blue: (foreground.b * alpha + background.b * backAlpha) / outAlpha, - colorSpace: foreground.colorSpace, + } else { + backAlpha = (backAlpha * invAlpha) ~/ 0xff; + final int outAlpha = alpha + backAlpha; + assert(outAlpha != 0x00); + return Color._fromARGBC( + outAlpha, + (foreground.red * alpha + background.red * backAlpha) ~/ outAlpha, + (foreground.green * alpha + background.green * backAlpha) ~/ outAlpha, + (foreground.blue * alpha + background.blue * backAlpha) ~/ outAlpha, + foreground.colorSpace, ); } } @@ -216,19 +216,15 @@ class Color { return false; } return other is Color && - other.a == a && - other.r == r && - other.g == g && - other.b == b && + other.value == value && other.colorSpace == colorSpace; } @override - int get hashCode => Object.hash(a, r, g, b, colorSpace); + int get hashCode => Object.hash(value, colorSpace); @override - String toString() => - 'Color(alpha: ${a.toStringAsFixed(4)}, red: ${r.toStringAsFixed(4)}, green: ${g.toStringAsFixed(4)}, blue: ${b.toStringAsFixed(4)}, colorSpace: $colorSpace)'; + String toString() => 'Color(0x${value.toRadixString(16).padLeft(8, '0')})'; } enum StrokeCap { diff --git a/lib/web_ui/test/ui/color_test.dart b/lib/web_ui/test/ui/color_test.dart index 6ee06e7f8a734..2ac2df7595d02 100644 --- a/lib/web_ui/test/ui/color_test.dart +++ b/lib/web_ui/test/ui/color_test.dart @@ -8,33 +8,6 @@ import 'package:ui/ui.dart'; import '../common/test_initialization.dart'; - -class _ColorMatcher extends Matcher { - _ColorMatcher(this._target, this._threshold); - - final Color _target; - final double _threshold; - - @override - Description describe(Description description) { - return description.add('matches color "$_target" with threshold "$_threshold".'); - } - - @override - bool matches(dynamic item, Map matchState) { - return item is Color && - item.colorSpace == _target.colorSpace && - (item.a - _target.a).abs() <= _threshold && - (item.r - _target.r).abs() <= _threshold && - (item.g - _target.g).abs() <= _threshold && - (item.b - _target.b).abs() <= _threshold; - } -} - -Matcher isSameColorAs(Color color, {double threshold = 0.004}) { - return _ColorMatcher(color, threshold); -} - void main() { internalBootstrapBrowserTest(() => testMain); } @@ -58,7 +31,7 @@ Future testMain() async { const Color c = Color(0x00000000); final Paint p = Paint(); p.color = c; - expect(c.toString(), equals('${const Color(0x00000000)}')); + expect(c.toString(), equals('Color(0x00000000)')); }); test('color created with out of bounds value', () { @@ -90,7 +63,7 @@ Future testMain() async { ); expect( Color.lerp(const Color(0x00000000), const Color(0xFFFFFFFF), 0.5), - isSameColorAs(const Color(0x7F7F7F7F)), + const Color(0x7F7F7F7F), ); expect( Color.lerp(const Color(0x00000000), const Color(0xFFFFFFFF), 1.0), @@ -129,23 +102,23 @@ Future testMain() async { ); expect( Color.alphaBlend(const Color(0x80808080), const Color(0xFFFFFFFF)), - isSameColorAs(const Color(0xFFBFBFBF)), + const Color(0xFFBFBFBF), ); expect( Color.alphaBlend(const Color(0x80808080), const Color(0xFF000000)), - isSameColorAs(const Color(0xFF404040)), + const Color(0xFF404040), ); expect( Color.alphaBlend(const Color(0x01020304), const Color(0xFF000000)), - isSameColorAs(const Color(0xFF000000)), + const Color(0xFF000000), ); expect( Color.alphaBlend(const Color(0x11223344), const Color(0xFF000000)), - isSameColorAs(const Color(0xFF020304)), + const Color(0xFF020304), ); expect( Color.alphaBlend(const Color(0x11223344), const Color(0x80000000)), - isSameColorAs(const Color(0x88040608)), + const Color(0x88040608), ); }); diff --git a/lib/web_ui/test/ui/filters_test.dart b/lib/web_ui/test/ui/filters_test.dart index fc7ce4aa604aa..d2ca97291548e 100644 --- a/lib/web_ui/test/ui/filters_test.dart +++ b/lib/web_ui/test/ui/filters_test.dart @@ -121,22 +121,22 @@ Future testMain() async { test('color filter as image filter', () async { const ui.ColorFilter colorFilter = ui.ColorFilter.mode( - ui.Color.fromARGB(128, 0, 0, 255), + ui.Color.fromRGBO(0, 0, 255, 128), ui.BlendMode.srcOver, ); await drawTestImageWithPaint(ui.Paint()..imageFilter = colorFilter); await matchGoldenFile('ui_filter_colorfilter_as_imagefilter.png', region: region); - expect(colorFilter.toString(), 'ColorFilter.mode(${const ui.Color(0x800000ff)}, BlendMode.srcOver)'); + expect(colorFilter.toString(), 'ColorFilter.mode(Color(0x800000ff), BlendMode.srcOver)'); }); test('mode color filter', () async { const ui.ColorFilter colorFilter = ui.ColorFilter.mode( - ui.Color.fromARGB(128, 0, 0, 255), + ui.Color.fromRGBO(0, 0, 255, 128), ui.BlendMode.srcOver, ); await drawTestImageWithPaint(ui.Paint()..colorFilter = colorFilter); await matchGoldenFile('ui_filter_mode_colorfilter.png', region: region); - expect(colorFilter.toString(), 'ColorFilter.mode(${const ui.Color(0x800000ff)}, BlendMode.srcOver)'); + expect(colorFilter.toString(), 'ColorFilter.mode(Color(0x800000ff), BlendMode.srcOver)'); }); test('linearToSRGBGamma color filter', () async { diff --git a/lib/web_ui/test/ui/paint_test.dart b/lib/web_ui/test/ui/paint_test.dart index 253ba3d17d38e..759aa636321d7 100644 --- a/lib/web_ui/test/ui/paint_test.dart +++ b/lib/web_ui/test/ui/paint_test.dart @@ -69,7 +69,7 @@ Future testMain() async { expect( paint.toString(), 'Paint(' - '${const ui.Color(0xaabbccdd)}; ' + 'Color(0xaabbccdd); ' 'BlendMode.darken; ' 'colorFilter: ColorFilter.linearToSrgbGamma(); ' 'maskFilter: MaskFilter.blur(BlurStyle.normal, 1.7); ' diff --git a/lib/web_ui/test/ui/text_style_test.dart b/lib/web_ui/test/ui/text_style_test.dart index 98b5241946703..67eda1dedf007 100644 --- a/lib/web_ui/test/ui/text_style_test.dart +++ b/lib/web_ui/test/ui/text_style_test.dart @@ -122,9 +122,9 @@ Future testMain() async { expect( style.toString(), 'TextStyle(' - 'color: ${const ui.Color(0xff000000)}, ' + 'color: Color(0xff000000), ' 'decoration: TextDecoration.none, ' - 'decorationColor: ${const ui.Color(0xffaa0000)}, ' + 'decorationColor: Color(0xffaa0000), ' 'decorationStyle: TextDecorationStyle.solid, ' 'decorationThickness: ${1.0}, ' 'fontWeight: FontWeight.w400, ' @@ -140,7 +140,7 @@ Future testMain() async { 'locale: en_US, ' 'background: Paint(), ' 'foreground: unspecified, ' - 'shadows: [TextShadow(${const ui.Color(0xff000000)}, Offset(0.0, 0.0), ${0.0})], ' + 'shadows: [TextShadow(Color(0xff000000), Offset(0.0, 0.0), ${0.0})], ' "fontFeatures: [FontFeature('case', 1)], " "fontVariations: [FontVariation('ital', 0.1)]" ')', @@ -165,7 +165,7 @@ Future testMain() async { 'TextStyle(' 'color: unspecified, ' 'decoration: TextDecoration.none, ' - 'decorationColor: ${const ui.Color(0xffaa0000)}, ' + 'decorationColor: Color(0xffaa0000), ' 'decorationStyle: TextDecorationStyle.solid, ' 'decorationThickness: ${1.0}, ' 'fontWeight: FontWeight.w400, ' @@ -181,7 +181,7 @@ Future testMain() async { 'locale: en_US, ' 'background: Paint(), ' 'foreground: Paint(), ' - 'shadows: [TextShadow(${const ui.Color(0xff000000)}, Offset(0.0, 0.0), ${0.0})], ' + 'shadows: [TextShadow(Color(0xff000000), Offset(0.0, 0.0), ${0.0})], ' "fontFeatures: [FontFeature('case', 1)], " "fontVariations: [FontVariation('ital', 0.1)]" ')', diff --git a/testing/dart/color_test.dart b/testing/dart/color_test.dart index f686bf48f8488..56e8766f103b2 100644 --- a/testing/dart/color_test.dart +++ b/testing/dart/color_test.dart @@ -6,19 +6,6 @@ import 'dart:ui'; import 'package:litetest/litetest.dart'; -/// Positive result when the Colors will map to the same argb8888 color. -Matcher colorMatches(dynamic o) => (v) { - Expect.isTrue(o is Color); - Expect.isTrue(v is Color); - if (o is Color && v is Color) { - Expect.equals(o.colorSpace, v.colorSpace); - Expect.approxEquals(o.a, v.a, 1 / 255); - Expect.approxEquals(o.r, v.r, 1 / 255); - Expect.approxEquals(o.g, v.g, 1 / 255); - Expect.approxEquals(o.b, v.b, 1 / 255); - } -}; - class NotAColor extends Color { const NotAColor(super.value); } @@ -40,7 +27,7 @@ void main() { const Color c = Color(0x00000000); final Paint p = Paint(); p.color = c; - expect(c, equals(const Color(0x00000000))); + expect(c.toString(), equals('Color(0x00000000)')); }); test('color created with out of bounds value', () { @@ -71,7 +58,7 @@ void main() { ); expect( Color.lerp(const Color(0x00000000), const Color(0xFFFFFFFF), 0.5), - colorMatches(const Color(0x7F7F7F7F)), + const Color(0x7F7F7F7F), ); expect( Color.lerp(const Color(0x00000000), const Color(0xFFFFFFFF), 1.0), @@ -161,23 +148,23 @@ void main() { ); expect( Color.alphaBlend(const Color(0x80808080), const Color(0xFFFFFFFF)), - colorMatches(const Color(0xFFBFBFBF)), + const Color(0xFFBFBFBF), ); expect( Color.alphaBlend(const Color(0x80808080), const Color(0xFF000000)), - colorMatches(const Color(0xFF404040)), + const Color(0xFF404040), ); expect( Color.alphaBlend(const Color(0x01020304), const Color(0xFF000000)), - colorMatches(const Color(0xFF000000)), + const Color(0xFF000000), ); expect( Color.alphaBlend(const Color(0x11223344), const Color(0xFF000000)), - colorMatches(const Color(0xFF020304)), + const Color(0xFF020304), ); expect( Color.alphaBlend(const Color(0x11223344), const Color(0x80000000)), - colorMatches(const Color(0x88040608)), + const Color(0x88040608), ); }); diff --git a/testing/dart/image_filter_test.dart b/testing/dart/image_filter_test.dart index d017ff24be229..0200d6f2d45cd 100644 --- a/testing/dart/image_filter_test.dart +++ b/testing/dart/image_filter_test.dart @@ -293,7 +293,7 @@ void main() async { ).toString(), contains( 'matrix([10.0, 0.0, 0.0, 0.0, 0.0, 10.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -0.0, -0.0, 0.0, 1.0], FilterQuality.low) -> ' - 'ColorFilter.mode(${const Color(0xFFABCDEF)}, BlendMode.color) -> ' + 'ColorFilter.mode(Color(0xffabcdef), BlendMode.color) -> ' 'blur(20.0, 20.0, repeated) -> ' 'blur(30.0, 30.0, mirror)' ), diff --git a/testing/dart/text_test.dart b/testing/dart/text_test.dart index 46f176bca0d67..108aefb7a53ed 100644 --- a/testing/dart/text_test.dart +++ b/testing/dart/text_test.dart @@ -80,7 +80,7 @@ void testTextStyle() { ); expect( ts1.toString(), - equals('TextStyle(color: ${const Color(0xFF00FF00)}, decoration: unspecified, decorationColor: unspecified, decorationStyle: unspecified, decorationThickness: unspecified, fontWeight: FontWeight.w800, fontStyle: unspecified, textBaseline: unspecified, fontFamily: unspecified, fontFamilyFallback: unspecified, fontSize: 10.0, letterSpacing: unspecified, wordSpacing: unspecified, height: 100.0x, leadingDistribution: unspecified, locale: unspecified, background: unspecified, foreground: unspecified, shadows: unspecified, fontFeatures: unspecified, fontVariations: unspecified)'), + equals('TextStyle(color: Color(0xff00ff00), decoration: unspecified, decorationColor: unspecified, decorationStyle: unspecified, decorationThickness: unspecified, fontWeight: FontWeight.w800, fontStyle: unspecified, textBaseline: unspecified, fontFamily: unspecified, fontFamilyFallback: unspecified, fontSize: 10.0, letterSpacing: unspecified, wordSpacing: unspecified, height: 100.0x, leadingDistribution: unspecified, locale: unspecified, background: unspecified, foreground: unspecified, shadows: unspecified, fontFeatures: unspecified, fontVariations: unspecified)'), ); expect( ts2.toString(),