[Web Animations] Allow getComputedStyle() to return animated values for accelerated...
authorgraouts@webkit.org <graouts@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 24 Nov 2017 13:30:36 +0000 (13:30 +0000)
committergraouts@webkit.org <graouts@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 24 Nov 2017 13:30:36 +0000 (13:30 +0000)
https://bugs.webkit.org/show_bug.cgi?id=179975
<rdar://problem/35676811>

Reviewed by Dean Jackson.

Source/WebCore:

In case we're running an accelerated animation, we are not blending RenderStyles as the animation
progresses and thus we need to hook into computeRenderStyleForProperty() to query the DocumentTimeline
for the animated style of running accelerated animations where we blend styles manually for the
animation's current time.

Test: http/wpt/wk-web-animations/interfaces/keyframe-effect-getComputedStyle.html

* animation/DocumentTimeline.cpp:
(WebCore::DocumentTimeline::animatedStyleForRenderer): Iterate through all running accelerated animations
for the element to which the provided renderer is attached and ask for their animated styles.
* animation/DocumentTimeline.h:
* animation/KeyframeEffect.cpp:
(WebCore::KeyframeEffect::getAnimatedStyle): Manually blend all animated properties and populate the provided
RenderStyle with their values, creating the RenderStyle if needed.
* animation/KeyframeEffect.h:
* css/CSSComputedStyleDeclaration.cpp:
(WebCore::computeRenderStyleForProperty): Query the DocumentTimeline for accelerated animated properties in
case such animations are running, otherwise let the CSS animation controller report the animated values.

LayoutTests:

Add a new test that checks that the computed style of accelerated animation returns the animated value.
This test would fail for the accelerated case prior to this patch.

* http/wpt/wk-web-animations/interfaces/keyframe-effect-getComputedStyle-expected.txt: Added.
* http/wpt/wk-web-animations/interfaces/keyframe-effect-getComputedStyle.html: Added.

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

LayoutTests/ChangeLog
LayoutTests/http/wpt/wk-web-animations/interfaces/keyframe-effect-getComputedStyle-expected.txt [new file with mode: 0644]
LayoutTests/http/wpt/wk-web-animations/interfaces/keyframe-effect-getComputedStyle.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/animation/DocumentTimeline.cpp
Source/WebCore/animation/DocumentTimeline.h
Source/WebCore/animation/KeyframeEffect.cpp
Source/WebCore/animation/KeyframeEffect.h
Source/WebCore/css/CSSComputedStyleDeclaration.cpp

index 708cf8f..2fd76a7 100644 (file)
@@ -1,3 +1,17 @@
+2017-11-24  Antoine Quint  <graouts@apple.com>
+
+        [Web Animations] Allow getComputedStyle() to return animated values for accelerated animations
+        https://bugs.webkit.org/show_bug.cgi?id=179975
+        <rdar://problem/35676811>
+
+        Reviewed by Dean Jackson.
+
+        Add a new test that checks that the computed style of accelerated animation returns the animated value.
+        This test would fail for the accelerated case prior to this patch.
+
+        * http/wpt/wk-web-animations/interfaces/keyframe-effect-getComputedStyle-expected.txt: Added.
+        * http/wpt/wk-web-animations/interfaces/keyframe-effect-getComputedStyle.html: Added.
+
 2017-11-24  Mark Lam  <mark.lam@apple.com>
 
         Move unsafe jsc shell test functions to the $vm object.
