diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index 3eb3f4fdd368..a8ebd7a63200 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -1905,8 +1905,6 @@ class Codec extends NativeFieldWrapperClass2 { int get repetitionCount => _cachedRepetitionCount ??= _repetitionCount; int get _repetitionCount native 'Codec_repetitionCount'; - FrameInfo? _cachedFrame; - /// Fetches the next animation frame. /// /// Wraps back to the first frame after returning the last frame. @@ -1916,24 +1914,20 @@ class Codec extends NativeFieldWrapperClass2 { /// The caller of this method is responsible for disposing the /// [FrameInfo.image] on the returned object. Future getNextFrame() async { - if (_cachedFrame == null || frameCount != 1) { - final Completer completer = Completer.sync(); - final String? error = _getNextFrame((_Image? image, int durationMilliseconds) { - if (image == null) { - throw Exception('Codec failed to produce an image, possibly due to invalid image data.'); - } - _cachedFrame = FrameInfo._( - image: Image._(image), - duration: Duration(milliseconds: durationMilliseconds), - ); - completer.complete(); - }); - if (error != null) { - throw Exception(error); + final Completer completer = Completer.sync(); + final String? error = _getNextFrame((_Image? image, int durationMilliseconds) { + if (image == null) { + throw Exception('Codec failed to produce an image, possibly due to invalid image data.'); } - await completer.future; + completer.complete(FrameInfo._( + image: Image._(image), + duration: Duration(milliseconds: durationMilliseconds), + )); + }); + if (error != null) { + throw Exception(error); } - return _cachedFrame!; + return await completer.future; } /// Returns an error message on failure, null on success. diff --git a/testing/dart/image_dispose_test.dart b/testing/dart/image_dispose_test.dart index 3e74fb3eebd0..9e2dcb365c45 100644 --- a/testing/dart/image_dispose_test.dart +++ b/testing/dart/image_dispose_test.dart @@ -114,6 +114,18 @@ void main() { expect(frame2.image.isCloneOf(frame.image), false); }); + + test('getNextFrame does not return a disposed image', () async { + final Uint8List bytes = await readFile('2x2.png'); + final Codec codec = await instantiateImageCodec(bytes); + final FrameInfo frame = await codec.getNextFrame(); + + frame.image.dispose(); + + final FrameInfo frame2 = await codec.getNextFrame(); + expect(frame2.image.clone()..dispose(), isNotNull); + frame2.image.dispose(); + }); } Future readFile(String fileName) async {