Use Length for the stroke-dasharray property in SVGLayoutStyle

This replaces the SVGLengthList used for strokeDashArray in
SVGLayoutStyle with a (reference-counted) Vector of Lengths.
SVGStrokeDasharrayStyleInterpolation is updated to treat a dash array in
a similar fashion, by having a list of LengthStyleInterpolations.
The storage of types in SVGStrokeDasharrayStyleInterpolation is dropped
for the same reason. AnimatableStrokeDasharrayList is updated to use
AnimatableLengths instead of AnimatableSVGLengths.

BUG=461375

Review URL: https://codereview.chromium.org/975733002

git-svn-id: svn://svn.chromium.org/blink/trunk@191432 bbb929c8-8fbe-4397-9dbb-9b2b20218538
diff --git a/LayoutTests/animations/interpolation/svg-stroke-dasharray-interpolation-expected.txt b/LayoutTests/animations/interpolation/svg-stroke-dasharray-interpolation-expected.txt
index 1887780..38707b0 100644
--- a/LayoutTests/animations/interpolation/svg-stroke-dasharray-interpolation-expected.txt
+++ b/LayoutTests/animations/interpolation/svg-stroke-dasharray-interpolation-expected.txt
@@ -26,7 +26,7 @@
 PASS: stroke-dasharray from [none] to [5 10] was [ 5 10] at 1
 PASS: stroke-dasharray from [none] to [5 10] was [ 6 12] at 1.2
 PASS: stroke-dasharray from [none] to [5em 10em] was [ 0em  0em] at -0.2
-FAIL: stroke-dasharray from [none] to [5em 10em] was [none] at 0, expected [0em, 0em]
+FAIL: stroke-dasharray from [none] to [5em 10em] was [none] at 0, expected [0em, 0em] (parsed as [0px, 0px])
 PASS: stroke-dasharray from [none] to [5em 10em] was [ 1em  2em] at 0.2
 PASS: stroke-dasharray from [none] to [5em 10em] was [ 2em  4em] at 0.4
 PASS: stroke-dasharray from [none] to [5em 10em] was [ 3em  6em] at 0.6
@@ -82,29 +82,29 @@
 FAIL: stroke-dasharray from [5 10 15] to [20 25 30 35 40] was [20px, 25px, 30px, 35px, 40px] at 1, expected [20 25 30 35 40 20 25 30 35 40 20 25 30 35 40] (parsed as [20px, 25px, 30px, 35px, 40px, 20px, 25px, 30px, 35px, 40px, 20px, 25px, 30px, 35px, 40px])
 PASS: stroke-dasharray from [5 10 15] to [20 25 30 35 40] was [23 28 33 41 46 21 29 34 39 47 22 27 35 40 45] at 1.2
 PASS: stroke-dasharray from [0em 20px 30px] to [40px 0em 60px] was [0px 24px 24px] at -0.2
-FAIL: stroke-dasharray from [0em 20px 30px] to [40px 0em 60px] was [0em, 20px, 30px] at 0, expected [0px 20px 30px] (parsed as [0px, 20px, 30px])
+PASS: stroke-dasharray from [0em 20px 30px] to [40px 0em 60px] was [0px 20px 30px] at 0
 PASS: stroke-dasharray from [0em 20px 30px] to [40px 0em 60px] was [8px 16px 36px] at 0.2
 PASS: stroke-dasharray from [0em 20px 30px] to [40px 0em 60px] was [16px 12px 42px] at 0.4
 PASS: stroke-dasharray from [0em 20px 30px] to [40px 0em 60px] was [24px 8px 48px] at 0.6
 PASS: stroke-dasharray from [0em 20px 30px] to [40px 0em 60px] was [32px 4px 54px] at 0.8
-FAIL: stroke-dasharray from [0em 20px 30px] to [40px 0em 60px] was [40px, 0em, 60px] at 1, expected [40px 0px 60px] (parsed as [40px, 0px, 60px])
+PASS: stroke-dasharray from [0em 20px 30px] to [40px 0em 60px] was [40px 0px 60px] at 1
 PASS: stroke-dasharray from [0em 20px 30px] to [40px 0em 60px] was [48px 0px 66px] at 1.2
-PASS: stroke-dasharray from [0em 20px 30px] to [40em 0em 60em] was [0em 20px 30px] at -0.2
+PASS: stroke-dasharray from [0em 20px 30px] to [40em 0em 60em] was [0em 24px 0px] at -0.2
 PASS: stroke-dasharray from [0em 20px 30px] to [40em 0em 60em] was [0em 20px 30px] at 0
-PASS: stroke-dasharray from [0em 20px 30px] to [40em 0em 60em] was [0em 20px 30px] at 0.2
-PASS: stroke-dasharray from [0em 20px 30px] to [40em 0em 60em] was [0em 20px 30px] at 0.4
-PASS: stroke-dasharray from [0em 20px 30px] to [40em 0em 60em] was [40em 0em 60em] at 0.6
-PASS: stroke-dasharray from [0em 20px 30px] to [40em 0em 60em] was [40em 0em 60em] at 0.8
+PASS: stroke-dasharray from [0em 20px 30px] to [40em 0em 60em] was [8em 16px 216px] at 0.2
+PASS: stroke-dasharray from [0em 20px 30px] to [40em 0em 60em] was [16em 12px 402px] at 0.4
+PASS: stroke-dasharray from [0em 20px 30px] to [40em 0em 60em] was [24em 8px 588px] at 0.6
+PASS: stroke-dasharray from [0em 20px 30px] to [40em 0em 60em] was [32em 4px 774px] at 0.8
 PASS: stroke-dasharray from [0em 20px 30px] to [40em 0em 60em] was [40em 0em 60em] at 1
-PASS: stroke-dasharray from [0em 20px 30px] to [40em 0em 60em] was [40em 0em 60em] at 1.2
-PASS: stroke-dasharray from [0px 20px] to [40px 0px 60em] was [0px 20px] at -0.2
-PASS: stroke-dasharray from [0px 20px] to [40px 0px 60em] was [0px 20px] at 0
-PASS: stroke-dasharray from [0px 20px] to [40px 0px 60em] was [0px 20px] at 0.2
-PASS: stroke-dasharray from [0px 20px] to [40px 0px 60em] was [0px 20px] at 0.4
-PASS: stroke-dasharray from [0px 20px] to [40px 0px 60em] was [40px 0px 60em] at 0.6
-PASS: stroke-dasharray from [0px 20px] to [40px 0px 60em] was [40px 0px 60em] at 0.8
-PASS: stroke-dasharray from [0px 20px] to [40px 0px 60em] was [40px 0px 60em] at 1
-PASS: stroke-dasharray from [0px 20px] to [40px 0px 60em] was [40px 0px 60em] at 1.2
+PASS: stroke-dasharray from [0em 20px 30px] to [40em 0em 60em] was [48em 0px 1146px] at 1.2
+PASS: stroke-dasharray from [0px 20px] to [40px 0px 60em] was [0px 24px 0px 16px 0px 0px] at -0.2
+FAIL: stroke-dasharray from [0px 20px] to [40px 0px 60em] was [0px, 20px] at 0, expected [0px 20px 0px 20px 0px 20px] (parsed as [0px, 20px, 0px, 20px, 0px, 20px])
+PASS: stroke-dasharray from [0px 20px] to [40px 0px 60em] was [8px 16px 192px 24px 0px 208px] at 0.2
+PASS: stroke-dasharray from [0px 20px] to [40px 0px 60em] was [16px 12px 384px 28px 0px 396px] at 0.4
+PASS: stroke-dasharray from [0px 20px] to [40px 0px 60em] was [24px 8px 576px 32px 0px 584px] at 0.6
+PASS: stroke-dasharray from [0px 20px] to [40px 0px 60em] was [32px 4px 768px 36px 0px 772px] at 0.8
+FAIL: stroke-dasharray from [0px 20px] to [40px 0px 60em] was [40px, 0px, 960px] at 1, expected [40px 0px 60em 40px 0px 60em] (parsed as [40px, 0px, 960px, 40px, 0px, 960px])
+PASS: stroke-dasharray from [0px 20px] to [40px 0px 60em] was [48px 0px 1152px 44px 0px 1148px] at 1.2
 PASS: stroke-dasharray from [10em 30px] to [20em 40px] was [8em 28px] at -0.2
 PASS: stroke-dasharray from [10em 30px] to [20em 40px] was [10em 30px] at 0
 PASS: stroke-dasharray from [10em 30px] to [20em 40px] was [12em 32px] at 0.2
