Title: [287707] trunk
Revision
287707
Author
grao...@webkit.org
Date
2022-01-06 11:57:38 -0800 (Thu, 06 Jan 2022)

Log Message

[Web Animations] inserting a rule within a @keyframes rule should update animations
https://bugs.webkit.org/show_bug.cgi?id=234895

Reviewed by Darin Adler.

LayoutTests/imported/w3c:

Mark WPT progressions.

* web-platform-tests/css/css-animations/KeyframeEffect-getKeyframes.tentative-expected.txt:
* web-platform-tests/css/css-animations/KeyframeEffect-setKeyframes.tentative-expected.txt:

Source/WebCore:

Using the CSSOM, it is possible to insert or delete rules within an @keyframes rule.
In fact, there are two WPT that check this behavior with the getKeyframes() and
setKeyframes() methods.

This would not have any effect until now because when we consider whether to invalidate
animations in Styleable::updateCSSAnimations(), we look at the previous and current
AnimationList and don't see any difference because we look, as far as keyframes are
concerned, at the @keyframes name but not at the keyframes content.

Now, when a rule is added or deleted from an @keyframes rule using the CSSOM, we notify
the Document using the new keyframesRuleDidChange() method, which in turn checks all
CSSAnimation objects applied to elements in that document using that @keyframes rule
and notifies them of the change by calling keyframesRuleDidChange().

This clears the keyframes on the associated KeyframeEffect, invalidates the target
and sets a flag on the ElementAnimationRareData that this element is pending update
to its CSS Animations' keyframe such that during the next call
Styleable::updateCSSAnimations() we force the update even if the previous and current
AnimationList look identical.

During that next call to Styleable::updateCSSAnimations(), we will call into the new
CSSAnimation::updateKeyframesIfNeeded() which will re-compute the keyframes based on the
current set of rules within the @keyframes rule.

The final piece of work required is to track when setKeyframes() is called on the effect
that updates to the @keyframes rule should no longer apply since they keyframes were overriden
by the Web Animations API. This is done by setting an additional flag in
CSSAnimation::effectKeyframesWereSetUsingBindings().

* animation/CSSAnimation.cpp:
(WebCore::CSSAnimation::effectKeyframesWereSetUsingBindings):
(WebCore::CSSAnimation::keyframesRuleDidChange):
(WebCore::CSSAnimation::updateKeyframesIfNeeded):
* animation/CSSAnimation.h:
* animation/ElementAnimationRareData.h:
(WebCore::ElementAnimationRareData::cssAnimationsDidUpdate):
(WebCore::ElementAnimationRareData::keyframesRuleDidChange):
(WebCore::ElementAnimationRareData::hasPendingKeyframesUpdate const):
* animation/KeyframeEffect.cpp:
(WebCore::KeyframeEffect::keyframesRuleDidChange):
* animation/KeyframeEffect.h:
* css/CSSStyleSheet.cpp:
(WebCore::CSSStyleSheet::didMutateRules):
(WebCore::CSSStyleSheet::RuleMutationScope::RuleMutationScope):
(WebCore::CSSStyleSheet::RuleMutationScope::~RuleMutationScope):
* css/CSSStyleSheet.h:
* dom/Document.cpp:
(WebCore::Document::keyframesRuleDidChange):
* dom/Document.h:
* dom/Element.cpp:
(WebCore::Element::cssAnimationsDidUpdate):
(WebCore::Element::keyframesRuleDidChange):
(WebCore::Element::hasPendingKeyframesUpdate const):
* dom/Element.h:
* style/Styleable.cpp:
(WebCore::Styleable::updateCSSAnimations const):
* style/Styleable.h:
(WebCore::Styleable::keyframesRuleDidChange const):

Modified Paths

Diff

Modified: trunk/LayoutTests/imported/w3c/ChangeLog (287706 => 287707)


