mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Skwasm heavy (#166619)
This produces a build of Skwasm that works on Firefox and Safari. This means we use `SkAnimatedImage` for animated gifs and webps and use builtin ICU data in Skia. I have unit test suites for Safari and Firefox with dart2wasm and both `ui` and `engine` test sets. However, there are a few issues with running these on CI: * Safari+dart2wasm doesn't work yet until the CI bots are upgraded to macOS 15, so these have been disabled on CI for now (but you can run the unit test suite locally). * Firefox+ui doesn't work because our Linux bots have no GPU and therefore no WebGL2 support, so that one is disabled. Firefox+dart2wasm with the `engine` suite is enabled on CI though. I did make some changes to the host page for our unit test harness so that Safari actually works though. Even though we're not running on CI, you can still run locally if you have macOS 15.
This commit is contained in:
parent
018c6d44df
commit
2b5ef64fc4
@ -193,25 +193,12 @@
|
||||
"--suite=chrome-dart2js-canvaskit-ui",
|
||||
"--suite=chrome-full-dart2js-canvaskit-canvaskit",
|
||||
"--suite=chrome-full-dart2js-canvaskit-ui",
|
||||
"--suite=edge-dart2js-canvaskit-engine",
|
||||
"--suite=edge-dart2js-canvaskit-canvaskit",
|
||||
"--suite=edge-dart2js-canvaskit-ui",
|
||||
"--suite=edge-full-dart2js-canvaskit-canvaskit",
|
||||
"--suite=edge-full-dart2js-canvaskit-ui",
|
||||
"--suite=firefox-dart2js-canvaskit-engine",
|
||||
"--suite=firefox-dart2js-canvaskit-canvaskit",
|
||||
"--suite=firefox-dart2js-canvaskit-ui",
|
||||
"--suite=safari-dart2js-canvaskit-engine",
|
||||
"--suite=safari-dart2js-canvaskit-canvaskit",
|
||||
"--suite=safari-dart2js-canvaskit-ui",
|
||||
"--suite=chrome-dart2wasm-canvaskit-engine",
|
||||
"--suite=chrome-coi-dart2wasm-skwasm-ui",
|
||||
"--suite=chrome-force-st-dart2wasm-skwasm-ui",
|
||||
"--suite=chrome-fallbacks",
|
||||
"--suite=chrome-coi-fallbacks",
|
||||
"--suite=chrome-force-st-fallbacks",
|
||||
"--suite=firefox-fallbacks",
|
||||
"--suite=safari-fallbacks"
|
||||
"--suite=chrome-force-st-fallbacks"
|
||||
],
|
||||
"script": "flutter/lib/web_ui/dev/felt"
|
||||
},
|
||||
@ -331,6 +318,7 @@
|
||||
"web_tests/test_bundles/dart2js-canvaskit-engine",
|
||||
"web_tests/test_bundles/dart2js-canvaskit-canvaskit",
|
||||
"web_tests/test_bundles/dart2js-canvaskit-ui",
|
||||
"web_tests/test_bundles/dart2wasm-canvaskit-engine",
|
||||
"web_tests/test_bundles/fallbacks"
|
||||
],
|
||||
"test_dependencies": [
|
||||
@ -349,30 +337,11 @@
|
||||
"parameters": [
|
||||
"test",
|
||||
"--copy-artifacts",
|
||||
"--suite=chrome-dart2js-canvaskit-engine",
|
||||
"--suite=chrome-dart2js-canvaskit-canvaskit",
|
||||
"--suite=chrome-dart2js-canvaskit-ui",
|
||||
"--suite=chrome-full-dart2js-canvaskit-canvaskit",
|
||||
"--suite=chrome-full-dart2js-canvaskit-ui",
|
||||
"--suite=edge-dart2js-canvaskit-engine",
|
||||
"--suite=edge-dart2js-canvaskit-canvaskit",
|
||||
"--suite=edge-dart2js-canvaskit-ui",
|
||||
"--suite=edge-full-dart2js-canvaskit-canvaskit",
|
||||
"--suite=edge-full-dart2js-canvaskit-ui",
|
||||
"--suite=firefox-dart2js-canvaskit-engine",
|
||||
"--suite=firefox-dart2js-canvaskit-canvaskit",
|
||||
"--suite=firefox-dart2js-canvaskit-ui",
|
||||
"--suite=safari-dart2js-canvaskit-engine",
|
||||
"--suite=safari-dart2js-canvaskit-canvaskit",
|
||||
"--suite=safari-dart2js-canvaskit-ui",
|
||||
"--suite=chrome-dart2wasm-canvaskit-engine",
|
||||
"--suite=chrome-coi-dart2wasm-skwasm-ui",
|
||||
"--suite=chrome-force-st-dart2wasm-skwasm-ui",
|
||||
"--suite=chrome-fallbacks",
|
||||
"--suite=chrome-coi-fallbacks",
|
||||
"--suite=chrome-force-st-fallbacks",
|
||||
"--suite=firefox-fallbacks",
|
||||
"--suite=safari-fallbacks"
|
||||
"--suite=firefox-dart2wasm-canvaskit-engine",
|
||||
"--suite=firefox-fallbacks"
|
||||
],
|
||||
"script": "flutter/lib/web_ui/dev/felt"
|
||||
},
|
||||
@ -403,6 +372,15 @@
|
||||
],
|
||||
"script": "flutter/lib/web_ui/dev/felt"
|
||||
},
|
||||
{
|
||||
"name": "run suite firefox-dart2wasm-canvaskit-engine",
|
||||
"parameters": [
|
||||
"test",
|
||||
"--run",
|
||||
"--suite=firefox-dart2wasm-canvaskit-engine"
|
||||
],
|
||||
"script": "flutter/lib/web_ui/dev/felt"
|
||||
},
|
||||
{
|
||||
"name": "run suite firefox-fallbacks",
|
||||
"parameters": [
|
||||
@ -444,29 +422,9 @@
|
||||
"parameters": [
|
||||
"test",
|
||||
"--copy-artifacts",
|
||||
"--suite=chrome-dart2js-canvaskit-engine",
|
||||
"--suite=chrome-dart2js-canvaskit-canvaskit",
|
||||
"--suite=chrome-dart2js-canvaskit-ui",
|
||||
"--suite=chrome-full-dart2js-canvaskit-canvaskit",
|
||||
"--suite=chrome-full-dart2js-canvaskit-ui",
|
||||
"--suite=edge-dart2js-canvaskit-engine",
|
||||
"--suite=edge-dart2js-canvaskit-canvaskit",
|
||||
"--suite=edge-dart2js-canvaskit-ui",
|
||||
"--suite=edge-full-dart2js-canvaskit-canvaskit",
|
||||
"--suite=edge-full-dart2js-canvaskit-ui",
|
||||
"--suite=firefox-dart2js-canvaskit-engine",
|
||||
"--suite=firefox-dart2js-canvaskit-canvaskit",
|
||||
"--suite=firefox-dart2js-canvaskit-ui",
|
||||
"--suite=safari-dart2js-canvaskit-engine",
|
||||
"--suite=safari-dart2js-canvaskit-canvaskit",
|
||||
"--suite=safari-dart2js-canvaskit-ui",
|
||||
"--suite=chrome-dart2wasm-canvaskit-engine",
|
||||
"--suite=chrome-coi-dart2wasm-skwasm-ui",
|
||||
"--suite=chrome-force-st-dart2wasm-skwasm-ui",
|
||||
"--suite=chrome-fallbacks",
|
||||
"--suite=chrome-coi-fallbacks",
|
||||
"--suite=chrome-force-st-fallbacks",
|
||||
"--suite=firefox-fallbacks",
|
||||
"--suite=safari-fallbacks"
|
||||
],
|
||||
"script": "flutter/lib/web_ui/dev/felt"
|
||||
|
||||
@ -52200,6 +52200,7 @@ ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/paragraph.
|
||||
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/path.dart + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/path_metrics.dart + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/picture.dart + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_animated_image.dart + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_canvas.dart + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_filters.dart + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_fonts.dart + ../../../flutter/LICENSE
|
||||
@ -52271,6 +52272,8 @@ ORIGIN: ../../../flutter/lib/web_ui/lib/ui_web/src/ui_web/platform_view_registry
|
||||
ORIGIN: ../../../flutter/lib/web_ui/lib/ui_web/src/ui_web/plugins.dart + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/lib/web_ui/lib/ui_web/src/ui_web/testing.dart + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/lib/web_ui/lib/window.dart + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/lib/web_ui/skwasm/animated_image.cpp + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/lib/web_ui/skwasm/animated_image_stub.cpp + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/lib/web_ui/skwasm/canvas.cpp + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/lib/web_ui/skwasm/contour_measure.cpp + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/lib/web_ui/skwasm/data.cpp + ../../../flutter/LICENSE
|
||||
@ -52291,6 +52294,8 @@ ORIGIN: ../../../flutter/lib/web_ui/skwasm/surface.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/lib/web_ui/skwasm/text/line_metrics.cpp + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/lib/web_ui/skwasm/text/paragraph.cpp + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/lib/web_ui/skwasm/text/paragraph_builder.cpp + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/lib/web_ui/skwasm/text/paragraph_builder_builtin_icu.cpp + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/lib/web_ui/skwasm/text/paragraph_builder_client_icu.cpp + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/lib/web_ui/skwasm/text/paragraph_style.cpp + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/lib/web_ui/skwasm/text/strut_style.cpp + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/lib/web_ui/skwasm/text/text_style.cpp + ../../../flutter/LICENSE
|
||||
@ -55199,6 +55204,7 @@ FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/paragraph.da
|
||||
FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/path.dart
|
||||
FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/path_metrics.dart
|
||||
FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/picture.dart
|
||||
FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_animated_image.dart
|
||||
FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_canvas.dart
|
||||
FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_filters.dart
|
||||
FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_fonts.dart
|
||||
@ -55270,6 +55276,8 @@ FILE: ../../../flutter/lib/web_ui/lib/ui_web/src/ui_web/platform_view_registry.d
|
||||
FILE: ../../../flutter/lib/web_ui/lib/ui_web/src/ui_web/plugins.dart
|
||||
FILE: ../../../flutter/lib/web_ui/lib/ui_web/src/ui_web/testing.dart
|
||||
FILE: ../../../flutter/lib/web_ui/lib/window.dart
|
||||
FILE: ../../../flutter/lib/web_ui/skwasm/animated_image.cpp
|
||||
FILE: ../../../flutter/lib/web_ui/skwasm/animated_image_stub.cpp
|
||||
FILE: ../../../flutter/lib/web_ui/skwasm/canvas.cpp
|
||||
FILE: ../../../flutter/lib/web_ui/skwasm/contour_measure.cpp
|
||||
FILE: ../../../flutter/lib/web_ui/skwasm/data.cpp
|
||||
@ -55290,6 +55298,8 @@ FILE: ../../../flutter/lib/web_ui/skwasm/surface.h
|
||||
FILE: ../../../flutter/lib/web_ui/skwasm/text/line_metrics.cpp
|
||||
FILE: ../../../flutter/lib/web_ui/skwasm/text/paragraph.cpp
|
||||
FILE: ../../../flutter/lib/web_ui/skwasm/text/paragraph_builder.cpp
|
||||
FILE: ../../../flutter/lib/web_ui/skwasm/text/paragraph_builder_builtin_icu.cpp
|
||||
FILE: ../../../flutter/lib/web_ui/skwasm/text/paragraph_builder_client_icu.cpp
|
||||
FILE: ../../../flutter/lib/web_ui/skwasm/text/paragraph_style.cpp
|
||||
FILE: ../../../flutter/lib/web_ui/skwasm/text/strut_style.cpp
|
||||
FILE: ../../../flutter/lib/web_ui/skwasm/text/text_style.cpp
|
||||
|
||||
@ -22,6 +22,8 @@ const Map<String, String> targetAliases = <String, String>{
|
||||
'flutter/third_party/canvaskit:canvaskit_experimental_webparagraph_group',
|
||||
'skwasm': 'flutter/third_party/canvaskit:skwasm_group',
|
||||
'skwasm_st': 'flutter/third_party/canvaskit:skwasm_st_group',
|
||||
'skwasm_heavy': 'flutter/third_party/canvaskit:skwasm_heavy_group',
|
||||
'skwasm_heavy_st': 'flutter/third_party/canvaskit:skwasm_heavy_st_group',
|
||||
'archive': 'flutter/web_sdk:flutter_web_sdk_archive',
|
||||
};
|
||||
|
||||
|
||||
@ -44,6 +44,7 @@ class RunConfiguration {
|
||||
this.variant,
|
||||
this.crossOriginIsolated,
|
||||
this.forceSingleThreadedSkwasm,
|
||||
this.wasmAllowList,
|
||||
);
|
||||
|
||||
final String name;
|
||||
@ -52,6 +53,7 @@ class RunConfiguration {
|
||||
final CanvasKitVariant? variant;
|
||||
final bool crossOriginIsolated;
|
||||
final bool forceSingleThreadedSkwasm;
|
||||
final Map<String, bool> wasmAllowList;
|
||||
}
|
||||
|
||||
class ArtifactDependencies {
|
||||
@ -190,6 +192,7 @@ class FeltConfig {
|
||||
final bool crossOriginIsolated = runConfigYaml['cross-origin-isolated'] as bool? ?? false;
|
||||
final bool forceSingleThreadedSkwasm =
|
||||
runConfigYaml['force-single-threaded-skwasm'] as bool? ?? false;
|
||||
final YamlMap wasmAllowList = (runConfigYaml['wasm-allow-list'] as YamlMap?) ?? YamlMap();
|
||||
final RunConfiguration runConfig = RunConfiguration(
|
||||
name,
|
||||
browser,
|
||||
@ -197,6 +200,7 @@ class FeltConfig {
|
||||
variant,
|
||||
crossOriginIsolated,
|
||||
forceSingleThreadedSkwasm,
|
||||
wasmAllowList.cast<String, bool>(),
|
||||
);
|
||||
runConfigs.add(runConfig);
|
||||
if (runConfigsByName.containsKey(name)) {
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:path/path.dart' as path;
|
||||
@ -65,6 +66,8 @@ class Firefox extends Browser {
|
||||
user_pref("browser.shell.checkDefaultBrowser", false);
|
||||
user_pref("dom.disable_open_during_load", false);
|
||||
user_pref("dom.max_script_run_time", 0);
|
||||
user_pref("trailhead.firstrun.branches", "nofirstrun-empty");
|
||||
user_pref("browser.aboutwelcome.enabled", false);
|
||||
''';
|
||||
|
||||
final Directory temporaryProfileDirectory = Directory(
|
||||
@ -80,7 +83,6 @@ user_pref("dom.max_script_run_time", 0);
|
||||
temporaryProfileDirectory.createSync(recursive: true);
|
||||
File(path.join(temporaryProfileDirectory.path, 'prefs.js')).writeAsStringSync(profile);
|
||||
|
||||
final bool isMac = Platform.isMacOS;
|
||||
final List<String> args = <String>[
|
||||
url.toString(),
|
||||
'--profile',
|
||||
@ -88,13 +90,18 @@ user_pref("dom.max_script_run_time", 0);
|
||||
if (!debug) '--headless',
|
||||
'-width $kMaxScreenshotWidth',
|
||||
'-height $kMaxScreenshotHeight',
|
||||
// On Mac Firefox uses the -- option prefix, while elsewhere it uses the - prefix.
|
||||
'${isMac ? '-' : ''}-new-window',
|
||||
'${isMac ? '-' : ''}-new-instance',
|
||||
'-new-window',
|
||||
'-new-instance',
|
||||
'--start-debugger-server $kDevtoolsPort',
|
||||
];
|
||||
|
||||
final Process process = await Process.start(installation.executable, args);
|
||||
process.stdout
|
||||
.transform<String>(const Utf8Decoder(allowMalformed: true))
|
||||
.listen((String string) => print('[Firefox:stdout] $string'));
|
||||
process.stderr
|
||||
.transform<String>(const Utf8Decoder(allowMalformed: true))
|
||||
.listen((String string) => print('[Firefox:stderr] $string'));
|
||||
|
||||
remoteDebuggerCompleter.complete(
|
||||
getRemoteDebuggerUrl(Uri.parse('http://localhost:$kDevtoolsPort')),
|
||||
|
||||
@ -114,8 +114,9 @@ class GenerateBuilderJsonCommand extends Command<bool> {
|
||||
String? specificOS,
|
||||
String? cpu,
|
||||
}) {
|
||||
final enabledSuites = suites.where((suite) => suite.enableCi);
|
||||
final filteredSuites = enabledSuites.where((suite) => suite.runConfig.browser == browser);
|
||||
final filteredSuites = suites.where(
|
||||
(suite) => suite.enableCi && suite.runConfig.browser == browser,
|
||||
);
|
||||
final bundles = filteredSuites.map((suite) => suite.testBundle).toSet();
|
||||
return <String, dynamic>{
|
||||
'name': '$platform run ${browser.name} suites',
|
||||
@ -149,7 +150,7 @@ class GenerateBuilderJsonCommand extends Command<bool> {
|
||||
'parameters': <String>[
|
||||
'test',
|
||||
'--copy-artifacts',
|
||||
for (final TestSuite suite in enabledSuites) '--suite=${suite.name}',
|
||||
for (final TestSuite suite in filteredSuites) '--suite=${suite.name}',
|
||||
],
|
||||
'script': 'flutter/lib/web_ui/dev/felt',
|
||||
},
|
||||
|
||||
@ -77,6 +77,7 @@ class CopyArtifactsStep implements PipelineStep {
|
||||
final String canvaskitSourceDirectory;
|
||||
final String canvaskitChromiumSourceDirectory;
|
||||
final String skwasmSourceDirectory;
|
||||
final String skwasmHeavySourceDirectory;
|
||||
switch (source) {
|
||||
case LocalArtifactSource(:final mode):
|
||||
final buildDirectory = getBuildDirectoryForRuntimeMode(mode).path;
|
||||
@ -88,6 +89,7 @@ class CopyArtifactsStep implements PipelineStep {
|
||||
canvaskitSourceDirectory = pathlib.join(buildDirectory, 'canvaskit');
|
||||
canvaskitChromiumSourceDirectory = pathlib.join(buildDirectory, 'canvaskit_chromium');
|
||||
skwasmSourceDirectory = pathlib.join(buildDirectory, 'skwasm');
|
||||
skwasmHeavySourceDirectory = pathlib.join(buildDirectory, 'skwasm_heavy');
|
||||
|
||||
case GcsArtifactSource(:final realm):
|
||||
final artifactsDirectory = (await _downloadArtifacts(realm)).path;
|
||||
@ -104,6 +106,7 @@ class CopyArtifactsStep implements PipelineStep {
|
||||
'chromium',
|
||||
);
|
||||
skwasmSourceDirectory = pathlib.join(artifactsDirectory, 'canvaskit');
|
||||
skwasmHeavySourceDirectory = pathlib.join(artifactsDirectory, 'canvaskit');
|
||||
}
|
||||
|
||||
await environment.webTestsArtifactsDir.create(recursive: true);
|
||||
@ -131,6 +134,7 @@ class CopyArtifactsStep implements PipelineStep {
|
||||
if (artifactDeps.skwasm) {
|
||||
copied.add('Skwasm');
|
||||
await copyWasmLibrary('skwasm', skwasmSourceDirectory, 'canvaskit');
|
||||
await copyWasmLibrary('skwasm_heavy', skwasmHeavySourceDirectory, 'canvaskit');
|
||||
}
|
||||
print('Copied artifacts: ${copied.join(', ')}');
|
||||
}
|
||||
|
||||
@ -536,6 +536,7 @@ class BrowserPlatform extends PlatformPlugin {
|
||||
canvasKitVariant: "${getCanvasKitVariant()}",
|
||||
canvasKitBaseUrl: "/canvaskit",
|
||||
forceSingleThreadedSkwasm: ${suite.runConfig.forceSingleThreadedSkwasm},
|
||||
wasmAllowList: ${jsonEncode(suite.runConfig.wasmAllowList)},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
@ -2,13 +2,36 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
const isBlink = () => {
|
||||
return (navigator.vendor === 'Google Inc.') ||
|
||||
(navigator.agent === 'Edg/');
|
||||
/** @type {import("./types").WasmAllowList} */
|
||||
export const defaultWasmSupport = {
|
||||
"blink": true,
|
||||
"gecko": false,
|
||||
"webkit": false,
|
||||
"unknown": false,
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {import("./types").BrowserEngine}
|
||||
*/
|
||||
const getBrowserEngine = () => {
|
||||
if ((navigator.vendor === 'Google Inc.') ||
|
||||
(navigator.userAgent.includes('Edg/'))) {
|
||||
return "blink";
|
||||
}
|
||||
if (navigator.vendor === "Apple Computer, Inc.") {
|
||||
return "webkit";
|
||||
}
|
||||
if (navigator.vendor === "" && navigator.userAgent.includes('Firefox')) {
|
||||
return "gecko";
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
/** @type {import("./types").BrowserEnvironment} */
|
||||
const browserEngine = getBrowserEngine();
|
||||
|
||||
const hasImageCodecs = () => {
|
||||
if (typeof ImageDecoder === 'undefined') {
|
||||
if (typeof ImageDecoder === "undefined") {
|
||||
return false;
|
||||
}
|
||||
// TODO(yjbanov): https://github.com/flutter/flutter/issues/122761
|
||||
@ -18,7 +41,7 @@ const hasImageCodecs = () => {
|
||||
// up potentially incompatible implementations of ImagdeDecoder API. Instead,
|
||||
// when a new browser engine launches the API, we'll evaluate it and enable it
|
||||
// explicitly.
|
||||
return isBlink();
|
||||
return browserEngine === "blink";
|
||||
}
|
||||
|
||||
const hasChromiumBreakIterators = () => {
|
||||
@ -35,10 +58,9 @@ const supportsWasmGC = () => {
|
||||
return WebAssembly.validate(new Uint8Array(bytes));
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {import("./types").BrowserEnvironment}
|
||||
*/
|
||||
/** @type {import("./types").BrowserEnvironment} */
|
||||
export const browserEnvironment = {
|
||||
browserEngine: browserEngine,
|
||||
hasImageCodecs: hasImageCodecs(),
|
||||
hasChromiumBreakIterators: hasChromiumBreakIterators(),
|
||||
supportsWasmGC: supportsWasmGC(),
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import { browserEnvironment } from './browser_environment.js';
|
||||
import { browserEnvironment, defaultWasmSupport } from './browser_environment.js';
|
||||
import { FlutterEntrypointLoader } from './entrypoint_loader.js';
|
||||
import { FlutterServiceWorkerLoader } from './service_worker_loader.js';
|
||||
import { FlutterTrustedTypesPolicy } from './trusted_types.js';
|
||||
@ -55,7 +55,7 @@ export class FlutterLoader {
|
||||
* Settings for the service worker to be loaded. Can pass `undefined` or
|
||||
* `null` to not launch a service worker at all.
|
||||
* @param {import("/.types".OnEntryPointLoadedCallback)} options.onEntrypointLoaded
|
||||
* An optional callback to invoke
|
||||
* An optional callback to invoke
|
||||
* @param {string} options.nonce
|
||||
* A nonce to be applied to the main JS script when loading it, which may
|
||||
* be required by the sites Content-Security-Policy.
|
||||
@ -76,12 +76,11 @@ export class FlutterLoader {
|
||||
throw "FlutterLoader.load requires _flutter.buildConfig to be set";
|
||||
}
|
||||
|
||||
const enableWasm = config.wasmAllowList?.[browserEnvironment.browserEngine] ?? defaultWasmSupport[browserEnvironment.browserEngine];
|
||||
const rendererIsCompatible = (renderer) => {
|
||||
switch (renderer) {
|
||||
case "skwasm":
|
||||
return browserEnvironment.hasChromiumBreakIterators
|
||||
&& browserEnvironment.hasImageCodecs
|
||||
&& browserEnvironment.supportsWasmGC;
|
||||
return browserEnvironment.supportsWasmGC && enableWasm;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -6,12 +6,14 @@ import { createWasmInstantiator } from "./instantiate_wasm.js";
|
||||
import { resolveUrlWithSegments } from "./utils.js";
|
||||
|
||||
export const loadSkwasm = async (deps, config, browserEnvironment, baseUrl) => {
|
||||
const rawSkwasmUrl = resolveUrlWithSegments(baseUrl, 'skwasm.js')
|
||||
const needsHeavy = (!browserEnvironment.hasImageCodecs || !browserEnvironment.hasChromiumBreakIterators)
|
||||
const fileStem = needsHeavy ? 'skwasm_heavy' : 'skwasm';
|
||||
const rawSkwasmUrl = resolveUrlWithSegments(baseUrl, `${fileStem}.js`)
|
||||
let skwasmUrl = rawSkwasmUrl;
|
||||
if (deps.flutterTT.policy) {
|
||||
skwasmUrl = deps.flutterTT.policy.createScriptURL(skwasmUrl);
|
||||
}
|
||||
const wasmInstantiator = createWasmInstantiator(resolveUrlWithSegments(baseUrl, 'skwasm.wasm'));
|
||||
const wasmInstantiator = createWasmInstantiator(resolveUrlWithSegments(baseUrl, `${fileStem}.wasm`));
|
||||
const skwasm = await import(skwasmUrl);
|
||||
return await skwasm.default({
|
||||
skwasmSingleThreaded: !browserEnvironment.crossOriginIsolated || config.forceSingleThreadedSkwasm,
|
||||
|
||||
@ -6,10 +6,8 @@ type JSCompileTarget = "dart2js" | "dartdevc";
|
||||
type WasmCompileTarget = "dart2wasm";
|
||||
|
||||
export type CompileTarget = JSCompileTarget | WasmCompileTarget;
|
||||
|
||||
export type WebRenderer =
|
||||
"canvaskit" |
|
||||
"skwasm";
|
||||
export type WebRenderer = "canvaskit" | "skwasm";
|
||||
export type BrowserEngine = "blink" | "gecko" | "webkit" | "unknown";
|
||||
|
||||
interface ApplicationBuildBase {
|
||||
renderer: WebRenderer;
|
||||
@ -31,11 +29,12 @@ export type ApplicationBuild = JSApplicationBuild | WasmApplicationBuild;
|
||||
export interface BuildConfig {
|
||||
serviceWorkerVersion: string;
|
||||
engineRevision: string;
|
||||
useLocalCanvasKit: bool?;
|
||||
useLocalCanvasKit?: boolean;
|
||||
builds: ApplicationBuild[];
|
||||
}
|
||||
|
||||
export interface BrowserEnvironment {
|
||||
browserEngine: BrowserEngine;
|
||||
hasImageCodecs: boolean;
|
||||
hasChromiumBreakIterators: boolean;
|
||||
supportsWasmGC: boolean;
|
||||
@ -47,21 +46,26 @@ type CanvasKitVariant =
|
||||
"full" |
|
||||
"chromium";
|
||||
|
||||
type WasmAllowList = {
|
||||
[k in BrowserEngine]?: boolean;
|
||||
}
|
||||
|
||||
export interface FlutterConfiguration {
|
||||
assetBase: string?;
|
||||
canvasKitBaseUrl: string?;
|
||||
canvasKitVariant: CanvasKitVariant?;
|
||||
renderer: WebRenderer?;
|
||||
hostElement: HtmlElement?;
|
||||
fontFallbackBaseUrl: string?;
|
||||
entryPointBaseUrl: string?;
|
||||
forceSingleThreadedSkwasm: boolean?;
|
||||
assetBase?: string;
|
||||
canvasKitBaseUrl?: string;
|
||||
canvasKitVariant?: CanvasKitVariant;
|
||||
renderer?: WebRenderer;
|
||||
hostElement?: HTMLElement;
|
||||
fontFallbackBaseUrl?: string;
|
||||
entryPointBaseUrl?: string;
|
||||
forceSingleThreadedSkwasm?: boolean;
|
||||
wasmAllowList?: WasmAllowList;
|
||||
}
|
||||
|
||||
export interface ServiceWorkerSettings {
|
||||
serviceWorkerVersion: string;
|
||||
serviceWorkerUrl: string?;
|
||||
timeoutMillis: number?;
|
||||
serviceWorkerUrl?: string;
|
||||
timeoutMillis?: number;
|
||||
}
|
||||
|
||||
export interface AppRunner {
|
||||
|
||||
@ -72,7 +72,7 @@ abstract class HtmlImageElementCodec implements ui.Codec {
|
||||
naturalWidth = kDefaultImageSizeFallback;
|
||||
naturalHeight = kDefaultImageSizeFallback;
|
||||
}
|
||||
final ui.Image image = createImageFromHTMLImageElement(
|
||||
final ui.Image image = await createImageFromHTMLImageElement(
|
||||
imgElement!,
|
||||
naturalWidth,
|
||||
naturalHeight,
|
||||
@ -81,7 +81,7 @@ abstract class HtmlImageElementCodec implements ui.Codec {
|
||||
}
|
||||
|
||||
/// Creates a [ui.Image] from an [HTMLImageElement] that has been loaded.
|
||||
ui.Image createImageFromHTMLImageElement(
|
||||
FutureOr<ui.Image> createImageFromHTMLImageElement(
|
||||
DomHTMLImageElement image,
|
||||
int naturalWidth,
|
||||
int naturalHeight,
|
||||
|
||||
@ -19,6 +19,7 @@ export 'skwasm_impl/paragraph.dart';
|
||||
export 'skwasm_impl/path.dart';
|
||||
export 'skwasm_impl/path_metrics.dart';
|
||||
export 'skwasm_impl/picture.dart';
|
||||
export 'skwasm_impl/raw/raw_animated_image.dart';
|
||||
export 'skwasm_impl/raw/raw_canvas.dart';
|
||||
export 'skwasm_impl/raw/raw_filters.dart';
|
||||
export 'skwasm_impl/raw/raw_fonts.dart';
|
||||
|
||||
@ -2,12 +2,16 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:ffi';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:ui/src/engine.dart';
|
||||
import 'package:ui/src/engine/skwasm/skwasm_impl.dart';
|
||||
import 'package:ui/ui.dart' as ui;
|
||||
|
||||
class SkwasmImageDecoder extends BrowserImageDecoder {
|
||||
SkwasmImageDecoder({
|
||||
class SkwasmBrowserImageDecoder extends BrowserImageDecoder {
|
||||
SkwasmBrowserImageDecoder({
|
||||
required super.contentType,
|
||||
required super.dataSource,
|
||||
required super.debugSource,
|
||||
@ -21,3 +25,69 @@ class SkwasmImageDecoder extends BrowserImageDecoder {
|
||||
return SkwasmImage(imageCreateFromTextureSource(frame, width, height, surface.handle));
|
||||
}
|
||||
}
|
||||
|
||||
class SkwasmDomImageDecoder extends HtmlBlobCodec {
|
||||
SkwasmDomImageDecoder(super.blob, [this.width, this.height]);
|
||||
|
||||
final int? width;
|
||||
final int? height;
|
||||
|
||||
@override
|
||||
FutureOr<ui.Image> createImageFromHTMLImageElement(
|
||||
DomHTMLImageElement image,
|
||||
int naturalWidth,
|
||||
int naturalHeight,
|
||||
) {
|
||||
return renderer.createImageFromTextureSource(
|
||||
image,
|
||||
width: width ?? naturalWidth,
|
||||
height: height ?? naturalHeight,
|
||||
transferOwnership: false,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class SkwasmAnimatedImageDecoder implements ui.Codec {
|
||||
factory SkwasmAnimatedImageDecoder(Uint8List imageData, [int? width, int? height]) {
|
||||
final SkDataHandle data = skDataCreate(imageData.length);
|
||||
final Pointer<Int8> dataPointer = skDataGetPointer(data).cast<Int8>();
|
||||
for (int i = 0; i < imageData.length; i++) {
|
||||
dataPointer[i] = imageData[i];
|
||||
}
|
||||
final AnimatedImageHandle handle = animatedImageCreate(data, width ?? 0, height ?? 0);
|
||||
skDataDispose(data);
|
||||
return SkwasmAnimatedImageDecoder._(handle);
|
||||
}
|
||||
|
||||
SkwasmAnimatedImageDecoder._(this.handle);
|
||||
|
||||
AnimatedImageHandle handle;
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
if (handle != nullptr) {
|
||||
animatedImageDispose(handle);
|
||||
handle = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
int get frameCount {
|
||||
return animatedImageGetFrameCount(handle);
|
||||
}
|
||||
|
||||
@override
|
||||
int get repetitionCount {
|
||||
return animatedImageGetRepetitionCount(handle);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ui.FrameInfo> getNextFrame() async {
|
||||
final Duration duration = Duration(
|
||||
milliseconds: animatedImageGetCurrentFrameDurationMilliseconds(handle),
|
||||
);
|
||||
final SkwasmImage image = SkwasmImage(animatedImageGetCurrentFrame(handle));
|
||||
final ui.FrameInfo frameInfo = AnimatedImageFrameInfo(duration, image);
|
||||
return frameInfo;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1080,7 +1080,9 @@ class SkwasmParagraphBuilder extends SkwasmObjectWrapper<RawParagraphBuilder>
|
||||
|
||||
@override
|
||||
ui.Paragraph build() {
|
||||
_addSegmenterData();
|
||||
if (!skwasmIsHeavy()) {
|
||||
_addSegmenterData();
|
||||
}
|
||||
return SkwasmParagraph(paragraphBuilderBuild(handle));
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,47 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
@DefaultAsset('skwasm')
|
||||
library skwasm_impl;
|
||||
|
||||
import 'dart:ffi';
|
||||
|
||||
import 'package:ui/src/engine/skwasm/skwasm_impl.dart';
|
||||
|
||||
final class RawAnimatedImage extends Opaque {}
|
||||
|
||||
typedef AnimatedImageHandle = Pointer<RawAnimatedImage>;
|
||||
|
||||
@Native<AnimatedImageHandle Function(SkDataHandle, Int32, Int32)>(
|
||||
symbol: 'animatedImage_create',
|
||||
isLeaf: true,
|
||||
)
|
||||
external AnimatedImageHandle animatedImageCreate(SkDataHandle handle, int width, int height);
|
||||
|
||||
@Native<Void Function(AnimatedImageHandle)>(symbol: 'animatedImage_dispose', isLeaf: true)
|
||||
external void animatedImageDispose(AnimatedImageHandle handle);
|
||||
|
||||
@Native<Int32 Function(AnimatedImageHandle)>(symbol: 'animatedImage_getFrameCount', isLeaf: true)
|
||||
external int animatedImageGetFrameCount(AnimatedImageHandle handle);
|
||||
|
||||
@Native<Int32 Function(AnimatedImageHandle)>(
|
||||
symbol: 'animatedImage_getRepetitionCount',
|
||||
isLeaf: true,
|
||||
)
|
||||
external int animatedImageGetRepetitionCount(AnimatedImageHandle handle);
|
||||
|
||||
@Native<Int32 Function(AnimatedImageHandle)>(
|
||||
symbol: 'animatedImage_getCurrentFrameDurationMilliseconds',
|
||||
isLeaf: true,
|
||||
)
|
||||
external int animatedImageGetCurrentFrameDurationMilliseconds(AnimatedImageHandle handle);
|
||||
|
||||
@Native<Void Function(AnimatedImageHandle)>(symbol: 'animatedImage_decodeNextFrame', isLeaf: true)
|
||||
external void animatedImageDecodeNextFrame(AnimatedImageHandle handle);
|
||||
|
||||
@Native<ImageHandle Function(AnimatedImageHandle)>(
|
||||
symbol: 'animatedImage_getCurrentFrame',
|
||||
isLeaf: true,
|
||||
)
|
||||
external ImageHandle animatedImageGetCurrentFrame(AnimatedImageHandle handle);
|
||||
@ -25,3 +25,6 @@ external WasmI32 addFunction(WasmFuncRef function);
|
||||
|
||||
@Native<Bool Function()>(symbol: 'skwasm_isMultiThreaded', isLeaf: true)
|
||||
external bool skwasmIsMultiThreaded();
|
||||
|
||||
@Native<Bool Function()>(symbol: 'skwasm_isHeavy', isLeaf: true)
|
||||
external bool skwasmIsHeavy();
|
||||
|
||||
@ -333,21 +333,30 @@ class SkwasmRenderer implements Renderer {
|
||||
if (contentType == null) {
|
||||
throw Exception('Could not determine content type of image from data');
|
||||
}
|
||||
final SkwasmImageDecoder baseDecoder = SkwasmImageDecoder(
|
||||
contentType: contentType.mimeType,
|
||||
dataSource: list.toJS,
|
||||
debugSource: 'encoded image bytes',
|
||||
);
|
||||
await baseDecoder.initialize();
|
||||
if (targetWidth == null && targetHeight == null) {
|
||||
return baseDecoder;
|
||||
if (browserSupportsImageDecoder) {
|
||||
final SkwasmBrowserImageDecoder baseDecoder = SkwasmBrowserImageDecoder(
|
||||
contentType: contentType.mimeType,
|
||||
dataSource: list.toJS,
|
||||
debugSource: 'encoded image bytes',
|
||||
);
|
||||
await baseDecoder.initialize();
|
||||
if (targetWidth == null && targetHeight == null) {
|
||||
return baseDecoder;
|
||||
}
|
||||
return ResizingCodec(
|
||||
baseDecoder,
|
||||
targetWidth: targetWidth,
|
||||
targetHeight: targetHeight,
|
||||
allowUpscaling: allowUpscaling,
|
||||
);
|
||||
} else {
|
||||
if (contentType.isAnimated) {
|
||||
return SkwasmAnimatedImageDecoder(list, targetWidth, targetHeight);
|
||||
} else {
|
||||
final DomBlob blob = createDomBlob(<ByteBuffer>[list.buffer]);
|
||||
return SkwasmDomImageDecoder(blob, targetWidth, targetHeight);
|
||||
}
|
||||
}
|
||||
return ResizingCodec(
|
||||
baseDecoder,
|
||||
targetWidth: targetWidth,
|
||||
targetHeight: targetHeight,
|
||||
allowUpscaling: allowUpscaling,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
@ -360,13 +369,28 @@ class SkwasmRenderer implements Renderer {
|
||||
if (contentType == null) {
|
||||
throw Exception('Could not determine content type of image at url $uri');
|
||||
}
|
||||
final SkwasmImageDecoder decoder = SkwasmImageDecoder(
|
||||
contentType: contentType,
|
||||
dataSource: response.body,
|
||||
debugSource: uri.toString(),
|
||||
);
|
||||
await decoder.initialize();
|
||||
return decoder;
|
||||
if (browserSupportsImageDecoder) {
|
||||
final SkwasmBrowserImageDecoder decoder = SkwasmBrowserImageDecoder(
|
||||
contentType: contentType,
|
||||
dataSource: response.body,
|
||||
debugSource: uri.toString(),
|
||||
);
|
||||
await decoder.initialize();
|
||||
return decoder;
|
||||
} else {
|
||||
final ByteBuffer buffer = await response.arrayBuffer();
|
||||
final Uint8List data = buffer.asUint8List();
|
||||
final ImageType? parsedContentType = detectImageType(data);
|
||||
if (parsedContentType == null) {
|
||||
throw Exception('Could not determine content type of image from data');
|
||||
}
|
||||
if (parsedContentType.isAnimated) {
|
||||
return SkwasmAnimatedImageDecoder(data);
|
||||
} else {
|
||||
final DomBlob blob = createDomBlob(<ByteBuffer>[buffer]);
|
||||
return SkwasmDomImageDecoder(blob);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@ -4,69 +4,90 @@
|
||||
|
||||
import("//build/toolchain/wasm.gni")
|
||||
|
||||
wasm_lib("skwasm") {
|
||||
public_configs = [ "//flutter:config" ]
|
||||
template("skwasm_variant") {
|
||||
wasm_lib(target_name) {
|
||||
public_configs = [ "//flutter:config" ]
|
||||
|
||||
sources = [
|
||||
"canvas.cpp",
|
||||
"contour_measure.cpp",
|
||||
"data.cpp",
|
||||
"export.h",
|
||||
"filters.cpp",
|
||||
"fonts.cpp",
|
||||
"helpers.h",
|
||||
"image.cpp",
|
||||
"paint.cpp",
|
||||
"path.cpp",
|
||||
"picture.cpp",
|
||||
"shaders.cpp",
|
||||
"skwasm_support.h",
|
||||
"string.cpp",
|
||||
"surface.cpp",
|
||||
"text/line_metrics.cpp",
|
||||
"text/paragraph.cpp",
|
||||
"text/paragraph_builder.cpp",
|
||||
"text/paragraph_style.cpp",
|
||||
"text/strut_style.cpp",
|
||||
"text/text_style.cpp",
|
||||
"vertices.cpp",
|
||||
"wrappers.h",
|
||||
]
|
||||
|
||||
cflags = [ "-mreference-types" ]
|
||||
|
||||
ldflags = [
|
||||
"-std=c++20",
|
||||
"-lGL",
|
||||
"-sUSE_WEBGL2=1",
|
||||
"-sMAX_WEBGL_VERSION=2",
|
||||
"-sOFFSCREENCANVAS_SUPPORT",
|
||||
"-sALLOW_MEMORY_GROWTH",
|
||||
"-sALLOW_TABLE_GROWTH",
|
||||
"-lexports.js",
|
||||
"-sEXPORTED_FUNCTIONS=[stackAlloc]",
|
||||
"-sEXPORTED_RUNTIME_METHODS=[addFunction,wasmExports,wasmMemory,stackAlloc]",
|
||||
"-sINCOMING_MODULE_JS_API=[instantiateWasm,locateFile,noExitRuntime,mainScriptUrlOrBlob,wasmMemory,wasm,skwasmSingleThreaded]",
|
||||
"-sUSE_ES6_IMPORT_META=0",
|
||||
"--js-library",
|
||||
rebase_path("library_skwasm_support.js"),
|
||||
]
|
||||
|
||||
inputs = [ rebase_path("library_skwasm_support.js") ]
|
||||
|
||||
if (is_debug) {
|
||||
ldflags += [
|
||||
"-sASSERTIONS=1",
|
||||
"-sGL_ASSERTIONS=1",
|
||||
"-sSTACK_OVERFLOW_CHECK=2",
|
||||
sources = [
|
||||
"canvas.cpp",
|
||||
"contour_measure.cpp",
|
||||
"data.cpp",
|
||||
"export.h",
|
||||
"filters.cpp",
|
||||
"fonts.cpp",
|
||||
"helpers.h",
|
||||
"image.cpp",
|
||||
"paint.cpp",
|
||||
"path.cpp",
|
||||
"picture.cpp",
|
||||
"shaders.cpp",
|
||||
"skwasm_support.h",
|
||||
"string.cpp",
|
||||
"surface.cpp",
|
||||
"text/line_metrics.cpp",
|
||||
"text/paragraph.cpp",
|
||||
"text/paragraph_builder.cpp",
|
||||
"text/paragraph_style.cpp",
|
||||
"text/strut_style.cpp",
|
||||
"text/text_style.cpp",
|
||||
"vertices.cpp",
|
||||
"wrappers.h",
|
||||
]
|
||||
} else {
|
||||
ldflags += [ "--closure=1" ]
|
||||
}
|
||||
|
||||
deps = [
|
||||
"//flutter/skia",
|
||||
"//flutter/skia/modules/skparagraph",
|
||||
"//flutter/skia/modules/skunicode",
|
||||
]
|
||||
cflags = [ "-mreference-types" ]
|
||||
|
||||
ldflags = [
|
||||
"-std=c++20",
|
||||
"-lGL",
|
||||
"-sUSE_WEBGL2=1",
|
||||
"-sMAX_WEBGL_VERSION=2",
|
||||
"-sOFFSCREENCANVAS_SUPPORT",
|
||||
"-sALLOW_MEMORY_GROWTH",
|
||||
"-sALLOW_TABLE_GROWTH",
|
||||
"-lexports.js",
|
||||
"-sEXPORTED_FUNCTIONS=[stackAlloc]",
|
||||
"-sEXPORTED_RUNTIME_METHODS=[addFunction,wasmExports,wasmMemory,stackAlloc]",
|
||||
"-sINCOMING_MODULE_JS_API=[instantiateWasm,locateFile,noExitRuntime,mainScriptUrlOrBlob,wasmMemory,wasm,skwasmSingleThreaded]",
|
||||
"-sUSE_ES6_IMPORT_META=0",
|
||||
"--js-library",
|
||||
rebase_path("library_skwasm_support.js"),
|
||||
]
|
||||
|
||||
inputs = [ rebase_path("library_skwasm_support.js") ]
|
||||
if (invoker.is_heavy) {
|
||||
sources += [
|
||||
"animated_image.cpp",
|
||||
"text/paragraph_builder_builtin_icu.cpp",
|
||||
]
|
||||
} else {
|
||||
sources += [
|
||||
"animated_image_stub.cpp",
|
||||
"text/paragraph_builder_client_icu.cpp",
|
||||
]
|
||||
}
|
||||
|
||||
if (is_debug) {
|
||||
ldflags += [
|
||||
"-sDEMANGLE_SUPPORT=1",
|
||||
"-sASSERTIONS=1",
|
||||
"-sGL_ASSERTIONS=1",
|
||||
]
|
||||
} else {
|
||||
ldflags += [ "--closure=1" ]
|
||||
}
|
||||
|
||||
deps = [
|
||||
"//flutter/skia",
|
||||
"//flutter/skia/modules/skparagraph",
|
||||
"//flutter/skia/modules/skunicode",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
skwasm_variant("skwasm") {
|
||||
is_heavy = false
|
||||
}
|
||||
|
||||
skwasm_variant("skwasm_heavy") {
|
||||
is_heavy = true
|
||||
}
|
||||
|
||||
77
engine/src/flutter/lib/web_ui/skwasm/animated_image.cpp
Normal file
77
engine/src/flutter/lib/web_ui/skwasm/animated_image.cpp
Normal file
@ -0,0 +1,77 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "export.h"
|
||||
#include "skwasm_support.h"
|
||||
|
||||
#include "third_party/skia/include/android/SkAnimatedImage.h"
|
||||
#include "third_party/skia/include/codec/SkAndroidCodec.h"
|
||||
#include "third_party/skia/include/codec/SkCodec.h"
|
||||
#include "third_party/skia/include/codec/SkGifDecoder.h"
|
||||
#include "third_party/skia/include/codec/SkWebpDecoder.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace {
|
||||
std::unique_ptr<SkCodec> getCodecForData(SkData* data) {
|
||||
if (SkGifDecoder::IsGif(data->data(), data->size())) {
|
||||
return SkGifDecoder::Decode(sk_ref_sp(data), nullptr);
|
||||
}
|
||||
if (SkWebpDecoder::IsWebp(data->data(), data->size())) {
|
||||
return SkWebpDecoder::Decode(sk_ref_sp(data), nullptr);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
SKWASM_EXPORT SkAnimatedImage* animatedImage_create(SkData* data,
|
||||
int targetWidth,
|
||||
int targetHeight) {
|
||||
auto codec = getCodecForData(data);
|
||||
if (!codec) {
|
||||
printf("Failed to create codec for animated image.\n");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto aCodec = SkAndroidCodec::MakeFromCodec(std::move(codec));
|
||||
if (aCodec == nullptr) {
|
||||
printf("Failed to create codec for animated image.\n");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (targetWidth == 0 || targetHeight == 0) {
|
||||
return SkAnimatedImage::Make(std::move(aCodec)).release();
|
||||
}
|
||||
|
||||
return SkAnimatedImage::Make(
|
||||
std::move(aCodec),
|
||||
SkImageInfo::MakeUnknown(targetWidth, targetHeight),
|
||||
SkIRect::MakeWH(targetWidth, targetHeight), nullptr)
|
||||
.release();
|
||||
}
|
||||
|
||||
SKWASM_EXPORT void animatedImage_dispose(SkAnimatedImage* image) {
|
||||
image->unref();
|
||||
}
|
||||
|
||||
SKWASM_EXPORT int animatedImage_getFrameCount(SkAnimatedImage* image) {
|
||||
return image->getFrameCount();
|
||||
}
|
||||
|
||||
SKWASM_EXPORT int animatedImage_getRepetitionCount(SkAnimatedImage* image) {
|
||||
return image->getRepetitionCount();
|
||||
}
|
||||
|
||||
SKWASM_EXPORT int animatedImage_getCurrentFrameDurationMilliseconds(
|
||||
SkAnimatedImage* image) {
|
||||
return image->currentFrameDuration();
|
||||
}
|
||||
|
||||
SKWASM_EXPORT void animatedImage_decodeNextFrame(SkAnimatedImage* image) {
|
||||
image->decodeNextFrame();
|
||||
}
|
||||
|
||||
SKWASM_EXPORT SkImage* animatedImage_getCurrentFrame(SkAnimatedImage* image) {
|
||||
return image->getCurrentFrame().release();
|
||||
}
|
||||
49
engine/src/flutter/lib/web_ui/skwasm/animated_image_stub.cpp
Normal file
49
engine/src/flutter/lib/web_ui/skwasm/animated_image_stub.cpp
Normal file
@ -0,0 +1,49 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "export.h"
|
||||
#include "skwasm_support.h"
|
||||
|
||||
SKWASM_EXPORT void* animatedImage_create(SkData* data,
|
||||
int targetWidth,
|
||||
int targetHeight) {
|
||||
emscripten_console_warn(
|
||||
"Animated image not implemented in non-heavy skwasm build.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SKWASM_EXPORT void animatedImage_dispose(void* image) {
|
||||
emscripten_console_warn(
|
||||
"Animated image not implemented in non-heavy skwasm build.");
|
||||
}
|
||||
|
||||
SKWASM_EXPORT int animatedImage_getFrameCount(void* image) {
|
||||
emscripten_console_warn(
|
||||
"Animated image not implemented in non-heavy skwasm build.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
SKWASM_EXPORT int animatedImage_getRepetitionCount(void* image) {
|
||||
emscripten_console_warn(
|
||||
"Animated image not implemented in non-heavy skwasm build.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
SKWASM_EXPORT int animatedImage_getCurrentFrameDurationMilliseconds(
|
||||
void* image) {
|
||||
emscripten_console_warn(
|
||||
"Animated image not implemented in non-heavy skwasm build.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
SKWASM_EXPORT void animatedImage_decodeNextFrame(void* image) {
|
||||
emscripten_console_warn(
|
||||
"Animated image not implemented in non-heavy skwasm build.");
|
||||
}
|
||||
|
||||
SKWASM_EXPORT void* animatedImage_getCurrentFrame(void* image) {
|
||||
emscripten_console_warn(
|
||||
"Animated image not implemented in non-heavy skwasm build.");
|
||||
return nullptr;
|
||||
}
|
||||
@ -10,13 +10,6 @@
|
||||
using namespace skia::textlayout;
|
||||
using namespace Skwasm;
|
||||
|
||||
SKWASM_EXPORT ParagraphBuilder* paragraphBuilder_create(
|
||||
ParagraphStyle* style,
|
||||
FlutterFontCollection* collection) {
|
||||
return ParagraphBuilder::make(*style, collection->collection, nullptr)
|
||||
.release();
|
||||
}
|
||||
|
||||
SKWASM_EXPORT void paragraphBuilder_dispose(ParagraphBuilder* builder) {
|
||||
delete builder;
|
||||
}
|
||||
@ -53,15 +46,6 @@ SKWASM_EXPORT void paragraphBuilder_pop(ParagraphBuilder* builder) {
|
||||
builder->pop();
|
||||
}
|
||||
|
||||
SKWASM_EXPORT Paragraph* paragraphBuilder_build(ParagraphBuilder* builder) {
|
||||
auto [words, graphemeBreaks, lineBreaks] = builder->getClientICUData();
|
||||
auto text = builder->getText();
|
||||
sk_sp<SkUnicode> clientICU =
|
||||
SkUnicodes::Client::Make(text, words, graphemeBreaks, lineBreaks);
|
||||
builder->SetUnicode(clientICU);
|
||||
return builder->Build().release();
|
||||
}
|
||||
|
||||
SKWASM_EXPORT std::vector<SkUnicode::Position>* unicodePositionBuffer_create(
|
||||
size_t length) {
|
||||
return new std::vector<SkUnicode::Position>(length);
|
||||
@ -92,21 +76,3 @@ SKWASM_EXPORT void lineBreakBuffer_free(
|
||||
std::vector<SkUnicode::LineBreakBefore>* buffer) {
|
||||
delete buffer;
|
||||
}
|
||||
|
||||
SKWASM_EXPORT void paragraphBuilder_setGraphemeBreaksUtf16(
|
||||
ParagraphBuilder* builder,
|
||||
std::vector<SkUnicode::Position>* breaks) {
|
||||
builder->setGraphemeBreaksUtf16(std::move(*breaks));
|
||||
}
|
||||
|
||||
SKWASM_EXPORT void paragraphBuilder_setWordBreaksUtf16(
|
||||
ParagraphBuilder* builder,
|
||||
std::vector<SkUnicode::Position>* breaks) {
|
||||
builder->setWordsUtf16(std::move(*breaks));
|
||||
}
|
||||
|
||||
SKWASM_EXPORT void paragraphBuilder_setLineBreaksUtf16(
|
||||
ParagraphBuilder* builder,
|
||||
std::vector<SkUnicode::LineBreakBefore>* breaks) {
|
||||
builder->setLineBreaksUtf16(std::move(*breaks));
|
||||
}
|
||||
|
||||
@ -0,0 +1,48 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "../export.h"
|
||||
#include "../wrappers.h"
|
||||
#include "modules/skunicode/include/SkUnicode_icu.h"
|
||||
#include "third_party/skia/modules/skparagraph/include/ParagraphBuilder.h"
|
||||
|
||||
using namespace skia::textlayout;
|
||||
using namespace Skwasm;
|
||||
|
||||
SKWASM_EXPORT bool skwasm_isHeavy() {
|
||||
return true;
|
||||
}
|
||||
|
||||
SKWASM_EXPORT ParagraphBuilder* paragraphBuilder_create(
|
||||
ParagraphStyle* style,
|
||||
FlutterFontCollection* collection) {
|
||||
return ParagraphBuilder::make(*style, collection->collection,
|
||||
SkUnicodes::ICU::Make())
|
||||
.release();
|
||||
}
|
||||
|
||||
SKWASM_EXPORT Paragraph* paragraphBuilder_build(ParagraphBuilder* builder) {
|
||||
return builder->Build().release();
|
||||
}
|
||||
|
||||
SKWASM_EXPORT void paragraphBuilder_setGraphemeBreaksUtf16(
|
||||
ParagraphBuilder* builder,
|
||||
std::vector<SkUnicode::Position>* breaks) {
|
||||
emscripten_console_warn(
|
||||
"warning: setGraphemeBreaksUtf16 not implemented in skwasm_heavy\n");
|
||||
}
|
||||
|
||||
SKWASM_EXPORT void paragraphBuilder_setWordBreaksUtf16(
|
||||
ParagraphBuilder* builder,
|
||||
std::vector<SkUnicode::Position>* breaks) {
|
||||
emscripten_console_warn(
|
||||
"warning: setWordBreaksUtf16 not implemented in skwasm_heavy\n");
|
||||
}
|
||||
|
||||
SKWASM_EXPORT void paragraphBuilder_setLineBreaksUtf16(
|
||||
ParagraphBuilder* builder,
|
||||
std::vector<SkUnicode::LineBreakBefore>* breaks) {
|
||||
emscripten_console_warn(
|
||||
"warning: setLineBreaksUtf16 not implemented in skwasm_heavy\n");
|
||||
}
|
||||
@ -0,0 +1,49 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "../export.h"
|
||||
#include "../wrappers.h"
|
||||
#include "third_party/skia/modules/skparagraph/include/ParagraphBuilder.h"
|
||||
#include "third_party/skia/modules/skunicode/include/SkUnicode_client.h"
|
||||
|
||||
using namespace skia::textlayout;
|
||||
using namespace Skwasm;
|
||||
|
||||
SKWASM_EXPORT bool skwasm_isHeavy() {
|
||||
return false;
|
||||
}
|
||||
|
||||
SKWASM_EXPORT ParagraphBuilder* paragraphBuilder_create(
|
||||
ParagraphStyle* style,
|
||||
FlutterFontCollection* collection) {
|
||||
return ParagraphBuilder::make(*style, collection->collection, nullptr)
|
||||
.release();
|
||||
}
|
||||
|
||||
SKWASM_EXPORT Paragraph* paragraphBuilder_build(ParagraphBuilder* builder) {
|
||||
auto [words, graphemeBreaks, lineBreaks] = builder->getClientICUData();
|
||||
auto text = builder->getText();
|
||||
sk_sp<SkUnicode> clientICU =
|
||||
SkUnicodes::Client::Make(text, words, graphemeBreaks, lineBreaks);
|
||||
builder->SetUnicode(clientICU);
|
||||
return builder->Build().release();
|
||||
}
|
||||
|
||||
SKWASM_EXPORT void paragraphBuilder_setGraphemeBreaksUtf16(
|
||||
ParagraphBuilder* builder,
|
||||
std::vector<SkUnicode::Position>* breaks) {
|
||||
builder->setGraphemeBreaksUtf16(std::move(*breaks));
|
||||
}
|
||||
|
||||
SKWASM_EXPORT void paragraphBuilder_setWordBreaksUtf16(
|
||||
ParagraphBuilder* builder,
|
||||
std::vector<SkUnicode::Position>* breaks) {
|
||||
builder->setWordsUtf16(std::move(*breaks));
|
||||
}
|
||||
|
||||
SKWASM_EXPORT void paragraphBuilder_setLineBreaksUtf16(
|
||||
ParagraphBuilder* builder,
|
||||
std::vector<SkUnicode::LineBreakBefore>* breaks) {
|
||||
builder->setLineBreaksUtf16(std::move(*breaks));
|
||||
}
|
||||
@ -99,10 +99,23 @@ run-configs:
|
||||
browser: firefox
|
||||
canvaskit-variant: full
|
||||
|
||||
- name: firefox-wasm
|
||||
browser: firefox
|
||||
canvaskit-variant: full
|
||||
wasm-allow-list:
|
||||
gecko: true
|
||||
|
||||
- name: safari
|
||||
browser: safari
|
||||
canvaskit-variant: full
|
||||
|
||||
- name: safari-wasm
|
||||
browser: safari
|
||||
canvaskit-variant: full
|
||||
wasm-allow-list:
|
||||
webkit: true
|
||||
|
||||
|
||||
test-suites:
|
||||
- name: chrome-dart2js-experimental-webparagraph-ui
|
||||
test-bundle: dart2js-canvaskit-ui
|
||||
@ -175,6 +188,12 @@ test-suites:
|
||||
run-config: firefox
|
||||
artifact-deps: [ canvaskit ]
|
||||
|
||||
- name: firefox-dart2wasm-skwasm-ui
|
||||
test-bundle: dart2wasm-skwasm-ui
|
||||
run-config: firefox-wasm
|
||||
artifact-deps: [ skwasm ]
|
||||
enable-ci: false
|
||||
|
||||
- name: safari-dart2js-canvaskit-engine
|
||||
test-bundle: dart2js-canvaskit-engine
|
||||
run-config: safari
|
||||
@ -190,11 +209,28 @@ test-suites:
|
||||
run-config: safari
|
||||
artifact-deps: [ canvaskit ]
|
||||
|
||||
- name: safari-dart2wasm-canvaskit-engine
|
||||
test-bundle: dart2wasm-canvaskit-engine
|
||||
run-config: safari-wasm
|
||||
artifact-deps: [ canvaskit ]
|
||||
enable-ci: false
|
||||
|
||||
- name: safari-dart2wasm-skwasm-ui
|
||||
test-bundle: dart2wasm-skwasm-ui
|
||||
run-config: safari-wasm
|
||||
artifact-deps: [ skwasm ]
|
||||
enable-ci: false
|
||||
|
||||
- name: chrome-dart2wasm-canvaskit-engine
|
||||
test-bundle: dart2wasm-canvaskit-engine
|
||||
run-config: chrome
|
||||
artifact-deps: [ canvaskit_chromium ]
|
||||
|
||||
- name: firefox-dart2wasm-canvaskit-engine
|
||||
test-bundle: dart2wasm-canvaskit-engine
|
||||
run-config: firefox-wasm
|
||||
artifact-deps: [ canvaskit ]
|
||||
|
||||
- name: chrome-coi-dart2wasm-skwasm-ui
|
||||
test-bundle: dart2wasm-skwasm-ui
|
||||
run-config: chrome-coi
|
||||
|
||||
@ -73,7 +73,6 @@ Future<void> testMain() async {
|
||||
});
|
||||
|
||||
const ui.Rect drawRegion = ui.Rect.fromLTWH(0, 0, 300, 300);
|
||||
const ui.Rect imageRegion = ui.Rect.fromLTWH(0, 0, 150, 150);
|
||||
|
||||
// Emits a set of rendering tests for an image
|
||||
// `imageGenerator` should produce an image that is 150x150 pixels.
|
||||
@ -126,7 +125,12 @@ Future<void> testMain() async {
|
||||
|
||||
final ui.PictureRecorder recorder = ui.PictureRecorder();
|
||||
final ui.Canvas canvas = ui.Canvas(recorder, drawRegion);
|
||||
const ui.Rect srcRect = ui.Rect.fromLTRB(50, 50, 100, 100);
|
||||
final ui.Rect srcRect = ui.Rect.fromLTRB(
|
||||
image.width / 3,
|
||||
image.height / 3,
|
||||
2 * image.width / 3,
|
||||
2 * image.height / 3,
|
||||
);
|
||||
canvas.drawImageRect(
|
||||
image,
|
||||
srcRect,
|
||||
@ -159,15 +163,16 @@ Future<void> testMain() async {
|
||||
|
||||
test('drawImageNine', () async {
|
||||
final ui.Image image = await generateImage();
|
||||
final ui.Rect srcRect = ui.Rect.fromLTRB(
|
||||
image.width / 3,
|
||||
image.height / 3,
|
||||
2 * image.width / 3,
|
||||
2 * image.height / 3,
|
||||
);
|
||||
|
||||
final ui.PictureRecorder recorder = ui.PictureRecorder();
|
||||
final ui.Canvas canvas = ui.Canvas(recorder, drawRegion);
|
||||
canvas.drawImageNine(
|
||||
image,
|
||||
const ui.Rect.fromLTRB(50, 50, 100, 100),
|
||||
drawRegion,
|
||||
ui.Paint(),
|
||||
);
|
||||
canvas.drawImageNine(image, srcRect, drawRegion, ui.Paint());
|
||||
|
||||
await drawPictureUsingCurrentRenderer(recorder.endRecording());
|
||||
|
||||
@ -253,10 +258,22 @@ Future<void> testMain() async {
|
||||
ui.Offset(0, 100),
|
||||
ui.Offset(0, 50),
|
||||
];
|
||||
final double imageWidth = image.width.toDouble();
|
||||
final double imageHeight = image.height.toDouble();
|
||||
final List<ui.Offset> texCoords = <ui.Offset>[
|
||||
ui.Offset(imageWidth / 3, 0),
|
||||
ui.Offset(2 * imageWidth / 3, 0),
|
||||
ui.Offset(imageWidth, imageHeight / 3),
|
||||
ui.Offset(imageWidth, 2 * imageHeight / 3),
|
||||
ui.Offset(2 * imageWidth / 3, imageHeight),
|
||||
ui.Offset(imageWidth / 3, imageHeight),
|
||||
ui.Offset(0, 2 * imageHeight / 3),
|
||||
ui.Offset(0, imageHeight / 3),
|
||||
];
|
||||
final ui.Vertices vertices = ui.Vertices(
|
||||
ui.VertexMode.triangles,
|
||||
vertexValues,
|
||||
textureCoordinates: vertexValues,
|
||||
textureCoordinates: texCoords,
|
||||
indices: <int>[
|
||||
0, 1, 2, //
|
||||
0, 2, 3, //
|
||||
@ -299,7 +316,7 @@ Future<void> testMain() async {
|
||||
|
||||
emitImageTests('picture_toImage', () {
|
||||
final ui.PictureRecorder recorder = ui.PictureRecorder();
|
||||
final ui.Canvas canvas = ui.Canvas(recorder, imageRegion);
|
||||
final ui.Canvas canvas = ui.Canvas(recorder, const ui.Rect.fromLTWH(0, 0, 150, 150));
|
||||
for (int y = 0; y < 15; y++) {
|
||||
for (int x = 0; x < 15; x++) {
|
||||
final ui.Offset center = ui.Offset(x * 10 + 5, y * 10 + 5);
|
||||
@ -488,4 +505,57 @@ Future<void> testMain() async {
|
||||
codec.dispose();
|
||||
return info.image;
|
||||
});
|
||||
|
||||
emitImageTests('animated_gif_list', () async {
|
||||
final ByteBuffer data = await httpFetchByteBuffer('/test_images/alphabetAnim.gif');
|
||||
final ui.Codec codec = await renderer.instantiateImageCodec(data.asUint8List());
|
||||
expect(codec.frameCount, 13);
|
||||
|
||||
// The second frame of this gif is more interesting to test than the first,
|
||||
// so skip the first frame.
|
||||
await codec.getNextFrame();
|
||||
final ui.FrameInfo info = await codec.getNextFrame();
|
||||
codec.dispose();
|
||||
return info.image;
|
||||
});
|
||||
|
||||
emitImageTests('animated_webp_list', () async {
|
||||
final ByteBuffer data = await httpFetchByteBuffer('/test_images/stoplight.webp');
|
||||
final ui.Codec codec = await renderer.instantiateImageCodec(data.asUint8List());
|
||||
expect(codec.frameCount, 3);
|
||||
|
||||
final ui.FrameInfo info = await codec.getNextFrame();
|
||||
codec.dispose();
|
||||
return info.image;
|
||||
});
|
||||
|
||||
if (!isCanvasKit) {
|
||||
// CanvasKit doesn't do the correct thing for animated images for the
|
||||
// `instantiateImageCodecFromUrl` code path.
|
||||
// See https://github.com/flutter/flutter/issues/166803
|
||||
emitImageTests('animated_gif_uri', () async {
|
||||
final ui.Codec codec = await renderer.instantiateImageCodecFromUrl(
|
||||
Uri(path: '/test_images/alphabetAnim.gif'),
|
||||
);
|
||||
expect(codec.frameCount, 13);
|
||||
|
||||
// The second frame of this gif is more interesting to test than the first,
|
||||
// so skip the first frame.
|
||||
await codec.getNextFrame();
|
||||
final ui.FrameInfo info = await codec.getNextFrame();
|
||||
codec.dispose();
|
||||
return info.image;
|
||||
});
|
||||
|
||||
emitImageTests('animated_webp_uri', () async {
|
||||
final ui.Codec codec = await renderer.instantiateImageCodecFromUrl(
|
||||
Uri(path: '/test_images/stoplight.webp'),
|
||||
);
|
||||
expect(codec.frameCount, 3);
|
||||
|
||||
final ui.FrameInfo info = await codec.getNextFrame();
|
||||
codec.dispose();
|
||||
return info.image;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -110,28 +110,42 @@ copy("canvaskit_experimental_webparagraph_group") {
|
||||
}
|
||||
|
||||
# This toolchain is only to be used by skwasm_group below.
|
||||
wasm_toolchain("skwasm") {
|
||||
extra_toolchain_args = {
|
||||
# In Chromium browsers, we can use the browser's APIs to get the necessary
|
||||
# ICU data.
|
||||
skia_use_icu = false
|
||||
skia_use_client_icu = true
|
||||
skia_icu_bidi_third_party_dir = "//flutter/third_party/canvaskit/icu_bidi"
|
||||
template("skwasm_toolchain") {
|
||||
assert(defined(invoker.skwasm_is_heavy))
|
||||
forward_variables_from(invoker, ["skwasm_is_mt", "skwasm_is_heavy"])
|
||||
wasm_toolchain(target_name) {
|
||||
extra_toolchain_args = {
|
||||
# In Chromium browsers, we can use the browser's APIs to get the necessary
|
||||
# ICU data. So we use built-in ICU data only in the heavy (non-chromium) case
|
||||
skia_use_icu = skwasm_is_heavy
|
||||
skia_use_client_icu = !skwasm_is_heavy
|
||||
if (!skwasm_is_heavy) {
|
||||
skia_icu_bidi_third_party_dir = "//flutter/third_party/canvaskit/icu_bidi"
|
||||
}
|
||||
|
||||
skia_use_libjpeg_turbo_decode = false
|
||||
skia_use_libpng_decode = false
|
||||
skia_use_libwebp_decode = false
|
||||
skia_use_libjpeg_turbo_decode = skwasm_is_heavy
|
||||
skia_use_libpng_decode = skwasm_is_heavy
|
||||
skia_use_libwebp_decode = skwasm_is_heavy
|
||||
|
||||
# We use OffscreenCanvas to produce PNG data instead of skia
|
||||
skia_use_no_png_encode = true
|
||||
skia_use_libpng_encode = false
|
||||
# We use OffscreenCanvas to produce PNG data instead of skia
|
||||
skia_use_no_png_encode = true
|
||||
skia_use_libpng_encode = false
|
||||
|
||||
# skwasm is multithreaded
|
||||
wasm_use_workers = true
|
||||
wasm_prioritize_size = true
|
||||
# skwasm is multithreaded
|
||||
wasm_use_workers = true
|
||||
wasm_prioritize_size = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
skwasm_toolchain("skwasm") {
|
||||
skwasm_is_heavy = false
|
||||
}
|
||||
|
||||
skwasm_toolchain("skwasm_heavy") {
|
||||
skwasm_is_heavy = true
|
||||
}
|
||||
|
||||
copy("skwasm_group") {
|
||||
visibility = [ "//flutter/web_sdk:*" ]
|
||||
public_deps = [ "//flutter/lib/web_ui/skwasm(:skwasm)" ]
|
||||
@ -148,3 +162,20 @@ copy("skwasm_group") {
|
||||
}
|
||||
outputs = [ "$root_out_dir/flutter_web_sdk/canvaskit/{{source_file_part}}" ]
|
||||
}
|
||||
|
||||
copy("skwasm_heavy_group") {
|
||||
visibility = [ "//flutter/web_sdk:*" ]
|
||||
public_deps = [ "//flutter/lib/web_ui/skwasm:skwasm_heavy(:skwasm_heavy)" ]
|
||||
|
||||
sources = [
|
||||
"$root_out_dir/skwasm_heavy/skwasm_heavy.js",
|
||||
"$root_out_dir/skwasm_heavy/skwasm_heavy.js.symbols",
|
||||
"$root_out_dir/skwasm_heavy/skwasm_heavy.wasm",
|
||||
]
|
||||
if (is_debug) {
|
||||
if (!wasm_use_dwarf) {
|
||||
sources += [ "$root_out_dir/skwasm_heavy/skwasm_heavy.wasm.map" ]
|
||||
}
|
||||
}
|
||||
outputs = [ "$root_out_dir/flutter_web_sdk/canvaskit/{{source_file_part}}" ]
|
||||
}
|
||||
|
||||
@ -414,6 +414,7 @@ if (!is_fuchsia) {
|
||||
"//flutter/third_party/canvaskit:canvaskit_chromium_group",
|
||||
"//flutter/third_party/canvaskit:canvaskit_group",
|
||||
"//flutter/third_party/canvaskit:skwasm_group",
|
||||
"//flutter/third_party/canvaskit:skwasm_heavy_group",
|
||||
]
|
||||
}
|
||||
deps += [ "//flutter/lib/web_ui/flutter_js" ]
|
||||
@ -438,6 +439,9 @@ if (!is_fuchsia) {
|
||||
"$root_out_dir/flutter_web_sdk/canvaskit/skwasm.js",
|
||||
"$root_out_dir/flutter_web_sdk/canvaskit/skwasm.js.symbols",
|
||||
"$root_out_dir/flutter_web_sdk/canvaskit/skwasm.wasm",
|
||||
"$root_out_dir/flutter_web_sdk/canvaskit/skwasm_heavy.js",
|
||||
"$root_out_dir/flutter_web_sdk/canvaskit/skwasm_heavy.js.symbols",
|
||||
"$root_out_dir/flutter_web_sdk/canvaskit/skwasm_heavy.wasm",
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@ -200,11 +200,6 @@ MultiChannel<dynamic> _connectToServer() {
|
||||
StreamChannel<dynamic> _connectToIframe(String url, int id) {
|
||||
final DomHTMLIFrameElement iframe = createDomHTMLIFrameElement();
|
||||
_iframes[id] = iframe;
|
||||
iframe
|
||||
..src = url
|
||||
..width = '1000'
|
||||
..height = '1000';
|
||||
domDocument.body!.appendChild(iframe);
|
||||
|
||||
final StreamChannelController<dynamic> controller = StreamChannelController<dynamic>(sync: true);
|
||||
|
||||
@ -225,14 +220,6 @@ StreamChannel<dynamic> _connectToIframe(String url, int id) {
|
||||
if (message.origin != domWindow.location.origin) {
|
||||
return;
|
||||
}
|
||||
// We have to do these ugly casts because the message is cross-origin
|
||||
// which isn't handled cleanly by dart:js_interop.
|
||||
if (((message.source as DomMessageEventSource?)?.location as DomMessageEventLocation?)
|
||||
?.href !=
|
||||
iframe.src) {
|
||||
return;
|
||||
}
|
||||
|
||||
message.stopPropagation();
|
||||
|
||||
if (message.data == 'port') {
|
||||
@ -277,5 +264,11 @@ StreamChannel<dynamic> _connectToIframe(String url, int id) {
|
||||
),
|
||||
);
|
||||
|
||||
iframe
|
||||
..src = url
|
||||
..width = '1000'
|
||||
..height = '1000';
|
||||
domDocument.body!.appendChild(iframe);
|
||||
|
||||
return controller.foreign;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user