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)