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 5 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
2 changes: 2 additions & 0 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -43580,6 +43580,7 @@ ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/image_web_codecs.da
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/layer.dart + ../../../flutter/LICENSE
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/layer_visitor.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
Expand Down Expand Up @@ -46451,6 +46452,7 @@ FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/image_web_codecs.dart
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/layer_visitor.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
Expand Down
1 change: 1 addition & 0 deletions lib/web_ui/lib/src/engine.dart
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export 'engine/canvaskit/image_web_codecs.dart';
export 'engine/canvaskit/layer.dart';
export 'engine/canvaskit/layer_scene_builder.dart';
export 'engine/canvaskit/layer_tree.dart';
export 'engine/canvaskit/layer_visitor.dart';
export 'engine/canvaskit/mask_filter.dart';
export 'engine/canvaskit/multi_surface_rasterizer.dart';
export 'engine/canvaskit/n_way_canvas.dart';
Expand Down
4 changes: 4 additions & 0 deletions lib/web_ui/lib/src/engine/canvaskit/canvas.dart
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,10 @@ class CkCanvas {
skCanvas.translate(dx, dy);
}

bool quickReject(ui.Rect rect) {
return skCanvas.quickReject(toSkRect(rect));
}

Float32List getLocalToDevice() {
final List<dynamic> list = skCanvas.getLocalToDevice();
final Float32List matrix4 = Float32List(16);
Expand Down
4 changes: 4 additions & 0 deletions lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2626,6 +2626,10 @@ extension SkCanvasExtension on SkCanvas {
List<dynamic> getLocalToDevice() => _getLocalToDevice().toObjectShallow as
List<dynamic>;

@JS('quickReject')
external JSBoolean _quickReject(JSFloat32Array rect);
bool quickReject(Float32List rect) => _quickReject(rect.toJS).toDart;

external JSVoid drawPicture(SkPicture picture);

@JS('drawParagraph')
Expand Down
158 changes: 97 additions & 61 deletions lib/web_ui/lib/src/engine/canvaskit/embedded_views.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import '../svg.dart';
import '../util.dart';
import '../vector_math.dart';
import 'canvas.dart';
import 'layer.dart';
import 'overlay_scene_optimizer.dart';
import 'painting.dart';
import 'path.dart';
Expand Down Expand Up @@ -66,6 +67,9 @@ class HtmlViewEmbedder {
/// Returns the most recent rendering. Only used in tests.
Rendering get debugActiveRendering => _activeRendering;

/// If [debugOverlayOptimizationBounds] is true, this canvas will draw
/// semitransparent rectangles showing the computed bounds of the platform
/// views and pictures in the scene.
DisplayCanvas? debugBoundsCanvas;

/// The size of the frame, in physical pixels.
Expand All @@ -75,27 +79,14 @@ class HtmlViewEmbedder {
_frameSize = size;
}

/// Returns a list of canvases which will be overlaid on top of the "base"
/// canvas after a platform view is composited into the scene.
///
/// The engine asks for the overlay canvases immediately before the paint
/// phase, after the preroll phase. In the preroll phase we must be
/// conservative and assume that every platform view which is prerolled is
/// also composited, and therefore requires an overlay canvas. However, not
/// every platform view which is prerolled ends up being composited (it may be
/// clipped out and not actually drawn). This means that we may end up
/// overallocating canvases. This isn't a problem in practice, however, as
/// unused recording canvases are simply deleted at the end of the frame.
Iterable<CkCanvas> getOverlayCanvases() {
return _context.pictureRecordersCreatedDuringPreroll
/// Returns a list of canvases for the optimized rendering. These are used in
/// the paint step.
Iterable<CkCanvas> getOptimizedCanvases() {
return _context.optimizedCanvasRecorders!
.map((CkPictureRecorder r) => r.recordingCanvas!);
}

void prerollCompositeEmbeddedView(int viewId, EmbeddedViewParams params) {
final CkPictureRecorder pictureRecorder = CkPictureRecorder();
pictureRecorder.beginRecording(ui.Offset.zero & _frameSize.toSize());
_context.pictureRecordersCreatedDuringPreroll.add(pictureRecorder);

// Do nothing if the params didn't change.
if (_currentCompositionParams[viewId] == params) {
// If the view was prerolled but not composited, then it needs to be
Expand All @@ -109,30 +100,24 @@ class HtmlViewEmbedder {
_viewsToRecomposite.add(viewId);
}

/// Adds the picture recorder associated with [picture] to the unoptimized
/// scene.
void addPictureToUnoptimizedScene(PictureLayer picture) {
_context.sceneElements.add(PictureSceneElement(picture));
}

/// Prepares to composite [viewId].
///
/// If this returns a [CkCanvas], then that canvas should be the new leaf
/// node. Otherwise, keep the same leaf node.
CkCanvas? compositeEmbeddedView(int viewId) {
void compositeEmbeddedView(int viewId) {
// Ensure platform view with `viewId` is injected into the `rasterizer.view`.
rasterizer.view.dom.injectPlatformView(viewId);

final int overlayIndex = _context.viewCount;
_compositionOrder.add(viewId);
_context.viewCount++;

CkPictureRecorder? recorderToUseForRendering;
if (overlayIndex < _context.pictureRecordersCreatedDuringPreroll.length) {
recorderToUseForRendering =
_context.pictureRecordersCreatedDuringPreroll[overlayIndex];
_context.pictureRecorders.add(recorderToUseForRendering);
}
_context.sceneElements.add(PlatformViewSceneElement(viewId));

if (_viewsToRecomposite.contains(viewId)) {
_compositeWithParams(viewId, _currentCompositionParams[viewId]!);
_viewsToRecomposite.remove(viewId);
}
return recorderToUseForRendering?.recordingCanvas;
}

void _compositeWithParams(int platformViewId, EmbeddedViewParams params) {
Expand Down Expand Up @@ -355,14 +340,41 @@ class HtmlViewEmbedder {
sceneHost.append(_svgPathDefs!);
}

Future<void> submitFrame(CkPicture basePicture) async {
final List<CkPicture> pictures = <CkPicture>[basePicture];
for (final CkPictureRecorder recorder in _context.pictureRecorders) {
pictures.add(recorder.endRecording());
}
/// Optimizes the scene to use the fewest possible canvases. This sets up
/// the final paint pass to paint the pictures into the optimized canvases.
void optimizeRendering() {
Rendering rendering = createOptimizedRendering(
pictures, _compositionOrder, _currentCompositionParams);
_context.sceneElements, _currentCompositionParams);
rendering = _modifyRenderingForMaxCanvases(rendering);
_context.optimizedRendering = rendering;
// Create new picture recorders for the optimized render canvases and record
// which pictures go in which canvas.
final List<CkPictureRecorder> optimizedCanvasRecorders =
<CkPictureRecorder>[];
final Map<PictureLayer, CkPictureRecorder> pictureToOptimizedCanvasMap =
<PictureLayer, CkPictureRecorder>{};
for (final RenderingRenderCanvas renderCanvas in rendering.canvases) {
final CkPictureRecorder pictureRecorder = CkPictureRecorder();
pictureRecorder.beginRecording(ui.Offset.zero & _frameSize.toSize());
optimizedCanvasRecorders.add(pictureRecorder);
for (final PictureLayer picture in renderCanvas.pictures) {
pictureToOptimizedCanvasMap[picture] =
pictureRecorder;
}
}
_context.optimizedCanvasRecorders = optimizedCanvasRecorders;
_context.pictureToOptimizedCanvasMap = pictureToOptimizedCanvasMap;
}

/// Returns the canvas that this picture layer should draw into in the
/// optimized scene.
CkCanvas getOptimizedCanvasFor(PictureLayer picture) {
assert(_context.optimizedRendering != null);
return _context.pictureToOptimizedCanvasMap![picture]!.recordingCanvas!;
}

Future<void> submitFrame() async {
final Rendering rendering = _context.optimizedRendering!;
_updateDomForNewRendering(rendering);
if (rendering.equalsForRendering(_activeRendering)) {
// Copy the display canvases to the new rendering.
Expand All @@ -375,13 +387,17 @@ class HtmlViewEmbedder {
_activeRendering = rendering;

final List<RenderingRenderCanvas> renderCanvases = rendering.canvases;
int renderCanvasIndex = 0;
for (final RenderingRenderCanvas renderCanvas in renderCanvases) {
final CkPicture renderPicture = _context
.optimizedCanvasRecorders![renderCanvasIndex++]
.endRecording();
await rasterizer.rasterizeToCanvas(
renderCanvas.displayCanvas!, renderCanvas.pictures);
renderCanvas.displayCanvas!, <CkPicture>[renderPicture]);
}

for (final CkPictureRecorder recorder
in _context.pictureRecordersCreatedDuringPreroll) {
in _context.measuringPictureRecorders.values) {
if (recorder.isRecording) {
recorder.endRecording();
}
Expand All @@ -393,11 +409,11 @@ class HtmlViewEmbedder {
debugBoundsCanvas ??= rasterizer.displayFactory.getCanvas();
final CkPictureRecorder boundsRecorder = CkPictureRecorder();
final CkCanvas boundsCanvas = boundsRecorder.beginRecording(
ui.Rect.fromLTWH(
0,
0,
_frameSize.width.toDouble(),
_frameSize.height.toDouble(),
ui.Rect.fromLTWH(
0,
0,
_frameSize.width.toDouble(),
_frameSize.height.toDouble(),
),
);
final CkPaint platformViewBoundsPaint = CkPaint()
Expand All @@ -411,8 +427,8 @@ class HtmlViewEmbedder {
entity.debugComputedBounds!, platformViewBoundsPaint);
}
} else if (entity is RenderingRenderCanvas) {
for (final CkPicture picture in entity.pictures) {
boundsCanvas.drawRect(picture.cullRect, pictureBoundsPaint);
for (final PictureLayer picture in entity.pictures) {
boundsCanvas.drawRect(picture.sceneBounds!, pictureBoundsPaint);
}
}
}
Expand Down Expand Up @@ -483,7 +499,7 @@ class HtmlViewEmbedder {
return rendering;
}
int numCanvasesToDelete = numCanvases - maximumCanvases;
final List<CkPicture> picturesForLastCanvas = <CkPicture>[];
final List<PictureLayer> picturesForLastCanvas = <PictureLayer>[];
final List<RenderingEntity> modifiedEntities =
List<RenderingEntity>.from(rendering.entities);
bool sawLastCanvas = false;
Expand Down Expand Up @@ -903,20 +919,40 @@ class MutatorsStack extends Iterable<Mutator> {
Iterable<Mutator> get reversed => _mutators;
}

/// The state for the current frame.
class EmbedderFrameContext {
/// Picture recorders which were created during the preroll phase.
///
/// These picture recorders will be "claimed" in the paint phase by platform
/// views being composited into the scene.
final List<CkPictureRecorder> pictureRecordersCreatedDuringPreroll =
<CkPictureRecorder>[];
sealed class SceneElement {}

/// Picture recorders which were actually used in the paint phase.
///
/// This is a subset of [_pictureRecordersCreatedDuringPreroll].
final List<CkPictureRecorder> pictureRecorders = <CkPictureRecorder>[];
class PictureSceneElement extends SceneElement {
PictureSceneElement(this.picture);

final PictureLayer picture;
}

class PlatformViewSceneElement extends SceneElement {
PlatformViewSceneElement(this.viewId);

final int viewId;
}

/// The number of platform views in this frame.
int viewCount = 0;
/// The state for the current frame.
class EmbedderFrameContext {
/// Picture recorders which were created d the final bounds of the picture in the scene.
final Map<PictureLayer, CkPictureRecorder> measuringPictureRecorders =
<PictureLayer, CkPictureRecorder>{};

/// List of picture recorders and platform view ids in the order they were
/// painted.
final List<SceneElement> sceneElements = <SceneElement>[];

/// The optimized rendering for this frame. This is set by calling
/// [optimizeRendering].
Rendering? optimizedRendering;

/// The picture recorders for the optimized rendering. This is set by calling
/// [optimizeRendering].
List<CkPictureRecorder>? optimizedCanvasRecorders;

/// A map from the original PictureLayer to the picture recorder it should go
/// into in the optimized rendering. This is set by calling
/// [optimizedRendering].
Map<PictureLayer, CkPictureRecorder>? pictureToOptimizedCanvasMap;
}
Loading