[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`.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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<Object?>(glassPaneElement, 'attachShadow') == null) {
|
||||
if (getJsProperty<Object?>(_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(<String, dynamic>{
|
||||
final DomShadowRoot shadowRoot = _glassPaneElement.attachShadow(<String, dynamic>{
|
||||
'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;
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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] <flutter-view>
|
||||
/// |
|
||||
/// +- [platformViewsHost] <flt-glass-pane>
|
||||
/// | |
|
||||
/// | +- [renderingHost] #shadow-root
|
||||
/// | | |
|
||||
/// | | +- <flt-semantics-placeholder>
|
||||
/// | | |
|
||||
/// | | +- <flt-scene-host>
|
||||
/// | | | |
|
||||
/// | | | +- <flt-scene>
|
||||
/// | | |
|
||||
/// | | +- <flt-announcement-host>
|
||||
/// | |
|
||||
/// | +- ...platform views
|
||||
/// |
|
||||
/// +- [textEditingHost] <text-editing-host>
|
||||
/// | |
|
||||
/// | +- ...text fields
|
||||
/// |
|
||||
/// +- [semanticsHost] <semantics-host>
|
||||
/// |
|
||||
/// +- ...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;
|
||||
}
|
||||
@@ -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<bool> 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.
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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<void>.delayed(liveMessageDuration * 2);
|
||||
embedder.glassPaneElement.remove();
|
||||
domManager.rootElement.remove();
|
||||
});
|
||||
|
||||
group('$AccessibilityAnnouncements', () {
|
||||
|
||||
@@ -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() {
|
||||
</sem>''');
|
||||
|
||||
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() {
|
||||
</sem>''');
|
||||
|
||||
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() {
|
||||
</sem>''');
|
||||
|
||||
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() {
|
||||
</sem-c>
|
||||
</sem>''');
|
||||
|
||||
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() {
|
||||
</sem>''');
|
||||
|
||||
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() {
|
||||
</sem>''');
|
||||
|
||||
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('<sem aria-owns="flt-pv-5" style="$rootSemanticStyle"></sem>');
|
||||
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() {
|
||||
</sem-c>
|
||||
</sem>''');
|
||||
|
||||
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);
|
||||
|
||||
@@ -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<String> ignoredAttributes = <String>['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' ||
|
||||
|
||||
@@ -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<int, SemanticsObject> 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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -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<void> 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<void> 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<void> 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',
|
||||
|
||||
@@ -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<void> main() async {
|
||||
if (!debugTest) {
|
||||
internalBootstrapBrowserTest(() => testMain);
|
||||
@@ -42,8 +46,7 @@ Future<void> testMain() async {
|
||||
|
||||
setUp(() async {
|
||||
SurfaceSceneBuilder.debugForgetFrameScene();
|
||||
for (final DomNode scene in
|
||||
flutterViewEmbedder.sceneHostElement!.querySelectorAll('flt-scene').cast<DomNode>()) {
|
||||
for (final DomNode scene in sceneHost.querySelectorAll('flt-scene').cast<DomNode>()) {
|
||||
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!);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user