diff --git a/lib/web_ui/lib/src/engine/html_image_codec.dart b/lib/web_ui/lib/src/engine/html_image_codec.dart
index 3ccd1faf11cb9..397b171b97b50 100644
--- a/lib/web_ui/lib/src/engine/html_image_codec.dart
+++ b/lib/web_ui/lib/src/engine/html_image_codec.dart
@@ -3,7 +3,6 @@
// found in the LICENSE file.
part of engine;
-
final bool _supportsDecode = js_util.getProperty(
js_util.getProperty(
js_util.getProperty(html.window, 'Image'), 'prototype'),
@@ -23,46 +22,54 @@ class HtmlCodec implements ui.Codec {
@override
Future getNextFrame() async {
- StreamSubscription loadSubscription;
- StreamSubscription errorSubscription;
final Completer completer = Completer();
- final html.ImageElement imgElement = html.ImageElement();
- // If the browser doesn't support asynchronous decoding of an image,
- // then use the `onload` event to decide when it's ready to paint to the
- // DOM. Unfortunately, this will case the image to be decoded synchronously
- // on the main thread, and may cause dropped framed.
- if (!_supportsDecode) {
- loadSubscription = imgElement.onLoad.listen((html.Event event) {
- loadSubscription.cancel();
- errorSubscription.cancel();
+ if (_supportsDecode) {
+ final html.ImageElement imgElement = html.ImageElement();
+ imgElement.src = src;
+ js_util.setProperty(imgElement, 'decoding', 'async');
+ imgElement.decode().then((dynamic _) {
final HtmlImage image = HtmlImage(
imgElement,
imgElement.naturalWidth,
imgElement.naturalHeight,
);
completer.complete(SingleFrameInfo(image));
+ }).catchError((e) {
+ // This code path is hit on Chrome 80.0.3987.16 when too many
+ // images are on the page (~1000).
+ // Fallback here is to load using onLoad instead.
+ _decodeUsingOnLoad(completer);
});
+ } else {
+ _decodeUsingOnLoad(completer);
}
+ return completer.future;
+ }
+
+ void _decodeUsingOnLoad(Completer completer) {
+ StreamSubscription loadSubscription;
+ StreamSubscription errorSubscription;
+ final html.ImageElement imgElement = html.ImageElement();
+ // If the browser doesn't support asynchronous decoding of an image,
+ // then use the `onload` event to decide when it's ready to paint to the
+ // DOM. Unfortunately, this will cause the image to be decoded synchronously
+ // on the main thread, and may cause dropped framed.
errorSubscription = imgElement.onError.listen((html.Event event) {
loadSubscription?.cancel();
errorSubscription.cancel();
completer.completeError(event);
});
+ loadSubscription = imgElement.onLoad.listen((html.Event event) {
+ loadSubscription.cancel();
+ errorSubscription.cancel();
+ final HtmlImage image = HtmlImage(
+ imgElement,
+ imgElement.naturalWidth,
+ imgElement.naturalHeight,
+ );
+ completer.complete(SingleFrameInfo(image));
+ });
imgElement.src = src;
- // If the browser supports asynchronous image decoding, use that instead
- // of `onload`.
- if (_supportsDecode) {
- imgElement.decode().then((dynamic _) {
- errorSubscription.cancel();
- final HtmlImage image = HtmlImage(
- imgElement,
- imgElement.naturalWidth,
- imgElement.naturalHeight,
- );
- completer.complete(SingleFrameInfo(image));
- });
- }
- return completer.future;
}
@override