Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 9b4dd0d

Browse files
authored
Merge branch 'main' into fix-some-issues-vk
2 parents 2cdd7f1 + 584144d commit 9b4dd0d

File tree

5 files changed

+157
-19
lines changed

5 files changed

+157
-19
lines changed

lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart

Lines changed: 64 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import 'package:ui/ui.dart' as ui;
2121
import '../configuration.dart';
2222
import '../dom.dart';
2323
import '../profiler.dart';
24+
import 'renderer.dart';
2425

2526
/// Entrypoint into the CanvasKit API.
2627
late CanvasKit canvasKit;
@@ -2678,45 +2679,90 @@ void patchCanvasKitModule(DomHTMLScriptElement canvasKitScript) {
26782679
js_util.callMethod(objectConstructor,
26792680
'defineProperty', <dynamic>[domWindow, 'module', moduleAccessor]);
26802681
}
2681-
domDocument.head!.appendChild(canvasKitScript);
26822682
}
26832683

2684-
String get canvasKitBuildUrl => configuration.canvasKitBaseUrl;
2685-
String get canvasKitJavaScriptBindingsUrl =>
2686-
'${canvasKitBuildUrl}canvaskit.js';
2687-
String canvasKitWasmModuleUrl(String canvasKitBase, String file) =>
2684+
const String _kFullCanvasKitJsFileName = 'canvaskit.js';
2685+
const String _kChromiumCanvasKitJsFileName = 'chromium/canvaskit.js';
2686+
2687+
String get _canvasKitBaseUrl => configuration.canvasKitBaseUrl;
2688+
List<String> get _canvasKitJsFileNames {
2689+
switch (configuration.canvasKitVariant) {
2690+
case CanvasKitVariant.auto:
2691+
return <String>[
2692+
if (browserSupportsCanvaskitChromium) _kChromiumCanvasKitJsFileName,
2693+
_kFullCanvasKitJsFileName,
2694+
];
2695+
case CanvasKitVariant.full:
2696+
return <String>[_kFullCanvasKitJsFileName];
2697+
case CanvasKitVariant.chromium:
2698+
return <String>[_kChromiumCanvasKitJsFileName];
2699+
}
2700+
}
2701+
Iterable<String> get _canvasKitJsUrls {
2702+
return _canvasKitJsFileNames.map((String filename) => '$_canvasKitBaseUrl$filename');
2703+
}
2704+
String canvasKitWasmModuleUrl(String file, String canvasKitBase) =>
26882705
canvasKitBase + file;
26892706

26902707
/// Download and initialize the CanvasKit module.
26912708
///
26922709
/// Downloads the CanvasKit JavaScript, then calls `CanvasKitInit` to download
26932710
/// and intialize the CanvasKit wasm.
26942711
Future<CanvasKit> downloadCanvasKit() async {
2695-
await _downloadCanvasKitJs();
2712+
await _downloadOneOf(_canvasKitJsUrls);
26962713

26972714
return CanvasKitInit(CanvasKitInitOptions(
2698-
locateFile: allowInterop((String file, String unusedBase) =>
2699-
canvasKitWasmModuleUrl(canvasKitBuildUrl, file)),
2715+
locateFile: allowInterop(canvasKitWasmModuleUrl),
27002716
));
27012717
}
27022718

