<!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 <simon.fraser@apple.com>
+
+ 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 <youenn.fablet@crf.canon.fr>
</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>+<!DOCTYPE html>
+
+<html>
+<head>
+ <title>Tests that clip-path with a composited descendent triggers composited clipping</title>
+ <style>
+ .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);
+ }
+ </style>
+ <script>
+ if (window.testRunner)
+ testRunner.dumpAsText();
+
+ function doTest()
+ {
+ if (window.internals)
+ document.getElementById('layers').textContent = window.internals.layerTreeAsText(document);
+
+ }
+ window.addEventListener('load', doTest, false);
+ </script>
+</head>
+<body>
+ <div class="box">
+ <div class="child"></div>
+ </div>
+<pre id="layers"></pre>
+</body>
+</html>
</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>+<!DOCTYPE html>
+
+<html>
+<head>
+ <style>
+ .box {
+ margin: 20px;
+ height: 150px;
+ width: 200px;
+ }
+ </style>
+</head>
+<body>
+
+<div class="box">
+ <svg width="100%" height="100%" viewBox="0 0 200 150">
+                <clipPath id="clip1">
+                        <path d="M100,40l20,0 0,60 20,0 0,-20 -60,0 0,-20 80,0 0,60 -60,0 0,-80z"/>
+                </clipPath>
+                <rect x="50" y="30" width="350" height="100" fill="blue" clip-path="url(#clip1)"/>
+ </svg>
+</div>
+
+<div class="evenodd box">
+ <svg width="100%" height="100%" viewBox="0 0 200 150">
+                <clipPath id="clip2">
+                        <path clip-rule="evenodd" d="M100,40l20,0 0,60 20,0 0,-20 -60,0 0,-20 80,0 0,60 -60,0 0,-80z"/>
+                </clipPath>
+                <rect x="50" y="30" width="350" height="100" fill="green" clip-path="url(#clip2)"/>
+ </svg>
+</div>
+
+</body>
+</html>
</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>+<!DOCTYPE html>
+
+<html>
+<head>
+ <style>
+ .box {
+ margin: 20px;
+ height: 150px;
+ width: 200px;
+ -webkit-clip-path: path("M100,40l20,0 0,60 20,0 0,-20 -60,0 0,-20 80,0 0,60 -60,0 0,-80z");
+ background-color: blue;
+ }
+
+ .box.evenodd {
+ -webkit-clip-path: path(evenodd, "M100,40l20,0 0,60 20,0 0,-20 -60,0 0,-20 80,0 0,60 -60,0 0,-80z");
+ background-color: green;
+ }
+ </style>
+</head>
+<body>
+
+<div class="box"></div>
+<div class="evenodd box"></div>
+
+</body>
+</html>
</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 - "-webkit-clip-path" property for "path1" 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 - "-webkit-clip-path" property for "path2" 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 - "-webkit-clip-path" property for "path3" 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>+<!DOCTYPE html>
+
+<html>
+<head>
+ <style>
+ .box {
+ display: inline-block;
+ height: 200px;
+ width: 200px;
+ margin: 10px;
+ background-color: gray;
+ transition: -webkit-clip-path 2s linear;
+ }
+
+ #path1 {
+ -webkit-clip-path: path("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")
+ }
+
+ body.final #path1 {
+ -webkit-clip-path: path("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");
+ }
+
+ /* Nonmatched segments, should not animate */
+ #path2 {
+ -webkit-clip-path: path("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")
+ }
+
+ body.final #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");
+ }
+
+ /* Nonmatched winding rule, should not animate */
+ #path3 {
+ -webkit-clip-path: path("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")
+ }
+
+ body.final #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");
+ }
+ </style>
+ <script src="resources/transition-test-helpers.js"></script>
+ <script type="text/javascript">
+
+ 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);
+ </script>
+</head>
+<body>
+ <div id="path1" class="box"></div>
+ <div id="path2" class="box"></div>
+ <div id="path3" class="box"></div>
+
+ <div id="result"></div>
+</body>
+</html>
</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 {"from": matches[1], "to": matches[2], "percent": 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 < 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 - "fill-opacity" property for "rect1" element at 1s saw something close to: 0.6
</span><span class="cx"> PASS - "stroke-width" property for "rect1" 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 <simon.fraser@apple.com>
+
+ 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 <yoon@igalia.com>
</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 "CSSValuePool.h"
</span><span class="cx"> #include "Pair.h"
</span><span class="cx"> #include "RenderStyle.h"
</span><ins>+#include "SVGPathByteStream.h"
</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<CSSBasicShape> basicShapeValue;
</span><span class="cx"> switch (basicShape.type()) {
</span><span class="cx"> case BasicShape::BasicShapeCircleType: {
</span><del>- const auto& circle = downcast<BasicShapeCircle>(basicShape);
</del><ins>+ auto& circle = downcast<BasicShapeCircle>(basicShape);
</ins><span class="cx"> auto circleValue = CSSBasicShapeCircle::create();
</span><span class="cx">
</span><span class="cx"> circleValue->setCenterX(valueForCenterCoordinate(cssValuePool, style, circle.centerX(), HORIZONTAL));
</span><span class="cx"> circleValue->setCenterY(valueForCenterCoordinate(cssValuePool, style, circle.centerY(), VERTICAL));
</span><span class="cx"> circleValue->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& ellipse = downcast<BasicShapeEllipse>(basicShape);
</del><ins>+ auto& ellipse = downcast<BasicShapeEllipse>(basicShape);
</ins><span class="cx"> auto ellipseValue = CSSBasicShapeEllipse::create();
</span><span class="cx">
</span><span class="cx"> ellipseValue->setCenterX(valueForCenterCoordinate(cssValuePool, style, ellipse.centerX(), HORIZONTAL));
</span><span class="cx"> ellipseValue->setCenterY(valueForCenterCoordinate(cssValuePool, style, ellipse.centerY(), VERTICAL));
</span><span class="cx"> ellipseValue->setRadiusX(basicShapeRadiusToCSSValue(style, cssValuePool, ellipse.radiusX()));
</span><span class="cx"> ellipseValue->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& polygon = downcast<BasicShapePolygon>(basicShape);
</del><ins>+ auto& polygon = downcast<BasicShapePolygon>(basicShape);
</ins><span class="cx"> auto polygonValue = CSSBasicShapePolygon::create();
</span><span class="cx">
</span><span class="cx"> polygonValue->setWindRule(polygon.windRule());
</span><span class="lines">@@ -100,11 +103,19 @@
</span><span class="cx"> for (unsigned i = 0; i < values.size(); i += 2)
</span><span class="cx"> polygonValue->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& pathShape = downcast<BasicShapePath>(basicShape);
+ auto pathShapeValue = CSSBasicShapePath::create(pathShape.pathData()->copy());
+ pathShapeValue->setWindRule(pathShape.windRule());
+
+ basicShapeValue = WTF::move(pathShapeValue);
+ break;
+ }
</ins><span class="cx"> case BasicShape::BasicShapeInsetType: {
</span><del>- const auto& inset = downcast<BasicShapeInset>(basicShape);
</del><ins>+ auto& inset = downcast<BasicShapeInset>(basicShape);
</ins><span class="cx"> auto insetValue = CSSBasicShapeInset::create();
</span><span class="cx">
</span><span class="cx"> insetValue->setTop(cssValuePool.createValue(inset.top(), style));
</span><span class="lines">@@ -117,11 +128,9 @@
</span><span class="cx"> insetValue->setBottomRightRadius(cssValuePool.createValue(inset.bottomRightRadius(), style));
</span><span class="cx"> insetValue->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->type()) {
</span><span class="cx"> case CSSBasicShape::CSSBasicShapeCircleType: {
</span><del>- const CSSBasicShapeCircle& circleValue = downcast<CSSBasicShapeCircle>(*basicShapeValue);
- RefPtr<BasicShapeCircle> circle = BasicShapeCircle::create();
</del><ins>+ auto& circleValue = downcast<CSSBasicShapeCircle>(*basicShapeValue);
+ auto circle = BasicShapeCircle::create();
</ins><span class="cx">
</span><span class="cx"> circle->setCenterX(convertToCenterCoordinate(conversionData, circleValue.centerX()));
</span><span class="cx"> circle->setCenterY(convertToCenterCoordinate(conversionData, circleValue.centerY()));
</span><span class="cx"> circle->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& ellipseValue = downcast<CSSBasicShapeEllipse>(*basicShapeValue);
- RefPtr<BasicShapeEllipse> ellipse = BasicShapeEllipse::create();
</del><ins>+ auto& ellipseValue = downcast<CSSBasicShapeEllipse>(*basicShapeValue);
+ auto ellipse = BasicShapeEllipse::create();
</ins><span class="cx">
</span><span class="cx"> ellipse->setCenterX(convertToCenterCoordinate(conversionData, ellipseValue.centerX()));
</span><span class="cx"> ellipse->setCenterY(convertToCenterCoordinate(conversionData, ellipseValue.centerY()));
</span><span class="lines">@@ -225,24 +234,24 @@
</span><span class="cx"> ellipse->setRadiusX(cssValueToBasicShapeRadius(conversionData, ellipseValue.radiusX()));
</span><span class="cx"> ellipse->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& polygonValue = downcast<CSSBasicShapePolygon>(*basicShapeValue);
- RefPtr<BasicShapePolygon> polygon = BasicShapePolygon::create();
</del><ins>+ auto& polygonValue = downcast<CSSBasicShapePolygon>(*basicShapeValue);
+ auto polygon = BasicShapePolygon::create();
</ins><span class="cx">
</span><span class="cx"> polygon->setWindRule(polygonValue.windRule());
</span><span class="cx"> const Vector<RefPtr<CSSPrimitiveValue>>& values = polygonValue.values();
</span><span class="cx"> for (unsigned i = 0; i < values.size(); i += 2)
</span><span class="cx"> polygon->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& rectValue = downcast<CSSBasicShapeInset>(*basicShapeValue);
- RefPtr<BasicShapeInset> rect = BasicShapeInset::create();
</del><ins>+ auto& rectValue = downcast<CSSBasicShapeInset>(*basicShapeValue);
+ auto rect = BasicShapeInset::create();
</ins><span class="cx">
</span><span class="cx"> rect->setTop(convertToLength(conversionData, rectValue.top()));
</span><span class="cx"> rect->setRight(convertToLength(conversionData, rectValue.right()));
</span><span class="lines">@@ -254,12 +263,18 @@
</span><span class="cx"> rect->setBottomRightRadius(convertToLengthSize(conversionData, rectValue.bottomRightRadius()));
</span><span class="cx"> rect->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& pathValue = downcast<CSSBasicShapePath>(*basicShapeValue);
+ auto path = BasicShapePath::create(pathValue.pathData().copy());
+ path->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 "CSSBasicShapes.h"
</span><span class="cx">
</span><ins>+#include "CSSParser.h"
</ins><span class="cx"> #include "CSSPrimitiveValueMappings.h"
</span><span class="cx"> #include "CSSValuePool.h"
</span><span class="cx"> #include "Pair.h"
</span><ins>+#include "SVGPathByteStream.h"
+#include "SVGPathUtilities.h"
</ins><span class="cx"> #include <wtf/text/StringBuilder.h>
</span><span class="cx">
</span><span class="cx"> using namespace WTF;
</span><span class="lines">@@ -198,6 +201,47 @@
</span><span class="cx"> && compareCSSValuePtr(m_radiusY, other.m_radiusY);
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+CSSBasicShapePath::CSSBasicShapePath(std::unique_ptr<SVGPathByteStream>&& pathData)
+ : m_byteStream(WTF::move(pathData))
+{
+}
+
+static String buildPathString(const WindRule& windRule, const String& path, const String& box)
+{
+ StringBuilder result;
+ if (windRule == RULE_EVENODD)
+ result.appendLiteral("path(evenodd, ");
+ else
+ result.appendLiteral("path(");
+
+ 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->cssText() : String());
+}
+
+bool CSSBasicShapePath::equals(const CSSBasicShape& otherShape) const
+{
+ if (!is<CSSBasicShapePath>(otherShape))
+ return false;
+
+ auto& otherShapePath = downcast<CSSBasicShapePath>(otherShape);
+ return windRule() == otherShapePath.windRule() && pathData() == otherShapePath.pathData();
+}
+
</ins><span class="cx"> static String buildPolygonString(const WindRule& windRule, const Vector<String>& 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<CSSBasicShape> {
</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<CSSPrimitiveValue> radius) { m_bottomRightRadius = radius; }
</span><span class="cx"> void setBottomLeftRadius(PassRefPtr<CSSPrimitiveValue> radius) { m_bottomLeftRadius = radius; }
</span><span class="cx">
</span><del>- virtual String cssText() const override;
- virtual bool equals(const CSSBasicShape&) 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&) const override;
</ins><span class="cx">
</span><span class="cx"> RefPtr<CSSPrimitiveValue> m_top;
</span><span class="cx"> RefPtr<CSSPrimitiveValue> m_right;
</span><span class="lines">@@ -130,9 +132,6 @@
</span><span class="cx"> public:
</span><span class="cx"> static Ref<CSSBasicShapeCircle> create() { return adoptRef(*new CSSBasicShapeCircle); }
</span><span class="cx">
</span><del>- virtual String cssText() const override;
- virtual bool equals(const CSSBasicShape&) 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&) const override;
</ins><span class="cx">
</span><span class="cx"> RefPtr<CSSPrimitiveValue> m_centerX;
</span><span class="cx"> RefPtr<CSSPrimitiveValue> m_centerY;
</span><span class="lines">@@ -165,13 +166,12 @@
</span><span class="cx"> void setRadiusX(PassRefPtr<CSSPrimitiveValue> radiusX) { m_radiusX = radiusX; }
</span><span class="cx"> void setRadiusY(PassRefPtr<CSSPrimitiveValue> radiusY) { m_radiusY = radiusY; }
</span><span class="cx">
</span><del>- virtual String cssText() const override;
- virtual bool equals(const CSSBasicShape&) 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&) const override;
</ins><span class="cx">
</span><span class="cx"> RefPtr<CSSPrimitiveValue> m_centerX;
</span><span class="cx"> RefPtr<CSSPrimitiveValue> m_centerY;
</span><span class="lines">@@ -193,12 +193,9 @@
</span><span class="cx"> RefPtr<CSSPrimitiveValue> getYAt(unsigned i) const { return m_values.at(i * 2 + 1); }
</span><span class="cx"> const Vector<RefPtr<CSSPrimitiveValue>>& 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&) 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&) const override;
</ins><span class="cx">
</span><span class="cx"> Vector<RefPtr<CSSPrimitiveValue>> 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<CSSBasicShapePath> create(std::unique_ptr<SVGPathByteStream>&& pathData)
+ {
+ return adoptRef(*new CSSBasicShapePath(WTF::move(pathData)));
+ }
+
+ const SVGPathByteStream& pathData() const
+ {
+ return *m_byteStream;
+ }
+
+ void setWindRule(WindRule rule) { m_windRule = rule; }
+ WindRule windRule() const { return m_windRule; }
+
+private:
+ CSSBasicShapePath(std::unique_ptr<SVGPathByteStream>&&);
+
+ virtual Type type() const override { return CSSBasicShapePathType; }
+ virtual String cssText() const override;
+ virtual bool equals(const CSSBasicShape&) const override;
+
+ std::unique_ptr<SVGPathByteStream> 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 "RenderTheme.h"
</span><span class="cx"> #include "RuntimeEnabledFeatures.h"
</span><span class="cx"> #include "SVGParserUtilities.h"
</span><ins>+#include "SVGPathByteStream.h"
+#include "SVGPathUtilities.h"
</ins><span class="cx"> #include "SelectorChecker.h"
</span><span class="cx"> #include "SelectorCheckerTestFunctions.h"
</span><span class="cx"> #include "Settings.h"
</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<CSSBasicShape> CSSParser::parseBasicShapePath(CSSParserValueList& args)
+{
+ unsigned size = args.size();
+ if (size != 1 && size != 3)
+ return nullptr;
+
+ WindRule windRule = RULE_NONZERO;
+
+ CSSParserValue* argument = args.current();
+ if (argument->id == CSSValueEvenodd || argument->id == CSSValueNonzero) {
+ windRule = argument->id == CSSValueEvenodd ? RULE_EVENODD : RULE_NONZERO;
+
+ if (!isComma(args.next()))
+ return nullptr;
+ argument = args.next();
+ }
+
+ if (argument->unit != CSSPrimitiveValue::CSS_STRING)
+ return nullptr;
+
+ auto byteStream = std::make_unique<SVGPathByteStream>();
+ if (!buildSVGPathByteStreamFromString(argument->string, *byteStream, UnalteredParsing))
+ return nullptr;
+
+ RefPtr<CSSBasicShapePath> shape = CSSBasicShapePath::create(WTF::move(byteStream));
+ shape->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->name, "polygon("))
</span><span class="cx"> shape = parseBasicShapePolygon(*args);
</span><ins>+ else if (equalIgnoringCase(value.function->name, "path("))
+ shape = parseBasicShapePath(*args);
</ins><span class="cx"> else if (equalIgnoringCase(value.function->name, "inset("))
</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<CSSBasicShape> parseBasicShapeCircle(CSSParserValueList&);
</span><span class="cx"> RefPtr<CSSBasicShape> parseBasicShapeEllipse(CSSParserValueList&);
</span><span class="cx"> RefPtr<CSSBasicShape> parseBasicShapePolygon(CSSParserValueList&);
</span><ins>+ RefPtr<CSSBasicShape> parseBasicShapePath(CSSParserValueList&);
</ins><span class="cx"> RefPtr<CSSBasicShape> parseBasicShapeInset(CSSParserValueList&);
</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() < 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 "LengthFunctions.h"
</span><span class="cx"> #include "Path.h"
</span><span class="cx"> #include "RenderBox.h"
</span><ins>+#include "SVGPathByteStream.h"
+#include "SVGPathUtilities.h"
</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& 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<BasicShapePolygon>(*this)
- && (downcast<BasicShapePolygon>(*this).values().size() != downcast<BasicShapePolygon>(other).values().size()
- || downcast<BasicShapePolygon>(*this).windRule() != downcast<BasicShapePolygon>(other).windRule()))
- return false;
-
- // Circles with keywords for radii coordinates cannot be animated.
- if (is<BasicShapeCircle>(*this)) {
- const auto& thisCircle = downcast<BasicShapeCircle>(*this);
- const auto& otherCircle = downcast<BasicShapeCircle>(other);
- if (!thisCircle.radius().canBlend(otherCircle.radius()))
- return false;
- }
-
- // Ellipses with keywords for radii coordinates cannot be animated.
- if (!is<BasicShapeEllipse>(*this))
- return true;
-
- const auto& thisEllipse = downcast<BasicShapeEllipse>(*this);
- const auto& otherEllipse = downcast<BasicShapeEllipse>(other);
- return (thisEllipse.radiusX().canBlend(otherEllipse.radiusX())
- && thisEllipse.radiusY().canBlend(otherEllipse.radiusY()));
-}
-
-
</del><span class="cx"> bool BasicShapeCircle::operator==(const BasicShape& 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& otherCircle = downcast<BasicShapeCircle>(other);
</del><ins>+ auto& otherCircle = downcast<BasicShapeCircle>(other);
</ins><span class="cx"> return m_centerX == otherCircle.m_centerX
</span><span class="cx"> && m_centerY == otherCircle.m_centerY
</span><span class="cx"> && 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& other) const
+{
+ if (type() != other.type())
+ return false;
+
+ return radius().canBlend(downcast<BasicShapeCircle>(other).radius());
+}
+
</ins><span class="cx"> Ref<BasicShape> BasicShapeCircle::blend(const BasicShape& other, double progress) const
</span><span class="cx"> {
</span><span class="cx"> ASSERT(type() == other.type());
</span><del>- const auto& otherCircle = downcast<BasicShapeCircle>(other);
- RefPtr<BasicShapeCircle> result = BasicShapeCircle::create();
</del><ins>+ auto& otherCircle = downcast<BasicShapeCircle>(other);
+ auto result = BasicShapeCircle::create();
</ins><span class="cx">
</span><span class="cx"> result->setCenterX(m_centerX.blend(otherCircle.centerX(), progress));
</span><span class="cx"> result->setCenterY(m_centerY.blend(otherCircle.centerY(), progress));
</span><span class="cx"> result->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& 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& otherEllipse = downcast<BasicShapeEllipse>(other);
</del><ins>+ auto& otherEllipse = downcast<BasicShapeEllipse>(other);
</ins><span class="cx"> return m_centerX == otherEllipse.m_centerX
</span><span class="cx"> && m_centerY == otherEllipse.m_centerY
</span><span class="cx"> && 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& other) const
+{
+ if (type() != other.type())
+ return false;
+
+ auto& otherEllipse = downcast<BasicShapeEllipse>(other);
+ return radiusX().canBlend(otherEllipse.radiusX()) && radiusY().canBlend(otherEllipse.radiusY());
+}
+
</ins><span class="cx"> Ref<BasicShape> BasicShapeEllipse::blend(const BasicShape& other, double progress) const
</span><span class="cx"> {
</span><span class="cx"> ASSERT(type() == other.type());
</span><del>- const auto& otherEllipse = downcast<BasicShapeEllipse>(other);
- RefPtr<BasicShapeEllipse> result = BasicShapeEllipse::create();
</del><ins>+ auto& otherEllipse = downcast<BasicShapeEllipse>(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->setCenterY(otherEllipse.centerY());
</span><span class="cx"> result->setRadiusX(otherEllipse.radiusX());
</span><span class="cx"> result->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->setCenterX(m_centerX.blend(otherEllipse.centerX(), progress));
</span><span class="cx"> result->setCenterY(m_centerY.blend(otherEllipse.centerY(), progress));
</span><span class="cx"> result->setRadiusX(m_radiusX.blend(otherEllipse.radiusX(), progress));
</span><span class="cx"> result->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& 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& otherPolygon = downcast<BasicShapePolygon>(other);
</del><ins>+ auto& otherPolygon = downcast<BasicShapePolygon>(other);
</ins><span class="cx"> return m_windRule == otherPolygon.m_windRule
</span><span class="cx"> && 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& other) const
+{
+ if (type() != other.type())
+ return false;
+
+ auto& otherPolygon = downcast<BasicShapePolygon>(other);
+ return values().size() == otherPolygon.values().size() && windRule() == otherPolygon.windRule();
+}
+
</ins><span class="cx"> Ref<BasicShape> BasicShapePolygon::blend(const BasicShape& other, double progress) const
</span><span class="cx"> {
</span><span class="cx"> ASSERT(type() == other.type());
</span><span class="cx">
</span><del>- const auto& otherPolygon = downcast<BasicShapePolygon>(other);
</del><ins>+ auto& otherPolygon = downcast<BasicShapePolygon>(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<BasicShapePolygon> 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->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<SVGPathByteStream>&& byteStream)
+ : m_byteStream(WTF::move(byteStream))
+{
+}
+
+void BasicShapePath::path(Path& path, const FloatRect& boundingBox)
+{
+ ASSERT(path.isEmpty());
+ buildPathFromByteStream(*m_byteStream, path);
+ path.translate(toFloatSize(boundingBox.location()));
+}
+
+bool BasicShapePath::operator==(const BasicShape& other) const
+{
+ if (type() != other.type())
+ return false;
+
+ auto& otherPath = downcast<BasicShapePath>(other);
+ return m_windRule == otherPath.m_windRule && *m_byteStream == *otherPath.m_byteStream;
+}
+
+bool BasicShapePath::canBlend(const BasicShape& other) const
+{
+ if (type() != other.type())
+ return false;
+
+ auto& otherPath = downcast<BasicShapePath>(other);
+ return windRule() == otherPath.windRule() && canBlendSVGPathByteStreams(*m_byteStream, *otherPath.pathData());
+}
+
+Ref<BasicShape> BasicShapePath::blend(const BasicShape& from, double progress) const
+{
+ ASSERT(type() == from.type());
+
+ auto& fromPath = downcast<BasicShapePath>(from);
+
+ auto resultingPathBytes = std::make_unique<SVGPathByteStream>();
+ buildAnimatedSVGPathByteStream(*fromPath.m_byteStream, *m_byteStream, *resultingPathBytes, progress);
+
+ auto result = BasicShapePath::create(WTF::move(resultingPathBytes));
+ result->setWindRule(windRule());
+ return WTF::move(result);
+}
+
</ins><span class="cx"> bool BasicShapeInset::operator==(const BasicShape& 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& otherInset = downcast<BasicShapeInset>(other);
</del><ins>+ auto& otherInset = downcast<BasicShapeInset>(other);
</ins><span class="cx"> return m_right == otherInset.m_right
</span><span class="cx"> && m_top == otherInset.m_top
</span><span class="cx"> && 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& other) const
+{
+ return type() == other.type();
+}
+
</ins><span class="cx"> Ref<BasicShape> BasicShapeInset::blend(const BasicShape& other, double progress) const
</span><span class="cx"> {
</span><span class="cx"> ASSERT(type() == other.type());
</span><span class="cx">
</span><del>- const auto& otherInset = downcast<BasicShapeInset>(other);
- RefPtr<BasicShapeInset> result = BasicShapeInset::create();
</del><ins>+ auto& otherInset = downcast<BasicShapeInset>(other);
+ auto result = BasicShapeInset::create();
</ins><span class="cx"> result->setTop(m_top.blend(otherInset.top(), progress));
</span><span class="cx"> result->setRight(m_right.blend(otherInset.right(), progress));
</span><span class="cx"> result->setBottom(m_bottom.blend(otherInset.bottom(), progress));
</span><span class="lines">@@ -311,6 +357,6 @@
</span><span class="cx"> result->setBottomRightRadius(m_bottomRightRadius.blend(otherInset.bottomRightRadius(), progress));
</span><span class="cx"> result->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<BasicShape> {
</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&) const;
</del><ins>+ virtual Type type() const = 0;
</ins><span class="cx">
</span><span class="cx"> virtual void path(Path&, const FloatRect&) = 0;
</span><span class="cx"> virtual WindRule windRule() const { return RULE_NONZERO; }
</span><ins>+
+ virtual bool canBlend(const BasicShape&) const = 0;
</ins><span class="cx"> virtual Ref<BasicShape> blend(const BasicShape&, double) const = 0;
</span><span class="cx">
</span><del>- virtual Type type() const = 0;
</del><span class="cx"> virtual bool operator==(const BasicShape&) 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& 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& other)
+ : m_value(other.value())
+ , m_type(other.type())
+ { }
+
</ins><span class="cx"> const Length& 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&, const FloatRect&) override;
</span><ins>+
+ virtual bool canBlend(const BasicShape&) const override;
</ins><span class="cx"> virtual Ref<BasicShape> blend(const BasicShape&, 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&) 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&, const FloatRect&) override;
</span><ins>+
+ virtual bool canBlend(const BasicShape&) const override;
</ins><span class="cx"> virtual Ref<BasicShape> blend(const BasicShape&, 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&) 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&, const FloatRect&) override;
</span><ins>+
+ virtual bool canBlend(const BasicShape&) const override;
</ins><span class="cx"> virtual Ref<BasicShape> blend(const BasicShape&, double) const override;
</span><span class="cx">
</span><ins>+ virtual bool operator==(const BasicShape&) const override;
+
+ WindRule m_windRule { RULE_NONZERO };
+ Vector<Length> m_values;
+};
+
+class BasicShapePath final : public BasicShape {
+public:
+ static Ref<BasicShapePath> create(std::unique_ptr<SVGPathByteStream>&& 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&) 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<SVGPathByteStream>&&);
</ins><span class="cx">
</span><del>- WindRule m_windRule;
- Vector<Length> m_values;
</del><ins>+ virtual Type type() const override { return BasicShapePathType; }
+
+ virtual void path(Path&, const FloatRect&) override;
+
+ virtual bool canBlend(const BasicShape&) const override;
+ virtual Ref<BasicShape> blend(const BasicShape&, double) const override;
+
+ virtual bool operator==(const BasicShape&) const override;
+
+ std::unique_ptr<SVGPathByteStream> 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&, const FloatRect&) override;
</span><ins>+
+ virtual bool canBlend(const BasicShape&) const override;
</ins><span class="cx"> virtual Ref<BasicShape> blend(const BasicShape&, 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&) 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& fromSource, SVGPathSource& toSource, SVGPathConsumer& consumer, unsigned repeatCount)
</span><span class="cx"> {
</span><del>- SVGPathBlender blender(fromSource, toSource, consumer);
</del><ins>+ SVGPathBlender blender(fromSource, toSource, &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& fromSource, SVGPathSource& toSource, SVGPathConsumer& consumer, float progress)
</span><span class="cx"> {
</span><del>- SVGPathBlender blender(fromSource, toSource, consumer);
</del><ins>+ SVGPathBlender blender(fromSource, toSource, &consumer);
</ins><span class="cx"> return blender.blendAnimatedPath(progress);
</span><span class="cx"> }
</span><span class="cx">
</span><del>-SVGPathBlender::SVGPathBlender(SVGPathSource& fromSource, SVGPathSource& toSource, SVGPathConsumer& consumer)
</del><ins>+bool SVGPathBlender::canBlendPaths(SVGPathSource& fromSource, SVGPathSource& toSource)
+{
+ SVGPathBlender blender(fromSource, toSource);
+ return blender.canBlendPaths();
+}
+
+SVGPathBlender::SVGPathBlender(SVGPathSource& fromSource, SVGPathSource& 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->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->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->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->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->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->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->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->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->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->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 && !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 && m_addTypesCount)
+ return false;
+
+ if (fromSourceHadData && !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 < 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->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& from, SVGPathSource& to, SVGPathConsumer&, unsigned repeatCount);
</span><span class="cx"> static bool blendAnimatedPath(SVGPathSource& from, SVGPathSource& to, SVGPathConsumer&, float);
</span><span class="cx">
</span><ins>+ static bool canBlendPaths(SVGPathSource& from, SVGPathSource& to);
+
</ins><span class="cx"> private:
</span><del>- SVGPathBlender(SVGPathSource&, SVGPathSource&, SVGPathConsumer&);
</del><ins>+ SVGPathBlender(SVGPathSource&, SVGPathSource&, 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& m_fromSource;
</span><span class="cx"> SVGPathSource& m_toSource;
</span><del>- SVGPathConsumer& 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& data) : m_data(data) { }
</span><ins>+
+ bool operator==(const SVGPathByteStream& other) const
+ {
+ return m_data == other.m_data;
+ }
</ins><span class="cx">
</span><span class="cx"> std::unique_ptr<SVGPathByteStream> 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& fromStream, const SVGPathByteStream& toStream)
+{
+ SVGPathByteStreamSource fromSource(fromStream);
+ SVGPathByteStreamSource toSource(toStream);
+ return SVGPathBlender::canBlendPaths(fromSource, toSource);
+}
+
</ins><span class="cx"> bool buildAnimatedSVGPathByteStream(const SVGPathByteStream& fromStream, const SVGPathByteStream& toStream, SVGPathByteStream& result, float progress)
</span><span class="cx"> {
</span><span class="cx"> ASSERT(&toStream != &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 -> SVGPathSegList
</span><span class="cx"> bool buildSVGPathSegListFromByteStream(const SVGPathByteStream&, SVGPathElement&, SVGPathSegList&, PathParsingMode);
</span><span class="cx">
</span><ins>+bool canBlendSVGPathByteStreams(const SVGPathByteStream& from, const SVGPathByteStream& to);
+
</ins><span class="cx"> bool buildAnimatedSVGPathByteStream(const SVGPathByteStream& from, const SVGPathByteStream& to, SVGPathByteStream& result, float progress);
</span><span class="cx"> bool addToSVGPathByteStream(SVGPathByteStream& streamToAppendTo, const SVGPathByteStream& from, unsigned repeatCount = 1);
</span><span class="cx">
</span></span></pre>
</div>
</div>
</body>
</html>