Title: [216907] branches/safari-604.1.21-branch/Source/WebCore

Diff

Modified: branches/safari-604.1.21-branch/Source/WebCore/ChangeLog (216906 => 216907)


--- branches/safari-604.1.21-branch/Source/WebCore/ChangeLog	2017-05-16 06:19:34 UTC (rev 216906)
+++ branches/safari-604.1.21-branch/Source/WebCore/ChangeLog	2017-05-16 06:19:40 UTC (rev 216907)
@@ -1,5 +1,102 @@
 2017-05-15  Matthew Hanson  <matthew_han...@apple.com>
 
+        Cherry-pick r216882. rdar://problem/32109397
+
+    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  Matthew Hanson  <matthew_han...@apple.com>
+
         Cherry-pick r216863. rdar://problem/31963192
 
     2017-05-15  Brent Fulgham  <bfulg...@apple.com>

Modified: branches/safari-604.1.21-branch/Source/WebCore/platform/graphics/BitmapImage.cpp (216906 => 216907)


--- branches/safari-604.1.21-branch/Source/WebCore/platform/graphics/BitmapImage.cpp	2017-05-16 06:19:34 UTC (rev 216906)
+++ branches/safari-604.1.21-branch/Source/WebCore/platform/graphics/BitmapImage.cpp	2017-05-16 06:19:40 UTC (rev 216907)
@@ -80,8 +80,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.
@@ -108,6 +110,10 @@
 
 EncodedDataStatus BitmapImage::dataChanged(bool allDataReceived)
 {
+    if (!shouldUseAsyncDecodingForLargeImages())
+        m_source.destroyIncompleteDecodedData();
+
+    m_currentFrameDecodingStatus = ImageFrame::DecodingStatus::Invalid;
     return m_source.dataChanged(data(), allDataReceived);
 }
 
@@ -184,13 +190,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)) {
@@ -200,7 +206,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();
@@ -237,6 +242,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);
@@ -361,16 +367,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)
@@ -416,6 +419,8 @@
 
     destroyDecodedDataIfNecessary(false);
 
+    if (m_currentFrameDecodingStatus == ImageFrame::DecodingStatus::Decoding)
+        m_currentFrameDecodingStatus = frameDecodingStatusAtIndex(m_currentFrame);
     if (imageObserver())
         imageObserver()->imageFrameAvailable(this, ImageAnimatingState::Yes);
 
@@ -463,10 +468,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: branches/safari-604.1.21-branch/Source/WebCore/platform/graphics/BitmapImage.h (216906 => 216907)


--- branches/safari-604.1.21-branch/Source/WebCore/platform/graphics/BitmapImage.h	2017-05-16 06:19:34 UTC (rev 216906)
+++ branches/safari-604.1.21-branch/Source/WebCore/platform/graphics/BitmapImage.h	2017-05-16 06:19:40 UTC (rev 216907)
@@ -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: branches/safari-604.1.21-branch/Source/WebCore/platform/graphics/ImageFrame.cpp (216906 => 216907)


--- branches/safari-604.1.21-branch/Source/WebCore/platform/graphics/ImageFrame.cpp	2017-05-16 06:19:34 UTC (rev 216906)
+++ branches/safari-604.1.21-branch/Source/WebCore/platform/graphics/ImageFrame.cpp	2017-05-16 06:19:40 UTC (rev 216907)
@@ -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: branches/safari-604.1.21-branch/Source/WebCore/platform/graphics/ImageFrame.h (216906 => 216907)


--- branches/safari-604.1.21-branch/Source/WebCore/platform/graphics/ImageFrame.h	2017-05-16 06:19:34 UTC (rev 216906)
+++ branches/safari-604.1.21-branch/Source/WebCore/platform/graphics/ImageFrame.h	2017-05-16 06:19:40 UTC (rev 216907)
@@ -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: branches/safari-604.1.21-branch/Source/WebCore/platform/graphics/ImageFrameCache.cpp (216906 => 216907)


--- branches/safari-604.1.21-branch/Source/WebCore/platform/graphics/ImageFrameCache.cpp	2017-05-16 06:19:34 UTC (rev 216906)
+++ branches/safari-604.1.21-branch/Source/WebCore/platform/graphics/ImageFrameCache.cpp	2017-05-16 06:19:40 UTC (rev 216907)
@@ -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;
     }
 
@@ -503,9 +493,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: branches/safari-604.1.21-branch/Source/WebCore/platform/graphics/ImageFrameCache.h (216906 => 216907)


