REGRESSION(r219045): A partially loaded image may not be repainted when its complete...
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 22 Jul 2017 12:12:33 +0000 (12:12 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 22 Jul 2017 12:12:33 +0000 (12:12 +0000)
https://bugs.webkit.org/show_bug.cgi?id=174230

Patch by Said Abou-Hallawa <sabouhallawa@apple.com> on 2017-07-22
Reviewed by Simon Fraser.

Because of r219045, we now only repaint the CachedImageClinets which tried
to draw the image but they could not because they have to wait for the image
decoding to finish. This was done by keeping a HashSet of these clients
and make CachedImage own it. This HashSet is cleared once the image frame
finishes decoding and all the waited clients are repainted.

But Multiple asynchronous image decoding requests are allowed for the same
frame if new data is added to the image source. If we tried to draw the
same image twice before it finishes decoding the first request, we will
not be to record this second request since the HashSet will not add the
same client twice. When he second request finishes decoding, CachedImage
will not repaint any client since its HashSet is empty.

To fix this problem we can do the following. When an image frame finishes
decoding, CachedImage will keep its HashSet of pending drawing clients as
long as the image frame is a partially loaded frame.

* loader/cache/CachedImage.cpp:
(WebCore::CachedImage::CachedImageObserver::imageFrameAvailable):
(WebCore::CachedImage::imageFrameAvailable):
* loader/cache/CachedImage.h:
* platform/graphics/BitmapImage.cpp:
(WebCore::BitmapImage::destroyDecodedData):
(WebCore::BitmapImage::dataChanged):
(WebCore::BitmapImage::setCurrentFrameDecodingStatusIfNecessary):
(WebCore::BitmapImage::draw):
(WebCore::BitmapImage::internalStartAnimation):
(WebCore::BitmapImage::internalAdvanceAnimation):
(WebCore::BitmapImage::imageFrameAvailableAtIndex):
* platform/graphics/BitmapImage.h:
* platform/graphics/ImageFrame.cpp:
(WebCore::ImageFrame::decodingStatus):
* platform/graphics/ImageFrame.h: Move DecodingStatus out of this class
to ImageTypes.h to avoid adding other header files to ImageObvsever.h
* platform/graphics/ImageFrameCache.cpp:
(WebCore::ImageFrameCache::setNativeImage):
(WebCore::ImageFrameCache::cacheMetadataAtIndex):
(WebCore::ImageFrameCache::cacheNativeImageAtIndex):
(WebCore::ImageFrameCache::cacheNativeImageAtIndexAsync):
(WebCore::ImageFrameCache::requestFrameAsyncDecodingAtIndex):
(WebCore::ImageFrameCache::frameDecodingStatusAtIndex):
* platform/graphics/ImageFrameCache.h:
* platform/graphics/ImageObserver.h:
* platform/graphics/ImageSource.h:
(WebCore::ImageSource::frameDecodingStatusAtIndex):
* platform/graphics/ImageTypes.h:
* platform/image-decoders/bmp/BMPImageReader.cpp:
(WebCore::BMPImageReader::decodeBMP):
* platform/image-decoders/gif/GIFImageDecoder.cpp:
(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::frameComplete):
* platform/image-decoders/webp/WEBPImageDecoder.cpp:
(WebCore::WEBPImageDecoder::decode):
* rendering/RenderBoxModelObject.cpp:
(WebCore::RenderBoxModelObject::decodingModeForImageDraw):

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

18 files changed:
Source/WebCore/ChangeLog
Source/WebCore/loader/cache/CachedImage.cpp
Source/WebCore/loader/cache/CachedImage.h
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/ImageObserver.h
Source/WebCore/platform/graphics/ImageSource.h
Source/WebCore/platform/graphics/ImageTypes.h
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
Source/WebCore/rendering/RenderBoxModelObject.cpp

index a82c7703cf0021ff1346a56007a5ef5c590b12c5..9709df4548c742f4ba3ccc29dfea2fab221a8a87 100644 (file)
@@ -1,3 +1,73 @@
+2017-07-22  Said Abou-Hallawa  <sabouhallawa@apple.com>
+
+        REGRESSION(r219045): A partially loaded image may not be repainted when its complete frame finishes decoding
+        https://bugs.webkit.org/show_bug.cgi?id=174230
+
+        Reviewed by Simon Fraser.
+
+        Because of r219045, we now only repaint the CachedImageClinets which tried
+        to draw the image but they could not because they have to wait for the image
+        decoding to finish. This was done by keeping a HashSet of these clients 
+        and make CachedImage own it. This HashSet is cleared once the image frame
+        finishes decoding and all the waited clients are repainted.
+
+        But Multiple asynchronous image decoding requests are allowed for the same
+        frame if new data is added to the image source. If we tried to draw the 
+        same image twice before it finishes decoding the first request, we will
+        not be to record this second request since the HashSet will not add the
+        same client twice. When he second request finishes decoding, CachedImage
+        will not repaint any client since its HashSet is empty.
+
+        To fix this problem we can do the following. When an image frame finishes
+        decoding, CachedImage will keep its HashSet of pending drawing clients as
+        long as the image frame is a partially loaded frame.
+
+        * loader/cache/CachedImage.cpp:
+        (WebCore::CachedImage::CachedImageObserver::imageFrameAvailable):
+        (WebCore::CachedImage::imageFrameAvailable):
+        * loader/cache/CachedImage.h:
+        * platform/graphics/BitmapImage.cpp:
+        (WebCore::BitmapImage::destroyDecodedData):
+        (WebCore::BitmapImage::dataChanged):
+        (WebCore::BitmapImage::setCurrentFrameDecodingStatusIfNecessary):
+        (WebCore::BitmapImage::draw):
+        (WebCore::BitmapImage::internalStartAnimation):
+        (WebCore::BitmapImage::internalAdvanceAnimation):
+        (WebCore::BitmapImage::imageFrameAvailableAtIndex):
+        * platform/graphics/BitmapImage.h:
+        * platform/graphics/ImageFrame.cpp:
+        (WebCore::ImageFrame::decodingStatus):
+        * platform/graphics/ImageFrame.h: Move DecodingStatus out of this class
+        to ImageTypes.h to avoid adding other header files to ImageObvsever.h
+        * platform/graphics/ImageFrameCache.cpp:
+        (WebCore::ImageFrameCache::setNativeImage):
+        (WebCore::ImageFrameCache::cacheMetadataAtIndex):
+        (WebCore::ImageFrameCache::cacheNativeImageAtIndex):
+        (WebCore::ImageFrameCache::cacheNativeImageAtIndexAsync):
+        (WebCore::ImageFrameCache::requestFrameAsyncDecodingAtIndex):
+        (WebCore::ImageFrameCache::frameDecodingStatusAtIndex):
+        * platform/graphics/ImageFrameCache.h:
+        * platform/graphics/ImageObserver.h:
+        * platform/graphics/ImageSource.h:
+        (WebCore::ImageSource::frameDecodingStatusAtIndex):
+        * platform/graphics/ImageTypes.h:
+        * platform/image-decoders/bmp/BMPImageReader.cpp:
+        (WebCore::BMPImageReader::decodeBMP):
+        * platform/image-decoders/gif/GIFImageDecoder.cpp:
+        (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::frameComplete):
+        * platform/image-decoders/webp/WEBPImageDecoder.cpp:
+        (WebCore::WEBPImageDecoder::decode):
+        * rendering/RenderBoxModelObject.cpp:
+        (WebCore::RenderBoxModelObject::decodingModeForImageDraw):
+
 2017-07-22  Timothy Horton  <timothy_horton@apple.com>
 
         Drag and Drop preview image for Twitter link is the wrong shape
index 97026e6f457f4b3bc61bf01955d3003b42dfae94..413f0414b737382752d11c6eddadc3aa32c6d38b 100644 (file)
@@ -374,10 +374,10 @@ bool CachedImage::CachedImageObserver::canDestroyDecodedData(const Image& image)
     return true;
 }
 