@@ -114,12 +114,12 @@
 PASS: stroke-dasharray from [10em 30px] to [20em 40px] was [20em 40px] at 1
 PASS: stroke-dasharray from [10em 30px] to [20em 40px] was [22em 42px] at 1.2
 PASS: stroke-dasharray from [10em 20px 30em 40px 50em 60px] to [100em 200px 300em 400px] was [0em 0px 0em 0px 40em 32px 0em 0px 16em 8px 0em 0px] at -0.2
-FAIL: stroke-dasharray from [10em 20px 30em 40px 50em 60px] to [100em 200px 300em 400px] was [10em, 20px, 30em, 40px, 50em, 60px] at 0, expected [10em 20px 30em 40px 50em 60px 10em 20px 30em 40px 50em 60px] (parsed as [10em, 20px, 30em, 40px, 50em, 60px, 10em, 20px, 30em, 40px, 50em, 60px])
+FAIL: stroke-dasharray from [10em 20px 30em 40px 50em 60px] to [100em 200px 300em 400px] was [160px, 20px, 480px, 40px, 800px, 60px] at 0, expected [10em 20px 30em 40px 50em 60px 10em 20px 30em 40px 50em 60px] (parsed as [160px, 20px, 480px, 40px, 800px, 60px, 160px, 20px, 480px, 40px, 800px, 60px])
 PASS: stroke-dasharray from [10em 20px 30em 40px 50em 60px] to [100em 200px 300em 400px] was [28em 56px 84em 112px 60em 88px 68em 96px 44em 72px 100em 128px] at 0.2
 PASS: stroke-dasharray from [10em 20px 30em 40px 50em 60px] to [100em 200px 300em 400px] was [46em 92px 138em 184px 70em 116px 126em 172px 58em 104px 150em 196px] at 0.4
 PASS: stroke-dasharray from [10em 20px 30em 40px 50em 60px] to [100em 200px 300em 400px] was [64em 128px 192em 256px 80em 144px 184em 248px 72em 136px 200em 264px] at 0.6
 PASS: stroke-dasharray from [10em 20px 30em 40px 50em 60px] to [100em 200px 300em 400px] was [82em 164px 246em 328px 90em 172px 242em 324px 86em 168px 250em 332px] at 0.8
-FAIL: stroke-dasharray from [10em 20px 30em 40px 50em 60px] to [100em 200px 300em 400px] was [100em, 200px, 300em, 400px] at 1, expected [100em 200px 300em 400px 100em 200px 300em 400px 100em 200px 300em 400px] (parsed as [100em, 200px, 300em, 400px, 100em, 200px, 300em, 400px, 100em, 200px, 300em, 400px])
+FAIL: stroke-dasharray from [10em 20px 30em 40px 50em 60px] to [100em 200px 300em 400px] was [1600px, 200px, 4800px, 400px] at 1, expected [100em 200px 300em 400px 100em 200px 300em 400px 100em 200px 300em 400px] (parsed as [1600px, 200px, 4800px, 400px, 1600px, 200px, 4800px, 400px, 1600px, 200px, 4800px, 400px])
 PASS: stroke-dasharray from [10em 20px 30em 40px 50em 60px] to [100em 200px 300em 400px] was [118em 236px 354em 472px 110em 228px 358em 476px 114em 232px 350em 468px] at 1.2
 
 Web Animations API:
@@ -213,22 +213,22 @@
 PASS: strokeDasharray from [0em 20px 30px] to [40px 0em 60px] was [32px 4px 54px] at 0.8
 PASS: strokeDasharray from [0em 20px 30px] to [40px 0em 60px] was [40px 0px 60px] at 1
 PASS: strokeDasharray from [0em 20px 30px] to [40px 0em 60px] was [48px 0px 66px] at 1.2
-PASS: strokeDasharray from [0em 20px 30px] to [40em 0em 60em] was [0em 20px 30px] at -0.2
+PASS: strokeDasharray from [0em 20px 30px] to [40em 0em 60em] was [0em 24px 0px] at -0.2
 PASS: strokeDasharray from [0em 20px 30px] to [40em 0em 60em] was [0em 20px 30px] at 0
-PASS: strokeDasharray from [0em 20px 30px] to [40em 0em 60em] was [0em 20px 30px] at 0.2
-PASS: strokeDasharray from [0em 20px 30px] to [40em 0em 60em] was [0em 20px 30px] at 0.4
-PASS: strokeDasharray from [0em 20px 30px] to [40em 0em 60em] was [40em 0em 60em] at 0.6
-PASS: strokeDasharray from [0em 20px 30px] to [40em 0em 60em] was [40em 0em 60em] at 0.8
+PASS: strokeDasharray from [0em 20px 30px] to [40em 0em 60em] was [8em 16px 216px] at 0.2
+PASS: strokeDasharray from [0em 20px 30px] to [40em 0em 60em] was [16em 12px 402px] at 0.4
+PASS: strokeDasharray from [0em 20px 30px] to [40em 0em 60em] was [24em 8px 588px] at 0.6
+PASS: strokeDasharray from [0em 20px 30px] to [40em 0em 60em] was [32em 4px 774px] at 0.8
 PASS: strokeDasharray from [0em 20px 30px] to [40em 0em 60em] was [40em 0em 60em] at 1
-PASS: strokeDasharray from [0em 20px 30px] to [40em 0em 60em] was [40em 0em 60em] at 1.2
-PASS: strokeDasharray from [0px 20px] to [40px 0px 60em] was [0px 20px] at -0.2
-PASS: strokeDasharray from [0px 20px] to [40px 0px 60em] was [0px 20px] at 0
-PASS: strokeDasharray from [0px 20px] to [40px 0px 60em] was [0px 20px] at 0.2
-PASS: strokeDasharray from [0px 20px] to [40px 0px 60em] was [0px 20px] at 0.4
-PASS: strokeDasharray from [0px 20px] to [40px 0px 60em] was [40px 0px 60em] at 0.6
-PASS: strokeDasharray from [0px 20px] to [40px 0px 60em] was [40px 0px 60em] at 0.8
-PASS: strokeDasharray from [0px 20px] to [40px 0px 60em] was [40px 0px 60em] at 1
-PASS: strokeDasharray from [0px 20px] to [40px 0px 60em] was [40px 0px 60em] at 1.2
+PASS: strokeDasharray from [0em 20px 30px] to [40em 0em 60em] was [48em 0px 1146px] at 1.2
+PASS: strokeDasharray from [0px 20px] to [40px 0px 60em] was [0px 24px 0px 16px 0px 0px] at -0.2
+PASS: strokeDasharray from [0px 20px] to [40px 0px 60em] was [0px 20px 0px 20px 0px 20px] at 0
+PASS: strokeDasharray from [0px 20px] to [40px 0px 60em] was [8px 16px 192px 24px 0px 208px] at 0.2
+PASS: strokeDasharray from [0px 20px] to [40px 0px 60em] was [16px 12px 384px 28px 0px 396px] at 0.4
+PASS: strokeDasharray from [0px 20px] to [40px 0px 60em] was [24px 8px 576px 32px 0px 584px] at 0.6
+PASS: strokeDasharray from [0px 20px] to [40px 0px 60em] was [32px 4px 768px 36px 0px 772px] at 0.8
+PASS: strokeDasharray from [0px 20px] to [40px 0px 60em] was [40px 0px 60em 40px 0px 60em] at 1
+PASS: strokeDasharray from [0px 20px] to [40px 0px 60em] was [48px 0px 1152px 44px 0px 1148px] at 1.2
 PASS: strokeDasharray from [10em 30px] to [20em 40px] was [8em 28px] at -0.2
 PASS: strokeDasharray from [10em 30px] to [20em 40px] was [10em 30px] at 0
 PASS: strokeDasharray from [10em 30px] to [20em 40px] was [12em 32px] at 0.2
diff --git a/LayoutTests/animations/interpolation/svg-stroke-dasharray-interpolation.html b/LayoutTests/animations/interpolation/svg-stroke-dasharray-interpolation.html
index 43a9b67..30440be 100644
--- a/LayoutTests/animations/interpolation/svg-stroke-dasharray-interpolation.html
+++ b/LayoutTests/animations/interpolation/svg-stroke-dasharray-interpolation.html
@@ -2,6 +2,7 @@
 <meta charset="UTF-8">
 <style>
 .target {
+  font-size: 16px;
   stroke-width: 10px;
   stroke: black;
 }
