diff --git a/DEPS b/DEPS index a6379bf372c11..d35ec06173054 100644 --- a/DEPS +++ b/DEPS @@ -277,7 +277,7 @@ allowed_hosts = [ ] deps = { - 'src': 'https://github.com/flutter/buildroot.git' + '@' + '8c2d66fa4e6298894425f5bdd0591bc5b1154c53', + 'src': 'https://github.com/flutter/buildroot.git' + '@' + 'e265c359126b24351f534080fb22edaa159f2215', 'src/flutter/third_party/depot_tools': Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '580b4ff3f5cd0dcaa2eacda28cefe0f45320e8f7', diff --git a/lib/web_ui/flutter_js/src/canvaskit_loader.js b/lib/web_ui/flutter_js/src/canvaskit_loader.js index 64dc6734ec273..4c8e91c7bc175 100644 --- a/lib/web_ui/flutter_js/src/canvaskit_loader.js +++ b/lib/web_ui/flutter_js/src/canvaskit_loader.js @@ -6,11 +6,11 @@ import { createWasmInstantiator } from "./instantiate_wasm.js"; import { joinPathSegments } from "./utils.js"; export const loadCanvasKit = (deps, config, browserEnvironment, canvasKitBaseUrl) => { - if (window.flutterCanvasKit) { - // The user has set this global variable ahead of time, so we just return that. - return Promise.resolve(window.flutterCanvasKit); - } - window.flutterCanvasKitLoaded = new Promise((resolve, reject) => { + window.flutterCanvasKitLoaded = (async () => { + if (window.flutterCanvasKit) { + // The user has set this global variable ahead of time, so we just return that. + return window.flutterCanvasKit; + } const supportsChromiumCanvasKit = browserEnvironment.hasChromiumBreakIterators && browserEnvironment.hasImageCodecs; if (!supportsChromiumCanvasKit && config.canvasKitVariant == "chromium") { throw "Chromium CanvasKit variant specifically requested, but unsupported in this browser"; @@ -25,24 +25,11 @@ export const loadCanvasKit = (deps, config, browserEnvironment, canvasKitBaseUrl canvasKitUrl = deps.flutterTT.policy.createScriptURL(canvasKitUrl); } const wasmInstantiator = createWasmInstantiator(joinPathSegments(baseUrl, "canvaskit.wasm")); - const script = document.createElement("script"); - script.src = canvasKitUrl; - if (config.nonce) { - script.nonce = config.nonce; - } - script.addEventListener("load", async () => { - try { - const canvasKit = await CanvasKitInit({ - instantiateWasm: wasmInstantiator, - }); - window.flutterCanvasKit = canvasKit; - resolve(canvasKit); - } catch (e) { - reject(e); - } + const canvasKitModule = await import(canvasKitUrl); + window.flutterCanvasKit = await canvasKitModule.default({ + instantiateWasm: wasmInstantiator, }); - script.addEventListener("error", reject); - document.head.appendChild(script); - }); + return window.flutterCanvasKit; + })(); return window.flutterCanvasKitLoaded; } diff --git a/lib/web_ui/flutter_js/src/skwasm_loader.js b/lib/web_ui/flutter_js/src/skwasm_loader.js index 241f4e8c81e02..01b4fe3cb2375 100644 --- a/lib/web_ui/flutter_js/src/skwasm_loader.js +++ b/lib/web_ui/flutter_js/src/skwasm_loader.js @@ -5,43 +5,28 @@ import { createWasmInstantiator } from "./instantiate_wasm.js"; import { joinPathSegments } from "./utils.js"; -export const loadSkwasm = (deps, config, browserEnvironment, baseUrl) => { - return new Promise((resolve, reject) => { - let skwasmUrl = joinPathSegments(baseUrl, "skwasm.js"); - if (deps.flutterTT.policy) { - skwasmUrl = deps.flutterTT.policy.createScriptURL(skwasmUrl); - } - const wasmInstantiator = createWasmInstantiator(joinPathSegments(baseUrl, "skwasm.wasm")); - const script = document.createElement("script"); - script.src = skwasmUrl; - if (config.nonce) { - script.nonce = config.nonce; - } - script.addEventListener("load", async () => { - try { - const skwasmInstance = await skwasm({ - instantiateWasm: wasmInstantiator, - locateFile: (fileName, scriptDirectory) => { - // When hosted via a CDN or some other url that is not the same - // origin as the main script of the page, we will fail to create - // a web worker with the .worker.js script. This workaround will - // make sure that the worker JS can be loaded regardless of where - // it is hosted. - const url = scriptDirectory + fileName; - if (url.endsWith(".worker.js")) { - return URL.createObjectURL(new Blob( - [`importScripts("${url}");`], - { "type": "application/javascript" })); - } - return url; - } - }); - resolve(skwasmInstance); - } catch (e) { - reject(e); +export const loadSkwasm = async (deps, config, browserEnvironment, baseUrl) => { + let skwasmUrl = joinPathSegments(baseUrl, "skwasm.js"); + if (deps.flutterTT.policy) { + skwasmUrl = deps.flutterTT.policy.createScriptURL(skwasmUrl); + } + const wasmInstantiator = createWasmInstantiator(joinPathSegments(baseUrl, "skwasm.wasm")); + const skwasm = await import(skwasmUrl); + return await skwasm.default({ + instantiateWasm: wasmInstantiator, + locateFile: (fileName, scriptDirectory) => { + // When hosted via a CDN or some other url that is not the same + // origin as the main script of the page, we will fail to create + // a web worker with the .worker.js script. This workaround will + // make sure that the worker JS can be loaded regardless of where + // it is hosted. + const url = scriptDirectory + fileName; + if (url.endsWith('.worker.js')) { + return URL.createObjectURL(new Blob( + [`importScripts('${url}');`], + { 'type': 'application/javascript' })); } - }); - script.addEventListener("error", reject); - document.head.appendChild(script); + return url; + } }); } diff --git a/lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart b/lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart index c41da41b36aac..2e6e8dfc62a6e 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart @@ -259,12 +259,13 @@ extension CanvasKitExtension on CanvasKit { ); } -@JS('window.CanvasKitInit') -external JSAny _CanvasKitInit(CanvasKitInitOptions options); +@JS() +@staticInterop +class CanvasKitModule {} -Future CanvasKitInit(CanvasKitInitOptions options) { - return js_util.promiseToFuture( - _CanvasKitInit(options).toObjectShallow); +extension CanvasKitModuleExtension on CanvasKitModule { + @JS('default') + external JSPromise defaultExport(CanvasKitInitOptions options); } typedef LocateFileCallback = String Function(String file, String unusedBase); @@ -3661,11 +3662,11 @@ String canvasKitWasmModuleUrl(String file, String canvasKitBase) => /// Downloads the CanvasKit JavaScript, then calls `CanvasKitInit` to download /// and intialize the CanvasKit wasm. Future downloadCanvasKit() async { - await _downloadOneOf(_canvasKitJsUrls); + final CanvasKitModule canvasKitModule = await _downloadOneOf(_canvasKitJsUrls); - final CanvasKit canvasKit = await CanvasKitInit(CanvasKitInitOptions( + final CanvasKit canvasKit = (await canvasKitModule.defaultExport(CanvasKitInitOptions( locateFile: createLocateFileCallback(canvasKitWasmModuleUrl), - )); + )).toDart) as CanvasKit; if (canvasKit.ParagraphBuilder.RequiresClientICU() && !browserSupportsCanvaskitChromium) { throw Exception( @@ -3681,10 +3682,12 @@ Future downloadCanvasKit() async { /// downloads it. /// /// If none of the URLs can be downloaded, throws an [Exception]. -Future _downloadOneOf(Iterable urls) async { +Future _downloadOneOf(Iterable urls) async { for (final String url in urls) { - if (await _downloadCanvasKitJs(url)) { - return; + try { + return await _downloadCanvasKitJs(url); + } catch (_) { + continue; } } @@ -3698,32 +3701,7 @@ Future _downloadOneOf(Iterable urls) async { /// /// Returns a [Future] that completes with `true` if the CanvasKit JavaScript /// file was successfully downloaded, or `false` if it failed. -Future _downloadCanvasKitJs(String url) { - final DomHTMLScriptElement canvasKitScript = - createDomHTMLScriptElement(configuration.nonce); - canvasKitScript.src = createTrustedScriptUrl(url); - - final Completer canvasKitLoadCompleter = Completer(); - - late final DomEventListener loadCallback; - late final DomEventListener errorCallback; - - void loadEventHandler(DomEvent _) { - canvasKitScript.remove(); - canvasKitLoadCompleter.complete(true); - } - void errorEventHandler(DomEvent errorEvent) { - canvasKitScript.remove(); - canvasKitLoadCompleter.complete(false); - } - - loadCallback = createDomEventListener(loadEventHandler); - errorCallback = createDomEventListener(errorEventHandler); - - canvasKitScript.addEventListener('load', loadCallback); - canvasKitScript.addEventListener('error', errorCallback); - - domDocument.head!.appendChild(canvasKitScript); - - return canvasKitLoadCompleter.future; +Future _downloadCanvasKitJs(String url) async { + final JSAny scriptUrl = createTrustedScriptUrl(url); + return (await importModule(scriptUrl).toDart) as CanvasKitModule; } diff --git a/lib/web_ui/lib/src/engine/configuration.dart b/lib/web_ui/lib/src/engine/configuration.dart index 33235af14c152..050dda1e494bd 100644 --- a/lib/web_ui/lib/src/engine/configuration.dart +++ b/lib/web_ui/lib/src/engine/configuration.dart @@ -241,7 +241,7 @@ class FlutterConfiguration { _configuration?.canvasKitBaseUrl ?? _defaultCanvasKitBaseUrl; static const String _defaultCanvasKitBaseUrl = String.fromEnvironment( 'FLUTTER_WEB_CANVASKIT_URL', - defaultValue: 'canvaskit/', + defaultValue: '/canvaskit/', ); /// The variant of CanvasKit to download. diff --git a/lib/web_ui/lib/src/engine/dom.dart b/lib/web_ui/lib/src/engine/dom.dart index b81bba41245f2..04eb31fdd507f 100644 --- a/lib/web_ui/lib/src/engine/dom.dart +++ b/lib/web_ui/lib/src/engine/dom.dart @@ -3383,16 +3383,16 @@ final DomTrustedTypePolicy _ttPolicy = domWindow.trustedTypes!.createPolicy( /// Converts a String `url` into a [DomTrustedScriptURL] object when the /// Trusted Types API is available, else returns the unmodified `url`. -Object createTrustedScriptUrl(String url) { +JSAny createTrustedScriptUrl(String url) { if (domWindow.trustedTypes != null) { // Pass `url` through Flutter Engine's TrustedType policy. final DomTrustedScriptURL trustedUrl = _ttPolicy.createScriptURL(url); assert(trustedUrl.url != '', 'URL: $url rejected by TrustedTypePolicy'); - return trustedUrl; + return trustedUrl as JSAny; } - return url; + return url.toJS; } DomMessageChannel createDomMessageChannel() => DomMessageChannel(); diff --git a/lib/web_ui/test/canvaskit/initialization/does_not_mock_module_exports_test.dart b/lib/web_ui/test/canvaskit/initialization/does_not_mock_module_exports_test.dart index b6676f2af4fcf..96e0c8a6d14d5 100644 --- a/lib/web_ui/test/canvaskit/initialization/does_not_mock_module_exports_test.dart +++ b/lib/web_ui/test/canvaskit/initialization/does_not_mock_module_exports_test.dart @@ -18,13 +18,6 @@ void testMain() { // Initialize CanvasKit... await bootstrapAndRunApp(); - // CanvasKitInit should be defined... - expect( - js_util.hasProperty(domWindow, 'CanvasKitInit'), - isTrue, - reason: 'CanvasKitInit should be defined on Window', - ); - // window.exports and window.module should be undefined! expect( js_util.hasProperty(domWindow, 'exports'), diff --git a/lib/web_ui/test/engine/configuration_test.dart b/lib/web_ui/test/engine/configuration_test.dart index 24f748f42f3ef..cb2ac7fdfbfc8 100644 --- a/lib/web_ui/test/engine/configuration_test.dart +++ b/lib/web_ui/test/engine/configuration_test.dart @@ -22,16 +22,16 @@ void testMain() { test('initializes with null', () async { final FlutterConfiguration config = FlutterConfiguration.legacy(null); - expect(config.canvasKitBaseUrl, 'canvaskit/'); // _defaultCanvasKitBaseUrl + expect(config.canvasKitBaseUrl, '/canvaskit/'); // _defaultCanvasKitBaseUrl }); test('legacy constructor initializes with a Js Object', () async { final FlutterConfiguration config = FlutterConfiguration.legacy( js_util.jsify({ - 'canvasKitBaseUrl': 'some_other_url/', + 'canvasKitBaseUrl': '/some_other_url/', }) as JsFlutterConfiguration); - expect(config.canvasKitBaseUrl, 'some_other_url/'); + expect(config.canvasKitBaseUrl, '/some_other_url/'); }); }); @@ -39,13 +39,13 @@ void testMain() { test('throws assertion error if already initialized from JS', () async { final FlutterConfiguration config = FlutterConfiguration.legacy( js_util.jsify({ - 'canvasKitBaseUrl': 'some_other_url/', + 'canvasKitBaseUrl': '/some_other_url/', }) as JsFlutterConfiguration); expect(() { config.setUserConfiguration( js_util.jsify({ - 'canvasKitBaseUrl': 'yet_another_url/', + 'canvasKitBaseUrl': '/yet_another_url/', }) as JsFlutterConfiguration); }, throwsAssertionError); }); @@ -55,10 +55,10 @@ void testMain() { config.setUserConfiguration( js_util.jsify({ - 'canvasKitBaseUrl': 'one_more_url/', + 'canvasKitBaseUrl': '/one_more_url/', }) as JsFlutterConfiguration); - expect(config.canvasKitBaseUrl, 'one_more_url/'); + expect(config.canvasKitBaseUrl, '/one_more_url/'); }); test('can receive non-existing properties without crashing', () async {