2703-
/// Downloads the CanvasKit JavaScript file at [canvasKitBase].
2704-
Future<void> _downloadCanvasKitJs() {
2705-
final String canvasKitJavaScriptUrl = canvasKitJavaScriptBindingsUrl;
2719+
/// Finds the first URL in [urls] that can be downloaded successfully, and
2720+
/// downloads it.
2721+
///
2722+
/// If none of the URLs can be downloaded, throws an [Exception].
2723+
Future<void> _downloadOneOf(Iterable<String> urls) async {
2724+
for (final String url in urls) {
2725+
if (await _downloadCanvasKitJs(url)) {
2726+
return;
2727+
}
2728+
}
27062729

2730+
// Reaching this point means that all URLs failed to download.
2731+
throw Exception(
2732+
'Failed to download any of the following CanvasKit URLs: $urls',
2733+
);
2734+
}
2735+
2736+
/// Downloads the CanvasKit JavaScript file at [url].
2737+
///
2738+
/// Returns a [Future] that completes with `true` if the CanvasKit JavaScript
2739+
/// file was successfully downloaded, or `false` if it failed.
2740+
Future<bool> _downloadCanvasKitJs(String url) {
27072741
final DomHTMLScriptElement canvasKitScript = createDomHTMLScriptElement();
2708-
canvasKitScript.src = createTrustedScriptUrl(canvasKitJavaScriptUrl);
2742+
canvasKitScript.src = createTrustedScriptUrl(url);
2743+
2744+
final Completer<bool> canvasKitLoadCompleter = Completer<bool>();
2745+
2746+
late final DomEventListener loadCallback;
2747+
late final DomEventListener errorCallback;
27092748

2710-
final Completer<void> canvasKitLoadCompleter = Completer<void>();
2711-
late DomEventListener callback;
27122749
void loadEventHandler(DomEvent _) {
2713-
canvasKitLoadCompleter.complete();
2714-
canvasKitScript.removeEventListener('load', callback);
2750+
canvasKitScript.remove();
2751+
canvasKitLoadCompleter.complete(true);
27152752
}
2716-
callback = allowInterop(loadEventHandler);
2717-
canvasKitScript.addEventListener('load', callback);
2753+
void errorEventHandler(DomEvent errorEvent) {
2754+
canvasKitScript.remove();
2755+
canvasKitLoadCompleter.complete(false);
2756+
}
2757+
2758+
loadCallback = allowInterop(loadEventHandler);
2759+
errorCallback = allowInterop(errorEventHandler);
2760+
2761+
canvasKitScript.addEventListener('load', loadCallback);
2762+
canvasKitScript.addEventListener('error', errorCallback);
27182763

27192764
patchCanvasKitModule(canvasKitScript);
2765+
domDocument.head!.appendChild(canvasKitScript);
27202766

27212767
return canvasKitLoadCompleter.future;
27222768
}

lib/web_ui/lib/src/engine/canvaskit/renderer.dart

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,22 @@ const bool browserSupportsCanvaskitChromium = false;
3535
// CanvasKit to download.
3636
// final bool browserSupportsCanvaskitChromium = domIntl.v8BreakIterator != null;
3737

38+
enum CanvasKitVariant {
39+
/// The appropriate variant is chosen based on the browser.
40+
///
41+
/// This is the default variant.
42+
auto,
43+
44+
/// The full variant that can be used in any browser.
45+
full,
46+
47+
/// The variant that is optimized for Chromium browsers.
48+
///
49+
/// WARNING: In most cases, you should use [auto] instead of this variant. Using
50+
/// this variant in a non-Chromium browser will result in a broken app.
51+
chromium,
52+
}
53+
3854
class CanvasKitRenderer implements Renderer {
3955
static CanvasKitRenderer get instance => _instance;
4056
static late CanvasKitRenderer _instance;

lib/web_ui/lib/src/engine/configuration.dart

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ library configuration;
4646

4747
import 'package:js/js.dart';
4848
import 'package:meta/meta.dart';
49+
import 'canvaskit/renderer.dart';
4950
import 'dom.dart';
5051

5152
/// The version of CanvasKit used by the web engine by default.
@@ -156,7 +157,8 @@ class FlutterConfiguration {
156157
// runtime. Runtime-supplied values take precedence over environment
157158
// variables.
158159

159-
/// The URL to use when downloading the CanvasKit script and associated wasm.
160+
/// The base URL to use when downloading the CanvasKit script and associated
161+
/// wasm.
160162
///
161163
/// The expected directory structure nested under this URL is as follows:
162164
///
@@ -183,6 +185,22 @@ class FlutterConfiguration {
183185
defaultValue: 'https://unpkg.com/canvaskit-wasm@$_canvaskitVersion/bin/',
184186
);
185187

188+
/// The variant of CanvasKit to download.
189+
///
190+
/// Available values are:
191+
///
192+
/// * `auto` - the default value. The engine will automatically detect the
193+
/// best variant to use based on the browser.
194+
///
195+
/// * `full` - the full variant of CanvasKit that can be used in any browser.
196+
///
197+
/// * `chromium` - the lite variant of CanvasKit that can be used in
198+
/// Chromium-based browsers.
199+
CanvasKitVariant get canvasKitVariant {
200+
final String variant = _configuration?.canvasKitVariant ?? 'auto';
201+
return CanvasKitVariant.values.byName(variant);
202+
}
203+
186204
/// If set to true, forces CPU-only rendering in CanvasKit (i.e. the engine
187205
/// won't use WebGL).
188206
///
@@ -249,6 +267,7 @@ class JsFlutterConfiguration {}
249267

250268
extension JsFlutterConfigurationExtension on JsFlutterConfiguration {
251269
external String? get canvasKitBaseUrl;
270+
external String? get canvasKitVariant;
252271
external bool? get canvasKitForceCpuOnly;
253272
external double? get canvasKitMaximumSurfaces;
254273
external bool? get debugShowSemanticsNodes;

lib/web_ui/test/canvaskit/canvaskit_api_test.dart

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1826,4 +1826,19 @@ void _paragraphTests() {
18261826

18271827
expect(surface, isNotNull);
18281828
}, skip: isFirefox); // Intended: Headless firefox has no webgl support https://github.com/flutter/flutter/issues/109265
1829+
1830+
test('respects actual location of canvaskit files', () {
1831+
expect(
1832+
canvasKitWasmModuleUrl('canvaskit.wasm', 'https://example.com/'),
1833+
'https://example.com/canvaskit.wasm',
1834+
);
1835+
expect(
1836+
canvasKitWasmModuleUrl('canvaskit.wasm', 'http://localhost:1234/'),
1837+
'http://localhost:1234/canvaskit.wasm',
1838+
);
1839+
expect(
1840+
canvasKitWasmModuleUrl('canvaskit.wasm', 'http://localhost:1234/foo/'),
1841+
'http://localhost:1234/foo/canvaskit.wasm',
1842+
);
1843+
});
18291844
}

lib/web_ui/test/engine/configuration_test.dart

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,4 +60,46 @@ void testMain() {
6060
expect(config.canvasKitMaximumSurfaces, 16);
6161
});
6262
});
63+
64+
group('CanvasKit config', () {
65+
test('default canvasKitVariant', () {
66+
final FlutterConfiguration config = FlutterConfiguration();
67+
68+
expect(config.canvasKitVariant, CanvasKitVariant.auto);
69+
});
70+
71+
test('default canvasKitVariant when it is undefined', () {
72+
final FlutterConfiguration config = FlutterConfiguration();
73+
config.setUserConfiguration(
74+
// With an empty map, the canvasKitVariant is undefined in JS.
75+
js_util.jsify(<String, Object?>{}) as JsFlutterConfiguration,
76+
);
77+
78+
expect(config.canvasKitVariant, CanvasKitVariant.auto);
79+
});
80+
81+
test('validates canvasKitVariant', () {
82+
final FlutterConfiguration config = FlutterConfiguration();
83+
84+
config.setUserConfiguration(
85+
js_util.jsify(<String, Object?>{'canvasKitVariant': 'foo'}) as JsFlutterConfiguration,
86+
);
87+
expect(() => config.canvasKitVariant, throwsArgumentError);
88+
89+
config.setUserConfiguration(
90+
js_util.jsify(<String, Object?>{'canvasKitVariant': 'auto'}) as JsFlutterConfiguration,
91+
);
92+
expect(config.canvasKitVariant, CanvasKitVariant.auto);
93+
94+
config.setUserConfiguration(
95+
js_util.jsify(<String, Object?>{'canvasKitVariant': 'full'}) as JsFlutterConfiguration,
96+
);
97+
expect(config.canvasKitVariant, CanvasKitVariant.full);
98+
99+
config.setUserConfiguration(
100+
js_util.jsify(<String, Object?>{'canvasKitVariant': 'chromium'}) as JsFlutterConfiguration,
101+
);
102+
expect(config.canvasKitVariant, CanvasKitVariant.chromium);
103+
});
104+
});
63105
}

0 commit comments

Comments
 (0)