Title: [275868] trunk
Revision
275868
Author
s...@apple.com
Date
2021-04-13 01:05:24 -0700 (Tue, 13 Apr 2021)

Log Message

SVG paced value animations overwrite user-provided keyTimes
https://bugs.webkit.org/show_bug.cgi?id=109010

Reviewed by Ryosuke Niwa.

LayoutTests/imported/w3c:

* web-platform-tests/svg/animations/scripted/paced-value-animation-overwrites-keyTimes-expected.txt:

Source/WebCore:

If the calcMode is Paced, the 'keyTimes' attribute is ignored. Distances
between the 'values' are used produce an even pace of change across the
animation.

When changing calcMode, times defined in the 'keyTimes' attribute should
be used instead. To fix this, SVGAnimationElement can maintain two lists
for keyTimes: (1) keyTimesFromAttribute (2) keyTimesForPaced.
One of these lists will be picked by a new function 'keyTimes()' based
on the current calcMode.

Specs: https://www.w3.org/TR/SVG11/animate.html#CalcModeAttribute

Test: svg/animations/animate-calcMode-paced-overwrite-key-times.html

* svg/SVGAnimationElement.cpp:
(WebCore::SVGAnimationElement::parseAttribute):
(WebCore::SVGAnimationElement::calculateKeyTimesForCalcModePaced):
(WebCore::SVGAnimationElement::keyTimes const):
(WebCore::SVGAnimationElement::calculateKeyTimesIndex const):
(WebCore::SVGAnimationElement::calculatePercentFromKeyPoints const):
(WebCore::SVGAnimationElement::calculatePercentForFromTo const):
(WebCore::SVGAnimationElement::currentValuesFromKeyPoints const):
(WebCore::SVGAnimationElement::currentValuesForValuesAnimation):
(WebCore::SVGAnimationElement::startedActiveInterval):
(WebCore::SVGAnimationElement::updateAnimation):
* svg/SVGAnimationElement.h:

LayoutTests:

Simplified from the WPT paced-value-animation-overwrites-keyTimes.html.

* svg/animations/animate-calcMode-paced-overwrite-key-times-expected.html: Added.
* svg/animations/animate-calcMode-paced-overwrite-key-times.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (275867 => 275868)


--- trunk/LayoutTests/ChangeLog	2021-04-13 08:04:07 UTC (rev 275867)
+++ trunk/LayoutTests/ChangeLog	2021-04-13 08:05:24 UTC (rev 275868)
@@ -1,3 +1,15 @@
+2021-04-13  Said Abou-Hallawa  <s...@apple.com>
+
+        SVG paced value animations overwrite user-provided keyTimes
+        https://bugs.webkit.org/show_bug.cgi?id=109010
+
+        Reviewed by Ryosuke Niwa.
+
+        Simplified from the WPT paced-value-animation-overwrites-keyTimes.html.
+
+        * svg/animations/animate-calcMode-paced-overwrite-key-times-expected.html: Added.
+        * svg/animations/animate-calcMode-paced-overwrite-key-times.html: Added.
+
 2021-04-12  Xabier Rodriguez Calvar  <calva...@igalia.com>
 
         [GTK] media/track/text-track-cue-is-reachable.html is flaky crashing in X11 release

Modified: trunk/LayoutTests/imported/w3c/ChangeLog (275867 => 275868)


--- trunk/LayoutTests/imported/w3c/ChangeLog	2021-04-13 08:04:07 UTC (rev 275867)
+++ trunk/LayoutTests/imported/w3c/ChangeLog	2021-04-13 08:05:24 UTC (rev 275868)
@@ -1,3 +1,12 @@
+2021-04-13  Said Abou-Hallawa  <s...@apple.com>
+
+        SVG paced value animations overwrite user-provided keyTimes
+        https://bugs.webkit.org/show_bug.cgi?id=109010
+
+        Reviewed by Ryosuke Niwa.
+
+        * web-platform-tests/svg/animations/scripted/paced-value-animation-overwrites-keyTimes-expected.txt:
+
 2021-04-12  Commit Queue  <commit-qu...@webkit.org>
 
         Unreviewed, reverting r275793.

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/svg/animations/scripted/paced-value-animation-overwrites-keyTimes-expected.txt (275867 => 275868)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/svg/animations/scripted/paced-value-animation-overwrites-keyTimes-expected.txt	2021-04-13 08:04:07 UTC (rev 275867)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/svg/animations/scripted/paced-value-animation-overwrites-keyTimes-expected.txt	2021-04-13 08:05:24 UTC (rev 275868)
@@ -1,3 +1,3 @@
 