diff --git a/LayoutTests/http/wpt/wk-web-animations/interfaces/keyframe-effect-getComputedStyle-expected.txt b/LayoutTests/http/wpt/wk-web-animations/interfaces/keyframe-effect-getComputedStyle-expected.txt
new file mode 100644 (file)
index 0000000..35277de
--- /dev/null
@@ -0,0 +1,4 @@
+
+PASS Querying the computed style for an accelerated animation. 
+PASS Querying the computed style for a non-accelerated animation. 
+
diff --git a/LayoutTests/http/wpt/wk-web-animations/interfaces/keyframe-effect-getComputedStyle.html b/LayoutTests/http/wpt/wk-web-animations/interfaces/keyframe-effect-getComputedStyle.html
new file mode 100644 (file)
index 0000000..528d750
--- /dev/null
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Using getComputedStyle() during animations</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+<div id="log"></div>
+<div id="hw-target"></div>
+<div id="sw-target"></div>
+<script>
+'use strict';
+
+testRunner.waitUntilDone();
+
+const tolerance = 1/100;
+
+const hwTest = async_test("Querying the computed style for an accelerated animation.");
+const swTest = async_test("Querying the computed style for a non-accelerated animation.");
+
+const hwAnimation = new Animation(new KeyframeEffect(document.getElementById("hw-target"), [
+    { opacity: 0 },
+    { opacity: 1 }
+]));
+hwAnimation.startTime = 0;
+hwAnimation.effect.timing.duration = 10000;
+
+const swAnimation = new Animation(new KeyframeEffect(document.getElementById("sw-target"), [
+    { left: 0 },
+    { left: "100px" }
+]));
+swAnimation.startTime = 0;
+swAnimation.effect.timing.duration = 10000;
+
+function progress(animation) {
+    return (animation.currentTime - animation.startTime) / animation.effect.timing.duration;
+}
+
+hwTest.step(() => {
+    assert_greater_than(hwAnimation.currentTime, hwAnimation.startTime, "The animation has started.");
+    assert_approx_equals(Number(getComputedStyle(hwAnimation.effect.target).opacity), progress(hwAnimation), tolerance);
+});
+hwTest.done();
+
+swTest.step(() => {
+    assert_greater_than(swAnimation.currentTime, swAnimation.startTime, "The animation has started.");
+    assert_approx_equals(parseFloat(getComputedStyle(swAnimation.effect.target).left), progress(swAnimation) * 100, tolerance);
+});
+swTest.done();
+
+testRunner.notifyDone();
+
+</script>
+</body>
index 1feeeca..4756c9b 100644 (file)
@@ -1,3 +1,30 @@
+2017-11-24  Antoine Quint  <graouts@apple.com>
+
+        [Web Animations] Allow getComputedStyle() to return animated values for accelerated animations
+        https://bugs.webkit.org/show_bug.cgi?id=179975
+        <rdar://problem/35676811>
+
+        Reviewed by Dean Jackson.
+
+        In case we're running an accelerated animation, we are not blending RenderStyles as the animation
+        progresses and thus we need to hook into computeRenderStyleForProperty() to query the DocumentTimeline
+        for the animated style of running accelerated animations where we blend styles manually for the
+        animation's current time.
+
+        Test: http/wpt/wk-web-animations/interfaces/keyframe-effect-getComputedStyle.html
+
+        * animation/DocumentTimeline.cpp:
+        (WebCore::DocumentTimeline::animatedStyleForRenderer): Iterate through all running accelerated animations
+        for the element to which the provided renderer is attached and ask for their animated styles.
+        * animation/DocumentTimeline.h:
+        * animation/KeyframeEffect.cpp:
+        (WebCore::KeyframeEffect::getAnimatedStyle): Manually blend all animated properties and populate the provided
+        RenderStyle with their values, creating the RenderStyle if needed.
+        * animation/KeyframeEffect.h:
+        * css/CSSComputedStyleDeclaration.cpp:
+        (WebCore::computeRenderStyleForProperty): Query the DocumentTimeline for accelerated animated properties in
+        case such animations are running, otherwise let the CSS animation controller report the animated values.
+
 2017-11-24  Zan Dobersek  <zdobersek@igalia.com>
 
         [CoordGraphics] CoordinatedGraphicsLayer::updateContentBuffers() should always assume a non-null CoordinatedBuffer
index 72576cb..c4dba7b 100644 (file)
@@ -34,6 +34,7 @@
 #include "Document.h"
 #include "KeyframeEffect.h"
 #include "Page.h"
+#include "RenderElement.h"
 
 static const Seconds animationInterval { 15_ms };
 
@@ -174,6 +175,23 @@ void DocumentTimeline::updateAnimations()
     animationTimingModelDidChange();
 }
 
