diff --git a/image/ImageUtils.cpp b/image/ImageUtils.cpp index 003de135d141..86a7e8d431ef 100644 --- a/image/ImageUtils.cpp +++ b/image/ImageUtils.cpp @@ -346,12 +346,7 @@ class AnonymousDecoderImpl final : public AnonymousDecoder { } } - if (!mMetadataResult.mAnimated) { - mMetadataResult.mFrameCount = 1; - mMetadataResult.mFrameCountComplete = true; - mMetadataTask = nullptr; - mFrameCountTask = nullptr; - } else if (mFrameCountTask && !mFrameCountTaskRunning) { + if (mFrameCountTask && !mFrameCountTaskRunning) { MOZ_LOG( sLog, LogLevel::Debug, ("[%p] AnonymousDecoderImpl::OnMetadata -- start frame count task", @@ -391,6 +386,17 @@ class AnonymousDecoderImpl final : public AnonymousDecoder { resolve = true; } + // If the frame count task discovered more than one frame, the image is + // actually animated even if the metadata decoder missed it (e.g. a GIF + // whose first frame has delay_time=0). + if (mFrameCount > 1 && !mMetadataResult.mAnimated) { + MOZ_LOG(sLog, LogLevel::Debug, + ("[%p] AnonymousDecoderImpl::OnFrameCount -- discovered " + "animation, frameCount %u", + this, mFrameCount)); + mMetadataResult.mAnimated = true; + } + // If metadata completing is waiting on an updated frame count, resolve it. mMetadataResult.mFrameCount = mFrameCount; mMetadataResult.mFrameCountComplete = aComplete; diff --git a/testing/web-platform/tests/webcodecs/animated-zero-delay.gif b/testing/web-platform/tests/webcodecs/animated-zero-delay.gif new file mode 100644 index 000000000000..1cbc4158db0c Binary files /dev/null and b/testing/web-platform/tests/webcodecs/animated-zero-delay.gif differ diff --git a/testing/web-platform/tests/webcodecs/image-decoder-animated-zero-delay.https.any.js b/testing/web-platform/tests/webcodecs/image-decoder-animated-zero-delay.https.any.js new file mode 100644 index 000000000000..6844ea844912 --- /dev/null +++ b/testing/web-platform/tests/webcodecs/image-decoder-animated-zero-delay.https.any.js @@ -0,0 +1,48 @@ +// META: global=window,dedicatedworker + +// Bug: An animated GIF whose first frame has delay_time=0 is incorrectly +// detected as non-animated by the metadata decoder. This causes ImageDecoder +// to report frameCount=1 and reject decode requests for subsequent frames. + +promise_test(async t => { + let support = await ImageDecoder.isTypeSupported('image/gif'); + assert_implements_optional(support, 'Optional codec image/gif not supported.'); + + let response = await fetch('animated-zero-delay.gif'); + let buffer = await response.arrayBuffer(); + let decoder = new ImageDecoder({data: buffer, type: 'image/gif'}); + + await decoder.tracks.ready; + assert_equals(decoder.tracks.length, 1, 'Should have one track'); + + let track = decoder.tracks.selectedTrack; + assert_true(track.animated, 'Track should be detected as animated'); + assert_equals(track.frameCount, 2, 'Should report 2 frames'); + + let result0 = await decoder.decode({frameIndex: 0}); + assert_true(result0.complete, 'Frame 0 should be complete'); + assert_equals(result0.image.codedWidth, 2); + assert_equals(result0.image.codedHeight, 2); + + let result1 = await decoder.decode({frameIndex: 1}); + assert_true(result1.complete, 'Frame 1 should be complete'); + assert_equals(result1.image.codedWidth, 2); + assert_equals(result1.image.codedHeight, 2); +}, 'Test animated GIF with zero first-frame delay decodes all frames'); + +promise_test(async t => { + let support = await ImageDecoder.isTypeSupported('image/gif'); + assert_implements_optional(support, 'Optional codec image/gif not supported.'); + + let response = await fetch('animated-zero-delay.gif'); + let buffer = await response.arrayBuffer(); + let decoder = new ImageDecoder({data: buffer, type: 'image/gif'}); + + await decoder.completed; + + let track = decoder.tracks.selectedTrack; + assert_true(track.animated, 'Track should be animated after completed'); + assert_equals(track.frameCount, 2, 'Should report 2 frames after completed'); + assert_equals(track.repetitionCount, Infinity, + 'Should report infinite repetitions (loop=0)'); +}, 'Test animated GIF with zero first-frame delay reports correct metadata');