Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
588af77
[web] Use CanvasKit to run tests under engine/
mdebbar Aug 26, 2024
b01778d
update ci builders
mdebbar Aug 27, 2024
a7e2814
also move image file used by test
mdebbar Aug 27, 2024
5caa636
Merge branch 'main' into engine_tests_use_canvaskit
mdebbar Aug 28, 2024
f33f1cb
deleted an unnecessary file
mdebbar Aug 29, 2024
f794a3a
Merge branch 'main' into engine_tests_use_canvaskit
mdebbar Sep 4, 2024
00a4103
skip one test in Firefox
mdebbar Sep 4, 2024
f00a7c8
Merge branch 'main' into engine_tests_use_canvaskit
mdebbar Sep 11, 2024
9022513
Merge branch 'main' into engine_tests_use_canvaskit
mdebbar Sep 17, 2024
5a80d5b
fix composition test for firefox
mdebbar Sep 18, 2024
7a7ce9d
Merge branch 'main' into engine_tests_use_canvaskit
mdebbar Oct 1, 2024
2f311fd
Merge branch 'main' into engine_tests_use_canvaskit
mdebbar Oct 15, 2024
9fd423c
Merge branch 'main' into engine_tests_use_canvaskit
mdebbar Oct 16, 2024
8ec88b6
Merge branch 'main' into engine_tests_use_canvaskit
mdebbar Oct 21, 2024
4116bc9
Merge branch 'main' into engine_tests_use_canvaskit
mdebbar Oct 22, 2024
1cde453
Merge branch 'main' into engine_tests_use_canvaskit
mdebbar Oct 30, 2024
be466bc
Merge branch 'main' into engine_tests_use_canvaskit
mdebbar Nov 4, 2024
21fff18
Merge branch 'main' into engine_tests_use_canvaskit
mdebbar Nov 5, 2024
655d7e0
Merge branch 'main' into engine_tests_use_canvaskit
mdebbar Nov 5, 2024
e6bbc9a
fix import
mdebbar Nov 7, 2024
14f9b9c
Merge branch 'main' into engine_tests_use_canvaskit
mdebbar Nov 7, 2024
636f47a
Merge branch 'main' into engine_tests_use_canvaskit
mdebbar Nov 8, 2024
1228a2d
Merge branch 'main' into engine_tests_use_canvaskit
mdebbar Nov 8, 2024
d240a2d
Merge branch 'main' into engine_tests_use_canvaskit
mdebbar Nov 11, 2024
3e95026
Merge branch 'main' into engine_tests_use_canvaskit
mdebbar Nov 15, 2024
ddf09bd
Merge branch 'main' into engine_tests_use_canvaskit
mdebbar Nov 26, 2024
b009d3f
Merge branch 'main' into engine_tests_use_canvaskit
mdebbar Dec 2, 2024
30200c9
Merge branch 'main' into engine_tests_use_canvaskit
mdebbar Dec 5, 2024
95af21f
Merge branch 'main' into engine_tests_use_canvaskit
mdebbar Dec 9, 2024
ff627f4
debug prints
mdebbar Nov 11, 2024
ee3d081
firefox solo in CI
mdebbar Nov 11, 2024
f8dfd50
more prints
mdebbar Nov 11, 2024
3c67655
more prints
mdebbar Nov 12, 2024
3884952
even more prints
mdebbar Nov 12, 2024
0110294
more debugging
mdebbar Nov 12, 2024
94ce701
fix js types
mdebbar Nov 12, 2024
95f80e9
fix more
mdebbar Nov 12, 2024
bf7da63
more debugging
mdebbar Nov 13, 2024
ddaca7c
moooore
mdebbar Dec 10, 2024
93901e8
Actual fixes!
mdebbar Dec 10, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
536 changes: 0 additions & 536 deletions .ci.yaml

Large diffs are not rendered by default.

