未验证 提交 41a92052 编写于 作者: F Ferhat 提交者: GitHub

Implement ColorFilter.matrix for html renderer (#25769)

上级 1019008f
repository: https://github.com/flutter/goldens.git
revision: 8d866a84b7ceb67412ce6767ea0c1eec2eb3fa3f
revision: 4a8da9f65353bda26a73e12838797f20cfdedc40
......@@ -631,29 +631,11 @@ class BitmapCanvas extends EngineCanvas {
paint.colorFilter as EngineColorFilter?;
html.HtmlElement imgElement;
if (colorFilter is _CkBlendModeColorFilter) {
switch (colorFilter.blendMode) {
case ui.BlendMode.colorBurn:
case ui.BlendMode.colorDodge:
case ui.BlendMode.hue:
case ui.BlendMode.modulate:
case ui.BlendMode.overlay:
case ui.BlendMode.plus:
case ui.BlendMode.srcIn:
case ui.BlendMode.srcATop:
case ui.BlendMode.srcOut:
case ui.BlendMode.saturation:
case ui.BlendMode.color:
case ui.BlendMode.luminosity:
case ui.BlendMode.xor:
case ui.BlendMode.dstATop:
imgElement = _createImageElementWithSvgFilter(
image, colorFilter.color, colorFilter.blendMode, paint);
break;
default:
imgElement = _createBackgroundImageWithBlend(
image, colorFilter.color, colorFilter.blendMode, paint);
break;
}
imgElement = _createImageElementWithBlend(image,
colorFilter.color, colorFilter.blendMode, paint);
} else if (colorFilter is _CkMatrixColorFilter) {
imgElement = _createImageElementWithSvgColorMatrixFilter(
image, colorFilter.matrix , paint);
} else {
// No Blending, create an image by cloning original loaded image.
imgElement = _reuseOrCreateImage(htmlImage);
......@@ -683,6 +665,31 @@ class BitmapCanvas extends EngineCanvas {
return imgElement;
}
html.HtmlElement _createImageElementWithBlend(HtmlImage image,
ui.Color color, ui.BlendMode blendMode, SurfacePaintData paint) {
switch (blendMode) {
case ui.BlendMode.colorBurn:
case ui.BlendMode.colorDodge:
case ui.BlendMode.hue:
case ui.BlendMode.modulate:
case ui.BlendMode.overlay:
case ui.BlendMode.plus:
case ui.BlendMode.srcIn:
case ui.BlendMode.srcATop:
case ui.BlendMode.srcOut:
case ui.BlendMode.saturation:
case ui.BlendMode.color:
case ui.BlendMode.luminosity:
case ui.BlendMode.xor:
case ui.BlendMode.dstATop:
return _createImageElementWithSvgBlendFilter(
image, color, blendMode, paint);
default:
return _createBackgroundImageWithBlend(
image, color, blendMode, paint);
}
}
@override
void drawImageRect(
ui.Image image, ui.Rect src, ui.Rect dst, SurfacePaintData paint) {
......@@ -811,7 +818,7 @@ class BitmapCanvas extends EngineCanvas {
}
// Creates an image element and an svg filter to apply on the element.
html.HtmlElement _createImageElementWithSvgFilter(
html.HtmlElement _createImageElementWithSvgBlendFilter(
HtmlImage image,
ui.Color? filterColor,
ui.BlendMode colorFilterBlendMode,
......@@ -831,6 +838,22 @@ class BitmapCanvas extends EngineCanvas {
return imgElement;
}
// Creates an image element and an svg color matrix filter to apply on the element.
html.HtmlElement _createImageElementWithSvgColorMatrixFilter(
HtmlImage image,
List<double> matrix,
SurfacePaintData paint) {
// For srcIn blendMode, we use an svg filter to apply to image element.
String? svgFilter = svgFilterFromColorMatrix(matrix);
final html.Element filterElement =
html.Element.html(svgFilter, treeSanitizer: _NullTreeSanitizer());
rootElement.append(filterElement);
_children.add(filterElement);
final html.HtmlElement imgElement = _reuseOrCreateImage(image);
imgElement.style.filter = 'url(#_fcf${_filterIdCounter})';
return imgElement;
}
// Should be called when we add new html elements into rootElement so that
// paint order is preserved.
//
......
......@@ -59,14 +59,18 @@ class PersistedColorFilter extends PersistedContainerSurface
childContainer?.style.visibility = 'visible';
return;
}
if (engineValue is! _CkBlendModeColorFilter) {
if (engineValue is _CkBlendModeColorFilter) {
_applyBlendModeFilter(engineValue);
} else if (engineValue is _CkMatrixColorFilter) {
_applyMatrixColorFilter(engineValue);
} else {
childContainer?.style.visibility = 'visible';
return;
}
}
ui.Color filterColor = engineValue.color;
ui.BlendMode colorFilterBlendMode = engineValue.blendMode;
void _applyBlendModeFilter(_CkBlendModeColorFilter colorFilter) {
ui.Color filterColor = colorFilter.color;
ui.BlendMode colorFilterBlendMode = colorFilter.blendMode;
html.CssStyleDeclaration style = rootElement!.style;
switch (colorFilterBlendMode) {
case ui.BlendMode.clear:
......@@ -123,7 +127,16 @@ class PersistedColorFilter extends PersistedContainerSurface
colorFilterBlendMode == ui.BlendMode.modulate) {
style.backgroundColor = colorToCssString(filterColor);
}
return;
}
}
void _applyMatrixColorFilter(_CkMatrixColorFilter colorFilter) {
String? svgFilter = svgFilterFromColorMatrix(colorFilter.matrix);
if (svgFilter != null) {
_filterElement =
html.Element.html(svgFilter, treeSanitizer: _NullTreeSanitizer());
rootElement!.append(_filterElement!);
rootElement!.style.filter = 'url(#_fcf${_filterIdCounter})';
}
}
......@@ -215,6 +228,23 @@ String? svgFilterFromBlendMode(
return svgFilter;
}
String? svgFilterFromColorMatrix(List<double> matrix) {
_filterIdCounter += 1;
final StringBuffer sbMatrix = StringBuffer();
assert(matrix.length == 20);
for (int i = 0; i < 20; i++) {
if (i != 0) {
sbMatrix.write(' ');
}
sbMatrix.write(matrix[i]);
}
return '$kSvgResourceHeader'
'<filter id="_fcf$_filterIdCounter" '
'filterUnits="objectBoundingBox" x="0%" y="0%" width="100%" height="100%">'
'<feColorMatrix values="$sbMatrix" result="comp"/>'
'</filter></svg>';
}
int _filterIdCounter = 0;
// The color matrix for feColorMatrix element changes colors based on
......
......@@ -24,11 +24,27 @@ void testMain() async {
// Regression test for https://github.com/flutter/flutter/issues/76966
test('Draws image with dstATop color filter', () async {
final RecordingCanvas canvas = RecordingCanvas(region);
canvas.drawImage(createFlutterLogoTestImage(), Offset(10, 10),
makePaint()
..colorFilter = EngineColorFilter.mode(Color(0x40000000),
BlendMode.dstATop));
await canvasScreenshot(canvas, 'image_color_fiter_dstatop',
region: region);
canvas.drawImage(
createFlutterLogoTestImage(),
Offset(10, 10),
makePaint()
..colorFilter =
EngineColorFilter.mode(Color(0x40000000), BlendMode.dstATop));
await canvasScreenshot(canvas, 'image_color_fiter_dstatop', region: region);
});
test('Draws image with matrix color filter', () async {
final RecordingCanvas canvas = RecordingCanvas(region);
canvas.drawImage(
createFlutterLogoTestImage(),
Offset(10, 10),
makePaint()
..colorFilter = EngineColorFilter.matrix(<double>[
0.2126, 0.7152, 0.0722, 0, 0, //
0.2126, 0.7152, 0.0722, 0, 0, //
0.2126, 0.7152, 0.0722, 0, 0, //
0, 0, 0, 1, 0, //
]));
await canvasScreenshot(canvas, 'image_matrix_color_fiter', region: region);
});
}
......@@ -48,6 +48,26 @@ void testMain() async {
maxDiffRatePercent: 12.0);
});
test('Should apply matrix color filter to image', () async {
final List<double> colorMatrix = <double>[
0.2126, 0.7152, 0.0722, 0, 0, //
0.2126, 0.7152, 0.0722, 0, 0, //
0.2126, 0.7152, 0.0722, 0, 0, //
0, 0, 0, 1, 0, //
];
final SurfaceSceneBuilder builder = SurfaceSceneBuilder();
final Picture backgroundPicture = _drawBackground();
builder.addPicture(Offset.zero, backgroundPicture);
builder.pushColorFilter(
EngineColorFilter.matrix(colorMatrix));
final Picture circles1 = _drawTestPictureWithCircles(30, 30);
builder.addPicture(Offset.zero, circles1);
builder.pop();
html.document.body!.append(builder.build().webOnlyRootElement!);
await matchGoldenFile('color_filter_matrix.png', region: region,
maxDiffRatePercent: 12.0);
});
/// Regression test for https://github.com/flutter/flutter/issues/59451.
///
/// Picture with overlay blend inside a physical shape. Should show image
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册