<!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>[208365] trunk/Source/WebCore</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/208365">208365</a></dd>
<dt>Author</dt> <dd>commit-queue@webkit.org</dd>
<dt>Date</dt> <dd>2016-11-03 19:57:49 -0700 (Thu, 03 Nov 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>Add the asynchronous image decoding mode
https://bugs.webkit.org/show_bug.cgi?id=155546

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

The asynchronous image decoding feature targets enhancing the rendering
in two scenarios: the animated images and scrolling a page which large
images. Enabling this feature for these two scenarios will be landed
separately.

The goal of the asynchronous image decoding is to have the decoded image
frame ready before it has to be drawn. Drawing an image does not have to
wait the image frame to be decoded.

* platform/graphics/BitmapImage.cpp:
(WebCore::BitmapImage::frameImageAtIndex): Use the negation of frameHasValidNativeImageAtIndex().
* platform/graphics/BitmapImage.h:
(WebCore::BitmapImage::frameIsBeingDecodedAtIndex): Answers whether a frame is being decoded.
(WebCore::BitmapImage::frameHasValidNativeImageAtIndex): Checks the validity of a frame.
(WebCore::BitmapImage::frameHasInvalidNativeImageAtIndex): Deleted.
* platform/graphics/Image.h:
(WebCore::Image::newFrameNativeImageAvailableAtIndex): Notifies the image with the availability of a frame NativeImage.
* platform/graphics/ImageFrame.h:
(WebCore::ImageFrame::isBeingDecoded): Answers whether the frame is being decoded.
(WebCore::ImageFrame::hasValidNativeImage): Checks the validity of the frame.
(WebCore::ImageFrame::hasInvalidNativeImage): Deleted.
* platform/graphics/ImageFrameCache.cpp:
(WebCore::ImageFrameCache::~ImageFrameCache): Asserts the decoding loop was ended before deleting the ImageFrameCache.
(WebCore::ImageFrameCache::setFrameNativeImageAtIndex): Rename this function to matches the other which take the frame index.
(WebCore::ImageFrameCache::setFrameMetadataAtIndex): Ditto.
(WebCore::ImageFrameCache::replaceFrameNativeImageAtIndex): It setts the ImageFrame's members and updates the decoded size.
(WebCore::ImageFrameCache::cacheFrameNativeImageAtIndex): Replaces the frame NativeImage and notifies the Image with the new frame.
(WebCore::ImageFrameCache::decodingQueue): Ensures the decoding WorkQueue is created and returns it.
(WebCore::ImageFrameCache::startAsyncDecodingQueue): Starts a decoding WorkQueue which loops until m_frameRequestQueue is closed.
(WebCore::ImageFrameCache::requestFrameAsyncDecodingAtIndex): Allows ImageSource to send a request to start asynchronous frame image decoding.
(WebCore::ImageFrameCache::stopAsyncDecodingQueue): Stops the decoding WorkQueue by closing m_frameRequestQueue.
(WebCore::ImageFrameCache::frameAtIndex): Call replaceFrameNativeImageAtIndex().
(WebCore::ImageFrameCache::frameIsBeingDecodedAtIndex): Returns true if a request for the image frame is issued but not finished yet.
(WebCore::ImageFrameCache::frameHasValidNativeImageAtIndex): Checks the validity of a frame.
(WebCore::ImageFrameCache::setFrameNativeImage): Deleted. Was renamed to be setFrameNativeImageAtIndex.
(WebCore::ImageFrameCache::setFrameMetadata): Deleted. Was renamed to be setFrameMetadataAtIndex
(WebCore::ImageFrameCache::frameHasInvalidNativeImageAtIndex): Deleted. Was renamed to be frameHasValidNativeImageAtIndex.
* platform/graphics/ImageFrameCache.h:
(WebCore::ImageFrameCache::create): The decoding queue needs to hold a reference to this class so it can stop decoding safely without blocking.
(WebCore::ImageFrameCache::hasDecodingQueue): Returns true if a decoding queue has started.
* platform/graphics/ImageSource.cpp:
(WebCore::ImageSource::ImageSource): Call ImageFrameCache::create().
(WebCore::ImageSource::clear): Deleting the decoder is unnecessary for asynchronous decoding because ImageFrameCache manages all the memory.

(WebCore::ImageSource::destroyDecodedData):
(WebCore::ImageSource::destroyDecodedDataIfNecessary):
(WebCore::ImageSource::ensureDecoderAvailable):
(WebCore::ImageSource::dataChanged):
(WebCore::ImageSource::isAllDataReceived):
(WebCore::ImageSource::isAsyncDecodingRequired): Answers the question whether the async image decoding is required for this ImageSource.
(WebCore::ImageSource::frameImageAtIndex):
* platform/graphics/ImageSource.h:
(WebCore::ImageSource::decodedSize):
(WebCore::ImageSource::requestFrameAsyncDecodingAtIndex):
(WebCore::ImageSource::stopAsyncDecodingQueue):
(WebCore::ImageSource::isSizeAvailable):
(WebCore::ImageSource::frameCount):
(WebCore::ImageSource::repetitionCount):
(WebCore::ImageSource::filenameExtension):
(WebCore::ImageSource::hotSpot):
(WebCore::ImageSource::size):
(WebCore::ImageSource::sizeRespectingOrientation):
(WebCore::ImageSource::singlePixelSolidColor):
(WebCore::ImageSource::frameIsBeingDecodedAtIndex):
(WebCore::ImageSource::frameIsCompleteAtIndex):
(WebCore::ImageSource::frameHasAlphaAtIndex):
(WebCore::ImageSource::frameHasImageAtIndex):
(WebCore::ImageSource::frameSubsamplingLevelAtIndex):
(WebCore::ImageSource::frameSizeAtIndex):
(WebCore::ImageSource::frameBytesAtIndex):
(WebCore::ImageSource::frameDurationAtIndex):
(WebCore::ImageSource::frameOrientationAtIndex):
 Make m_frameCache a type Ref&lt;ImageFrameCache&gt;. Use '-&gt;' instead of '.' when accessing its members.

(WebCore::ImageSource::frameHasValidNativeImageAtIndex): Checks the validity of a frame.
(WebCore::ImageSource::frameHasInvalidNativeImageAtIndex): Deleted. Was renamed to be frameHasValidNativeImageAtIndex.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</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="#trunkSourceWebCoreplatformgraphicsImageFrameh">trunk/Source/WebCore/platform/graphics/ImageFrame.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>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (208364 => 208365)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2016-11-04 02:37:45 UTC (rev 208364)
+++ trunk/Source/WebCore/ChangeLog        2016-11-04 02:57:49 UTC (rev 208365)
</span><span class="lines">@@ -1,3 +1,87 @@
</span><ins>+2016-11-03  Said Abou-Hallawa  &lt;sabouhallawa@apple.com&gt;
+
+        Add the asynchronous image decoding mode
+        https://bugs.webkit.org/show_bug.cgi?id=155546
+
+        Reviewed by Simon Fraser.
+
+        The asynchronous image decoding feature targets enhancing the rendering
+        in two scenarios: the animated images and scrolling a page which large
+        images. Enabling this feature for these two scenarios will be landed
+        separately. 
+
+        The goal of the asynchronous image decoding is to have the decoded image
+        frame ready before it has to be drawn. Drawing an image does not have to
+        wait the image frame to be decoded.
+
+        * platform/graphics/BitmapImage.cpp:
+        (WebCore::BitmapImage::frameImageAtIndex): Use the negation of frameHasValidNativeImageAtIndex().
+        * platform/graphics/BitmapImage.h:
+        (WebCore::BitmapImage::frameIsBeingDecodedAtIndex): Answers whether a frame is being decoded.
+        (WebCore::BitmapImage::frameHasValidNativeImageAtIndex): Checks the validity of a frame.
+        (WebCore::BitmapImage::frameHasInvalidNativeImageAtIndex): Deleted.
+        * platform/graphics/Image.h:
+        (WebCore::Image::newFrameNativeImageAvailableAtIndex): Notifies the image with the availability of a frame NativeImage.
+        * platform/graphics/ImageFrame.h:
+        (WebCore::ImageFrame::isBeingDecoded): Answers whether the frame is being decoded.
+        (WebCore::ImageFrame::hasValidNativeImage): Checks the validity of the frame.
+        (WebCore::ImageFrame::hasInvalidNativeImage): Deleted.
+        * platform/graphics/ImageFrameCache.cpp:
+        (WebCore::ImageFrameCache::~ImageFrameCache): Asserts the decoding loop was ended before deleting the ImageFrameCache.
+        (WebCore::ImageFrameCache::setFrameNativeImageAtIndex): Rename this function to matches the other which take the frame index.
+        (WebCore::ImageFrameCache::setFrameMetadataAtIndex): Ditto.
+        (WebCore::ImageFrameCache::replaceFrameNativeImageAtIndex): It setts the ImageFrame's members and updates the decoded size.
+        (WebCore::ImageFrameCache::cacheFrameNativeImageAtIndex): Replaces the frame NativeImage and notifies the Image with the new frame.
+        (WebCore::ImageFrameCache::decodingQueue): Ensures the decoding WorkQueue is created and returns it.
+        (WebCore::ImageFrameCache::startAsyncDecodingQueue): Starts a decoding WorkQueue which loops until m_frameRequestQueue is closed.
+        (WebCore::ImageFrameCache::requestFrameAsyncDecodingAtIndex): Allows ImageSource to send a request to start asynchronous frame image decoding.
+        (WebCore::ImageFrameCache::stopAsyncDecodingQueue): Stops the decoding WorkQueue by closing m_frameRequestQueue.
+        (WebCore::ImageFrameCache::frameAtIndex): Call replaceFrameNativeImageAtIndex().
+        (WebCore::ImageFrameCache::frameIsBeingDecodedAtIndex): Returns true if a request for the image frame is issued but not finished yet.
+        (WebCore::ImageFrameCache::frameHasValidNativeImageAtIndex): Checks the validity of a frame.
+        (WebCore::ImageFrameCache::setFrameNativeImage): Deleted. Was renamed to be setFrameNativeImageAtIndex.
+        (WebCore::ImageFrameCache::setFrameMetadata): Deleted. Was renamed to be setFrameMetadataAtIndex
+        (WebCore::ImageFrameCache::frameHasInvalidNativeImageAtIndex): Deleted. Was renamed to be frameHasValidNativeImageAtIndex.
+        * platform/graphics/ImageFrameCache.h:
+        (WebCore::ImageFrameCache::create): The decoding queue needs to hold a reference to this class so it can stop decoding safely without blocking.
+        (WebCore::ImageFrameCache::hasDecodingQueue): Returns true if a decoding queue has started.
+        * platform/graphics/ImageSource.cpp:
+        (WebCore::ImageSource::ImageSource): Call ImageFrameCache::create().
+        (WebCore::ImageSource::clear): Deleting the decoder is unnecessary for asynchronous decoding because ImageFrameCache manages all the memory.
+        
+        (WebCore::ImageSource::destroyDecodedData):
+        (WebCore::ImageSource::destroyDecodedDataIfNecessary):
+        (WebCore::ImageSource::ensureDecoderAvailable):
+        (WebCore::ImageSource::dataChanged):
+        (WebCore::ImageSource::isAllDataReceived):
+        (WebCore::ImageSource::isAsyncDecodingRequired): Answers the question whether the async image decoding is required for this ImageSource.
+        (WebCore::ImageSource::frameImageAtIndex):
+        * platform/graphics/ImageSource.h:
+        (WebCore::ImageSource::decodedSize):
+        (WebCore::ImageSource::requestFrameAsyncDecodingAtIndex):
+        (WebCore::ImageSource::stopAsyncDecodingQueue):
+        (WebCore::ImageSource::isSizeAvailable):
+        (WebCore::ImageSource::frameCount):
+        (WebCore::ImageSource::repetitionCount):
+        (WebCore::ImageSource::filenameExtension):
+        (WebCore::ImageSource::hotSpot):
+        (WebCore::ImageSource::size):
+        (WebCore::ImageSource::sizeRespectingOrientation):
+        (WebCore::ImageSource::singlePixelSolidColor):
+        (WebCore::ImageSource::frameIsBeingDecodedAtIndex):
+        (WebCore::ImageSource::frameIsCompleteAtIndex):
+        (WebCore::ImageSource::frameHasAlphaAtIndex):
+        (WebCore::ImageSource::frameHasImageAtIndex):
+        (WebCore::ImageSource::frameSubsamplingLevelAtIndex):
+        (WebCore::ImageSource::frameSizeAtIndex):
+        (WebCore::ImageSource::frameBytesAtIndex):
+        (WebCore::ImageSource::frameDurationAtIndex):
+        (WebCore::ImageSource::frameOrientationAtIndex):
+         Make m_frameCache a type Ref&lt;ImageFrameCache&gt;. Use '-&gt;' instead of '.' when accessing its members.
+
+        (WebCore::ImageSource::frameHasValidNativeImageAtIndex): Checks the validity of a frame.
+        (WebCore::ImageSource::frameHasInvalidNativeImageAtIndex): Deleted. Was renamed to be frameHasValidNativeImageAtIndex.
+
</ins><span class="cx"> 2016-11-03  Myles C. Maxfield  &lt;mmaxfield@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [WebGL2] Implement getBufferSubData()
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsBitmapImagecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/BitmapImage.cpp (208364 => 208365)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/BitmapImage.cpp        2016-11-04 02:37:45 UTC (rev 208364)
+++ trunk/Source/WebCore/platform/graphics/BitmapImage.cpp        2016-11-04 02:57:49 UTC (rev 208365)
</span><span class="lines">@@ -82,7 +82,7 @@
</span><span class="cx"> 
</span><span class="cx"> NativeImagePtr BitmapImage::frameImageAtIndex(size_t index, SubsamplingLevel subsamplingLevel, const GraphicsContext* targetContext)
</span><span class="cx"> {
</span><del>-    if (frameHasInvalidNativeImageAtIndex(index, subsamplingLevel)) {
</del><ins>+    if (!frameHasValidNativeImageAtIndex(index, subsamplingLevel)) {
</ins><span class="cx">         LOG(Images, &quot;BitmapImage %p frameImageAtIndex - subsamplingLevel was %d, resampling&quot;, this, static_cast&lt;int&gt;(frameSubsamplingLevelAtIndex(index)));
</span><span class="cx">         invalidatePlatformData();
</span><span class="cx">     }
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsBitmapImageh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/BitmapImage.h (208364 => 208365)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/BitmapImage.h        2016-11-04 02:37:45 UTC (rev 208364)
+++ trunk/Source/WebCore/platform/graphics/BitmapImage.h        2016-11-04 02:57:49 UTC (rev 208365)
</span><span class="lines">@@ -82,9 +82,10 @@
</span><span class="cx"> 
</span><span class="cx">     void setAllowSubsampling(bool allowSubsampling) { m_source.setAllowSubsampling(allowSubsampling); }
</span><span class="cx"> 
</span><ins>+    bool frameIsBeingDecodedAtIndex(size_t index) const { return m_source.frameIsBeingDecodedAtIndex(index); }
</ins><span class="cx">     bool frameIsCompleteAtIndex(size_t index) const { return m_source.frameIsCompleteAtIndex(index); }
</span><span class="cx">     bool frameHasAlphaAtIndex(size_t index) const { return m_source.frameHasAlphaAtIndex(index); }
</span><del>-    bool frameHasInvalidNativeImageAtIndex(size_t index, SubsamplingLevel subsamplingLevel) const { return m_source.frameHasInvalidNativeImageAtIndex(index, subsamplingLevel); }
</del><ins>+    bool frameHasValidNativeImageAtIndex(size_t index, SubsamplingLevel subsamplingLevel) const { return m_source.frameHasValidNativeImageAtIndex(index, subsamplingLevel); }
</ins><span class="cx">     SubsamplingLevel frameSubsamplingLevelAtIndex(size_t index) const { return m_source.frameSubsamplingLevelAtIndex(index); }
</span><span class="cx"> 
</span><span class="cx">     float frameDurationAtIndex(size_t index) const { return m_source.frameDurationAtIndex(index); }
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsImageh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/Image.h (208364 => 208365)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/Image.h        2016-11-04 02:37:45 UTC (rev 208364)
+++ trunk/Source/WebCore/platform/graphics/Image.h        2016-11-04 02:57:49 UTC (rev 208365)
</span><span class="lines">@@ -129,6 +129,7 @@
</span><span class="cx">     virtual void startAnimation() { }
</span><span class="cx">     virtual void stopAnimation() {}
</span><span class="cx">     virtual void resetAnimation() {}
</span><ins>+    virtual void newFrameNativeImageAvailableAtIndex(size_t) { }
</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="trunkSourceWebCoreplatformgraphicsImageFrameh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/ImageFrame.h (208364 => 208365)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/ImageFrame.h        2016-11-04 02:37:45 UTC (rev 208364)
+++ trunk/Source/WebCore/platform/graphics/ImageFrame.h        2016-11-04 02:57:49 UTC (rev 208365)
</span><span class="lines">@@ -82,7 +82,7 @@
</span><span class="cx">     friend class ImageFrameCache;
</span><span class="cx"> public:
</span><span class="cx">     enum class Caching { Empty, Metadata, MetadataAndImage };
</span><del>-    enum class Decoding { Empty, Partial, Complete };
</del><ins>+    enum class Decoding { Empty, BeingDecoded, Partial, Complete };
</ins><span class="cx"> 
</span><span class="cx">     ImageFrame();
</span><span class="cx">     ImageFrame(const ImageFrame&amp; other) { operator=(other); }
</span><span class="lines">@@ -104,6 +104,7 @@
</span><span class="cx">     void setDecoding(Decoding decoding) { m_decoding = decoding; }
</span><span class="cx">     Decoding decoding() const { return m_decoding; }
</span><span class="cx">     bool isEmpty() const { return m_decoding == Decoding::Empty; }
</span><ins>+    bool isBeingDecoded() const { return m_decoding == Decoding::BeingDecoded; }
</ins><span class="cx">     bool isPartial() const { return m_decoding == Decoding::Partial; }
</span><span class="cx">     bool isComplete() const { return m_decoding == Decoding::Complete; }
</span><span class="cx"> 
</span><span class="lines">@@ -130,7 +131,7 @@
</span><span class="cx">     bool hasAlpha() const { return !hasMetadata() || m_hasAlpha; }
</span><span class="cx"> 
</span><span class="cx">     bool hasNativeImage() const { return m_nativeImage; }
</span><del>-    bool hasInvalidNativeImage(SubsamplingLevel subsamplingLevel) const { return hasNativeImage() &amp;&amp; subsamplingLevel &lt; m_subsamplingLevel; }
</del><ins>+    bool hasValidNativeImage(SubsamplingLevel subsamplingLevel) const { return hasNativeImage() &amp;&amp; subsamplingLevel &gt;= m_subsamplingLevel; }
</ins><span class="cx">     bool hasMetadata() const { return !size().isEmpty(); }
</span><span class="cx"> 
</span><span class="cx"> #if !USE(CG)
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsImageFrameCachecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/ImageFrameCache.cpp (208364 => 208365)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/ImageFrameCache.cpp        2016-11-04 02:37:45 UTC (rev 208364)
+++ trunk/Source/WebCore/platform/graphics/ImageFrameCache.cpp        2016-11-04 02:57:49 UTC (rev 208365)
</span><span class="lines">@@ -39,8 +39,9 @@
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="cx"> #include &lt;wtf/CheckedArithmetic.h&gt;
</span><ins>+#include &lt;wtf/MainThread.h&gt;
+#include &lt;wtf/RunLoop.h&gt;
</ins><span class="cx"> 
</span><del>-
</del><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><span class="cx"> ImageFrameCache::ImageFrameCache(Image* image)
</span><span class="lines">@@ -64,6 +65,11 @@
</span><span class="cx">     m_sizeRespectingOrientation = m_size;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+ImageFrameCache::~ImageFrameCache()
+{
+    ASSERT(!hasDecodingQueue());
+}
+
</ins><span class="cx"> void ImageFrameCache::destroyDecodedData(bool destroyAll, size_t count)
</span><span class="cx"> {
</span><span class="cx">     if (destroyAll)
</span><span class="lines">@@ -178,7 +184,7 @@
</span><span class="cx">     frame.m_hasAlpha = nativeImageHasAlpha(frame.m_nativeImage);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void ImageFrameCache::setFrameNativeImage(NativeImagePtr&amp;&amp; nativeImage, size_t index, SubsamplingLevel subsamplingLevel)
</del><ins>+void ImageFrameCache::setFrameNativeImageAtIndex(NativeImagePtr&amp;&amp; nativeImage, size_t index, SubsamplingLevel subsamplingLevel)
</ins><span class="cx"> {
</span><span class="cx">     ASSERT(index &lt; m_frames.size());
</span><span class="cx">     ImageFrame&amp; frame = m_frames[index];
</span><span class="lines">@@ -186,10 +192,10 @@
</span><span class="cx">     ASSERT(isDecoderAvailable());
</span><span class="cx"> 
</span><span class="cx">     frame.m_nativeImage = WTFMove(nativeImage);
</span><del>-    setFrameMetadata(index, subsamplingLevel);
</del><ins>+    setFrameMetadataAtIndex(index, subsamplingLevel);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void ImageFrameCache::setFrameMetadata(size_t index, SubsamplingLevel subsamplingLevel)
</del><ins>+void ImageFrameCache::setFrameMetadataAtIndex(size_t index, SubsamplingLevel subsamplingLevel)
</ins><span class="cx"> {
</span><span class="cx">     ASSERT(index &lt; m_frames.size());
</span><span class="cx">     ImageFrame&amp; frame = m_frames[index];
</span><span class="lines">@@ -208,34 +214,121 @@
</span><span class="cx">         frame.m_duration = m_decoder-&gt;frameDurationAtIndex(index);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-const ImageFrame&amp; ImageFrameCache::frameAtIndex(size_t index, SubsamplingLevel subsamplingLevel, ImageFrame::Caching caching)
</del><ins>+void ImageFrameCache::replaceFrameNativeImageAtIndex(NativeImagePtr&amp;&amp; nativeImage, size_t index, SubsamplingLevel subsamplingLevel)
</ins><span class="cx"> {
</span><span class="cx">     ASSERT(index &lt; m_frames.size());
</span><span class="cx">     ImageFrame&amp; frame = m_frames[index];
</span><del>-    if (!isDecoderAvailable() || caching == ImageFrame::Caching::Empty)
-        return frame;
</del><ins>+
+    if (!frame.hasValidNativeImage(subsamplingLevel)) {
+        // Clear the current image frame and update the observer with this clearance.
+        unsigned decodedSize = frame.clear();
+        decodedSizeDecreased(decodedSize);
+    }
+
+    // Do not cache the NativeImage if adding its frameByes to the MemoryCache will cause numerical overflow.
+    size_t frameBytes = size().unclampedArea() * sizeof(RGBA32);
+    if (!WTF::isInBounds&lt;unsigned&gt;(frameBytes + decodedSize()))
+        return;
+
+    // Copy the new image to the cache.
+    setFrameNativeImageAtIndex(WTFMove(nativeImage), index, subsamplingLevel);
+
+    // Update the observer with the new image frame bytes.
+    decodedSizeIncreased(frame.frameBytes());
+}
+
+void ImageFrameCache::cacheFrameNativeImageAtIndex(NativeImagePtr&amp;&amp; nativeImage, size_t index, SubsamplingLevel subsamplingLevel)
+{
+    if (!isDecoderAvailable())
+        return;
+
+    // Clean the old native image and set a new one
+    replaceFrameNativeImageAtIndex(WTFMove(nativeImage), index, subsamplingLevel);
+
+    // Notify the image with the readiness of the new frame NativeImage.
+    if (m_image)
+        m_image-&gt;newFrameNativeImageAvailableAtIndex(index);
+}
+
+Ref&lt;WorkQueue&gt; ImageFrameCache::decodingQueue()
+{
+    if (!m_decodingQueue)
+        m_decodingQueue = WorkQueue::create(&quot;org.webkit.ImageDecoder&quot;, WorkQueue::Type::Serial, WorkQueue::QOS::UserInteractive);
</ins><span class="cx">     
</span><ins>+    return *m_decodingQueue;
+}
+
+void ImageFrameCache::startAsyncDecodingQueue()
+{
+    if (hasDecodingQueue() || !isDecoderAvailable())
+        return;
+
+    Ref&lt;ImageFrameCache&gt; protectedThis = Ref&lt;ImageFrameCache&gt;(*this);
+    Ref&lt;WorkQueue&gt; protectedQueue = decodingQueue();
+
+    // We need to protect this and m_decodingQueue from being deleted while we are in the decoding loop.
+    decodingQueue()-&gt;dispatch([this, protectedThis = WTFMove(protectedThis), protectedQueue = WTFMove(protectedQueue)] {
+        ImageFrameRequest frameRequest;
+
+        while (m_frameRequestQueue.dequeue(frameRequest)) {
+            // Get the frame NativeImage on the decoding thread.
+            NativeImagePtr nativeImage = m_decoder-&gt;createFrameImageAtIndex(frameRequest.index, frameRequest.subsamplingLevel, DecodingMode::Immediate);
+
+            // Update the cached frames on the main thread to avoid updating the MemoryCache from a different thread.
+            callOnMainThread([this, nativeImage, frameRequest] () mutable {
+                // The queue may be closed if after we got the frame NativeImage, stopAsyncDecodingQueue() was called
+                if (hasDecodingQueue())
+                    cacheFrameNativeImageAtIndex(WTFMove(nativeImage), frameRequest.index, frameRequest.subsamplingLevel);
+            });
+        }
+    });
+}
+
+void ImageFrameCache::requestFrameAsyncDecodingAtIndex(size_t index, SubsamplingLevel subsamplingLevel)
+{
+    if (!isDecoderAvailable())
+        return;
+
+    if (!hasDecodingQueue())
+        startAsyncDecodingQueue();
+
+    ASSERT(index &lt; m_frames.size());
+    ImageFrame&amp; frame = m_frames[index];
+    
</ins><span class="cx">     if (subsamplingLevel == SubsamplingLevel::Undefinded)
</span><span class="cx">         subsamplingLevel = frame.subsamplingLevel();
</span><span class="cx">     
</span><del>-    if (frame.hasInvalidNativeImage(subsamplingLevel)) {
-        unsigned decodedSize = frame.clear();
-        decodedSizeDecreased(decodedSize);
-    }
</del><ins>+    if (frame.hasValidNativeImage(subsamplingLevel))
+        return;
</ins><span class="cx">     
</span><del>-    if (!frame.isComplete() &amp;&amp; caching == ImageFrame::Caching::Metadata)
-        setFrameMetadata(index, subsamplingLevel);
</del><ins>+    frame.setDecoding(ImageFrame::Decoding::BeingDecoded);
+    m_frameRequestQueue.enqueue({ index, subsamplingLevel });
+}
+
+void ImageFrameCache::stopAsyncDecodingQueue()
+{
+    if (!hasDecodingQueue())
+        return;
</ins><span class="cx">     
</span><del>-    if (!frame.hasNativeImage() &amp;&amp; caching == ImageFrame::Caching::MetadataAndImage) {
-        size_t frameBytes = size().unclampedArea() * sizeof(RGBA32);
</del><ins>+    m_frameRequestQueue.close();
+    m_decodingQueue = nullptr;
+}
</ins><span class="cx"> 
</span><del>-        // Do not create the NativeImage if adding its frameByes to the MemoryCache will cause numerical overflow.
-        if (WTF::isInBounds&lt;unsigned&gt;(frameBytes + decodedSize())) {
-            setFrameNativeImage(m_decoder-&gt;createFrameImageAtIndex(index, subsamplingLevel), index, subsamplingLevel);
-            decodedSizeIncreased(frame.frameBytes());
-        }
-    }
</del><ins>+const ImageFrame&amp; ImageFrameCache::frameAtIndex(size_t index, SubsamplingLevel subsamplingLevel, ImageFrame::Caching caching)
+{
+    ASSERT(index &lt; m_frames.size());
+    ImageFrame&amp; frame = m_frames[index];
+    if (!isDecoderAvailable() || frame.isBeingDecoded() || caching == ImageFrame::Caching::Empty)
+        return frame;
</ins><span class="cx">     
</span><ins>+    if (subsamplingLevel == SubsamplingLevel::Undefinded)
+        subsamplingLevel = frame.subsamplingLevel();
+
+    if (!frame.isComplete() &amp;&amp; caching == ImageFrame::Caching::Metadata)
+        setFrameMetadataAtIndex(index, subsamplingLevel);
+    else if (!frame.hasValidNativeImage(subsamplingLevel) &amp;&amp; caching == ImageFrame::Caching::MetadataAndImage)
+        replaceFrameNativeImageAtIndex(m_decoder-&gt;createFrameImageAtIndex(index, subsamplingLevel), index, subsamplingLevel);
+
</ins><span class="cx">     return frame;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -327,6 +420,11 @@
</span><span class="cx">     return frameCount() == 1 ? frameMetadataAtIndex&lt;Color, (&amp;ImageFrame::singlePixelSolidColor)&gt;(0, SubsamplingLevel::Undefinded, ImageFrame::Caching::MetadataAndImage, &amp;m_singlePixelSolidColor) : Color();
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool ImageFrameCache::frameIsBeingDecodedAtIndex(size_t index)
+{
+    return frameMetadataAtIndex&lt;bool, (&amp;ImageFrame::isBeingDecoded)&gt;(index);
+}
+
</ins><span class="cx"> bool ImageFrameCache::frameIsCompleteAtIndex(size_t index)
</span><span class="cx"> {
</span><span class="cx">     return frameMetadataAtIndex&lt;bool, (&amp;ImageFrame::isComplete)&gt;(index);
</span><span class="lines">@@ -342,9 +440,9 @@
</span><span class="cx">     return frameMetadataAtIndex&lt;bool, (&amp;ImageFrame::hasNativeImage)&gt;(index);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool ImageFrameCache::frameHasInvalidNativeImageAtIndex(size_t index, SubsamplingLevel subsamplingLevel)
</del><ins>+bool ImageFrameCache::frameHasValidNativeImageAtIndex(size_t index, SubsamplingLevel subsamplingLevel)
</ins><span class="cx"> {
</span><del>-    return frameHasImageAtIndex(index) &amp;&amp; subsamplingLevel &lt; frameSubsamplingLevelAtIndex(index);
</del><ins>+    return frameHasImageAtIndex(index) &amp;&amp; subsamplingLevel &gt;= frameSubsamplingLevelAtIndex(index);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> SubsamplingLevel ImageFrameCache::frameSubsamplingLevelAtIndex(size_t index)
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsImageFrameCacheh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/ImageFrameCache.h (208364 => 208365)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/ImageFrameCache.h        2016-11-04 02:37:45 UTC (rev 208364)
+++ trunk/Source/WebCore/platform/graphics/ImageFrameCache.h        2016-11-04 02:57:49 UTC (rev 208365)
</span><span class="lines">@@ -30,6 +30,9 @@
</span><span class="cx"> 
</span><span class="cx"> #include &lt;wtf/Forward.h&gt;
</span><span class="cx"> #include &lt;wtf/Optional.h&gt;
</span><ins>+#include &lt;wtf/SynchronizedFixedQueue.h&gt;
+#include &lt;wtf/WorkQueue.h&gt;
+#include &lt;wtf/threads/BinarySemaphore.h&gt;
</ins><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><span class="lines">@@ -37,12 +40,21 @@
</span><span class="cx"> class Image;
</span><span class="cx"> class ImageDecoder;
</span><span class="cx"> 
</span><del>-class ImageFrameCache {
</del><ins>+class ImageFrameCache : public RefCounted&lt;ImageFrameCache&gt; {
</ins><span class="cx">     friend class ImageSource;
</span><span class="cx"> public:
</span><del>-    ImageFrameCache(Image*);
-    ImageFrameCache(NativeImagePtr&amp;&amp;);
</del><ins>+    static Ref&lt;ImageFrameCache&gt; create(Image* image)
+    {
+        return adoptRef(*new ImageFrameCache(image));
+    }
</ins><span class="cx"> 
</span><ins>+    static Ref&lt;ImageFrameCache&gt; create(NativeImagePtr&amp;&amp; nativeImage)
+    {
+        return adoptRef(*new ImageFrameCache(WTFMove(nativeImage)));
+    }
+
+    ~ImageFrameCache();
+
</ins><span class="cx">     void setDecoder(ImageDecoder* decoder) { m_decoder = decoder; }
</span><span class="cx">     ImageDecoder* decoder() const { return m_decoder; }
</span><span class="cx"> 
</span><span class="lines">@@ -53,6 +65,12 @@
</span><span class="cx"> 
</span><span class="cx">     void growFrames();
</span><span class="cx">     void clearMetadata();
</span><ins>+    
+    // Asynchronous image decoding
+    void startAsyncDecodingQueue();
+    void requestFrameAsyncDecodingAtIndex(size_t, SubsamplingLevel);
+    void stopAsyncDecodingQueue();
+    bool hasDecodingQueue() { return m_decodingQueue; }
</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 class="lines">@@ -69,10 +87,11 @@
</span><span class="cx">     Color singlePixelSolidColor();
</span><span class="cx"> 
</span><span class="cx">     // ImageFrame metadata which does not require caching the ImageFrame.
</span><ins>+    bool frameIsBeingDecodedAtIndex(size_t);
</ins><span class="cx">     bool frameIsCompleteAtIndex(size_t);
</span><span class="cx">     bool frameHasAlphaAtIndex(size_t);
</span><span class="cx">     bool frameHasImageAtIndex(size_t);
</span><del>-    bool frameHasInvalidNativeImageAtIndex(size_t, SubsamplingLevel);
</del><ins>+    bool frameHasValidNativeImageAtIndex(size_t, SubsamplingLevel);
</ins><span class="cx">     SubsamplingLevel frameSubsamplingLevelAtIndex(size_t);
</span><span class="cx">     
</span><span class="cx">     // ImageFrame metadata which forces caching or re-caching the ImageFrame.
</span><span class="lines">@@ -83,6 +102,9 @@
</span><span class="cx">     NativeImagePtr frameImageAtIndex(size_t, SubsamplingLevel = SubsamplingLevel::Default);
</span><span class="cx"> 
</span><span class="cx"> private:
</span><ins>+    ImageFrameCache(Image*);
+    ImageFrameCache(NativeImagePtr&amp;&amp;);
+
</ins><span class="cx">     template&lt;typename T, T (ImageDecoder::*functor)() const&gt;
</span><span class="cx">     T metadata(const T&amp; defaultValue, Optional&lt;T&gt;* cachedValue = nullptr);
</span><span class="cx"> 
</span><span class="lines">@@ -97,8 +119,13 @@
</span><span class="cx">     void decodedSizeReset(unsigned decodedSize);
</span><span class="cx"> 
</span><span class="cx">     void setNativeImage(NativeImagePtr&amp;&amp;);
</span><del>-    void setFrameNativeImage(NativeImagePtr&amp;&amp;, size_t, SubsamplingLevel);
-    void setFrameMetadata(size_t, SubsamplingLevel);
</del><ins>+    void setFrameNativeImageAtIndex(NativeImagePtr&amp;&amp;, size_t, SubsamplingLevel);
+    void setFrameMetadataAtIndex(size_t, SubsamplingLevel);
+    void replaceFrameNativeImageAtIndex(NativeImagePtr&amp;&amp;, size_t, SubsamplingLevel);
+    void cacheFrameNativeImageAtIndex(NativeImagePtr&amp;&amp;, size_t, SubsamplingLevel);
+
+    Ref&lt;WorkQueue&gt; decodingQueue();
+
</ins><span class="cx">     const ImageFrame&amp; frameAtIndex(size_t, SubsamplingLevel, ImageFrame::Caching);
</span><span class="cx"> 
</span><span class="cx">     // Animated images over a certain size are considered large enough that we'll only hang on to one frame at a time.
</span><span class="lines">@@ -115,6 +142,16 @@
</span><span class="cx"> 
</span><span class="cx">     Vector&lt;ImageFrame, 1&gt; m_frames;
</span><span class="cx"> 
</span><ins>+    // Asynchronous image decoding.
+    struct ImageFrameRequest {
+        size_t index;
+        SubsamplingLevel subsamplingLevel;
+    };
+    static const int BufferSize = 8;
+    using FrameRequestQueue = SynchronizedFixedQueue&lt;ImageFrameRequest, BufferSize&gt;;
+    FrameRequestQueue m_frameRequestQueue;
+    RefPtr&lt;WorkQueue&gt; m_decodingQueue;
+
</ins><span class="cx">     // Image metadata.
</span><span class="cx">     Optional&lt;bool&gt; m_isSizeAvailable;
</span><span class="cx">     Optional&lt;size_t&gt; m_frameCount;
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsImageSourcecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/ImageSource.cpp (208364 => 208365)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/ImageSource.cpp        2016-11-04 02:37:45 UTC (rev 208364)
+++ trunk/Source/WebCore/platform/graphics/ImageSource.cpp        2016-11-04 02:57:49 UTC (rev 208365)
</span><span class="lines">@@ -46,12 +46,12 @@
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><span class="cx"> ImageSource::ImageSource(NativeImagePtr&amp;&amp; nativeImage)
</span><del>-    : m_frameCache(WTFMove(nativeImage))
</del><ins>+    : m_frameCache(ImageFrameCache::create(WTFMove(nativeImage)))
</ins><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx">     
</span><span class="cx"> ImageSource::ImageSource(Image* image, AlphaOption alphaOption, GammaAndColorProfileOption gammaAndColorProfileOption)
</span><del>-    : m_frameCache(image)
</del><ins>+    : m_frameCache(ImageFrameCache::create(image))
</ins><span class="cx">     , m_alphaOption(alphaOption)
</span><span class="cx">     , m_gammaAndColorProfileOption(gammaAndColorProfileOption)
</span><span class="cx"> {
</span><span class="lines">@@ -72,19 +72,19 @@
</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) {
</del><ins>+    if (!destroyAll || m_frameCache-&gt;hasDecodingQueue()) {
</ins><span class="cx">         clearFrameBufferCache(count);
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     m_decoder = nullptr;
</span><del>-    m_frameCache.setDecoder(nullptr);
</del><ins>+    m_frameCache-&gt;setDecoder(nullptr);
</ins><span class="cx">     setData(data, isAllDataReceived());
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void ImageSource::destroyDecodedData(SharedBuffer* data, bool destroyAll, size_t count)
</span><span class="cx"> {
</span><del>-    m_frameCache.destroyDecodedData(destroyAll, count);
</del><ins>+    m_frameCache-&gt;destroyDecodedData(destroyAll, count);
</ins><span class="cx">     clear(destroyAll, count, data);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -92,10 +92,10 @@
</span><span class="cx"> {
</span><span class="cx">     // If we have decoded frames but there is no encoded data, we shouldn't destroy
</span><span class="cx">     // the decoded image since we won't be able to reconstruct it later.
</span><del>-    if (!data &amp;&amp; m_frameCache.frameCount())
</del><ins>+    if (!data &amp;&amp; m_frameCache-&gt;frameCount())
</ins><span class="cx">         return false;
</span><span class="cx"> 
</span><del>-    if (!m_frameCache.destroyDecodedDataIfNecessary(destroyAll, count))
</del><ins>+    if (!m_frameCache-&gt;destroyDecodedDataIfNecessary(destroyAll, count))
</ins><span class="cx">         return false;
</span><span class="cx"> 
</span><span class="cx">     clear(destroyAll, count, data);
</span><span class="lines">@@ -111,7 +111,7 @@
</span><span class="cx">     if (!isDecoderAvailable())
</span><span class="cx">         return false;
</span><span class="cx"> 
</span><del>-    m_frameCache.setDecoder(m_decoder.get());
</del><ins>+    m_frameCache-&gt;setDecoder(m_decoder.get());
</ins><span class="cx">     return true;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -138,7 +138,7 @@
</span><span class="cx"> 
</span><span class="cx"> bool ImageSource::dataChanged(SharedBuffer* data, bool allDataReceived)
</span><span class="cx"> {
</span><del>-    m_frameCache.destroyIncompleteDecodedData();
</del><ins>+    m_frameCache-&gt;destroyIncompleteDecodedData();
</ins><span class="cx"> 
</span><span class="cx"> #if PLATFORM(IOS)
</span><span class="cx">     // FIXME: We should expose a setting to enable/disable progressive loading and make this
</span><span class="lines">@@ -162,19 +162,25 @@
</span><span class="cx">     setData(data, allDataReceived);
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><del>-    m_frameCache.clearMetadata();
</del><ins>+    m_frameCache-&gt;clearMetadata();
</ins><span class="cx">     if (!isSizeAvailable())
</span><span class="cx">         return false;
</span><span class="cx"> 
</span><del>-    m_frameCache.growFrames();
</del><ins>+    m_frameCache-&gt;growFrames();
</ins><span class="cx">     return true;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> bool ImageSource::isAllDataReceived()
</span><span class="cx"> {
</span><del>-    return isDecoderAvailable() ? m_decoder-&gt;isAllDataReceived() : m_frameCache.frameCount();
</del><ins>+    return isDecoderAvailable() ? m_decoder-&gt;isAllDataReceived() : m_frameCache-&gt;frameCount();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool ImageSource::isAsyncDecodingRequired()
+{
+    // FIXME: figure out the best heuristic for enabling async image decoding.
+    return size().area() * sizeof(RGBA32) &gt;= 100 * KB;
+}
+
</ins><span class="cx"> SubsamplingLevel ImageSource::maximumSubsamplingLevel()
</span><span class="cx"> {
</span><span class="cx">     if (m_maximumSubsamplingLevel)
</span><span class="lines">@@ -216,7 +222,7 @@
</span><span class="cx"> {
</span><span class="cx">     setDecoderTargetContext(targetContext);
</span><span class="cx"> 
</span><del>-    return m_frameCache.frameImageAtIndex(index, subsamplingLevel);
</del><ins>+    return m_frameCache-&gt;frameImageAtIndex(index, subsamplingLevel);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void ImageSource::dump(TextStream&amp; ts)
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsImageSourceh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/ImageSource.h (208364 => 208365)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/ImageSource.h        2016-11-04 02:37:45 UTC (rev 208364)
+++ trunk/Source/WebCore/platform/graphics/ImageSource.h        2016-11-04 02:57:49 UTC (rev 208365)
</span><span class="lines">@@ -62,33 +62,38 @@
</span><span class="cx">     void setData(SharedBuffer* data, bool allDataReceived);
</span><span class="cx">     bool dataChanged(SharedBuffer* data, bool allDataReceived);
</span><span class="cx"> 
</span><del>-    unsigned decodedSize() const { return m_frameCache.decodedSize(); }
</del><ins>+    unsigned decodedSize() const { return m_frameCache-&gt;decodedSize(); }
</ins><span class="cx">     bool isAllDataReceived();
</span><span class="cx"> 
</span><ins>+    bool isAsyncDecodingRequired();
+    void requestFrameAsyncDecodingAtIndex(size_t index, SubsamplingLevel subsamplingLevel) { m_frameCache-&gt;requestFrameAsyncDecodingAtIndex(index, subsamplingLevel); }
+    void stopAsyncDecodingQueue() { m_frameCache-&gt;stopAsyncDecodingQueue(); }
+
</ins><span class="cx">     // Image metadata which is calculated by the decoder or can deduced by the case of the memory NativeImage.
</span><del>-    bool isSizeAvailable() { return m_frameCache.isSizeAvailable(); }
-    size_t frameCount() { return m_frameCache.frameCount(); }
-    RepetitionCount repetitionCount() { return m_frameCache.repetitionCount(); }
-    String filenameExtension() { return m_frameCache.filenameExtension(); }
-    Optional&lt;IntPoint&gt; hotSpot() { return m_frameCache.hotSpot(); }
</del><ins>+    bool isSizeAvailable() { return m_frameCache-&gt;isSizeAvailable(); }
+    size_t frameCount() { return m_frameCache-&gt;frameCount(); }
+    RepetitionCount repetitionCount() { return m_frameCache-&gt;repetitionCount(); }
+    String filenameExtension() { return m_frameCache-&gt;filenameExtension(); }
+    Optional&lt;IntPoint&gt; hotSpot() { return m_frameCache-&gt;hotSpot(); }
</ins><span class="cx"> 
</span><span class="cx">     // Image metadata which is calculated from the first ImageFrame.
</span><del>-    IntSize size() { return m_frameCache.size(); }
-    IntSize sizeRespectingOrientation() { return m_frameCache.sizeRespectingOrientation(); }
-    Color singlePixelSolidColor() { return m_frameCache.singlePixelSolidColor(); }
</del><ins>+    IntSize size() { return m_frameCache-&gt;size(); }
+    IntSize sizeRespectingOrientation() { return m_frameCache-&gt;sizeRespectingOrientation(); }
+    Color singlePixelSolidColor() { return m_frameCache-&gt;singlePixelSolidColor(); }
</ins><span class="cx"> 
</span><span class="cx">     // ImageFrame metadata which does not require caching the ImageFrame.
</span><del>-    bool frameIsCompleteAtIndex(size_t index) { return m_frameCache.frameIsCompleteAtIndex(index); }
-    bool frameHasAlphaAtIndex(size_t index) { return m_frameCache.frameHasAlphaAtIndex(index); }
-    bool frameHasImageAtIndex(size_t index) { return m_frameCache.frameHasImageAtIndex(index); }
-    bool frameHasInvalidNativeImageAtIndex(size_t index, SubsamplingLevel subsamplingLevel) { return m_frameCache.frameHasInvalidNativeImageAtIndex(index, subsamplingLevel); }
-    SubsamplingLevel frameSubsamplingLevelAtIndex(size_t index) { return m_frameCache.frameSubsamplingLevelAtIndex(index); }
</del><ins>+    bool frameIsBeingDecodedAtIndex(size_t index) { return m_frameCache-&gt;frameIsBeingDecodedAtIndex(index); }
+    bool frameIsCompleteAtIndex(size_t index) { return m_frameCache-&gt;frameIsCompleteAtIndex(index); }
+    bool frameHasAlphaAtIndex(size_t index) { return m_frameCache-&gt;frameHasAlphaAtIndex(index); }
+    bool frameHasImageAtIndex(size_t index) { return m_frameCache-&gt;frameHasImageAtIndex(index); }
+    bool frameHasValidNativeImageAtIndex(size_t index, SubsamplingLevel subsamplingLevel) { return m_frameCache-&gt;frameHasValidNativeImageAtIndex(index, subsamplingLevel); }
+    SubsamplingLevel frameSubsamplingLevelAtIndex(size_t index) { return m_frameCache-&gt;frameSubsamplingLevelAtIndex(index); }
</ins><span class="cx"> 
</span><span class="cx">     // ImageFrame metadata which forces caching or re-caching the ImageFrame.
</span><del>-    IntSize frameSizeAtIndex(size_t index, SubsamplingLevel subsamplingLevel = SubsamplingLevel::Default) { return m_frameCache.frameSizeAtIndex(index, subsamplingLevel); }
-    unsigned frameBytesAtIndex(size_t index, SubsamplingLevel subsamplingLevel = SubsamplingLevel::Default) { return m_frameCache.frameBytesAtIndex(index, subsamplingLevel); }
-    float frameDurationAtIndex(size_t index) { return m_frameCache.frameDurationAtIndex(index); }
-    ImageOrientation frameOrientationAtIndex(size_t index) { return m_frameCache.frameOrientationAtIndex(index); }
</del><ins>+    IntSize frameSizeAtIndex(size_t index, SubsamplingLevel subsamplingLevel = SubsamplingLevel::Default) { return m_frameCache-&gt;frameSizeAtIndex(index, subsamplingLevel); }
+    unsigned frameBytesAtIndex(size_t index, SubsamplingLevel subsamplingLevel = SubsamplingLevel::Default) { return m_frameCache-&gt;frameBytesAtIndex(index, subsamplingLevel); }
+    float frameDurationAtIndex(size_t index) { return m_frameCache-&gt;frameDurationAtIndex(index); }
+    ImageOrientation frameOrientationAtIndex(size_t index) { return m_frameCache-&gt;frameOrientationAtIndex(index); }
</ins><span class="cx">     NativeImagePtr frameImageAtIndex(size_t index, SubsamplingLevel = SubsamplingLevel::Default, const GraphicsContext* targetContext = nullptr);
</span><span class="cx"> 
</span><span class="cx">     SubsamplingLevel maximumSubsamplingLevel();
</span><span class="lines">@@ -103,7 +108,7 @@
</span><span class="cx"> 
</span><span class="cx">     void setDecoderTargetContext(const GraphicsContext*);
</span><span class="cx"> 
</span><del>-    ImageFrameCache m_frameCache;
</del><ins>+    Ref&lt;ImageFrameCache&gt; m_frameCache;
</ins><span class="cx">     std::unique_ptr&lt;ImageDecoder&gt; m_decoder;
</span><span class="cx"> 
</span><span class="cx">     Optional&lt;SubsamplingLevel&gt; m_maximumSubsamplingLevel;
</span></span></pre>
</div>
</div>

</body>
</html>