-FAIL Paced value animation doesn't overwrite keyTimes assert_approx_equals: expected 150 +/- 5 but got 120
+PASS Paced value animation doesn't overwrite keyTimes
 

Added: trunk/LayoutTests/svg/animations/animate-calcMode-paced-overwrite-key-times-expected.html (0 => 275868)


--- trunk/LayoutTests/svg/animations/animate-calcMode-paced-overwrite-key-times-expected.html	                        (rev 0)
+++ trunk/LayoutTests/svg/animations/animate-calcMode-paced-overwrite-key-times-expected.html	2021-04-13 08:05:24 UTC (rev 275868)
@@ -0,0 +1,6 @@
+<body>
+  <svg id="svg" width="500" height="500">
+    <rect x="150" y="0" width="100" height="100" fill="green"/>
+  </svg>
+  </script>
+</body>

Added: trunk/LayoutTests/svg/animations/animate-calcMode-paced-overwrite-key-times.html (0 => 275868)


--- trunk/LayoutTests/svg/animations/animate-calcMode-paced-overwrite-key-times.html	                        (rev 0)
+++ trunk/LayoutTests/svg/animations/animate-calcMode-paced-overwrite-key-times.html	2021-04-13 08:05:24 UTC (rev 275868)
@@ -0,0 +1,26 @@
+<body>
+    <svg id="svg" width="500" height="500">
+        <rect x="150" y="0" width="100" height="100" fill="red"/>
+        <rect width="100" height="100" fill="green">
+            <animate id="animate1" attributeName="x" dur="10s" calcMode="paced" values="100; 150; 200;" keyTimes="0; 0.2; 1"/>
+        </rect>
+    </svg>
+    <script>
+        window.addEventListener('load', (event) => {
+            if (window.testRunner)
+                testRunner.waitUntilDone();
+
+            window.requestAnimationFrame(() => {
+                let svg = document.getElementById('svg');
+                let animate1 = document.getElementById('animate1');
+
+                animate1.setAttribute('calcMode', 'linear');
+                svg.pauseAnimations();
+                svg.setCurrentTime(2);
+
+                if (window.testRunner)
+                    testRunner.notifyDone();
+            });
+        });
+  </script>
+</body>

Modified: trunk/Source/WebCore/ChangeLog (275867 => 275868)


--- trunk/Source/WebCore/ChangeLog	2021-04-13 08:04:07 UTC (rev 275867)
+++ trunk/Source/WebCore/ChangeLog	2021-04-13 08:05:24 UTC (rev 275868)
@@ -1,3 +1,37 @@
+2021-04-13  Said Abou-Hallawa  <s...@apple.com>
+
+        SVG paced value animations overwrite user-provided keyTimes
+        https://bugs.webkit.org/show_bug.cgi?id=109010
+
+        Reviewed by Ryosuke Niwa.
+
+        If the calcMode is Paced, the 'keyTimes' attribute is ignored. Distances
+        between the 'values' are used produce an even pace of change across the
+        animation.
+
+        When changing calcMode, times defined in the 'keyTimes' attribute should
+        be used instead. To fix this, SVGAnimationElement can maintain two lists 
+        for keyTimes: (1) keyTimesFromAttribute (2) keyTimesForPaced.
+        One of these lists will be picked by a new function 'keyTimes()' based
+        on the current calcMode.
+
+        Specs: https://www.w3.org/TR/SVG11/animate.html#CalcModeAttribute
+
+        Test: svg/animations/animate-calcMode-paced-overwrite-key-times.html
+
+        * svg/SVGAnimationElement.cpp:
+        (WebCore::SVGAnimationElement::parseAttribute):
+        (WebCore::SVGAnimationElement::calculateKeyTimesForCalcModePaced):
+        (WebCore::SVGAnimationElement::keyTimes const):
+        (WebCore::SVGAnimationElement::calculateKeyTimesIndex const):
+        (WebCore::SVGAnimationElement::calculatePercentFromKeyPoints const):
+        (WebCore::SVGAnimationElement::calculatePercentForFromTo const):
+        (WebCore::SVGAnimationElement::currentValuesFromKeyPoints const):
+        (WebCore::SVGAnimationElement::currentValuesForValuesAnimation):
+        (WebCore::SVGAnimationElement::startedActiveInterval):
+        (WebCore::SVGAnimationElement::updateAnimation):
+        * svg/SVGAnimationElement.h:
+
 2021-04-12  Ryosuke Niwa  <rn...@webkit.org>
 
         TextManipulationController should use weak pointers to Node

