blob: 58a23e871cc9224d23024e30a4135813b8d77525 [file] [log] [blame]
// 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;
abstract class Rasterizer {
/// Creates a [ViewRasterizer] for a given [view].
ViewRasterizer createViewRasterizer(EngineFlutterView view);
/// Sets the maximum size of the resource cache to [bytes].
void setResourceCacheMaxBytes(int bytes);
/// Disposes this rasterizer and all [ViewRasterizer]s that it created.
void dispose();
}
abstract class ViewRasterizer {
ViewRasterizer(this.view);
/// The view this rasterizer renders into.
final EngineFlutterView view;
/// The queue of render requests for this view.
final RenderQueue queue = RenderQueue();
/// The size of the current frame being rasterized.
ui.Size currentFrameSize = ui.Size.zero;
/// The context which is persisted between frames.
final CompositorContext context = CompositorContext();
/// The platform view embedder.
late final HtmlViewEmbedder viewEmbedder = HtmlViewEmbedder(sceneHost, this);
/// A factory for creating overlays.
DisplayCanvasFactory<DisplayCanvas> get displayFactory;
/// The scene host which this rasterizer should raster into.
DomElement get sceneHost => view.dom.sceneHost;
/// Draws the [layerTree] to the screen for the view associated with this
/// rasterizer.
Future<void> draw(LayerTree layerTree) async {
final ui.Size frameSize = view.physicalSize;
if (frameSize.isEmpty) {
// Available drawing area is empty. Skip drawing.
return;
}
currentFrameSize = frameSize;
prepareToDraw();
viewEmbedder.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!, viewEmbedder);
compositorFrame.raster(layerTree, ignoreRasterCache: true);
sceneHost.prepend(displayFactory.baseCanvas.hostElement);
await rasterizeToCanvas(
displayFactory.baseCanvas, <CkPicture>[pictureRecorder.endRecording()]);
await viewEmbedder.submitFrame();
}
/// Do some initialization to prepare to draw a frame.
///
/// For example, in the [OffscreenCanvasRasterizer], this ensures the backing
/// [OffscreenCanvas] is the correct size to draw the frame.
void prepareToDraw();
/// Rasterize the [pictures] to the given [canvas].
Future<void> rasterizeToCanvas(
DisplayCanvas canvas, List<CkPicture> pictures);
/// Get a [DisplayCanvas] to use as an overlay.
DisplayCanvas getOverlay() {
return displayFactory.getCanvas();
}
/// Release the given [overlay] so it may be reused.
void releaseOverlay(DisplayCanvas overlay) {
displayFactory.releaseCanvas(overlay);
}
/// Release all overlays.
void releaseOverlays() {
displayFactory.releaseCanvases();
}
/// Remove all overlays that have been created from the DOM.
void removeOverlaysFromDom() {
displayFactory.removeCanvasesFromDom();
}
/// Disposes this rasterizer.
void dispose() {
viewEmbedder.dispose();
displayFactory.dispose();
}
}
/// A [DisplayCanvas] is an abstraction for a canvas element which displays
/// Skia-drawn pictures to the screen. They are also sometimes called "overlays"
/// because they can be overlaid on top of platform views, which are HTML
/// content that isn't rendered by Skia.
///
/// [DisplayCanvas]es are drawn into with [ViewRasterizer.rasterizeToCanvas].
abstract class DisplayCanvas {
/// The DOM element which, when appended to the scene host, will display the
/// Skia-rendered content to the screen.
DomElement get hostElement;
/// Whether or not this overlay canvas is attached to the DOM.
bool get isConnected;
/// Initialize the overlay.
void initialize();
/// Disposes this overlay.
void dispose();
}
/// Encapsulates a request to render a [ui.Scene]. Contains the scene to render
/// and a [Completer] which completes when the scene has been rendered.
typedef RenderRequest = ({
ui.Scene scene,
Completer<void> completer,
});
/// A per-view queue of render requests. Only contains the current render
/// request and the next render request. If a new render request is made before
/// the current request is complete, then the next render request is replaced
/// with the most recently requested render and the other one is dropped.
class RenderQueue {
RenderQueue();
RenderRequest? current;
RenderRequest? next;
}