426 changes: 19 additions & 407 deletions ci/builders/linux_web_engine.json

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions lib/web_ui/dev/test_platform.dart
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ class BrowserPlatform extends PlatformPlugin {
.add(_createSourceHandler())

// Serves files from the root of web_ui. Some tests download assets that are embedded
// directly in the test folder, such as test/engine/image/sample_image1.png etc
// directly in the test folder, such as test/html/image/sample_image1.png etc
.add(createStaticHandler(env.environment.webUiRootDir.path))

// Serves absolute package URLs (i.e. not /packages/* but /Users/user/*/hosted/pub.dartlang.org/*).
Expand Down Expand Up @@ -1121,10 +1121,10 @@ class BrowserManager {
/// Closes the manager and releases any resources it owns, including closing
/// the browser.
Future<void> close() => _closeMemoizer.runOnce(() {
if (Configuration.current.pauseAfterLoad) {
// if (Configuration.current.pauseAfterLoad) {
print('Test run finished. Press enter to close browser...');
stdin.readLineSync();
}
// }
_closed = true;
_timer.cancel();
_pauseCompleter?.complete();
Expand Down
32 changes: 26 additions & 6 deletions lib/web_ui/flutter_js/src/canvaskit_loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,15 @@ import { createWasmInstantiator } from "./instantiate_wasm.js";
import { resolveUrlWithSegments } from "./utils.js";

export const loadCanvasKit = (deps, config, browserEnvironment, canvasKitBaseUrl) => {
window.flutterCanvasKitLoaded = (async () => {
window.printCanvasKitLoaded = () => {
console.log('## printCanvasKitLoaded:');
console.log(' window.flutterCanvasKit:', window.flutterCanvasKit);
console.log(' window.flutterCanvasKitLoaded:', window.flutterCanvasKitLoaded);
};
console.log('## loadCanvasKit:', deps, config, browserEnvironment, canvasKitBaseUrl);
window.flutterCanvasKitLoaded = new Promise((res, rej) => {
if (window.flutterCanvasKit) {
console.log('## window.flutterCanvasKit:', window.flutterCanvasKit);
// The user has set this global variable ahead of time, so we just return that.
return window.flutterCanvasKit;
}
Expand All @@ -21,15 +28,28 @@ export const loadCanvasKit = (deps, config, browserEnvironment, canvasKitBaseUrl
baseUrl = resolveUrlWithSegments(baseUrl, "chromium");
}
let canvasKitUrl = resolveUrlWithSegments(baseUrl, "canvaskit.js");
console.log('## canvasKitUrl:', canvasKitUrl);
if (deps.flutterTT.policy) {
canvasKitUrl = deps.flutterTT.policy.createScriptURL(canvasKitUrl);
console.log('## flutterTT policy:', canvasKitUrl);
}
const wasmInstantiator = createWasmInstantiator(resolveUrlWithSegments(baseUrl, "canvaskit.wasm"));
const canvasKitModule = await import(canvasKitUrl);
window.flutterCanvasKit = await canvasKitModule.default({
instantiateWasm: wasmInstantiator,
console.log('## wasmInstantiator:', wasmInstantiator);
import(canvasKitUrl).then((canvasKitModule) => {
console.log('## canvasKitModule:', canvasKitModule);
let temp = canvasKitModule.default({
instantiateWasm: wasmInstantiator,
});
console.log('## canvasKitModule.default:', temp);
temp.then(() => {
console.log('## !!!');
});
return temp;
}).then((canvasKit) => {
window.flutterCanvasKit = canvasKit;
console.log('## flutterCanvasKit(resolving):', window.flutterCanvasKit);
res(window.flutterCanvasKit);
});
return window.flutterCanvasKit;
})();
});
return window.flutterCanvasKitLoaded;
}
3 changes: 3 additions & 0 deletions lib/web_ui/flutter_js/src/entrypoint_loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ export class FlutterEntrypointLoader {
* configuration.
*/
async load(build, deps, config, nonce, onEntrypointLoaded) {
console.log('...load...');
console.log(build);
console.log(config);
onEntrypointLoaded ??= (engineInitializer) => {
engineInitializer.initializeEngine(config).then((appRunner) => appRunner.runApp())
};
Expand Down
6 changes: 6 additions & 0 deletions lib/web_ui/flutter_js/src/instantiate_wasm.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,17 @@
// This is a little helper function that helps us start the fetch and compilation
// of an emscripten wasm module in parallel with the fetch of its script.
export const createWasmInstantiator = (url) => {
console.log('## createWasmInstantiator:', url);
const modulePromise = WebAssembly.compileStreaming(fetch(url));
console.log('## modulePromise:', modulePromise);
return (imports, successCallback) => {
console.log('...wasmInstantiator...');
(async () => {
console.log('await modulePromise');
const module = await modulePromise;
console.log('## module:', module);
const instance = await WebAssembly.instantiate(module, imports);
console.log('## instance:', instance);
successCallback(instance, module);
})();
return {};
Expand Down
2 changes: 2 additions & 0 deletions lib/web_ui/flutter_js/src/loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,10 @@ export class FlutterLoader {
});
}

console.log('...load...');
const canvasKitBaseUrl = getCanvaskitBaseUrl(config, buildConfig);
if (build.renderer === "canvaskit") {
console.log('...loadCanvasKit...');
deps.canvasKit = loadCanvasKit(deps, config, browserEnvironment, canvasKitBaseUrl);
} else if (build.renderer === "skwasm") {
deps.skwasm = loadSkwasm(deps, config, browserEnvironment, canvasKitBaseUrl);
Expand Down
6 changes: 6 additions & 0 deletions lib/web_ui/lib/src/engine/canvaskit/fonts.dart
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,10 @@ class SkiaFontCollection implements FlutterFontCollection {
}
}

// print(' <=await renderer.initialize();');
// Make sure CanvasKit is actually loaded
await renderer.initialize();
// print(' </await renderer.initialize();');

final SkTypeface? typeface =
canvasKit.Typeface.MakeFreeTypeFaceFromData(list.buffer);
Expand Down Expand Up @@ -125,16 +127,20 @@ class SkiaFontCollection implements FlutterFontCollection {

final Map<String, FontLoadError> fontFailures = <String, FontLoadError>{};
final List<(String, UnregisteredFont)> downloadedFonts = <(String, UnregisteredFont)>[];
// print(' <=await Future.wait(pendingDownloads);');
for (final FontDownloadResult result in await Future.wait(pendingDownloads)) {
if (result.font != null) {
downloadedFonts.add((result.assetName, result.font!));
} else {
fontFailures[result.assetName] = result.error!;
}
}
// print(' </await Future.wait(pendingDownloads);');

// print(' <=await renderer.initialize();');
// Make sure CanvasKit is actually loaded
await renderer.initialize();
// print(' </await renderer.initialize();');

final List<String> loadedFonts = <String>[];
for (final (String assetName, UnregisteredFont unregisteredFont) in downloadedFonts) {
Expand Down
32 changes: 30 additions & 2 deletions lib/web_ui/lib/src/engine/canvaskit/renderer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,18 @@ import 'package:ui/src/engine.dart';
import 'package:ui/ui.dart' as ui;
import 'package:ui/ui_web/src/ui_web.dart' as ui_web;

extension on JSPromise {
external JSPromise then(JSFunction callback);
@JS('catch')
external JSPromise onError(JSFunction callback);
@JS('finally')
external void onFinally(JSFunction callback);
}


@JS('window.printCanvasKitLoaded')
external void printFlutterCanvasKitLoaded();

enum CanvasKitVariant {
/// The appropriate variant is chosen based on the browser.
///
Expand Down Expand Up @@ -73,16 +85,32 @@ class CanvasKitRenderer implements Renderer {

@override
Future<void> initialize() async {
// print(' == renderer.initialize();');
_initialized ??= () async {
if (windowFlutterCanvasKit != null) {
canvasKit = windowFlutterCanvasKit!;
} else if (windowFlutterCanvasKitLoaded != null) {
// CanvasKit is being preloaded by flutter.js. Wait for it to complete.
canvasKit =
await promiseToFuture<CanvasKit>(windowFlutterCanvasKitLoaded!);
// print(' <=await promiseToFuture(windowFlutterCanvasKitLoaded!);');
// print(' [windowFlutterCanvasKitLoaded=$windowFlutterCanvasKitLoaded]');
windowFlutterCanvasKitLoaded!
.then(
((JSAny? val) => print(' >>[val=$val]')).toJS,
)
.onError(
((JSAny? err) => print(' >>[err=$err]')).toJS,
)
.onFinally(
(( ) => print(' >>[finally=]')).toJS,
);
printFlutterCanvasKitLoaded();
canvasKit = await windowFlutterCanvasKitLoaded!.toDart as CanvasKit;
// print(' </await promiseToFuture(windowFlutterCanvasKitLoaded!);');
} else {
// print(' <=await downloadCanvasKit();');
canvasKit = await downloadCanvasKit();
windowFlutterCanvasKit = canvasKit;
// print(' </await downloadCanvasKit();');
}
// Views may have been registered before this renderer was initialized.
// Create rasterizers for them and then start listening for new view
Expand Down
2 changes: 1 addition & 1 deletion lib/web_ui/lib/src/engine/dom.dart
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ extension DomConsoleExtension on DomConsole {
void error(Object? arg) => _error(arg.toString().toJS);

@JS('debug')
external void _debug(JSString? arg);
external void _debug(JSAny? arg);
void debug(Object? arg) => _debug(arg.toString().toJS);
}

Expand Down
11 changes: 10 additions & 1 deletion lib/web_ui/lib/src/engine/initialization.dart
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,9 @@ Future<void> initializeEngineServices({
_setAssetManager(assetManager);

Future<void> initializeRendererCallback () async => renderer.initialize();
// print(' <=await Future.wait([initializeRendererCallback(), _downloadAssetFonts()]);');
await Future.wait<void>(<Future<void>>[initializeRendererCallback(), _downloadAssetFonts()]);
// print(' </await Future.wait([initializeRendererCallback(), _downloadAssetFonts()]);');
_initializationState = DebugEngineInitializationState.initializedServices;
}

Expand Down Expand Up @@ -262,14 +264,21 @@ Future<void> _downloadAssetFonts() async {
if (ui_web.debugEmulateFlutterTesterEnvironment) {
// Load the embedded test font before loading fonts from the assets so that
// the embedded test font is the default (first) font.
// print(' <=await renderer.fontCollection.loadFontFromList(EmbeddedTestFont.flutterTest.data ...);');
await renderer.fontCollection.loadFontFromList(
EmbeddedTestFont.flutterTest.data,
fontFamily: EmbeddedTestFont.flutterTest.fontFamily
);
// print(' </await renderer.fontCollection.loadFontFromList(EmbeddedTestFont.flutterTest.data ...);');
}

if (_debugAssetManager != null || _assetManager != null) {
await renderer.fontCollection.loadAssetFonts(await fetchFontManifest(ui_web.assetManager));
// print(' <=await fetchFontManifest(ui_web.assetManager);');
final manifest = await fetchFontManifest(ui_web.assetManager);
// print(' </await fetchFontManifest(ui_web.assetManager);');
// print(' <=await renderer.fontCollection.loadAssetFonts(manifest);');
await renderer.fontCollection.loadAssetFonts(manifest);
// print(' </await renderer.fontCollection.loadAssetFonts(manifest);');
}
}

Expand Down
5 changes: 5 additions & 0 deletions lib/web_ui/lib/ui_web/src/ui_web/initialization.dart
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,16 @@ Future<void> bootstrapEngine({
// Create the object that knows how to bootstrap an app from JS and Dart.
final AppBootstrap bootstrap = AppBootstrap(
initializeEngine: ([JsFlutterConfiguration? configuration]) async {
// print(' <=await initializeEngineServices(jsConfiguration: configuration);');
await initializeEngineServices(jsConfiguration: configuration);
// print(' </await initializeEngineServices(jsConfiguration: configuration);');
}, runApp: () async {
if (registerPlugins != null) {
registerPlugins();
}
// print(' <=await initializeEngineUi();');
await initializeEngineUi();
// print(' </await initializeEngineUi();');
if (runApp != null) {
runApp();
}
Expand All @@ -50,6 +54,7 @@ Future<void> bootstrapEngine({
await bootstrap.autoStart();
} else {
// Yield control of the bootstrap procedure to the user.
// print(' ==didCreateEngineInitializer(...);');
loader.didCreateEngineInitializer(bootstrap.prepareEngineInitializer());
}
}
29 changes: 0 additions & 29 deletions lib/web_ui/test/canvaskit/semantics_test.dart

This file was deleted.

29 changes: 29 additions & 0 deletions lib/web_ui/test/common/test_initialization.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,27 @@ import 'package:ui/ui_web/src/ui_web.dart' as ui_web;
import 'fake_asset_manager.dart';
import 'rendering.dart';

@JS('window.dartPrint')
external set dartPrint(JSFunction f);

void setUpUnitTests({
bool withImplicitView = false,
bool emulateTesterEnvironment = true,
bool setUpTestViewDimensions = true,
}) {
late final FakeAssetScope debugFontsScope;
setUpAll(() async {
// dartPrint = ((JSAny x) => print(x)).toJS;
print('<=setUpAll');
if (emulateTesterEnvironment) {
ui_web.debugEmulateFlutterTesterEnvironment = true;
}

debugFontsScope = configureDebugFontsAssetScope(fakeAssetManager);
debugOnlyAssetManager = fakeAssetManager;
// print(' <=await bootstrapAndRunApp(withImplicitView: $withImplicitView);');
await bootstrapAndRunApp(withImplicitView: withImplicitView);
// print(' </await bootstrapAndRunApp(withImplicitView: $withImplicitView);');
engine.debugOverrideJsConfiguration(<String, Object?>{
'fontFallbackBaseUrl': 'assets/fallback_fonts/',
}.jsify() as engine.JsFlutterConfiguration?);
Expand All @@ -44,17 +51,39 @@ void setUpUnitTests({
}

setUpRenderingForTests();
print('</setUpAll');
});

tearDownAll(() async {
fakeAssetManager.popAssetScope(debugFontsScope);
});
}

void setUpImplicitView() {
late engine.EngineFlutterWindow myWindow;

final engine.EnginePlatformDispatcher dispatcher = engine.EnginePlatformDispatcher.instance;

setUp(() {
myWindow = engine.EngineFlutterView.implicit(dispatcher, null);
dispatcher.viewManager.registerView(myWindow);
});

tearDown(() async {
dispatcher.viewManager.unregisterView(myWindow.viewId);
await myWindow.resetHistory();
myWindow.dispose();
});
}

Future<void> bootstrapAndRunApp({bool withImplicitView = false}) async {
final Completer<void> completer = Completer<void>();
// print(' <=await ui_web.bootstrapEngine();');
await ui_web.bootstrapEngine(runApp: () => completer.complete());
// print(' </await ui_web.bootstrapEngine();');
print(' <=await completer.future;');
await completer.future;
print(' </await completer.future;');
if (!withImplicitView) {
_disableImplicitView();
}
Expand Down
2 changes: 1 addition & 1 deletion lib/web_ui/test/engine/clipboard_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ void main() {
}

Future<void> testMain() async {
setUpUnitTests();
setUpImplicitView();
group('message handler', () {
const String testText = 'test text';

Expand Down
10 changes: 9 additions & 1 deletion lib/web_ui/test/engine/composition_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ GloballyPositionedTextEditingStrategy _enableEditingStrategy({
}

Future<void> testMain() async {
await bootstrapAndRunApp(withImplicitView: true);
setUpImplicitView();

const String fakeComposingText = 'ImComposingText';

Expand Down Expand Up @@ -323,6 +323,14 @@ Future<void> testMain() async {
_inputElement.dispatchEvent(createDomCompositionEvent(
_MockWithCompositionAwareMixin._kCompositionUpdate,
<Object?, Object?>{ 'data': newComposingText }));
// On Chrome and Safari, a `compositionupdate` event automatically
// triggers a `selectionchange` event, which leads to triggering
// `DefaultTextEditingStrategy.handleChange`.
//
// But in Firefox, `selectionchange` event is not triggered, so we need to
// manually dispatch an `input` event to trigger
// `DefaultTextEditingStrategy.handleChange`.
_inputElement.dispatchEvent(createDomInputEvent('input'));

await containExpect;
});
Expand Down
Loading
Loading