Modified: trunk/Source/WebCore/svg/SVGAnimationElement.cpp (275867 => 275868)


--- trunk/Source/WebCore/svg/SVGAnimationElement.cpp	2021-04-13 08:04:07 UTC (rev 275867)
+++ trunk/Source/WebCore/svg/SVGAnimationElement.cpp	2021-04-13 08:05:24 UTC (rev 275868)
@@ -2,7 +2,7 @@
  * Copyright (C) 2004, 2005 Nikolas Zimmermann <zimmerm...@kde.org>
  * Copyright (C) 2004, 2005, 2006, 2007 Rob Buis <b...@kde.org>
  * Copyright (C) 2007 Eric Seidel <e...@webkit.org>
- * Copyright (C) 2008, 2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2008-2021 Apple Inc. All rights reserved.
  * Copyright (C) 2009 Cameron McCormack <c...@mcc.id.au>
  * Copyright (C) Research In Motion Limited 2010. All rights reserved.
  * Copyright (C) 2014 Adobe Systems Incorporated. All rights reserved.
@@ -161,7 +161,7 @@
     }
 
     if (name == SVGNames::keyTimesAttr) {
-        parseKeyTimes(value, m_keyTimes, true);
+        parseKeyTimes(value, m_keyTimesFromAttribute, true);
         return;
     }
 
@@ -346,8 +346,7 @@
     if (valuesCount == 1)
         return;
 
-    // FIXME, webkit.org/b/109010: m_keyTimes should not be modified in this function.
-    m_keyTimes.clear();
+    m_keyTimesForPaced.clear();
 
     Vector<float> keyTimesForPaced;
     float totalDistance = 0;
@@ -368,21 +367,26 @@
         keyTimesForPaced[n] = keyTimesForPaced[n - 1] + keyTimesForPaced[n] / totalDistance;
     keyTimesForPaced[keyTimesForPaced.size() - 1] = 1;
 
-    // Use key times calculated based on pacing instead of the user provided ones.
-    m_keyTimes = keyTimesForPaced;
+    m_keyTimesForPaced = WTFMove(keyTimesForPaced);
 }
 
 static inline double solveEpsilon(double duration) { return 1 / (200 * duration); }
 
