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 1bf67b6b9a957..e5c7266c010ed 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 47173a65b22fe..bf020566835dc 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. 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..789e9b62d2116 --- /dev/null +++ b/lib/web_ui/test/canvaskit/scene_test.dart @@ -0,0 +1,54 @@ +// 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()); + }); + // TODO: https://github.com/flutter/flutter/issues/60040 + }, skip: isIosSafari); +}