-void CachedImage::CachedImageObserver::imageFrameAvailable(const Image& image, ImageAnimatingState animatingState, const IntRect* changeRect)
+void CachedImage::CachedImageObserver::imageFrameAvailable(const Image& image, ImageAnimatingState animatingState, const IntRect* changeRect, DecodingStatus decodingStatus)
 {
     for (auto cachedImage : m_cachedImages)
-        cachedImage->imageFrameAvailable(image, animatingState, changeRect);
+        cachedImage->imageFrameAvailable(image, animatingState, changeRect, decodingStatus);
 }
 
 void CachedImage::CachedImageObserver::changedInRect(const Image& image, const IntRect* rect)
@@ -548,7 +548,7 @@ bool CachedImage::canDestroyDecodedData(const Image& image)
     return true;
 }
 
-void CachedImage::imageFrameAvailable(const Image& image, ImageAnimatingState animatingState, const IntRect* changeRect)
+void CachedImage::imageFrameAvailable(const Image& image, ImageAnimatingState animatingState, const IntRect* changeRect, DecodingStatus decodingStatus)
 {
     if (&image != m_image)
         return;
@@ -567,7 +567,8 @@ void CachedImage::imageFrameAvailable(const Image& image, ImageAnimatingState an
     if (visibleState == VisibleInViewportState::No && animatingState == ImageAnimatingState::Yes)
         m_image->stopAnimation();
 
-    m_pendingImageDrawingClients.clear();
+    if (decodingStatus != DecodingStatus::Partial)
+        m_pendingImageDrawingClients.clear();
 }
 
 void CachedImage::changedInRect(const Image& image, const IntRect* rect)
index f095ac228015aed7e199fe4df9d7f53459e747cd..8ea6f2e10ea037b9f4208b3507ccf6b28e53283a 100644 (file)
@@ -134,7 +134,7 @@ private:
         void didDraw(const Image&) final;
 
         bool canDestroyDecodedData(const Image&) final;
-        void imageFrameAvailable(const Image&, ImageAnimatingState, const IntRect* changeRect = nullptr) final;
+        void imageFrameAvailable(const Image&, ImageAnimatingState, const IntRect* changeRect = nullptr, DecodingStatus = DecodingStatus::Invalid) final;
         void changedInRect(const Image&, const IntRect*) final;
 
         HashSet<CachedImage*> m_cachedImages;
@@ -143,7 +143,7 @@ private:
     void decodedSizeChanged(const Image&, long long delta);
     void didDraw(const Image&);
     bool canDestroyDecodedData(const Image&);
-    void imageFrameAvailable(const Image&, ImageAnimatingState, const IntRect* changeRect = nullptr);
+    void imageFrameAvailable(const Image&, ImageAnimatingState, const IntRect* changeRect = nullptr, DecodingStatus = DecodingStatus::Invalid);
     void changedInRect(const Image&, const IntRect*);
 
     void addIncrementalDataBuffer(SharedBuffer&);
index dd5fc8ce395c288cac3b840b5419cd3d0995b87d..bc16b406e7f2fe9fe2b0cc756c5e69fa62b0f474 100644 (file)
@@ -79,7 +79,7 @@ void BitmapImage::destroyDecodedData(bool destroyAll)
         m_source.destroyAllDecodedDataExcludeFrame(m_currentFrame);
     else {
         m_source.destroyAllDecodedData();
-        m_currentFrameDecodingStatus = ImageFrame::DecodingStatus::Invalid;
+        m_currentFrameDecodingStatus = DecodingStatus::Invalid;
     }
 
     // There's no need to throw away the decoder unless we're explicitly asked
@@ -110,9 +110,19 @@ EncodedDataStatus BitmapImage::dataChanged(bool allDataReceived)
     if (m_source.decodedSize() && !canUseAsyncDecodingForLargeImages())
         m_source.destroyIncompleteDecodedData();
 
-    m_currentFrameDecodingStatus = ImageFrame::DecodingStatus::Invalid;
+    m_currentFrameDecodingStatus = DecodingStatus::Invalid;
     return m_source.dataChanged(data(), allDataReceived);
 }
