From 4bb1a74025d9992f25ed5db2dee83b2fd5f43afd Mon Sep 17 00:00:00 2001 From: Mouad Debbar Date: Wed, 15 Nov 2023 10:37:06 -0500 Subject: [PATCH] [web] Move `EmbeddingStrategy` and `DimensionsProvider` out of `FlutterViewEmbedder` (flutter/engine#48025) Part of https://github.com/flutter/flutter/issues/134443 Part of https://github.com/flutter/flutter/issues/117098 --- .../lib/web_ui/lib/src/engine/embedder.dart | 35 +++----------- .../web_ui/lib/src/engine/initialization.dart | 2 +- .../lib/web_ui/lib/src/engine/window.dart | 46 +++++++++++++------ .../lib/web_ui/test/engine/routing_test.dart | 2 +- .../engine/surface/platform_view_test.dart | 6 ++- .../lib/web_ui/test/engine/window_test.dart | 2 +- 6 files changed, 46 insertions(+), 47 deletions(-) diff --git a/engine/src/flutter/lib/web_ui/lib/src/engine/embedder.dart b/engine/src/flutter/lib/web_ui/lib/src/engine/embedder.dart index d09208487ac..f81be23a9f3 100644 --- a/engine/src/flutter/lib/web_ui/lib/src/engine/embedder.dart +++ b/engine/src/flutter/lib/web_ui/lib/src/engine/embedder.dart @@ -14,9 +14,7 @@ import 'platform_dispatcher.dart'; import 'pointer_binding.dart'; import 'semantics.dart'; import 'text_editing/text_editing.dart'; -import 'view_embedder/dimensions_provider/dimensions_provider.dart'; import 'view_embedder/dom_manager.dart'; -import 'view_embedder/embedding_strategy/embedding_strategy.dart'; import 'view_embedder/style_manager.dart'; import 'window.dart'; @@ -40,30 +38,10 @@ import 'window.dart'; /// multiple instances in a multi-view scenario. (One ViewEmbedder per FlutterView). class FlutterViewEmbedder { /// Creates a FlutterViewEmbedder. - /// - /// The incoming [hostElement] parameter specifies the root element in the DOM - /// into which Flutter will be rendered. - /// - /// The hostElement is abstracted by an [EmbeddingStrategy] instance, which has - /// different behavior depending on the `hostElement` value: - /// - /// - A `null` `hostElement` will cause Flutter to take over the whole page. - /// - A non-`null` `hostElement` will render flutter inside that element. - FlutterViewEmbedder({DomElement? hostElement}) - : _embeddingStrategy = - EmbeddingStrategy.create(hostElement: hostElement) { - // Configure the EngineWindow so it knows how to measure itself. - // TODO(dit): Refactor ownership according to new design, https://github.com/flutter/flutter/issues/117098 - window.configureDimensionsProvider(DimensionsProvider.create( - hostElement: hostElement, - )); - + FlutterViewEmbedder() { reset(); } - /// Abstracts all the DOM manipulations required to embed a Flutter app in an user-supplied `hostElement`. - final EmbeddingStrategy _embeddingStrategy; - /// The element that contains the [sceneElement]. /// /// This element is created and inserted in the HTML DOM once. It is never @@ -139,7 +117,7 @@ class FlutterViewEmbedder { : 'requested explicitly'; // Initializes the embeddingStrategy so it can host a single-view Flutter app. - _embeddingStrategy.initialize( + window.embeddingStrategy.initialize( hostElementAttributes: { 'flt-renderer': '${renderer.rendererTag} ($rendererSelection)', 'flt-build-mode': buildMode, @@ -158,7 +136,7 @@ class FlutterViewEmbedder { // // The embeddingStrategy will take care of cleaning up the glassPane on hot // restart. - _embeddingStrategy.attachGlassPane(_flutterViewElement); + window.embeddingStrategy.attachGlassPane(_flutterViewElement); _flutterViewElement.appendChild(_glassPaneElement); if (getJsProperty(_glassPaneElement, 'attachShadow') == null) { @@ -270,7 +248,7 @@ class FlutterViewEmbedder { ..style.visibility = 'hidden'; if (isWebKit) { // The resourcesHost *must* be a sibling of the glassPaneElement. - _embeddingStrategy.attachResourcesHost(resourcesHost, + window.embeddingStrategy.attachResourcesHost(resourcesHost, nextTo: _flutterViewElement); } else { _glassPaneShadow.insertBefore(resourcesHost, _glassPaneShadow.firstChild); @@ -312,10 +290,9 @@ FlutterViewEmbedder? _flutterViewEmbedder; /// Initializes the [FlutterViewEmbedder], if it's not already initialized. FlutterViewEmbedder ensureFlutterViewEmbedderInitialized() { // FlutterViewEmbedder needs the implicit view to be initialized because it - // uses some of its methods e.g. `configureDimensionsProvider`, `onResize`. + // uses some of its members e.g. `embeddingStrategy`, `onResize`. ensureImplicitViewInitialized(); - return _flutterViewEmbedder ??= - FlutterViewEmbedder(hostElement: configuration.hostElement); + return _flutterViewEmbedder ??= FlutterViewEmbedder(); } /// Creates a node to host text editing elements and applies a stylesheet diff --git a/engine/src/flutter/lib/web_ui/lib/src/engine/initialization.dart b/engine/src/flutter/lib/web_ui/lib/src/engine/initialization.dart index 16faf280b1e..2d17adc0d4d 100644 --- a/engine/src/flutter/lib/web_ui/lib/src/engine/initialization.dart +++ b/engine/src/flutter/lib/web_ui/lib/src/engine/initialization.dart @@ -218,7 +218,7 @@ Future initializeEngineUi() async { _initializationState = DebugEngineInitializationState.initializingUi; RawKeyboard.initialize(onMacOs: operatingSystem == OperatingSystem.macOs); - ensureImplicitViewInitialized(); + ensureImplicitViewInitialized(hostElement: configuration.hostElement); ensureFlutterViewEmbedderInitialized(); _initializationState = DebugEngineInitializationState.initialized; } diff --git a/engine/src/flutter/lib/web_ui/lib/src/engine/window.dart b/engine/src/flutter/lib/web_ui/lib/src/engine/window.dart index 4cb82d98246..fbddc632839 100644 --- a/engine/src/flutter/lib/web_ui/lib/src/engine/window.dart +++ b/engine/src/flutter/lib/web_ui/lib/src/engine/window.dart @@ -26,6 +26,7 @@ import 'semantics/accessibility.dart'; import 'services.dart'; import 'util.dart'; import 'view_embedder/dom_manager.dart'; +import 'view_embedder/embedding_strategy/embedding_strategy.dart'; typedef _HandleMessageCallBack = Future Function(); @@ -40,15 +41,25 @@ const int kImplicitViewId = 0; /// In addition to everything defined in [ui.FlutterView], this class adds /// a few web-specific properties. base class EngineFlutterView implements ui.FlutterView { + /// Creates a [ui.FlutterView] that can be used in multi-view mode. + /// + /// The [hostElement] parameter specifies the container in the DOM into which + /// the Flutter view will be rendered. factory EngineFlutterView( int viewId, EnginePlatformDispatcher platformDispatcher, + DomElement hostElement, ) = _EngineFlutterViewImpl; EngineFlutterView._( this.viewId, this.platformDispatcher, - ); + // This is nullable to accommodate the legacy `EngineFlutterWindow`. In + // multi-view mode, the host element is required for each view (as reflected + // by the public `EngineFlutterView` constructor). + DomElement? hostElement, + ) : embeddingStrategy = EmbeddingStrategy.create(hostElement: hostElement), + _dimensionsProvider = DimensionsProvider.create(hostElement: hostElement); @override final int viewId; @@ -56,6 +67,9 @@ base class EngineFlutterView implements ui.FlutterView { @override final EnginePlatformDispatcher platformDispatcher; + /// Abstracts all the DOM manipulations required to embed a Flutter view in a user-supplied `hostElement`. + final EmbeddingStrategy embeddingStrategy; + final ViewConfiguration _viewConfiguration = const ViewConfiguration(); @override @@ -143,19 +157,17 @@ base class EngineFlutterView implements ui.FlutterView { @override double get devicePixelRatio => display.devicePixelRatio; - late DimensionsProvider _dimensionsProvider; - void configureDimensionsProvider(DimensionsProvider dimensionsProvider) { - _dimensionsProvider = dimensionsProvider; - } + final DimensionsProvider _dimensionsProvider; Stream get onResize => _dimensionsProvider.onResize; } final class _EngineFlutterViewImpl extends EngineFlutterView { _EngineFlutterViewImpl( - int viewId, - EnginePlatformDispatcher platformDispatcher, - ) : super._(viewId, platformDispatcher) { + super.viewId, + super.platformDispatcher, + super.hostElement, + ) : super._() { platformDispatcher.registerView(this); registerHotRestartListener(() { // TODO(harryterkelsen): What should we do about this in multi-view? @@ -168,9 +180,10 @@ final class _EngineFlutterViewImpl extends EngineFlutterView { /// The Web implementation of [ui.SingletonFlutterWindow]. final class EngineFlutterWindow extends EngineFlutterView implements ui.SingletonFlutterWindow { EngineFlutterWindow( - int viewId, - EnginePlatformDispatcher platformDispatcher, - ) : super._(viewId, platformDispatcher) { + super.viewId, + super.platformDispatcher, + super.hostElement, + ) : super._() { platformDispatcher.registerView(this); if (ui_web.isCustomUrlStrategySet) { _browserHistory = createHistoryForExistingState(ui_web.urlStrategy); @@ -585,9 +598,14 @@ EngineFlutterWindow? _window; /// Initializes the [window] (aka the implicit view), if it's not already /// initialized. -EngineFlutterWindow ensureImplicitViewInitialized() { - return _window ??= - EngineFlutterWindow(kImplicitViewId, EnginePlatformDispatcher.instance); +EngineFlutterWindow ensureImplicitViewInitialized({ + DomElement? hostElement, +}) { + return _window ??= EngineFlutterWindow( + kImplicitViewId, + EnginePlatformDispatcher.instance, + hostElement, + ); } /// The Web implementation of [ui.ViewPadding]. diff --git a/engine/src/flutter/lib/web_ui/test/engine/routing_test.dart b/engine/src/flutter/lib/web_ui/test/engine/routing_test.dart index f5875754c7a..68185c40420 100644 --- a/engine/src/flutter/lib/web_ui/test/engine/routing_test.dart +++ b/engine/src/flutter/lib/web_ui/test/engine/routing_test.dart @@ -37,7 +37,7 @@ void testMain() { setUp(() { savedWindow = EnginePlatformDispatcher.instance.implicitView; - myWindow = EngineFlutterWindow(0, EnginePlatformDispatcher.instance); + myWindow = EngineFlutterWindow(0, EnginePlatformDispatcher.instance, createDomHTMLDivElement()); }); tearDown(() async { diff --git a/engine/src/flutter/lib/web_ui/test/engine/surface/platform_view_test.dart b/engine/src/flutter/lib/web_ui/test/engine/surface/platform_view_test.dart index 5ca231ecfd2..64dd789d4f6 100644 --- a/engine/src/flutter/lib/web_ui/test/engine/surface/platform_view_test.dart +++ b/engine/src/flutter/lib/web_ui/test/engine/surface/platform_view_test.dart @@ -14,7 +14,11 @@ import '../../common/matchers.dart'; import '../../common/test_initialization.dart'; const MethodCodec codec = StandardMethodCodec(); -final EngineFlutterWindow window = EngineFlutterWindow(0, EnginePlatformDispatcher.instance); +final EngineFlutterWindow window = EngineFlutterWindow( + 0, + EnginePlatformDispatcher.instance, + createDomHTMLDivElement(), +); void main() { internalBootstrapBrowserTest(() => testMain); diff --git a/engine/src/flutter/lib/web_ui/test/engine/window_test.dart b/engine/src/flutter/lib/web_ui/test/engine/window_test.dart index 3c8847ccd25..a1f950eb3d6 100644 --- a/engine/src/flutter/lib/web_ui/test/engine/window_test.dart +++ b/engine/src/flutter/lib/web_ui/test/engine/window_test.dart @@ -27,7 +27,7 @@ Future testMain() async { late EngineFlutterWindow myWindow; setUp(() { - myWindow = EngineFlutterWindow(99, EnginePlatformDispatcher.instance); + myWindow = EngineFlutterWindow(99, EnginePlatformDispatcher.instance, createDomHTMLDivElement()); }); tearDown(() async {