| // 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 '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); | |
| } | |
| class TestRasterizer extends Rasterizer { | |
| Map<EngineFlutterView, TestViewRasterizer> viewRasterizers = | |
| <EngineFlutterView, TestViewRasterizer>{}; | |
| @override | |
| TestViewRasterizer createViewRasterizer(EngineFlutterView view) { | |
| return viewRasterizers.putIfAbsent(view, () => TestViewRasterizer(view)); | |
| } | |
| @override | |
| void dispose() { | |
| // Do nothing | |
| } | |
| @override | |
| void setResourceCacheMaxBytes(int bytes) { | |
| // Do nothing | |
| } | |
| List<LayerTree> treesRenderedInView(EngineFlutterView view) { | |
| return viewRasterizers[view]!.treesRendered; | |
| } | |
| } | |
| class TestViewRasterizer extends ViewRasterizer { | |
| TestViewRasterizer(super.view); | |
| List<LayerTree> treesRendered = <LayerTree>[]; | |
| @override | |
| DisplayCanvasFactory<DisplayCanvas> get displayFactory => | |
| throw UnimplementedError(); | |
| @override | |
| void prepareToDraw() { | |
| // Do nothing | |
| } | |
| @override | |
| Future<void> draw(LayerTree tree) async { | |
| treesRendered.add(tree); | |
| return Future<void>.value(); | |
| } | |
| @override | |
| Future<void> rasterizeToCanvas( | |
| DisplayCanvas canvas, List<CkPicture> pictures) { | |
| // No-op | |
| return Future<void>.value(); | |
| } | |
| } | |
| void testMain() { | |
| group('Renderer', () { | |
| setUpCanvasKitTest(); | |
| test('always renders most recent picture and skips intermediate pictures', | |
| () async { | |
| final TestRasterizer testRasterizer = TestRasterizer(); | |
| CanvasKitRenderer.instance.debugOverrideRasterizer(testRasterizer); | |
| // Create another view to render into to force the renderer to make | |
| // a [ViewRasterizer] for it. | |
| final EngineFlutterView testView = EngineFlutterView( | |
| EnginePlatformDispatcher.instance, createDomElement('test-view')); | |
| EnginePlatformDispatcher.instance.viewManager.registerView(testView); | |
| final List<LayerTree> treesToRender = <LayerTree>[]; | |
| final List<Future<void>> renderFutures = <Future<void>>[]; | |
| for (int i = 1; i < 20; i++) { | |
| final ui.PictureRecorder recorder = ui.PictureRecorder(); | |
| final ui.Canvas canvas = ui.Canvas(recorder); | |
| canvas.drawRect(const ui.Rect.fromLTWH(0, 0, 50, 50), | |
| ui.Paint()..color = const ui.Color(0xff00ff00)); | |
| final ui.Picture picture = recorder.endRecording(); | |
| final ui.SceneBuilder builder = ui.SceneBuilder(); | |
| builder.addPicture(ui.Offset.zero, picture); | |
| final ui.Scene scene = builder.build(); | |
| treesToRender.add((scene as LayerScene).layerTree); | |
| renderFutures | |
| .add(CanvasKitRenderer.instance.renderScene(scene, testView)); | |
| } | |
| await Future.wait(renderFutures); | |
| // Should just render the first and last pictures and skip the one inbetween. | |
| final List<LayerTree> treesRendered = | |
| testRasterizer.treesRenderedInView(testView); | |
| expect(treesRendered.length, 2); | |
| expect(treesRendered.first, treesToRender.first); | |
| expect(treesRendered.last, treesToRender.last); | |
| }); | |
| test('can render multiple frames at once into multiple views', () async { | |
| final TestRasterizer testRasterizer = TestRasterizer(); | |
| CanvasKitRenderer.instance.debugOverrideRasterizer(testRasterizer); | |
| // Create another view to render into to force the renderer to make | |
| // a [ViewRasterizer] for it. | |
| final EngineFlutterView testView1 = EngineFlutterView( | |
| EnginePlatformDispatcher.instance, createDomElement('test-view')); | |
| EnginePlatformDispatcher.instance.viewManager.registerView(testView1); | |
| final EngineFlutterView testView2 = EngineFlutterView( | |
| EnginePlatformDispatcher.instance, createDomElement('test-view')); | |
| EnginePlatformDispatcher.instance.viewManager.registerView(testView2); | |
| final EngineFlutterView testView3 = EngineFlutterView( | |
| EnginePlatformDispatcher.instance, createDomElement('test-view')); | |
| EnginePlatformDispatcher.instance.viewManager.registerView(testView3); | |
| final Map<EngineFlutterView, List<LayerTree>> treesToRender = | |
| <EngineFlutterView, List<LayerTree>>{}; | |
| treesToRender[testView1] = <LayerTree>[]; | |
| treesToRender[testView2] = <LayerTree>[]; | |
| treesToRender[testView3] = <LayerTree>[]; | |
| final List<Future<void>> renderFutures = <Future<void>>[]; | |
| for (int i = 1; i < 20; i++) { | |
| for (final EngineFlutterView testView in <EngineFlutterView>[ | |
| testView1, | |
| testView2, | |
| testView3, | |
| ]) { | |
| final ui.PictureRecorder recorder = ui.PictureRecorder(); | |
| final ui.Canvas canvas = ui.Canvas(recorder); | |
| canvas.drawRect(const ui.Rect.fromLTWH(0, 0, 50, 50), | |
| ui.Paint()..color = const ui.Color(0xff00ff00)); | |
| final ui.Picture picture = recorder.endRecording(); | |
| final ui.SceneBuilder builder = ui.SceneBuilder(); | |
| builder.addPicture(ui.Offset.zero, picture); | |
| final ui.Scene scene = builder.build(); | |
| treesToRender[testView]!.add((scene as LayerScene).layerTree); | |
| renderFutures | |
| .add(CanvasKitRenderer.instance.renderScene(scene, testView)); | |
| } | |
| } | |
| await Future.wait(renderFutures); | |
| // Should just render the first and last pictures and skip the one inbetween. | |
| final List<LayerTree> treesRenderedInView1 = | |
| testRasterizer.treesRenderedInView(testView1); | |
| final List<LayerTree> treesToRenderInView1 = treesToRender[testView1]!; | |
| expect(treesRenderedInView1.length, 2); | |
| expect(treesRenderedInView1.first, treesToRenderInView1.first); | |
| expect(treesRenderedInView1.last, treesToRenderInView1.last); | |
| final List<LayerTree> treesRenderedInView2 = | |
| testRasterizer.treesRenderedInView(testView2); | |
| final List<LayerTree> treesToRenderInView2 = treesToRender[testView2]!; | |
| expect(treesRenderedInView2.length, 2); | |
| expect(treesRenderedInView2.first, treesToRenderInView2.first); | |
| expect(treesRenderedInView2.last, treesToRenderInView2.last); | |
| final List<LayerTree> treesRenderedInView3 = | |
| testRasterizer.treesRenderedInView(testView3); | |
| final List<LayerTree> treesToRenderInView3 = treesToRender[testView3]!; | |
| expect(treesRenderedInView3.length, 2); | |
| expect(treesRenderedInView3.first, treesToRenderInView3.first); | |
| expect(treesRenderedInView3.last, treesToRenderInView3.last); | |
| }); | |
| }); | |
| } |