mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
[web] Upgrade Chrome to 141 (for engine tests) (#177743)
- Update Chrome to 141 for web engine tests. - Improve image codec tests so they exercise all frames. - Skip the frames of certain images that are known to cause problems in Chrome. Chrome bug for the problematic images: https://issues.chromium.org/456445108 Fixes https://github.com/flutter/flutter/issues/168686
This commit is contained in:
parent
a913d39131
commit
e5d5c01850
@ -179,7 +179,7 @@
|
||||
},
|
||||
{
|
||||
"dependency": "chrome_and_driver",
|
||||
"version": "125.0.6422.141"
|
||||
"version": "141.0.7390.76"
|
||||
}
|
||||
],
|
||||
"tasks": [
|
||||
|
||||
@ -1,9 +1,13 @@
|
||||
# Please refer to the "Upgrade Browser Version" section in the README.md for
|
||||
# more details on how to update browser version numbers.
|
||||
chrome:
|
||||
version: '133.0.6943.53'
|
||||
# Latest version can be found here:
|
||||
# https://googlechromelabs.github.io/chrome-for-testing/
|
||||
version: '141.0.7390.76'
|
||||
|
||||
firefox:
|
||||
# Latest version can be found here:
|
||||
# https://www.firefox.com/en-US/releases/
|
||||
version: '143.0'
|
||||
|
||||
edge:
|
||||
|
||||
@ -134,7 +134,16 @@ abstract class BrowserImageDecoder implements ui.Codec {
|
||||
}
|
||||
|
||||
final DecodeResult result = await webDecoder
|
||||
.decode(DecodeOptions(frameIndex: _nextFrameIndex))
|
||||
// Using `completeFramesOnly: false` to get frames even from partially decoded images.
|
||||
// Typically, this wouldn't work well in Flutter because Flutter doesn't support progressive
|
||||
// image rendering. So this could result in frames being rendered at lower quality than
|
||||
// expected.
|
||||
//
|
||||
// However, since we wait for the entire image to be decoded using [webDecoder.completed],
|
||||
// this ends up being a non-issue in practice.
|
||||
//
|
||||
// For more details, see: https://issues.chromium.org/issues/456445108
|
||||
.decode(DecodeOptions(frameIndex: _nextFrameIndex, completeFramesOnly: false))
|
||||
.toDart;
|
||||
final VideoFrame frame = result.image;
|
||||
_nextFrameIndex = (_nextFrameIndex + 1) % frameCount;
|
||||
|
||||
@ -152,7 +152,7 @@ extension type DecodeResult(JSObject _) implements JSObject {
|
||||
///
|
||||
/// * https://www.w3.org/TR/webcodecs/#dictdef-imagedecodeoptions
|
||||
extension type DecodeOptions._(JSObject _) implements JSObject {
|
||||
external DecodeOptions({required int frameIndex});
|
||||
external DecodeOptions({required int frameIndex, required bool completeFramesOnly});
|
||||
}
|
||||
|
||||
/// The only frame in a static image, or one of the frames in an animated one.
|
||||
|
||||
@ -18,35 +18,19 @@ void main() {
|
||||
}
|
||||
|
||||
abstract class TestCodec {
|
||||
TestCodec({required this.description});
|
||||
final String description;
|
||||
|
||||
ui.Codec? _cachedCodec;
|
||||
|
||||
Future<ui.Codec> getCodec() async => _cachedCodec ??= await createCodec();
|
||||
|
||||
Future<ui.Codec> createCodec();
|
||||
|
||||
void dispose() {
|
||||
_cachedCodec?.dispose();
|
||||
_cachedCodec = null;
|
||||
}
|
||||
}
|
||||
|
||||
abstract class TestFileCodec extends TestCodec {
|
||||
TestFileCodec.fromTestFile(this.testFile, {required super.description});
|
||||
TestCodec.fromTestFile(this.testFile, {required this.description});
|
||||
|
||||
final String testFile;
|
||||
final String description;
|
||||
|
||||
Future<ui.Codec> createCodecFromTestFile(String testFile);
|
||||
|
||||
@override
|
||||
Future<ui.Codec> createCodec() {
|
||||
return createCodecFromTestFile(testFile);
|
||||
}
|
||||
}
|
||||
|
||||
class UrlTestCodec extends TestFileCodec {
|
||||
class UrlTestCodec extends TestCodec {
|
||||
UrlTestCodec(super.testFile, this.codecFactory, String function)
|
||||
: super.fromTestFile(description: 'created with $function("$testFile")');
|
||||
|
||||
@ -58,7 +42,7 @@ class UrlTestCodec extends TestFileCodec {
|
||||
}
|
||||
}
|
||||
|
||||
class FetchTestCodec extends TestFileCodec {
|
||||
class FetchTestCodec extends TestCodec {
|
||||
FetchTestCodec(super.testFile, this.codecFactory, String function)
|
||||
: super.fromTestFile(
|
||||
description:
|
||||
@ -70,7 +54,7 @@ class FetchTestCodec extends TestFileCodec {
|
||||
|
||||
@override
|
||||
Future<ui.Codec> createCodecFromTestFile(String testFile) async {
|
||||
final HttpFetchResponse response = await httpFetch(testFile);
|
||||
final HttpFetchResponse response = await httpFetch('/test_images/$testFile');
|
||||
|
||||
if (!response.hasPayload) {
|
||||
throw Exception('Unable to fetch() image test file "$testFile"');
|
||||
@ -81,7 +65,7 @@ class FetchTestCodec extends TestFileCodec {
|
||||
}
|
||||
}
|
||||
|
||||
class BitmapTestCodec extends TestFileCodec {
|
||||
class BitmapTestCodec extends TestCodec {
|
||||
BitmapTestCodec(super.testFile, this.codecFactory, String function)
|
||||
: super.fromTestFile(
|
||||
description:
|
||||
@ -94,7 +78,7 @@ class BitmapTestCodec extends TestFileCodec {
|
||||
@override
|
||||
Future<ui.Codec> createCodecFromTestFile(String testFile) async {
|
||||
final DomHTMLImageElement imageElement = createDomHTMLImageElement();
|
||||
imageElement.src = testFile;
|
||||
imageElement.src = '/test_images/$testFile';
|
||||
imageElement.decoding = 'async';
|
||||
|
||||
await imageElement.decode();
|
||||
@ -168,26 +152,25 @@ Future<void> testMain() async {
|
||||
);
|
||||
testCodecs.add(
|
||||
FetchTestCodec(
|
||||
'/test_images/$testFile',
|
||||
testFile,
|
||||
(Uint8List bytes) => renderer.instantiateImageCodec(bytes),
|
||||
'renderer.instantiateImageCodec',
|
||||
),
|
||||
);
|
||||
testCodecs.add(
|
||||
FetchTestCodec(
|
||||
'/test_images/$testFile',
|
||||
testFile,
|
||||
(Uint8List bytes) => renderer.instantiateImageCodec(
|
||||
bytes,
|
||||
targetWidth: testTargetWidth,
|
||||
targetHeight: testTargetHeight,
|
||||
),
|
||||
'renderer.instantiateImageCodec '
|
||||
'($testTargetWidth x $testTargetHeight)',
|
||||
'renderer.instantiateImageCodec ($testTargetWidth x $testTargetHeight)',
|
||||
),
|
||||
);
|
||||
testCodecs.add(
|
||||
BitmapTestCodec(
|
||||
'test_images/$testFile',
|
||||
testFile,
|
||||
(DomImageBitmap bitmap) async => renderer.createImageFromImageBitmap(bitmap),
|
||||
'renderer.createImageFromImageBitmap',
|
||||
),
|
||||
@ -204,33 +187,47 @@ Future<void> testMain() async {
|
||||
mockHttpFetchResponseFactory = null;
|
||||
});
|
||||
|
||||
group('Codecs', () {
|
||||
final List<TestCodec> testCodecs = createTestCodecs();
|
||||
for (final TestCodec testCodec in testCodecs) {
|
||||
test('${testCodec.description} can create an image', () async {
|
||||
try {
|
||||
final ui.Codec codec = await testCodec.getCodec();
|
||||
final ui.FrameInfo frameInfo = await codec.getNextFrame();
|
||||
final ui.Image image = frameInfo.image;
|
||||
expect(image, isNotNull);
|
||||
expect(image.width, isNonZero);
|
||||
expect(image.height, isNonZero);
|
||||
expect(image.colorSpace, isNotNull);
|
||||
} catch (e) {
|
||||
throw TestFailure('Failed to get image for ${testCodec.description}: $e');
|
||||
}
|
||||
});
|
||||
void runCodecTest(TestCodec testCodec) {
|
||||
const problematicChromeImages = <String, Set<int>>{
|
||||
// Frame 2 cause Chrome to crash.
|
||||
// https://issues.chromium.org/456445108
|
||||
'crbug445556737.png': {2},
|
||||
// Frames 2 and 3 cause Chrome to crash.
|
||||
// https://issues.chromium.org/456445108
|
||||
'interlaced-multiframe-with-blending.png': {2, 3},
|
||||
};
|
||||
|
||||
test('${testCodec.description} can be decoded with toByteData', () async {
|
||||
ui.Image image;
|
||||
test('${testCodec.description} can create an image and convert it to byte array', () async {
|
||||
final ui.Codec codec = await testCodec.createCodec();
|
||||
|
||||
final Set<int> problematicFrames;
|
||||
if (isChromium && problematicChromeImages.containsKey(testCodec.testFile)) {
|
||||
// Encountered an image with known problematic frames on Chromium.
|
||||
problematicFrames = problematicChromeImages[testCodec.testFile]!;
|
||||
} else {
|
||||
problematicFrames = <int>{};
|
||||
}
|
||||
|
||||
for (int i = 0; i < codec.frameCount; i++) {
|
||||
if (problematicFrames.contains(i)) {
|
||||
printWarning(
|
||||
'Skipping frame $i of ${testCodec.description} due to known Chromium crash bug.',
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
final ui.Image image;
|
||||
try {
|
||||
final ui.Codec codec = await testCodec.getCodec();
|
||||
final ui.FrameInfo frameInfo = await codec.getNextFrame();
|
||||
image = frameInfo.image;
|
||||
} catch (e) {
|
||||
throw TestFailure('Failed to get image for ${testCodec.description}: $e');
|
||||
codec.dispose();
|
||||
throw TestFailure('Failed to get image at frame $i for ${testCodec.description}: $e');
|
||||
}
|
||||
|
||||
expect(image.width, isNonZero);
|
||||
expect(image.height, isNonZero);
|
||||
|
||||
final ByteData? byteData = await image.toByteData();
|
||||
expect(
|
||||
byteData,
|
||||
@ -249,12 +246,31 @@ Future<void> testMain() async {
|
||||
'${testCodec.description} toByteData() should '
|
||||
'contain nonzero value',
|
||||
);
|
||||
});
|
||||
}
|
||||
for (final testCodec in testCodecs) {
|
||||
testCodec.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
// After all frames are decoded and tested, dispose the codec.
|
||||
codec.dispose();
|
||||
});
|
||||
}
|
||||
|
||||
group('Codecs (default browserSupportsImageDecoder)', () {
|
||||
createTestCodecs().forEach(runCodecTest);
|
||||
});
|
||||
|
||||
if (browserSupportsImageDecoder) {
|
||||
// For the sake of completeness, test codec fallback logic on browsers that support
|
||||
// `ImageDecoder`.
|
||||
group('Codecs (browserSupportsImageDecoder=false)', () {
|
||||
setUpAll(() {
|
||||
browserSupportsImageDecoder = false;
|
||||
});
|
||||
tearDownAll(() {
|
||||
debugResetBrowserSupportsImageDecoder();
|
||||
});
|
||||
|
||||
createTestCodecs().forEach(runCodecTest);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
test('crossOrigin requests cause an error', () async {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user