--- trunk/LayoutTests/imported/w3c/ChangeLog	2022-01-06 19:47:35 UTC (rev 287706)
+++ trunk/LayoutTests/imported/w3c/ChangeLog	2022-01-06 19:57:38 UTC (rev 287707)
@@ -1,3 +1,15 @@
+2022-01-06  Antoine Quint  <grao...@webkit.org>
+
+        [Web Animations] inserting a rule within a @keyframes rule should update animations
+        https://bugs.webkit.org/show_bug.cgi?id=234895
+
+        Reviewed by Darin Adler.
+
+        Mark WPT progressions.
+
+        * web-platform-tests/css/css-animations/KeyframeEffect-getKeyframes.tentative-expected.txt:
+        * web-platform-tests/css/css-animations/KeyframeEffect-setKeyframes.tentative-expected.txt:
+
 2022-01-06  Martin Robinson  <mrobin...@webkit.org>
 
         REGRESSION (r287323): [iOS] 9 imported/w3c/web-platform-tests/css/css-transforms tests consistently failing

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-animations/KeyframeEffect-getKeyframes.tentative-expected.txt (287706 => 287707)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-animations/KeyframeEffect-getKeyframes.tentative-expected.txt	2022-01-06 19:47:35 UTC (rev 287706)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-animations/KeyframeEffect-getKeyframes.tentative-expected.txt	2022-01-06 19:57:38 UTC (rev 287707)
@@ -23,5 +23,5 @@
 PASS KeyframeEffect.getKeyframes() returns expected values for animations with CSS variables as keyframe values in a shorthand property
 PASS KeyframeEffect.getKeyframes() returns expected values for animations with a CSS variable which is overriden by the value in keyframe
 FAIL KeyframeEffect.getKeyframes() returns expected values for animations with only custom property in a keyframe assert_equals: value for 'transform' on Keyframe #0 should match expected "translate(100px)" but got "matrix(1, 0, 0, 1, 100, 0)"
-FAIL KeyframeEffect.getKeyframes() reflects changes to @keyframes rules assert_equals: value for 'left' on Keyframes reflects the updated @keyframes rule should match expected "200px" but got "100px"
+PASS KeyframeEffect.getKeyframes() reflects changes to @keyframes rules
 

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-animations/KeyframeEffect-setKeyframes.tentative-expected.txt (287706 => 287707)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-animations/KeyframeEffect-setKeyframes.tentative-expected.txt	2022-01-06 19:47:35 UTC (rev 287706)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-animations/KeyframeEffect-setKeyframes.tentative-expected.txt	2022-01-06 19:57:38 UTC (rev 287707)
@@ -1,5 +1,5 @@
 
 PASS KeyframeEffect.setKeyframes() causes subsequent changes to @keyframes rules to be ignored
 PASS KeyframeEffect.setKeyframes() causes subsequent changes to animation-timing-function to be ignored
-FAIL KeyframeEffect.setKeyframes() should NOT cause subsequent changes to @keyframes rules to be ignored if it threw assert_equals: value for 'left' on Keyframes reflect the value set via style should match expected "300px" but got "100px"
+PASS KeyframeEffect.setKeyframes() should NOT cause subsequent changes to @keyframes rules to be ignored if it threw
 

Modified: trunk/Source/WebCore/ChangeLog (287706 => 287707)


