mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
[canvaskit] Fix backdrop filter with platform views as children (flutter/engine#51442)
There is a bug in CanvasKit where a backdrop filter with a platform view as a child will cause the backdrop filter to apply multiple times. This change fixes it by only applying the backdrop filter once. The bug case is more likely to happen since https://github.com/flutter/engine/pull/47317 landed because when we encounter an invisible platform view, we always create a new SkPicture instead of continuing to use the same SkPicture. BEFORE:  AFTER:  ## 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] and the [C++, Objective-C, Java style guides]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I added new tests to check the change I am making or feature I am adding, or the PR is [test-exempt]. See [testing the engine] for instructions on writing and running engine tests. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I signed the [CLA]. - [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/wiki/Tree-hygiene#overview [Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene [test-exempt]: https://github.com/flutter/flutter/wiki/Tree-hygiene#tests [Flutter Style Guide]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo [C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style [testing the engine]: https://github.com/flutter/flutter/wiki/Testing-the-engine [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/wiki/Chat
This commit is contained in:
parent
0b1158bdb7
commit
3eb357342b
@ -178,11 +178,16 @@ class BackdropFilterEngineLayer extends ContainerLayer
|
||||
@override
|
||||
void paint(PaintContext paintContext) {
|
||||
final CkPaint paint = CkPaint()..blendMode = _blendMode;
|
||||
paintContext.internalNodesCanvas
|
||||
.saveLayerWithFilter(paintBounds, _filter, paint);
|
||||
|
||||
// Only apply the backdrop filter to the current canvas. If we apply the
|
||||
// backdrop filter to every canvas (i.e. by applying it to the
|
||||
// [internalNodesCanvas]), then later when we compose the canvases into a
|
||||
// single canvas, the backdrop filter will be applied multiple times.
|
||||
final CkCanvas currentCanvas = paintContext.leafNodesCanvas!;
|
||||
currentCanvas.saveLayerWithFilter(paintBounds, _filter, paint);
|
||||
paint.dispose();
|
||||
paintChildren(paintContext);
|
||||
paintContext.internalNodesCanvas.restore();
|
||||
currentCanvas.restore();
|
||||
}
|
||||
|
||||
// TODO(dnfield): dispose of the _filter
|
||||
|
||||
@ -6,6 +6,7 @@ import 'package:test/bootstrap/browser.dart';
|
||||
import 'package:test/test.dart';
|
||||
import 'package:ui/src/engine.dart';
|
||||
import 'package:ui/ui.dart' as ui;
|
||||
import 'package:ui/ui_web/src/ui_web.dart' as ui_web;
|
||||
|
||||
import 'common.dart';
|
||||
|
||||
@ -18,7 +19,15 @@ const ui.Rect region = ui.Rect.fromLTRB(0, 0, 500, 500);
|
||||
void testMain() {
|
||||
group('BackdropFilter', () {
|
||||
setUpCanvasKitTest(withImplicitView: true);
|
||||
EngineFlutterDisplay.instance.debugOverrideDevicePixelRatio(1.0);
|
||||
|
||||
setUp(() {
|
||||
EngineFlutterDisplay.instance.debugOverrideDevicePixelRatio(1);
|
||||
});
|
||||
|
||||
tearDown(() {
|
||||
PlatformViewManager.instance.debugClear();
|
||||
CanvasKitRenderer.instance.debugClear();
|
||||
});
|
||||
|
||||
test('blur renders to the edges', () async {
|
||||
// Make a checkerboard picture so we can see the blur.
|
||||
@ -76,6 +85,77 @@ void testMain() {
|
||||
builder.build(),
|
||||
region: region);
|
||||
});
|
||||
|
||||
test('works with an invisible platform view inside', () async {
|
||||
ui_web.platformViewRegistry.registerViewFactory(
|
||||
'test-platform-view',
|
||||
(int viewId) => createDomHTMLDivElement()..id = 'view-0',
|
||||
isVisible: false,
|
||||
);
|
||||
await createPlatformView(0, 'test-platform-view');
|
||||
|
||||
// Make a checkerboard picture so we can see the blur.
|
||||
final CkPictureRecorder recorder = CkPictureRecorder();
|
||||
final CkCanvas canvas = recorder.beginRecording(region);
|
||||
canvas.drawColor(const ui.Color(0xffffffff), ui.BlendMode.srcOver);
|
||||
final double sideLength = region.width / 20;
|
||||
final int rows = (region.height / sideLength).ceil();
|
||||
|
||||
for (int row = 0; row < rows; row++) {
|
||||
for (int column = 0; column < 10; column++) {
|
||||
final ui.Rect rect = ui.Rect.fromLTWH(
|
||||
row.isEven
|
||||
? (column * 2) * sideLength
|
||||
: (column * 2 + 1) * sideLength,
|
||||
row * sideLength,
|
||||
sideLength,
|
||||
sideLength,
|
||||
);
|
||||
canvas.drawRect(rect, CkPaint()..color = const ui.Color(0xffff0000));
|
||||
}
|
||||
}
|
||||
final CkPicture checkerboard = recorder.endRecording();
|
||||
|
||||
final LayerSceneBuilder builder = LayerSceneBuilder();
|
||||
builder.pushOffset(0, 0);
|
||||
builder.addPicture(ui.Offset.zero, checkerboard);
|
||||
builder.pushBackdropFilter(ui.ImageFilter.blur(sigmaX: 10, sigmaY: 10));
|
||||
|
||||
// Draw a green rectangle, then an invisible platform view, then a blue
|
||||
// rectangle. Both rectangles should not be blurred.
|
||||
final CkPictureRecorder greenRectRecorder = CkPictureRecorder();
|
||||
final CkCanvas greenRectCanvas = greenRectRecorder.beginRecording(region);
|
||||
final CkPaint greenPaint = CkPaint()..color = const ui.Color(0xff00ff00);
|
||||
greenRectCanvas.drawRect(
|
||||
ui.Rect.fromCenter(
|
||||
center: ui.Offset(region.width / 3, region.height / 2),
|
||||
width: region.width / 6,
|
||||
height: region.height / 6),
|
||||
greenPaint);
|
||||
final CkPicture greenRectPicture = greenRectRecorder.endRecording();
|
||||
|
||||
final CkPictureRecorder blueRectRecorder = CkPictureRecorder();
|
||||
final CkCanvas blueRectCanvas = blueRectRecorder.beginRecording(region);
|
||||
final CkPaint bluePaint = CkPaint()..color = const ui.Color(0xff0000ff);
|
||||
blueRectCanvas.drawRect(
|
||||
ui.Rect.fromCenter(
|
||||
center: ui.Offset(2 * region.width / 3, region.height / 2),
|
||||
width: region.width / 6,
|
||||
height: region.height / 6),
|
||||
bluePaint);
|
||||
final CkPicture blueRectPicture = blueRectRecorder.endRecording();
|
||||
|
||||
builder.addPicture(ui.Offset.zero, greenRectPicture);
|
||||
builder.addPlatformView(0, width: 10, height: 10);
|
||||
builder.addPicture(ui.Offset.zero, blueRectPicture);
|
||||
|
||||
// Pop the backdrop filter layer.
|
||||
builder.pop();
|
||||
|
||||
await matchSceneGolden(
|
||||
'canvaskit_backdropfilter_with_platformview.png', builder.build(),
|
||||
region: region);
|
||||
});
|
||||
// TODO(hterkelsen): https://github.com/flutter/flutter/issues/71520
|
||||
}, skip: isSafari || isFirefox);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user