From 2dacc8254f4d93a73bc820660c842292ca89f72e Mon Sep 17 00:00:00 2001 From: Harry Terkelsen Date: Thu, 16 Nov 2023 15:28:33 -0800 Subject: [PATCH 01/43] WIP add multiview to renderer --- .../lib/src/engine/canvaskit/rasterizer.dart | 83 +++++++------------ .../lib/src/engine/canvaskit/renderer.dart | 13 ++- lib/web_ui/lib/src/engine/html/renderer.dart | 2 +- .../lib/src/engine/platform_dispatcher.dart | 2 +- lib/web_ui/lib/src/engine/renderer.dart | 2 +- .../engine/skwasm/skwasm_impl/renderer.dart | 3 +- .../engine/skwasm/skwasm_stub/renderer.dart | 2 +- .../test/canvaskit/canvas_golden_test.dart | 2 +- .../test/canvaskit/embedded_views_test.dart | 14 ++-- .../test/canvaskit/multi_view_test.dart | 24 ++++++ 10 files changed, 72 insertions(+), 75 deletions(-) create mode 100644 lib/web_ui/test/canvaskit/multi_view_test.dart diff --git a/lib/web_ui/lib/src/engine/canvaskit/rasterizer.dart b/lib/web_ui/lib/src/engine/canvaskit/rasterizer.dart index 8d150ecae4144..acf7a5164f535 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/rasterizer.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/rasterizer.dart @@ -2,80 +2,53 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'package:meta/meta.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' as ui; /// A class that can rasterize [LayerTree]s into a given [Surface]. -class Rasterizer { +class ViewRenderer { + ViewRenderer(this.view); + + final ui.FlutterView view; + final CompositorContext context = CompositorContext(); - final List _postFrameCallbacks = []; - /// This is an SkSurface backed by an OffScreenCanvas. This single Surface is - /// used to render to many RenderCanvases to produce the rendered scene. - final Surface _offscreenSurface = Surface(); ui.Size _currentFrameSize = ui.Size.zero; /// Render the given [pictures] so it is displayed by the given [canvas]. Future rasterizeToCanvas( RenderCanvas canvas, List pictures) async { - await _offscreenSurface.rasterizeToCanvas( - _currentFrameSize, canvas, pictures); + await CanvasKitRenderer.instance.offscreenSurface.rasterizeToCanvas( + _currentFrameSize, + canvas, + pictures, + ); } - /// Sets the maximum size of the Skia resource cache, in bytes. - void setSkiaResourceCacheMaxBytes(int bytes) => - _offscreenSurface.setSkiaResourceCacheMaxBytes(bytes); - /// Creates a new frame from this rasterizer's surface, draws the given /// [LayerTree] into it, and then submits the frame. void draw(LayerTree layerTree) { - try { - if (layerTree.frameSize.isEmpty) { - // Available drawing area is empty. Skip drawing. - return; - } - - _currentFrameSize = layerTree.frameSize; - _offscreenSurface.acquireFrame(_currentFrameSize); - HtmlViewEmbedder.instance.frameSize = _currentFrameSize; - final CkPictureRecorder pictureRecorder = CkPictureRecorder(); - pictureRecorder.beginRecording(ui.Offset.zero & _currentFrameSize); - pictureRecorder.recordingCanvas!.clear(const ui.Color(0x00000000)); - final Frame compositorFrame = context.acquireFrame( - pictureRecorder.recordingCanvas!, HtmlViewEmbedder.instance); - - compositorFrame.raster(layerTree, ignoreRasterCache: true); - - CanvasKitRenderer.instance.sceneHost! - .prepend(RenderCanvasFactory.instance.baseCanvas.htmlElement); - rasterizeToCanvas(RenderCanvasFactory.instance.baseCanvas, - [pictureRecorder.endRecording()]); - - HtmlViewEmbedder.instance.submitFrame(); - } finally { - _runPostFrameCallbacks(); + if (layerTree.frameSize.isEmpty) { + // Available drawing area is empty. Skip drawing. + return; } - } - void addPostFrameCallback(ui.VoidCallback callback) { - _postFrameCallbacks.add(callback); - } + _currentFrameSize = layerTree.frameSize; + CanvasKitRenderer.instance.offscreenSurface.acquireFrame(_currentFrameSize); + HtmlViewEmbedder.instance.frameSize = _currentFrameSize; + final CkPictureRecorder pictureRecorder = CkPictureRecorder(); + pictureRecorder.beginRecording(ui.Offset.zero & _currentFrameSize); + pictureRecorder.recordingCanvas!.clear(const ui.Color(0x00000000)); + final Frame compositorFrame = context.acquireFrame( + pictureRecorder.recordingCanvas!, HtmlViewEmbedder.instance); - void _runPostFrameCallbacks() { - for (int i = 0; i < _postFrameCallbacks.length; i++) { - final ui.VoidCallback callback = _postFrameCallbacks[i]; - callback(); - } - for (int i = 0; i < frameReferences.length; i++) { - frameReferences[i].value = null; - } - frameReferences.clear(); - } + compositorFrame.raster(layerTree, ignoreRasterCache: true); + + CanvasKitRenderer.instance.sceneHost! + .prepend(RenderCanvasFactory.instance.baseCanvas.htmlElement); + rasterizeToCanvas(RenderCanvasFactory.instance.baseCanvas, + [pictureRecorder.endRecording()]); - /// Forces the post-frame callbacks to run. Useful in tests. - @visibleForTesting - void debugRunPostFrameCallbacks() { - _runPostFrameCallbacks(); + HtmlViewEmbedder.instance.submitFrame(); } } diff --git a/lib/web_ui/lib/src/engine/canvaskit/renderer.dart b/lib/web_ui/lib/src/engine/canvaskit/renderer.dart index cc189ab40d795..448102d94d1f1 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/renderer.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/renderer.dart @@ -40,13 +40,12 @@ class CanvasKitRenderer implements Renderer { @override SkiaFontCollection get fontCollection => _fontCollection; - /// The scene host, where the root canvas and overlay canvases are added to. - DomElement? _sceneHost; - DomElement? get sceneHost => _sceneHost; + /// This is an SkSurface backed by an OffScreenCanvas. This single Surface is + /// used to render to many RenderCanvases to produce the rendered scene. + final Surface offscreenSurface = Surface(); - late Rasterizer rasterizer = Rasterizer(); - - set resourceCacheMaxBytes(int bytes) => rasterizer.setSkiaResourceCacheMaxBytes(bytes); + set resourceCacheMaxBytes(int bytes) => + offscreenSurface.setSkiaResourceCacheMaxBytes(bytes); @override Future initialize() async { @@ -371,7 +370,7 @@ class CanvasKitRenderer implements Renderer { CkParagraphBuilder(style); @override - void renderScene(ui.Scene scene) { + 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. diff --git a/lib/web_ui/lib/src/engine/html/renderer.dart b/lib/web_ui/lib/src/engine/html/renderer.dart index 9aa45c5e08a1a..cf6e62709f6b2 100644 --- a/lib/web_ui/lib/src/engine/html/renderer.dart +++ b/lib/web_ui/lib/src/engine/html/renderer.dart @@ -327,7 +327,7 @@ class HtmlRenderer implements Renderer { CanvasParagraphBuilder(style as EngineParagraphStyle); @override - void renderScene(ui.Scene scene) { + void renderScene(ui.Scene scene, [ui.FlutterView? view]) { _viewEmbedder.addSceneToSceneHost((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 2853ff14933ff..1d945de34a87d 100644 --- a/lib/web_ui/lib/src/engine/platform_dispatcher.dart +++ b/lib/web_ui/lib/src/engine/platform_dispatcher.dart @@ -717,7 +717,7 @@ class EnginePlatformDispatcher extends ui.PlatformDispatcher { /// painting. @override void render(ui.Scene scene, [ui.FlutterView? view]) { - renderer.renderScene(scene); + renderer.renderScene(scene, view); } /// Additional accessibility features that may be enabled by the platform. diff --git a/lib/web_ui/lib/src/engine/renderer.dart b/lib/web_ui/lib/src/engine/renderer.dart index 0f4982de62eba..1707e39abf5bc 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); - FutureOr renderScene(ui.Scene scene); + FutureOr renderScene(ui.Scene scene, [ui.FlutterView? view]); } 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 136caa160d645..3008c515a4d90 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 @@ -399,7 +399,8 @@ class SkwasmRenderer implements Renderer { } @override - Future renderScene(ui.Scene scene) => sceneView.renderScene(scene as EngineScene); + Future renderScene(ui.Scene scene, [ui.FlutterView? view]) => + sceneView.renderScene(scene as EngineScene); @override String get rendererTag => 'skwasm'; 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 3964590b3e70a..17a13eecf3e5c 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 - void renderScene(ui.Scene scene) { + void renderScene(ui.Scene scene, [ui.FlutterView? view]) { throw UnimplementedError('Skwasm not implemented on this platform.'); } diff --git a/lib/web_ui/test/canvaskit/canvas_golden_test.dart b/lib/web_ui/test/canvaskit/canvas_golden_test.dart index 46a436db87726..1d69f80d8eda1 100644 --- a/lib/web_ui/test/canvaskit/canvas_golden_test.dart +++ b/lib/web_ui/test/canvaskit/canvas_golden_test.dart @@ -162,7 +162,7 @@ void testMain() { // Regression test for https://github.com/flutter/flutter/issues/121758 test('resources used in temporary surfaces for Image.toByteData can cross to rendering overlays', () async { - final Rasterizer rasterizer = CanvasKitRenderer.instance.rasterizer; + final ViewRenderer rasterizer = CanvasKitRenderer.instance.rasterizer; RenderCanvasFactory.instance.debugClear(); ui_web.platformViewRegistry.registerViewFactory( diff --git a/lib/web_ui/test/canvaskit/embedded_views_test.dart b/lib/web_ui/test/canvaskit/embedded_views_test.dart index cda10de9fc96b..ba9310c559618 100644 --- a/lib/web_ui/test/canvaskit/embedded_views_test.dart +++ b/lib/web_ui/test/canvaskit/embedded_views_test.dart @@ -33,7 +33,7 @@ void testMain() { }); test('embeds interactive platform views', () async { - final Rasterizer rasterizer = CanvasKitRenderer.instance.rasterizer; + final ViewRenderer rasterizer = CanvasKitRenderer.instance.rasterizer; ui_web.platformViewRegistry.registerViewFactory( 'test-platform-view', (int viewId) => createDomHTMLDivElement()..id = 'view-0', @@ -67,7 +67,7 @@ void testMain() { }); test('clips platform views with RRects', () async { - final Rasterizer rasterizer = CanvasKitRenderer.instance.rasterizer; + final ViewRenderer rasterizer = CanvasKitRenderer.instance.rasterizer; ui_web.platformViewRegistry.registerViewFactory( 'test-platform-view', (int viewId) => createDomHTMLDivElement()..id = 'view-0', @@ -122,7 +122,7 @@ void testMain() { }); test('correctly transforms platform views', () async { - final Rasterizer rasterizer = CanvasKitRenderer.instance.rasterizer; + final ViewRenderer rasterizer = CanvasKitRenderer.instance.rasterizer; ui_web.platformViewRegistry.registerViewFactory( 'test-platform-view', (int viewId) => createDomHTMLDivElement()..id = 'view-0', @@ -664,7 +664,7 @@ void testMain() { }, skip: isSafari || isFirefox); test('removed the DOM node of an unrendered platform view', () async { - final Rasterizer rasterizer = CanvasKitRenderer.instance.rasterizer; + final ViewRenderer rasterizer = CanvasKitRenderer.instance.rasterizer; ui_web.platformViewRegistry.registerViewFactory( 'test-platform-view', (int viewId) => createDomHTMLDivElement()..id = 'view-0', @@ -720,7 +720,7 @@ void testMain() { test( 'removes old SVG clip definitions from the DOM when the view is recomposited', () async { - final Rasterizer rasterizer = CanvasKitRenderer.instance.rasterizer; + final ViewRenderer rasterizer = CanvasKitRenderer.instance.rasterizer; ui_web.platformViewRegistry.registerViewFactory( 'test-platform-view', (int viewId) => createDomHTMLDivElement()..id = 'test-view', @@ -755,7 +755,7 @@ void testMain() { test('does not crash when a prerolled platform view is not composited', () async { - final Rasterizer rasterizer = CanvasKitRenderer.instance.rasterizer; + final ViewRenderer rasterizer = CanvasKitRenderer.instance.rasterizer; ui_web.platformViewRegistry.registerViewFactory( 'test-platform-view', (int viewId) => createDomHTMLDivElement()..id = 'view-0', @@ -775,7 +775,7 @@ void testMain() { }); test('does not create overlays for invisible platform views', () async { - final Rasterizer rasterizer = CanvasKitRenderer.instance.rasterizer; + final ViewRenderer rasterizer = CanvasKitRenderer.instance.rasterizer; ui_web.platformViewRegistry.registerViewFactory( 'test-visible-view', (int viewId) => diff --git a/lib/web_ui/test/canvaskit/multi_view_test.dart b/lib/web_ui/test/canvaskit/multi_view_test.dart new file mode 100644 index 0000000000000..5a7be3487c148 --- /dev/null +++ b/lib/web_ui/test/canvaskit/multi_view_test.dart @@ -0,0 +1,24 @@ +// 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:typed_data'; + +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('CanvasKit', () { + setUpCanvasKitTest(); + + test('can create multiple views', () async {}); + }); +} From d0b625e344d5644f8b3abfcdf99aa7729cbe7ef0 Mon Sep 17 00:00:00 2001 From: Harry Terkelsen Date: Mon, 20 Nov 2023 09:22:42 -0800 Subject: [PATCH 02/43] WIP --- .../src/engine/canvaskit/embedded_views.dart | 9 +- .../lib/src/engine/canvaskit/rasterizer.dart | 7 +- .../canvaskit/render_canvas_factory.dart | 21 - .../lib/src/engine/canvaskit/renderer.dart | 458 +++++++++--------- .../dimensions_provider.dart | 9 +- .../src/engine/view_embedder/dom_manager.dart | 6 +- .../embedding_strategy.dart | 9 +- lib/web_ui/lib/src/engine/window.dart | 92 ++-- .../test/canvaskit/canvas_golden_test.dart | 2 +- .../test/canvaskit/embedded_views_test.dart | 14 +- 10 files changed, 308 insertions(+), 319 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 a5e9425c0027c..988c1932c7228 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/embedded_views.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/embedded_views.dart @@ -17,18 +17,19 @@ import 'embedded_views_diff.dart'; import 'path.dart'; import 'picture.dart'; import 'picture_recorder.dart'; +import 'rasterizer.dart'; import 'render_canvas.dart'; import 'render_canvas_factory.dart'; import 'renderer.dart'; /// This composites HTML views into the [ui.Scene]. class HtmlViewEmbedder { - HtmlViewEmbedder._(); + HtmlViewEmbedder(this.view, this.rasterizer); - /// The [HtmlViewEmbedder] singleton. - static HtmlViewEmbedder instance = HtmlViewEmbedder._(); + final ui.FlutterView view; + final Rasterizer rasterizer; - DomElement get skiaSceneHost => CanvasKitRenderer.instance.sceneHost!; + DomElement get skiaSceneHost => (view as EngineFlutterView).dom.sceneHost; /// The context for the current frame. EmbedderFrameContext _context = EmbedderFrameContext(); diff --git a/lib/web_ui/lib/src/engine/canvaskit/rasterizer.dart b/lib/web_ui/lib/src/engine/canvaskit/rasterizer.dart index acf7a5164f535..ca5c72043a3b8 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/rasterizer.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/rasterizer.dart @@ -6,12 +6,13 @@ import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' as ui; /// A class that can rasterize [LayerTree]s into a given [Surface]. -class ViewRenderer { - ViewRenderer(this.view); +class Rasterizer { + Rasterizer(this.view); final ui.FlutterView view; - final CompositorContext context = CompositorContext(); + final RenderCanvasFactory renderCanvasFactory = RenderCanvasFactory(); + final HtmlViewEmbedder viewEmbedder = HtmlViewEmbedder(); ui.Size _currentFrameSize = ui.Size.zero; diff --git a/lib/web_ui/lib/src/engine/canvaskit/render_canvas_factory.dart b/lib/web_ui/lib/src/engine/canvaskit/render_canvas_factory.dart index 593390972377c..39e6538575bef 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/render_canvas_factory.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/render_canvas_factory.dart @@ -14,26 +14,6 @@ class RenderCanvasFactory { }()); } - /// The lazy-initialized singleton surface factory. - /// - /// [debugClear] causes this singleton to be reinitialized. - static RenderCanvasFactory get instance => - _instance ??= RenderCanvasFactory(); - - /// Returns the raw (potentially uninitialized) value of the singleton. - /// - /// Useful in tests for checking the lifecycle of this class. - static RenderCanvasFactory? get debugUninitializedInstance => _instance; - - // Override the current instance with a new one. - // - // This should only be used in tests. - static void debugSetInstance(RenderCanvasFactory newInstance) { - _instance = newInstance; - } - - static RenderCanvasFactory? _instance; - /// The base canvas to paint on. This is the default canvas which will be /// painted to. If there are no platform views, then this canvas will render /// the entire scene. @@ -137,6 +117,5 @@ class RenderCanvasFactory { baseCanvas.dispose(); _liveCanvases.clear(); _cache.clear(); - _instance = null; } } diff --git a/lib/web_ui/lib/src/engine/canvaskit/renderer.dart b/lib/web_ui/lib/src/engine/canvaskit/renderer.dart index 8cc6db358243f..2d6c8c6b81201 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/renderer.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/renderer.dart @@ -66,10 +66,11 @@ class CanvasKitRenderer implements Renderer { // CanvasKit uses a static scene element that never gets replaced, so it's // added eagerly during initialization here and never touched, unless the // system is reset due to hot restart or in a test. - _sceneHost = createDomElement('flt-scene'); + DomElement _sceneHost = createDomElement('flt-scene'); // TODO(harryterkelsen): Do this operation on the appropriate Flutter View. - final EngineFlutterView implicitView = EnginePlatformDispatcher.instance.implicitView!; - implicitView.dom.setScene(_sceneHost!); + final EngineFlutterView implicitView = + EnginePlatformDispatcher.instance.implicitView!; + implicitView.dom.setScene(_sceneHost); } @override @@ -82,12 +83,11 @@ class CanvasKitRenderer implements Renderer { List? textureCoordinates, List? colors, List? indices, - }) => CkVertices( - mode, - positions, - textureCoordinates: textureCoordinates, - colors: colors, - indices: indices); + }) => + CkVertices(mode, positions, + textureCoordinates: textureCoordinates, + colors: colors, + indices: indices); @override ui.Vertices createVerticesRaw( @@ -96,26 +96,23 @@ class CanvasKitRenderer implements Renderer { Float32List? textureCoordinates, Int32List? colors, Uint16List? indices, - }) => CkVertices.raw( - mode, - positions, - textureCoordinates: textureCoordinates, - colors: colors, - indices: indices); + }) => + CkVertices.raw(mode, positions, + textureCoordinates: textureCoordinates, + colors: colors, + indices: indices); @override ui.Canvas createCanvas(ui.PictureRecorder recorder, [ui.Rect? cullRect]) => - CanvasKitCanvas(recorder, cullRect); + CanvasKitCanvas(recorder, cullRect); @override ui.Gradient createLinearGradient( - ui.Offset from, - ui.Offset to, - List colors, [ - List? colorStops, - ui.TileMode tileMode = ui.TileMode.clamp, - Float32List? matrix4 - ]) => CkGradientLinear(from, to, colors, colorStops, tileMode, matrix4); + ui.Offset from, ui.Offset to, List colors, + [List? colorStops, + ui.TileMode tileMode = ui.TileMode.clamp, + Float32List? matrix4]) => + CkGradientLinear(from, to, colors, colorStops, tileMode, matrix4); @override ui.Gradient createRadialGradient( @@ -125,38 +122,27 @@ class CanvasKitRenderer implements Renderer { List? colorStops, ui.TileMode tileMode = ui.TileMode.clamp, Float32List? matrix4, - ]) => CkGradientRadial(center, radius, colors, colorStops, tileMode, matrix4); + ]) => + CkGradientRadial(center, radius, colors, colorStops, tileMode, matrix4); @override - ui.Gradient createConicalGradient( - ui.Offset focal, - double focalRadius, - ui.Offset center, - double radius, - List colors, - [List? colorStops, - ui.TileMode tileMode = ui.TileMode.clamp, - Float32List? matrix] - ) => CkGradientConical( - focal, - focalRadius, - center, - radius, - colors, - colorStops, - tileMode, - matrix); - - @override - ui.Gradient createSweepGradient( - ui.Offset center, - List colors, [ - List? colorStops, - ui.TileMode tileMode = ui.TileMode.clamp, - double startAngle = 0.0, - double endAngle = math.pi * 2, - Float32List? matrix4 - ]) => CkGradientSweep(center, colors, colorStops, tileMode, startAngle, endAngle, matrix4); + ui.Gradient createConicalGradient(ui.Offset focal, double focalRadius, + ui.Offset center, double radius, List colors, + [List? colorStops, + ui.TileMode tileMode = ui.TileMode.clamp, + Float32List? matrix]) => + CkGradientConical(focal, focalRadius, center, radius, colors, colorStops, + tileMode, matrix); + + @override + ui.Gradient createSweepGradient(ui.Offset center, List colors, + [List? colorStops, + ui.TileMode tileMode = ui.TileMode.clamp, + double startAngle = 0.0, + double endAngle = math.pi * 2, + Float32List? matrix4]) => + CkGradientSweep( + center, colors, colorStops, tileMode, startAngle, endAngle, matrix4); @override ui.PictureRecorder createPictureRecorder() => CkPictureRecorder(); @@ -165,60 +151,57 @@ class CanvasKitRenderer implements Renderer { ui.SceneBuilder createSceneBuilder() => LayerSceneBuilder(); @override - ui.ImageFilter createBlurImageFilter({ - double sigmaX = 0.0, - double sigmaY = 0.0, - ui.TileMode tileMode = ui.TileMode.clamp - }) => CkImageFilter.blur(sigmaX: sigmaX, sigmaY: sigmaY, tileMode: tileMode); + ui.ImageFilter createBlurImageFilter( + {double sigmaX = 0.0, + double sigmaY = 0.0, + ui.TileMode tileMode = ui.TileMode.clamp}) => + CkImageFilter.blur(sigmaX: sigmaX, sigmaY: sigmaY, tileMode: tileMode); @override - ui.ImageFilter createDilateImageFilter({double radiusX = 0.0, double radiusY = 0.0}) { + ui.ImageFilter createDilateImageFilter( + {double radiusX = 0.0, double radiusY = 0.0}) { // TODO(fzyzcjy): implement dilate. https://github.com/flutter/flutter/issues/101085 - throw UnimplementedError('ImageFilter.dilate not implemented for CanvasKit.'); + throw UnimplementedError( + 'ImageFilter.dilate not implemented for CanvasKit.'); } @override - ui.ImageFilter createErodeImageFilter({double radiusX = 0.0, double radiusY = 0.0}) { + ui.ImageFilter createErodeImageFilter( + {double radiusX = 0.0, double radiusY = 0.0}) { // TODO(fzyzcjy): implement erode. https://github.com/flutter/flutter/issues/101085 - throw UnimplementedError('ImageFilter.erode not implemented for CanvasKit.'); + throw UnimplementedError( + 'ImageFilter.erode not implemented for CanvasKit.'); } @override - ui.ImageFilter createMatrixImageFilter( - Float64List matrix4, { - ui.FilterQuality filterQuality = ui.FilterQuality.low - }) => CkImageFilter.matrix(matrix: matrix4, filterQuality: filterQuality); + ui.ImageFilter createMatrixImageFilter(Float64List matrix4, + {ui.FilterQuality filterQuality = ui.FilterQuality.low}) => + CkImageFilter.matrix(matrix: matrix4, filterQuality: filterQuality); @override - ui.ImageFilter composeImageFilters({required ui.ImageFilter outer, required ui.ImageFilter inner}) { - // TODO(ferhat): add implementation - throw UnimplementedError('ImageFilter.compose not implemented for CanvasKit.'); + ui.ImageFilter composeImageFilters( + {required ui.ImageFilter outer, required ui.ImageFilter inner}) { + // TODO(ferhat): add implementation + throw UnimplementedError( + 'ImageFilter.compose not implemented for CanvasKit.'); } @override - Future instantiateImageCodec( - Uint8List list, { - int? targetWidth, - int? targetHeight, - bool allowUpscaling = true - }) async => skiaInstantiateImageCodec( - list, - targetWidth, - targetHeight - ); + Future instantiateImageCodec(Uint8List list, + {int? targetWidth, + int? targetHeight, + bool allowUpscaling = true}) async => + skiaInstantiateImageCodec(list, targetWidth, targetHeight); @override - Future instantiateImageCodecFromUrl( - Uri uri, { - ui_web.ImageCodecChunkCallback? chunkCallback - }) => skiaInstantiateWebImageCodec(uri.toString(), chunkCallback); + Future instantiateImageCodecFromUrl(Uri uri, + {ui_web.ImageCodecChunkCallback? chunkCallback}) => + skiaInstantiateWebImageCodec(uri.toString(), chunkCallback); @override ui.Image createImageFromImageBitmap(DomImageBitmap imageBitmap) { - final SkImage? skImage = canvasKit.MakeLazyImageFromImageBitmap( - imageBitmap, - true - ); + final SkImage? skImage = + canvasKit.MakeLazyImageFromImageBitmap(imageBitmap, true); if (skImage == null) { throw Exception('Failed to convert image bitmap to an SkImage.'); } @@ -226,36 +209,26 @@ class CanvasKitRenderer implements Renderer { } @override - void decodeImageFromPixels( - Uint8List pixels, - int width, - int height, - ui.PixelFormat format, - ui.ImageDecoderCallback callback, { - int? rowBytes, - int? targetWidth, - int? targetHeight, - bool allowUpscaling = true - }) => skiaDecodeImageFromPixels( - pixels, - width, - height, - format, - callback, - rowBytes: rowBytes, - targetWidth: targetWidth, - targetHeight: targetHeight, - allowUpscaling: allowUpscaling - ); + void decodeImageFromPixels(Uint8List pixels, int width, int height, + ui.PixelFormat format, ui.ImageDecoderCallback callback, + {int? rowBytes, + int? targetWidth, + int? targetHeight, + bool allowUpscaling = true}) => + skiaDecodeImageFromPixels(pixels, width, height, format, callback, + rowBytes: rowBytes, + targetWidth: targetWidth, + targetHeight: targetHeight, + allowUpscaling: allowUpscaling); @override ui.ImageShader createImageShader( - ui.Image image, - ui.TileMode tmx, - ui.TileMode tmy, - Float64List matrix4, - ui.FilterQuality? filterQuality - ) => CkImageShader(image, tmx, tmy, matrix4, filterQuality); + ui.Image image, + ui.TileMode tmx, + ui.TileMode tmy, + Float64List matrix4, + ui.FilterQuality? filterQuality) => + CkImageShader(image, tmx, tmy, matrix4, filterQuality); @override ui.Path createPath() => CkPath(); @@ -265,114 +238,115 @@ class CanvasKitRenderer implements Renderer { @override ui.Path combinePaths(ui.PathOperation op, ui.Path path1, ui.Path path2) => - CkPath.combine(op, path1, path2); - - @override - ui.TextStyle createTextStyle({ - ui.Color? color, - ui.TextDecoration? decoration, - ui.Color? decorationColor, - ui.TextDecorationStyle? decorationStyle, - double? decorationThickness, - ui.FontWeight? fontWeight, - ui.FontStyle? fontStyle, - ui.TextBaseline? textBaseline, - String? fontFamily, - List? fontFamilyFallback, - double? fontSize, - double? letterSpacing, - double? wordSpacing, - double? height, - ui.TextLeadingDistribution? leadingDistribution, - ui.Locale? locale, - ui.Paint? background, - ui.Paint? foreground, - List? shadows, - List? fontFeatures, - List? fontVariations - }) => CkTextStyle( - color: color, - decoration: decoration, - decorationColor: decorationColor, - decorationStyle: decorationStyle, - decorationThickness: decorationThickness, - fontWeight: fontWeight, - fontStyle: fontStyle, - textBaseline: textBaseline, - fontFamily: fontFamily, - fontFamilyFallback: fontFamilyFallback, - fontSize: fontSize, - letterSpacing: letterSpacing, - wordSpacing: wordSpacing, - height: height, - leadingDistribution: leadingDistribution, - locale: locale, - background: background as CkPaint?, - foreground: foreground as CkPaint?, - shadows: shadows, - fontFeatures: fontFeatures, - fontVariations: fontVariations, - ); - - @override - ui.ParagraphStyle createParagraphStyle({ - ui.TextAlign? textAlign, - ui.TextDirection? textDirection, - int? maxLines, - String? fontFamily, - double? fontSize, - double? height, - ui.TextHeightBehavior? textHeightBehavior, - ui.FontWeight? fontWeight, - ui.FontStyle? fontStyle, - ui.StrutStyle? strutStyle, - String? ellipsis, - ui.Locale? locale - }) => CkParagraphStyle( - textAlign: textAlign, - textDirection: textDirection, - maxLines: maxLines, - fontFamily: fontFamily, - fontSize: fontSize, - height: height, - textHeightBehavior: textHeightBehavior, - fontWeight: fontWeight, - fontStyle: fontStyle, - strutStyle: strutStyle, - ellipsis: ellipsis, - locale: locale, - applyRoundingHack: !ui.ParagraphBuilder.shouldDisableRoundingHack, - ); - - @override - ui.StrutStyle createStrutStyle({ - String? fontFamily, - List? fontFamilyFallback, - double? fontSize, - double? height, - ui.TextLeadingDistribution? leadingDistribution, - double? leading, - ui.FontWeight? fontWeight, - ui.FontStyle? fontStyle, - bool? forceStrutHeight - }) => CkStrutStyle( - fontFamily: fontFamily, - fontFamilyFallback: fontFamilyFallback, - fontSize: fontSize, - height: height, - leadingDistribution: leadingDistribution, - leading: leading, - fontWeight: fontWeight, - fontStyle: fontStyle, - forceStrutHeight: forceStrutHeight, - ); + CkPath.combine(op, path1, path2); + + @override + ui.TextStyle createTextStyle( + {ui.Color? color, + ui.TextDecoration? decoration, + ui.Color? decorationColor, + ui.TextDecorationStyle? decorationStyle, + double? decorationThickness, + ui.FontWeight? fontWeight, + ui.FontStyle? fontStyle, + ui.TextBaseline? textBaseline, + String? fontFamily, + List? fontFamilyFallback, + double? fontSize, + double? letterSpacing, + double? wordSpacing, + double? height, + ui.TextLeadingDistribution? leadingDistribution, + ui.Locale? locale, + ui.Paint? background, + ui.Paint? foreground, + List? shadows, + List? fontFeatures, + List? fontVariations}) => + CkTextStyle( + color: color, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fontWeight: fontWeight, + fontStyle: fontStyle, + textBaseline: textBaseline, + fontFamily: fontFamily, + fontFamilyFallback: fontFamilyFallback, + fontSize: fontSize, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + height: height, + leadingDistribution: leadingDistribution, + locale: locale, + background: background as CkPaint?, + foreground: foreground as CkPaint?, + shadows: shadows, + fontFeatures: fontFeatures, + fontVariations: fontVariations, + ); + + @override + ui.ParagraphStyle createParagraphStyle( + {ui.TextAlign? textAlign, + ui.TextDirection? textDirection, + int? maxLines, + String? fontFamily, + double? fontSize, + double? height, + ui.TextHeightBehavior? textHeightBehavior, + ui.FontWeight? fontWeight, + ui.FontStyle? fontStyle, + ui.StrutStyle? strutStyle, + String? ellipsis, + ui.Locale? locale}) => + CkParagraphStyle( + textAlign: textAlign, + textDirection: textDirection, + maxLines: maxLines, + fontFamily: fontFamily, + fontSize: fontSize, + height: height, + textHeightBehavior: textHeightBehavior, + fontWeight: fontWeight, + fontStyle: fontStyle, + strutStyle: strutStyle, + ellipsis: ellipsis, + locale: locale, + applyRoundingHack: !ui.ParagraphBuilder.shouldDisableRoundingHack, + ); + + @override + ui.StrutStyle createStrutStyle( + {String? fontFamily, + List? fontFamilyFallback, + double? fontSize, + double? height, + ui.TextLeadingDistribution? leadingDistribution, + double? leading, + ui.FontWeight? fontWeight, + ui.FontStyle? fontStyle, + bool? forceStrutHeight}) => + CkStrutStyle( + fontFamily: fontFamily, + fontFamilyFallback: fontFamilyFallback, + fontSize: fontSize, + height: height, + leadingDistribution: leadingDistribution, + leading: leading, + fontWeight: fontWeight, + fontStyle: fontStyle, + forceStrutHeight: forceStrutHeight, + ); @override ui.ParagraphBuilder createParagraphBuilder(ui.ParagraphStyle style) => - CkParagraphBuilder(style); + CkParagraphBuilder(style); @override void renderScene(ui.Scene scene, [ui.FlutterView? view]) { + view ??= EnginePlatformDispatcher.instance.implicitView!; // "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. @@ -383,47 +357,53 @@ class CanvasKitRenderer implements Renderer { frameTimingsOnBuildFinish(); frameTimingsOnRasterStart(); + final Rasterizer rasterizer = _getRasterizerForView(view); + rasterizer.draw((scene as LayerScene).layerTree); frameTimingsOnRasterFinish(); } + final _rasterizers = {}; + Rasterizer _getRasterizerForView(ui.FlutterView view) {} + @override void clearFragmentProgramCache() { _programs.clear(); } - static final Map> _programs = >{}; + static final Map> _programs = + >{}; @override Future createFragmentProgram(String assetKey) { if (_programs.containsKey(assetKey)) { return _programs[assetKey]!; } - return _programs[assetKey] = ui_web.assetManager.load(assetKey).then((ByteData data) { + return _programs[assetKey] = + ui_web.assetManager.load(assetKey).then((ByteData data) { return CkFragmentProgram.fromBytes(assetKey, data.buffer.asUint8List()); }); } @override - ui.LineMetrics createLineMetrics({ - required bool hardBreak, - required double ascent, - required double descent, - required double unscaledAscent, - required double height, - required double width, - required double left, - required double baseline, - required int lineNumber - }) => EngineLineMetrics( - hardBreak: hardBreak, - ascent: ascent, - descent: descent, - unscaledAscent: unscaledAscent, - height: height, - width: width, - left: left, - baseline: baseline, - lineNumber: lineNumber - ); + ui.LineMetrics createLineMetrics( + {required bool hardBreak, + required double ascent, + required double descent, + required double unscaledAscent, + required double height, + required double width, + required double left, + required double baseline, + required int lineNumber}) => + EngineLineMetrics( + hardBreak: hardBreak, + ascent: ascent, + descent: descent, + unscaledAscent: unscaledAscent, + height: height, + width: width, + left: left, + baseline: baseline, + lineNumber: lineNumber); } diff --git a/lib/web_ui/lib/src/engine/view_embedder/dimensions_provider/dimensions_provider.dart b/lib/web_ui/lib/src/engine/view_embedder/dimensions_provider/dimensions_provider.dart index 16f80ea1ba2d3..47ccdbb11ed29 100644 --- a/lib/web_ui/lib/src/engine/view_embedder/dimensions_provider/dimensions_provider.dart +++ b/lib/web_ui/lib/src/engine/view_embedder/dimensions_provider/dimensions_provider.dart @@ -29,11 +29,12 @@ abstract class DimensionsProvider { DimensionsProvider(); /// Creates the appropriate DimensionsProvider depending on the incoming [hostElement]. - factory DimensionsProvider.create({DomElement? hostElement}) { - if (hostElement != null) { - return CustomElementDimensionsProvider(hostElement); - } else { + factory DimensionsProvider.create( + {required DomElement hostElement, bool isFullPage = false}) { + if (isFullPage) { return FullPageDimensionsProvider(); + } else { + return CustomElementDimensionsProvider(hostElement); } } diff --git a/lib/web_ui/lib/src/engine/view_embedder/dom_manager.dart b/lib/web_ui/lib/src/engine/view_embedder/dom_manager.dart index 9b39c34c6c7cd..efc5f394453cf 100644 --- a/lib/web_ui/lib/src/engine/view_embedder/dom_manager.dart +++ b/lib/web_ui/lib/src/engine/view_embedder/dom_manager.dart @@ -43,8 +43,10 @@ import 'style_manager.dart'; /// +-