--- trunk/Source/WebCore/ChangeLog	2022-01-06 19:47:35 UTC (rev 287706)
+++ trunk/Source/WebCore/ChangeLog	2022-01-06 19:57:38 UTC (rev 287707)
@@ -1,3 +1,69 @@
+2022-01-06  Antoine Quint  <grao...@webkit.org>
+
+        [Web Animations] inserting a rule within a @keyframes rule should update animations
+        https://bugs.webkit.org/show_bug.cgi?id=234895
+
+        Reviewed by Darin Adler.
+
+        Using the CSSOM, it is possible to insert or delete rules within an @keyframes rule.
+        In fact, there are two WPT that check this behavior with the getKeyframes() and
+        setKeyframes() methods.
+
+        This would not have any effect until now because when we consider whether to invalidate
+        animations in Styleable::updateCSSAnimations(), we look at the previous and current
+        AnimationList and don't see any difference because we look, as far as keyframes are
+        concerned, at the @keyframes name but not at the keyframes content.
+
+        Now, when a rule is added or deleted from an @keyframes rule using the CSSOM, we notify
+        the Document using the new keyframesRuleDidChange() method, which in turn checks all
+        CSSAnimation objects applied to elements in that document using that @keyframes rule
+        and notifies them of the change by calling keyframesRuleDidChange().
+
+        This clears the keyframes on the associated KeyframeEffect, invalidates the target
+        and sets a flag on the ElementAnimationRareData that this element is pending update
+        to its CSS Animations' keyframe such that during the next call
+        Styleable::updateCSSAnimations() we force the update even if the previous and current
+        AnimationList look identical.
+
+        During that next call to Styleable::updateCSSAnimations(), we will call into the new
+        CSSAnimation::updateKeyframesIfNeeded() which will re-compute the keyframes based on the
+        current set of rules within the @keyframes rule.
+
+        The final piece of work required is to track when setKeyframes() is called on the effect
+        that updates to the @keyframes rule should no longer apply since they keyframes were overriden
+        by the Web Animations API. This is done by setting an additional flag in
+        CSSAnimation::effectKeyframesWereSetUsingBindings().
+
+        * animation/CSSAnimation.cpp:
+        (WebCore::CSSAnimation::effectKeyframesWereSetUsingBindings):
+        (WebCore::CSSAnimation::keyframesRuleDidChange):
+        (WebCore::CSSAnimation::updateKeyframesIfNeeded):
+        * animation/CSSAnimation.h:
+        * animation/ElementAnimationRareData.h:
+        (WebCore::ElementAnimationRareData::cssAnimationsDidUpdate):
+        (WebCore::ElementAnimationRareData::keyframesRuleDidChange):
+        (WebCore::ElementAnimationRareData::hasPendingKeyframesUpdate const):
+        * animation/KeyframeEffect.cpp:
+        (WebCore::KeyframeEffect::keyframesRuleDidChange):
+        * animation/KeyframeEffect.h:
+        * css/CSSStyleSheet.cpp:
+        (WebCore::CSSStyleSheet::didMutateRules):
+        (WebCore::CSSStyleSheet::RuleMutationScope::RuleMutationScope):
+        (WebCore::CSSStyleSheet::RuleMutationScope::~RuleMutationScope):
+        * css/CSSStyleSheet.h:
+        * dom/Document.cpp:
+        (WebCore::Document::keyframesRuleDidChange):
+        * dom/Document.h:
+        * dom/Element.cpp:
+        (WebCore::Element::cssAnimationsDidUpdate):
+        (WebCore::Element::keyframesRuleDidChange):
+        (WebCore::Element::hasPendingKeyframesUpdate const):
+        * dom/Element.h:
+        * style/Styleable.cpp:
+        (WebCore::Styleable::updateCSSAnimations const):
+        * style/Styleable.h:
+        (WebCore::Styleable::keyframesRuleDidChange const):
+
 2022-01-06  Andres Gonzalez  <andresg...@apple.com>
 
         Replace WTFMove + clear with std::exchange for AXObjectCache notification queues.

Modified: trunk/Source/WebCore/animation/CSSAnimation.cpp (287706 => 287707)


--- trunk/Source/WebCore/animation/CSSAnimation.cpp	2022-01-06 19:47:35 UTC (rev 287706)
+++ trunk/Source/WebCore/animation/CSSAnimation.cpp	2022-01-06 19:57:38 UTC (rev 287707)
@@ -237,9 +237,33 @@
     // After a successful call to setKeyframes() on the KeyframeEffect associated with a CSSAnimation, any subsequent change to
     // matching @keyframes rules or the resolved value of the animation-timing-function property for the target element will not
     // be reflected in that animation.
+    m_overriddenProperties.add(Property::Keyframes);
     m_overriddenProperties.add(Property::TimingFunction);
 }
 
