Normalize the translation column of the color matrix. (#161109)

`dart:ui` specifies that the translation column of the color matrix
should be in the range 0..255. Skia expects a normalized range between 0
and 1. Skwasm was not normalizing this before passing it to Skia, but
CanvasKit was. After writing a unit test, it appears that the HTML
renderer has the same problem, so I also fixed that as well.

This addresses https://github.com/flutter/flutter/issues/159697
This commit is contained in:
Jackson Gardner 2025-01-08 12:39:21 -08:00 committed by GitHub
parent 132e298335
commit 1e9202e1ee
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 45 additions and 42 deletions

View File

@ -312,7 +312,18 @@ class SvgFilter {
SvgFilter svgFilterFromColorMatrix(List<double> matrix) {
final SvgFilterBuilder builder = SvgFilterBuilder();
builder.setFeColorMatrix(matrix, result: 'comp');
/// Flutter documentation says the translation column of the color matrix
/// is specified in unnormalized 0..255 space. `feColorMatrix` expects the
/// translation values to be normalized to 0..1 space.
///
/// See [https://api.flutter.dev/flutter/dart-ui/ColorFilter/ColorFilter.matrix.html]
final normalizedMatrix = List<double>.generate(
matrix.length,
(int i) => (i % 5 == 4) ? matrix[i] / 255.0 : matrix[i],
growable: false,
);
builder.setFeColorMatrix(normalizedMatrix, result: 'comp');
return builder.build();
}

View File

@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:ffi';
import 'dart:typed_data';
import 'package:ui/src/engine.dart';
@ -318,7 +319,18 @@ class SkwasmMatrixColorFilter extends SkwasmColorFilter {
@override
void withRawColorFilter(ColorFilterHandleBorrow borrow) {
withStackScope((scope) {
final rawColorFilter = colorFilterCreateMatrix(scope.convertDoublesToNative(matrix));
assert(matrix.length == 20);
final Pointer<Float> rawMatrix = scope.convertDoublesToNative(matrix);
/// Flutter documentation says the translation column of the color matrix
/// is specified in unnormalized 0..255 space. Skia expects the
/// translation values to be normalized to 0..1 space.
///
/// See [https://api.flutter.dev/flutter/dart-ui/ColorFilter/ColorFilter.matrix.html].
for (final i in <int>[4, 9, 14, 19]) {
rawMatrix[i] /= 255.0;
}
final rawColorFilter = colorFilterCreateMatrix(rawMatrix);
borrow(rawColorFilter);
colorFilterDispose(rawColorFilter);
});

View File

@ -146,32 +146,28 @@ Future<void> testMain() async {
test('matrix color filter', () async {
const ui.ColorFilter sepia = ui.ColorFilter.matrix(<double>[
0.393,
0.769,
0.189,
0,
0,
0.349,
0.686,
0.168,
0,
0,
0.272,
0.534,
0.131,
0,
0,
0,
0,
0,
1,
0,
0.393, 0.769, 0.189, 0, 0, // row
0.349, 0.686, 0.168, 0, 0, // row
0.272, 0.534, 0.131, 0, 0, // row
0, 0, 0, 1, 0, // row
]);
await drawTestImageWithPaint(ui.Paint()..colorFilter = sepia);
await matchGoldenFile('ui_filter_matrix_colorfilter.png', region: region);
expect(sepia.toString(), startsWith('ColorFilter.matrix([0.393, 0.769, 0.189, '));
});
test('matrix color filter with 0..255 translation values', () async {
const ui.ColorFilter sepia = ui.ColorFilter.matrix(<double>[
0.393, 0.769, 0.189, 0, 50.0, // row
0.349, 0.686, 0.168, 0, 50.0, // row
0.272, 0.534, 0.131, 0, 50.0, // row
0, 0, 0, 1, 0, // row
]);
await drawTestImageWithPaint(ui.Paint()..colorFilter = sepia);
await matchGoldenFile('ui_filter_matrix_colorfilter_with_translation.png', region: region);
expect(sepia.toString(), startsWith('ColorFilter.matrix([0.393, 0.769, 0.189, '));
});
test('invert colors', () async {
await drawTestImageWithPaint(ui.Paint()..invertColors = true);
await matchGoldenFile('ui_filter_invert_colors.png', region: region);
@ -179,26 +175,10 @@ Future<void> testMain() async {
test('invert colors with color filter', () async {
const ui.ColorFilter sepia = ui.ColorFilter.matrix(<double>[
0.393,
0.769,
0.189,
0,
0,
0.349,
0.686,
0.168,
0,
0,
0.272,
0.534,
0.131,
0,
0,
0,
0,
0,
1,
0,
0.393, 0.769, 0.189, 0, 0, // row
0.349, 0.686, 0.168, 0, 0, // row
0.272, 0.534, 0.131, 0, 0, // row
0, 0, 0, 1, 0, // row
]);
await drawTestImageWithPaint(