<!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>[213618] 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/213618">213618</a></dd>
<dt>Author</dt> <dd>commit-queue@webkit.org</dd>
<dt>Date</dt> <dd>2017-03-08 18:16:51 -0800 (Wed, 08 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-08
Reviewed by Simon Fraser.

Source/WebCore:

Once FrameView finishes flushing compositing, it will request all its
images, which intersect with the tileCoverageRect (aka the futureRect)
of the  TileController, to start asynchronously decoding their image frames.
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.

* html/HTMLImageElement.cpp:
(WebCore::HTMLImageElement::didAttachRenderers):
(WebCore::HTMLImageElement::willDetachRenderers):
Register/unregister the renderer of the HTMLImageElement for async image decoding
from the RenderView. I followed what HTMLMediaElement to registerForVisibleInViewportCallback().
* html/HTMLImageElement.h:

* page/FrameView.cpp:
(WebCore::FrameView::flushCompositingStateForThisFrame): For all the images inside
the  tileCoverageRect of the TileController, request async image decoding.
(WebCore::FrameView::applyRecursivelyWithAbsoluteRect): Request the async image decoding for the
the images inside this FrameView and then recursively do the same thing for all sub FrameViews.
(WebCore::FrameView::requestAsyncDecodingForImagesInAbsoluteRect): Calls the RenderView to
make the request.
(WebCore::FrameView::requestAsyncDecodingForImagesInAbsoluteRectIncludingSubframes): Calls
applyRecursivelyWithAbsoluteRect giving an apply lambda which calls requestAsyncDecodingForImagesInAbsoluteRect.
* page/FrameView.h:

* platform/graphics/BitmapImage.cpp:
(WebCore::BitmapImage::destroyDecodedData): ImageSource::hasDecodingQueue() is renamed to ImageSource::hasAsyncDecodingQueue().
(WebCore::BitmapImage::dataChanged): 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 the 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::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::requestAsyncDecoding): This is called form
RenderView::requestAsyncDecodingForImagesInRect().
* platform/graphics/BitmapImage.h:

* platform/graphics/Image.h:
(WebCore::Image::requestAsyncDecoding): Add the default implementation of a virtual function.

* 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.h:
(WebCore::ImageSource::hasAsyncDecodingQueue): hasDecodingQueue() was renamed to hasAsyncDecodingQueue().
(WebCore::ImageSource::isAsyncDecodingQueueIdle): A wrapper for ImageFrameCache::isAsyncDecodingQueueIdle().
(WebCore::ImageSource::hasDecodingQueue): Deleted.

* platform/graphics/TiledBacking.h: Fix a comment. tileGridExtent() is the only one that is used for testing.

* rendering/RenderElement.cpp:
(WebCore::RenderElement::~RenderElement):
(WebCore::RenderElement::intersectsAbsoluteRect): Make this function does what shouldRepaintForImageAnimation()
was doing expect the check for document.activeDOMObjectsAreSuspended().
(WebCore::RenderElement::newImageAnimationFrameAvailable): Replace the call to
shouldRepaintForImageAnimation() by checking document().activeDOMObjectsAreSuspended() then a call to
RenderElement::intersectsAbsoluteRect().
(WebCore::RenderElement::repaintForPausedImageAnimationsIfNeeded): Ditto.
(WebCore::RenderElement::registerForAsyncImageDecodingCallback): Call the RenderView to register the renderer..
(WebCore::RenderElement::unregisterForAsyncImageDecodingCallback): Call the RenderView to unregister the renderer..
(WebCore::shouldRepaintForImageAnimation): Deleted.
* rendering/RenderElement.h:

* rendering/RenderObject.cpp:
(WebCore::RenderObject::setIsRegisteredForAsyncImageDecodingCallback):
* rendering/RenderObject.h:
(WebCore::RenderObject::isRegisteredForAsyncImageDecodingCallback):
(WebCore::RenderObject::RenderObjectRareData::RenderObjectRareData):
Mark/unmark the renderer for being RegisteredForAsyncImageDecodingCallback.

* rendering/RenderReplaced.h: Make intrinsicSize() be a public function.