+void CSSAnimation::keyframesRuleDidChange()
+{
+    if (m_overriddenProperties.contains(Property::Keyframes) || !is<KeyframeEffect>(effect()))
+        return;
+
+    auto owningElement = this->owningElement();
+    if (!owningElement)
+        return;
+
+    downcast<KeyframeEffect>(*effect()).keyframesRuleDidChange();
+    owningElement->keyframesRuleDidChange();
+}
+
+void CSSAnimation::updateKeyframesIfNeeded(const RenderStyle* oldStyle, const RenderStyle& newStyle, const Style::ResolutionContext& resolutionContext)
+{
+    if (m_overriddenProperties.contains(Property::Keyframes) || !is<KeyframeEffect>(effect()))
+        return;
+
+    auto& keyframeEffect = downcast<KeyframeEffect>(*effect());
+    if (keyframeEffect.blendingKeyframes().isEmpty())
+        keyframeEffect.computeDeclarativeAnimationBlendingKeyframes(oldStyle, newStyle, resolutionContext);
+}
+
 Ref<AnimationEventBase> CSSAnimation::createEvent(const AtomString& eventType, double elapsedTime, const String& pseudoId, std::optional<Seconds> timelineTime)
 {
     return AnimationEvent::create(eventType, m_animationName, elapsedTime, pseudoId, timelineTime, this);

Modified: trunk/Source/WebCore/animation/CSSAnimation.h (287706 => 287707)


--- trunk/Source/WebCore/animation/CSSAnimation.h	2022-01-06 19:47:35 UTC (rev 287706)
+++ trunk/Source/WebCore/animation/CSSAnimation.h	2022-01-06 19:57:38 UTC (rev 287707)
@@ -46,6 +46,8 @@
 
     void effectTimingWasUpdatedUsingBindings(OptionalEffectTiming);
     void effectKeyframesWereSetUsingBindings();
+    void keyframesRuleDidChange();
+    void updateKeyframesIfNeeded(const RenderStyle* oldStyle, const RenderStyle& newStyle, const Style::ResolutionContext&);
 
 private:
     CSSAnimation(const Styleable&, const Animation&);
@@ -59,7 +61,7 @@
     void setBindingsStartTime(std::optional<double>) final;
     ExceptionOr<void> bindingsReverse() final;
 
-    enum class Property : uint8_t {
+    enum class Property : uint16_t {
         Name = 1 << 0,
         Duration = 1 << 1,
         TimingFunction = 1 << 2,
@@ -67,7 +69,8 @@
         Direction = 1 << 4,
         PlayState = 1 << 5,
         Delay = 1 << 6,
-        FillMode = 1 << 7
+        FillMode = 1 << 7,
+        Keyframes = 1 << 8
     };
 
     String m_animationName;

Modified: trunk/Source/WebCore/animation/ElementAnimationRareData.h (287706 => 287707)


--- trunk/Source/WebCore/animation/ElementAnimationRareData.h	2022-01-06 19:47:35 UTC (rev 287706)
+++ trunk/Source/WebCore/animation/ElementAnimationRareData.h	2022-01-06 19:57:38 UTC (rev 287707)
@@ -54,6 +54,9 @@
     PropertyToTransitionMap& runningTransitionsByProperty() { return m_runningTransitionsByProperty; }
     const RenderStyle* lastStyleChangeEventStyle() const { return m_lastStyleChangeEventStyle.get(); }
     void setLastStyleChangeEventStyle(std::unique_ptr<const RenderStyle>&& style) { m_lastStyleChangeEventStyle = WTFMove(style); }
+    void cssAnimationsDidUpdate() { m_hasPendingKeyframesUpdate = false; }
+    void keyframesRuleDidChange() { m_hasPendingKeyframesUpdate = true; }
+    bool hasPendingKeyframesUpdate() const { return m_hasPendingKeyframesUpdate; }
 
 private:
 
@@ -64,6 +67,7 @@
     PropertyToTransitionMap m_completedTransitionsByProperty;
     PropertyToTransitionMap m_runningTransitionsByProperty;
     PseudoId m_pseudoId;
+    bool m_hasPendingKeyframesUpdate { false };
 };
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/animation/KeyframeEffect.cpp (287706 => 287707)


--- trunk/Source/WebCore/animation/KeyframeEffect.cpp	2022-01-06 19:47:35 UTC (rev 287706)
+++ trunk/Source/WebCore/animation/KeyframeEffect.cpp	2022-01-06 19:57:38 UTC (rev 287707)
@@ -784,6 +784,13 @@
     return processKeyframesResult;
 }
 
