Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit c1fec26

Browse files
author
Harry Terkelsen
authored
Add flag to disable overlays (#28312)
1 parent 5329749 commit c1fec26

File tree

5 files changed

+88
-55
lines changed

5 files changed

+88
-55
lines changed

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

Lines changed: 66 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,18 @@ class HtmlViewEmbedder {
2727
HtmlViewEmbedder._();
2828

2929
/// The maximum number of overlay surfaces that can be live at once.
30-
static const int maximumOverlaySurfaces = int.fromEnvironment(
31-
'FLUTTER_WEB_MAXIMUM_OVERLAYS',
30+
static const int maximumSurfaces = int.fromEnvironment(
31+
'FLUTTER_WEB_MAXIMUM_SURFACES',
3232
defaultValue: 8,
3333
);
3434

35+
/// If `true`, overlay canvases are disabled.
36+
///
37+
/// This causes all drawing to go to a single canvas, with all of the platform
38+
/// views rendered over top. This may result in incorrect rendering with
39+
/// platform views.
40+
static const bool disableOverlays = maximumSurfaces <= 1;
41+
3542
/// The picture recorder shared by all platform views which paint to the
3643
/// backup surface.
3744
CkPictureRecorder? _backupPictureRecorder;
@@ -86,6 +93,9 @@ class HtmlViewEmbedder {
8693
}
8794

8895
List<CkCanvas> getCurrentCanvases() {
96+
if (disableOverlays) {
97+
return const <CkCanvas>[];
98+
}
8999
final Set<CkCanvas> canvases = <CkCanvas>{};
90100
for (int i = 0; i < _compositionOrder.length; i++) {
91101
final int viewId = _compositionOrder[i];
@@ -95,21 +105,23 @@ class HtmlViewEmbedder {
95105
}
96106

97107
void prerollCompositeEmbeddedView(int viewId, EmbeddedViewParams params) {
98-
_ensureOverlayInitialized(viewId);
99-
if (_viewsUsingBackupSurface.contains(viewId)) {
100-
if (_backupPictureRecorder == null) {
101-
// Only initialize the picture recorder for the backup surface once.
108+
if (!disableOverlays) {
109+
_ensureOverlayInitialized(viewId);
110+
if (_viewsUsingBackupSurface.contains(viewId)) {
111+
if (_backupPictureRecorder == null) {
112+
// Only initialize the picture recorder for the backup surface once.
113+
final CkPictureRecorder pictureRecorder = CkPictureRecorder();
114+
pictureRecorder.beginRecording(ui.Offset.zero & _frameSize);
115+
pictureRecorder.recordingCanvas!.clear(const ui.Color(0x00000000));
116+
_backupPictureRecorder = pictureRecorder;
117+
}
118+
_pictureRecorders[viewId] = _backupPictureRecorder!;
119+
} else {
102120
final CkPictureRecorder pictureRecorder = CkPictureRecorder();
103121
pictureRecorder.beginRecording(ui.Offset.zero & _frameSize);
104122
pictureRecorder.recordingCanvas!.clear(const ui.Color(0x00000000));
105-
_backupPictureRecorder = pictureRecorder;
123+
_pictureRecorders[viewId] = pictureRecorder;
106124
}
107-
_pictureRecorders[viewId] = _backupPictureRecorder!;
108-
} else {
109-
final CkPictureRecorder pictureRecorder = CkPictureRecorder();
110-
pictureRecorder.beginRecording(ui.Offset.zero & _frameSize);
111-
pictureRecorder.recordingCanvas!.clear(const ui.Color(0x00000000));
112-
_pictureRecorders[viewId] = pictureRecorder;
113125
}
114126
_compositionOrder.add(viewId);
115127

@@ -121,14 +133,26 @@ class HtmlViewEmbedder {
121133
_viewsToRecomposite.add(viewId);
122134
}
123135

136+
/// Prepares to composite [viewId].
137+
///
138+
/// If this returns a [CkCanvas], then that canvas should be the new leaf
139+
/// node. Otherwise, keep the same leaf node.
124140
CkCanvas? compositeEmbeddedView(int viewId) {
125141
// Do nothing if this view doesn't need to be composited.
126142
if (!_viewsToRecomposite.contains(viewId)) {
127-
return _pictureRecorders[viewId]!.recordingCanvas;
143+
if (!disableOverlays) {
144+
return _pictureRecorders[viewId]!.recordingCanvas;
145+
} else {
146+
return null;
147+
}
128148
}
129149
_compositeWithParams(viewId, _currentCompositionParams[viewId]!);
130150
_viewsToRecomposite.remove(viewId);
131-
return _pictureRecorders[viewId]!.recordingCanvas;
151+
if (!disableOverlays) {
152+
return _pictureRecorders[viewId]!.recordingCanvas;
153+
} else {
154+
return null;
155+
}
132156
}
133157

134158
void _compositeWithParams(int viewId, EmbeddedViewParams params) {
@@ -351,26 +375,29 @@ class HtmlViewEmbedder {
351375

352376
void submitFrame() {
353377
bool _didPaintBackupSurface = false;
354-
for (int i = 0; i < _compositionOrder.length; i++) {
355-
final int viewId = _compositionOrder[i];
356-
if (_viewsUsingBackupSurface.contains(viewId)) {
357-
// Only draw the picture to the backup surface once.
358-
if (!_didPaintBackupSurface) {
359-
final SurfaceFrame backupFrame =
360-
SurfaceFactory.instance.backupSurface.acquireFrame(_frameSize);
361-
backupFrame.skiaCanvas
362-
.drawPicture(_backupPictureRecorder!.endRecording());
363-
_backupPictureRecorder = null;
364-
backupFrame.submit();
365-
_didPaintBackupSurface = true;
378+
if (!disableOverlays) {
379+
for (int i = 0; i < _compositionOrder.length; i++) {
380+
final int viewId = _compositionOrder[i];
381+
if (_viewsUsingBackupSurface.contains(viewId)) {
382+
// Only draw the picture to the backup surface once.
383+
if (!_didPaintBackupSurface) {
384+
final SurfaceFrame backupFrame =
385+
SurfaceFactory.instance.backupSurface.acquireFrame(_frameSize);
386+
backupFrame.skiaCanvas
387+
.drawPicture(_backupPictureRecorder!.endRecording());
388+
_backupPictureRecorder = null;
389+
backupFrame.submit();
390+
_didPaintBackupSurface = true;
391+
}
392+
} else {
393+
final SurfaceFrame frame =
394+
_overlays[viewId]!.acquireFrame(_frameSize);
395+
final CkCanvas canvas = frame.skiaCanvas;
396+
canvas.drawPicture(
397+
_pictureRecorders[viewId]!.endRecording(),
398+
);
399+
frame.submit();
366400
}
367-
} else {
368-
final SurfaceFrame frame = _overlays[viewId]!.acquireFrame(_frameSize);
369-
final CkCanvas canvas = frame.skiaCanvas;
370-
canvas.drawPicture(
371-
_pictureRecorders[viewId]!.endRecording(),
372-
);
373-
frame.submit();
374401
}
375402
}
376403
if (listEquals(_compositionOrder, _activeCompositionOrder)) {
@@ -396,11 +423,13 @@ class HtmlViewEmbedder {
396423

397424
unusedViews.remove(viewId);
398425
final html.Element platformViewRoot = _viewClipChains[viewId]!.root;
399-
final html.Element overlay = _overlays[viewId]!.htmlElement;
400426
platformViewRoot.remove();
401427
skiaSceneHost!.append(platformViewRoot);
402-
overlay.remove();
403-
skiaSceneHost!.append(overlay);
428+
if (!disableOverlays) {
429+
final html.Element overlay = _overlays[viewId]!.htmlElement;
430+
overlay.remove();
431+
skiaSceneHost!.append(overlay);
432+
}
404433
_activeCompositionOrder.add(viewId);
405434
}
406435
if (_didPaintBackupSurface) {

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

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,8 @@ class TransformEngineLayer extends ContainerLayer
363363
void preroll(PrerollContext prerollContext, Matrix4 matrix) {
364364
final Matrix4 childMatrix = matrix.multiplied(_transform);
365365
prerollContext.mutatorsStack.pushTransform(_transform);
366-
final ui.Rect childPaintBounds = prerollChildren(prerollContext, childMatrix);
366+
final ui.Rect childPaintBounds =
367+
prerollChildren(prerollContext, childMatrix);
367368
paintBounds = transformRect(_transform, childPaintBounds);
368369
prerollContext.mutatorsStack.pop();
369370
}
@@ -602,7 +603,10 @@ class PlatformViewLayer extends Layer {
602603

603604
@override
604605
void paint(PaintContext paintContext) {
605-
final CkCanvas? canvas = paintContext.viewEmbedder!.compositeEmbeddedView(viewId);
606-
paintContext.leafNodesCanvas = canvas;
606+
final CkCanvas? canvas =
607+
paintContext.viewEmbedder!.compositeEmbeddedView(viewId);
608+
if (canvas != null) {
609+
paintContext.leafNodesCanvas = canvas;
610+
}
607611
}
608612
}

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@ import 'surface.dart';
1212
class SurfaceFactory {
1313
/// The cache singleton.
1414
static final SurfaceFactory instance =
15-
SurfaceFactory(HtmlViewEmbedder.maximumOverlaySurfaces);
15+
SurfaceFactory(HtmlViewEmbedder.maximumSurfaces);
1616

1717
SurfaceFactory(this.maximumSurfaces)
18-
: assert(maximumSurfaces >= 2,
19-
'The maximum number of surfaces must be at least 2');
18+
: assert(maximumSurfaces >= 1,
19+
'The maximum number of surfaces must be at least 1');
2020

2121
/// The base surface to paint on. This is the default surface which will be
2222
/// painted to. If there are no platform views, then this surface will receive

lib/web_ui/test/canvaskit/embedded_views_test.dart

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ void testMain() {
213213

214214
// Initialize all platform views to be used in the test.
215215
final List<int> platformViewIds = <int>[];
216-
for (int i = 0; i < HtmlViewEmbedder.maximumOverlaySurfaces * 2; i++) {
216+
for (int i = 0; i < HtmlViewEmbedder.maximumSurfaces * 2; i++) {
217217
ui.platformViewRegistry.registerViewFactory(
218218
'test-platform-view',
219219
(int viewId) => html.DivElement()..id = 'view-$i',
@@ -242,8 +242,8 @@ void testMain() {
242242
// Frame 1:
243243
// Render: up to cache size platform views.
244244
// Expect: main canvas plus platform view overlays.
245-
renderTestScene(viewCount: HtmlViewEmbedder.maximumOverlaySurfaces);
246-
expect(countCanvases(), HtmlViewEmbedder.maximumOverlaySurfaces);
245+
renderTestScene(viewCount: HtmlViewEmbedder.maximumSurfaces);
246+
expect(countCanvases(), HtmlViewEmbedder.maximumSurfaces);
247247

248248
// Frame 2:
249249
// Render: zero platform views.
@@ -256,15 +256,15 @@ void testMain() {
256256
// Render: less than cache size platform views.
257257
// Expect: overlays reused.
258258
await Future<void>.delayed(Duration.zero);
259-
renderTestScene(viewCount: HtmlViewEmbedder.maximumOverlaySurfaces - 2);
260-
expect(countCanvases(), HtmlViewEmbedder.maximumOverlaySurfaces - 1);
259+
renderTestScene(viewCount: HtmlViewEmbedder.maximumSurfaces - 2);
260+
expect(countCanvases(), HtmlViewEmbedder.maximumSurfaces - 1);
261261

262262
// Frame 4:
263263
// Render: more platform views than max cache size.
264264
// Expect: main canvas, backup overlay, maximum overlays.
265265
await Future<void>.delayed(Duration.zero);
266-
renderTestScene(viewCount: HtmlViewEmbedder.maximumOverlaySurfaces * 2);
267-
expect(countCanvases(), HtmlViewEmbedder.maximumOverlaySurfaces);
266+
renderTestScene(viewCount: HtmlViewEmbedder.maximumSurfaces * 2);
267+
expect(countCanvases(), HtmlViewEmbedder.maximumSurfaces);
268268

269269
// Frame 5:
270270
// Render: zero platform views.
@@ -346,21 +346,21 @@ void testMain() {
346346
// Render: Views 1-10
347347
// Expect: main canvas plus platform view overlays; empty cache.
348348
renderTestScene(<int>[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
349-
expect(countCanvases(), HtmlViewEmbedder.maximumOverlaySurfaces);
349+
expect(countCanvases(), HtmlViewEmbedder.maximumSurfaces);
350350

351351
// Frame 2:
352352
// Render: Views 2-11
353353
// Expect: main canvas plus platform view overlays; empty cache.
354354
await Future<void>.delayed(Duration.zero);
355355
renderTestScene(<int>[2, 3, 4, 5, 6, 7, 8, 9, 10, 11]);
356-
expect(countCanvases(), HtmlViewEmbedder.maximumOverlaySurfaces);
356+
expect(countCanvases(), HtmlViewEmbedder.maximumSurfaces);
357357

358358
// Frame 3:
359359
// Render: Views 3-12
360360
// Expect: main canvas plus platform view overlays; empty cache.
361361
await Future<void>.delayed(Duration.zero);
362362
renderTestScene(<int>[3, 4, 5, 6, 7, 8, 9, 10, 11, 12]);
363-
expect(countCanvases(), HtmlViewEmbedder.maximumOverlaySurfaces);
363+
expect(countCanvases(), HtmlViewEmbedder.maximumSurfaces);
364364

365365
// TODO(yjbanov): skipped due to https://github.com/flutter/flutter/issues/73867
366366
}, skip: isSafari);

lib/web_ui/test/canvaskit/surface_factory_test.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ void testMain() {
1919
group('$SurfaceFactory', () {
2020
setUpCanvasKitTest();
2121

22-
test('cannot be created with size less than 2', () {
22+
test('cannot be created with size less than 1', () {
2323
expect(() => SurfaceFactory(-1), throwsAssertionError);
2424
expect(() => SurfaceFactory(0), throwsAssertionError);
25-
expect(() => SurfaceFactory(1), throwsAssertionError);
25+
expect(SurfaceFactory(1), isNotNull);
2626
expect(SurfaceFactory(2), isNotNull);
2727
});
2828

0 commit comments

Comments
 (0)