From a352e07f2a6c9ed164af38d201cc0a955fab5f3c Mon Sep 17 00:00:00 2001 From: Harry Terkelsen Date: Fri, 23 Oct 2020 12:37:23 -0700 Subject: [PATCH 1/4] Implement Scene.toImage() in CanvasKit mode. --- .../engine/canvaskit/layer_scene_builder.dart | 3 ++- .../lib/src/engine/canvaskit/layer_tree.dart | 21 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/lib/web_ui/lib/src/engine/canvaskit/layer_scene_builder.dart b/lib/web_ui/lib/src/engine/canvaskit/layer_scene_builder.dart index 71e634ed41b94..35e3504677f4b 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/layer_scene_builder.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/layer_scene_builder.dart @@ -17,7 +17,8 @@ class LayerScene implements ui.Scene { @override Future toImage(int width, int height) { - throw UnsupportedError('LayerScene.toImage not implemented.'); + ui.Picture picture = layerTree.flatten(); + return picture.toImage(width, height); } } diff --git a/lib/web_ui/lib/src/engine/canvaskit/layer_tree.dart b/lib/web_ui/lib/src/engine/canvaskit/layer_tree.dart index 3b40be4728b39..a130211feab6d 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/layer_tree.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/layer_tree.dart @@ -52,6 +52,27 @@ class LayerTree { rootLayer!.paint(context); } } + + /// Flattens the tree into a single [ui.Picture]. + /// + /// This picture does not contain any platform views. + ui.Picture flatten() { + CkPictureRecorder recorder = CkPictureRecorder(); + CkCanvas canvas = recorder.beginRecording(ui.Rect.largest); + if (rootLayer != null) { + final PrerollContext prerollContext = PrerollContext(null, null); + rootLayer!.preroll(prerollContext, Matrix4.identity()); + + CkNWayCanvas internalNodesCanvas = CkNWayCanvas(); + internalNodesCanvas.addCanvas(canvas); + final PaintContext paintContext = + PaintContext(internalNodesCanvas, canvas, null, null); + if (rootLayer!.needsPainting) { + rootLayer!.paint(paintContext); + } + } + return recorder.endRecording(); + } } /// A single frame to be rendered. From d942c69cc0f78fbb6b7d7520985949bef4501557 Mon Sep 17 00:00:00 2001 From: Harry Terkelsen Date: Thu, 19 Nov 2020 15:12:58 -0800 Subject: [PATCH 2/4] Add test --- lib/web_ui/test/canvaskit/scene_test.dart | 53 +++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 lib/web_ui/test/canvaskit/scene_test.dart diff --git a/lib/web_ui/test/canvaskit/scene_test.dart b/lib/web_ui/test/canvaskit/scene_test.dart new file mode 100644 index 0000000000000..505ed93bc590f --- /dev/null +++ b/lib/web_ui/test/canvaskit/scene_test.dart @@ -0,0 +1,53 @@ +// 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.6 +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 'common.dart'; + +void main() { + internalBootstrapBrowserTest(() => testMain); +} + +void testMain() { + group('LayerScene', () { + setUpAll(() async { + await ui.webOnlyInitializePlatform(); + }); + + test('toImage returns an image', () async { + final ui.PictureRecorder recorder = ui.PictureRecorder(); + expect(recorder, isA()); + + final ui.Canvas canvas = ui.Canvas(recorder); + expect(canvas, isA()); + + final ui.Paint paint = ui.Paint(); + expect(paint, isA()); + paint.color = ui.Color.fromARGB(255, 255, 0, 0); + + // Draw a red circle. + canvas.drawCircle(ui.Offset(20, 20), 10, paint); + + final ui.Picture picture = recorder.endRecording(); + expect(picture, isA()); + + final ui.SceneBuilder builder = ui.SceneBuilder(); + expect(builder, isA()); + + builder.pushOffset(0, 0); + builder.addPicture(ui.Offset(0, 0), picture); + + final ui.Scene scene = builder.build(); + + final ui.Image sceneImage = await scene.toImage(100, 100); + expect(sceneImage, isA()); + }); + }); +} From 4dc3290fbd1120d0ce117dbd037ef98176bb234d Mon Sep 17 00:00:00 2001 From: Harry Terkelsen Date: Thu, 19 Nov 2020 15:49:19 -0800 Subject: [PATCH 3/4] Delete unused import --- lib/web_ui/test/canvaskit/scene_test.dart | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/web_ui/test/canvaskit/scene_test.dart b/lib/web_ui/test/canvaskit/scene_test.dart index 505ed93bc590f..71db20cff5dcd 100644 --- a/lib/web_ui/test/canvaskit/scene_test.dart +++ b/lib/web_ui/test/canvaskit/scene_test.dart @@ -9,8 +9,6 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' as ui; -import 'common.dart'; - void main() { internalBootstrapBrowserTest(() => testMain); } From af43d1d6fdfd5c902f6c693bbf3e851fc6fbba1f Mon Sep 17 00:00:00 2001 From: Harry Terkelsen Date: Thu, 19 Nov 2020 16:16:32 -0800 Subject: [PATCH 4/4] Skip tests on Safari --- lib/web_ui/test/canvaskit/scene_test.dart | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/web_ui/test/canvaskit/scene_test.dart b/lib/web_ui/test/canvaskit/scene_test.dart index 71db20cff5dcd..789e9b62d2116 100644 --- a/lib/web_ui/test/canvaskit/scene_test.dart +++ b/lib/web_ui/test/canvaskit/scene_test.dart @@ -9,6 +9,8 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' as ui; +import 'common.dart'; + void main() { internalBootstrapBrowserTest(() => testMain); } @@ -47,5 +49,6 @@ void testMain() { final ui.Image sceneImage = await scene.toImage(100, 100); expect(sceneImage, isA()); }); - }); + // TODO: https://github.com/flutter/flutter/issues/60040 + }, skip: isIosSafari); }