+void KeyframeEffect::keyframesRuleDidChange()
+{
+    ASSERT(is<CSSAnimation>(animation()));
+    clearBlendingKeyframes();
+    invalidate();
+}
+
 ExceptionOr<void> KeyframeEffect::processKeyframes(JSGlobalObject& lexicalGlobalObject, Strong<JSObject>&& keyframesInput)
 {
     // 1. If object is null, return an empty sequence of keyframes.

Modified: trunk/Source/WebCore/animation/KeyframeEffect.h (287706 => 287707)


--- trunk/Source/WebCore/animation/KeyframeEffect.h	2022-01-06 19:47:35 UTC (rev 287706)
+++ trunk/Source/WebCore/animation/KeyframeEffect.h	2022-01-06 19:57:38 UTC (rev 287707)
@@ -169,6 +169,8 @@
 
     void stopAcceleratingTransformRelatedProperties(UseAcceleratedAction);
 
+    void keyframesRuleDidChange();
+
 private:
     KeyframeEffect(Element*, PseudoId);
 

Modified: trunk/Source/WebCore/css/CSSStyleSheet.cpp (287706 => 287707)


--- trunk/Source/WebCore/css/CSSStyleSheet.cpp	2022-01-06 19:47:35 UTC (rev 287706)
+++ trunk/Source/WebCore/css/CSSStyleSheet.cpp	2022-01-06 19:57:38 UTC (rev 287707)
@@ -151,7 +151,7 @@
     didMutate();
 }
 
-void CSSStyleSheet::didMutateRules(RuleMutationType mutationType, WhetherContentsWereClonedForMutation contentsWereClonedForMutation, StyleRuleKeyframes* insertedKeyframesRule)
+void CSSStyleSheet::didMutateRules(RuleMutationType mutationType, WhetherContentsWereClonedForMutation contentsWereClonedForMutation, StyleRuleKeyframes* insertedKeyframesRule, const String& modifiedKeyframesRuleName)
 {
     ASSERT(m_contents->isMutable());
     ASSERT(m_contents->hasOneClient());
@@ -170,6 +170,21 @@
         return;
     }
 
+    if (mutationType == RuleInsertion && !contentsWereClonedForMutation && !scope->activeStyleSheetsContains(this)) {
+        if (insertedKeyframesRule) {
+            if (auto* resolver = scope->resolverIfExists())
+                resolver->addKeyframeStyle(*insertedKeyframesRule);
+            return;
+        }
+        scope->didChangeActiveStyleSheetCandidates();
+        return;
+    }
+
+    if (mutationType == KeyframesRuleMutation) {
+        if (auto* ownerDocument = this->ownerDocument())
+            ownerDocument->keyframesRuleDidChange(modifiedKeyframesRuleName);
+    }
+
     scope->didChangeStyleSheetContents();
 
     m_mutatedRules = true;
@@ -401,9 +416,10 @@
 
 CSSStyleSheet::RuleMutationScope::RuleMutationScope(CSSRule* rule)
     : m_styleSheet(rule ? rule->parentStyleSheet() : nullptr)
-    , m_mutationType(OtherMutation)
+    , m_mutationType(is<CSSKeyframesRule>(rule) ? KeyframesRuleMutation : OtherMutation)
     , m_contentsWereClonedForMutation(ContentsWereNotClonedForMutation)
     , m_insertedKeyframesRule(nullptr)
+    , m_modifiedKeyframesRuleName(is<CSSKeyframesRule>(rule) ? downcast<CSSKeyframesRule>(*rule).name() : emptyString())
 {
     if (m_styleSheet)
         m_contentsWereClonedForMutation = m_styleSheet->willMutateRules();
@@ -412,7 +428,7 @@
 CSSStyleSheet::RuleMutationScope::~RuleMutationScope()
 {
     if (m_styleSheet)
-        m_styleSheet->didMutateRules(m_mutationType, m_contentsWereClonedForMutation, m_insertedKeyframesRule);
+        m_styleSheet->didMutateRules(m_mutationType, m_contentsWereClonedForMutation, m_insertedKeyframesRule, m_modifiedKeyframesRuleName);
 }
 
 }

Modified: trunk/Source/WebCore/css/CSSStyleSheet.h (287706 => 287707)


