blob: 873fef83d04ed014b6b0f520d7508ac0cbabd263 [file] [log] [blame]
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:html' as html;
import 'dart:js_util' as js_util;
import 'package:test/bootstrap/browser.dart';
import 'package:test/test.dart';
import 'package:ui/src/engine.dart' hide PhysicalShapeEngineLayer;
import 'package:ui/ui.dart';
import '../../golden_tester.dart';
const Rect region = Rect.fromLTWH(0, 0, 500, 500);
void main() {
internalBootstrapBrowserTest(() => testMain);
}
Future<void> testMain() async {
setUp(() async {
debugShowClipLayers = true;
SurfaceSceneBuilder.debugForgetFrameScene();
for (final html.Node scene in html.document.querySelectorAll('flt-scene')) {
scene.remove();
}
await webOnlyInitializePlatform();
webOnlyFontCollection.debugRegisterTestFonts();
await webOnlyFontCollection.ensureFontsLoaded();
});
test('Should apply color filter to image', () async {
final SurfaceSceneBuilder builder = SurfaceSceneBuilder();
final Picture backgroundPicture = _drawBackground();
builder.addPicture(Offset.zero, backgroundPicture);
builder.pushColorFilter(
const EngineColorFilter.mode(Color(0xF0000080), BlendMode.color));
final Picture circles1 = _drawTestPictureWithCircles(30, 30);
builder.addPicture(Offset.zero, circles1);
builder.pop();
html.document.body!.append(builder.build().webOnlyRootElement!);
// TODO(ferhat): update golden for this test after canvas sandwich detection is
// added to RecordingCanvas.
await matchGoldenFile('color_filter_blendMode_color.png', region: region,
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/85733
test('Should apply mode color filter to circles', () async {
final SurfaceSceneBuilder builder = SurfaceSceneBuilder();
final Picture backgroundPicture = _drawBackground();
builder.addPicture(Offset.zero, backgroundPicture);
builder.pushColorFilter(
const ColorFilter.mode(
Color(0xFFFF0000),
BlendMode.srcIn,
));
final Picture circles1 = _drawTestPictureWithCircles(30, 30);
builder.addPicture(Offset.zero, circles1);
builder.pop();
html.document.body!.append(builder.build().webOnlyRootElement!);
await matchGoldenFile('color_filter_mode.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
/// at 0,0. In the filed issue it was leaving a gap on top.
test('Should render image with color filter without gap', () async {
final SurfaceSceneBuilder builder = SurfaceSceneBuilder();
final Path path = Path();
path.addRRect(RRect.fromRectAndRadius(
const Rect.fromLTRB(0, 0, 400, 400), const Radius.circular(2)));
final PhysicalShapeEngineLayer oldLayer = builder.pushPhysicalShape(
path: path, color: const Color(0xFFFFFFFF), elevation: 0);
final Picture circles1 = _drawTestPictureWithImage(
const ColorFilter.mode(Color(0x3C4043), BlendMode.overlay));
builder.addPicture(const Offset(10, 0), circles1);
builder.pop();
builder.build();
final SurfaceSceneBuilder builder2 = SurfaceSceneBuilder();
builder2.pushPhysicalShape(
path: path, color: const Color(0xFFFFFFFF), elevation: 0, oldLayer: oldLayer);
builder2.addPicture(const Offset(10, 0), circles1);
builder2.pop();
html.document.body!.append(builder2.build().webOnlyRootElement!);
await matchGoldenFile('color_filter_blendMode_overlay.png',
region: region,
maxDiffRatePercent: 12.0);
});
}
Picture _drawTestPictureWithCircles(double offsetX, double offsetY) {
final EnginePictureRecorder recorder =
PictureRecorder() as EnginePictureRecorder;
final RecordingCanvas canvas =
recorder.beginRecording(const Rect.fromLTRB(0, 0, 400, 400));
canvas.drawCircle(Offset(offsetX + 10, offsetY + 10), 10,
(Paint()..style = PaintingStyle.fill) as SurfacePaint);
canvas.drawCircle(
Offset(offsetX + 60, offsetY + 10),
10,
(Paint()
..style = PaintingStyle.fill
..color = const Color.fromRGBO(255, 0, 0, 1)) as SurfacePaint);
canvas.drawCircle(
Offset(offsetX + 10, offsetY + 60),
10,
(Paint()
..style = PaintingStyle.fill
..color = const Color.fromRGBO(0, 255, 0, 1)) as SurfacePaint);
canvas.drawCircle(
Offset(offsetX + 60, offsetY + 60),
10,
(Paint()
..style = PaintingStyle.fill
..color = const Color.fromRGBO(0, 0, 255, 1)) as SurfacePaint);
return recorder.endRecording();
}
Picture _drawTestPictureWithImage(ColorFilter filter) {
final EnginePictureRecorder recorder =
PictureRecorder() as EnginePictureRecorder;
final RecordingCanvas canvas =
recorder.beginRecording(const Rect.fromLTRB(0, 0, 400, 400));
final Image testImage = createTestImage();
canvas.drawImageRect(
testImage,
const Rect.fromLTWH(0, 0, 200, 150),
const Rect.fromLTWH(0, 0, 300, 300),
(Paint()
..style = PaintingStyle.fill
..colorFilter = filter
..color = const Color.fromRGBO(0, 0, 255, 1)) as SurfacePaint);
return recorder.endRecording();
}
Picture _drawBackground() {
final EnginePictureRecorder recorder =
PictureRecorder() as EnginePictureRecorder;
final RecordingCanvas canvas =
recorder.beginRecording(const Rect.fromLTRB(0, 0, 400, 400));
canvas.drawRect(
const Rect.fromLTWH(8, 8, 400.0 - 16, 400.0 - 16),
(Paint()
..style = PaintingStyle.fill
..color = const Color(0xFFE0FFE0)) as SurfacePaint);
return recorder.endRecording();
}
HtmlImage createTestImage({int width = 200, int height = 150}) {
final html.CanvasElement canvas =
html.CanvasElement(width: width, height: height);
final html.CanvasRenderingContext2D ctx = canvas.context2D;
ctx.fillStyle = '#E04040';
ctx.fillRect(0, 0, width / 3, height);
ctx.fill();
ctx.fillStyle = '#40E080';
ctx.fillRect(width / 3, 0, width / 3, height);
ctx.fill();
ctx.fillStyle = '#2040E0';
ctx.fillRect(2 * width / 3, 0, width / 3, height);
ctx.fill();
final html.ImageElement imageElement = html.ImageElement();
// ignore: implicit_dynamic_function
imageElement.src = js_util.callMethod(canvas, 'toDataURL', <dynamic>[]) as String;
return HtmlImage(imageElement, width, height);
}