diff --git a/lib/web_ui/lib/src/engine/browser_detection.dart b/lib/web_ui/lib/src/engine/browser_detection.dart index b167480f80547..f771c9ea64ee4 100644 --- a/lib/web_ui/lib/src/engine/browser_detection.dart +++ b/lib/web_ui/lib/src/engine/browser_detection.dart @@ -81,7 +81,8 @@ BrowserEngine detectBrowserEngineByVendorAgent(String vendor, String agent) { } // Assume Blink otherwise, but issue a warning. - print('WARNING: failed to detect current browser engine. Assuming this is a Chromium-compatible browser.'); + print( + 'WARNING: failed to detect current browser engine. Assuming this is a Chromium-compatible browser.'); return BrowserEngine.blink; } @@ -141,8 +142,9 @@ OperatingSystem detectOperatingSystem({ if (platform.startsWith('Mac')) { // iDevices requesting a "desktop site" spoof their UA so it looks like a Mac. // This checks if we're in a touch device, or on a real mac. - final int maxTouchPoints = - overrideMaxTouchPoints ?? domWindow.navigator.maxTouchPoints?.toInt() ?? 0; + final int maxTouchPoints = overrideMaxTouchPoints ?? + domWindow.navigator.maxTouchPoints?.toInt() ?? + 0; if (maxTouchPoints > 2) { return OperatingSystem.iOs; } @@ -204,6 +206,36 @@ bool get isIOS15 { domWindow.navigator.userAgent.contains('OS 15_'); } +/// Detect if running on Chrome version 110 or older on Windows. +/// +/// These versions of Chrome have a bug on Windows which causes +/// rendering to be flipped upside down. +// TODO(harryterkelsen): Remove this check once we stop supporting Chrome 110 +// and earlier, https://github.com/flutter/flutter/issues/139186. +bool get isChrome110OrOlderOnWindows { + if (debugIsChrome110OrOlderOnWindows != null) { + return debugIsChrome110OrOlderOnWindows!; + } + if (_cachedIsChrome110OrOlderOnWindows != null) { + return _cachedIsChrome110OrOlderOnWindows!; + } + if (operatingSystem != OperatingSystem.windows) { + return _cachedIsChrome110OrOlderOnWindows = false; + } + final RegExp chromeRegexp = RegExp(r'Chrom(e|ium)\/([0-9]+)\.'); + final RegExpMatch? match = + chromeRegexp.firstMatch(domWindow.navigator.userAgent); + if (match != null) { + final int chromeVersion = int.parse(match.group(2)!); + return _cachedIsChrome110OrOlderOnWindows = chromeVersion <= 110; + } + return _cachedIsChrome110OrOlderOnWindows = false; +} + +// Cache the result of checking if the app is running on Chrome 110 on Windows +// since we check this on every frame. +bool? _cachedIsChrome110OrOlderOnWindows; + /// If set to true pretends that the current browser is iOS Safari. /// /// Useful for tests. Do not use in production code. @@ -234,6 +266,9 @@ bool get isWasm => const bool.fromEnvironment('dart.library.ffi'); /// Use in tests to simulate the detection of iOS 15. bool? debugIsIOS15; +/// Use in tests to simulated the detection of Chrome 110 or older on Windows. +bool? debugIsChrome110OrOlderOnWindows; + int? _cachedWebGLVersion; /// The highest WebGL version supported by the current browser, or -1 if WebGL diff --git a/lib/web_ui/lib/src/engine/dom.dart b/lib/web_ui/lib/src/engine/dom.dart index 284cd7296832a..47c464a8de840 100644 --- a/lib/web_ui/lib/src/engine/dom.dart +++ b/lib/web_ui/lib/src/engine/dom.dart @@ -3672,8 +3672,10 @@ external JSAny? get _createImageBitmapFunction; /// Set to `true` to disable `createImageBitmap` support. Used in tests. bool debugDisableCreateImageBitmapSupport = false; -bool browserSupportsCreateImageBitmap = - !debugDisableCreateImageBitmapSupport || _createImageBitmapFunction != null; +bool get browserSupportsCreateImageBitmap => + _createImageBitmapFunction != null && + !isChrome110OrOlderOnWindows && + !debugDisableCreateImageBitmapSupport; @JS() @staticInterop diff --git a/lib/web_ui/test/canvaskit/no_create_image_bitmap_test.dart b/lib/web_ui/test/canvaskit/no_create_image_bitmap_test.dart index 4ee6b09aa3a2f..d23270e1e8a31 100644 --- a/lib/web_ui/test/canvaskit/no_create_image_bitmap_test.dart +++ b/lib/web_ui/test/canvaskit/no_create_image_bitmap_test.dart @@ -20,14 +20,18 @@ void testMain() { setUpCanvasKitTest(); setUp(() async { EngineFlutterDisplay.instance.debugOverrideDevicePixelRatio(1.0); - debugDisableCreateImageBitmapSupport = true; }); tearDown(() { debugDisableCreateImageBitmapSupport = false; + debugIsChrome110OrOlderOnWindows = null; }); test('can render without createImageBitmap', () async { + debugDisableCreateImageBitmapSupport = true; + + expect(browserSupportsCreateImageBitmap, isFalse); + final CkPictureRecorder recorder = CkPictureRecorder(); final CkCanvas canvas = recorder.beginRecording(region); @@ -61,5 +65,14 @@ void testMain() { region: region, ); }); + + test( + 'createImageBitmap support is disabled on ' + 'Windows on Chrome version 110 or older', () async { + debugIsChrome110OrOlderOnWindows = true; + debugDisableCreateImageBitmapSupport = false; + + expect(browserSupportsCreateImageBitmap, isFalse); + }); }); }