Title: [261756] trunk
Revision
261756
Author
[email protected]
Date
2020-05-15 13:07:26 -0700 (Fri, 15 May 2020)

Log Message

[Web Animations] Animation with a single keyframe is not accelerated
https://bugs.webkit.org/show_bug.cgi?id=188730
<rdar://problem/43481113>

Reviewed by Dean Jackson.

Source/WebCore:

Test: webanimations/accelerated-animation-single-keyframe.html

Prior to attempting to run an accelerated effect, ensure that the KeyframeList passed to
RenderLayerModelObject::startAnimation() does not have implicit keyframes since eventually
GraphicsLayerCA::animationCanBeAccelerated() would be called and would reject a single-keyframe
animation. To do this, we use the same code used in Style::Resolver::keyframeStylesForAnimation()
which we refactor in the new KeyframeList::fillImplicitKeyframes() method.

* animation/KeyframeEffect.cpp:
(WebCore::KeyframeEffect::copyPropertiesFromSource):
(WebCore::KeyframeEffect::applyPendingAcceleratedActions):
* rendering/style/KeyframeList.cpp:
(WebCore::KeyframeList::hasImplicitKeyframes const):
(WebCore::KeyframeList::copyKeyframes):
(WebCore::zeroPercentKeyframe):
(WebCore::hundredPercentKeyframe):
(WebCore::KeyframeList::fillImplicitKeyframes):
* rendering/style/KeyframeList.h:
* style/StyleResolver.cpp:
(WebCore::Style::Resolver::keyframeStylesForAnimation):

LayoutTests:

Add a new test that runs a single-keyframe transform animation and checks that it runs accelerated.

* webanimations/accelerated-animation-single-keyframe-expected.txt: Added.
* webanimations/accelerated-animation-single-keyframe.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (261755 => 261756)


--- trunk/LayoutTests/ChangeLog	2020-05-15 19:39:36 UTC (rev 261755)
+++ trunk/LayoutTests/ChangeLog	2020-05-15 20:07:26 UTC (rev 261756)
@@ -1,3 +1,16 @@
+2020-05-15  Antoine Quint  <[email protected]>
+
+        [Web Animations] Animation with a single keyframe is not accelerated
+        https://bugs.webkit.org/show_bug.cgi?id=188730
+        <rdar://problem/43481113>
+
+        Reviewed by Dean Jackson.
+
+        Add a new test that runs a single-keyframe transform animation and checks that it runs accelerated.
+
+        * webanimations/accelerated-animation-single-keyframe-expected.txt: Added.
+        * webanimations/accelerated-animation-single-keyframe.html: Added.
+
 2020-05-15  Eric Carlson  <[email protected]>
 
         media/video-poster-set-after-playback.html is a flaky failure

Added: trunk/LayoutTests/webanimations/accelerated-animation-single-keyframe-expected.txt (0 => 261756)


--- trunk/LayoutTests/webanimations/accelerated-animation-single-keyframe-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/webanimations/accelerated-animation-single-keyframe-expected.txt	2020-05-15 20:07:26 UTC (rev 261756)
@@ -0,0 +1,3 @@
+
+PASS A transform animation with a single keyframe should be able to run accelerated. 
+

Added: trunk/LayoutTests/webanimations/accelerated-animation-single-keyframe.html (0 => 261756)


--- trunk/LayoutTests/webanimations/accelerated-animation-single-keyframe.html	                        (rev 0)
+++ trunk/LayoutTests/webanimations/accelerated-animation-single-keyframe.html	2020-05-15 20:07:26 UTC (rev 261756)
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<body>
+<script src=""
+<script src=""
+<style>
+
+    #target {
+        position: absolute;
+        left: 0;
+        top: 0;
+        width: 100px;
+        height: 100px;
+        background-color: black;
+    }
+
+</style>
+<div id="target"></div>
+<script>
+
+async_test(async t => {
+    // Start an animation with an implicit from keyframe.
+    const animation = document.getElementById("target").animate({ transform: "translateX(600px)" }, { duration: 1000 * 1000 });
+
+    // Wait two frames for the accelerated animation to be committed.
+    await animation.ready;
+    await new Promise(requestAnimationFrame);
+    await new Promise(requestAnimationFrame);
+
+    assert_equals(internals.acceleratedAnimationsForElement(target).length, 1, "There should be an accelerated animation.");
+    t.done();
+}, "A transform animation with a single keyframe should be able to run accelerated.");
+
+</script>
+</body>