--- trunk/Source/WebCore/css/CSSStyleSheet.h	2022-01-06 19:47:35 UTC (rev 287706)
+++ trunk/Source/WebCore/css/CSSStyleSheet.h	2022-01-06 19:57:38 UTC (rev 287707)
@@ -95,7 +95,7 @@
     bool hadRulesMutation() const { return m_mutatedRules; }
     void clearHadRulesMutation() { m_mutatedRules = false; }
 
-    enum RuleMutationType { OtherMutation, RuleInsertion };
+    enum RuleMutationType { OtherMutation, RuleInsertion, KeyframesRuleMutation };
     enum WhetherContentsWereClonedForMutation { ContentsWereNotClonedForMutation = 0, ContentsWereClonedForMutation };
 
     class RuleMutationScope {
@@ -110,10 +110,11 @@
         RuleMutationType m_mutationType;
         WhetherContentsWereClonedForMutation m_contentsWereClonedForMutation;
         StyleRuleKeyframes* m_insertedKeyframesRule;
+        String m_modifiedKeyframesRuleName;
     };
 
     WhetherContentsWereClonedForMutation willMutateRules();
-    void didMutateRules(RuleMutationType, WhetherContentsWereClonedForMutation, StyleRuleKeyframes* insertedKeyframesRule);
+    void didMutateRules(RuleMutationType, WhetherContentsWereClonedForMutation, StyleRuleKeyframes* insertedKeyframesRule, const String& modifiedKeyframesRuleName);
     void didMutateRuleFromCSSStyleDeclaration();
     void didMutate();
     

Modified: trunk/Source/WebCore/dom/Document.cpp (287706 => 287707)


--- trunk/Source/WebCore/dom/Document.cpp	2022-01-06 19:47:35 UTC (rev 287706)
+++ trunk/Source/WebCore/dom/Document.cpp	2022-01-06 19:57:38 UTC (rev 287707)
@@ -33,6 +33,7 @@
 #include "Attr.h"
 #include "BeforeUnloadEvent.h"
 #include "CDATASection.h"
+#include "CSSAnimation.h"
 #include "CSSFontSelector.h"
 #include "CSSParser.h"
 #include "CSSStyleDeclaration.h"
@@ -8569,6 +8570,24 @@
     return animations;
 }
 
+void Document::keyframesRuleDidChange(const String& name)
+{
+    for (auto* animation : WebAnimation::instances()) {
+        if (!is<CSSAnimation>(animation) || !animation->isRelevant())
+            continue;
+
+        auto& cssAnimation = downcast<CSSAnimation>(*animation);
+        if (cssAnimation.animationName() != name)
+            continue;
+
+        auto owningElement = cssAnimation.owningElement();
+        if (!owningElement || !owningElement->element.isConnected() || &owningElement->element.document() != this)
+            continue;
+
+        cssAnimation.keyframesRuleDidChange();
+    }
+}
+
 void Document::addTopLayerElement(Element& element)
 {
     RELEASE_ASSERT(&element.document() == this && element.isConnected() && !element.isInTopLayer());

Modified: trunk/Source/WebCore/dom/Document.h (287706 => 287707)


--- trunk/Source/WebCore/dom/Document.h	2022-01-06 19:47:35 UTC (rev 287706)
+++ trunk/Source/WebCore/dom/Document.h	2022-01-06 19:57:38 UTC (rev 287707)
@@ -1541,6 +1541,7 @@
     Vector<RefPtr<WebAnimation>> matchingAnimations(const Function<bool(Element&)>&);
     DocumentTimelinesController* timelinesController() const { return m_timelinesController.get(); }
     WEBCORE_EXPORT DocumentTimelinesController& ensureTimelinesController();
+    void keyframesRuleDidChange(const String& name);
 
     void addTopLayerElement(Element&);
     void removeTopLayerElement(Element&);

Modified: trunk/Source/WebCore/dom/Element.cpp (287706 => 287707)


--- trunk/Source/WebCore/dom/Element.cpp	2022-01-06 19:47:35 UTC (rev 287706)
+++ trunk/Source/WebCore/dom/Element.cpp	2022-01-06 19:57:38 UTC (rev 287707)
@@ -4050,6 +4050,22 @@
         ensureAnimationRareData(pseudoId).setLastStyleChangeEventStyle(WTFMove(style));
 }
 