+    
+void BitmapImage::setCurrentFrameDecodingStatusIfNecessary(DecodingStatus decodingStatus)
+{
+    // When new data is received, m_currentFrameDecodingStatus is set to DecodingStatus::Invalid
+    // to force decoding the frame when it's drawn. m_currentFrameDecodingStatus should not be
+    // changed in this case till draw() is called and sets its value to DecodingStatus::Decoding.
+    if (m_currentFrameDecodingStatus != DecodingStatus::Decoding)
+        return;
+    m_currentFrameDecodingStatus = decodingStatus;
+}
 
 NativeImagePtr BitmapImage::frameImageAtIndexCacheIfNeeded(size_t index, SubsamplingLevel subsamplingLevel, const GraphicsContext* targetContext)
 {
@@ -192,13 +202,13 @@ ImageDrawResult BitmapImage::draw(GraphicsContext& context, const FloatRect& des
 
         // 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) || m_currentFrameDecodingStatus == ImageFrame::DecodingStatus::Invalid) {
+        if ((!frameIsCompatible && !frameIsBeingDecoded) || m_currentFrameDecodingStatus == DecodingStatus::Invalid) {
             LOG(Images, "BitmapImage::%s - %p - url: %s [requesting large async decoding]", __FUNCTION__, this, sourceURL().string().utf8().data());
             m_source.requestFrameAsyncDecodingAtIndex(m_currentFrame, m_currentSubsamplingLevel, sizeForDrawing);
-            m_currentFrameDecodingStatus = ImageFrame::DecodingStatus::Decoding;
+            m_currentFrameDecodingStatus = DecodingStatus::Decoding;
         }
 
-        if (m_currentFrameDecodingStatus == ImageFrame::DecodingStatus::Decoding)
+        if (m_currentFrameDecodingStatus == DecodingStatus::Decoding)
             result = ImageDrawResult::DidRequestDecoding;
 
         if (!frameHasDecodedNativeImageCompatibleWithOptionsAtIndex(m_currentFrame, m_currentSubsamplingLevel, DecodingMode::Asynchronous)) {
@@ -231,7 +241,7 @@ ImageDrawResult BitmapImage::draw(GraphicsContext& context, const FloatRect& des
         if (!image) // If it's too early we won't have an image yet.
             return ImageDrawResult::DidNothing;
 
-        if (m_currentFrameDecodingStatus != ImageFrame::DecodingStatus::Complete)
+        if (m_currentFrameDecodingStatus != DecodingStatus::Complete)
             ++m_decodeCountForTesting;
     }
 
@@ -391,7 +401,7 @@ BitmapImage::StartAnimationStatus BitmapImage::internalStartAnimation()
             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;
+            m_currentFrameDecodingStatus = DecodingStatus::Decoding;
             LOG(Images, "BitmapImage::%s - %p - url: %s [requesting async decoding for nextFrame = %ld]", __FUNCTION__, this, sourceURL().string().utf8().data(), nextFrame);
         }
 
@@ -439,10 +449,11 @@ void BitmapImage::internalAdvanceAnimation()
 
     destroyDecodedDataIfNecessary(false);
 
-    if (m_currentFrameDecodingStatus == ImageFrame::DecodingStatus::Decoding)
-        m_currentFrameDecodingStatus = frameDecodingStatusAtIndex(m_currentFrame);
+    DecodingStatus decodingStatus = frameDecodingStatusAtIndex(m_currentFrame);
+    setCurrentFrameDecodingStatusIfNecessary(decodingStatus);
+    
     if (imageObserver())
-        imageObserver()->imageFrameAvailable(*this, ImageAnimatingState::Yes);
+        imageObserver()->imageFrameAvailable(*this, ImageAnimatingState::Yes, nullptr, decodingStatus);
 
     LOG(Images, "BitmapImage::%s - %p - url: %s [m_currentFrame = %ld]", __FUNCTION__, this, sourceURL().string().utf8().data(), m_currentFrame);
 }
@@ -497,14 +508,15 @@ void BitmapImage::imageFrameAvailableAtIndex(size_t index)
     ASSERT(index == m_currentFrame && !m_currentFrame);
     if (m_source.isAsyncDecodingQueueIdle())
         m_source.stopAsyncDecodingQueue();
-    if (m_currentFrameDecodingStatus == ImageFrame::DecodingStatus::Decoding)
-        m_currentFrameDecodingStatus = frameDecodingStatusAtIndex(m_currentFrame);
 
-    if (m_currentFrameDecodingStatus == ImageFrame::DecodingStatus::Complete)
+    DecodingStatus decodingStatus = frameDecodingStatusAtIndex(m_currentFrame);
+    setCurrentFrameDecodingStatusIfNecessary(decodingStatus);
+    
+    if (m_currentFrameDecodingStatus == DecodingStatus::Complete)
         ++m_decodeCountForTesting;
 
     if (imageObserver())
-        imageObserver()->imageFrameAvailable(*this, ImageAnimatingState::No);
+        imageObserver()->imageFrameAvailable(*this, ImageAnimatingState::No, nullptr, decodingStatus);
 }
 
 unsigned BitmapImage::decodeCountForTesting() const
