From 57cc7e9136a212ae4885aa37233ad10c2be6d077 Mon Sep 17 00:00:00 2001 From: Mouad Debbar Date: Fri, 27 Oct 2023 19:53:27 -0400 Subject: [PATCH] [web] DomManager for each FlutterView (flutter/engine#47388) The PR may seem large, but the main changes are simple: - Introduce a `DomManager` that aims to take over all DOM responsibilities from `FlutterViewEmbedder`. - Update all references to `flutterViewEmbedder.*domElement*` to `domManager.*domElement*`. - Describe the general DOM structure of a Flutter View in a doc comment. Next steps (in future PRs): - Move all DOM manipulation methods out of `FlutterViewEmbedder` into `DomManager`. - Move DOM creation logic out of `FlutterViewEmbedder` into `DomManager`. --- .../ci/licenses_golden/licenses_flutter | 2 + .../flutter/lib/web_ui/lib/src/engine.dart | 1 + .../lib/web_ui/lib/src/engine/embedder.dart | 48 ++-- .../event_position_helper.dart | 11 +- .../lib/src/engine/semantics/semantics.dart | 6 +- .../lib/src/engine/text/measurement.dart | 18 +- .../src/engine/text_editing/text_editing.dart | 6 +- .../src/engine/view_embedder/dom_manager.dart | 66 ++++++ .../lib/web_ui/lib/src/engine/window.dart | 12 +- .../test/canvaskit/embedded_views_test.dart | 34 ++- .../lib/web_ui/test/engine/embedder_test.dart | 22 +- .../test/engine/pointer_binding_test.dart | 217 +++++++++--------- .../engine/semantics/accessibility_test.dart | 12 +- .../test/engine/semantics/semantics_test.dart | 53 +++-- .../engine/semantics/semantics_tester.dart | 9 +- .../engine/semantics/text_field_test.dart | 100 ++++---- .../view_embedder/dom_manager_test.dart | 27 +++ .../test/html/bitmap_canvas_golden_test.dart | 10 +- .../html/shaders/shader_mask_golden_test.dart | 11 +- 19 files changed, 387 insertions(+), 278 deletions(-) create mode 100644 engine/src/flutter/lib/web_ui/lib/src/engine/view_embedder/dom_manager.dart create mode 100644 engine/src/flutter/lib/web_ui/test/engine/view_embedder/dom_manager_test.dart diff --git a/engine/src/flutter/ci/licenses_golden/licenses_flutter b/engine/src/flutter/ci/licenses_golden/licenses_flutter index fd6748c5a5..7d526232a1 100644 --- a/engine/src/flutter/ci/licenses_golden/licenses_flutter +++ b/engine/src/flutter/ci/licenses_golden/licenses_flutter @@ -3765,6 +3765,7 @@ ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/vector_math.dart + ../../../f ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/view_embedder/dimensions_provider/custom_element_dimensions_provider.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/view_embedder/dimensions_provider/dimensions_provider.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/view_embedder/dimensions_provider/full_page_dimensions_provider.dart + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/view_embedder/dom_manager.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/view_embedder/embedding_strategy/custom_element_embedding_strategy.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/view_embedder/embedding_strategy/embedding_strategy.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/view_embedder/embedding_strategy/full_page_embedding_strategy.dart + ../../../flutter/LICENSE @@ -6552,6 +6553,7 @@ FILE: ../../../flutter/lib/web_ui/lib/src/engine/vector_math.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/view_embedder/dimensions_provider/custom_element_dimensions_provider.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/view_embedder/dimensions_provider/dimensions_provider.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/view_embedder/dimensions_provider/full_page_dimensions_provider.dart +FILE: ../../../flutter/lib/web_ui/lib/src/engine/view_embedder/dom_manager.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/view_embedder/embedding_strategy/custom_element_embedding_strategy.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/view_embedder/embedding_strategy/embedding_strategy.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/view_embedder/embedding_strategy/full_page_embedding_strategy.dart diff --git a/engine/src/flutter/lib/web_ui/lib/src/engine.dart b/engine/src/flutter/lib/web_ui/lib/src/engine.dart index 974411798a..d6df3f0c20 100644 --- a/engine/src/flutter/lib/web_ui/lib/src/engine.dart +++ b/engine/src/flutter/lib/web_ui/lib/src/engine.dart @@ -187,6 +187,7 @@ export 'engine/vector_math.dart'; export 'engine/view_embedder/dimensions_provider/custom_element_dimensions_provider.dart'; export 'engine/view_embedder/dimensions_provider/dimensions_provider.dart'; export 'engine/view_embedder/dimensions_provider/full_page_dimensions_provider.dart'; +export 'engine/view_embedder/dom_manager.dart'; export 'engine/view_embedder/embedding_strategy/custom_element_embedding_strategy.dart'; export 'engine/view_embedder/embedding_strategy/embedding_strategy.dart'; export 'engine/view_embedder/embedding_strategy/full_page_embedding_strategy.dart'; 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 7f362eee1f..57904dc838 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 @@ -75,8 +75,8 @@ class FlutterViewEmbedder { /// /// This element is inserted after the [semanticsHostElement] so that /// platform views take precedence in DOM event handling. - DomElement? get sceneHostElement => _sceneHostElement; - DomElement? _sceneHostElement; + DomElement get sceneHostElement => _sceneHostElement; + late DomElement _sceneHostElement; /// A child element of body outside the shadowroot that hosts /// global resources such svg filters and clip paths when using webkit. @@ -95,8 +95,8 @@ class FlutterViewEmbedder { /// /// This element is inserted before the [semanticsHostElement] so that /// platform views take precedence in DOM event handling. - DomElement? get semanticsHostElement => _semanticsHostElement; - DomElement? _semanticsHostElement; + DomElement get semanticsHostElementDEPRECATED => _semanticsHostElement; + late DomElement _semanticsHostElement; /// The last scene element rendered by the [render] method. DomElement? get sceneElement => _sceneElement; @@ -110,7 +110,7 @@ class FlutterViewEmbedder { if (sceneElement != _sceneElement) { _sceneElement?.remove(); _sceneElement = sceneElement; - _sceneHostElement!.append(sceneElement!); + _sceneHostElement.append(sceneElement!); } } @@ -120,17 +120,17 @@ class FlutterViewEmbedder { /// which captures semantics input events. The semantics DOM tree must be a /// child of the glass pane element so that events bubble up to the glass pane /// if they are not handled by semantics. - DomElement get flutterViewElement => _flutterViewElement; + DomElement get flutterViewElementDEPRECATED => _flutterViewElement; late DomElement _flutterViewElement; - DomElement get glassPaneElement => _glassPaneElement; + DomElement get glassPaneElementDEPRECATED => _glassPaneElement; late DomElement _glassPaneElement; /// The shadow root of the [glassPaneElement], which contains the whole Flutter app. - DomShadowRoot get glassPaneShadow => _glassPaneShadow; + DomShadowRoot get glassPaneShadowDEPRECATED => _glassPaneShadow; late DomShadowRoot _glassPaneShadow; - DomElement get textEditingHostNode => _textEditingHostNode; + DomElement get textEditingHostNodeDEPRECATED => _textEditingHostNode; late DomElement _textEditingHostNode; AccessibilityAnnouncements get accessibilityAnnouncements => _accessibilityAnnouncements; @@ -169,16 +169,16 @@ class FlutterViewEmbedder { // // The embeddingStrategy will take care of cleaning up the glassPane on hot // restart. - _embeddingStrategy.attachGlassPane(flutterViewElement); - flutterViewElement.appendChild(glassPaneElement); + _embeddingStrategy.attachGlassPane(_flutterViewElement); + _flutterViewElement.appendChild(_glassPaneElement); - if (getJsProperty(glassPaneElement, 'attachShadow') == null) { + if (getJsProperty(_glassPaneElement, 'attachShadow') == null) { throw UnsupportedError('ShadowDOM is not supported in this browser.'); } // Create a [HostNode] under the glass pane element, and attach everything // there, instead of directly underneath the glass panel. - final DomShadowRoot shadowRoot = glassPaneElement.attachShadow({ + final DomShadowRoot shadowRoot = _glassPaneElement.attachShadow({ 'mode': 'open', // This needs to stay false to prevent issues like this: // - https://github.com/flutter/flutter/issues/85759 @@ -196,7 +196,7 @@ class FlutterViewEmbedder { ); _textEditingHostNode = - createTextEditingHostNode(flutterViewElement, defaultCssFont, configuration.nonce); + createTextEditingHostNode(_flutterViewElement, defaultCssFont, configuration.nonce); // Don't allow the scene to receive pointer events. _sceneHostElement = domDocument.createElement('flt-scene-host') @@ -204,12 +204,10 @@ class FlutterViewEmbedder { renderer.reset(this); - final DomElement semanticsHostElement = - domDocument.createElement('flt-semantics-host'); - semanticsHostElement.style + _semanticsHostElement = domDocument.createElement('flt-semantics-host'); + _semanticsHostElement.style ..position = 'absolute' ..transformOrigin = '0 0 0'; - _semanticsHostElement = semanticsHostElement; updateSemanticsScreenProperties(); final DomElement accessibilityPlaceholder = EngineSemanticsOwner @@ -220,7 +218,7 @@ class FlutterViewEmbedder { _accessibilityAnnouncements = AccessibilityAnnouncements(hostElement: announcementsElement); shadowRoot.append(accessibilityPlaceholder); - shadowRoot.append(_sceneHostElement!); + shadowRoot.append(_sceneHostElement); shadowRoot.append(announcementsElement); // The semantic host goes last because hit-test order-wise it must be @@ -233,17 +231,17 @@ class FlutterViewEmbedder { // elements transparent. This way, if a platform view appears among other // interactive Flutter widgets, as long as those widgets do not intersect // with the platform view, the platform view will be reachable. - flutterViewElement.appendChild(semanticsHostElement); + _flutterViewElement.appendChild(_semanticsHostElement); // When debugging semantics, make the scene semi-transparent so that the // semantics tree is more prominent. if (configuration.debugShowSemanticsNodes) { - _sceneHostElement!.style.opacity = '0.3'; + _sceneHostElement.style.opacity = '0.3'; } KeyboardBinding.initInstance(); PointerBinding.initInstance( - flutterViewElement, + _flutterViewElement, KeyboardBinding.instance!.converter, ); @@ -259,7 +257,7 @@ class FlutterViewEmbedder { /// logical pixels. To compensate, an inverse scale is injected at the root /// level. void updateSemanticsScreenProperties() { - _semanticsHostElement!.style + _semanticsHostElement.style .setProperty('transform', 'scale(${1 / window.devicePixelRatio})'); } @@ -301,9 +299,9 @@ class FlutterViewEmbedder { if (isWebKit) { // The resourcesHost *must* be a sibling of the glassPaneElement. _embeddingStrategy.attachResourcesHost(resourcesHost, - nextTo: flutterViewElement); + nextTo: _flutterViewElement); } else { - glassPaneShadow.insertBefore(resourcesHost, glassPaneShadow.firstChild); + _glassPaneShadow.insertBefore(resourcesHost, _glassPaneShadow.firstChild); } _resourcesHost = resourcesHost; } diff --git a/engine/src/flutter/lib/web_ui/lib/src/engine/pointer_binding/event_position_helper.dart b/engine/src/flutter/lib/web_ui/lib/src/engine/pointer_binding/event_position_helper.dart index a2db5d7538..2331a05b09 100644 --- a/engine/src/flutter/lib/web_ui/lib/src/engine/pointer_binding/event_position_helper.dart +++ b/engine/src/flutter/lib/web_ui/lib/src/engine/pointer_binding/event_position_helper.dart @@ -4,13 +4,13 @@ import 'dart:typed_data'; -import 'package:ui/src/engine/embedder.dart'; -import 'package:ui/src/engine/text_editing/text_editing.dart'; -import 'package:ui/src/engine/vector_math.dart'; import 'package:ui/ui.dart' as ui show Offset; import '../dom.dart'; +import '../platform_dispatcher.dart'; import '../semantics.dart' show EngineSemanticsOwner; +import '../text_editing/text_editing.dart'; +import '../vector_math.dart'; /// Returns an [ui.Offset] of the position of [event], relative to the position of [actualTarget]. /// @@ -30,7 +30,10 @@ ui.Offset computeEventOffsetToTarget(DomMouseEvent event, DomElement actualTarge } // On one of our text-editing nodes - final bool isInput = flutterViewEmbedder.textEditingHostNode.contains(event.target! as DomNode); + // TODO(mdebbar): There could be multiple views with multiple text editing hosts. + // https://github.com/flutter/flutter/issues/137344 + final DomElement textEditingHost = EnginePlatformDispatcher.instance.implicitView!.dom.textEditingHost; + final bool isInput = textEditingHost.contains(event.target! as DomNode); if (isInput) { final EditableTextGeometry? inputGeometry = textEditing.strategy.geometry; if (inputGeometry != null) { diff --git a/engine/src/flutter/lib/web_ui/lib/src/engine/semantics/semantics.dart b/engine/src/flutter/lib/web_ui/lib/src/engine/semantics/semantics.dart index 8a6ec7c0d3..82d9a2d874 100644 --- a/engine/src/flutter/lib/web_ui/lib/src/engine/semantics/semantics.dart +++ b/engine/src/flutter/lib/web_ui/lib/src/engine/semantics/semantics.dart @@ -14,7 +14,6 @@ import '../alarm_clock.dart'; import '../browser_detection.dart'; import '../configuration.dart'; import '../dom.dart'; -import '../embedder.dart'; import '../platform_dispatcher.dart'; import '../util.dart'; import '../vector_math.dart'; @@ -2198,7 +2197,10 @@ class EngineSemanticsOwner { if (_rootSemanticsElement == null) { final SemanticsObject root = _semanticsTree[0]!; _rootSemanticsElement = root.element; - flutterViewEmbedder.semanticsHostElement!.append(root.element); + // TODO(mdebbar): There could be multiple views with multiple semantics hosts. + // https://github.com/flutter/flutter/issues/137344 + final DomElement semanticsHost = EnginePlatformDispatcher.instance.implicitView!.dom.semanticsHost; + semanticsHost.append(root.element); } _finalizeTree(); diff --git a/engine/src/flutter/lib/web_ui/lib/src/engine/text/measurement.dart b/engine/src/flutter/lib/web_ui/lib/src/engine/text/measurement.dart index a1f3bdf6eb..b5ca5dff66 100644 --- a/engine/src/flutter/lib/web_ui/lib/src/engine/text/measurement.dart +++ b/engine/src/flutter/lib/web_ui/lib/src/engine/text/measurement.dart @@ -4,7 +4,8 @@ import '../../engine.dart' show registerHotRestartListener; import '../dom.dart'; -import '../embedder.dart'; +import '../platform_dispatcher.dart'; +import '../view_embedder/dom_manager.dart'; // TODO(yjbanov): this is a hack we use to compute ideographic baseline; this // number is the ratio ideographic/alphabetic for font Ahem, @@ -14,11 +15,9 @@ import '../embedder.dart'; // anything as of this writing. const double baselineRatioHack = 1.1662499904632568; -/// Hosts ruler DOM elements in a hidden container under a `root` [DomNode]. -/// -/// The `root` [DomNode] is optional. Defaults to [flutterViewEmbedder.glassPaneShadow]. +/// Hosts ruler DOM elements in a hidden container under [DomManager.renderingHost]. class RulerHost { - RulerHost({DomNode? root}) { + RulerHost() { _rulerHost.style ..position = 'fixed' ..visibility = 'hidden' @@ -28,11 +27,10 @@ class RulerHost { ..width = '0' ..height = '0'; - if (root == null) { - flutterViewEmbedder.glassPaneShadow.appendChild(_rulerHost); - } else { - root.appendChild(_rulerHost); - } + // TODO(mdebbar): There could be multiple views with multiple rendering hosts. + // https://github.com/flutter/flutter/issues/137344 + final DomNode renderingHost = EnginePlatformDispatcher.instance.implicitView!.dom.renderingHost; + renderingHost.appendChild(_rulerHost); registerHotRestartListener(dispose); } diff --git a/engine/src/flutter/lib/web_ui/lib/src/engine/text_editing/text_editing.dart b/engine/src/flutter/lib/web_ui/lib/src/engine/text_editing/text_editing.dart index 3be53ed83c..8b4dd212c1 100644 --- a/engine/src/flutter/lib/web_ui/lib/src/engine/text_editing/text_editing.dart +++ b/engine/src/flutter/lib/web_ui/lib/src/engine/text_editing/text_editing.dart @@ -11,7 +11,6 @@ import 'package:ui/ui.dart' as ui; import '../browser_detection.dart'; import '../dom.dart'; -import '../embedder.dart'; import '../mouse/prevent_default.dart'; import '../platform_dispatcher.dart'; import '../safe_browser_api.dart'; @@ -51,8 +50,9 @@ void _emptyCallback(dynamic _) {} /// The default [HostNode] that hosts all DOM required for text editing when a11y is not enabled. @visibleForTesting -DomElement get defaultTextEditingRoot => - flutterViewEmbedder.textEditingHostNode; +// TODO(mdebbar): There could be multiple views with multiple text editing hosts. +// https://github.com/flutter/flutter/issues/137344 +DomElement get defaultTextEditingRoot => EnginePlatformDispatcher.instance.implicitView!.dom.textEditingHost; /// These style attributes are constant throughout the life time of an input /// element. diff --git a/engine/src/flutter/lib/web_ui/lib/src/engine/view_embedder/dom_manager.dart b/engine/src/flutter/lib/web_ui/lib/src/engine/view_embedder/dom_manager.dart new file mode 100644 index 0000000000..44f3468611 --- /dev/null +++ b/engine/src/flutter/lib/web_ui/lib/src/engine/view_embedder/dom_manager.dart @@ -0,0 +1,66 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:ui/ui.dart' as ui; + +import '../dom.dart'; +import '../embedder.dart'; + +/// Manages DOM elements and the DOM structure for a [ui.FlutterView]. +/// +/// Here's the general DOM structure of a Flutter View: +/// +/// [rootElement] +/// | +/// +- [platformViewsHost] +/// | | +/// | +- [renderingHost] #shadow-root +/// | | | +/// | | +- +/// | | | +/// | | +- +/// | | | | +/// | | | +- +/// | | | +/// | | +- +/// | | +/// | +- ...platform views +/// | +/// +- [textEditingHost] +/// | | +/// | +- ...text fields +/// | +/// +- [semanticsHost] +/// | +/// +- ...semantics nodes +/// +class DomManager { + DomManager.fromFlutterViewEmbedderDEPRECATED(this._embedder); + + final FlutterViewEmbedder _embedder; + + /// The root DOM element for the entire Flutter View. + /// + /// This is where input events are captured, such as pointer events. + /// + /// If semantics is enabled, this element also contains the semantics DOM tree, + /// which captures semantics input events. + DomElement get rootElement => _embedder.flutterViewElementDEPRECATED; + + /// Hosts all platform view elements. + DomElement get platformViewsHost => _embedder.glassPaneElementDEPRECATED; + + /// Hosts all rendering elements and canvases. + DomShadowRoot get renderingHost => _embedder.glassPaneShadowDEPRECATED; + + /// Hosts all text editing elements. + DomElement get textEditingHost => _embedder.textEditingHostNodeDEPRECATED; + + /// Hosts the semantics tree. + /// + /// This element is in front of the [renderingHost] and [platformViewsHost]. + /// Otherwise, the phone will disable focusing by touch, only by tabbing + /// around the UI. + DomElement get semanticsHost => _embedder.semanticsHostElementDEPRECATED; +} 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 55b24574b2..f3c5e9b2b8 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 @@ -24,6 +24,7 @@ import 'platform_dispatcher.dart'; import 'platform_views/message_handler.dart'; import 'services.dart'; import 'util.dart'; +import 'view_embedder/dom_manager.dart'; typedef _HandleMessageCallBack = Future Function(); @@ -39,9 +40,9 @@ const int kImplicitViewId = 0; /// a few web-specific properties. abstract interface class EngineFlutterView extends ui.FlutterView { ContextMenu get contextMenu; + DomManager get dom; MouseCursor get mouseCursor; PlatformViewMessageHandler get platformViewMessageHandler; - DomElement get rootElement; } /// The Web implementation of [ui.SingletonFlutterWindow]. @@ -69,17 +70,18 @@ class EngineFlutterWindow extends ui.SingletonFlutterWindow implements EngineFlu final EnginePlatformDispatcher platformDispatcher; @override - late final MouseCursor mouseCursor = MouseCursor(rootElement); + late final MouseCursor mouseCursor = MouseCursor(dom.rootElement); @override - late final ContextMenu contextMenu = ContextMenu(rootElement); + late final ContextMenu contextMenu = ContextMenu(dom.rootElement); @override - DomElement get rootElement => flutterViewEmbedder.flutterViewElement; + late final DomManager dom = + DomManager.fromFlutterViewEmbedderDEPRECATED(flutterViewEmbedder); @override late final PlatformViewMessageHandler platformViewMessageHandler = - PlatformViewMessageHandler(platformViewsContainer: flutterViewEmbedder.glassPaneElement); + PlatformViewMessageHandler(platformViewsContainer: dom.platformViewsHost); /// Handles the browser history integration to allow users to use the back /// button, etc. 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 40b5060fb5..d0b1859816 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 @@ -13,6 +13,10 @@ import 'package:ui/ui_web/src/ui_web.dart' as ui_web; import 'common.dart'; import 'test_data.dart'; +DomElement get platformViewsHost { + return EnginePlatformDispatcher.instance.implicitView!.dom.platformViewsHost; +} + void main() { internalBootstrapBrowserTest(() => testMain); } @@ -41,8 +45,7 @@ void testMain() { // The platform view is now split in two parts. The contents live // as a child of the glassPane, and the slot lives in the glassPane // shadow root. The slot is the one that has pointer events auto. - final DomElement contents = - flutterViewEmbedder.glassPaneElement.querySelector('#view-0')!; + final DomElement contents = platformViewsHost.querySelector('#view-0')!; final DomElement slot = flutterViewEmbedder.sceneElement!.querySelector('slot')!; final DomElement contentsHost = contents.parent!; @@ -594,10 +597,7 @@ void testMain() { _overlay, ]); - expect( - flutterViewEmbedder.glassPaneElement.querySelector('flt-platform-view'), - isNotNull, - ); + expect(platformViewsHost.querySelector('flt-platform-view'), isNotNull); await disposePlatformView(0); @@ -609,10 +609,7 @@ void testMain() { _overlay, ]); - expect( - flutterViewEmbedder.glassPaneElement.querySelector('flt-platform-view'), - isNull, - ); + expect(platformViewsHost.querySelector('flt-platform-view'), isNull); }); test( @@ -681,10 +678,7 @@ void testMain() { _overlay, ]); - expect( - flutterViewEmbedder.glassPaneElement.querySelector('flt-platform-view'), - isNotNull, - ); + expect(platformViewsHost.querySelector('flt-platform-view'), isNotNull); // Render a frame with a different platform view. await createPlatformView(1, 'test-platform-view'); @@ -699,9 +693,9 @@ void testMain() { ]); expect( - flutterViewEmbedder.glassPaneElement - .querySelectorAll('flt-platform-view'), - hasLength(2)); + platformViewsHost.querySelectorAll('flt-platform-view'), + hasLength(2), + ); // Render a frame without a platform view, but also without disposing of // the platform view. @@ -715,9 +709,9 @@ void testMain() { // The actual contents of the platform view are kept in the dom, until // it's actually disposed of! expect( - flutterViewEmbedder.glassPaneElement - .querySelectorAll('flt-platform-view'), - hasLength(2)); + platformViewsHost.querySelectorAll('flt-platform-view'), + hasLength(2), + ); }); test( diff --git a/engine/src/flutter/lib/web_ui/test/engine/embedder_test.dart b/engine/src/flutter/lib/web_ui/test/engine/embedder_test.dart index 29dc8bafdc..b1ec92426e 100644 --- a/engine/src/flutter/lib/web_ui/test/engine/embedder_test.dart +++ b/engine/src/flutter/lib/web_ui/test/engine/embedder_test.dart @@ -47,7 +47,7 @@ void testMain() { final FlutterViewEmbedder embedder = FlutterViewEmbedder(); expect( - embedder.glassPaneShadow.querySelectorAll('flt-semantics-placeholder'), + embedder.glassPaneShadowDEPRECATED.querySelectorAll('flt-semantics-placeholder'), isNotEmpty, ); }); @@ -71,7 +71,7 @@ void testMain() { regularTextField.focus(); DomCSSStyleDeclaration? style = domWindow.getComputedStyle( - embedder.glassPaneShadow.querySelector('input')!, + embedder.glassPaneShadowDEPRECATED.querySelector('input')!, '::placeholder'); expect(style, isNotNull); expect(style.opacity, isNot('0')); @@ -83,7 +83,7 @@ void testMain() { textField.focus(); style = domWindow.getComputedStyle( - embedder.glassPaneShadow.querySelector('input.flt-text-editing')!, + embedder.glassPaneShadowDEPRECATED.querySelector('input.flt-text-editing')!, '::placeholder'); expect(style, isNotNull); expect(style.opacity, '0'); @@ -97,7 +97,7 @@ void testMain() { }); tearDown(() { - embedder.glassPaneElement.remove(); + embedder.glassPaneElementDEPRECATED.remove(); }); test('throws when shadowDom is not available', () { @@ -111,27 +111,27 @@ void testMain() { }); test('Initializes and attaches a shadow root', () { - expect(domInstanceOfString(embedder.glassPaneShadow, 'ShadowRoot'), isTrue); - expect(embedder.glassPaneShadow.host, embedder.glassPaneElement); - expect(embedder.glassPaneShadow, embedder.glassPaneElement.shadowRoot); + expect(domInstanceOfString(embedder.glassPaneShadowDEPRECATED, 'ShadowRoot'), isTrue); + expect(embedder.glassPaneShadowDEPRECATED.host, embedder.glassPaneElementDEPRECATED); + expect(embedder.glassPaneShadowDEPRECATED, embedder.glassPaneElementDEPRECATED.shadowRoot); // The shadow root should be initialized with correct parameters. - expect(embedder.glassPaneShadow.mode, 'open'); + expect(embedder.glassPaneShadowDEPRECATED.mode, 'open'); if (browserEngine != BrowserEngine.firefox && browserEngine != BrowserEngine.webkit) { // Older versions of Safari and Firefox don't support this flag yet. // See: https://caniuse.com/mdn-api_shadowroot_delegatesfocus - expect(embedder.glassPaneShadow.delegatesFocus, isFalse); + expect(embedder.glassPaneShadowDEPRECATED.delegatesFocus, isFalse); } }); test('Attaches a stylesheet to the shadow root', () { final DomElement? style = - embedder.glassPaneShadow.querySelector('#flt-internals-stylesheet'); + embedder.glassPaneShadowDEPRECATED.querySelector('#flt-internals-stylesheet'); expect(style, isNotNull); expect(style!.tagName, equalsIgnoringCase('style')); - expect(style.parentNode, embedder.glassPaneShadow); + expect(style.parentNode, embedder.glassPaneShadowDEPRECATED); }); }); } diff --git a/engine/src/flutter/lib/web_ui/test/engine/pointer_binding_test.dart b/engine/src/flutter/lib/web_ui/test/engine/pointer_binding_test.dart index e85b84bf10..f93d1a2e96 100644 --- a/engine/src/flutter/lib/web_ui/test/engine/pointer_binding_test.dart +++ b/engine/src/flutter/lib/web_ui/test/engine/pointer_binding_test.dart @@ -42,7 +42,8 @@ void main() { void testMain() { ensureFlutterViewEmbedderInitialized(); - final DomElement flutterViewElement = flutterViewEmbedder.flutterViewElement; + final DomElement rootElement = + EnginePlatformDispatcher.instance.implicitView!.dom.rootElement; late double dpi; setUp(() { @@ -496,7 +497,7 @@ void testMain() { }; final DomElement child = createDomHTMLDivElement(); - flutterViewElement.append(child); + rootElement.append(child); final DomEventListener stopPropagationListener = createDomEventListener((DomEvent event) { event.stopPropagation(); @@ -532,7 +533,7 @@ void testMain() { receivedPacket = packet; }; - flutterViewElement.dispatchEvent(context.primaryDown()); + rootElement.dispatchEvent(context.primaryDown()); expect(receivedPacket, isNotNull); expect(receivedPacket!.data[0].buttons, equals(1)); @@ -553,7 +554,7 @@ void testMain() { packets.add(packet); }; - flutterViewElement.dispatchEvent(context.primaryDown()); + rootElement.dispatchEvent(context.primaryDown()); expect(packets, hasLength(1)); expect(packets.single.data, hasLength(2)); @@ -587,7 +588,7 @@ void testMain() { expect(keyboardConverter.keyIsPressed(physicalLeft), false); expect(keyboardConverter.keyIsPressed(physicalRight), false); - flutterViewElement.dispatchEvent(context.primaryDown()); + rootElement.dispatchEvent(context.primaryDown()); expect(keyDataList.length, 1); expectKeyData(keyDataList.last, type: ui.KeyEventType.down, @@ -639,7 +640,7 @@ void testMain() { expect(keyboardConverter.keyIsPressed(physicalRight), false); keyDataList.clear(); // Remove key data generated by handleEvent - flutterViewElement.dispatchEvent(context.primaryDown()); + rootElement.dispatchEvent(context.primaryDown()); expect(keyDataList.length, 0); } @@ -659,7 +660,7 @@ void testMain() { expect(keyboardConverter.keyIsPressed(physicalRight), true); keyDataList.clear(); // Remove key data generated by handleEvent - flutterViewElement.dispatchEvent(context.primaryDown()); + rootElement.dispatchEvent(context.primaryDown()); expect(keyDataList.length, 0); } @@ -709,7 +710,7 @@ void testMain() { expect(keyboardConverter.keyIsPressed(physicalRight), false); keyDataList.clear(); // Remove key data generated by handleEvent - flutterViewElement.dispatchEvent(context.primaryDown()); + rootElement.dispatchEvent(context.primaryDown()); expect(keyDataList.length, 1); expectKeyData(keyDataList.last, type: ui.KeyEventType.up, @@ -738,7 +739,7 @@ void testMain() { expect(keyboardConverter.keyIsPressed(physicalRight), true); keyDataList.clear(); // Remove key data generated by handleEvent - flutterViewElement.dispatchEvent(context.primaryDown()); + rootElement.dispatchEvent(context.primaryDown()); expect(keyDataList.length, 1); expectKeyData(keyDataList.last, type: ui.KeyEventType.up, @@ -790,7 +791,7 @@ void testMain() { expect(keyboardConverter.keyIsPressed(physicalRight), false); keyDataList.clear(); // Remove key data generated by handleEvent - flutterViewElement.dispatchEvent(context.primaryDown()); + rootElement.dispatchEvent(context.primaryDown()); expect(keyDataList.length, 0); } @@ -827,7 +828,7 @@ void testMain() { expect(keyboardConverter.keyIsPressed(physicalAltRight), true); keyDataList.clear(); // Remove key data generated by handleEvent. - flutterViewElement.dispatchEvent(context.primaryDown()); + rootElement.dispatchEvent(context.primaryDown()); expect(keyDataList.length, 1); expectKeyData(keyDataList.last, type: ui.KeyEventType.up, @@ -855,7 +856,7 @@ void testMain() { final DomElement semanticsPlaceholder = createDomElement('flt-semantics-placeholder'); - flutterViewElement.append(semanticsPlaceholder); + rootElement.append(semanticsPlaceholder); // Press on the semantics placeholder. semanticsPlaceholder.dispatchEvent(context.primaryDown( @@ -894,7 +895,7 @@ void testMain() { packets.clear(); // Release the pointer on the semantics placeholder. - flutterViewElement.dispatchEvent(context.primaryUp( + rootElement.dispatchEvent(context.primaryUp( clientX: 100.0, clientY: 200.0, )); @@ -928,7 +929,7 @@ void testMain() { packets.add(packet); }; - flutterViewElement.dispatchEvent(context.hover()); + rootElement.dispatchEvent(context.hover()); expect(packets, hasLength(1)); expect(packets.single.data, hasLength(2)); @@ -952,7 +953,7 @@ void testMain() { packets.add(packet); }; - flutterViewElement.dispatchEvent(context.primaryDown( + rootElement.dispatchEvent(context.primaryDown( clientX: 10.0, clientY: 10.0, )); @@ -964,7 +965,7 @@ void testMain() { expect(packets[0].data[1].change, equals(ui.PointerChange.down)); packets.clear(); - flutterViewElement.dispatchEvent(context.primaryDown( + rootElement.dispatchEvent(context.primaryDown( clientX: 20.0, clientY: 20.0, )); @@ -989,7 +990,7 @@ void testMain() { packets.add(packet); }; - flutterViewElement.dispatchEvent(context.wheel( + rootElement.dispatchEvent(context.wheel( buttons: 0, clientX: 10, clientY: 10, @@ -997,7 +998,7 @@ void testMain() { deltaY: 10, )); - flutterViewElement.dispatchEvent(context.wheel( + rootElement.dispatchEvent(context.wheel( buttons: 0, clientX: 20, clientY: 50, @@ -1005,14 +1006,14 @@ void testMain() { deltaY: 10, )); - flutterViewElement.dispatchEvent(context.mouseDown( + rootElement.dispatchEvent(context.mouseDown( button: 0, buttons: 1, clientX: 20.0, clientY: 50.0, )); - flutterViewElement.dispatchEvent(context.wheel( + rootElement.dispatchEvent(context.wheel( buttons: 1, clientX: 30, clientY: 60, @@ -1114,7 +1115,7 @@ void testMain() { packets.add(packet); }; - flutterViewElement.dispatchEvent(context.wheel( + rootElement.dispatchEvent(context.wheel( buttons: 0, clientX: 10, clientY: 10, @@ -1163,7 +1164,7 @@ void testMain() { packets.add(packet); }; - flutterViewElement.dispatchEvent(context.wheel( + rootElement.dispatchEvent(context.wheel( buttons: 0, clientX: 10, clientY: 10, @@ -1211,7 +1212,7 @@ void testMain() { packets.add(packet); }; - flutterViewElement.dispatchEvent(context.wheel( + rootElement.dispatchEvent(context.wheel( buttons: 0, clientX: 10, clientY: 10, @@ -1222,7 +1223,7 @@ void testMain() { timeStamp: 0, )); - flutterViewElement.dispatchEvent(context.wheel( + rootElement.dispatchEvent(context.wheel( buttons: 0, clientX: 10, clientY: 10, @@ -1233,7 +1234,7 @@ void testMain() { timeStamp: 10, )); - flutterViewElement.dispatchEvent(context.wheel( + rootElement.dispatchEvent(context.wheel( buttons: 0, clientX: 10, clientY: 10, @@ -1244,7 +1245,7 @@ void testMain() { timeStamp: 20, )); - flutterViewElement.dispatchEvent(context.wheel( + rootElement.dispatchEvent(context.wheel( buttons: 0, clientX: 10, clientY: 10, @@ -1255,7 +1256,7 @@ void testMain() { timeStamp: 1000, )); - flutterViewElement.dispatchEvent(context.wheel( + rootElement.dispatchEvent(context.wheel( buttons: 0, clientX: 10, clientY: 10, @@ -1266,7 +1267,7 @@ void testMain() { timeStamp: 1010, )); - flutterViewElement.dispatchEvent(context.wheel( + rootElement.dispatchEvent(context.wheel( buttons: 0, clientX: 10, clientY: 10, @@ -1277,7 +1278,7 @@ void testMain() { timeStamp: 2000, )); - flutterViewElement.dispatchEvent(context.wheel( + rootElement.dispatchEvent(context.wheel( buttons: 0, clientX: 10, clientY: 10, @@ -1452,7 +1453,7 @@ void testMain() { packets.add(packet); }; - flutterViewElement.dispatchEvent(context.wheel( + rootElement.dispatchEvent(context.wheel( buttons: 0, clientX: 10, clientY: 10, @@ -1460,7 +1461,7 @@ void testMain() { deltaY: 120, )); - flutterViewElement.dispatchEvent(context.wheel( + rootElement.dispatchEvent(context.wheel( buttons: 0, clientX: 10, clientY: 10, @@ -1472,7 +1473,7 @@ void testMain() { debugOperatingSystemOverride = OperatingSystem.macOs; KeyboardBinding.instance?.converter.handleEvent(keyDownEvent('ControlLeft', 'Control', kCtrl)); - flutterViewElement.dispatchEvent(context.wheel( + rootElement.dispatchEvent(context.wheel( buttons: 0, clientX: 10, clientY: 10, @@ -1557,7 +1558,7 @@ void testMain() { packets.add(packet); }; - flutterViewElement.dispatchEvent(context.hover( + rootElement.dispatchEvent(context.hover( clientX: 10.0, clientY: 10.0, )); @@ -1580,7 +1581,7 @@ void testMain() { expect(packets[0].data[1].physicalDeltaY, equals(0.0)); packets.clear(); - flutterViewElement.dispatchEvent(context.hover( + rootElement.dispatchEvent(context.hover( clientX: 20.0, clientY: 20.0, )); @@ -1595,7 +1596,7 @@ void testMain() { expect(packets[0].data[0].physicalDeltaY, equals(10.0 * dpi)); packets.clear(); - flutterViewElement.dispatchEvent(context.primaryDown( + rootElement.dispatchEvent(context.primaryDown( clientX: 20.0, clientY: 20.0, )); @@ -1610,7 +1611,7 @@ void testMain() { expect(packets[0].data[0].physicalDeltaY, equals(0.0)); packets.clear(); - flutterViewElement.dispatchEvent(context.primaryMove( + rootElement.dispatchEvent(context.primaryMove( clientX: 40.0, clientY: 30.0, )); @@ -1625,7 +1626,7 @@ void testMain() { expect(packets[0].data[0].physicalDeltaY, equals(10.0 * dpi)); packets.clear(); - flutterViewElement.dispatchEvent(context.primaryUp( + rootElement.dispatchEvent(context.primaryUp( clientX: 40.0, clientY: 30.0, )); @@ -1640,7 +1641,7 @@ void testMain() { expect(packets[0].data[0].physicalDeltaY, equals(0.0)); packets.clear(); - flutterViewElement.dispatchEvent(context.hover( + rootElement.dispatchEvent(context.hover( clientX: 20.0, clientY: 10.0, )); @@ -1655,7 +1656,7 @@ void testMain() { expect(packets[0].data[0].physicalDeltaY, equals(-20.0 * dpi)); packets.clear(); - flutterViewElement.dispatchEvent(context.primaryDown( + rootElement.dispatchEvent(context.primaryDown( clientX: 20.0, clientY: 10.0, )); @@ -1687,7 +1688,7 @@ void testMain() { // Add and hover - flutterViewElement.dispatchEvent(context.hover( + rootElement.dispatchEvent(context.hover( clientX: 10, clientY: 11, )); @@ -1706,7 +1707,7 @@ void testMain() { expect(packets[0].data[1].buttons, equals(0)); packets.clear(); - flutterViewElement.dispatchEvent(context.mouseDown( + rootElement.dispatchEvent(context.mouseDown( button: 0, buttons: 1, clientX: 10.0, @@ -1721,7 +1722,7 @@ void testMain() { expect(packets[0].data[0].buttons, equals(1)); packets.clear(); - flutterViewElement.dispatchEvent(context.mouseMove( + rootElement.dispatchEvent(context.mouseMove( button: _kNoButtonChange, buttons: 1, clientX: 20.0, @@ -1736,7 +1737,7 @@ void testMain() { expect(packets[0].data[0].buttons, equals(1)); packets.clear(); - flutterViewElement.dispatchEvent(context.mouseUp( + rootElement.dispatchEvent(context.mouseUp( button: 0, clientX: 20.0, clientY: 21.0, @@ -1751,7 +1752,7 @@ void testMain() { packets.clear(); // Drag with secondary button - flutterViewElement.dispatchEvent(context.mouseDown( + rootElement.dispatchEvent(context.mouseDown( button: 2, buttons: 2, clientX: 20.0, @@ -1766,7 +1767,7 @@ void testMain() { expect(packets[0].data[0].buttons, equals(2)); packets.clear(); - flutterViewElement.dispatchEvent(context.mouseMove( + rootElement.dispatchEvent(context.mouseMove( button: _kNoButtonChange, buttons: 2, clientX: 30.0, @@ -1781,7 +1782,7 @@ void testMain() { expect(packets[0].data[0].buttons, equals(2)); packets.clear(); - flutterViewElement.dispatchEvent(context.mouseUp( + rootElement.dispatchEvent(context.mouseUp( button: 2, clientX: 30.0, clientY: 31.0, @@ -1796,7 +1797,7 @@ void testMain() { packets.clear(); // Drag with middle button - flutterViewElement.dispatchEvent(context.mouseDown( + rootElement.dispatchEvent(context.mouseDown( button: 1, buttons: 4, clientX: 30.0, @@ -1811,7 +1812,7 @@ void testMain() { expect(packets[0].data[0].buttons, equals(4)); packets.clear(); - flutterViewElement.dispatchEvent(context.mouseMove( + rootElement.dispatchEvent(context.mouseMove( button: _kNoButtonChange, buttons: 4, clientX: 40.0, @@ -1826,7 +1827,7 @@ void testMain() { expect(packets[0].data[0].buttons, equals(4)); packets.clear(); - flutterViewElement.dispatchEvent(context.mouseUp( + rootElement.dispatchEvent(context.mouseUp( button: 1, clientX: 40.0, clientY: 41.0, @@ -1842,7 +1843,7 @@ void testMain() { // Leave - flutterViewElement.dispatchEvent(context.mouseLeave( + rootElement.dispatchEvent(context.mouseLeave( buttons: 1, clientX: 1000.0, clientY: 2000.0, @@ -1850,7 +1851,7 @@ void testMain() { expect(packets, isEmpty); packets.clear(); - flutterViewElement.dispatchEvent(context.mouseLeave( + rootElement.dispatchEvent(context.mouseLeave( buttons: 0, clientX: 1000.0, clientY: 2000.0, @@ -1880,7 +1881,7 @@ void testMain() { }; // Press LMB. - flutterViewElement.dispatchEvent(context.mouseDown( + rootElement.dispatchEvent(context.mouseDown( button: 0, buttons: 1, )); @@ -1895,7 +1896,7 @@ void testMain() { packets.clear(); // Press MMB. - flutterViewElement.dispatchEvent(context.mouseMove( + rootElement.dispatchEvent(context.mouseMove( button: 1, buttons: 5, )); @@ -1907,7 +1908,7 @@ void testMain() { packets.clear(); // Release LMB. - flutterViewElement.dispatchEvent(context.mouseMove( + rootElement.dispatchEvent(context.mouseMove( button: 0, buttons: 4, )); @@ -1919,7 +1920,7 @@ void testMain() { packets.clear(); // Release MMB. - flutterViewElement.dispatchEvent(context.mouseUp( + rootElement.dispatchEvent(context.mouseUp( button: 1, )); expect(packets, hasLength(1)); @@ -1947,7 +1948,7 @@ void testMain() { packets.add(packet); }; - flutterViewElement.dispatchEvent(context.mouseDown( + rootElement.dispatchEvent(context.mouseDown( button: 2, buttons: 2, clientX: 10, @@ -1968,7 +1969,7 @@ void testMain() { expect(packets[0].data[1].buttons, equals(2)); packets.clear(); - flutterViewElement.dispatchEvent(context.mouseMove( + rootElement.dispatchEvent(context.mouseMove( button: _kNoButtonChange, buttons: 2, clientX: 20.0, @@ -1983,7 +1984,7 @@ void testMain() { expect(packets[0].data[0].buttons, equals(2)); packets.clear(); - flutterViewElement.dispatchEvent(context.mouseMove( + rootElement.dispatchEvent(context.mouseMove( button: _kNoButtonChange, buttons: 2, clientX: 20.0, @@ -1998,7 +1999,7 @@ void testMain() { expect(packets[0].data[0].buttons, equals(2)); packets.clear(); - flutterViewElement.dispatchEvent(context.mouseUp( + rootElement.dispatchEvent(context.mouseUp( button: 2, clientX: 20.0, clientY: 21.0, @@ -2034,7 +2035,7 @@ void testMain() { }; // Press RMB and hold, popping up the context menu. - flutterViewElement.dispatchEvent(context.mouseDown( + rootElement.dispatchEvent(context.mouseDown( button: 2, buttons: 2, )); @@ -2051,7 +2052,7 @@ void testMain() { // Press LMB. The event will have "button: -1" here, despite the change // in "buttons", probably because the "press" gesture was absorbed by // dismissing the context menu. - flutterViewElement.dispatchEvent(context.mouseMove( + rootElement.dispatchEvent(context.mouseMove( button: _kNoButtonChange, buttons: 3, )); @@ -2063,7 +2064,7 @@ void testMain() { packets.clear(); // Release LMB. - flutterViewElement.dispatchEvent(context.mouseMove( + rootElement.dispatchEvent(context.mouseMove( button: 0, buttons: 2, )); @@ -2075,7 +2076,7 @@ void testMain() { packets.clear(); // Release RMB. - flutterViewElement.dispatchEvent(context.mouseUp( + rootElement.dispatchEvent(context.mouseUp( button: 2, )); expect(packets, hasLength(1)); @@ -2107,7 +2108,7 @@ void testMain() { // Press RMB popping up the context menu, then release by LMB down and up. // Browser won't send up event in that case. - flutterViewElement.dispatchEvent(context.mouseDown( + rootElement.dispatchEvent(context.mouseDown( button: 2, buttons: 2, )); @@ -2122,7 +2123,7 @@ void testMain() { packets.clear(); // User now hovers. - flutterViewElement.dispatchEvent(context.mouseMove( + rootElement.dispatchEvent(context.mouseMove( button: _kNoButtonChange, buttons: 0, )); @@ -2156,7 +2157,7 @@ void testMain() { }; // Press RMB and hold, popping up the context menu. - flutterViewElement.dispatchEvent(context.mouseMove( + rootElement.dispatchEvent(context.mouseMove( button: -1, buttons: 2, clientX: 10.0, @@ -2193,7 +2194,7 @@ void testMain() { }; // Press RMB and hold, popping up the context menu. - flutterViewElement.dispatchEvent(context.mouseDown( + rootElement.dispatchEvent(context.mouseDown( button: 2, buttons: 2, clientX: 10.0, @@ -2212,7 +2213,7 @@ void testMain() { // Move the mouse. The event will have "buttons: 0" because RMB was // released but the browser didn't send a pointerup/mouseup event. // The hover is also triggered at a different position. - flutterViewElement.dispatchEvent(context.hover( + rootElement.dispatchEvent(context.hover( clientX: 20.0, clientY: 20.0, )); @@ -2256,7 +2257,7 @@ void testMain() { }; // Press RMB and hold, popping up the context menu. - flutterViewElement.dispatchEvent(context.mouseDown( + rootElement.dispatchEvent(context.mouseDown( button: 2, buttons: 2, clientX: 10.0, @@ -2273,7 +2274,7 @@ void testMain() { packets.clear(); // Press LMB. - flutterViewElement.dispatchEvent(context.mouseDown( + rootElement.dispatchEvent(context.mouseDown( button: 0, buttons: 3, clientX: 20.0, @@ -2287,7 +2288,7 @@ void testMain() { packets.clear(); // Release LMB. - flutterViewElement.dispatchEvent(context.primaryUp( + rootElement.dispatchEvent(context.primaryUp( clientX: 20.0, clientY: 20.0, )); @@ -2319,7 +2320,7 @@ void testMain() { }; // Press RMB and hold, popping up the context menu. - flutterViewElement.dispatchEvent(context.mouseDown( + rootElement.dispatchEvent(context.mouseDown( button: 2, buttons: 2, clientX: 10.0, @@ -2337,7 +2338,7 @@ void testMain() { // Press RMB again. In Chrome, when RMB is clicked again while the // context menu is still active, it sends a pointerdown/mousedown event // with "buttons:0". We convert this to pointer up, pointer down. - flutterViewElement.dispatchEvent(context.mouseDown( + rootElement.dispatchEvent(context.mouseDown( button: 2, buttons: 0, clientX: 20.0, @@ -2359,7 +2360,7 @@ void testMain() { packets.clear(); // Release RMB. - flutterViewElement.dispatchEvent(context.mouseUp( + rootElement.dispatchEvent(context.mouseUp( button: 2, clientX: 20.0, clientY: 20.0, @@ -2394,7 +2395,7 @@ void testMain() { }; // Press RMB, popping up the context menu. - flutterViewElement.dispatchEvent(context.mouseDown( + rootElement.dispatchEvent(context.mouseDown( button: 2, buttons: 2, clientX: 10.0, @@ -2410,7 +2411,7 @@ void testMain() { packets.clear(); // RMB up. - flutterViewElement.dispatchEvent(context.mouseUp( + rootElement.dispatchEvent(context.mouseUp( button: 2, clientX: 10.0, clientY: 10.0, @@ -2425,7 +2426,7 @@ void testMain() { // Press RMB again. In Chrome, when RMB is clicked again while the // context menu is still active, it sends a pointerdown/mousedown event // with "buttons:0". - flutterViewElement.dispatchEvent(context.mouseDown( + rootElement.dispatchEvent(context.mouseDown( button: 2, buttons: 0, clientX: 20.0, @@ -2442,7 +2443,7 @@ void testMain() { packets.clear(); // Release RMB. - flutterViewElement.dispatchEvent(context.mouseUp( + rootElement.dispatchEvent(context.mouseUp( button: 2, clientX: 20.0, clientY: 20.0, @@ -2480,7 +2481,7 @@ void testMain() { }; // Press RMB and hold, popping up the context menu. - flutterViewElement.dispatchEvent(context.mouseDown( + rootElement.dispatchEvent(context.mouseDown( button: 2, buttons: 2, clientX: 10.0, @@ -2496,7 +2497,7 @@ void testMain() { packets.clear(); // Release RMB. - flutterViewElement.dispatchEvent(context.mouseUp( + rootElement.dispatchEvent(context.mouseUp( button: 2, clientX: 10.0, clientY: 10.0, @@ -2508,7 +2509,7 @@ void testMain() { packets.clear(); // Press RMB again, in a different location. - flutterViewElement.dispatchEvent(context.mouseDown( + rootElement.dispatchEvent(context.mouseDown( button: 2, buttons: 2, clientX: 20.0, @@ -2546,7 +2547,7 @@ void testMain() { }; // Press and hold LMB. - flutterViewElement.dispatchEvent(context.mouseDown( + rootElement.dispatchEvent(context.mouseDown( button: 0, buttons: 1, clientX: 5.0, @@ -2565,7 +2566,7 @@ void testMain() { // Press and hold RMB. The pointer is already down, so we only send a move // to update the position of the pointer. - flutterViewElement.dispatchEvent(context.mouseDown( + rootElement.dispatchEvent(context.mouseDown( button: 2, buttons: 3, clientX: 20.0, @@ -2581,7 +2582,7 @@ void testMain() { // Release LMB. The pointer is still down (RMB), so we only send a move to // update the position of the pointer. - flutterViewElement.dispatchEvent(context.mouseUp( + rootElement.dispatchEvent(context.mouseUp( button: 0, buttons: 2, clientX: 30.0, @@ -2596,7 +2597,7 @@ void testMain() { packets.clear(); // Release RMB. There's no more buttons down, so we send an up event. - flutterViewElement.dispatchEvent(context.mouseUp( + rootElement.dispatchEvent(context.mouseUp( button: 2, buttons: 0, clientX: 30.0, @@ -2627,26 +2628,26 @@ void testMain() { }; // Press and drag around. - flutterViewElement.dispatchEvent(context.primaryDown( + rootElement.dispatchEvent(context.primaryDown( clientX: 10.0, clientY: 10.0, )); - flutterViewElement.dispatchEvent(context.primaryMove( + rootElement.dispatchEvent(context.primaryMove( clientX: 12.0, clientY: 10.0, )); - flutterViewElement.dispatchEvent(context.primaryMove( + rootElement.dispatchEvent(context.primaryMove( clientX: 15.0, clientY: 10.0, )); - flutterViewElement.dispatchEvent(context.primaryMove( + rootElement.dispatchEvent(context.primaryMove( clientX: 20.0, clientY: 10.0, )); packets.clear(); // Move outside the flutterViewElement. - flutterViewElement.dispatchEvent(context.primaryMove( + rootElement.dispatchEvent(context.primaryMove( clientX: 900.0, clientY: 1900.0, )); @@ -2658,7 +2659,7 @@ void testMain() { packets.clear(); // Release outside the flutterViewElement. - flutterViewElement.dispatchEvent(context.primaryUp( + rootElement.dispatchEvent(context.primaryUp( clientX: 1000.0, clientY: 2000.0, )); @@ -2694,7 +2695,7 @@ void testMain() { context.multiTouchDown(const <_TouchDetails>[ _TouchDetails(pointer: 2, clientX: 100, clientY: 101), _TouchDetails(pointer: 3, clientX: 200, clientY: 201), - ]).forEach(flutterViewElement.dispatchEvent); + ]).forEach(rootElement.dispatchEvent); if (context.runtimeType == _PointerEventContext) { expect(packets.length, 2); expect(packets[0].data.length, 2); @@ -2741,7 +2742,7 @@ void testMain() { context.multiTouchMove(const <_TouchDetails>[ _TouchDetails(pointer: 3, clientX: 300, clientY: 302), _TouchDetails(pointer: 2, clientX: 400, clientY: 402), - ]).forEach(flutterViewElement.dispatchEvent); + ]).forEach(rootElement.dispatchEvent); if (context.runtimeType == _PointerEventContext) { expect(packets.length, 2); expect(packets[0].data.length, 1); @@ -2775,7 +2776,7 @@ void testMain() { // One pointer up context.multiTouchUp(const <_TouchDetails>[ _TouchDetails(pointer: 3, clientX: 300, clientY: 302), - ]).forEach(flutterViewElement.dispatchEvent); + ]).forEach(rootElement.dispatchEvent); expect(packets, hasLength(1)); expect(packets[0].data, hasLength(2)); expect(packets[0].data[0].change, equals(ui.PointerChange.up)); @@ -2798,7 +2799,7 @@ void testMain() { // Another pointer up context.multiTouchUp(const <_TouchDetails>[ _TouchDetails(pointer: 2, clientX: 400, clientY: 402), - ]).forEach(flutterViewElement.dispatchEvent); + ]).forEach(rootElement.dispatchEvent); expect(packets, hasLength(1)); expect(packets[0].data, hasLength(2)); expect(packets[0].data[0].change, equals(ui.PointerChange.up)); @@ -2822,7 +2823,7 @@ void testMain() { context.multiTouchDown(const <_TouchDetails>[ _TouchDetails(pointer: 3, clientX: 500, clientY: 501), _TouchDetails(pointer: 2, clientX: 600, clientY: 601), - ]).forEach(flutterViewElement.dispatchEvent); + ]).forEach(rootElement.dispatchEvent); if (context.runtimeType == _PointerEventContext) { expect(packets.length, 2); expect(packets[0].data.length, 2); @@ -2884,13 +2885,13 @@ void testMain() { context.multiTouchDown(const <_TouchDetails>[ _TouchDetails(pointer: 2, clientX: 100, clientY: 101), _TouchDetails(pointer: 3, clientX: 200, clientY: 201), - ]).forEach(flutterViewElement.dispatchEvent); + ]).forEach(rootElement.dispatchEvent); packets.clear(); // Down event is tested in other tests. // One pointer cancel context.multiTouchCancel(const <_TouchDetails>[ _TouchDetails(pointer: 3, clientX: 300, clientY: 302), - ]).forEach(flutterViewElement.dispatchEvent); + ]).forEach(rootElement.dispatchEvent); expect(packets.length, 1); expect(packets[0].data.length, 2); expect(packets[0].data[0].change, equals(ui.PointerChange.cancel)); @@ -2928,7 +2929,7 @@ void testMain() { context.multiTouchDown(const <_TouchDetails>[ _TouchDetails(pointer: 1, clientX: 100, clientY: 101), - ]).forEach(flutterViewElement.dispatchEvent); + ]).forEach(rootElement.dispatchEvent); expect(packets, hasLength(1)); // An add will be synthesized. expect(packets[0].data, hasLength(2)); @@ -2941,7 +2942,7 @@ void testMain() { context.multiTouchDown(const <_TouchDetails>[ _TouchDetails(pointer: 2, clientX: 200, clientY: 202), - ]).forEach(flutterViewElement.dispatchEvent); + ]).forEach(rootElement.dispatchEvent); // An add will be synthesized. expect(packets, hasLength(1)); expect(packets[0].data, hasLength(2)); @@ -2968,12 +2969,12 @@ void testMain() { context.multiTouchUp(const <_TouchDetails>[ _TouchDetails(pointer: 23, clientX: 200, clientY: 202), - ]).forEach(flutterViewElement.dispatchEvent); + ]).forEach(rootElement.dispatchEvent); expect(packets, hasLength(0)); context.multiTouchCancel(const <_TouchDetails>[ _TouchDetails(pointer: 24, clientX: 200, clientY: 202), - ]).forEach(flutterViewElement.dispatchEvent); + ]).forEach(rootElement.dispatchEvent); expect(packets, hasLength(0)); }, ); @@ -2996,7 +2997,7 @@ void testMain() { packets.add(packet); }; - flutterViewElement.dispatchEvent(context.mouseDown( + rootElement.dispatchEvent(context.mouseDown( pointerId: 12, button: 0, buttons: 1, @@ -3014,7 +3015,7 @@ void testMain() { expect( () { - flutterViewElement.dispatchEvent(context.mouseUp( + rootElement.dispatchEvent(context.mouseUp( pointerId: 41, button: 0, buttons: 0, @@ -3049,7 +3050,7 @@ void testMain() { context.multiTouchDown(const <_TouchDetails>[ _TouchDetails(pointer: 1, clientX: 20, clientY: 20), - ]).forEach(flutterViewElement.dispatchEvent); + ]).forEach(rootElement.dispatchEvent); expect(packets, hasLength(1)); expect(packets[0].data, hasLength(2)); expect(packets[0].data[0].change, equals(ui.PointerChange.add)); @@ -3071,7 +3072,7 @@ void testMain() { context.multiTouchMove(const <_TouchDetails>[ _TouchDetails(pointer: 1, clientX: 40, clientY: 30), - ]).forEach(flutterViewElement.dispatchEvent); + ]).forEach(rootElement.dispatchEvent); expect(packets, hasLength(1)); expect(packets[0].data, hasLength(1)); expect(packets[0].data[0].change, equals(ui.PointerChange.move)); @@ -3085,7 +3086,7 @@ void testMain() { context.multiTouchUp(const <_TouchDetails>[ _TouchDetails(pointer: 1, clientX: 40, clientY: 30), - ]).forEach(flutterViewElement.dispatchEvent); + ]).forEach(rootElement.dispatchEvent); expect(packets, hasLength(1)); expect(packets[0].data, hasLength(2)); expect(packets[0].data[0].change, equals(ui.PointerChange.up)); @@ -3107,7 +3108,7 @@ void testMain() { context.multiTouchDown(const <_TouchDetails>[ _TouchDetails(pointer: 2, clientX: 20, clientY: 10), - ]).forEach(flutterViewElement.dispatchEvent); + ]).forEach(rootElement.dispatchEvent); expect(packets, hasLength(1)); expect(packets[0].data, hasLength(2)); expect(packets[0].data[0].change, equals(ui.PointerChange.add)); diff --git a/engine/src/flutter/lib/web_ui/test/engine/semantics/accessibility_test.dart b/engine/src/flutter/lib/web_ui/test/engine/semantics/accessibility_test.dart index f39236b8c9..36385dd066 100644 --- a/engine/src/flutter/lib/web_ui/test/engine/semantics/accessibility_test.dart +++ b/engine/src/flutter/lib/web_ui/test/engine/semantics/accessibility_test.dart @@ -11,6 +11,7 @@ import 'package:ui/src/engine/dom.dart'; import 'package:ui/src/engine/embedder.dart'; import 'package:ui/src/engine/semantics.dart'; import 'package:ui/src/engine/services.dart'; +import 'package:ui/src/engine/view_embedder/dom_manager.dart'; const StandardMessageCodec codec = StandardMessageCodec(); @@ -19,26 +20,27 @@ void main() { } void testMain() { - late FlutterViewEmbedder embedder; + late DomManager domManager; late AccessibilityAnnouncements accessibilityAnnouncements; setUp(() { - embedder = FlutterViewEmbedder(); + final FlutterViewEmbedder embedder = FlutterViewEmbedder(); + domManager = DomManager.fromFlutterViewEmbedderDEPRECATED(embedder); accessibilityAnnouncements = embedder.accessibilityAnnouncements; setLiveMessageDurationForTest(const Duration(milliseconds: 10)); expect( - embedder.glassPaneShadow.querySelector('flt-announcement-polite'), + domManager.renderingHost.querySelector('flt-announcement-polite'), accessibilityAnnouncements.ariaLiveElementFor(Assertiveness.polite), ); expect( - embedder.glassPaneShadow.querySelector('flt-announcement-assertive'), + domManager.renderingHost.querySelector('flt-announcement-assertive'), accessibilityAnnouncements.ariaLiveElementFor(Assertiveness.assertive), ); }); tearDown(() async { await Future.delayed(liveMessageDuration * 2); - embedder.glassPaneElement.remove(); + domManager.rootElement.remove(); }); group('$AccessibilityAnnouncements', () { diff --git a/engine/src/flutter/lib/web_ui/test/engine/semantics/semantics_test.dart b/engine/src/flutter/lib/web_ui/test/engine/semantics/semantics_test.dart index 88cc01db8c..f9abdde052 100644 --- a/engine/src/flutter/lib/web_ui/test/engine/semantics/semantics_test.dart +++ b/engine/src/flutter/lib/web_ui/test/engine/semantics/semantics_test.dart @@ -22,6 +22,11 @@ DateTime _testTime = DateTime(2018, 12, 17); EngineSemanticsOwner semantics() => EngineSemanticsOwner.instance; +DomShadowRoot get renderingHost => + EnginePlatformDispatcher.instance.implicitView!.dom.renderingHost; +DomElement get platformViewsHost => + EnginePlatformDispatcher.instance.implicitView!.dom.platformViewsHost; + void main() { internalBootstrapBrowserTest(() { return testMain; @@ -224,8 +229,8 @@ void _testEngineSemanticsOwner() { expect(semantics().semanticsEnabled, isFalse); // Synthesize a click on the placeholder. - final DomElement placeholder = flutterViewEmbedder.glassPaneShadow - .querySelector('flt-semantics-placeholder')!; + final DomElement placeholder = + renderingHost.querySelector('flt-semantics-placeholder')!; expect(placeholder.isConnected, isTrue); @@ -320,8 +325,8 @@ void _testEngineSemanticsOwner() { .instance.accessibilityFeatures.accessibleNavigation, isFalse); - final DomElement placeholder = flutterViewEmbedder.glassPaneShadow - .querySelector('flt-semantics-placeholder')!; + final DomElement placeholder = + renderingHost.querySelector('flt-semantics-placeholder')!; expect(placeholder.isConnected, isTrue); @@ -795,9 +800,9 @@ void _testContainer() { '''); final DomElement parentElement = - appHostNode.querySelector('flt-semantics')!; + rootElement.querySelector('flt-semantics')!; final DomElement container = - appHostNode.querySelector('flt-semantics-container')!; + rootElement.querySelector('flt-semantics-container')!; if (isMacOrIOS) { expect(parentElement.style.top, '0px'); @@ -846,9 +851,9 @@ void _testContainer() { '''); final DomElement parentElement = - appHostNode.querySelector('flt-semantics')!; + rootElement.querySelector('flt-semantics')!; final DomElement container = - appHostNode.querySelector('flt-semantics-container')!; + rootElement.querySelector('flt-semantics-container')!; expect(parentElement.style.transform, 'matrix(1, 0, 0, 1, 10, 10)'); expect(parentElement.style.transformOrigin, '0px 0px 0px'); @@ -886,9 +891,9 @@ void _testContainer() { '''); final DomElement parentElement = - appHostNode.querySelector('flt-semantics')!; + rootElement.querySelector('flt-semantics')!; final DomElement container = - appHostNode.querySelector('flt-semantics-container')!; + rootElement.querySelector('flt-semantics-container')!; if (isMacOrIOS) { expect(parentElement.style.top, '0px'); @@ -1028,15 +1033,15 @@ void _testContainer() { '''); - final DomElement root = appHostNode.querySelector('#flt-semantic-node-0')!; + final DomElement root = rootElement.querySelector('#flt-semantic-node-0')!; expect(root.style.pointerEvents, 'none'); final DomElement child1 = - appHostNode.querySelector('#flt-semantic-node-1')!; + rootElement.querySelector('#flt-semantic-node-1')!; expect(child1.style.pointerEvents, 'all'); final DomElement child2 = - appHostNode.querySelector('#flt-semantic-node-2')!; + rootElement.querySelector('#flt-semantic-node-2')!; expect(child2.style.pointerEvents, 'all'); semantics().semanticsEnabled = false; @@ -1472,7 +1477,7 @@ void _testIncrementables() { '''); final DomHTMLInputElement input = - appHostNode.querySelector('input')! as DomHTMLInputElement; + rootElement.querySelector('input')! as DomHTMLInputElement; input.value = '2'; input.dispatchEvent(createDomEvent('Event', 'change')); @@ -1505,7 +1510,7 @@ void _testIncrementables() { '''); final DomHTMLInputElement input = - appHostNode.querySelector('input')! as DomHTMLInputElement; + rootElement.querySelector('input')! as DomHTMLInputElement; input.value = '0'; input.dispatchEvent(createDomEvent('Event', 'change')); @@ -1640,13 +1645,13 @@ void _testTextField() { semantics().updateSemantics(builder.build()); final DomElement textField = - appHostNode.querySelector('input[data-semantics-role="text-field"]')!; + rootElement.querySelector('input[data-semantics-role="text-field"]')!; - expect(appHostNode.ownerDocument?.activeElement, isNot(textField)); + expect(rootElement.ownerDocument?.activeElement, isNot(textField)); textField.focus(); - expect(appHostNode.ownerDocument?.activeElement, textField); + expect(rootElement.ownerDocument?.activeElement, textField); expect(await logger.idLog.first, 0); expect(await logger.actionLog.first, ui.SemanticsAction.didGainAccessibilityFocus); @@ -2370,7 +2375,7 @@ void _testPlatformView() { semantics().updateSemantics(builder.build()); expectSemanticsTree(''); - final DomElement element = appHostNode.querySelector('flt-semantics')!; + final DomElement element = rootElement.querySelector('flt-semantics')!; expect(element.style.pointerEvents, 'none'); semantics().semanticsEnabled = false; @@ -2459,11 +2464,11 @@ void _testPlatformView() { '''); - final DomElement root = appHostNode.querySelector('#flt-semantic-node-0')!; + final DomElement root = rootElement.querySelector('#flt-semantic-node-0')!; expect(root.style.pointerEvents, 'none'); final DomElement child1 = - appHostNode.querySelector('#flt-semantic-node-1')!; + rootElement.querySelector('#flt-semantic-node-1')!; expect(child1.style.pointerEvents, 'all'); final DomRect child1Rect = child1.getBoundingClientRect(); expect(child1Rect.left, 0); @@ -2472,7 +2477,7 @@ void _testPlatformView() { expect(child1Rect.bottom, 25); final DomElement child2 = - appHostNode.querySelector('#flt-semantic-node-2')!; + rootElement.querySelector('#flt-semantic-node-2')!; expect(child2.style.pointerEvents, 'none'); final DomRect child2Rect = child2.getBoundingClientRect(); expect(child2Rect.left, 0); @@ -2481,7 +2486,7 @@ void _testPlatformView() { expect(child2Rect.bottom, 45); final DomElement child3 = - appHostNode.querySelector('#flt-semantic-node-3')!; + rootElement.querySelector('#flt-semantic-node-3')!; expect(child3.style.pointerEvents, 'all'); final DomRect child3Rect = child3.getBoundingClientRect(); expect(child3Rect.left, 0); @@ -2490,7 +2495,7 @@ void _testPlatformView() { expect(child3Rect.bottom, 60); final DomElement platformViewElement = - flutterViewEmbedder.glassPaneElement.querySelector('#view-0')!; + platformViewsHost.querySelector('#view-0')!; final DomRect platformViewRect = platformViewElement.getBoundingClientRect(); expect(platformViewRect.left, 0); diff --git a/engine/src/flutter/lib/web_ui/test/engine/semantics/semantics_tester.dart b/engine/src/flutter/lib/web_ui/test/engine/semantics/semantics_tester.dart index 881acdcfa6..f0c61e92ca 100644 --- a/engine/src/flutter/lib/web_ui/test/engine/semantics/semantics_tester.dart +++ b/engine/src/flutter/lib/web_ui/test/engine/semantics/semantics_tester.dart @@ -7,7 +7,7 @@ import 'dart:typed_data'; import 'package:test/test.dart'; import 'package:ui/src/engine/dom.dart'; -import 'package:ui/src/engine/embedder.dart'; +import 'package:ui/src/engine/platform_dispatcher.dart'; import 'package:ui/src/engine/semantics.dart'; import 'package:ui/src/engine/util.dart'; import 'package:ui/src/engine/vector_math.dart'; @@ -22,7 +22,8 @@ import '../../common/matchers.dart'; /// tree has moved outside of the shadowDOM as a workaround for a password /// autofill bug on Chrome. /// Ref: https://github.com/flutter/flutter/issues/87735 -DomElement get appHostNode => flutterViewEmbedder.flutterViewElement; +DomElement get rootElement => + EnginePlatformDispatcher.instance.implicitView!.dom.rootElement; /// CSS style applied to the root of the semantics tree. // TODO(yjbanov): this should be handled internally by [expectSemanticsTree]. @@ -354,14 +355,14 @@ class SemanticsTester { void expectSemanticsTree(String semanticsHtml) { const List ignoredAttributes = ['pointer-events']; expect( - canonicalizeHtml(appHostNode.querySelector('flt-semantics')!.outerHTML!, ignoredAttributes: ignoredAttributes), + canonicalizeHtml(rootElement.querySelector('flt-semantics')!.outerHTML!, ignoredAttributes: ignoredAttributes), canonicalizeHtml(semanticsHtml), ); } /// Finds the first HTML element in the semantics tree used for scrolling. DomElement? findScrollable() { - return appHostNode.querySelectorAll('flt-semantics').firstWhereOrNull( + return rootElement.querySelectorAll('flt-semantics').firstWhereOrNull( (DomElement? element) { return element!.style.overflow == 'hidden' || element.style.overflowY == 'scroll' || diff --git a/engine/src/flutter/lib/web_ui/test/engine/semantics/text_field_test.dart b/engine/src/flutter/lib/web_ui/test/engine/semantics/text_field_test.dart index 197e2fe506..29dcc3b275 100644 --- a/engine/src/flutter/lib/web_ui/test/engine/semantics/text_field_test.dart +++ b/engine/src/flutter/lib/web_ui/test/engine/semantics/text_field_test.dart @@ -98,20 +98,20 @@ void testMain() { final SemanticsActionLogger logger = SemanticsActionLogger(); createTextFieldSemantics(value: 'hello'); - final DomElement textField = appHostNode + final DomElement textField = rootElement .querySelector('input[data-semantics-role="text-field"]')!; - expect(appHostNode.ownerDocument?.activeElement, isNot(textField)); + expect(rootElement.ownerDocument?.activeElement, isNot(textField)); textField.focus(); - expect(appHostNode.ownerDocument?.activeElement, textField); + expect(rootElement.ownerDocument?.activeElement, textField); expect(await logger.idLog.first, 0); expect(await logger.actionLog.first, ui.SemanticsAction.didGainAccessibilityFocus); textField.blur(); - expect(appHostNode.ownerDocument?.activeElement, isNot(textField)); + expect(rootElement.ownerDocument?.activeElement, isNot(textField)); expect(await logger.idLog.first, 0); expect(await logger.actionLog.first, ui.SemanticsAction.didLoseAccessibilityFocus); }, // TODO(yjbanov): https://github.com/flutter/flutter/issues/46638 @@ -119,7 +119,7 @@ void testMain() { skip: browserEngine != BrowserEngine.blink); test('Syncs semantic state from framework', () { - expect(appHostNode.ownerDocument?.activeElement, domDocument.body); + expect(rootElement.ownerDocument?.activeElement, domDocument.body); int changeCount = 0; int actionCount = 0; @@ -142,7 +142,7 @@ void testMain() { ); final TextField textField = textFieldSemantics.primaryRole! as TextField; - expect(appHostNode.ownerDocument?.activeElement, strategy.domElement); + expect(rootElement.ownerDocument?.activeElement, strategy.domElement); expect(textField.editableElement, strategy.domElement); expect(textField.activeEditableElement.getAttribute('aria-label'), 'greeting'); expect(textField.activeEditableElement.style.width, '10px'); @@ -155,7 +155,7 @@ void testMain() { rect: const ui.Rect.fromLTWH(0, 0, 12, 17), ); - expect(appHostNode.ownerDocument?.activeElement, domDocument.body); + expect(rootElement.ownerDocument?.activeElement, domDocument.body); expect(strategy.domElement, null); expect(textField.activeEditableElement.getAttribute('aria-label'), 'farewell'); expect(textField.activeEditableElement.style.width, '12px'); @@ -200,7 +200,7 @@ void testMain() { test( 'Updates editing state when receiving framework messages from the text input channel', () { - expect(appHostNode.ownerDocument?.activeElement, domDocument.body); + expect(rootElement.ownerDocument?.activeElement, domDocument.body); strategy.enable( singlelineConfig, @@ -243,7 +243,7 @@ void testMain() { }); test('Gives up focus after DOM blur', () { - expect(appHostNode.ownerDocument?.activeElement, domDocument.body); + expect(rootElement.ownerDocument?.activeElement, domDocument.body); strategy.enable( singlelineConfig, @@ -257,11 +257,11 @@ void testMain() { final TextField textField = textFieldSemantics.primaryRole! as TextField; expect(textField.editableElement, strategy.domElement); - expect(appHostNode.ownerDocument?.activeElement, strategy.domElement); + expect(rootElement.ownerDocument?.activeElement, strategy.domElement); // The input should not refocus after blur. textField.activeEditableElement.blur(); - expect(appHostNode.ownerDocument?.activeElement, domDocument.body); + expect(rootElement.ownerDocument?.activeElement, domDocument.body); strategy.disable(); }); @@ -281,17 +281,17 @@ void testMain() { isFocused: true, ); expect(strategy.domElement, isNotNull); - expect(appHostNode.ownerDocument?.activeElement, strategy.domElement); + expect(rootElement.ownerDocument?.activeElement, strategy.domElement); strategy.disable(); expect(strategy.domElement, isNull); // It doesn't remove the DOM element. final TextField textField = textFieldSemantics.primaryRole! as TextField; - expect(appHostNode.contains(textField.editableElement), isTrue); + expect(rootElement.contains(textField.editableElement), isTrue); // Editing element is not enabled. expect(strategy.isEnabled, isFalse); - expect(appHostNode.ownerDocument?.activeElement, domDocument.body); + expect(rootElement.ownerDocument?.activeElement, domDocument.body); }); test('Refocuses when setting editing state', () { @@ -306,11 +306,11 @@ void testMain() { isFocused: true, ); expect(strategy.domElement, isNotNull); - expect(appHostNode.ownerDocument?.activeElement, strategy.domElement); + expect(rootElement.ownerDocument?.activeElement, strategy.domElement); // Blur the element without telling the framework. strategy.activeDomElement.blur(); - expect(appHostNode.ownerDocument?.activeElement, domDocument.body); + expect(rootElement.ownerDocument?.activeElement, domDocument.body); // The input will have focus after editing state is set and semantics updated. strategy.setEditingState(EditingState(text: 'foo')); @@ -328,7 +328,7 @@ void testMain() { value: 'hello', isFocused: true, ); - expect(appHostNode.ownerDocument?.activeElement, strategy.domElement); + expect(rootElement.ownerDocument?.activeElement, strategy.domElement); strategy.disable(); }); @@ -348,7 +348,7 @@ void testMain() { final DomHTMLTextAreaElement textArea = strategy.domElement! as DomHTMLTextAreaElement; - expect(appHostNode.ownerDocument?.activeElement, strategy.domElement); + expect(rootElement.ownerDocument?.activeElement, strategy.domElement); strategy.enable( singlelineConfig, @@ -357,11 +357,11 @@ void testMain() { ); textArea.blur(); - expect(appHostNode.ownerDocument?.activeElement, domDocument.body); + expect(rootElement.ownerDocument?.activeElement, domDocument.body); strategy.disable(); // It doesn't remove the textarea from the DOM. - expect(appHostNode.contains(textArea), isTrue); + expect(rootElement.contains(textArea), isTrue); // Editing element is not enabled. expect(strategy.isEnabled, isFalse); }); @@ -441,13 +441,13 @@ void testMain() { createTwoFieldSemantics(tester, focusFieldId: 1); expect(tester.apply().length, 3); - expect(appHostNode.ownerDocument?.activeElement, + expect(rootElement.ownerDocument?.activeElement, tester.getTextField(1).editableElement); expect(strategy.domElement, tester.getTextField(1).editableElement); createTwoFieldSemantics(tester, focusFieldId: 2); expect(tester.apply().length, 3); - expect(appHostNode.ownerDocument?.activeElement, + expect(rootElement.ownerDocument?.activeElement, tester.getTextField(2).editableElement); expect(strategy.domElement, tester.getTextField(2).editableElement); } @@ -478,16 +478,16 @@ void testMain() { }); test('does not render a text field', () { - expect(appHostNode.querySelector('flt-semantics[role="textbox"]'), isNull); + expect(rootElement.querySelector('flt-semantics[role="textbox"]'), isNull); createTextFieldSemanticsForIos(value: 'hello'); - expect(appHostNode.querySelector('flt-semantics[role="textbox"]'), isNotNull); + expect(rootElement.querySelector('flt-semantics[role="textbox"]'), isNotNull); }); test('tap detection works', () async { final SemanticsActionLogger logger = SemanticsActionLogger(); createTextFieldSemanticsForIos(value: 'hello'); - final DomElement textField = appHostNode + final DomElement textField = rootElement .querySelector('flt-semantics[role="textbox"]')!; simulateTap(textField); @@ -496,7 +496,7 @@ void testMain() { }); test('Syncs semantic state from framework', () { - expect(appHostNode.ownerDocument?.activeElement, domDocument.body); + expect(rootElement.ownerDocument?.activeElement, domDocument.body); int changeCount = 0; int actionCount = 0; @@ -519,7 +519,7 @@ void testMain() { ); final TextField textField = textFieldSemantics.primaryRole! as TextField; - expect(appHostNode.ownerDocument?.activeElement, strategy.domElement); + expect(rootElement.ownerDocument?.activeElement, strategy.domElement); expect(textField.editableElement, strategy.domElement); expect(textField.activeEditableElement.getAttribute('aria-label'), 'greeting'); expect(textField.activeEditableElement.style.width, '10px'); @@ -532,10 +532,10 @@ void testMain() { rect: const ui.Rect.fromLTWH(0, 0, 12, 17), ); final DomElement textBox = - appHostNode.querySelector('flt-semantics[role="textbox"]')!; + rootElement.querySelector('flt-semantics[role="textbox"]')!; expect(strategy.domElement, null); - expect(appHostNode.ownerDocument?.activeElement, textBox); + expect(rootElement.ownerDocument?.activeElement, textBox); expect(textBox.getAttribute('aria-label'), 'farewell'); strategy.disable(); @@ -577,7 +577,7 @@ void testMain() { test( 'Updates editing state when receiving framework messages from the text input channel', () { - expect(appHostNode.ownerDocument?.activeElement, domDocument.body); + expect(rootElement.ownerDocument?.activeElement, domDocument.body); strategy.enable( singlelineConfig, @@ -620,7 +620,7 @@ void testMain() { }); test('Gives up focus after DOM blur', () { - expect(appHostNode.ownerDocument?.activeElement, domDocument.body); + expect(rootElement.ownerDocument?.activeElement, domDocument.body); strategy.enable( singlelineConfig, @@ -634,13 +634,13 @@ void testMain() { final TextField textField = textFieldSemantics.primaryRole! as TextField; expect(textField.editableElement, strategy.domElement); - expect(appHostNode.ownerDocument?.activeElement, strategy.domElement); + expect(rootElement.ownerDocument?.activeElement, strategy.domElement); // The input should not refocus after blur. textField.activeEditableElement.blur(); final DomElement textBox = - appHostNode.querySelector('flt-semantics[role="textbox"]')!; - expect(appHostNode.ownerDocument?.activeElement, textBox); + rootElement.querySelector('flt-semantics[role="textbox"]')!; + expect(rootElement.ownerDocument?.activeElement, textBox); strategy.disable(); }); @@ -661,20 +661,20 @@ void testMain() { isFocused: true, ); expect(strategy.domElement, isNotNull); - expect(appHostNode.ownerDocument?.activeElement, strategy.domElement); + expect(rootElement.ownerDocument?.activeElement, strategy.domElement); strategy.disable(); expect(strategy.domElement, isNull); // It removes the DOM element. final TextField textField = textFieldSemantics.primaryRole! as TextField; - expect(appHostNode.contains(textField.editableElement), isFalse); + expect(rootElement.contains(textField.editableElement), isFalse); // Editing element is not enabled. expect(strategy.isEnabled, isFalse); // Focus is on the semantic object final DomElement textBox = - appHostNode.querySelector('flt-semantics[role="textbox"]')!; - expect(appHostNode.ownerDocument?.activeElement, textBox); + rootElement.querySelector('flt-semantics[role="textbox"]')!; + expect(rootElement.ownerDocument?.activeElement, textBox); }); test('Refocuses when setting editing state', () { @@ -689,13 +689,13 @@ void testMain() { isFocused: true, ); expect(strategy.domElement, isNotNull); - expect(appHostNode.ownerDocument?.activeElement, strategy.domElement); + expect(rootElement.ownerDocument?.activeElement, strategy.domElement); // Blur the element without telling the framework. strategy.activeDomElement.blur(); final DomElement textBox = - appHostNode.querySelector('flt-semantics[role="textbox"]')!; - expect(appHostNode.ownerDocument?.activeElement, textBox); + rootElement.querySelector('flt-semantics[role="textbox"]')!; + expect(rootElement.ownerDocument?.activeElement, textBox); // The input will have focus after editing state is set and semantics updated. strategy.setEditingState(EditingState(text: 'foo')); @@ -713,7 +713,7 @@ void testMain() { value: 'hello', isFocused: true, ); - expect(appHostNode.ownerDocument?.activeElement, strategy.domElement); + expect(rootElement.ownerDocument?.activeElement, strategy.domElement); strategy.disable(); }); @@ -732,7 +732,7 @@ void testMain() { final DomHTMLTextAreaElement textArea = strategy.domElement! as DomHTMLTextAreaElement; - expect(appHostNode.ownerDocument?.activeElement, strategy.domElement); + expect(rootElement.ownerDocument?.activeElement, strategy.domElement); strategy.enable( singlelineConfig, @@ -740,17 +740,17 @@ void testMain() { onAction: (_) {}, ); - expect(appHostNode.contains(textArea), isTrue); + expect(rootElement.contains(textArea), isTrue); textArea.blur(); final DomElement textBox = - appHostNode.querySelector('flt-semantics[role="textbox"]')!; + rootElement.querySelector('flt-semantics[role="textbox"]')!; - expect(appHostNode.ownerDocument?.activeElement, textBox); + expect(rootElement.ownerDocument?.activeElement, textBox); strategy.disable(); // It removes the textarea from the DOM. - expect(appHostNode.contains(textArea), isFalse); + expect(rootElement.contains(textArea), isFalse); // Editing element is not enabled. expect(strategy.isEnabled, isFalse); }); @@ -809,13 +809,13 @@ void testMain() { createTwoFieldSemanticsForIos(tester, focusFieldId: 1); expect(tester.apply().length, 3); - expect(appHostNode.ownerDocument?.activeElement, + expect(rootElement.ownerDocument?.activeElement, tester.getTextField(1).editableElement); expect(strategy.domElement, tester.getTextField(1).editableElement); createTwoFieldSemanticsForIos(tester, focusFieldId: 2); expect(tester.apply().length, 3); - expect(appHostNode.ownerDocument?.activeElement, + expect(rootElement.ownerDocument?.activeElement, tester.getTextField(2).editableElement); expect(strategy.domElement, tester.getTextField(2).editableElement); } @@ -976,7 +976,7 @@ Map createTwoFieldSemanticsForIos(SemanticsTester builder, builder.apply(); final String label = focusFieldId == 1 ? 'Hello' : 'World'; final DomElement textBox = - appHostNode.querySelector('flt-semantics[aria-label="$label"]')!; + rootElement.querySelector('flt-semantics[aria-label="$label"]')!; simulateTap(textBox); diff --git a/engine/src/flutter/lib/web_ui/test/engine/view_embedder/dom_manager_test.dart b/engine/src/flutter/lib/web_ui/test/engine/view_embedder/dom_manager_test.dart new file mode 100644 index 0000000000..915a4eb07f --- /dev/null +++ b/engine/src/flutter/lib/web_ui/test/engine/view_embedder/dom_manager_test.dart @@ -0,0 +1,27 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:test/bootstrap/browser.dart'; +import 'package:test/test.dart'; +import 'package:ui/src/engine.dart'; + +void main() { + internalBootstrapBrowserTest(() => doTests); +} + +void doTests() { + group('DomManager', () { + test('fromFlutterViewEmbedderDEPRECATED', () { + final FlutterViewEmbedder embedder = FlutterViewEmbedder(); + final DomManager domManager = + DomManager.fromFlutterViewEmbedderDEPRECATED(embedder); + + expect(domManager.rootElement, embedder.flutterViewElementDEPRECATED); + expect(domManager.renderingHost, embedder.glassPaneShadowDEPRECATED); + expect(domManager.platformViewsHost, embedder.glassPaneElementDEPRECATED); + expect(domManager.textEditingHost, embedder.textEditingHostNodeDEPRECATED); + expect(domManager.semanticsHost, embedder.semanticsHostElementDEPRECATED); + }); + }); +} diff --git a/engine/src/flutter/lib/web_ui/test/html/bitmap_canvas_golden_test.dart b/engine/src/flutter/lib/web_ui/test/html/bitmap_canvas_golden_test.dart index ea593da907..17c4c4ebdf 100644 --- a/engine/src/flutter/lib/web_ui/test/html/bitmap_canvas_golden_test.dart +++ b/engine/src/flutter/lib/web_ui/test/html/bitmap_canvas_golden_test.dart @@ -13,6 +13,10 @@ import 'package:web_engine_tester/golden_tester.dart'; import '../common/test_initialization.dart'; import 'paragraph/helper.dart'; +DomElement get sceneHost => + EnginePlatformDispatcher.instance.implicitView!.dom.renderingHost + .querySelector('flt-scene-host')!; + void main() { internalBootstrapBrowserTest(() => testMain); } @@ -32,7 +36,7 @@ Future testMain() async { testScene.style.transform = 'scale(0.3)'; } testScene.append(canvas.rootElement); - flutterViewEmbedder.glassPaneShadow.querySelector('flt-scene-host')!.append(testScene); + sceneHost.append(testScene); } setUpUnitTests( @@ -41,7 +45,7 @@ Future testMain() async { ); tearDown(() { - flutterViewEmbedder.glassPaneShadow.querySelector('flt-scene')?.remove(); + sceneHost.querySelector('flt-scene')?.remove(); }); /// Draws several lines, some aligned precisely with the pixel grid, and some @@ -263,7 +267,7 @@ Future testMain() async { } sceneElement.querySelector('flt-clip')!.append(canvas.rootElement); - flutterViewEmbedder.glassPaneShadow.querySelector('flt-scene-host')!.append(sceneElement); + sceneHost.append(sceneElement); await matchGoldenFile( 'bitmap_canvas_draws_text_on_top_of_canvas.png', diff --git a/engine/src/flutter/lib/web_ui/test/html/shaders/shader_mask_golden_test.dart b/engine/src/flutter/lib/web_ui/test/html/shaders/shader_mask_golden_test.dart index b2fd11110f..fe46e29dc6 100644 --- a/engine/src/flutter/lib/web_ui/test/html/shaders/shader_mask_golden_test.dart +++ b/engine/src/flutter/lib/web_ui/test/html/shaders/shader_mask_golden_test.dart @@ -17,6 +17,10 @@ import '../../common/test_initialization.dart'; /// test/golden_tests/engine/shader_mask_golden_test.dart --profile const bool debugTest = false; +DomElement get sceneHost => + EnginePlatformDispatcher.instance.implicitView!.dom.renderingHost + .querySelector('flt-scene-host')!; + Future main() async { if (!debugTest) { internalBootstrapBrowserTest(() => testMain); @@ -42,8 +46,7 @@ Future testMain() async { setUp(() async { SurfaceSceneBuilder.debugForgetFrameScene(); - for (final DomNode scene in - flutterViewEmbedder.sceneHostElement!.querySelectorAll('flt-scene').cast()) { + for (final DomNode scene in sceneHost.querySelectorAll('flt-scene').cast()) { scene.remove(); } initWebGl(); @@ -164,7 +167,7 @@ void _renderCirclesScene(BlendMode blendMode) { builder.addPicture(Offset.zero, circles2); builder.pop(); - flutterViewEmbedder.sceneHostElement!.append(builder.build().webOnlyRootElement!); + sceneHost.append(builder.build().webOnlyRootElement!); } Picture _drawTestPictureWithText( @@ -219,5 +222,5 @@ void _renderTextScene(BlendMode blendMode) { builder.addPicture(Offset.zero, textPicture2); builder.pop(); - flutterViewEmbedder.sceneHostElement!.append(builder.build().webOnlyRootElement!); + sceneHost.append(builder.build().webOnlyRootElement!); }