<!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>[160121] 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/160121">160121</a></dd>
<dt>Author</dt> <dd>commit-queue@webkit.org</dd>
<dt>Date</dt> <dd>2013-12-04 13:35:38 -0800 (Wed, 04 Dec 2013)</dd>
</dl>

<h3>Log Message</h3>
<pre>Allow ImageBuffer to use an IOSurface that is larger than necessary
https://bugs.webkit.org/show_bug.cgi?id=124626

Patch by Myles C. Maxfield &lt;mmaxfield@apple.com&gt; on 2013-12-04
Reviewed by Simon Fraser.

Source/WebCore:

Because creating ImageBuffer's backing store can be so expensive, it
would be beneficial to have a pool of pre-created backing stores
available. However, this means that ImageBuffer might have to use a
backing store that is larger than the exact dimensions that it needs.
This patch adds a field, m_backingStoreSize, to CG's ImageBufferData
class, and uses this new field when performing ImageBuffer operations
to allow for larger-than-necessary backing stores. Content is always
drawn in the top left corner of the backing store.

No new tests are necessary because there is no behavior change.

* platform/graphics/ImageBuffer.h:
(WebCore::ImageBuffer::baseTransform): The base transform has to put
content at the top left corner instead of bottom left
* platform/graphics/cg/ImageBufferCG.cpp:
(WebCore::createCroppedImageIfNecessary): Convenience function to figure out
the dimensions of the backing texture in user space
(WebCore::ImageBuffer::ImageBuffer): Set up new m_backingStoreSize member
(WebCore::maybeCropToBounds): Some ImageBuffer API functions require
outputting an image with logical size. This function performs the cropping
(WebCore::ImageBuffer::copyImage): Updated for larger-than-necessary
backing stores
(WebCore::ImageBuffer::copyNativeImage): Ditto
(WebCore::ImageBuffer::draw): Ditto
(WebCore::ImageBuffer::clip): Ditto
(WebCore::ImageBuffer::putByteArray): Ditto
(WebCore::ImageBuffer::toDataURL): Ditto
* platform/graphics/cg/ImageBufferDataCG.cpp:
(WebCore::ImageBufferData::getData): Ditto
(WebCore::ImageBufferData::putData): Ditto
* platform/graphics/cg/ImageBufferDataCG.h: New m_backingStoreSize field

LayoutTests:

Update tests to be more robust with respect to accelerated vs
non-accelerated ImageBuffers.