--- branches/safari-604.1.21-branch/Source/WebCore/platform/graphics/ImageFrameCache.h	2017-05-16 06:19:34 UTC (rev 216906)
+++ branches/safari-604.1.21-branch/Source/WebCore/platform/graphics/ImageFrameCache.h	2017-05-16 06:19:40 UTC (rev 216907)
@@ -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: branches/safari-604.1.21-branch/Source/WebCore/platform/graphics/ImageSource.cpp (216906 => 216907)


--- branches/safari-604.1.21-branch/Source/WebCore/platform/graphics/ImageSource.cpp	2017-05-16 06:19:34 UTC (rev 216906)
+++ branches/safari-604.1.21-branch/Source/WebCore/platform/graphics/ImageSource.cpp	2017-05-16 06:19:40 UTC (rev 216907)
@@ -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: branches/safari-604.1.21-branch/Source/WebCore/platform/graphics/ImageSource.h (216906 => 216907)


--- branches/safari-604.1.21-branch/Source/WebCore/platform/graphics/ImageSource.h	2017-05-16 06:19:34 UTC (rev 216906)
+++ branches/safari-604.1.21-branch/Source/WebCore/platform/graphics/ImageSource.h	2017-05-16 06:19:40 UTC (rev 216907)
@@ -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: branches/safari-604.1.21-branch/Source/WebCore/platform/image-decoders/ImageDecoder.cpp (216906 => 216907)


--- branches/safari-604.1.21-branch/Source/WebCore/platform/image-decoders/ImageDecoder.cpp	2017-05-16 06:19:34 UTC (rev 216906)
+++ branches/safari-604.1.21-branch/Source/WebCore/platform/image-decoders/ImageDecoder.cpp	2017-05-16 06:19:40 UTC (rev 216907)
@@ -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: branches/safari-604.1.21-branch/Source/WebCore/platform/image-decoders/bmp/BMPImageReader.cpp (216906 => 216907)


--- branches/safari-604.1.21-branch/Source/WebCore/platform/image-decoders/bmp/BMPImageReader.cpp	2017-05-16 06:19:34 UTC (rev 216906)
+++ branches/safari-604.1.21-branch/Source/WebCore/platform/image-decoders/bmp/BMPImageReader.cpp	2017-05-16 06:19:40 UTC (rev 216907)
@@ -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: branches/safari-604.1.21-branch/Source/WebCore/platform/image-decoders/gif/GIFImageDecoder.cpp (216906 => 216907)


--- branches/safari-604.1.21-branch/Source/WebCore/platform/image-decoders/gif/GIFImageDecoder.cpp	2017-05-16 06:19:34 UTC (rev 216906)
+++ branches/safari-604.1.21-branch/Source/WebCore/platform/image-decoders/gif/GIFImageDecoder.cpp	2017-05-16 06:19:40 UTC (rev 216907)
@@ -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: branches/safari-604.1.21-branch/Source/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.cpp (216906 => 216907)


--- branches/safari-604.1.21-branch/Source/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.cpp	2017-05-16 06:19:34 UTC (rev 216906)
+++ branches/safari-604.1.21-branch/Source/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.cpp	2017-05-16 06:19:40 UTC (rev 216907)
@@ -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: branches/safari-604.1.21-branch/Source/WebCore/platform/image-decoders/png/PNGImageDecoder.cpp (216906 => 216907)


--- branches/safari-604.1.21-branch/Source/WebCore/platform/image-decoders/png/PNGImageDecoder.cpp	2017-05-16 06:19:34 UTC (rev 216906)
+++ branches/safari-604.1.21-branch/Source/WebCore/platform/image-decoders/png/PNGImageDecoder.cpp	2017-05-16 06:19:40 UTC (rev 216907)
@@ -429,7 +429,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);
@@ -447,7 +447,7 @@
             }
         }
 
-        buffer.setDecoding(ImageFrame::Decoding::Partial);
+        buffer.setDecodingStatus(ImageFrame::DecodingStatus::Partial);
         buffer.setHasAlpha(false);
 
 #if ENABLE(APNG)
@@ -555,7 +555,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)
@@ -739,7 +739,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();
     }
@@ -747,7 +747,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();
     }
 }
@@ -822,7 +822,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: branches/safari-604.1.21-branch/Source/WebCore/platform/image-decoders/webp/WEBPImageDecoder.cpp (216906 => 216907)


--- branches/safari-604.1.21-branch/Source/WebCore/platform/image-decoders/webp/WEBPImageDecoder.cpp	2017-05-16 06:19:34 UTC (rev 216906)
+++ branches/safari-604.1.21-branch/Source/WebCore/platform/image-decoders/webp/WEBPImageDecoder.cpp	2017-05-16 06:19:40 UTC (rev 216907)
@@ -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