| // 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); |
| }); |
| }); |
| } |