CSS Animations with triggers should map scroll position to duration
authordino@apple.com <dino@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 20 Mar 2015 04:47:20 +0000 (04:47 +0000)
committerdino@apple.com <dino@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 20 Mar 2015 04:47:20 +0000 (04:47 +0000)
https://bugs.webkit.org/show_bug.cgi?id=142870
<rdar://problem/20227244>

Reviewed by Simon Fraser.

Source/WebCore:

Expose a prototype implementation of what will eventually be called
animation-timebase, mapping the scroll location to the duration of an
animation. This only applies if the animation has a start and end
trigger.

Test: animations/trigger-container-scroll-boundaries.html
Test: animations/trigger-container-scroll-empty.html

* css/CSSComputedStyleDeclaration.cpp:
(WebCore::createAnimationTriggerValue): Change to downcast.

* css/CSSToStyleMap.cpp:
(WebCore::CSSToStyleMap::mapAnimationTrigger): Fix a bug where I wasn't
telling the ScrollAnimationTrigger object whether or not it had
an end value. This wasn't visible before because we were not using
the end value.

* page/animation/AnimationBase.cpp:
(WebCore::AnimationBase::fireAnimationEventsIfNeeded): Add a comment and
change to using a downcast.
(WebCore::AnimationBase::timeToNextService): Change to downcast.
(WebCore::AnimationBase::freezeAtTime): Whitespace cleanup.
(WebCore::AnimationBase::getElapsedTime): Calculate the elapsedTime based
on the scroll position relative to the start and end trigger spots.

* page/animation/AnimationController.cpp:
(WebCore::AnimationControllerPrivate::updateAnimations): Since this
can potentially call into beginAnimationUpdateTime, it should have
an update blocker. This fixes the assert we were seeing in tests.
(WebCore::AnimationControllerPrivate::scrollWasUpdated): Keep track of the scroll
position so we don't need to ask for it all the time.
* page/animation/AnimationControllerPrivate.h:
(WebCore::AnimationControllerPrivate::scrollPosition): New accessor.

* platform/animation/AnimationTrigger.h: Add downcast macros.
(WebCore::ScrollAnimationTrigger::create): Calculate hasEndValue from the passed
parameters rather than a separate value.
(WebCore::ScrollAnimationTrigger::hasEndValue):
(WebCore::ScrollAnimationTrigger::ScrollAnimationTrigger):
(WebCore::ScrollAnimationTrigger::setHasEndValue): Deleted.

* platform/graphics/ca/GraphicsLayerCA.cpp:
(WebCore::GraphicsLayerCA::animationCanBeAccelerated): If we have an
animation of this sort, we can't use a CAAnimation.

LayoutTests:

Add a new test that exercises an animation trigger over a scroll
region, and a test of the boundary condition. Also, unskip a test that
was failing due to a bug fixed in this patch.

* animations/trigger-container-scroll-boundaries-expected.txt: Added.
* animations/trigger-container-scroll-boundaries.html: Added.
* animations/trigger-container-scroll-empty-expected.txt: Added.
* animations/trigger-container-scroll-empty.html: Added.
* platform/efl/TestExpectations:
* platform/gtk/TestExpectations:
* platform/mac/TestExpectations:
* platform/win/TestExpectations:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@181778 268f45cc-cd09-0410-ab3c-d52691b4dbfc

16 files changed:
LayoutTests/ChangeLog
LayoutTests/animations/trigger-container-scroll-boundaries-expected.txt [new file with mode: 0644]
LayoutTests/animations/trigger-container-scroll-boundaries.html [new file with mode: 0644]
LayoutTests/animations/trigger-container-scroll-empty-expected.txt [new file with mode: 0644]
LayoutTests/animations/trigger-container-scroll-empty.html [new file with mode: 0644]
LayoutTests/platform/efl/TestExpectations
LayoutTests/platform/gtk/TestExpectations
LayoutTests/platform/mac/TestExpectations
LayoutTests/platform/win/TestExpectations
Source/WebCore/ChangeLog
Source/WebCore/css/CSSComputedStyleDeclaration.cpp
Source/WebCore/page/animation/AnimationBase.cpp
Source/WebCore/page/animation/AnimationController.cpp
Source/WebCore/page/animation/AnimationControllerPrivate.h
Source/WebCore/platform/animation/AnimationTrigger.h
Source/WebCore/platform/graphics/ca/GraphicsLayerCA.cpp

