<!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>[161235] 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/161235">161235</a></dd>
<dt>Author</dt> <dd>mmaxfield@apple.com</dd>
<dt>Date</dt> <dd>2014-01-02 15:32:47 -0800 (Thu, 02 Jan 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>Allow ImageBuffer to re-use IOSurfaces
https://bugs.webkit.org/show_bug.cgi?id=125477

Source/WebCore:

Reviewed by Geoff Garen. Modifications reviewed by Tim Horton.

This patch is taken from <a href="http://trac.webkit.org/projects/webkit/changeset/160945">r160945</a>, but the modifications to ImageBufferCG.cpp
have been reverted.

This test adds a static class, ImageBufferBackingStoreCache, that vends
IOSurfaces. It remembers IOSurfaces that have been returned to it until
a configurable timeout.

The storage used by this class is in the form of a HashMap from a
bucketed size to the IOSurface. There are many other data structures
that could be used, but this implementation gives a 80% hit rate on
normal browsing of some example sites with Canvas and
text-decoration-skip: ink. Because the buckets are fairly
small (rounding the width and height up to multiples of 8), traversing the
bucket contents takes on average 2 steps.

Test: fast/canvas/canvas-backing-store-reuse.html

* WebCore.xcodeproj/project.pbxproj: Added new caching class
* platform/graphics/cg/ImageBufferBackingStoreCache.cpp: Added.
(WebCore::createIOSurface): Copied from ImageBufferCG.cpp
(WebCore::ImageBufferBackingStoreCache::timerFired): Forget the cache
contents
(WebCore::ImageBufferBackingStoreCache::schedulePurgeTimer):
(WebCore::ImageBufferBackingStoreCache::get): Static getter
(WebCore::ImageBufferBackingStoreCache::ImageBufferBackingStoreCache):
(WebCore::ImageBufferBackingStoreCache::insertIntoCache): Memory-management
creation function
(WebCore::ImageBufferBackingStoreCache::takeFromCache): Memory-management
deletion function
(WebCore::ImageBufferBackingStoreCache::isAcceptableSurface): Does this cached
IOSurface fit the bill?
(WebCore::ImageBufferBackingStoreCache::tryTakeFromCache): Lookup
a bucket and walk through its contents
(WebCore::ImageBufferBackingStoreCache::getOrAllocate): Public function
for clients who want a IOSurface from the cache
(WebCore::ImageBufferBackingStoreCache::deallocate): Public
function for clients to return an IOSurface to the pool
* platform/graphics/cg/ImageBufferBackingStoreCache.h: Added.
(WebCore::ImageBuffer::ImageBuffer):
(WebCore::ImageBuffer::~ImageBuffer):

PerformanceTests:

Reviewed by Geoff Garen.

This test times creating a variety of different sizes of canvases
once some have already been created. The second creation of the
canvases should re-use the existing IOSurfaces.

* Canvas/reuse.html: Added.

LayoutTests:

Reviewed by Geoff Garen.

Now that we're re-using the backing store of canvases, this
test makes sure that if we draw to a canvas, then destroy it,
then create a new canvas (which should share the same backing
store) that it doesn't have the stale data in it

* fast/canvas/canvas-backing-store-reuse-expected.txt: Added.
* fast/canvas/canvas-backing-store-reuse.html: Added.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkPerformanceTestsChangeLog">trunk/PerformanceTests/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreWebCorexcodeprojprojectpbxproj">trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsfastcanvascanvasbackingstorereuseexpectedtxt">trunk/LayoutTests/fast/canvas/canvas-backing-store-reuse-expected.txt</a></li>
<li><a href="#trunkLayoutTestsfastcanvascanvasbackingstorereusehtml">trunk/LayoutTests/fast/canvas/canvas-backing-store-reuse.html</a></li>
<li><a href="#trunkPerformanceTestsCanvasreusehtml">trunk/PerformanceTests/Canvas/reuse.html</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicscgImageBufferBackingStoreCachecpp">trunk/Source/WebCore/platform/graphics/cg/ImageBufferBackingStoreCache.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicscgImageBufferBackingStoreCacheh">trunk/Source/WebCore/platform/graphics/cg/ImageBufferBackingStoreCache.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (161234 => 161235)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2014-01-02 23:28:36 UTC (rev 161234)
+++ trunk/LayoutTests/ChangeLog        2014-01-02 23:32:47 UTC (rev 161235)
</span><span class="lines">@@ -1,3 +1,18 @@
</span><ins>+2014-01-02  Myles C. Maxfield  &lt;mmaxfield@apple.com&gt;
+
+        Allow ImageBuffer to re-use IOSurfaces
+        https://bugs.webkit.org/show_bug.cgi?id=125477
+
+        Reviewed by Geoff Garen.
+
+        Now that we're re-using the backing store of canvases, this 
+        test makes sure that if we draw to a canvas, then destroy it, 
+        then create a new canvas (which should share the same backing 
+        store) that it doesn't have the stale data in it 
+
+        * fast/canvas/canvas-backing-store-reuse-expected.txt: Added.
+        * fast/canvas/canvas-backing-store-reuse.html: Added.
+
</ins><span class="cx"> 2014-01-02  Dirk Schulze  &lt;krit@webkit.org&gt;
</span><span class="cx"> 
</span><span class="cx">         Support &lt;box&gt; values computed style for 'clip-path' property
</span></span></pre></div>
<a id="trunkLayoutTestsfastcanvascanvasbackingstorereuseexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/canvas/canvas-backing-store-reuse-expected.txt (0 => 161235)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/canvas/canvas-backing-store-reuse-expected.txt                                (rev 0)
+++ trunk/LayoutTests/fast/canvas/canvas-backing-store-reuse-expected.txt        2014-01-02 23:32:47 UTC (rev 161235)
</span><span class="lines">@@ -0,0 +1,5 @@
</span><ins>+PASS data.data is [0, 0, 0, 0]
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsfastcanvascanvasbackingstorereusehtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/canvas/canvas-backing-store-reuse.html (0 => 161235)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/canvas/canvas-backing-store-reuse.html                                (rev 0)
+++ trunk/LayoutTests/fast/canvas/canvas-backing-store-reuse.html        2014-01-02 23:32:47 UTC (rev 161235)
</span><span class="lines">@@ -0,0 +1,33 @@
</span><ins>+&lt;!DOCTYPE HTML&gt;
+&lt;html&gt;
+&lt;head&gt;
+&lt;script src=&quot;../../resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
+&lt;/head&gt;
+&lt;body&gt;
+&lt;script&gt;
+if (window.testRunner)
+    testRunner.dumpAsText();
+
+(function() {
+  var canvas = document.createElement(&quot;canvas&quot;);
+  canvas.width = 99;
+  canvas.height = 99;
+  var context = canvas.getContext(&quot;2d&quot;);
+  context.fillStyle = '#f00';
+  context.fillRect(0, 0, 100, 100);
+})();
+
+if (window.GCController)
+  GCController.collect();
+
+var canvas = document.createElement(&quot;canvas&quot;);
+canvas.width = 95;
+canvas.height = 95;
+var context = canvas.getContext(&quot;2d&quot;);
+var data = context.getImageData(50, 50, 1, 1);
+shouldBe(&quot;data.data&quot;, &quot;[0, 0, 0, 0]&quot;);
+document.body.appendChild(canvas);
+&lt;/script&gt;
+&lt;script src=&quot;../../resources/js-test-post.js&quot;&gt;&lt;/script&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkPerformanceTestsCanvasreusehtml"></a>
<div class="addfile"><h4>Added: trunk/PerformanceTests/Canvas/reuse.html (0 => 161235)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/PerformanceTests/Canvas/reuse.html                                (rev 0)
+++ trunk/PerformanceTests/Canvas/reuse.html        2014-01-02 23:32:47 UTC (rev 161235)
</span><span class="lines">@@ -0,0 +1,31 @@
</span><ins>+&lt;!DOCTYPE html&gt;
+&lt;html&gt;
+&lt;body&gt;
+&lt;script src=&quot;../resources/runner.js&quot;&gt;&lt;/script&gt;
+&lt;script&gt;
+
+var numCreated = 1000;
+
+function testCreation() {
+    (function() {
+        var canvases = [];
+        for (var i = 0; i &lt; numCreated; i += 16) {
+            var canvas = document.createElement(&quot;canvas&quot;);
+            canvas.width = i;
+            canvas.height = i;
+            var context = canvas.getContext(&quot;2d&quot;);
+            context.fillRect(0, 0, 1, 1);
+            canvases.push(canvas);
+        }
+    })();
+    
+    if (window.GCController)
+        window.GCController.collect();
+}
+
+PerfTestRunner.measureRunsPerSecond({run: function() {
+    testCreation();
+}});
+&lt;/script&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkPerformanceTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/PerformanceTests/ChangeLog (161234 => 161235)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/PerformanceTests/ChangeLog        2014-01-02 23:28:36 UTC (rev 161234)
+++ trunk/PerformanceTests/ChangeLog        2014-01-02 23:32:47 UTC (rev 161235)
</span><span class="lines">@@ -1,3 +1,16 @@
</span><ins>+2014-01-02  Myles C. Maxfield  &lt;mmaxfield@apple.com&gt;
+
+        Allow ImageBuffer to re-use IOSurfaces
+        https://bugs.webkit.org/show_bug.cgi?id=125477
+
+        Reviewed by Geoff Garen. 
+
+        This test times creating a variety of different sizes of canvases 
+        once some have already been created. The second creation of the 
+        canvases should re-use the existing IOSurfaces. 
+        
+        * Canvas/reuse.html: Added.
+
</ins><span class="cx"> 2013-12-23  Commit Queue  &lt;commit-queue@webkit.org&gt;
</span><span class="cx"> 
</span><span class="cx">         Unreviewed, rolling out r160945.
</span></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (161234 => 161235)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2014-01-02 23:28:36 UTC (rev 161234)
+++ trunk/Source/WebCore/ChangeLog        2014-01-02 23:32:47 UTC (rev 161235)
</span><span class="lines">@@ -1,3 +1,51 @@
</span><ins>+2014-01-02  Myles C. Maxfield  &lt;mmaxfield@apple.com&gt;
+
+        Allow ImageBuffer to re-use IOSurfaces
+        https://bugs.webkit.org/show_bug.cgi?id=125477
+
+        Reviewed by Geoff Garen. Modifications reviewed by Tim Horton.
+
+        This patch is taken from r160945, but the modifications to ImageBufferCG.cpp
+        have been reverted.
+
+        This test adds a static class, ImageBufferBackingStoreCache, that vends 
+        IOSurfaces. It remembers IOSurfaces that have been returned to it until 
+        a configurable timeout. 
+
+        The storage used by this class is in the form of a HashMap from a 
+        bucketed size to the IOSurface. There are many other data structures 
+        that could be used, but this implementation gives a 80% hit rate on 
+        normal browsing of some example sites with Canvas and 
+        text-decoration-skip: ink. Because the buckets are fairly 
+        small (rounding the width and height up to multiples of 8), traversing the 
+        bucket contents takes on average 2 steps.  
+
+        Test: fast/canvas/canvas-backing-store-reuse.html 
+
+        * WebCore.xcodeproj/project.pbxproj: Added new caching class 
+        * platform/graphics/cg/ImageBufferBackingStoreCache.cpp: Added. 
+        (WebCore::createIOSurface): Copied from ImageBufferCG.cpp 
+        (WebCore::ImageBufferBackingStoreCache::timerFired): Forget the cache 
+        contents 
+        (WebCore::ImageBufferBackingStoreCache::schedulePurgeTimer): 
+        (WebCore::ImageBufferBackingStoreCache::get): Static getter 
+        (WebCore::ImageBufferBackingStoreCache::ImageBufferBackingStoreCache): 
+        (WebCore::ImageBufferBackingStoreCache::insertIntoCache): Memory-management 
+        creation function 
+        (WebCore::ImageBufferBackingStoreCache::takeFromCache): Memory-management 
+        deletion function 
+        (WebCore::ImageBufferBackingStoreCache::isAcceptableSurface): Does this cached 
+        IOSurface fit the bill? 
+        (WebCore::ImageBufferBackingStoreCache::tryTakeFromCache): Lookup 
+        a bucket and walk through its contents 
+        (WebCore::ImageBufferBackingStoreCache::getOrAllocate): Public function 
+        for clients who want a IOSurface from the cache 
+        (WebCore::ImageBufferBackingStoreCache::deallocate): Public 
+        function for clients to return an IOSurface to the pool 
+        * platform/graphics/cg/ImageBufferBackingStoreCache.h: Added. 
+        (WebCore::ImageBuffer::ImageBuffer): 
+        (WebCore::ImageBuffer::~ImageBuffer): 
+
</ins><span class="cx"> 2014-01-02  Piotr Grad  &lt;p.grad@samsung.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Video-seek-with-negative-playback was flaky.
</span></span></pre></div>
<a id="trunkSourceWebCoreWebCorexcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (161234 => 161235)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj        2014-01-02 23:28:36 UTC (rev 161234)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj        2014-01-02 23:32:47 UTC (rev 161235)
</span><span class="lines">@@ -850,6 +850,8 @@
</span><span class="cx">                 1C11CCC80AA6093700DADB20 /* DOMHTMLElement.h in Copy Generated Headers */ = {isa = PBXBuildFile; fileRef = 85DF2EEB0AA387CB00AD64C5 /* DOMHTMLElement.h */; };
</span><span class="cx">                 1C18DA58181AF6A500C4EF22 /* TextPainter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1C18DA56181AF6A500C4EF22 /* TextPainter.cpp */; };
</span><span class="cx">                 1C18DA59181AF6A500C4EF22 /* TextPainter.h in Headers */ = {isa = PBXBuildFile; fileRef = 1C18DA57181AF6A500C4EF22 /* TextPainter.h */; };
</span><ins>+                1C21E57C183ED1FF001C289D /* ImageBufferBackingStoreCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1C21E57A183ED1FF001C289D /* ImageBufferBackingStoreCache.cpp */; };
+                1C21E57D183ED1FF001C289D /* ImageBufferBackingStoreCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 1C21E57B183ED1FF001C289D /* ImageBufferBackingStoreCache.h */; };
</ins><span class="cx">                 1C26497A0D7E248A00BD10F2 /* DocumentLoaderMac.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1C2649790D7E248A00BD10F2 /* DocumentLoaderMac.cpp */; };
</span><span class="cx">                 1C26497C0D7E24EC00BD10F2 /* PageMac.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1C26497B0D7E24EC00BD10F2 /* PageMac.cpp */; };
</span><span class="cx">                 1C4C8F020AD85D87009475CE /* DeleteButtonController.h in Headers */ = {isa = PBXBuildFile; fileRef = 1C4C8F000AD85D87009475CE /* DeleteButtonController.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="lines">@@ -7513,6 +7515,8 @@
</span><span class="cx">                 1AFE11980CBFFCC4003017FA /* JSSQLResultSetRowList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSSQLResultSetRowList.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 1C18DA56181AF6A500C4EF22 /* TextPainter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TextPainter.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 1C18DA57181AF6A500C4EF22 /* TextPainter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TextPainter.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><ins>+                1C21E57A183ED1FF001C289D /* ImageBufferBackingStoreCache.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ImageBufferBackingStoreCache.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
+                1C21E57B183ED1FF001C289D /* ImageBufferBackingStoreCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ImageBufferBackingStoreCache.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</ins><span class="cx">                 1C2649790D7E248A00BD10F2 /* DocumentLoaderMac.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DocumentLoaderMac.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 1C26497B0D7E24EC00BD10F2 /* PageMac.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PageMac.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 1C4C8EFF0AD85D87009475CE /* DeleteButtonController.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DeleteButtonController.cpp; sourceTree = &quot;&lt;group&gt;&quot;; tabWidth = 8; usesTabs = 0; };
</span><span class="lines">@@ -19325,6 +19329,8 @@
</span><span class="cx">                                 1FC40FB81655C5910040F29E /* SubimageCacheWithTimer.cpp */,
</span><span class="cx">                                 1FC40FB71655C5910040F29E /* SubimageCacheWithTimer.h */,
</span><span class="cx">                                 B275352A0B053814002CE64F /* TransformationMatrixCG.cpp */,
</span><ins>+                                1C21E57A183ED1FF001C289D /* ImageBufferBackingStoreCache.cpp */,
+                                1C21E57B183ED1FF001C289D /* ImageBufferBackingStoreCache.h */,
</ins><span class="cx">                         );
</span><span class="cx">                         path = cg;
</span><span class="cx">                         sourceTree = &quot;&lt;group&gt;&quot;;
</span><span class="lines">@@ -23741,6 +23747,7 @@
</span><span class="cx">                                 E1AD14231295EA7F00ACA989 /* JSHTMLInputElementCustom.h in Headers */,
</span><span class="cx">                                 A6148A7912E41E3B0044A784 /* JSHTMLKeygenElement.h in Headers */,
</span><span class="cx">                                 1AE2AB220A1CE63B00B42B25 /* JSHTMLLabelElement.h in Headers */,
</span><ins>+                                1C21E57D183ED1FF001C289D /* ImageBufferBackingStoreCache.h in Headers */,
</ins><span class="cx">                                 1AE2AB240A1CE63B00B42B25 /* JSHTMLLegendElement.h in Headers */,
</span><span class="cx">                                 1AE2AB260A1CE63B00B42B25 /* JSHTMLLIElement.h in Headers */,
</span><span class="cx">                                 A80E7B0D0A19D606007FB8C5 /* JSHTMLLinkElement.h in Headers */,
</span><span class="lines">@@ -26927,6 +26934,7 @@
</span><span class="cx">                                 B58CEB6A11913607002A6790 /* JSDatabaseSync.cpp in Sources */,
</span><span class="cx">                                 4162A4571011464700DFF3ED /* JSDedicatedWorkerGlobalScope.cpp in Sources */,
</span><span class="cx">                                 4162A454101145E300DFF3ED /* JSDedicatedWorkerGlobalScopeCustom.cpp in Sources */,
</span><ins>+                                1C21E57C183ED1FF001C289D /* ImageBufferBackingStoreCache.cpp in Sources */,
</ins><span class="cx">                                 FDA15ED112B03F94003A583A /* JSDelayNode.cpp in Sources */,
</span><span class="cx">                                 31FB1A65120A5D3F00DC02A0 /* JSDeviceMotionEvent.cpp in Sources */,
</span><span class="cx">                                 07C59B6317F4D1BF000FBCBB /* MockMediaStreamCenter.cpp in Sources */,
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicscgImageBufferBackingStoreCachecpp"></a>
<div class="addfile"><h4>Added: trunk/Source/WebCore/platform/graphics/cg/ImageBufferBackingStoreCache.cpp (0 => 161235)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/cg/ImageBufferBackingStoreCache.cpp                                (rev 0)
+++ trunk/Source/WebCore/platform/graphics/cg/ImageBufferBackingStoreCache.cpp        2014-01-02 23:32:47 UTC (rev 161235)
</span><span class="lines">@@ -0,0 +1,221 @@
</span><ins>+/*
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include &quot;config.h&quot;
+#include &quot;ImageBufferBackingStoreCache.h&quot;
+
+#if USE(IOSURFACE_CANVAS_BACKING_STORE)
+#include &lt;IOSurface/IOSurface.h&gt;
+
+namespace WebCore {
+
+static RetainPtr&lt;IOSurfaceRef&gt; createIOSurface(const IntSize&amp; size)
+{
+    unsigned pixelFormat = 'BGRA';
+    unsigned bytesPerElement = 4;
+    int width = size.width();
+    int height = size.height();
+
+    unsigned long bytesPerRow = IOSurfaceAlignProperty(kIOSurfaceBytesPerRow, size.width() * bytesPerElement);
+    if (!bytesPerRow)
+        return 0;
+
+    unsigned long allocSize = IOSurfaceAlignProperty(kIOSurfaceAllocSize, size.height() * bytesPerRow);
+    if (!allocSize)
+        return 0;
+
+    const int kNumCreationParameters = 6;
+    const void* keys[kNumCreationParameters];
+    const void* values[kNumCreationParameters];
+    keys[0] = kIOSurfaceWidth;
+    values[0] = CFNumberCreate(0, kCFNumberIntType, &amp;width);
+    keys[1] = kIOSurfaceHeight;
+    values[1] = CFNumberCreate(0, kCFNumberIntType, &amp;height);
+    keys[2] = kIOSurfacePixelFormat;
+    values[2] = CFNumberCreate(0, kCFNumberIntType, &amp;pixelFormat);
+    keys[3] = kIOSurfaceBytesPerElement;
+    values[3] = CFNumberCreate(0, kCFNumberIntType, &amp;bytesPerElement);
+    keys[4] = kIOSurfaceBytesPerRow;
+    values[4] = CFNumberCreate(0, kCFNumberLongType, &amp;bytesPerRow);
+    keys[5] = kIOSurfaceAllocSize;
+    values[5] = CFNumberCreate(0, kCFNumberLongType, &amp;allocSize);
+
+    RetainPtr&lt;CFDictionaryRef&gt; dict = adoptCF(CFDictionaryCreate(0, keys, values, kNumCreationParameters, &amp;kCFTypeDictionaryKeyCallBacks, &amp;kCFTypeDictionaryValueCallBacks));
+    for (unsigned i = 0; i &lt; kNumCreationParameters; i++)
+        CFRelease(values[i]);
+
+    return adoptCF(IOSurfaceCreate(dict.get()));
+}
+
+ImageBufferBackingStoreCache&amp; ImageBufferBackingStoreCache::get()
+{
+    DEFINE_STATIC_LOCAL(ImageBufferBackingStoreCache, cache, ());
+    return cache;
+}
+
+bool ImageBufferBackingStoreCache::isAcceptableSurface(const IOSurfaceAndContextWithCreationParams&amp; info, const IntSize&amp; requestedSize, CGColorSpaceRef colorSpace, bool needExactSize) const
+{
+    IOSurfaceRef surface = info.surface.get();
+    IntSize actualSize(IOSurfaceGetWidth(surface), IOSurfaceGetHeight(surface));
+    if (!CFEqual(info.colorSpace.get(), colorSpace))
+        return false;
+    if (needExactSize &amp;&amp; actualSize != requestedSize)
+        return false;
+    if (actualSize.width() &lt; requestedSize.width() || actualSize.height() &lt; requestedSize.height())
+        return false;
+    return true;
+}
+
+void ImageBufferBackingStoreCache::insertIntoCache(IOSurfaceAndContextWithCreationParams&amp;&amp; info)
+{
+    IOSurfaceRef surface = info.surface.get();
+    IntSize surfaceSize(IOSurfaceGetWidth(surface), IOSurfaceGetHeight(surface));
+
+    auto toAdd = new IOSurfaceAndContextWithCreationParams(info);
+    auto insertedTuple = m_cachedSurfaces.add(convertSizeToKey(surfaceSize), InfoLinkedList());
+    insertedTuple.iterator-&gt;value.append(toAdd);
+    
+    m_pixelsCached += surfaceSize.area();
+}
+
+auto ImageBufferBackingStoreCache::takeFromCache(CachedSurfaceMap::iterator iter, IOSurfaceAndContextWithCreationParams* info) -&gt; IOSurfaceAndContextWithCreationParams
+{
+    ASSERT(info);
+    ASSERT(iter != m_cachedSurfaces.end());
+
+    IOSurfaceRef surface = info-&gt;surface.get();
+    m_pixelsCached -= IOSurfaceGetWidth(surface) * IOSurfaceGetHeight(surface);
+
+    iter-&gt;value.remove(info);
+    if (iter-&gt;value.isEmpty())
+        m_cachedSurfaces.remove(iter);
+    IOSurfaceAndContextWithCreationParams result = std::move(*info);
+    delete info;
+    return result;
+}
+
+bool ImageBufferBackingStoreCache::tryTakeFromCache(const IntSize&amp; size, CGColorSpaceRef colorSpace, bool needExactSize, IOSurfaceAndContextWithCreationParams&amp; outInfo)
+{
+    CachedSurfaceMap::iterator i = m_cachedSurfaces.find(convertSizeToKey(size));
+    if (i == m_cachedSurfaces.end())
+        return nullptr;
+    InfoLinkedList&amp; ll = i-&gt;value;
+    for (auto info = ll.head(); info; info = info-&gt;next()) {
+        if (isAcceptableSurface(*info, size, colorSpace, needExactSize)) {
+            outInfo = takeFromCache(i, info);
+            return true;
+        }
+    }
+    return false;
+}
+
+ImageBufferBackingStoreCache::IOSurfaceAndContext ImageBufferBackingStoreCache::getOrAllocate(IntSize size, CGColorSpaceRef colorSpace, bool needExactSize)
+{
+    IOSurfaceAndContextWithCreationParams foundInfo;
+    if (tryTakeFromCache(size, colorSpace, needExactSize, foundInfo)) {
+        IOSurfaceRef surface = foundInfo.surface.get();
+        CGContextRef context = foundInfo.context.get();
+        CGContextSaveGState(context);
+        auto activeInserted = m_activeSurfaces.add(surface, std::move(foundInfo));
+        ASSERT(activeInserted.isNewEntry);
+        return activeInserted.iterator-&gt;value;
+    }
+
+    RetainPtr&lt;IOSurfaceRef&gt; surface = createIOSurface(size);
+    if (!surface.get())
+        return IOSurfaceAndContext();
+
+    RetainPtr&lt;CGContextRef&gt; context = adoptCF(wkIOSurfaceContextCreate(surface.get(), size.width(), size.height(), colorSpace));
+    if (!context.get())
+        return IOSurfaceAndContext();
+    CGContextSaveGState(context.get());
+
+    auto insertedTuple = m_activeSurfaces.add(surface, IOSurfaceAndContextWithCreationParams(surface.get(), context.get(), colorSpace));
+    ASSERT(insertedTuple.isNewEntry);
+
+    return insertedTuple.iterator-&gt;value;
+}
+
+void ImageBufferBackingStoreCache::deallocate(IOSurfaceRef surface)
+{
+    ActiveSurfaceMap::iterator lookup = m_activeSurfaces.find(surface);
+    ASSERT(lookup != m_activeSurfaces.end());
+    
+    auto info = std::move(lookup-&gt;value);
+    m_activeSurfaces.remove(lookup);
+    
+    IOSurfaceRef ioSurface = info.surface.get();
+    CGContextRef context = info.context.get();
+    IntSize surfaceSize(IOSurfaceGetWidth(ioSurface), IOSurfaceGetHeight(ioSurface));
+    int surfaceArea = surfaceSize.area();
+
+    static const int kMaxPixelsCached = 1024 * 1024 * 64; // 256MB
+    if (surfaceArea &gt; kMaxPixelsCached)
+        return;
+
+    // Evict
+    auto bucket = m_cachedSurfaces.find(convertSizeToKey(surfaceSize));
+    if (bucket != m_cachedSurfaces.end()) {
+        for (int itemsInBucket = bucket-&gt;value.size();
+            itemsInBucket &gt; 0 &amp;&amp; m_pixelsCached + surfaceArea &gt; kMaxPixelsCached;
+            --itemsInBucket)
+            takeFromCache(bucket, bucket-&gt;value.head());
+    }
+    while (m_pixelsCached + surfaceArea &gt; kMaxPixelsCached) {
+        CachedSurfaceMap::iterator iter = m_cachedSurfaces.begin();
+        takeFromCache(iter, iter-&gt;value.head());
+    }
+
+    CGContextRestoreGState(context);
+    // Clear opportunistically so CG has more time to carry it out.
+    CGContextClearRect(context, CGRectMake(0, 0, surfaceSize.width(), surfaceSize.height()));
+#if __MAC_OS_X_VERSION_MIN_REQUIRED &lt; 1090
+    CGContextFlush(context);
+#endif
+
+    insertIntoCache(std::move(info));
+
+    schedulePurgeTimer();
+}
+
+void ImageBufferBackingStoreCache::timerFired(Timer&lt;ImageBufferBackingStoreCache&gt;*)
+{
+    while (!m_cachedSurfaces.isEmpty()) {
+        CachedSurfaceMap::iterator iter = m_cachedSurfaces.begin();
+        takeFromCache(iter, iter-&gt;value.head());
+    }
+}
+
+void ImageBufferBackingStoreCache::schedulePurgeTimer()
+{
+    if (m_purgeTimer.isActive())
+        m_purgeTimer.stop();
+
+    static const double purgeInterval = 5;
+    m_purgeTimer.startOneShot(purgeInterval);
+}
+
+}
+#endif // IOSURFACE_CANVAS_BACKING_STORE
</ins></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicscgImageBufferBackingStoreCacheh"></a>
<div class="addfile"><h4>Added: trunk/Source/WebCore/platform/graphics/cg/ImageBufferBackingStoreCache.h (0 => 161235)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/cg/ImageBufferBackingStoreCache.h                                (rev 0)
+++ trunk/Source/WebCore/platform/graphics/cg/ImageBufferBackingStoreCache.h        2014-01-02 23:32:47 UTC (rev 161235)
</span><span class="lines">@@ -0,0 +1,117 @@
</span><ins>+/*
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ImageBufferBackingStoreCache_h
+#define ImageBufferBackingStoreCache_h
+
+#include &quot;ImageBuffer.h&quot;
+
+#include &quot;Timer.h&quot;
+
+#include &lt;ApplicationServices/ApplicationServices.h&gt;
+#include &lt;wtf/DoublyLinkedList.h&gt;
+#include &lt;wtf/HashMap.h&gt;
+
+#if USE(IOSURFACE_CANVAS_BACKING_STORE)
+
+namespace WebCore {
+
+class ImageBufferBackingStoreCache {
+    WTF_MAKE_NONCOPYABLE(ImageBufferBackingStoreCache); WTF_MAKE_FAST_ALLOCATED;
+
+public:
+    static ImageBufferBackingStoreCache&amp; get();
+    
+    struct IOSurfaceAndContext {
+        IOSurfaceAndContext()
+        {
+        }
+
+        IOSurfaceAndContext(IOSurfaceRef surface, CGContextRef context)
+            : surface(surface)
+            , context(context)
+        {
+        }
+
+        RetainPtr&lt;IOSurfaceRef&gt; surface;
+        RetainPtr&lt;CGContextRef&gt; context;
+    };
+
+    IOSurfaceAndContext getOrAllocate(IntSize, CGColorSpaceRef, bool needExactSize);
+    void deallocate(IOSurfaceRef);
+
+private:
+    ImageBufferBackingStoreCache()
+        : m_purgeTimer(this, &amp;ImageBufferBackingStoreCache::timerFired)
+        , m_pixelsCached(0)
+    {
+    }
+
+    struct IOSurfaceAndContextWithCreationParams : public IOSurfaceAndContext, public DoublyLinkedListNode&lt;IOSurfaceAndContextWithCreationParams&gt; {
+        IOSurfaceAndContextWithCreationParams()
+        {
+        }
+
+        IOSurfaceAndContextWithCreationParams(IOSurfaceRef surface, CGContextRef context, CGColorSpaceRef colorSpace)
+            : IOSurfaceAndContext(surface, context)
+            , colorSpace(colorSpace)
+        {
+        }
+
+        IOSurfaceAndContextWithCreationParams* m_prev;
+        IOSurfaceAndContextWithCreationParams* m_next;
+        RetainPtr&lt;CGColorSpaceRef&gt; colorSpace;
+    };
+    typedef HashMap&lt;RetainPtr&lt;IOSurfaceRef&gt;, IOSurfaceAndContextWithCreationParams&gt; ActiveSurfaceMap;
+    typedef std::pair&lt;int, int&gt; CachedSurfaceKey;
+    typedef DoublyLinkedList&lt;IOSurfaceAndContextWithCreationParams&gt; InfoLinkedList;
+    typedef HashMap&lt;CachedSurfaceKey, InfoLinkedList&gt; CachedSurfaceMap;
+
+    static CachedSurfaceKey convertSizeToKey(const IntSize&amp; size)
+    {
+        return std::make_pair(WTF::roundUpToMultipleOf(8, size.width()), WTF::roundUpToMultipleOf(8, size.height()));
+    }
+
+    IOSurfaceAndContextWithCreationParams takeFromCache(CachedSurfaceMap::iterator, IOSurfaceAndContextWithCreationParams*);
+    void insertIntoCache(IOSurfaceAndContextWithCreationParams&amp;&amp;);
+
+    // If we find an acceptable surface, this function removes it from the cache as
+    // well as placing it in the out parameter.
+    bool tryTakeFromCache(const IntSize&amp;, CGColorSpaceRef, bool needExactSize, IOSurfaceAndContextWithCreationParams&amp; outInfo);
+    bool isAcceptableSurface(const IOSurfaceAndContextWithCreationParams&amp;, const IntSize&amp;, CGColorSpaceRef, bool needExactSize) const;
+
+    void timerFired(Timer&lt;ImageBufferBackingStoreCache&gt;*);
+    void schedulePurgeTimer();
+
+    Timer&lt;ImageBufferBackingStoreCache&gt; m_purgeTimer;
+    ActiveSurfaceMap m_activeSurfaces;
+    CachedSurfaceMap m_cachedSurfaces;
+    int m_pixelsCached;
+};
+
+}
+#endif // IOSURFACE_CANVAS_BACKING_STORE
+
+#endif // ImageBufferBackingStoreCache_h
</ins></span></pre>
</div>
</div>

</body>
</html>