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
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