index 44dd7737a59ba02bed04231032919c1624c3d4e3..df9bb78a1db34807efe68d2a02c13f977fc8cc35 100644 (file)
@@ -85,8 +85,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); }
-    ImageFrame::DecodingStatus frameDecodingStatusAtIndex(size_t index) const { return m_source.frameDecodingStatusAtIndex(index); }
-    bool frameIsCompleteAtIndex(size_t index) const { return frameDecodingStatusAtIndex(index) == ImageFrame::DecodingStatus::Complete; }
+    DecodingStatus frameDecodingStatusAtIndex(size_t index) const { return m_source.frameDecodingStatusAtIndex(index); }
+    bool frameIsCompleteAtIndex(size_t index) const { return frameDecodingStatusAtIndex(index) == 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); }
@@ -193,6 +193,7 @@ private:
     void clearTimer();
     void startTimer(Seconds delay);
     bool canDestroyDecodedData();
+    void setCurrentFrameDecodingStatusIfNecessary(DecodingStatus);
     bool isBitmapImage() const override { return true; }
     void dump(TextStream&) const override;
 
@@ -203,7 +204,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 };
+    DecodingStatus m_currentFrameDecodingStatus { 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 8e78a66e3322f41487b9d05574a5dc319c72a199..8165486b640f1c800743bbeca1f7c40fde1affb7 100644 (file)
@@ -77,7 +77,7 @@ void ImageFrame::setDecodingStatus(DecodingStatus decodingStatus)
     m_decodingStatus = decodingStatus;
 }
 
