Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 8609af6

Browse files
authored
Revert "Update Color to do all calculations with floating point components" (#55153)
Reverts #54981 This is causing failures in customer tests that need to be updated: https://github.com/flutter/flutter/pull/155107/checks?check_run_id=30069840819
1 parent 8ccdbda commit 8609af6

File tree

12 files changed

+138
-164
lines changed

12 files changed

+138
-164
lines changed

flutter_frontend_server/test/to_string_test.dart

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,7 @@ void main() {
6060
]));
6161
final runResult = io.Process.runSync(dart, <String>[regularDill]);
6262
checkProcessResult(runResult);
63-
var paintString =
64-
'"Paint.toString":"Paint(Color(alpha: 1.0000, red: 1.0000, green: 1.0000, blue: 1.0000, colorSpace: ColorSpace.sRGB))"';
63+
var paintString = '"Paint.toString":"Paint(Color(0xffffffff))"';
6564
if (buildDir.contains('release')) {
6665
paintString = '"Paint.toString":"Instance of \'Paint\'"';
6766
}

lib/ui/lerp.dart

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,15 @@ double _lerpDouble(double a, double b, double t) {
3737
double _lerpInt(int a, int b, double t) {
3838
return a + (b - a) * t;
3939
}
40+
41+
/// Same as [num.clamp] but specialized for non-null [int].
42+
int _clampInt(int value, int min, int max) {
43+
assert(min <= max);
44+
if (value < min) {
45+
return min;
46+
} else if (value > max) {
47+
return max;
48+
} else {
49+
return value;
50+
}
51+
}

lib/ui/painting.dart

Lines changed: 48 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ bool _radiusIsValid(Radius radius) {
4848
return true;
4949
}
5050

51-
Color _scaleAlpha(Color x, double factor) {
52-
return x.withValues(alpha: clampDouble(x.a * factor, 0, 1));
51+
Color _scaleAlpha(Color a, double factor) {
52+
return a.withAlpha((a.alpha * factor).round().clamp(0, 255));
5353
}
5454

5555
/// An immutable 32 bit color value in ARGB format.
@@ -310,11 +310,10 @@ class Color {
310310
///
311311
/// See <https://en.wikipedia.org/wiki/Relative_luminance>.
312312
double computeLuminance() {
313-
assert(colorSpace != ColorSpace.extendedSRGB);
314313
// See <https://www.w3.org/TR/WCAG20/#relativeluminancedef>
315-
final double R = _linearizeColorComponent(r);
316-
final double G = _linearizeColorComponent(g);
317-
final double B = _linearizeColorComponent(b);
314+
final double R = _linearizeColorComponent(red / 0xFF);
315+
final double G = _linearizeColorComponent(green / 0xFF);
316+
final double B = _linearizeColorComponent(blue / 0xFF);
318317
return 0.2126 * R + 0.7152 * G + 0.0722 * B;
319318
}
320319

@@ -340,26 +339,28 @@ class Color {
340339
///
341340
/// Values for `t` are usually obtained from an [Animation<double>], such as
342341
/// an [AnimationController].
343-
static Color? lerp(Color? x, Color? y, double t) {
344-
assert(x?.colorSpace != ColorSpace.extendedSRGB);
345-
assert(y?.colorSpace != ColorSpace.extendedSRGB);
346-
if (y == null) {
347-
if (x == null) {
342+
static Color? lerp(Color? a, Color? b, double t) {
343+
// TODO(gaaclarke): Update math to use floats. This was already attempted
344+
// but it leads to subtle changes that change test results.
345+
assert(a?.colorSpace != ColorSpace.extendedSRGB);
346+
assert(b?.colorSpace != ColorSpace.extendedSRGB);
347+
if (b == null) {
348+
if (a == null) {
348349
return null;
349350
} else {
350-
return _scaleAlpha(x, 1.0 - t);
351+
return _scaleAlpha(a, 1.0 - t);
351352
}
352353
} else {
353-
if (x == null) {
354-
return _scaleAlpha(y, t);
354+
if (a == null) {
355+
return _scaleAlpha(b, t);
355356
} else {
356-
assert(x.colorSpace == y.colorSpace);
357-
return Color.from(
358-
alpha: clampDouble(_lerpDouble(x.a, y.a, t), 0, 1),
359-
red: clampDouble(_lerpDouble(x.r, y.r, t), 0, 1),
360-
green: clampDouble(_lerpDouble(x.g, y.g, t), 0, 1),
361-
blue: clampDouble(_lerpDouble(x.b, y.b, t), 0, 1),
362-
colorSpace: x.colorSpace,
357+
assert(a.colorSpace == b.colorSpace);
358+
return Color._fromARGBC(
359+
_clampInt(_lerpInt(a.alpha, b.alpha, t).toInt(), 0, 255),
360+
_clampInt(_lerpInt(a.red, b.red, t).toInt(), 0, 255),
361+
_clampInt(_lerpInt(a.green, b.green, t).toInt(), 0, 255),
362+
_clampInt(_lerpInt(a.blue, b.blue, t).toInt(), 0, 255),
363+
a.colorSpace,
363364
);
364365
}
365366
}
@@ -376,30 +377,32 @@ class Color {
376377
static Color alphaBlend(Color foreground, Color background) {
377378
assert(foreground.colorSpace == background.colorSpace);
378379
assert(foreground.colorSpace != ColorSpace.extendedSRGB);
379-
final double alpha = foreground.a;
380-
if (alpha == 0) { // Foreground completely transparent.
380+
// TODO(gaaclarke): Update math to use floats. This was already attempted
381+
// but it leads to subtle changes that change test results.
382+
final int alpha = foreground.alpha;
383+
if (alpha == 0x00) { // Foreground completely transparent.
381384
return background;
382385
}
383-
final double invAlpha = 1 - alpha;
384-
double backAlpha = background.a;
385-
if (backAlpha == 1) { // Opaque background case
386-
return Color.from(
387-
alpha: 1,
388-
red: alpha * foreground.r + invAlpha * background.r,
389-
green: alpha * foreground.g + invAlpha * background.g,
390-
blue: alpha * foreground.b + invAlpha * background.b,
391-
colorSpace: foreground.colorSpace,
386+
final int invAlpha = 0xff - alpha;
387+
int backAlpha = background.alpha;
388+
if (backAlpha == 0xff) { // Opaque background case
389+
return Color._fromARGBC(
390+
0xff,
391+
(alpha * foreground.red + invAlpha * background.red) ~/ 0xff,
392+
(alpha * foreground.green + invAlpha * background.green) ~/ 0xff,
393+
(alpha * foreground.blue + invAlpha * background.blue) ~/ 0xff,
394+
foreground.colorSpace,
392395
);
393396
} else { // General case
394-
backAlpha = backAlpha * invAlpha;
395-
final double outAlpha = alpha + backAlpha;
396-
assert(outAlpha != 0);
397-
return Color.from(
398-
alpha: outAlpha,
399-
red: (foreground.r * alpha + background.r * backAlpha) / outAlpha,
400-
green: (foreground.g * alpha + background.g * backAlpha) / outAlpha,
401-
blue: (foreground.b * alpha + background.b * backAlpha) / outAlpha,
402-
colorSpace: foreground.colorSpace,
397+
backAlpha = (backAlpha * invAlpha) ~/ 0xff;
398+
final int outAlpha = alpha + backAlpha;
399+
assert(outAlpha != 0x00);
400+
return Color._fromARGBC(
401+
outAlpha,
402+
(foreground.red * alpha + background.red * backAlpha) ~/ outAlpha,
403+
(foreground.green * alpha + background.green * backAlpha) ~/ outAlpha,
404+
(foreground.blue * alpha + background.blue * backAlpha) ~/ outAlpha,
405+
foreground.colorSpace,
403406
);
404407
}
405408
}
@@ -420,19 +423,16 @@ class Color {
420423
return false;
421424
}
422425
return other is Color &&
423-
other.a == a &&
424-
other.r == r &&
425-
other.g == g &&
426-
other.b == b &&
426+
other.value == value &&
427427
other.colorSpace == colorSpace;
428428
}
429429

430430
@override
431-
int get hashCode => Object.hash(a, r, g, b, colorSpace);
431+
int get hashCode => Object.hash(value, colorSpace);
432432

433+
// TODO(gaaclarke): Make toString() print out float values.
433434
@override
434-
String toString() =>
435-
'Color(alpha: ${a.toStringAsFixed(4)}, red: ${r.toStringAsFixed(4)}, green: ${g.toStringAsFixed(4)}, blue: ${b.toStringAsFixed(4)}, colorSpace: $colorSpace)';
435+
String toString() => 'Color(0x${value.toRadixString(16).padLeft(8, '0')})';
436436
}
437437

438438
/// Algorithms to use when painting on the canvas.

lib/web_ui/lib/lerp.dart

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,10 @@ double? lerpDouble(num? a, num? b, double t) {
2828
double _lerpDouble(double a, double b, double t) {
2929
return a * (1.0 - t) + b * t;
3030
}
31+
32+
/// Linearly interpolate between two integers.
33+
///
34+
/// Same as [lerpDouble] but specialized for non-null `int` type.
35+
double _lerpInt(int a, int b, double t) {
36+
return a * (1.0 - t) + b * t;
37+
}

lib/web_ui/lib/painting.dart

Lines changed: 44 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ void _validateColorStops(List<Color> colors, List<double>? colorStops) {
1717
}
1818
}
1919

20-
Color _scaleAlpha(Color x, double factor) {
21-
return x.withValues(alpha: (x.a * factor).clamp(0, 1));
20+
Color _scaleAlpha(Color a, double factor) {
21+
return a.withAlpha(engine.clampInt((a.alpha * factor).round(), 0, 255));
2222
}
2323

2424
class Color {
@@ -141,32 +141,32 @@ class Color {
141141

142142
double computeLuminance() {
143143
// See <https://www.w3.org/TR/WCAG20/#relativeluminancedef>
144-
final double R = _linearizeColorComponent(r);
145-
final double G = _linearizeColorComponent(g);
146-
final double B = _linearizeColorComponent(b);
144+
final double R = _linearizeColorComponent(red / 0xFF);
145+
final double G = _linearizeColorComponent(green / 0xFF);
146+
final double B = _linearizeColorComponent(blue / 0xFF);
147147
return 0.2126 * R + 0.7152 * G + 0.0722 * B;
148148
}
149149

150-
static Color? lerp(Color? x, Color? y, double t) {
151-
assert(x?.colorSpace != ColorSpace.extendedSRGB);
152-
assert(y?.colorSpace != ColorSpace.extendedSRGB);
153-
if (y == null) {
154-
if (x == null) {
150+
static Color? lerp(Color? a, Color? b, double t) {
151+
assert(a?.colorSpace != ColorSpace.extendedSRGB);
152+
assert(b?.colorSpace != ColorSpace.extendedSRGB);
153+
if (b == null) {
154+
if (a == null) {
155155
return null;
156156
} else {
157-
return _scaleAlpha(x, 1.0 - t);
157+
return _scaleAlpha(a, 1.0 - t);
158158
}
159159
} else {
160-
if (x == null) {
161-
return _scaleAlpha(y, t);
160+
if (a == null) {
161+
return _scaleAlpha(b, t);
162162
} else {
163-
assert(x.colorSpace == y.colorSpace);
164-
return Color.from(
165-
alpha: _lerpDouble(x.a, y.a, t).clamp(0, 1),
166-
red: _lerpDouble(x.r, y.r, t).clamp(0, 1),
167-
green: _lerpDouble(x.g, y.g, t).clamp(0, 1),
168-
blue: _lerpDouble(x.b, y.b, t).clamp(0, 1),
169-
colorSpace: x.colorSpace,
163+
assert(a.colorSpace == b.colorSpace);
164+
return Color._fromARGBC(
165+
engine.clampInt(_lerpInt(a.alpha, b.alpha, t).toInt(), 0, 255),
166+
engine.clampInt(_lerpInt(a.red, b.red, t).toInt(), 0, 255),
167+
engine.clampInt(_lerpInt(a.green, b.green, t).toInt(), 0, 255),
168+
engine.clampInt(_lerpInt(a.blue, b.blue, t).toInt(), 0, 255),
169+
a.colorSpace,
170170
);
171171
}
172172
}
@@ -175,30 +175,30 @@ class Color {
175175
static Color alphaBlend(Color foreground, Color background) {
176176
assert(foreground.colorSpace == background.colorSpace);
177177
assert(foreground.colorSpace != ColorSpace.extendedSRGB);
178-
final double alpha = foreground.a;
179-
if (alpha == 0) { // Foreground completely transparent.
178+
final int alpha = foreground.alpha;
179+
if (alpha == 0x00) {
180180
return background;
181181
}
182-
final double invAlpha = 1 - alpha;
183-
double backAlpha = background.a;
184-
if (backAlpha == 1) { // Opaque background case
185-
return Color.from(
186-
alpha: 1,
187-
red: alpha * foreground.r + invAlpha * background.r,
188-
green: alpha * foreground.g + invAlpha * background.g,
189-
blue: alpha * foreground.b + invAlpha * background.b,
190-
colorSpace: foreground.colorSpace,
182+
final int invAlpha = 0xff - alpha;
183+
int backAlpha = background.alpha;
184+
if (backAlpha == 0xff) {
185+
return Color._fromARGBC(
186+
0xff,
187+
(alpha * foreground.red + invAlpha * background.red) ~/ 0xff,
188+
(alpha * foreground.green + invAlpha * background.green) ~/ 0xff,
189+
(alpha * foreground.blue + invAlpha * background.blue) ~/ 0xff,
190+
foreground.colorSpace,
191191
);
192-
} else { // General case
193-
backAlpha = backAlpha * invAlpha;
194-
final double outAlpha = alpha + backAlpha;
195-
assert(outAlpha != 0);
196-
return Color.from(
197-
alpha: outAlpha,
198-
red: (foreground.r * alpha + background.r * backAlpha) / outAlpha,
199-
green: (foreground.g * alpha + background.g * backAlpha) / outAlpha,
200-
blue: (foreground.b * alpha + background.b * backAlpha) / outAlpha,
201-
colorSpace: foreground.colorSpace,
192+
} else {
193+
backAlpha = (backAlpha * invAlpha) ~/ 0xff;
194+
final int outAlpha = alpha + backAlpha;
195+
assert(outAlpha != 0x00);
196+
return Color._fromARGBC(
197+
outAlpha,
198+
(foreground.red * alpha + background.red * backAlpha) ~/ outAlpha,
199+
(foreground.green * alpha + background.green * backAlpha) ~/ outAlpha,
200+
(foreground.blue * alpha + background.blue * backAlpha) ~/ outAlpha,
201+
foreground.colorSpace,
202202
);
203203
}
204204
}
@@ -216,19 +216,15 @@ class Color {
216216
return false;
217217
}
218218
return other is Color &&
219-
other.a == a &&
220-
other.r == r &&
221-
other.g == g &&
222-
other.b == b &&
219+
other.value == value &&
223220
other.colorSpace == colorSpace;
224221
}
225222

226223
@override
227-
int get hashCode => Object.hash(a, r, g, b, colorSpace);
224+
int get hashCode => Object.hash(value, colorSpace);
228225

229226
@override
230-
String toString() =>
231-
'Color(alpha: ${a.toStringAsFixed(4)}, red: ${r.toStringAsFixed(4)}, green: ${g.toStringAsFixed(4)}, blue: ${b.toStringAsFixed(4)}, colorSpace: $colorSpace)';
227+
String toString() => 'Color(0x${value.toRadixString(16).padLeft(8, '0')})';
232228
}
233229

234230
enum StrokeCap {

0 commit comments

Comments
 (0)