index 857bd91..9a91566 100644 (file)
@@ -1,3 +1,24 @@
+2015-03-19  Dean Jackson  <dino@apple.com>
+
+        CSS Animations with triggers should map scroll position to duration
+        https://bugs.webkit.org/show_bug.cgi?id=142870
+        <rdar://problem/20227244>
+
+        Reviewed by Simon Fraser.
+
+        Add a new test that exercises an animation trigger over a scroll
+        region, and a test of the boundary condition. Also, unskip a test that
+        was failing due to a bug fixed in this patch.
+
+        * animations/trigger-container-scroll-boundaries-expected.txt: Added.
+        * animations/trigger-container-scroll-boundaries.html: Added.
+        * animations/trigger-container-scroll-empty-expected.txt: Added.
+        * animations/trigger-container-scroll-empty.html: Added.
+        * platform/efl/TestExpectations:
+        * platform/gtk/TestExpectations:
+        * platform/mac/TestExpectations:
+        * platform/win/TestExpectations:
+
 2015-03-19  Joseph Pecoraro  <pecoraro@apple.com>
 
         Web Inspector: Adopt ES6 Class Syntax for all Model Objects
diff --git a/LayoutTests/animations/trigger-container-scroll-boundaries-expected.txt b/LayoutTests/animations/trigger-container-scroll-boundaries-expected.txt
new file mode 100644 (file)
index 0000000..2210924
--- /dev/null
@@ -0,0 +1,14 @@
+This element should begin animating only when the page scrolls to 20px from the top. It then animates smoothly, moving 100px to the left over the next 100px of scrolling. Remember to scroll to the top of the page before reloading!
+
+PASS: Value before animation is applied is auto
+PASS: Value with animation but no scroll was 0px
+PASS: Value with scroll amount of 10 was 10px
+PASS: Value with scroll amount of 20 was 20px
+PASS: Value with scroll amount of 30 was 30px
+PASS: Value with scroll amount of 40 was 40px
+PASS: Value with scroll amount of 50 was 50px
+PASS: Value with scroll amount of 60 was 60px
+PASS: Value with scroll amount of 70 was 70px
+PASS: Value with scroll amount of 80 was 80px
+PASS: Value with scroll amount of 90 was 90px
+
diff --git a/LayoutTests/animations/trigger-container-scroll-boundaries.html b/LayoutTests/animations/trigger-container-scroll-boundaries.html
new file mode 100644 (file)
index 0000000..717b0e5
--- /dev/null
@@ -0,0 +1,97 @@
+<!DOCTYPE html>
+<style>
+body {
+    height: 2000px;
+}
+
+#box {
+    position: relative;
+    width: 20px;
+    height: 20px;
+    background-color: blue;
+}
+
+.animating {
+    animation-name: slide;
+    animation-duration: 1ms;
+    animation-fill-mode: forwards;
+    animation-timing-function: linear;
+    -webkit-animation-trigger: container-scroll(20px, 120px);
+}
+
+@-webkit-keyframes slide {
+  from {
+      left: 0px;
+  }
+  to {
+      left: 100px;
+  }
+}
+</style>
+<script>
+
+var results;
+var box;
+
+var scrollMin = 20;
+var scrollMax = 120;
+
+if (window.testRunner) {
+    window.testRunner.dumpAsText();
+    window.testRunner.waitUntilDone();
+}
+
+function runTest() {
+    results = document.getElementById("results");
+    box = document.getElementById("box");
+    var leftValue = window.getComputedStyle(box).left;
+    if (leftValue == "auto")
+        results.innerHTML = "PASS: Value before animation is applied is auto<br>";
+    else
+        results.innerHTML = "FAIL: Value before animation is applied should be auto, was " + leftValue + "<br>";
+    box.className = "animating";
+    setTimeout(checkValueWithoutScroll, 0);
+}
+
+function checkValueWithoutScroll() {
+    var leftValue = window.getComputedStyle(box).left;
+    if (leftValue == "0px")
+        results.innerHTML += "PASS: Value with animation but no scroll was 0px<br>";
+    else
+        results.innerHTML += "FAIL: Value with animation but no scroll should be 0px, was " + leftValue + "<br>";
+
+    window.scrollTo(0, scrollMin + 10);
+    setTimeout(function () {
+        checkValueWithScroll(10);
+    }, 0);
+}
+
+function checkValueWithScroll(scrollAmount) {
+    var leftValue = Math.round(window.getComputedStyle(box).getPropertyCSSValue("left").getFloatValue(CSSPrimitiveValue.CSS_NUMBER));
+
+    if (leftValue == scrollAmount)
+        results.innerHTML += "PASS: Value with scroll amount of " + scrollAmount + " was " + scrollAmount + "px<br>";
+    else
+        results.innerHTML += "FAIL: Value with scroll amount of " + scrollAmount + " should be " + scrollAmount + "px, was " + leftValue + "px<br>";
+
+    if (scrollMin + scrollAmount + 10 < scrollMax) {
+        window.scrollTo(0, scrollMin + scrollAmount + 10);
+        setTimeout(function () {
+            checkValueWithScroll(scrollAmount + 10);
+        }, 0);
+    } else {
+        if (window.testRunner)
+            window.testRunner.notifyDone();
+    }
+}
+
+window.addEventListener("load", runTest, false);
+
+</script>
+
+<p>This element should begin animating only when the page scrolls to 20px from
+the top. It then animates smoothly, moving 100px to the left over the next
+100px of scrolling. Remember to scroll to the top of the page before reloading!</p>
+<div id="box"></div>
+
+<div id="results"></div>
diff --git a/LayoutTests/animations/trigger-container-scroll-empty-expected.txt b/LayoutTests/animations/trigger-container-scroll-empty-expected.txt
new file mode 100644 (file)
index 0000000..3a6b6c8
--- /dev/null
@@ -0,0 +1,6 @@
+This element should begin animating only when the page scrolls to 20px from the top. It specifies an end value, but that should be ignored because it is not greater than the start. This means the animation will run to completion rather than take the scroll value as input. Remember to scroll to the top of the page before reloading!
+
+Value before animation is applied: auto (should be auto)
+Value with animation but no scroll: 0px (should be 0px)
+PASS: Animation was not depending on scroll.
+
diff --git a/LayoutTests/animations/trigger-container-scroll-empty.html b/LayoutTests/animations/trigger-container-scroll-empty.html
new file mode 100644 (file)
index 0000000..2cb37c7
--- /dev/null
@@ -0,0 +1,78 @@
+<!DOCTYPE html>
+<style>
+body {
+    height: 2000px;
+}
+
+#box {
+    position: relative;
+    width: 20px;
+    height: 20px;
+    background-color: blue;
+}
+
+.animating {
+    animation-name: slide;
+    animation-duration: 1ms;
+    animation-fill-mode: forwards;
+    animation-timing-function: linear;
+    -webkit-animation-trigger: container-scroll(20px, 20px);
+}
+
+@-webkit-keyframes slide {
+  from {
+      left: 0px;
+  }
+  to {
+      left: 100px;
+  }
+}
+</style>
+<script>
+
+var results;
+var box;
+
+if (window.testRunner) {
+    window.testRunner.dumpAsText();
+    window.testRunner.waitUntilDone();
+}
+
+function runTest() {
+    results = document.getElementById("results");
+    box = document.getElementById("box");
+    results.innerHTML = "Value before animation is applied: " + window.getComputedStyle(box).left + " (should be auto)<br>";
+    box.className = "animating";
+    setTimeout(checkValueWithoutScroll, 0);
+}
+
+function checkValueWithoutScroll() {
+    results.innerHTML += "Value with animation but no scroll: " + window.getComputedStyle(box).left + " (should be 0px)<br>";
+    window.scrollTo(0, 30);
+    setTimeout(checkValueWithScroll, 10);
+}
+
+function checkValueWithScroll() {
+    var leftValue = Math.round(window.getComputedStyle(box).getPropertyCSSValue("left").getFloatValue(CSSPrimitiveValue.CSS_NUMBER));
+
+    if (leftValue > 11) // If we were reacting to scroll we'd have a value of 10.
+        results.innerHTML += "PASS: Animation was not depending on scroll.<br>";
+    else
+        results.innerHTML += "FAIL: Value seems to be reacting to scroll. It was " + leftValue + "px<br>";
+
+    if (window.testRunner)
+        window.testRunner.notifyDone();
+}
+
+window.addEventListener("load", runTest, false);
+
+</script>
+
+<p>This element should begin animating only when the page scrolls to 20px from
+the top. It specifies an end value, but that should be ignored because it is
+not greater than the start. This means the animation will run to completion
+rather than take the scroll value as input. Remember to scroll to the top of
+the page before reloading!</p>
+<div id="box"></div>
+
+<div id="results"></div>
index 6cd7aea..c89a6d3 100644 (file)
@@ -66,6 +66,7 @@ css3/scroll-snap [ Skip ]
 animations/trigger-computed-style.html [ Skip ]
 animations/trigger-parsing.html [ Skip ]
 animations/trigger-container-scroll-simple.html [ Skip ]