Modified: trunk/Source/WebCore/ChangeLog (261755 => 261756)


--- trunk/Source/WebCore/ChangeLog	2020-05-15 19:39:36 UTC (rev 261755)
+++ trunk/Source/WebCore/ChangeLog	2020-05-15 20:07:26 UTC (rev 261756)
@@ -1,3 +1,32 @@
+2020-05-15  Antoine Quint  <[email protected]>
+
+        [Web Animations] Animation with a single keyframe is not accelerated
+        https://bugs.webkit.org/show_bug.cgi?id=188730
+        <rdar://problem/43481113>
+
+        Reviewed by Dean Jackson.
+
+        Test: webanimations/accelerated-animation-single-keyframe.html
+
+        Prior to attempting to run an accelerated effect, ensure that the KeyframeList passed to
+        RenderLayerModelObject::startAnimation() does not have implicit keyframes since eventually
+        GraphicsLayerCA::animationCanBeAccelerated() would be called and would reject a single-keyframe
+        animation. To do this, we use the same code used in Style::Resolver::keyframeStylesForAnimation()
+        which we refactor in the new KeyframeList::fillImplicitKeyframes() method.
+
+        * animation/KeyframeEffect.cpp:
+        (WebCore::KeyframeEffect::copyPropertiesFromSource):
+        (WebCore::KeyframeEffect::applyPendingAcceleratedActions):
+        * rendering/style/KeyframeList.cpp:
+        (WebCore::KeyframeList::hasImplicitKeyframes const):
+        (WebCore::KeyframeList::copyKeyframes):
+        (WebCore::zeroPercentKeyframe):
+        (WebCore::hundredPercentKeyframe):
+        (WebCore::KeyframeList::fillImplicitKeyframes):
+        * rendering/style/KeyframeList.h:
+        * style/StyleResolver.cpp:
+        (WebCore::Style::Resolver::keyframeStylesForAnimation):
+
 2020-05-15  Said Abou-Hallawa  <[email protected]>
 
         The initial value of "transform-box" should be "view-box"

Modified: trunk/Source/WebCore/animation/KeyframeEffect.cpp (261755 => 261756)


--- trunk/Source/WebCore/animation/KeyframeEffect.cpp	2020-05-15 19:39:36 UTC (rev 261755)
+++ trunk/Source/WebCore/animation/KeyframeEffect.cpp	2020-05-15 20:07:26 UTC (rev 261756)
@@ -565,12 +565,7 @@
     updateStaticTimingProperties();
 
     KeyframeList keyframeList("keyframe-effect-" + createCanonicalUUIDString());
-    for (auto& keyframe : source->m_blendingKeyframes.keyframes()) {
-        KeyframeValue keyframeValue(keyframe.key(), RenderStyle::clonePtr(*keyframe.style()));
-        for (auto propertyId : keyframe.properties())
-            keyframeValue.addProperty(propertyId);
-        keyframeList.insert(WTFMove(keyframeValue));
-    }
+    keyframeList.copyKeyframes(source->m_blendingKeyframes);
     setBlendingKeyframes(keyframeList);
 }
 
@@ -1578,11 +1573,24 @@
     // To simplify the code we use a default of 0s for an unresolved current time since for a Stop action that is acceptable.
     auto timeOffset = animation()->currentTime().valueOr(0_s).seconds() - delay().seconds();
 
