<!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>[244913] 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/244913">244913</a></dd>
<dt>Author</dt> <dd>commit-queue@webkit.org</dd>
<dt>Date</dt> <dd>2019-05-03 11:31:06 -0700 (Fri, 03 May 2019)</dd>
</dl>

<h3>Log Message</h3>
<pre>[Cairo] Improve ShadowBlur performance using tiling optimization
https://bugs.webkit.org/show_bug.cgi?id=197308
Patch by Tomoki Imai <Tomoki.Imai@sony.com> on 2019-05-03
Reviewed by Žan Doberšek.

Enable tiling tiling-based optimization for drawRectShadow() and drawInsetShadow().
Since <a href="http://trac.webkit.org/projects/webkit/changeset/228776">r228776</a>, cairo ports doesn't have tiling-based optimization.

For AppleWin, this patch refactors code and it shares almost same code as cairo port.
Only the difference is that AppleWin uses ScratchBuffer, but cairo ports doesn't.
This should avoid a performance regression for AppleWin.

No new tests, covered by existing tests.

* platform/graphics/ShadowBlur.cpp:
(WebCore::calculateLobes):
Fix stylecheck errors

(WebCore::ShadowBlur::blurLayerImage):
Fix stylecheck errors

(WebCore::ShadowBlur::calculateLayerBoundingRect):
We don't use position of m_sourceRect, so change the type to FloatSize.

(WebCore::ShadowBlur::drawShadowBuffer):
Use m_layerSize instead of m_shadowedResultSize to fillRect, as m_layerSize is always smaller than m_shadowedResultSize.
It's because in m_layerSize is equal to m_shadowedResultSize if it's not clipped.
Clipping doesn't increase size of m_layerSize, so m_layerSize is always smaller than or equal to m_shadowedResultSize.

(WebCore::ShadowBlur::templateSize const):
Fix stylecheck errors

(WebCore::ShadowBlur::drawRectShadow):
(WebCore::ShadowBlur::drawInsetShadow):
(WebCore::ShadowBlur::drawRectShadowWithoutTiling):
(WebCore::ShadowBlur::drawInsetShadowWithoutTiling):
(WebCore::ShadowBlur::drawRectShadowWithTiling):
(WebCore::ShadowBlur::drawInsetShadowWithTiling):
Incorporate tile-based drawing.
To accomplish it, this patch abstracts GraphicsContext::drawImageBuffer to ShadowBlur::DrawImageCallback,
GraphicsContext::fillRect to ShadowBlur::FillRectCallback, drawing rect with hole to  ShadowBlur::FillRectWithHoleCallback.

Variants which takes GraphicsContext as parameter now just calls another drawRectShadow.

(WebCore::ShadowBlur::drawLayerPieces):
Instead of graphicsContext.drawImageBuffer, call corresponding callback.

(WebCore::ShadowBlur::drawLayerPiecesAndFillCenter):
This function calls drawLayerPieces and fill center for outer shadow.
Drawing outer shadow requires another callback for graphicsContext.fillRect.

(WebCore::ShadowBlur::drawShadowLayer):
Use m_layerSize instead of m_shadowedResultSize to fillRect,
as m_layerSize is always smaller than m_shadowedResultSize.

* platform/graphics/ShadowBlur.h:
Rename m_sourceRect to m_shadowedResultSize, and change it to FloatSize from FloatRect.
Remove GraphicsContext usage as much as possible and replace them by corresponding callbacks.

* platform/graphics/cairo/CairoOperations.cpp:
(WebCore::Cairo::drawShadowImage):
This function corresponds to ShadowBlur::DrawImageCallback.

(WebCore::Cairo::fillShadowBuffer):
Erase sourceRect, as it's always bigger than layerSize.

(WebCore::Cairo::drawPathShadow):
(WebCore::Cairo::drawGlyphsShadow):
Erase unused parameter.

(WebCore::Cairo::fillRect):
(WebCore::Cairo::fillRoundedRect):
(WebCore::Cairo::fillRectWithRoundedHole):
For tile-based optimization, add extra arguments to drawRectShadow.

