From c23afcc5793630212f04c1dfbf87c86582887033 Mon Sep 17 00:00:00 2001 From: Chris Bracken Date: Thu, 21 Dec 2023 10:16:42 -0800 Subject: [PATCH 1/2] Revert "[web:multiview] Only call `Renderer.clearFragmentProgramCache` on hot restart (#48758)" This reverts commit 53392972bea9accb9272abde5b209683d4f0cece. --- .../src/engine/canvaskit/embedded_views.dart | 5 +- .../lib/src/engine/canvaskit/renderer.dart | 2 - lib/web_ui/lib/src/engine/html/renderer.dart | 1 - .../engine/skwasm/skwasm_impl/renderer.dart | 1 - lib/web_ui/lib/src/engine/window.dart | 105 +++++++----------- .../test/canvaskit/embedded_views_test.dart | 13 +-- 6 files changed, 46 insertions(+), 81 deletions(-) diff --git a/lib/web_ui/lib/src/engine/canvaskit/embedded_views.dart b/lib/web_ui/lib/src/engine/canvaskit/embedded_views.dart index 9289184310ba5..43f847caa9474 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/embedded_views.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/embedded_views.dart @@ -443,7 +443,8 @@ class HtmlViewEmbedder { sceneHost.insertBefore(platformViewRoot, elementToInsertBefore); final RenderCanvas? overlay = _overlays[viewId]; if (overlay != null) { - sceneHost.insertBefore(overlay.htmlElement, elementToInsertBefore); + sceneHost.insertBefore( + overlay.htmlElement, elementToInsertBefore); } } else { final DomElement platformViewRoot = _viewClipChains[viewId]!.root; @@ -653,8 +654,6 @@ class HtmlViewEmbedder { } } _svgClipDefs.clear(); - _svgPathDefs?.remove(); - _svgPathDefs = null; } static void removeElement(DomElement element) { diff --git a/lib/web_ui/lib/src/engine/canvaskit/renderer.dart b/lib/web_ui/lib/src/engine/canvaskit/renderer.dart index df9ae2fa20b54..deb63b4b159bf 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/renderer.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/renderer.dart @@ -85,7 +85,6 @@ class CanvasKitRenderer implements Renderer { viewManager.onViewDisposed.listen(_onViewDisposed); _instance = this; }(); - registerHotRestartListener(dispose); return _initialized; } @@ -452,7 +451,6 @@ class CanvasKitRenderer implements Renderer { rasterizer.dispose(); } _rasterizers.clear(); - clearFragmentProgramCache(); } @override diff --git a/lib/web_ui/lib/src/engine/html/renderer.dart b/lib/web_ui/lib/src/engine/html/renderer.dart index afada4fca1896..0cf11314f8d74 100644 --- a/lib/web_ui/lib/src/engine/html/renderer.dart +++ b/lib/web_ui/lib/src/engine/html/renderer.dart @@ -31,7 +31,6 @@ class HtmlRenderer implements Renderer { // to make the unpacking happen while we are waiting for network requests. lineLookup; }); - registerHotRestartListener(clearFragmentProgramCache); _instance = this; } diff --git a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/renderer.dart b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/renderer.dart index df4cf213a33a3..292994ec18122 100644 --- a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/renderer.dart +++ b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/renderer.dart @@ -349,7 +349,6 @@ class SkwasmRenderer implements Renderer { FutureOr initialize() { surface = SkwasmSurface(); sceneView = EngineSceneView(SkwasmPictureRenderer(surface)); - registerHotRestartListener(clearFragmentProgramCache); } @override diff --git a/lib/web_ui/lib/src/engine/window.dart b/lib/web_ui/lib/src/engine/window.dart index 50937070ed961..716dc70e04760 100644 --- a/lib/web_ui/lib/src/engine/window.dart +++ b/lib/web_ui/lib/src/engine/window.dart @@ -9,7 +9,7 @@ import 'package:meta/meta.dart'; import 'package:ui/ui.dart' as ui; import 'package:ui/ui_web/src/ui_web.dart' as ui_web; -import '../engine.dart' show DimensionsProvider, registerHotRestartListener; +import '../engine.dart' show DimensionsProvider, registerHotRestartListener, renderer; import 'browser_detection.dart'; import 'display.dart'; import 'dom.dart'; @@ -58,8 +58,7 @@ base class EngineFlutterView implements ui.FlutterView { // by the public `EngineFlutterView` constructor). DomElement? hostElement, ) : embeddingStrategy = EmbeddingStrategy.create(hostElement: hostElement), - dimensionsProvider = - DimensionsProvider.create(hostElement: hostElement) { + dimensionsProvider = DimensionsProvider.create(hostElement: hostElement) { // The embeddingStrategy will take care of cleaning up the rootElement on // hot restart. embeddingStrategy.attachViewRoot(dom.rootElement); @@ -71,8 +70,7 @@ base class EngineFlutterView implements ui.FlutterView { static EngineFlutterWindow implicit( EnginePlatformDispatcher platformDispatcher, DomElement? hostElement, - ) => - EngineFlutterWindow._(platformDispatcher, hostElement); + ) => EngineFlutterWindow._(platformDispatcher, hostElement); @override final int viewId; @@ -102,6 +100,8 @@ base class EngineFlutterView implements ui.FlutterView { dimensionsProvider.close(); pointerBinding.dispose(); dom.rootElement.remove(); + // TODO(harryterkelsen): What should we do about this in multi-view? + renderer.clearFragmentProgramCache(); semantics.reset(); } @@ -114,8 +114,7 @@ base class EngineFlutterView implements ui.FlutterView { @override void updateSemantics(ui.SemanticsUpdate update) { - assert(!isDisposed, - 'Trying to update semantics on a disposed EngineFlutterView.'); + assert(!isDisposed, 'Trying to update semantics on a disposed EngineFlutterView.'); semantics.updateSemantics(update); } @@ -128,18 +127,15 @@ base class EngineFlutterView implements ui.FlutterView { late final ContextMenu contextMenu = ContextMenu(dom.rootElement); - late final DomManager dom = - DomManager(viewId: viewId, devicePixelRatio: devicePixelRatio); + late final DomManager dom = DomManager(viewId: viewId, devicePixelRatio: devicePixelRatio); late final PointerBinding pointerBinding; // TODO(goderbauer): Provide API to configure constraints. See also TODO in "render". @override - ViewConstraints get physicalConstraints => - ViewConstraints.tight(physicalSize); + ViewConstraints get physicalConstraints => ViewConstraints.tight(physicalSize); - late final EngineSemanticsOwner semantics = - EngineSemanticsOwner(dom.semanticsHost); + late final EngineSemanticsOwner semantics = EngineSemanticsOwner(dom.semanticsHost); @override ui.Size get physicalSize { @@ -188,8 +184,7 @@ base class EngineFlutterView implements ui.FlutterView { ui.GestureSettings get gestureSettings => _viewConfiguration.gestureSettings; @override - List get displayFeatures => - _viewConfiguration.displayFeatures; + List get displayFeatures => _viewConfiguration.displayFeatures; @override EngineFlutterDisplay get display => EngineFlutterDisplay.instance; @@ -245,14 +240,11 @@ base class EngineFlutterView implements ui.FlutterView { // Return false if the previous dimensions are not set. if (_physicalSize != null) { // First confirm both height and width are effected. - if (_physicalSize!.height != newPhysicalSize.height && - _physicalSize!.width != newPhysicalSize.width) { + if (_physicalSize!.height != newPhysicalSize.height && _physicalSize!.width != newPhysicalSize.width) { // If prior to rotation height is bigger than width it should be the // opposite after the rotation and vice versa. - if ((_physicalSize!.height > _physicalSize!.width && - newPhysicalSize.height < newPhysicalSize.width) || - (_physicalSize!.width > _physicalSize!.height && - newPhysicalSize.width < newPhysicalSize.height)) { + if ((_physicalSize!.height > _physicalSize!.width && newPhysicalSize.height < newPhysicalSize.width) || + (_physicalSize!.width > _physicalSize!.height && newPhysicalSize.width < newPhysicalSize.height)) { // Rotation detected return true; } @@ -277,8 +269,7 @@ final class _EngineFlutterViewImpl extends EngineFlutterView { } /// The Web implementation of [ui.SingletonFlutterWindow]. -final class EngineFlutterWindow extends EngineFlutterView - implements ui.SingletonFlutterWindow { +final class EngineFlutterWindow extends EngineFlutterView implements ui.SingletonFlutterWindow { EngineFlutterWindow._( EnginePlatformDispatcher platformDispatcher, DomElement? hostElement, @@ -325,8 +316,7 @@ final class EngineFlutterWindow extends EngineFlutterView double get textScaleFactor => platformDispatcher.textScaleFactor; @override - bool get nativeSpellCheckServiceDefined => - platformDispatcher.nativeSpellCheckServiceDefined; + bool get nativeSpellCheckServiceDefined => platformDispatcher.nativeSpellCheckServiceDefined; @override bool get brieflyShowPassword => platformDispatcher.brieflyShowPassword; @@ -335,8 +325,7 @@ final class EngineFlutterWindow extends EngineFlutterView bool get alwaysUse24HourFormat => platformDispatcher.alwaysUse24HourFormat; @override - ui.VoidCallback? get onTextScaleFactorChanged => - platformDispatcher.onTextScaleFactorChanged; + ui.VoidCallback? get onTextScaleFactorChanged => platformDispatcher.onTextScaleFactorChanged; @override set onTextScaleFactorChanged(ui.VoidCallback? callback) { platformDispatcher.onTextScaleFactorChanged = callback; @@ -346,8 +335,7 @@ final class EngineFlutterWindow extends EngineFlutterView ui.Brightness get platformBrightness => platformDispatcher.platformBrightness; @override - ui.VoidCallback? get onPlatformBrightnessChanged => - platformDispatcher.onPlatformBrightnessChanged; + ui.VoidCallback? get onPlatformBrightnessChanged => platformDispatcher.onPlatformBrightnessChanged; @override set onPlatformBrightnessChanged(ui.VoidCallback? callback) { platformDispatcher.onPlatformBrightnessChanged = callback; @@ -357,8 +345,7 @@ final class EngineFlutterWindow extends EngineFlutterView String? get systemFontFamily => platformDispatcher.systemFontFamily; @override - ui.VoidCallback? get onSystemFontFamilyChanged => - platformDispatcher.onSystemFontFamilyChanged; + ui.VoidCallback? get onSystemFontFamilyChanged => platformDispatcher.onSystemFontFamilyChanged; @override set onSystemFontFamilyChanged(ui.VoidCallback? callback) { platformDispatcher.onSystemFontFamilyChanged = callback; @@ -386,8 +373,7 @@ final class EngineFlutterWindow extends EngineFlutterView } @override - ui.PointerDataPacketCallback? get onPointerDataPacket => - platformDispatcher.onPointerDataPacket; + ui.PointerDataPacketCallback? get onPointerDataPacket => platformDispatcher.onPointerDataPacket; @override set onPointerDataPacket(ui.PointerDataPacketCallback? callback) { platformDispatcher.onPointerDataPacket = callback; @@ -410,8 +396,7 @@ final class EngineFlutterWindow extends EngineFlutterView bool get semanticsEnabled => platformDispatcher.semanticsEnabled; @override - ui.VoidCallback? get onSemanticsEnabledChanged => - platformDispatcher.onSemanticsEnabledChanged; + ui.VoidCallback? get onSemanticsEnabledChanged => platformDispatcher.onSemanticsEnabledChanged; @override set onSemanticsEnabledChanged(ui.VoidCallback? callback) { platformDispatcher.onSemanticsEnabledChanged = callback; @@ -426,8 +411,7 @@ final class EngineFlutterWindow extends EngineFlutterView set onFrameDataChanged(ui.VoidCallback? callback) {} @override - ui.AccessibilityFeatures get accessibilityFeatures => - platformDispatcher.accessibilityFeatures; + ui.AccessibilityFeatures get accessibilityFeatures => platformDispatcher.accessibilityFeatures; @override ui.VoidCallback? get onAccessibilityFeaturesChanged => @@ -447,16 +431,14 @@ final class EngineFlutterWindow extends EngineFlutterView } @override - ui.PlatformMessageCallback? get onPlatformMessage => - platformDispatcher.onPlatformMessage; + ui.PlatformMessageCallback? get onPlatformMessage => platformDispatcher.onPlatformMessage; @override set onPlatformMessage(ui.PlatformMessageCallback? callback) { platformDispatcher.onPlatformMessage = callback; } @override - void setIsolateDebugName(String name) => - ui.PlatformDispatcher.instance.setIsolateDebugName(name); + void setIsolateDebugName(String name) => ui.PlatformDispatcher.instance.setIsolateDebugName(name); /// Handles the browser history integration to allow users to use the back /// button, etc. @@ -562,8 +544,7 @@ final class EngineFlutterWindow extends EngineFlutterView Future handleNavigationMessage(ByteData? data) async { return _waitInTheLine(() async { final MethodCall decoded = const JSONMethodCodec().decodeMethodCall(data); - final Map? arguments = - decoded.arguments as Map?; + final Map? arguments = decoded.arguments as Map?; switch (decoded.method) { case 'selectMultiEntryHistory': await _useMultiEntryBrowserHistory(); @@ -587,9 +568,7 @@ final class EngineFlutterWindow extends EngineFlutterView path = Uri.decodeComponent( Uri( path: uri.path.isEmpty ? '/' : uri.path, - queryParameters: uri.queryParametersAll.isEmpty - ? null - : uri.queryParametersAll, + queryParameters: uri.queryParametersAll.isEmpty ? null : uri.queryParametersAll, fragment: uri.fragment.isEmpty ? null : uri.fragment, ).toString(), ); @@ -665,7 +644,6 @@ EngineFlutterWindow get window { ); return _window!; } - EngineFlutterWindow? _window; /// Initializes the [window] (aka the implicit view), if it's not already @@ -711,10 +689,10 @@ class ViewConstraints implements ui.ViewConstraints { }); ViewConstraints.tight(ui.Size size) - : minWidth = size.width, - maxWidth = size.width, - minHeight = size.height, - maxHeight = size.height; + : minWidth = size.width, + maxWidth = size.width, + minHeight = size.height, + maxHeight = size.height; @override final double minWidth; @@ -727,17 +705,15 @@ class ViewConstraints implements ui.ViewConstraints { @override bool isSatisfiedBy(ui.Size size) { - return (minWidth <= size.width) && - (size.width <= maxWidth) && - (minHeight <= size.height) && - (size.height <= maxHeight); + return (minWidth <= size.width) && (size.width <= maxWidth) && + (minHeight <= size.height) && (size.height <= maxHeight); } @override bool get isTight => minWidth >= maxWidth && minHeight >= maxHeight; @override - ViewConstraints operator /(double factor) { + ViewConstraints operator/(double factor) { return ViewConstraints( minWidth: minWidth / factor, maxWidth: maxWidth / factor, @@ -754,11 +730,11 @@ class ViewConstraints implements ui.ViewConstraints { if (other.runtimeType != runtimeType) { return false; } - return other is ViewConstraints && - other.minWidth == minWidth && - other.maxWidth == maxWidth && - other.minHeight == minHeight && - other.maxHeight == maxHeight; + return other is ViewConstraints + && other.minWidth == minWidth + && other.maxWidth == maxWidth + && other.minHeight == minHeight + && other.maxHeight == maxHeight; } @override @@ -769,10 +745,8 @@ class ViewConstraints implements ui.ViewConstraints { if (minWidth == double.infinity && minHeight == double.infinity) { return 'ViewConstraints(biggest)'; } - if (minWidth == 0 && - maxWidth == double.infinity && - minHeight == 0 && - maxHeight == double.infinity) { + if (minWidth == 0 && maxWidth == double.infinity && + minHeight == 0 && maxHeight == double.infinity) { return 'ViewConstraints(unconstrained)'; } String describe(double min, double max, String dim) { @@ -781,7 +755,6 @@ class ViewConstraints implements ui.ViewConstraints { } return '${min.toStringAsFixed(1)}<=$dim<=${max.toStringAsFixed(1)}'; } - final String width = describe(minWidth, maxWidth, 'w'); final String height = describe(minHeight, maxHeight, 'h'); return 'ViewConstraints($width, $height)'; diff --git a/lib/web_ui/test/canvaskit/embedded_views_test.dart b/lib/web_ui/test/canvaskit/embedded_views_test.dart index c90a9e00b318b..57ef4a8d74c31 100644 --- a/lib/web_ui/test/canvaskit/embedded_views_test.dart +++ b/lib/web_ui/test/canvaskit/embedded_views_test.dart @@ -731,15 +731,12 @@ void testMain() { await renderScene(sb.build()); } - await renderTestScene(); + final DomNode skPathDefs = sceneHost.querySelector('#sk_path_defs')!; - final DomElement? skPathDefs = sceneHost.querySelector('#sk_path_defs'); - expect( - skPathDefs, - isNotNull, - reason: 'Should have created SVG paths after rendering the scene', - ); - expect(skPathDefs!.childNodes, hasLength(1)); + expect(skPathDefs.childNodes, hasLength(0)); + + await renderTestScene(); + expect(skPathDefs.childNodes, hasLength(1)); await renderTestScene(); expect(skPathDefs.childNodes, hasLength(1)); From c918a13aabf3c3790ddb6ff8c51fd4fa1e6c0ff1 Mon Sep 17 00:00:00 2001 From: Chris Bracken Date: Thu, 21 Dec 2023 10:16:56 -0800 Subject: [PATCH 2/2] Revert "[web] Enforce onDrawFrame/onBeginFrame render rule (#49214)" This reverts commit d9cc20704e4aae5d75bb3e223647c4368eda8659. --- lib/web_ui/lib/platform_dispatcher.dart | 2 +- .../src/engine/canvaskit/embedded_views.dart | 4 +- .../lib/src/engine/canvaskit/rasterizer.dart | 6 +- .../lib/src/engine/canvaskit/renderer.dart | 4 +- .../lib/src/engine/canvaskit/surface.dart | 22 ++-- lib/web_ui/lib/src/engine/dom.dart | 8 +- lib/web_ui/lib/src/engine/html/renderer.dart | 2 +- .../lib/src/engine/platform_dispatcher.dart | 24 +---- lib/web_ui/lib/src/engine/renderer.dart | 2 +- .../engine/skwasm/skwasm_stub/renderer.dart | 2 +- .../backdrop_filter_golden_test.dart | 15 +-- .../test/canvaskit/canvas_golden_test.dart | 13 ++- lib/web_ui/test/canvaskit/common.dart | 12 +-- .../test/canvaskit/embedded_views_test.dart | 102 ++++++++++-------- .../test/canvaskit/image_golden_test.dart | 35 +++--- lib/web_ui/test/canvaskit/layer_test.dart | 4 +- .../test/canvaskit/multi_view_test.dart | 4 +- .../test/canvaskit/render_canvas_test.dart | 4 +- .../test/common/frame_timings_common.dart | 5 +- lib/web_ui/test/common/rendering.dart | 38 ------- .../test/common/test_initialization.dart | 3 - lib/web_ui/test/engine/scene_view_test.dart | 18 ++-- .../test/engine/semantics/semantics_test.dart | 4 +- .../engine/surface/scene_builder_test.dart | 4 +- .../test/html/text/canvas_paragraph_test.dart | 5 +- lib/web_ui/test/ui/image_golden_test.dart | 2 +- lib/web_ui/test/ui/platform_view_test.dart | 10 +- lib/web_ui/test/ui/scene_builder_test.dart | 21 ++-- lib/web_ui/test/ui/utils.dart | 4 +- 29 files changed, 165 insertions(+), 214 deletions(-) delete mode 100644 lib/web_ui/test/common/rendering.dart diff --git a/lib/web_ui/lib/platform_dispatcher.dart b/lib/web_ui/lib/platform_dispatcher.dart index 7f0d66f7fc173..f463595697e88 100644 --- a/lib/web_ui/lib/platform_dispatcher.dart +++ b/lib/web_ui/lib/platform_dispatcher.dart @@ -80,7 +80,7 @@ abstract class PlatformDispatcher { void scheduleFrame(); - Future render(Scene scene, [FlutterView view]); + void render(Scene scene, [FlutterView view]); AccessibilityFeatures get accessibilityFeatures; diff --git a/lib/web_ui/lib/src/engine/canvaskit/embedded_views.dart b/lib/web_ui/lib/src/engine/canvaskit/embedded_views.dart index 43f847caa9474..933efdcbbd119 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/embedded_views.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/embedded_views.dart @@ -364,7 +364,7 @@ class HtmlViewEmbedder { sceneHost.append(_svgPathDefs!); } - Future submitFrame() async { + void submitFrame() { final ViewListDiffResult? diffResult = (_activeCompositionOrder.isEmpty || _compositionOrder.isEmpty) ? null @@ -388,7 +388,7 @@ class HtmlViewEmbedder { _context.pictureRecorders[pictureRecorderIndex].endRecording()); pictureRecorderIndex++; } - await rasterizer.rasterizeToCanvas(overlay, pictures); + rasterizer.rasterizeToCanvas(overlay, pictures); } for (final CkPictureRecorder recorder in _context.pictureRecordersCreatedDuringPreroll) { diff --git a/lib/web_ui/lib/src/engine/canvaskit/rasterizer.dart b/lib/web_ui/lib/src/engine/canvaskit/rasterizer.dart index 4e987d3a517f8..d9280f28b6d7e 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/rasterizer.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/rasterizer.dart @@ -30,7 +30,7 @@ class Rasterizer { /// Creates a new frame from this rasterizer's surface, draws the given /// [LayerTree] into it, and then submits the frame. - Future draw(LayerTree layerTree) async { + void draw(LayerTree layerTree) { final ui.Size frameSize = view.physicalSize; if (frameSize.isEmpty) { // Available drawing area is empty. Skip drawing. @@ -49,10 +49,10 @@ class Rasterizer { compositorFrame.raster(layerTree, ignoreRasterCache: true); sceneHost.prepend(renderCanvasFactory.baseCanvas.htmlElement); - await rasterizeToCanvas(renderCanvasFactory.baseCanvas, + rasterizeToCanvas(renderCanvasFactory.baseCanvas, [pictureRecorder.endRecording()]); - await viewEmbedder.submitFrame(); + viewEmbedder.submitFrame(); } /// Disposes of this rasterizer. diff --git a/lib/web_ui/lib/src/engine/canvaskit/renderer.dart b/lib/web_ui/lib/src/engine/canvaskit/renderer.dart index deb63b4b159bf..567fac6849883 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/renderer.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/renderer.dart @@ -402,7 +402,7 @@ class CanvasKitRenderer implements Renderer { CkParagraphBuilder(style); @override - Future renderScene(ui.Scene scene, ui.FlutterView view) async { + void renderScene(ui.Scene scene, ui.FlutterView view) { // "Build finish" and "raster start" happen back-to-back because we // render on the same thread, so there's no overhead from hopping to // another thread. @@ -417,7 +417,7 @@ class CanvasKitRenderer implements Renderer { "Unable to render to a view which hasn't been registered"); final Rasterizer rasterizer = _rasterizers[view.viewId]!; - await rasterizer.draw((scene as LayerScene).layerTree); + rasterizer.draw((scene as LayerScene).layerTree); frameTimingsOnRasterFinish(); } diff --git a/lib/web_ui/lib/src/engine/canvaskit/surface.dart b/lib/web_ui/lib/src/engine/canvaskit/surface.dart index d3e1b8f9f150a..f86998f43f421 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/surface.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/surface.dart @@ -115,18 +115,22 @@ class Surface { _surface!.flush(); if (browserSupportsCreateImageBitmap) { - JSObject bitmapSource; + DomImageBitmap bitmap; if (Surface.offscreenCanvasSupported) { - bitmapSource = _offscreenCanvas! as JSObject; + bitmap = (await createImageBitmap(_offscreenCanvas! as JSObject, ( + x: 0, + y: _pixelHeight - frameSize.height.toInt(), + width: frameSize.width.toInt(), + height: frameSize.height.toInt(), + )).toDart)! as DomImageBitmap; } else { - bitmapSource = _canvasElement! as JSObject; + bitmap = (await createImageBitmap(_canvasElement! as JSObject, ( + x: 0, + y: _pixelHeight - frameSize.height.toInt(), + width: frameSize.width.toInt(), + height: frameSize.height.toInt() + )).toDart)! as DomImageBitmap; } - final DomImageBitmap bitmap = await createImageBitmap(bitmapSource, ( - x: 0, - y: _pixelHeight - frameSize.height.toInt(), - width: frameSize.width.toInt(), - height: frameSize.height.toInt(), - )); canvas.render(bitmap); } else { // If the browser doesn't support `createImageBitmap` (e.g. Safari 14) diff --git a/lib/web_ui/lib/src/engine/dom.dart b/lib/web_ui/lib/src/engine/dom.dart index 367f876ff3c51..6cc26d0a6c6b4 100644 --- a/lib/web_ui/lib/src/engine/dom.dart +++ b/lib/web_ui/lib/src/engine/dom.dart @@ -210,16 +210,14 @@ external JSPromise _createImageBitmap2( JSNumber width, JSNumber height, ); -Future createImageBitmap(JSAny source, +JSPromise createImageBitmap(JSAny source, [({int x, int y, int width, int height})? bounds]) { - JSPromise jsPromise; if (bounds != null) { - jsPromise = _createImageBitmap2(source, bounds.x.toJS, bounds.y.toJS, + return _createImageBitmap2(source, bounds.x.toJS, bounds.y.toJS, bounds.width.toJS, bounds.height.toJS); } else { - jsPromise = _createImageBitmap1(source); + return _createImageBitmap1(source); } - return js_util.promiseToFuture(jsPromise); } @JS() diff --git a/lib/web_ui/lib/src/engine/html/renderer.dart b/lib/web_ui/lib/src/engine/html/renderer.dart index 0cf11314f8d74..7e74faefc09a0 100644 --- a/lib/web_ui/lib/src/engine/html/renderer.dart +++ b/lib/web_ui/lib/src/engine/html/renderer.dart @@ -323,7 +323,7 @@ class HtmlRenderer implements Renderer { CanvasParagraphBuilder(style as EngineParagraphStyle); @override - Future renderScene(ui.Scene scene, ui.FlutterView view) async { + void renderScene(ui.Scene scene, ui.FlutterView view) { final EngineFlutterView implicitView = EnginePlatformDispatcher.instance.implicitView!; implicitView.dom.setScene((scene as SurfaceScene).webOnlyRootElement!); frameTimingsOnRasterFinish(); diff --git a/lib/web_ui/lib/src/engine/platform_dispatcher.dart b/lib/web_ui/lib/src/engine/platform_dispatcher.dart index 7ca80db0fc439..b783bcb9b0c31 100644 --- a/lib/web_ui/lib/src/engine/platform_dispatcher.dart +++ b/lib/web_ui/lib/src/engine/platform_dispatcher.dart @@ -213,10 +213,6 @@ class EnginePlatformDispatcher extends ui.PlatformDispatcher { } } - /// A set of views which have rendered in the current `onBeginFrame` or - /// `onDrawFrame` scope. - Set? _viewsRenderedInCurrentFrame; - /// A callback invoked when any window begins a frame. /// /// A callback that is invoked to notify the application that it is an @@ -239,9 +235,7 @@ class EnginePlatformDispatcher extends ui.PlatformDispatcher { /// Engine code should use this method instead of the callback directly. /// Otherwise zones won't work properly. void invokeOnBeginFrame(Duration duration) { - _viewsRenderedInCurrentFrame = {}; invoke1(_onBeginFrame, _onBeginFrameZone, duration); - _viewsRenderedInCurrentFrame = null; } /// A callback that is invoked for each frame after [onBeginFrame] has @@ -262,9 +256,7 @@ class EnginePlatformDispatcher extends ui.PlatformDispatcher { /// Engine code should use this method instead of the callback directly. /// Otherwise zones won't work properly. void invokeOnDrawFrame() { - _viewsRenderedInCurrentFrame = {}; invoke(_onDrawFrame, _onDrawFrameZone); - _viewsRenderedInCurrentFrame = null; } /// A callback that is invoked when pointer data is available. @@ -761,23 +753,14 @@ class EnginePlatformDispatcher extends ui.PlatformDispatcher { /// * [RendererBinding], the Flutter framework class which manages layout and /// painting. @override - Future render(ui.Scene scene, [ui.FlutterView? view]) async { + void render(ui.Scene scene, [ui.FlutterView? view]) { assert(view != null || implicitView != null, 'Calling render without a FlutterView'); if (view == null && implicitView == null) { // If there is no view to render into, then this is a no-op. return; } - final ui.FlutterView viewToRender = view ?? implicitView!; - - // Only render in an `onDrawFrame` or `onBeginFrame` scope. This is checked - // by checking if the `_viewsRenderedInCurrentFrame` is non-null and this - // view hasn't been rendered already in this scope. - final bool shouldRender = - _viewsRenderedInCurrentFrame?.add(viewToRender) ?? false; - if (shouldRender) { - await renderer.renderScene(scene, viewToRender); - } + renderer.renderScene(scene, view ?? implicitView!); } /// Additional accessibility features that may be enabled by the platform. @@ -1292,8 +1275,7 @@ class EnginePlatformDispatcher extends ui.PlatformDispatcher { String get defaultRouteName { // TODO(mdebbar): What should we do in multi-view mode? // https://github.com/flutter/flutter/issues/139174 - return _defaultRouteName ??= - implicitView?.browserHistory.currentPath ?? '/'; + return _defaultRouteName ??= implicitView?.browserHistory.currentPath ?? '/'; } /// Lazily initialized when the `defaultRouteName` getter is invoked. diff --git a/lib/web_ui/lib/src/engine/renderer.dart b/lib/web_ui/lib/src/engine/renderer.dart index dbd7e633d2722..9f39fcff9ea94 100644 --- a/lib/web_ui/lib/src/engine/renderer.dart +++ b/lib/web_ui/lib/src/engine/renderer.dart @@ -222,5 +222,5 @@ abstract class Renderer { ui.ParagraphBuilder createParagraphBuilder(ui.ParagraphStyle style); - Future renderScene(ui.Scene scene, ui.FlutterView view); + FutureOr renderScene(ui.Scene scene, ui.FlutterView view); } diff --git a/lib/web_ui/lib/src/engine/skwasm/skwasm_stub/renderer.dart b/lib/web_ui/lib/src/engine/skwasm/skwasm_stub/renderer.dart index 59f52969e3b74..fe63d34ad0462 100644 --- a/lib/web_ui/lib/src/engine/skwasm/skwasm_stub/renderer.dart +++ b/lib/web_ui/lib/src/engine/skwasm/skwasm_stub/renderer.dart @@ -150,7 +150,7 @@ class SkwasmRenderer implements Renderer { } @override - Future renderScene(ui.Scene scene, ui.FlutterView view) { + void renderScene(ui.Scene scene, ui.FlutterView view) { throw UnimplementedError('Skwasm not implemented on this platform.'); } diff --git a/lib/web_ui/test/canvaskit/backdrop_filter_golden_test.dart b/lib/web_ui/test/canvaskit/backdrop_filter_golden_test.dart index 29a252f1a4cca..cb0b178e0554f 100644 --- a/lib/web_ui/test/canvaskit/backdrop_filter_golden_test.dart +++ b/lib/web_ui/test/canvaskit/backdrop_filter_golden_test.dart @@ -7,6 +7,8 @@ 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() { @@ -47,8 +49,8 @@ void testMain() { builder.pushOffset(0, 0); builder.addPicture(ui.Offset.zero, checkerboard); builder.pushBackdropFilter(ui.ImageFilter.blur(sigmaX: 10, sigmaY: 10)); - await matchSceneGolden( - 'canvaskit_backdropfilter_blur_edges.png', builder.build(), + CanvasKitRenderer.instance.renderScene(builder.build(), implicitView); + await matchGoldenFile('canvaskit_backdropfilter_blur_edges.png', region: region); }); test('ImageFilter with ColorFilter as child', () async { @@ -60,7 +62,9 @@ void testMain() { final CkPictureRecorder recorder = CkPictureRecorder(); final CkCanvas canvas = recorder.beginRecording(region); final ui.ColorFilter colorFilter = ui.ColorFilter.mode( - const ui.Color(0XFF00FF00).withOpacity(0.55), ui.BlendMode.darken); + const ui.Color(0XFF00FF00).withOpacity(0.55), + ui.BlendMode.darken + ); // using a colorFilter as an imageFilter for backDrop filter builder.pushBackdropFilter(colorFilter); @@ -71,10 +75,7 @@ void testMain() { ); final CkPicture redCircle1 = recorder.endRecording(); builder.addPicture(ui.Offset.zero, redCircle1); - await matchSceneGolden( - 'canvaskit_red_circle_green_backdrop_colorFilter.png', - builder.build(), - region: region); + await matchSceneGolden('canvaskit_red_circle_green_backdrop_colorFilter.png', builder.build(), region: region); }); // TODO(hterkelsen): https://github.com/flutter/flutter/issues/71520 }, skip: isSafari || isFirefox); diff --git a/lib/web_ui/test/canvaskit/canvas_golden_test.dart b/lib/web_ui/test/canvaskit/canvas_golden_test.dart index 4d3c7bc4cddcb..3ada138eb3722 100644 --- a/lib/web_ui/test/canvaskit/canvas_golden_test.dart +++ b/lib/web_ui/test/canvaskit/canvas_golden_test.dart @@ -11,6 +11,8 @@ import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' as ui; import 'package:ui/ui_web/src/ui_web.dart' as ui_web; +import 'package:web_engine_tester/golden_tester.dart'; + import 'common.dart'; void main() { @@ -145,14 +147,16 @@ void testMain() { builder.pushOffset(0, 0); builder.addPicture(ui.Offset.zero, picture); final LayerScene scene = builder.build(); - await renderScene(scene); + CanvasKitRenderer.instance.renderScene(scene, implicitView); // Now draw an empty layer tree and confirm that the red rectangle is // no longer drawn. final LayerSceneBuilder emptySceneBuilder = LayerSceneBuilder(); emptySceneBuilder.pushOffset(0, 0); final LayerScene emptyScene = emptySceneBuilder.build(); - await matchSceneGolden('canvaskit_empty_scene.png', emptyScene, + CanvasKitRenderer.instance.renderScene(emptyScene, implicitView); + + await matchGoldenFile('canvaskit_empty_scene.png', region: const ui.Rect.fromLTRB(0, 0, 100, 100)); }); @@ -207,8 +211,9 @@ void testMain() { sb.pop(); // The below line should not throw an error. - await matchSceneGolden('cross_overlay_resources.png', sb.build(), - region: const ui.Rect.fromLTRB(0, 0, 100, 100)); + CanvasKitRenderer.instance.renderScene(sb.build(), implicitView); + + await matchGoldenFile('cross_overlay_resources.png', region: const ui.Rect.fromLTRB(0, 0, 100, 100)); }); }); } diff --git a/lib/web_ui/test/canvaskit/common.dart b/lib/web_ui/test/canvaskit/common.dart index 8a545c2a079fd..72f5e64e652cb 100644 --- a/lib/web_ui/test/canvaskit/common.dart +++ b/lib/web_ui/test/canvaskit/common.dart @@ -11,11 +11,8 @@ import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' as ui; import 'package:web_engine_tester/golden_tester.dart'; -import '../common/rendering.dart'; import '../common/test_initialization.dart'; -export '../common/rendering.dart' show renderScene; - const MethodCodec codec = StandardMethodCodec(); /// Common test setup for all CanvasKit unit-tests. @@ -47,10 +44,13 @@ CkPicture paintPicture( Future matchSceneGolden( String goldenFile, - ui.Scene scene, { + LayerScene scene, { required ui.Rect region, }) async { - await renderScene(scene); + // TODO(harryterkelsen): Enforce the render rule. Render can only be called in + // the scope of `onBeginFrame` or `onDrawFrame`, + // https://github.com/flutter/flutter/issues/137073. + CanvasKitRenderer.instance.renderScene(scene, implicitView); await matchGoldenFile(goldenFile, region: region); } @@ -63,7 +63,7 @@ Future matchPictureGolden(String goldenFile, CkPicture picture, final LayerSceneBuilder sb = LayerSceneBuilder(); sb.pushOffset(0, 0); sb.addPicture(ui.Offset.zero, picture); - await renderScene(sb.build()); + CanvasKitRenderer.instance.renderScene(sb.build(), implicitView); await matchGoldenFile(goldenFile, region: region); } diff --git a/lib/web_ui/test/canvaskit/embedded_views_test.dart b/lib/web_ui/test/canvaskit/embedded_views_test.dart index 57ef4a8d74c31..1f225d9498eaa 100644 --- a/lib/web_ui/test/canvaskit/embedded_views_test.dart +++ b/lib/web_ui/test/canvaskit/embedded_views_test.dart @@ -41,7 +41,7 @@ void testMain() { final LayerSceneBuilder sb = LayerSceneBuilder(); sb.pushOffset(0, 0); sb.addPlatformView(0, width: 10, height: 10); - await renderScene(sb.build()); + CanvasKitRenderer.instance.renderScene(sb.build(), implicitView); // The platform view is now split in two parts. The contents live // as a child of the glassPane, and the slot lives in the glassPane @@ -77,7 +77,7 @@ void testMain() { sb.pushClipRRect( ui.RRect.fromLTRBR(0, 0, 10, 10, const ui.Radius.circular(3))); sb.addPlatformView(0, width: 10, height: 10); - await renderScene(sb.build()); + CanvasKitRenderer.instance.renderScene(sb.build(), implicitView); expect( sceneHost.querySelectorAll('#sk_path_defs').single, @@ -122,7 +122,7 @@ void testMain() { sb.pushTransform(scaleMatrix.toFloat64()); sb.pushOffset(3, 3); sb.addPlatformView(0, width: 10, height: 10); - await renderScene(sb.build()); + CanvasKitRenderer.instance.renderScene(sb.build(), implicitView); // Transformations happen on the slot element. final DomElement slotHost = @@ -148,7 +148,7 @@ void testMain() { final LayerSceneBuilder sb = LayerSceneBuilder(); sb.addPlatformView(0, offset: const ui.Offset(3, 4), width: 5, height: 6); - await renderScene(sb.build()); + CanvasKitRenderer.instance.renderScene(sb.build(), implicitView); final DomElement slotHost = sceneHost.querySelector('flt-platform-view-slot')!; @@ -194,7 +194,7 @@ void testMain() { sb.pushOffset(6, 6); sb.addPlatformView(0, width: 10, height: 10); sb.pop(); - await renderScene(sb.build()); + CanvasKitRenderer.instance.renderScene(sb.build(), implicitView); // Transformations happen on the slot element. DomElement slotHost = sceneHost.querySelector('flt-platform-view-slot')!; @@ -214,7 +214,7 @@ void testMain() { sb.pushClipRect(ui.Rect.largest); sb.pushOffset(9, 9); sb.addPlatformView(0, width: 10, height: 10); - await renderScene(sb.build()); + CanvasKitRenderer.instance.renderScene(sb.build(), implicitView); // Transformations happen on the slot element. slotHost = sceneHost.querySelector('flt-platform-view-slot')!; @@ -244,7 +244,7 @@ void testMain() { sb.pushOffset(2, 2); sb.pushOffset(3, 3); sb.addPlatformView(0, width: 10, height: 10); - await renderScene(sb.build()); + CanvasKitRenderer.instance.renderScene(sb.build(), implicitView); // Transformations happen on the slot element. final DomElement slotHost = @@ -273,7 +273,7 @@ void testMain() { sb.pushClipRect(ui.Rect.largest); sb.pushOffset(9, 9); sb.addPlatformView(0, width: 10, height: 10); - await renderScene(sb.build()); + CanvasKitRenderer.instance.renderScene(sb.build(), implicitView); // Transformations happen on the slot element. final DomElement slotHost = @@ -308,20 +308,20 @@ void testMain() { platformViewIds.add(i); } - Future renderTestScene({required int viewCount}) async { + void renderTestScene({required int viewCount}) { final LayerSceneBuilder sb = LayerSceneBuilder(); sb.pushOffset(0, 0); for (int i = 0; i < viewCount; i++) { sb.addPicture(ui.Offset.zero, testPicture); sb.addPlatformView(i, width: 10, height: 10); } - await renderScene(sb.build()); + CanvasKitRenderer.instance.renderScene(sb.build(), implicitView); } // Frame 1: // Render: up to cache size platform views. // Expect: main canvas plus platform view overlays. - await renderTestScene(viewCount: 8); + renderTestScene(viewCount: 8); _expectSceneMatches(<_EmbeddedViewMarker>[ _overlay, _platformView, @@ -344,13 +344,15 @@ void testMain() { // Frame 2: // Render: zero platform views. // Expect: main canvas, no overlays. - await renderTestScene(viewCount: 0); + await Future.delayed(Duration.zero); + renderTestScene(viewCount: 0); _expectSceneMatches(<_EmbeddedViewMarker>[_overlay]); // Frame 3: // Render: less than cache size platform views. // Expect: overlays reused. - await renderTestScene(viewCount: 6); + await Future.delayed(Duration.zero); + renderTestScene(viewCount: 6); _expectSceneMatches(<_EmbeddedViewMarker>[ _overlay, _platformView, @@ -370,7 +372,8 @@ void testMain() { // Frame 4: // Render: more platform views than max overlay count. // Expect: main canvas, backup overlay, maximum overlays. - await renderTestScene(viewCount: 16); + await Future.delayed(Duration.zero); + renderTestScene(viewCount: 16); _expectSceneMatches(<_EmbeddedViewMarker>[ _overlay, _platformView, @@ -401,7 +404,8 @@ void testMain() { // Frame 5: // Render: zero platform views. // Expect: main canvas, no overlays. - await renderTestScene(viewCount: 0); + await Future.delayed(Duration.zero); + renderTestScene(viewCount: 0); _expectSceneMatches(<_EmbeddedViewMarker>[_overlay]); // Frame 6: @@ -422,7 +426,7 @@ void testMain() { } try { - await renderTestScene(viewCount: platformViewIds.length); + renderTestScene(viewCount: platformViewIds.length); fail('Expected to throw'); } on AssertionError catch (error) { expect( @@ -435,7 +439,7 @@ void testMain() { // Render: a platform view after error. // Expect: success. Just checking the system is not left in a corrupted state. await createPlatformView(0, 'test-platform-view'); - await renderTestScene(viewCount: 0); + renderTestScene(viewCount: 0); _expectSceneMatches(<_EmbeddedViewMarker>[_overlay]); for (int i = 0; i < 16; i++) { @@ -460,20 +464,20 @@ void testMain() { platformViewIds.add(i); } - Future renderTestScene(List views) async { + void renderTestScene(List views) { final LayerSceneBuilder sb = LayerSceneBuilder(); sb.pushOffset(0, 0); for (final int view in views) { sb.addPicture(ui.Offset.zero, testPicture); sb.addPlatformView(view, width: 10, height: 10); } - await renderScene(sb.build()); + CanvasKitRenderer.instance.renderScene(sb.build(), implicitView); } // Frame 1: // Render: Views 1-10 // Expect: main canvas plus platform view overlays; empty cache. - await renderTestScene([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); + renderTestScene([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); _expectSceneMatches(<_EmbeddedViewMarker>[ _overlay, _platformView, @@ -498,7 +502,8 @@ void testMain() { // Frame 2: // Render: Views 2-11 // Expect: main canvas plus platform view overlays; empty cache. - await renderTestScene([2, 3, 4, 5, 6, 7, 8, 9, 10, 11]); + await Future.delayed(Duration.zero); + renderTestScene([2, 3, 4, 5, 6, 7, 8, 9, 10, 11]); _expectSceneMatches(<_EmbeddedViewMarker>[ _overlay, _platformView, @@ -523,7 +528,8 @@ void testMain() { // Frame 3: // Render: Views 3-12 // Expect: main canvas plus platform view overlays; empty cache. - await renderTestScene([3, 4, 5, 6, 7, 8, 9, 10, 11, 12]); + await Future.delayed(Duration.zero); + renderTestScene([3, 4, 5, 6, 7, 8, 9, 10, 11, 12]); _expectSceneMatches(<_EmbeddedViewMarker>[ _overlay, _platformView, @@ -548,7 +554,8 @@ void testMain() { // Frame 4: // Render: Views 3-12 again (same as last frame) // Expect: main canvas plus platform view overlays; empty cache. - await renderTestScene([3, 4, 5, 6, 7, 8, 9, 10, 11, 12]); + await Future.delayed(Duration.zero); + renderTestScene([3, 4, 5, 6, 7, 8, 9, 10, 11, 12]); _expectSceneMatches(<_EmbeddedViewMarker>[ _overlay, _platformView, @@ -573,6 +580,7 @@ void testMain() { for (int i = 0; i < 20; i++) { await disposePlatformView(i); } + }); test('embeds and disposes of a platform view', () async { @@ -585,7 +593,7 @@ void testMain() { LayerSceneBuilder sb = LayerSceneBuilder(); sb.pushOffset(0, 0); sb.addPlatformView(0, width: 10, height: 10); - await renderScene(sb.build()); + CanvasKitRenderer.instance.renderScene(sb.build(), implicitView); _expectSceneMatches(<_EmbeddedViewMarker>[ _overlay, _platformView, @@ -598,7 +606,7 @@ void testMain() { sb = LayerSceneBuilder(); sb.pushOffset(0, 0); - await renderScene(sb.build()); + CanvasKitRenderer.instance.renderScene(sb.build(), implicitView); _expectSceneMatches(<_EmbeddedViewMarker>[ _overlay, @@ -634,7 +642,7 @@ void testMain() { implicitView.debugPhysicalSizeOverride = const ui.Size(100, 100); implicitView.debugForceResize(); - await renderScene(sb.build()); + CanvasKitRenderer.instance.renderScene(sb.build(), implicitView); _expectSceneMatches(<_EmbeddedViewMarker>[ _overlay, _platformView, @@ -643,7 +651,7 @@ void testMain() { implicitView.debugPhysicalSizeOverride = const ui.Size(200, 200); implicitView.debugForceResize(); - await renderScene(sb.build()); + CanvasKitRenderer.instance.renderScene(sb.build(), implicitView); _expectSceneMatches(<_EmbeddedViewMarker>[ _overlay, _platformView, @@ -667,7 +675,7 @@ void testMain() { LayerSceneBuilder sb = LayerSceneBuilder(); sb.pushOffset(0, 0); sb.addPlatformView(0, width: 10, height: 10); - await renderScene(sb.build()); + CanvasKitRenderer.instance.renderScene(sb.build(), implicitView); _expectSceneMatches(<_EmbeddedViewMarker>[ _overlay, _platformView, @@ -681,7 +689,7 @@ void testMain() { sb = LayerSceneBuilder(); sb.pushOffset(0, 0); sb.addPlatformView(1, width: 10, height: 10); - await renderScene(sb.build()); + CanvasKitRenderer.instance.renderScene(sb.build(), implicitView); _expectSceneMatches(<_EmbeddedViewMarker>[ _overlay, _platformView, @@ -697,7 +705,7 @@ void testMain() { // the platform view. sb = LayerSceneBuilder(); sb.pushOffset(0, 0); - await renderScene(sb.build()); + CanvasKitRenderer.instance.renderScene(sb.build(), implicitView); _expectSceneMatches(<_EmbeddedViewMarker>[ _overlay, ]); @@ -722,26 +730,28 @@ void testMain() { ); await createPlatformView(0, 'test-platform-view'); - Future renderTestScene() async { + void renderTestScene() { final LayerSceneBuilder sb = LayerSceneBuilder(); sb.pushOffset(0, 0); sb.pushClipRRect( ui.RRect.fromLTRBR(0, 0, 10, 10, const ui.Radius.circular(3))); sb.addPlatformView(0, width: 10, height: 10); - await renderScene(sb.build()); + CanvasKitRenderer.instance.renderScene(sb.build(), implicitView); } final DomNode skPathDefs = sceneHost.querySelector('#sk_path_defs')!; expect(skPathDefs.childNodes, hasLength(0)); - await renderTestScene(); + renderTestScene(); expect(skPathDefs.childNodes, hasLength(1)); - await renderTestScene(); + await Future.delayed(Duration.zero); + renderTestScene(); expect(skPathDefs.childNodes, hasLength(1)); - await renderTestScene(); + await Future.delayed(Duration.zero); + renderTestScene(); expect(skPathDefs.childNodes, hasLength(1)); await disposePlatformView(0); @@ -761,7 +771,7 @@ void testMain() { sb.addPlatformView(0, width: 10, height: 10); sb.pop(); // The below line should not throw an error. - await renderScene(sb.build()); + CanvasKitRenderer.instance.renderScene(sb.build(), implicitView); _expectSceneMatches(<_EmbeddedViewMarker>[ _overlay, ]); @@ -795,7 +805,7 @@ void testMain() { sb.pushOffset(0, 0); sb.addPlatformView(1, width: 10, height: 10); sb.pop(); - await renderScene(sb.build()); + CanvasKitRenderer.instance.renderScene(sb.build(), implicitView); _expectSceneMatches(<_EmbeddedViewMarker>[ _overlay, _platformView, @@ -806,7 +816,7 @@ void testMain() { sb.addPlatformView(0, width: 10, height: 10); sb.addPlatformView(1, width: 10, height: 10); sb.pop(); - await renderScene(sb.build()); + CanvasKitRenderer.instance.renderScene(sb.build(), implicitView); _expectSceneMatches(<_EmbeddedViewMarker>[ _overlay, _platformView, @@ -820,7 +830,7 @@ void testMain() { sb.addPlatformView(1, width: 10, height: 10); sb.addPlatformView(2, width: 10, height: 10); sb.pop(); - await renderScene(sb.build()); + CanvasKitRenderer.instance.renderScene(sb.build(), implicitView); _expectSceneMatches(<_EmbeddedViewMarker>[ _overlay, _platformView, @@ -839,7 +849,7 @@ void testMain() { sb.addPlatformView(2, width: 10, height: 10); sb.addPlatformView(3, width: 10, height: 10); sb.pop(); - await renderScene(sb.build()); + CanvasKitRenderer.instance.renderScene(sb.build(), implicitView); _expectSceneMatches(<_EmbeddedViewMarker>[ _overlay, _platformView, @@ -858,7 +868,7 @@ void testMain() { sb.addPlatformView(3, width: 10, height: 10); sb.addPlatformView(4, width: 10, height: 10); sb.pop(); - await renderScene(sb.build()); + CanvasKitRenderer.instance.renderScene(sb.build(), implicitView); _expectSceneMatches(<_EmbeddedViewMarker>[ _overlay, _platformView, @@ -879,7 +889,7 @@ void testMain() { sb.addPlatformView(4, width: 10, height: 10); sb.addPlatformView(5, width: 10, height: 10); sb.pop(); - await renderScene(sb.build()); + CanvasKitRenderer.instance.renderScene(sb.build(), implicitView); _expectSceneMatches(<_EmbeddedViewMarker>[ _overlay, _platformView, @@ -902,7 +912,7 @@ void testMain() { sb.addPlatformView(5, width: 10, height: 10); sb.addPlatformView(6, width: 10, height: 10); sb.pop(); - await renderScene(sb.build()); + CanvasKitRenderer.instance.renderScene(sb.build(), implicitView); _expectSceneMatches(<_EmbeddedViewMarker>[ _overlay, _platformView, @@ -924,7 +934,7 @@ void testMain() { sb.addPlatformView(5, width: 10, height: 10); sb.addPlatformView(6, width: 10, height: 10); sb.pop(); - await renderScene(sb.build()); + CanvasKitRenderer.instance.renderScene(sb.build(), implicitView); _expectSceneMatches(<_EmbeddedViewMarker>[ _overlay, _platformView, @@ -943,7 +953,7 @@ void testMain() { sb.addPlatformView(3, width: 10, height: 10); sb.addPlatformView(4, width: 10, height: 10); sb.pop(); - await renderScene(sb.build()); + CanvasKitRenderer.instance.renderScene(sb.build(), implicitView); _expectSceneMatches(<_EmbeddedViewMarker>[ _overlay, _platformView, @@ -960,7 +970,7 @@ void testMain() { sb.addPlatformView(2, width: 10, height: 10); sb.addPlatformView(1, width: 10, height: 10); sb.pop(); - await renderScene(sb.build()); + CanvasKitRenderer.instance.renderScene(sb.build(), implicitView); _expectSceneMatches(<_EmbeddedViewMarker>[ _overlay, _platformView, diff --git a/lib/web_ui/test/canvaskit/image_golden_test.dart b/lib/web_ui/test/canvaskit/image_golden_test.dart index d622164c4ed96..a662b25ea0bfd 100644 --- a/lib/web_ui/test/canvaskit/image_golden_test.dart +++ b/lib/web_ui/test/canvaskit/image_golden_test.dart @@ -10,6 +10,7 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' as ui; import 'package:ui/ui_web/src/ui_web.dart' as ui_web; +import 'package:web_engine_tester/golden_tester.dart'; import '../common/matchers.dart'; import 'common.dart'; @@ -636,9 +637,11 @@ void _testForImageCodecs({required bool useBrowserImageDecoder}) { canvas.drawImage(snapshot, ui.Offset.zero, CkPaint()); sb.addPicture(ui.Offset.zero, recorder.endRecording()); - await matchSceneGolden( - 'canvaskit_read_back_decoded_image_$mode.png', sb.build(), - region: const ui.Rect.fromLTRB(0, 0, 150, 150)); + CanvasKitRenderer.instance.renderScene(sb.build(), implicitView); + await matchGoldenFile( + 'canvaskit_read_back_decoded_image_$mode.png', + region: const ui.Rect.fromLTRB(0, 0, 150, 150), + ); } image.dispose(); @@ -684,10 +687,11 @@ void _testForImageCodecs({required bool useBrowserImageDecoder}) { canvas.drawParagraph(makeSimpleText('2'), const ui.Offset(2, 2)); sb.addPicture(ui.Offset.zero, recorder.endRecording()); } - - await matchSceneGolden( - 'canvaskit_cross_gl_context_image_$mode.png', sb.build(), - region: const ui.Rect.fromLTRB(0, 0, 100, 100)); + CanvasKitRenderer.instance.renderScene(sb.build(), implicitView); + await matchGoldenFile( + 'canvaskit_cross_gl_context_image_$mode.png', + region: const ui.Rect.fromLTRB(0, 0, 100, 100), + ); await disposePlatformView(0); }); @@ -727,10 +731,11 @@ void _testForImageCodecs({required bool useBrowserImageDecoder}) { canvas.restore(); sb.addPicture(ui.Offset.zero, recorder.endRecording()); } - - await matchSceneGolden( - 'canvaskit_picture_texture_toimage.png', sb.build(), - region: const ui.Rect.fromLTRB(0, 0, 128, 128)); + CanvasKitRenderer.instance.renderScene(sb.build(), implicitView); + await matchGoldenFile( + 'canvaskit_picture_texture_toimage.png', + region: const ui.Rect.fromLTRB(0, 0, 128, 128), + ); mandrill.dispose(); codec.dispose(); }); @@ -769,9 +774,11 @@ void _testForImageCodecs({required bool useBrowserImageDecoder}) { canvas.drawImage(snapshot, ui.Offset.zero, CkPaint()); sb.addPicture(ui.Offset.zero, recorder.endRecording()); - await matchSceneGolden( - 'canvaskit_read_back_decoded_image_$mode.png', sb.build(), - region: const ui.Rect.fromLTRB(0, 0, 150, 150)); + CanvasKitRenderer.instance.renderScene(sb.build(), implicitView); + await matchGoldenFile( + 'canvaskit_read_back_decoded_image_$mode.png', + region: const ui.Rect.fromLTRB(0, 0, 150, 150), + ); } image.dispose(); diff --git a/lib/web_ui/test/canvaskit/layer_test.dart b/lib/web_ui/test/canvaskit/layer_test.dart index 5b308ff8e6900..cf83e8abee889 100644 --- a/lib/web_ui/test/canvaskit/layer_test.dart +++ b/lib/web_ui/test/canvaskit/layer_test.dart @@ -39,7 +39,7 @@ void testMain() { sb.addPicture(ui.Offset.zero, picture); final LayerScene scene = sb.build(); final LayerTree layerTree = scene.layerTree; - await renderScene(scene); + CanvasKitRenderer.instance.renderScene(scene, implicitView); final ClipRectEngineLayer clipRect = layerTree.rootLayer.debugLayers.single as ClipRectEngineLayer; expect(clipRect.paintBounds, const ui.Rect.fromLTRB(15, 15, 30, 30)); @@ -95,7 +95,7 @@ void testMain() { final LayerScene scene = sb.build(); final LayerTree layerTree = scene.layerTree; - await renderScene(scene); + CanvasKitRenderer.instance.renderScene(scene, implicitView); final ImageFilterEngineLayer imageFilterLayer = layerTree.rootLayer.debugLayers.single as ImageFilterEngineLayer; diff --git a/lib/web_ui/test/canvaskit/multi_view_test.dart b/lib/web_ui/test/canvaskit/multi_view_test.dart index dac4055c67518..a5a67f473f4aa 100644 --- a/lib/web_ui/test/canvaskit/multi_view_test.dart +++ b/lib/web_ui/test/canvaskit/multi_view_test.dart @@ -33,13 +33,13 @@ void testMain() { }); test('can render into arbitrary views', () async { - await CanvasKitRenderer.instance.renderScene(scene, implicitView); + CanvasKitRenderer.instance.renderScene(scene, implicitView); final EngineFlutterView anotherView = EngineFlutterView( EnginePlatformDispatcher.instance, createDomElement('another-view')); EnginePlatformDispatcher.instance.viewManager.registerView(anotherView); - await CanvasKitRenderer.instance.renderScene(scene, anotherView); + CanvasKitRenderer.instance.renderScene(scene, anotherView); }); test('will error if trying to render into an unregistered view', () async { diff --git a/lib/web_ui/test/canvaskit/render_canvas_test.dart b/lib/web_ui/test/canvaskit/render_canvas_test.dart index f5a174e7c9a69..dade8c2161d4d 100644 --- a/lib/web_ui/test/canvaskit/render_canvas_test.dart +++ b/lib/web_ui/test/canvaskit/render_canvas_test.dart @@ -21,13 +21,13 @@ void testMain() { }); Future newBitmap(int width, int height) async { - return createImageBitmap( + return (await createImageBitmap( createBlankDomImageData(width, height) as JSAny, ( x: 0, y: 0, width: width, height: height, - )); + )).toDart)! as DomImageBitmap; } // Regression test for https://github.com/flutter/flutter/issues/75286 diff --git a/lib/web_ui/test/common/frame_timings_common.dart b/lib/web_ui/test/common/frame_timings_common.dart index 2bcc08438eb2a..51087f3094b39 100644 --- a/lib/web_ui/test/common/frame_timings_common.dart +++ b/lib/web_ui/test/common/frame_timings_common.dart @@ -21,9 +21,8 @@ Future runFrameTimingsTest() async { sceneBuilder ..pushOffset(0, 0) ..pop(); - ui.PlatformDispatcher.instance.render(sceneBuilder.build()).then((_) { - frameDone.complete(); - }); + ui.PlatformDispatcher.instance.render(sceneBuilder.build()); + frameDone.complete(); }; // Frame 1. diff --git a/lib/web_ui/test/common/rendering.dart b/lib/web_ui/test/common/rendering.dart deleted file mode 100644 index 89ecc319b19bb..0000000000000 --- a/lib/web_ui/test/common/rendering.dart +++ /dev/null @@ -1,38 +0,0 @@ -// 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 'dart:async'; - -import 'package:ui/src/engine.dart'; -import 'package:ui/ui.dart' as ui; - -// The scene that will be rendered in the next call to `onDrawFrame`. -ui.Scene? _sceneToRender; - -// Completer that will complete when the call to render completes. -Completer? _sceneCompleter; - -/// Sets up rendering so that `onDrawFrame` will render the last requested -/// scene. -void setUpRenderingForTests() { - // Set `onDrawFrame` to call `renderer.renderScene`. - EnginePlatformDispatcher.instance.onDrawFrame = () { - if (_sceneToRender != null) { - EnginePlatformDispatcher.instance.render(_sceneToRender!).then((_) { - _sceneCompleter?.complete(); - }).catchError((Object error) { - _sceneCompleter?.completeError(error); - }); - _sceneToRender = null; - } - }; -} - -/// Render the given [scene] in an `onDrawFrame` scope. -Future renderScene(ui.Scene scene) { - _sceneToRender = scene; - _sceneCompleter = Completer(); - EnginePlatformDispatcher.instance.invokeOnDrawFrame(); - return _sceneCompleter!.future; -} diff --git a/lib/web_ui/test/common/test_initialization.dart b/lib/web_ui/test/common/test_initialization.dart index 0aa715232389c..b6359877d587f 100644 --- a/lib/web_ui/test/common/test_initialization.dart +++ b/lib/web_ui/test/common/test_initialization.dart @@ -11,7 +11,6 @@ import 'package:ui/ui.dart' as ui; import 'package:ui/ui_web/src/ui_web.dart' as ui_web; import 'fake_asset_manager.dart'; -import 'rendering.dart'; void setUpUnitTests({ bool emulateTesterEnvironment = true, @@ -45,8 +44,6 @@ void setUpUnitTests({ const ui.Size(800 * devicePixelRatio, 600 * devicePixelRatio); engine.scheduleFrameCallback = () {}; } - - setUpRenderingForTests(); }); tearDownAll(() async { diff --git a/lib/web_ui/test/engine/scene_view_test.dart b/lib/web_ui/test/engine/scene_view_test.dart index 185c1771e53d5..2580be479554a 100644 --- a/lib/web_ui/test/engine/scene_view_test.dart +++ b/lib/web_ui/test/engine/scene_view_test.dart @@ -26,13 +26,10 @@ class StubPictureRenderer implements PictureRenderer { Future renderPicture(ScenePicture picture) async { renderedPictures.add(picture); final ui.Rect cullRect = picture.cullRect; - final DomImageBitmap bitmap = - await createImageBitmap(scratchCanvasElement as JSObject, ( - x: 0, - y: 0, - width: cullRect.width.toInt(), - height: cullRect.height.toInt(), - )); + final DomImageBitmap bitmap = (await createImageBitmap( + scratchCanvasElement as JSObject, + (x: 0, y: 0, width: cullRect.width.toInt(), height: cullRect.height.toInt()) + ).toDart)! as DomImageBitmap; return bitmap; } @@ -86,8 +83,7 @@ void testMain() { debugOverrideDevicePixelRatio(null); }); - test('SceneView places platform view according to device-pixel ratio', - () async { + test('SceneView places platform view according to device-pixel ratio', () async { debugOverrideDevicePixelRatio(2.0); final PlatformView platformView = PlatformView( @@ -117,9 +113,7 @@ void testMain() { debugOverrideDevicePixelRatio(null); }); - test( - 'SceneView always renders most recent picture and skips intermediate pictures', - () async { + test('SceneView always renders most recent picture and skips intermediate pictures', () async { final List pictures = []; final List> renderFutures = >[]; for (int i = 1; i < 20; i++) { diff --git a/lib/web_ui/test/engine/semantics/semantics_test.dart b/lib/web_ui/test/engine/semantics/semantics_test.dart index d751eb589f075..390b3f8887d21 100644 --- a/lib/web_ui/test/engine/semantics/semantics_test.dart +++ b/lib/web_ui/test/engine/semantics/semantics_test.dart @@ -13,7 +13,6 @@ import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' as ui; import 'package:ui/ui_web/src/ui_web.dart' as ui_web; -import '../../common/rendering.dart'; import '../../common/test_initialization.dart'; import 'semantics_tester.dart'; @@ -33,7 +32,6 @@ void main() { Future testMain() async { await bootstrapAndRunApp(); - setUpRenderingForTests(); runSemanticsTests(); } @@ -2528,7 +2526,7 @@ void _testPlatformView() { width: 20, height: 30, ); - await renderScene(sceneBuilder.build()); + ui.PlatformDispatcher.instance.render(sceneBuilder.build()); final ui.SemanticsUpdateBuilder builder = ui.SemanticsUpdateBuilder(); final double dpr = EngineFlutterDisplay.instance.devicePixelRatio; diff --git a/lib/web_ui/test/engine/surface/scene_builder_test.dart b/lib/web_ui/test/engine/surface/scene_builder_test.dart index bb6698d04104c..3c893ddc2ec6f 100644 --- a/lib/web_ui/test/engine/surface/scene_builder_test.dart +++ b/lib/web_ui/test/engine/surface/scene_builder_test.dart @@ -15,7 +15,6 @@ import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' as ui; import '../../common/matchers.dart'; -import '../../common/rendering.dart'; import '../../common/test_initialization.dart'; void main() { @@ -25,7 +24,6 @@ void main() { void testMain() { setUpAll(() async { await bootstrapAndRunApp(); - setUpRenderingForTests(); }); group('SceneBuilder', () { @@ -479,7 +477,7 @@ void testMain() { // Pump an empty scene to reset it, otherwise the first frame will attempt // to diff left-overs from a previous test, which results in unpredictable // DOM mutations. - await renderScene(SurfaceSceneBuilder().build()); + ui.PlatformDispatcher.instance.render(SurfaceSceneBuilder().build()); // Renders a `string` by breaking it up into individual characters and // rendering each character into its own layer. diff --git a/lib/web_ui/test/html/text/canvas_paragraph_test.dart b/lib/web_ui/test/html/text/canvas_paragraph_test.dart index 38b26ee898bc0..4a38f4f5cee1b 100644 --- a/lib/web_ui/test/html/text/canvas_paragraph_test.dart +++ b/lib/web_ui/test/html/text/canvas_paragraph_test.dart @@ -7,7 +7,6 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' as ui; -import '../../common/rendering.dart'; import '../../common/test_initialization.dart'; import '../paragraph/helper.dart'; @@ -792,7 +791,7 @@ Future testMain() async { expect(paragraph.height, 10); }); - test('Render after dispose', () async { + test('Render after dispose', () { final ui.Paragraph paragraph = plain(ahemStyle, 'abc'); paragraph.layout(const ui.ParagraphConstraints(width: 30.8)); @@ -807,7 +806,7 @@ Future testMain() async { builder.addPicture(ui.Offset.zero, picture); final ui.Scene scene = builder.build(); - await renderScene(scene); + ui.PlatformDispatcher.instance.render(scene); picture.dispose(); scene.dispose(); diff --git a/lib/web_ui/test/ui/image_golden_test.dart b/lib/web_ui/test/ui/image_golden_test.dart index 60b9810d1df62..8dff0b43f6db9 100644 --- a/lib/web_ui/test/ui/image_golden_test.dart +++ b/lib/web_ui/test/ui/image_golden_test.dart @@ -318,7 +318,7 @@ Future testMain() async { image.src = url; await completer.future; - final DomImageBitmap bitmap = await createImageBitmap(image as JSObject); + final DomImageBitmap bitmap = (await createImageBitmap(image as JSObject).toDart)! as DomImageBitmap; expect(bitmap.width.toDartInt, 150); expect(bitmap.height.toDartInt, 150); diff --git a/lib/web_ui/test/ui/platform_view_test.dart b/lib/web_ui/test/ui/platform_view_test.dart index ccfc595e12ce1..7d0b01c2fbb82 100644 --- a/lib/web_ui/test/ui/platform_view_test.dart +++ b/lib/web_ui/test/ui/platform_view_test.dart @@ -11,8 +11,8 @@ import 'package:ui/ui.dart' as ui; import 'package:ui/ui_web/src/ui_web.dart' as ui_web; import 'package:web_engine_tester/golden_tester.dart'; -import '../common/rendering.dart'; import '../common/test_initialization.dart'; +import 'utils.dart'; void main() { internalBootstrapBrowserTest(() => testMain); @@ -65,7 +65,7 @@ Future testMain() async { width: 50, height: 50, ); - await renderScene(sb.build()); + await renderer.renderScene(sb.build(), implicitView); await matchGoldenFile('picture_platformview_overlap.png', region: region); }); @@ -97,7 +97,7 @@ Future testMain() async { ); sb.addPicture(const ui.Offset(125, 125), picture); - await renderScene(sb.build()); + await renderer.renderScene(sb.build(), implicitView); await matchGoldenFile('picture_platformview_sandwich.png', region: region); }); @@ -126,7 +126,7 @@ Future testMain() async { width: 50, height: 50, ); - await renderScene(sb.build()); + await renderer.renderScene(sb.build(), implicitView); await matchGoldenFile('platformview_transformed.png', region: region); }); @@ -155,7 +155,7 @@ Future testMain() async { width: 50, height: 50, ); - await renderScene(sb.build()); + await renderer.renderScene(sb.build(), implicitView); await matchGoldenFile('platformview_opacity.png', region: region); }); diff --git a/lib/web_ui/test/ui/scene_builder_test.dart b/lib/web_ui/test/ui/scene_builder_test.dart index b94e28c5c6920..6ecc2f33f896e 100644 --- a/lib/web_ui/test/ui/scene_builder_test.dart +++ b/lib/web_ui/test/ui/scene_builder_test.dart @@ -10,7 +10,6 @@ import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' as ui; import 'package:web_engine_tester/golden_tester.dart'; -import '../common/rendering.dart'; import '../common/test_initialization.dart'; import 'utils.dart'; @@ -37,7 +36,7 @@ Future testMain() async { ); })); - await renderScene(sceneBuilder.build()); + await renderer.renderScene(sceneBuilder.build(), implicitView); await matchGoldenFile('scene_builder_centered_circle.png', region: region); }); @@ -61,7 +60,7 @@ Future testMain() async { ); })); - await renderScene(sceneBuilder.build()); + await renderer.renderScene(sceneBuilder.build(), implicitView); await matchGoldenFile('scene_builder_rotated_rounded_square.png', region: region); }); @@ -76,7 +75,7 @@ Future testMain() async { ); })); - await renderScene(sceneBuilder.build()); + await renderer.renderScene(sceneBuilder.build(), implicitView); await matchGoldenFile('scene_builder_circle_clip_rect.png', region: region); }); @@ -94,7 +93,7 @@ Future testMain() async { ); })); - await renderScene(sceneBuilder.build()); + await renderer.renderScene(sceneBuilder.build(), implicitView); await matchGoldenFile('scene_builder_circle_clip_rrect.png', region: region); }); @@ -110,7 +109,7 @@ Future testMain() async { ); })); - await renderScene(sceneBuilder.build()); + await renderer.renderScene(sceneBuilder.build(), implicitView); await matchGoldenFile('scene_builder_rectangle_clip_circular_path.png', region: region); }); @@ -138,7 +137,7 @@ Future testMain() async { ); })); - await renderScene(sceneBuilder.build()); + await renderer.renderScene(sceneBuilder.build(), implicitView); await matchGoldenFile('scene_builder_opacity_circles_on_square.png', region: region); }); @@ -178,7 +177,7 @@ Future testMain() async { ); })); - await renderScene(sceneBuilder.build()); + await renderer.renderScene(sceneBuilder.build(), implicitView); await matchGoldenFile('scene_builder_shader_mask.png', region: region); }, skip: isFirefox && isHtml); // https://github.com/flutter/flutter/issues/86623 @@ -210,7 +209,7 @@ Future testMain() async { ); })); - await renderScene(sceneBuilder.build()); + await renderer.renderScene(sceneBuilder.build(), implicitView); await matchGoldenFile('scene_builder_backdrop_filter.png', region: region); }); @@ -229,7 +228,7 @@ Future testMain() async { ); })); - await renderScene(sceneBuilder.build()); + await renderer.renderScene(sceneBuilder.build(), implicitView); await matchGoldenFile('scene_builder_image_filter.png', region: region); }); @@ -251,7 +250,7 @@ Future testMain() async { ); })); - await renderScene(sceneBuilder.build()); + await renderer.renderScene(sceneBuilder.build(), implicitView); await matchGoldenFile('scene_builder_color_filter.png', region: region); }); }); diff --git a/lib/web_ui/test/ui/utils.dart b/lib/web_ui/test/ui/utils.dart index ec7eaf4c0aed8..24d8c148f240e 100644 --- a/lib/web_ui/test/ui/utils.dart +++ b/lib/web_ui/test/ui/utils.dart @@ -9,8 +9,6 @@ import 'package:ui/src/engine/skwasm/skwasm_stub.dart' if (dart.library.ffi) 'package:ui/src/engine/skwasm/skwasm_impl.dart'; import 'package:ui/ui.dart'; -import '../common/rendering.dart'; - Picture drawPicture(void Function(Canvas) drawCommands) { final PictureRecorder recorder = PictureRecorder(); final Canvas canvas = Canvas(recorder); @@ -23,7 +21,7 @@ Future drawPictureUsingCurrentRenderer(Picture picture) async { final SceneBuilder sb = SceneBuilder(); sb.pushOffset(0, 0); sb.addPicture(Offset.zero, picture); - await renderScene(sb.build()); + await renderer.renderScene(sb.build(), implicitView); } /// Convenience getter for the implicit view.