diff --git a/engine/src/flutter/lib/web_ui/lib/src/engine/canvaskit/embedded_views.dart b/engine/src/flutter/lib/web_ui/lib/src/engine/canvaskit/embedded_views.dart index adda18f947..acbd5e8560 100644 --- a/engine/src/flutter/lib/web_ui/lib/src/engine/canvaskit/embedded_views.dart +++ b/engine/src/flutter/lib/web_ui/lib/src/engine/canvaskit/embedded_views.dart @@ -651,7 +651,8 @@ class HtmlViewEmbedder { // them. Otherwise, we will need to release overlays from the unchanged // segment of view ids. if (diffResult.viewsToAdd.length > availableOverlays) { - int viewsToDispose = diffResult.viewsToAdd.length - availableOverlays; + int viewsToDispose = math.min(SurfaceFactory.instance.maximumOverlays, + diffResult.viewsToAdd.length - availableOverlays); // The first `maximumSurfaces` views in the previous composition order // had an overlay. int index = SurfaceFactory.instance.maximumOverlays - diff --git a/engine/src/flutter/lib/web_ui/lib/src/engine/configuration.dart b/engine/src/flutter/lib/web_ui/lib/src/engine/configuration.dart index f2bc94fbcd..c5f373557f 100644 --- a/engine/src/flutter/lib/web_ui/lib/src/engine/configuration.dart +++ b/engine/src/flutter/lib/web_ui/lib/src/engine/configuration.dart @@ -166,8 +166,10 @@ external JsFlutterConfiguration? get _jsConfiguration; class JsFlutterConfiguration { external String? get canvasKitBaseUrl; external bool? get canvasKitForceCpuOnly; - external int? get canvasKitMaximumSurfaces; external bool? get debugShowSemanticsNodes; + + external int? get canvasKitMaximumSurfaces; + external set canvasKitMaximumSurfaces(int? maxSurfaces); } /// A JavaScript entrypoint that allows developer to set rendering backend diff --git a/engine/src/flutter/lib/web_ui/test/canvaskit/embedded_views_test.dart b/engine/src/flutter/lib/web_ui/test/canvaskit/embedded_views_test.dart index a7b6d17b82..c619f5e546 100644 --- a/engine/src/flutter/lib/web_ui/test/canvaskit/embedded_views_test.dart +++ b/engine/src/flutter/lib/web_ui/test/canvaskit/embedded_views_test.dart @@ -601,6 +601,53 @@ void testMain() { HtmlViewEmbedder.debugDisableOverlays = false; }); + test('works correctly with max overlays == 2', () async { + debugSetConfiguration(FlutterConfiguration( + JsFlutterConfiguration()..canvasKitMaximumSurfaces = 2)); + SurfaceFactory.instance.debugClear(); + + expect(SurfaceFactory.instance.maximumSurfaces, 2); + expect(SurfaceFactory.instance.maximumOverlays, 0); + + ui.platformViewRegistry.registerViewFactory( + 'test-platform-view', + (int viewId) => html.DivElement()..id = 'view-0', + ); + await createPlatformView(0, 'test-platform-view'); + await createPlatformView(1, 'test-platform-view'); + + final EnginePlatformDispatcher dispatcher = + ui.window.platformDispatcher as EnginePlatformDispatcher; + + LayerSceneBuilder sb = LayerSceneBuilder(); + sb.pushOffset(0, 0); + sb.addPlatformView(0, width: 10, height: 10); + sb.pop(); + // The below line should not throw an error. + dispatcher.rasterizer!.draw(sb.build().layerTree); + + expect( + flutterViewEmbedder.glassPaneShadow! + .querySelectorAll('flt-platform-view-slot'), + hasLength(1)); + + sb = LayerSceneBuilder(); + sb.pushOffset(0, 0); + sb.addPlatformView(1, width: 10, height: 10); + sb.addPlatformView(0, width: 10, height: 10); + sb.pop(); + // The below line should not throw an error. + dispatcher.rasterizer!.draw(sb.build().layerTree); + + expect( + flutterViewEmbedder.glassPaneShadow! + .querySelectorAll('flt-platform-view-slot'), + hasLength(2)); + + // Reset configuration + debugSetConfiguration(FlutterConfiguration(null)); + }); + test( 'correctly renders when overlays are disabled and a subset ' 'of views is used', () async {