+    auto startAnimation = [&]() -> bool {
+        renderer->animationFinished(m_blendingKeyframes.animationName());
+
+        if (!m_blendingKeyframes.hasImplicitKeyframes())
+            return renderer->startAnimation(timeOffset, backingAnimationForCompositedRenderer(), m_blendingKeyframes);
+
+        ASSERT(m_unanimatedStyle);
+        ASSERT(m_target);
+        KeyframeList explicitKeyframes(m_blendingKeyframes.animationName());
+        explicitKeyframes.copyKeyframes(m_blendingKeyframes);
+        explicitKeyframes.fillImplicitKeyframes(*m_target, m_target->styleResolver(), m_unanimatedStyle.get());
+        return renderer->startAnimation(timeOffset, backingAnimationForCompositedRenderer(), explicitKeyframes);
+    };
+
     for (const auto& action : pendingAcceleratedActions) {
         switch (action) {
         case AcceleratedAction::Play:
-            renderer->animationFinished(m_blendingKeyframes.animationName());
-            m_isRunningAccelerated = renderer->startAnimation(timeOffset, backingAnimationForCompositedRenderer(), m_blendingKeyframes);
+            m_isRunningAccelerated = startAnimation();
             if (!m_isRunningAccelerated) {
                 m_lastRecordedAcceleratedAction = AcceleratedAction::Stop;
                 return;
@@ -1592,8 +1600,7 @@
             renderer->animationPaused(timeOffset, m_blendingKeyframes.animationName());
             break;
         case AcceleratedAction::UpdateTiming:
-            renderer->animationFinished(m_blendingKeyframes.animationName());
-            renderer->startAnimation(timeOffset, backingAnimationForCompositedRenderer(), m_blendingKeyframes);
+            startAnimation();
             if (animation()->playState() == WebAnimation::PlayState::Paused)
                 renderer->animationPaused(timeOffset, m_blendingKeyframes.animationName());
             break;

Modified: trunk/Source/WebCore/rendering/style/KeyframeList.cpp (261755 => 261756)


--- trunk/Source/WebCore/rendering/style/KeyframeList.cpp	2020-05-15 19:39:36 UTC (rev 261755)
+++ trunk/Source/WebCore/rendering/style/KeyframeList.cpp	2020-05-15 20:07:26 UTC (rev 261756)
@@ -23,7 +23,9 @@
 #include "KeyframeList.h"
 
 #include "Animation.h"
+#include "CSSKeyframeRule.h"
 #include "RenderObject.h"
+#include "StyleResolver.h"
 
 namespace WebCore {
 
@@ -74,4 +76,59 @@
         m_properties.add(property);
 }
 
+bool KeyframeList::hasImplicitKeyframes() const
+{
+    return size() && (m_keyframes[0].key() || m_keyframes[size() - 1].key() != 1);
+}
+
+void KeyframeList::copyKeyframes(KeyframeList& other)
+{
+    for (auto& keyframe : other.keyframes()) {
+        KeyframeValue keyframeValue(keyframe.key(), RenderStyle::clonePtr(*keyframe.style()));
+        for (auto propertyId : keyframe.properties())
+            keyframeValue.addProperty(propertyId);
+        insert(WTFMove(keyframeValue));
+    }
+}
+
+static const StyleRuleKeyframe& zeroPercentKeyframe()
+{
+    static LazyNeverDestroyed<Ref<StyleRuleKeyframe>> rule;
+    static std::once_flag onceFlag;
+    std::call_once(onceFlag, [] {
+        rule.construct(StyleRuleKeyframe::create(MutableStyleProperties::create()));
+        rule.get()->setKey(0);
+    });
+    return rule.get().get();
+}
+
+static const StyleRuleKeyframe& hundredPercentKeyframe()
+{
+    static LazyNeverDestroyed<Ref<StyleRuleKeyframe>> rule;
+    static std::once_flag onceFlag;
+    std::call_once(onceFlag, [] {
+        rule.construct(StyleRuleKeyframe::create(MutableStyleProperties::create()));
+        rule.get()->setKey(1);
+    });
+    return rule.get().get();
+}
+
+void KeyframeList::fillImplicitKeyframes(const Element& element, Style::Resolver& styleResolver, const RenderStyle* elementStyle)
+{
+    // If the 0% keyframe is missing, create it (but only if there is at least one other keyframe).
+    auto initialSize = size();
+    if (initialSize > 0 && m_keyframes[0].key()) {
+        KeyframeValue keyframeValue(0, nullptr);
+        keyframeValue.setStyle(styleResolver.styleForKeyframe(element, elementStyle, &zeroPercentKeyframe(), keyframeValue));
+        insert(WTFMove(keyframeValue));
+    }
+
+    // If the 100% keyframe is missing, create it (but only if there is at least one other keyframe).
+    if (initialSize > 0 && (m_keyframes[size() - 1].key() != 1)) {
+        KeyframeValue keyframeValue(1, nullptr);
+        keyframeValue.setStyle(styleResolver.styleForKeyframe(element, elementStyle, &hundredPercentKeyframe(), keyframeValue));
+        insert(WTFMove(keyframeValue));
+    }
+}
+
 } // namespace WebCore

Modified: trunk/Source/WebCore/rendering/style/KeyframeList.h (261755 => 261756)


--- trunk/Source/WebCore/rendering/style/KeyframeList.h	2020-05-15 19:39:36 UTC (rev 261755)
+++ trunk/Source/WebCore/rendering/style/KeyframeList.h	2020-05-15 20:07:26 UTC (rev 261756)
@@ -34,6 +34,10 @@
 class RenderStyle;
 class TimingFunction;
 
+namespace Style {
+class Resolver;
+}
+
 class KeyframeValue {
 public:
     KeyframeValue(double key, std::unique_ptr<RenderStyle> style)
@@ -54,7 +58,7 @@
 
     TimingFunction* timingFunction() const { return m_timingFunction.get(); }
     void setTimingFunction(const RefPtr<TimingFunction>& timingFunction) { m_timingFunction = timingFunction; }
-    
+
 private:
     double m_key;
     HashSet<CSSPropertyID> m_properties; // The properties specified in this keyframe.
@@ -88,6 +92,10 @@
     const KeyframeValue& operator[](size_t index) const { return m_keyframes[index]; }
     const Vector<KeyframeValue>& keyframes() const { return m_keyframes; }
 
+    void copyKeyframes(KeyframeList&);
+    bool hasImplicitKeyframes() const;
+    void fillImplicitKeyframes(const Element&, Style::Resolver&, const RenderStyle*);
+
 private:
     AtomString m_animationName;
     Vector<KeyframeValue> m_keyframes; // Kept sorted by key.

Modified: trunk/Source/WebCore/style/StyleResolver.cpp (261755 => 261756)


--- trunk/Source/WebCore/style/StyleResolver.cpp	2020-05-15 19:39:36 UTC (rev 261755)
+++ trunk/Source/WebCore/style/StyleResolver.cpp	2020-05-15 20:07:26 UTC (rev 261756)
@@ -359,30 +359,7 @@
         }
     }
 
-    // If the 0% keyframe is missing, create it (but only if there is at least one other keyframe).
-    int initialListSize = list.size();
-    if (initialListSize > 0 && list[0].key()) {
-        static StyleRuleKeyframe* zeroPercentKeyframe;
-        if (!zeroPercentKeyframe) {
-            zeroPercentKeyframe = &StyleRuleKeyframe::create(MutableStyleProperties::create()).leakRef();
-            zeroPercentKeyframe->setKey(0);
-        }
-        KeyframeValue keyframeValue(0, nullptr);
-        keyframeValue.setStyle(styleForKeyframe(element, elementStyle, zeroPercentKeyframe, keyframeValue));
-        list.insert(WTFMove(keyframeValue));
-    }
-
-    // If the 100% keyframe is missing, create it (but only if there is at least one other keyframe).
-    if (initialListSize > 0 && (list[list.size() - 1].key() != 1)) {
-        static StyleRuleKeyframe* hundredPercentKeyframe;
-        if (!hundredPercentKeyframe) {
-            hundredPercentKeyframe = &StyleRuleKeyframe::create(MutableStyleProperties::create()).leakRef();
-            hundredPercentKeyframe->setKey(1);
-        }
-        KeyframeValue keyframeValue(1, nullptr);
-        keyframeValue.setStyle(styleForKeyframe(element, elementStyle, hundredPercentKeyframe, keyframeValue));
-        list.insert(WTFMove(keyframeValue));
-    }
+    list.fillImplicitKeyframes(element, *this, elementStyle);
 }
 
 std::unique_ptr<RenderStyle> Resolver::pseudoStyleForElement(const Element& element, const PseudoElementRequest& pseudoElementRequest, const RenderStyle& parentStyle, const RenderStyle* parentBoxStyle, const SelectorFilter* selectorFilter)
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to