+std::unique_ptr<RenderStyle> DocumentTimeline::animatedStyleForRenderer(RenderElement& renderer)
+{
+    std::unique_ptr<RenderStyle> result;
+
+    if (auto* element = renderer.element()) {
+        for (auto animation : animationsForElement(*element)) {
+            if (animation->effect() && animation->effect()->isKeyframeEffect())
+                downcast<KeyframeEffect>(animation->effect())->getAnimatedStyle(result);
+        }
+    }
+
+    if (!result)
+        result = RenderStyle::clonePtr(renderer.style());
+
+    return result;
+}
+
 void DocumentTimeline::animationAcceleratedRunningStateDidChange(WebAnimation& animation)
 {
     m_acceleratedAnimationsPendingRunningStateChange.add(&animation);
index 8c22af3..ff1e576 100644 (file)
@@ -37,6 +37,8 @@
 
 namespace WebCore {
 
+class RenderElement;
+
 class DocumentTimeline final : public AnimationTimeline
 #if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
     , public DisplayRefreshMonitorClient
@@ -52,6 +54,7 @@ public:
     void animationTimingModelDidChange() override;
     void windowScreenDidChange(PlatformDisplayID);
 
+    std::unique_ptr<RenderStyle> animatedStyleForRenderer(RenderElement& renderer);
     void animationAcceleratedRunningStateDidChange(WebAnimation&);
     bool runningAnimationsForElementAreAllAccelerated(Element&);
     void detachFromDocument();
index 39bc715..0e55b69 100644 (file)
@@ -192,6 +192,30 @@ bool KeyframeEffect::shouldRunAccelerated()
     return true;
 }
 
+void KeyframeEffect::getAnimatedStyle(std::unique_ptr<RenderStyle>& animatedStyle)
+{
+    if (!animation() || !timing()->duration())
+        return;
+
+    auto localTime = animation()->currentTime();
+
+    // FIXME: Assume animations only apply in the range [0, duration[
+    // until we support fill modes, delays and iterations.
+    if (!localTime || localTime < 0_s || localTime >= timing()->duration())
+        return;
+
+    if (!m_keyframes.size())
+        return;
+
+    if (!animatedStyle)
+        animatedStyle = RenderStyle::clonePtr(renderer()->style());
+
+    for (auto cssPropertyId : m_keyframes.properties()) {
+        float progress = localTime.value() / timing()->duration();
+        CSSPropertyAnimation::blendProperties(this, cssPropertyId, animatedStyle.get(), m_keyframes[0].style(), m_keyframes[1].style(), progress);
+    }
+}
+
 void KeyframeEffect::startOrStopAccelerated()
 {
     auto* renderer = this->renderer();
index c3e5f41..7b49c19 100644 (file)
@@ -43,6 +43,7 @@ public:
 
     Element* target() const { return m_target.get(); }
     ExceptionOr<void> setKeyframes(JSC::ExecState&, JSC::Strong<JSC::JSObject>&&);
+    void getAnimatedStyle(std::unique_ptr<RenderStyle>& animatedStyle);
     void applyAtLocalTime(Seconds, RenderStyle&) override;
     void startOrStopAccelerated();
     bool isRunningAccelerated() const { return m_startedAccelerated; }
index 6f0a609..23ed46a 100644 (file)
@@ -53,6 +53,7 @@
 #include "CursorList.h"
 #include "DeprecatedCSSOMValue.h"
 #include "Document.h"
+#include "DocumentTimeline.h"
 #include "FontCascade.h"
 #include "FontSelectionValueInlines.h"
 #include "FontTaggedSettings.h"
@@ -2449,7 +2450,10 @@ static inline const RenderStyle* computeRenderStyleForProperty(Element& element,
     auto* renderer = element.renderer();
 
     if (renderer && renderer->isComposited() && CSSAnimationController::supportsAcceleratedAnimationOfProperty(propertyID)) {
-        ownedStyle = renderer->animation().animatedStyleForRenderer(*renderer);
+        if (auto timeline = element.document().existingTimeline())
+            ownedStyle = timeline->animatedStyleForRenderer(*renderer);
+        else
+            ownedStyle = renderer->animation().animatedStyleForRenderer(*renderer);
         if (pseudoElementSpecifier && !element.isPseudoElement()) {
             // FIXME: This cached pseudo style will only exist if the animation has been run at least once.
             return ownedStyle->getCachedPseudoStyle(pseudoElementSpecifier);