<!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>[191551] 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/191551">191551</a></dd>
<dt>Author</dt> <dd>simon.fraser@apple.com</dd>
<dt>Date</dt> <dd>2015-10-25 21:57:46 -0700 (Sun, 25 Oct 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>Support bezier paths in clip-path property
https://bugs.webkit.org/show_bug.cgi?id=149996

Reviewed by Darin Adler.

Source/WebCore:

Support path() in the -webkit-clip-path property, as specified in
https://drafts.csswg.org/css-shapes-2/#supported-basic-shapes

Added BasicShapePath and CSSBasicShapePath, which both represent the path
as a SVGPathByteStream and wind rule.

Make BasicShape::canBlend() a virtual function, and implement it on each subclass.
Make various BasicShape subclass function overrides private, other than windRule()
wich is called on derived classes in a few places.

Add SVGPathBlender::canBlendPaths() which returns true if the given paths can be
interpolated. Uses the same logic as blendAnimatedPath(), without doing any interpolation.

RenderElement::createsGroup() is fixed to have clip-path trigger a group,
which fixes rendering of clip-path with a descendant compositing layer.

Tests: compositing/masks/clip-path-composited-descendent.html
       css3/masking/clip-path-with-path.html
       transitions/clip-path-path-transitions.html

* css/BasicShapeFunctions.cpp:
(WebCore::valueForBasicShape):
(WebCore::basicShapeForValue):
* css/CSSBasicShapes.cpp:
(WebCore::CSSBasicShapePath::CSSBasicShapePath):
(WebCore::CSSBasicShapePath::pathData):
(WebCore::buildPathString):
(WebCore::CSSBasicShapePath::cssText):
(WebCore::CSSBasicShapePath::equals):
* css/CSSBasicShapes.h:
* css/CSSParser.cpp:
(WebCore::CSSParser::parseBasicShapePath):
(WebCore::CSSParser::parseBasicShape):
* css/CSSParser.h:
* rendering/RenderElement.h:
(WebCore::RenderElement::createsGroup):
* rendering/style/BasicShapes.cpp:
(WebCore::BasicShapeCircle::canBlend):
(WebCore::BasicShapeEllipse::canBlend):
(WebCore::BasicShapePolygon::canBlend):
(WebCore::BasicShapePath::BasicShapePath):
(WebCore::BasicShapePath::path):
(WebCore::BasicShapePath::operator==):
(WebCore::BasicShapePath::canBlend):
(WebCore::BasicShapePath::blend):
(WebCore::BasicShapeInset::canBlend):
(WebCore::BasicShape::canBlend): Deleted.
* rendering/style/BasicShapes.h:
* svg/SVGPathBlender.cpp:
(WebCore::SVGPathBlender::addAnimatedPath):
(WebCore::SVGPathBlender::blendAnimatedPath):
(WebCore::SVGPathBlender::canBlendPaths):
(WebCore::SVGPathBlender::SVGPathBlender):
(WebCore::SVGPathBlender::blendMoveToSegment):
(WebCore::SVGPathBlender::blendLineToSegment):
(WebCore::SVGPathBlender::blendLineToHorizontalSegment):
(WebCore::SVGPathBlender::blendLineToVerticalSegment):
(WebCore::SVGPathBlender::blendCurveToCubicSegment):
(WebCore::SVGPathBlender::blendCurveToCubicSmoothSegment):
(WebCore::SVGPathBlender::blendCurveToQuadraticSegment):
(WebCore::SVGPathBlender::blendCurveToQuadraticSmoothSegment):
(WebCore::SVGPathBlender::blendArcToSegment):
* svg/SVGPathBlender.h:
* svg/SVGPathByteStream.h:
(WebCore::SVGPathByteStream::operator==):
* svg/SVGPathUtilities.cpp:
(WebCore::canBlendSVGPathByteStreams):
* svg/SVGPathUtilities.h:

LayoutTests:

Tests for compositing with clip-path and a composited descendant,
a ref test which tests clip-paths with evenodd, comparing to SVG rendering,
and a transition test to test path blendability.

* compositing/masks/clip-path-composited-descendent-expected.txt: Added.
* compositing/masks/clip-path-composited-descendent.html: Added.
* css3/masking/clip-path-with-path-expected.html: Added.
* css3/masking/clip-path-with-path.html: Added.
* transitions/clip-path-path-transitions-expected.txt: Added.
* transitions/clip-path-path-transitions.html: Added.
* transitions/resources/transition-test-helpers.js: Add some basic parsing
support for paths.
(extractPathValues):
(parseClipPath):
* transitions/svg-transitions-expected.txt:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkLayoutTeststransitionsresourcestransitiontesthelpersjs">trunk/LayoutTests/transitions/resources/transition-test-helpers.js</a></li>
<li><a href="#trunkLayoutTeststransitionssvgtransitionsexpectedtxt">trunk/LayoutTests/transitions/svg-transitions-expected.txt</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCorecssBasicShapeFunctionscpp">trunk/Source/WebCore/css/BasicShapeFunctions.cpp</a></li>
<li><a href="#trunkSourceWebCorecssCSSBasicShapescpp">trunk/Source/WebCore/css/CSSBasicShapes.cpp</a></li>
<li><a href="#trunkSourceWebCorecssCSSBasicShapesh">trunk/Source/WebCore/css/CSSBasicShapes.h</a></li>
<li><a href="#trunkSourceWebCorecssCSSParsercpp">trunk/Source/WebCore/css/CSSParser.cpp</a></li>
<li><a href="#trunkSourceWebCorecssCSSParserh">trunk/Source/WebCore/css/CSSParser.h</a></li>
<li><a href="#trunkSourceWebCorerenderingRenderElementh">trunk/Source/WebCore/rendering/RenderElement.h</a></li>
<li><a href="#trunkSourceWebCorerenderingstyleBasicShapescpp">trunk/Source/WebCore/rendering/style/BasicShapes.cpp</a></li>
<li><a href="#trunkSourceWebCorerenderingstyleBasicShapesh">trunk/Source/WebCore/rendering/style/BasicShapes.h</a></li>
<li><a href="#trunkSourceWebCoresvgSVGPathBlendercpp">trunk/Source/WebCore/svg/SVGPathBlender.cpp</a></li>
<li><a href="#trunkSourceWebCoresvgSVGPathBlenderh">trunk/Source/WebCore/svg/SVGPathBlender.h</a></li>
<li><a href="#trunkSourceWebCoresvgSVGPathByteStreamh">trunk/Source/WebCore/svg/SVGPathByteStream.h</a></li>
<li><a href="#trunkSourceWebCoresvgSVGPathUtilitiescpp">trunk/Source/WebCore/svg/SVGPathUtilities.cpp</a></li>
<li><a href="#trunkSourceWebCoresvgSVGPathUtilitiesh">trunk/Source/WebCore/svg/SVGPathUtilities.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestscompositingmasksclippathcompositeddescendentexpectedtxt">trunk/LayoutTests/compositing/masks/clip-path-composited-descendent-expected.txt</a></li>
<li><a href="#trunkLayoutTestscompositingmasksclippathcompositeddescendenthtml">trunk/LayoutTests/compositing/masks/clip-path-composited-descendent.html</a></li>
<li><a href="#trunkLayoutTestscss3maskingclippathwithpathexpectedhtml">trunk/LayoutTests/css3/masking/clip-path-with-path-expected.html</a></li>
<li><a href="#trunkLayoutTestscss3maskingclippathwithpathhtml">trunk/LayoutTests/css3/masking/clip-path-with-path.html</a></li>
<li><a href="#trunkLayoutTeststransitionsclippathpathtransitionsexpectedtxt">trunk/LayoutTests/transitions/clip-path-path-transitions-expected.txt</a></li>
<li><a href="#trunkLayoutTeststransitionsclippathpathtransitionshtml">trunk/LayoutTests/transitions/clip-path-path-transitions.html</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (191550 => 191551)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2015-10-25 19:06:15 UTC (rev 191550)
+++ trunk/LayoutTests/ChangeLog        2015-10-26 04:57:46 UTC (rev 191551)
</span><span class="lines">@@ -1,3 +1,26 @@
</span><ins>+2015-10-25  Simon Fraser  &lt;simon.fraser@apple.com&gt;
+
+        Support bezier paths in clip-path property
+        https://bugs.webkit.org/show_bug.cgi?id=149996
+
+        Reviewed by Darin Adler.
+        
+        Tests for compositing with clip-path and a composited descendant,
+        a ref test which tests clip-paths with evenodd, comparing to SVG rendering,
+        and a transition test to test path blendability.
+
+        * compositing/masks/clip-path-composited-descendent-expected.txt: Added.
+        * compositing/masks/clip-path-composited-descendent.html: Added.
+        * css3/masking/clip-path-with-path-expected.html: Added.
+        * css3/masking/clip-path-with-path.html: Added.
+        * transitions/clip-path-path-transitions-expected.txt: Added.
+        * transitions/clip-path-path-transitions.html: Added.
+        * transitions/resources/transition-test-helpers.js: Add some basic parsing
+        support for paths.
+        (extractPathValues):
+        (parseClipPath):
+        * transitions/svg-transitions-expected.txt:
+
</ins><span class="cx"> 2015-10-25  Youenn Fablet  &lt;youenn.fablet@crf.canon.fr&gt;
</span><span class="cx"> 
</span><span class="cx">         Import W3C XMLHttpRequest tests
</span></span></pre></div>
<a id="trunkLayoutTestscompositingmasksclippathcompositeddescendentexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/compositing/masks/clip-path-composited-descendent-expected.txt (0 => 191551)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/compositing/masks/clip-path-composited-descendent-expected.txt                                (rev 0)
+++ trunk/LayoutTests/compositing/masks/clip-path-composited-descendent-expected.txt        2015-10-26 04:57:46 UTC (rev 191551)
</span><span class="lines">@@ -0,0 +1,27 @@
</span><ins>+(GraphicsLayer
+  (anchor 0.00 0.00)
+  (bounds 800.00 600.00)
+  (children 1
+    (GraphicsLayer
+      (bounds 800.00 600.00)
+      (contentsOpaque 1)
+      (children 1
+        (GraphicsLayer
+          (position 8.00 8.00)
+          (bounds 200.00 200.00)
+          (mask layer)
+            (GraphicsLayer
+              (bounds 200.00 200.00)
+            )
+          (children 1
+            (GraphicsLayer
+              (bounds 300.00 300.00)
+              (contentsOpaque 1)
+            )
+          )
+        )
+      )
+    )
+  )
+)
+
</ins></span></pre></div>
<a id="trunkLayoutTestscompositingmasksclippathcompositeddescendenthtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/compositing/masks/clip-path-composited-descendent.html (0 => 191551)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/compositing/masks/clip-path-composited-descendent.html                                (rev 0)
+++ trunk/LayoutTests/compositing/masks/clip-path-composited-descendent.html        2015-10-26 04:57:46 UTC (rev 191551)
</span><span class="lines">@@ -0,0 +1,40 @@
</span><ins>+&lt;!DOCTYPE html&gt;
+
+&lt;html&gt;
+&lt;head&gt;
+    &lt;title&gt;Tests that clip-path with a composited descendent triggers composited clipping&lt;/title&gt;
+    &lt;style&gt;
+        .box {
+            width: 200px;
+            height: 200px;
+            background-color: red;
+            -webkit-clip-path: inset(100px 100px 0px 0px);
+        }
+        
+        .child {
+            width: 300px;
+            height: 300px;
+            background-color: green;
+            -webkit-transform: translateZ(0);
+        }
+    &lt;/style&gt;
+    &lt;script&gt;
+        if (window.testRunner)
+            testRunner.dumpAsText();
+
+        function doTest()
+        {
+            if (window.internals)
+                document.getElementById('layers').textContent = window.internals.layerTreeAsText(document);
+
+        }
+        window.addEventListener('load', doTest, false);
+    &lt;/script&gt;
+&lt;/head&gt;
+&lt;body&gt;
+    &lt;div class=&quot;box&quot;&gt;
+        &lt;div class=&quot;child&quot;&gt;&lt;/div&gt;
+    &lt;/div&gt;
+&lt;pre id=&quot;layers&quot;&gt;&lt;/pre&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestscss3maskingclippathwithpathexpectedhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/css3/masking/clip-path-with-path-expected.html (0 => 191551)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/css3/masking/clip-path-with-path-expected.html                                (rev 0)
+++ trunk/LayoutTests/css3/masking/clip-path-with-path-expected.html        2015-10-26 04:57:46 UTC (rev 191551)
</span><span class="lines">@@ -0,0 +1,34 @@
</span><ins>+&lt;!DOCTYPE html&gt;
+
+&lt;html&gt;
+&lt;head&gt;
+    &lt;style&gt;
+        .box {
+            margin: 20px;
+            height: 150px;
+            width: 200px;
+        }
+    &lt;/style&gt;
+&lt;/head&gt;
+&lt;body&gt;
+
+&lt;div class=&quot;box&quot;&gt;
+    &lt;svg width=&quot;100%&quot; height=&quot;100%&quot; viewBox=&quot;0 0 200 150&quot;&gt;
+                &lt;clipPath id=&quot;clip1&quot;&gt;
+                        &lt;path d=&quot;M100,40l20,0 0,60 20,0 0,-20 -60,0 0,-20 80,0 0,60 -60,0 0,-80z&quot;/&gt;
+                &lt;/clipPath&gt;
+                &lt;rect x=&quot;50&quot; y=&quot;30&quot; width=&quot;350&quot; height=&quot;100&quot; fill=&quot;blue&quot; clip-path=&quot;url(#clip1)&quot;/&gt;
+    &lt;/svg&gt;
+&lt;/div&gt;
+
+&lt;div class=&quot;evenodd box&quot;&gt;
+    &lt;svg width=&quot;100%&quot; height=&quot;100%&quot; viewBox=&quot;0 0 200 150&quot;&gt;
+                &lt;clipPath id=&quot;clip2&quot;&gt;
+                        &lt;path clip-rule=&quot;evenodd&quot; d=&quot;M100,40l20,0 0,60 20,0 0,-20 -60,0 0,-20 80,0 0,60 -60,0 0,-80z&quot;/&gt;
+                &lt;/clipPath&gt;
+                &lt;rect x=&quot;50&quot; y=&quot;30&quot; width=&quot;350&quot; height=&quot;100&quot; fill=&quot;green&quot; clip-path=&quot;url(#clip2)&quot;/&gt;
+    &lt;/svg&gt;
+&lt;/div&gt;
+
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestscss3maskingclippathwithpathhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/css3/masking/clip-path-with-path.html (0 => 191551)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/css3/masking/clip-path-with-path.html                                (rev 0)
+++ trunk/LayoutTests/css3/masking/clip-path-with-path.html        2015-10-26 04:57:46 UTC (rev 191551)
</span><span class="lines">@@ -0,0 +1,26 @@
</span><ins>+&lt;!DOCTYPE html&gt;
+
+&lt;html&gt;
+&lt;head&gt;
+    &lt;style&gt;
+        .box {
+            margin: 20px;
+            height: 150px;
+            width: 200px;
+            -webkit-clip-path: path(&quot;M100,40l20,0 0,60 20,0 0,-20 -60,0 0,-20 80,0 0,60 -60,0 0,-80z&quot;);
+            background-color: blue;
+        }
+        
+        .box.evenodd {
+            -webkit-clip-path: path(evenodd, &quot;M100,40l20,0 0,60 20,0 0,-20 -60,0 0,-20 80,0 0,60 -60,0 0,-80z&quot;);
+            background-color: green;
+        }
+    &lt;/style&gt;
+&lt;/head&gt;
+&lt;body&gt;
+
+&lt;div class=&quot;box&quot;&gt;&lt;/div&gt;
+&lt;div class=&quot;evenodd box&quot;&gt;&lt;/div&gt;
+
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkLayoutTeststransitionsclippathpathtransitionsexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/transitions/clip-path-path-transitions-expected.txt (0 => 191551)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/transitions/clip-path-path-transitions-expected.txt                                (rev 0)
+++ trunk/LayoutTests/transitions/clip-path-path-transitions-expected.txt        2015-10-26 04:57:46 UTC (rev 191551)
</span><span class="lines">@@ -0,0 +1,5 @@
</span><ins>+  
+PASS - &quot;-webkit-clip-path&quot; property for &quot;path1&quot; element at 1s saw something close to: path('M 80 40 l 20 0 l 0 60 l 20 0 l 0 -20 l -50 0 l 0 -20 l 80 0 l 0 60 l -60 0 l 0 -80 Z')
+PASS - &quot;-webkit-clip-path&quot; property for &quot;path2&quot; element at 1s saw something close to: path('M 100 40 l 20 0 l 0 60 l 0 -20 l -60 0 l 0 -20 l 80 0 l 0 60 l -60 0 l 0 -80 Z')
+PASS - &quot;-webkit-clip-path&quot; property for &quot;path3&quot; element at 1s saw something close to: path(evenodd, 'M 100 40 l 20 0 l 0 60 l 20 0 l 0 -20 l -60 0 l 0 -20 l 80 0 l 0 60 l -60 0 l 0 -80 Z')
+
</ins></span></pre></div>
<a id="trunkLayoutTeststransitionsclippathpathtransitionshtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/transitions/clip-path-path-transitions.html (0 => 191551)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/transitions/clip-path-path-transitions.html                                (rev 0)
+++ trunk/LayoutTests/transitions/clip-path-path-transitions.html        2015-10-26 04:57:46 UTC (rev 191551)
</span><span class="lines">@@ -0,0 +1,66 @@
</span><ins>+&lt;!DOCTYPE html&gt;
+
+&lt;html&gt;
+&lt;head&gt;
+  &lt;style&gt;
+    .box {
+        display: inline-block;
+        height: 200px;
+        width: 200px;
+        margin: 10px;
+        background-color: gray;
+        transition: -webkit-clip-path 2s linear;
+    }
+    
+    #path1 {
+        -webkit-clip-path: path(&quot;M 60 40 l 20 0 l 0 60 l 20 0 l 0 -20 l -40 0 l 0 -20 l 80 0 l 0 60 l -60 0 l 0 -80 Z&quot;)
+    }
+    
+    body.final #path1 {
+        -webkit-clip-path: path(&quot;M 100 40 l 20 0 l 0 60 l 20 0 l 0 -20 l -60 0 l 0 -20 l 80 0 l 0 60 l -60 0 l 0 -80 Z&quot;);
+    }
+
+    /* Nonmatched segments, should not animate */
+    #path2 {
+        -webkit-clip-path: path(&quot;M 60 40 l 20 0 l 0 60 l 20 0 l 0 -20 l -40 0 l 0 -20 l 80 0 l 0 60 l -60 0 l 0 -80 Z&quot;)
+    }
+    
+    body.final #path2 {
+        -webkit-clip-path: path(&quot;M 100 40 l 20 0 l 0 60 l 0 -20 l -60 0 l 0 -20 l 80 0 l 0 60 l -60 0 l 0 -80 Z&quot;);
+    }
+
+    /* Nonmatched winding rule, should not animate */
+    #path3 {
+        -webkit-clip-path: path(&quot;M 60 40 l 20 0 l 0 60 l 20 0 l 0 -20 l -40 0 l 0 -20 l 80 0 l 0 60 l -60 0 l 0 -80 Z&quot;)
+    }
+    
+    body.final #path3 {
+        -webkit-clip-path: path(evenodd, &quot;M 100 40 l 20 0 l 0 60 l 20 0 l 0 -20 l -60 0 l 0 -20 l 80 0 l 0 60 l -60 0 l 0 -80 Z&quot;);
+    }
+  &lt;/style&gt;
+  &lt;script src=&quot;resources/transition-test-helpers.js&quot;&gt;&lt;/script&gt;
+  &lt;script type=&quot;text/javascript&quot;&gt;
+
+    const expectedValues = [
+      // [time, element-id, property, expected-value, tolerance]
+      [1, 'path1', '-webkit-clip-path', 'path(\'M 80 40 l 20 0 l 0 60 l 20 0 l 0 -20 l -50 0 l 0 -20 l 80 0 l 0 60 l -60 0 l 0 -80 Z\')', 2],
+      [1, 'path2', '-webkit-clip-path', 'path(\'M 100 40 l 20 0 l 0 60 l 0 -20 l -60 0 l 0 -20 l 80 0 l 0 60 l -60 0 l 0 -80 Z\')', 2],
+      [1, 'path3', '-webkit-clip-path', 'path(evenodd, \'M 100 40 l 20 0 l 0 60 l 20 0 l 0 -20 l -60 0 l 0 -20 l 80 0 l 0 60 l -60 0 l 0 -80 Z\')', 2],
+    ];
+  
+    function setupTest()
+    {
+        document.body.classList.add('final');
+    }
+    
+    runTransitionTest(expectedValues, setupTest, usePauseAPI);
+  &lt;/script&gt;
+&lt;/head&gt;
+&lt;body&gt;
+  &lt;div id=&quot;path1&quot; class=&quot;box&quot;&gt;&lt;/div&gt;
+  &lt;div id=&quot;path2&quot; class=&quot;box&quot;&gt;&lt;/div&gt;
+  &lt;div id=&quot;path3&quot; class=&quot;box&quot;&gt;&lt;/div&gt;
+
+  &lt;div id=&quot;result&quot;&gt;&lt;/div&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkLayoutTeststransitionsresourcestransitiontesthelpersjs"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/transitions/resources/transition-test-helpers.js (191550 => 191551)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/transitions/resources/transition-test-helpers.js        2015-10-25 19:06:15 UTC (rev 191550)
+++ trunk/LayoutTests/transitions/resources/transition-test-helpers.js        2015-10-26 04:57:46 UTC (rev 191551)
</span><span class="lines">@@ -69,17 +69,35 @@
</span><span class="cx">     return {&quot;from&quot;: matches[1], &quot;to&quot;: matches[2], &quot;percent&quot;: parseFloat(matches[3])}
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+function extractPathValues(path)
+{
+    var components = path.split(' ');
+    var result = [];
+    for (component of components) {
+        var compMatch;
+        if (compMatch = component.match(/[0-9.-]+/)) {
+            result.push(parseFloat(component))
+        }
+    }
+    return result;
+}
+
</ins><span class="cx"> function parseClipPath(s)
</span><span class="cx"> {
</span><ins>+    var pathMatch;
+    if (pathMatch = s.match(/path\(((evenodd|nonzero), ?)?\'(.+)\'\)/))
+        return extractPathValues(pathMatch[pathMatch.length - 1]);
+    
</ins><span class="cx">     // FIXME: This only matches a subset of the shape syntax, and the polygon expects 4 points.
</span><span class="cx">     var patterns = [
</span><span class="cx">         /inset\(([\d.]+)\w+ ([\d.]+)\w+\)/,
</span><span class="cx">         /circle\(([\d.]+)\w+ at ([\d.]+)\w+ ([\d.]+)\w+\)/,
</span><span class="cx">         /ellipse\(([\d.]+)\w+ ([\d.]+)\w+ at ([\d.]+)\w+ ([\d.]+)\w+\)/,
</span><del>-        /polygon\(([\d.]+)\w* ([\d.]+)\w*\, ([\d.]+)\w* ([\d.]+)\w*\, ([\d.]+)\w* ([\d.]+)\w*\, ([\d.]+)\w* ([\d.]+)\w*\)/
</del><ins>+        /polygon\(([\d.]+)\w* ([\d.]+)\w*\, ([\d.]+)\w* ([\d.]+)\w*\, ([\d.]+)\w* ([\d.]+)\w*\, ([\d.]+)\w* ([\d.]+)\w*\)/,
</ins><span class="cx">     ];
</span><span class="cx">     
</span><span class="cx">     for (pattern of patterns) {
</span><ins>+        var matchResult;
</ins><span class="cx">         if (matchResult = s.match(pattern)) {
</span><span class="cx">             var result = [];
</span><span class="cx">             for (var i = 1; i &lt; matchResult.length; ++i)
</span></span></pre></div>
<a id="trunkLayoutTeststransitionssvgtransitionsexpectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/transitions/svg-transitions-expected.txt (191550 => 191551)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/transitions/svg-transitions-expected.txt        2015-10-25 19:06:15 UTC (rev 191550)
+++ trunk/LayoutTests/transitions/svg-transitions-expected.txt        2015-10-26 04:57:46 UTC (rev 191551)
</span><span class="lines">@@ -1,4 +1,4 @@
</span><del>-CONSOLE MESSAGE: line 275: Failed to pause 'fill' transition on element 'rect7'
</del><ins>+CONSOLE MESSAGE: line 293: Failed to pause 'fill' transition on element 'rect7'
</ins><span class="cx"> Example
</span><span class="cx"> PASS - &quot;fill-opacity&quot; property for &quot;rect1&quot; element at 1s saw something close to: 0.6
</span><span class="cx"> PASS - &quot;stroke-width&quot; property for &quot;rect1&quot; element at 1s saw something close to: 3
</span></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (191550 => 191551)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2015-10-25 19:06:15 UTC (rev 191550)
+++ trunk/Source/WebCore/ChangeLog        2015-10-26 04:57:46 UTC (rev 191551)
</span><span class="lines">@@ -1,3 +1,79 @@
</span><ins>+2015-10-25  Simon Fraser  &lt;simon.fraser@apple.com&gt;
+
+        Support bezier paths in clip-path property
+        https://bugs.webkit.org/show_bug.cgi?id=149996
+
+        Reviewed by Darin Adler.
+        
+        Support path() in the -webkit-clip-path property, as specified in
+        https://drafts.csswg.org/css-shapes-2/#supported-basic-shapes
+        
+        Added BasicShapePath and CSSBasicShapePath, which both represent the path
+        as a SVGPathByteStream and wind rule.
+        
+        Make BasicShape::canBlend() a virtual function, and implement it on each subclass.
+        Make various BasicShape subclass function overrides private, other than windRule()
+        wich is called on derived classes in a few places.
+        
+        Add SVGPathBlender::canBlendPaths() which returns true if the given paths can be
+        interpolated. Uses the same logic as blendAnimatedPath(), without doing any interpolation.
+        
+        RenderElement::createsGroup() is fixed to have clip-path trigger a group,
+        which fixes rendering of clip-path with a descendant compositing layer.
+
+        Tests: compositing/masks/clip-path-composited-descendent.html
+               css3/masking/clip-path-with-path.html
+               transitions/clip-path-path-transitions.html
+
+        * css/BasicShapeFunctions.cpp:
+        (WebCore::valueForBasicShape):
+        (WebCore::basicShapeForValue):
+        * css/CSSBasicShapes.cpp:
+        (WebCore::CSSBasicShapePath::CSSBasicShapePath):
+        (WebCore::CSSBasicShapePath::pathData):
+        (WebCore::buildPathString):
+        (WebCore::CSSBasicShapePath::cssText):
+        (WebCore::CSSBasicShapePath::equals):
+        * css/CSSBasicShapes.h:
+        * css/CSSParser.cpp:
+        (WebCore::CSSParser::parseBasicShapePath):
+        (WebCore::CSSParser::parseBasicShape):
+        * css/CSSParser.h:
+        * rendering/RenderElement.h:
+        (WebCore::RenderElement::createsGroup):
+        * rendering/style/BasicShapes.cpp:
+        (WebCore::BasicShapeCircle::canBlend):
+        (WebCore::BasicShapeEllipse::canBlend):
+        (WebCore::BasicShapePolygon::canBlend):
+        (WebCore::BasicShapePath::BasicShapePath):
+        (WebCore::BasicShapePath::path):
+        (WebCore::BasicShapePath::operator==):
+        (WebCore::BasicShapePath::canBlend):
+        (WebCore::BasicShapePath::blend):
+        (WebCore::BasicShapeInset::canBlend):
+        (WebCore::BasicShape::canBlend): Deleted.
+        * rendering/style/BasicShapes.h:
+        * svg/SVGPathBlender.cpp:
+        (WebCore::SVGPathBlender::addAnimatedPath):
+        (WebCore::SVGPathBlender::blendAnimatedPath):
+        (WebCore::SVGPathBlender::canBlendPaths):
+        (WebCore::SVGPathBlender::SVGPathBlender):
+        (WebCore::SVGPathBlender::blendMoveToSegment):
+        (WebCore::SVGPathBlender::blendLineToSegment):
+        (WebCore::SVGPathBlender::blendLineToHorizontalSegment):
+        (WebCore::SVGPathBlender::blendLineToVerticalSegment):
+        (WebCore::SVGPathBlender::blendCurveToCubicSegment):
+        (WebCore::SVGPathBlender::blendCurveToCubicSmoothSegment):
+        (WebCore::SVGPathBlender::blendCurveToQuadraticSegment):
+        (WebCore::SVGPathBlender::blendCurveToQuadraticSmoothSegment):
+        (WebCore::SVGPathBlender::blendArcToSegment):
+        * svg/SVGPathBlender.h:
+        * svg/SVGPathByteStream.h:
+        (WebCore::SVGPathByteStream::operator==):
+        * svg/SVGPathUtilities.cpp:
+        (WebCore::canBlendSVGPathByteStreams):
+        * svg/SVGPathUtilities.h:
+
</ins><span class="cx"> 2015-10-25  Gwang Yoon Hwang  &lt;yoon@igalia.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [TexMap] Fix a misused flag for GstGL
</span></span></pre></div>
<a id="trunkSourceWebCorecssBasicShapeFunctionscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/css/BasicShapeFunctions.cpp (191550 => 191551)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/css/BasicShapeFunctions.cpp        2015-10-25 19:06:15 UTC (rev 191550)
+++ trunk/Source/WebCore/css/BasicShapeFunctions.cpp        2015-10-26 04:57:46 UTC (rev 191551)
</span><span class="lines">@@ -36,6 +36,7 @@
</span><span class="cx"> #include &quot;CSSValuePool.h&quot;
</span><span class="cx"> #include &quot;Pair.h&quot;
</span><span class="cx"> #include &quot;RenderStyle.h&quot;
</span><ins>+#include &quot;SVGPathByteStream.h&quot;
</ins><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><span class="lines">@@ -71,28 +72,30 @@
</span><span class="cx">     RefPtr&lt;CSSBasicShape&gt; basicShapeValue;
</span><span class="cx">     switch (basicShape.type()) {
</span><span class="cx">     case BasicShape::BasicShapeCircleType: {
</span><del>-        const auto&amp; circle = downcast&lt;BasicShapeCircle&gt;(basicShape);
</del><ins>+        auto&amp; circle = downcast&lt;BasicShapeCircle&gt;(basicShape);
</ins><span class="cx">         auto circleValue = CSSBasicShapeCircle::create();
</span><span class="cx"> 
</span><span class="cx">         circleValue-&gt;setCenterX(valueForCenterCoordinate(cssValuePool, style, circle.centerX(), HORIZONTAL));
</span><span class="cx">         circleValue-&gt;setCenterY(valueForCenterCoordinate(cssValuePool, style, circle.centerY(), VERTICAL));
</span><span class="cx">         circleValue-&gt;setRadius(basicShapeRadiusToCSSValue(style, cssValuePool, circle.radius()));
</span><del>-        basicShapeValue = circleValue.copyRef();
</del><ins>+
+        basicShapeValue = WTF::move(circleValue);
</ins><span class="cx">         break;
</span><span class="cx">     }
</span><span class="cx">     case BasicShape::BasicShapeEllipseType: {
</span><del>-        const auto&amp; ellipse = downcast&lt;BasicShapeEllipse&gt;(basicShape);
</del><ins>+        auto&amp; ellipse = downcast&lt;BasicShapeEllipse&gt;(basicShape);
</ins><span class="cx">         auto ellipseValue = CSSBasicShapeEllipse::create();
</span><span class="cx"> 
</span><span class="cx">         ellipseValue-&gt;setCenterX(valueForCenterCoordinate(cssValuePool, style, ellipse.centerX(), HORIZONTAL));
</span><span class="cx">         ellipseValue-&gt;setCenterY(valueForCenterCoordinate(cssValuePool, style, ellipse.centerY(), VERTICAL));
</span><span class="cx">         ellipseValue-&gt;setRadiusX(basicShapeRadiusToCSSValue(style, cssValuePool, ellipse.radiusX()));
</span><span class="cx">         ellipseValue-&gt;setRadiusY(basicShapeRadiusToCSSValue(style, cssValuePool, ellipse.radiusY()));
</span><del>-        basicShapeValue = ellipseValue.copyRef();
</del><ins>+
+        basicShapeValue = WTF::move(ellipseValue);
</ins><span class="cx">         break;
</span><span class="cx">     }
</span><span class="cx">     case BasicShape::BasicShapePolygonType: {
</span><del>-        const auto&amp; polygon = downcast&lt;BasicShapePolygon&gt;(basicShape);
</del><ins>+        auto&amp; polygon = downcast&lt;BasicShapePolygon&gt;(basicShape);
</ins><span class="cx">         auto polygonValue = CSSBasicShapePolygon::create();
</span><span class="cx"> 
</span><span class="cx">         polygonValue-&gt;setWindRule(polygon.windRule());
</span><span class="lines">@@ -100,11 +103,19 @@
</span><span class="cx">         for (unsigned i = 0; i &lt; values.size(); i += 2)
</span><span class="cx">             polygonValue-&gt;appendPoint(cssValuePool.createValue(values.at(i), style), cssValuePool.createValue(values.at(i + 1), style));
</span><span class="cx"> 
</span><del>-        basicShapeValue = polygonValue.copyRef();
</del><ins>+        basicShapeValue = WTF::move(polygonValue);
</ins><span class="cx">         break;
</span><span class="cx">     }
</span><ins>+    case BasicShape::BasicShapePathType: {
+        auto&amp; pathShape = downcast&lt;BasicShapePath&gt;(basicShape);
+        auto pathShapeValue = CSSBasicShapePath::create(pathShape.pathData()-&gt;copy());
+        pathShapeValue-&gt;setWindRule(pathShape.windRule());
+
+        basicShapeValue = WTF::move(pathShapeValue);
+        break;
+    }
</ins><span class="cx">     case BasicShape::BasicShapeInsetType: {
</span><del>-        const auto&amp; inset = downcast&lt;BasicShapeInset&gt;(basicShape);
</del><ins>+        auto&amp; inset = downcast&lt;BasicShapeInset&gt;(basicShape);
</ins><span class="cx">         auto insetValue = CSSBasicShapeInset::create();
</span><span class="cx"> 
</span><span class="cx">         insetValue-&gt;setTop(cssValuePool.createValue(inset.top(), style));
</span><span class="lines">@@ -117,11 +128,9 @@
</span><span class="cx">         insetValue-&gt;setBottomRightRadius(cssValuePool.createValue(inset.bottomRightRadius(), style));
</span><span class="cx">         insetValue-&gt;setBottomLeftRadius(cssValuePool.createValue(inset.bottomLeftRadius(), style));
</span><span class="cx"> 
</span><del>-        basicShapeValue = insetValue.copyRef();
</del><ins>+        basicShapeValue = WTF::move(insetValue);
</ins><span class="cx">         break;
</span><span class="cx">     }
</span><del>-    default:
-        break;
</del><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     return cssValuePool.createValue(basicShapeValue.releaseNonNull());
</span><span class="lines">@@ -205,19 +214,19 @@
</span><span class="cx"> 
</span><span class="cx">     switch (basicShapeValue-&gt;type()) {
</span><span class="cx">     case CSSBasicShape::CSSBasicShapeCircleType: {
</span><del>-        const CSSBasicShapeCircle&amp; circleValue = downcast&lt;CSSBasicShapeCircle&gt;(*basicShapeValue);
-        RefPtr&lt;BasicShapeCircle&gt; circle = BasicShapeCircle::create();
</del><ins>+        auto&amp; circleValue = downcast&lt;CSSBasicShapeCircle&gt;(*basicShapeValue);
+        auto circle = BasicShapeCircle::create();
</ins><span class="cx"> 
</span><span class="cx">         circle-&gt;setCenterX(convertToCenterCoordinate(conversionData, circleValue.centerX()));
</span><span class="cx">         circle-&gt;setCenterY(convertToCenterCoordinate(conversionData, circleValue.centerY()));
</span><span class="cx">         circle-&gt;setRadius(cssValueToBasicShapeRadius(conversionData, circleValue.radius()));
</span><span class="cx"> 
</span><del>-        basicShape = circle.release();
</del><ins>+        basicShape = WTF::move(circle);
</ins><span class="cx">         break;
</span><span class="cx">     }
</span><span class="cx">     case CSSBasicShape::CSSBasicShapeEllipseType: {
</span><del>-        const CSSBasicShapeEllipse&amp; ellipseValue = downcast&lt;CSSBasicShapeEllipse&gt;(*basicShapeValue);
-        RefPtr&lt;BasicShapeEllipse&gt; ellipse = BasicShapeEllipse::create();
</del><ins>+        auto&amp; ellipseValue = downcast&lt;CSSBasicShapeEllipse&gt;(*basicShapeValue);
+        auto ellipse = BasicShapeEllipse::create();
</ins><span class="cx"> 
</span><span class="cx">         ellipse-&gt;setCenterX(convertToCenterCoordinate(conversionData, ellipseValue.centerX()));
</span><span class="cx">         ellipse-&gt;setCenterY(convertToCenterCoordinate(conversionData, ellipseValue.centerY()));
</span><span class="lines">@@ -225,24 +234,24 @@
</span><span class="cx">         ellipse-&gt;setRadiusX(cssValueToBasicShapeRadius(conversionData, ellipseValue.radiusX()));
</span><span class="cx">         ellipse-&gt;setRadiusY(cssValueToBasicShapeRadius(conversionData, ellipseValue.radiusY()));
</span><span class="cx"> 
</span><del>-        basicShape = ellipse.release();
</del><ins>+        basicShape = WTF::move(ellipse);
</ins><span class="cx">         break;
</span><span class="cx">     }
</span><span class="cx">     case CSSBasicShape::CSSBasicShapePolygonType: {
</span><del>-        const CSSBasicShapePolygon&amp; polygonValue = downcast&lt;CSSBasicShapePolygon&gt;(*basicShapeValue);
-        RefPtr&lt;BasicShapePolygon&gt; polygon = BasicShapePolygon::create();
</del><ins>+        auto&amp; polygonValue = downcast&lt;CSSBasicShapePolygon&gt;(*basicShapeValue);
+        auto polygon = BasicShapePolygon::create();
</ins><span class="cx"> 
</span><span class="cx">         polygon-&gt;setWindRule(polygonValue.windRule());
</span><span class="cx">         const Vector&lt;RefPtr&lt;CSSPrimitiveValue&gt;&gt;&amp; values = polygonValue.values();
</span><span class="cx">         for (unsigned i = 0; i &lt; values.size(); i += 2)
</span><span class="cx">             polygon-&gt;appendPoint(convertToLength(conversionData, values.at(i).get()), convertToLength(conversionData, values.at(i + 1).get()));
</span><span class="cx"> 
</span><del>-        basicShape = polygon.release();
</del><ins>+        basicShape = WTF::move(polygon);
</ins><span class="cx">         break;
</span><span class="cx">     }
</span><span class="cx">     case CSSBasicShape::CSSBasicShapeInsetType: {
</span><del>-        const CSSBasicShapeInset&amp; rectValue = downcast&lt;CSSBasicShapeInset&gt;(*basicShapeValue);
-        RefPtr&lt;BasicShapeInset&gt; rect = BasicShapeInset::create();
</del><ins>+        auto&amp; rectValue = downcast&lt;CSSBasicShapeInset&gt;(*basicShapeValue);
+        auto rect = BasicShapeInset::create();
</ins><span class="cx"> 
</span><span class="cx">         rect-&gt;setTop(convertToLength(conversionData, rectValue.top()));
</span><span class="cx">         rect-&gt;setRight(convertToLength(conversionData, rectValue.right()));
</span><span class="lines">@@ -254,12 +263,18 @@
</span><span class="cx">         rect-&gt;setBottomRightRadius(convertToLengthSize(conversionData, rectValue.bottomRightRadius()));
</span><span class="cx">         rect-&gt;setBottomLeftRadius(convertToLengthSize(conversionData, rectValue.bottomLeftRadius()));
</span><span class="cx"> 
</span><del>-        basicShape = rect.release();
</del><ins>+        basicShape = WTF::move(rect);
</ins><span class="cx">         break;
</span><span class="cx">     }
</span><del>-    default:
</del><ins>+    case CSSBasicShape::CSSBasicShapePathType: {
+        auto&amp; pathValue = downcast&lt;CSSBasicShapePath&gt;(*basicShapeValue);
+        auto path = BasicShapePath::create(pathValue.pathData().copy());
+        path-&gt;setWindRule(pathValue.windRule());
+
+        basicShape = WTF::move(path);
</ins><span class="cx">         break;
</span><span class="cx">     }
</span><ins>+    }
</ins><span class="cx"> 
</span><span class="cx">     return basicShape.releaseNonNull();
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceWebCorecssCSSBasicShapescpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/css/CSSBasicShapes.cpp (191550 => 191551)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/css/CSSBasicShapes.cpp        2015-10-25 19:06:15 UTC (rev 191550)
+++ trunk/Source/WebCore/css/CSSBasicShapes.cpp        2015-10-26 04:57:46 UTC (rev 191551)
</span><span class="lines">@@ -31,9 +31,12 @@
</span><span class="cx"> 
</span><span class="cx"> #include &quot;CSSBasicShapes.h&quot;
</span><span class="cx"> 
</span><ins>+#include &quot;CSSParser.h&quot;
</ins><span class="cx"> #include &quot;CSSPrimitiveValueMappings.h&quot;
</span><span class="cx"> #include &quot;CSSValuePool.h&quot;
</span><span class="cx"> #include &quot;Pair.h&quot;
</span><ins>+#include &quot;SVGPathByteStream.h&quot;
+#include &quot;SVGPathUtilities.h&quot;
</ins><span class="cx"> #include &lt;wtf/text/StringBuilder.h&gt;
</span><span class="cx"> 
</span><span class="cx"> using namespace WTF;
</span><span class="lines">@@ -198,6 +201,47 @@
</span><span class="cx">         &amp;&amp; compareCSSValuePtr(m_radiusY, other.m_radiusY);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+CSSBasicShapePath::CSSBasicShapePath(std::unique_ptr&lt;SVGPathByteStream&gt;&amp;&amp; pathData)
+    : m_byteStream(WTF::move(pathData))
+{
+}
+
+static String buildPathString(const WindRule&amp; windRule, const String&amp; path, const String&amp; box)
+{
+    StringBuilder result;
+    if (windRule == RULE_EVENODD)
+        result.appendLiteral(&quot;path(evenodd, &quot;);
+    else
+        result.appendLiteral(&quot;path(&quot;);
+
+    result.append(quoteCSSString(path));
+    result.append(')');
+
+    if (box.length()) {
+        result.append(' ');
+        result.append(box);
+    }
+
+    return result.toString();
+}
+
+String CSSBasicShapePath::cssText() const
+{
+    String pathString;
+    buildStringFromByteStream(*m_byteStream, pathString, UnalteredParsing);
+
+    return buildPathString(m_windRule, pathString, m_referenceBox ? m_referenceBox-&gt;cssText() : String());
+}
+
+bool CSSBasicShapePath::equals(const CSSBasicShape&amp; otherShape) const
+{
+    if (!is&lt;CSSBasicShapePath&gt;(otherShape))
+        return false;
+
+    auto&amp; otherShapePath = downcast&lt;CSSBasicShapePath&gt;(otherShape);
+    return windRule() == otherShapePath.windRule() &amp;&amp; pathData() == otherShapePath.pathData();
+}
+
</ins><span class="cx"> static String buildPolygonString(const WindRule&amp; windRule, const Vector&lt;String&gt;&amp; points)
</span><span class="cx"> {
</span><span class="cx">     ASSERT(!(points.size() % 2));
</span></span></pre></div>
<a id="trunkSourceWebCorecssCSSBasicShapesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/css/CSSBasicShapes.h (191550 => 191551)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/css/CSSBasicShapes.h        2015-10-25 19:06:15 UTC (rev 191550)
+++ trunk/Source/WebCore/css/CSSBasicShapes.h        2015-10-26 04:57:46 UTC (rev 191551)
</span><span class="lines">@@ -39,13 +39,16 @@
</span><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><ins>+class SVGPathByteStream;
+
</ins><span class="cx"> class CSSBasicShape : public RefCounted&lt;CSSBasicShape&gt; {
</span><span class="cx"> public:
</span><span class="cx">     enum Type {
</span><span class="cx">         CSSBasicShapePolygonType,
</span><span class="cx">         CSSBasicShapeCircleType,
</span><span class="cx">         CSSBasicShapeEllipseType,
</span><del>-        CSSBasicShapeInsetType
</del><ins>+        CSSBasicShapeInsetType,
+        CSSBasicShapePathType
</ins><span class="cx">     };
</span><span class="cx"> 
</span><span class="cx">     virtual Type type() const = 0;
</span><span class="lines">@@ -107,13 +110,12 @@
</span><span class="cx">     void setBottomRightRadius(PassRefPtr&lt;CSSPrimitiveValue&gt; radius) { m_bottomRightRadius = radius; }
</span><span class="cx">     void setBottomLeftRadius(PassRefPtr&lt;CSSPrimitiveValue&gt; radius) { m_bottomLeftRadius = radius; }
</span><span class="cx"> 
</span><del>-    virtual String cssText() const override;
-    virtual bool equals(const CSSBasicShape&amp;) const override;
-
</del><span class="cx"> private:
</span><span class="cx">     CSSBasicShapeInset() { }
</span><span class="cx"> 
</span><span class="cx">     virtual Type type() const override { return CSSBasicShapeInsetType; }
</span><ins>+    virtual String cssText() const override;
+    virtual bool equals(const CSSBasicShape&amp;) const override;
</ins><span class="cx"> 
</span><span class="cx">     RefPtr&lt;CSSPrimitiveValue&gt; m_top;
</span><span class="cx">     RefPtr&lt;CSSPrimitiveValue&gt; m_right;
</span><span class="lines">@@ -130,9 +132,6 @@
</span><span class="cx"> public:
</span><span class="cx">     static Ref&lt;CSSBasicShapeCircle&gt; create() { return adoptRef(*new CSSBasicShapeCircle); }
</span><span class="cx"> 
</span><del>-    virtual String cssText() const override;
-    virtual bool equals(const CSSBasicShape&amp;) const override;
-
</del><span class="cx">     CSSPrimitiveValue* centerX() const { return m_centerX.get(); }
</span><span class="cx">     CSSPrimitiveValue* centerY() const { return m_centerY.get(); }
</span><span class="cx">     CSSPrimitiveValue* radius() const { return m_radius.get(); }
</span><span class="lines">@@ -145,6 +144,8 @@
</span><span class="cx">     CSSBasicShapeCircle() { }
</span><span class="cx"> 
</span><span class="cx">     virtual Type type() const override { return CSSBasicShapeCircleType; }
</span><ins>+    virtual String cssText() const override;
+    virtual bool equals(const CSSBasicShape&amp;) const override;
</ins><span class="cx"> 
</span><span class="cx">     RefPtr&lt;CSSPrimitiveValue&gt; m_centerX;
</span><span class="cx">     RefPtr&lt;CSSPrimitiveValue&gt; m_centerY;
</span><span class="lines">@@ -165,13 +166,12 @@
</span><span class="cx">     void setRadiusX(PassRefPtr&lt;CSSPrimitiveValue&gt; radiusX) { m_radiusX = radiusX; }
</span><span class="cx">     void setRadiusY(PassRefPtr&lt;CSSPrimitiveValue&gt; radiusY) { m_radiusY = radiusY; }
</span><span class="cx"> 
</span><del>-    virtual String cssText() const override;
-    virtual bool equals(const CSSBasicShape&amp;) const override;
-
</del><span class="cx"> private:
</span><span class="cx">     CSSBasicShapeEllipse() { }
</span><span class="cx"> 
</span><span class="cx">     virtual Type type() const override { return CSSBasicShapeEllipseType; }
</span><ins>+    virtual String cssText() const override;
+    virtual bool equals(const CSSBasicShape&amp;) const override;
</ins><span class="cx"> 
</span><span class="cx">     RefPtr&lt;CSSPrimitiveValue&gt; m_centerX;
</span><span class="cx">     RefPtr&lt;CSSPrimitiveValue&gt; m_centerY;
</span><span class="lines">@@ -193,12 +193,9 @@
</span><span class="cx">     RefPtr&lt;CSSPrimitiveValue&gt; getYAt(unsigned i) const { return m_values.at(i * 2 + 1); }
</span><span class="cx">     const Vector&lt;RefPtr&lt;CSSPrimitiveValue&gt;&gt;&amp; values() const { return m_values; }
</span><span class="cx"> 
</span><del>-    void setWindRule(WindRule w) { m_windRule = w; }
</del><ins>+    void setWindRule(WindRule rule) { m_windRule = rule; }
</ins><span class="cx">     WindRule windRule() const { return m_windRule; }
</span><span class="cx"> 
</span><del>-    virtual String cssText() const override;
-    virtual bool equals(const CSSBasicShape&amp;) const override;
-
</del><span class="cx"> private:
</span><span class="cx">     CSSBasicShapePolygon()
</span><span class="cx">         : m_windRule(RULE_NONZERO)
</span><span class="lines">@@ -206,11 +203,39 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     virtual Type type() const override { return CSSBasicShapePolygonType; }
</span><ins>+    virtual String cssText() const override;
+    virtual bool equals(const CSSBasicShape&amp;) const override;
</ins><span class="cx"> 
</span><span class="cx">     Vector&lt;RefPtr&lt;CSSPrimitiveValue&gt;&gt; m_values;
</span><span class="cx">     WindRule m_windRule;
</span><span class="cx"> };
</span><span class="cx"> 
</span><ins>+class CSSBasicShapePath final : public CSSBasicShape {
+public:
+    static Ref&lt;CSSBasicShapePath&gt; create(std::unique_ptr&lt;SVGPathByteStream&gt;&amp;&amp; pathData)
+    {
+        return adoptRef(*new CSSBasicShapePath(WTF::move(pathData)));
+    }
+
+    const SVGPathByteStream&amp; pathData() const
+    {
+        return *m_byteStream;
+    }
+
+    void setWindRule(WindRule rule) { m_windRule = rule; }
+    WindRule windRule() const { return m_windRule; }
+
+private:
+    CSSBasicShapePath(std::unique_ptr&lt;SVGPathByteStream&gt;&amp;&amp;);
+
+    virtual Type type() const override { return CSSBasicShapePathType; }
+    virtual String cssText() const override;
+    virtual bool equals(const CSSBasicShape&amp;) const override;
+
+    std::unique_ptr&lt;SVGPathByteStream&gt; m_byteStream;
+    WindRule m_windRule { RULE_NONZERO };
+};
+
</ins><span class="cx"> } // namespace WebCore
</span><span class="cx"> 
</span><span class="cx"> #define SPECIALIZE_TYPE_TRAITS_CSS_BASIC_SHAPES(ToValueTypeName) \
</span><span class="lines">@@ -222,5 +247,6 @@
</span><span class="cx"> SPECIALIZE_TYPE_TRAITS_CSS_BASIC_SHAPES(CSSBasicShapeCircle)
</span><span class="cx"> SPECIALIZE_TYPE_TRAITS_CSS_BASIC_SHAPES(CSSBasicShapeEllipse)
</span><span class="cx"> SPECIALIZE_TYPE_TRAITS_CSS_BASIC_SHAPES(CSSBasicShapePolygon)
</span><ins>+SPECIALIZE_TYPE_TRAITS_CSS_BASIC_SHAPES(CSSBasicShapePath)
</ins><span class="cx"> 
</span><span class="cx"> #endif // CSSBasicShapes_h
</span></span></pre></div>
<a id="trunkSourceWebCorecssCSSParsercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/css/CSSParser.cpp (191550 => 191551)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/css/CSSParser.cpp        2015-10-25 19:06:15 UTC (rev 191550)
+++ trunk/Source/WebCore/css/CSSParser.cpp        2015-10-26 04:57:46 UTC (rev 191551)
</span><span class="lines">@@ -83,6 +83,8 @@
</span><span class="cx"> #include &quot;RenderTheme.h&quot;
</span><span class="cx"> #include &quot;RuntimeEnabledFeatures.h&quot;
</span><span class="cx"> #include &quot;SVGParserUtilities.h&quot;
</span><ins>+#include &quot;SVGPathByteStream.h&quot;
+#include &quot;SVGPathUtilities.h&quot;
</ins><span class="cx"> #include &quot;SelectorChecker.h&quot;
</span><span class="cx"> #include &quot;SelectorCheckerTestFunctions.h&quot;
</span><span class="cx"> #include &quot;Settings.h&quot;
</span><span class="lines">@@ -6638,6 +6640,37 @@
</span><span class="cx">     return shape;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+RefPtr&lt;CSSBasicShape&gt; CSSParser::parseBasicShapePath(CSSParserValueList&amp; args)
+{
+    unsigned size = args.size();
+    if (size != 1 &amp;&amp; size != 3)
+        return nullptr;
+
+    WindRule windRule = RULE_NONZERO;
+
+    CSSParserValue* argument = args.current();
+    if (argument-&gt;id == CSSValueEvenodd || argument-&gt;id == CSSValueNonzero) {
+        windRule = argument-&gt;id == CSSValueEvenodd ? RULE_EVENODD : RULE_NONZERO;
+
+        if (!isComma(args.next()))
+            return nullptr;
+        argument = args.next();
+    }
+
+    if (argument-&gt;unit != CSSPrimitiveValue::CSS_STRING)
+        return nullptr;
+
+    auto byteStream = std::make_unique&lt;SVGPathByteStream&gt;();
+    if (!buildSVGPathByteStreamFromString(argument-&gt;string, *byteStream, UnalteredParsing))
+        return nullptr;
+
+    RefPtr&lt;CSSBasicShapePath&gt; shape = CSSBasicShapePath::create(WTF::move(byteStream));
+    shape-&gt;setWindRule(windRule);
+
+    args.next();
+    return shape;
+}
+
</ins><span class="cx"> static bool isBoxValue(CSSValueID valueId, CSSPropertyID propId)
</span><span class="cx"> {
</span><span class="cx">     switch (valueId) {
</span><span class="lines">@@ -6748,6 +6781,8 @@
</span><span class="cx">         shape = parseBasicShapeEllipse(*args);
</span><span class="cx">     else if (equalIgnoringCase(value.function-&gt;name, &quot;polygon(&quot;))
</span><span class="cx">         shape = parseBasicShapePolygon(*args);
</span><ins>+    else if (equalIgnoringCase(value.function-&gt;name, &quot;path(&quot;))
+        shape = parseBasicShapePath(*args);
</ins><span class="cx">     else if (equalIgnoringCase(value.function-&gt;name, &quot;inset(&quot;))
</span><span class="cx">         shape = parseBasicShapeInset(*args);
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCorecssCSSParserh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/css/CSSParser.h (191550 => 191551)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/css/CSSParser.h        2015-10-25 19:06:15 UTC (rev 191550)
+++ trunk/Source/WebCore/css/CSSParser.h        2015-10-26 04:57:46 UTC (rev 191551)
</span><span class="lines">@@ -244,6 +244,7 @@
</span><span class="cx">     RefPtr&lt;CSSBasicShape&gt; parseBasicShapeCircle(CSSParserValueList&amp;);
</span><span class="cx">     RefPtr&lt;CSSBasicShape&gt; parseBasicShapeEllipse(CSSParserValueList&amp;);
</span><span class="cx">     RefPtr&lt;CSSBasicShape&gt; parseBasicShapePolygon(CSSParserValueList&amp;);
</span><ins>+    RefPtr&lt;CSSBasicShape&gt; parseBasicShapePath(CSSParserValueList&amp;);
</ins><span class="cx">     RefPtr&lt;CSSBasicShape&gt; parseBasicShapeInset(CSSParserValueList&amp;);
</span><span class="cx"> 
</span><span class="cx">     bool parseFont(bool important);
</span></span></pre></div>
<a id="trunkSourceWebCorerenderingRenderElementh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/rendering/RenderElement.h (191550 => 191551)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/rendering/RenderElement.h        2015-10-25 19:06:15 UTC (rev 191550)
+++ trunk/Source/WebCore/rendering/RenderElement.h        2015-10-26 04:57:46 UTC (rev 191551)
</span><span class="lines">@@ -152,7 +152,7 @@
</span><span class="cx">     bool mayCauseRepaintInsideViewport(const IntRect* visibleRect = nullptr) const;
</span><span class="cx"> 
</span><span class="cx">     // Returns true if this renderer requires a new stacking context.
</span><del>-    bool createsGroup() const { return isTransparent() || hasMask() || hasFilter() || hasBackdropFilter() || hasBlendMode(); }
</del><ins>+    bool createsGroup() const { return isTransparent() || hasMask() || hasClipPath() || hasFilter() || hasBackdropFilter() || hasBlendMode(); }
</ins><span class="cx"> 
</span><span class="cx">     bool isTransparent() const { return style().opacity() &lt; 1.0f; }
</span><span class="cx">     float opacity() const { return style().opacity(); }
</span></span></pre></div>
<a id="trunkSourceWebCorerenderingstyleBasicShapescpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/rendering/style/BasicShapes.cpp (191550 => 191551)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/rendering/style/BasicShapes.cpp        2015-10-25 19:06:15 UTC (rev 191550)
+++ trunk/Source/WebCore/rendering/style/BasicShapes.cpp        2015-10-26 04:57:46 UTC (rev 191551)
</span><span class="lines">@@ -38,6 +38,8 @@
</span><span class="cx"> #include &quot;LengthFunctions.h&quot;
</span><span class="cx"> #include &quot;Path.h&quot;
</span><span class="cx"> #include &quot;RenderBox.h&quot;
</span><ins>+#include &quot;SVGPathByteStream.h&quot;
+#include &quot;SVGPathUtilities.h&quot;
</ins><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><span class="lines">@@ -58,43 +60,12 @@
</span><span class="cx">     m_computedLength = Length(CalculationValue::create(WTF::move(op), CalculationRangeAll));
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool BasicShape::canBlend(const BasicShape&amp; other) const
-{
-    // FIXME: Support animations between different shapes in the future.
-    if (type() != other.type())
-        return false;
-
-    // Just polygons with same number of vertices can be animated.
-    if (is&lt;BasicShapePolygon&gt;(*this)
-        &amp;&amp; (downcast&lt;BasicShapePolygon&gt;(*this).values().size() != downcast&lt;BasicShapePolygon&gt;(other).values().size()
-        || downcast&lt;BasicShapePolygon&gt;(*this).windRule() != downcast&lt;BasicShapePolygon&gt;(other).windRule()))
-        return false;
-
-    // Circles with keywords for radii coordinates cannot be animated.
-    if (is&lt;BasicShapeCircle&gt;(*this)) {
-        const auto&amp; thisCircle = downcast&lt;BasicShapeCircle&gt;(*this);
-        const auto&amp; otherCircle = downcast&lt;BasicShapeCircle&gt;(other);
-        if (!thisCircle.radius().canBlend(otherCircle.radius()))
-            return false;
-    }
-
-    // Ellipses with keywords for radii coordinates cannot be animated.
-    if (!is&lt;BasicShapeEllipse&gt;(*this))
-        return true;
-
-    const auto&amp; thisEllipse = downcast&lt;BasicShapeEllipse&gt;(*this);
-    const auto&amp; otherEllipse = downcast&lt;BasicShapeEllipse&gt;(other);
-    return (thisEllipse.radiusX().canBlend(otherEllipse.radiusX())
-        &amp;&amp; thisEllipse.radiusY().canBlend(otherEllipse.radiusY()));
-}
-
-
</del><span class="cx"> bool BasicShapeCircle::operator==(const BasicShape&amp; other) const
</span><span class="cx"> {
</span><span class="cx">     if (type() != other.type())
</span><span class="cx">         return false;
</span><span class="cx"> 
</span><del>-    const auto&amp; otherCircle = downcast&lt;BasicShapeCircle&gt;(other);
</del><ins>+    auto&amp; otherCircle = downcast&lt;BasicShapeCircle&gt;(other);
</ins><span class="cx">     return m_centerX == otherCircle.m_centerX
</span><span class="cx">         &amp;&amp; m_centerY == otherCircle.m_centerY
</span><span class="cx">         &amp;&amp; m_radius == otherCircle.m_radius;
</span><span class="lines">@@ -132,16 +103,24 @@
</span><span class="cx">     ));
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool BasicShapeCircle::canBlend(const BasicShape&amp; other) const
+{
+    if (type() != other.type())
+        return false;
+
+    return radius().canBlend(downcast&lt;BasicShapeCircle&gt;(other).radius());
+}
+
</ins><span class="cx"> Ref&lt;BasicShape&gt; BasicShapeCircle::blend(const BasicShape&amp; other, double progress) const
</span><span class="cx"> {
</span><span class="cx">     ASSERT(type() == other.type());
</span><del>-    const auto&amp; otherCircle = downcast&lt;BasicShapeCircle&gt;(other);
-    RefPtr&lt;BasicShapeCircle&gt; result =  BasicShapeCircle::create();
</del><ins>+    auto&amp; otherCircle = downcast&lt;BasicShapeCircle&gt;(other);
+    auto result =  BasicShapeCircle::create();
</ins><span class="cx"> 
</span><span class="cx">     result-&gt;setCenterX(m_centerX.blend(otherCircle.centerX(), progress));
</span><span class="cx">     result-&gt;setCenterY(m_centerY.blend(otherCircle.centerY(), progress));
</span><span class="cx">     result-&gt;setRadius(m_radius.blend(otherCircle.radius(), progress));
</span><del>-    return result.releaseNonNull();
</del><ins>+    return WTF::move(result);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> bool BasicShapeEllipse::operator==(const BasicShape&amp; other) const
</span><span class="lines">@@ -149,7 +128,7 @@
</span><span class="cx">     if (type() != other.type())
</span><span class="cx">         return false;
</span><span class="cx"> 
</span><del>-    const auto&amp; otherEllipse = downcast&lt;BasicShapeEllipse&gt;(other);
</del><ins>+    auto&amp; otherEllipse = downcast&lt;BasicShapeEllipse&gt;(other);
</ins><span class="cx">     return m_centerX == otherEllipse.m_centerX
</span><span class="cx">         &amp;&amp; m_centerY == otherEllipse.m_centerY
</span><span class="cx">         &amp;&amp; m_radiusX == otherEllipse.m_radiusX
</span><span class="lines">@@ -184,11 +163,20 @@
</span><span class="cx">         radiusY * 2));
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool BasicShapeEllipse::canBlend(const BasicShape&amp; other) const
+{
+    if (type() != other.type())
+        return false;
+
+    auto&amp; otherEllipse = downcast&lt;BasicShapeEllipse&gt;(other);
+    return radiusX().canBlend(otherEllipse.radiusX()) &amp;&amp; radiusY().canBlend(otherEllipse.radiusY());
+}
+
</ins><span class="cx"> Ref&lt;BasicShape&gt; BasicShapeEllipse::blend(const BasicShape&amp; other, double progress) const
</span><span class="cx"> {
</span><span class="cx">     ASSERT(type() == other.type());
</span><del>-    const auto&amp; otherEllipse = downcast&lt;BasicShapeEllipse&gt;(other);
-    RefPtr&lt;BasicShapeEllipse&gt; result = BasicShapeEllipse::create();
</del><ins>+    auto&amp; otherEllipse = downcast&lt;BasicShapeEllipse&gt;(other);
+    auto result = BasicShapeEllipse::create();
</ins><span class="cx"> 
</span><span class="cx">     if (m_radiusX.type() != BasicShapeRadius::Value || otherEllipse.radiusX().type() != BasicShapeRadius::Value
</span><span class="cx">         || m_radiusY.type() != BasicShapeRadius::Value || otherEllipse.radiusY().type() != BasicShapeRadius::Value) {
</span><span class="lines">@@ -196,14 +184,14 @@
</span><span class="cx">         result-&gt;setCenterY(otherEllipse.centerY());
</span><span class="cx">         result-&gt;setRadiusX(otherEllipse.radiusX());
</span><span class="cx">         result-&gt;setRadiusY(otherEllipse.radiusY());
</span><del>-        return result.releaseNonNull();
</del><ins>+        return WTF::move(result);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     result-&gt;setCenterX(m_centerX.blend(otherEllipse.centerX(), progress));
</span><span class="cx">     result-&gt;setCenterY(m_centerY.blend(otherEllipse.centerY(), progress));
</span><span class="cx">     result-&gt;setRadiusX(m_radiusX.blend(otherEllipse.radiusX(), progress));
</span><span class="cx">     result-&gt;setRadiusY(m_radiusY.blend(otherEllipse.radiusY(), progress));
</span><del>-    return result.releaseNonNull();
</del><ins>+    return WTF::move(result);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> bool BasicShapePolygon::operator==(const BasicShape&amp; other) const
</span><span class="lines">@@ -211,7 +199,7 @@
</span><span class="cx">     if (type() != other.type())
</span><span class="cx">         return false;
</span><span class="cx"> 
</span><del>-    const auto&amp; otherPolygon = downcast&lt;BasicShapePolygon&gt;(other);
</del><ins>+    auto&amp; otherPolygon = downcast&lt;BasicShapePolygon&gt;(other);
</ins><span class="cx">     return m_windRule == otherPolygon.m_windRule
</span><span class="cx">         &amp;&amp; m_values == otherPolygon.m_values;
</span><span class="cx"> }
</span><span class="lines">@@ -234,18 +222,27 @@
</span><span class="cx">     path.closeSubpath();
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool BasicShapePolygon::canBlend(const BasicShape&amp; other) const
+{
+    if (type() != other.type())
+        return false;
+
+    auto&amp; otherPolygon = downcast&lt;BasicShapePolygon&gt;(other);
+    return values().size() == otherPolygon.values().size() &amp;&amp; windRule() == otherPolygon.windRule();
+}
+
</ins><span class="cx"> Ref&lt;BasicShape&gt; BasicShapePolygon::blend(const BasicShape&amp; other, double progress) const
</span><span class="cx"> {
</span><span class="cx">     ASSERT(type() == other.type());
</span><span class="cx"> 
</span><del>-    const auto&amp; otherPolygon = downcast&lt;BasicShapePolygon&gt;(other);
</del><ins>+    auto&amp; otherPolygon = downcast&lt;BasicShapePolygon&gt;(other);
</ins><span class="cx">     ASSERT(m_values.size() == otherPolygon.values().size());
</span><span class="cx">     ASSERT(!(m_values.size() % 2));
</span><span class="cx"> 
</span><span class="cx">     size_t length = m_values.size();
</span><del>-    RefPtr&lt;BasicShapePolygon&gt; result = BasicShapePolygon::create();
</del><ins>+    auto result = BasicShapePolygon::create();
</ins><span class="cx">     if (!length)
</span><del>-        return result.releaseNonNull();
</del><ins>+        return WTF::move(result);
</ins><span class="cx"> 
</span><span class="cx">     result-&gt;setWindRule(otherPolygon.windRule());
</span><span class="cx"> 
</span><span class="lines">@@ -254,15 +251,59 @@
</span><span class="cx">             m_values.at(i + 1).blend(otherPolygon.values().at(i + 1), progress));
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    return result.releaseNonNull();
</del><ins>+    return WTF::move(result);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+BasicShapePath::BasicShapePath(std::unique_ptr&lt;SVGPathByteStream&gt;&amp;&amp; byteStream)
+    : m_byteStream(WTF::move(byteStream))
+{
+}
+
+void BasicShapePath::path(Path&amp; path, const FloatRect&amp; boundingBox)
+{
+    ASSERT(path.isEmpty());
+    buildPathFromByteStream(*m_byteStream, path);
+    path.translate(toFloatSize(boundingBox.location()));
+}
+
+bool BasicShapePath::operator==(const BasicShape&amp; other) const
+{
+    if (type() != other.type())
+        return false;
+
+    auto&amp; otherPath = downcast&lt;BasicShapePath&gt;(other);
+    return m_windRule == otherPath.m_windRule &amp;&amp; *m_byteStream == *otherPath.m_byteStream;
+}
+
+bool BasicShapePath::canBlend(const BasicShape&amp; other) const
+{
+    if (type() != other.type())
+        return false;
+
+    auto&amp; otherPath = downcast&lt;BasicShapePath&gt;(other);
+    return windRule() == otherPath.windRule() &amp;&amp; canBlendSVGPathByteStreams(*m_byteStream, *otherPath.pathData());
+}
+
+Ref&lt;BasicShape&gt; BasicShapePath::blend(const BasicShape&amp; from, double progress) const
+{
+    ASSERT(type() == from.type());
+
+    auto&amp; fromPath = downcast&lt;BasicShapePath&gt;(from);
+
+    auto resultingPathBytes = std::make_unique&lt;SVGPathByteStream&gt;();
+    buildAnimatedSVGPathByteStream(*fromPath.m_byteStream, *m_byteStream, *resultingPathBytes, progress);
+
+    auto result = BasicShapePath::create(WTF::move(resultingPathBytes));
+    result-&gt;setWindRule(windRule());
+    return WTF::move(result);
+}
+
</ins><span class="cx"> bool BasicShapeInset::operator==(const BasicShape&amp; other) const
</span><span class="cx"> {
</span><span class="cx">     if (type() != other.type())
</span><span class="cx">         return false;
</span><span class="cx"> 
</span><del>-    const auto&amp; otherInset = downcast&lt;BasicShapeInset&gt;(other);
</del><ins>+    auto&amp; otherInset = downcast&lt;BasicShapeInset&gt;(other);
</ins><span class="cx">     return m_right == otherInset.m_right
</span><span class="cx">         &amp;&amp; m_top == otherInset.m_top
</span><span class="cx">         &amp;&amp; m_bottom == otherInset.m_bottom
</span><span class="lines">@@ -295,12 +336,17 @@
</span><span class="cx">     path.addRoundedRect(FloatRoundedRect(rect, radii));
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool BasicShapeInset::canBlend(const BasicShape&amp; other) const
+{
+    return type() == other.type();
+}
+
</ins><span class="cx"> Ref&lt;BasicShape&gt; BasicShapeInset::blend(const BasicShape&amp; other, double progress) const
</span><span class="cx"> {
</span><span class="cx">     ASSERT(type() == other.type());
</span><span class="cx"> 
</span><del>-    const auto&amp; otherInset = downcast&lt;BasicShapeInset&gt;(other);
-    RefPtr&lt;BasicShapeInset&gt; result =  BasicShapeInset::create();
</del><ins>+    auto&amp; otherInset = downcast&lt;BasicShapeInset&gt;(other);
+    auto result =  BasicShapeInset::create();
</ins><span class="cx">     result-&gt;setTop(m_top.blend(otherInset.top(), progress));
</span><span class="cx">     result-&gt;setRight(m_right.blend(otherInset.right(), progress));
</span><span class="cx">     result-&gt;setBottom(m_bottom.blend(otherInset.bottom(), progress));
</span><span class="lines">@@ -311,6 +357,6 @@
</span><span class="cx">     result-&gt;setBottomRightRadius(m_bottomRightRadius.blend(otherInset.bottomRightRadius(), progress));
</span><span class="cx">     result-&gt;setBottomLeftRadius(m_bottomLeftRadius.blend(otherInset.bottomLeftRadius(), progress));
</span><span class="cx"> 
</span><del>-    return result.releaseNonNull();
</del><ins>+    return WTF::move(result);
</ins><span class="cx"> }
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceWebCorerenderingstyleBasicShapesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/rendering/style/BasicShapes.h (191550 => 191551)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/rendering/style/BasicShapes.h        2015-10-25 19:06:15 UTC (rev 191550)
+++ trunk/Source/WebCore/rendering/style/BasicShapes.h        2015-10-26 04:57:46 UTC (rev 191551)
</span><span class="lines">@@ -44,6 +44,7 @@
</span><span class="cx"> class FloatRect;
</span><span class="cx"> class Path;
</span><span class="cx"> class RenderBox;
</span><ins>+class SVGPathByteStream;
</ins><span class="cx"> 
</span><span class="cx"> class BasicShape : public RefCounted&lt;BasicShape&gt; {
</span><span class="cx"> public:
</span><span class="lines">@@ -51,18 +52,20 @@
</span><span class="cx"> 
</span><span class="cx">     enum Type {
</span><span class="cx">         BasicShapePolygonType,
</span><ins>+        BasicShapePathType,
</ins><span class="cx">         BasicShapeCircleType,
</span><span class="cx">         BasicShapeEllipseType,
</span><span class="cx">         BasicShapeInsetType
</span><span class="cx">     };
</span><span class="cx"> 
</span><del>-    bool canBlend(const BasicShape&amp;) const;
</del><ins>+    virtual Type type() const = 0;
</ins><span class="cx"> 
</span><span class="cx">     virtual void path(Path&amp;, const FloatRect&amp;) = 0;
</span><span class="cx">     virtual WindRule windRule() const { return RULE_NONZERO; }
</span><ins>+
+    virtual bool canBlend(const BasicShape&amp;) const = 0;
</ins><span class="cx">     virtual Ref&lt;BasicShape&gt; blend(const BasicShape&amp;, double) const = 0;
</span><span class="cx"> 
</span><del>-    virtual Type type() const = 0;
</del><span class="cx">     virtual bool operator==(const BasicShape&amp;) const = 0;
</span><span class="cx"> };
</span><span class="cx"> 
</span><span class="lines">@@ -111,11 +114,11 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx"> private:
</span><ins>+    void updateComputedLength();
+
</ins><span class="cx">     Direction m_direction;
</span><span class="cx">     Length m_length;
</span><span class="cx">     Length m_computedLength;
</span><del>-
-    void updateComputedLength();
</del><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> class BasicShapeRadius {
</span><span class="lines">@@ -125,11 +128,24 @@
</span><span class="cx">         ClosestSide,
</span><span class="cx">         FarthestSide
</span><span class="cx">     };
</span><del>-    BasicShapeRadius() : m_value(Undefined), m_type(ClosestSide) { }
-    explicit BasicShapeRadius(Length v) : m_value(v), m_type(Value) { }
-    explicit BasicShapeRadius(Type t) : m_value(Undefined), m_type(t) { }
-    BasicShapeRadius(const BasicShapeRadius&amp; other) : m_value(other.value()), m_type(other.type()) { }
</del><ins>+    BasicShapeRadius()
+        : m_value(Undefined),
+        m_type(ClosestSide)
+    { }
</ins><span class="cx"> 
</span><ins>+    explicit BasicShapeRadius(Length v)
+        : m_value(v)
+        , m_type(Value)
+    { }
+    explicit BasicShapeRadius(Type t)
+        : m_value(Undefined)
+        , m_type(t)
+    { }
+    BasicShapeRadius(const BasicShapeRadius&amp; other)
+        : m_value(other.value())
+        , m_type(other.type())
+    { }
+
</ins><span class="cx">     const Length&amp; value() const { return m_value; }
</span><span class="cx">     Type type() const { return m_type; }
</span><span class="cx"> 
</span><span class="lines">@@ -171,15 +187,18 @@
</span><span class="cx">     void setCenterY(BasicShapeCenterCoordinate centerY) { m_centerY = WTF::move(centerY); }
</span><span class="cx">     void setRadius(BasicShapeRadius radius) { m_radius = WTF::move(radius); }
</span><span class="cx"> 
</span><ins>+private:
+    BasicShapeCircle() = default;
+
+    virtual Type type() const override { return BasicShapeCircleType; }
+
</ins><span class="cx">     virtual void path(Path&amp;, const FloatRect&amp;) override;
</span><ins>+
+    virtual bool canBlend(const BasicShape&amp;) const override;
</ins><span class="cx">     virtual Ref&lt;BasicShape&gt; blend(const BasicShape&amp;, double) const override;
</span><span class="cx"> 
</span><del>-    virtual Type type() const override { return BasicShapeCircleType; }
</del><span class="cx">     virtual bool operator==(const BasicShape&amp;) const override;
</span><span class="cx"> 
</span><del>-private:
-    BasicShapeCircle() { }
-
</del><span class="cx">     BasicShapeCenterCoordinate m_centerX;
</span><span class="cx">     BasicShapeCenterCoordinate m_centerY;
</span><span class="cx">     BasicShapeRadius m_radius;
</span><span class="lines">@@ -200,15 +219,18 @@
</span><span class="cx">     void setRadiusX(BasicShapeRadius radiusX) { m_radiusX = WTF::move(radiusX); }
</span><span class="cx">     void setRadiusY(BasicShapeRadius radiusY) { m_radiusY = WTF::move(radiusY); }
</span><span class="cx"> 
</span><ins>+private:
+    BasicShapeEllipse() = default;
+
+    virtual Type type() const override { return BasicShapeEllipseType; }
+
</ins><span class="cx">     virtual void path(Path&amp;, const FloatRect&amp;) override;
</span><ins>+
+    virtual bool canBlend(const BasicShape&amp;) const override;
</ins><span class="cx">     virtual Ref&lt;BasicShape&gt; blend(const BasicShape&amp;, double) const override;
</span><span class="cx"> 
</span><del>-    virtual Type type() const override { return BasicShapeEllipseType; }
</del><span class="cx">     virtual bool operator==(const BasicShape&amp;) const override;
</span><span class="cx"> 
</span><del>-private:
-    BasicShapeEllipse() { }
-
</del><span class="cx">     BasicShapeCenterCoordinate m_centerX;
</span><span class="cx">     BasicShapeCenterCoordinate m_centerY;
</span><span class="cx">     BasicShapeRadius m_radiusX;
</span><span class="lines">@@ -226,21 +248,50 @@
</span><span class="cx">     void setWindRule(WindRule windRule) { m_windRule = windRule; }
</span><span class="cx">     void appendPoint(Length x, Length y) { m_values.append(WTF::move(x)); m_values.append(WTF::move(y)); }
</span><span class="cx"> 
</span><ins>+    virtual WindRule windRule() const override { return m_windRule; }
+
+private:
+    BasicShapePolygon() = default;
+
+    virtual Type type() const override { return BasicShapePolygonType; }
+
</ins><span class="cx">     virtual void path(Path&amp;, const FloatRect&amp;) override;
</span><ins>+
+    virtual bool canBlend(const BasicShape&amp;) const override;
</ins><span class="cx">     virtual Ref&lt;BasicShape&gt; blend(const BasicShape&amp;, double) const override;
</span><span class="cx"> 
</span><ins>+    virtual bool operator==(const BasicShape&amp;) const override;
+
+    WindRule m_windRule { RULE_NONZERO };
+    Vector&lt;Length&gt; m_values;
+};
+
+class BasicShapePath final : public BasicShape {
+public:
+    static Ref&lt;BasicShapePath&gt; create(std::unique_ptr&lt;SVGPathByteStream&gt;&amp;&amp; byteStream)
+    {
+        return adoptRef(*new BasicShapePath(WTF::move(byteStream)));
+    }
+
+    void setWindRule(WindRule windRule) { m_windRule = windRule; }
</ins><span class="cx">     virtual WindRule windRule() const override { return m_windRule; }
</span><span class="cx"> 
</span><del>-    virtual Type type() const override { return BasicShapePolygonType; }
-    virtual bool operator==(const BasicShape&amp;) const override;
</del><ins>+    const SVGPathByteStream* pathData() const { return m_byteStream.get(); }
</ins><span class="cx"> 
</span><span class="cx"> private:
</span><del>-    BasicShapePolygon()
-        : m_windRule(RULE_NONZERO)
-    { }
</del><ins>+    BasicShapePath(std::unique_ptr&lt;SVGPathByteStream&gt;&amp;&amp;);
</ins><span class="cx"> 
</span><del>-    WindRule m_windRule;
-    Vector&lt;Length&gt; m_values;
</del><ins>+    virtual Type type() const override { return BasicShapePathType; }
+
+    virtual void path(Path&amp;, const FloatRect&amp;) override;
+
+    virtual bool canBlend(const BasicShape&amp;) const override;
+    virtual Ref&lt;BasicShape&gt; blend(const BasicShape&amp;, double) const override;
+
+    virtual bool operator==(const BasicShape&amp;) const override;
+
+    std::unique_ptr&lt;SVGPathByteStream&gt; m_byteStream;
+    WindRule m_windRule { RULE_NONZERO };
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> class BasicShapeInset final : public BasicShape {
</span><span class="lines">@@ -267,15 +318,18 @@
</span><span class="cx">     void setBottomRightRadius(LengthSize radius) { m_bottomRightRadius = WTF::move(radius); }
</span><span class="cx">     void setBottomLeftRadius(LengthSize radius) { m_bottomLeftRadius = WTF::move(radius); }
</span><span class="cx"> 
</span><ins>+private:
+    BasicShapeInset() = default;
+
+    virtual Type type() const override { return BasicShapeInsetType; }
+
</ins><span class="cx">     virtual void path(Path&amp;, const FloatRect&amp;) override;
</span><ins>+
+    virtual bool canBlend(const BasicShape&amp;) const override;
</ins><span class="cx">     virtual Ref&lt;BasicShape&gt; blend(const BasicShape&amp;, double) const override;
</span><span class="cx"> 
</span><del>-    virtual Type type() const override { return BasicShapeInsetType; }
</del><span class="cx">     virtual bool operator==(const BasicShape&amp;) const override;
</span><span class="cx"> 
</span><del>-private:
-    BasicShapeInset() { }
-
</del><span class="cx">     Length m_right;
</span><span class="cx">     Length m_top;
</span><span class="cx">     Length m_bottom;
</span><span class="lines">@@ -297,6 +351,7 @@
</span><span class="cx"> SPECIALIZE_TYPE_TRAITS_BASIC_SHAPE(BasicShapeCircle, BasicShape::BasicShapeCircleType)
</span><span class="cx"> SPECIALIZE_TYPE_TRAITS_BASIC_SHAPE(BasicShapeEllipse, BasicShape::BasicShapeEllipseType)
</span><span class="cx"> SPECIALIZE_TYPE_TRAITS_BASIC_SHAPE(BasicShapePolygon, BasicShape::BasicShapePolygonType)
</span><ins>+SPECIALIZE_TYPE_TRAITS_BASIC_SHAPE(BasicShapePath, BasicShape::BasicShapePathType)
</ins><span class="cx"> SPECIALIZE_TYPE_TRAITS_BASIC_SHAPE(BasicShapeInset, BasicShape::BasicShapeInsetType)
</span><span class="cx"> 
</span><span class="cx"> #endif // BasicShapes_h
</span></span></pre></div>
<a id="trunkSourceWebCoresvgSVGPathBlendercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/svg/SVGPathBlender.cpp (191550 => 191551)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/svg/SVGPathBlender.cpp        2015-10-25 19:06:15 UTC (rev 191550)
+++ trunk/Source/WebCore/svg/SVGPathBlender.cpp        2015-10-26 04:57:46 UTC (rev 191551)
</span><span class="lines">@@ -30,17 +30,23 @@
</span><span class="cx"> 
</span><span class="cx"> bool SVGPathBlender::addAnimatedPath(SVGPathSource&amp; fromSource, SVGPathSource&amp; toSource, SVGPathConsumer&amp; consumer, unsigned repeatCount)
</span><span class="cx"> {
</span><del>-    SVGPathBlender blender(fromSource, toSource, consumer);
</del><ins>+    SVGPathBlender blender(fromSource, toSource, &amp;consumer);
</ins><span class="cx">     return blender.addAnimatedPath(repeatCount);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> bool SVGPathBlender::blendAnimatedPath(SVGPathSource&amp; fromSource, SVGPathSource&amp; toSource, SVGPathConsumer&amp; consumer, float progress)
</span><span class="cx"> {
</span><del>-    SVGPathBlender blender(fromSource, toSource, consumer);
</del><ins>+    SVGPathBlender blender(fromSource, toSource, &amp;consumer);
</ins><span class="cx">     return blender.blendAnimatedPath(progress);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-SVGPathBlender::SVGPathBlender(SVGPathSource&amp; fromSource, SVGPathSource&amp; toSource, SVGPathConsumer&amp; consumer)
</del><ins>+bool SVGPathBlender::canBlendPaths(SVGPathSource&amp; fromSource, SVGPathSource&amp; toSource)
+{
+    SVGPathBlender blender(fromSource, toSource);
+    return blender.canBlendPaths();
+}
+
+SVGPathBlender::SVGPathBlender(SVGPathSource&amp; fromSource, SVGPathSource&amp; toSource, SVGPathConsumer* consumer)
</ins><span class="cx">     : m_fromSource(fromSource)
</span><span class="cx">     , m_toSource(toSource)
</span><span class="cx">     , m_consumer(consumer)
</span><span class="lines">@@ -118,7 +124,10 @@
</span><span class="cx">         || !m_toSource.parseMoveToSegment(toTargetPoint))
</span><span class="cx">         return false;
</span><span class="cx"> 
</span><del>-    m_consumer.moveTo(blendAnimatedFloatPoint(fromTargetPoint, toTargetPoint, progress), false, m_isInFirstHalfOfAnimation ? m_fromMode : m_toMode);
</del><ins>+    if (!m_consumer)
+        return true;
+
+    m_consumer-&gt;moveTo(blendAnimatedFloatPoint(fromTargetPoint, toTargetPoint, progress), false, m_isInFirstHalfOfAnimation ? m_fromMode : m_toMode);
</ins><span class="cx">     m_fromCurrentPoint = m_fromMode == AbsoluteCoordinates ? fromTargetPoint : m_fromCurrentPoint + fromTargetPoint;
</span><span class="cx">     m_toCurrentPoint = m_toMode == AbsoluteCoordinates ? toTargetPoint : m_toCurrentPoint + toTargetPoint;
</span><span class="cx">     return true;
</span><span class="lines">@@ -132,7 +141,10 @@
</span><span class="cx">         || !m_toSource.parseLineToSegment(toTargetPoint))
</span><span class="cx">         return false;
</span><span class="cx"> 
</span><del>-    m_consumer.lineTo(blendAnimatedFloatPoint(fromTargetPoint, toTargetPoint, progress), m_isInFirstHalfOfAnimation ? m_fromMode : m_toMode);
</del><ins>+    if (!m_consumer)
+        return true;
+
+    m_consumer-&gt;lineTo(blendAnimatedFloatPoint(fromTargetPoint, toTargetPoint, progress), m_isInFirstHalfOfAnimation ? m_fromMode : m_toMode);
</ins><span class="cx">     m_fromCurrentPoint = m_fromMode == AbsoluteCoordinates ? fromTargetPoint : m_fromCurrentPoint + fromTargetPoint;
</span><span class="cx">     m_toCurrentPoint = m_toMode == AbsoluteCoordinates ? toTargetPoint : m_toCurrentPoint + toTargetPoint;
</span><span class="cx">     return true;
</span><span class="lines">@@ -146,7 +158,10 @@
</span><span class="cx">         || !m_toSource.parseLineToHorizontalSegment(toX))
</span><span class="cx">         return false;
</span><span class="cx"> 
</span><del>-    m_consumer.lineToHorizontal(blendAnimatedDimensonalFloat(fromX, toX, BlendHorizontal, progress), m_isInFirstHalfOfAnimation ? m_fromMode : m_toMode);
</del><ins>+    if (!m_consumer)
+        return true;
+
+    m_consumer-&gt;lineToHorizontal(blendAnimatedDimensonalFloat(fromX, toX, BlendHorizontal, progress), m_isInFirstHalfOfAnimation ? m_fromMode : m_toMode);
</ins><span class="cx">     m_fromCurrentPoint.setX(m_fromMode == AbsoluteCoordinates ? fromX : m_fromCurrentPoint.x() + fromX);
</span><span class="cx">     m_toCurrentPoint.setX(m_toMode == AbsoluteCoordinates ? toX : m_toCurrentPoint.x() + toX);
</span><span class="cx">     return true;
</span><span class="lines">@@ -160,7 +175,10 @@
</span><span class="cx">         || !m_toSource.parseLineToVerticalSegment(toY))
</span><span class="cx">         return false;
</span><span class="cx"> 
</span><del>-    m_consumer.lineToVertical(blendAnimatedDimensonalFloat(fromY, toY, BlendVertical, progress), m_isInFirstHalfOfAnimation ? m_fromMode : m_toMode);
</del><ins>+    if (!m_consumer)
+        return true;
+
+    m_consumer-&gt;lineToVertical(blendAnimatedDimensonalFloat(fromY, toY, BlendVertical, progress), m_isInFirstHalfOfAnimation ? m_fromMode : m_toMode);
</ins><span class="cx">     m_fromCurrentPoint.setY(m_fromMode == AbsoluteCoordinates ? fromY : m_fromCurrentPoint.y() + fromY);
</span><span class="cx">     m_toCurrentPoint.setY(m_toMode == AbsoluteCoordinates ? toY : m_toCurrentPoint.y() + toY);
</span><span class="cx">     return true;
</span><span class="lines">@@ -178,7 +196,10 @@
</span><span class="cx">         || !m_toSource.parseCurveToCubicSegment(toPoint1, toPoint2, toTargetPoint))
</span><span class="cx">         return false;
</span><span class="cx"> 
</span><del>-    m_consumer.curveToCubic(blendAnimatedFloatPoint(fromPoint1, toPoint1, progress),
</del><ins>+    if (!m_consumer)
+        return true;
+
+    m_consumer-&gt;curveToCubic(blendAnimatedFloatPoint(fromPoint1, toPoint1, progress),
</ins><span class="cx">         blendAnimatedFloatPoint(fromPoint2, toPoint2, progress),
</span><span class="cx">         blendAnimatedFloatPoint(fromTargetPoint, toTargetPoint, progress),
</span><span class="cx">         m_isInFirstHalfOfAnimation ? m_fromMode : m_toMode);
</span><span class="lines">@@ -197,7 +218,10 @@
</span><span class="cx">         || !m_toSource.parseCurveToCubicSmoothSegment(toPoint2, toTargetPoint))
</span><span class="cx">         return false;
</span><span class="cx"> 
</span><del>-    m_consumer.curveToCubicSmooth(blendAnimatedFloatPoint(fromPoint2, toPoint2, progress),
</del><ins>+    if (!m_consumer)
+        return true;
+
+    m_consumer-&gt;curveToCubicSmooth(blendAnimatedFloatPoint(fromPoint2, toPoint2, progress),
</ins><span class="cx">         blendAnimatedFloatPoint(fromTargetPoint, toTargetPoint, progress),
</span><span class="cx">         m_isInFirstHalfOfAnimation ? m_fromMode : m_toMode);
</span><span class="cx">     m_fromCurrentPoint = m_fromMode == AbsoluteCoordinates ? fromTargetPoint : m_fromCurrentPoint + fromTargetPoint;
</span><span class="lines">@@ -215,7 +239,10 @@
</span><span class="cx">         || !m_toSource.parseCurveToQuadraticSegment(toPoint1, toTargetPoint))
</span><span class="cx">         return false;
</span><span class="cx"> 
</span><del>-    m_consumer.curveToQuadratic(blendAnimatedFloatPoint(fromPoint1, toPoint1, progress),
</del><ins>+    if (!m_consumer)
+        return true;
+
+    m_consumer-&gt;curveToQuadratic(blendAnimatedFloatPoint(fromPoint1, toPoint1, progress),
</ins><span class="cx">         blendAnimatedFloatPoint(fromTargetPoint, toTargetPoint, progress),
</span><span class="cx">         m_isInFirstHalfOfAnimation ? m_fromMode : m_toMode);
</span><span class="cx">     m_fromCurrentPoint = m_fromMode == AbsoluteCoordinates ? fromTargetPoint : m_fromCurrentPoint + fromTargetPoint;
</span><span class="lines">@@ -231,7 +258,10 @@
</span><span class="cx">         || !m_toSource.parseCurveToQuadraticSmoothSegment(toTargetPoint))
</span><span class="cx">         return false;
</span><span class="cx"> 
</span><del>-    m_consumer.curveToQuadraticSmooth(blendAnimatedFloatPoint(fromTargetPoint, toTargetPoint, progress), m_isInFirstHalfOfAnimation ? m_fromMode : m_toMode);
</del><ins>+    if (!m_consumer)
+        return true;
+
+    m_consumer-&gt;curveToQuadraticSmooth(blendAnimatedFloatPoint(fromTargetPoint, toTargetPoint, progress), m_isInFirstHalfOfAnimation ? m_fromMode : m_toMode);
</ins><span class="cx">     m_fromCurrentPoint = m_fromMode == AbsoluteCoordinates ? fromTargetPoint : m_fromCurrentPoint + fromTargetPoint;
</span><span class="cx">     m_toCurrentPoint = m_toMode == AbsoluteCoordinates ? toTargetPoint : m_toCurrentPoint + toTargetPoint;
</span><span class="cx">     return true;
</span><span class="lines">@@ -255,11 +285,14 @@
</span><span class="cx">         || !m_toSource.parseArcToSegment(toRx, toRy, toAngle, toLargeArc, toSweep, toTargetPoint))
</span><span class="cx">         return false;
</span><span class="cx"> 
</span><ins>+    if (!m_consumer)
+        return true;
+
</ins><span class="cx">     if (m_addTypesCount) {
</span><span class="cx">         ASSERT(m_fromMode == m_toMode);
</span><span class="cx">         FloatPoint scaledToTargetPoint = toTargetPoint;
</span><span class="cx">         scaledToTargetPoint.scale(m_addTypesCount, m_addTypesCount);
</span><del>-        m_consumer.arcTo(fromRx + toRx * m_addTypesCount,
</del><ins>+        m_consumer-&gt;arcTo(fromRx + toRx * m_addTypesCount,
</ins><span class="cx">             fromRy + toRy * m_addTypesCount,
</span><span class="cx">             fromAngle + toAngle * m_addTypesCount,
</span><span class="cx">             fromLargeArc || toLargeArc,
</span><span class="lines">@@ -267,7 +300,7 @@
</span><span class="cx">             fromTargetPoint + scaledToTargetPoint,
</span><span class="cx">             m_fromMode);
</span><span class="cx">     } else {
</span><del>-        m_consumer.arcTo(blend(fromRx, toRx, progress),
</del><ins>+        m_consumer-&gt;arcTo(blend(fromRx, toRx, progress),
</ins><span class="cx">             blend(fromRy, toRy, progress),
</span><span class="cx">             blend(fromAngle, toAngle, progress),
</span><span class="cx">             m_isInFirstHalfOfAnimation ? fromLargeArc : toLargeArc,
</span><span class="lines">@@ -312,6 +345,87 @@
</span><span class="cx">     return blendAnimatedPath(0);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool SVGPathBlender::canBlendPaths()
+{
+    float progress = 0.5;
+    bool fromSourceHadData = m_fromSource.hasMoreData();
+    while (m_toSource.hasMoreData()) {
+        SVGPathSegType fromCommand;
+        SVGPathSegType toCommand;
+        if ((fromSourceHadData &amp;&amp; !m_fromSource.parseSVGSegmentType(fromCommand)) || !m_toSource.parseSVGSegmentType(toCommand))
+            return false;
+
+        m_toMode = coordinateModeOfCommand(toCommand);
+        m_fromMode = fromSourceHadData ? coordinateModeOfCommand(fromCommand) : m_toMode;
+        if (m_fromMode != m_toMode &amp;&amp; m_addTypesCount)
+            return false;
+
+        if (fromSourceHadData &amp;&amp; !isSegmentEqual(fromCommand, toCommand, m_fromMode, m_toMode))
+            return false;
+
+        switch (toCommand) {
+        case PathSegMoveToRel:
+        case PathSegMoveToAbs:
+            if (!blendMoveToSegment(progress))
+                return false;
+            break;
+        case PathSegLineToRel:
+        case PathSegLineToAbs:
+            if (!blendLineToSegment(progress))
+                return false;
+            break;
+        case PathSegLineToHorizontalRel:
+        case PathSegLineToHorizontalAbs:
+            if (!blendLineToHorizontalSegment(progress))
+                return false;
+            break;
+        case PathSegLineToVerticalRel:
+        case PathSegLineToVerticalAbs:
+            if (!blendLineToVerticalSegment(progress))
+                return false;
+            break;
+        case PathSegClosePath:
+            break;
+        case PathSegCurveToCubicRel:
+        case PathSegCurveToCubicAbs:
+            if (!blendCurveToCubicSegment(progress))
+                return false;
+            break;
+        case PathSegCurveToCubicSmoothRel:
+        case PathSegCurveToCubicSmoothAbs:
+            if (!blendCurveToCubicSmoothSegment(progress))
+                return false;
+            break;
+        case PathSegCurveToQuadraticRel:
+        case PathSegCurveToQuadraticAbs:
+            if (!blendCurveToQuadraticSegment(progress))
+                return false;
+            break;
+        case PathSegCurveToQuadraticSmoothRel:
+        case PathSegCurveToQuadraticSmoothAbs:
+            if (!blendCurveToQuadraticSmoothSegment(progress))
+                return false;
+            break;
+        case PathSegArcRel:
+        case PathSegArcAbs:
+            if (!blendArcToSegment(progress))
+                return false;
+            break;
+        case PathSegUnknown:
+            return false;
+        }
+
+        if (!fromSourceHadData)
+            continue;
+        if (m_fromSource.hasMoreData() != m_toSource.hasMoreData())
+            return false;
+        if (!m_fromSource.hasMoreData() || !m_toSource.hasMoreData())
+            return true;
+    }
+
+    return true;
+}
+
</ins><span class="cx"> bool SVGPathBlender::blendAnimatedPath(float progress)
</span><span class="cx"> {
</span><span class="cx">     m_isInFirstHalfOfAnimation = progress &lt; 0.5f;
</span><span class="lines">@@ -353,7 +467,7 @@
</span><span class="cx">                 return false;
</span><span class="cx">             break;
</span><span class="cx">         case PathSegClosePath:
</span><del>-            m_consumer.closePath();
</del><ins>+            m_consumer-&gt;closePath();
</ins><span class="cx">             break;
</span><span class="cx">         case PathSegCurveToCubicRel:
</span><span class="cx">         case PathSegCurveToCubicAbs:
</span></span></pre></div>
<a id="trunkSourceWebCoresvgSVGPathBlenderh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/svg/SVGPathBlender.h (191550 => 191551)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/svg/SVGPathBlender.h        2015-10-25 19:06:15 UTC (rev 191550)
+++ trunk/Source/WebCore/svg/SVGPathBlender.h        2015-10-26 04:57:46 UTC (rev 191551)
</span><span class="lines">@@ -39,9 +39,13 @@
</span><span class="cx">     static bool addAnimatedPath(SVGPathSource&amp; from, SVGPathSource&amp; to, SVGPathConsumer&amp;, unsigned repeatCount);
</span><span class="cx">     static bool blendAnimatedPath(SVGPathSource&amp; from, SVGPathSource&amp; to, SVGPathConsumer&amp;, float);
</span><span class="cx"> 
</span><ins>+    static bool canBlendPaths(SVGPathSource&amp; from, SVGPathSource&amp; to);
+
</ins><span class="cx"> private:
</span><del>-    SVGPathBlender(SVGPathSource&amp;, SVGPathSource&amp;, SVGPathConsumer&amp;);
</del><ins>+    SVGPathBlender(SVGPathSource&amp;, SVGPathSource&amp;, SVGPathConsumer* = nullptr);
</ins><span class="cx"> 
</span><ins>+    bool canBlendPaths();
+
</ins><span class="cx">     bool addAnimatedPath(unsigned repeatCount);
</span><span class="cx">     bool blendAnimatedPath(float progress);
</span><span class="cx"> 
</span><span class="lines">@@ -60,7 +64,7 @@
</span><span class="cx"> 
</span><span class="cx">     SVGPathSource&amp; m_fromSource;
</span><span class="cx">     SVGPathSource&amp; m_toSource;
</span><del>-    SVGPathConsumer&amp; m_consumer;
</del><ins>+    SVGPathConsumer* m_consumer; // A null consumer indicates that we're just checking blendability.
</ins><span class="cx"> 
</span><span class="cx">     FloatPoint m_fromCurrentPoint;
</span><span class="cx">     FloatPoint m_toCurrentPoint;
</span></span></pre></div>
<a id="trunkSourceWebCoresvgSVGPathByteStreamh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/svg/SVGPathByteStream.h (191550 => 191551)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/svg/SVGPathByteStream.h        2015-10-25 19:06:15 UTC (rev 191550)
+++ trunk/Source/WebCore/svg/SVGPathByteStream.h        2015-10-26 04:57:46 UTC (rev 191551)
</span><span class="lines">@@ -49,6 +49,11 @@
</span><span class="cx"> 
</span><span class="cx">     SVGPathByteStream() { }
</span><span class="cx">     SVGPathByteStream(const Data&amp; data) : m_data(data) { }
</span><ins>+    
+    bool operator==(const SVGPathByteStream&amp; other) const
+    {
+        return m_data == other.m_data;
+    }
</ins><span class="cx"> 
</span><span class="cx">     std::unique_ptr&lt;SVGPathByteStream&gt; copy() const
</span><span class="cx">     {
</span></span></pre></div>
<a id="trunkSourceWebCoresvgSVGPathUtilitiescpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/svg/SVGPathUtilities.cpp (191550 => 191551)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/svg/SVGPathUtilities.cpp        2015-10-25 19:06:15 UTC (rev 191550)
+++ trunk/Source/WebCore/svg/SVGPathUtilities.cpp        2015-10-26 04:57:46 UTC (rev 191551)
</span><span class="lines">@@ -125,6 +125,13 @@
</span><span class="cx">     return SVGPathParser::parseToByteStream(source, result, parsingMode);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool canBlendSVGPathByteStreams(const SVGPathByteStream&amp; fromStream, const SVGPathByteStream&amp; toStream)
+{
+    SVGPathByteStreamSource fromSource(fromStream);
+    SVGPathByteStreamSource toSource(toStream);
+    return SVGPathBlender::canBlendPaths(fromSource, toSource);
+}
+
</ins><span class="cx"> bool buildAnimatedSVGPathByteStream(const SVGPathByteStream&amp; fromStream, const SVGPathByteStream&amp; toStream, SVGPathByteStream&amp; result, float progress)
</span><span class="cx"> {
</span><span class="cx">     ASSERT(&amp;toStream != &amp;result);
</span></span></pre></div>
<a id="trunkSourceWebCoresvgSVGPathUtilitiesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/svg/SVGPathUtilities.h (191550 => 191551)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/svg/SVGPathUtilities.h        2015-10-25 19:06:15 UTC (rev 191550)
+++ trunk/Source/WebCore/svg/SVGPathUtilities.h        2015-10-26 04:57:46 UTC (rev 191551)
</span><span class="lines">@@ -49,6 +49,8 @@
</span><span class="cx"> // SVGPathByteStream -&gt; SVGPathSegList
</span><span class="cx"> bool buildSVGPathSegListFromByteStream(const SVGPathByteStream&amp;, SVGPathElement&amp;, SVGPathSegList&amp;, PathParsingMode);
</span><span class="cx"> 
</span><ins>+bool canBlendSVGPathByteStreams(const SVGPathByteStream&amp; from, const SVGPathByteStream&amp; to);
+
</ins><span class="cx"> bool buildAnimatedSVGPathByteStream(const SVGPathByteStream&amp; from, const SVGPathByteStream&amp; to, SVGPathByteStream&amp; result, float progress);
</span><span class="cx"> bool addToSVGPathByteStream(SVGPathByteStream&amp; streamToAppendTo, const SVGPathByteStream&amp; from, unsigned repeatCount = 1);
</span><span class="cx"> 
</span></span></pre>
</div>
</div>

</body>
</html>