From 08e97bf5151e9c4fa08be02c41ed0c71d4660c40 Mon Sep 17 00:00:00 2001 From: Mouad Debbar Date: Wed, 15 Mar 2023 10:27:02 -0400 Subject: [PATCH 1/6] [web] Remove image codecs from Canvaskit Chromium --- third_party/canvaskit/BUILD.gn | 12 ++++++++++++ tools/gn | 3 --- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/third_party/canvaskit/BUILD.gn b/third_party/canvaskit/BUILD.gn index 188bfdff04692..24bf40b6f0759 100644 --- a/third_party/canvaskit/BUILD.gn +++ b/third_party/canvaskit/BUILD.gn @@ -7,8 +7,14 @@ import("//build/toolchain/wasm.gni") # This toolchain is only to be used by the canvaskit target below. wasm_toolchain("canvaskit") { extra_toolchain_args = { + # Include ICU data. skia_use_icu = true skia_use_client_icu = false + + # Include image codecs. + skia_use_libjpeg_turbo_decode = true + skia_use_libpng_decode = true + skia_use_libwebp_decode = true } } @@ -20,9 +26,15 @@ group("canvaskit_group") { # This toolchain is only to be used by canvaskit_chromium_group below. wasm_toolchain("canvaskit_chromium") { extra_toolchain_args = { + # Remove ICU data. skia_use_icu = false skia_use_client_icu = true skia_icu_bidi_third_party_dir = "//flutter/third_party/canvaskit/icu_bidi" + + # Remove image codecs. + skia_use_libjpeg_turbo_decode = false + skia_use_libpng_decode = false + skia_use_libwebp_decode = false } } diff --git a/tools/gn b/tools/gn index 47664dd4620ca..8a073143cb5c2 100755 --- a/tools/gn +++ b/tools/gn @@ -617,11 +617,8 @@ def to_gn_wasm_args(args, gn_args): gn_args['skia_use_vulkan'] = False gn_args['skia_use_webgpu'] = False gn_args['skia_use_libheif'] = False - gn_args['skia_use_libjpeg_turbo_decode'] = True gn_args['skia_use_libjpeg_turbo_encode'] = False - gn_args['skia_use_libpng_decode'] = True gn_args['skia_use_libpng_encode'] = True - gn_args['skia_use_libwebp_decode'] = True gn_args['skia_use_libwebp_encode'] = False gn_args['skia_use_lua'] = False gn_args['skia_use_wuffs'] = True From 453f30003f520aff69c349ebffd01a4f7da576ff Mon Sep 17 00:00:00 2001 From: Mouad Debbar Date: Wed, 15 Mar 2023 17:10:40 -0400 Subject: [PATCH 2/6] update browser detection --- lib/web_ui/lib/src/engine/browser_detection.dart | 4 +++- lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/web_ui/lib/src/engine/browser_detection.dart b/lib/web_ui/lib/src/engine/browser_detection.dart index 4073b82b0c0f2..464e392b8e382 100644 --- a/lib/web_ui/lib/src/engine/browser_detection.dart +++ b/lib/web_ui/lib/src/engine/browser_detection.dart @@ -5,6 +5,7 @@ import 'package:meta/meta.dart'; import 'dom.dart'; +import 'safe_browser_api.dart'; // iOS 15 launched WebGL 2.0, but there's something broken about it, which // leads to apps failing to load. For now, we're forcing WebGL 1 on iOS. @@ -268,4 +269,5 @@ int _detectWebGLVersion() { } /// Whether the current browser supports the Chromium variant of CanvasKit. -final bool browserSupportsCanvaskitChromium = domIntl.v8BreakIterator != null; +final bool browserSupportsCanvaskitChromium = + browserSupportsImageDecoder && 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 dbd01511304d6..00c8662ed6422 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart @@ -29,6 +29,7 @@ import 'renderer.dart'; late CanvasKit canvasKit; // TODO(mdebbar): Turn this on when CanvasKit Chromium is ready. +// Set it to `browserSupportsCanvasKitChromium`. // https://github.com/flutter/flutter/issues/122329 const bool _enableCanvasKitChromiumInAutoMode = false; From e875ac0d791e2547ab1a7723fc101fa0e89a6bd7 Mon Sep 17 00:00:00 2001 From: Mouad Debbar Date: Wed, 15 Mar 2023 17:32:20 -0400 Subject: [PATCH 3/6] tests for browser detection --- .../lib/src/engine/safe_browser_api.dart | 13 ++--- lib/web_ui/test/browser_detect_test.dart | 49 +++++++++++++++++++ 2 files changed, 56 insertions(+), 6 deletions(-) diff --git a/lib/web_ui/lib/src/engine/safe_browser_api.dart b/lib/web_ui/lib/src/engine/safe_browser_api.dart index 38c7f52c3db94..0ada04bcca3cc 100644 --- a/lib/web_ui/lib/src/engine/safe_browser_api.dart +++ b/lib/web_ui/lib/src/engine/safe_browser_api.dart @@ -217,17 +217,18 @@ const bool _browserImageDecodingEnabled = bool.fromEnvironment( ); /// Whether the current browser supports `ImageDecoder`. -bool browserSupportsImageDecoder = - _browserImageDecodingEnabled && - _imageDecoderConstructor != null && - browserEngine == BrowserEngine.blink; +bool browserSupportsImageDecoder = _defaultBrowserSupportsImageDecoder; /// Sets the value of [browserSupportsImageDecoder] to its default value. void debugResetBrowserSupportsImageDecoder() { - browserSupportsImageDecoder = - _imageDecoderConstructor != null; + browserSupportsImageDecoder = _defaultBrowserSupportsImageDecoder; } +bool _defaultBrowserSupportsImageDecoder = + _browserImageDecodingEnabled && + _imageDecoderConstructor != null && + browserEngine == BrowserEngine.blink; + /// The signature of the function passed to the constructor of JavaScript `Promise`. typedef JsPromiseCallback = void Function(void Function(Object? value) resolve, void Function(Object? error) reject); diff --git a/lib/web_ui/test/browser_detect_test.dart b/lib/web_ui/test/browser_detect_test.dart index ae291d0cc5bf7..ff3af2fe233dc 100644 --- a/lib/web_ui/test/browser_detect_test.dart +++ b/lib/web_ui/test/browser_detect_test.dart @@ -2,9 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'package:js/js.dart'; + import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; import 'package:ui/src/engine/browser_detection.dart'; +import 'package:ui/src/engine/safe_browser_api.dart'; void main() { internalBootstrapBrowserTest(() => testMain); @@ -152,4 +155,50 @@ void testMain() { ); }); }); + + group('browserSupportsCanvasKitChromium', () { + late dynamic oldV8BreakIterator = v8BreakIterator; + setUp(() { + oldV8BreakIterator = v8BreakIterator; + }); + tearDown(() { + v8BreakIterator = oldV8BreakIterator; + debugResetBrowserSupportsImageDecoder(); + }); + + test('Detect browsers that support CanvasKit Chromium', () { + v8BreakIterator = Object(); // Any non-null value. + browserSupportsImageDecoder = true; + + expect(browserSupportsCanvaskitChromium, isTrue); + }); + + test('Detect browsers that do not support image codecs', () { + v8BreakIterator = Object(); // Any non-null value. + browserSupportsImageDecoder = false; + + expect(browserSupportsCanvaskitChromium, isFalse); + }); + + test('Detect browsers that do not support v8BreakIterator', () { + v8BreakIterator = null; + browserSupportsImageDecoder = true; + + expect(browserSupportsCanvaskitChromium, isFalse); + }); + + test('Detect browsers that support neither', () { + v8BreakIterator = null; + browserSupportsImageDecoder = false; + + expect(browserSupportsCanvaskitChromium, isFalse); + }); + }); } + + +@JS('window.Intl.v8BreakIterator') +external dynamic get v8BreakIterator; + +@JS('window.Intl.v8BreakIterator') +external set v8BreakIterator(dynamic x); From f24f10dd4eda1ead850d465cdfb8313b9141abc3 Mon Sep 17 00:00:00 2001 From: Mouad Debbar Date: Wed, 15 Mar 2023 18:07:48 -0400 Subject: [PATCH 4/6] review comments --- lib/web_ui/lib/src/engine/safe_browser_api.dart | 17 +++++++++++++---- third_party/canvaskit/BUILD.gn | 5 +++-- tools/gn | 2 ++ 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/lib/web_ui/lib/src/engine/safe_browser_api.dart b/lib/web_ui/lib/src/engine/safe_browser_api.dart index 0ada04bcca3cc..6c8bf4fc290dc 100644 --- a/lib/web_ui/lib/src/engine/safe_browser_api.dart +++ b/lib/web_ui/lib/src/engine/safe_browser_api.dart @@ -217,17 +217,26 @@ const bool _browserImageDecodingEnabled = bool.fromEnvironment( ); /// Whether the current browser supports `ImageDecoder`. -bool browserSupportsImageDecoder = _defaultBrowserSupportsImageDecoder; +bool browserSupportsImageDecoder = _kDefaultBrowserSupportsImageDecoder; /// Sets the value of [browserSupportsImageDecoder] to its default value. void debugResetBrowserSupportsImageDecoder() { - browserSupportsImageDecoder = _defaultBrowserSupportsImageDecoder; + browserSupportsImageDecoder = _kDefaultBrowserSupportsImageDecoder; } -bool _defaultBrowserSupportsImageDecoder = +bool get _kDefaultBrowserSupportsImageDecoder => _browserImageDecodingEnabled && _imageDecoderConstructor != null && - browserEngine == BrowserEngine.blink; + _kProtectFromImageDecoderIncompatibilities; + +// TODO(yjbanov): https://github.com/flutter/flutter/issues/122761 +// Frequently, when a browser launches an API that other browsers already +// support, there are subtle incompatibilities that may cause apps to crash if, +// we blindly adopt the new implementation. This variable prevents us from +// picking up potentially incompatible implementations of ImagdeDecoder API. +// Instead, when a new browser engine launches the API, we'll evaluate it and +// enable it explicitly. +bool get _kProtectFromImageDecoderIncompatibilities => browserEngine == BrowserEngine.blink; /// The signature of the function passed to the constructor of JavaScript `Promise`. typedef JsPromiseCallback = void Function(void Function(Object? value) resolve, void Function(Object? error) reject); diff --git a/third_party/canvaskit/BUILD.gn b/third_party/canvaskit/BUILD.gn index 24bf40b6f0759..fe7032bfd5b77 100644 --- a/third_party/canvaskit/BUILD.gn +++ b/third_party/canvaskit/BUILD.gn @@ -26,12 +26,13 @@ group("canvaskit_group") { # This toolchain is only to be used by canvaskit_chromium_group below. wasm_toolchain("canvaskit_chromium") { extra_toolchain_args = { - # Remove ICU data. + # 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" - # Remove image codecs. + # In Chromium browsers, we can use the browser's built-in codecs. skia_use_libjpeg_turbo_decode = false skia_use_libpng_decode = false skia_use_libwebp_decode = false diff --git a/tools/gn b/tools/gn index 8a073143cb5c2..c58801869b3df 100755 --- a/tools/gn +++ b/tools/gn @@ -618,6 +618,8 @@ def to_gn_wasm_args(args, gn_args): gn_args['skia_use_webgpu'] = False gn_args['skia_use_libheif'] = False gn_args['skia_use_libjpeg_turbo_encode'] = False + # TODO(yjbanov): https://github.com/flutter/flutter/issues/122759 + # Remove this and implement it through Canvas2d. gn_args['skia_use_libpng_encode'] = True gn_args['skia_use_libwebp_encode'] = False gn_args['skia_use_lua'] = False From 56dccbe3869927ccea664ec9b330d29a7fc634a7 Mon Sep 17 00:00:00 2001 From: Mouad Debbar Date: Thu, 16 Mar 2023 13:44:12 -0400 Subject: [PATCH 5/6] make it a getter to fix tests --- lib/web_ui/lib/src/engine/browser_detection.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/web_ui/lib/src/engine/browser_detection.dart b/lib/web_ui/lib/src/engine/browser_detection.dart index 464e392b8e382..431a81f304808 100644 --- a/lib/web_ui/lib/src/engine/browser_detection.dart +++ b/lib/web_ui/lib/src/engine/browser_detection.dart @@ -269,5 +269,5 @@ int _detectWebGLVersion() { } /// Whether the current browser supports the Chromium variant of CanvasKit. -final bool browserSupportsCanvaskitChromium = +bool get browserSupportsCanvaskitChromium => browserSupportsImageDecoder && domIntl.v8BreakIterator != null; From 43aae6a885b2e1c4e7ce9095f33fe9ca51409836 Mon Sep 17 00:00:00 2001 From: Mouad Debbar Date: Fri, 17 Mar 2023 13:22:10 -0400 Subject: [PATCH 6/6] renames --- lib/web_ui/lib/src/engine/safe_browser_api.dart | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/web_ui/lib/src/engine/safe_browser_api.dart b/lib/web_ui/lib/src/engine/safe_browser_api.dart index 6c8bf4fc290dc..c908bf514575b 100644 --- a/lib/web_ui/lib/src/engine/safe_browser_api.dart +++ b/lib/web_ui/lib/src/engine/safe_browser_api.dart @@ -217,17 +217,17 @@ const bool _browserImageDecodingEnabled = bool.fromEnvironment( ); /// Whether the current browser supports `ImageDecoder`. -bool browserSupportsImageDecoder = _kDefaultBrowserSupportsImageDecoder; +bool browserSupportsImageDecoder = _defaultBrowserSupportsImageDecoder; /// Sets the value of [browserSupportsImageDecoder] to its default value. void debugResetBrowserSupportsImageDecoder() { - browserSupportsImageDecoder = _kDefaultBrowserSupportsImageDecoder; + browserSupportsImageDecoder = _defaultBrowserSupportsImageDecoder; } -bool get _kDefaultBrowserSupportsImageDecoder => +bool get _defaultBrowserSupportsImageDecoder => _browserImageDecodingEnabled && _imageDecoderConstructor != null && - _kProtectFromImageDecoderIncompatibilities; + _isBrowserImageDecoderStable; // TODO(yjbanov): https://github.com/flutter/flutter/issues/122761 // Frequently, when a browser launches an API that other browsers already @@ -236,7 +236,7 @@ bool get _kDefaultBrowserSupportsImageDecoder => // picking up potentially incompatible implementations of ImagdeDecoder API. // Instead, when a new browser engine launches the API, we'll evaluate it and // enable it explicitly. -bool get _kProtectFromImageDecoderIncompatibilities => browserEngine == BrowserEngine.blink; +bool get _isBrowserImageDecoderStable => browserEngine == BrowserEngine.blink; /// The signature of the function passed to the constructor of JavaScript `Promise`. typedef JsPromiseCallback = void Function(void Function(Object? value) resolve, void Function(Object? error) reject);