Title: [216882] trunk/Source/WebCore
Revision
216882
Author
commit-qu...@webkit.org
Date
2017-05-15 15:10:37 -0700 (Mon, 15 May 2017)

Log Message

REGRESSION (216471): Infinite repaint-drawing loop when asynchronously decoding incomplete image frames
https://bugs.webkit.org/show_bug.cgi?id=171900

Patch by Said Abou-Hallawa <sabouhall...@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):

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (216881 => 216882)


--- trunk/Source/WebCore/ChangeLog	2017-05-15 22:07:54 UTC (rev 216881)
+++ trunk/Source/WebCore/ChangeLog	2017-05-15 22:10:37 UTC (rev 216882)
@@ -1,3 +1,96 @@
+2017-05-15  Said Abou-Hallawa  <sabouhall...@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  <cdu...@apple.com>
 
         Align WebKitCSSMatrix stringifier with spec for DOMMatrix

Modified: trunk/Source/WebCore/platform/graphics/BitmapImage.cpp (216881 => 216882)


--- trunk/Source/WebCore/platform/graphics/BitmapImage.cpp	2017-05-15 22:07:54 UTC (rev 216881)
+++ trunk/Source/WebCore/platform/graphics/BitmapImage.cpp	2017-05-15 22:10:37 UTC (rev 216882)
@@ -81,8 +81,10 @@
         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 @@
 
 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 @@
 
         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 @@
         }
 
         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 @@
         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 @@
     // 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)
+        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 {
+            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);
-        else
-            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
+        }
 
         m_desiredFrameDecodeTimeForTesting = time + std::max(m_frameDecodingDurationForTesting, 0_s);
         if (m_clearDecoderAfterAsyncFrameRequestForTesting)
@@ -417,6 +420,8 @@
 
     destroyDecodedDataIfNecessary(false);
 
+    if (m_currentFrameDecodingStatus == ImageFrame::DecodingStatus::Decoding)
+        m_currentFrameDecodingStatus = frameDecodingStatusAtIndex(m_currentFrame);
     if (imageObserver())
         imageObserver()->imageFrameAvailable(this, ImageAnimatingState::Yes);
 
@@ -464,10 +469,12 @@
             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);
     }
 }
 

Modified: trunk/Source/WebCore/platform/graphics/BitmapImage.h (216881 => 216882)


--- trunk/Source/WebCore/platform/graphics/BitmapImage.h	2017-05-15 22:07:54 UTC (rev 216881)
+++ trunk/Source/WebCore/platform/graphics/BitmapImage.h	2017-05-15 22:10:37 UTC (rev 216882)
@@ -86,7 +86,8 @@
     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 @@
 
     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().

Modified: trunk/Source/WebCore/platform/graphics/ImageFrame.cpp (216881 => 216882)


--- trunk/Source/WebCore/platform/graphics/ImageFrame.cpp	2017-05-15 22:07:54 UTC (rev 216881)
+++ trunk/Source/WebCore/platform/graphics/ImageFrame.cpp	2017-05-15 22:10:37 UTC (rev 216882)
@@ -50,7 +50,7 @@
     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 @@
     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)

Modified: trunk/Source/WebCore/platform/graphics/ImageFrame.h (216881 => 216882)


--- trunk/Source/WebCore/platform/graphics/ImageFrame.h	2017-05-15 22:07:54 UTC (rev 216881)
+++ trunk/Source/WebCore/platform/graphics/ImageFrame.h	2017-05-15 22:10:37 UTC (rev 216882)
@@ -40,7 +40,7 @@
     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 @@
     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 @@
     Color singlePixelSolidColor() const;
 
 private:
-    Decoding m_decoding { Decoding::None };
+    DecodingStatus m_decodingStatus { DecodingStatus::Invalid };
     IntSize m_size;
 
 #if !USE(CG)

Modified: trunk/Source/WebCore/platform/graphics/ImageFrameCache.cpp (216881 => 216882)


--- trunk/Source/WebCore/platform/graphics/ImageFrameCache.cpp	2017-05-15 22:07:54 UTC (rev 216881)
+++ trunk/Source/WebCore/platform/graphics/ImageFrameCache.cpp	2017-05-15 22:10:37 UTC (rev 216882)
@@ -189,18 +189,22 @@
 
     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 @@
         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 @@
     // 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 @@
                 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 @@
     });
 }
 
-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 @@
     
     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 @@
         // 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 @@
         // 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 @@
     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)

Modified: trunk/Source/WebCore/platform/graphics/ImageFrameCache.h (216881 => 216882)


--- trunk/Source/WebCore/platform/graphics/ImageFrameCache.h	2017-05-15 22:07:54 UTC (rev 216881)
+++ trunk/Source/WebCore/platform/graphics/ImageFrameCache.h	2017-05-15 22:10:37 UTC (rev 216882)
@@ -71,7 +71,7 @@
     
     // 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 @@
 
     // 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 @@
     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 @@
         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;

