Relands "Wide gamut framework gradient test (#153976)" (#157643)

This was reverted because it failed to run. Colors were getting clamped
in the dithering fragment shader.

One change was made when relanding, i increased the epsilon for the
radial and conical gradients. They don't appear to give back the exact
color you asked for.

Do not land until https://github.com/flutter/engine/pull/56140 is rolled
into the framework.

## Pre-launch Checklist

- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [x] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [x] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [x] All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel
on [Discord].

<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview
[Tree Hygiene]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
[test-exempt]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md
[Features we expect every widget to implement]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Discord]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md
[Data Driven Fixes]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
This commit is contained in:
gaaclarke 2024-10-26 08:44:53 -07:00 committed by GitHub
parent 9327c24d80
commit 5a11904383
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 175 additions and 21 deletions

View File

@ -44,7 +44,8 @@ bool _isAlmost(double x, double y, double epsilon) {
List<double> _deepRed = <double>[1.0931, -0.2268, -0.1501];
bool _findRGBAF16Color(
Uint8List bytes, int width, int height, List<double> color) {
Uint8List bytes, int width, int height, List<double> color,
{required double epsilon}) {
final ByteData byteData = ByteData.sublistView(bytes);
expect(bytes.lengthInBytes, width * height * 8);
expect(bytes.lengthInBytes, byteData.lengthInBytes);
@ -54,9 +55,9 @@ bool _findRGBAF16Color(
final double blue = _decodeHalf((pixel >> 32) & 0xffff);
final double green = _decodeHalf((pixel >> 16) & 0xffff);
final double red = _decodeHalf((pixel >> 0) & 0xffff);
if (_isAlmost(red, color[0], 0.01) &&
_isAlmost(green, color[1], 0.01) &&
_isAlmost(blue, color[2], 0.01)) {
if (_isAlmost(red, color[0], epsilon) &&
_isAlmost(green, color[1], epsilon) &&
_isAlmost(blue, color[2], epsilon)) {
foundDeepRed = true;
}
}
@ -64,7 +65,8 @@ bool _findRGBAF16Color(
}
bool _findBGRA10Color(
Uint8List bytes, int width, int height, List<double> color) {
Uint8List bytes, int width, int height, List<double> color,
{required double epsilon}) {
final ByteData byteData = ByteData.sublistView(bytes);
expect(bytes.lengthInBytes, width * height * 8);
expect(bytes.lengthInBytes, byteData.lengthInBytes);
@ -74,17 +76,17 @@ bool _findBGRA10Color(
final double blue = _decodeBGR10((pixel >> 6) & 0x3ff);
final double green = _decodeBGR10((pixel >> 22) & 0x3ff);
final double red = _decodeBGR10((pixel >> 38) & 0x3ff);
if (_isAlmost(red, color[0], 0.01) &&
_isAlmost(green, color[1], 0.01) &&
_isAlmost(blue, color[2], 0.01)) {
if (_isAlmost(red, color[0], epsilon) &&
_isAlmost(green, color[1], epsilon) &&
_isAlmost(blue, color[2], epsilon)) {
foundDeepRed = true;
}
}
return foundDeepRed;
}
bool _findBGR10Color(
Uint8List bytes, int width, int height, List<double> color) {
bool _findBGR10Color(Uint8List bytes, int width, int height, List<double> color,
{required double epsilon}) {
final ByteData byteData = ByteData.sublistView(bytes);
expect(bytes.lengthInBytes, width * height * 4);
expect(bytes.lengthInBytes, byteData.lengthInBytes);
@ -94,23 +96,27 @@ bool _findBGR10Color(
final double blue = _decodeBGR10(pixel & 0x3ff);
final double green = _decodeBGR10((pixel >> 10) & 0x3ff);
final double red = _decodeBGR10((pixel >> 20) & 0x3ff);
if (_isAlmost(red, color[0], 0.01) &&
_isAlmost(green, color[1], 0.01) &&
_isAlmost(blue, color[2], 0.01)) {
if (_isAlmost(red, color[0], epsilon) &&
_isAlmost(green, color[1], epsilon) &&
_isAlmost(blue, color[2], epsilon)) {
foundDeepRed = true;
}
}
return foundDeepRed;
}
bool _findColor(List<dynamic> result, List<double> color) {
bool _findColor(List<dynamic> result, List<double> color,
{double epsilon = 0.01}) {
expect(result, isNotNull);
expect(result.length, 4);
final [int width, int height, String format, Uint8List bytes] = result;
return switch (format) {
'MTLPixelFormatBGR10_XR' => _findBGR10Color(bytes, width, height, color),
'MTLPixelFormatBGRA10_XR' => _findBGRA10Color(bytes, width, height, color),
'MTLPixelFormatRGBA16Float' => _findRGBAF16Color(bytes, width, height, color),
'MTLPixelFormatBGR10_XR' =>
_findBGR10Color(bytes, width, height, color, epsilon: epsilon),
'MTLPixelFormatBGRA10_XR' =>
_findBGRA10Color(bytes, width, height, color, epsilon: epsilon),
'MTLPixelFormatRGBA16Float' =>
_findRGBAF16Color(bytes, width, height, color, epsilon: epsilon),
_ => fail('Unsupported pixel format: $format'),
};
}
@ -157,7 +163,8 @@ void main() {
expect(_findColor(result, _deepRed), isTrue);
expect(_findColor(result, <double>[0.0, 1.0, 0.0]), isTrue);
});
testWidgets('draw image with wide gamut works', (WidgetTester tester) async {
testWidgets('draw image with wide gamut works',
(WidgetTester tester) async {
app.run(app.Setup.drawnImage);
await tester.pumpAndSettle(const Duration(seconds: 2));
@ -166,7 +173,8 @@ void main() {
await channel.invokeMethod('test') as List<Object?>;
expect(_findColor(result, <double>[0.0, 1.0, 0.0]), isTrue);
});
testWidgets('draw container with wide gamut works', (WidgetTester tester) async {
testWidgets('draw container with wide gamut works',
(WidgetTester tester) async {
app.run(app.Setup.container);
await tester.pumpAndSettle(const Duration(seconds: 2));
@ -175,5 +183,49 @@ void main() {
await channel.invokeMethod('test') as List<Object?>;
expect(_findColor(result, _deepRed), isTrue);
});
testWidgets('draw wide gamut linear gradient works',
(WidgetTester tester) async {
app.run(app.Setup.linearGradient);
await tester.pumpAndSettle(const Duration(seconds: 2));
const MethodChannel channel = MethodChannel('flutter/screenshot');
final List<Object?> result =
await channel.invokeMethod('test') as List<Object?>;
expect(_findColor(result, _deepRed), isTrue);
});
testWidgets('draw wide gamut radial gradient works',
(WidgetTester tester) async {
app.run(app.Setup.radialGradient);
await tester.pumpAndSettle(const Duration(seconds: 2));
const MethodChannel channel = MethodChannel('flutter/screenshot');
final List<Object?> result =
await channel.invokeMethod('test') as List<Object?>;
expect(_findColor(result, _deepRed, epsilon: 0.05), isTrue);
});
testWidgets('draw wide gamut conical gradient works',
(WidgetTester tester) async {
app.run(app.Setup.conicalGradient);
await tester.pumpAndSettle(const Duration(seconds: 2));
const MethodChannel channel = MethodChannel('flutter/screenshot');
final List<Object?> result =
await channel.invokeMethod('test') as List<Object?>;
expect(_findColor(result, _deepRed, epsilon: 0.05), isTrue);
});
testWidgets('draw wide gamut sweep gradient works',
(WidgetTester tester) async {
app.run(app.Setup.sweepGradient);
await tester.pumpAndSettle(const Duration(seconds: 2));
const MethodChannel channel = MethodChannel('flutter/screenshot');
final List<Object?> result =
await channel.invokeMethod('test') as List<Object?>;
expect(_findColor(result, _deepRed), isTrue);
});
});
}

View File

@ -137,7 +137,7 @@ const String _displayP3Logo =
'gr3yrjmlwqXLjmWw1O2I5Wmp9Xxjyh+AVIZ6ADIAqcwClakzeMgApDILVKbO4CED'
'kMosUJk6g4dUBuRfvf1am9VRqzYAAAAASUVORK5CYII=';
void main() => run(Setup.container);
void main() => run(Setup.sweepGradient);
enum Setup {
none,
@ -146,6 +146,10 @@ enum Setup {
blur,
drawnImage,
container,
linearGradient,
radialGradient,
conicalGradient,
sweepGradient,
}
void run(Setup setup) {
@ -265,7 +269,14 @@ class _MyHomePageState extends State<MyHomePage> {
_loadImage().then((ui.Image? value) => setState(() { _image = value; }));
case Setup.drawnImage:
_drawImage().then((ui.Image? value) => setState(() { _image = value; }));
case Setup.image || Setup.blur || Setup.none || Setup.container:
case Setup.image ||
Setup.blur ||
Setup.none ||
Setup.container ||
Setup.linearGradient ||
Setup.radialGradient ||
Setup.conicalGradient ||
Setup.sweepGradient:
break;
}
super.initState();
@ -308,6 +319,97 @@ class _MyHomePageState extends State<MyHomePage> {
green: 0,
blue: 0,
colorSpace: ui.ColorSpace.displayP3));
case Setup.linearGradient:
imageWidget = Container(
width: 100,
height: 100,
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: <Color>[
Color.from(
alpha: 1,
red: 1,
green: 0,
blue: 0,
colorSpace: ui.ColorSpace.displayP3),
Color.from(
alpha: 1,
red: 0,
green: 1,
blue: 0,
colorSpace: ui.ColorSpace.displayP3)],
),
),
);
case Setup.radialGradient:
imageWidget = Container(
width: 100,
height: 100,
decoration: const BoxDecoration(
gradient: RadialGradient(
colors: <Color>[
Color.from(
alpha: 1,
red: 1,
green: 0,
blue: 0,
colorSpace: ui.ColorSpace.displayP3),
Color.from(
alpha: 1,
red: 0,
green: 1,
blue: 0,
colorSpace: ui.ColorSpace.displayP3)],
),
),
);
case Setup.conicalGradient:
imageWidget = Container(
width: 100,
height: 100,
decoration: const BoxDecoration(
gradient: RadialGradient(
focal: Alignment(0.2, 0.2),
colors: <Color>[
Color.from(
alpha: 1,
red: 1,
green: 0,
blue: 0,
colorSpace: ui.ColorSpace.displayP3),
Color.from(
alpha: 1,
red: 0,
green: 1,
blue: 0,
colorSpace: ui.ColorSpace.displayP3)],
),
),
);
case Setup.sweepGradient:
imageWidget = Container(
width: 100,
height: 100,
decoration: const BoxDecoration(
gradient: SweepGradient(
colors: <Color>[
Color.from(
alpha: 1,
red: 1,
green: 0,
blue: 0,
colorSpace: ui.ColorSpace.displayP3),
Color.from(
alpha: 1,
red: 0,
green: 1,
blue: 0,
colorSpace: ui.ColorSpace.displayP3)],
),
),
);
}
return Scaffold(