Changeset 287769 in webkit


Ignore:
Timestamp:
Jan 7, 2022 11:22:52 AM (6 months ago)
Author:
graouts@webkit.org
Message:

Inserting a new @keyframes rule does not start animations that already used this name
https://bugs.webkit.org/show_bug.cgi?id=234955

Reviewed by Antti Koivisto.

LayoutTests/imported/w3c:

Mark WPT progression.

  • web-platform-tests/css/css-animations/Element-getAnimations.tentative-expected.txt:

Source/WebCore:

In bug 234895, we added logic to handle the case where an existing @keyframes rule was manipulated
via the CSSOM API and ensured this would update the keyframes of any existing CSSAnimation currently
referencing this @keyframes rule.

Another WPT tests the case where a @keyframes rule is referenced by an animation prior to existing
in the stylesheet, adding that named @keyframes rule, and then testing a CSSAnimation was created.

To handle this case, we need to track which animation names were ignored during style resolution
due not matching an existing @keyframes rule. We now manage a list of invalid CSS animation names
stored on the KeyframeEffectStack (where we also keep track of the AnimationList last seen during
style resolution) and use that to determine when, even though the previous and current AnimationList
contain the same data, a previously-ignored animation should now be processed due to its referenced
@keyframes rule now existing.

  • animation/KeyframeEffectStack.cpp:

(WebCore::KeyframeEffectStack::clearInvalidCSSAnimationNames):
(WebCore::KeyframeEffectStack::hasInvalidCSSAnimationNames const):
(WebCore::KeyframeEffectStack::containsInvalidCSSAnimationName const):
(WebCore::KeyframeEffectStack::addInvalidCSSAnimationName):

  • animation/KeyframeEffectStack.h:
  • style/Styleable.cpp:

(WebCore::keyframesRuleExistsForAnimation):
(WebCore::Styleable::animationListContainsNewlyValidAnimation const):
(WebCore::Styleable::updateCSSAnimations const):
(WebCore::shouldConsiderAnimation): Deleted.

  • style/Styleable.h:
