<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[213764] trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/213764">213764</a></dd>
<dt>Author</dt> <dd>commit-queue@webkit.org</dd>
<dt>Date</dt> <dd>2017-03-11 19:00:46 -0800 (Sat, 11 Mar 2017)</dd>
</dl>

<h3>Log Message</h3>
<pre>Enable async image decoding for large images
https://bugs.webkit.org/show_bug.cgi?id=165039

Patch by Said Abou-Hallawa &lt;sabouhallawa@apple.com&gt; on 2017-03-11
Reviewed by Simon Fraser.

Source/WebCore:

When BitmapImage::draw() is called for a large image, we are going to request async
image decoding for the native image instead of drawing it. If a lower resolution
native image is available for this, it is going to be drawn. Otherwise nothing will
be drawn. In both cases, a repaint will be scheduled for the image observer. This
should improve the image first time paint and the scrolling scenarios. It also makes
the scrolling more responsive by removing the decoding step from the main thread.

For now we are going to disable the asynchronous image decoding for the webkit test
runner because drawing the image does not block the page rendering anymore. An image
can be repainted later when its frame is ready for painting. This can cause a test
to fail because the webkit test runner may capture an image for the page before painting
all the images. The asynchronous image decoding can to be explicitly enabled from
the test page. Once the specs of the image 'async' attribute and 'ready' event is
approved, this should be revisited. It is important to test what we ship and eventually
async image decoding should be enabled in the webkit test runner.

* loader/cache/CachedImage.h: Change the default of LargeImageAsyncDecoding and AnimatedImageAsyncDecoding
to be false. This change fixes a layout test which creates an CachedImage inside an ImageDocument. The
CachedImage in this case does not have a loader so getting the values of these options from the settings
which is false for the DRT/WTR did not happen.
* platform/graphics/BitmapImage.cpp:
(WebCore::BitmapImage::destroyDecodedData): ImageSource::hasDecodingQueue() is renamed to ImageSource::hasAsyncDecodingQueue().
(WebCore::BitmapImage::frameImageAtIndex): Use String::utf8().data() instead of String::characters8().
(WebCore::BitmapImage::draw): If drawing the current frame is called while it is being
decoded, draw the current native image if the current frame was decoded but for a
different size  and and will not invoke decoding while painting. If the frame is being
decoded and there isn't a decoded frame, return without drawing but set a flag that
that this image needs a repaint.
(WebCore::BitmapImage::shouldUseAsyncDecodingForLargeImage): Renaming a function.
(WebCore::BitmapImage::shouldUseAsyncDecodingForAnimatedImage): Ditto.
(WebCore::BitmapImage::internalStartAnimation): Use String::utf8().data() instead of String::characters8().
(WebCore::BitmapImage::advanceAnimation): Ditto.
(WebCore::BitmapImage::internalAdvanceAnimation): Ditto.
(WebCore::BitmapImage::newFrameNativeImageAvailableAtIndex): Now this callback can be
called form the ImageFrameCache when finishing a frame of an animated image or the
frame of a large image. For large images, we need to call CachedImage::changedInRect()
if this image needs a repaint. If the decoding queue is idle, we should close it.
(WebCore::BitmapImage::isLargeImageAsyncDecodingRequired): Deleted. Function was renamed.
(WebCore::BitmapImage::isAnimatedImageAsyncDecodingRequired): Deleted. Ditto.
* platform/graphics/BitmapImage.h:

* platform/graphics/ImageFrameCache.cpp:
(WebCore::ImageFrameCache::~ImageFrameCache): hasDecodingQueue() was renamed to hasAsyncDecodingQueue().
(WebCore::ImageFrameCache::decodingQueue): Change the QNS of the decoding thread to be WorkQueue::QOS::Default.
WorkQueue::QOS::UserInteractive causes the scrolling thread to preempted  which can make the scrolling choppy.
(WebCore::ImageFrameCache::startAsyncDecodingQueue): hasDecodingQueue() was renamed to hasAsyncDecodingQueue().
(WebCore::ImageFrameCache::requestFrameAsyncDecodingAtIndex): Ditto.
(WebCore::ImageFrameCache::isAsyncDecodingQueueIdle): A helper function to tell whether the decoding thread is idle.
(WebCore::ImageFrameCache::stopAsyncDecodingQueue): hasDecodingQueue() was renamed to hasAsyncDecodingQueue().
* platform/graphics/ImageFrameCache.h:
(WebCore::ImageFrameCache::hasAsyncDecodingQueue): Rename this function to be consistent with the rest of the functions.
(WebCore::ImageFrameCache::hasDecodingQueue): Deleted.

* platform/graphics/ImageSource.cpp:
(WebCore::ImageSource::shouldUseAsyncDecoding): Renaming a function. Change the heuristic for large images be
a little bigger than the heuristic for animated images.
(WebCore::ImageSource::isAsyncDecodingRequired): Deleted.
* platform/graphics/ImageSource.h:
(WebCore::ImageSource::hasAsyncDecodingQueue): hasDecodingQueue() was renamed to hasAsyncDecodingQueue().
(WebCore::ImageSource::isAsyncDecodingQueueIdle): A wrapper for ImageFrameCache::isAsyncDecodingQueueIdle().
(WebCore::ImageSource::hasDecodingQueue): Deleted.

* platform/graphics/cg/ImageDecoderCG.cpp:
(WebCore::ImageDecoder::createFrameImageAtIndex): CGImageSourceCreateThumbnailAtIndex() returns a CGImage with
the image native size regardless of the subsamplingLevel unless kCGImageSourceSubsampleFactor is passed. Here
we are trying to see which size is smaller: the image native size or the sizeForDrawing. If we want a CGImage
with the image native size, sizeForDrawing will not passed. So we need to get the image native size with the
default subsampling and then compare it with sizeForDrawing.

Source/WebKit2:

Add WK2 preferences for setting/getting LargeImageAsyncDecoding and
AnimatedImageAsyncDecoding.

* UIProcess/API/C/WKPreferences.cpp:
(WKPreferencesSetLargeImageAsyncDecodingEnabled):
(WKPreferencesGetLargeImageAsyncDecodingEnabled):
(WKPreferencesSetAnimatedImageAsyncDecodingEnabled):
(WKPreferencesGetAnimatedImageAsyncDecodingEnabled):
* UIProcess/API/C/WKPreferencesRefPrivate.h:

Tools:

Disable LargeImageAsyncDecoding for DRT/WTR.

