Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -5916,6 +5916,7 @@ ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/canvas.dart + ../..
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/canvaskit_canvas.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/color_filter.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/display_canvas_factory.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/embedded_views.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/embedded_views_diff.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/fonts.dart + ../../../flutter/LICENSE
Expand All @@ -5927,8 +5928,10 @@ ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/layer.dart + ../../
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/layer_scene_builder.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/layer_tree.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/mask_filter.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/multi_surface_rasterizer.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/n_way_canvas.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/native_memory.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/offscreen_canvas_rasterizer.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/painting.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/path.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/path_metrics.dart + ../../../flutter/LICENSE
Expand All @@ -5938,7 +5941,6 @@ ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/platform_message.da
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/raster_cache.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/rasterizer.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/render_canvas.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/render_canvas_factory.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/renderer.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/shader.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/surface.dart + ../../../flutter/LICENSE
Expand Down Expand Up @@ -8757,6 +8759,7 @@ FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/canvas.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/canvaskit_canvas.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/color_filter.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/display_canvas_factory.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/embedded_views.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/embedded_views_diff.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/fonts.dart
Expand All @@ -8768,8 +8771,10 @@ FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/layer.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/layer_scene_builder.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/layer_tree.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/mask_filter.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/multi_surface_rasterizer.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/n_way_canvas.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/native_memory.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/offscreen_canvas_rasterizer.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/painting.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/path.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/path_metrics.dart
Expand All @@ -8779,7 +8784,6 @@ FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/platform_message.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/raster_cache.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/rasterizer.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/render_canvas.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/render_canvas_factory.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/renderer.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/shader.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/surface.dart
Expand Down
4 changes: 3 additions & 1 deletion lib/web_ui/lib/src/engine.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export 'engine/canvaskit/canvas.dart';
export 'engine/canvaskit/canvaskit_api.dart';
export 'engine/canvaskit/canvaskit_canvas.dart';
export 'engine/canvaskit/color_filter.dart';
export 'engine/canvaskit/display_canvas_factory.dart';
export 'engine/canvaskit/embedded_views.dart';
export 'engine/canvaskit/embedded_views_diff.dart';
export 'engine/canvaskit/fonts.dart';
Expand All @@ -34,8 +35,10 @@ export 'engine/canvaskit/layer.dart';
export 'engine/canvaskit/layer_scene_builder.dart';
export 'engine/canvaskit/layer_tree.dart';
export 'engine/canvaskit/mask_filter.dart';
export 'engine/canvaskit/multi_surface_rasterizer.dart';
export 'engine/canvaskit/n_way_canvas.dart';
export 'engine/canvaskit/native_memory.dart';
export 'engine/canvaskit/offscreen_canvas_rasterizer.dart';
export 'engine/canvaskit/painting.dart';
export 'engine/canvaskit/path.dart';
export 'engine/canvaskit/path_metrics.dart';
Expand All @@ -44,7 +47,6 @@ export 'engine/canvaskit/picture_recorder.dart';
export 'engine/canvaskit/raster_cache.dart';
export 'engine/canvaskit/rasterizer.dart';
export 'engine/canvaskit/render_canvas.dart';
export 'engine/canvaskit/render_canvas_factory.dart';
export 'engine/canvaskit/renderer.dart';
export 'engine/canvaskit/shader.dart';
export 'engine/canvaskit/surface.dart';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,30 @@ import 'package:meta/meta.dart';

import '../../engine.dart';

