REGRESSION (216471): Infinite repaint-drawing loop when asynchronously decoding incom...
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 15 May 2017 22:10:37 +0000 (22:10 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 15 May 2017 22:10:37 +0000 (22:10 +0000)
https://bugs.webkit.org/show_bug.cgi?id=171900

Patch by Said Abou-Hallawa <sabouhallawa@apple.com> on 2017-05-15
Reviewed by Tim Horton.

-- Don't destroy incomplete decoded image frames for large images. This
is to avoid flickering while decoding another image frame with the new
data. The old incomplete image frame will be destroyed once the newer one
finishes decoding.

-- Extend the enum ImageFrame::DecodingStatus by adding a new value called
'Decoding'. This new value will never be cached in the ImageFrame::
m_decodingStatus. Add a member m_currentFrameDecodingStatus to BitmapImage.
The purpose of this member is to invalidate the current frame, without
deleting it, when new encoded data is received.

-- Don't wait until the native image is decoded to cache the ImageFrame
decodingStatus. There is a big chance that more data arrives between
starting the decoding and finishing it such that the decoding changes
from Partial to Complete. We need to prevent keeping incomplete ImageFrames
cached because we mistakenly assume they are complete. To fix this issue
we need to know the ImageFrame decodingStatus when the decoding is requested.

* platform/graphics/BitmapImage.cpp:
(WebCore::BitmapImage::destroyDecodedData):
(WebCore::BitmapImage::dataChanged):
(WebCore::BitmapImage::draw):
(WebCore::BitmapImage::internalStartAnimation): At the beginning of this
function we check whether the next frame is being decoded or not and we
return DecodingActive if it is. Let's handle the second check here also
before requesting the decoding of nextFrame. We need to check whether the
nextFrame has a native image with decoded with the native size or not.
(WebCore::BitmapImage::internalAdvanceAnimation):
(WebCore::BitmapImage::imageFrameAvailableAtIndex):
* platform/graphics/BitmapImage.h:
* platform/graphics/ImageFrame.cpp:
(WebCore::ImageFrame::operator=):
(WebCore::ImageFrame::setDecodingStatus):
(WebCore::ImageFrame::decodingStatus):
* platform/graphics/ImageFrame.h:
(WebCore::ImageFrame::isInvalid):
(WebCore::ImageFrame::isPartial):
(WebCore::ImageFrame::isComplete):
(WebCore::ImageFrame::setDecoding): Deleted.
(WebCore::ImageFrame::decoding): Deleted.
(WebCore::ImageFrame::isEmpty): Deleted.
* platform/graphics/ImageFrameCache.cpp:
(WebCore::ImageFrameCache::setNativeImage):
(WebCore::ImageFrameCache::cacheMetadataAtIndex):
(WebCore::ImageFrameCache::cacheNativeImageAtIndex):
(WebCore::ImageFrameCache::cacheNativeImageAtIndexAsync):
(WebCore::ImageFrameCache::startAsyncDecodingQueue):
(WebCore::ImageFrameCache::requestFrameAsyncDecodingAtIndex):
(WebCore::ImageFrameCache::stopAsyncDecodingQueue):
(WebCore::ImageFrameCache::frameAtIndexCacheIfNeeded):
(WebCore::ImageFrameCache::frameDecodingStatusAtIndex):
(WebCore::ImageFrameCache::cacheFrameMetadataAtIndex): Deleted.
(WebCore::ImageFrameCache::cacheFrameNativeImageAtIndex): Deleted.
(WebCore::ImageFrameCache::cacheAsyncFrameNativeImageAtIndex): Deleted.
(WebCore::ImageFrameCache::frameIsCompleteAtIndex): Deleted.
* platform/graphics/ImageFrameCache.h:
(WebCore::ImageFrameCache::ImageFrameRequest::operator==):
* platform/graphics/ImageSource.cpp:
(WebCore::ImageSource::dataChanged):
* platform/graphics/ImageSource.h:
(WebCore::ImageSource::destroyIncompleteDecodedData):
(WebCore::ImageSource::requestFrameAsyncDecodingAtIndex): Let the caller
decide whether another request for the same image frame is allowed or not.
(WebCore::ImageSource::frameDecodingStatusAtIndex):
(WebCore::ImageSource::frameIsCompleteAtIndex): Deleted.
* platform/image-decoders/ImageDecoder.cpp:
(WebCore::ImageDecoder::frameDurationAtIndex):
(WebCore::ImageDecoder::createFrameImageAtIndex):
* platform/image-decoders/bmp/BMPImageReader.cpp:
(WebCore::BMPImageReader::decodeBMP):
* platform/image-decoders/gif/GIFImageDecoder.cpp:
(WebCore::GIFImageDecoder::clearFrameBufferCache):
(WebCore::GIFImageDecoder::haveDecodedRow):
(WebCore::GIFImageDecoder::frameComplete):
(WebCore::GIFImageDecoder::initFrameBuffer):
* platform/image-decoders/jpeg/JPEGImageDecoder.cpp:
(WebCore::JPEGImageDecoder::outputScanlines):
(WebCore::JPEGImageDecoder::jpegComplete):
* platform/image-decoders/png/PNGImageDecoder.cpp:
(WebCore::PNGImageDecoder::rowAvailable):
(WebCore::PNGImageDecoder::pngComplete):
(WebCore::PNGImageDecoder::clearFrameBufferCache):
(WebCore::PNGImageDecoder::frameComplete):
* platform/image-decoders/webp/WEBPImageDecoder.cpp:
(WebCore::WEBPImageDecoder::decode):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@216882 268f45cc-cd09-0410-ab3c-d52691b4dbfc

15 files changed:
Source/WebCore/ChangeLog
Source/WebCore/platform/graphics/BitmapImage.cpp
Source/WebCore/platform/graphics/BitmapImage.h
Source/WebCore/platform/graphics/ImageFrame.cpp
Source/WebCore/platform/graphics/ImageFrame.h
Source/WebCore/platform/graphics/ImageFrameCache.cpp
Source/WebCore/platform/graphics/ImageFrameCache.h
Source/WebCore/platform/graphics/ImageSource.cpp
Source/WebCore/platform/graphics/ImageSource.h
Source/WebCore/platform/image-decoders/ImageDecoder.cpp
Source/WebCore/platform/image-decoders/bmp/BMPImageReader.cpp
Source/WebCore/platform/image-decoders/gif/GIFImageDecoder.cpp
Source/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.cpp
Source/WebCore/platform/image-decoders/png/PNGImageDecoder.cpp
Source/WebCore/platform/image-decoders/webp/WEBPImageDecoder.cpp

index 9c035cb..54ba5eb 100644 (file)
@@ -1,3 +1,96 @@
+2017-05-15  Said Abou-Hallawa  <sabouhallawa@apple.com>
+
+        REGRESSION (216471): Infinite repaint-drawing loop when asynchronously decoding incomplete image frames
+        https://bugs.webkit.org/show_bug.cgi?id=171900
+
+        Reviewed by Tim Horton.
+
+        -- Don't destroy incomplete decoded image frames for large images. This
+        is to avoid flickering while decoding another image frame with the new
+        data. The old incomplete image frame will be destroyed once the newer one
+        finishes decoding.
+
+        -- Extend the enum ImageFrame::DecodingStatus by adding a new value called
+        'Decoding'. This new value will never be cached in the ImageFrame::
+        m_decodingStatus. Add a member m_currentFrameDecodingStatus to BitmapImage.
+        The purpose of this member is to invalidate the current frame, without
+        deleting it, when new encoded data is received.
+
+        -- Don't wait until the native image is decoded to cache the ImageFrame
+        decodingStatus. There is a big chance that more data arrives between
+        starting the decoding and finishing it such that the decoding changes
+        from Partial to Complete. We need to prevent keeping incomplete ImageFrames
+        cached because we mistakenly assume they are complete. To fix this issue
+        we need to know the ImageFrame decodingStatus when the decoding is requested.
+
+        * platform/graphics/BitmapImage.cpp:
+        (WebCore::BitmapImage::destroyDecodedData):
+        (WebCore::BitmapImage::dataChanged):
+        (WebCore::BitmapImage::draw):
+        (WebCore::BitmapImage::internalStartAnimation): At the beginning of this 
+        function we check whether the next frame is being decoded or not and we 
+        return DecodingActive if it is. Let's handle the second check here also 
+        before requesting the decoding of nextFrame. We need to check whether the
+        nextFrame has a native image with decoded with the native size or not.
+        (WebCore::BitmapImage::internalAdvanceAnimation):
+        (WebCore::BitmapImage::imageFrameAvailableAtIndex):
+        * platform/graphics/BitmapImage.h:
+        * platform/graphics/ImageFrame.cpp:
+        (WebCore::ImageFrame::operator=):
+        (WebCore::ImageFrame::setDecodingStatus):
+        (WebCore::ImageFrame::decodingStatus):
+        * platform/graphics/ImageFrame.h:
+        (WebCore::ImageFrame::isInvalid):
+        (WebCore::ImageFrame::isPartial):
+        (WebCore::ImageFrame::isComplete):
+        (WebCore::ImageFrame::setDecoding): Deleted.
+        (WebCore::ImageFrame::decoding): Deleted.
+        (WebCore::ImageFrame::isEmpty): Deleted.
+        * platform/graphics/ImageFrameCache.cpp:
+        (WebCore::ImageFrameCache::setNativeImage):
+        (WebCore::ImageFrameCache::cacheMetadataAtIndex):
+        (WebCore::ImageFrameCache::cacheNativeImageAtIndex):
+        (WebCore::ImageFrameCache::cacheNativeImageAtIndexAsync):
+        (WebCore::ImageFrameCache::startAsyncDecodingQueue):
+        (WebCore::ImageFrameCache::requestFrameAsyncDecodingAtIndex):
+        (WebCore::ImageFrameCache::stopAsyncDecodingQueue):
+        (WebCore::ImageFrameCache::frameAtIndexCacheIfNeeded):
+        (WebCore::ImageFrameCache::frameDecodingStatusAtIndex):
+        (WebCore::ImageFrameCache::cacheFrameMetadataAtIndex): Deleted.
+        (WebCore::ImageFrameCache::cacheFrameNativeImageAtIndex): Deleted.
+        (WebCore::ImageFrameCache::cacheAsyncFrameNativeImageAtIndex): Deleted.
+        (WebCore::ImageFrameCache::frameIsCompleteAtIndex): Deleted.
+        * platform/graphics/ImageFrameCache.h:
+        (WebCore::ImageFrameCache::ImageFrameRequest::operator==):
+        * platform/graphics/ImageSource.cpp:
+        (WebCore::ImageSource::dataChanged):
+        * platform/graphics/ImageSource.h:
+        (WebCore::ImageSource::destroyIncompleteDecodedData):
+        (WebCore::ImageSource::requestFrameAsyncDecodingAtIndex): Let the caller
+        decide whether another request for the same image frame is allowed or not.
+        (WebCore::ImageSource::frameDecodingStatusAtIndex):
+        (WebCore::ImageSource::frameIsCompleteAtIndex): Deleted.
+        * platform/image-decoders/ImageDecoder.cpp:
+        (WebCore::ImageDecoder::frameDurationAtIndex):
+        (WebCore::ImageDecoder::createFrameImageAtIndex):
+        * platform/image-decoders/bmp/BMPImageReader.cpp:
+        (WebCore::BMPImageReader::decodeBMP):
+        * platform/image-decoders/gif/GIFImageDecoder.cpp:
+        (WebCore::GIFImageDecoder::clearFrameBufferCache):
+        (WebCore::GIFImageDecoder::haveDecodedRow):
+        (WebCore::GIFImageDecoder::frameComplete):
+        (WebCore::GIFImageDecoder::initFrameBuffer):
+        * platform/image-decoders/jpeg/JPEGImageDecoder.cpp:
+        (WebCore::JPEGImageDecoder::outputScanlines):
+        (WebCore::JPEGImageDecoder::jpegComplete):
+        * platform/image-decoders/png/PNGImageDecoder.cpp:
+        (WebCore::PNGImageDecoder::rowAvailable):
+        (WebCore::PNGImageDecoder::pngComplete):
+        (WebCore::PNGImageDecoder::clearFrameBufferCache):
+        (WebCore::PNGImageDecoder::frameComplete):
+        * platform/image-decoders/webp/WEBPImageDecoder.cpp:
+        (WebCore::WEBPImageDecoder::decode):
+
 2017-05-15  Chris Dumez  <cdumez@apple.com>
 
         Align WebKitCSSMatrix stringifier with spec for DOMMatrix
index 228031b..3d4a521 100644 (file)
@@ -81,8 +81,10 @@ void BitmapImage::destroyDecodedData(bool destroyAll)
         m_source.destroyDecodedDataBeforeFrame(m_currentFrame);
     else if (m_source.hasAsyncDecodingQueue())
         m_source.destroyAllDecodedDataExcludeFrame(m_currentFrame);
-    else
+    else {
         m_source.destroyAllDecodedData();
+        m_currentFrameDecodingStatus = ImageFrame::DecodingStatus::Invalid;
+    }
 
     // There's no need to throw away the decoder unless we're explicitly asked
     // to destroy all of the frames.
@@ -109,6 +111,10 @@ void BitmapImage::destroyDecodedDataIfNecessary(bool destroyAll)
 
 EncodedDataStatus BitmapImage::dataChanged(bool allDataReceived)
 {
+    if (!shouldUseAsyncDecodingForLargeImages())
+        m_source.destroyIncompleteDecodedData();
+
+    m_currentFrameDecodingStatus = ImageFrame::DecodingStatus::Invalid;
     return m_source.dataChanged(data(), allDataReceived);
 }
 
@@ -185,13 +191,13 @@ void BitmapImage::draw(GraphicsContext& context, const FloatRect& destRect, cons
 
         bool frameIsCompatible = frameHasDecodedNativeImageCompatibleWithOptionsAtIndex(m_currentFrame, m_currentSubsamplingLevel, DecodingOptions(sizeForDrawing));
         bool frameIsBeingDecoded = frameIsBeingDecodedAndIsCompatibleWithOptionsAtIndex(m_currentFrame, DecodingOptions(sizeForDrawing));
-        bool frameIsComplete = frameIsCompleteAtIndex(m_currentFrame);
 
         // If the current frame is incomplete, a new request for decoding this frame has to be made even if
         // it is currently being decoded. New data may have been received since the previous request was made.
-        if ((!frameIsCompatible && !frameIsBeingDecoded) || !frameIsComplete) {
+        if ((!frameIsCompatible && !frameIsBeingDecoded) || m_currentFrameDecodingStatus == ImageFrame::DecodingStatus::Invalid) {
             LOG(Images, "BitmapImage::%s - %p - url: %s [requesting large async decoding]", __FUNCTION__, this, sourceURL().string().utf8().data());
-            frameIsBeingDecoded = m_source.requestFrameAsyncDecodingAtIndex(0, m_currentSubsamplingLevel, sizeForDrawing);
+            m_source.requestFrameAsyncDecodingAtIndex(0, m_currentSubsamplingLevel, sizeForDrawing);
+            m_currentFrameDecodingStatus = ImageFrame::DecodingStatus::Decoding;
         }
 
         if (!frameHasDecodedNativeImageCompatibleWithOptionsAtIndex(m_currentFrame, m_currentSubsamplingLevel, DecodingMode::Asynchronous)) {
@@ -201,7 +207,6 @@ void BitmapImage::draw(GraphicsContext& context, const FloatRect& destRect, cons
         }
 
         image = frameImageAtIndex(m_currentFrame);
-        ASSERT_IMPLIES(encodedDataStatus() == EncodedDataStatus::Complete, frameIsBeingDecoded || frameIsComplete);
         LOG(Images, "BitmapImage::%s - %p - url: %s [a decoded image frame is available for drawing]", __FUNCTION__, this, sourceURL().string().utf8().data());
     } else {
         StartAnimationStatus status = internalStartAnimation();
@@ -238,6 +243,7 @@ void BitmapImage::draw(GraphicsContext& context, const FloatRect& destRect, cons
         orientation = frameOrientationAtIndex(m_currentFrame);
 
     drawNativeImage(image, context, destRect, srcRect, IntSize(size()), op, mode, orientation);
+    m_currentFrameDecodingStatus = frameDecodingStatusAtIndex(m_currentFrame);
 
     if (imageObserver())
         imageObserver()->didDraw(this);
@@ -362,16 +368,13 @@ BitmapImage::StartAnimationStatus BitmapImage::internalStartAnimation()
     // through the callback newFrameNativeImageAvailableAtIndex(). Otherwise, advanceAnimation() will be called
     // when the timer fires and m_currentFrame will be advanced to nextFrame since it is not being decoded.
     if (shouldUseAsyncDecodingForAnimatedImages()) {
-        bool isAsyncDecode = m_source.requestFrameAsyncDecodingAtIndex(nextFrame, m_currentSubsamplingLevel);
-
-#if !LOG_DISABLED
-        if (isAsyncDecode)
-            LOG(Images, "BitmapImage::%s - %p - url: %s [requesting async decoding for nextFrame = %ld]", __FUNCTION__, this, sourceURL().string().utf8().data(), nextFrame);
-        else
+        if (frameHasDecodedNativeImageCompatibleWithOptionsAtIndex(nextFrame, m_currentSubsamplingLevel, { }))
             LOG(Images, "BitmapImage::%s - %p - url: %s [cachedFrameCount = %ld nextFrame = %ld]", __FUNCTION__, this, sourceURL().string().utf8().data(), ++m_cachedFrameCount, nextFrame);
-#else
-        UNUSED_PARAM(isAsyncDecode);
-#endif
+        else {
+            m_source.requestFrameAsyncDecodingAtIndex(nextFrame, m_currentSubsamplingLevel);
+            m_currentFrameDecodingStatus = ImageFrame::DecodingStatus::Decoding;
+            LOG(Images, "BitmapImage::%s - %p - url: %s [requesting async decoding for nextFrame = %ld]", __FUNCTION__, this, sourceURL().string().utf8().data(), nextFrame);
+        }
 
         m_desiredFrameDecodeTimeForTesting = time + std::max(m_frameDecodingDurationForTesting, 0_s);
         if (m_clearDecoderAfterAsyncFrameRequestForTesting)
@@ -417,6 +420,8 @@ void BitmapImage::internalAdvanceAnimation()
 
     destroyDecodedDataIfNecessary(false);
 
+    if (m_currentFrameDecodingStatus == ImageFrame::DecodingStatus::Decoding)
+        m_currentFrameDecodingStatus = frameDecodingStatusAtIndex(m_currentFrame);
     if (imageObserver())
         imageObserver()->imageFrameAvailable(this, ImageAnimatingState::Yes);
 
@@ -464,10 +469,12 @@ void BitmapImage::imageFrameAvailableAtIndex(size_t index)
             LOG(Images, "BitmapImage::%s - %p - url: %s [earlyFrameCount = %ld nextFrame = %ld]", __FUNCTION__, this, sourceURL().string().utf8().data(), ++m_earlyFrameCount, index);
     } else {
         ASSERT(index == m_currentFrame && !m_currentFrame);
-        imageObserver()->imageFrameAvailable(this, ImageAnimatingState::No);
-        
         if (m_source.isAsyncDecodingQueueIdle())
             m_source.stopAsyncDecodingQueue();
+        if (m_currentFrameDecodingStatus == ImageFrame::DecodingStatus::Decoding)
+            m_currentFrameDecodingStatus = frameDecodingStatusAtIndex(m_currentFrame);
+        if (imageObserver())
+            imageObserver()->imageFrameAvailable(this, ImageAnimatingState::No);
     }
 }
 
index 45eee2d..5ee6970 100644 (file)
@@ -86,7 +86,8 @@ public:
     IntSize sizeRespectingOrientation() const { return m_source.sizeRespectingOrientation(); }
     Color singlePixelSolidColor() const override { return m_source.singlePixelSolidColor(); }
     bool frameIsBeingDecodedAndIsCompatibleWithOptionsAtIndex(size_t index, const DecodingOptions& decodingOptions) const { return m_source.frameIsBeingDecodedAndIsCompatibleWithOptionsAtIndex(index, decodingOptions); }
-    bool frameIsCompleteAtIndex(size_t index) const { return m_source.frameIsCompleteAtIndex(index); }
+    ImageFrame::DecodingStatus frameDecodingStatusAtIndex(size_t index) const { return m_source.frameDecodingStatusAtIndex(index); }
+    bool frameIsCompleteAtIndex(size_t index) const { return frameDecodingStatusAtIndex(index) == ImageFrame::DecodingStatus::Complete; }
     bool frameHasAlphaAtIndex(size_t index) const { return m_source.frameHasAlphaAtIndex(index); }
 
     bool frameHasFullSizeNativeImageAtIndex(size_t index, SubsamplingLevel subsamplingLevel) { return m_source.frameHasFullSizeNativeImageAtIndex(index, subsamplingLevel); }
@@ -200,6 +201,7 @@ private:
 
     size_t m_currentFrame { 0 }; // The index of the current frame of animation.
     SubsamplingLevel m_currentSubsamplingLevel { SubsamplingLevel::Default };
+    ImageFrame::DecodingStatus m_currentFrameDecodingStatus { ImageFrame::DecodingStatus::Invalid };
     std::unique_ptr<Timer> m_frameTimer;
     RepetitionCount m_repetitionsComplete { RepetitionCountNone }; // How many repetitions we've finished.
     MonotonicTime m_desiredFrameStartTime; // The system time at which we hope to see the next call to startAnimation().
index acaec6f..8e78a66 100644 (file)
@@ -50,7 +50,7 @@ ImageFrame& ImageFrame::operator=(const ImageFrame& other)
     if (this == &other)
         return *this;
 
-    m_decoding = other.m_decoding;
+    m_decodingStatus = other.m_decodingStatus;
     m_size = other.m_size;
 
 #if !USE(CG)
@@ -71,6 +71,18 @@ ImageFrame& ImageFrame::operator=(const ImageFrame& other)
     return *this;
 }
 
+void ImageFrame::setDecodingStatus(DecodingStatus decodingStatus)
+{
+    ASSERT(decodingStatus != DecodingStatus::Decoding);
+    m_decodingStatus = decodingStatus;
+}
+
+ImageFrame::DecodingStatus ImageFrame::decodingStatus() const
+{
+    ASSERT(m_decodingStatus != DecodingStatus::Decoding);
+    return m_decodingStatus;
+}
+
 unsigned ImageFrame::clearImage()
 {
 #if !USE(CG)
index e134e34..19e2f02 100644 (file)
@@ -40,7 +40,7 @@ class ImageFrame {
     friend class ImageFrameCache;
 public:
     enum class Caching { Metadata, MetadataAndImage };
-    enum class Decoding { None, Partial, Complete };
+    enum class DecodingStatus { Invalid, Partial, Complete, Decoding };
 
     ImageFrame();
     ImageFrame(const ImageFrame& other) { operator=(other); }
@@ -59,12 +59,12 @@ public:
     bool initialize(const IntSize&, bool premultiplyAlpha);
 #endif
 
-    void setDecoding(Decoding decoding) { m_decoding = decoding; }
-    Decoding decoding() const { return m_decoding; }
+    void setDecodingStatus(DecodingStatus);
+    DecodingStatus decodingStatus() const;
 
-    bool isEmpty() const { return m_decoding == Decoding::None; }
-    bool isPartial() const { return m_decoding == Decoding::Partial; }
-    bool isComplete() const { return m_decoding == Decoding::Complete; }
+    bool isInvalid() const { return m_decodingStatus == DecodingStatus::Invalid; }
+    bool isPartial() const { return m_decodingStatus == DecodingStatus::Partial; }
+    bool isComplete() const { return m_decodingStatus == DecodingStatus::Complete; }
 
     IntSize size() const;
     IntSize sizeRespectingOrientation() const { return !m_orientation.usesWidthAsHeight() ? size() : size().transposedSize(); }
@@ -101,7 +101,7 @@ public:
     Color singlePixelSolidColor() const;
 
 private:
-    Decoding m_decoding { Decoding::None };
+    DecodingStatus m_decodingStatus { DecodingStatus::Invalid };
     IntSize m_size;
 
 #if !USE(CG)
index 9cf42fb..cd8a4b4 100644 (file)
@@ -189,18 +189,22 @@ void ImageFrameCache::setNativeImage(NativeImagePtr&& nativeImage)
 
     frame.m_nativeImage = WTFMove(nativeImage);
 
-    frame.m_decoding = ImageFrame::Decoding::Complete;
+    frame.m_decodingStatus = ImageFrame::DecodingStatus::Complete;
     frame.m_size = nativeImageSize(frame.m_nativeImage);
     frame.m_hasAlpha = nativeImageHasAlpha(frame.m_nativeImage);
 }
 
-void ImageFrameCache::cacheFrameMetadataAtIndex(size_t index, SubsamplingLevel subsamplingLevel)
+void ImageFrameCache::cacheMetadataAtIndex(size_t index, SubsamplingLevel subsamplingLevel, ImageFrame::DecodingStatus decodingStatus)
 {
     ASSERT(index < m_frames.size());
     ImageFrame& frame = m_frames[index];
 
     ASSERT(isDecoderAvailable());
-    frame.m_decoding = m_decoder->frameIsCompleteAtIndex(index) ? ImageFrame::Decoding::Complete : ImageFrame::Decoding::Partial;
+    if (decodingStatus == ImageFrame::DecodingStatus::Invalid)
+        frame.m_decodingStatus = m_decoder->frameIsCompleteAtIndex(index) ? ImageFrame::DecodingStatus::Complete : ImageFrame::DecodingStatus::Partial;
+    else
+        frame.m_decodingStatus = decodingStatus;
+
     if (frame.hasMetadata())
         return;
     
@@ -219,7 +223,7 @@ void ImageFrameCache::cacheFrameMetadataAtIndex(size_t index, SubsamplingLevel s
         frame.m_duration = m_decoder->frameDurationAtIndex(index);
 }
 
-void ImageFrameCache::cacheFrameNativeImageAtIndex(NativeImagePtr&& nativeImage, size_t index, SubsamplingLevel subsamplingLevel, const DecodingOptions& decodingOptions)
+void ImageFrameCache::cacheNativeImageAtIndex(NativeImagePtr&& nativeImage, size_t index, SubsamplingLevel subsamplingLevel, const DecodingOptions& decodingOptions, ImageFrame::DecodingStatus decodingStatus)
 {
     ASSERT(index < m_frames.size());
     ImageFrame& frame = m_frames[index];
@@ -235,22 +239,21 @@ void ImageFrameCache::cacheFrameNativeImageAtIndex(NativeImagePtr&& nativeImage,
     // Move the new image to the cache.
     frame.m_nativeImage = WTFMove(nativeImage);
     frame.m_decodingOptions = decodingOptions;
-    cacheFrameMetadataAtIndex(index, subsamplingLevel);
+    cacheMetadataAtIndex(index, subsamplingLevel, decodingStatus);
 
     // Update the observer with the new image frame bytes.
     decodedSizeIncreased(frame.frameBytes());
 }
 
-void ImageFrameCache::cacheAsyncFrameNativeImageAtIndex(NativeImagePtr&& nativeImage, size_t index, SubsamplingLevel subsamplingLevel, const DecodingOptions& decodingOptions)
+void ImageFrameCache::cacheNativeImageAtIndexAsync(NativeImagePtr&& nativeImage, size_t index, SubsamplingLevel subsamplingLevel, const DecodingOptions& decodingOptions, ImageFrame::DecodingStatus decodingStatus)
 {
     if (!isDecoderAvailable())
         return;
 
     ASSERT(index < m_frames.size());
-    ASSERT(!frameIsCompleteAtIndex(index) || !frameHasDecodedNativeImageCompatibleWithOptionsAtIndex(index, subsamplingLevel, decodingOptions));
 
     // Clean the old native image and set a new one
-    cacheFrameNativeImageAtIndex(WTFMove(nativeImage), index, subsamplingLevel, decodingOptions);
+    cacheNativeImageAtIndex(WTFMove(nativeImage), index, subsamplingLevel, decodingOptions, decodingStatus);
     LOG(Images, "ImageFrameCache::%s - %p - url: %s [frame %ld has been cached]", __FUNCTION__, this, sourceURL().string().utf8().data(), index);
 
     // Notify the image with the readiness of the new frame NativeImage.
@@ -297,7 +300,7 @@ void ImageFrameCache::startAsyncDecodingQueue()
                 if (protectedQueue.ptr() == m_decodingQueue) {
                     ASSERT(m_frameCommitQueue.first() == frameRequest);
                     m_frameCommitQueue.removeFirst();
-                    cacheAsyncFrameNativeImageAtIndex(WTFMove(nativeImage), frameRequest.index, frameRequest.subsamplingLevel, frameRequest.decodingOptions);
+                    cacheNativeImageAtIndexAsync(WTFMove(nativeImage), frameRequest.index, frameRequest.subsamplingLevel, frameRequest.decodingOptions, frameRequest.decodingStatus);
                 } else
                     LOG(Images, "ImageFrameCache::%s - %p - url: %s [frame %ld will not cached]", __FUNCTION__, this, sourceURL().string().utf8().data(), frameRequest.index);
             });
@@ -305,31 +308,18 @@ void ImageFrameCache::startAsyncDecodingQueue()
     });
 }
 
-bool ImageFrameCache::requestFrameAsyncDecodingAtIndex(size_t index, SubsamplingLevel subsamplingLevel, const std::optional<IntSize>& sizeForDrawing)
+void ImageFrameCache::requestFrameAsyncDecodingAtIndex(size_t index, SubsamplingLevel subsamplingLevel, const std::optional<IntSize>& sizeForDrawing)
 {
-    if (!isDecoderAvailable())
-        return false;
-
-    // Allow new requests for the same frame if the frame is incomplete.
-    ASSERT(index < m_frames.size());
-    if (frameIsCompleteAtIndex(index)) {
-        // We need to coalesce multiple requests for decoding the same ImageFrame while it
-        // is still being decoded. This may happen if the image rectangle is repainted
-        // multiple times while the ImageFrame has not finished decoding.
-        if (frameIsBeingDecodedAndIsCompatibleWithOptionsAtIndex(index, sizeForDrawing))
-            return true;
-
-        if (frameHasDecodedNativeImageCompatibleWithOptionsAtIndex(index, subsamplingLevel, sizeForDrawing))
-            return false;
-    }
-
+    ASSERT(isDecoderAvailable());
     if (!hasAsyncDecodingQueue())
         startAsyncDecodingQueue();
+    
+    ASSERT(index < m_frames.size());
+    ImageFrame::DecodingStatus decodingStatus = m_decoder->frameIsCompleteAtIndex(index) ? ImageFrame::DecodingStatus::Complete : ImageFrame::DecodingStatus::Partial;
 
     LOG(Images, "ImageFrameCache::%s - %p - url: %s [enqueuing frame %ld for decoding]", __FUNCTION__, this, sourceURL().string().utf8().data(), index);
-    m_frameRequestQueue.enqueue({ index, subsamplingLevel, sizeForDrawing });
-    m_frameCommitQueue.append({ index, subsamplingLevel, sizeForDrawing });
-    return true;
+    m_frameRequestQueue.enqueue({ index, subsamplingLevel, sizeForDrawing, decodingStatus });
+    m_frameCommitQueue.append({ index, subsamplingLevel, sizeForDrawing, decodingStatus });
 }
 
 bool ImageFrameCache::isAsyncDecodingQueueIdle() const
@@ -344,7 +334,7 @@ void ImageFrameCache::stopAsyncDecodingQueue()
     
     std::for_each(m_frameCommitQueue.begin(), m_frameCommitQueue.end(), [this](const ImageFrameRequest& frameRequest) {
         ImageFrame& frame = m_frames[frameRequest.index];
-        if (!frame.isEmpty()) {
+        if (!frame.isInvalid()) {
             LOG(Images, "ImageFrameCache::%s - %p - url: %s [decoding has been cancelled for frame %ld]", __FUNCTION__, this, sourceURL().string().utf8().data(), frameRequest.index);
             frame.clear();
         }
@@ -370,7 +360,7 @@ const ImageFrame& ImageFrameCache::frameAtIndexCacheIfNeeded(size_t index, Image
         // Retrieve the metadata from ImageDecoder if the ImageFrame isn't complete.
         if (frame.isComplete())
             break;
-        cacheFrameMetadataAtIndex(index, subsamplingLevelValue);
+        cacheMetadataAtIndex(index, subsamplingLevelValue);
         break;
             
     case ImageFrame::Caching::MetadataAndImage:
@@ -380,7 +370,7 @@ const ImageFrame& ImageFrameCache::frameAtIndexCacheIfNeeded(size_t index, Image
         // We have to perform synchronous image decoding in this code. 
         NativeImagePtr nativeImage = m_decoder->createFrameImageAtIndex(index, subsamplingLevelValue);
         // Clean the old native image and set a new one.
-        cacheFrameNativeImageAtIndex(WTFMove(nativeImage), index, subsamplingLevelValue, DecodingMode::Synchronous);
+        cacheNativeImageAtIndex(WTFMove(nativeImage), index, subsamplingLevelValue, DecodingMode::Synchronous);
         break;
     }
 
@@ -509,9 +499,9 @@ bool ImageFrameCache::frameIsBeingDecodedAndIsCompatibleWithOptionsAtIndex(size_
     return it != m_frameCommitQueue.end();
 }
 
-bool ImageFrameCache::frameIsCompleteAtIndex(size_t index)
+ImageFrame::DecodingStatus ImageFrameCache::frameDecodingStatusAtIndex(size_t index)
 {
-    return frameMetadataAtIndex<bool>(index, (&ImageFrame::isComplete));
+    return frameMetadataAtIndex<ImageFrame::DecodingStatus>(index, (&ImageFrame::decodingStatus));
 }
 
 bool ImageFrameCache::frameHasAlphaAtIndex(size_t index)
index 897e73b..52d3603 100644 (file)
@@ -71,7 +71,7 @@ public:
     
     // Asynchronous image decoding
     void startAsyncDecodingQueue();
-    bool requestFrameAsyncDecodingAtIndex(size_t, SubsamplingLevel, const std::optional<IntSize>&);
+    void requestFrameAsyncDecodingAtIndex(size_t, SubsamplingLevel, const std::optional<IntSize>&);
     void stopAsyncDecodingQueue();
     bool hasAsyncDecodingQueue() const { return m_decodingQueue; }
     bool isAsyncDecodingQueueIdle() const;
@@ -94,13 +94,13 @@ public:
 
     // ImageFrame metadata which does not require caching the ImageFrame.
     bool frameIsBeingDecodedAndIsCompatibleWithOptionsAtIndex(size_t, const DecodingOptions&);
-    bool frameIsCompleteAtIndex(size_t);
+    ImageFrame::DecodingStatus frameDecodingStatusAtIndex(size_t);
     bool frameHasAlphaAtIndex(size_t);
     bool frameHasImageAtIndex(size_t);
     bool frameHasFullSizeNativeImageAtIndex(size_t, const std::optional<SubsamplingLevel>&);
     bool frameHasDecodedNativeImageCompatibleWithOptionsAtIndex(size_t, const std::optional<SubsamplingLevel>&, const DecodingOptions&);
     SubsamplingLevel frameSubsamplingLevelAtIndex(size_t);
-    
+
     // ImageFrame metadata which forces caching or re-caching the ImageFrame.
     IntSize frameSizeAtIndex(size_t, SubsamplingLevel = SubsamplingLevel::Default);
     unsigned frameBytesAtIndex(size_t, SubsamplingLevel = SubsamplingLevel::Default);
@@ -132,9 +132,9 @@ private:
     void decodedSizeReset(unsigned decodedSize);
 
     void setNativeImage(NativeImagePtr&&);
-    void cacheFrameMetadataAtIndex(size_t, SubsamplingLevel);
-    void cacheFrameNativeImageAtIndex(NativeImagePtr&&, size_t, SubsamplingLevel, const DecodingOptions&);
-    void cacheAsyncFrameNativeImageAtIndex(NativeImagePtr&&, size_t, SubsamplingLevel, const DecodingOptions&);
+    void cacheMetadataAtIndex(size_t, SubsamplingLevel, ImageFrame::DecodingStatus = ImageFrame::DecodingStatus::Invalid);
+    void cacheNativeImageAtIndex(NativeImagePtr&&, size_t, SubsamplingLevel, const DecodingOptions&, ImageFrame::DecodingStatus = ImageFrame::DecodingStatus::Invalid);
+    void cacheNativeImageAtIndexAsync(NativeImagePtr&&, size_t, SubsamplingLevel, const DecodingOptions&, ImageFrame::DecodingStatus);
 
     Ref<WorkQueue> decodingQueue();
 
@@ -152,9 +152,10 @@ private:
         size_t index;
         SubsamplingLevel subsamplingLevel;
         DecodingOptions decodingOptions;
+        ImageFrame::DecodingStatus decodingStatus;
         bool operator==(const ImageFrameRequest& other) const
         {
-            return index == other.index && subsamplingLevel == other.subsamplingLevel && decodingOptions == other.decodingOptions;
+            return index == other.index && subsamplingLevel == other.subsamplingLevel && decodingOptions == other.decodingOptions && decodingStatus == other.decodingStatus;
         }
     };
     static const int BufferSize = 8;
index 2895f4d..d8d9feb 100644 (file)
@@ -113,8 +113,6 @@ void ImageSource::setData(SharedBuffer* data, bool allDataReceived)
 
 EncodedDataStatus ImageSource::dataChanged(SharedBuffer* data, bool allDataReceived)
 {
-    m_frameCache->destroyIncompleteDecodedData();
-
 #if PLATFORM(IOS)
     // FIXME: We should expose a setting to enable/disable progressive loading and make this
     // code conditional on it. Then we can remove the PLATFORM(IOS)-guard.
index 387e8ca..acb20b2 100644 (file)
@@ -57,6 +57,7 @@ public:
     void destroyAllDecodedData() { m_frameCache->destroyAllDecodedData(); }
     void destroyAllDecodedDataExcludeFrame(size_t excludeFrame) { m_frameCache->destroyAllDecodedDataExcludeFrame(excludeFrame); }
     void destroyDecodedDataBeforeFrame(size_t beforeFrame) { m_frameCache->destroyDecodedDataBeforeFrame(beforeFrame); }
+    void destroyIncompleteDecodedData() { m_frameCache->destroyIncompleteDecodedData(); }
     void clearFrameBufferCache(size_t);
     void clear(SharedBuffer* data);
 
@@ -70,7 +71,7 @@ public:
     bool isAllDataReceived();
 
     bool shouldUseAsyncDecoding();
-    bool requestFrameAsyncDecodingAtIndex(size_t index, SubsamplingLevel subsamplingLevel, const std::optional<IntSize>& sizeForDrawing = { }) { return m_frameCache->requestFrameAsyncDecodingAtIndex(index, subsamplingLevel, sizeForDrawing); }
+    void requestFrameAsyncDecodingAtIndex(size_t index, SubsamplingLevel subsamplingLevel, const std::optional<IntSize>& sizeForDrawing = { }) { m_frameCache->requestFrameAsyncDecodingAtIndex(index, subsamplingLevel, sizeForDrawing); }
     bool hasAsyncDecodingQueue() const { return m_frameCache->hasAsyncDecodingQueue(); }
     bool isAsyncDecodingQueueIdle() const  { return m_frameCache->isAsyncDecodingQueueIdle(); }
     void stopAsyncDecodingQueue() { m_frameCache->stopAsyncDecodingQueue(); }
@@ -90,7 +91,7 @@ public:
 
     // ImageFrame metadata which does not require caching the ImageFrame.
     bool frameIsBeingDecodedAndIsCompatibleWithOptionsAtIndex(size_t index, const DecodingOptions& decodingOptions) { return m_frameCache->frameIsBeingDecodedAndIsCompatibleWithOptionsAtIndex(index, decodingOptions); }
-    bool frameIsCompleteAtIndex(size_t index) { return m_frameCache->frameIsCompleteAtIndex(index); }
+    ImageFrame::DecodingStatus frameDecodingStatusAtIndex(size_t index) { return m_frameCache->frameDecodingStatusAtIndex(index); }
     bool frameHasAlphaAtIndex(size_t index) { return m_frameCache->frameHasAlphaAtIndex(index); }
     bool frameHasImageAtIndex(size_t index) { return m_frameCache->frameHasImageAtIndex(index); }
     bool frameHasFullSizeNativeImageAtIndex(size_t index, const std::optional<SubsamplingLevel>& subsamplingLevel) { return m_frameCache->frameHasFullSizeNativeImageAtIndex(index, subsamplingLevel); }
index 89ae3ff..4179352 100644 (file)
@@ -196,7 +196,7 @@ unsigned ImageDecoder::frameBytesAtIndex(size_t index) const
 float ImageDecoder::frameDurationAtIndex(size_t index)
 {
     ImageFrame* buffer = frameBufferAtIndex(index);
-    if (!buffer || buffer->isEmpty())
+    if (!buffer || buffer->isInvalid())
         return 0;
     
     // Many annoying ads specify a 0 duration to make an image flash as quickly as possible.
@@ -216,7 +216,7 @@ NativeImagePtr ImageDecoder::createFrameImageAtIndex(size_t index, SubsamplingLe
         return nullptr;
 
     ImageFrame* buffer = frameBufferAtIndex(index);
-    if (!buffer || buffer->isEmpty() || !buffer->hasBackingStore())
+    if (!buffer || buffer->isInvalid() || !buffer->hasBackingStore())
         return nullptr;
 
     // Return the buffer contents as a native image. For some ports, the data
index 2212f14..8d68a40 100644 (file)
@@ -77,11 +77,11 @@ bool BMPImageReader::decodeBMP(bool onlySize)
 
     // Initialize the framebuffer if needed.
     ASSERT(m_buffer);  // Parent should set this before asking us to decode!
-    if (m_buffer->isEmpty()) {
+    if (m_buffer->isInvalid()) {
         if (!m_buffer->initialize(m_parent->size(), m_parent->premultiplyAlpha()))
             return m_parent->setFailed(); // Unable to allocate.
 
-        m_buffer->setDecoding(ImageFrame::Decoding::Partial);
+        m_buffer->setDecodingStatus(ImageFrame::DecodingStatus::Partial);
         m_buffer->setHasAlpha(false);
 
         if (!m_isTopDown)
@@ -117,7 +117,7 @@ bool BMPImageReader::decodeBMP(bool onlySize)
     }
 
     // Done!
-    m_buffer->setDecoding(ImageFrame::Decoding::Complete);
+    m_buffer->setDecodingStatus(ImageFrame::DecodingStatus::Complete);
     return true;
 }
 
index f37a77c..fd0cc75 100644 (file)
@@ -159,7 +159,7 @@ void GIFImageDecoder::clearFrameBufferCache(size_t clearBeforeFrame)
     //     has a disposal method other than DisposalMethod::RestoreToPrevious, stop
     //     scanning, as we'll only need this frame when decoding the next one.
     Vector<ImageFrame>::iterator i(end);
-    for (; (i != m_frameBufferCache.begin()) && (i->isEmpty() || (i->disposalMethod() == ImageFrame::DisposalMethod::RestoreToPrevious)); --i) {
+    for (; (i != m_frameBufferCache.begin()) && (i->isInvalid() || (i->disposalMethod() == ImageFrame::DisposalMethod::RestoreToPrevious)); --i) {
         if (i->isComplete() && (i != end))
             i->clear();
     }
@@ -167,7 +167,7 @@ void GIFImageDecoder::clearFrameBufferCache(size_t clearBeforeFrame)
     // Now |i| holds the last frame we need to preserve; clear prior frames.
     for (Vector<ImageFrame>::iterator j(m_frameBufferCache.begin()); j != i; ++j) {
         ASSERT(!j->isPartial());
-        if (j->isEmpty())
+        if (j->isInvalid())
             j->clear();
     }
 
@@ -207,7 +207,7 @@ bool GIFImageDecoder::haveDecodedRow(unsigned frameIndex, const Vector<unsigned
 
     // Initialize the frame if necessary.
     ImageFrame& buffer = m_frameBufferCache[frameIndex];
-    if ((buffer.isEmpty() && !initFrameBuffer(frameIndex)) || !buffer.hasBackingStore())
+    if ((buffer.isInvalid() && !initFrameBuffer(frameIndex)) || !buffer.hasBackingStore())
         return false;
 
     RGBA32* currentAddress = buffer.backingStore()->pixelAt(xBegin, yBegin);
@@ -244,10 +244,10 @@ bool GIFImageDecoder::frameComplete(unsigned frameIndex, unsigned frameDuration,
     // Initialize the frame if necessary.  Some GIFs insert do-nothing frames,
     // in which case we never reach haveDecodedRow() before getting here.
     ImageFrame& buffer = m_frameBufferCache[frameIndex];
-    if (buffer.isEmpty() && !initFrameBuffer(frameIndex))
+    if (buffer.isInvalid() && !initFrameBuffer(frameIndex))
         return false; // initFrameBuffer() has already called setFailed().
 
-    buffer.setDecoding(ImageFrame::Decoding::Complete);
+    buffer.setDecodingStatus(ImageFrame::DecodingStatus::Complete);
     buffer.setDuration(frameDuration);
     buffer.setDisposalMethod(disposalMethod);
 
@@ -401,7 +401,7 @@ bool GIFImageDecoder::initFrameBuffer(unsigned frameIndex)
     buffer->backingStore()->setFrameRect(IntRect(left, top, right - left, bottom - top));
 
     // Update our status to be partially complete.
-    buffer->setDecoding(ImageFrame::Decoding::Partial);
+    buffer->setDecodingStatus(ImageFrame::DecodingStatus::Partial);
 
     // Reset the alpha pixel tracker for this frame.
     m_currentBufferSawAlpha = false;
index 836c553..86ae04c 100644 (file)
@@ -605,10 +605,10 @@ bool JPEGImageDecoder::outputScanlines()
 
     // Initialize the framebuffer if needed.
     ImageFrame& buffer = m_frameBufferCache[0];
-    if (buffer.isEmpty()) {
+    if (buffer.isInvalid()) {
         if (!buffer.initialize(scaledSize(), m_premultiplyAlpha))
             return setFailed();
-        buffer.setDecoding(ImageFrame::Decoding::Partial);
+        buffer.setDecodingStatus(ImageFrame::DecodingStatus::Partial);
         // The buffer is transparent outside the decoded area while the image is
         // loading. The completed image will be marked fully opaque in jpegComplete().
         buffer.setHasAlpha(true);
@@ -652,7 +652,7 @@ void JPEGImageDecoder::jpegComplete()
     // empty.
     ImageFrame& buffer = m_frameBufferCache[0];
     buffer.setHasAlpha(false);
-    buffer.setDecoding(ImageFrame::Decoding::Complete);
+    buffer.setDecodingStatus(ImageFrame::DecodingStatus::Complete);
 }
 
 void JPEGImageDecoder::decode(bool onlySize, bool allDataReceived)
index 17c5707..8a4f711 100644 (file)
@@ -430,7 +430,7 @@ void PNGImageDecoder::rowAvailable(unsigned char* rowBuffer, unsigned rowIndex,
         return;
 #endif
     ImageFrame& buffer = m_frameBufferCache[m_currentFrame];
-    if (buffer.isEmpty()) {
+    if (buffer.isInvalid()) {
         png_structp png = m_reader->pngPtr();
         if (!buffer.initialize(scaledSize(), m_premultiplyAlpha)) {
             longjmp(JMPBUF(png), 1);
@@ -448,7 +448,7 @@ void PNGImageDecoder::rowAvailable(unsigned char* rowBuffer, unsigned rowIndex,
             }
         }
 
-        buffer.setDecoding(ImageFrame::Decoding::Partial);
+        buffer.setDecodingStatus(ImageFrame::DecodingStatus::Partial);
         buffer.setHasAlpha(false);
 
 #if ENABLE(APNG)
@@ -556,7 +556,7 @@ void PNGImageDecoder::pngComplete()
     }
 #endif
     if (!m_frameBufferCache.isEmpty())
-        m_frameBufferCache.first().setDecoding(ImageFrame::Decoding::Complete);
+        m_frameBufferCache.first().setDecodingStatus(ImageFrame::DecodingStatus::Complete);
 }
 
 void PNGImageDecoder::decode(bool onlySize, unsigned haltAtFrame, bool allDataReceived)
@@ -740,7 +740,7 @@ void PNGImageDecoder::clearFrameBufferCache(size_t clearBeforeFrame)
     const Vector<ImageFrame>::iterator end(m_frameBufferCache.begin() + clearBeforeFrame);
 
     Vector<ImageFrame>::iterator i(end);
-    for (; (i != m_frameBufferCache.begin()) && (i->isEmpty() || (i->disposalMethod() == ImageFrame::DisposalMethod::RestoreToPrevious)); --i) {
+    for (; (i != m_frameBufferCache.begin()) && (i->isInvalid() || (i->disposalMethod() == ImageFrame::DisposalMethod::RestoreToPrevious)); --i) {
         if (i->isComplete() && (i != end))
             i->clear();
     }
@@ -748,7 +748,7 @@ void PNGImageDecoder::clearFrameBufferCache(size_t clearBeforeFrame)
     // Now |i| holds the last frame we need to preserve; clear prior frames.
     for (Vector<ImageFrame>::iterator j(m_frameBufferCache.begin()); j != i; ++j) {
         ASSERT(!j->isPartial());
-        if (j->isEmpty())
+        if (j->isInvalid())
             j->clear();
     }
 }
@@ -823,7 +823,7 @@ void PNGImageDecoder::frameComplete()
         return;
 
     ImageFrame& buffer = m_frameBufferCache[m_currentFrame];
-    buffer.setDecoding(ImageFrame::Decoding::Complete);
+    buffer.setDecodingStatus(ImageFrame::DecodingStatus::Complete);
 
     png_bytep interlaceBuffer = m_reader->interlaceBuffer();
 
index e88a81a..48cf5ad 100644 (file)
@@ -116,10 +116,10 @@ bool WEBPImageDecoder::decode(bool onlySize, bool)
     ImageFrame& buffer = m_frameBufferCache[0];
     ASSERT(!buffer.isComplete());
 
-    if (buffer.isEmpty()) {
+    if (buffer.isInvalid()) {
         if (!buffer.initialize(size(), m_premultiplyAlpha))
             return setFailed();
-        buffer.setDecoding(ImageFrame::Decoding::Partial);
+        buffer.setDecodingStatus(ImageFrame::DecodingStatus::Partial);
         buffer.setHasAlpha(m_hasAlpha);
     }
 
@@ -137,7 +137,7 @@ bool WEBPImageDecoder::decode(bool onlySize, bool)
 
     switch (WebPIUpdate(m_decoder, dataBytes, dataSize)) {
     case VP8_STATUS_OK:
-        buffer.setDecoding(ImageFrame::Decoding::Complete);
+        buffer.setDecodingStatus(ImageFrame::DecodingStatus::Complete);
         clear();
         return true;
     case VP8_STATUS_SUSPENDED: