[web] Explicit initialization of the implicit view (flutter/engine#47921)

- An explicit API for initializing the implicit view (aka `window`).
- The explicit API is being called during the engine initialization for now, but we could simply remove that or make it conditional.
- Remove direct usages of `window` in tests:
    - Most of the usages were being delegated to `PlatformDispatcher` anyway (e.g. `sendPlatformMessage`).
    - This makes it **_clearer_** which tests depend on the implicit view (there are still hidden/indirect dependencies though).

Part of https://github.com/flutter/flutter/issues/134443
This commit is contained in:
Mouad Debbar 2023-11-14 11:14:50 -05:00 committed by GitHub
parent ae786cb22a
commit 44cbbf526f
41 changed files with 366 additions and 298 deletions

View File

@ -5,7 +5,7 @@
import 'package:ui/src/engine/safe_browser_api.dart';
import 'package:ui/ui.dart' as ui;
import '../engine.dart' show buildMode, renderer, window;
import '../engine.dart' show buildMode, renderer;
import 'browser_detection.dart';
import 'configuration.dart';
import 'dom.dart';
@ -18,6 +18,7 @@ import 'view_embedder/dimensions_provider/dimensions_provider.dart';
import 'view_embedder/dom_manager.dart';
import 'view_embedder/embedding_strategy/embedding_strategy.dart';
import 'view_embedder/style_manager.dart';
import 'window.dart';
/// Controls the placement and lifecycle of a Flutter view on the web page.
///
@ -309,9 +310,13 @@ FlutterViewEmbedder get flutterViewEmbedder {
FlutterViewEmbedder? _flutterViewEmbedder;
/// Initializes the [FlutterViewEmbedder], if it's not already initialized.
FlutterViewEmbedder ensureFlutterViewEmbedderInitialized() =>
_flutterViewEmbedder ??=
FlutterViewEmbedder(hostElement: configuration.hostElement);
FlutterViewEmbedder ensureFlutterViewEmbedderInitialized() {
// FlutterViewEmbedder needs the implicit view to be initialized because it
// uses some of its methods e.g. `configureDimensionsProvider`, `onResize`.
ensureImplicitViewInitialized();
return _flutterViewEmbedder ??=
FlutterViewEmbedder(hostElement: configuration.hostElement);
}
/// Creates a node to host text editing elements and applies a stylesheet
/// to Flutter nodes that exist outside of the shadowDOM.

View File

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

View File

@ -135,6 +135,13 @@ class EnginePlatformDispatcher extends ui.PlatformDispatcher {
viewData[view.viewId] = view;
}
/// Removes [view] from the platform dispatcher's registry of [views].
///
/// Nothing happens if the view is not already registered.
void unregisterView(EngineFlutterView view) {
viewData.remove(view.viewId);
}
/// The current list of windows.
@override
Iterable<EngineFlutterView> get views => viewData.values;

View File

@ -7,6 +7,7 @@ import 'dart:async';
import 'package:ui/src/engine/window.dart';
import 'package:ui/ui.dart' as ui show Size;
import '../../display.dart';
import '../../dom.dart';
import 'custom_element_dimensions_provider.dart';
import 'full_page_dimensions_provider.dart';
@ -39,7 +40,7 @@ abstract class DimensionsProvider {
/// Returns the DPI reported by the browser.
double getDevicePixelRatio() {
// This is overridable in tests.
return window.devicePixelRatio;
return EngineFlutterDisplay.instance.devicePixelRatio;
}
/// Returns the [ui.Size] of the "viewport".

View File

@ -573,8 +573,22 @@ final class EngineFlutterWindow extends EngineFlutterView implements ui.Singleto
/// `dart:ui` window delegates to this value. However, this value has a wider
/// API surface, providing Web-specific functionality that the standard
/// `dart:ui` version does not.
final EngineFlutterWindow window =
EngineFlutterWindow(kImplicitViewId, EnginePlatformDispatcher.instance);
EngineFlutterWindow get window {
assert(
_window != null,
'Trying to access the implicit FlutterView, but it is not available.\n'
'Note: the implicit FlutterView is not available in multi-view mode.',
);
return _window!;
}
EngineFlutterWindow? _window;
/// Initializes the [window] (aka the implicit view), if it's not already
/// initialized.
EngineFlutterWindow ensureImplicitViewInitialized() {
return _window ??=
EngineFlutterWindow(kImplicitViewId, EnginePlatformDispatcher.instance);
}
/// The Web implementation of [ui.ViewPadding].
class ViewPadding implements ui.ViewPadding {

View File

@ -31,6 +31,7 @@ bool get debugEmulateFlutterTesterEnvironment =>
set debugEmulateFlutterTesterEnvironment(bool value) {
_debugEmulateFlutterTesterEnvironment = value;
if (_debugEmulateFlutterTesterEnvironment) {
ensureImplicitViewInitialized();
const ui.Size logicalSize = ui.Size(800.0, 600.0);
window.debugPhysicalSizeOverride = logicalSize * window.devicePixelRatio;
}

View File

@ -20,7 +20,7 @@ const ui.Rect region = ui.Rect.fromLTRB(0, 0, 500, 500);
void testMain() {
group('BackdropFilter', () {
setUpCanvasKitTest();
window.debugOverrideDevicePixelRatio(1.0);
EngineFlutterDisplay.instance.debugOverrideDevicePixelRatio(1.0);
test('blur renders to the edges', () async {
// Make a checkerboard picture so we can see the blur.

View File

@ -85,7 +85,7 @@ Future<bool> matchImage(ui.Image left, ui.Image right) async {
/// Sends a platform message to create a Platform View with the given id and viewType.
Future<void> createPlatformView(int id, String viewType) {
final Completer<void> completer = Completer<void>();
window.sendPlatformMessage(
ui.PlatformDispatcher.instance.sendPlatformMessage(
'flutter/platform_views',
codec.encodeMethodCall(MethodCall(
'create',
@ -102,7 +102,7 @@ Future<void> createPlatformView(int id, String viewType) {
/// Disposes of the platform view with the given [id].
Future<void> disposePlatformView(int id) {
final Completer<void> completer = Completer<void>();
window.sendPlatformMessage(
ui.PlatformDispatcher.instance.sendPlatformMessage(
'flutter/platform_views',
codec.encodeMethodCall(MethodCall('dispose', id)),
(dynamic _) => completer.complete(),

View File

@ -13,6 +13,9 @@ import 'package:ui/ui_web/src/ui_web.dart' as ui_web;
import 'common.dart';
import 'test_data.dart';
EngineFlutterWindow get implicitView =>
EnginePlatformDispatcher.instance.implicitView!;
DomElement get platformViewsHost {
return EnginePlatformDispatcher.instance.implicitView!.dom.platformViewsHost;
}
@ -26,7 +29,7 @@ void testMain() {
setUpCanvasKitTest();
setUp(() {
window.debugOverrideDevicePixelRatio(1);
EngineFlutterDisplay.instance.debugOverrideDevicePixelRatio(1);
});
test('embeds interactive platform views', () async {
@ -238,7 +241,7 @@ void testMain() {
});
test('converts device pixels to logical pixels (no clips)', () async {
window.debugOverrideDevicePixelRatio(4);
EngineFlutterDisplay.instance.debugOverrideDevicePixelRatio(4);
ui_web.platformViewRegistry.registerViewFactory(
'test-platform-view',
(int viewId) => createDomHTMLDivElement()..id = 'view-0',
@ -263,7 +266,7 @@ void testMain() {
});
test('converts device pixels to logical pixels (with clips)', () async {
window.debugOverrideDevicePixelRatio(4);
EngineFlutterDisplay.instance.debugOverrideDevicePixelRatio(4);
ui_web.platformViewRegistry.registerViewFactory(
'test-platform-view',
(int viewId) => createDomHTMLDivElement()..id = 'view-0',
@ -417,7 +420,7 @@ void testMain() {
for (final int id in platformViewIds) {
const StandardMethodCodec codec = StandardMethodCodec();
final Completer<void> completer = Completer<void>();
ui.window.sendPlatformMessage(
ui.PlatformDispatcher.instance.sendPlatformMessage(
'flutter/platform_views',
codec.encodeMethodCall(MethodCall(
'dispose',
@ -637,8 +640,8 @@ void testMain() {
sb.addPicture(ui.Offset.zero, picture);
sb.addPlatformView(0, width: 10, height: 10);
window.debugPhysicalSizeOverride = const ui.Size(100, 100);
window.debugForceResize();
implicitView.debugPhysicalSizeOverride = const ui.Size(100, 100);
implicitView.debugForceResize();
CanvasKitRenderer.instance.rasterizer.draw(sb.build().layerTree);
_expectSceneMatches(<_EmbeddedViewMarker>[
_overlay,
@ -646,8 +649,8 @@ void testMain() {
_overlay,
]);
window.debugPhysicalSizeOverride = const ui.Size(200, 200);
window.debugForceResize();
implicitView.debugPhysicalSizeOverride = const ui.Size(200, 200);
implicitView.debugForceResize();
CanvasKitRenderer.instance.rasterizer.draw(sb.build().layerTree);
_expectSceneMatches(<_EmbeddedViewMarker>[
_overlay,
@ -655,8 +658,8 @@ void testMain() {
_overlay,
]);
window.debugPhysicalSizeOverride = null;
window.debugForceResize();
implicitView.debugPhysicalSizeOverride = null;
implicitView.debugForceResize();
// ImageDecoder is not supported in Safari or Firefox.
}, skip: isSafari || isFirefox);

View File

@ -17,7 +17,7 @@ void testMain() {
group('CanvasKit', () {
setUpCanvasKitTest();
setUp(() async {
window.debugOverrideDevicePixelRatio(1.0);
EngineFlutterDisplay.instance.debugOverrideDevicePixelRatio(1.0);
});
Future<DomImageBitmap> newBitmap(int width, int height) async {
@ -43,7 +43,7 @@ void testMain() {
// Increase device-pixel ratio: this makes CSS pixels bigger, so we need
// fewer of them to cover the browser window.
window.debugOverrideDevicePixelRatio(2.0);
EngineFlutterDisplay.instance.debugOverrideDevicePixelRatio(2.0);
canvas.render(await newBitmap(10, 16));
expect(canvas.canvasElement.width, 10);
expect(canvas.canvasElement.height, 16);
@ -52,7 +52,7 @@ void testMain() {
// Decrease device-pixel ratio: this makes CSS pixels smaller, so we need
// more of them to cover the browser window.
window.debugOverrideDevicePixelRatio(0.5);
EngineFlutterDisplay.instance.debugOverrideDevicePixelRatio(0.5);
canvas.render(await newBitmap(10, 16));
expect(canvas.canvasElement.width, 10);
expect(canvas.canvasElement.height, 16);

View File

@ -19,7 +19,7 @@ void testMain() {
group('CanvasKit', () {
setUpCanvasKitTest();
setUp(() {
window.debugOverrideDevicePixelRatio(1.0);
EngineFlutterDisplay.instance.debugOverrideDevicePixelRatio(1.0);
});
test('Surface allocates canvases efficiently', () {
@ -90,7 +90,7 @@ void testMain() {
// Doubling the DPR should halve the CSS width, height, and translation of the canvas.
// This tests https://github.com/flutter/flutter/issues/77084
window.debugOverrideDevicePixelRatio(2.0);
EngineFlutterDisplay.instance.debugOverrideDevicePixelRatio(2.0);
final CkSurface dpr2Surface2 =
surface.acquireFrame(const ui.Size(5, 15)).skiaSurface;
final DomOffscreenCanvas dpr2Canvas = surface.debugOffscreenCanvas!;
@ -168,7 +168,7 @@ void testMain() {
// Increase device-pixel ratio: this makes CSS pixels bigger, so we need
// fewer of them to cover the browser window.
window.debugOverrideDevicePixelRatio(2.0);
EngineFlutterDisplay.instance.debugOverrideDevicePixelRatio(2.0);
final CkSurface highDpr =
surface.acquireFrame(const ui.Size(10, 16)).skiaSurface;
expect(highDpr.width(), 10);
@ -178,7 +178,7 @@ void testMain() {
// Decrease device-pixel ratio: this makes CSS pixels smaller, so we need
// more of them to cover the browser window.
window.debugOverrideDevicePixelRatio(0.5);
EngineFlutterDisplay.instance.debugOverrideDevicePixelRatio(0.5);
final CkSurface lowDpr =
surface.acquireFrame(const ui.Size(10, 16)).skiaSurface;
expect(lowDpr.width(), 10);
@ -187,7 +187,7 @@ void testMain() {
expect(surface.debugOffscreenCanvas!.height, 16);
// See https://github.com/flutter/flutter/issues/77084#issuecomment-1120151172
window.debugOverrideDevicePixelRatio(2.0);
EngineFlutterDisplay.instance.debugOverrideDevicePixelRatio(2.0);
final CkSurface changeRatioAndSize =
surface.acquireFrame(const ui.Size(9.9, 15.9)).skiaSurface;
expect(changeRatioAndSize.width(), 10);

View File

@ -97,7 +97,9 @@ void testMain() {
group('test fonts in flutterTester environment', () {
final bool resetValue = ui_web.debugEmulateFlutterTesterEnvironment;
ui_web.debugEmulateFlutterTesterEnvironment = true;
tearDownAll(() => ui_web.debugEmulateFlutterTesterEnvironment = resetValue);
tearDownAll(() {
ui_web.debugEmulateFlutterTesterEnvironment = resetValue;
});
const List<String> testFonts = <String>['FlutterTest', 'Ahem'];
test('The default test font is used when a non-test fontFamily is specified', () {

View File

@ -12,28 +12,28 @@ import 'package:ui/ui.dart' as ui;
/// See CanvasKit-specific and HTML-specific test files `frame_timings_test.dart`.
Future<void> runFrameTimingsTest() async {
List<ui.FrameTiming>? timings;
ui.window.onReportTimings = (List<ui.FrameTiming> data) {
ui.PlatformDispatcher.instance.onReportTimings = (List<ui.FrameTiming> data) {
timings = data;
};
Completer<void> frameDone = Completer<void>();
ui.window.onDrawFrame = () {
ui.PlatformDispatcher.instance.onDrawFrame = () {
final ui.SceneBuilder sceneBuilder = ui.SceneBuilder();
sceneBuilder
..pushOffset(0, 0)
..pop();
ui.window.render(sceneBuilder.build());
ui.PlatformDispatcher.instance.render(sceneBuilder.build());
frameDone.complete();
};
// Frame 1.
ui.window.scheduleFrame();
ui.PlatformDispatcher.instance.scheduleFrame();
await frameDone.future;
expect(timings, isNull, reason: "100 ms hasn't passed yet");
await Future<void>.delayed(const Duration(milliseconds: 150));
// Frame 2.
frameDone = Completer<void>();
ui.window.scheduleFrame();
ui.PlatformDispatcher.instance.scheduleFrame();
await frameDone.future;
expect(timings, hasLength(2), reason: '100 ms passed. 2 frames pumped.');
for (final ui.FrameTiming timing in timings!) {

View File

@ -53,8 +53,8 @@ class PlatformMessagesSpy {
));
};
_backup = window.onPlatformMessage;
window.onPlatformMessage = _callback;
_backup = PlatformDispatcher.instance.onPlatformMessage;
PlatformDispatcher.instance.onPlatformMessage = _callback;
}
/// Stop spying on platform messages and clear all intercepted messages.
@ -62,11 +62,11 @@ class PlatformMessagesSpy {
/// Make sure this is called after each test that uses [PlatformMessagesSpy].
void tearDown() {
assert(_isActive);
// Make sure [window.onPlatformMessage] wasn't tampered with.
assert(window.onPlatformMessage == _callback);
// Make sure [PlatformDispatcher.instance.onPlatformMessage] wasn't tampered with.
assert(PlatformDispatcher.instance.onPlatformMessage == _callback);
_callback = null;
messages.clear();
window.onPlatformMessage = _backup;
PlatformDispatcher.instance.onPlatformMessage = _backup;
}
}

View File

@ -15,6 +15,10 @@ void setUpUnitTests({
}) {
late final FakeAssetScope debugFontsScope;
setUpAll(() async {
// The implicit view is needed for `debugEmulateFlutterTesterEnvironment`,
// `flutterViewEmbedder`, and `debugPhysicalSizeOverride`.
engine.ensureImplicitViewInitialized();
if (emulateTesterEnvironment) {
ui_web.debugEmulateFlutterTesterEnvironment = true;
}
@ -31,8 +35,8 @@ void setUpUnitTests({
// we don't have an embedder yet this is the lowest-most layer we can put
// this stuff in.
const double devicePixelRatio = 3.0;
engine.window.debugOverrideDevicePixelRatio(devicePixelRatio);
engine.window.debugPhysicalSizeOverride =
engine.EngineFlutterDisplay.instance.debugOverrideDevicePixelRatio(devicePixelRatio);
engine.EnginePlatformDispatcher.instance.implicitView!.debugPhysicalSizeOverride =
const ui.Size(800 * devicePixelRatio, 600 * devicePixelRatio);
engine.scheduleFrameCallback = () {};
}

View File

@ -15,6 +15,10 @@ void main() {
}
void testMain() {
setUpAll(() {
ensureImplicitViewInitialized();
});
test('populates flt-renderer and flt-build-mode', () {
FlutterViewEmbedder();
expect(domDocument.body!.getAttribute('flt-renderer'),

View File

@ -7,16 +7,15 @@ import 'dart:async';
import 'package:quiver/testing/async.dart';
import 'package:test/bootstrap/browser.dart';
import 'package:test/test.dart';
import 'package:ui/src/engine.dart' show window;
import 'package:ui/src/engine/dom.dart' show DomEvent, createDomPopStateEvent;
import 'package:ui/src/engine/navigation/history.dart';
import 'package:ui/src/engine/services.dart';
import 'package:ui/src/engine/test_embedding.dart';
import 'package:ui/src/engine.dart';
import 'package:ui/ui_web/src/ui_web.dart';
import '../common/matchers.dart';
import '../common/spy.dart';
EngineFlutterWindow get implicitView =>
EnginePlatformDispatcher.instance.implicitView!;
Map<String, dynamic> _wrapOriginState(dynamic state) {
return <String, dynamic>{'origin': true, 'state': state};
}
@ -38,6 +37,10 @@ void main() {
}
void testMain() {
setUpAll(() {
ensureImplicitViewInitialized();
});
test('createHistoryForExistingState', () {
TestUrlStrategy strategy;
BrowserHistory history;
@ -91,14 +94,14 @@ void testMain() {
tearDown(() async {
spy.tearDown();
await window.resetHistory();
await implicitView.resetHistory();
});
test('basic setup works', () async {
final TestUrlStrategy strategy = TestUrlStrategy.fromEntry(
const TestHistoryEntry('initial state', null, '/initial'),
);
await window.debugInitializeHistory(strategy, useSingle: true);
await implicitView.debugInitializeHistory(strategy, useSingle: true);
// There should be two entries: origin and flutter.
expect(strategy.history, hasLength(2));
@ -127,7 +130,7 @@ void testMain() {
);
expect(strategy.listeners, isEmpty);
await window.debugInitializeHistory(strategy, useSingle: true);
await implicitView.debugInitializeHistory(strategy, useSingle: true);
// There should be one `popstate` listener and two history entries.
@ -139,7 +142,7 @@ void testMain() {
expect(strategy.history[1].url, '/initial');
FakeAsync().run((FakeAsync fakeAsync) {
window.browserHistory.dispose();
implicitView.browserHistory.dispose();
// The `TestUrlStrategy` implementation uses microtasks to schedule the
// removal of event listeners.
fakeAsync.flushMicrotasks();
@ -156,7 +159,7 @@ void testMain() {
// An extra call to dispose should be safe.
FakeAsync().run((FakeAsync fakeAsync) {
expect(() => window.browserHistory.dispose(), returnsNormally);
expect(() => implicitView.browserHistory.dispose(), returnsNormally);
fakeAsync.flushMicrotasks();
});
@ -169,22 +172,22 @@ void testMain() {
expect(strategy.history[1].url, '/initial');
// Can still teardown after being disposed.
await window.browserHistory.tearDown();
await implicitView.browserHistory.tearDown();
expect(strategy.history, hasLength(2));
expect(strategy.currentEntry.state, unwrappedOriginState);
expect(strategy.currentEntry.url, '/initial');
});
test('disposes gracefully when url strategy is null', () async {
await window.debugInitializeHistory(null, useSingle: true);
expect(() => window.browserHistory.dispose(), returnsNormally);
await implicitView.debugInitializeHistory(null, useSingle: true);
expect(() => implicitView.browserHistory.dispose(), returnsNormally);
});
test('browser back button pops routes correctly', () async {
final TestUrlStrategy strategy = TestUrlStrategy.fromEntry(
const TestHistoryEntry(null, null, '/home'),
);
await window.debugInitializeHistory(strategy, useSingle: true);
await implicitView.debugInitializeHistory(strategy, useSingle: true);
// Initially, we should be on the flutter entry.
expect(strategy.history, hasLength(2));
@ -219,7 +222,7 @@ void testMain() {
final TestUrlStrategy strategy = TestUrlStrategy.fromEntry(
const TestHistoryEntry(null, null, '/home'),
);
await window.debugInitializeHistory(strategy, useSingle: true);
await implicitView.debugInitializeHistory(strategy, useSingle: true);
await routeUpdated('/page1');
await routeUpdated('/page2');
@ -285,7 +288,7 @@ void testMain() {
final TestUrlStrategy strategy = TestUrlStrategy.fromEntry(
const TestHistoryEntry(null, null, '/home'),
);
await window.debugInitializeHistory(strategy, useSingle: true);
await implicitView.debugInitializeHistory(strategy, useSingle: true);
await strategy.simulateUserTypingUrl('/page3');
// This delay is necessary to wait for [BrowserHistory] because it
@ -326,7 +329,7 @@ void testMain() {
final TestUrlStrategy strategy = TestUrlStrategy.fromEntry(
const TestHistoryEntry(null, null, '/home'),
);
await window.debugInitializeHistory(strategy, useSingle: true);
await implicitView.debugInitializeHistory(strategy, useSingle: true);
await strategy.simulateUserTypingUrl('/unknown');
// This delay is necessary to wait for [BrowserHistory] because it
@ -356,14 +359,14 @@ void testMain() {
tearDown(() async {
spy.tearDown();
await window.resetHistory();
await implicitView.resetHistory();
});
test('basic setup works', () async {
final TestUrlStrategy strategy = TestUrlStrategy.fromEntry(
const TestHistoryEntry('initial state', null, '/initial'),
);
await window.debugInitializeHistory(strategy, useSingle: false);
await implicitView.debugInitializeHistory(strategy, useSingle: false);
// There should be only one entry.
expect(strategy.history, hasLength(1));
@ -383,7 +386,7 @@ void testMain() {
);
expect(strategy.listeners, isEmpty);
await window.debugInitializeHistory(strategy, useSingle: false);
await implicitView.debugInitializeHistory(strategy, useSingle: false);
// There should be one `popstate` listener and one history entry.
@ -393,7 +396,7 @@ void testMain() {
expect(strategy.history.single.url, '/initial');
FakeAsync().run((FakeAsync fakeAsync) {
window.browserHistory.dispose();
implicitView.browserHistory.dispose();
// The `TestUrlStrategy` implementation uses microtasks to schedule the
// removal of event listeners.
fakeAsync.flushMicrotasks();
@ -408,7 +411,7 @@ void testMain() {
// An extra call to dispose should be safe.
FakeAsync().run((FakeAsync fakeAsync) {
expect(() => window.browserHistory.dispose(), returnsNormally);
expect(() => implicitView.browserHistory.dispose(), returnsNormally);
fakeAsync.flushMicrotasks();
});
@ -419,22 +422,22 @@ void testMain() {
expect(strategy.history.single.url, '/initial');
// Can still teardown after being disposed.
await window.browserHistory.tearDown();
await implicitView.browserHistory.tearDown();
expect(strategy.history, hasLength(1));
expect(strategy.history.single.state, untaggedState);
expect(strategy.history.single.url, '/initial');
});
test('disposes gracefully when url strategy is null', () async {
await window.debugInitializeHistory(null, useSingle: false);
expect(() => window.browserHistory.dispose(), returnsNormally);
await implicitView.debugInitializeHistory(null, useSingle: false);
expect(() => implicitView.browserHistory.dispose(), returnsNormally);
});
test('browser back button push route information correctly', () async {
final TestUrlStrategy strategy = TestUrlStrategy.fromEntry(
const TestHistoryEntry('initial state', null, '/home'),
);
await window.debugInitializeHistory(strategy, useSingle: false);
await implicitView.debugInitializeHistory(strategy, useSingle: false);
// Initially, we should be on the flutter entry.
expect(strategy.history, hasLength(1));
@ -473,7 +476,7 @@ void testMain() {
final TestUrlStrategy strategy = TestUrlStrategy.fromEntry(
const TestHistoryEntry('initial state', null, '/home'),
);
await window.debugInitializeHistory(strategy, useSingle: false);
await implicitView.debugInitializeHistory(strategy, useSingle: false);
await routeInformationUpdated('/page1', 'page1 state');
await routeInformationUpdated('/page2', 'page2 state');
@ -522,7 +525,7 @@ void testMain() {
final TestUrlStrategy strategy = TestUrlStrategy.fromEntry(
const TestHistoryEntry('initial state', null, '/home'),
);
await window.debugInitializeHistory(strategy, useSingle: false);
await implicitView.debugInitializeHistory(strategy, useSingle: false);
await strategy.simulateUserTypingUrl('/page3');
// This delay is necessary to wait for [BrowserHistory] because it
@ -565,7 +568,7 @@ void testMain() {
final TestUrlStrategy strategy = TestUrlStrategy.fromEntry(
const TestHistoryEntry('initial state', null, '/home'),
);
await window.debugInitializeHistory(strategy, useSingle: false);
await implicitView.debugInitializeHistory(strategy, useSingle: false);
await routeInformationUpdated('/page1', 'page1 state');
await routeInformationUpdated('/page2', 'page2 state');
@ -743,7 +746,7 @@ void testMain() {
Future<void> routeUpdated(String routeName) {
final Completer<void> completer = Completer<void>();
window.sendPlatformMessage(
implicitView.sendPlatformMessage(
'flutter/navigation',
codec.encodeMethodCall(MethodCall(
'routeUpdated',
@ -756,7 +759,7 @@ Future<void> routeUpdated(String routeName) {
Future<void> routeInformationUpdated(String location, dynamic state) {
final Completer<void> completer = Completer<void>();
window.sendPlatformMessage(
implicitView.sendPlatformMessage(
'flutter/navigation',
codec.encodeMethodCall(MethodCall(
'routeInformationUpdated',
@ -769,7 +772,7 @@ Future<void> routeInformationUpdated(String location, dynamic state) {
Future<void> systemNavigatorPop() {
final Completer<void> completer = Completer<void>();
window.sendPlatformMessage(
implicitView.sendPlatformMessage(
'flutter/platform',
codec.encodeMethodCall(const MethodCall('SystemNavigator.pop')),
(_) => completer.complete(),

View File

@ -8,9 +8,14 @@ import 'dart:typed_data';
import 'package:test/bootstrap/browser.dart';
import 'package:test/test.dart';
import 'package:ui/src/engine.dart' as engine;
import 'package:ui/src/engine/window.dart';
import 'package:ui/ui.dart' as ui;
const engine.MethodCodec codec = engine.JSONMethodCodec();
engine.EngineFlutterWindow get implicitView =>
engine.EnginePlatformDispatcher.instance.implicitView!;
void emptyCallback(ByteData date) {}
void main() {
@ -20,19 +25,23 @@ void main() {
void testMain() {
engine.TestUrlStrategy? strategy;
setUpAll(() {
ensureImplicitViewInitialized();
});
setUp(() async {
strategy = engine.TestUrlStrategy();
await engine.window.debugInitializeHistory(strategy, useSingle: true);
await implicitView.debugInitializeHistory(strategy, useSingle: true);
});
tearDown(() async {
strategy = null;
await engine.window.resetHistory();
await implicitView.resetHistory();
});
test('Tracks pushed, replaced and popped routes', () async {
final Completer<void> completer = Completer<void>();
engine.window.sendPlatformMessage(
ui.PlatformDispatcher.instance.sendPlatformMessage(
'flutter/navigation',
codec.encodeMethodCall(const engine.MethodCall(
'routeUpdated',

View File

@ -31,7 +31,7 @@ Future<void> testMain() async {
expect(domDocument.title, '');
expect(getCssThemeColor(), isNull);
ui.window.sendPlatformMessage(
ui.PlatformDispatcher.instance.sendPlatformMessage(
'flutter/platform',
codec.encodeMethodCall(const MethodCall(
'SystemChrome.setApplicationSwitcherDescription',
@ -48,7 +48,7 @@ Future<void> testMain() async {
expect(domDocument.title, 'Title Test');
expect(getCssThemeColor(), expectedPrimaryColor.toCssString());
ui.window.sendPlatformMessage(
ui.PlatformDispatcher.instance.sendPlatformMessage(
'flutter/platform',
codec.encodeMethodCall(const MethodCall(
'SystemChrome.setApplicationSwitcherDescription',
@ -75,7 +75,7 @@ Future<void> testMain() async {
domDocument.title = 'Something Else';
expect(domDocument.title, 'Something Else');
ui.window.sendPlatformMessage(
ui.PlatformDispatcher.instance.sendPlatformMessage(
'flutter/platform',
codec.encodeMethodCall(const MethodCall(
'SystemChrome.setApplicationSwitcherDescription',
@ -93,7 +93,7 @@ Future<void> testMain() async {
domDocument.title = 'Something Else';
expect(domDocument.title, 'Something Else');
ui.window.sendPlatformMessage(
ui.PlatformDispatcher.instance.sendPlatformMessage(
'flutter/platform',
codec.encodeMethodCall(const MethodCall(
'SystemChrome.setApplicationSwitcherDescription',

View File

@ -18,7 +18,7 @@ void testMain() {
const MethodCodec codec = JSONMethodCodec();
void sendSetSystemUIOverlayStyle({ui.Color? statusBarColor}) {
ui.window.sendPlatformMessage(
ui.PlatformDispatcher.instance.sendPlatformMessage(
'flutter/platform',
codec.encodeMethodCall(MethodCall(
'SystemChrome.setSystemUIOverlayStyle',

View File

@ -28,8 +28,8 @@ void testMain() {
late double dpi;
setUp(() {
ui.window.onPointerDataPacket = null;
dpi = window.devicePixelRatio;
ui.PlatformDispatcher.instance.onPointerDataPacket = null;
dpi = EngineFlutterDisplay.instance.devicePixelRatio;
});
tearDown(() {
@ -253,7 +253,7 @@ void testMain() {
() {
final _BasicEventContext context = _PointerEventContext();
final List<ui.PointerDataPacket> packets = <ui.PointerDataPacket>[];
ui.window.onPointerDataPacket = (ui.PointerDataPacket packet) {
ui.PlatformDispatcher.instance.onPointerDataPacket = (ui.PointerDataPacket packet) {
packets.add(packet);
};
@ -285,7 +285,7 @@ void testMain() {
() {
final _BasicEventContext context = _PointerEventContext();
ui.PointerDataPacket? receivedPacket;
ui.window.onPointerDataPacket = (ui.PointerDataPacket packet) {
ui.PlatformDispatcher.instance.onPointerDataPacket = (ui.PointerDataPacket packet) {
receivedPacket = packet;
};
@ -301,7 +301,7 @@ void testMain() {
() {
final _BasicEventContext context = _PointerEventContext();
final List<ui.PointerDataPacket> packets = <ui.PointerDataPacket>[];
ui.window.onPointerDataPacket = (ui.PointerDataPacket packet) {
ui.PlatformDispatcher.instance.onPointerDataPacket = (ui.PointerDataPacket packet) {
packets.add(packet);
};
@ -576,7 +576,7 @@ void testMain() {
() {
final _ButtonedEventMixin context = _PointerEventContext();
final List<ui.PointerDataPacket> packets = <ui.PointerDataPacket>[];
ui.window.onPointerDataPacket = (ui.PointerDataPacket packet) {
ui.PlatformDispatcher.instance.onPointerDataPacket = (ui.PointerDataPacket packet) {
packets.add(packet);
};
@ -647,7 +647,7 @@ void testMain() {
() {
final _ButtonedEventMixin context = _PointerEventContext();
final List<ui.PointerDataPacket> packets = <ui.PointerDataPacket>[];
ui.window.onPointerDataPacket = (ui.PointerDataPacket packet) {
ui.PlatformDispatcher.instance.onPointerDataPacket = (ui.PointerDataPacket packet) {
packets.add(packet);
};
@ -667,7 +667,7 @@ void testMain() {
() {
final _ButtonedEventMixin context = _PointerEventContext();
final List<ui.PointerDataPacket> packets = <ui.PointerDataPacket>[];
ui.window.onPointerDataPacket = (ui.PointerDataPacket packet) {
ui.PlatformDispatcher.instance.onPointerDataPacket = (ui.PointerDataPacket packet) {
packets.add(packet);
};
@ -700,7 +700,7 @@ void testMain() {
() {
final _ButtonedEventMixin context = _PointerEventContext();
final List<ui.PointerDataPacket> packets = <ui.PointerDataPacket>[];
ui.window.onPointerDataPacket = (ui.PointerDataPacket packet) {
ui.PlatformDispatcher.instance.onPointerDataPacket = (ui.PointerDataPacket packet) {
packets.add(packet);
};
@ -818,10 +818,10 @@ void testMain() {
const double dpi = 2.5;
debugOperatingSystemOverride = OperatingSystem.macOs;
debugBrowserEngineOverride = BrowserEngine.firefox;
window.debugOverrideDevicePixelRatio(dpi);
EngineFlutterDisplay.instance.debugOverrideDevicePixelRatio(dpi);
final List<ui.PointerDataPacket> packets = <ui.PointerDataPacket>[];
ui.window.onPointerDataPacket = (ui.PointerDataPacket packet) {
ui.PlatformDispatcher.instance.onPointerDataPacket = (ui.PointerDataPacket packet) {
packets.add(packet);
};
@ -849,7 +849,7 @@ void testMain() {
expect(packets[0].data[0].scrollDeltaX, equals(10.0 * dpi));
expect(packets[0].data[0].scrollDeltaY, equals(10.0 * dpi));
window.debugOverrideDevicePixelRatio(1.0);
EngineFlutterDisplay.instance.debugOverrideDevicePixelRatio(1.0);
debugOperatingSystemOverride = null;
debugBrowserEngineOverride = null;
},
@ -863,10 +863,10 @@ void testMain() {
const double dpi = 2.5;
debugOperatingSystemOverride = OperatingSystem.macOs;
debugBrowserEngineOverride = BrowserEngine.blink;
window.debugOverrideDevicePixelRatio(dpi);
EngineFlutterDisplay.instance.debugOverrideDevicePixelRatio(dpi);
final List<ui.PointerDataPacket> packets = <ui.PointerDataPacket>[];
ui.window.onPointerDataPacket = (ui.PointerDataPacket packet) {
ui.PlatformDispatcher.instance.onPointerDataPacket = (ui.PointerDataPacket packet) {
packets.add(packet);
};
@ -894,7 +894,7 @@ void testMain() {
expect(packets[0].data[0].scrollDeltaX, equals(10.0));
expect(packets[0].data[0].scrollDeltaY, equals(10.0));
window.debugOverrideDevicePixelRatio(1.0);
EngineFlutterDisplay.instance.debugOverrideDevicePixelRatio(1.0);
debugOperatingSystemOverride = null;
debugBrowserEngineOverride = null;
},
@ -910,7 +910,7 @@ void testMain() {
}
final _ButtonedEventMixin context = _PointerEventContext();
final List<ui.PointerDataPacket> packets = <ui.PointerDataPacket>[];
ui.window.onPointerDataPacket = (ui.PointerDataPacket packet) {
ui.PlatformDispatcher.instance.onPointerDataPacket = (ui.PointerDataPacket packet) {
packets.add(packet);
};
@ -1147,7 +1147,7 @@ void testMain() {
() {
final _ButtonedEventMixin context = _PointerEventContext();
final List<ui.PointerDataPacket> packets = <ui.PointerDataPacket>[];
ui.window.onPointerDataPacket = (ui.PointerDataPacket packet) {
ui.PlatformDispatcher.instance.onPointerDataPacket = (ui.PointerDataPacket packet) {
packets.add(packet);
};
@ -1248,7 +1248,7 @@ void testMain() {
() {
final _ButtonedEventMixin context = _PointerEventContext();
final List<ui.PointerDataPacket> packets = <ui.PointerDataPacket>[];
ui.window.onPointerDataPacket = (ui.PointerDataPacket packet) {
ui.PlatformDispatcher.instance.onPointerDataPacket = (ui.PointerDataPacket packet) {
packets.add(packet);
};
@ -1372,7 +1372,7 @@ void testMain() {
() {
final _ButtonedEventMixin context = _PointerEventContext();
final List<ui.PointerDataPacket> packets = <ui.PointerDataPacket>[];
ui.window.onPointerDataPacket = (ui.PointerDataPacket packet) {
ui.PlatformDispatcher.instance.onPointerDataPacket = (ui.PointerDataPacket packet) {
packets.add(packet);
};
@ -1562,7 +1562,7 @@ void testMain() {
() {
final _ButtonedEventMixin context = _PointerEventContext();
final List<ui.PointerDataPacket> packets = <ui.PointerDataPacket>[];
ui.window.onPointerDataPacket = (ui.PointerDataPacket packet) {
ui.PlatformDispatcher.instance.onPointerDataPacket = (ui.PointerDataPacket packet) {
packets.add(packet);
};
@ -1626,7 +1626,7 @@ void testMain() {
// clicking, then dismisses it with a left click.
final List<ui.PointerDataPacket> packets = <ui.PointerDataPacket>[];
ui.window.onPointerDataPacket = (ui.PointerDataPacket packet) {
ui.PlatformDispatcher.instance.onPointerDataPacket = (ui.PointerDataPacket packet) {
packets.add(packet);
};
@ -1708,7 +1708,7 @@ void testMain() {
// - Releases RMB.
final List<ui.PointerDataPacket> packets = <ui.PointerDataPacket>[];
ui.window.onPointerDataPacket = (ui.PointerDataPacket packet) {
ui.PlatformDispatcher.instance.onPointerDataPacket = (ui.PointerDataPacket packet) {
packets.add(packet);
};
@ -1777,7 +1777,7 @@ void testMain() {
// - Moves mouse.
final List<ui.PointerDataPacket> packets = <ui.PointerDataPacket>[];
ui.window.onPointerDataPacket = (ui.PointerDataPacket packet) {
ui.PlatformDispatcher.instance.onPointerDataPacket = (ui.PointerDataPacket packet) {
packets.add(packet);
};
@ -1823,7 +1823,7 @@ void testMain() {
// The move event will have "button:-1, buttons:2".
final List<ui.PointerDataPacket> packets = <ui.PointerDataPacket>[];
ui.window.onPointerDataPacket = (ui.PointerDataPacket packet) {
ui.PlatformDispatcher.instance.onPointerDataPacket = (ui.PointerDataPacket packet) {
packets.add(packet);
};
@ -1856,7 +1856,7 @@ void testMain() {
// - Move the pointer to hover.
final List<ui.PointerDataPacket> packets = <ui.PointerDataPacket>[];
ui.window.onPointerDataPacket = (ui.PointerDataPacket packet) {
ui.PlatformDispatcher.instance.onPointerDataPacket = (ui.PointerDataPacket packet) {
packets.add(packet);
};
@ -1915,7 +1915,7 @@ void testMain() {
// could be in a different location without any `*move` events in between.
final List<ui.PointerDataPacket> packets = <ui.PointerDataPacket>[];
ui.window.onPointerDataPacket = (ui.PointerDataPacket packet) {
ui.PlatformDispatcher.instance.onPointerDataPacket = (ui.PointerDataPacket packet) {
packets.add(packet);
};
@ -1974,7 +1974,7 @@ void testMain() {
// - Clicks RMB again in a different location;
final List<ui.PointerDataPacket> packets = <ui.PointerDataPacket>[];
ui.window.onPointerDataPacket = (ui.PointerDataPacket packet) {
ui.PlatformDispatcher.instance.onPointerDataPacket = (ui.PointerDataPacket packet) {
packets.add(packet);
};
@ -2045,7 +2045,7 @@ void testMain() {
// This seems to be happening sometimes when using RMB on the Mac trackpad.
final List<ui.PointerDataPacket> packets = <ui.PointerDataPacket>[];
ui.window.onPointerDataPacket = (ui.PointerDataPacket packet) {
ui.PlatformDispatcher.instance.onPointerDataPacket = (ui.PointerDataPacket packet) {
packets.add(packet);
};
@ -2127,7 +2127,7 @@ void testMain() {
// when the context menu is shown.
final List<ui.PointerDataPacket> packets = <ui.PointerDataPacket>[];
ui.window.onPointerDataPacket = (ui.PointerDataPacket packet) {
ui.PlatformDispatcher.instance.onPointerDataPacket = (ui.PointerDataPacket packet) {
packets.add(packet);
};
@ -2189,7 +2189,7 @@ void testMain() {
// Flutter: down-------move-------move-------up
final List<ui.PointerDataPacket> packets = <ui.PointerDataPacket>[];
ui.window.onPointerDataPacket = (ui.PointerDataPacket packet) {
ui.PlatformDispatcher.instance.onPointerDataPacket = (ui.PointerDataPacket packet) {
packets.add(packet);
};
@ -2266,7 +2266,7 @@ void testMain() {
// browser window.
final List<ui.PointerDataPacket> packets = <ui.PointerDataPacket>[];
ui.window.onPointerDataPacket = (ui.PointerDataPacket packet) {
ui.PlatformDispatcher.instance.onPointerDataPacket = (ui.PointerDataPacket packet) {
packets.add(packet);
};
@ -2326,7 +2326,7 @@ void testMain() {
final _MultiPointerEventMixin context = _PointerEventContext();
final List<ui.PointerDataPacket> packets = <ui.PointerDataPacket>[];
List<ui.PointerData> data;
ui.window.onPointerDataPacket = (ui.PointerDataPacket packet) {
ui.PlatformDispatcher.instance.onPointerDataPacket = (ui.PointerDataPacket packet) {
packets.add(packet);
};
@ -2491,7 +2491,7 @@ void testMain() {
() {
final _MultiPointerEventMixin context = _PointerEventContext();
final List<ui.PointerDataPacket> packets = <ui.PointerDataPacket>[];
ui.window.onPointerDataPacket = (ui.PointerDataPacket packet) {
ui.PlatformDispatcher.instance.onPointerDataPacket = (ui.PointerDataPacket packet) {
packets.add(packet);
};
@ -2532,7 +2532,7 @@ void testMain() {
() {
final _PointerEventContext context = _PointerEventContext();
final List<ui.PointerDataPacket> packets = <ui.PointerDataPacket>[];
ui.window.onPointerDataPacket = (ui.PointerDataPacket packet) {
ui.PlatformDispatcher.instance.onPointerDataPacket = (ui.PointerDataPacket packet) {
packets.add(packet);
};
@ -2569,7 +2569,7 @@ void testMain() {
() {
final _PointerEventContext context = _PointerEventContext();
final List<ui.PointerDataPacket> packets = <ui.PointerDataPacket>[];
ui.window.onPointerDataPacket = (ui.PointerDataPacket packet) {
ui.PlatformDispatcher.instance.onPointerDataPacket = (ui.PointerDataPacket packet) {
packets.add(packet);
};
@ -2596,7 +2596,7 @@ void testMain() {
// For more info, see: https://github.com/flutter/flutter/issues/75559
final List<ui.PointerDataPacket> packets = <ui.PointerDataPacket>[];
ui.window.onPointerDataPacket = (ui.PointerDataPacket packet) {
ui.PlatformDispatcher.instance.onPointerDataPacket = (ui.PointerDataPacket packet) {
packets.add(packet);
};
@ -2684,7 +2684,7 @@ void _testClickDebouncer() {
context = _PointerEventContext();
pointerPackets = <ui.PointerChange>[];
semanticsActions = <CapturedSemanticsEvent>[];
ui.window.onPointerDataPacket = (ui.PointerDataPacket packet) {
ui.PlatformDispatcher.instance.onPointerDataPacket = (ui.PointerDataPacket packet) {
for (final ui.PointerData data in packet.data) {
pointerPackets.add(data.change);
}

View File

@ -7,11 +7,7 @@ import 'dart:typed_data';
import 'package:quiver/testing/async.dart';
import 'package:test/bootstrap/browser.dart';
import 'package:test/test.dart';
import 'package:ui/src/engine/browser_detection.dart';
import 'package:ui/src/engine/dom.dart';
import 'package:ui/src/engine/raw_keyboard.dart';
import 'package:ui/src/engine/services.dart';
import 'package:ui/src/engine/text_editing/text_editing.dart';
import 'package:ui/src/engine.dart';
import 'package:ui/ui.dart' as ui;
void main() {
@ -20,15 +16,15 @@ void main() {
void testMain() {
group('RawKeyboard', () {
/// Used to save and restore [ui.window.onPlatformMessage] after each test.
/// Used to save and restore [PlatformDispatcher.onPlatformMessage] after each test.
ui.PlatformMessageCallback? savedCallback;
setUp(() {
savedCallback = ui.window.onPlatformMessage;
savedCallback = ui.PlatformDispatcher.instance.onPlatformMessage;
});
tearDown(() {
ui.window.onPlatformMessage = savedCallback;
ui.PlatformDispatcher.instance.onPlatformMessage = savedCallback;
});
test('initializes and disposes', () {
@ -44,7 +40,7 @@ void testMain() {
String? channelReceived;
Map<String, dynamic>? dataReceived;
ui.window.onPlatformMessage = (String channel, ByteData? data,
ui.PlatformDispatcher.instance.onPlatformMessage = (String channel, ByteData? data,
ui.PlatformMessageResponseCallback? callback) {
channelReceived = channel;
dataReceived = const JSONMessageCodec().decodeMessage(data) as Map<String, dynamic>?;
@ -78,7 +74,7 @@ void testMain() {
String? channelReceived;
Map<String, dynamic>? dataReceived;
ui.window.onPlatformMessage = (String channel, ByteData? data,
ui.PlatformDispatcher.instance.onPlatformMessage = (String channel, ByteData? data,
ui.PlatformMessageResponseCallback? callback) {
channelReceived = channel;
dataReceived = const JSONMessageCodec().decodeMessage(data) as Map<String, dynamic>?;
@ -108,7 +104,7 @@ void testMain() {
RawKeyboard.initialize();
Map<String, dynamic>? dataReceived;
ui.window.onPlatformMessage = (String channel, ByteData? data,
ui.PlatformDispatcher.instance.onPlatformMessage = (String channel, ByteData? data,
ui.PlatformMessageResponseCallback? callback) {
dataReceived = const JSONMessageCodec().decodeMessage(data) as Map<String, dynamic>?;
};
@ -161,7 +157,7 @@ void testMain() {
RawKeyboard.initialize();
Map<String, dynamic>? dataReceived;
ui.window.onPlatformMessage = (String channel, ByteData? data,
ui.PlatformDispatcher.instance.onPlatformMessage = (String channel, ByteData? data,
ui.PlatformMessageResponseCallback? callback) {
dataReceived = const JSONMessageCodec().decodeMessage(data) as Map<String, dynamic>?;
};
@ -189,7 +185,7 @@ void testMain() {
RawKeyboard.initialize();
final List<Map<String, dynamic>> messages = <Map<String, dynamic>>[];
ui.window.onPlatformMessage = (String channel, ByteData? data,
ui.PlatformDispatcher.instance.onPlatformMessage = (String channel, ByteData? data,
ui.PlatformMessageResponseCallback? callback) {
messages.add(const JSONMessageCodec().decodeMessage(data) as Map<String, dynamic>);
};
@ -242,7 +238,7 @@ void testMain() {
RawKeyboard.initialize();
int count = 0;
ui.window.onPlatformMessage = (String channel, ByteData? data,
ui.PlatformDispatcher.instance.onPlatformMessage = (String channel, ByteData? data,
ui.PlatformMessageResponseCallback? callback) {
count += 1;
};
@ -266,7 +262,7 @@ void testMain() {
RawKeyboard.initialize();
int count = 0;
ui.window.onPlatformMessage = (String channel, ByteData? data,
ui.PlatformDispatcher.instance.onPlatformMessage = (String channel, ByteData? data,
ui.PlatformMessageResponseCallback? callback) {
count += 1;
final ByteData response = const JSONMessageCodec().encodeMessage(<String, dynamic>{'handled': true})!;
@ -289,7 +285,7 @@ void testMain() {
RawKeyboard.initialize();
int count = 0;
ui.window.onPlatformMessage = (String channel, ByteData? data,
ui.PlatformDispatcher.instance.onPlatformMessage = (String channel, ByteData? data,
ui.PlatformMessageResponseCallback? callback) {
count += 1;
final ByteData response = const JSONMessageCodec().encodeMessage(<String, dynamic>{'handled': false})!;
@ -312,7 +308,7 @@ void testMain() {
RawKeyboard.initialize();
int count = 0;
ui.window.onPlatformMessage = (String channel, ByteData? data,
ui.PlatformDispatcher.instance.onPlatformMessage = (String channel, ByteData? data,
ui.PlatformMessageResponseCallback? callback) {
count += 1;
};
@ -338,7 +334,7 @@ void testMain() {
RawKeyboard.initialize();
int count = 0;
ui.window.onPlatformMessage = (String channel, ByteData? data,
ui.PlatformDispatcher.instance.onPlatformMessage = (String channel, ByteData? data,
ui.PlatformMessageResponseCallback? callback) {
count += 1;
final ByteData response = const JSONMessageCodec().encodeMessage(<String, dynamic>{'handled': true})!;
@ -364,7 +360,7 @@ void testMain() {
RawKeyboard.initialize();
int count = 0;
ui.window.onPlatformMessage = (String channel, ByteData? data,
ui.PlatformDispatcher.instance.onPlatformMessage = (String channel, ByteData? data,
ui.PlatformMessageResponseCallback? callback) {
count += 1;
final ByteData response = const JSONMessageCodec()
@ -395,7 +391,7 @@ void testMain() {
RawKeyboard.initialize(onMacOs: true);
final List<Map<String, dynamic>> messages = <Map<String, dynamic>>[];
ui.window.onPlatformMessage = (String channel, ByteData? data,
ui.PlatformDispatcher.instance.onPlatformMessage = (String channel, ByteData? data,
ui.PlatformMessageResponseCallback? callback) {
messages.add(const JSONMessageCodec().decodeMessage(data) as Map<String, dynamic>);
};
@ -518,7 +514,7 @@ void testMain() {
RawKeyboard.initialize(onMacOs: true);
final List<Map<String, dynamic>> messages = <Map<String, dynamic>>[];
ui.window.onPlatformMessage = (String channel, ByteData? data,
ui.PlatformDispatcher.instance.onPlatformMessage = (String channel, ByteData? data,
ui.PlatformMessageResponseCallback? callback) {
messages.add(const JSONMessageCodec().decodeMessage(data) as Map<String, dynamic>);
};
@ -600,7 +596,7 @@ void testMain() {
RawKeyboard.initialize();
final List<Map<String, dynamic>> messages = <Map<String, dynamic>>[];
ui.window.onPlatformMessage = (String channel, ByteData? data,
ui.PlatformDispatcher.instance.onPlatformMessage = (String channel, ByteData? data,
ui.PlatformMessageResponseCallback? callback) {
messages.add(const JSONMessageCodec().decodeMessage(data) as Map<String, dynamic>);
};
@ -630,7 +626,7 @@ void testMain() {
RawKeyboard.initialize(onMacOs: true);
final List<Map<String, dynamic>> messages = <Map<String, dynamic>>[];
ui.window.onPlatformMessage = (String channel, ByteData? data,
ui.PlatformDispatcher.instance.onPlatformMessage = (String channel, ByteData? data,
ui.PlatformMessageResponseCallback? callback) {
messages.add(const JSONMessageCodec().decodeMessage(data) as Map<String, dynamic>);
};
@ -694,7 +690,7 @@ void testMain() {
RawKeyboard.initialize(); // onMacOs: false
final List<Map<String, dynamic>> messages = <Map<String, dynamic>>[];
ui.window.onPlatformMessage = (String channel, ByteData? data,
ui.PlatformDispatcher.instance.onPlatformMessage = (String channel, ByteData? data,
ui.PlatformMessageResponseCallback? callback) {
messages.add(const JSONMessageCodec().decodeMessage(data) as Map<String, dynamic>);
};

View File

@ -27,25 +27,33 @@ void main() {
}
void testMain() {
late EngineFlutterWindow window;
EngineFlutterWindow? savedWindow;
late EngineFlutterWindow myWindow;
setUpAll(() async {
await initializeEngine();
});
setUp(() {
window = EngineFlutterWindow(0, EnginePlatformDispatcher.instance);
savedWindow = EnginePlatformDispatcher.instance.implicitView;
myWindow = EngineFlutterWindow(0, EnginePlatformDispatcher.instance);
});
tearDown(() async {
await window.resetHistory();
await myWindow.resetHistory();
// Restore the original implicit view.
EnginePlatformDispatcher.instance.unregisterView(myWindow);
if (savedWindow != null) {
EnginePlatformDispatcher.instance.registerView(savedWindow!);
}
});
// For now, web always has an implicit view provided by the web engine.
test('EnginePlatformDispatcher.instance.implicitView should be non-null', () async {
expect(EnginePlatformDispatcher.instance.implicitView, isNotNull);
expect(EnginePlatformDispatcher.instance.implicitView?.viewId, 0);
expect(window.viewId, 0);
expect(myWindow.viewId, 0);
});
test('window.defaultRouteName should work with a custom url strategy', () async {
@ -53,8 +61,8 @@ void testMain() {
const Object state = <dynamic, dynamic>{'origin': true};
final _SampleUrlStrategy customStrategy = _SampleUrlStrategy(path, state);
await window.debugInitializeHistory(customStrategy, useSingle: true);
expect(window.defaultRouteName, '/initial');
await myWindow.debugInitializeHistory(customStrategy, useSingle: true);
expect(myWindow.defaultRouteName, '/initial');
// Also make sure that the custom url strategy was actually used.
expect(customStrategy.wasUsed, isTrue);
});
@ -63,12 +71,12 @@ void testMain() {
final TestUrlStrategy strategy = TestUrlStrategy.fromEntry(
const TestHistoryEntry('initial state', null, '/initial'),
);
await window.debugInitializeHistory(strategy, useSingle: true);
expect(window.defaultRouteName, '/initial');
await myWindow.debugInitializeHistory(strategy, useSingle: true);
expect(myWindow.defaultRouteName, '/initial');
// Changing the URL in the address bar later shouldn't affect [window.defaultRouteName].
strategy.replaceState(null, '', '/newpath');
expect(window.defaultRouteName, '/initial');
expect(myWindow.defaultRouteName, '/initial');
});
// window.defaultRouteName is now permanently decoupled from the history,
@ -76,17 +84,17 @@ void testMain() {
test('window.defaultRouteName should reset after navigation platform message',
() async {
await window.debugInitializeHistory(TestUrlStrategy.fromEntry(
await myWindow.debugInitializeHistory(TestUrlStrategy.fromEntry(
// The URL here does not set the PlatformDispatcher's defaultRouteName,
// since it got cached as soon as we read it above.
const TestHistoryEntry('initial state', null, '/not-really-inital/THIS_IS_IGNORED'),
), useSingle: true);
// Reading it multiple times should return the same value.
expect(window.defaultRouteName, '/initial');
expect(window.defaultRouteName, '/initial');
expect(myWindow.defaultRouteName, '/initial');
expect(myWindow.defaultRouteName, '/initial');
final Completer<void> callback = Completer<void>();
window.sendPlatformMessage(
myWindow.sendPlatformMessage(
'flutter/navigation',
const JSONMethodCodec().encodeMethodCall(const MethodCall(
'routeUpdated',
@ -97,27 +105,27 @@ void testMain() {
await callback.future;
// After a navigation platform message, the PlatformDispatcher's
// defaultRouteName resets to "/".
expect(window.defaultRouteName, '/');
expect(myWindow.defaultRouteName, '/');
});
// window.defaultRouteName is now '/'.
test('can switch history mode', () async {
Completer<void> callback;
await window.debugInitializeHistory(TestUrlStrategy.fromEntry(
await myWindow.debugInitializeHistory(TestUrlStrategy.fromEntry(
const TestHistoryEntry('initial state', null, '/initial'),
), useSingle: false);
expect(window.browserHistory, isA<MultiEntriesBrowserHistory>());
expect(myWindow.browserHistory, isA<MultiEntriesBrowserHistory>());
Future<void> check<T>(String method, Object? arguments) async {
callback = Completer<void>();
window.sendPlatformMessage(
myWindow.sendPlatformMessage(
'flutter/navigation',
const JSONMethodCodec().encodeMethodCall(MethodCall(method, arguments)),
(_) { callback.complete(); },
);
await callback.future;
expect(window.browserHistory, isA<T>());
expect(myWindow.browserHistory, isA<T>());
}
// These may be initialized as `null`
@ -135,7 +143,7 @@ void testMain() {
test('handleNavigationMessage throws for route update methods called with null arguments',
() async {
expect(() async {
await window.handleNavigationMessage(
await myWindow.handleNavigationMessage(
const JSONMethodCodec().encodeMethodCall(const MethodCall(
'routeUpdated',
))
@ -143,7 +151,7 @@ void testMain() {
}, throwsAssertionError);
expect(() async {
await window.handleNavigationMessage(
await myWindow.handleNavigationMessage(
const JSONMethodCodec().encodeMethodCall(const MethodCall(
'routeInformationUpdated',
))
@ -153,33 +161,33 @@ void testMain() {
test('handleNavigationMessage execute request in order.', () async {
// Start with multi entries.
await window.debugInitializeHistory(TestUrlStrategy.fromEntry(
await myWindow.debugInitializeHistory(TestUrlStrategy.fromEntry(
const TestHistoryEntry('initial state', null, '/initial'),
), useSingle: false);
expect(window.browserHistory, isA<MultiEntriesBrowserHistory>());
expect(myWindow.browserHistory, isA<MultiEntriesBrowserHistory>());
final List<String> executionOrder = <String>[];
await window.handleNavigationMessage(
await myWindow.handleNavigationMessage(
const JSONMethodCodec().encodeMethodCall(const MethodCall(
'selectSingleEntryHistory',
))
).then<void>((bool data) {
executionOrder.add('1');
});
await window.handleNavigationMessage(
await myWindow.handleNavigationMessage(
const JSONMethodCodec().encodeMethodCall(const MethodCall(
'selectMultiEntryHistory',
))
).then<void>((bool data) {
executionOrder.add('2');
});
await window.handleNavigationMessage(
await myWindow.handleNavigationMessage(
const JSONMethodCodec().encodeMethodCall(const MethodCall(
'selectSingleEntryHistory',
))
).then<void>((bool data) {
executionOrder.add('3');
});
await window.handleNavigationMessage(
await myWindow.handleNavigationMessage(
const JSONMethodCodec().encodeMethodCall(const MethodCall(
'routeInformationUpdated',
<String, dynamic>{
@ -201,14 +209,14 @@ void testMain() {
test('should not throw when using nav1 and nav2 together',
() async {
await window.debugInitializeHistory(TestUrlStrategy.fromEntry(
await myWindow.debugInitializeHistory(TestUrlStrategy.fromEntry(
const TestHistoryEntry('initial state', null, '/initial'),
), useSingle: false);
expect(window.browserHistory, isA<MultiEntriesBrowserHistory>());
expect(myWindow.browserHistory, isA<MultiEntriesBrowserHistory>());
// routeUpdated resets the history type
Completer<void> callback = Completer<void>();
window.sendPlatformMessage(
myWindow.sendPlatformMessage(
'flutter/navigation',
const JSONMethodCodec().encodeMethodCall(const MethodCall(
'routeUpdated',
@ -217,12 +225,12 @@ void testMain() {
(_) { callback.complete(); },
);
await callback.future;
expect(window.browserHistory, isA<SingleEntryBrowserHistory>());
expect(window.browserHistory.urlStrategy!.getPath(), '/bar');
expect(myWindow.browserHistory, isA<SingleEntryBrowserHistory>());
expect(myWindow.browserHistory.urlStrategy!.getPath(), '/bar');
// routeInformationUpdated does not
callback = Completer<void>();
window.sendPlatformMessage(
myWindow.sendPlatformMessage(
'flutter/navigation',
const JSONMethodCodec().encodeMethodCall(const MethodCall(
'routeInformationUpdated',
@ -234,31 +242,31 @@ void testMain() {
(_) { callback.complete(); },
);
await callback.future;
expect(window.browserHistory, isA<SingleEntryBrowserHistory>());
expect(window.browserHistory.urlStrategy!.getPath(), '/baz');
expect(myWindow.browserHistory, isA<SingleEntryBrowserHistory>());
expect(myWindow.browserHistory.urlStrategy!.getPath(), '/baz');
// they can be interleaved safely
await window.handleNavigationMessage(
await myWindow.handleNavigationMessage(
const JSONMethodCodec().encodeMethodCall(const MethodCall(
'routeUpdated',
<String, dynamic>{'routeName': '/foo'},
))
);
expect(window.browserHistory, isA<SingleEntryBrowserHistory>());
expect(window.browserHistory.urlStrategy!.getPath(), '/foo');
expect(myWindow.browserHistory, isA<SingleEntryBrowserHistory>());
expect(myWindow.browserHistory.urlStrategy!.getPath(), '/foo');
});
test('should not throw when state is complex json object',
() async {
// Regression test https://github.com/flutter/flutter/issues/87823.
await window.debugInitializeHistory(TestUrlStrategy.fromEntry(
await myWindow.debugInitializeHistory(TestUrlStrategy.fromEntry(
const TestHistoryEntry('initial state', null, '/initial'),
), useSingle: false);
expect(window.browserHistory, isA<MultiEntriesBrowserHistory>());
expect(myWindow.browserHistory, isA<MultiEntriesBrowserHistory>());
// routeInformationUpdated does not
final Completer<void> callback = Completer<void>();
window.sendPlatformMessage(
myWindow.sendPlatformMessage(
'flutter/navigation',
const JSONMethodCodec().encodeMethodCall(const MethodCall(
'routeInformationUpdated',
@ -278,9 +286,9 @@ void testMain() {
(_) { callback.complete(); },
);
await callback.future;
expect(window.browserHistory, isA<MultiEntriesBrowserHistory>());
expect(window.browserHistory.urlStrategy!.getPath(), '/baz');
final dynamic wrappedState = window.browserHistory.urlStrategy!.getState();
expect(myWindow.browserHistory, isA<MultiEntriesBrowserHistory>());
expect(myWindow.browserHistory.urlStrategy!.getPath(), '/baz');
final dynamic wrappedState = myWindow.browserHistory.urlStrategy!.getState();
final dynamic actualState = wrappedState['state'];
expect(actualState['state1'], true);
expect(actualState['state2'], 1);
@ -291,14 +299,14 @@ void testMain() {
test('routeInformationUpdated can handle uri',
() async {
await window.debugInitializeHistory(TestUrlStrategy.fromEntry(
await myWindow.debugInitializeHistory(TestUrlStrategy.fromEntry(
const TestHistoryEntry('initial state', null, '/initial'),
), useSingle: false);
expect(window.browserHistory, isA<MultiEntriesBrowserHistory>());
expect(myWindow.browserHistory, isA<MultiEntriesBrowserHistory>());
// routeInformationUpdated does not
final Completer<void> callback = Completer<void>();
window.sendPlatformMessage(
myWindow.sendPlatformMessage(
'flutter/navigation',
const JSONMethodCodec().encodeMethodCall(const MethodCall(
'routeInformationUpdated',
@ -309,19 +317,19 @@ void testMain() {
(_) { callback.complete(); },
);
await callback.future;
expect(window.browserHistory, isA<MultiEntriesBrowserHistory>());
expect(window.browserHistory.urlStrategy!.getPath(), '/baz?abc=def#fragment');
expect(myWindow.browserHistory, isA<MultiEntriesBrowserHistory>());
expect(myWindow.browserHistory.urlStrategy!.getPath(), '/baz?abc=def#fragment');
});
test('can replace in MultiEntriesBrowserHistory',
() async {
await window.debugInitializeHistory(TestUrlStrategy.fromEntry(
await myWindow.debugInitializeHistory(TestUrlStrategy.fromEntry(
const TestHistoryEntry('initial state', null, '/initial'),
), useSingle: false);
expect(window.browserHistory, isA<MultiEntriesBrowserHistory>());
expect(myWindow.browserHistory, isA<MultiEntriesBrowserHistory>());
Completer<void> callback = Completer<void>();
window.sendPlatformMessage(
myWindow.sendPlatformMessage(
'flutter/navigation',
const JSONMethodCodec().encodeMethodCall(const MethodCall(
'routeInformationUpdated',
@ -333,11 +341,11 @@ void testMain() {
(_) { callback.complete(); },
);
await callback.future;
expect(window.browserHistory.urlStrategy!.getPath(), '/baz');
expect(window.browserHistory.urlStrategy!.getState(), _tagStateWithSerialCount('/state', 1));
expect(myWindow.browserHistory.urlStrategy!.getPath(), '/baz');
expect(myWindow.browserHistory.urlStrategy!.getState(), _tagStateWithSerialCount('/state', 1));
callback = Completer<void>();
window.sendPlatformMessage(
myWindow.sendPlatformMessage(
'flutter/navigation',
const JSONMethodCodec().encodeMethodCall(const MethodCall(
'routeInformationUpdated',
@ -350,11 +358,11 @@ void testMain() {
(_) { callback.complete(); },
);
await callback.future;
expect(window.browserHistory.urlStrategy!.getPath(), '/baz');
expect(window.browserHistory.urlStrategy!.getState(), _tagStateWithSerialCount('/state1', 1));
expect(myWindow.browserHistory.urlStrategy!.getPath(), '/baz');
expect(myWindow.browserHistory.urlStrategy!.getState(), _tagStateWithSerialCount('/state1', 1));
callback = Completer<void>();
window.sendPlatformMessage(
myWindow.sendPlatformMessage(
'flutter/navigation',
const JSONMethodCodec().encodeMethodCall(const MethodCall(
'routeInformationUpdated',
@ -366,12 +374,12 @@ void testMain() {
(_) { callback.complete(); },
);
await callback.future;
expect(window.browserHistory.urlStrategy!.getPath(), '/foo');
expect(window.browserHistory.urlStrategy!.getState(), _tagStateWithSerialCount('/foostate1', 2));
expect(myWindow.browserHistory.urlStrategy!.getPath(), '/foo');
expect(myWindow.browserHistory.urlStrategy!.getState(), _tagStateWithSerialCount('/foostate1', 2));
await window.browserHistory.back();
expect(window.browserHistory.urlStrategy!.getPath(), '/baz');
expect(window.browserHistory.urlStrategy!.getState(), _tagStateWithSerialCount('/state1', 1));
await myWindow.browserHistory.back();
expect(myWindow.browserHistory.urlStrategy!.getPath(), '/baz');
expect(myWindow.browserHistory.urlStrategy!.getState(), _tagStateWithSerialCount('/state1', 1));
});
test('initialize browser history with default url strategy (single)', () async {
@ -380,10 +388,10 @@ void testMain() {
// Without initializing history, the default route name should be
// initialized to "/" in tests.
expect(window.defaultRouteName, '/');
expect(myWindow.defaultRouteName, '/');
final Completer<void> callback = Completer<void>();
window.sendPlatformMessage(
myWindow.sendPlatformMessage(
'flutter/navigation',
const JSONMethodCodec().encodeMethodCall(const MethodCall(
'routeUpdated',
@ -392,11 +400,11 @@ void testMain() {
(_) { callback.complete(); },
);
await callback.future;
expect(window.browserHistory, isA<SingleEntryBrowserHistory>());
expect(myWindow.browserHistory, isA<SingleEntryBrowserHistory>());
// The url strategy should've been set to the default, and the path
// should've been correctly set to "/bar".
expect(window.browserHistory.urlStrategy, isNot(isNull));
expect(window.browserHistory.urlStrategy!.getPath(), '/bar');
expect(myWindow.browserHistory.urlStrategy, isNot(isNull));
expect(myWindow.browserHistory.urlStrategy!.getPath(), '/bar');
}, skip: isSafari); // https://github.com/flutter/flutter/issues/50836
test('initialize browser history with default url strategy (multiple)', () async {
@ -405,10 +413,10 @@ void testMain() {
// Without initializing history, the default route name should be
// initialized to "/" in tests.
expect(window.defaultRouteName, '/');
expect(myWindow.defaultRouteName, '/');
final Completer<void> callback = Completer<void>();
window.sendPlatformMessage(
myWindow.sendPlatformMessage(
'flutter/navigation',
const JSONMethodCodec().encodeMethodCall(const MethodCall(
'routeInformationUpdated',
@ -420,11 +428,11 @@ void testMain() {
(_) { callback.complete(); },
);
await callback.future;
expect(window.browserHistory, isA<MultiEntriesBrowserHistory>());
expect(myWindow.browserHistory, isA<MultiEntriesBrowserHistory>());
// The url strategy should've been set to the default, and the path
// should've been correctly set to "/baz".
expect(window.browserHistory.urlStrategy, isNot(isNull));
expect(window.browserHistory.urlStrategy!.getPath(), '/baz');
expect(myWindow.browserHistory.urlStrategy, isNot(isNull));
expect(myWindow.browserHistory.urlStrategy!.getPath(), '/baz');
}, skip: isSafari); // https://github.com/flutter/flutter/issues/50836
test('can disable location strategy', () async {
@ -436,23 +444,23 @@ void testMain() {
returnsNormally,
);
// History should be initialized.
expect(window.browserHistory, isNotNull);
expect(myWindow.browserHistory, isNotNull);
// But without a URL strategy.
expect(window.browserHistory.urlStrategy, isNull);
expect(myWindow.browserHistory.urlStrategy, isNull);
// Current path is always "/" in this case.
expect(window.browserHistory.currentPath, '/');
expect(myWindow.browserHistory.currentPath, '/');
// Perform some navigation operations.
await routeInformationUpdated('/foo/bar', null);
// Path should not be updated because URL strategy is disabled.
expect(window.browserHistory.currentPath, '/');
expect(myWindow.browserHistory.currentPath, '/');
});
test('cannot set url strategy after it was initialized', () async {
final TestUrlStrategy testStrategy = TestUrlStrategy.fromEntry(
const TestHistoryEntry('initial state', null, '/'),
);
await window.debugInitializeHistory(testStrategy, useSingle: true);
await myWindow.debugInitializeHistory(testStrategy, useSingle: true);
expect(
() {
@ -482,8 +490,8 @@ void testMain() {
// Regression test for https://github.com/flutter/flutter/issues/77817
test('window.locale(s) are not nullable', () {
// If the getters were nullable, these expressions would result in compiler errors.
ui.window.locale.countryCode;
ui.window.locales.first.countryCode;
ui.PlatformDispatcher.instance.locale.countryCode;
ui.PlatformDispatcher.instance.locales.first.countryCode;
});
}

View File

@ -39,6 +39,11 @@ class StubPictureRenderer implements PictureRenderer {
void testMain() {
late EngineSceneView sceneView;
late StubPictureRenderer stubPictureRenderer;
setUpAll(() {
ensureImplicitViewInitialized();
});
setUp(() {
stubPictureRenderer = StubPictureRenderer();
sceneView = EngineSceneView(stubPictureRenderer);

View File

@ -2513,16 +2513,15 @@ void _testPlatformView() {
width: 20,
height: 30,
);
ui.window.render(sceneBuilder.build());
ui.PlatformDispatcher.instance.render(sceneBuilder.build());
final ui.SemanticsUpdateBuilder builder = ui.SemanticsUpdateBuilder();
final double dpr = EngineFlutterDisplay.instance.devicePixelRatio;
updateNode(builder,
rect: const ui.Rect.fromLTRB(0, 0, 20, 60),
childrenInTraversalOrder: Int32List.fromList(<int>[1, 2, 3]),
childrenInHitTestOrder: Int32List.fromList(<int>[1, 2, 3]),
transform: Float64List.fromList(Matrix4.diagonal3Values(
ui.window.devicePixelRatio, ui.window.devicePixelRatio, 1)
.storage));
transform: Float64List.fromList(Matrix4.diagonal3Values(dpr, dpr, 1).storage));
updateNode(
builder,
id: 1,
@ -3137,7 +3136,7 @@ const MethodCodec codec = StandardMethodCodec();
/// Sends a platform message to create a Platform View with the given id and viewType.
Future<void> createPlatformView(int id, String viewType) {
final Completer<void> completer = Completer<void>();
ui.window.sendPlatformMessage(
ui.PlatformDispatcher.instance.sendPlatformMessage(
'flutter/platform_views',
codec.encodeMethodCall(MethodCall(
'create',
@ -3154,7 +3153,7 @@ Future<void> createPlatformView(int id, String viewType) {
/// Disposes of the platform view with the given [id].
Future<void> disposePlatformView(int id) {
final Completer<void> completer = Completer<void>();
window.sendPlatformMessage(
ui.PlatformDispatcher.instance.sendPlatformMessage(
'flutter/platform_views',
codec.encodeMethodCall(MethodCall('dispose', id)),
(dynamic _) => completer.complete(),

View File

@ -371,7 +371,7 @@ DomElement? findScrollable() {
);
}
/// Logs semantics actions dispatched to [ui.window].
/// Logs semantics actions dispatched to [ui.PlatformDispatcher].
class SemanticsActionLogger {
SemanticsActionLogger() {
_idLogController = StreamController<int>();
@ -401,7 +401,7 @@ class SemanticsActionLogger {
Stream<int> get idLog => _idLog;
late Stream<int> _idLog;
/// The actions that were dispatched to [ui.window].
/// The actions that were dispatched to [ui.PlatformDispatcher].
Stream<ui.SemanticsAction> get actionLog => _actionLog;
late Stream<ui.SemanticsAction> _actionLog;
}

View File

@ -104,7 +104,7 @@ Future<void> testMain() async {
// Sends a platform message to create a Platform View with the given id and viewType.
Future<void> _createPlatformView(int id, String viewType) {
final Completer<void> completer = Completer<void>();
window.sendPlatformMessage(
ui.PlatformDispatcher.instance.sendPlatformMessage(
'flutter/platform_views',
codec.encodeMethodCall(MethodCall(
'create',

View File

@ -477,7 +477,7 @@ void testMain() {
// Pump an empty scene to reset it, otherwise the first frame will attempt
// to diff left-overs from a previous test, which results in unpredictable
// DOM mutations.
window.render(SurfaceSceneBuilder().build());
ui.PlatformDispatcher.instance.render(SurfaceSceneBuilder().build());
// Renders a `string` by breaking it up into individual characters and
// rendering each character into its own layer.

View File

@ -373,10 +373,10 @@ Future<void> testMain() async {
});
test('handling keyboard event prevents triggering input action', () {
final ui.PlatformMessageCallback? savedCallback = ui.window.onPlatformMessage;
final ui.PlatformMessageCallback? savedCallback = ui.PlatformDispatcher.instance.onPlatformMessage;
bool markTextEventHandled = false;
ui.window.onPlatformMessage = (String channel, ByteData? data,
ui.PlatformDispatcher.instance.onPlatformMessage = (String channel, ByteData? data,
ui.PlatformMessageResponseCallback? callback) {
final ByteData response = const JSONMessageCodec()
.encodeMessage(<String, dynamic>{'handled': markTextEventHandled})!;
@ -414,7 +414,7 @@ Future<void> testMain() async {
// Input action received.
expect(lastInputAction, 'TextInputAction.done');
ui.window.onPlatformMessage = savedCallback;
ui.PlatformDispatcher.instance.onPlatformMessage = savedCallback;
RawKeyboard.instance?.dispose();
});

View File

@ -9,9 +9,7 @@ import 'dart:async';
import 'package:test/bootstrap/browser.dart';
import 'package:test/test.dart';
import 'package:ui/src/engine/dom.dart';
import 'package:ui/src/engine/view_embedder/dimensions_provider/custom_element_dimensions_provider.dart';
import 'package:ui/src/engine/window.dart';
import 'package:ui/src/engine.dart';
import 'package:ui/ui.dart' as ui show Size;
void main() {
@ -42,7 +40,7 @@ void doTests() {
const double dpr = 2.5;
const double logicalWidth = 50;
const double logicalHeight = 75;
window.debugOverrideDevicePixelRatio(dpr);
EngineFlutterDisplay.instance.debugOverrideDevicePixelRatio(dpr);
sizeSource
..style.width = '${logicalWidth}px'
@ -75,7 +73,7 @@ void doTests() {
test('from viewport physical size (simulated keyboard) - always zero', () {
// Simulate a 100px tall keyboard showing...
const double dpr = 2.5;
window.debugOverrideDevicePixelRatio(dpr);
EngineFlutterDisplay.instance.debugOverrideDevicePixelRatio(dpr);
const double keyboardGap = 100;
final double physicalHeight =
(domWindow.visualViewport!.height! + keyboardGap) * dpr;

View File

@ -7,11 +7,7 @@ library;
import 'package:test/bootstrap/browser.dart';
import 'package:test/test.dart';
import 'package:ui/src/engine/dom.dart';
import 'package:ui/src/engine/view_embedder/dimensions_provider/custom_element_dimensions_provider.dart';
import 'package:ui/src/engine/view_embedder/dimensions_provider/dimensions_provider.dart';
import 'package:ui/src/engine/view_embedder/dimensions_provider/full_page_dimensions_provider.dart';
import 'package:ui/src/engine/window.dart';
import 'package:ui/src/engine.dart';
void main() {
internalBootstrapBrowserTest(() => doTests);
@ -39,7 +35,7 @@ void doTests() {
group('getDevicePixelRatio', () {
test('Returns the correct pixelRatio', () async {
// Override the DPI to something known, but weird...
window.debugOverrideDevicePixelRatio(33930);
EngineFlutterDisplay.instance.debugOverrideDevicePixelRatio(33930);
final DimensionsProvider provider = DimensionsProvider.create();

View File

@ -9,9 +9,7 @@ import 'dart:async';
import 'package:test/bootstrap/browser.dart';
import 'package:test/test.dart';
import 'package:ui/src/engine/dom.dart';
import 'package:ui/src/engine/view_embedder/dimensions_provider/full_page_dimensions_provider.dart';
import 'package:ui/src/engine/window.dart';
import 'package:ui/src/engine.dart';
import 'package:ui/ui.dart' as ui show Size;
void main() {
@ -28,7 +26,7 @@ void doTests() {
test('returns visualViewport physical size (width * dpr)', () {
const double dpr = 2.5;
window.debugOverrideDevicePixelRatio(dpr);
EngineFlutterDisplay.instance.debugOverrideDevicePixelRatio(dpr);
final ui.Size expected = ui.Size(domWindow.visualViewport!.width! * dpr,
domWindow.visualViewport!.height! * dpr);
@ -48,7 +46,7 @@ void doTests() {
test('from viewport physical size (simulated keyboard)', () {
// Simulate a 100px tall keyboard showing...
const double dpr = 2.5;
window.debugOverrideDevicePixelRatio(dpr);
EngineFlutterDisplay.instance.debugOverrideDevicePixelRatio(dpr);
const double keyboardGap = 100;
final double physicalHeight =
(domWindow.visualViewport!.height! + keyboardGap) * dpr;

View File

@ -13,6 +13,7 @@ void main() {
void doTests() {
group('DomManager', () {
test('fromFlutterViewEmbedderDEPRECATED', () {
ensureImplicitViewInitialized();
final FlutterViewEmbedder embedder = FlutterViewEmbedder();
final DomManager domManager =
DomManager.fromFlutterViewEmbedderDEPRECATED(embedder);

View File

@ -23,6 +23,17 @@ void main() {
Future<void> testMain() async {
await ui_web.bootstrapEngine();
late EngineFlutterWindow myWindow;
setUp(() {
myWindow = EngineFlutterWindow(99, EnginePlatformDispatcher.instance);
});
tearDown(() async {
await myWindow.resetHistory();
EnginePlatformDispatcher.instance.unregisterView(myWindow);
});
test('onTextScaleFactorChanged preserves the zone', () {
final Zone innerZone = Zone.current.fork();
@ -30,10 +41,10 @@ Future<void> testMain() async {
void callback() {
expect(Zone.current, innerZone);
}
window.onTextScaleFactorChanged = callback;
myWindow.onTextScaleFactorChanged = callback;
// Test that the getter returns the exact same callback, e.g. it doesn't wrap it.
expect(window.onTextScaleFactorChanged, same(callback));
expect(myWindow.onTextScaleFactorChanged, same(callback));
});
EnginePlatformDispatcher.instance.invokeOnTextScaleFactorChanged();
@ -46,10 +57,10 @@ Future<void> testMain() async {
void callback() {
expect(Zone.current, innerZone);
}
window.onPlatformBrightnessChanged = callback;
myWindow.onPlatformBrightnessChanged = callback;
// Test that the getter returns the exact same callback, e.g. it doesn't wrap it.
expect(window.onPlatformBrightnessChanged, same(callback));
expect(myWindow.onPlatformBrightnessChanged, same(callback));
});
EnginePlatformDispatcher.instance.invokeOnPlatformBrightnessChanged();
@ -62,10 +73,10 @@ Future<void> testMain() async {
void callback() {
expect(Zone.current, innerZone);
}
window.onMetricsChanged = callback;
myWindow.onMetricsChanged = callback;
// Test that the getter returns the exact same callback, e.g. it doesn't wrap it.
expect(window.onMetricsChanged, same(callback));
expect(myWindow.onMetricsChanged, same(callback));
});
EnginePlatformDispatcher.instance.invokeOnMetricsChanged();
@ -78,10 +89,10 @@ Future<void> testMain() async {
void callback() {
expect(Zone.current, innerZone);
}
window.onLocaleChanged = callback;
myWindow.onLocaleChanged = callback;
// Test that the getter returns the exact same callback, e.g. it doesn't wrap it.
expect(window.onLocaleChanged, same(callback));
expect(myWindow.onLocaleChanged, same(callback));
});
EnginePlatformDispatcher.instance.invokeOnLocaleChanged();
@ -94,10 +105,10 @@ Future<void> testMain() async {
void callback(Duration _) {
expect(Zone.current, innerZone);
}
window.onBeginFrame = callback;
myWindow.onBeginFrame = callback;
// Test that the getter returns the exact same callback, e.g. it doesn't wrap it.
expect(window.onBeginFrame, same(callback));
expect(myWindow.onBeginFrame, same(callback));
});
EnginePlatformDispatcher.instance.invokeOnBeginFrame(Duration.zero);
@ -110,10 +121,10 @@ Future<void> testMain() async {
void callback(List<dynamic> _) {
expect(Zone.current, innerZone);
}
window.onReportTimings = callback;
myWindow.onReportTimings = callback;
// Test that the getter returns the exact same callback, e.g. it doesn't wrap it.
expect(window.onReportTimings, same(callback));
expect(myWindow.onReportTimings, same(callback));
});
EnginePlatformDispatcher.instance.invokeOnReportTimings(<ui.FrameTiming>[]);
@ -126,10 +137,10 @@ Future<void> testMain() async {
void callback() {
expect(Zone.current, innerZone);
}
window.onDrawFrame = callback;
myWindow.onDrawFrame = callback;
// Test that the getter returns the exact same callback, e.g. it doesn't wrap it.
expect(window.onDrawFrame, same(callback));
expect(myWindow.onDrawFrame, same(callback));
});
EnginePlatformDispatcher.instance.invokeOnDrawFrame();
@ -142,10 +153,10 @@ Future<void> testMain() async {
void callback(ui.PointerDataPacket _) {
expect(Zone.current, innerZone);
}
window.onPointerDataPacket = callback;
myWindow.onPointerDataPacket = callback;
// Test that the getter returns the exact same callback, e.g. it doesn't wrap it.
expect(window.onPointerDataPacket, same(callback));
expect(myWindow.onPointerDataPacket, same(callback));
});
EnginePlatformDispatcher.instance.invokeOnPointerDataPacket(const ui.PointerDataPacket());
@ -175,11 +186,11 @@ Future<void> testMain() async {
expect(Zone.current, innerZone);
return false;
}
window.onKeyData = onKeyData;
myWindow.onKeyData = onKeyData;
// Test that the getter returns the exact same onKeyData, e.g. it doesn't
// wrap it.
expect(window.onKeyData, same(onKeyData));
expect(myWindow.onKeyData, same(onKeyData));
});
const ui.KeyData keyData = ui.KeyData(
@ -194,7 +205,7 @@ Future<void> testMain() async {
expect(result, isFalse);
});
window.onKeyData = null;
myWindow.onKeyData = null;
});
test('onSemanticsEnabledChanged preserves the zone', () {
@ -204,10 +215,10 @@ Future<void> testMain() async {
void callback() {
expect(Zone.current, innerZone);
}
window.onSemanticsEnabledChanged = callback;
myWindow.onSemanticsEnabledChanged = callback;
// Test that the getter returns the exact same callback, e.g. it doesn't wrap it.
expect(window.onSemanticsEnabledChanged, same(callback));
expect(myWindow.onSemanticsEnabledChanged, same(callback));
});
EnginePlatformDispatcher.instance.invokeOnSemanticsEnabledChanged();
@ -236,10 +247,10 @@ Future<void> testMain() async {
void callback() {
expect(Zone.current, innerZone);
}
window.onAccessibilityFeaturesChanged = callback;
myWindow.onAccessibilityFeaturesChanged = callback;
// Test that the getter returns the exact same callback, e.g. it doesn't wrap it.
expect(window.onAccessibilityFeaturesChanged, same(callback));
expect(myWindow.onAccessibilityFeaturesChanged, same(callback));
});
EnginePlatformDispatcher.instance.invokeOnAccessibilityFeaturesChanged();
@ -252,10 +263,10 @@ Future<void> testMain() async {
void callback(String _, ByteData? __, void Function(ByteData?)? ___) {
expect(Zone.current, innerZone);
}
window.onPlatformMessage = callback;
myWindow.onPlatformMessage = callback;
// Test that the getter returns the exact same callback, e.g. it doesn't wrap it.
expect(window.onPlatformMessage, same(callback));
expect(myWindow.onPlatformMessage, same(callback));
});
EnginePlatformDispatcher.instance.invokeOnPlatformMessage('foo', null, (ByteData? data) {
@ -270,7 +281,7 @@ Future<void> testMain() async {
innerZone.runGuarded(() {
final ByteData inputData = ByteData(4);
inputData.setUint32(0, 42);
window.sendPlatformMessage(
myWindow.sendPlatformMessage(
'flutter/debug-echo',
inputData,
(ByteData? outputData) {
@ -288,7 +299,7 @@ Future<void> testMain() async {
final ByteData inputData = ByteData(4);
inputData.setUint32(0, 42);
window.sendPlatformMessage(
myWindow.sendPlatformMessage(
'flutter/__unknown__channel__',
null,
(ByteData? outputData) {
@ -309,7 +320,7 @@ Future<void> testMain() async {
orientations,
));
window.sendPlatformMessage(
myWindow.sendPlatformMessage(
'flutter/platform',
inputData,
(ByteData? outputData) {
@ -411,7 +422,7 @@ Future<void> testMain() async {
test('SingletonFlutterWindow implements locale, locales, and locale change notifications', () async {
// This will count how many times we notified about locale changes.
int localeChangedCount = 0;
window.onLocaleChanged = () {
myWindow.onLocaleChanged = () {
localeChangedCount += 1;
};
@ -420,18 +431,18 @@ Future<void> testMain() async {
// We populate the initial list of locales automatically (only test that we
// got some locales; some contributors may be in different locales, so we
// can't test the exact contents).
expect(window.locale, isA<ui.Locale>());
expect(window.locales, isNotEmpty);
expect(myWindow.locale, isA<ui.Locale>());
expect(myWindow.locales, isNotEmpty);
// Trigger a change notification (reset locales because the notification
// doesn't actually change the list of languages; the test only observes
// that the list is populated again).
EnginePlatformDispatcher.instance.debugResetLocales();
expect(window.locales, isEmpty);
expect(window.locale, equals(const ui.Locale.fromSubtags()));
expect(myWindow.locales, isEmpty);
expect(myWindow.locale, equals(const ui.Locale.fromSubtags()));
expect(localeChangedCount, 0);
domWindow.dispatchEvent(createDomEvent('Event', 'languagechange'));
expect(window.locales, isNotEmpty);
expect(myWindow.locales, isNotEmpty);
expect(localeChangedCount, 1);
});
@ -442,7 +453,7 @@ Future<void> testMain() async {
final Zone innerZone = Zone.current.fork();
innerZone.runGuarded(() {
window.sendPlatformMessage(
myWindow.sendPlatformMessage(
'flutter/service_worker',
ByteData(0),
(ByteData? outputData) { },

View File

@ -157,7 +157,7 @@ Future<void> testMain() async {
for (final int testDpr in <int>[1, 2, 4]) {
test('MaskFilter.blur blurs correctly for device-pixel ratio $testDpr', () async {
window.debugOverrideDevicePixelRatio(testDpr.toDouble());
EngineFlutterDisplay.instance.debugOverrideDevicePixelRatio(testDpr.toDouble());
const ui.Rect screenRect = ui.Rect.fromLTWH(0, 0, 150, 150);
final RecordingCanvas rc = RecordingCanvas(screenRect);
@ -174,7 +174,7 @@ Future<void> testMain() async {
await canvasScreenshot(rc, 'mask_filter_blur_dpr_$testDpr',
region: screenRect);
window.debugOverrideDevicePixelRatio(1.0);
EngineFlutterDisplay.instance.debugOverrideDevicePixelRatio(1.0);
});
}
}

View File

@ -408,7 +408,7 @@ void testMain() {
// Regression test for https://github.com/flutter/flutter/issues/44470
test('Should handle contains for devicepixelratio != 1.0', () {
js_util.setProperty(domWindow, 'devicePixelRatio', 4.0);
window.debugOverrideDevicePixelRatio(4.0);
EngineFlutterDisplay.instance.debugOverrideDevicePixelRatio(4.0);
final Path path = Path()
..moveTo(50, 0)
..lineTo(100, 100)
@ -417,7 +417,7 @@ void testMain() {
..close();
expect(path.contains(const Offset(50, 50)), isTrue);
js_util.setProperty(domWindow, 'devicePixelRatio', 1.0);
window.debugOverrideDevicePixelRatio(1.0);
EngineFlutterDisplay.instance.debugOverrideDevicePixelRatio(1.0);
// TODO(ferhat): Investigate failure on CI. Locally this passes.
// [Exception... "Failure" nsresult: "0x80004005 (NS_ERROR_FAILURE)"
}, skip: browserEngine == BrowserEngine.firefox);

View File

@ -806,7 +806,7 @@ Future<void> testMain() async {
builder.addPicture(ui.Offset.zero, picture);
final ui.Scene scene = builder.build();
ui.window.render(scene);
ui.PlatformDispatcher.instance.render(scene);
picture.dispose();
scene.dispose();

View File

@ -70,10 +70,10 @@ Future<void> testMain() async {
skip: browserEngine == BrowserEngine.webkit);
test('loading font should send font change message', () async {
final ui.PlatformMessageCallback? oldHandler = ui.window.onPlatformMessage;
final ui.PlatformMessageCallback? oldHandler = ui.PlatformDispatcher.instance.onPlatformMessage;
String? actualName;
String? message;
window.onPlatformMessage = (String name, ByteData? data,
ui.PlatformDispatcher.instance.onPlatformMessage = (String name, ByteData? data,
ui.PlatformMessageResponseCallback? callback) {
actualName = name;
final ByteBuffer buffer = data!.buffer;
@ -86,7 +86,7 @@ Future<void> testMain() async {
final Completer<void> completer = Completer<void>();
domWindow.requestAnimationFrame((_) { completer.complete();});
await completer.future;
window.onPlatformMessage = oldHandler;
ui.PlatformDispatcher.instance.onPlatformMessage = oldHandler;
expect(actualName, 'flutter/system');
expect(message, '{"type":"fontsChange"}');
},

View File

@ -410,7 +410,9 @@ Future<void> testMain() async {
group('test fonts in flutterTester environment', () {
final bool resetValue = ui_web.debugEmulateFlutterTesterEnvironment;
ui_web.debugEmulateFlutterTesterEnvironment = true;
tearDownAll(() => ui_web.debugEmulateFlutterTesterEnvironment = resetValue);
tearDownAll(() {
ui_web.debugEmulateFlutterTesterEnvironment = resetValue;
});
const List<String> testFonts = <String>['FlutterTest', 'Ahem'];
test('The default test font is used when a non-test fontFamily is specified, or fontFamily is not specified', () {

View File

@ -31,7 +31,7 @@ void testMain() {
debugDisableFontFallbacks = false;
});
/// Used to save and restore [ui.window.onPlatformMessage] after each test.
/// Used to save and restore [ui.PlatformDispatcher.onPlatformMessage] after each test.
ui.PlatformMessageCallback? savedCallback;
final List<String> downloadedFontFamilies = <String>[];
@ -41,12 +41,12 @@ void testMain() {
renderer.fontCollection.fontFallbackManager!.downloadQueue.fallbackFontUrlPrefixOverride = 'assets/fallback_fonts/';
renderer.fontCollection.fontFallbackManager!.downloadQueue.debugOnLoadFontFamily
= (String family) => downloadedFontFamilies.add(family);
savedCallback = ui.window.onPlatformMessage;
savedCallback = ui.PlatformDispatcher.instance.onPlatformMessage;
});
tearDown(() {
downloadedFontFamilies.clear();
ui.window.onPlatformMessage = savedCallback;
ui.PlatformDispatcher.instance.onPlatformMessage = savedCallback;
});
test('Roboto is always a fallback font', () {

View File

@ -164,7 +164,7 @@ Future<void> testMain() async {
Future<void> _createPlatformView(int id, String viewType) {
final Completer<void> completer = Completer<void>();
const MethodCodec codec = StandardMethodCodec();
window.sendPlatformMessage(
ui.PlatformDispatcher.instance.sendPlatformMessage(
'flutter/platform_views',
codec.encodeMethodCall(MethodCall(
'create',