(WebCore::Cairo::drawSurface):
Erase unused parameter.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicsShadowBlurcpp">trunk/Source/WebCore/platform/graphics/ShadowBlur.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicsShadowBlurh">trunk/Source/WebCore/platform/graphics/ShadowBlur.h</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicscairoCairoOperationscpp">trunk/Source/WebCore/platform/graphics/cairo/CairoOperations.cpp</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (244912 => 244913)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog   2019-05-03 18:18:12 UTC (rev 244912)
+++ trunk/Source/WebCore/ChangeLog      2019-05-03 18:31:06 UTC (rev 244913)
</span><span class="lines">@@ -1,3 +1,82 @@
</span><ins>+2019-05-03  Tomoki Imai  <Tomoki.Imai@sony.com>
+
+        [Cairo] Improve ShadowBlur performance using tiling optimization
+        https://bugs.webkit.org/show_bug.cgi?id=197308
+        Reviewed by Žan Doberšek.
+
+        Enable tiling tiling-based optimization for drawRectShadow() and drawInsetShadow().
+        Since r228776, cairo ports doesn't have tiling-based optimization.
+
+        For AppleWin, this patch refactors code and it shares almost same code as cairo port.
+        Only the difference is that AppleWin uses ScratchBuffer, but cairo ports doesn't.
+        This should avoid a performance regression for AppleWin.
+
+        No new tests, covered by existing tests.
+
+        * platform/graphics/ShadowBlur.cpp:
+        (WebCore::calculateLobes):
+        Fix stylecheck errors
+
+        (WebCore::ShadowBlur::blurLayerImage):
+        Fix stylecheck errors
+
+        (WebCore::ShadowBlur::calculateLayerBoundingRect):
+        We don't use position of m_sourceRect, so change the type to FloatSize.
+
+        (WebCore::ShadowBlur::drawShadowBuffer):
+        Use m_layerSize instead of m_shadowedResultSize to fillRect, as m_layerSize is always smaller than m_shadowedResultSize.
+        It's because in m_layerSize is equal to m_shadowedResultSize if it's not clipped.
+        Clipping doesn't increase size of m_layerSize, so m_layerSize is always smaller than or equal to m_shadowedResultSize.
+
+        (WebCore::ShadowBlur::templateSize const):
+        Fix stylecheck errors
+
+        (WebCore::ShadowBlur::drawRectShadow):
+        (WebCore::ShadowBlur::drawInsetShadow):
+        (WebCore::ShadowBlur::drawRectShadowWithoutTiling):
+        (WebCore::ShadowBlur::drawInsetShadowWithoutTiling):
+        (WebCore::ShadowBlur::drawRectShadowWithTiling):
+        (WebCore::ShadowBlur::drawInsetShadowWithTiling):
+        Incorporate tile-based drawing.
+        To accomplish it, this patch abstracts GraphicsContext::drawImageBuffer to ShadowBlur::DrawImageCallback,
+        GraphicsContext::fillRect to ShadowBlur::FillRectCallback, drawing rect with hole to  ShadowBlur::FillRectWithHoleCallback.
+
+        Variants which takes GraphicsContext as parameter now just calls another drawRectShadow.
+
+        (WebCore::ShadowBlur::drawLayerPieces):
+        Instead of graphicsContext.drawImageBuffer, call corresponding callback.
+
+        (WebCore::ShadowBlur::drawLayerPiecesAndFillCenter):
+        This function calls drawLayerPieces and fill center for outer shadow.
+        Drawing outer shadow requires another callback for graphicsContext.fillRect.
+
+        (WebCore::ShadowBlur::drawShadowLayer):
+        Use m_layerSize instead of m_shadowedResultSize to fillRect,
+        as m_layerSize is always smaller than m_shadowedResultSize.
+
+        * platform/graphics/ShadowBlur.h:
+        Rename m_sourceRect to m_shadowedResultSize, and change it to FloatSize from FloatRect.
+        Remove GraphicsContext usage as much as possible and replace them by corresponding callbacks.
+
+        * platform/graphics/cairo/CairoOperations.cpp:
+        (WebCore::Cairo::drawShadowImage):
+        This function corresponds to ShadowBlur::DrawImageCallback.
+
+        (WebCore::Cairo::fillShadowBuffer):
+        Erase sourceRect, as it's always bigger than layerSize.
+
+        (WebCore::Cairo::drawPathShadow):
+        (WebCore::Cairo::drawGlyphsShadow):
+        Erase unused parameter.
+
+        (WebCore::Cairo::fillRect):
+        (WebCore::Cairo::fillRoundedRect):
+        (WebCore::Cairo::fillRectWithRoundedHole):
+        For tile-based optimization, add extra arguments to drawRectShadow.
+
+        (WebCore::Cairo::drawSurface):
+        Erase unused parameter.
+
</ins><span class="cx"> 2019-05-03  Antti Koivisto  <antti@apple.com>
</span><span class="cx"> 
</span><span class="cx">         Add a quirk to make youtube navigation bar scrollable without mouse hover on iOS
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsShadowBlurcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/ShadowBlur.cpp (244912 => 244913)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/ShadowBlur.cpp    2019-05-03 18:18:12 UTC (rev 244912)
+++ trunk/Source/WebCore/platform/graphics/ShadowBlur.cpp       2019-05-03 18:31:06 UTC (rev 244913)
</span><span class="lines">@@ -24,7 +24,7 @@
</span><span class="cx">  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
</span><span class="cx">  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
</span><span class="cx">  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
</span><del>- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
</del><ins>+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
</ins><span class="cx">  */
</span><span class="cx"> 
</span><span class="cx"> #include "config.h"
</span><span class="lines">@@ -42,10 +42,11 @@
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><span class="cx"> enum {
</span><del>-    leftLobe = 0,
-    rightLobe = 1
</del><ins>+    LeftLobe = 0,
+    RightLobe = 1
</ins><span class="cx"> };
</span><span class="cx"> 
</span><ins>+#if USE(CG)
</ins><span class="cx"> static inline int roundUpToMultipleOf32(int d)
</span><span class="cx"> {
</span><span class="cx">     return (1 + (d >> 5)) << 5;
</span><span class="lines">@@ -65,7 +66,7 @@
</span><span class="cx"> #endif
</span><span class="cx">     {
</span><span class="cx">     }
</span><del>-    
</del><ins>+
</ins><span class="cx">     ImageBuffer* getScratchBuffer(const IntSize& size)
</span><span class="cx">     {
</span><span class="cx">         ASSERT(!m_bufferInUse);
</span><span class="lines">@@ -127,7 +128,7 @@
</span><span class="cx">         const Seconds scratchBufferPurgeInterval { 2_s };
</span><span class="cx">         m_purgeTimer.startOneShot(scratchBufferPurgeInterval);
</span><span class="cx">     }
</span><del>-    
</del><ins>+
</ins><span class="cx">     static ScratchBuffer& singleton();
</span><span class="cx"> 
</span><span class="cx"> private:
</span><span class="lines">@@ -140,7 +141,7 @@
</span><span class="cx"> 
</span><span class="cx">     std::unique_ptr<ImageBuffer> m_imageBuffer;
</span><span class="cx">     Timer m_purgeTimer;
</span><del>-    
</del><ins>+
</ins><span class="cx">     FloatRect m_lastInsetBounds;
</span><span class="cx">     FloatRect m_lastShadowRect;
</span><span class="cx">     FloatRoundedRect::Radii m_lastRadii;
</span><span class="lines">@@ -148,7 +149,7 @@
</span><span class="cx">     FloatSize m_lastRadius;
</span><span class="cx">     bool m_lastWasInset;
</span><span class="cx">     FloatSize m_lastLayerSize;
</span><del>-    
</del><ins>+
</ins><span class="cx"> #if !ASSERT_DISABLED
</span><span class="cx">     bool m_bufferInUse;
</span><span class="cx"> #endif
</span><span class="lines">@@ -160,9 +161,6 @@
</span><span class="cx">     return scratchBuffer;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static const int templateSideLength = 1;
-
-#if USE(CG)
</del><span class="cx"> static float radiusToLegacyRadius(float radius)
</span><span class="cx"> {
</span><span class="cx">     return radius > 8 ? 8 + 4 * sqrt((radius - 8) / 2) : radius;
</span><span class="lines">@@ -169,6 +167,8 @@
</span><span class="cx"> }
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><ins>+static const int templateSideLength = 1;
+
</ins><span class="cx"> ShadowBlur::ShadowBlur() = default;
</span><span class="cx"> 
</span><span class="cx"> ShadowBlur::ShadowBlur(const FloatSize& radius, const FloatSize& offset, const Color& color, bool shadowsIgnoreTransforms)
</span><span class="lines">@@ -249,23 +249,23 @@
</span><span class="cx">     if (diameter & 1) {
</span><span class="cx">         // if d is odd, use three box-blurs of size 'd', centered on the output pixel.
</span><span class="cx">         int lobeSize = (diameter - 1) / 2;
</span><del>-        lobes[0][leftLobe] = lobeSize;
-        lobes[0][rightLobe] = lobeSize;
-        lobes[1][leftLobe] = lobeSize;
-        lobes[1][rightLobe] = lobeSize;
-        lobes[2][leftLobe] = lobeSize;
-        lobes[2][rightLobe] = lobeSize;
</del><ins>+        lobes[0][LeftLobe] = lobeSize;
+        lobes[0][RightLobe] = lobeSize;
+        lobes[1][LeftLobe] = lobeSize;
+        lobes[1][RightLobe] = lobeSize;
+        lobes[2][LeftLobe] = lobeSize;
+        lobes[2][RightLobe] = lobeSize;
</ins><span class="cx">     } else {
</span><span class="cx">         // if d is even, two box-blurs of size 'd' (the first one centered on the pixel boundary
</span><span class="cx">         // between the output pixel and the one to the left, the second one centered on the pixel
</span><span class="cx">         // boundary between the output pixel and the one to the right) and one box blur of size 'd+1' centered on the output pixel
</span><span class="cx">         int lobeSize = diameter / 2;
</span><del>-        lobes[0][leftLobe] = lobeSize;
-        lobes[0][rightLobe] = lobeSize - 1;
-        lobes[1][leftLobe] = lobeSize - 1;
-        lobes[1][rightLobe] = lobeSize;
-        lobes[2][leftLobe] = lobeSize;
-        lobes[2][rightLobe] = lobeSize;
</del><ins>+        lobes[0][LeftLobe] = lobeSize;
+        lobes[0][RightLobe] = lobeSize - 1;
+        lobes[1][LeftLobe] = lobeSize - 1;
+        lobes[1][RightLobe] = lobeSize;
+        lobes[2][LeftLobe] = lobeSize;
+        lobes[2][RightLobe] = lobeSize;
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -293,7 +293,7 @@
</span><span class="cx">     // Two stages: horizontal and vertical
</span><span class="cx">     for (int pass = 0; pass < 2; ++pass) {
</span><span class="cx">         unsigned char* pixels = imageData;
</span><del>-        
</del><ins>+
</ins><span class="cx">         if (!pass && !m_blurRadius.width())
</span><span class="cx">             final = 0; // Do no work if horizonal blur is zero.
</span><span class="cx"> 
</span><span class="lines">@@ -304,8 +304,8 @@
</span><span class="cx">             // This is much more efficient than computing the sum of each pixels
</span><span class="cx">             // covered by the box kernel size for each x.
</span><span class="cx">             for (int step = 0; step < 3; ++step) {
</span><del>-                int side1 = lobes[step][leftLobe];
-                int side2 = lobes[step][rightLobe];
</del><ins>+                int side1 = lobes[step][LeftLobe];
+                int side2 = lobes[step][RightLobe];
</ins><span class="cx">                 int pixelCount = side1 + 1 + side2;
</span><span class="cx">                 int invCount = ((1 << blurSumShift) + pixelCount - 1) / pixelCount;
</span><span class="cx">                 int ofs = 1 + side2;
</span><span class="lines">@@ -331,13 +331,13 @@
</span><span class="cx">                     *ptr = (sum * invCount) >> blurSumShift;
</span><span class="cx">                     sum += ((ofs < dim) ? *next : alpha2) - alpha1;
</span><span class="cx">                 }
</span><del>-                
</del><ins>+
</ins><span class="cx">                 prev = pixels + channels[step];
</span><span class="cx">                 for (; ofs < dim; ptr += stride, prev += stride, next += stride, ++i, ++ofs) {
</span><span class="cx">                     *ptr = (sum * invCount) >> blurSumShift;
</span><span class="cx">                     sum += (*next) - (*prev);
</span><span class="cx">                 }
</span><del>-                
</del><ins>+
</ins><span class="cx">                 for (; i < dim; ptr += stride, prev += stride, ++i) {
</span><span class="cx">                     *ptr = (sum * invCount) >> blurSumShift;
</span><span class="cx">                     sum += alpha2 - (*prev);
</span><span class="lines">@@ -422,13 +422,13 @@
</span><span class="cx">             inflatedClip.inflateX(1);
</span><span class="cx">             inflatedClip.inflateY(1);
</span><span class="cx">         }
</span><del>-        
</del><ins>+
</ins><span class="cx">         layerRect.intersect(inflatedClip);
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     IntSize frameSize = inflation;
</span><span class="cx">     frameSize.scale(2);
</span><del>-    m_sourceRect = FloatRect(0, 0, shadowedRect.width() + frameSize.width(), shadowedRect.height() + frameSize.height());
</del><ins>+    m_shadowedResultSize = FloatSize(shadowedRect.width() + frameSize.width(), shadowedRect.height() + frameSize.height());
</ins><span class="cx">     m_layerOrigin = FloatPoint(layerRect.x(), layerRect.y());
</span><span class="cx">     m_layerSize = layerRect.size();
</span><span class="cx"> 
</span><span class="lines">@@ -461,7 +461,7 @@
</span><span class="cx">     graphicsContext.setFillColor(m_color);
</span><span class="cx"> 
</span><span class="cx">     graphicsContext.clearShadow();
</span><del>-    graphicsContext.fillRect(FloatRect(m_layerOrigin, m_sourceRect.size()));
</del><ins>+    graphicsContext.fillRect(FloatRect(m_layerOrigin, m_layerSize));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> static void computeSliceSizesFromRadii(const IntSize& twiceRadius, const FloatRoundedRect::Radii& radii, int& leftSlice, int& rightSlice, int& topSlice, int& bottomSlice)
</span><span class="lines">@@ -481,30 +481,76 @@
</span><span class="cx">     int rightSlice;
</span><span class="cx">     int topSlice;
</span><span class="cx">     int bottomSlice;
</span><del>-    
</del><ins>+
</ins><span class="cx">     IntSize blurExpansion = radiusPadding;
</span><span class="cx">     blurExpansion.scale(2);
</span><span class="cx"> 
</span><span class="cx">     computeSliceSizesFromRadii(blurExpansion, radii, leftSlice, rightSlice, topSlice, bottomSlice);
</span><del>-    
-    return IntSize(templateSideLength + leftSlice + rightSlice,
-                   templateSideLength + topSlice + bottomSlice);
</del><ins>+
+    return IntSize(templateSideLength + leftSlice + rightSlice, templateSideLength + topSlice + bottomSlice);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void ShadowBlur::drawRectShadow(GraphicsContext& graphicsContext, const FloatRoundedRect& shadowedRect)
</span><span class="cx"> {
</span><del>-    IntSize layerSize = calculateLayerBoundingRect(graphicsContext.getCTM(), shadowedRect.rect(), graphicsContext.clipBounds());
</del><ins>+    drawRectShadow(graphicsContext.getCTM(), graphicsContext.clipBounds(), shadowedRect,
+        [this, &graphicsContext](ImageBuffer&, const FloatPoint&, const FloatSize&) {
+            // FIXME: Use parameters instead of implicit parameters defined as class variables.
+            drawShadowBuffer(graphicsContext);
+        },
+        [&graphicsContext](ImageBuffer& image, const FloatRect& destRect, const FloatRect& srcRect) {
+            GraphicsContextStateSaver stateSaver(graphicsContext);
+            graphicsContext.clearShadow();
+            graphicsContext.drawImageBuffer(image, destRect, srcRect);
+        },
+        [&graphicsContext](const FloatRect& rect, const Color& color) {
+            GraphicsContextStateSaver stateSaver(graphicsContext);
+            graphicsContext.setFillColor(color);
+            graphicsContext.clearShadow();
+            graphicsContext.fillRect(rect);
+        });
+}
+
+void ShadowBlur::drawInsetShadow(GraphicsContext& graphicsContext, const FloatRect& fullRect, const FloatRoundedRect& holeRect)
+{
+    drawInsetShadow(graphicsContext.getCTM(), graphicsContext.clipBounds(), fullRect, holeRect,
+        [this, &graphicsContext](ImageBuffer&, const FloatPoint&, const FloatSize&) {
+            // FIXME: Use parameters instead of implicit parameters defined as class variables.
+            drawShadowBuffer(graphicsContext);
+        },
+        [&graphicsContext](ImageBuffer& image, const FloatRect& destRect, const FloatRect& srcRect) {
+            // Note that drawing the ImageBuffer is faster than creating a Image and drawing that,
+            // because ImageBuffer::draw() knows that it doesn't have to copy the image bits.
+            GraphicsContextStateSaver stateSaver(graphicsContext);
+            graphicsContext.clearShadow();
+            graphicsContext.drawImageBuffer(image, destRect, srcRect);
+        },
+        [&graphicsContext](const FloatRect& rect, const FloatRect& holeRect, const Color& color) {
+            Path exteriorPath;
+            exteriorPath.addRect(rect);
+            exteriorPath.addRect(holeRect);
+
+            GraphicsContextStateSaver fillStateSaver(graphicsContext);
+            graphicsContext.setFillRule(WindRule::EvenOdd);
+            graphicsContext.setFillColor(color);
+            graphicsContext.clearShadow();
+            graphicsContext.fillPath(exteriorPath);
+        });
+}
+
+void ShadowBlur::drawRectShadow(const AffineTransform& transform, const IntRect& clipBounds, const FloatRoundedRect& shadowedRect, const DrawBufferCallback& drawBuffer, const DrawImageCallback& drawImage, const FillRectCallback& fillRect)
+{
+    IntSize layerSize = calculateLayerBoundingRect(transform, shadowedRect.rect(), clipBounds);
</ins><span class="cx">     if (layerSize.isEmpty())
</span><span class="cx">         return;
</span><span class="cx"> 
</span><del>-    adjustBlurRadius(graphicsContext.getCTM());
</del><ins>+    adjustBlurRadius(transform);
</ins><span class="cx"> 
</span><ins>+    bool canUseTilingTechnique = true;
+
</ins><span class="cx">     // drawRectShadowWithTiling does not work with rotations.
</span><span class="cx">     // https://bugs.webkit.org/show_bug.cgi?id=45042
</span><del>-    if (!graphicsContext.getCTM().preservesAxisAlignment() || m_type != BlurShadow) {
-        drawRectShadowWithoutTiling(graphicsContext, shadowedRect, layerSize);
-        return;
-    }
</del><ins>+    if (!transform.preservesAxisAlignment() || m_type != BlurShadow)
+        canUseTilingTechnique = false;
</ins><span class="cx"> 
</span><span class="cx">     IntSize edgeSize = blurredEdgeSize();
</span><span class="cx">     IntSize templateSize = this->templateSize(edgeSize, shadowedRect.radii());
</span><span class="lines">@@ -511,28 +557,29 @@
</span><span class="cx">     const FloatRect& rect = shadowedRect.rect();
</span><span class="cx"> 
</span><span class="cx">     if (templateSize.width() > rect.width() || templateSize.height() > rect.height()
</span><del>-        || (templateSize.width() * templateSize.height() > m_sourceRect.width() * m_sourceRect.height())) {
-        drawRectShadowWithoutTiling(graphicsContext, shadowedRect, layerSize);
-        return;
-    }
</del><ins>+        || (templateSize.width() * templateSize.height() > m_shadowedResultSize.width() * m_shadowedResultSize.height()))
+        canUseTilingTechnique = false;
</ins><span class="cx"> 
</span><del>-    drawRectShadowWithTiling(graphicsContext, shadowedRect, templateSize, edgeSize);
</del><ins>+    if (canUseTilingTechnique)
+        drawRectShadowWithTiling(transform, shadowedRect, templateSize, edgeSize, drawImage, fillRect);
+    else
+        drawRectShadowWithoutTiling(transform, shadowedRect, layerSize, drawBuffer);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void ShadowBlur::drawInsetShadow(GraphicsContext& graphicsContext, const FloatRect& rect, const FloatRoundedRect& holeRect)
</del><ins>+void ShadowBlur::drawInsetShadow(const AffineTransform& transform, const IntRect& clipBounds, const FloatRect& fullRect, const FloatRoundedRect& holeRect, const DrawBufferCallback& drawBuffer, const DrawImageCallback& drawImage, const FillRectWithHoleCallback& fillRectWithHole)
</ins><span class="cx"> {
</span><del>-    IntSize layerSize = calculateLayerBoundingRect(graphicsContext.getCTM(), rect, graphicsContext.clipBounds());
</del><ins>+    IntSize layerSize = calculateLayerBoundingRect(transform, fullRect, clipBounds);
</ins><span class="cx">     if (layerSize.isEmpty())
</span><span class="cx">         return;
</span><span class="cx"> 
</span><del>-    adjustBlurRadius(graphicsContext.getCTM());
</del><ins>+    adjustBlurRadius(transform);
</ins><span class="cx"> 
</span><del>-    // drawInsetShadowWithTiling does not work with rotations.
</del><ins>+    bool canUseTilingTechnique = true;
+
+    // drawRectShadowWithTiling does not work with rotations.
</ins><span class="cx">     // https://bugs.webkit.org/show_bug.cgi?id=45042
</span><del>-    if (!graphicsContext.getCTM().preservesAxisAlignment() || m_type != BlurShadow) {
-        drawInsetShadowWithoutTiling(graphicsContext, rect, holeRect, layerSize);
-        return;
-    }
</del><ins>+    if (!transform.preservesAxisAlignment() || m_type != BlurShadow)
+        canUseTilingTechnique = false;
</ins><span class="cx"> 
</span><span class="cx">     IntSize edgeSize = blurredEdgeSize();
</span><span class="cx">     IntSize templateSize = this->templateSize(edgeSize, holeRect.radii());
</span><span class="lines">@@ -539,29 +586,26 @@
</span><span class="cx">     const FloatRect& hRect = holeRect.rect();
</span><span class="cx"> 
</span><span class="cx">     if (templateSize.width() > hRect.width() || templateSize.height() > hRect.height()
</span><del>-        || (templateSize.width() * templateSize.height() > hRect.width() * hRect.height())) {
-        drawInsetShadowWithoutTiling(graphicsContext, rect, holeRect, layerSize);
-        return;
-    }
</del><ins>+        || (templateSize.width() * templateSize.height() > hRect.width() * hRect.height()))
+        canUseTilingTechnique = false;
</ins><span class="cx"> 
</span><del>-    drawInsetShadowWithTiling(graphicsContext, rect, holeRect, templateSize, edgeSize);
</del><ins>+    if (canUseTilingTechnique)
+        drawInsetShadowWithTiling(transform, fullRect, holeRect, templateSize, edgeSize, drawImage, fillRectWithHole);
+    else
+        drawInsetShadowWithoutTiling(transform, fullRect, holeRect, layerSize, drawBuffer);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void ShadowBlur::drawRectShadow(const AffineTransform& transform, const IntRect& clipBounds, const FloatRoundedRect& shadowedRect, const DrawBufferCallback& drawBuffer)
</del><ins>+void ShadowBlur::drawRectShadowWithoutTiling(const AffineTransform&, const FloatRoundedRect& shadowedRect, const IntSize& layerSize, const DrawBufferCallback& drawBuffer)
</ins><span class="cx"> {
</span><del>-    // FIXME: Try incorporating tile-based rect shadow drawing for the same use case.
-
-    IntSize layerSize = calculateLayerBoundingRect(transform, shadowedRect.rect(), clipBounds);
-    if (layerSize.isEmpty())
-        return;
-
-    adjustBlurRadius(transform);
-
</del><span class="cx">     auto layerImage = ImageBuffer::create(layerSize, Unaccelerated, 1);
</span><span class="cx">     if (!layerImage)
</span><span class="cx">         return;
</span><span class="cx">     m_layerImage = layerImage.get();
</span><span class="cx"> 
</span><ins>+    GraphicsContext& shadowContext = layerImage->context();
+    GraphicsContextStateSaver stateSaver(shadowContext);
+    shadowContext.setFillColor(Color::black);
+
</ins><span class="cx">     {
</span><span class="cx">         GraphicsContext& shadowContext = layerImage->context();
</span><span class="cx">         GraphicsContextStateSaver stateSaver(shadowContext);
</span><span class="lines">@@ -577,20 +621,11 @@
</span><span class="cx"> 
</span><span class="cx">         blurShadowBuffer(layerSize);
</span><span class="cx">     }
</span><del>-
-    drawBuffer(*layerImage, m_layerOrigin, m_layerSize, m_sourceRect);
</del><ins>+    drawBuffer(*layerImage, m_layerOrigin, m_layerSize);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void ShadowBlur::drawInsetShadow(const AffineTransform& transform, const IntRect& clipBounds, const FloatRect& rect, const FloatRoundedRect& holeRect, const DrawBufferCallback& drawBuffer)
</del><ins>+void ShadowBlur::drawInsetShadowWithoutTiling(const AffineTransform&, const FloatRect& fullRect, const FloatRoundedRect& holeRect, const IntSize& layerSize, const DrawBufferCallback& drawBuffer)
</ins><span class="cx"> {
</span><del>-    // FIXME: Try incorporating tile-based inset shadow drawing for the same use case.
-
-    IntSize layerSize = calculateLayerBoundingRect(transform, rect, clipBounds);
-    if (layerSize.isEmpty())
-        return;
-
-    adjustBlurRadius(transform);
-
</del><span class="cx">     auto layerImage = ImageBuffer::create(layerSize, Unaccelerated, 1);
</span><span class="cx">     if (!layerImage)
</span><span class="cx">         return;
</span><span class="lines">@@ -602,7 +637,7 @@
</span><span class="cx">         shadowContext.translate(m_layerContextTranslation);
</span><span class="cx"> 
</span><span class="cx">         Path path;
</span><del>-        path.addRect(rect);
</del><ins>+        path.addRect(fullRect);
</ins><span class="cx">         if (holeRect.radii().isZero())
</span><span class="cx">             path.addRect(holeRect.rect());
</span><span class="cx">         else
</span><span class="lines">@@ -615,85 +650,9 @@
</span><span class="cx">         blurShadowBuffer(layerSize);
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    drawBuffer(*layerImage, m_layerOrigin, m_layerSize, m_sourceRect);
</del><ins>+    drawBuffer(*layerImage, m_layerOrigin, m_layerSize);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void ShadowBlur::drawRectShadowWithoutTiling(GraphicsContext& graphicsContext, const FloatRoundedRect& shadowedRect, const IntSize& layerSize)
-{
-    m_layerImage = ScratchBuffer::singleton().getScratchBuffer(layerSize);
-    if (!m_layerImage)
-        return;
-
-    FloatRect bufferRelativeShadowedRect = shadowedRect.rect();
-    bufferRelativeShadowedRect.move(m_layerContextTranslation);
-
-    // Only redraw in the scratch buffer if its cached contents don't match our needs
-    bool redrawNeeded = ScratchBuffer::singleton().setCachedShadowValues(m_blurRadius, Color::black, bufferRelativeShadowedRect, shadowedRect.radii(), m_layerSize);
-    if (redrawNeeded) {
-        GraphicsContext& shadowContext = m_layerImage->context();
-        GraphicsContextStateSaver stateSaver(shadowContext);
-
-        // Add a pixel to avoid later edge aliasing when rotated.
-        shadowContext.clearRect(FloatRect(0, 0, m_layerSize.width() + 1, m_layerSize.height() + 1));
-        shadowContext.translate(m_layerContextTranslation);
-        shadowContext.setFillColor(Color::black);
-        if (shadowedRect.radii().isZero())
-            shadowContext.fillRect(shadowedRect.rect());
-        else {
-            Path path;
-            path.addRoundedRect(shadowedRect);
-            shadowContext.fillPath(path);
-        }
-
-        blurShadowBuffer(layerSize);
-    }
-    
-    drawShadowBuffer(graphicsContext);
-    m_layerImage = nullptr;
-    ScratchBuffer::singleton().scheduleScratchBufferPurge();
-}
-
-void ShadowBlur::drawInsetShadowWithoutTiling(GraphicsContext& graphicsContext, const FloatRect& rect, const FloatRoundedRect& holeRect, const IntSize& layerSize)
-{
-    m_layerImage = ScratchBuffer::singleton().getScratchBuffer(layerSize);
-    if (!m_layerImage)
-        return;
-
-    FloatRect bufferRelativeRect = rect;
-    bufferRelativeRect.move(m_layerContextTranslation);
-
-    FloatRect bufferRelativeHoleRect = holeRect.rect();
-    bufferRelativeHoleRect.move(m_layerContextTranslation);
-
-    // Only redraw in the scratch buffer if its cached contents don't match our needs
-    bool redrawNeeded = ScratchBuffer::singleton().setCachedInsetShadowValues(m_blurRadius, Color::black, bufferRelativeRect, bufferRelativeHoleRect, holeRect.radii());
-    if (redrawNeeded) {
-        GraphicsContext& shadowContext = m_layerImage->context();
-        GraphicsContextStateSaver stateSaver(shadowContext);
-
-        // Add a pixel to avoid later edge aliasing when rotated.
-        shadowContext.clearRect(FloatRect(0, 0, m_layerSize.width() + 1, m_layerSize.height() + 1));
-        shadowContext.translate(m_layerContextTranslation);
-
-        Path path;
-        path.addRect(rect);
-        if (holeRect.radii().isZero())
-            path.addRect(holeRect.rect());
-        else
-            path.addRoundedRect(holeRect);
-
-        shadowContext.setFillRule(WindRule::EvenOdd);
-        shadowContext.setFillColor(Color::black);
-        shadowContext.fillPath(path);
-
-        blurShadowBuffer(layerSize);
-    }
-    
-    drawShadowBuffer(graphicsContext);
-    m_layerImage = nullptr;
-    ScratchBuffer::singleton().scheduleScratchBufferPurge();
-}
-
</del><span class="cx"> /*
</span><span class="cx">   These functions use tiling to improve the performance of the shadow
</span><span class="cx">   drawing of rounded rectangles. The code basically does the following
</span><span class="lines">@@ -726,18 +685,84 @@
</span><span class="cx">      the shadow.
</span><span class="cx">  */
</span><span class="cx"> 
</span><del>-void ShadowBlur::drawInsetShadowWithTiling(GraphicsContext& graphicsContext, const FloatRect& rect, const FloatRoundedRect& holeRect, const IntSize& templateSize, const IntSize& edgeSize)
</del><ins>+void ShadowBlur::drawRectShadowWithTiling(const AffineTransform& transform, const FloatRoundedRect& shadowedRect, const IntSize& templateSize, const IntSize& edgeSize, const DrawImageCallback& drawImage, const FillRectCallback& fillRect)
</ins><span class="cx"> {
</span><ins>+#if USE(CG)
</ins><span class="cx">     m_layerImage = ScratchBuffer::singleton().getScratchBuffer(templateSize);
</span><ins>+#else
+    auto layerImage = ImageBuffer::create(templateSize, Unaccelerated, 1);
+    m_layerImage = layerImage.get();
+#endif
+
</ins><span class="cx">     if (!m_layerImage)
</span><span class="cx">         return;
</span><span class="cx"> 
</span><ins>+    FloatRect templateShadow = FloatRect(edgeSize.width(), edgeSize.height(), templateSize.width() - 2 * edgeSize.width(), templateSize.height() - 2 * edgeSize.height());
+
+    bool redrawNeeded = true;
+#if USE(CG)
+    // Only redraw in the scratch buffer if its cached contents don't match our needs
+    redrawNeeded = ScratchBuffer::singleton().setCachedShadowValues(m_blurRadius, m_color, templateShadow, shadowedRect.radii(), m_layerSize);
+#endif
+
+    if (redrawNeeded) {
+        // Draw shadow into the ImageBuffer.
+        GraphicsContext& shadowContext = m_layerImage->context();
+        GraphicsContextStateSaver shadowStateSaver(shadowContext);
+
+        shadowContext.clearRect(FloatRect(0, 0, templateSize.width(), templateSize.height()));
+        shadowContext.setFillColor(Color::black);
+
+        if (shadowedRect.radii().isZero())
+            shadowContext.fillRect(templateShadow);
+        else {
+            Path path;
+            path.addRoundedRect(FloatRoundedRect(templateShadow, shadowedRect.radii()));
+            shadowContext.fillPath(path);
+        }
+        blurAndColorShadowBuffer(templateSize);
+    }
+
+    FloatSize offset = m_offset;
+    if (shadowsIgnoreTransforms())
+        offset.scale(1 / transform.xScale(), 1 / transform.yScale());
+
+    FloatRect shadowBounds = shadowedRect.rect();
+    shadowBounds.move(offset);
+    shadowBounds.inflateX(edgeSize.width());
+    shadowBounds.inflateY(edgeSize.height());
+
+    drawLayerPiecesAndFillCenter(shadowBounds, shadowedRect.radii(), edgeSize, templateSize, drawImage, fillRect);
+
+    m_layerImage = nullptr;
+
+#if USE(CG)
+    ScratchBuffer::singleton().scheduleScratchBufferPurge();
+#endif
+}
+
+void ShadowBlur::drawInsetShadowWithTiling(const AffineTransform& transform, const FloatRect& fullRect, const FloatRoundedRect& holeRect, const IntSize& templateSize, const IntSize& edgeSize, const DrawImageCallback& drawImage, const FillRectWithHoleCallback& fillRectWithHole)
+{
+#if USE(CG)
+    m_layerImage = ScratchBuffer::singleton().getScratchBuffer(templateSize);
+#else
+    auto layerImage = ImageBuffer::create(templateSize, Unaccelerated, 1);
+    m_layerImage = layerImage.get();
+#endif
+
+    if (!m_layerImage)
+        return;
+
</ins><span class="cx">     // Draw the rectangle with hole.
</span><span class="cx">     FloatRect templateBounds(0, 0, templateSize.width(), templateSize.height());
</span><span class="cx">     FloatRect templateHole = FloatRect(edgeSize.width(), edgeSize.height(), templateSize.width() - 2 * edgeSize.width(), templateSize.height() - 2 * edgeSize.height());
</span><span class="cx"> 
</span><ins>+    bool redrawNeeded = true;
+#if USE(CG)
</ins><span class="cx">     // Only redraw in the scratch buffer if its cached contents don't match our needs
</span><del>-    bool redrawNeeded = ScratchBuffer::singleton().setCachedInsetShadowValues(m_blurRadius, m_color, templateBounds, templateHole, holeRect.radii());
</del><ins>+    redrawNeeded = ScratchBuffer::singleton().setCachedInsetShadowValues(m_blurRadius, m_color, templateBounds, templateHole, holeRect.radii());
+#endif
+
</ins><span class="cx">     if (redrawNeeded) {
</span><span class="cx">         // Draw shadow into a new ImageBuffer.
</span><span class="cx">         GraphicsContext& shadowContext = m_layerImage->context();
</span><span class="lines">@@ -758,12 +783,10 @@
</span><span class="cx">         blurAndColorShadowBuffer(templateSize);
</span><span class="cx">     }
</span><span class="cx">     FloatSize offset = m_offset;
</span><del>-    if (shadowsIgnoreTransforms()) {
-        AffineTransform transform = graphicsContext.getCTM();
</del><ins>+    if (shadowsIgnoreTransforms())
</ins><span class="cx">         offset.scale(1 / transform.xScale(), 1 / transform.yScale());
</span><del>-    }
</del><span class="cx"> 
</span><del>-    FloatRect boundingRect = rect;
</del><ins>+    FloatRect boundingRect = fullRect;
</ins><span class="cx">     boundingRect.move(offset);
</span><span class="cx"> 
</span><span class="cx">     FloatRect destHoleRect = holeRect.rect();
</span><span class="lines">@@ -773,71 +796,18 @@
</span><span class="cx">     destHoleBounds.inflateY(edgeSize.height());
</span><span class="cx"> 
</span><span class="cx">     // Fill the external part of the shadow (which may be visible because of offset).
</span><del>-    Path exteriorPath;
-    exteriorPath.addRect(boundingRect);
-    exteriorPath.addRect(destHoleBounds);
</del><ins>+    fillRectWithHole(boundingRect, destHoleBounds, m_color);
</ins><span class="cx"> 
</span><del>-    {
-        GraphicsContextStateSaver fillStateSaver(graphicsContext);
-        graphicsContext.setFillRule(WindRule::EvenOdd);
-        graphicsContext.setFillColor(m_color);
-        graphicsContext.clearShadow();
-        graphicsContext.fillPath(exteriorPath);
-    }
-    
-    drawLayerPieces(graphicsContext, destHoleBounds, holeRect.radii(), edgeSize, templateSize, InnerShadow);
</del><ins>+    drawLayerPieces(destHoleBounds, holeRect.radii(), edgeSize, templateSize, drawImage);
</ins><span class="cx"> 
</span><span class="cx">     m_layerImage = nullptr;
</span><del>-    ScratchBuffer::singleton().scheduleScratchBufferPurge();
-}
</del><span class="cx"> 
</span><del>-void ShadowBlur::drawRectShadowWithTiling(GraphicsContext& graphicsContext, const FloatRoundedRect& shadowedRect, const IntSize& templateSize, const IntSize& edgeSize)
-{
-    auto& scratchBuffer = ScratchBuffer::singleton();
-    m_layerImage = scratchBuffer.getScratchBuffer(templateSize);
-    if (!m_layerImage)
-        return;
-
-    FloatRect templateShadow = FloatRect(edgeSize.width(), edgeSize.height(), templateSize.width() - 2 * edgeSize.width(), templateSize.height() - 2 * edgeSize.height());
-
-    // Only redraw in the scratch buffer if its cached contents don't match our needs
-    bool redrawNeeded = scratchBuffer.setCachedShadowValues(m_blurRadius, m_color, templateShadow, shadowedRect.radii(), m_layerSize);
-    if (redrawNeeded) {
-        // Draw shadow into the ImageBuffer.
-        GraphicsContext& shadowContext = m_layerImage->context();
-        GraphicsContextStateSaver shadowStateSaver(shadowContext);
-
-        shadowContext.clearRect(FloatRect(0, 0, templateSize.width(), templateSize.height()));
-        shadowContext.setFillColor(Color::black);
-        
-        if (shadowedRect.radii().isZero())
-            shadowContext.fillRect(templateShadow);
-        else {
-            Path path;
-            path.addRoundedRect(FloatRoundedRect(templateShadow, shadowedRect.radii()));
-            shadowContext.fillPath(path);
-        }
-
-        blurAndColorShadowBuffer(templateSize);
-    }
-    FloatSize offset = m_offset;
-    if (shadowsIgnoreTransforms()) {
-        AffineTransform transform = graphicsContext.getCTM();
-        offset.scale(1 / transform.xScale(), 1 / transform.yScale());
-    }
-
-    FloatRect shadowBounds = shadowedRect.rect();
-    shadowBounds.move(offset);
-    shadowBounds.inflateX(edgeSize.width());
-    shadowBounds.inflateY(edgeSize.height());
-
-    drawLayerPieces(graphicsContext, shadowBounds, shadowedRect.radii(), edgeSize, templateSize, OuterShadow);
-
-    m_layerImage = nullptr;
</del><ins>+#if USE(CG)
</ins><span class="cx">     ScratchBuffer::singleton().scheduleScratchBufferPurge();
</span><ins>+#endif
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void ShadowBlur::drawLayerPieces(GraphicsContext& graphicsContext, const FloatRect& shadowBounds, const FloatRoundedRect::Radii& radii, const IntSize& bufferPadding, const IntSize& templateSize, ShadowDirection direction)
</del><ins>+void ShadowBlur::drawLayerPieces(const FloatRect& shadowBounds, const FloatRoundedRect::Radii& radii, const IntSize& bufferPadding, const IntSize& templateSize, const DrawImageCallback& drawImage)
</ins><span class="cx"> {
</span><span class="cx">     const IntSize twiceRadius = IntSize(bufferPadding.width() * 2, bufferPadding.height() * 2);
</span><span class="cx"> 
</span><span class="lines">@@ -849,30 +819,12 @@
</span><span class="cx"> 
</span><span class="cx">     int centerWidth = shadowBounds.width() - leftSlice - rightSlice;
</span><span class="cx">     int centerHeight = shadowBounds.height() - topSlice - bottomSlice;
</span><ins>+    FloatRect centerRect(shadowBounds.x() + leftSlice, shadowBounds.y() + topSlice, centerWidth, centerHeight);
</ins><span class="cx"> 
</span><del>-    if (direction == OuterShadow) {
-        FloatRect shadowInterior(shadowBounds.x() + leftSlice, shadowBounds.y() + topSlice, centerWidth, centerHeight);
-        if (!shadowInterior.isEmpty()) {
-            GraphicsContextStateSaver stateSaver(graphicsContext);
-            graphicsContext.setFillColor(m_color);
-            graphicsContext.clearShadow();
-            graphicsContext.fillRect(shadowInterior);
-        }
-    }
-
-    GraphicsContextStateSaver stateSaver(graphicsContext);
-    graphicsContext.setFillColor(m_color);
-    graphicsContext.clearShadow();
-
-    // Note that drawing the ImageBuffer is faster than creating a Image and drawing that,
-    // because ImageBuffer::draw() knows that it doesn't have to copy the image bits.
-    FloatRect centerRect(shadowBounds.x() + leftSlice, shadowBounds.y() + topSlice, centerWidth, centerHeight);
-    centerRect = graphicsContext.roundToDevicePixels(centerRect);
-    
</del><span class="cx">     // Top side.
</span><span class="cx">     FloatRect tileRect = FloatRect(leftSlice, 0, templateSideLength, topSlice);
</span><span class="cx">     FloatRect destRect = FloatRect(centerRect.x(), centerRect.y() - topSlice, centerRect.width(), topSlice);
</span><del>-    graphicsContext.drawImageBuffer(*m_layerImage, destRect, tileRect);
</del><ins>+    drawImage(*m_layerImage, destRect, tileRect);
</ins><span class="cx"> 
</span><span class="cx">     // Draw the bottom side.
</span><span class="cx">     tileRect.setY(templateSize.height() - bottomSlice);
</span><span class="lines">@@ -879,12 +831,12 @@
</span><span class="cx">     tileRect.setHeight(bottomSlice);
</span><span class="cx">     destRect.setY(centerRect.maxY());
</span><span class="cx">     destRect.setHeight(bottomSlice);
</span><del>-    graphicsContext.drawImageBuffer(*m_layerImage, destRect, tileRect);
</del><ins>+    drawImage(*m_layerImage, destRect, tileRect);
</ins><span class="cx"> 
</span><span class="cx">     // Left side.
</span><span class="cx">     tileRect = FloatRect(0, topSlice, leftSlice, templateSideLength);
</span><span class="cx">     destRect = FloatRect(centerRect.x() - leftSlice, centerRect.y(), leftSlice, centerRect.height());
</span><del>-    graphicsContext.drawImageBuffer(*m_layerImage, destRect, tileRect);
</del><ins>+    drawImage(*m_layerImage, destRect, tileRect);
</ins><span class="cx"> 
</span><span class="cx">     // Right side.
</span><span class="cx">     tileRect.setX(templateSize.width() - rightSlice);
</span><span class="lines">@@ -891,30 +843,50 @@
</span><span class="cx">     tileRect.setWidth(rightSlice);
</span><span class="cx">     destRect.setX(centerRect.maxX());
</span><span class="cx">     destRect.setWidth(rightSlice);
</span><del>-    graphicsContext.drawImageBuffer(*m_layerImage, destRect, tileRect);
</del><ins>+    drawImage(*m_layerImage, destRect, tileRect);
</ins><span class="cx"> 
</span><span class="cx">     // Top left corner.
</span><span class="cx">     tileRect = FloatRect(0, 0, leftSlice, topSlice);
</span><span class="cx">     destRect = FloatRect(centerRect.x() - leftSlice, centerRect.y() - topSlice, leftSlice, topSlice);
</span><del>-    graphicsContext.drawImageBuffer(*m_layerImage, destRect, tileRect);
</del><ins>+    drawImage(*m_layerImage, destRect, tileRect);
</ins><span class="cx"> 
</span><span class="cx">     // Top right corner.
</span><span class="cx">     tileRect = FloatRect(templateSize.width() - rightSlice, 0, rightSlice, topSlice);
</span><span class="cx">     destRect = FloatRect(centerRect.maxX(), centerRect.y() - topSlice, rightSlice, topSlice);
</span><del>-    graphicsContext.drawImageBuffer(*m_layerImage, destRect, tileRect);
</del><ins>+    drawImage(*m_layerImage, destRect, tileRect);
</ins><span class="cx"> 
</span><span class="cx">     // Bottom right corner.
</span><span class="cx">     tileRect = FloatRect(templateSize.width() - rightSlice, templateSize.height() - bottomSlice, rightSlice, bottomSlice);
</span><span class="cx">     destRect = FloatRect(centerRect.maxX(), centerRect.maxY(), rightSlice, bottomSlice);
</span><del>-    graphicsContext.drawImageBuffer(*m_layerImage, destRect, tileRect);
</del><ins>+    drawImage(*m_layerImage, destRect, tileRect);
</ins><span class="cx"> 
</span><span class="cx">     // Bottom left corner.
</span><span class="cx">     tileRect = FloatRect(0, templateSize.height() - bottomSlice, leftSlice, bottomSlice);
</span><span class="cx">     destRect = FloatRect(centerRect.x() - leftSlice, centerRect.maxY(), leftSlice, bottomSlice);
</span><del>-    graphicsContext.drawImageBuffer(*m_layerImage, destRect, tileRect);
</del><ins>+    drawImage(*m_layerImage, destRect, tileRect);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void ShadowBlur::drawLayerPiecesAndFillCenter(const FloatRect& shadowBounds, const FloatRoundedRect::Radii& radii, const IntSize& bufferPadding, const IntSize& templateSize, const DrawImageCallback& drawImage, const FillRectCallback& fillRect)
+{
+    const IntSize twiceRadius = IntSize(bufferPadding.width() * 2, bufferPadding.height() * 2);
</ins><span class="cx"> 
</span><ins>+    int leftSlice;
+    int rightSlice;
+    int topSlice;
+    int bottomSlice;
+    computeSliceSizesFromRadii(twiceRadius, radii, leftSlice, rightSlice, topSlice, bottomSlice);
+
+    int centerWidth = shadowBounds.width() - leftSlice - rightSlice;
+    int centerHeight = shadowBounds.height() - topSlice - bottomSlice;
+    FloatRect centerRect(shadowBounds.x() + leftSlice, shadowBounds.y() + topSlice, centerWidth, centerHeight);
+
+    // Fill center
+    if (!centerRect.isEmpty())
+        fillRect(centerRect, m_color);
+
+    drawLayerPieces(shadowBounds, radii, bufferPadding, templateSize, drawImage);
+}
+
</ins><span class="cx"> void ShadowBlur::blurShadowBuffer(const IntSize& templateSize)
</span><span class="cx"> {
</span><span class="cx">     if (m_type != BlurShadow)
</span><span class="lines">@@ -962,7 +934,7 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     blurAndColorShadowBuffer(expandedIntSize(m_layerSize));
</span><del>-    drawBuffer(*layerImage, m_layerOrigin, m_layerSize, m_sourceRect);
</del><ins>+    drawBuffer(*layerImage, m_layerOrigin, m_layerSize);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> } // namespace WebCore
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsShadowBlurh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/ShadowBlur.h (244912 => 244913)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/ShadowBlur.h      2019-05-03 18:18:12 UTC (rev 244912)
+++ trunk/Source/WebCore/platform/graphics/ShadowBlur.h 2019-05-03 18:31:06 UTC (rev 244913)
</span><span class="lines">@@ -23,11 +23,10 @@
</span><span class="cx">  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
</span><span class="cx">  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
</span><span class="cx">  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
</span><del>- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
</del><ins>+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
</ins><span class="cx">  */
</span><span class="cx"> 
</span><del>-#ifndef ShadowBlur_h
-#define ShadowBlur_h
</del><ins>+#pragma once
</ins><span class="cx"> 
</span><span class="cx"> #include "Color.h"
</span><span class="cx"> #include "FloatRect.h"
</span><span class="lines">@@ -63,13 +62,18 @@
</span><span class="cx">     void drawRectShadow(GraphicsContext&, const FloatRoundedRect&);
</span><span class="cx">     void drawInsetShadow(GraphicsContext&, const FloatRect&, const FloatRoundedRect& holeRect);
</span><span class="cx"> 
</span><del>-    using DrawBufferCallback = WTF::Function<void(ImageBuffer&, const FloatPoint&, const FloatSize&, const FloatRect&)>;
-    void drawRectShadow(const AffineTransform&, const IntRect&, const FloatRoundedRect&, const DrawBufferCallback&);
-    void drawInsetShadow(const AffineTransform&, const IntRect&, const FloatRect&, const FloatRoundedRect&, const DrawBufferCallback&);
-
</del><ins>+    using DrawBufferCallback = WTF::Function<void(ImageBuffer&, const FloatPoint&, const FloatSize&)>;
+    using DrawImageCallback = WTF::Function<void(ImageBuffer&, const FloatRect&, const FloatRect&)>;
+    using FillRectCallback = WTF::Function<void(const FloatRect&, const Color&)>;
+    using FillRectWithHoleCallback = WTF::Function<void(const FloatRect&, const FloatRect&, const Color&)>;
</ins><span class="cx">     using DrawShadowCallback = WTF::Function<void(GraphicsContext&)>;
</span><del>-    void drawShadowLayer(const AffineTransform&, const IntRect&, const FloatRect&, const DrawShadowCallback&, const DrawBufferCallback&);
</del><span class="cx"> 
</span><ins>+    // DrawBufferCallback is for drawing shadow without tiling.
+    // DrawImageCallback and FillRectCallback is for drawing shadow with tiling.
+    void drawRectShadow(const AffineTransform&, const IntRect& clipBounds, const FloatRoundedRect& shadowedRect, const DrawBufferCallback&, const DrawImageCallback&, const FillRectCallback&);
+    void drawInsetShadow(const AffineTransform&, const IntRect& clipBounds, const FloatRect& fullRect, const FloatRoundedRect& holeRect, const DrawBufferCallback&, const DrawImageCallback&, const FillRectWithHoleCallback&);
+    void drawShadowLayer(const AffineTransform&, const IntRect& clipBounds, const FloatRect& layerArea, const DrawShadowCallback&, const DrawBufferCallback&);
+
</ins><span class="cx">     void blurLayerImage(unsigned char*, const IntSize&, int stride);
</span><span class="cx"> 
</span><span class="cx">     void clear();
</span><span class="lines">@@ -82,29 +86,29 @@
</span><span class="cx">     void drawShadowBuffer(GraphicsContext&);
</span><span class="cx"> 
</span><span class="cx">     void adjustBlurRadius(const AffineTransform&);
</span><del>-    
</del><ins>+
</ins><span class="cx">     enum ShadowDirection {
</span><span class="cx">         OuterShadow,
</span><span class="cx">         InnerShadow
</span><span class="cx">     };
</span><del>-    
</del><ins>+
</ins><span class="cx">     IntSize calculateLayerBoundingRect(const AffineTransform&, const FloatRect& layerArea, const IntRect& clipRect);
</span><span class="cx">     IntSize templateSize(const IntSize& blurredEdgeSize, const FloatRoundedRect::Radii&) const;
</span><span class="cx"> 
</span><del>-    void drawRectShadowWithoutTiling(GraphicsContext&, const FloatRoundedRect&, const IntSize& layerSize);
-    void drawRectShadowWithTiling(GraphicsContext&, const FloatRoundedRect&, const IntSize& shadowTemplateSize, const IntSize& blurredEdgeSize);
-
-    void drawInsetShadowWithoutTiling(GraphicsContext&, const FloatRect&, const FloatRoundedRect& holeRect, const IntSize& layerSize);
-    void drawInsetShadowWithTiling(GraphicsContext&, const FloatRect&, const FloatRoundedRect& holeRect, const IntSize& shadowTemplateSize, const IntSize& blurredEdgeSize);
-    
-    void drawLayerPieces(GraphicsContext&, const FloatRect& shadowBounds, const FloatRoundedRect::Radii&, const IntSize& roundedRadius, const IntSize& templateSize, ShadowDirection);
-    
</del><span class="cx">     void blurShadowBuffer(const IntSize& templateSize);
</span><span class="cx">     void blurAndColorShadowBuffer(const IntSize& templateSize);
</span><del>-    
</del><ins>+
+    void drawInsetShadowWithoutTiling(const AffineTransform&, const FloatRect& fullRect, const FloatRoundedRect& holeRect, const IntSize& layerSize, const DrawBufferCallback&);
+    void drawInsetShadowWithTiling(const AffineTransform&, const FloatRect& fullRect, const FloatRoundedRect& holeRect, const IntSize& shadowTemplateSize, const IntSize& blurredEdgeSize, const DrawImageCallback&, const FillRectWithHoleCallback&);
+
+    void drawRectShadowWithoutTiling(const AffineTransform&, const FloatRoundedRect& shadowedRect, const IntSize& layerSize, const DrawBufferCallback&);
+    void drawRectShadowWithTiling(const AffineTransform&, const FloatRoundedRect& shadowedRect, const IntSize& shadowTemplateSize, const IntSize& blurredEdgeSize, const DrawImageCallback&, const FillRectCallback&);
+
+    void drawLayerPiecesAndFillCenter(const FloatRect& shadowBounds, const FloatRoundedRect::Radii&, const IntSize& roundedRadius, const IntSize& templateSize, const DrawImageCallback&, const FillRectCallback&);
+    void drawLayerPieces(const FloatRect& shadowBounds, const FloatRoundedRect::Radii&, const IntSize& roundedRadius, const IntSize& templateSize, const DrawImageCallback&);
+
</ins><span class="cx">     IntSize blurredEdgeSize() const;
</span><del>-    
-    
</del><ins>+
</ins><span class="cx">     ShadowType m_type { NoShadow };
</span><span class="cx"> 
</span><span class="cx">     Color m_color;
</span><span class="lines">@@ -113,7 +117,7 @@
</span><span class="cx"> 
</span><span class="cx">     ImageBuffer* m_layerImage { nullptr }; // Buffer to where the temporary shadow will be drawn to.
</span><span class="cx"> 
</span><del>-    FloatRect m_sourceRect; // Sub-rect of m_layerImage that contains the shadow pixels.
</del><ins>+    FloatSize m_shadowedResultSize; // Size of the result of shadowing which is same as shadowedRect + blurred edges.
</ins><span class="cx">     FloatPoint m_layerOrigin; // Top-left corner of the (possibly clipped) bounding rect to draw the shadow to.
</span><span class="cx">     FloatSize m_layerSize; // Size of m_layerImage pixels that need blurring.
</span><span class="cx">     FloatSize m_layerContextTranslation; // Translation to apply to m_layerContext for the shadow to be correctly clipped.
</span><span class="lines">@@ -122,5 +126,3 @@
</span><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } // namespace WebCore
</span><del>-
-#endif // ShadowBlur_h
</del></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicscairoCairoOperationscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/cairo/CairoOperations.cpp (244912 => 244913)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/cairo/CairoOperations.cpp 2019-05-03 18:18:12 UTC (rev 244912)
+++ trunk/Source/WebCore/platform/graphics/cairo/CairoOperations.cpp    2019-05-03 18:31:06 UTC (rev 244913)
</span><span class="lines">@@ -184,8 +184,21 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static void fillShadowBuffer(PlatformContextCairo& platformContext, ImageBuffer& layerImage, const FloatPoint& layerOrigin, const FloatSize& layerSize, const FloatRect& sourceRect, const ShadowState& shadowState)
</del><ins>+// FIXME: This is mostly same as drawShadowLayerBuffer, so we should merge two.
+static void drawShadowImage(PlatformContextCairo& platformContext, ImageBuffer& layerImage, const FloatRect& destRect, const FloatRect& srcRect, const ShadowState& shadowState)
</ins><span class="cx"> {
</span><ins>+    RefPtr<Image> image = layerImage.copyImage(DontCopyBackingStore);
+    if (!image)
+        return;
+
+    if (auto surface = image->nativeImageForCurrentFrame()) {
+        drawNativeImage(platformContext, surface.get(), destRect, srcRect, shadowState.globalCompositeOperator, BlendMode::Normal, ImageOrientation(),
+            InterpolationDefault, shadowState.globalAlpha, ShadowState());
+    }
+}
+
+static void fillShadowBuffer(PlatformContextCairo& platformContext, ImageBuffer& layerImage, const FloatPoint& layerOrigin, const FloatSize& layerSize, const ShadowState& shadowState)
+{
</ins><span class="cx">     save(platformContext);
</span><span class="cx"> 
</span><span class="cx">     RefPtr<Image> image = layerImage.copyImage(DontCopyBackingStore);
</span><span class="lines">@@ -197,7 +210,7 @@
</span><span class="cx">     FillSource fillSource;
</span><span class="cx">     fillSource.globalAlpha = shadowState.globalAlpha;
</span><span class="cx">     fillSource.color = shadowState.color;
</span><del>-    fillRect(platformContext, FloatRect(layerOrigin, sourceRect.size()), fillSource, ShadowState());
</del><ins>+    fillRect(platformContext, FloatRect(layerOrigin, expandedIntSize(layerSize)), fillSource, ShadowState());
</ins><span class="cx"> 
</span><span class="cx">     restore(platformContext);
</span><span class="cx"> }
</span><span class="lines">@@ -252,7 +265,7 @@
</span><span class="cx">                 cairo_stroke(cairoShadowContext);
</span><span class="cx">             }
</span><span class="cx">         },
</span><del>-        [&platformContext, &shadowState, &cairoContext, &path](ImageBuffer& layerImage, const FloatPoint& layerOrigin, const FloatSize& layerSize, const FloatRect&)
</del><ins>+        [&platformContext, &shadowState, &cairoContext, &path](ImageBuffer& layerImage, const FloatPoint& layerOrigin, const FloatSize& layerSize)
</ins><span class="cx">         {
</span><span class="cx">             // The original path may still be hanging around on the context and endShadowLayer
</span><span class="cx">             // will take care of properly creating a path to draw the result shadow. We remove the path
</span><span class="lines">@@ -266,6 +279,7 @@
</span><span class="cx">         });
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> static inline void fillCurrentCairoPath(PlatformContextCairo& platformContext, const FillSource& fillSource)
</span><span class="cx"> {
</span><span class="cx">     cairo_t* cr = platformContext.cr();
</span><span class="lines">@@ -350,7 +364,7 @@
</span><span class="cx">         {
</span><span class="cx">             drawGlyphsToContext(shadowContext.platformContext()->cr(), scaledFont, syntheticBoldOffset, glyphs);
</span><span class="cx">         },
</span><del>-        [&platformContext, &shadowState](ImageBuffer& layerImage, const FloatPoint& layerOrigin, const FloatSize& layerSize, const FloatRect&)
</del><ins>+        [&platformContext, &shadowState](ImageBuffer& layerImage, const FloatPoint& layerOrigin, const FloatSize& layerSize)
</ins><span class="cx">         {
</span><span class="cx">             drawShadowLayerBuffer(platformContext, layerImage, layerOrigin, layerSize, shadowState);
</span><span class="cx">         });
</span><span class="lines">@@ -690,9 +704,17 @@
</span><span class="cx">     if (shadowState.isVisible()) {
</span><span class="cx">         ShadowBlur shadow({ shadowState.blur, shadowState.blur }, shadowState.offset, shadowState.color, shadowState.ignoreTransforms);
</span><span class="cx">         shadow.drawRectShadow(State::getCTM(platformContext), State::getClipBounds(platformContext), FloatRoundedRect(rect),
</span><del>-            [&platformContext, &shadowState](ImageBuffer& layerImage, const FloatPoint& layerOrigin, const FloatSize& layerSize, const FloatRect& sourceRect)
</del><ins>+            [&platformContext, &shadowState](ImageBuffer& layerImage, const FloatPoint& layerOrigin, const FloatSize& layerSize)
</ins><span class="cx">             {
</span><del>-                fillShadowBuffer(platformContext, layerImage, layerOrigin, layerSize, sourceRect, shadowState);
</del><ins>+                fillShadowBuffer(platformContext, layerImage, layerOrigin, layerSize, shadowState);
+            },
+            [&platformContext, &shadowState](ImageBuffer& layerImage, const FloatRect& destRect, const FloatRect& srcRect)
+            {
+                drawShadowImage(platformContext, layerImage, destRect, srcRect, shadowState);
+            },
+            [&platformContext](const FloatRect& rect, const Color& color)
+            {
+                fillRectWithColor(platformContext.cr(), rect, color);
</ins><span class="cx">             });
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -713,9 +735,17 @@
</span><span class="cx">     if (shadowState.isVisible()) {
</span><span class="cx">         ShadowBlur shadow({ shadowState.blur, shadowState.blur }, shadowState.offset, shadowState.color, shadowState.ignoreTransforms);
</span><span class="cx">         shadow.drawRectShadow(State::getCTM(platformContext), State::getClipBounds(platformContext), rect,
</span><del>-            [&platformContext, &shadowState](ImageBuffer& layerImage, const FloatPoint& layerOrigin, const FloatSize& layerSize, const FloatRect& sourceRect)
</del><ins>+            [&platformContext, &shadowState](ImageBuffer& layerImage, const FloatPoint& layerOrigin, const FloatSize& layerSize)
</ins><span class="cx">             {
</span><del>-                fillShadowBuffer(platformContext, layerImage, layerOrigin, layerSize, sourceRect, shadowState);
</del><ins>+                fillShadowBuffer(platformContext, layerImage, layerOrigin, layerSize, shadowState);
+            },
+            [&platformContext, &shadowState](ImageBuffer& layerImage, const FloatRect& destRect, const FloatRect& srcRect)
+            {
+                drawShadowImage(platformContext, layerImage, destRect, srcRect, shadowState);
+            },
+            [&platformContext](const FloatRect& rect, const Color& color)
+            {
+                fillRectWithColor(platformContext.cr(), rect, color);
</ins><span class="cx">             });
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -738,9 +768,25 @@
</span><span class="cx">     if (shadowState.isVisible()) {
</span><span class="cx">         ShadowBlur shadow({ shadowState.blur, shadowState.blur }, shadowState.offset, shadowState.color, shadowState.ignoreTransforms);
</span><span class="cx">         shadow.drawInsetShadow(State::getCTM(platformContext), State::getClipBounds(platformContext), rect, roundedHoleRect,
</span><del>-            [&platformContext, &shadowState](ImageBuffer& layerImage, const FloatPoint& layerOrigin, const FloatSize& layerSize, const FloatRect& sourceRect)
</del><ins>+            [&platformContext, &shadowState](ImageBuffer& layerImage, const FloatPoint& layerOrigin, const FloatSize& layerSize)
</ins><span class="cx">             {
</span><del>-                fillShadowBuffer(platformContext, layerImage, layerOrigin, layerSize, sourceRect, shadowState);
</del><ins>+                fillShadowBuffer(platformContext, layerImage, layerOrigin, layerSize, shadowState);
+            },
+            [&platformContext, &shadowState](ImageBuffer& layerImage, const FloatRect& destRect, const FloatRect& srcRect)
+            {
+                drawShadowImage(platformContext, layerImage, destRect, srcRect, shadowState);
+            },
+            [&platformContext](const FloatRect& rect, const FloatRect& holeRect, const Color& color)
+            {
+                // FIXME: We should use fillRectWithRoundedHole.
+                cairo_t* cr = platformContext.cr();
+                cairo_save(cr);
+                setSourceRGBAFromColor(cr, color);
+                cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD);
+                cairo_rectangle(cr, rect.x(), rect.y(), rect.width(), rect.height());
+                cairo_rectangle(cr, holeRect.x(), holeRect.y(), holeRect.width(), holeRect.height());
+                cairo_fill(cr);
+                cairo_restore(cr);
</ins><span class="cx">             });
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -932,7 +978,7 @@
</span><span class="cx">             {
</span><span class="cx">                 drawPatternToCairoContext(shadowContext.platformContext()->cr(), pattern.get(), destRect, 1);
</span><span class="cx">             },
</span><del>-            [&platformContext, &shadowState](ImageBuffer& layerImage, const FloatPoint& layerOrigin, const FloatSize& layerSize, const FloatRect&)
</del><ins>+            [&platformContext, &shadowState](ImageBuffer& layerImage, const FloatPoint& layerOrigin, const FloatSize& layerSize)
</ins><span class="cx">             {
</span><span class="cx">                 drawShadowLayerBuffer(platformContext, layerImage, layerOrigin, layerSize, shadowState);
</span><span class="cx">             });
</span></span></pre>
</div>
</div>

</body>
</html>