* DumpRenderTree/mac/DumpRenderTree.mm:
(resetWebPreferencesToConsistentValues):
* WebKitTestRunner/TestController.cpp:
(WTR::TestController::resetPreferencesToConsistentValues):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreloadercacheCachedImageh">trunk/Source/WebCore/loader/cache/CachedImage.h</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicsBitmapImagecpp">trunk/Source/WebCore/platform/graphics/BitmapImage.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicsBitmapImageh">trunk/Source/WebCore/platform/graphics/BitmapImage.h</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicsImageFrameCachecpp">trunk/Source/WebCore/platform/graphics/ImageFrameCache.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicsImageFrameCacheh">trunk/Source/WebCore/platform/graphics/ImageFrameCache.h</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicsImageSourcecpp">trunk/Source/WebCore/platform/graphics/ImageSource.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicsImageSourceh">trunk/Source/WebCore/platform/graphics/ImageSource.h</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicscgImageDecoderCGcpp">trunk/Source/WebCore/platform/graphics/cg/ImageDecoderCG.cpp</a></li>
<li><a href="#trunkSourceWebKit2ChangeLog">trunk/Source/WebKit2/ChangeLog</a></li>
<li><a href="#trunkSourceWebKit2UIProcessAPICWKPreferencescpp">trunk/Source/WebKit2/UIProcess/API/C/WKPreferences.cpp</a></li>
<li><a href="#trunkSourceWebKit2UIProcessAPICWKPreferencesRefPrivateh">trunk/Source/WebKit2/UIProcess/API/C/WKPreferencesRefPrivate.h</a></li>
<li><a href="#trunkToolsChangeLog">trunk/Tools/ChangeLog</a></li>
<li><a href="#trunkToolsDumpRenderTreemacDumpRenderTreemm">trunk/Tools/DumpRenderTree/mac/DumpRenderTree.mm</a></li>
<li><a href="#trunkToolsWebKitTestRunnerTestControllercpp">trunk/Tools/WebKitTestRunner/TestController.cpp</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (213763 => 213764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2017-03-12 01:07:32 UTC (rev 213763)
+++ trunk/Source/WebCore/ChangeLog        2017-03-12 03:00:46 UTC (rev 213764)
</span><span class="lines">@@ -1,3 +1,79 @@
</span><ins>+2017-03-11  Said Abou-Hallawa  &lt;sabouhallawa@apple.com&gt;
+
+        Enable async image decoding for large images
+        https://bugs.webkit.org/show_bug.cgi?id=165039
+
+        Reviewed by Simon Fraser.
+
+        When BitmapImage::draw() is called for a large image, we are going to request async
+        image decoding for the native image instead of drawing it. If a lower resolution 
+        native image is available for this, it is going to be drawn. Otherwise nothing will
+        be drawn. In both cases, a repaint will be scheduled for the image observer. This
+        should improve the image first time paint and the scrolling scenarios. It also makes
+        the scrolling more responsive by removing the decoding step from the main thread. 
+        
+        For now we are going to disable the asynchronous image decoding for the webkit test
+        runner because drawing the image does not block the page rendering anymore. An image
+        can be repainted later when its frame is ready for painting. This can cause a test
+        to fail because the webkit test runner may capture an image for the page before painting
+        all the images. The asynchronous image decoding can to be explicitly enabled from
+        the test page. Once the specs of the image 'async' attribute and 'ready' event is
+        approved, this should be revisited. It is important to test what we ship and eventually
+        async image decoding should be enabled in the webkit test runner.
+
+        * loader/cache/CachedImage.h: Change the default of LargeImageAsyncDecoding and AnimatedImageAsyncDecoding
+        to be false. This change fixes a layout test which creates an CachedImage inside an ImageDocument. The
+        CachedImage in this case does not have a loader so getting the values of these options from the settings
+        which is false for the DRT/WTR did not happen.
+        * platform/graphics/BitmapImage.cpp:
+        (WebCore::BitmapImage::destroyDecodedData): ImageSource::hasDecodingQueue() is renamed to ImageSource::hasAsyncDecodingQueue().
+        (WebCore::BitmapImage::frameImageAtIndex): Use String::utf8().data() instead of String::characters8().
+        (WebCore::BitmapImage::draw): If drawing the current frame is called while it is being
+        decoded, draw the current native image if the current frame was decoded but for a 
+        different size  and and will not invoke decoding while painting. If the frame is being
+        decoded and there isn't a decoded frame, return without drawing but set a flag that
+        that this image needs a repaint.
+        (WebCore::BitmapImage::shouldUseAsyncDecodingForLargeImage): Renaming a function.
+        (WebCore::BitmapImage::shouldUseAsyncDecodingForAnimatedImage): Ditto.
+        (WebCore::BitmapImage::internalStartAnimation): Use String::utf8().data() instead of String::characters8().
+        (WebCore::BitmapImage::advanceAnimation): Ditto.
+        (WebCore::BitmapImage::internalAdvanceAnimation): Ditto.
+        (WebCore::BitmapImage::newFrameNativeImageAvailableAtIndex): Now this callback can be
+        called form the ImageFrameCache when finishing a frame of an animated image or the
+        frame of a large image. For large images, we need to call CachedImage::changedInRect()
+        if this image needs a repaint. If the decoding queue is idle, we should close it.
+        (WebCore::BitmapImage::isLargeImageAsyncDecodingRequired): Deleted. Function was renamed.
+        (WebCore::BitmapImage::isAnimatedImageAsyncDecodingRequired): Deleted. Ditto.
+        * platform/graphics/BitmapImage.h:
+
+        * platform/graphics/ImageFrameCache.cpp:
+        (WebCore::ImageFrameCache::~ImageFrameCache): hasDecodingQueue() was renamed to hasAsyncDecodingQueue().
+        (WebCore::ImageFrameCache::decodingQueue): Change the QNS of the decoding thread to be WorkQueue::QOS::Default.
+        WorkQueue::QOS::UserInteractive causes the scrolling thread to preempted  which can make the scrolling choppy.
+        (WebCore::ImageFrameCache::startAsyncDecodingQueue): hasDecodingQueue() was renamed to hasAsyncDecodingQueue().
+        (WebCore::ImageFrameCache::requestFrameAsyncDecodingAtIndex): Ditto.
+        (WebCore::ImageFrameCache::isAsyncDecodingQueueIdle): A helper function to tell whether the decoding thread is idle.
+        (WebCore::ImageFrameCache::stopAsyncDecodingQueue): hasDecodingQueue() was renamed to hasAsyncDecodingQueue().
+        * platform/graphics/ImageFrameCache.h:
+        (WebCore::ImageFrameCache::hasAsyncDecodingQueue): Rename this function to be consistent with the rest of the functions.
+        (WebCore::ImageFrameCache::hasDecodingQueue): Deleted.
+
+        * platform/graphics/ImageSource.cpp:
+        (WebCore::ImageSource::shouldUseAsyncDecoding): Renaming a function. Change the heuristic for large images be
+        a little bigger than the heuristic for animated images.
+        (WebCore::ImageSource::isAsyncDecodingRequired): Deleted.
+        * platform/graphics/ImageSource.h:
+        (WebCore::ImageSource::hasAsyncDecodingQueue): hasDecodingQueue() was renamed to hasAsyncDecodingQueue().
+        (WebCore::ImageSource::isAsyncDecodingQueueIdle): A wrapper for ImageFrameCache::isAsyncDecodingQueueIdle().
+        (WebCore::ImageSource::hasDecodingQueue): Deleted.
+        
+        * platform/graphics/cg/ImageDecoderCG.cpp:
+        (WebCore::ImageDecoder::createFrameImageAtIndex): CGImageSourceCreateThumbnailAtIndex() returns a CGImage with
+        the image native size regardless of the subsamplingLevel unless kCGImageSourceSubsampleFactor is passed. Here
+        we are trying to see which size is smaller: the image native size or the sizeForDrawing. If we want a CGImage
+        with the image native size, sizeForDrawing will not passed. So we need to get the image native size with the
+        default subsampling and then compare it with sizeForDrawing.
+
</ins><span class="cx"> 2017-03-11  Jon Lee  &lt;jonlee@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         WebGPU prototype - Front-End
</span></span></pre></div>
<a id="trunkSourceWebCoreloadercacheCachedImageh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/loader/cache/CachedImage.h (213763 => 213764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/loader/cache/CachedImage.h        2017-03-12 01:07:32 UTC (rev 213763)
+++ trunk/Source/WebCore/loader/cache/CachedImage.h        2017-03-12 03:00:46 UTC (rev 213764)
</span><span class="lines">@@ -144,8 +144,8 @@
</span><span class="cx"> #else
</span><span class="cx">         bool m_allowSubsampling { false };
</span><span class="cx"> #endif
</span><del>-        bool m_allowLargeImageAsyncDecoding { true };
-        bool m_allowAnimatedImageAsyncDecoding { true };
</del><ins>+        bool m_allowLargeImageAsyncDecoding { false };
+        bool m_allowAnimatedImageAsyncDecoding { false };
</ins><span class="cx">         bool m_showDebugBackground { false };
</span><span class="cx">     };
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsBitmapImagecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/BitmapImage.cpp (213763 => 213764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/BitmapImage.cpp        2017-03-12 01:07:32 UTC (rev 213763)
+++ trunk/Source/WebCore/platform/graphics/BitmapImage.cpp        2017-03-12 03:00:46 UTC (rev 213764)
</span><span class="lines">@@ -67,7 +67,7 @@
</span><span class="cx"> {
</span><span class="cx">     if (!destroyAll)
</span><span class="cx">         m_source.destroyDecodedDataBeforeFrame(m_currentFrame);
</span><del>-    else if (m_source.hasDecodingQueue())
</del><ins>+    else if (m_source.hasAsyncDecodingQueue())
</ins><span class="cx">         m_source.destroyAllDecodedDataExcludeFrame(m_currentFrame);
</span><span class="cx">     else
</span><span class="cx">         m_source.destroyAllDecodedData();
</span><span class="lines">@@ -74,7 +74,7 @@
</span><span class="cx"> 
</span><span class="cx">     // There's no need to throw away the decoder unless we're explicitly asked
</span><span class="cx">     // to destroy all of the frames.
</span><del>-    if (!destroyAll || m_source.hasDecodingQueue())
</del><ins>+    if (!destroyAll || m_source.hasAsyncDecodingQueue())
</ins><span class="cx">         m_source.clearFrameBufferCache(m_currentFrame);
</span><span class="cx">     else
</span><span class="cx">         m_source.clear(data());
</span><span class="lines">@@ -103,7 +103,7 @@
</span><span class="cx"> NativeImagePtr BitmapImage::frameImageAtIndex(size_t index, const std::optional&lt;SubsamplingLevel&gt;&amp; subsamplingLevel, const std::optional&lt;IntSize&gt;&amp; sizeForDrawing, const GraphicsContext* targetContext)
</span><span class="cx"> {
</span><span class="cx">     if (!frameHasValidNativeImageAtIndex(index, subsamplingLevel, sizeForDrawing)) {
</span><del>-        LOG(Images, &quot;BitmapImage::%s - %p - url: %s [subsamplingLevel was %d, resampling]&quot;, __FUNCTION__, this, sourceURL().characters8(), static_cast&lt;int&gt;(frameSubsamplingLevelAtIndex(index)));
</del><ins>+        LOG(Images, &quot;BitmapImage::%s - %p - url: %s [subsamplingLevel was %d, resampling]&quot;, __FUNCTION__, this, sourceURL().utf8().data(), static_cast&lt;int&gt;(frameSubsamplingLevelAtIndex(index)));
</ins><span class="cx">         invalidatePlatformData();
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -161,29 +161,53 @@
</span><span class="cx">     if (destRect.isEmpty() || srcRect.isEmpty())
</span><span class="cx">         return;
</span><span class="cx"> 
</span><del>-    m_sizeForDrawing = enclosingIntRect(destRect).size();
-    StartAnimationResult result = internalStartAnimation();
</del><ins>+    float scale = subsamplingScale(context, destRect, srcRect);
+    m_currentSubsamplingLevel = allowSubsampling() ? m_source.subsamplingLevelForScale(scale) : SubsamplingLevel::Default;
+    m_sizeForDrawing = enclosingIntRect(context.getCTM().mapRect(destRect)).size();
</ins><span class="cx"> 
</span><del>-    Color color;
-    if (result == StartAnimationResult::DecodingActive &amp;&amp; showDebugBackground())
-        color = Color::yellow;
-    else
-        color = singlePixelSolidColor();
</del><ins>+    LOG(Images, &quot;BitmapImage::%s - %p - url: %s [subsamplingLevel = %d scale = %.4f]&quot;, __FUNCTION__, this, sourceURL().utf8().data(), static_cast&lt;int&gt;(m_currentSubsamplingLevel), scale);
</ins><span class="cx"> 
</span><del>-    if (color.isValid()) {
-        fillWithSolidColor(context, destRect, color, op);
</del><ins>+    StartAnimationResult result = internalStartAnimation();
+    if (result == StartAnimationResult::DecodingActive &amp;&amp; showDebugBackground()) {
+        fillWithSolidColor(context, destRect, Color::yellow, op);
</ins><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    float scale = subsamplingScale(context, destRect, srcRect);
-    m_currentSubsamplingLevel = allowSubsampling() ? m_source.subsamplingLevelForScale(scale) : SubsamplingLevel::Default;
-    LOG(Images, &quot;BitmapImage::%s - %p - url: %s [m_currentFrame = %ld subsamplingLevel = %d scale = %.4f]&quot;, __FUNCTION__, this, sourceURL().characters8(), m_currentFrame, static_cast&lt;int&gt;(m_currentSubsamplingLevel), scale);
</del><ins>+    ASSERT_IMPLIES(result == StartAnimationResult::DecodingActive, m_source.frameHasValidNativeImageAtIndex(m_currentFrame, m_currentSubsamplingLevel, m_sizeForDrawing));
</ins><span class="cx"> 
</span><del>-    ASSERT_IMPLIES(result == StartAnimationResult::DecodingActive, m_source.frameHasValidNativeImageAtIndex(m_currentFrame, m_currentSubsamplingLevel, m_sizeForDrawing));
-    auto image = frameImageAtIndex(m_currentFrame, m_currentSubsamplingLevel, m_sizeForDrawing, &amp;context);
</del><ins>+    NativeImagePtr image;
+    if (shouldUseAsyncDecodingForLargeImage()) {
+        if (m_source.frameHasValidNativeImageAtIndex(m_currentFrame, m_currentSubsamplingLevel, m_sizeForDrawing))
+            image = frameImageAtIndex(m_currentFrame, m_currentSubsamplingLevel, m_sizeForDrawing, &amp;context);
+        else {
+            ASSERT(!canAnimate() &amp;&amp; !m_currentFrame);
+            if (!frameIsBeingDecodedAtIndex(m_currentFrame, m_sizeForDrawing)) {
+                m_source.requestFrameAsyncDecodingAtIndex(0, m_currentSubsamplingLevel, m_sizeForDrawing);
+                LOG(Images, &quot;BitmapImage::%s - %p - url: %s [requesting large async decoding]&quot;, __FUNCTION__, this, sourceURL().utf8().data());
+            }
+
+            if (!frameHasDecodedNativeImage(m_currentFrame)) {
+                if (showDebugBackground())
+                    fillWithSolidColor(context, destRect, Color::yellow, op);
+                return;
+            }
+
+            image = frameImageAtIndex(m_currentFrame);
+        }
+    } else {
+        ASSERT(!frameIsBeingDecodedAtIndex(m_currentFrame, m_sizeForDrawing));
+        image = frameImageAtIndex(m_currentFrame, m_currentSubsamplingLevel, { }, &amp;context);
+    }
+
</ins><span class="cx">     if (!image) // If it's too early we won't have an image yet.
</span><span class="cx">         return;
</span><span class="cx"> 
</span><ins>+    Color color = singlePixelSolidColor();
+    if (color.isValid()) {
+        fillWithSolidColor(context, destRect, color, op);
+        return;
+    }
+
</ins><span class="cx">     ImageOrientation orientation(description.imageOrientation());
</span><span class="cx">     if (description.respectImageOrientation() == RespectImageOrientation)
</span><span class="cx">         orientation = frameOrientationAtIndex(m_currentFrame);
</span><span class="lines">@@ -238,14 +262,14 @@
</span><span class="cx">     return shouldAnimate() &amp;&amp; frameCount() &gt; 1;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool BitmapImage::isLargeImageAsyncDecodingRequired()
</del><ins>+bool BitmapImage::shouldUseAsyncDecodingForLargeImage()
</ins><span class="cx"> {
</span><del>-    return !canAnimate() &amp;&amp; allowLargeImageAsyncDecoding() &amp;&amp; (isAsyncDecodingForcedForTesting() || m_source.isAsyncDecodingRequired());
</del><ins>+    return !canAnimate() &amp;&amp; allowLargeImageAsyncDecoding() &amp;&amp; (shouldUseAsyncDecodingForTesting() || m_source.shouldUseAsyncDecoding());
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool BitmapImage::isAnimatedImageAsyncDecodingRequired()
</del><ins>+bool BitmapImage::shouldUseAsyncDecodingForAnimatedImage()
</ins><span class="cx"> {
</span><del>-    return canAnimate() &amp;&amp; allowAnimatedImageAsyncDecoding() &amp;&amp; (isAsyncDecodingForcedForTesting() || m_source.isAsyncDecodingRequired());
</del><ins>+    return canAnimate() &amp;&amp; allowAnimatedImageAsyncDecoding() &amp;&amp; (shouldUseAsyncDecodingForTesting() || m_source.shouldUseAsyncDecoding());
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void BitmapImage::clearTimer()
</span><span class="lines">@@ -267,11 +291,11 @@
</span><span class="cx"> 
</span><span class="cx">     if (m_frameTimer)
</span><span class="cx">         return StartAnimationResult::TimerActive;
</span><del>-    
</del><ins>+
</ins><span class="cx">     // Don't start a new animation until we draw the frame that is currently being decoded.
</span><span class="cx">     size_t nextFrame = (m_currentFrame + 1) % frameCount();
</span><span class="cx">     if (frameIsBeingDecodedAtIndex(nextFrame, m_sizeForDrawing)) {
</span><del>-        LOG(Images, &quot;BitmapImage::%s - %p - url: %s [nextFrame = %ld is being decoded]&quot;, __FUNCTION__, this, sourceURL().characters8(), nextFrame);
</del><ins>+        LOG(Images, &quot;BitmapImage::%s - %p - url: %s [nextFrame = %ld is being decoded]&quot;, __FUNCTION__, this, sourceURL().utf8().data(), nextFrame);
</ins><span class="cx">         return StartAnimationResult::DecodingActive;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -312,14 +336,14 @@
</span><span class="cx">     // it will be decoded on a separate work queue. When decoding nextFrame finishes, we will be notified
</span><span class="cx">     // through the callback newFrameNativeImageAvailableAtIndex(). Otherwise, advanceAnimation() will be called
</span><span class="cx">     // when the timer fires and m_currentFrame will be advanced to nextFrame since it is not being decoded.
</span><del>-    if (m_sizeForDrawing &amp;&amp; isAnimatedImageAsyncDecodingRequired()) {
-        bool isAsyncDecode = m_source.requestFrameAsyncDecodingAtIndex(nextFrame, m_currentSubsamplingLevel, *m_sizeForDrawing);
</del><ins>+    if (shouldUseAsyncDecodingForAnimatedImage()) {
+        bool isAsyncDecode = m_source.requestFrameAsyncDecodingAtIndex(nextFrame, m_currentSubsamplingLevel, m_sizeForDrawing);
</ins><span class="cx"> 
</span><span class="cx"> #if !LOG_DISABLED
</span><span class="cx">         if (isAsyncDecode)
</span><del>-            LOG(Images, &quot;BitmapImage::%s - %p - url: %s [requesting async decoding for nextFrame = %ld]&quot;, __FUNCTION__, this, sourceURL().characters8(), nextFrame);
</del><ins>+            LOG(Images, &quot;BitmapImage::%s - %p - url: %s [requesting async decoding for nextFrame = %ld]&quot;, __FUNCTION__, this, sourceURL().utf8().data(), nextFrame);
</ins><span class="cx">         else
</span><del>-            LOG(Images, &quot;BitmapImage::%s - %p - url: %s [cachedFrameCount = %ld nextFrame = %ld]&quot;, __FUNCTION__, this, sourceURL().characters8(), ++m_cachedFrameCount, nextFrame);
</del><ins>+            LOG(Images, &quot;BitmapImage::%s - %p - url: %s [cachedFrameCount = %ld nextFrame = %ld]&quot;, __FUNCTION__, this, sourceURL().utf8().data(), ++m_cachedFrameCount, nextFrame);
</ins><span class="cx"> #else
</span><span class="cx">         UNUSED_PARAM(isAsyncDecode);
</span><span class="cx"> #endif
</span><span class="lines">@@ -338,7 +362,7 @@
</span><span class="cx"> 
</span><span class="cx">     // Pretend as if decoding nextFrame has taken m_frameDecodingDurationForTesting from
</span><span class="cx">     // the time this decoding was requested.
</span><del>-    if (isAsyncDecodingForcedForTesting()) {
</del><ins>+    if (shouldUseAsyncDecodingForTesting()) {
</ins><span class="cx">         double time = monotonicallyIncreasingTime();
</span><span class="cx">         // Start a timer with the remaining time from now till the m_desiredFrameDecodeTime.
</span><span class="cx">         if (m_desiredFrameDecodeTimeForTesting &gt; std::max(time, m_desiredFrameStartTime)) {
</span><span class="lines">@@ -346,7 +370,7 @@
</span><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx">     }
</span><del>-    
</del><ins>+
</ins><span class="cx">     // Don't advance to nextFrame unless its decoding has finished or was not required.
</span><span class="cx">     size_t nextFrame = (m_currentFrame + 1) % frameCount();
</span><span class="cx">     if (!frameIsBeingDecodedAtIndex(nextFrame, m_sizeForDrawing))
</span><span class="lines">@@ -355,7 +379,7 @@
</span><span class="cx">         // Force repaint if showDebugBackground() is on.
</span><span class="cx">         if (showDebugBackground())
</span><span class="cx">             imageObserver()-&gt;changedInRect(this);
</span><del>-        LOG(Images, &quot;BitmapImage::%s - %p - url: %s [lateFrameCount = %ld nextFrame = %ld]&quot;, __FUNCTION__, this, sourceURL().characters8(), ++m_lateFrameCount, nextFrame);
</del><ins>+        LOG(Images, &quot;BitmapImage::%s - %p - url: %s [lateFrameCount = %ld nextFrame = %ld]&quot;, __FUNCTION__, this, sourceURL().utf8().data(), ++m_lateFrameCount, nextFrame);
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -369,7 +393,7 @@
</span><span class="cx">     if (imageObserver())
</span><span class="cx">         imageObserver()-&gt;animationAdvanced(this);
</span><span class="cx"> 
</span><del>-    LOG(Images, &quot;BitmapImage::%s - %p - url: %s [m_currentFrame = %ld]&quot;, __FUNCTION__, this, sourceURL().characters8(), m_currentFrame);
</del><ins>+    LOG(Images, &quot;BitmapImage::%s - %p - url: %s [m_currentFrame = %ld]&quot;, __FUNCTION__, this, sourceURL().utf8().data(), m_currentFrame);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void BitmapImage::stopAnimation()
</span><span class="lines">@@ -395,13 +419,21 @@
</span><span class="cx"> void BitmapImage::newFrameNativeImageAvailableAtIndex(size_t index)
</span><span class="cx"> {
</span><span class="cx">     UNUSED_PARAM(index);
</span><del>-    ASSERT(index == (m_currentFrame + 1) % frameCount());
-
-    // Don't advance to nextFrame unless the timer was fired before its decoding finishes.
-    if (canAnimate() &amp;&amp; !m_frameTimer)
-        internalAdvanceAnimation();
-    else
-        LOG(Images, &quot;BitmapImage::%s - %p - url: %s [earlyFrameCount = %ld nextFrame = %ld]&quot;, __FUNCTION__, this, sourceURL().characters8(), ++m_earlyFrameCount, index);
</del><ins>+    if (canAnimate()) {
+        ASSERT(index == (m_currentFrame + 1) % frameCount());
+        
+        // Don't advance to nextFrame unless the timer was fired before its decoding finishes.
+        if (canAnimate() &amp;&amp; !m_frameTimer)
+            internalAdvanceAnimation();
+        else
+            LOG(Images, &quot;BitmapImage::%s - %p - url: %s [earlyFrameCount = %ld nextFrame = %ld]&quot;, __FUNCTION__, this, sourceURL().utf8().data(), ++m_earlyFrameCount, index);
+    } else {
+        ASSERT(index == m_currentFrame &amp;&amp; !m_currentFrame);
+        imageObserver()-&gt;changedInRect(this, nullptr);
+        
+        if (m_source.isAsyncDecodingQueueIdle())
+            m_source.stopAsyncDecodingQueue();
+    }
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void BitmapImage::dump(TextStream&amp; ts) const
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsBitmapImageh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/BitmapImage.h (213763 => 213764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/BitmapImage.h        2017-03-12 01:07:32 UTC (rev 213763)
+++ trunk/Source/WebCore/platform/graphics/BitmapImage.h        2017-03-12 03:00:46 UTC (rev 213764)
</span><span class="lines">@@ -96,10 +96,10 @@
</span><span class="cx">     bool currentFrameKnownToBeOpaque() const override { return !frameHasAlphaAtIndex(currentFrame()); }
</span><span class="cx">     ImageOrientation orientationForCurrentFrame() const override { return frameOrientationAtIndex(currentFrame()); }
</span><span class="cx"> 
</span><del>-    bool isAsyncDecodingForcedForTesting() const { return m_frameDecodingDurationForTesting &gt; 0; }
</del><ins>+    bool shouldUseAsyncDecodingForTesting() const { return m_frameDecodingDurationForTesting &gt; 0; }
</ins><span class="cx">     void setFrameDecodingDurationForTesting(float duration) { m_frameDecodingDurationForTesting = duration; }
</span><del>-    bool isLargeImageAsyncDecodingRequired();
-    bool isAnimatedImageAsyncDecodingRequired();
</del><ins>+    bool shouldUseAsyncDecodingForLargeImage();
+    bool shouldUseAsyncDecodingForAnimatedImage();
</ins><span class="cx"> 
</span><span class="cx">     // Accessors for native image formats.
</span><span class="cx"> #if USE(APPKIT)
</span><span class="lines">@@ -202,7 +202,7 @@
</span><span class="cx"> 
</span><span class="cx">     size_t m_currentFrame { 0 }; // The index of the current frame of animation.
</span><span class="cx">     SubsamplingLevel m_currentSubsamplingLevel { SubsamplingLevel::Default };
</span><del>-    std::optional&lt;IntSize&gt; m_sizeForDrawing;
</del><ins>+    IntSize m_sizeForDrawing;
</ins><span class="cx">     std::unique_ptr&lt;Timer&gt; m_frameTimer;
</span><span class="cx">     RepetitionCount m_repetitionsComplete { RepetitionCountNone }; // How many repetitions we've finished.
</span><span class="cx">     double m_desiredFrameStartTime { 0 }; // The system time at which we hope to see the next call to startAnimation().
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsImageFrameCachecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/ImageFrameCache.cpp (213763 => 213764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/ImageFrameCache.cpp        2017-03-12 01:07:32 UTC (rev 213763)
+++ trunk/Source/WebCore/platform/graphics/ImageFrameCache.cpp        2017-03-12 03:00:46 UTC (rev 213764)
</span><span class="lines">@@ -67,7 +67,7 @@
</span><span class="cx"> 
</span><span class="cx"> ImageFrameCache::~ImageFrameCache()
</span><span class="cx"> {
</span><del>-    ASSERT(!hasDecodingQueue());
</del><ins>+    ASSERT(!hasAsyncDecodingQueue());
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void ImageFrameCache::destroyDecodedData(size_t frameCount, size_t excludeFrame)
</span><span class="lines">@@ -256,7 +256,7 @@
</span><span class="cx"> Ref&lt;WorkQueue&gt; ImageFrameCache::decodingQueue()
</span><span class="cx"> {
</span><span class="cx">     if (!m_decodingQueue)
</span><del>-        m_decodingQueue = WorkQueue::create(&quot;org.webkit.ImageDecoder&quot;, WorkQueue::Type::Serial, WorkQueue::QOS::UserInteractive);
</del><ins>+        m_decodingQueue = WorkQueue::create(&quot;org.webkit.ImageDecoder&quot;, WorkQueue::Type::Serial, WorkQueue::QOS::Default);
</ins><span class="cx">     
</span><span class="cx">     return *m_decodingQueue;
</span><span class="cx"> }
</span><span class="lines">@@ -263,7 +263,7 @@
</span><span class="cx"> 
</span><span class="cx"> void ImageFrameCache::startAsyncDecodingQueue()
</span><span class="cx"> {
</span><del>-    if (hasDecodingQueue() || !isDecoderAvailable())
</del><ins>+    if (hasAsyncDecodingQueue() || !isDecoderAvailable())
</ins><span class="cx">         return;
</span><span class="cx"> 
</span><span class="cx">     m_frameRequestQueue.open();
</span><span class="lines">@@ -306,7 +306,7 @@
</span><span class="cx">     if (frame.hasValidNativeImage(subsamplingLevel, sizeForDrawing))
</span><span class="cx">         return false;
</span><span class="cx"> 
</span><del>-    if (!hasDecodingQueue())
</del><ins>+    if (!hasAsyncDecodingQueue())
</ins><span class="cx">         startAsyncDecodingQueue();
</span><span class="cx">     
</span><span class="cx">     frame.enqueueSizeForDecoding(sizeForDrawing);
</span><span class="lines">@@ -314,9 +314,18 @@
</span><span class="cx">     return true;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool ImageFrameCache::isAsyncDecodingQueueIdle() const
+{
+    for (const ImageFrame&amp; frame : m_frames) {
+        if (frame.isBeingDecoded())
+            return false;
+    }
+    return true;
+}
+    
</ins><span class="cx"> void ImageFrameCache::stopAsyncDecodingQueue()
</span><span class="cx"> {
</span><del>-    if (!hasDecodingQueue())
</del><ins>+    if (!hasAsyncDecodingQueue())
</ins><span class="cx">         return;
</span><span class="cx">     
</span><span class="cx">     m_frameRequestQueue.close();
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsImageFrameCacheh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/ImageFrameCache.h (213763 => 213764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/ImageFrameCache.h        2017-03-12 01:07:32 UTC (rev 213763)
+++ trunk/Source/WebCore/platform/graphics/ImageFrameCache.h        2017-03-12 03:00:46 UTC (rev 213764)
</span><span class="lines">@@ -71,7 +71,8 @@
</span><span class="cx">     void startAsyncDecodingQueue();
</span><span class="cx">     bool requestFrameAsyncDecodingAtIndex(size_t, SubsamplingLevel, const IntSize&amp;);
</span><span class="cx">     void stopAsyncDecodingQueue();
</span><del>-    bool hasDecodingQueue() { return m_decodingQueue; }
</del><ins>+    bool hasAsyncDecodingQueue() const { return m_decodingQueue; }
+    bool isAsyncDecodingQueueIdle() const;
</ins><span class="cx"> 
</span><span class="cx">     // Image metadata which is calculated either by the ImageDecoder or directly
</span><span class="cx">     // from the NativeImage if this class was created for a memory image.
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsImageSourcecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/ImageSource.cpp (213763 => 213764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/ImageSource.cpp        2017-03-12 01:07:32 UTC (rev 213763)
+++ trunk/Source/WebCore/platform/graphics/ImageSource.cpp        2017-03-12 03:00:46 UTC (rev 213764)
</span><span class="lines">@@ -148,10 +148,10 @@
</span><span class="cx">     return isDecoderAvailable() ? m_decoder-&gt;isAllDataReceived() : m_frameCache-&gt;frameCount();
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool ImageSource::isAsyncDecodingRequired()
</del><ins>+bool ImageSource::shouldUseAsyncDecoding()
</ins><span class="cx"> {
</span><span class="cx">     // FIXME: figure out the best heuristic for enabling async image decoding.
</span><del>-    return size().area() * sizeof(RGBA32) &gt;= 100 * KB;
</del><ins>+    return size().area() * sizeof(RGBA32) &gt;= (frameCount() &gt; 1 ? 100 * KB : 500 * KB);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> SubsamplingLevel ImageSource::maximumSubsamplingLevel()
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsImageSourceh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/ImageSource.h (213763 => 213764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/ImageSource.h        2017-03-12 01:07:32 UTC (rev 213763)
+++ trunk/Source/WebCore/platform/graphics/ImageSource.h        2017-03-12 03:00:46 UTC (rev 213764)
</span><span class="lines">@@ -68,9 +68,10 @@
</span><span class="cx">     unsigned decodedSize() const { return m_frameCache-&gt;decodedSize(); }
</span><span class="cx">     bool isAllDataReceived();
</span><span class="cx"> 
</span><del>-    bool isAsyncDecodingRequired();
</del><ins>+    bool shouldUseAsyncDecoding();
</ins><span class="cx">     bool requestFrameAsyncDecodingAtIndex(size_t index, SubsamplingLevel subsamplingLevel, const IntSize&amp; sizeForDrawing) { return m_frameCache-&gt;requestFrameAsyncDecodingAtIndex(index, subsamplingLevel, sizeForDrawing); }
</span><del>-    bool hasDecodingQueue() const { return m_frameCache-&gt;hasDecodingQueue(); }
</del><ins>+    bool hasAsyncDecodingQueue() const { return m_frameCache-&gt;hasAsyncDecodingQueue(); }
+    bool isAsyncDecodingQueueIdle() const  { return m_frameCache-&gt;isAsyncDecodingQueueIdle(); }
</ins><span class="cx">     void stopAsyncDecodingQueue() { m_frameCache-&gt;stopAsyncDecodingQueue(); }
</span><span class="cx"> 
</span><span class="cx">     // Image metadata which is calculated by the decoder or can deduced by the case of the memory NativeImage.
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicscgImageDecoderCGcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/cg/ImageDecoderCG.cpp (213763 => 213764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/cg/ImageDecoderCG.cpp        2017-03-12 01:07:32 UTC (rev 213763)
+++ trunk/Source/WebCore/platform/graphics/cg/ImageDecoderCG.cpp        2017-03-12 03:00:46 UTC (rev 213764)
</span><span class="lines">@@ -377,7 +377,13 @@
</span><span class="cx">         options = imageSourceOptions(subsamplingLevel);
</span><span class="cx">         image = adoptCF(CGImageSourceCreateImageAtIndex(m_nativeDecoder.get(), index, options.get()));
</span><span class="cx">     } else {
</span><del>-        IntSize size = frameSizeAtIndex(index, subsamplingLevel);
</del><ins>+        // CGImageSourceCreateThumbnailAtIndex() returns a CGImage with the image native size
+        // regardless of the subsamplingLevel unless kCGImageSourceSubsampleFactor is passed.
+        // Here we are trying to see which size is smaller: the image native size or the
+        // sizeForDrawing. If we want a CGImage with the image native size, sizeForDrawing will
+        // not passed. So we need to get the image native size with the default subsampling and
+        // then compare it with sizeForDrawing.
+        IntSize size = frameSizeAtIndex(index, SubsamplingLevel::Default);
</ins><span class="cx"> 
</span><span class="cx">         if (size.unclampedArea() &lt; sizeForDrawing.value().unclampedArea()) {
</span><span class="cx">             // Decode an image asynchronously for its native size.
</span></span></pre></div>
<a id="trunkSourceWebKit2ChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/ChangeLog (213763 => 213764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/ChangeLog        2017-03-12 01:07:32 UTC (rev 213763)
+++ trunk/Source/WebKit2/ChangeLog        2017-03-12 03:00:46 UTC (rev 213764)
</span><span class="lines">@@ -1,3 +1,20 @@
</span><ins>+2017-03-11  Said Abou-Hallawa  &lt;sabouhallawa@apple.com&gt;
+
+        Enable async image decoding for large images
+        https://bugs.webkit.org/show_bug.cgi?id=165039
+
+        Reviewed by Simon Fraser.
+
+        Add WK2 preferences for setting/getting LargeImageAsyncDecoding and
+        AnimatedImageAsyncDecoding.
+        
+        * UIProcess/API/C/WKPreferences.cpp:
+        (WKPreferencesSetLargeImageAsyncDecodingEnabled):
+        (WKPreferencesGetLargeImageAsyncDecodingEnabled):
+        (WKPreferencesSetAnimatedImageAsyncDecodingEnabled):
+        (WKPreferencesGetAnimatedImageAsyncDecodingEnabled):
+        * UIProcess/API/C/WKPreferencesRefPrivate.h:
+
</ins><span class="cx"> 2017-03-11  Alex Christensen  &lt;achristensen@webkit.org&gt;
</span><span class="cx"> 
</span><span class="cx">         Rollout r213746
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessAPICWKPreferencescpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/API/C/WKPreferences.cpp (213763 => 213764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/API/C/WKPreferences.cpp        2017-03-12 01:07:32 UTC (rev 213763)
+++ trunk/Source/WebKit2/UIProcess/API/C/WKPreferences.cpp        2017-03-12 03:00:46 UTC (rev 213764)
</span><span class="lines">@@ -1691,6 +1691,26 @@
</span><span class="cx">     return toImpl(preferencesRef)-&gt;linkPreloadEnabled();
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void WKPreferencesSetLargeImageAsyncDecodingEnabled(WKPreferencesRef preferencesRef, bool flag)
+{
+    toImpl(preferencesRef)-&gt;setLargeImageAsyncDecodingEnabled(flag);
+}
+
+bool WKPreferencesGetLargeImageAsyncDecodingEnabled(WKPreferencesRef preferencesRef)
+{
+    return toImpl(preferencesRef)-&gt;largeImageAsyncDecodingEnabled();
+}
+
+void WKPreferencesSetAnimatedImageAsyncDecodingEnabled(WKPreferencesRef preferencesRef, bool flag)
+{
+    toImpl(preferencesRef)-&gt;setAnimatedImageAsyncDecodingEnabled(flag);
+}
+
+bool WKPreferencesGetAnimatedImageAsyncDecodingEnabled(WKPreferencesRef preferencesRef)
+{
+    return toImpl(preferencesRef)-&gt;animatedImageAsyncDecodingEnabled();
+}
+
</ins><span class="cx"> void WKPreferencesSetShouldSuppressKeyboardInputDuringProvisionalNavigation(WKPreferencesRef preferencesRef, bool flag)
</span><span class="cx"> {
</span><span class="cx">     toImpl(preferencesRef)-&gt;setShouldSuppressKeyboardInputDuringProvisionalNavigation(flag);
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessAPICWKPreferencesRefPrivateh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/API/C/WKPreferencesRefPrivate.h (213763 => 213764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/API/C/WKPreferencesRefPrivate.h        2017-03-12 01:07:32 UTC (rev 213763)
+++ trunk/Source/WebKit2/UIProcess/API/C/WKPreferencesRefPrivate.h        2017-03-12 03:00:46 UTC (rev 213764)
</span><span class="lines">@@ -465,6 +465,14 @@
</span><span class="cx"> WK_EXPORT void WKPreferencesSetSubtleCryptoEnabled(WKPreferencesRef, bool flag);
</span><span class="cx"> WK_EXPORT bool WKPreferencesGetSubtleCryptoEnabled(WKPreferencesRef);
</span><span class="cx"> 
</span><ins>+// Defaults to true.
+WK_EXPORT void WKPreferencesSetLargeImageAsyncDecodingEnabled(WKPreferencesRef preferencesRef, bool flag);
+WK_EXPORT bool WKPreferencesGetLargeImageAsyncDecodingEnabled(WKPreferencesRef preferencesRef);
+
+// Defaults to true.
+WK_EXPORT void WKPreferencesSetAnimatedImageAsyncDecodingEnabled(WKPreferencesRef preferencesRef, bool flag);
+WK_EXPORT bool WKPreferencesGetAnimatedImageAsyncDecodingEnabled(WKPreferencesRef preferencesRef);
+
</ins><span class="cx"> // Defaults to false
</span><span class="cx"> WK_EXPORT void WKPreferencesSetShouldSuppressKeyboardInputDuringProvisionalNavigation(WKPreferencesRef, bool flag);
</span><span class="cx"> WK_EXPORT bool WKPreferencesGetShouldSuppressKeyboardInputDuringProvisionalNavigation(WKPreferencesRef);
</span></span></pre></div>
<a id="trunkToolsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Tools/ChangeLog (213763 => 213764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/ChangeLog        2017-03-12 01:07:32 UTC (rev 213763)
+++ trunk/Tools/ChangeLog        2017-03-12 03:00:46 UTC (rev 213764)
</span><span class="lines">@@ -1,3 +1,17 @@
</span><ins>+2017-03-11  Said Abou-Hallawa  &lt;sabouhallawa@apple.com&gt;
+
+        Enable async image decoding for large images
+        https://bugs.webkit.org/show_bug.cgi?id=165039
+
+        Reviewed by Simon Fraser.
+
+        Disable LargeImageAsyncDecoding for DRT/WTR.
+
+        * DumpRenderTree/mac/DumpRenderTree.mm:
+        (resetWebPreferencesToConsistentValues):
+        * WebKitTestRunner/TestController.cpp:
+        (WTR::TestController::resetPreferencesToConsistentValues):
+
</ins><span class="cx"> 2017-03-10  Alex Christensen  &lt;achristensen@webkit.org&gt;
</span><span class="cx"> 
</span><span class="cx">         Fix watch and tv builds after r213294
</span></span></pre></div>
<a id="trunkToolsDumpRenderTreemacDumpRenderTreemm"></a>
<div class="modfile"><h4>Modified: trunk/Tools/DumpRenderTree/mac/DumpRenderTree.mm (213763 => 213764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/DumpRenderTree/mac/DumpRenderTree.mm        2017-03-12 01:07:32 UTC (rev 213763)
+++ trunk/Tools/DumpRenderTree/mac/DumpRenderTree.mm        2017-03-12 03:00:46 UTC (rev 213764)
</span><span class="lines">@@ -956,6 +956,8 @@
</span><span class="cx">     [preferences setHiddenPageCSSAnimationSuspensionEnabled:NO];
</span><span class="cx">     
</span><span class="cx">     [preferences setMediaStreamEnabled:YES];
</span><ins>+    
+    [preferences setLargeImageAsyncDecodingEnabled:NO];
</ins><span class="cx"> 
</span><span class="cx">     [WebPreferences _clearNetworkLoaderSession];
</span><span class="cx">     [WebPreferences _setCurrentNetworkLoaderSessionCookieAcceptPolicy:NSHTTPCookieAcceptPolicyOnlyFromMainDocumentDomain];
</span></span></pre></div>
<a id="trunkToolsWebKitTestRunnerTestControllercpp"></a>
<div class="modfile"><h4>Modified: trunk/Tools/WebKitTestRunner/TestController.cpp (213763 => 213764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/WebKitTestRunner/TestController.cpp        2017-03-12 01:07:32 UTC (rev 213763)
+++ trunk/Tools/WebKitTestRunner/TestController.cpp        2017-03-12 03:00:46 UTC (rev 213764)
</span><span class="lines">@@ -719,6 +719,8 @@
</span><span class="cx">     WKCookieManagerDeleteAllCookies(WKContextGetCookieManager(m_context.get()));
</span><span class="cx"> 
</span><span class="cx">     WKPreferencesSetMockCaptureDevicesEnabled(preferences, true);
</span><ins>+    
+    WKPreferencesSetLargeImageAsyncDecodingEnabled(preferences, false);
</ins><span class="cx"> 
</span><span class="cx">     platformResetPreferencesToConsistentValues();
</span><span class="cx"> }
</span></span></pre>
</div>
</div>

</body>
</html>