-ImageFrame::DecodingStatus ImageFrame::decodingStatus() const
+DecodingStatus ImageFrame::decodingStatus() const
 {
     ASSERT(m_decodingStatus != DecodingStatus::Decoding);
     return m_decodingStatus;
index 212a2cb7fb9c52a56d80f475dd41587b54ff33f2..182186363c79bc7297999a39e200e201823688bd 100644 (file)
@@ -39,7 +39,6 @@ class ImageFrame {
     friend class ImageFrameCache;
 public:
     enum class Caching { Metadata, MetadataAndImage };
-    enum class DecodingStatus { Invalid, Partial, Complete, Decoding };
 
     ImageFrame();
     ImageFrame(const ImageFrame& other) { operator=(other); }
index 8c336f41be97f81bcb164b6021355fb915e4a5d2..b564698ec825bb365b905eec10a94e77d43e7d58 100644 (file)
@@ -190,19 +190,19 @@ void ImageFrameCache::setNativeImage(NativeImagePtr&& nativeImage)
 
     frame.m_nativeImage = WTFMove(nativeImage);
 
-    frame.m_decodingStatus = ImageFrame::DecodingStatus::Complete;
+    frame.m_decodingStatus = DecodingStatus::Complete;
     frame.m_size = nativeImageSize(frame.m_nativeImage);
     frame.m_hasAlpha = nativeImageHasAlpha(frame.m_nativeImage);
 }
 
-void ImageFrameCache::cacheMetadataAtIndex(size_t index, SubsamplingLevel subsamplingLevel, ImageFrame::DecodingStatus decodingStatus)
+void ImageFrameCache::cacheMetadataAtIndex(size_t index, SubsamplingLevel subsamplingLevel, DecodingStatus decodingStatus)
 {
     ASSERT(index < m_frames.size());
     ImageFrame& frame = m_frames[index];
 
     ASSERT(isDecoderAvailable());
-    if (decodingStatus == ImageFrame::DecodingStatus::Invalid)
-        frame.m_decodingStatus = m_decoder->frameIsCompleteAtIndex(index) ? ImageFrame::DecodingStatus::Complete : ImageFrame::DecodingStatus::Partial;
+    if (decodingStatus == DecodingStatus::Invalid)
+        frame.m_decodingStatus = m_decoder->frameIsCompleteAtIndex(index) ? DecodingStatus::Complete : DecodingStatus::Partial;
     else
         frame.m_decodingStatus = decodingStatus;
 
@@ -224,7 +224,7 @@ void ImageFrameCache::cacheMetadataAtIndex(size_t index, SubsamplingLevel subsam
         frame.m_duration = m_decoder->frameDurationAtIndex(index);
 }
 
-void ImageFrameCache::cacheNativeImageAtIndex(NativeImagePtr&& nativeImage, size_t index, SubsamplingLevel subsamplingLevel, const DecodingOptions& decodingOptions, ImageFrame::DecodingStatus decodingStatus)
+void ImageFrameCache::cacheNativeImageAtIndex(NativeImagePtr&& nativeImage, size_t index, SubsamplingLevel subsamplingLevel, const DecodingOptions& decodingOptions, DecodingStatus decodingStatus)
 {
     ASSERT(index < m_frames.size());
     ImageFrame& frame = m_frames[index];
@@ -246,7 +246,7 @@ void ImageFrameCache::cacheNativeImageAtIndex(NativeImagePtr&& nativeImage, size
     decodedSizeIncreased(frame.frameBytes());
 }
 
-void ImageFrameCache::cacheNativeImageAtIndexAsync(NativeImagePtr&& nativeImage, size_t index, SubsamplingLevel subsamplingLevel, const DecodingOptions& decodingOptions, ImageFrame::DecodingStatus decodingStatus)
+void ImageFrameCache::cacheNativeImageAtIndexAsync(NativeImagePtr&& nativeImage, size_t index, SubsamplingLevel subsamplingLevel, const DecodingOptions& decodingOptions, DecodingStatus decodingStatus)
 {
     if (!isDecoderAvailable())
         return;
@@ -314,7 +314,7 @@ void ImageFrameCache::requestFrameAsyncDecodingAtIndex(size_t index, Subsampling
         startAsyncDecodingQueue();
     
     ASSERT(index < m_frames.size());
-    ImageFrame::DecodingStatus decodingStatus = m_decoder->frameIsCompleteAtIndex(index) ? ImageFrame::DecodingStatus::Complete : ImageFrame::DecodingStatus::Partial;
+    DecodingStatus decodingStatus = m_decoder->frameIsCompleteAtIndex(index) ? DecodingStatus::Complete : 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, decodingStatus });
@@ -499,9 +499,9 @@ bool ImageFrameCache::frameIsBeingDecodedAndIsCompatibleWithOptionsAtIndex(size_
     return it != m_frameCommitQueue.end();
 }
 
-ImageFrame::DecodingStatus ImageFrameCache::frameDecodingStatusAtIndex(size_t index)
+DecodingStatus ImageFrameCache::frameDecodingStatusAtIndex(size_t index)
 {
-    return frameMetadataAtIndex<ImageFrame::DecodingStatus>(index, (&ImageFrame::decodingStatus));
+    return frameMetadataAtIndex<DecodingStatus>(index, (&ImageFrame::decodingStatus));
 }
 
 bool ImageFrameCache::frameHasAlphaAtIndex(size_t index)
index c77b9273c47d381889613687df293300e8b8522c..649abfc2362c845e3bc1af77048c3405b5b9e64b 100644 (file)
@@ -93,7 +93,7 @@ public:
 
     // ImageFrame metadata which does not require caching the ImageFrame.
     bool frameIsBeingDecodedAndIsCompatibleWithOptionsAtIndex(size_t, const DecodingOptions&);
-    ImageFrame::DecodingStatus frameDecodingStatusAtIndex(size_t);
+    DecodingStatus frameDecodingStatusAtIndex(size_t);
     bool frameHasAlphaAtIndex(size_t);
     bool frameHasImageAtIndex(size_t);
     bool frameHasFullSizeNativeImageAtIndex(size_t, const std::optional<SubsamplingLevel>&);
@@ -131,9 +131,9 @@ private:
     void decodedSizeReset(unsigned decodedSize);
 
     void setNativeImage(NativeImagePtr&&);
-    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);
+    void cacheMetadataAtIndex(size_t, SubsamplingLevel, DecodingStatus = DecodingStatus::Invalid);
+    void cacheNativeImageAtIndex(NativeImagePtr&&, size_t, SubsamplingLevel, const DecodingOptions&, DecodingStatus = DecodingStatus::Invalid);
+    void cacheNativeImageAtIndexAsync(NativeImagePtr&&, size_t, SubsamplingLevel, const DecodingOptions&, DecodingStatus);
 
     Ref<WorkQueue> decodingQueue();
 
@@ -151,7 +151,7 @@ private:
         size_t index;
         SubsamplingLevel subsamplingLevel;
         DecodingOptions decodingOptions;
-        ImageFrame::DecodingStatus decodingStatus;
+        DecodingStatus decodingStatus;
         bool operator==(const ImageFrameRequest& other) const
         {
             return index == other.index && subsamplingLevel == other.subsamplingLevel && decodingOptions == other.decodingOptions && decodingStatus == other.decodingStatus;
index 80062cad1e0e779f72a765dc7078f36b39f007af..a06851ec1e76eaa6d78a75bf49ec53b2de249087 100644 (file)
@@ -46,7 +46,7 @@ public:
     virtual void didDraw(const Image&) = 0;
 
     virtual bool canDestroyDecodedData(const Image&) = 0;
-    virtual void imageFrameAvailable(const Image&, ImageAnimatingState, const IntRect* changeRect = nullptr) = 0;
+    virtual void imageFrameAvailable(const Image&, ImageAnimatingState, const IntRect* changeRect = nullptr, DecodingStatus = DecodingStatus::Invalid) = 0;
     virtual void changedInRect(const Image&, const IntRect* changeRect = nullptr) = 0;
 };
 
index b36c6aa3839122e1d72266df0259b47c76d2d076..f4dd4d88844d5253f699973b378a0ee34097a45c 100644 (file)
@@ -91,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); }
-    ImageFrame::DecodingStatus frameDecodingStatusAtIndex(size_t index) { return m_frameCache->frameDecodingStatusAtIndex(index); }
+    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 ba7b254eef42f1cc94c5f32ea66fa68b4a6e9bfc..0fbb99e33cfc8ca7a8e86792e95dc4fe210776d3 100644 (file)
@@ -78,6 +78,13 @@ enum class EncodedDataStatus {
     Complete
 };
 