/// Caches canvases used to overlay platform views.
class RenderCanvasFactory {
RenderCanvasFactory() {
/// Caches canvases used to display Skia-drawn content.
class DisplayCanvasFactory<T extends DisplayCanvas> {
DisplayCanvasFactory({required this.createCanvas}) {
assert(() {
registerHotRestartListener(dispose);
return true;
}());
}

/// A function which is passed in as a constructor parameter which is used to
/// create new display canvases.
final T Function() createCanvas;

/// 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.
final RenderCanvas baseCanvas = RenderCanvas();
late final T baseCanvas = createCanvas()..initialize();

/// Canvases created by this factory which are currently in use.
final List<RenderCanvas> _liveCanvases = <RenderCanvas>[];
final List<T> _liveCanvases = <T>[];

/// Canvases created by this factory which are no longer in use. These can be
/// reused.
final List<RenderCanvas> _cache = <RenderCanvas>[];
final List<T> _cache = <T>[];

/// The number of canvases which have been created by this factory.
int get _canvasCount => _liveCanvases.length + _cache.length + 1;
Expand All @@ -38,15 +42,16 @@ class RenderCanvasFactory {
/// Useful in tests.
int get debugCacheSize => _cache.length;

/// Gets an overlay canvas from the cache or creates a new one if there are
/// Gets a display canvas from the cache or creates a new one if there are
/// none in the cache.
RenderCanvas getCanvas() {
T getCanvas() {
if (_cache.isNotEmpty) {
final RenderCanvas canvas = _cache.removeLast();
final T canvas = _cache.removeLast();
_liveCanvases.add(canvas);
return canvas;
} else {
final RenderCanvas canvas = RenderCanvas();
final T canvas = createCanvas();
canvas.initialize();
_liveCanvases.add(canvas);
return canvas;
}
Expand All @@ -63,27 +68,35 @@ class RenderCanvasFactory {
_liveCanvases.clear();
}

/// Removes all surfaces except the base surface from the DOM.
/// Removes all canvases except the base canvas from the DOM.
///
/// This is called at the beginning of the frame to prepare for painting into
/// the new surfaces.
void removeSurfacesFromDom() {
/// the new canvases.
void removeCanvasesFromDom() {
_cache.forEach(_removeFromDom);
_liveCanvases.forEach(_removeFromDom);
}

/// Calls [callback] on each canvas created by this factory.
void forEachCanvas(void Function(T canvas) callback) {
callback(baseCanvas);
_cache.forEach(callback);
_liveCanvases.forEach(callback);
}

// Removes [canvas] from the DOM.
void _removeFromDom(RenderCanvas canvas) {
canvas.htmlElement.remove();
void _removeFromDom(T canvas) {
canvas.hostElement.remove();
}

/// Signals that a canvas is no longer being used. It can be reused.
void releaseCanvas(RenderCanvas canvas) {
void releaseCanvas(T canvas) {
assert(canvas != baseCanvas, 'Attempting to release the base canvas');
assert(
_liveCanvases.contains(canvas),
'Attempting to release a Canvas which '
'was not created by this factory');
canvas.htmlElement.remove();
canvas.hostElement.remove();
_liveCanvases.remove(canvas);
_cache.add(canvas);
}
Expand All @@ -94,7 +107,7 @@ class RenderCanvasFactory {
///
/// If a canvas is not live, then it must be in the cache and ready to be
/// reused.
bool isLive(RenderCanvas canvas) {
bool isLive(T canvas) {
if (canvas == baseCanvas || _liveCanvases.contains(canvas)) {
return true;
}
Expand All @@ -104,10 +117,10 @@ class RenderCanvasFactory {

/// Dispose all canvases created by this factory.
void dispose() {
for (final RenderCanvas canvas in _cache) {
for (final T canvas in _cache) {
canvas.dispose();
}
for (final RenderCanvas canvas in _liveCanvases) {
for (final T canvas in _liveCanvases) {
canvas.dispose();
}
baseCanvas.dispose();
Expand Down
35 changes: 16 additions & 19 deletions lib/web_ui/lib/src/engine/canvaskit/embedded_views.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,13 @@ import 'path.dart';
import 'picture.dart';
import 'picture_recorder.dart';
import 'rasterizer.dart';
import 'render_canvas.dart';
import 'render_canvas_factory.dart';

/// This composites HTML views into the [ui.Scene].
class HtmlViewEmbedder {
HtmlViewEmbedder(this.sceneHost, this.rasterizer, this.renderCanvasFactory);
HtmlViewEmbedder(this.sceneHost, this.rasterizer);

final DomElement sceneHost;
final Rasterizer rasterizer;
final RenderCanvasFactory renderCanvasFactory;
final ViewRasterizer rasterizer;

/// The context for the current frame.
EmbedderFrameContext _context = EmbedderFrameContext();
Expand All @@ -53,7 +50,7 @@ class HtmlViewEmbedder {
static const int maximumOverlays = 7;

/// Canvases used to draw on top of platform views, keyed by platform view ID.
final Map<int, RenderCanvas> _overlays = <int, RenderCanvas>{};
final Map<int, DisplayCanvas> _overlays = <int, DisplayCanvas>{};

/// The views that need to be recomposited into the scene on the next frame.
final Set<int> _viewsToRecomposite = <int>{};
Expand Down Expand Up @@ -381,7 +378,7 @@ class HtmlViewEmbedder {

int pictureRecorderIndex = 0;
for (final OverlayGroup overlayGroup in _activeOverlayGroups) {
final RenderCanvas overlay = _overlays[overlayGroup.last]!;
final DisplayCanvas overlay = _overlays[overlayGroup.last]!;
final List<CkPicture> pictures = <CkPicture>[];
for (int i = 0; i < overlayGroup.visibleCount; i++) {
pictures.add(
Expand Down Expand Up @@ -441,17 +438,17 @@ class HtmlViewEmbedder {
if (diffResult.addToBeginning) {
final DomElement platformViewRoot = _viewClipChains[viewId]!.root;
sceneHost.insertBefore(platformViewRoot, elementToInsertBefore);
final RenderCanvas? overlay = _overlays[viewId];
final DisplayCanvas? overlay = _overlays[viewId];
if (overlay != null) {
sceneHost.insertBefore(
overlay.htmlElement, elementToInsertBefore);
overlay.hostElement, elementToInsertBefore);
}
} else {
final DomElement platformViewRoot = _viewClipChains[viewId]!.root;
sceneHost.append(platformViewRoot);
final RenderCanvas? overlay = _overlays[viewId];
final DisplayCanvas? overlay = _overlays[viewId];
if (overlay != null) {
sceneHost.append(overlay.htmlElement);
sceneHost.append(overlay.hostElement);
}
}
}
Expand All @@ -460,7 +457,7 @@ class HtmlViewEmbedder {
for (int i = 0; i < _compositionOrder.length; i++) {
final int view = _compositionOrder[i];
if (_overlays[view] != null) {
final DomElement overlayElement = _overlays[view]!.htmlElement;
final DomElement overlayElement = _overlays[view]!.hostElement;
if (!overlayElement.isConnected!) {
// This overlay wasn't added to the DOM.
if (i == _compositionOrder.length - 1) {
Expand All @@ -474,7 +471,7 @@ class HtmlViewEmbedder {
}
}
} else {
renderCanvasFactory.removeSurfacesFromDom();
rasterizer.removeOverlaysFromDom();
for (int i = 0; i < _compositionOrder.length; i++) {
final int viewId = _compositionOrder[i];

Expand All @@ -492,10 +489,10 @@ class HtmlViewEmbedder {
}

final DomElement platformViewRoot = _viewClipChains[viewId]!.root;
final RenderCanvas? overlay = _overlays[viewId];
final DisplayCanvas? overlay = _overlays[viewId];
sceneHost.append(platformViewRoot);
if (overlay != null) {
sceneHost.append(overlay.htmlElement);
sceneHost.append(overlay.hostElement);
}
_activeCompositionOrder.add(viewId);
unusedViews.remove(viewId);
Expand Down Expand Up @@ -528,8 +525,8 @@ class HtmlViewEmbedder {

void _releaseOverlay(int viewId) {
if (_overlays[viewId] != null) {
final RenderCanvas overlay = _overlays[viewId]!;
renderCanvasFactory.releaseCanvas(overlay);
final DisplayCanvas overlay = _overlays[viewId]!;
rasterizer.releaseOverlay(overlay);
_overlays.remove(viewId);
}
}
Expand Down Expand Up @@ -569,7 +566,7 @@ class HtmlViewEmbedder {
if (diffResult == null) {
// Everything is going to be explicitly recomposited anyway. Release all
// the surfaces and assign an overlay to all the surfaces needing one.
renderCanvasFactory.releaseCanvases();
rasterizer.releaseOverlays();
_overlays.clear();
viewsNeedingOverlays.forEach(_initializeOverlay);
} else {
Expand Down Expand Up @@ -639,7 +636,7 @@ class HtmlViewEmbedder {
assert(!_overlays.containsKey(viewId));

// Try reusing a cached overlay created for another platform view.
final RenderCanvas overlay = renderCanvasFactory.getCanvas();
final DisplayCanvas overlay = rasterizer.getOverlay();
_overlays[viewId] = overlay;
}

Expand Down
71 changes: 71 additions & 0 deletions lib/web_ui/lib/src/engine/canvaskit/multi_surface_rasterizer.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'package:ui/src/engine.dart';
import 'package:ui/ui.dart' as ui;

/// A Rasterizer which uses one or many on-screen WebGL contexts to display the
/// scene. This way of rendering is prone to bugs because there is a limit to
/// how many WebGL contexts can be live at one time as well as bugs in sharing
/// GL resources between the contexts. However, using [createImageBitmap] is
/// currently very slow on Firefox and Safari browsers, so directly rendering
/// to several [Surface]s is how we can achieve 60 fps on these browsers.
class MultiSurfaceRasterizer extends Rasterizer {
@override
MultiSurfaceViewRasterizer createViewRasterizer(EngineFlutterView view) {
return _viewRasterizers.putIfAbsent(
view, () => MultiSurfaceViewRasterizer(view, this));
}

final Map<EngineFlutterView, MultiSurfaceViewRasterizer> _viewRasterizers =
<EngineFlutterView, MultiSurfaceViewRasterizer>{};

@override
void dispose() {
for (final MultiSurfaceViewRasterizer viewRasterizer
in _viewRasterizers.values) {
viewRasterizer.dispose();
}
_viewRasterizers.clear();
}

@override
void setResourceCacheMaxBytes(int bytes) {
for (final MultiSurfaceViewRasterizer viewRasterizer
in _viewRasterizers.values) {
viewRasterizer.displayFactory.forEachCanvas((Surface surface) {
surface.setSkiaResourceCacheMaxBytes(bytes);
});
}
}
}

class MultiSurfaceViewRasterizer extends ViewRasterizer {
MultiSurfaceViewRasterizer(super.view, this.rasterizer);

final MultiSurfaceRasterizer rasterizer;

@override
final DisplayCanvasFactory<Surface> displayFactory =
DisplayCanvasFactory<Surface>(
createCanvas: () => Surface(isDisplayCanvas: true));

@override
void prepareToDraw() {
displayFactory.baseCanvas.createOrUpdateSurface(currentFrameSize);
}

@override
Future<void> rasterizeToCanvas(
DisplayCanvas canvas, List<CkPicture> pictures) {
final Surface surface = canvas as Surface;
surface.createOrUpdateSurface(currentFrameSize);
surface.positionToShowFrame(currentFrameSize);
final CkCanvas skCanvas = surface.getCanvas();
skCanvas.clear(const ui.Color(0x00000000));
pictures.forEach(skCanvas.drawPicture);
surface.flush();
return Future<void>.value();
}
}
Loading