Skip to content

Commit

Permalink
Implement pushColorFilter in CanvasKit (flutter#22838)
Browse files Browse the repository at this point in the history
* Implement pushColorFilter in CanvasKit

* Add test

* Update goldens lock
  • Loading branch information
Harry Terkelsen committed Dec 12, 2020
1 parent 5d51422 commit 25293df
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 6 deletions.
2 changes: 1 addition & 1 deletion lib/web_ui/dev/goldens_lock.yaml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
repository: https://github.com/flutter/goldens.git
revision: ac75f12c6e93461369e1391da6cc20bf8cb08829
revision: c808c28c81b6c3143ae969e8c49bed4a6d49aabb
23 changes: 21 additions & 2 deletions lib/web_ui/lib/src/engine/canvaskit/layer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -449,8 +449,8 @@ class PhysicalShapeLayer extends ContainerLayer
assert(needsPainting);

if (_elevation != 0) {
drawShadow(paintContext.leafNodesCanvas!, _path, _shadowColor!, _elevation,
_color.alpha != 0xff);
drawShadow(paintContext.leafNodesCanvas!, _path, _shadowColor!,
_elevation, _color.alpha != 0xff);
}

final CkPaint paint = CkPaint()..color = _color;
Expand Down Expand Up @@ -497,6 +497,25 @@ class PhysicalShapeLayer extends ContainerLayer
}
}

/// A layer which contains a [ui.ColorFilter].
class ColorFilterLayer extends ContainerLayer {
ColorFilterLayer(this.filter);

final ui.ColorFilter filter;

@override
void paint(PaintContext paintContext) {
assert(needsPainting);

CkPaint paint = CkPaint();
paint.colorFilter = filter;

paintContext.internalNodesCanvas.saveLayer(paintBounds, paint);
paintChildren(paintContext);
paintContext.internalNodesCanvas.restore();
}
}

/// A layer which renders a platform view (an HTML element in this case).
class PlatformViewLayer extends Layer {
PlatformViewLayer(this.viewId, this.offset, this.width, this.height);
Expand Down
5 changes: 3 additions & 2 deletions lib/web_ui/lib/src/engine/canvaskit/layer_scene_builder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -138,12 +138,13 @@ class LayerSceneBuilder implements ui.SceneBuilder {
}

@override
ui.ColorFilterEngineLayer pushColorFilter(
ui.ColorFilterEngineLayer? pushColorFilter(
ui.ColorFilter filter, {
ui.ColorFilterEngineLayer? oldLayer,
}) {
assert(filter != null); // ignore: unnecessary_null_comparison
throw UnimplementedError();
pushLayer(ColorFilterLayer(filter));
return null;
}

ui.ImageFilterEngineLayer? pushImageFilter(
Expand Down
78 changes: 78 additions & 0 deletions lib/web_ui/test/canvaskit/color_filter_golden_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// 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.

// @dart = 2.12
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:web_engine_tester/golden_tester.dart';

import 'common.dart';

void main() {
internalBootstrapBrowserTest(() => testMain);
}

const ui.Rect region = const ui.Rect.fromLTRB(0, 0, 500, 250);

Future<void> matchSceneGolden(String goldenFile, LayerScene scene,
{bool write = false}) async {
final EnginePlatformDispatcher dispatcher =
ui.window.platformDispatcher as EnginePlatformDispatcher;
dispatcher.rasterizer!.draw(scene.layerTree);
await matchGoldenFile(goldenFile, region: region, write: write);
}

void testMain() {
group('ColorFilter', () {
setUpCanvasKitTest();

test('ColorFilter.matrix applies a color filter', () async {
final LayerSceneBuilder builder = LayerSceneBuilder();

builder.pushOffset(0, 0);

// Draw a red circle and apply it to the scene.
final CkPictureRecorder recorder = CkPictureRecorder();
final CkCanvas canvas = recorder.beginRecording(region);

canvas.drawCircle(
ui.Offset(75, 125),
50,
CkPaint()..color = ui.Color.fromARGB(255, 255, 0, 0),
);
final CkPicture redCircle = recorder.endRecording();

builder.addPicture(ui.Offset.zero, redCircle);

// Apply a "greyscale" color filter.
builder.pushColorFilter(ui.ColorFilter.matrix([
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, //
]));

// Draw another red circle and apply it to the scene.
// This one should be grey since we have the color filter.
final CkPictureRecorder recorder2 = CkPictureRecorder();
final CkCanvas canvas2 = recorder2.beginRecording(region);

canvas2.drawCircle(
ui.Offset(425, 125),
50,
CkPaint()..color = ui.Color.fromARGB(255, 255, 0, 0),
);
final CkPicture greyCircle = recorder2.endRecording();

builder.addPicture(ui.Offset.zero, greyCircle);

await matchSceneGolden('canvaskit_colorfilter.png', builder.build());
});
// TODO: https://github.com/flutter/flutter/issues/60040
// TODO: https://github.com/flutter/flutter/issues/71520
}, skip: isIosSafari || isFirefox);
}
13 changes: 12 additions & 1 deletion lib/web_ui/test/canvaskit/scene_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,17 @@ void testMain() {
final ui.Image sceneImage = await scene.toImage(100, 100);
expect(sceneImage, isA<CkImage>());
});
// TODO: https://github.com/flutter/flutter/issues/60040

test('pushColorFilter does not throw', () async {
final ui.SceneBuilder builder = ui.SceneBuilder();
expect(builder, isA<LayerSceneBuilder>());

builder.pushOffset(0, 0);
builder.pushColorFilter(ui.ColorFilter.srgbToLinearGamma());

final ui.Scene scene = builder.build();
expect(scene, isNotNull);
});
// TODO: https://github.com/flutter/flutter/issues/60040
}, skip: isIosSafari);
}

0 comments on commit 25293df

Please sign in to comment.