@@ -201,14 +202,14 @@
   from: '0em 20px 30px',
   to: '40em 0em 60em'
 }, [
-  {at: -0.2, is: '0em 20px 30px'},
+  {at: -0.2, is: '0em 24px 0px'},
   {at:  0,   is: '0em 20px 30px'},
-  {at:  0.2, is: '0em 20px 30px'},
-  {at:  0.4, is: '0em 20px 30px'},
-  {at:  0.6, is: '40em 0em 60em'},
-  {at:  0.8, is: '40em 0em 60em'},
+  {at:  0.2, is: '8em 16px 216px'},
+  {at:  0.4, is: '16em 12px 402px'},
+  {at:  0.6, is: '24em 8px 588px'},
+  {at:  0.8, is: '32em 4px 774px'},
   {at:  1,   is: '40em 0em 60em'},
-  {at:  1.2, is: '40em 0em 60em'},
+  {at:  1.2, is: '48em 0px 1146px'},
 ]);
 
 assertInterpolation({
@@ -216,14 +217,14 @@
   from: '0px 20px',
   to: '40px 0px 60em'
 }, [
-  {at: -0.2, is: '0px 20px'},
-  {at:  0,   is: '0px 20px'},
-  {at:  0.2, is: '0px 20px'},
-  {at:  0.4, is: '0px 20px'},
-  {at:  0.6, is: '40px 0px 60em'},
-  {at:  0.8, is: '40px 0px 60em'},
-  {at:  1,   is: '40px 0px 60em'},
-  {at:  1.2, is: '40px 0px 60em'},
+  {at: -0.2, is: '0px 24px 0px 16px 0px 0px'},
+  {at:  0,   is: '0px 20px 0px 20px 0px 20px'},
+  {at:  0.2, is: '8px 16px 192px 24px 0px 208px'},
+  {at:  0.4, is: '16px 12px 384px 28px 0px 396px'},
+  {at:  0.6, is: '24px 8px 576px 32px 0px 584px'},
+  {at:  0.8, is: '32px 4px 768px 36px 0px 772px'},
+  {at:  1,   is: '40px 0px 60em 40px 0px 60em'},
+  {at:  1.2, is: '48px 0px 1152px 44px 0px 1148px'},
 ]);
 
 // Mixed units
diff --git a/LayoutTests/web-animations-api/animations-responsive-strokeDasharray.html b/LayoutTests/web-animations-api/animations-responsive-strokeDasharray.html
new file mode 100644
index 0000000..d088ad0
--- /dev/null
+++ b/LayoutTests/web-animations-api/animations-responsive-strokeDasharray.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<div id='container'>
+    <div id='element'></div>
+</div>
+<script>
+
+var container = document.getElementById('container');
+var element = document.getElementById('element');
+
+test(function() {
+    container.style.fontSize = '10px';
+
+    var keyframes = [
+        {strokeDasharray: '10em 10em'},
+        {strokeDasharray: '10em 10em'}
+    ];
+    var player = element.animate(keyframes, 10);
+    player.pause();
+    player.currentTime = 5;
+
+    var strokeDasharray = getComputedStyle(element).strokeDasharray;
+    container.style.fontSize = '20px';
+    assert_not_equals(getComputedStyle(element).strokeDasharray, strokeDasharray);
+}, 'strokeDasharray responsive to style changes');
+
+</script>
diff --git a/Source/core/animation/SVGStrokeDasharrayStyleInterpolation.cpp b/Source/core/animation/SVGStrokeDasharrayStyleInterpolation.cpp
index 93353a9..716a643 100644
--- a/Source/core/animation/SVGStrokeDasharrayStyleInterpolation.cpp
+++ b/Source/core/animation/SVGStrokeDasharrayStyleInterpolation.cpp
@@ -5,7 +5,7 @@
 #include "config.h"
 #include "core/animation/SVGStrokeDasharrayStyleInterpolation.h"
 
-#include "core/animation/SVGLengthStyleInterpolation.h"
+#include "core/animation/LengthStyleInterpolation.h"
 #include "core/css/CSSValueList.h"
 #include "core/css/resolver/StyleBuilder.h"
 
@@ -25,15 +25,13 @@
 
 } // namespace
 
-PassRefPtrWillBeRawPtr<CSSValueList> SVGStrokeDasharrayStyleInterpolation::interpolableValueToStrokeDasharray(const InterpolableValue& interpolableValue, const Vector<CSSPrimitiveValue::UnitType>& types)
+PassRefPtrWillBeRawPtr<CSSValueList> SVGStrokeDasharrayStyleInterpolation::interpolableValueToStrokeDasharray(const InterpolableValue& interpolableValue)
 {
     const InterpolableList& interpolableList = toInterpolableList(interpolableValue);
-    ASSERT(types.size() == interpolableList.length());
 
     RefPtrWillBeRawPtr<CSSValueList> ret = CSSValueList::createCommaSeparated();
-    for (size_t index = 0; index < interpolableList.length(); ++index) {
-        ret->append(SVGLengthStyleInterpolation::interpolableValueToLength(*interpolableList.get(index), types.at(index), RangeNonNegative));
-    }
+    for (size_t index = 0; index < interpolableList.length(); ++index)
+        ret->append(LengthStyleInterpolation::fromInterpolableValue(*interpolableList.get(index), RangeNonNegative));
     return ret.release();
 }
 
@@ -44,7 +42,7 @@
     const CSSValueList& valueList = toCSSValueList(value);
 
     for (size_t index = 0; index < valueList.length(); ++index) {
-        if (!SVGLengthStyleInterpolation::canCreateFrom(*valueList.item(index)))
+        if (!LengthStyleInterpolation::canCreateFrom(*valueList.item(index)))
             return false;
     }
     return true;
@@ -63,7 +61,6 @@
     size_t size = lowestCommonMultiple(valueListStart.length(), valueListEnd.length());
     ASSERT(size > 0);
 
-    Vector<CSSPrimitiveValue::UnitType> types(size);
     OwnPtrWillBeRawPtr<InterpolableList> interpolableStart = InterpolableList::create(size);
     OwnPtrWillBeRawPtr<InterpolableList> interpolableEnd = InterpolableList::create(size);
 
@@ -71,19 +68,15 @@
         const CSSPrimitiveValue& from = *toCSSPrimitiveValue(valueListStart.item(i % valueListStart.length()));
         const CSSPrimitiveValue& to = *toCSSPrimitiveValue(valueListEnd.item(i % valueListEnd.length()));
 
-        // Spec: If a pair of values cannot be interpolated, then the lists are not interpolable.
-        types[i] = SVGLengthStyleInterpolation::commonUnitType(from, to);
-        if (types[i] == CSSPrimitiveValue::CSS_UNKNOWN)
-            return nullptr;
-        interpolableStart->set(i, SVGLengthStyleInterpolation::lengthToInterpolableValue(from));
-        interpolableEnd->set(i, SVGLengthStyleInterpolation::lengthToInterpolableValue(to));
+        interpolableStart->set(i, LengthStyleInterpolation::toInterpolableValue(from));
+        interpolableEnd->set(i, LengthStyleInterpolation::toInterpolableValue(to));
     }
-    return adoptRefWillBeNoop(new SVGStrokeDasharrayStyleInterpolation(interpolableStart.release(), interpolableEnd.release(), id, types));
+    return adoptRefWillBeNoop(new SVGStrokeDasharrayStyleInterpolation(interpolableStart.release(), interpolableEnd.release(), id));
 }
 
 void SVGStrokeDasharrayStyleInterpolation::apply(StyleResolverState& state) const
 {
-    StyleBuilder::applyProperty(m_id, state, interpolableValueToStrokeDasharray(*m_cachedValue, m_types).get());
+    StyleBuilder::applyProperty(m_id, state, interpolableValueToStrokeDasharray(*m_cachedValue).get());
 }
 
 }
diff --git a/Source/core/animation/SVGStrokeDasharrayStyleInterpolation.h b/Source/core/animation/SVGStrokeDasharrayStyleInterpolation.h
index ac3e096..e9acec2 100644
--- a/Source/core/animation/SVGStrokeDasharrayStyleInterpolation.h
+++ b/Source/core/animation/SVGStrokeDasharrayStyleInterpolation.h
@@ -24,15 +24,12 @@
     }
 
 private:
-    SVGStrokeDasharrayStyleInterpolation(PassOwnPtrWillBeRawPtr<InterpolableValue> start, PassOwnPtrWillBeRawPtr<InterpolableValue> end, CSSPropertyID id, const Vector<CSSPrimitiveValue::UnitType>& types)
+    SVGStrokeDasharrayStyleInterpolation(PassOwnPtrWillBeRawPtr<InterpolableValue> start, PassOwnPtrWillBeRawPtr<InterpolableValue> end, CSSPropertyID id)
         : StyleInterpolation(start, end, id)