+const Vector<float>& SVGAnimationElement::keyTimes() const
+{
+    return calcMode() == CalcMode::Paced ? m_keyTimesForPaced : m_keyTimesFromAttribute;
+}
+
 unsigned SVGAnimationElement::calculateKeyTimesIndex(float percent) const
 {
+    const auto& keyTimes = this->keyTimes();
     unsigned index;
-    unsigned keyTimesCount = m_keyTimes.size();
+    unsigned keyTimesCount = keyTimes.size();
     // Compare index + 1 to keyTimesCount because the last keyTimes entry is
     // required to be 1, and percent can never exceed 1; i.e., the second last
     // keyTimes entry defines the beginning of the final interval
     for (index = 1; index + 1 < keyTimesCount; ++index) {
-        if (m_keyTimes[index] > percent)
+        if (keyTimes[index] > percent)
             break;
     }
     return --index;
@@ -401,17 +405,19 @@
 
 float SVGAnimationElement::calculatePercentFromKeyPoints(float percent) const
 {
+    const auto& keyTimes = this->keyTimes();
+
     ASSERT(!m_keyPoints.isEmpty());
     ASSERT(calcMode() != CalcMode::Paced);
-    ASSERT(m_keyTimes.size() > 1);
-    ASSERT(m_keyPoints.size() == m_keyTimes.size());
+    ASSERT(keyTimes.size() > 1);
+    ASSERT(m_keyPoints.size() == keyTimes.size());
 
     if (percent == 1)
         return m_keyPoints[m_keyPoints.size() - 1];
 
     unsigned index = calculateKeyTimesIndex(percent);
-    float fromPercent = m_keyTimes[index];
-    float toPercent = m_keyTimes[index + 1];
+    float fromPercent = keyTimes[index];
+    float toPercent = keyTimes[index + 1];
     float fromKeyPoint = m_keyPoints[index];
     float toKeyPoint = m_keyPoints[index + 1];
     
@@ -429,8 +435,9 @@
 
 float SVGAnimationElement::calculatePercentForFromTo(float percent) const
 {
-    if (calcMode() == CalcMode::Discrete && m_keyTimes.size() == 2)
-        return percent > m_keyTimes[1] ? 1 : 0;
+    const auto& keyTimes = this->keyTimes();
+    if (calcMode() == CalcMode::Discrete && keyTimes.size() == 2)
+        return percent > keyTimes[1] ? 1 : 0;
 
     return percent;
 }
@@ -438,7 +445,7 @@
 void SVGAnimationElement::currentValuesFromKeyPoints(float percent, float& effectivePercent, String& from, String& to) const
 {
     ASSERT(!m_keyPoints.isEmpty());
-    ASSERT(m_keyPoints.size() == m_keyTimes.size());
+    ASSERT(m_keyPoints.size() == keyTimes().size());
     ASSERT(calcMode() != CalcMode::Paced);
     effectivePercent = calculatePercentFromKeyPoints(percent);
     unsigned index = effectivePercent == 1 ? m_values.size() - 2 : static_cast<unsigned>(effectivePercent * (m_values.size() - 1));
@@ -468,9 +475,10 @@
     if (!m_keyPoints.isEmpty() && calcMode != CalcMode::Paced)
         return currentValuesFromKeyPoints(percent, effectivePercent, from, to);
     
-    unsigned keyTimesCount = m_keyTimes.size();
+    const auto& keyTimes = this->keyTimes();
+    unsigned keyTimesCount = keyTimes.size();
     ASSERT(!keyTimesCount || valuesCount == keyTimesCount);
-    ASSERT(!keyTimesCount || (keyTimesCount > 1 && !m_keyTimes[0]));
+    ASSERT(!keyTimesCount || (keyTimesCount > 1 && !keyTimes[0]));
 
     unsigned index = calculateKeyTimesIndex(percent);
     if (calcMode == CalcMode::Discrete) {
@@ -485,8 +493,8 @@
     float fromPercent;
     float toPercent;
     if (keyTimesCount) {
-        fromPercent = m_keyTimes[index];
-        toPercent = m_keyTimes[index + 1];
+        fromPercent = keyTimes[index];
+        toPercent = keyTimes[index + 1];
     } else {        
         index = static_cast<unsigned>(floorf(percent * (valuesCount - 1)));
         fromPercent =  static_cast<float>(index) / (valuesCount - 1);
@@ -513,8 +521,10 @@
     if (!hasValidAttributeType())
         return;
 
+    const auto& keyTimes = this->keyTimes();
+
     // These validations are appropriate for all animation modes.
-    if (hasAttributeWithoutSynchronization(SVGNames::keyPointsAttr) && m_keyPoints.size() != m_keyTimes.size())
+    if (hasAttributeWithoutSynchronization(SVGNames::keyPointsAttr) && m_keyPoints.size() != keyTimes.size())
         return;
 
     AnimationMode animationMode = this->animationMode();
@@ -524,7 +534,7 @@
         if (!splinesCount
             || (hasAttributeWithoutSynchronization(SVGNames::keyPointsAttr) && m_keyPoints.size() - 1 != splinesCount)
             || (animationMode == AnimationMode::Values && m_values.size() - 1 != splinesCount)
-            || (hasAttributeWithoutSynchronization(SVGNames::keyTimesAttr) && m_keyTimes.size() - 1 != splinesCount))
+            || (hasAttributeWithoutSynchronization(SVGNames::keyTimesAttr) && keyTimes.size() - 1 != splinesCount))
             return;
     }
 
@@ -534,7 +544,7 @@
     if (animationMode == AnimationMode::None)
         return;
     if ((animationMode == AnimationMode::FromTo || animationMode == AnimationMode::FromBy || animationMode == AnimationMode::To || animationMode == AnimationMode::By)
-        && (hasAttributeWithoutSynchronization(SVGNames::keyPointsAttr) && hasAttributeWithoutSynchronization(SVGNames::keyTimesAttr) && (m_keyTimes.size() < 2 || m_keyTimes.size() != m_keyPoints.size())))
+        && (hasAttributeWithoutSynchronization(SVGNames::keyPointsAttr) && hasAttributeWithoutSynchronization(SVGNames::keyTimesAttr) && (keyTimes.size() < 2 || keyTimes.size() != m_keyPoints.size())))
         return;
     if (animationMode == AnimationMode::FromTo)
         m_animationValid = calculateFromAndToValues(from, to);
@@ -548,16 +558,16 @@
         m_animationValid = calculateFromAndByValues(emptyString(), by);
     else if (animationMode == AnimationMode::Values) {
         m_animationValid = m_values.size() >= 1
-            && (calcMode == CalcMode::Paced || !hasAttributeWithoutSynchronization(SVGNames::keyTimesAttr) || hasAttributeWithoutSynchronization(SVGNames::keyPointsAttr) || (m_values.size() == m_keyTimes.size()))
-            && (calcMode == CalcMode::Discrete || !m_keyTimes.size() || m_keyTimes.last() == 1)
+            && (calcMode == CalcMode::Paced || !hasAttributeWithoutSynchronization(SVGNames::keyTimesAttr) || hasAttributeWithoutSynchronization(SVGNames::keyPointsAttr) || (m_values.size() == keyTimes.size()))
+            && (calcMode == CalcMode::Discrete || !keyTimes.size() || keyTimes.last() == 1)
             && (calcMode != CalcMode::Spline || ((m_keySplines.size() && (m_keySplines.size() == m_values.size() - 1)) || m_keySplines.size() == m_keyPoints.size() - 1))
-            && (!hasAttributeWithoutSynchronization(SVGNames::keyPointsAttr) || (m_keyTimes.size() > 1 && m_keyTimes.size() == m_keyPoints.size()));
+            && (!hasAttributeWithoutSynchronization(SVGNames::keyPointsAttr) || (keyTimes.size() > 1 && keyTimes.size() == m_keyPoints.size()));
         if (m_animationValid)
             m_animationValid = calculateToAtEndOfDurationValue(m_values.last());
         if (calcMode == CalcMode::Paced && m_animationValid)
             calculateKeyTimesForCalcModePaced();
     } else if (animationMode == AnimationMode::Path)
-        m_animationValid = calcMode == CalcMode::Paced || !hasAttributeWithoutSynchronization(SVGNames::keyPointsAttr) || (m_keyTimes.size() > 1 && m_keyTimes.size() == m_keyPoints.size());
+        m_animationValid = calcMode == CalcMode::Paced || !hasAttributeWithoutSynchronization(SVGNames::keyPointsAttr) || (keyTimes.size() > 1 && keyTimes.size() == m_keyPoints.size());
 }
 
 void SVGAnimationElement::updateAnimation(float percent, unsigned repeatCount)
@@ -581,7 +591,7 @@
         }
     } else if (!m_keyPoints.isEmpty() && calcMode != CalcMode::Paced)
         effectivePercent = calculatePercentFromKeyPoints(percent);
