@@ -14,6 +14,7 @@ import '../svg.dart';
14
14
import '../util.dart' ;
15
15
import '../vector_math.dart' ;
16
16
import 'canvas.dart' ;
17
+ import 'layer.dart' ;
17
18
import 'overlay_scene_optimizer.dart' ;
18
19
import 'painting.dart' ;
19
20
import 'path.dart' ;
@@ -66,6 +67,9 @@ class HtmlViewEmbedder {
66
67
/// Returns the most recent rendering. Only used in tests.
67
68
Rendering get debugActiveRendering => _activeRendering;
68
69
70
+ /// If [debugOverlayOptimizationBounds] is true, this canvas will draw
71
+ /// semitransparent rectangles showing the computed bounds of the platform
72
+ /// views and pictures in the scene.
69
73
DisplayCanvas ? debugBoundsCanvas;
70
74
71
75
/// The size of the frame, in physical pixels.
@@ -75,27 +79,23 @@ class HtmlViewEmbedder {
75
79
_frameSize = size;
76
80
}
77
81
78
- /// Returns a list of canvases which will be overlaid on top of the "base"
79
- /// canvas after a platform view is composited into the scene.
80
- ///
81
- /// The engine asks for the overlay canvases immediately before the paint
82
- /// phase, after the preroll phase. In the preroll phase we must be
83
- /// conservative and assume that every platform view which is prerolled is
84
- /// also composited, and therefore requires an overlay canvas. However, not
85
- /// every platform view which is prerolled ends up being composited (it may be
86
- /// clipped out and not actually drawn). This means that we may end up
87
- /// overallocating canvases. This isn't a problem in practice, however, as
88
- /// unused recording canvases are simply deleted at the end of the frame.
89
- Iterable <CkCanvas > getOverlayCanvases () {
90
- return _context.pictureRecordersCreatedDuringPreroll
82
+ /// Returns a list of recording canvases which the pictures in the upcoming
83
+ /// paint step will be drawn into. These recording canvases are combined into
84
+ /// an N-way canvas for the rasterizer to record clip and transform operations
85
+ /// during the measure step.
86
+ Iterable <CkCanvas > getPictureCanvases () {
87
+ return _context.measuringPictureRecorders.values
91
88
.map ((CkPictureRecorder r) => r.recordingCanvas! );
92
89
}
93
90
94
- void prerollCompositeEmbeddedView (int viewId, EmbeddedViewParams params) {
95
- final CkPictureRecorder pictureRecorder = CkPictureRecorder ();
96
- pictureRecorder.beginRecording (ui.Offset .zero & _frameSize.toSize ());
97
- _context.pictureRecordersCreatedDuringPreroll.add (pictureRecorder);
91
+ /// Returns a list of canvases for the optimized rendering. These are used in
92
+ /// the paint step.
93
+ Iterable <CkCanvas > getOptimizedCanvases () {
94
+ return _context.optimizedCanvasRecorders!
95
+ .map ((CkPictureRecorder r) => r.recordingCanvas! );
96
+ }
98
97
98
+ void prerollCompositeEmbeddedView (int viewId, EmbeddedViewParams params) {
99
99
// Do nothing if the params didn't change.
100
100
if (_currentCompositionParams[viewId] == params) {
101
101
// If the view was prerolled but not composited, then it needs to be
@@ -109,30 +109,38 @@ class HtmlViewEmbedder {
109
109
_viewsToRecomposite.add (viewId);
110
110
}
111
111
112
+ /// Record that a picture recorder is needed for [picture] to be measured.
113
+ void prerollPicture (PictureLayer picture) {
114
+ final CkPictureRecorder pictureRecorder = CkPictureRecorder ();
115
+ pictureRecorder.beginRecording (ui.Offset .zero & _frameSize.toSize ());
116
+ _context.measuringPictureRecorders[picture] = pictureRecorder;
117
+ }
118
+
119
+ /// Returns the canvas that was created to measure [picture] .
120
+ CkCanvas getMeasuringCanvasFor (PictureLayer picture) {
121
+ return _context.measuringPictureRecorders[picture]! .recordingCanvas! ;
122
+ }
123
+
124
+ /// Adds the picture recorder associated with [picture] to the unoptimized
125
+ /// scene.
126
+ void addPictureToUnoptimizedScene (PictureLayer picture) {
127
+ final CkPictureRecorder recorder =
128
+ _context.measuringPictureRecorders[picture]! ;
129
+ _context.sceneElements.add (PictureSceneElement (picture, recorder));
130
+ }
131
+
112
132
/// Prepares to composite [viewId] .
113
- ///
114
- /// If this returns a [CkCanvas] , then that canvas should be the new leaf
115
- /// node. Otherwise, keep the same leaf node.
116
- CkCanvas ? compositeEmbeddedView (int viewId) {
133
+ void compositeEmbeddedView (int viewId) {
117
134
// Ensure platform view with `viewId` is injected into the `rasterizer.view`.
118
135
rasterizer.view.dom.injectPlatformView (viewId);
119
136
120
- final int overlayIndex = _context.viewCount;
121
137
_compositionOrder.add (viewId);
122
- _context.viewCount++ ;
123
-
124
- CkPictureRecorder ? recorderToUseForRendering;
125
- if (overlayIndex < _context.pictureRecordersCreatedDuringPreroll.length) {
126
- recorderToUseForRendering =
127
- _context.pictureRecordersCreatedDuringPreroll[overlayIndex];
128
- _context.pictureRecorders.add (recorderToUseForRendering);
129
- }
138
+ _context.sceneElements.add (PlatformViewSceneElement (viewId));
130
139
131
140
if (_viewsToRecomposite.contains (viewId)) {
132
141
_compositeWithParams (viewId, _currentCompositionParams[viewId]! );
133
142
_viewsToRecomposite.remove (viewId);
134
143
}
135
- return recorderToUseForRendering? .recordingCanvas;
136
144
}
137
145
138
146
void _compositeWithParams (int platformViewId, EmbeddedViewParams params) {
@@ -355,14 +363,57 @@ class HtmlViewEmbedder {
355
363
sceneHost.append (_svgPathDefs! );
356
364
}
357
365
358
- Future <void > submitFrame (CkPicture basePicture) async {
359
- final List <CkPicture > pictures = < CkPicture > [basePicture];
360
- for (final CkPictureRecorder recorder in _context.pictureRecorders) {
361
- pictures.add (recorder.endRecording ());
362
- }
366
+ /// Optimizes the scene to use the fewest possible canvases. This sets up
367
+ /// the final paint pass to paint the pictures into the optimized canvases.
368
+ void optimizeRendering () {
369
+ final Map <CkPicture , PictureLayer > scenePictureToRawPicture =
370
+ < CkPicture , PictureLayer > {};
371
+ final Iterable <SceneElement > unoptimizedRendering =
372
+ _context.sceneElements.map <SceneElement >((SceneElement element) {
373
+ if (element is PictureSceneElement ) {
374
+ final CkPicture scenePicture = element.pictureRecorder.endRecording ();
375
+ if (scenePicture.cullRect.isEmpty) {
376
+ element.picture.isCulled = true ;
377
+ }
378
+ element.scenePicture = scenePicture;
379
+ scenePictureToRawPicture[scenePicture] = element.picture;
380
+ return element;
381
+ } else {
382
+ return element;
383
+ }
384
+ });
363
385
Rendering rendering = createOptimizedRendering (
364
- pictures, _compositionOrder , _currentCompositionParams);
386
+ unoptimizedRendering , _currentCompositionParams);
365
387
rendering = _modifyRenderingForMaxCanvases (rendering);
388
+ _context.optimizedRendering = rendering;
389
+ // Create new picture recorders for the optimized render canvases and record
390
+ // which pictures go in which canvas.
391
+ final List <CkPictureRecorder > optimizedCanvasRecorders =
392
+ < CkPictureRecorder > [];
393
+ final Map <PictureLayer , CkPictureRecorder > pictureToOptimizedCanvasMap =
394
+ < PictureLayer , CkPictureRecorder > {};
395
+ for (final RenderingRenderCanvas renderCanvas in rendering.canvases) {
396
+ final CkPictureRecorder pictureRecorder = CkPictureRecorder ();
397
+ pictureRecorder.beginRecording (ui.Offset .zero & _frameSize.toSize ());
398
+ optimizedCanvasRecorders.add (pictureRecorder);
399
+ for (final CkPicture picture in renderCanvas.pictures) {
400
+ pictureToOptimizedCanvasMap[scenePictureToRawPicture[picture]! ] =
401
+ pictureRecorder;
402
+ }
403
+ }
404
+ _context.optimizedCanvasRecorders = optimizedCanvasRecorders;
405
+ _context.pictureToOptimizedCanvasMap = pictureToOptimizedCanvasMap;
406
+ }
407
+
408
+ /// Returns the canvas that this picture layer should draw into in the
409
+ /// optimized scene.
410
+ CkCanvas getOptimizedCanvasFor (PictureLayer picture) {
411
+ assert (_context.optimizedRendering != null );
412
+ return _context.pictureToOptimizedCanvasMap! [picture]! .recordingCanvas! ;
413
+ }
414
+
415
+ Future <void > submitFrame () async {
416
+ final Rendering rendering = _context.optimizedRendering! ;
366
417
_updateDomForNewRendering (rendering);
367
418
if (rendering.equalsForRendering (_activeRendering)) {
368
419
// Copy the display canvases to the new rendering.
@@ -375,13 +426,17 @@ class HtmlViewEmbedder {
375
426
_activeRendering = rendering;
376
427
377
428
final List <RenderingRenderCanvas > renderCanvases = rendering.canvases;
429
+ int renderCanvasIndex = 0 ;
378
430
for (final RenderingRenderCanvas renderCanvas in renderCanvases) {
431
+ final CkPicture renderPicture = _context
432
+ .optimizedCanvasRecorders! [renderCanvasIndex++ ]
433
+ .endRecording ();
379
434
await rasterizer.rasterizeToCanvas (
380
- renderCanvas.displayCanvas! , renderCanvas.pictures );
435
+ renderCanvas.displayCanvas! , < CkPicture > [renderPicture] );
381
436
}
382
437
383
438
for (final CkPictureRecorder recorder
384
- in _context.pictureRecordersCreatedDuringPreroll ) {
439
+ in _context.measuringPictureRecorders.values ) {
385
440
if (recorder.isRecording) {
386
441
recorder.endRecording ();
387
442
}
@@ -393,11 +448,11 @@ class HtmlViewEmbedder {
393
448
debugBoundsCanvas ?? = rasterizer.displayFactory.getCanvas ();
394
449
final CkPictureRecorder boundsRecorder = CkPictureRecorder ();
395
450
final CkCanvas boundsCanvas = boundsRecorder.beginRecording (
396
- ui.Rect .fromLTWH (
397
- 0 ,
398
- 0 ,
399
- _frameSize.width.toDouble (),
400
- _frameSize.height.toDouble (),
451
+ ui.Rect .fromLTWH (
452
+ 0 ,
453
+ 0 ,
454
+ _frameSize.width.toDouble (),
455
+ _frameSize.height.toDouble (),
401
456
),
402
457
);
403
458
final CkPaint platformViewBoundsPaint = CkPaint ()
@@ -903,20 +958,45 @@ class MutatorsStack extends Iterable<Mutator> {
903
958
Iterable <Mutator > get reversed => _mutators;
904
959
}
905
960
906
- /// The state for the current frame.
907
- class EmbedderFrameContext {
908
- /// Picture recorders which were created during the preroll phase.
909
- ///
910
- /// These picture recorders will be "claimed" in the paint phase by platform
911
- /// views being composited into the scene.
912
- final List <CkPictureRecorder > pictureRecordersCreatedDuringPreroll =
913
- < CkPictureRecorder > [];
961
+ sealed class SceneElement {}
914
962
915
- /// Picture recorders which were actually used in the paint phase.
916
- ///
917
- /// This is a subset of [_pictureRecordersCreatedDuringPreroll] .
918
- final List <CkPictureRecorder > pictureRecorders = < CkPictureRecorder > [];
963
+ class PictureSceneElement extends SceneElement {
964
+ PictureSceneElement (this .picture, this .pictureRecorder);
965
+
966
+ final PictureLayer picture;
967
+ final CkPictureRecorder pictureRecorder;
968
+
969
+ /// The picture as it would be painted in the final scene, with clips and
970
+ /// transforms applied. This is set by [optimizeRendering] .
971
+ CkPicture ? scenePicture;
972
+ }
919
973
920
- /// The number of platform views in this frame.
921
- int viewCount = 0 ;
974
+ class PlatformViewSceneElement extends SceneElement {
975
+ PlatformViewSceneElement (this .viewId);
976
+
977
+ final int viewId;
978
+ }
979
+
980
+ /// The state for the current frame.
981
+ class EmbedderFrameContext {
982
+ /// Picture recorders which were created d the final bounds of the picture in the scene.
983
+ final Map <PictureLayer , CkPictureRecorder > measuringPictureRecorders =
984
+ < PictureLayer , CkPictureRecorder > {};
985
+
986
+ /// List of picture recorders and platform view ids in the order they were
987
+ /// painted.
988
+ final List <SceneElement > sceneElements = < SceneElement > [];
989
+
990
+ /// The optimized rendering for this frame. This is set by calling
991
+ /// [optimizeRendering] .
992
+ Rendering ? optimizedRendering;
993
+
994
+ /// The picture recorders for the optimized rendering. This is set by calling
995
+ /// [optimizeRendering] .
996
+ List <CkPictureRecorder >? optimizedCanvasRecorders;
997
+
998
+ /// A map from the original PictureLayer to the picture recorder it should go
999
+ /// into in the optimized rendering. This is set by calling
1000
+ /// [optimizedRendering] .
1001
+ Map <PictureLayer , CkPictureRecorder >? pictureToOptimizedCanvasMap;
922
1002
}
0 commit comments