| // 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/ui.dart' as ui; |
| |
| import '../../engine.dart' show kProfilePrerollFrame, kProfileApplyFrame; |
| import '../profiler.dart'; |
| import '../vector_math.dart'; |
| import 'canvas.dart'; |
| import 'embedded_views.dart'; |
| import 'layer.dart'; |
| import 'n_way_canvas.dart'; |
| import 'picture_recorder.dart'; |
| import 'raster_cache.dart'; |
| |
| /// A tree of [Layer]s that, together with a [Size] compose a frame. |
| class LayerTree { |
| LayerTree(this.rootLayer); |
| |
| /// The root of the layer tree. |
| final RootLayer rootLayer; |
| |
| /// The size (in physical pixels) of the frame to paint this layer tree into. |
| final ui.Size frameSize = ui.window.physicalSize; |
| |
| /// The devicePixelRatio of the frame to paint this layer tree into. |
| double? devicePixelRatio; |
| |
| /// Performs a preroll phase before painting the layer tree. |
| /// |
| /// In this phase, the paint boundary for each layer is computed and |
| /// pictures are registered with the raster cache as potential candidates |
| /// to raster. If [ignoreRasterCache] is `true`, then there will be no |
| /// attempt to register pictures to cache. |
| void preroll(Frame frame, {bool ignoreRasterCache = false}) { |
| final PrerollContext context = PrerollContext( |
| ignoreRasterCache ? null : frame.rasterCache, |
| frame.viewEmbedder, |
| ); |
| rootLayer.preroll(context, Matrix4.identity()); |
| } |
| |
| /// Paints the layer tree into the given [frame]. |
| /// |
| /// If [ignoreRasterCache] is `true`, then the raster cache will |
| /// not be used. |
| void paint(Frame frame, {bool ignoreRasterCache = false}) { |
| final CkNWayCanvas internalNodesCanvas = CkNWayCanvas(); |
| internalNodesCanvas.addCanvas(frame.canvas); |
| final List<CkCanvas> overlayCanvases = |
| frame.viewEmbedder!.getCurrentCanvases(); |
| for (int i = 0; i < overlayCanvases.length; i++) { |
| internalNodesCanvas.addCanvas(overlayCanvases[i]); |
| } |
| // Clear the canvases before painting |
| internalNodesCanvas.clear(const ui.Color(0x00000000)); |
| final PaintContext context = PaintContext( |
| internalNodesCanvas, |
| frame.canvas, |
| ignoreRasterCache ? null : frame.rasterCache, |
| frame.viewEmbedder, |
| ); |
| if (rootLayer.needsPainting) { |
| rootLayer.paint(context); |
| } |
| } |
| |
| /// Flattens the tree into a single [ui.Picture]. |
| /// |
| /// This picture does not contain any platform views. |
| ui.Picture flatten() { |
| final CkPictureRecorder recorder = CkPictureRecorder(); |
| final CkCanvas canvas = recorder.beginRecording(ui.Rect.largest); |
| final PrerollContext prerollContext = PrerollContext(null, null); |
| rootLayer.preroll(prerollContext, Matrix4.identity()); |
| |
| final CkNWayCanvas internalNodesCanvas = CkNWayCanvas(); |
| internalNodesCanvas.addCanvas(canvas); |
| final PaintContext paintContext = |
| PaintContext(internalNodesCanvas, canvas, null, null); |
| if (rootLayer.needsPainting) { |
| rootLayer.paint(paintContext); |
| } |
| return recorder.endRecording(); |
| } |
| } |
| |
| /// A single frame to be rendered. |
| class Frame { |
| /// The canvas to render this frame to. |
| final CkCanvas canvas; |
| |
| /// A cache of pre-rastered pictures. |
| final RasterCache? rasterCache; |
| |
| /// The platform view embedder. |
| final HtmlViewEmbedder? viewEmbedder; |
| |
| Frame(this.canvas, this.rasterCache, this.viewEmbedder); |
| |
| /// Rasterize the given layer tree into this frame. |
| bool raster(LayerTree layerTree, {bool ignoreRasterCache = false}) { |
| timeAction<void>(kProfilePrerollFrame, () { |
| layerTree.preroll(this, ignoreRasterCache: ignoreRasterCache); |
| }); |
| timeAction<void>(kProfileApplyFrame, () { |
| layerTree.paint(this, ignoreRasterCache: ignoreRasterCache); |
| }); |
| return true; |
| } |
| } |
| |
| /// The state of the compositor, which is persisted between frames. |
| class CompositorContext { |
| /// A cache of pictures, which is shared between successive frames. |
| RasterCache? rasterCache; |
| |
| /// Acquire a frame using this compositor's settings. |
| Frame acquireFrame(CkCanvas canvas, HtmlViewEmbedder? viewEmbedder) { |
| return Frame(canvas, rasterCache, viewEmbedder); |
| } |
| } |