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 7 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 @@ -5924,8 +5924,11 @@ 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/overlay_canvas_factory.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 @@ -5935,7 +5938,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,8 +8759,11 @@ 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/overlay_canvas_factory.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 @@ -8768,7 +8773,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 @@ -34,8 +34,11 @@ 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/overlay_canvas_factory.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
27 changes: 12 additions & 15 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, OverlayCanvas> _overlays = <int, OverlayCanvas>{};

/// 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 OverlayCanvas overlay = _overlays[overlayGroup.last]!;
final List<CkPicture> pictures = <CkPicture>[];
for (int i = 0; i < overlayGroup.visibleCount; i++) {
pictures.add(
Expand Down Expand Up @@ -441,15 +438,15 @@ class HtmlViewEmbedder {
if (diffResult.addToBeginning) {
final DomElement platformViewRoot = _viewClipChains[viewId]!.root;
sceneHost.insertBefore(platformViewRoot, elementToInsertBefore);
final RenderCanvas? overlay = _overlays[viewId];
final OverlayCanvas? overlay = _overlays[viewId];
if (overlay != null) {
sceneHost.insertBefore(
overlay.htmlElement, elementToInsertBefore);
}
} else {
final DomElement platformViewRoot = _viewClipChains[viewId]!.root;
sceneHost.append(platformViewRoot);
final RenderCanvas? overlay = _overlays[viewId];
final OverlayCanvas? overlay = _overlays[viewId];
if (overlay != null) {
sceneHost.append(overlay.htmlElement);
}
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,7 +489,7 @@ class HtmlViewEmbedder {
}

final DomElement platformViewRoot = _viewClipChains[viewId]!.root;
final RenderCanvas? overlay = _overlays[viewId];
final OverlayCanvas? overlay = _overlays[viewId];
sceneHost.append(platformViewRoot);
if (overlay != null) {
sceneHost.append(overlay.htmlElement);
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 OverlayCanvas 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 OverlayCanvas 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
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.overlayFactory.forEachCanvas((Surface surface) {
surface.setSkiaResourceCacheMaxBytes(bytes);
});
}
}
}

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

final MultiSurfaceRasterizer rasterizer;

@override
final OverlayCanvasFactory<Surface> overlayFactory =
OverlayCanvasFactory<Surface>(
createCanvas: () => Surface(isRenderCanvas: true));

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

@override
Future<void> rasterizeToCanvas(
OverlayCanvas 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();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// 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';

/// A [Rasterizer] that uses a single GL context in an OffscreenCanvas to do
/// all the rendering. It transers bitmaps created in the OffscreenCanvas to
/// one or many on-screen <canvas> elements to actually display the scene.
class OffscreenCanvasRasterizer extends Rasterizer {
/// 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();

@override
OffscreenCanvasViewRasterizer createViewRasterizer(EngineFlutterView view) {
return _viewRasterizers.putIfAbsent(
view, () => OffscreenCanvasViewRasterizer(view, this));
}

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

@override
void setResourceCacheMaxBytes(int bytes) {
offscreenSurface.setSkiaResourceCacheMaxBytes(bytes);
}

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

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

final OffscreenCanvasRasterizer rasterizer;

@override
final OverlayCanvasFactory<RenderCanvas> overlayFactory =
OverlayCanvasFactory<RenderCanvas>(createCanvas: () => RenderCanvas());

/// Render the given [pictures] so it is displayed by the given [canvas].
@override
Future<void> rasterizeToCanvas(
OverlayCanvas canvas, List<CkPicture> pictures) async {
await rasterizer.offscreenSurface.rasterizeToCanvas(
currentFrameSize,
canvas as RenderCanvas,
pictures,
);
}

@override
void prepareToDraw() {
rasterizer.offscreenSurface.createOrUpdateSurface(currentFrameSize);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,29 @@ import 'package:meta/meta.dart';
import '../../engine.dart';

/// Caches canvases used to overlay platform views.
class RenderCanvasFactory {
RenderCanvasFactory() {
class OverlayCanvasFactory<T extends OverlayCanvas> {
OverlayCanvasFactory({required this.createCanvas}) {
assert(() {
registerHotRestartListener(dispose);
return true;
}());
}

/// A function which is passed in as a constructor parameter which is used to
/// create new overlay 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 @@ -40,13 +44,14 @@ class RenderCanvasFactory {

/// Gets an overlay 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 @@ -69,15 +74,23 @@ class RenderCanvasFactory {
/// the new surfaces.
void removeSurfacesFromDom() {
_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) {
void _removeFromDom(T canvas) {
canvas.htmlElement.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),
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
Loading