* fast/canvas/script-tests/canvas-fillPath-shadow.js: Don't sample a canvas at exactly
the corner of a drawn shape (because the corner might be antialiased). Instead, sample
a single pixel inside the shape
* fast/canvas/script-tests/canvas-scale-shadowBlur.js: Don't sample a canvas at exactly
the edge of the blur radius. Instead, sample a single pixel past the blur radius.
* fast/canvas/script-tests/canvas-scale-strokePath-shadow.js:
(shouldBeAround): Allow this test to be less strict when sampling inside a blurred region
* platform/mac/fast/canvas/canvas-scale-shadowBlur-expected.txt: Matching update w/r/t
canvas-scale-shadowBlur.js</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkLayoutTestsfastcanvasscripttestscanvasfillPathshadowjs">trunk/LayoutTests/fast/canvas/script-tests/canvas-fillPath-shadow.js</a></li>
<li><a href="#trunkLayoutTestsfastcanvasscripttestscanvasscaleshadowBlurjs">trunk/LayoutTests/fast/canvas/script-tests/canvas-scale-shadowBlur.js</a></li>
<li><a href="#trunkLayoutTestsfastcanvasscripttestscanvasscalestrokePathshadowjs">trunk/LayoutTests/fast/canvas/script-tests/canvas-scale-strokePath-shadow.js</a></li>
<li><a href="#trunkLayoutTestsplatformmacfastcanvascanvasscaleshadowBlurexpectedtxt">trunk/LayoutTests/platform/mac/fast/canvas/canvas-scale-shadowBlur-expected.txt</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicsImageBufferh">trunk/Source/WebCore/platform/graphics/ImageBuffer.h</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicscgImageBufferCGcpp">trunk/Source/WebCore/platform/graphics/cg/ImageBufferCG.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicscgImageBufferDataCGcpp">trunk/Source/WebCore/platform/graphics/cg/ImageBufferDataCG.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicscgImageBufferDataCGh">trunk/Source/WebCore/platform/graphics/cg/ImageBufferDataCG.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (160120 => 160121)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2013-12-04 21:29:45 UTC (rev 160120)
+++ trunk/LayoutTests/ChangeLog        2013-12-04 21:35:38 UTC (rev 160121)
</span><span class="lines">@@ -1,3 +1,23 @@
</span><ins>+2013-12-04  Myles C. Maxfield  &lt;mmaxfield@apple.com&gt;
+
+        Allow ImageBuffer to use an IOSurface that is larger than necessary
+        https://bugs.webkit.org/show_bug.cgi?id=124626
+
+        Reviewed by Simon Fraser.
+
+        Update tests to be more robust with respect to accelerated vs
+        non-accelerated ImageBuffers. 
+
+        * fast/canvas/script-tests/canvas-fillPath-shadow.js: Don't sample a canvas at exactly
+        the corner of a drawn shape (because the corner might be antialiased). Instead, sample
+        a single pixel inside the shape
+        * fast/canvas/script-tests/canvas-scale-shadowBlur.js: Don't sample a canvas at exactly
+        the edge of the blur radius. Instead, sample a single pixel past the blur radius.
+        * fast/canvas/script-tests/canvas-scale-strokePath-shadow.js:
+        (shouldBeAround): Allow this test to be less strict when sampling inside a blurred region
+        * platform/mac/fast/canvas/canvas-scale-shadowBlur-expected.txt: Matching update w/r/t
+        canvas-scale-shadowBlur.js
+
</ins><span class="cx"> 2013-12-03  Dean Jackson  &lt;dino@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [WebGL] Support for texImage2D/texSubImage2D of type HALF_FLOAT_OES
</span></span></pre></div>
<a id="trunkLayoutTestsfastcanvasscripttestscanvasfillPathshadowjs"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/fast/canvas/script-tests/canvas-fillPath-shadow.js (160120 => 160121)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/canvas/script-tests/canvas-fillPath-shadow.js        2013-12-04 21:29:45 UTC (rev 160120)
+++ trunk/LayoutTests/fast/canvas/script-tests/canvas-fillPath-shadow.js        2013-12-04 21:35:38 UTC (rev 160121)
</span><span class="lines">@@ -70,7 +70,7 @@
</span><span class="cx"> shouldBe('data[1]', '20');
</span><span class="cx"> shouldBe('data[2]', '0');
</span><span class="cx"> 
</span><del>-imageData = ctx.getImageData(380, 30, 1, 1);
</del><ins>+imageData = ctx.getImageData(381, 31, 1, 1);
</ins><span class="cx"> data = imageData.data;
</span><span class="cx"> shouldBe('data[0]', '255');
</span><span class="cx"> shouldBe('data[1]', '20');
</span></span></pre></div>
<a id="trunkLayoutTestsfastcanvasscripttestscanvasscaleshadowBlurjs"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/fast/canvas/script-tests/canvas-scale-shadowBlur.js (160120 => 160121)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/canvas/script-tests/canvas-scale-shadowBlur.js        2013-12-04 21:29:45 UTC (rev 160120)
+++ trunk/LayoutTests/fast/canvas/script-tests/canvas-scale-shadowBlur.js        2013-12-04 21:35:38 UTC (rev 160121)
</span><span class="lines">@@ -67,7 +67,7 @@
</span><span class="cx"> shouldBe('d[2]', '0');
</span><span class="cx"> shouldBeAround('d[3]', '255');
</span><span class="cx"> 
</span><del>-d = ctx.getImageData(250, 175, 1, 1).data;
</del><ins>+d = ctx.getImageData(250, 174, 1, 1).data;
</ins><span class="cx"> shouldBe('d[0]', '0');
</span><span class="cx"> shouldBe('d[1]', '0');
</span><span class="cx"> shouldBe('d[2]', '0');
</span><span class="lines">@@ -79,7 +79,7 @@
</span><span class="cx"> shouldBe('d[2]', '0');
</span><span class="cx"> shouldBe('d[3]', '0');
</span><span class="cx"> 
</span><del>-d = ctx.getImageData(175, 250, 1, 1).data;
</del><ins>+d = ctx.getImageData(174, 250, 1, 1).data;
</ins><span class="cx"> shouldBe('d[0]', '0');
</span><span class="cx"> shouldBe('d[1]', '0');
</span><span class="cx"> shouldBe('d[2]', '0');
</span><span class="lines">@@ -135,7 +135,7 @@
</span><span class="cx"> shouldBe('d[2]', '0');
</span><span class="cx"> shouldBeAround('d[3]', '255');
</span><span class="cx"> 
</span><del>-d = ctx.getImageData(450, 175, 1, 1).data;
</del><ins>+d = ctx.getImageData(450, 174, 1, 1).data;
</ins><span class="cx"> shouldBe('d[0]', '0');
</span><span class="cx"> shouldBe('d[1]', '0');
</span><span class="cx"> shouldBe('d[2]', '0');
</span><span class="lines">@@ -147,7 +147,7 @@
</span><span class="cx"> shouldBe('d[2]', '0');
</span><span class="cx"> shouldBe('d[3]', '0');
</span><span class="cx"> 
</span><del>-d = ctx.getImageData(375, 250, 1, 1).data;
</del><ins>+d = ctx.getImageData(374, 250, 1, 1).data;
</ins><span class="cx"> shouldBe('d[0]', '0');
</span><span class="cx"> shouldBe('d[1]', '0');
</span><span class="cx"> shouldBe('d[2]', '0');
</span></span></pre></div>
<a id="trunkLayoutTestsfastcanvasscripttestscanvasscalestrokePathshadowjs"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/fast/canvas/script-tests/canvas-scale-strokePath-shadow.js (160120 => 160121)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/canvas/script-tests/canvas-scale-strokePath-shadow.js        2013-12-04 21:29:45 UTC (rev 160120)
+++ trunk/LayoutTests/fast/canvas/script-tests/canvas-scale-strokePath-shadow.js        2013-12-04 21:35:38 UTC (rev 160121)
</span><span class="lines">@@ -10,7 +10,7 @@
</span><span class="cx">     document.getElementById(&quot;console&quot;).appendChild(paragraph);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-function shouldBeAround(a, b)
</del><ins>+function shouldBeAround(a, b, argdelta)
</ins><span class="cx"> {
</span><span class="cx">     var evalA;
</span><span class="cx">     try {
</span><span class="lines">@@ -19,7 +19,11 @@
</span><span class="cx">         evalA = e;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    if (Math.abs(evalA - b) &lt; 20)
</del><ins>+    var delta = 20;
+    if (typeof argdelta != &quot;undefined&quot;)
+        delta = argdelta;
+
+    if (Math.abs(evalA - b) &lt; delta)
</ins><span class="cx">         print(&quot;PASS &quot; + a + &quot; is around &quot; + b , &quot;green&quot;)
</span><span class="cx">     else
</span><span class="cx">         print(&quot;FAIL &quot; + a + &quot; is not around &quot; + b + &quot; (actual: &quot; + evalA + &quot;)&quot;, &quot;red&quot;);
</span><span class="lines">@@ -119,7 +123,7 @@
</span><span class="cx"> shouldBe('d[0]', '255');
</span><span class="cx"> shouldBe('d[1]', '0');
</span><span class="cx"> shouldBe('d[2]', '0');
</span><del>-shouldBeAround('d[3]', '200');
</del><ins>+shouldBeAround('d[3]', '200', 25);
</ins><span class="cx"> 
</span><span class="cx"> d = ctx.getImageData(508, 250, 1, 1).data;
</span><span class="cx"> shouldBe('d[0]', '255');
</span><span class="lines">@@ -131,7 +135,7 @@
</span><span class="cx"> shouldBe('d[0]', '255');
</span><span class="cx"> shouldBe('d[1]', '0');
</span><span class="cx"> shouldBe('d[2]', '0');
</span><del>-shouldBeAround('d[3]', '199');
</del><ins>+shouldBeAround('d[3]', '199', 25);
</ins><span class="cx"> 
</span><span class="cx"> // Verify blurry alpha shadow.
</span><span class="cx"> d = ctx.getImageData(505, 450, 1, 1).data;
</span></span></pre></div>
<a id="trunkLayoutTestsplatformmacfastcanvascanvasscaleshadowBlurexpectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/platform/mac/fast/canvas/canvas-scale-shadowBlur-expected.txt (160120 => 160121)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/platform/mac/fast/canvas/canvas-scale-shadowBlur-expected.txt        2013-12-04 21:29:45 UTC (rev 160120)
+++ trunk/LayoutTests/platform/mac/fast/canvas/canvas-scale-shadowBlur-expected.txt        2013-12-04 21:35:38 UTC (rev 160121)
</span><span class="lines">@@ -10,7 +10,7 @@
</span><span class="cx"> FAIL d[0] should be 0. Was 255.
</span><span class="cx"> PASS d[1] is 0
</span><span class="cx"> PASS d[2] is 0
</span><del>-FAIL d[3] should be 0. Was 6.
</del><ins>+FAIL d[3] should be 0. Was 5.
</ins><span class="cx"> FAIL d[0] should be 0. Was 255.
</span><span class="cx"> PASS d[1] is 0
</span><span class="cx"> PASS d[2] is 0
</span><span class="lines">@@ -18,7 +18,7 @@
</span><span class="cx"> FAIL d[0] should be 0. Was 255.
</span><span class="cx"> PASS d[1] is 0
</span><span class="cx"> PASS d[2] is 0
</span><del>-FAIL d[3] should be 0. Was 6.
</del><ins>+FAIL d[3] should be 0. Was 5.
</ins><span class="cx"> FAIL d[0] should be 0. Was 255.
</span><span class="cx"> PASS d[1] is 0
</span><span class="cx"> PASS d[2] is 0
</span><span class="lines">@@ -54,7 +54,7 @@
</span><span class="cx"> FAIL d[0] should be 0. Was 255.
</span><span class="cx"> PASS d[1] is 0
</span><span class="cx"> PASS d[2] is 0
</span><del>-FAIL d[3] should be 0. Was 6.
</del><ins>+FAIL d[3] should be 0. Was 5.
</ins><span class="cx"> FAIL d[0] should be 0. Was 255.
</span><span class="cx"> PASS d[1] is 0
</span><span class="cx"> PASS d[2] is 0
</span><span class="lines">@@ -62,7 +62,7 @@
</span><span class="cx"> FAIL d[0] should be 0. Was 255.
</span><span class="cx"> PASS d[1] is 0
</span><span class="cx"> PASS d[2] is 0
</span><del>-FAIL d[3] should be 0. Was 6.
</del><ins>+FAIL d[3] should be 0. Was 5.
</ins><span class="cx"> FAIL d[0] should be 0. Was 255.
</span><span class="cx"> PASS d[1] is 0
</span><span class="cx"> PASS d[2] is 0
</span></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (160120 => 160121)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2013-12-04 21:29:45 UTC (rev 160120)
+++ trunk/Source/WebCore/ChangeLog        2013-12-04 21:35:38 UTC (rev 160121)
</span><span class="lines">@@ -1,3 +1,42 @@
</span><ins>+2013-12-04  Myles C. Maxfield  &lt;mmaxfield@apple.com&gt;
+
+        Allow ImageBuffer to use an IOSurface that is larger than necessary
+        https://bugs.webkit.org/show_bug.cgi?id=124626
+
+        Reviewed by Simon Fraser.
+
+        Because creating ImageBuffer's backing store can be so expensive, it
+        would be beneficial to have a pool of pre-created backing stores
+        available. However, this means that ImageBuffer might have to use a
+        backing store that is larger than the exact dimensions that it needs.
+        This patch adds a field, m_backingStoreSize, to CG's ImageBufferData
+        class, and uses this new field when performing ImageBuffer operations
+        to allow for larger-than-necessary backing stores. Content is always
+        drawn in the top left corner of the backing store.
+
+        No new tests are necessary because there is no behavior change.
+
+        * platform/graphics/ImageBuffer.h:
+        (WebCore::ImageBuffer::baseTransform): The base transform has to put
+        content at the top left corner instead of bottom left
+        * platform/graphics/cg/ImageBufferCG.cpp:
+        (WebCore::createCroppedImageIfNecessary): Convenience function to figure out
+        the dimensions of the backing texture in user space
+        (WebCore::ImageBuffer::ImageBuffer): Set up new m_backingStoreSize member
+        (WebCore::maybeCropToBounds): Some ImageBuffer API functions require
+        outputting an image with logical size. This function performs the cropping
+        (WebCore::ImageBuffer::copyImage): Updated for larger-than-necessary
+        backing stores
+        (WebCore::ImageBuffer::copyNativeImage): Ditto
+        (WebCore::ImageBuffer::draw): Ditto
+        (WebCore::ImageBuffer::clip): Ditto
+        (WebCore::ImageBuffer::putByteArray): Ditto
+        (WebCore::ImageBuffer::toDataURL): Ditto
+        * platform/graphics/cg/ImageBufferDataCG.cpp:
+        (WebCore::ImageBufferData::getData): Ditto
+        (WebCore::ImageBufferData::putData): Ditto
+        * platform/graphics/cg/ImageBufferDataCG.h: New m_backingStoreSize field
+
</ins><span class="cx"> 2013-12-03  Dean Jackson  &lt;dino@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [WebGL] Support for texImage2D of type HALF_FLOAT_OES
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsImageBufferh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/ImageBuffer.h (160120 => 160121)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/ImageBuffer.h        2013-12-04 21:29:45 UTC (rev 160120)
+++ trunk/Source/WebCore/platform/graphics/ImageBuffer.h        2013-12-04 21:35:38 UTC (rev 160121)
</span><span class="lines">@@ -117,7 +117,7 @@
</span><span class="cx">         void transformColorSpace(ColorSpace srcColorSpace, ColorSpace dstColorSpace);
</span><span class="cx">         void platformTransformColorSpace(const Vector&lt;int&gt;&amp;);
</span><span class="cx"> #else
</span><del>-        AffineTransform baseTransform() const { return AffineTransform(1, 0, 0, -1, 0, internalSize().height()); }
</del><ins>+        AffineTransform baseTransform() const { return AffineTransform(1, 0, 0, -1, 0, m_data.m_backingStoreSize.height()); }
</ins><span class="cx"> #endif
</span><span class="cx"> #if USE(ACCELERATED_COMPOSITING)
</span><span class="cx">         PlatformLayer* platformLayer() const;
</span><span class="lines">@@ -135,6 +135,8 @@
</span><span class="cx"> 
</span><span class="cx">     private:
</span><span class="cx"> #if USE(CG)
</span><ins>+        // The returned image might be larger than the internalSize(). If you want the smaller
+        // image, crop the result.
</ins><span class="cx">         RetainPtr&lt;CGImageRef&gt; copyNativeImage(BackingStoreCopy = CopyBackingStore) const;
</span><span class="cx">         void flushContext() const;
</span><span class="cx"> #endif
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicscgImageBufferCGcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/cg/ImageBufferCG.cpp (160120 => 160121)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/cg/ImageBufferCG.cpp        2013-12-04 21:29:45 UTC (rev 160120)
+++ trunk/Source/WebCore/platform/graphics/cg/ImageBufferCG.cpp        2013-12-04 21:35:38 UTC (rev 160121)
</span><span class="lines">@@ -98,6 +98,13 @@
</span><span class="cx">     fastFree(const_cast&lt;void*&gt;(data));
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+static FloatSize scaleSizeToUserSpace(const FloatSize&amp; logicalSize, const IntSize&amp; backingStoreSize, const IntSize&amp; internalSize)
+{
+    float xMagnification = static_cast&lt;float&gt;(backingStoreSize.width()) / internalSize.width();
+    float yMagnification = static_cast&lt;float&gt;(backingStoreSize.height()) / internalSize.height();
+    return FloatSize(logicalSize.width() * xMagnification, logicalSize.height() * yMagnification);
+}
+
</ins><span class="cx"> ImageBuffer::ImageBuffer(const IntSize&amp; size, float resolutionScale, ColorSpace imageColorSpace, RenderingMode renderingMode, bool&amp; success)
</span><span class="cx">     : m_data(size) // NOTE: The input here isn't important as ImageBufferDataCG's constructor just ignores it.
</span><span class="cx">     , m_logicalSize(size)
</span><span class="lines">@@ -111,6 +118,7 @@
</span><span class="cx">         return;
</span><span class="cx"> 
</span><span class="cx">     m_size = IntSize(scaledWidth, scaledHeight);
</span><ins>+    m_data.m_backingStoreSize = m_size;
</ins><span class="cx"> 
</span><span class="cx">     success = false;  // Make early return mean failure.
</span><span class="cx">     bool accelerateRendering = renderingMode == Accelerated;
</span><span class="lines">@@ -121,8 +129,8 @@
</span><span class="cx">     Checked&lt;int, RecordOverflow&gt; height = m_size.height();
</span><span class="cx"> 
</span><span class="cx">     // Prevent integer overflows
</span><del>-    m_data.m_bytesPerRow = 4 * width;
-    Checked&lt;size_t, RecordOverflow&gt; numBytes = height * m_data.m_bytesPerRow;
</del><ins>+    m_data.m_bytesPerRow = 4 * Checked&lt;unsigned, RecordOverflow&gt;(m_data.m_backingStoreSize.width());
+    Checked&lt;size_t, RecordOverflow&gt; numBytes = Checked&lt;unsigned, RecordOverflow&gt;(m_data.m_backingStoreSize.height()) * m_data.m_bytesPerRow;
</ins><span class="cx">     if (numBytes.hasOverflowed())
</span><span class="cx">         return;
</span><span class="cx"> 
</span><span class="lines">@@ -148,20 +156,21 @@
</span><span class="cx">     RetainPtr&lt;CGContextRef&gt; cgContext;
</span><span class="cx">     if (accelerateRendering) {
</span><span class="cx"> #if USE(IOSURFACE_CANVAS_BACKING_STORE)
</span><del>-        m_data.m_surface = createIOSurface(m_size);
-        cgContext = adoptCF(wkIOSurfaceContextCreate(m_data.m_surface.get(), width.unsafeGet(), height.unsafeGet(), m_data.m_colorSpace));
</del><ins>+        m_data.m_surface = createIOSurface(m_data.m_backingStoreSize);
+        FloatSize userBounds = scaleSizeToUserSpace(FloatSize(width.unsafeGet(), height.unsafeGet()), m_data.m_backingStoreSize, m_size);
+        cgContext = adoptCF(wkIOSurfaceContextCreate(m_data.m_surface.get(), userBounds.width(), userBounds.height(), m_data.m_colorSpace));
</ins><span class="cx"> #endif
</span><span class="cx">         if (!cgContext)
</span><span class="cx">             accelerateRendering = false; // If allocation fails, fall back to non-accelerated path.
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     if (!accelerateRendering) {
</span><del>-        if (!tryFastCalloc(height.unsafeGet(), m_data.m_bytesPerRow.unsafeGet()).getValue(m_data.m_data))
</del><ins>+        if (!tryFastCalloc(m_data.m_backingStoreSize.height(), m_data.m_bytesPerRow.unsafeGet()).getValue(m_data.m_data))
</ins><span class="cx">             return;
</span><span class="cx">         ASSERT(!(reinterpret_cast&lt;intptr_t&gt;(m_data.m_data) &amp; 3));
</span><span class="cx"> 
</span><span class="cx">         m_data.m_bitmapInfo = kCGImageAlphaPremultipliedLast;
</span><del>-        cgContext = adoptCF(CGBitmapContextCreate(m_data.m_data, width.unsafeGet(), height.unsafeGet(), 8, m_data.m_bytesPerRow.unsafeGet(), m_data.m_colorSpace, m_data.m_bitmapInfo));
</del><ins>+        cgContext = adoptCF(CGBitmapContextCreate(m_data.m_data, m_data.m_backingStoreSize.width(), m_data.m_backingStoreSize.height(), 8, m_data.m_bytesPerRow.unsafeGet(), m_data.m_colorSpace, m_data.m_bitmapInfo));
</ins><span class="cx">         // Create a live image that wraps the data.
</span><span class="cx">         m_data.m_dataProvider = adoptCF(CGDataProviderCreateWithData(0, m_data.m_data, numBytes.unsafeGet(), releaseImageData));
</span><span class="cx">     }
</span><span class="lines">@@ -170,9 +179,9 @@
</span><span class="cx">         return;
</span><span class="cx"> 
</span><span class="cx">     m_context = adoptPtr(new GraphicsContext(cgContext.get()));
</span><ins>+    m_context-&gt;scale(FloatSize(1, -1));
+    m_context-&gt;translate(0, -m_data.m_backingStoreSize.height());
</ins><span class="cx">     m_context-&gt;applyDeviceScaleFactor(m_resolutionScale);
</span><del>-    m_context-&gt;scale(FloatSize(1, -1));
-    m_context-&gt;translate(0, -size.height());
</del><span class="cx">     m_context-&gt;setIsAcceleratedContext(accelerateRendering);
</span><span class="cx">     success = true;
</span><span class="cx"> }
</span><span class="lines">@@ -191,6 +200,15 @@
</span><span class="cx">     CGContextFlush(m_context-&gt;platformContext());
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+static RetainPtr&lt;CGImageRef&gt; createCroppedImageIfNecessary(CGImageRef image, const IntSize&amp; bounds)
+{
+    if (image &amp;&amp; (CGImageGetWidth(image) != static_cast&lt;size_t&gt;(bounds.width())
+        || CGImageGetHeight(image) != static_cast&lt;size_t&gt;(bounds.height()))) {
+        return adoptCF(CGImageCreateWithImageInRect(image, CGRectMake(0, static_cast&lt;int&gt;(CGImageGetHeight(image)) - bounds.height(), bounds.width(), bounds.height())));
+    }
+    return image;
+}
+
</ins><span class="cx"> PassRefPtr&lt;Image&gt; ImageBuffer::copyImage(BackingStoreCopy copyBehavior, ScaleBehavior scaleBehavior) const
</span><span class="cx"> {
</span><span class="cx">     RetainPtr&lt;CGImageRef&gt; image;
</span><span class="lines">@@ -200,13 +218,18 @@
</span><span class="cx">         image = copyNativeImage(DontCopyBackingStore);
</span><span class="cx">         RetainPtr&lt;CGContextRef&gt; context = adoptCF(CGBitmapContextCreate(0, logicalSize().width(), logicalSize().height(), 8, 4 * logicalSize().width(), deviceRGBColorSpaceRef(), kCGImageAlphaPremultipliedLast));
</span><span class="cx">         CGContextSetBlendMode(context.get(), kCGBlendModeCopy);
</span><del>-        CGContextDrawImage(context.get(), CGRectMake(0, 0, logicalSize().width(), logicalSize().height()), image.get());
</del><ins>+        CGContextDrawImage(context.get(), CGRectMake(0, 0, m_data.m_backingStoreSize.width(), m_data.m_backingStoreSize.height()), image.get());
</ins><span class="cx">         image = adoptCF(CGBitmapContextCreateImage(context.get()));
</span><span class="cx">     }
</span><ins>+    
+    image = createCroppedImageIfNecessary(image.get(), internalSize());
</ins><span class="cx"> 
</span><span class="cx">     if (!image)
</span><span class="cx">         return 0;
</span><span class="cx"> 
</span><ins>+    ASSERT(CGImageGetWidth(image.get()) == static_cast&lt;size_t&gt;(m_logicalSize.width()));
+    ASSERT(CGImageGetHeight(image.get()) == static_cast&lt;size_t&gt;(m_logicalSize.height()));
+
</ins><span class="cx">     RefPtr&lt;BitmapImage&gt; bitmapImage = BitmapImage::create(image.get());
</span><span class="cx">     bitmapImage-&gt;setSpaceSize(spaceSize());
</span><span class="cx"> 
</span><span class="lines">@@ -224,7 +247,7 @@
</span><span class="cx">     if (!m_context-&gt;isAcceleratedContext()) {
</span><span class="cx">         switch (copyBehavior) {
</span><span class="cx">         case DontCopyBackingStore:
</span><del>-            image = CGImageCreate(internalSize().width(), internalSize().height(), 8, 32, m_data.m_bytesPerRow.unsafeGet(), m_data.m_colorSpace, m_data.m_bitmapInfo, m_data.m_dataProvider.get(), 0, true, kCGRenderingIntentDefault);
</del><ins>+            image = CGImageCreate(m_data.m_backingStoreSize.width(), m_data.m_backingStoreSize.height(), 8, 32, m_data.m_bytesPerRow.unsafeGet(), m_data.m_colorSpace, m_data.m_bitmapInfo, m_data.m_dataProvider.get(), 0, true, kCGRenderingIntentDefault);
</ins><span class="cx">             break;
</span><span class="cx">         case CopyBackingStore:
</span><span class="cx">             image = CGBitmapContextCreateImage(context()-&gt;platformContext());
</span><span class="lines">@@ -279,12 +302,15 @@
</span><span class="cx"> 
</span><span class="cx"> void ImageBuffer::clip(GraphicsContext* contextToClip, const FloatRect&amp; rect) const
</span><span class="cx"> {
</span><ins>+    FloatSize backingStoreSizeInUserSpace = scaleSizeToUserSpace(rect.size(), m_data.m_backingStoreSize, internalSize());
+
</ins><span class="cx">     CGContextRef platformContextToClip = contextToClip-&gt;platformContext();
</span><span class="cx">     // FIXME: This image needs to be grayscale to be used as an alpha mask here.
</span><span class="cx">     RetainPtr&lt;CGImageRef&gt; image = copyNativeImage(DontCopyBackingStore);
</span><del>-    CGContextTranslateCTM(platformContextToClip, rect.x(), rect.y() + rect.height());
</del><ins>+    CGContextTranslateCTM(platformContextToClip, rect.x(), rect.y() + backingStoreSizeInUserSpace.height());
</ins><span class="cx">     CGContextScaleCTM(platformContextToClip, 1, -1);
</span><del>-    CGContextClipToMask(platformContextToClip, FloatRect(FloatPoint(), rect.size()), image.get());
</del><ins>+    CGContextClipToRect(platformContextToClip, FloatRect(FloatPoint(0, backingStoreSizeInUserSpace.height() - rect.height()), rect.size()));
+    CGContextClipToMask(platformContextToClip, FloatRect(FloatPoint(), backingStoreSizeInUserSpace), image.get());
</ins><span class="cx">     CGContextScaleCTM(platformContextToClip, 1, -1);
</span><span class="cx">     CGContextTranslateCTM(platformContextToClip, -rect.x(), -rect.y() - rect.height());
</span><span class="cx"> }
</span><span class="lines">@@ -335,10 +361,14 @@
</span><span class="cx">     CGContextSetShadowWithColor(destContext, CGSizeZero, 0, 0);
</span><span class="cx"> 
</span><span class="cx">     // Draw the image in CG coordinate space
</span><del>-    IntPoint destPointInCGCoords(destPoint.x() + sourceRect.x(), (coordinateSystem == LogicalCoordinateSystem ? logicalSize() : internalSize()).height() - (destPoint.y() + sourceRect.y()) - sourceRect.height());
</del><ins>+    FloatSize scaledDestSize = scaleSizeToUserSpace(coordinateSystem == LogicalCoordinateSystem ? logicalSize() : internalSize(), m_data.m_backingStoreSize, internalSize());
+    IntPoint destPointInCGCoords(destPoint.x() + sourceRect.x(), scaledDestSize.height() - (destPoint.y() + sourceRect.y()) - sourceRect.height());
</ins><span class="cx">     IntRect destRectInCGCoords(destPointInCGCoords, sourceCopySize);
</span><ins>+    CGContextClipToRect(destContext, destRectInCGCoords);
+
</ins><span class="cx">     RetainPtr&lt;CGImageRef&gt; sourceCopyImage = sourceCopy-&gt;copyNativeImage();
</span><del>-    CGContextDrawImage(destContext, destRectInCGCoords, sourceCopyImage.get());
</del><ins>+    FloatRect backingStoreInDestRect = FloatRect(FloatPoint(destPointInCGCoords.x(), destPointInCGCoords.y() + sourceCopySize.height() - (int)CGImageGetHeight(sourceCopyImage.get())), FloatSize(CGImageGetWidth(sourceCopyImage.get()), CGImageGetHeight(sourceCopyImage.get())));
+    CGContextDrawImage(destContext, backingStoreInDestRect, sourceCopyImage.get());
</ins><span class="cx">     CGContextRestoreGState(destContext);
</span><span class="cx"> #endif
</span><span class="cx"> }
</span><span class="lines">@@ -442,13 +472,16 @@
</span><span class="cx">         image = adoptCF(CGImageCreate(logicalSize().width(), logicalSize().height(), 8, 32, 4 * logicalSize().width(),
</span><span class="cx">                                     deviceRGBColorSpaceRef(), kCGBitmapByteOrderDefault | kCGImageAlphaNoneSkipLast,
</span><span class="cx">                                     dataProvider.get(), 0, false, kCGRenderingIntentDefault));
</span><del>-    } else if (m_resolutionScale == 1)
</del><ins>+    } else if (m_resolutionScale == 1) {
</ins><span class="cx">         image = copyNativeImage(CopyBackingStore);
</span><del>-    else {
</del><ins>+        image = createCroppedImageIfNecessary(image.get(), internalSize());
+    } else {
</ins><span class="cx">         image = copyNativeImage(DontCopyBackingStore);
</span><span class="cx">         RetainPtr&lt;CGContextRef&gt; context = adoptCF(CGBitmapContextCreate(0, logicalSize().width(), logicalSize().height(), 8, 4 * logicalSize().width(), deviceRGBColorSpaceRef(), kCGImageAlphaPremultipliedLast));
</span><span class="cx">         CGContextSetBlendMode(context.get(), kCGBlendModeCopy);
</span><del>-        CGContextDrawImage(context.get(), CGRectMake(0, 0, logicalSize().width(), logicalSize().height()), image.get());
</del><ins>+        CGContextClipToRect(context.get(), CGRectMake(0, 0, logicalSize().width(), logicalSize().height()));
+        FloatSize imageRectInUserBounds = scaleSizeToUserSpace(logicalSize(), m_data.m_backingStoreSize, internalSize());
+        CGContextDrawImage(context.get(), CGRectMake(0, 0, imageRectInUserBounds.width(), imageRectInUserBounds.height()), image.get());
</ins><span class="cx">         image = adoptCF(CGBitmapContextCreateImage(context.get()));
</span><span class="cx">     }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicscgImageBufferDataCGcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/cg/ImageBufferDataCG.cpp (160120 => 160121)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/cg/ImageBufferDataCG.cpp        2013-12-04 21:29:45 UTC (rev 160120)
+++ trunk/Source/WebCore/platform/graphics/cg/ImageBufferDataCG.cpp        2013-12-04 21:35:38 UTC (rev 160121)
</span><span class="lines">@@ -158,7 +158,7 @@
</span><span class="cx">     unsigned char* srcRows;
</span><span class="cx">     
</span><span class="cx">     if (!accelerateRendering) {
</span><del>-        srcBytesPerRow = 4 * size.width();
</del><ins>+        srcBytesPerRow = m_bytesPerRow.unsafeGet();
</ins><span class="cx">         srcRows = reinterpret_cast&lt;unsigned char*&gt;(m_data) + originy * srcBytesPerRow + originx * 4;
</span><span class="cx">         
</span><span class="cx"> #if USE(ACCELERATE)
</span><span class="lines">@@ -339,6 +339,10 @@
</span><span class="cx"> 
</span><span class="cx"> void ImageBufferData::putData(Uint8ClampedArray*&amp; source, const IntSize&amp; sourceSize, const IntRect&amp; sourceRect, const IntPoint&amp; destPoint, const IntSize&amp; size, bool accelerateRendering, bool unmultiplied, float resolutionScale)
</span><span class="cx"> {
</span><ins>+#if ASSERT_DISABLED
+    UNUSED_PARAM(size);
+#endif
+
</ins><span class="cx">     ASSERT(sourceRect.width() &gt; 0);
</span><span class="cx">     ASSERT(sourceRect.height() &gt; 0);
</span><span class="cx">     
</span><span class="lines">@@ -381,7 +385,7 @@
</span><span class="cx">     unsigned char* destRows;
</span><span class="cx">     
</span><span class="cx">     if (!accelerateRendering) {
</span><del>-        destBytesPerRow = 4 * size.width();
</del><ins>+        destBytesPerRow = m_bytesPerRow.unsafeGet();
</ins><span class="cx">         destRows = reinterpret_cast&lt;unsigned char*&gt;(m_data) + (desty * destBytesPerRow + destx * 4).unsafeGet();
</span><span class="cx">         
</span><span class="cx"> #if  USE(ACCELERATE)
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicscgImageBufferDataCGh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/cg/ImageBufferDataCG.h (160120 => 160121)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/cg/ImageBufferDataCG.h        2013-12-04 21:29:45 UTC (rev 160120)
+++ trunk/Source/WebCore/platform/graphics/cg/ImageBufferDataCG.h        2013-12-04 21:35:38 UTC (rev 160121)
</span><span class="lines">@@ -54,6 +54,7 @@
</span><span class="cx">     Checked&lt;unsigned, RecordOverflow&gt; m_bytesPerRow;
</span><span class="cx">     CGColorSpaceRef m_colorSpace;
</span><span class="cx">     RetainPtr&lt;IOSurfaceRef&gt; m_surface;
</span><ins>+    IntSize m_backingStoreSize;
</ins><span class="cx"> 
</span><span class="cx">     PassRefPtr&lt;Uint8ClampedArray&gt; getData(const IntRect&amp;, const IntSize&amp;, bool accelerateRendering, bool unmultiplied, float resolutionScale) const;
</span><span class="cx">     void putData(Uint8ClampedArray*&amp; source, const IntSize&amp; sourceSize, const IntRect&amp; sourceRect, const IntPoint&amp; destPoint, const IntSize&amp;, bool accelerateRendering, bool unmultiplied, float resolutionScale);
</span></span></pre>
</div>
</div>

</body>
</html>