+void Element::cssAnimationsDidUpdate(PseudoId pseudoId)
+{
+    ensureAnimationRareData(pseudoId).cssAnimationsDidUpdate();
+}
+
+void Element::keyframesRuleDidChange(PseudoId pseudoId)
+{
+    ensureAnimationRareData(pseudoId).keyframesRuleDidChange();
+}
+
+bool Element::hasPendingKeyframesUpdate(PseudoId pseudoId) const
+{
+    auto* data = ""
+    return data && data->hasPendingKeyframesUpdate();
+}
+
 void Element::disconnectFromResizeObservers()
 {
     auto* observerData = resizeObserverData();

Modified: trunk/Source/WebCore/dom/Element.h (287706 => 287707)


--- trunk/Source/WebCore/dom/Element.h	2022-01-06 19:47:35 UTC (rev 287706)
+++ trunk/Source/WebCore/dom/Element.h	2022-01-06 19:57:38 UTC (rev 287707)
@@ -532,6 +532,10 @@
     const RenderStyle* lastStyleChangeEventStyle(PseudoId) const;
     void setLastStyleChangeEventStyle(PseudoId, std::unique_ptr<const RenderStyle>&&);
 
+    void cssAnimationsDidUpdate(PseudoId);
+    void keyframesRuleDidChange(PseudoId);
+    bool hasPendingKeyframesUpdate(PseudoId) const;
+
     bool isInTopLayer() const { return hasNodeFlag(NodeFlag::IsInTopLayer); }
     void addToTopLayer();
     void removeFromTopLayer();

Modified: trunk/Source/WebCore/style/Styleable.cpp (287706 => 287707)


--- trunk/Source/WebCore/style/Styleable.cpp	2022-01-06 19:47:35 UTC (rev 287706)
+++ trunk/Source/WebCore/style/Styleable.cpp	2022-01-06 19:57:38 UTC (rev 287707)
@@ -230,7 +230,7 @@
 
     auto* currentAnimationList = newStyle.animations();
     auto* previousAnimationList = keyframeEffectStack.cssAnimationList();
-    if (previousAnimationList && !previousAnimationList->isEmpty() && newStyle.hasAnimations() && *(previousAnimationList) == *(newStyle.animations()))
+    if (!element.hasPendingKeyframesUpdate(pseudoId) && previousAnimationList && !previousAnimationList->isEmpty() && newStyle.hasAnimations() && *(previousAnimationList) == *(newStyle.animations()))
         return;
 
     CSSAnimationCollection newAnimations;
@@ -257,6 +257,9 @@
                     // Timing properties or play state may have changed so we need to update the backing animation with
                     // the Animation found in the current style.
                     previousAnimation->setBackingAnimation(currentAnimation);
+                    // Keyframes may have been cleared if the @keyframes rules was changed since
+                    // the last style update, so we must ensure keyframes are picked up.
+                    previousAnimation->updateKeyframesIfNeeded(currentStyle, newStyle, resolutionContext);
                     newAnimations.add(previousAnimation);
                     // Remove the matched animation from the list of previous animations so we may not match it again.
                     previousAnimations.remove(previousAnimation);
@@ -281,6 +284,8 @@
     setAnimationsCreatedByMarkup(WTFMove(newAnimations));
 
     keyframeEffectStack.setCSSAnimationList(currentAnimationList);
+
+    element.cssAnimationsDidUpdate(pseudoId);
 }
 
 static KeyframeEffect* keyframeEffectForElementAndProperty(const Styleable& styleable, CSSPropertyID property)

Modified: trunk/Source/WebCore/style/Styleable.h (287706 => 287707)


--- trunk/Source/WebCore/style/Styleable.h	2022-01-06 19:47:35 UTC (rev 287706)
+++ trunk/Source/WebCore/style/Styleable.h	2022-01-06 19:57:38 UTC (rev 287707)
@@ -145,6 +145,11 @@
         element.setLastStyleChangeEventStyle(pseudoId, WTFMove(style));
     }
 
+    void keyframesRuleDidChange() const
+    {
+        element.keyframesRuleDidChange(pseudoId);
+    }
+
     void elementWasRemoved() const;
 
     void willChangeRenderer() const;
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to