Location:
trunk
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/imported/w3c/ChangeLog

    r287764 r287769  
     12022-01-07  Antoine Quint  <graouts@webkit.org>
     2
     3        Inserting a new @keyframes rule does not start animations that already used this name
     4        https://bugs.webkit.org/show_bug.cgi?id=234955
     5
     6        Reviewed by Antti Koivisto.
     7
     8        Mark WPT progression.
     9
     10        * web-platform-tests/css/css-animations/Element-getAnimations.tentative-expected.txt:
     11
    1122022-01-07  Antoine Quint  <graouts@webkit.org>
    213
  • trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-animations/Element-getAnimations.tentative-expected.txt

    r267650 r287769  
    99PASS getAnimations for CSS Animations with animation-name: none
    1010PASS getAnimations for CSS Animations with animation-name: missing
    11 FAIL getAnimations for CSS Animations where the @keyframes rule is added later assert_equals: getAnimations includes Animation when @keyframes rule is added later expected 2 but got 1
     11PASS getAnimations for CSS Animations where the @keyframes rule is added later
    1212PASS getAnimations for CSS Animations with duplicated animation-name
    1313PASS getAnimations for CSS Animations with empty keyframes rule
  • trunk/Source/WebCore/ChangeLog

    r287764 r287769  
     12022-01-07  Antoine Quint  <graouts@webkit.org>
     2
     3        Inserting a new @keyframes rule does not start animations that already used this name
     4        https://bugs.webkit.org/show_bug.cgi?id=234955
     5
     6        Reviewed by Antti Koivisto.
     7
     8        In bug 234895, we added logic to handle the case where an existing @keyframes rule was manipulated
     9        via the CSSOM API and ensured this would update the keyframes of any existing CSSAnimation currently
     10        referencing this @keyframes rule.
     11
     12        Another WPT tests the case where a @keyframes rule is referenced by an animation prior to existing
     13        in the stylesheet, adding that named @keyframes rule, and then testing a CSSAnimation was created.
     14
     15        To handle this case, we need to track which animation names were ignored during style resolution
     16        due not matching an existing @keyframes rule. We now manage a list of invalid CSS animation names
     17        stored on the KeyframeEffectStack (where we also keep track of the AnimationList last seen during
     18        style resolution) and use that to determine when, even though the previous and current AnimationList
     19        contain the same data, a previously-ignored animation should now be processed due to its referenced
     20        @keyframes rule now existing.
     21
     22        * animation/KeyframeEffectStack.cpp:
     23        (WebCore::KeyframeEffectStack::clearInvalidCSSAnimationNames):
     24        (WebCore::KeyframeEffectStack::hasInvalidCSSAnimationNames const):
     25        (WebCore::KeyframeEffectStack::containsInvalidCSSAnimationName const):
     26        (WebCore::KeyframeEffectStack::addInvalidCSSAnimationName):
     27        * animation/KeyframeEffectStack.h:
     28        * style/Styleable.cpp:
     29        (WebCore::keyframesRuleExistsForAnimation):
     30        (WebCore::Styleable::animationListContainsNewlyValidAnimation const):
     31        (WebCore::Styleable::updateCSSAnimations const):
     32        (WebCore::shouldConsiderAnimation): Deleted.
     33        * style/Styleable.h:
     34
    1352022-01-07  Antoine Quint  <graouts@webkit.org>
    236
  • trunk/Source/WebCore/animation/KeyframeEffectStack.cpp

    r285397 r287769  
    157157}
    158158
     159void KeyframeEffectStack::clearInvalidCSSAnimationNames()
     160{
     161    m_invalidCSSAnimationNames.clear();
     162}
     163
     164bool KeyframeEffectStack::hasInvalidCSSAnimationNames() const
     165{
     166    return !m_invalidCSSAnimationNames.isEmpty();
     167}
     168
     169bool KeyframeEffectStack::containsInvalidCSSAnimationName(const String& name) const
     170{
     171    return m_invalidCSSAnimationNames.contains(name);
     172}
     173
     174void KeyframeEffectStack::addInvalidCSSAnimationName(const String& name)
     175{
     176    m_invalidCSSAnimationNames.add(name);
     177}
     178
    159179} // namespace WebCore
  • trunk/Source/WebCore/animation/KeyframeEffectStack.h

    r284693 r287769  
    6060    void stopAcceleratingTransformRelatedProperties(UseAcceleratedAction);
    6161
     62    void clearInvalidCSSAnimationNames();
     63    bool hasInvalidCSSAnimationNames() const;
     64    bool containsInvalidCSSAnimationName(const String&) const;
     65    void addInvalidCSSAnimationName(const String&);
     66
    6267private:
    6368    void ensureEffectsAreSorted();
    6469
    6570    Vector<WeakPtr<KeyframeEffect>> m_effects;
     71    HashSet<String> m_invalidCSSAnimationNames;
    6672    RefPtr<const AnimationList> m_cssAnimationList;
    6773    bool m_isSorted { true };
    68 
    6974};
    7075
  • trunk/Source/WebCore/style/Styleable.cpp

    r287764 r287769  
    202202}
    203203
    204 static bool shouldConsiderAnimation(Element& element, const Animation& animation)
    205 {
    206     if (!animation.isValidAnimation())
     204static bool keyframesRuleExistsForAnimation(Element& element, const Animation& animation, const String& animationName)
     205{
     206    auto* styleScope = Style::Scope::forOrdinal(element, animation.nameStyleScopeOrdinal());
     207    return styleScope && styleScope->resolver().isAnimationNameValid(animationName);
     208}
     209
     210bool Styleable::animationListContainsNewlyValidAnimation(const AnimationList& animations) const
     211{
     212    auto& keyframeEffectStack = ensureKeyframeEffectStack();
     213    if (!keyframeEffectStack.hasInvalidCSSAnimationNames())
    207214        return false;
    208215
    209     auto& name = animation.name().string;
    210     if (name == "none" || name.isEmpty())
    211         return false;
    212 
    213     if (auto* styleScope = Style::Scope::forOrdinal(element, animation.nameStyleScopeOrdinal()))
    214         return styleScope->resolver().isAnimationNameValid(name);
     216    for (auto& animation : animations) {
     217        auto& name = animation->name().string;
     218        if (name != "none" && !name.isEmpty() && keyframeEffectStack.containsInvalidCSSAnimationName(name) && keyframesRuleExistsForAnimation(element, animation.get(), name))
     219            return true;
     220    }
    215221
    216222    return false;
     
    231237    auto* currentAnimationList = newStyle.animations();
    232238    auto* previousAnimationList = keyframeEffectStack.cssAnimationList();
    233     if (!element.hasPendingKeyframesUpdate(pseudoId) && previousAnimationList && !previousAnimationList->isEmpty() && newStyle.hasAnimations() && *(previousAnimationList) == *(newStyle.animations()))
     239    if (!element.hasPendingKeyframesUpdate(pseudoId) && previousAnimationList && !previousAnimationList->isEmpty() && newStyle.hasAnimations() && *(previousAnimationList) == *(newStyle.animations()) && !animationListContainsNewlyValidAnimation(*newStyle.animations()))
    234240        return;
    235241
    236242    CSSAnimationCollection newAnimations;
    237243    auto& previousAnimations = animationsCreatedByMarkup();
     244
     245    keyframeEffectStack.clearInvalidCSSAnimationNames();
    238246
    239247    // https://www.w3.org/TR/css-animations-1/#animations
     
    248256    if (currentAnimationList) {
    249257        for (auto& currentAnimation : makeReversedRange(*currentAnimationList)) {
    250             if (!shouldConsiderAnimation(this->element, currentAnimation.get()))
     258            if (!currentAnimation->isValidAnimation())
    251259                continue;
     260
     261            auto& animationName = currentAnimation->name().string;
     262            if (animationName == "none" || animationName.isEmpty())
     263                continue;
     264
     265            if (!keyframesRuleExistsForAnimation(element, currentAnimation.get(), animationName)) {
     266                keyframeEffectStack.addInvalidCSSAnimationName(animationName);
     267                continue;
     268            }
    252269
    253270            bool foundMatchingAnimation = false;
    254271            for (auto& previousAnimation : previousAnimations) {
    255                 if (previousAnimation->animationName() == currentAnimation->name().string) {
     272                if (previousAnimation->animationName() == animationName) {
    256273                    // Timing properties or play state may have changed so we need to update the backing animation with
    257274                    // the Animation found in the current style.
  • trunk/Source/WebCore/style/Styleable.h

    r287707 r287769  
    151151    }
    152152
     153    bool animationListContainsNewlyValidAnimation(const AnimationList&) const;
     154
    153155    void elementWasRemoved() const;
    154156
Note: See TracChangeset for help on using the changeset viewer.