Skip to content

Commit 454a34f

Browse files
authored
[canvaskit] support adding leaf layers w/o container layers (#24357)
1 parent 0d4accf commit 454a34f

File tree

5 files changed

+48
-40
lines changed

5 files changed

+48
-40
lines changed

lib/web_ui/lib/src/engine/canvaskit/layer.dart

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,17 @@ abstract class ContainerLayer extends Layer {
117117
}
118118
}
119119

120+
/// The top-most layer in the layer tree.
121+
///
122+
/// This layer does not draw anything. It's only used so we can add leaf layers
123+
/// to [LayerSceneBuilder] without requiring a [ContainerLayer].
124+
class RootLayer extends ContainerLayer {
125+
@override
126+
void paint(PaintContext context) {
127+
paintChildren(context);
128+
}
129+
}
130+
120131
class BackdropFilterEngineLayer extends ContainerLayer implements ui.BackdropFilterEngineLayer {
121132
final ui.ImageFilter _filter;
122133

lib/web_ui/lib/src/engine/canvaskit/layer_scene_builder.dart

Lines changed: 14 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,7 @@ part of engine;
88
class LayerScene implements ui.Scene {
99
final LayerTree layerTree;
1010

11-
LayerScene(Layer? rootLayer) : layerTree = LayerTree() {
12-
layerTree.rootLayer = rootLayer;
13-
}
11+
LayerScene(RootLayer rootLayer) : layerTree = LayerTree(rootLayer);
1412

1513
@override
1614
void dispose() {}
@@ -23,8 +21,12 @@ class LayerScene implements ui.Scene {
2321
}
2422

2523
class LayerSceneBuilder implements ui.SceneBuilder {
26-
Layer? rootLayer;
27-
ContainerLayer? currentLayer;
24+
LayerSceneBuilder() : rootLayer = RootLayer() {
25+
currentLayer = rootLayer;
26+
}
27+
28+
final RootLayer rootLayer;
29+
late ContainerLayer currentLayer;
2830

2931
@override
3032
void addChildScene({
@@ -50,16 +52,13 @@ class LayerSceneBuilder implements ui.SceneBuilder {
5052
bool isComplexHint = false,
5153
bool willChangeHint = false,
5254
}) {
53-
currentLayer!.add(PictureLayer(
55+
currentLayer.add(PictureLayer(
5456
picture as CkPicture, offset, isComplexHint, willChangeHint));
5557
}
5658

5759
@override
5860
void addRetained(ui.EngineLayer retainedLayer) {
59-
if (currentLayer == null) {
60-
return;
61-
}
62-
currentLayer!.add(retainedLayer as Layer);
61+
currentLayer.add(retainedLayer as Layer);
6362
}
6463

6564
@override
@@ -82,7 +81,7 @@ class LayerSceneBuilder implements ui.SceneBuilder {
8281
double height = 0.0,
8382
Object? webOnlyPaintedBy,
8483
}) {
85-
currentLayer!.add(PlatformViewLayer(viewId, offset, width, height));
84+
currentLayer.add(PlatformViewLayer(viewId, offset, width, height));
8685
}
8786

8887
@override
@@ -92,10 +91,11 @@ class LayerSceneBuilder implements ui.SceneBuilder {
9291

9392
@override
9493
void pop() {
95-
if (currentLayer == null) {
94+
if (currentLayer == rootLayer) {
95+
// Don't pop the root layer. It must always be there.
9696
return;
9797
}
98-
currentLayer = currentLayer!.parent;
98+
currentLayer = currentLayer.parent!;
9999
}
100100

101101
@override
@@ -221,16 +221,7 @@ class LayerSceneBuilder implements ui.SceneBuilder {
221221
}
222222

223223
T pushLayer<T extends ContainerLayer>(T layer) {
224-
if (rootLayer == null) {
225-
rootLayer = currentLayer = layer;
226-
return layer;
227-
}
228-
229-
if (currentLayer == null) {
230-
return layer;
231-
}
232-
233-
currentLayer!.add(layer);
224+
currentLayer.add(layer);
234225
currentLayer = layer;
235226
return layer;
236227
}

lib/web_ui/lib/src/engine/canvaskit/layer_tree.dart

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@ part of engine;
77

88
/// A tree of [Layer]s that, together with a [Size] compose a frame.
99
class LayerTree {
10+
LayerTree(this.rootLayer);
11+
1012
/// The root of the layer tree.
11-
Layer? rootLayer;
13+
final RootLayer rootLayer;
1214

1315
/// The size (in physical pixels) of the frame to paint this layer tree into.
1416
final ui.Size frameSize = ui.window.physicalSize;
@@ -27,7 +29,7 @@ class LayerTree {
2729
ignoreRasterCache ? null : frame.rasterCache,
2830
frame.viewEmbedder,
2931
);
30-
rootLayer!.preroll(context, Matrix4.identity());
32+
rootLayer.preroll(context, Matrix4.identity());
3133
}
3234

3335
/// Paints the layer tree into the given [frame].
@@ -48,8 +50,8 @@ class LayerTree {
4850
ignoreRasterCache ? null : frame.rasterCache,
4951
frame.viewEmbedder,
5052
);
51-
if (rootLayer!.needsPainting) {
52-
rootLayer!.paint(context);
53+
if (rootLayer.needsPainting) {
54+
rootLayer.paint(context);
5355
}
5456
}
5557

@@ -59,17 +61,15 @@ class LayerTree {
5961
ui.Picture flatten() {
6062
CkPictureRecorder recorder = CkPictureRecorder();
6163
CkCanvas canvas = recorder.beginRecording(ui.Rect.largest);
62-
if (rootLayer != null) {
63-
final PrerollContext prerollContext = PrerollContext(null, null);
64-
rootLayer!.preroll(prerollContext, Matrix4.identity());
65-
66-
CkNWayCanvas internalNodesCanvas = CkNWayCanvas();
67-
internalNodesCanvas.addCanvas(canvas);
68-
final PaintContext paintContext =
69-
PaintContext(internalNodesCanvas, canvas, null, null);
70-
if (rootLayer!.needsPainting) {
71-
rootLayer!.paint(paintContext);
72-
}
64+
final PrerollContext prerollContext = PrerollContext(null, null);
65+
rootLayer.preroll(prerollContext, Matrix4.identity());
66+
67+
CkNWayCanvas internalNodesCanvas = CkNWayCanvas();
68+
internalNodesCanvas.addCanvas(canvas);
69+
final PaintContext paintContext =
70+
PaintContext(internalNodesCanvas, canvas, null, null);
71+
if (rootLayer.needsPainting) {
72+
rootLayer.paint(paintContext);
7373
}
7474
return recorder.endRecording();
7575
}

lib/web_ui/test/canvaskit/canvas_golden_test.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ void testMain() {
197197

198198
// Render the scene once without painting the shadow bounds just to
199199
// preroll the scene to compute the shadow bounds.
200-
buildTestScene(paintShadowBounds: false).rootLayer!.preroll(
200+
buildTestScene(paintShadowBounds: false).rootLayer.preroll(
201201
PrerollContext(
202202
RasterCache(),
203203
HtmlViewEmbedder(),

lib/web_ui/test/canvaskit/layer_test.dart

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,18 @@ void testMain() {
4444
sb.addPicture(ui.Offset.zero, picture);
4545
final LayerTree layerTree = sb.build().layerTree;
4646
dispatcher.rasterizer!.draw(layerTree);
47-
final ClipRectEngineLayer clipRect = layerTree.rootLayer as ClipRectEngineLayer;
47+
final ClipRectEngineLayer clipRect = layerTree.rootLayer.debugLayers.single as ClipRectEngineLayer;
4848
expect(clipRect.paintBounds, ui.Rect.fromLTRB(15, 15, 30, 30));
4949

5050
final TransformEngineLayer transform = clipRect.debugLayers.single as TransformEngineLayer;
5151
expect(transform.paintBounds, ui.Rect.fromLTRB(0, 0, 30, 30));
5252
});
53+
54+
test('can push a leaf layer without a container layer', () async {
55+
final CkPictureRecorder recorder = CkPictureRecorder();
56+
recorder.beginRecording(ui.Rect.zero);
57+
LayerSceneBuilder().addPicture(ui.Offset.zero, recorder.endRecording());
58+
});
5359
// TODO: https://github.com/flutter/flutter/issues/60040
5460
}, skip: isIosSafari);
5561
}

0 commit comments

Comments
 (0)