-        , m_types(types)
     { }
 
     static bool canCreateFrom(const CSSValue&);
-    static PassRefPtrWillBeRawPtr<CSSValueList> interpolableValueToStrokeDasharray(const InterpolableValue&, const Vector<CSSPrimitiveValue::UnitType>&);
-
-    Vector<CSSPrimitiveValue::UnitType> m_types;
+    static PassRefPtrWillBeRawPtr<CSSValueList> interpolableValueToStrokeDasharray(const InterpolableValue&);
 
     friend class AnimationSVGStrokeDasharrayStyleInterpolationTest;
 };
diff --git a/Source/core/animation/SVGStrokeDasharrayStyleInterpolationTest.cpp b/Source/core/animation/SVGStrokeDasharrayStyleInterpolationTest.cpp
index 0009e17..fd0975b 100644
--- a/Source/core/animation/SVGStrokeDasharrayStyleInterpolationTest.cpp
+++ b/Source/core/animation/SVGStrokeDasharrayStyleInterpolationTest.cpp
@@ -14,16 +14,16 @@
 
 class AnimationSVGStrokeDasharrayStyleInterpolationTest : public ::testing::Test {
 protected:
-    static PassRefPtrWillBeRawPtr<CSSValueList> interpolableValueToStrokeDasharray(const InterpolableValue& value, const Vector<CSSPrimitiveValue::UnitType>& types)
+    static PassRefPtrWillBeRawPtr<CSSValueList> interpolableValueToStrokeDasharray(const InterpolableValue& value)
     {
-        return SVGStrokeDasharrayStyleInterpolation::interpolableValueToStrokeDasharray(value, types);
+        return SVGStrokeDasharrayStyleInterpolation::interpolableValueToStrokeDasharray(value);
     }
 
-    static PassRefPtrWillBeRawPtr<CSSValueList> roundTrip(const CSSValue& value, const Vector<CSSPrimitiveValue::UnitType>& types)
+    static PassRefPtrWillBeRawPtr<CSSValueList> roundTrip(const CSSValue& value)
     {
         RefPtrWillBeRawPtr<SVGStrokeDasharrayStyleInterpolation> interpolation = SVGStrokeDasharrayStyleInterpolation::maybeCreate(value, value, CSSPropertyStrokeDasharray);
         ASSERT(interpolation);
-        return SVGStrokeDasharrayStyleInterpolation::interpolableValueToStrokeDasharray(*interpolation->m_start, types);
+        return SVGStrokeDasharrayStyleInterpolation::interpolableValueToStrokeDasharray(*interpolation->m_start);
     }
 
     static void testPrimitiveValue(const CSSValue& cssValue, double value, CSSPrimitiveValue::UnitType unitType)
@@ -43,11 +43,7 @@
     start->append(CSSPrimitiveValue::create(0, CSSPrimitiveValue::CSS_EMS));
     start->append(CSSPrimitiveValue::create(0, CSSPrimitiveValue::CSS_PX));
 
-    Vector<CSSPrimitiveValue::UnitType> types(3);
-    types[0] = CSSPrimitiveValue::CSS_PERCENTAGE;
-    types[1] = CSSPrimitiveValue::CSS_EMS;
-    types[2] = CSSPrimitiveValue::CSS_PX;
-    RefPtrWillBeRawPtr<CSSValueList> value = roundTrip(*start, types);
+    RefPtrWillBeRawPtr<CSSValueList> value = roundTrip(*start);
     EXPECT_EQ(value->length(), 3u);
     testPrimitiveValue(*value->item(0), 0, CSSPrimitiveValue::CSS_PERCENTAGE);
     testPrimitiveValue(*value->item(1), 0, CSSPrimitiveValue::CSS_EMS);
@@ -63,13 +59,7 @@
     start->append(CSSPrimitiveValue::create(0, CSSPrimitiveValue::CSS_PERCENTAGE));
     start->append(CSSPrimitiveValue::create(30, CSSPrimitiveValue::CSS_EMS));
 
-    Vector<CSSPrimitiveValue::UnitType> types(5);
-    types[0] = CSSPrimitiveValue::CSS_PX;
-    types[1] = CSSPrimitiveValue::CSS_EMS;
-    types[2] = CSSPrimitiveValue::CSS_EMS;
-    types[3] = CSSPrimitiveValue::CSS_PERCENTAGE;
-    types[4] = CSSPrimitiveValue::CSS_EMS;
-    RefPtrWillBeRawPtr<CSSValueList> value = roundTrip(*start, types);
+    RefPtrWillBeRawPtr<CSSValueList> value = roundTrip(*start);
     EXPECT_EQ(value->length(), 5u);
     testPrimitiveValue(*value->item(0), 0, CSSPrimitiveValue::CSS_PX);
     testPrimitiveValue(*value->item(1), 10, CSSPrimitiveValue::CSS_EMS);
@@ -82,9 +72,7 @@
 {
     RefPtrWillBeRawPtr<CSSPrimitiveValue> start = CSSPrimitiveValue::createIdentifier(CSSValueNone);
 
-    Vector<CSSPrimitiveValue::UnitType> types(1);
-    types[0] = CSSPrimitiveValue::CSS_PX;
-    RefPtrWillBeRawPtr<CSSValueList> value = roundTrip(*start, types);
+    RefPtrWillBeRawPtr<CSSValueList> value = roundTrip(*start);
     EXPECT_EQ(value->length(), 1u);
     testPrimitiveValue(*value->item(0), 0, CSSPrimitiveValue::CSS_PX);
 }
diff --git a/Source/core/animation/animatable/AnimatableStrokeDasharrayList.cpp b/Source/core/animation/animatable/AnimatableStrokeDasharrayList.cpp
index 360a25e..1c84a7c 100644
--- a/Source/core/animation/animatable/AnimatableStrokeDasharrayList.cpp
+++ b/Source/core/animation/animatable/AnimatableStrokeDasharrayList.cpp
@@ -31,28 +31,22 @@
 #include "config.h"
 #include "core/animation/animatable/AnimatableStrokeDasharrayList.h"
 
-#include "core/animation/animatable/AnimatableSVGLength.h"
+#include "core/animation/animatable/AnimatableLength.h"
 
 namespace blink {
 
-AnimatableStrokeDasharrayList::AnimatableStrokeDasharrayList(PassRefPtrWillBeRawPtr<SVGLengthList> passLengths)
+AnimatableStrokeDasharrayList::AnimatableStrokeDasharrayList(PassRefPtr<SVGDashArray> passLengths, float zoom)
 {
-    RefPtrWillBeRawPtr<SVGLengthList> lengths = passLengths;
-    SVGLengthList::ConstIterator it = lengths->begin();
-    SVGLengthList::ConstIterator itEnd = lengths->end();
-    for (; it != itEnd; ++it)
-        m_values.append(AnimatableSVGLength::create(*it));
+    RefPtr<SVGDashArray> lengths = passLengths;
+    for (const Length& dashLength : lengths->vector())
+        m_values.append(AnimatableLength::create(dashLength, zoom));
 }
 
-PassRefPtrWillBeRawPtr<SVGLengthList> AnimatableStrokeDasharrayList::toSVGLengthList() const
+PassRefPtr<SVGDashArray> AnimatableStrokeDasharrayList::toSVGDashArray(float zoom) const
 {
-    RefPtrWillBeRawPtr<SVGLengthList> lengths = SVGLengthList::create();
-    for (size_t i = 0; i < m_values.size(); ++i) {
-        RefPtrWillBeRawPtr<SVGLength> length = toAnimatableSVGLength(m_values[i].get())->toSVGLength()->clone();
-        if (length->valueInSpecifiedUnits() < 0)
-            length->setValueInSpecifiedUnits(0);
-        lengths->append(length);
-    }
+    RefPtr<SVGDashArray> lengths = SVGDashArray::create();
+    for (const auto& dashLength : m_values)
+        lengths->append(toAnimatableLength(dashLength.get())->length(zoom, ValueRangeNonNegative));
     return lengths.release();
 }
 
@@ -79,7 +73,7 @@
     if (from.isEmpty() && to.isEmpty())
         return takeConstRef(this);
     if (from.isEmpty() || to.isEmpty()) {
-        DEFINE_STATIC_REF_WILL_BE_PERSISTENT(AnimatableSVGLength, zeroPixels, (AnimatableSVGLength::create(SVGLength::create())));
+        DEFINE_STATIC_REF_WILL_BE_PERSISTENT(AnimatableLength, zeroPixels, (AnimatableLength::create(Length(Fixed), 1)));
         if (from.isEmpty()) {
             from.append(zeroPixels);
             from.append(zeroPixels);
diff --git a/Source/core/animation/animatable/AnimatableStrokeDasharrayList.h b/Source/core/animation/animatable/AnimatableStrokeDasharrayList.h
index 8fbc0b3..e49b1ba 100644
--- a/Source/core/animation/animatable/AnimatableStrokeDasharrayList.h
+++ b/Source/core/animation/animatable/AnimatableStrokeDasharrayList.h
@@ -32,7 +32,7 @@
 #define AnimatableStrokeDasharrayList_h
 
 #include "core/animation/animatable/AnimatableRepeatable.h"
-#include "core/svg/SVGLengthList.h"
+#include "core/layout/style/SVGLayoutStyleDefs.h"
 
 namespace blink {
 
@@ -40,12 +40,12 @@
 public:
     virtual ~AnimatableStrokeDasharrayList() { }
 
-    static PassRefPtrWillBeRawPtr<AnimatableStrokeDasharrayList> create(PassRefPtrWillBeRawPtr<SVGLengthList> lengths)
+    static PassRefPtrWillBeRawPtr<AnimatableStrokeDasharrayList> create(PassRefPtr<SVGDashArray> lengths, float zoom)
     {
-        return adoptRefWillBeNoop(new AnimatableStrokeDasharrayList(lengths));
+        return adoptRefWillBeNoop(new AnimatableStrokeDasharrayList(lengths, zoom));
     }
 
-    PassRefPtrWillBeRawPtr<SVGLengthList> toSVGLengthList() const;
+    PassRefPtr<SVGDashArray> toSVGDashArray(float zoom) const;
 
     DECLARE_VIRTUAL_TRACE();
 
@@ -54,7 +54,7 @@
     virtual bool usesDefaultInterpolationWith(const AnimatableValue*) const override;
 
 private:
-    explicit AnimatableStrokeDasharrayList(PassRefPtrWillBeRawPtr<SVGLengthList>);
+    AnimatableStrokeDasharrayList(PassRefPtr<SVGDashArray>, float zoom);
     // This will consume the vector passed into it.
     AnimatableStrokeDasharrayList(WillBeHeapVector<RefPtrWillBeMember<AnimatableValue> >& values)
         : AnimatableRepeatable(values)
diff --git a/Source/core/animation/animatable/AnimatableStrokeDasharrayListTest.cpp b/Source/core/animation/animatable/AnimatableStrokeDasharrayListTest.cpp
index 327747d..f7a2975 100644
--- a/Source/core/animation/animatable/AnimatableStrokeDasharrayListTest.cpp
+++ b/Source/core/animation/animatable/AnimatableStrokeDasharrayListTest.cpp
@@ -31,7 +31,7 @@
 #include "config.h"
 #include "core/animation/animatable/AnimatableStrokeDasharrayList.h"
 
-#include "core/svg/SVGLength.h"
+#include "core/layout/style/SVGLayoutStyleDefs.h"
 
 #include <gtest/gtest.h>
 
@@ -39,29 +39,28 @@
 
 namespace {
 
-PassRefPtrWillBeRawPtr<SVGLengthList> createSVGLengthList(size_t length)
+PassRefPtr<SVGDashArray> createSVGDashArray(size_t length)
 {
-    RefPtrWillBeRawPtr<SVGLengthList> list = SVGLengthList::create();
+    RefPtr<SVGDashArray> list = SVGDashArray::create();
     for (size_t i = 0; i < length; ++i)
-        list->append(SVGLength::create());
+        list->append(Length(Fixed));
     return list.release();
 }
 
 TEST(AnimationAnimatableStrokeDasharrayListTest, EqualTo)
 {
-    RefPtrWillBeRawPtr<SVGLengthList> svgListA = createSVGLengthList(4);
-    RefPtrWillBeRawPtr<SVGLengthList> svgListB = createSVGLengthList(4);
-    RefPtrWillBeRawPtr<AnimatableStrokeDasharrayList> listA = AnimatableStrokeDasharrayList::create(svgListA);
-    RefPtrWillBeRawPtr<AnimatableStrokeDasharrayList> listB = AnimatableStrokeDasharrayList::create(svgListB);
+    RefPtr<SVGDashArray> svgListA = createSVGDashArray(4);
+    RefPtr<SVGDashArray> svgListB = createSVGDashArray(4);
+    RefPtrWillBeRawPtr<AnimatableStrokeDasharrayList> listA = AnimatableStrokeDasharrayList::create(svgListA, 1);
+    RefPtrWillBeRawPtr<AnimatableStrokeDasharrayList> listB = AnimatableStrokeDasharrayList::create(svgListB, 1);
     EXPECT_TRUE(listA->equals(listB.get()));
 
-    TrackExceptionState exceptionState;
-    svgListB->at(3)->newValueSpecifiedUnits(LengthTypePX, 50);
-    listB = AnimatableStrokeDasharrayList::create(svgListB);
+    svgListB->at(3) = Length(50, Fixed);
+    listB = AnimatableStrokeDasharrayList::create(svgListB, 1);
     EXPECT_FALSE(listA->equals(listB.get()));
 
-    svgListB = createSVGLengthList(5);
-    listB = AnimatableStrokeDasharrayList::create(svgListB);
+    svgListB = createSVGDashArray(5);
+    listB = AnimatableStrokeDasharrayList::create(svgListB, 1);
     EXPECT_FALSE(listA->equals(listB.get()));
 }
 
diff --git a/Source/core/animation/animatable/AnimatableValueTestHelper.cpp b/Source/core/animation/animatable/AnimatableValueTestHelper.cpp
index 5b02a04..a697295 100644
--- a/Source/core/animation/animatable/AnimatableValueTestHelper.cpp
+++ b/Source/core/animation/animatable/AnimatableValueTestHelper.cpp
@@ -88,10 +88,14 @@
 void PrintTo(const AnimatableStrokeDasharrayList& animValue, ::std::ostream* os)
 {
     *os << "AnimatableStrokeDasharrayList(";
-    RefPtrWillBeRawPtr<SVGLengthList> list = animValue.toSVGLengthList();
-    size_t length = list->length();
+    RefPtr<SVGDashArray> list = animValue.toSVGDashArray(1);
+    size_t length = list->size();
     for (size_t i = 0; i < length; ++i) {
-        *os << list->at(i)->valueAsString().utf8().data();
+        const Length& dashLength = list->at(i);
+        PixelsAndPercent pixelsAndPercent = dashLength.pixelsAndPercent();
+        *os << pixelsAndPercent.pixels << '+';
+        *os << pixelsAndPercent.percent << '%';
+
         if (i != length-1)
             *os << ", ";
     }
diff --git a/Source/core/animation/animatable/AnimatableValueTestHelperTest.cpp b/Source/core/animation/animatable/AnimatableValueTestHelperTest.cpp
index e4ed137..1c6bdc2 100644
--- a/Source/core/animation/animatable/AnimatableValueTestHelperTest.cpp
+++ b/Source/core/animation/animatable/AnimatableValueTestHelperTest.cpp
@@ -32,6 +32,7 @@
 
 #include "core/animation/animatable/AnimatableValueTestHelper.h"
 
+#include "bindings/core/v8/ExceptionStatePlaceholder.h"
 #include "core/layout/ClipPathOperation.h"
 #include "core/layout/style/BasicShapes.h"
 #include "core/svg/SVGLengthContext.h"
@@ -84,12 +85,12 @@
         PrintToString(AnimatableShapeValue::create(ShapeValue::createShapeValue(BasicShapeCircle::create().get(), ContentBox).get())),
         testing::StartsWith("AnimatableShapeValue@"));
 
-    RefPtrWillBeRawPtr<SVGLengthList> l2 = SVGLengthList::create();
-    l2->append(length1cm);
-    l2->append(length2cm);
+    RefPtr<SVGDashArray> l2 = SVGDashArray::create();
+    l2->append(Length(1, blink::Fixed));
+    l2->append(Length(2, blink::Percent));
     EXPECT_EQ(
-        ::std::string("AnimatableStrokeDasharrayList(1cm, 2cm)"),
-        PrintToString(AnimatableStrokeDasharrayList::create(l2)));
+        ::std::string("AnimatableStrokeDasharrayList(1+0%, 0+2%)"),
+        PrintToString(AnimatableStrokeDasharrayList::create(l2, 1)));
 
     TransformOperations operations1;
     operations1.operations().append(TranslateTransformOperation::create(Length(2, blink::Fixed), Length(0, blink::Fixed), TransformOperation::TranslateX));
diff --git a/Source/core/animation/css/CSSAnimatableValueFactory.cpp b/Source/core/animation/css/CSSAnimatableValueFactory.cpp
index 957b72b..b2a6b31 100644
--- a/Source/core/animation/css/CSSAnimatableValueFactory.cpp
+++ b/Source/core/animation/css/CSSAnimatableValueFactory.cpp
@@ -440,7 +440,7 @@
     case CSSPropertyStopOpacity:
         return createFromDouble(style.stopOpacity());
     case CSSPropertyStrokeDasharray:
-        return AnimatableStrokeDasharrayList::create(style.strokeDashArray());
+        return AnimatableStrokeDasharrayList::create(style.strokeDashArray(), style.effectiveZoom());
     case CSSPropertyStrokeDashoffset:
         return createFromLength(style.strokeDashOffset(), style);
     case CSSPropertyStrokeMiterlimit:
diff --git a/Source/core/animation/css/CSSPropertyEquality.cpp b/Source/core/animation/css/CSSPropertyEquality.cpp
index 8eb1bf5..4775574 100644
--- a/Source/core/animation/css/CSSPropertyEquality.cpp
+++ b/Source/core/animation/css/CSSPropertyEquality.cpp
@@ -221,7 +221,7 @@
             && (aSVG.visitedLinkStrokePaintType() != SVG_PAINTTYPE_RGBCOLOR || aSVG.visitedLinkStrokePaintColor() == bSVG.visitedLinkStrokePaintColor());
     }
     case CSSPropertyStrokeDasharray:
-        return dataEquivalent(a.strokeDashArray(), b.strokeDashArray());
+        return a.strokeDashArray() == b.strokeDashArray();
     case CSSPropertyStrokeDashoffset:
         return a.strokeDashOffset() == b.strokeDashOffset();
     case CSSPropertyStrokeMiterlimit:
diff --git a/Source/core/css/LayoutStyleCSSValueMapping.cpp b/Source/core/css/LayoutStyleCSSValueMapping.cpp
index bc39fa6..a331569 100644
--- a/Source/core/css/LayoutStyleCSSValueMapping.cpp
+++ b/Source/core/css/LayoutStyleCSSValueMapping.cpp
@@ -1120,18 +1120,14 @@
     }
 }
 
-static PassRefPtrWillBeRawPtr<CSSValue> strokeDashArrayToCSSValueList(PassRefPtrWillBeRawPtr<SVGLengthList> passDashes)
+static PassRefPtrWillBeRawPtr<CSSValue> strokeDashArrayToCSSValueList(const SVGDashArray& dashes, const LayoutStyle& style)
 {
-    RefPtrWillBeRawPtr<SVGLengthList> dashes = passDashes;
-
-    if (dashes->isEmpty())
+    if (dashes.isEmpty())
         return CSSPrimitiveValue::createIdentifier(CSSValueNone);
 
     RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
-    SVGLengthList::ConstIterator it = dashes->begin();
-    SVGLengthList::ConstIterator itEnd = dashes->end();
-    for (; it != itEnd; ++it)
-        list->append(SVGLength::toCSSPrimitiveValue(*it));
+    for (const Length& dashLength : dashes.vector())
+        list->append(zoomAdjustedPixelValueForLength(dashLength, style));
 
     return list.release();
 }
@@ -2522,7 +2518,7 @@
     case CSSPropertyStroke:
         return adjustSVGPaintForCurrentColor(svgStyle.strokePaintType(), svgStyle.strokePaintUri(), svgStyle.strokePaintColor(), style.color());
     case CSSPropertyStrokeDasharray:
-        return strokeDashArrayToCSSValueList(svgStyle.strokeDashArray());
+        return strokeDashArrayToCSSValueList(*svgStyle.strokeDashArray(), style);
     case CSSPropertyStrokeDashoffset:
         return zoomAdjustedPixelValueForLength(svgStyle.strokeDashOffset(), style);
     case CSSPropertyStrokeWidth:
diff --git a/Source/core/css/resolver/AnimatedStyleBuilder.cpp b/Source/core/css/resolver/AnimatedStyleBuilder.cpp
index a4a6b7e..d246097 100644
--- a/Source/core/css/resolver/AnimatedStyleBuilder.cpp
+++ b/Source/core/css/resolver/AnimatedStyleBuilder.cpp
@@ -486,7 +486,7 @@
         style->setStopOpacity(clampTo<float>(toAnimatableDouble(value)->toDouble(), 0, 1));
         return;
     case CSSPropertyStrokeDasharray:
-        style->setStrokeDashArray(toAnimatableStrokeDasharrayList(value)->toSVGLengthList());
+        style->setStrokeDashArray(toAnimatableStrokeDasharrayList(value)->toSVGDashArray(style->effectiveZoom()));
         return;
     case CSSPropertyStrokeDashoffset:
         style->setStrokeDashOffset(animatableValueToLength(value, state));
diff --git a/Source/core/css/resolver/StyleBuilderConverter.cpp b/Source/core/css/resolver/StyleBuilderConverter.cpp
index ad8ddec..37168922 100644
--- a/Source/core/css/resolver/StyleBuilderConverter.cpp
+++ b/Source/core/css/resolver/StyleBuilderConverter.cpp
@@ -814,14 +814,14 @@
     return primitiveValue->computeLength<float>(state.cssToLengthConversionData());
 }
 
-PassRefPtrWillBeRawPtr<SVGLengthList> StyleBuilderConverter::convertStrokeDasharray(StyleResolverState&, CSSValue* value)
+PassRefPtr<SVGDashArray> StyleBuilderConverter::convertStrokeDasharray(StyleResolverState& state, CSSValue* value)
 {
     if (!value->isValueList())
         return SVGLayoutStyle::initialStrokeDashArray();
 
     CSSValueList* dashes = toCSSValueList(value);
 
-    RefPtrWillBeRawPtr<SVGLengthList> array = SVGLengthList::create();
+    RefPtr<SVGDashArray> array = SVGDashArray::create();
     size_t length = dashes->length();
     for (size_t i = 0; i < length; ++i) {
         CSSValue* currValue = dashes->item(i);
@@ -829,7 +829,7 @@
             continue;
 
         CSSPrimitiveValue* dash = toCSSPrimitiveValue(dashes->item(i));
-        array->append(SVGLength::fromCSSPrimitiveValue(dash));
+        array->append(convertLength(state, dash));
     }
 
     return array.release();
diff --git a/Source/core/css/resolver/StyleBuilderConverter.h b/Source/core/css/resolver/StyleBuilderConverter.h
index 6cbb722..1976266 100644
--- a/Source/core/css/resolver/StyleBuilderConverter.h
+++ b/Source/core/css/resolver/StyleBuilderConverter.h
@@ -82,7 +82,7 @@
     static PassRefPtr<ShapeValue> convertShapeValue(StyleResolverState&, CSSValue*);
     static float convertSpacing(StyleResolverState&, CSSValue*);
     template <CSSValueID IdForNone> static AtomicString convertString(StyleResolverState&, CSSValue*);
-    static PassRefPtrWillBeRawPtr<SVGLengthList> convertStrokeDasharray(StyleResolverState&, CSSValue*);
+    static PassRefPtr<SVGDashArray> convertStrokeDasharray(StyleResolverState&, CSSValue*);
     static StyleColor convertStyleColor(StyleResolverState&, CSSValue*, bool forVisitedLink = false);
     static Color convertSVGColor(StyleResolverState&, CSSValue*);
     static PassRefPtrWillBeRawPtr<SVGLength> convertSVGLength(StyleResolverState&, CSSValue*);
diff --git a/Source/core/dom/StyleElement.cpp b/Source/core/dom/StyleElement.cpp
index 112e68c..032fc01 100644
--- a/Source/core/dom/StyleElement.cpp
+++ b/Source/core/dom/StyleElement.cpp
@@ -33,6 +33,7 @@
 #include "core/frame/LocalFrame.h"
 #include "core/frame/csp/ContentSecurityPolicy.h"
 #include "core/html/HTMLStyleElement.h"
+#include "core/svg/SVGStyleElement.h"
 #include "platform/TraceEvent.h"
 #include "wtf/text/StringBuilder.h"
 
diff --git a/Source/core/dom/StyleEngine.cpp b/Source/core/dom/StyleEngine.cpp
index 45d2459..31e2efc 100644
--- a/Source/core/dom/StyleEngine.cpp
+++ b/Source/core/dom/StyleEngine.cpp
@@ -39,13 +39,14 @@
 #include "core/dom/ProcessingInstruction.h"
 #include "core/dom/ShadowTreeStyleSheetCollection.h"
 #include "core/dom/shadow/ShadowRoot.h"
+#include "core/frame/Settings.h"
 #include "core/html/HTMLIFrameElement.h"
 #include "core/html/HTMLLinkElement.h"
 #include "core/html/imports/HTMLImportsController.h"
 #include "core/inspector/InspectorInstrumentation.h"
 #include "core/page/InjectedStyleSheets.h"
 #include "core/page/Page.h"
-#include "core/frame/Settings.h"
+#include "core/svg/SVGStyleElement.h"
 #include "platform/URLPatternMatcher.h"
 
 namespace blink {
diff --git a/Source/core/html/forms/InputType.cpp b/Source/core/html/forms/InputType.cpp
index 5f7dd11..f3ff5fe 100644
--- a/Source/core/html/forms/InputType.cpp
+++ b/Source/core/html/forms/InputType.cpp
@@ -32,6 +32,7 @@
 #include "bindings/core/v8/ExceptionState.h"
 #include "core/InputTypeNames.h"
 #include "core/dom/AXObjectCache.h"
+#include "core/dom/ExceptionCode.h"
 #include "core/dom/NodeLayoutStyle.h"
 #include "core/events/KeyboardEvent.h"
 #include "core/events/ScopedEventQueue.h"
diff --git a/Source/core/layout/style/LayoutStyle.h b/Source/core/layout/style/LayoutStyle.h
index 388c937..45b5333 100644
--- a/Source/core/layout/style/LayoutStyle.h
+++ b/Source/core/layout/style/LayoutStyle.h
@@ -1369,8 +1369,8 @@
     void setStrokeOpacity(float f) { accessSVGStyle().setStrokeOpacity(f); }
     SVGLength* strokeWidth() const { return svgStyle().strokeWidth(); }
     void setStrokeWidth(PassRefPtrWillBeRawPtr<SVGLength> w) { accessSVGStyle().setStrokeWidth(w); }
-    SVGLengthList* strokeDashArray() const { return svgStyle().strokeDashArray(); }
-    void setStrokeDashArray(PassRefPtrWillBeRawPtr<SVGLengthList> array) { accessSVGStyle().setStrokeDashArray(array); }
+    SVGDashArray* strokeDashArray() const { return svgStyle().strokeDashArray(); }
+    void setStrokeDashArray(PassRefPtr<SVGDashArray> array) { accessSVGStyle().setStrokeDashArray(array); }
     const Length& strokeDashOffset() const { return svgStyle().strokeDashOffset(); }
     void setStrokeDashOffset(const Length& d) { accessSVGStyle().setStrokeDashOffset(d); }
     float strokeMiterLimit() const { return svgStyle().strokeMiterLimit(); }
diff --git a/Source/core/layout/style/SVGLayoutStyle.cpp b/Source/core/layout/style/SVGLayoutStyle.cpp
index 2be0dac..55957ff 100644
--- a/Source/core/layout/style/SVGLayoutStyle.cpp
+++ b/Source/core/layout/style/SVGLayoutStyle.cpp
@@ -120,6 +120,12 @@
     resources = other->resources;
 }
 
+PassRefPtr<SVGDashArray> SVGLayoutStyle::initialStrokeDashArray()
+{
+    DEFINE_STATIC_REF(SVGDashArray, initialDashArray, SVGDashArray::create());
+    return initialDashArray;
+}
+
 StyleDifference SVGLayoutStyle::diff(const SVGLayoutStyle* other) const
 {
     StyleDifference styleDifference;
diff --git a/Source/core/layout/style/SVGLayoutStyle.h b/Source/core/layout/style/SVGLayoutStyle.h
index 8424738..29f3540 100644
--- a/Source/core/layout/style/SVGLayoutStyle.h
+++ b/Source/core/layout/style/SVGLayoutStyle.h
@@ -75,7 +75,7 @@
     static SVGPaintType initialStrokePaintType() { return SVG_PAINTTYPE_NONE; }
     static Color initialStrokePaintColor() { return Color(); }
     static String initialStrokePaintUri() { return String(); }
-    static PassRefPtrWillBeRawPtr<SVGLengthList> initialStrokeDashArray() { return SVGLengthList::create(); }
+    static PassRefPtr<SVGDashArray> initialStrokeDashArray();
     static Length initialStrokeDashOffset() { return Length(Fixed); }
     static float initialStrokeMiterLimit() { return 4; }
     static float initialStopOpacity() { return 1; }
@@ -195,10 +195,10 @@
         }
     }
 
-    void setStrokeDashArray(PassRefPtrWillBeRawPtr<SVGLengthList> obj)
+    void setStrokeDashArray(PassRefPtr<SVGDashArray> dashArray)
     {
-        if (*stroke->dashArray != *obj)
-            stroke.access()->dashArray = obj;
+        if (*stroke->dashArray != *dashArray)
+            stroke.access()->dashArray = dashArray;
     }
 
     void setStrokeMiterLimit(float obj)
@@ -319,7 +319,7 @@
     const SVGPaintType& strokePaintType() const { return stroke->paintType; }
     const Color& strokePaintColor() const { return stroke->paintColor; }
     const String& strokePaintUri() const { return stroke->paintUri; }
-    SVGLengthList* strokeDashArray() const { return stroke->dashArray.get(); }
+    SVGDashArray* strokeDashArray() const { return stroke->dashArray.get(); }
     float strokeMiterLimit() const { return stroke->miterLimit; }
     SVGLength* strokeWidth() const { return stroke->width.get(); }
     const Length& strokeDashOffset() const { return stroke->dashOffset; }
diff --git a/Source/core/layout/style/SVGLayoutStyleDefs.cpp b/Source/core/layout/style/SVGLayoutStyleDefs.cpp
index 2419eef..44b837e 100644
--- a/Source/core/layout/style/SVGLayoutStyleDefs.cpp
+++ b/Source/core/layout/style/SVGLayoutStyleDefs.cpp
@@ -87,7 +87,7 @@
     , miterLimit(other.miterLimit)
     , width(other.width->clone())
     , dashOffset(other.dashOffset)
-    , dashArray(other.dashArray->clone())
+    , dashArray(other.dashArray)
     , paintType(other.paintType)
     , paintColor(other.paintColor)
     , paintUri(other.paintUri)
diff --git a/Source/core/layout/style/SVGLayoutStyleDefs.h b/Source/core/layout/style/SVGLayoutStyleDefs.h
index 6431379..3bd1bcb 100644
--- a/Source/core/layout/style/SVGLayoutStyleDefs.h
+++ b/Source/core/layout/style/SVGLayoutStyleDefs.h
@@ -29,15 +29,19 @@
 #define SVGLayoutStyleDefs_h
 
 #include "core/svg/SVGLength.h"
-#include "core/svg/SVGLengthList.h"
 #include "platform/Length.h"
+#include "platform/graphics/Color.h"
 #include "wtf/OwnPtr.h"
 #include "wtf/PassOwnPtr.h"
 #include "wtf/RefCounted.h"
 #include "wtf/RefPtr.h"
+#include "wtf/RefVector.h"
+#include "wtf/text/WTFString.h"
 
 namespace blink {
 
+typedef RefVector<Length> SVGDashArray;
+
 enum SVGPaintType {
     SVG_PAINTTYPE_RGBCOLOR,
     SVG_PAINTTYPE_NONE,
@@ -162,7 +166,7 @@
 
     RefPtrWillBePersistent<SVGLength> width;
     Length dashOffset;
-    RefPtrWillBePersistent<SVGLengthList> dashArray;
+    RefPtr<SVGDashArray> dashArray;
 
     SVGPaintType paintType;
     Color paintColor;
diff --git a/Source/core/layout/style/SVGLayoutStyleTest.cpp b/Source/core/layout/style/SVGLayoutStyleTest.cpp
index ad3d662..c4709a4 100644
--- a/Source/core/layout/style/SVGLayoutStyleTest.cpp
+++ b/Source/core/layout/style/SVGLayoutStyleTest.cpp
@@ -5,8 +5,7 @@
 #include "config.h"
 #include "core/layout/style/SVGLayoutStyle.h"
 
-#include "core/layout/ClipPathOperation.h"
-#include "core/layout/style/ShapeValue.h"
+#include "core/svg/SVGLength.h"
 
 #include <gtest/gtest.h>
 
@@ -14,8 +13,8 @@
 
 namespace {
 
-// Ensures RefPtr values are compared by their values, not by pointers.
-#define TEST_STYLE_REFPTR_VALUE_NO_DIFF(type, fieldName) \
+// Ensures RefPtrWillBePersistent values are compared by their values, not by pointers.
+#define TEST_STYLE_REFPTRWILLBEPERSISTENT_VALUE_NO_DIFF(type, fieldName) \
     { \
         RefPtr<SVGLayoutStyle> svg1 = SVGLayoutStyle::create(); \
         RefPtr<SVGLayoutStyle> svg2 = SVGLayoutStyle::create(); \
@@ -26,6 +25,18 @@
         EXPECT_FALSE(svg1->diff(svg2.get()).hasDifference()); \
     }
 
+// Ensures RefPtr values are compared by their values, not by pointers.
+#define TEST_STYLE_REFPTR_VALUE_NO_DIFF(type, fieldName) \
+    { \
+        RefPtr<SVGLayoutStyle> svg1 = SVGLayoutStyle::create(); \
+        RefPtr<SVGLayoutStyle> svg2 = SVGLayoutStyle::create(); \
+        RefPtr<type> value1 = type::create(); \
+        RefPtr<type> value2 = value1->copy(); \
+        svg1->set##fieldName(value1); \
+        svg2->set##fieldName(value2); \
+        EXPECT_FALSE(svg1->diff(svg2.get()).hasDifference()); \
+    }
+
 // This is not very useful for fields directly stored by values, because they can only be
 // compared by values. This macro mainly ensures that we update the comparisons and tests
 // when we change some field to RefPtr in the future.
@@ -42,9 +53,9 @@
 {
     TEST_STYLE_VALUE_NO_DIFF(float, StrokeOpacity);
     TEST_STYLE_VALUE_NO_DIFF(float, StrokeMiterLimit);
-    TEST_STYLE_REFPTR_VALUE_NO_DIFF(SVGLength, StrokeWidth);
+    TEST_STYLE_REFPTRWILLBEPERSISTENT_VALUE_NO_DIFF(SVGLength, StrokeWidth);
     TEST_STYLE_VALUE_NO_DIFF(Length, StrokeDashOffset);
-    TEST_STYLE_REFPTR_VALUE_NO_DIFF(SVGLengthList, StrokeDashArray);
+    TEST_STYLE_REFPTR_VALUE_NO_DIFF(SVGDashArray, StrokeDashArray);
 
     {
         RefPtr<SVGLayoutStyle> svg1 = SVGLayoutStyle::create();
diff --git a/Source/core/layout/svg/SVGLayoutSupport.cpp b/Source/core/layout/svg/SVGLayoutSupport.cpp
index bd23d62..c9c11fe 100644
--- a/Source/core/layout/svg/SVGLayoutSupport.cpp
+++ b/Source/core/layout/svg/SVGLayoutSupport.cpp
@@ -348,6 +348,14 @@
     return pointInClippingArea(object, localPoint);
 }
 
+DashArray SVGLayoutSupport::resolveSVGDashArray(const SVGDashArray& svgDashArray, const LayoutStyle& style, const SVGLengthContext& lengthContext)
+{
+    DashArray dashArray;
+    for (const Length& dashLength : svgDashArray.vector())
+        dashArray.append(lengthContext.valueForLength(dashLength, style));
+    return dashArray;
+}
+
 void SVGLayoutSupport::applyStrokeStyleToContext(GraphicsContext& context, const LayoutStyle& style, const LayoutObject& object)
 {
     ASSERT(object.node());
@@ -361,14 +369,7 @@
     context.setLineJoin(svgStyle.joinStyle());
     context.setMiterLimit(svgStyle.strokeMiterLimit());
 
-    RefPtrWillBeRawPtr<SVGLengthList> dashes = svgStyle.strokeDashArray();
-    DashArray dashArray;
-    if (!dashes->isEmpty()) {
-        SVGLengthList::ConstIterator it = dashes->begin();
-        SVGLengthList::ConstIterator itEnd = dashes->end();
-        for (; it != itEnd; ++it)
-            dashArray.append(it->value(lengthContext));
-    }
+    DashArray dashArray = resolveSVGDashArray(*svgStyle.strokeDashArray(), style, lengthContext);
     context.setLineDash(dashArray, lengthContext.valueForLength(svgStyle.strokeDashOffset(), style));
 }
 
@@ -385,14 +386,7 @@
     strokeData.setLineJoin(svgStyle.joinStyle());
     strokeData.setMiterLimit(svgStyle.strokeMiterLimit());
 
-    RefPtrWillBeRawPtr<SVGLengthList> dashes = svgStyle.strokeDashArray();
-    DashArray dashArray;
-    if (!dashes->isEmpty()) {
-        SVGLengthList::ConstIterator it = dashes->begin();
-        SVGLengthList::ConstIterator itEnd = dashes->end();
-        for (; it != itEnd; ++it)
-            dashArray.append(it->value(lengthContext));
-    }
+    DashArray dashArray = resolveSVGDashArray(*svgStyle.strokeDashArray(), style, lengthContext);
     strokeData.setLineDash(dashArray, lengthContext.valueForLength(svgStyle.strokeDashOffset(), style));
 }
 
diff --git a/Source/core/layout/svg/SVGLayoutSupport.h b/Source/core/layout/svg/SVGLayoutSupport.h
index 03e7f2c..5bf34b4 100644
--- a/Source/core/layout/svg/SVGLayoutSupport.h
+++ b/Source/core/layout/svg/SVGLayoutSupport.h
@@ -25,6 +25,7 @@
 #define SVGLayoutSupport_h
 
 #include "core/layout/svg/LayoutSVGResourcePaintServer.h"
+#include "platform/graphics/DashArray.h"
 
 namespace blink {
 
@@ -41,6 +42,7 @@
 class LayoutObject;
 class LayoutStyle;
 class LayoutSVGRoot;
+class SVGLengthContext;
 class StrokeData;
 class TransformState;
 
@@ -81,6 +83,8 @@
     static void applyStrokeStyleToContext(GraphicsContext&, const LayoutStyle&, const LayoutObject&);
     static void applyStrokeStyleToStrokeData(StrokeData&, const LayoutStyle&, const LayoutObject&);
 
+    static DashArray resolveSVGDashArray(const SVGDashArray&, const LayoutStyle&, const SVGLengthContext&);
+
     // Update the GC state (on |paintInfo.context|) for painting |renderer|
     // using |style|. |resourceMode| is used to decide between fill/stroke.
     // Previous state will be saved (if needed) using |stateSaver|.
diff --git a/Source/core/layout/svg/SVGLayoutTreeAsText.cpp b/Source/core/layout/svg/SVGLayoutTreeAsText.cpp
index bd6d17e..56b6b95 100644
--- a/Source/core/layout/svg/SVGLayoutTreeAsText.cpp
+++ b/Source/core/layout/svg/SVGLayoutTreeAsText.cpp
@@ -290,13 +290,7 @@
             SVGLengthContext lengthContext(shape.element());
             double dashOffset = lengthContext.valueForLength(svgStyle.strokeDashOffset(), style);
             double strokeWidth = svgStyle.strokeWidth()->value(lengthContext);
-            RefPtrWillBeRawPtr<SVGLengthList> dashes = svgStyle.strokeDashArray();
-
-            DashArray dashArray;
-            SVGLengthList::ConstIterator it = dashes->begin();
-            SVGLengthList::ConstIterator itEnd = dashes->end();
-            for (; it != itEnd; ++it)
-                dashArray.append(it->value(lengthContext));
+            DashArray dashArray = SVGLayoutSupport::resolveSVGDashArray(*svgStyle.strokeDashArray(), style, lengthContext);
 
             writeIfNotDefault(ts, "opacity", svgStyle.strokeOpacity(), 1.0f);
             writeIfNotDefault(ts, "stroke width", strokeWidth, 1.0);
diff --git a/Source/core/workers/Worker.cpp b/Source/core/workers/Worker.cpp
index 1431a29..8a0b761 100644
--- a/Source/core/workers/Worker.cpp
+++ b/Source/core/workers/Worker.cpp
@@ -30,6 +30,7 @@
 
 #include "bindings/core/v8/ExceptionState.h"
 #include "core/dom/Document.h"
+#include "core/dom/ExceptionCode.h"
 #include "core/events/MessageEvent.h"
 #include "core/fetch/ResourceFetcher.h"
 #include "core/inspector/InspectorInstrumentation.h"
diff --git a/Source/wtf/RefVector.h b/Source/wtf/RefVector.h
index d719b7a..0571fc7 100644
--- a/Source/wtf/RefVector.h
+++ b/Source/wtf/RefVector.h
@@ -26,6 +26,7 @@
     bool operator!=(const RefVector& o) const { return m_vector != o.m_vector; }
 
     size_t size() const { return m_vector.size(); }
+    bool isEmpty() const { return !size(); }
     void append(const T& decoration) { m_vector.append(decoration); }
     const Vector<T>& vector() const { return m_vector; }