+animations/trigger-container-scroll-boundaries.html [ Skip ]
 
 # ----------------------------------------
 # Tests which also fail in other platforms
index da56df2..6641319 100644 (file)
@@ -465,6 +465,7 @@ css3/scroll-snap
 animations/trigger-computed-style.html [ Skip ]
 animations/trigger-parsing.html [ Skip ]
 animations/trigger-container-scroll-simple.html [ Skip ]
+animations/trigger-container-scroll-boundaries.html [ Skip ]
 
 # ENABLE(SHADOW_DOM) is disabled.
 Bug(GTK) fast/dom/shadow [ Skip ]
index b799848..4687eb3 100644 (file)
@@ -26,9 +26,6 @@ webkit.org/b/126066 accessibility/loading-iframe-updates-axtree.html [ Failure C
 
 webkit.org/b/116636 accessibility/document-attributes.html [ Failure ]
 
-# Skip this test while it is crashing
-webkit.org/b/142790 animations/trigger-container-scroll-simple.html [ Skip ]
-
 # Accessibility tests with missing AccessibilityController functionality.
 webkit.org/b/116637 accessibility/selection-states.html [ Failure ]
 
index 294590c..92adc34 100644 (file)
@@ -600,6 +600,7 @@ webkit.org/b/142731 fast/images/animated-png.html [ Skip ]
 animations/trigger-computed-style.html [ Skip ]
 animations/trigger-parsing.html [ Skip ]
 animations/trigger-container-scroll-simple.html [ Skip ]
+animations/trigger-container-scroll-boundaries.html [ Skip ]
 
 ################################################################################
 ###########    End Missing Functionality Prevents Testing         ##############
index fc7fba8..e52155f 100644 (file)
@@ -1,3 +1,55 @@
+2015-03-19  Dean Jackson  <dino@apple.com>
+
+        CSS Animations with triggers should map scroll position to duration
+        https://bugs.webkit.org/show_bug.cgi?id=142870
+        <rdar://problem/20227244>
+
+        Reviewed by Simon Fraser.
+
+        Expose a prototype implementation of what will eventually be called
+        animation-timebase, mapping the scroll location to the duration of an
+        animation. This only applies if the animation has a start and end
+        trigger.
+
+        Test: animations/trigger-container-scroll-boundaries.html
+
+        * css/CSSComputedStyleDeclaration.cpp:
+        (WebCore::createAnimationTriggerValue): Change to downcast.
+
+        * css/CSSToStyleMap.cpp:
+        (WebCore::CSSToStyleMap::mapAnimationTrigger): Fix a bug where I wasn't
+        telling the ScrollAnimationTrigger object whether or not it had
+        an end value. This wasn't visible before because we were not using
+        the end value.
+
+        * page/animation/AnimationBase.cpp:
+        (WebCore::AnimationBase::fireAnimationEventsIfNeeded): Add a comment and
+        change to using a downcast.
+        (WebCore::AnimationBase::timeToNextService): Change to downcast.
+        (WebCore::AnimationBase::freezeAtTime): Whitespace cleanup.
+        (WebCore::AnimationBase::getElapsedTime): Calculate the elapsedTime based
+        on the scroll position relative to the start and end trigger spots.
+
+        * page/animation/AnimationController.cpp:
+        (WebCore::AnimationControllerPrivate::updateAnimations): Since this
+        can potentially call into beginAnimationUpdateTime, it should have
+        an update blocker. This fixes the assert we were seeing in tests.
+        (WebCore::AnimationControllerPrivate::scrollWasUpdated): Keep track of the scroll
+        position so we don't need to ask for it all the time.
+        * page/animation/AnimationControllerPrivate.h:
+        (WebCore::AnimationControllerPrivate::scrollPosition): New accessor.
+
+        * platform/animation/AnimationTrigger.h: Add downcast macros.
+        (WebCore::ScrollAnimationTrigger::create): Calculate hasEndValue from the passed
+        parameters rather than a separate value.
+        (WebCore::ScrollAnimationTrigger::hasEndValue):
+        (WebCore::ScrollAnimationTrigger::ScrollAnimationTrigger):
+        (WebCore::ScrollAnimationTrigger::setHasEndValue): Deleted.
+
+        * platform/graphics/ca/GraphicsLayerCA.cpp:
+        (WebCore::GraphicsLayerCA::animationCanBeAccelerated): If we have an
+        animation of this sort, we can't use a CAAnimation.
+
 2015-03-19  Eric Carlson  <eric.carlson@apple.com>
 
         [Mac] Move MediaPlaybackTargetPicker
index c1fa00b..408b60a 100644 (file)
@@ -1234,12 +1234,11 @@ static Ref<CSSValue> createAnimationTriggerValue(const AnimationTrigger* trigger
 {
     switch (trigger->type()) {
     case AnimationTrigger::AnimationTriggerType::ScrollAnimationTriggerType: {
-        const ScrollAnimationTrigger* scrollAnimationTrigger = static_cast<const ScrollAnimationTrigger*>(trigger);
-        if (scrollAnimationTrigger->endValue().isAuto())
-            return CSSAnimationTriggerScrollValue::create(zoomAdjustedPixelValueForLength(scrollAnimationTrigger->startValue(), style));
-        else
-            return CSSAnimationTriggerScrollValue::create(zoomAdjustedPixelValueForLength(scrollAnimationTrigger->startValue(), style),
-                                                          zoomAdjustedPixelValueForLength(scrollAnimationTrigger->endValue(), style));
+        auto& scrollAnimationTrigger = downcast<ScrollAnimationTrigger>(*trigger);
+        if (scrollAnimationTrigger.endValue().isAuto())
+            return CSSAnimationTriggerScrollValue::create(zoomAdjustedPixelValueForLength(scrollAnimationTrigger.startValue(), style));
+        return CSSAnimationTriggerScrollValue::create(zoomAdjustedPixelValueForLength(scrollAnimationTrigger.startValue(), style),
+                                                      zoomAdjustedPixelValueForLength(scrollAnimationTrigger.endValue(), style));
     }
     default:
         ASSERT(trigger->type() == AnimationTrigger::AnimationTriggerType::AutoAnimationTriggerType);
index eb4c424..88d62a5 100644 (file)
@@ -462,9 +462,9 @@ void AnimationBase::fireAnimationEventsIfNeeded()
 #if ENABLE(CSS_ANIMATIONS_LEVEL_2)
         if (m_animation->trigger() && m_animation->trigger()->isScrollAnimationTrigger()) {
             if (m_object) {
-                LayoutSize offset = m_object->view().frameView().scrollOffsetForFixedPosition();
-                ScrollAnimationTrigger* scrollTrigger = static_cast<ScrollAnimationTrigger*>(m_animation->trigger().get());
-                if (offset.height().toFloat() > scrollTrigger->startValue().value())
+                float offset = m_compositeAnimation->animationController()->scrollPosition();
+                ScrollAnimationTrigger& scrollTrigger = downcast<ScrollAnimationTrigger>(*m_animation->trigger().get());
+                if (offset > scrollTrigger.startValue().value())
                     updateStateMachine(AnimationStateInput::StartTimerFired, 0);
             }
 
@@ -475,9 +475,11 @@ void AnimationBase::fireAnimationEventsIfNeeded()
             updateStateMachine(AnimationStateInput::StartTimerFired, 0);
         return;
     }
-    
+
     double elapsedDuration = beginAnimationUpdateTime() - m_startTime;
 #if ENABLE(CSS_ANIMATIONS_LEVEL_2)
+    // If we are a triggered animation that depends on scroll, our elapsed
+    // time is determined by the scroll position.
     if (m_animation->trigger() && m_animation->trigger()->isScrollAnimationTrigger())
         elapsedDuration = getElapsedTime();
 #endif
@@ -544,8 +546,8 @@ double AnimationBase::timeToNextService()
         if (m_animation->trigger()->isScrollAnimationTrigger()) {
             if (m_object) {
                 float currentScrollOffset = m_object->view().frameView().scrollOffsetForFixedPosition().height().toFloat();
-                ScrollAnimationTrigger* scrollTrigger = static_cast<ScrollAnimationTrigger*>(m_animation->trigger().get());
-                if (currentScrollOffset >= scrollTrigger->startValue().value() && (!scrollTrigger->hasEndValue() || currentScrollOffset <= scrollTrigger->endValue().value()))
+                ScrollAnimationTrigger& scrollTrigger = downcast<ScrollAnimationTrigger>(*m_animation->trigger().get());
+                if (currentScrollOffset >= scrollTrigger.startValue().value() && (!scrollTrigger.hasEndValue() || currentScrollOffset <= scrollTrigger.endValue().value()))
                     return 0;
             }
             return -1;
@@ -682,7 +684,7 @@ void AnimationBase::freezeAtTime(double t)
         onAnimationStartResponse(monotonicallyIncreasingTime());
     }
 
-    ASSERT(m_startTime);        // if m_startTime is zero, we haven't started yet, so we'll get a bad pause time.
+    ASSERT(m_startTime); // If m_startTime is zero, we haven't started yet, so we'll get a bad pause time.
     if (t <= m_animation->delay())
         m_pauseTime = m_startTime;
     else
@@ -702,6 +704,22 @@ double AnimationBase::beginAnimationUpdateTime() const
 
 double AnimationBase::getElapsedTime() const
 {
+#if ENABLE(CSS_ANIMATIONS_LEVEL_2)
+    if (m_animation->trigger() && m_animation->trigger()->isScrollAnimationTrigger()) {
+        ScrollAnimationTrigger& scrollTrigger = downcast<ScrollAnimationTrigger>(*m_animation->trigger().get());
+        if (scrollTrigger.hasEndValue() && m_object) {
+            float offset = m_compositeAnimation->animationController()->scrollPosition();
+            float startValue = scrollTrigger.startValue().value();
+            if (offset < startValue)
+                return 0;
+            float endValue = scrollTrigger.endValue().value();
+            if (offset > endValue)
+                return m_animation->duration();
+            return m_animation->duration() * (offset - startValue) / (endValue - startValue);
+        }
+    }
+#endif
+
     if (paused())
         return m_pauseTime - m_startTime;
     if (m_startTime <= 0)
index 6452a89..c573686 100644 (file)
@@ -111,6 +111,7 @@ bool AnimationControllerPrivate::clear(RenderElement& renderer)
 
 double AnimationControllerPrivate::updateAnimations(SetChanged callSetChanged/* = DoNotCallSetChanged*/)
 {
+    AnimationPrivateUpdateBlock updateBlock(*this);
     double timeToNextService = -1;
     bool calledSetChanged = false;
 
@@ -518,6 +519,8 @@ void AnimationControllerPrivate::animationWillBeRemoved(AnimationBase* animation
 #if ENABLE(CSS_ANIMATIONS_LEVEL_2)
 void AnimationControllerPrivate::scrollWasUpdated()
 {
+    m_scrollPosition = m_frame.view()->scrollOffsetForFixedPosition().height().toFloat();
+
     updateAnimations(CallSetChanged);
 }
 #endif
index 0ee31d7..706da16 100644 (file)
@@ -119,6 +119,7 @@ public:
 
 #if ENABLE(CSS_ANIMATIONS_LEVEL_2)
     void scrollWasUpdated();
+    float scrollPosition() const { return m_scrollPosition; }
 #endif
 
 private:
@@ -159,6 +160,10 @@ private:
     // behavior of allowing new transitions and animations to
     // run even when this object is suspended.
     bool m_allowsNewAnimationsWhileSuspended;
+
+#if ENABLE(CSS_ANIMATIONS_LEVEL_2)
+    float m_scrollPosition = 0;
+#endif
 };
 
 } // namespace WebCore
index 1e131a2..306c05c 100644 (file)
@@ -31,6 +31,7 @@
 #include "Length.h"
 #include <wtf/RefCounted.h>
 #include <wtf/RefPtr.h>
+#include <wtf/TypeCasts.h>
 
 namespace WebCore {
 
@@ -89,9 +90,9 @@ private:
 
 class ScrollAnimationTrigger : public AnimationTrigger {
 public:
-    static PassRefPtr<ScrollAnimationTrigger> create(Length startValue, Length endValue , bool hasEndValue = false)
+    static PassRefPtr<ScrollAnimationTrigger> create(Length startValue, Length endValue)
     {
-        return adoptRef(new ScrollAnimationTrigger(startValue, endValue, hasEndValue));
+        return adoptRef(new ScrollAnimationTrigger(startValue, endValue));
     }
 
     virtual ~ScrollAnimationTrigger() { }
@@ -121,25 +122,20 @@ public:
         m_endValue = value;
     }
 
-    bool hasEndValue() const { return m_hasEndValue; }
-
-    void setHasEndValue(bool value)
-    {
-        m_hasEndValue = value;
-    }
+    bool hasEndValue() const { return !m_endValue.isAuto() && m_endValue.value() > m_startValue.value(); }
 
 private:
-    explicit ScrollAnimationTrigger(Length startValue, Length endValue, bool hasEndValue)
+    explicit ScrollAnimationTrigger(Length startValue, Length endValue)
         : AnimationTrigger(AnimationTriggerType::ScrollAnimationTriggerType)
         , m_startValue(startValue)
-        , m_endValue(endValue)
-        , m_hasEndValue(hasEndValue)
     {
+        if (!endValue.isAuto() && endValue.value() > startValue.value())
+            m_endValue = endValue;
     }
 
     virtual PassRefPtr<AnimationTrigger> clone() const override
     {
-        return adoptRef(new ScrollAnimationTrigger(m_startValue, m_endValue, m_hasEndValue));
+        return adoptRef(new ScrollAnimationTrigger(m_startValue, m_endValue));
     }
 
     Length m_startValue;
@@ -149,6 +145,14 @@ private:
 
 } // namespace WebCore
 
+#define SPECIALIZE_TYPE_TRAITS_ANIMATION_TRIGGER(ToClassName, TriggerTest) \
+SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::ToClassName) \
+static bool isType(const WebCore::AnimationTrigger& trigger) { return trigger.TriggerTest(); } \
+SPECIALIZE_TYPE_TRAITS_END()
+
+SPECIALIZE_TYPE_TRAITS_ANIMATION_TRIGGER(AutoAnimationTrigger, isAutoAnimationTrigger);
+SPECIALIZE_TYPE_TRAITS_ANIMATION_TRIGGER(ScrollAnimationTrigger, isScrollAnimationTrigger);
+
 #endif
 
 #endif // AnimationTrigger_h
index 6eb8d92..528ecfe 100644 (file)
@@ -864,6 +864,15 @@ bool GraphicsLayerCA::animationCanBeAccelerated(const KeyframeValueList& valueLi
     if (animationHasStepsTimingFunction(valueList, anim))
         return false;
 
+#if ENABLE(CSS_ANIMATIONS_LEVEL_2)
+    // If there is a trigger that depends on the scroll position, we cannot accelerate the animation.
+    if (anim->trigger()->isScrollAnimationTrigger()) {
+        ScrollAnimationTrigger& scrollTrigger = downcast<ScrollAnimationTrigger>(*anim->trigger().get());
+        if (scrollTrigger.hasEndValue())
+            return false;
+    }
+#endif
+
     return true;
 }