<!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>[196483] 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/196483">196483</a></dd>
<dt>Author</dt> <dd>akling@apple.com</dd>
<dt>Date</dt> <dd>2016-02-12 10:34:57 -0800 (Fri, 12 Feb 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>[Mac] BitmapImage::decodedDataIsPurgeable() is telling lies and causing massive memory usage.
&lt;https://webkit.org/b/154172&gt;

Reviewed by Antti Koivisto.

The underlying mechanism in CoreAnimation that made this work is no longer in place.

Instead of keeping purgeable frames and juggling volatility bits, we were simply caching
every single frame of large GIF animations, sometimes leading to monstrous memory usage.

Remove the code from WebCore since it's not doing at all what it means to.

Now iOS and Mac will behave the same again, and frame caching decisions will be
made by WebKit, based on total pixel byte size.

* loader/cache/CachedImage.h:
* loader/cache/CachedResource.h:
(WebCore::CachedResource::decodedDataIsPurgeable): Deleted.
* loader/cache/MemoryCache.cpp:
(WebCore::MemoryCache::pruneLiveResourcesToSize): Deleted.
* platform/graphics/BitmapImage.cpp:
(WebCore::BitmapImage::decodedDataIsPurgeable): Deleted.
(WebCore::BitmapImage::destroyDecodedDataIfNecessary): Deleted.
* platform/graphics/BitmapImage.h:
* platform/graphics/Image.h:
(WebCore::Image::decodedDataIsPurgeable): Deleted.
* platform/graphics/cg/BitmapImageCG.cpp:
(WebCore::BitmapImage::decodedDataIsPurgeable): Deleted.
* platform/graphics/cg/ImageSourceCG.cpp:
(WebCore::ImageSource::createFrameAtIndex): Deleted.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreloadercacheCachedImageh">trunk/Source/WebCore/loader/cache/CachedImage.h</a></li>
<li><a href="#trunkSourceWebCoreloadercacheCachedResourceh">trunk/Source/WebCore/loader/cache/CachedResource.h</a></li>
<li><a href="#trunkSourceWebCoreloadercacheMemoryCachecpp">trunk/Source/WebCore/loader/cache/MemoryCache.cpp</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="#trunkSourceWebCoreplatformgraphicscgBitmapImageCGcpp">trunk/Source/WebCore/platform/graphics/cg/BitmapImageCG.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicscgImageSourceCGcpp">trunk/Source/WebCore/platform/graphics/cg/ImageSourceCG.cpp</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (196482 => 196483)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2016-02-12 18:30:43 UTC (rev 196482)
+++ trunk/Source/WebCore/ChangeLog        2016-02-12 18:34:57 UTC (rev 196483)
</span><span class="lines">@@ -1,3 +1,36 @@
</span><ins>+2016-02-12  Andreas Kling  &lt;akling@apple.com&gt;
+
+        [Mac] BitmapImage::decodedDataIsPurgeable() is telling lies and causing massive memory usage.
+        &lt;https://webkit.org/b/154172&gt;
+
+        Reviewed by Antti Koivisto.
+
+        The underlying mechanism in CoreAnimation that made this work is no longer in place.
+
+        Instead of keeping purgeable frames and juggling volatility bits, we were simply caching
+        every single frame of large GIF animations, sometimes leading to monstrous memory usage.
+
+        Remove the code from WebCore since it's not doing at all what it means to.
+
+        Now iOS and Mac will behave the same again, and frame caching decisions will be
+        made by WebKit, based on total pixel byte size.
+
+        * loader/cache/CachedImage.h:
+        * loader/cache/CachedResource.h:
+        (WebCore::CachedResource::decodedDataIsPurgeable): Deleted.
+        * loader/cache/MemoryCache.cpp:
+        (WebCore::MemoryCache::pruneLiveResourcesToSize): Deleted.
+        * platform/graphics/BitmapImage.cpp:
+        (WebCore::BitmapImage::decodedDataIsPurgeable): Deleted.
+        (WebCore::BitmapImage::destroyDecodedDataIfNecessary): Deleted.
+        * platform/graphics/BitmapImage.h:
+        * platform/graphics/Image.h:
+        (WebCore::Image::decodedDataIsPurgeable): Deleted.
+        * platform/graphics/cg/BitmapImageCG.cpp:
+        (WebCore::BitmapImage::decodedDataIsPurgeable): Deleted.
+        * platform/graphics/cg/ImageSourceCG.cpp:
+        (WebCore::ImageSource::createFrameAtIndex): Deleted.
+
</ins><span class="cx"> 2016-02-12  Brady Eidson  &lt;beidson@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Modern IDB: Ref cycle between IDBObjectStore and IDBIndex.
</span></span></pre></div>
<a id="trunkSourceWebCoreloadercacheCachedImageh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/loader/cache/CachedImage.h (196482 => 196483)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/loader/cache/CachedImage.h        2016-02-12 18:30:43 UTC (rev 196482)
+++ trunk/Source/WebCore/loader/cache/CachedImage.h        2016-02-12 18:34:57 UTC (rev 196483)
</span><span class="lines">@@ -116,8 +116,6 @@
</span><span class="cx"> 
</span><span class="cx">     virtual bool stillNeedsLoad() const override { return !errorOccurred() &amp;&amp; status() == Unknown &amp;&amp; !isLoading(); }
</span><span class="cx"> 
</span><del>-    virtual bool decodedDataIsPurgeable() const override { return m_image &amp;&amp; m_image-&gt;decodedDataIsPurgeable(); }
-
</del><span class="cx">     // ImageObserver
</span><span class="cx">     virtual void decodedSizeChanged(const Image*, int delta) override;
</span><span class="cx">     virtual void didDraw(const Image*) override;
</span></span></pre></div>
<a id="trunkSourceWebCoreloadercacheCachedResourceh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/loader/cache/CachedResource.h (196482 => 196483)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/loader/cache/CachedResource.h        2016-02-12 18:30:43 UTC (rev 196482)
+++ trunk/Source/WebCore/loader/cache/CachedResource.h        2016-02-12 18:34:57 UTC (rev 196483)
</span><span class="lines">@@ -147,8 +147,6 @@
</span><span class="cx">     unsigned encodedSize() const { return m_encodedSize; }
</span><span class="cx">     unsigned decodedSize() const { return m_decodedSize; }
</span><span class="cx">     unsigned overheadSize() const;
</span><del>-
-    virtual bool decodedDataIsPurgeable() const { return false; }
</del><span class="cx">     
</span><span class="cx">     bool isLoaded() const { return !m_loading; } // FIXME. Method name is inaccurate. Loading might not have started yet.
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreloadercacheMemoryCachecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/loader/cache/MemoryCache.cpp (196482 => 196483)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/loader/cache/MemoryCache.cpp        2016-02-12 18:30:43 UTC (rev 196482)
+++ trunk/Source/WebCore/loader/cache/MemoryCache.cpp        2016-02-12 18:34:57 UTC (rev 196483)
</span><span class="lines">@@ -314,9 +314,6 @@
</span><span class="cx">             if (!shouldDestroyDecodedDataForAllLiveResources &amp;&amp; elapsedTime &lt; cMinDelayBeforeLiveDecodedPrune)
</span><span class="cx">                 return;
</span><span class="cx"> 
</span><del>-            if (current-&gt;decodedDataIsPurgeable())
-                continue;
-
</del><span class="cx">             // Destroy our decoded data. This will remove us from m_liveDecodedResources, and possibly move us
</span><span class="cx">             // to a different LRU list in m_allResources.
</span><span class="cx">             current-&gt;destroyDecodedData();
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsBitmapImagecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/BitmapImage.cpp (196482 => 196483)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/BitmapImage.cpp        2016-02-12 18:30:43 UTC (rev 196482)
+++ trunk/Source/WebCore/platform/graphics/BitmapImage.cpp        2016-02-12 18:34:57 UTC (rev 196483)
</span><span class="lines">@@ -96,13 +96,6 @@
</span><span class="cx">     m_frameTimer-&gt;startOneShot(delay);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-#if !USE(CG)
-bool BitmapImage::decodedDataIsPurgeable() const
-{
-    return false;
-}
-#endif
-
</del><span class="cx"> bool BitmapImage::haveFrameAtIndex(size_t index)
</span><span class="cx"> {
</span><span class="cx">     if (index &gt;= frameCount())
</span><span class="lines">@@ -150,11 +143,6 @@
</span><span class="cx">     const unsigned largeAnimationCutoff = 5242880;
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><del>-    // If decoded data is purgeable, the operating system will
-    // take care of throwing it away when the system is under pressure.
-    if (decodedDataIsPurgeable())
-        return;
-
</del><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><span class="cx">     if (!data() &amp;&amp; m_frames.size())
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsBitmapImageh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/BitmapImage.h (196482 => 196483)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/BitmapImage.h        2016-02-12 18:30:43 UTC (rev 196482)
+++ trunk/Source/WebCore/platform/graphics/BitmapImage.h        2016-02-12 18:34:57 UTC (rev 196483)
</span><span class="lines">@@ -288,7 +288,6 @@
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="cx"> private:
</span><del>-    virtual bool decodedDataIsPurgeable() const override;
</del><span class="cx">     void clearTimer();
</span><span class="cx">     void startTimer(double delay);
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsImageh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/Image.h (196482 => 196483)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/Image.h        2016-02-12 18:30:43 UTC (rev 196482)
+++ trunk/Source/WebCore/platform/graphics/Image.h        2016-02-12 18:34:57 UTC (rev 196483)
</span><span class="lines">@@ -119,7 +119,6 @@
</span><span class="cx">     virtual String filenameExtension() const { return String(); } // null string if unknown
</span><span class="cx"> 
</span><span class="cx">     virtual void destroyDecodedData(bool destroyAll = true) = 0;
</span><del>-    virtual bool decodedDataIsPurgeable() const { return false; }
</del><span class="cx"> 
</span><span class="cx">     SharedBuffer* data() { return m_encodedImageData.get(); }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicscgBitmapImageCGcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/cg/BitmapImageCG.cpp (196482 => 196483)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/cg/BitmapImageCG.cpp        2016-02-12 18:30:43 UTC (rev 196482)
+++ trunk/Source/WebCore/platform/graphics/cg/BitmapImageCG.cpp        2016-02-12 18:34:57 UTC (rev 196483)
</span><span class="lines">@@ -265,13 +265,6 @@
</span><span class="cx">     return m_source.createFrameAtIndex(index);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool BitmapImage::decodedDataIsPurgeable() const
-{
-    return m_frames.size() &gt;= 1
-        &amp;&amp; m_frames[0].m_frame
-        &amp;&amp; CGImageGetCachingFlags(m_frames[0].m_frame) &amp; kCGImageCachingTransient;
</del><span class="cx"> }
</span><span class="cx"> 
</span><del>-}
-
</del><span class="cx"> #endif // USE(CG)
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicscgImageSourceCGcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/cg/ImageSourceCG.cpp (196482 => 196483)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/cg/ImageSourceCG.cpp        2016-02-12 18:30:43 UTC (rev 196482)
+++ trunk/Source/WebCore/platform/graphics/cg/ImageSourceCG.cpp        2016-02-12 18:34:57 UTC (rev 196483)
</span><span class="lines">@@ -368,13 +368,6 @@
</span><span class="cx">     if (!imageUTI)
</span><span class="cx">         return image.leakRef();
</span><span class="cx"> 
</span><del>-#if PLATFORM(MAC)
-    if (CFEqual(imageUTI, kUTTypeGIF)) {
-        CGImageSetCachingFlags(image.get(), kCGImageCachingTransient);
-        return image.leakRef();
-    }
-#endif
-
</del><span class="cx">     if (!CFEqual(imageUTI, xbmUTI))
</span><span class="cx">         return image.leakRef();
</span><span class="cx">     
</span></span></pre>
</div>
</div>

</body>
</html>