The Incomplete asynchronously decoded image frame should be decoded every time it...
authorsaid@apple.com <said@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 9 May 2017 01:53:54 +0000 (01:53 +0000)
committersaid@apple.com <said@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 9 May 2017 01:53:54 +0000 (01:53 +0000)
https://bugs.webkit.org/show_bug.cgi?id=170836

Reviewed by Tim Horton.

The asynchronously decoded image frames has to be cached to prevent flickering,
but we have to keep requesting new decoding for the incomplete frame every time
it's drawn. This is to avoid drawing an incomplete image frame even after all
its encoded data is received.

* platform/graphics/BitmapImage.cpp:
(WebCore::BitmapImage::draw):
* platform/graphics/ImageFrameCache.cpp:
(WebCore::ImageFrameCache::cacheAsyncFrameNativeImageAtIndex):
(WebCore::ImageFrameCache::requestFrameAsyncDecodingAtIndex):

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

Source/WebCore/ChangeLog
Source/WebCore/platform/graphics/BitmapImage.cpp
Source/WebCore/platform/graphics/ImageFrameCache.cpp

index 54c77ff..119fbd7 100644 (file)
@@ -1,3 +1,21 @@
+2017-05-08  Said Abou-Hallawa  <sabouhallawa@apple.com>
+
+        The Incomplete asynchronously decoded image frame should be decoded every time it's drawn
+        https://bugs.webkit.org/show_bug.cgi?id=170836
+
+        Reviewed by Tim Horton.
+
+        The asynchronously decoded image frames has to be cached to prevent flickering,
+        but we have to keep requesting new decoding for the incomplete frame every time
+        it's drawn. This is to avoid drawing an incomplete image frame even after all
+        its encoded data is received.
+
+        * platform/graphics/BitmapImage.cpp:
+        (WebCore::BitmapImage::draw):
+        * platform/graphics/ImageFrameCache.cpp:
+        (WebCore::ImageFrameCache::cacheAsyncFrameNativeImageAtIndex):
+        (WebCore::ImageFrameCache::requestFrameAsyncDecodingAtIndex):
+
 2017-05-08  Wenson Hsieh  <wenson_hsieh@apple.com>
 
         Guard DragController::cleanupAfterSystemDrag to only clear drag state on Mac
index 9a6ab12..228031b 100644 (file)
@@ -183,10 +183,15 @@ void BitmapImage::draw(GraphicsContext& context, const FloatRect& destRect, cons
     if (decodingMode == DecodingMode::Asynchronous && shouldUseAsyncDecodingForLargeImages()) {
         ASSERT(!canAnimate() && !m_currentFrame);
 
-        if (!frameHasDecodedNativeImageCompatibleWithOptionsAtIndex(m_currentFrame, m_currentSubsamplingLevel, DecodingOptions(sizeForDrawing))
-            && !frameIsBeingDecodedAndIsCompatibleWithOptionsAtIndex(m_currentFrame, DecodingOptions(sizeForDrawing))) {
+        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) {
             LOG(Images, "BitmapImage::%s - %p - url: %s [requesting large async decoding]", __FUNCTION__, this, sourceURL().string().utf8().data());
-            m_source.requestFrameAsyncDecodingAtIndex(0, m_currentSubsamplingLevel, sizeForDrawing);
+            frameIsBeingDecoded = m_source.requestFrameAsyncDecodingAtIndex(0, m_currentSubsamplingLevel, sizeForDrawing);
         }
 
         if (!frameHasDecodedNativeImageCompatibleWithOptionsAtIndex(m_currentFrame, m_currentSubsamplingLevel, DecodingMode::Asynchronous)) {
@@ -196,6 +201,7 @@ void BitmapImage::draw(GraphicsContext& context, const FloatRect& destRect, cons
         }
 
         image = frameImageAtIndex(m_currentFrame);
+        ASSERT_IMPLIES(encodedDataStatus() == EncodedDataStatus::Complete, frameIsBeingDecoded || frameIsComplete);
         LOG(Images, "BitmapImage::%s - %p - url: %s [a decoded image frame is available for drawing]", __FUNCTION__, this, sourceURL().string().utf8().data());
     } else {
         StartAnimationStatus status = internalStartAnimation();
index 36f8b6e..b4b28d4 100644 (file)
@@ -247,7 +247,7 @@ void ImageFrameCache::cacheAsyncFrameNativeImageAtIndex(NativeImagePtr&& nativeI
         return;
 
     ASSERT(index < m_frames.size());
-    ASSERT(!frameHasDecodedNativeImageCompatibleWithOptionsAtIndex(index, subsamplingLevel, decodingOptions));
+    ASSERT(!frameIsCompleteAtIndex(index) || !frameHasDecodedNativeImageCompatibleWithOptionsAtIndex(index, subsamplingLevel, decodingOptions));
 
     // Clean the old native image and set a new one
     cacheFrameNativeImageAtIndex(WTFMove(nativeImage), index, subsamplingLevel, decodingOptions);
@@ -310,16 +310,18 @@ bool ImageFrameCache::requestFrameAsyncDecodingAtIndex(size_t index, Subsampling
     if (!isDecoderAvailable())
         return false;
 
+    // Allow new requests for the same frame if the frame is incomplete.
     ASSERT(index < m_frames.size());
-
-    // 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;
+    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;
+    }
 
     if (!hasAsyncDecodingQueue())
         startAsyncDecodingQueue();