diff --git a/lib/web_ui/lib/src/engine/browser_detection.dart b/lib/web_ui/lib/src/engine/browser_detection.dart index 6cafa6e387e0a..66801b61bc7ce 100644 --- a/lib/web_ui/lib/src/engine/browser_detection.dart +++ b/lib/web_ui/lib/src/engine/browser_detection.dart @@ -266,3 +266,8 @@ int _detectWebGLVersion() { } return -1; } + +/// Whether the current browser supports the Chromium variant of CanvasKit. +const bool browserSupportsCanvaskitChromium = false; +// TODO(mdebbar): Uncomment this to enable real detection of browser support. +// final bool browserSupportsCanvaskitChromium = domIntl.v8BreakIterator != null; 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 3ae7d33efa7c6..d588da5a54c39 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart @@ -16,8 +16,10 @@ import 'dart:js_util' as js_util; import 'dart:typed_data'; import 'package:js/js.dart'; +import 'package:meta/meta.dart'; import 'package:ui/ui.dart' as ui; +import '../browser_detection.dart'; import '../configuration.dart'; import '../dom.dart'; import '../profiler.dart'; @@ -26,6 +28,22 @@ import 'renderer.dart'; /// Entrypoint into the CanvasKit API. late CanvasKit canvasKit; +late CanvasKitVariant _canvasKitVariant; + +/// Which variant of CanvasKit we are using. +CanvasKitVariant get canvasKitVariant => _canvasKitVariant; +set canvasKitVariant(CanvasKitVariant value) { + if (value == CanvasKitVariant.auto) { + throw ArgumentError.value( + value, + 'value', + 'CanvasKitVariant.auto is not a valid value for canvasKitVariant', + ); + } + _canvasKitVariant = value; +} + + /// Sets the [CanvasKit] object on `window` so we can use `@JS()` to bind to /// static APIs. /// @@ -2681,26 +2699,48 @@ void patchCanvasKitModule(DomHTMLScriptElement canvasKitScript) { } } +String get _canvasKitBaseUrl => configuration.canvasKitBaseUrl; + const String _kFullCanvasKitJsFileName = 'canvaskit.js'; const String _kChromiumCanvasKitJsFileName = 'chromium/canvaskit.js'; -String get _canvasKitBaseUrl => configuration.canvasKitBaseUrl; -List get _canvasKitJsFileNames { +// TODO(mdebbar): Replace this with a Record once it's supported in Dart. +class _CanvasKitVariantUrl { + const _CanvasKitVariantUrl(this.url, this.variant) + : assert( + variant != CanvasKitVariant.auto, + 'CanvasKitVariant.auto cannot have a url', + ); + + final String url; + final CanvasKitVariant variant; + + static _CanvasKitVariantUrl chromium = _CanvasKitVariantUrl( + '$_canvasKitBaseUrl$_kChromiumCanvasKitJsFileName', + CanvasKitVariant.chromium, + ); + + static _CanvasKitVariantUrl full = _CanvasKitVariantUrl( + '$_canvasKitBaseUrl$_kFullCanvasKitJsFileName', + CanvasKitVariant.full, + ); +} + +List<_CanvasKitVariantUrl> get _canvasKitUrls { switch (configuration.canvasKitVariant) { case CanvasKitVariant.auto: - return [ - if (browserSupportsCanvaskitChromium) _kChromiumCanvasKitJsFileName, - _kFullCanvasKitJsFileName, + return <_CanvasKitVariantUrl>[ + if (browserSupportsCanvaskitChromium) _CanvasKitVariantUrl.chromium, + _CanvasKitVariantUrl.full, ]; case CanvasKitVariant.full: - return [_kFullCanvasKitJsFileName]; + return <_CanvasKitVariantUrl>[_CanvasKitVariantUrl.full]; case CanvasKitVariant.chromium: - return [_kChromiumCanvasKitJsFileName]; + return <_CanvasKitVariantUrl>[_CanvasKitVariantUrl.chromium]; } } -Iterable get _canvasKitJsUrls { - return _canvasKitJsFileNames.map((String filename) => '$_canvasKitBaseUrl$filename'); -} + +@visibleForTesting String canvasKitWasmModuleUrl(String file, String canvasKitBase) => canvasKitBase + file; @@ -2709,20 +2749,23 @@ 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); + await _downloadOneOf(_canvasKitUrls); return CanvasKitInit(CanvasKitInitOptions( locateFile: allowInterop(canvasKitWasmModuleUrl), )); } -/// Finds the first URL in [urls] that can be downloaded successfully, and +/// Finds the first entry in [urls] that can be downloaded successfully, and /// downloads it. /// /// If none of the URLs can be downloaded, throws an [Exception]. -Future _downloadOneOf(Iterable urls) async { - for (final String url in urls) { - if (await _downloadCanvasKitJs(url)) { +/// +/// Also sets [canvasKitVariant] to the variant of CanvasKit that was downloaded. +Future _downloadOneOf(Iterable<_CanvasKitVariantUrl> urls) async { + for (final _CanvasKitVariantUrl entry in urls) { + if (await _downloadCanvasKitJs(entry.url)) { + canvasKitVariant = entry.variant; return; } } diff --git a/lib/web_ui/lib/src/engine/canvaskit/renderer.dart b/lib/web_ui/lib/src/engine/canvaskit/renderer.dart index 4f77899c4f10b..5a78d009ca0d9 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/renderer.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/renderer.dart @@ -28,13 +28,6 @@ import 'shader.dart'; import 'text.dart'; import 'vertices.dart'; -/// Whether we can use client-provided ICU information instead of CanvasKit's -/// built-in ICU. -const bool browserSupportsCanvaskitChromium = false; -// TODO(mdebbar): Uncomment this and use it to determine which flavor of -// CanvasKit to download. -// final bool browserSupportsCanvaskitChromium = domIntl.v8BreakIterator != null; - enum CanvasKitVariant { /// The appropriate variant is chosen based on the browser. /// diff --git a/lib/web_ui/lib/src/engine/canvaskit/text.dart b/lib/web_ui/lib/src/engine/canvaskit/text.dart index b1dbdbe42f754..ae1d2331dcc43 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/text.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/text.dart @@ -977,7 +977,7 @@ class CkParagraphBuilder implements ui.ParagraphBuilder { /// Builds the CkParagraph with the builder and deletes the builder. SkParagraph _buildSkParagraph() { - if (browserSupportsCanvaskitChromium) { + if (canvasKitVariant == CanvasKitVariant.chromium) { final String text = _paragraphBuilder.getText(); _paragraphBuilder.setWordsUtf16( fragmentUsingIntlSegmenter(text, IntlSegmenterGranularity.word),