-    else if (m_keyPoints.isEmpty() && calcMode == CalcMode::Spline && m_keyTimes.size() > 1)
+    else if (m_keyPoints.isEmpty() && calcMode == CalcMode::Spline && keyTimes().size() > 1)
         effectivePercent = calculatePercentForSpline(percent, calculateKeyTimesIndex(percent));
     else if (animationMode == AnimationMode::FromTo || animationMode == AnimationMode::To)
         effectivePercent = calculatePercentForFromTo(percent);

Modified: trunk/Source/WebCore/svg/SVGAnimationElement.h (275867 => 275868)


--- trunk/Source/WebCore/svg/SVGAnimationElement.h	2021-04-13 08:04:07 UTC (rev 275867)
+++ trunk/Source/WebCore/svg/SVGAnimationElement.h	2021-04-13 08:05:24 UTC (rev 275868)
@@ -2,7 +2,7 @@
  * Copyright (C) 2004, 2005 Nikolas Zimmermann <zimmerm...@kde.org>
  * Copyright (C) 2004, 2005, 2006 Rob Buis <b...@kde.org>
  * Copyright (C) 2007 Eric Seidel <e...@webkit.org>
- * Copyright (C) 2008-2019 Apple Inc. All rights reserved.
+ * Copyright (C) 2008-2021 Apple Inc. All rights reserved.
  * Copyright (C) 2008 Cameron McCormack <c...@mcc.id.au>
  * Copyright (C) Research In Motion Limited 2011. All rights reserved.
  *
@@ -123,6 +123,7 @@
     virtual void calculateAnimatedValue(float percent, unsigned repeatCount) = 0;
     virtual Optional<float> calculateDistance(const String& /*fromString*/, const String& /*toString*/) = 0;
 
+    const Vector<float>& keyTimes() const;
     void currentValuesForValuesAnimation(float percent, float& effectivePercent, String& from, String& to);
     void calculateKeyTimesForCalcModePaced();
     float calculatePercentFromKeyPoints(float percent) const;
@@ -137,7 +138,8 @@
 
     AttributeType m_attributeType { AttributeType::Auto };
     Vector<String> m_values;
-    Vector<float> m_keyTimes;
+    Vector<float> m_keyTimesFromAttribute;
+    Vector<float> m_keyTimesForPaced;
     Vector<float> m_keyPoints;
     Vector<UnitBezier> m_keySplines;
     String m_lastValuesAnimationFrom;
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to