blob: e26dfccffb8eb72ab2126e940edd35ff69aff96f [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 'package:test/bootstrap/browser.dart';
import 'package:test/test.dart';
import 'package:ui/src/engine.dart' hide ClipRectEngineLayer, BackdropFilterEngineLayer;
import 'package:ui/ui.dart';
import 'package:web_engine_tester/golden_tester.dart';
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();
});
// The black circle on the left should not be blurred since it is outside
// the clip boundary around backdrop filter. However there should be only
// one red dot since the other one should be blurred by filter.
test('Background should only blur at ancestor clip boundary', () async {
const Rect region = Rect.fromLTWH(0, 0, 190, 130);
final SurfaceSceneBuilder builder = SurfaceSceneBuilder();
final Picture backgroundPicture = _drawBackground(region);
builder.addPicture(Offset.zero, backgroundPicture);
builder.pushClipRect(
const Rect.fromLTRB(10, 10, 180, 120),
);
final Picture circles1 = _drawTestPictureWithCircles(region, 30, 30);
builder.addPicture(Offset.zero, circles1);
builder.pushClipRect(
const Rect.fromLTRB(60, 10, 180, 120),
);
builder.pushBackdropFilter(ImageFilter.blur(sigmaX: 10.0, sigmaY: 10.0),
oldLayer: null);
final Picture circles2 = _drawTestPictureWithCircles(region, 90, 30);
builder.addPicture(Offset.zero, circles2);
builder.pop();
builder.pop();
builder.pop();
html.document.body!.append(builder
.build()
.webOnlyRootElement!);
await matchGoldenFile('backdrop_filter_clip.png', region: region);
});
test('Background should only blur at ancestor clip boundary after move', () async {
const Rect region = Rect.fromLTWH(0, 0, 190, 130);
final SurfaceSceneBuilder builder = SurfaceSceneBuilder();
final Picture backgroundPicture = _drawBackground(region);
builder.addPicture(Offset.zero, backgroundPicture);
final ClipRectEngineLayer clipEngineLayer = builder.pushClipRect(
const Rect.fromLTRB(10, 10, 180, 120),
);
final Picture circles1 = _drawTestPictureWithCircles(region, 30, 30);
builder.addPicture(Offset.zero, circles1);
final ClipRectEngineLayer clipEngineLayer2 = builder.pushClipRect(
const Rect.fromLTRB(60, 10, 180, 120),
);
final BackdropFilterEngineLayer oldBackdropFilterLayer =
builder.pushBackdropFilter(ImageFilter.blur(sigmaX: 10.0, sigmaY: 10.0),
oldLayer: null);
final Picture circles2 = _drawTestPictureWithCircles(region, 90, 30);
builder.addPicture(Offset.zero, circles2);
builder.pop();
builder.pop();
builder.pop();
builder.build();
// Now reparent filter layer in next scene.
final SurfaceSceneBuilder builder2 = SurfaceSceneBuilder();
builder2.addPicture(Offset.zero, backgroundPicture);
builder2.pushClipRect(
const Rect.fromLTRB(10, 10, 180, 120),
oldLayer: clipEngineLayer
);
builder2.addPicture(Offset.zero, circles1);
builder2.pushClipRect(
const Rect.fromLTRB(10, 75, 180, 120),
oldLayer: clipEngineLayer2
);
builder2.pushBackdropFilter(ImageFilter.blur(sigmaX: 10.0, sigmaY: 10.0),
oldLayer: oldBackdropFilterLayer);
builder2.addPicture(Offset.zero, circles2);
builder2.pop();
builder2.pop();
builder2.pop();
html.document.body!.append(builder2
.build()
.webOnlyRootElement!);
await matchGoldenFile('backdrop_filter_clip_moved.png', region: region);
});
// The blur filter should be applied to the background inside the clip even
// though there are no children of the backdrop filter.
test('Background should blur even if child does not paint', () async {
const Rect region = Rect.fromLTWH(0, 0, 190, 130);
final SurfaceSceneBuilder builder = SurfaceSceneBuilder();
final Picture backgroundPicture = _drawBackground(region);
builder.addPicture(Offset.zero, backgroundPicture);
builder.pushClipRect(
const Rect.fromLTRB(10, 10, 180, 120),
);
final Picture circles1 = _drawTestPictureWithCircles(region, 30, 30);
builder.addPicture(Offset.zero, circles1);
builder.pushClipRect(
const Rect.fromLTRB(60, 10, 180, 120),
);
builder.pushBackdropFilter(ImageFilter.blur(sigmaX: 10.0, sigmaY: 10.0),
oldLayer: null);
builder.pop();
builder.pop();
builder.pop();
html.document.body!.append(builder
.build()
.webOnlyRootElement!);
await matchGoldenFile('backdrop_filter_no_child_rendering.png',
region: region);
});
}
Picture _drawTestPictureWithCircles(Rect region, double offsetX, double offsetY) {
final EnginePictureRecorder recorder = PictureRecorder() as EnginePictureRecorder;
final RecordingCanvas canvas =
recorder.beginRecording(region);
canvas.drawCircle(
Offset(offsetX + 10, offsetY + 10), 10, SurfacePaint()..style = PaintingStyle.fill);
canvas.drawCircle(
Offset(offsetX + 60, offsetY + 10),
10,
SurfacePaint()
..style = PaintingStyle.fill
..color = const Color.fromRGBO(255, 0, 0, 1));
canvas.drawCircle(
Offset(offsetX + 10, offsetY + 60),
10,
SurfacePaint()
..style = PaintingStyle.fill
..color = const Color.fromRGBO(0, 255, 0, 1));
canvas.drawCircle(
Offset(offsetX + 60, offsetY + 60),
10,
SurfacePaint()
..style = PaintingStyle.fill
..color = const Color.fromRGBO(0, 0, 255, 1));
return recorder.endRecording();
}
Picture _drawBackground(Rect region) {
final EnginePictureRecorder recorder = PictureRecorder() as EnginePictureRecorder;
final RecordingCanvas canvas =
recorder.beginRecording(region);
canvas.drawRect(
region.deflate(8.0),
SurfacePaint()
..style = PaintingStyle.fill
..color = const Color(0xFFE0FFE0)
);
return recorder.endRecording();
}