[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
This commit is contained in:
Mouad Debbar 2023-11-15 10:37:06 -05:00 committed by GitHub
parent ab53a52abc
commit 4bb1a74025
6 changed files with 46 additions and 47 deletions

View File

@ -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: <String, String>{
'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<Object?>(_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

View File

@ -218,7 +218,7 @@ Future<void> initializeEngineUi() async {
_initializationState = DebugEngineInitializationState.initializingUi;
RawKeyboard.initialize(onMacOs: operatingSystem == OperatingSystem.macOs);
ensureImplicitViewInitialized();
ensureImplicitViewInitialized(hostElement: configuration.hostElement);
ensureFlutterViewEmbedderInitialized();
_initializationState = DebugEngineInitializationState.initialized;
}

View File

@ -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<bool> 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<ui.Size?> 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].

View File

@ -37,7 +37,7 @@ void testMain() {
setUp(() {
savedWindow = EnginePlatformDispatcher.instance.implicitView;
myWindow = EngineFlutterWindow(0, EnginePlatformDispatcher.instance);
myWindow = EngineFlutterWindow(0, EnginePlatformDispatcher.instance, createDomHTMLDivElement());
});
tearDown(() async {

View File

@ -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);

View File

@ -27,7 +27,7 @@ Future<void> testMain() async {
late EngineFlutterWindow myWindow;
setUp(() {
myWindow = EngineFlutterWindow(99, EnginePlatformDispatcher.instance);
myWindow = EngineFlutterWindow(99, EnginePlatformDispatcher.instance, createDomHTMLDivElement());
});
tearDown(() async {