Modified: trunk/Source/WebCore/platform/graphics/ImageSource.cpp (216881 => 216882)


--- trunk/Source/WebCore/platform/graphics/ImageSource.cpp	2017-05-15 22:07:54 UTC (rev 216881)
+++ trunk/Source/WebCore/platform/graphics/ImageSource.cpp	2017-05-15 22:10:37 UTC (rev 216882)
@@ -113,8 +113,6 @@
 
 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.

Modified: trunk/Source/WebCore/platform/graphics/ImageSource.h (216881 => 216882)


--- trunk/Source/WebCore/platform/graphics/ImageSource.h	2017-05-15 22:07:54 UTC (rev 216881)
+++ trunk/Source/WebCore/platform/graphics/ImageSource.h	2017-05-15 22:10:37 UTC (rev 216882)
@@ -57,6 +57,7 @@
     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 @@
     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 @@
 
     // 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); }

Modified: trunk/Source/WebCore/platform/image-decoders/ImageDecoder.cpp (216881 => 216882)


--- trunk/Source/WebCore/platform/image-decoders/ImageDecoder.cpp	2017-05-15 22:07:54 UTC (rev 216881)
+++ trunk/Source/WebCore/platform/image-decoders/ImageDecoder.cpp	2017-05-15 22:10:37 UTC (rev 216882)
@@ -196,7 +196,7 @@
 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 @@
         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

Modified: trunk/Source/WebCore/platform/image-decoders/bmp/BMPImageReader.cpp (216881 => 216882)


--- trunk/Source/WebCore/platform/image-decoders/bmp/BMPImageReader.cpp	2017-05-15 22:07:54 UTC (rev 216881)
+++ trunk/Source/WebCore/platform/image-decoders/bmp/BMPImageReader.cpp	2017-05-15 22:10:37 UTC (rev 216882)
@@ -77,11 +77,11 @@
 
     // 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 @@
     }
 
     // Done!
-    m_buffer->setDecoding(ImageFrame::Decoding::Complete);
+    m_buffer->setDecodingStatus(ImageFrame::DecodingStatus::Complete);
     return true;
 }
 

Modified: trunk/Source/WebCore/platform/image-decoders/gif/GIFImageDecoder.cpp (216881 => 216882)


--- trunk/Source/WebCore/platform/image-decoders/gif/GIFImageDecoder.cpp	2017-05-15 22:07:54 UTC (rev 216881)
+++ trunk/Source/WebCore/platform/image-decoders/gif/GIFImageDecoder.cpp	2017-05-15 22:10:37 UTC (rev 216882)
@@ -159,7 +159,7 @@
     //     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 @@
     // 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 @@
 
     // 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 @@
     // 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 @@
     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;

Modified: trunk/Source/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.cpp (216881 => 216882)


--- trunk/Source/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.cpp	2017-05-15 22:07:54 UTC (rev 216881)
+++ trunk/Source/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.cpp	2017-05-15 22:10:37 UTC (rev 216882)
@@ -605,10 +605,10 @@
 
     // 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 @@
     // 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)

Modified: trunk/Source/WebCore/platform/image-decoders/png/PNGImageDecoder.cpp (216881 => 216882)


--- trunk/Source/WebCore/platform/image-decoders/png/PNGImageDecoder.cpp	2017-05-15 22:07:54 UTC (rev 216881)
+++ trunk/Source/WebCore/platform/image-decoders/png/PNGImageDecoder.cpp	2017-05-15 22:10:37 UTC (rev 216882)
@@ -430,7 +430,7 @@
         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 @@
             }
         }
 
-        buffer.setDecoding(ImageFrame::Decoding::Partial);
+        buffer.setDecodingStatus(ImageFrame::DecodingStatus::Partial);
         buffer.setHasAlpha(false);
 
 #if ENABLE(APNG)
@@ -556,7 +556,7 @@
     }
 #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 @@
     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 @@
     // 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 @@
         return;
 
     ImageFrame& buffer = m_frameBufferCache[m_currentFrame];
-    buffer.setDecoding(ImageFrame::Decoding::Complete);
+    buffer.setDecodingStatus(ImageFrame::DecodingStatus::Complete);
 
     png_bytep interlaceBuffer = m_reader->interlaceBuffer();
 

Modified: trunk/Source/WebCore/platform/image-decoders/webp/WEBPImageDecoder.cpp (216881 => 216882)


--- trunk/Source/WebCore/platform/image-decoders/webp/WEBPImageDecoder.cpp	2017-05-15 22:07:54 UTC (rev 216881)
+++ trunk/Source/WebCore/platform/image-decoders/webp/WEBPImageDecoder.cpp	2017-05-15 22:10:37 UTC (rev 216882)
@@ -116,10 +116,10 @@
     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 @@
 
     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:
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to