+enum class DecodingStatus {
+    Invalid,
+    Partial,
+    Complete,
+    Decoding
+};
+
 enum class ImageDrawResult {
     DidNothing,
     DidRequestDecoding,
index 8d68a40008a64598a9d7c64d83e95a509308bba2..01683433453994a7e9b4fb279de500e386e24109 100644 (file)
@@ -81,7 +81,7 @@ bool BMPImageReader::decodeBMP(bool onlySize)
         if (!m_buffer->initialize(m_parent->size(), m_parent->premultiplyAlpha()))
             return m_parent->setFailed(); // Unable to allocate.
 
-        m_buffer->setDecodingStatus(ImageFrame::DecodingStatus::Partial);
+        m_buffer->setDecodingStatus(DecodingStatus::Partial);
         m_buffer->setHasAlpha(false);
 
         if (!m_isTopDown)
@@ -117,7 +117,7 @@ bool BMPImageReader::decodeBMP(bool onlySize)
     }
 
     // Done!
-    m_buffer->setDecodingStatus(ImageFrame::DecodingStatus::Complete);
+    m_buffer->setDecodingStatus(DecodingStatus::Complete);
     return true;
 }
 
index fd0cc75099f5ba42de999c87201436d0533997be..9cac1138ffaa853e6238bb372edd8faf9ddc830c 100644 (file)
@@ -247,7 +247,7 @@ bool GIFImageDecoder::frameComplete(unsigned frameIndex, unsigned frameDuration,
     if (buffer.isInvalid() && !initFrameBuffer(frameIndex))
         return false; // initFrameBuffer() has already called setFailed().
 
-    buffer.setDecodingStatus(ImageFrame::DecodingStatus::Complete);
+    buffer.setDecodingStatus(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->setDecodingStatus(ImageFrame::DecodingStatus::Partial);
+    buffer->setDecodingStatus(DecodingStatus::Partial);
 
     // Reset the alpha pixel tracker for this frame.
     m_currentBufferSawAlpha = false;
index 551af6e44313e106cd6c6116fffab0013ed4bc50..74ca111399a36c27e2798e98e11f936d5eeb6b05 100644 (file)
@@ -608,7 +608,7 @@ bool JPEGImageDecoder::outputScanlines()
     if (buffer.isInvalid()) {
         if (!buffer.initialize(scaledSize(), m_premultiplyAlpha))
             return setFailed();
-        buffer.setDecodingStatus(ImageFrame::DecodingStatus::Partial);
+        buffer.setDecodingStatus(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.setDecodingStatus(ImageFrame::DecodingStatus::Complete);
+    buffer.setDecodingStatus(DecodingStatus::Complete);
 }
 
 void JPEGImageDecoder::decode(bool onlySize, bool allDataReceived)
index 2fb6c440d436dab960dd8a000e9a2cecdac9354b..ecda18df7be7ad21b62d15727ad8f8252ab0f725 100644 (file)
@@ -450,7 +450,7 @@ void PNGImageDecoder::rowAvailable(unsigned char* rowBuffer, unsigned rowIndex,
             }
         }
 
-        buffer.setDecodingStatus(ImageFrame::DecodingStatus::Partial);
+        buffer.setDecodingStatus(DecodingStatus::Partial);
         buffer.setHasAlpha(false);
 
 #if ENABLE(APNG)
@@ -558,7 +558,7 @@ void PNGImageDecoder::pngComplete()
     }
 #endif
     if (!m_frameBufferCache.isEmpty())
-        m_frameBufferCache.first().setDecodingStatus(ImageFrame::DecodingStatus::Complete);
+        m_frameBufferCache.first().setDecodingStatus(DecodingStatus::Complete);
 }
 
 void PNGImageDecoder::decode(bool onlySize, unsigned haltAtFrame, bool allDataReceived)