* rendering/RenderView.cpp:
(WebCore::RenderView::registerForAsyncImageDecodingCallback): Register a renderer for async image decoding.
(WebCore::RenderView::unregisterForAsyncImageDecodingCallback): Remove a renderer from the list of async image decoding.
(WebCore::RenderView::requestAsyncDecodingForImagesInAbsoluteRect):This loops through all the registered RenderImages
inside this RenderView and if any of them intersects with the rectangle, requestAsyncDecoding for it.
* rendering/RenderView.h:

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="#trunkSourceWebCorehtmlHTMLImageElementcpp">trunk/Source/WebCore/html/HTMLImageElement.cpp</a></li>
<li><a href="#trunkSourceWebCorehtmlHTMLImageElementh">trunk/Source/WebCore/html/HTMLImageElement.h</a></li>
<li><a href="#trunkSourceWebCorepageFrameViewcpp">trunk/Source/WebCore/page/FrameView.cpp</a></li>
<li><a href="#trunkSourceWebCorepageFrameViewh">trunk/Source/WebCore/page/FrameView.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="#trunkSourceWebCoreplatformgraphicsImageh">trunk/Source/WebCore/platform/graphics/Image.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="#trunkSourceWebCoreplatformgraphicsImageSourceh">trunk/Source/WebCore/platform/graphics/ImageSource.h</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicsTiledBackingh">trunk/Source/WebCore/platform/graphics/TiledBacking.h</a></li>
<li><a href="#trunkSourceWebCorerenderingRenderElementcpp">trunk/Source/WebCore/rendering/RenderElement.cpp</a></li>
<li><a href="#trunkSourceWebCorerenderingRenderElementh">trunk/Source/WebCore/rendering/RenderElement.h</a></li>
<li><a href="#trunkSourceWebCorerenderingRenderObjectcpp">trunk/Source/WebCore/rendering/RenderObject.cpp</a></li>
<li><a href="#trunkSourceWebCorerenderingRenderObjecth">trunk/Source/WebCore/rendering/RenderObject.h</a></li>
<li><a href="#trunkSourceWebCorerenderingRenderReplacedh">trunk/Source/WebCore/rendering/RenderReplaced.h</a></li>
<li><a href="#trunkSourceWebCorerenderingRenderViewcpp">trunk/Source/WebCore/rendering/RenderView.cpp</a></li>
<li><a href="#trunkSourceWebCorerenderingRenderViewh">trunk/Source/WebCore/rendering/RenderView.h</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 (213617 => 213618)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2017-03-09 02:13:31 UTC (rev 213617)
+++ trunk/Source/WebCore/ChangeLog        2017-03-09 02:16:51 UTC (rev 213618)
</span><span class="lines">@@ -1,3 +1,115 @@
</span><ins>+2017-03-08  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.
+
+        Once FrameView finishes flushing compositing, it will request all its
+        images, which intersect with the tileCoverageRect (aka the futureRect)
+        of the  TileController, to start asynchronously decoding their image frames.
+        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.
+
+        * html/HTMLImageElement.cpp:
+        (WebCore::HTMLImageElement::didAttachRenderers):
+        (WebCore::HTMLImageElement::willDetachRenderers):
+        Register/unregister the renderer of the HTMLImageElement for async image decoding
+        from the RenderView. I followed what HTMLMediaElement to registerForVisibleInViewportCallback().
+        * html/HTMLImageElement.h:
+        
+        * page/FrameView.cpp:
+        (WebCore::FrameView::flushCompositingStateForThisFrame): For all the images inside
+        the  tileCoverageRect of the TileController, request async image decoding.
+        (WebCore::FrameView::applyRecursivelyWithAbsoluteRect): Request the async image decoding for the
+        the images inside this FrameView and then recursively do the same thing for all sub FrameViews.
+        (WebCore::FrameView::requestAsyncDecodingForImagesInAbsoluteRect): Calls the RenderView to
+        make the request.
+        (WebCore::FrameView::requestAsyncDecodingForImagesInAbsoluteRectIncludingSubframes): Calls
+        applyRecursivelyWithAbsoluteRect giving an apply lambda which calls requestAsyncDecodingForImagesInAbsoluteRect.
+        * page/FrameView.h:
+
+        * platform/graphics/BitmapImage.cpp:
+        (WebCore::BitmapImage::destroyDecodedData): ImageSource::hasDecodingQueue() is renamed to ImageSource::hasAsyncDecodingQueue().
+        (WebCore::BitmapImage::dataChanged): 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 the 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::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::requestAsyncDecoding): This is called form 
+        RenderView::requestAsyncDecodingForImagesInRect().
+        * platform/graphics/BitmapImage.h:
+
+        * platform/graphics/Image.h:
+        (WebCore::Image::requestAsyncDecoding): Add the default implementation of a virtual function.
+
+        * 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.h:
+        (WebCore::ImageSource::hasAsyncDecodingQueue): hasDecodingQueue() was renamed to hasAsyncDecodingQueue().
+        (WebCore::ImageSource::isAsyncDecodingQueueIdle): A wrapper for ImageFrameCache::isAsyncDecodingQueueIdle().
+        (WebCore::ImageSource::hasDecodingQueue): Deleted.
+        
+        * platform/graphics/TiledBacking.h: Fix a comment. tileGridExtent() is the only one that is used for testing.
+
+        * rendering/RenderElement.cpp:
+        (WebCore::RenderElement::~RenderElement):
+        (WebCore::RenderElement::intersectsAbsoluteRect): Make this function does what shouldRepaintForImageAnimation()
+        was doing expect the check for document.activeDOMObjectsAreSuspended().
+        (WebCore::RenderElement::newImageAnimationFrameAvailable): Replace the call to
+        shouldRepaintForImageAnimation() by checking document().activeDOMObjectsAreSuspended() then a call to
+        RenderElement::intersectsAbsoluteRect().
+        (WebCore::RenderElement::repaintForPausedImageAnimationsIfNeeded): Ditto.
+        (WebCore::RenderElement::registerForAsyncImageDecodingCallback): Call the RenderView to register the renderer..
+        (WebCore::RenderElement::unregisterForAsyncImageDecodingCallback): Call the RenderView to unregister the renderer..
+        (WebCore::shouldRepaintForImageAnimation): Deleted.
+        * rendering/RenderElement.h:
+
+        * rendering/RenderObject.cpp:
+        (WebCore::RenderObject::setIsRegisteredForAsyncImageDecodingCallback):
+        * rendering/RenderObject.h:
+        (WebCore::RenderObject::isRegisteredForAsyncImageDecodingCallback):
+        (WebCore::RenderObject::RenderObjectRareData::RenderObjectRareData):
+        Mark/unmark the renderer for being RegisteredForAsyncImageDecodingCallback.
+
+        * rendering/RenderReplaced.h: Make intrinsicSize() be a public function.
+
+        * rendering/RenderView.cpp:
+        (WebCore::RenderView::registerForAsyncImageDecodingCallback): Register a renderer for async image decoding.
+        (WebCore::RenderView::unregisterForAsyncImageDecodingCallback): Remove a renderer from the list of async image decoding.
+        (WebCore::RenderView::requestAsyncDecodingForImagesInAbsoluteRect):This loops through all the registered RenderImages
+        inside this RenderView and if any of them intersects with the rectangle, requestAsyncDecoding for it.
+        * rendering/RenderView.h:
+
</ins><span class="cx"> 2017-03-08  Michael Catanzaro  &lt;mcatanzaro@igalia.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Fix missing return value after r213499
</span></span></pre></div>
<a id="trunkSourceWebCorehtmlHTMLImageElementcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/html/HTMLImageElement.cpp (213617 => 213618)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/html/HTMLImageElement.cpp        2017-03-09 02:13:31 UTC (rev 213617)
+++ trunk/Source/WebCore/html/HTMLImageElement.cpp        2017-03-09 02:16:51 UTC (rev 213618)
</span><span class="lines">@@ -289,8 +289,18 @@
</span><span class="cx">     // image height and width for the alt text instead.
</span><span class="cx">     if (!m_imageLoader.image() &amp;&amp; !renderImageResource.cachedImage())
</span><span class="cx">         renderImage.setImageSizeForAltText();
</span><ins>+    
+    renderImage.registerForAsyncImageDecodingCallback();
</ins><span class="cx"> }
</span><ins>+    
+void HTMLImageElement::willDetachRenderers()
+{
+    if (!is&lt;RenderImage&gt;(renderer()))
+        return;
</ins><span class="cx"> 
</span><ins>+    renderer()-&gt;unregisterForAsyncImageDecodingCallback();
+}
+
</ins><span class="cx"> Node::InsertionNotificationRequest HTMLImageElement::insertedInto(ContainerNode&amp; insertionPoint)
</span><span class="cx"> {
</span><span class="cx">     if (m_formSetByParser) {
</span></span></pre></div>
<a id="trunkSourceWebCorehtmlHTMLImageElementh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/html/HTMLImageElement.h (213617 => 213618)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/html/HTMLImageElement.h        2017-03-09 02:13:31 UTC (rev 213617)
+++ trunk/Source/WebCore/html/HTMLImageElement.h        2017-03-09 02:16:51 UTC (rev 213618)
</span><span class="lines">@@ -105,6 +105,7 @@
</span><span class="cx">     void collectStyleForPresentationAttribute(const QualifiedName&amp;, const AtomicString&amp;, MutableStyleProperties&amp;) override;
</span><span class="cx"> 
</span><span class="cx">     void didAttachRenderers() override;
</span><ins>+    void willDetachRenderers() override;
</ins><span class="cx">     RenderPtr&lt;RenderElement&gt; createElementRenderer(RenderStyle&amp;&amp;, const RenderTreePosition&amp;) override;
</span><span class="cx">     void setBestFitURLAndDPRFromImageCandidate(const ImageCandidate&amp;);
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCorepageFrameViewcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/page/FrameView.cpp (213617 => 213618)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/page/FrameView.cpp        2017-03-09 02:13:31 UTC (rev 213617)
+++ trunk/Source/WebCore/page/FrameView.cpp        2017-03-09 02:16:51 UTC (rev 213618)
</span><span class="lines">@@ -1058,6 +1058,10 @@
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="cx">     renderView-&gt;compositor().flushPendingLayerChanges(&amp;rootFrameForFlush == m_frame.ptr());
</span><ins>+    
+    if (TiledBacking* tiledBacking = this-&gt;tiledBacking())
+        requestAsyncDecodingForImagesInAbsoluteRectIncludingSubframes(tiledBacking-&gt;tileCoverageRect());
+    
</ins><span class="cx">     return true;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -2527,7 +2531,20 @@
</span><span class="cx">     updateLayoutViewport();
</span><span class="cx">     viewportContentsChanged();
</span><span class="cx"> }
</span><ins>+    
+void FrameView::applyRecursivelyWithAbsoluteRect(const IntRect&amp; rect, const std::function&lt;void(FrameView&amp;, const IntRect&amp;)&gt;&amp; apply)
+{
+    apply(*this, rect);
</ins><span class="cx"> 
</span><ins>+    // Recursive call for subframes. We cache the current FrameView's windowClipRect to avoid recomputing it for every subframe.
+    IntRect windowClipRect = contentsToWindow(rect);
+    SetForScope&lt;IntRect*&gt; windowClipRectCache(m_cachedWindowClipRect, &amp;windowClipRect);
+    for (Frame* childFrame = frame().tree().firstChild(); childFrame; childFrame = childFrame-&gt;tree().nextSibling()) {
+        if (auto* childView = childFrame-&gt;view())
+            childView-&gt;applyRecursivelyWithAbsoluteRect(rect, apply);
+    }
+}
+
</ins><span class="cx"> void FrameView::applyRecursivelyWithVisibleRect(const std::function&lt;void (FrameView&amp; frameView, const IntRect&amp; visibleRect)&gt;&amp; apply)
</span><span class="cx"> {
</span><span class="cx">     IntRect windowClipRect = this-&gt;windowClipRect();
</span><span class="lines">@@ -2581,6 +2598,30 @@
</span><span class="cx">     });
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void FrameView::requestAsyncDecodingForImagesInAbsoluteRect(const IntRect&amp; rect)
+{
+    if (!frame().view()) {
+        // The frame is being destroyed.
+        return;
+    }
+
+    if (rect.isEmpty())
+        return;
+
+    if (auto* renderView = frame().contentRenderer())
+        renderView-&gt;requestAsyncDecodingForImagesInAbsoluteRect(rect);
+}
+
+void FrameView::requestAsyncDecodingForImagesInAbsoluteRectIncludingSubframes(const IntRect&amp; rect)
+{
+    if (!frame().settings().largeImageAsyncDecodingEnabled())
+        return;
+
+    applyRecursivelyWithAbsoluteRect(rect, [] (FrameView&amp; frameView, const IntRect&amp; rect) {
+        frameView.requestAsyncDecodingForImagesInAbsoluteRect(rect);
+    });
+}
+
</ins><span class="cx"> void FrameView::updateLayerPositionsAfterScrolling()
</span><span class="cx"> {
</span><span class="cx">     // If we're scrolling as a result of updating the view size after layout, we'll update widgets and layer positions soon anyway.
</span></span></pre></div>
<a id="trunkSourceWebCorepageFrameViewh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/page/FrameView.h (213617 => 213618)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/page/FrameView.h        2017-03-09 02:13:31 UTC (rev 213617)
+++ trunk/Source/WebCore/page/FrameView.h        2017-03-09 02:16:51 UTC (rev 213618)
</span><span class="lines">@@ -275,6 +275,7 @@
</span><span class="cx"> 
</span><span class="cx">     void viewportContentsChanged();
</span><span class="cx">     WEBCORE_EXPORT void resumeVisibleImageAnimationsIncludingSubframes();
</span><ins>+    void requestAsyncDecodingForImagesInAbsoluteRectIncludingSubframes(const IntRect&amp;);
</ins><span class="cx"> 
</span><span class="cx">     String mediaType() const;
</span><span class="cx">     WEBCORE_EXPORT void setMediaType(const String&amp;);
</span><span class="lines">@@ -645,9 +646,11 @@
</span><span class="cx">     void performPostLayoutTasks();
</span><span class="cx">     void autoSizeIfEnabled();
</span><span class="cx"> 
</span><ins>+    void applyRecursivelyWithAbsoluteRect(const IntRect&amp;, const std::function&lt;void(FrameView&amp; frameView, const IntRect&amp; rect)&gt;&amp;);
</ins><span class="cx">     void applyRecursivelyWithVisibleRect(const std::function&lt;void (FrameView&amp; frameView, const IntRect&amp; visibleRect)&gt;&amp;);
</span><span class="cx">     void resumeVisibleImageAnimations(const IntRect&amp; visibleRect);
</span><span class="cx">     void updateScriptedAnimationsAndTimersThrottlingState(const IntRect&amp; visibleRect);
</span><ins>+    void requestAsyncDecodingForImagesInAbsoluteRect(const IntRect&amp;);
</ins><span class="cx"> 
</span><span class="cx">     void updateLayerFlushThrottling();
</span><span class="cx">     WEBCORE_EXPORT void adjustTiledBackingCoverage();
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsBitmapImagecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/BitmapImage.cpp (213617 => 213618)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/BitmapImage.cpp        2017-03-09 02:13:31 UTC (rev 213617)
+++ trunk/Source/WebCore/platform/graphics/BitmapImage.cpp        2017-03-09 02:16:51 UTC (rev 213618)
</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">@@ -164,26 +164,41 @@
</span><span class="cx">     m_sizeForDrawing = enclosingIntRect(destRect).size();
</span><span class="cx">     StartAnimationResult result = internalStartAnimation();
</span><span class="cx"> 
</span><del>-    Color color;
-    if (result == StartAnimationResult::DecodingActive &amp;&amp; showDebugBackground())
-        color = Color::yellow;
-    else
-        color = singlePixelSolidColor();
-
-    if (color.isValid()) {
-        fillWithSolidColor(context, destRect, color, op);
</del><ins>+    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>+    NativeImagePtr image;
+    if (frameIsBeingDecodedAtIndex(m_currentFrame, m_sizeForDrawing)) {
+        ASSERT(!canAnimate() &amp;&amp; !m_currentFrame);
+        m_needsRepaint = true;
</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>+        if (!frameHasDecodedNativeImage(m_currentFrame)) {
+            if (showDebugBackground())
+                fillWithSolidColor(context, destRect, Color::yellow, op);
+            return;
+        }
+
+        image = frameImageAtIndex(m_currentFrame);
+    } else {
+        float scale = subsamplingScale(context, destRect, srcRect);
+        m_currentSubsamplingLevel = allowSubsampling() ? m_source.subsamplingLevelForScale(scale) : SubsamplingLevel::Default;
+        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);
+
+        ASSERT_IMPLIES(result == StartAnimationResult::DecodingActive, m_source.frameHasValidNativeImageAtIndex(m_currentFrame, m_currentSubsamplingLevel, m_sizeForDrawing));
+        image = frameImageAtIndex(m_currentFrame, m_currentSubsamplingLevel, m_sizeForDrawing, &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">@@ -267,11 +282,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">@@ -317,9 +332,9 @@
</span><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">@@ -346,7 +361,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 +370,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 +384,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 +410,42 @@
</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());
</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);
+        
+        if (m_needsRepaint) {
+            imageObserver()-&gt;changedInRect(this, nullptr);
+            m_needsRepaint = false;
+        }
+        
+        // Keep the number of decoding threads under control. 
+        if (m_source.isAsyncDecodingQueueIdle())
+            m_source.stopAsyncDecodingQueue();
+    }
+}
</ins><span class="cx"> 
</span><del>-    // 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>+void BitmapImage::requestAsyncDecoding(const IntSize&amp; sizeForDrawing)
+{
+    if (!isLargeImageAsyncDecodingRequired())
+        return;
+
+    ASSERT(!m_currentFrame);
+    bool isAsyncDecode = m_source.requestFrameAsyncDecodingAtIndex(0, m_currentSubsamplingLevel, sizeForDrawing);
+
+#if !LOG_DISABLED
+    if (isAsyncDecode)
+        LOG(Images, &quot;BitmapImage::%s - %p - url: %s&quot;, __FUNCTION__, this, sourceURL().utf8().data());
+#else
+    UNUSED_PARAM(isAsyncDecode);
+#endif
</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 (213617 => 213618)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/BitmapImage.h        2017-03-09 02:13:31 UTC (rev 213617)
+++ trunk/Source/WebCore/platform/graphics/BitmapImage.h        2017-03-09 02:16:51 UTC (rev 213618)
</span><span class="lines">@@ -173,6 +173,7 @@
</span><span class="cx">     void stopAnimation() override;
</span><span class="cx">     void resetAnimation() override;
</span><span class="cx">     void newFrameNativeImageAvailableAtIndex(size_t) override;
</span><ins>+    void requestAsyncDecoding(const IntSize&amp; sizeForDrawing) override;
</ins><span class="cx"> 
</span><span class="cx">     // Handle platform-specific data
</span><span class="cx">     void invalidatePlatformData();
</span><span class="lines">@@ -207,6 +208,7 @@
</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 class="cx">     bool m_animationFinished { false };
</span><ins>+    bool m_needsRepaint { false };
</ins><span class="cx"> 
</span><span class="cx">     float m_frameDecodingDurationForTesting { 0 };
</span><span class="cx">     double m_desiredFrameDecodeTimeForTesting { 0 };
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsImageh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/Image.h (213617 => 213618)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/Image.h        2017-03-09 02:13:31 UTC (rev 213617)
+++ trunk/Source/WebCore/platform/graphics/Image.h        2017-03-09 02:16:51 UTC (rev 213618)
</span><span class="lines">@@ -130,6 +130,7 @@
</span><span class="cx">     virtual void stopAnimation() {}
</span><span class="cx">     virtual void resetAnimation() {}
</span><span class="cx">     virtual void newFrameNativeImageAvailableAtIndex(size_t) { }
</span><ins>+    virtual void requestAsyncDecoding(const IntSize&amp;) { }
</ins><span class="cx">     
</span><span class="cx">     // Typically the CachedImage that owns us.
</span><span class="cx">     ImageObserver* imageObserver() const { return m_imageObserver; }
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsImageFrameCachecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/ImageFrameCache.cpp (213617 => 213618)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/ImageFrameCache.cpp        2017-03-09 02:13:31 UTC (rev 213617)
+++ trunk/Source/WebCore/platform/graphics/ImageFrameCache.cpp        2017-03-09 02:16:51 UTC (rev 213618)
</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 (213617 => 213618)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/ImageFrameCache.h        2017-03-09 02:13:31 UTC (rev 213617)
+++ trunk/Source/WebCore/platform/graphics/ImageFrameCache.h        2017-03-09 02:16:51 UTC (rev 213618)
</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="trunkSourceWebCoreplatformgraphicsImageSourceh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/ImageSource.h (213617 => 213618)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/ImageSource.h        2017-03-09 02:13:31 UTC (rev 213617)
+++ trunk/Source/WebCore/platform/graphics/ImageSource.h        2017-03-09 02:16:51 UTC (rev 213618)
</span><span class="lines">@@ -70,7 +70,8 @@
</span><span class="cx"> 
</span><span class="cx">     bool isAsyncDecodingRequired();
</span><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="trunkSourceWebCoreplatformgraphicsTiledBackingh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/TiledBacking.h (213617 => 213618)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/TiledBacking.h        2017-03-09 02:13:31 UTC (rev 213617)
+++ trunk/Source/WebCore/platform/graphics/TiledBacking.h        2017-03-09 02:16:51 UTC (rev 213618)
</span><span class="lines">@@ -145,11 +145,12 @@
</span><span class="cx">     virtual IntRect bounds() const = 0;
</span><span class="cx">     virtual IntRect boundsWithoutMargin() const = 0;
</span><span class="cx"> 
</span><del>-    // Exposed for testing
</del><span class="cx">     virtual IntRect tileCoverageRect() const = 0;
</span><del>-    virtual IntRect tileGridExtent() const = 0;
</del><span class="cx">     virtual void setScrollingModeIndication(ScrollingModeIndication) = 0;
</span><span class="cx"> 
</span><ins>+    // Exposed for testing
+    virtual IntRect tileGridExtent() const = 0;
+
</ins><span class="cx"> #if USE(CA)
</span><span class="cx">     virtual PlatformCALayer* tiledScrollingIndicatorLayer() = 0;
</span><span class="cx"> #endif
</span></span></pre></div>
<a id="trunkSourceWebCorerenderingRenderElementcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/rendering/RenderElement.cpp (213617 => 213618)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/rendering/RenderElement.cpp        2017-03-09 02:13:31 UTC (rev 213617)
+++ trunk/Source/WebCore/rendering/RenderElement.cpp        2017-03-09 02:16:51 UTC (rev 213618)
</span><span class="lines">@@ -154,6 +154,8 @@
</span><span class="cx">         view().removeRendererWithPausedImageAnimations(*this);
</span><span class="cx">     if (isRegisteredForVisibleInViewportCallback())
</span><span class="cx">         view().unregisterForVisibleInViewportCallback(*this);
</span><ins>+    if (isRegisteredForAsyncImageDecodingCallback())
+        view().unregisterForAsyncImageDecodingCallback(*this);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> RenderPtr&lt;RenderElement&gt; RenderElement::createFor(Element&amp; element, RenderStyle&amp;&amp; style, RendererCreationType creationType)
</span><span class="lines">@@ -1434,23 +1436,20 @@
</span><span class="cx">     return visibleRect.intersects(enclosingIntRect(absoluteClippedOverflowRect()));
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static bool shouldRepaintForImageAnimation(const RenderElement&amp; renderer, const IntRect&amp; visibleRect)
</del><ins>+bool RenderElement::intersectsAbsoluteRect(const IntRect&amp; rect) const
</ins><span class="cx"> {
</span><del>-    const Document&amp; document = renderer.document();
-    if (document.activeDOMObjectsAreSuspended())
</del><ins>+    if (style().visibility() != VISIBLE)
</ins><span class="cx">         return false;
</span><del>-    if (renderer.style().visibility() != VISIBLE)
</del><ins>+    if (view().frameView().isOffscreen())
</ins><span class="cx">         return false;
</span><del>-    if (renderer.view().frameView().isOffscreen())
-        return false;
</del><span class="cx"> 
</span><span class="cx">     // Use background rect if we are the root or if we are the body and the background is propagated to the root.
</span><span class="cx">     // FIXME: This is overly conservative as the image may not be a background-image, in which case it will not
</span><span class="cx">     // be propagated to the root. At this point, we unfortunately don't have access to the image anymore so we
</span><span class="cx">     // can no longer check if it is a background image.
</span><del>-    bool backgroundIsPaintedByRoot = renderer.isDocumentElementRenderer();
-    if (renderer.isBody()) {
-        auto&amp; rootRenderer = *renderer.parent(); // If &lt;body&gt; has a renderer then &lt;html&gt; does too.
</del><ins>+    bool backgroundIsPaintedByRoot = isDocumentElementRenderer();
+    if (isBody()) {
+        auto&amp; rootRenderer = *parent(); // If &lt;body&gt; has a renderer then &lt;html&gt; does too.
</ins><span class="cx">         ASSERT(rootRenderer.isDocumentElementRenderer());
</span><span class="cx">         ASSERT(is&lt;HTMLHtmlElement&gt;(rootRenderer.element()));
</span><span class="cx">         // FIXME: Should share body background propagation code.
</span><span class="lines">@@ -1457,11 +1456,8 @@
</span><span class="cx">         backgroundIsPaintedByRoot = !rootRenderer.hasBackground();
</span><span class="cx"> 
</span><span class="cx">     }
</span><del>-    LayoutRect backgroundPaintingRect = backgroundIsPaintedByRoot ? renderer.view().backgroundRect() : renderer.absoluteClippedOverflowRect();
-    if (!visibleRect.intersects(enclosingIntRect(backgroundPaintingRect)))
-        return false;
-
-    return true;
</del><ins>+    LayoutRect backgroundPaintingRect = backgroundIsPaintedByRoot ? view().backgroundRect() : absoluteClippedOverflowRect();
+    return rect.intersects(enclosingIntRect(backgroundPaintingRect));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void RenderElement::registerForVisibleInViewportCallback()
</span><span class="lines">@@ -1496,7 +1492,7 @@
</span><span class="cx"> {
</span><span class="cx">     auto&amp; frameView = view().frameView();
</span><span class="cx">     auto visibleRect = frameView.windowToContents(frameView.windowClipRect());
</span><del>-    if (!shouldRepaintForImageAnimation(*this, visibleRect)) {
</del><ins>+    if (document().activeDOMObjectsAreSuspended() || !intersectsAbsoluteRect(visibleRect)) {
</ins><span class="cx">         // FIXME: It would be better to pass the image along with the renderer
</span><span class="cx">         // so that we can be smarter about detecting if the image is inside the
</span><span class="cx">         // viewport in repaintForPausedImageAnimationsIfNeeded().
</span><span class="lines">@@ -1509,7 +1505,7 @@
</span><span class="cx"> bool RenderElement::repaintForPausedImageAnimationsIfNeeded(const IntRect&amp; visibleRect)
</span><span class="cx"> {
</span><span class="cx">     ASSERT(m_hasPausedImageAnimations);
</span><del>-    if (!shouldRepaintForImageAnimation(*this, visibleRect))
</del><ins>+    if (document().activeDOMObjectsAreSuspended() || !intersectsAbsoluteRect(visibleRect))
</ins><span class="cx">         return false;
</span><span class="cx"> 
</span><span class="cx">     repaint();
</span><span class="lines">@@ -1520,7 +1516,25 @@
</span><span class="cx"> 
</span><span class="cx">     return true;
</span><span class="cx"> }
</span><ins>+    
+void RenderElement::registerForAsyncImageDecodingCallback()
+{
+    if (isRegisteredForAsyncImageDecodingCallback())
+        return;
</ins><span class="cx"> 
</span><ins>+    view().registerForAsyncImageDecodingCallback(*this);
+    setIsRegisteredForAsyncImageDecodingCallback(true);
+}
+    
+void RenderElement::unregisterForAsyncImageDecodingCallback()
+{
+    if (!isRegisteredForAsyncImageDecodingCallback())
+        return;
+
+    view().unregisterForAsyncImageDecodingCallback(*this);
+    setIsRegisteredForAsyncImageDecodingCallback(false);
+}
+
</ins><span class="cx"> const RenderStyle* RenderElement::getCachedPseudoStyle(PseudoId pseudo, const RenderStyle* parentStyle) const
</span><span class="cx"> {
</span><span class="cx">     if (pseudo &lt; FIRST_INTERNAL_PSEUDOID &amp;&amp; !style().hasPseudoStyle(pseudo))
</span></span></pre></div>
<a id="trunkSourceWebCorerenderingRenderElementh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/rendering/RenderElement.h (213617 => 213618)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/rendering/RenderElement.h        2017-03-09 02:13:31 UTC (rev 213617)
+++ trunk/Source/WebCore/rendering/RenderElement.h        2017-03-09 02:16:51 UTC (rev 213618)
</span><span class="lines">@@ -138,6 +138,7 @@
</span><span class="cx"> 
</span><span class="cx">     bool borderImageIsLoadedAndCanBeRendered() const;
</span><span class="cx">     bool mayCauseRepaintInsideViewport(const IntRect* visibleRect = nullptr) const;
</span><ins>+    bool intersectsAbsoluteRect(const IntRect&amp;) const;
</ins><span class="cx"> 
</span><span class="cx">     // Returns true if this renderer requires a new stacking context.
</span><span class="cx">     bool createsGroup() const { return isTransparent() || hasMask() || hasClipPath() || hasFilter() || hasBackdropFilter() || hasBlendMode(); }
</span><span class="lines">@@ -190,6 +191,9 @@
</span><span class="cx">     bool repaintForPausedImageAnimationsIfNeeded(const IntRect&amp; visibleRect);
</span><span class="cx">     bool hasPausedImageAnimations() const { return m_hasPausedImageAnimations; }
</span><span class="cx">     void setHasPausedImageAnimations(bool b) { m_hasPausedImageAnimations = b; }
</span><ins>+    
+    void registerForAsyncImageDecodingCallback();
+    void unregisterForAsyncImageDecodingCallback();
</ins><span class="cx"> 
</span><span class="cx">     void setRenderBoxNeedsLazyRepaint(bool b) { m_renderBoxNeedsLazyRepaint = b; }
</span><span class="cx">     bool renderBoxNeedsLazyRepaint() const { return m_renderBoxNeedsLazyRepaint; }
</span></span></pre></div>
<a id="trunkSourceWebCorerenderingRenderObjectcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/rendering/RenderObject.cpp (213617 => 213618)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/rendering/RenderObject.cpp        2017-03-09 02:13:31 UTC (rev 213617)
+++ trunk/Source/WebCore/rendering/RenderObject.cpp        2017-03-09 02:16:51 UTC (rev 213618)
</span><span class="lines">@@ -1995,6 +1995,12 @@
</span><span class="cx">     if (visible != VisibilityUnknown || hasRareData())
</span><span class="cx">         ensureRareData().setVisibleInViewportState(visible);
</span><span class="cx"> }
</span><ins>+    
+void RenderObject::setIsRegisteredForAsyncImageDecodingCallback(bool registered)
+{
+    if (registered || hasRareData())
+        ensureRareData().setIsRegisteredForAsyncImageDecodingCallback(registered);
+}
</ins><span class="cx"> 
</span><span class="cx"> RenderObject::RareDataMap&amp; RenderObject::rareDataMap()
</span><span class="cx"> {
</span></span></pre></div>
<a id="trunkSourceWebCorerenderingRenderObjecth"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/rendering/RenderObject.h (213617 => 213618)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/rendering/RenderObject.h        2017-03-09 02:13:31 UTC (rev 213617)
+++ trunk/Source/WebCore/rendering/RenderObject.h        2017-03-09 02:16:51 UTC (rev 213618)
</span><span class="lines">@@ -458,6 +458,8 @@
</span><span class="cx">         NotVisibleInViewport,
</span><span class="cx">     };
</span><span class="cx">     VisibleInViewportState visibleInViewportState() { return m_bitfields.hasRareData() ? rareData().visibleInViewportState() : VisibilityUnknown; }
</span><ins>+    
+    bool isRegisteredForAsyncImageDecodingCallback() { return m_bitfields.hasRareData() &amp;&amp; rareData().isRegisteredForAsyncImageDecodingCallback(); }
</ins><span class="cx"> 
</span><span class="cx">     bool hasLayer() const { return m_bitfields.hasLayer(); }
</span><span class="cx"> 
</span><span class="lines">@@ -569,6 +571,7 @@
</span><span class="cx">     void setHasOutlineAutoAncestor(bool = true);
</span><span class="cx">     void setIsRegisteredForVisibleInViewportCallback(bool);
</span><span class="cx">     void setVisibleInViewportState(VisibleInViewportState);
</span><ins>+    void setIsRegisteredForAsyncImageDecodingCallback(bool);
</ins><span class="cx"> 
</span><span class="cx">     // Hook so that RenderTextControl can return the line height of its inner renderer.
</span><span class="cx">     // For other renderers, the value is the same as lineHeight(false).
</span><span class="lines">@@ -985,6 +988,7 @@
</span><span class="cx">             , m_hasOutlineAutoAncestor(false)
</span><span class="cx">             , m_isRegisteredForVisibleInViewportCallback(false)
</span><span class="cx">             , m_visibleInViewportState(VisibilityUnknown)
</span><ins>+            , m_isRegisteredForAsyncImageDecodingCallback(false)
</ins><span class="cx">         {
</span><span class="cx">         }
</span><span class="cx">         ADD_BOOLEAN_BITFIELD(isDragging, IsDragging);
</span><span class="lines">@@ -995,6 +999,7 @@
</span><span class="cx">         // From RenderElement
</span><span class="cx">         ADD_BOOLEAN_BITFIELD(isRegisteredForVisibleInViewportCallback, IsRegisteredForVisibleInViewportCallback);
</span><span class="cx">         ADD_ENUM_BITFIELD(visibleInViewportState, VisibleInViewportState, VisibleInViewportState, 2);
</span><ins>+        ADD_BOOLEAN_BITFIELD(isRegisteredForAsyncImageDecodingCallback, IsRegisteredForAsyncImageDecodingCallback);
</ins><span class="cx">         std::unique_ptr&lt;RenderStyle&gt; cachedFirstLineStyle;
</span><span class="cx">     };
</span><span class="cx">     
</span></span></pre></div>
<a id="trunkSourceWebCorerenderingRenderReplacedh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/rendering/RenderReplaced.h (213617 => 213618)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/rendering/RenderReplaced.h        2017-03-09 02:13:31 UTC (rev 213617)
+++ trunk/Source/WebCore/rendering/RenderReplaced.h        2017-03-09 02:16:51 UTC (rev 213618)
</span><span class="lines">@@ -32,6 +32,7 @@
</span><span class="cx">     LayoutUnit computeReplacedLogicalWidth(ShouldComputePreferred = ComputeActual) const override;
</span><span class="cx">     LayoutUnit computeReplacedLogicalHeight() const override;
</span><span class="cx"> 
</span><ins>+    LayoutSize intrinsicSize() const final { return m_intrinsicSize; }
</ins><span class="cx">     LayoutRect replacedContentRect(const LayoutSize&amp; intrinsicSize) const;
</span><span class="cx"> 
</span><span class="cx">     bool hasReplacedLogicalWidth() const;
</span><span class="lines">@@ -45,7 +46,6 @@
</span><span class="cx"> 
</span><span class="cx">     void layout() override;
</span><span class="cx"> 
</span><del>-    LayoutSize intrinsicSize() const final { return m_intrinsicSize; }
</del><span class="cx">     void computeIntrinsicRatioInformation(FloatSize&amp; intrinsicSize, double&amp; intrinsicRatio) const override;
</span><span class="cx"> 
</span><span class="cx">     void computeIntrinsicLogicalWidths(LayoutUnit&amp; minLogicalWidth, LayoutUnit&amp; maxLogicalWidth) const final;
</span></span></pre></div>
<a id="trunkSourceWebCorerenderingRenderViewcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/rendering/RenderView.cpp (213617 => 213618)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/rendering/RenderView.cpp        2017-03-09 02:13:31 UTC (rev 213617)
+++ trunk/Source/WebCore/rendering/RenderView.cpp        2017-03-09 02:16:51 UTC (rev 213618)
</span><span class="lines">@@ -35,10 +35,13 @@
</span><span class="cx"> #include &quot;HTMLHtmlElement.h&quot;
</span><span class="cx"> #include &quot;HTMLIFrameElement.h&quot;
</span><span class="cx"> #include &quot;HitTestResult.h&quot;
</span><ins>+#include &quot;Image.h&quot;
</ins><span class="cx"> #include &quot;ImageQualityController.h&quot;
</span><span class="cx"> #include &quot;NodeTraversal.h&quot;
</span><span class="cx"> #include &quot;Page.h&quot;
</span><ins>+#include &quot;RenderDescendantIterator.h&quot;
</ins><span class="cx"> #include &quot;RenderGeometryMap.h&quot;
</span><ins>+#include &quot;RenderImage.h&quot;
</ins><span class="cx"> #include &quot;RenderIterator.h&quot;
</span><span class="cx"> #include &quot;RenderLayer.h&quot;
</span><span class="cx"> #include &quot;RenderLayerBacking.h&quot;
</span><span class="lines">@@ -1421,6 +1424,40 @@
</span><span class="cx">         removeRendererWithPausedImageAnimations(*renderer);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void RenderView::registerForAsyncImageDecodingCallback(RenderElement&amp; renderer)
+{
+    ASSERT(!m_asyncDecodingImageRenderers.contains(&amp;renderer));
+    m_asyncDecodingImageRenderers.add(&amp;renderer);
+}
+
+void RenderView::unregisterForAsyncImageDecodingCallback(RenderElement&amp; renderer)
+{
+    ASSERT(m_asyncDecodingImageRenderers.contains(&amp;renderer));
+    m_asyncDecodingImageRenderers.remove(&amp;renderer);
+}
+    
+void RenderView::requestAsyncDecodingForImagesInAbsoluteRect(const IntRect&amp; rect)
+{
+    for (auto* renderer : m_asyncDecodingImageRenderers) {
+        if (!renderer-&gt;intersectsAbsoluteRect(rect))
+            continue;
+        
+        auto&amp; renderImage = downcast&lt;RenderImage&gt;(*renderer);
+        
+        CachedImage* image = renderImage.cachedImage();
+        if (!image || !image-&gt;hasImage())
+            continue;
+
+        // Get the destination rectangle of the image scaled by the all the scaling factors
+        // that will eventually be applied to the graphics context.
+        LayoutRect replacedContentRect = renderImage.replacedContentRect(renderImage.intrinsicSize());
+        FloatRect rect = snapRectToDevicePixels(replacedContentRect, document().deviceScaleFactor());
+        rect.scale(frame().page()-&gt;pageScaleFactor() * frame().pageZoomFactor() * document().deviceScaleFactor());
+
+        image-&gt;image()-&gt;requestAsyncDecoding(expandedIntSize(rect.size()));
+    }
+}
+
</ins><span class="cx"> RenderView::RepaintRegionAccumulator::RepaintRegionAccumulator(RenderView* view)
</span><span class="cx">     : m_rootView(view ? view-&gt;document().topDocument().renderView() : nullptr)
</span><span class="cx"> {
</span></span></pre></div>
<a id="trunkSourceWebCorerenderingRenderViewh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/rendering/RenderView.h (213617 => 213618)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/rendering/RenderView.h        2017-03-09 02:13:31 UTC (rev 213617)
+++ trunk/Source/WebCore/rendering/RenderView.h        2017-03-09 02:16:51 UTC (rev 213618)
</span><span class="lines">@@ -231,6 +231,9 @@
</span><span class="cx">     void resumePausedImageAnimationsIfNeeded(IntRect visibleRect);
</span><span class="cx">     void addRendererWithPausedImageAnimations(RenderElement&amp;);
</span><span class="cx">     void removeRendererWithPausedImageAnimations(RenderElement&amp;);
</span><ins>+    void registerForAsyncImageDecodingCallback(RenderElement&amp;);
+    void unregisterForAsyncImageDecodingCallback(RenderElement&amp;);
+    void requestAsyncDecodingForImagesInAbsoluteRect(const IntRect&amp;);
</ins><span class="cx"> 
</span><span class="cx">     class RepaintRegionAccumulator {
</span><span class="cx">         WTF_MAKE_NONCOPYABLE(RepaintRegionAccumulator);
</span><span class="lines">@@ -388,6 +391,7 @@
</span><span class="cx"> 
</span><span class="cx">     HashSet&lt;RenderElement*&gt; m_renderersWithPausedImageAnimation;
</span><span class="cx">     HashSet&lt;RenderElement*&gt; m_visibleInViewportRenderers;
</span><ins>+    HashSet&lt;RenderElement*&gt; m_asyncDecodingImageRenderers;
</ins><span class="cx">     Vector&lt;RefPtr&lt;RenderWidget&gt;&gt; m_protectedRenderWidgets;
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(SERVICE_CONTROLS)
</span></span></pre></div>
<a id="trunkSourceWebKit2ChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/ChangeLog (213617 => 213618)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/ChangeLog        2017-03-09 02:13:31 UTC (rev 213617)
+++ trunk/Source/WebKit2/ChangeLog        2017-03-09 02:16:51 UTC (rev 213618)
</span><span class="lines">@@ -1,3 +1,20 @@
</span><ins>+2017-03-08  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-08  Wenson Hsieh  &lt;wenson_hsieh@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Add TextIndicator support for providing a snapshot excluding selected content
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessAPICWKPreferencescpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/API/C/WKPreferences.cpp (213617 => 213618)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/API/C/WKPreferences.cpp        2017-03-09 02:13:31 UTC (rev 213617)
+++ trunk/Source/WebKit2/UIProcess/API/C/WKPreferences.cpp        2017-03-09 02:16:51 UTC (rev 213618)
</span><span class="lines">@@ -1681,6 +1681,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 (213617 => 213618)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/API/C/WKPreferencesRefPrivate.h        2017-03-09 02:13:31 UTC (rev 213617)
+++ trunk/Source/WebKit2/UIProcess/API/C/WKPreferencesRefPrivate.h        2017-03-09 02:16:51 UTC (rev 213618)
</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 (213617 => 213618)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/ChangeLog        2017-03-09 02:13:31 UTC (rev 213617)
+++ trunk/Tools/ChangeLog        2017-03-09 02:16:51 UTC (rev 213618)
</span><span class="lines">@@ -1,3 +1,17 @@
</span><ins>+2017-03-08  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-08  Matt Rajca  &lt;mrajca@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Add support for updating autoplay policies after a page has been loaded.
</span></span></pre></div>
<a id="trunkToolsDumpRenderTreemacDumpRenderTreemm"></a>
<div class="modfile"><h4>Modified: trunk/Tools/DumpRenderTree/mac/DumpRenderTree.mm (213617 => 213618)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/DumpRenderTree/mac/DumpRenderTree.mm        2017-03-09 02:13:31 UTC (rev 213617)
+++ trunk/Tools/DumpRenderTree/mac/DumpRenderTree.mm        2017-03-09 02:16:51 UTC (rev 213618)
</span><span class="lines">@@ -955,6 +955,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 (213617 => 213618)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/WebKitTestRunner/TestController.cpp        2017-03-09 02:13:31 UTC (rev 213617)
+++ trunk/Tools/WebKitTestRunner/TestController.cpp        2017-03-09 02:16:51 UTC (rev 213618)
</span><span class="lines">@@ -718,6 +718,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>