@@ -825,7 +825,7 @@ void PNGImageDecoder::frameComplete()
         return;
 
     ImageFrame& buffer = m_frameBufferCache[m_currentFrame];
-    buffer.setDecodingStatus(ImageFrame::DecodingStatus::Complete);
+    buffer.setDecodingStatus(DecodingStatus::Complete);
 
     png_bytep interlaceBuffer = m_reader->interlaceBuffer();
 
index 44551dcb00c4e9cd576ad15708d8d42354a7db00..b3a632fa713a237416289170dc658872a3da6ef1 100644 (file)
@@ -119,7 +119,7 @@ bool WEBPImageDecoder::decode(bool onlySize, bool)
     if (buffer.isInvalid()) {
         if (!buffer.initialize(size(), m_premultiplyAlpha))
             return setFailed();
-        buffer.setDecodingStatus(ImageFrame::DecodingStatus::Partial);
+        buffer.setDecodingStatus(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.setDecodingStatus(ImageFrame::DecodingStatus::Complete);
+        buffer.setDecodingStatus(DecodingStatus::Complete);
         clear();
         return true;
     case VP8_STATUS_SUSPENDED:
index 01ed005967588d621e539d3c3917d27db333ef5f..e39640b36035e52562330841db9816ca0cbe9fa9 100644 (file)
@@ -324,8 +324,6 @@ DecodingMode RenderBoxModelObject::decodingModeForImageDraw(const Image& image,
     if (IOSApplication::isIBooksStorytime())
         return DecodingMode::Synchronous;
 #endif
-    if (document().isImageDocument())
-        return DecodingMode::Synchronous;
     if (!settings().largeImageAsyncDecodingEnabled())
         return DecodingMode::Synchronous;
     if (!bitmapImage.canUseAsyncDecodingForLargeImages())