[Web Animations] Refactor animation comparison by composite order in a single utility...
authorgraouts@webkit.org <graouts@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 11 May 2020 09:14:37 +0000 (09:14 +0000)
committergraouts@webkit.org <graouts@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 11 May 2020 09:14:37 +0000 (09:14 +0000)
https://bugs.webkit.org/show_bug.cgi?id=211695

Reviewed by Darin Adler.

We used to split sorting of animations by composite order across several functions and files. Specifically,
DocumentTimeline::getAnimations() would first collect animations by class (CSS Transitions, then CSS
Animations, then JS-originated animations), and then sort each class, calling into the static function
compareDeclarativeAnimationOwningElementPositionsInDocumentTreeOrder() in some cases and into the
WebAnimationUtilities compareAnimationsByCompositeOrder() function in other.

Since we need to be able to sort animations by composite order in other situations, for instance when sorting
events when updating animations and sending events (which we will do in a future patch), we refactor all
of the comparison logic into compareAnimationsByCompositeOrder(), removing the need to provide an AnimationList,
which is specific to the case where we know we are comparing CSSAnimation objects targeting a shared element.

This effectively empties DocumentTimeline::getAnimations() so we remove this function and filter relevant
animations in Document::matchingAnimations() and call compareAnimationsByCompositeOrder() before returning
the compiled animations.

No new tests since there is no change of behavior.

* animation/DocumentTimeline.cpp:
(WebCore::compareDeclarativeAnimationOwningElementPositionsInDocumentTreeOrder): Deleted.
(WebCore::DocumentTimeline::getAnimations const): Deleted.
* animation/DocumentTimeline.h:
* animation/KeyframeEffectStack.cpp:
(WebCore::KeyframeEffectStack::ensureEffectsAreSorted):
* animation/WebAnimation.cpp:
(WebCore::WebAnimation::commitStyles):
* animation/WebAnimationUtilities.cpp:
(WebCore::compareDeclarativeAnimationOwningElementPositionsInDocumentTreeOrder):
(WebCore::compareCSSTransitions):
(WebCore::compareCSSAnimations):
(WebCore::compareAnimationsByCompositeOrder):
* animation/WebAnimationUtilities.h:
* dom/Document.cpp:
(WebCore::Document::matchingAnimations):

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

Source/WebCore/ChangeLog
Source/WebCore/animation/DocumentTimeline.cpp
Source/WebCore/animation/DocumentTimeline.h
Source/WebCore/animation/KeyframeEffectStack.cpp
Source/WebCore/animation/WebAnimation.cpp
Source/WebCore/animation/WebAnimationUtilities.cpp
Source/WebCore/animation/WebAnimationUtilities.h
Source/WebCore/dom/Document.cpp

index fdd590b..f57470f 100644 (file)
@@ -1,3 +1,44 @@
+2020-05-10  Antoine Quint  <graouts@apple.com>
+
+        [Web Animations] Refactor animation comparison by composite order in a single utility function
+        https://bugs.webkit.org/show_bug.cgi?id=211695
+
+        Reviewed by Darin Adler.
+
+        We used to split sorting of animations by composite order across several functions and files. Specifically,
+        DocumentTimeline::getAnimations() would first collect animations by class (CSS Transitions, then CSS
+        Animations, then JS-originated animations), and then sort each class, calling into the static function
+        compareDeclarativeAnimationOwningElementPositionsInDocumentTreeOrder() in some cases and into the
+        WebAnimationUtilities compareAnimationsByCompositeOrder() function in other.
+
+        Since we need to be able to sort animations by composite order in other situations, for instance when sorting
+        events when updating animations and sending events (which we will do in a future patch), we refactor all
+        of the comparison logic into compareAnimationsByCompositeOrder(), removing the need to provide an AnimationList,
+        which is specific to the case where we know we are comparing CSSAnimation objects targeting a shared element.
+
+        This effectively empties DocumentTimeline::getAnimations() so we remove this function and filter relevant
+        animations in Document::matchingAnimations() and call compareAnimationsByCompositeOrder() before returning
+        the compiled animations.
+
+        No new tests since there is no change of behavior.
+
+        * animation/DocumentTimeline.cpp:
+        (WebCore::compareDeclarativeAnimationOwningElementPositionsInDocumentTreeOrder): Deleted.
+        (WebCore::DocumentTimeline::getAnimations const): Deleted.
+        * animation/DocumentTimeline.h:
+        * animation/KeyframeEffectStack.cpp:
+        (WebCore::KeyframeEffectStack::ensureEffectsAreSorted):
+        * animation/WebAnimation.cpp:
+        (WebCore::WebAnimation::commitStyles):
+        * animation/WebAnimationUtilities.cpp:
+        (WebCore::compareDeclarativeAnimationOwningElementPositionsInDocumentTreeOrder):
+        (WebCore::compareCSSTransitions):
+        (WebCore::compareCSSAnimations):
+        (WebCore::compareAnimationsByCompositeOrder):
+        * animation/WebAnimationUtilities.h:
+        * dom/Document.cpp:
+        (WebCore::Document::matchingAnimations):
+
 2020-05-11  Charlie Turner  <cturner@igalia.com>
 
         [WPE] Layout test media/encrypted-media/mock-MediaKeySystemAccess.html is crashing
index e48e0f6..6420c8f 100644 (file)
@@ -27,7 +27,6 @@
 #include "DocumentTimeline.h"
 
 #include "AnimationEventBase.h"
-#include "CSSAnimation.h"
 #include "CSSTransition.h"
 #include "DeclarativeAnimation.h"
 #include "Document.h"
@@ -38,7 +37,6 @@
 #include "KeyframeEffectStack.h"
 #include "Node.h"
 #include "Page.h"
-#include "PseudoElement.h"
 #include "RenderElement.h"
 #include "RenderLayer.h"
 #include "RenderLayerBacking.h"
@@ -100,114 +98,6 @@ void DocumentTimeline::detachFromDocument()
     m_document = nullptr;
 }
 
-static inline bool compareDeclarativeAnimationOwningElementPositionsInDocumentTreeOrder(Element* lhsOwningElement, Element* rhsOwningElement)
-{
-    // With regard to pseudo-elements, the sort order is as follows:
-    //     - element
-    //     - ::before
-    //     - ::after
-    //     - element children
-    
-    // We could be comparing two pseudo-elements that are hosted on the same element.
-    if (is<PseudoElement>(lhsOwningElement) && is<PseudoElement>(rhsOwningElement)) {
-        auto* lhsPseudoElement = downcast<PseudoElement>(lhsOwningElement);
-        auto* rhsPseudoElement = downcast<PseudoElement>(rhsOwningElement);
-        if (lhsPseudoElement->hostElement() == rhsPseudoElement->hostElement())
-            return lhsPseudoElement->isBeforePseudoElement();
-    }
-
-    // Or comparing a pseudo-element that is compared to another non-pseudo element, in which case
-    // we want to see if it's hosted on that other element, and if not use its host element to compare.
-    if (is<PseudoElement>(lhsOwningElement)) {
-        auto* lhsHostElement = downcast<PseudoElement>(lhsOwningElement)->hostElement();
-        if (rhsOwningElement == lhsHostElement)
-            return false;
-        lhsOwningElement = lhsHostElement;
-    }
-
-    if (is<PseudoElement>(rhsOwningElement)) {
-        auto* rhsHostElement = downcast<PseudoElement>(rhsOwningElement)->hostElement();
-        if (lhsOwningElement == rhsHostElement)
-            return true;
-        rhsOwningElement = rhsHostElement;
-    }
-
-    return lhsOwningElement->compareDocumentPosition(*rhsOwningElement) & Node::DOCUMENT_POSITION_FOLLOWING;
-}
-
-Vector<RefPtr<WebAnimation>> DocumentTimeline::getAnimations() const
-{
-    ASSERT(m_document);
-
-    Vector<RefPtr<WebAnimation>> cssTransitions;
-    Vector<RefPtr<WebAnimation>> cssAnimations;
-    Vector<RefPtr<WebAnimation>> webAnimations;
-
-    // First, let's get all qualifying animations in their right group.
-    for (const auto& animation : m_animations) {
-        if (!animation || !animation->isRelevant() || animation->timeline() != this || !is<KeyframeEffect>(animation->effect()))
-            continue;
-
-        auto* target = downcast<KeyframeEffect>(animation->effect())->target();
-        if (!target || !target->isDescendantOf(*m_document))
-            continue;
-
-        if (is<CSSTransition>(animation.get()) && downcast<CSSTransition>(animation.get())->owningElement())
-            cssTransitions.append(animation);
-        else if (is<CSSAnimation>(animation.get()) && downcast<CSSAnimation>(animation.get())->owningElement())
-            cssAnimations.append(animation);
-        else
-            webAnimations.append(animation);
-    }
-
-    // Now sort CSS Transitions by their composite order.
-    std::stable_sort(cssTransitions.begin(), cssTransitions.end(), [](auto& lhs, auto& rhs) {
-        // https://drafts.csswg.org/css-transitions-2/#animation-composite-order
-        auto* lhsTransition = downcast<CSSTransition>(lhs.get());
-        auto* rhsTransition = downcast<CSSTransition>(rhs.get());
-
-        auto* lhsOwningElement = lhsTransition->owningElement();
-        auto* rhsOwningElement = rhsTransition->owningElement();
-
-        // If the owning element of A and B differs, sort A and B by tree order of their corresponding owning elements.
-        if (lhsOwningElement != rhsOwningElement)
-            return compareDeclarativeAnimationOwningElementPositionsInDocumentTreeOrder(lhsOwningElement, rhsOwningElement);
-
-        // Otherwise, if A and B have different transition generation values, sort by their corresponding transition generation in ascending order.
-        if (lhsTransition->generationTime() != rhsTransition->generationTime())
-            return lhsTransition->generationTime() < rhsTransition->generationTime();
-
-        // Otherwise, sort A and B in ascending order by the Unicode codepoints that make up the expanded transition property name of each transition
-        // (i.e. without attempting case conversion and such that ‘-moz-column-width’ sorts before ‘column-width’).
-        return lhsTransition->transitionProperty().utf8() < rhsTransition->transitionProperty().utf8();
-    });
-
-    // Now sort CSS Animations by their composite order.
-    std::stable_sort(cssAnimations.begin(), cssAnimations.end(), [](auto& lhs, auto& rhs) {
-        // https://drafts.csswg.org/css-animations-2/#animation-composite-order
-        auto* lhsOwningElement = downcast<CSSAnimation>(lhs.get())->owningElement();
-        auto* rhsOwningElement = downcast<CSSAnimation>(rhs.get())->owningElement();
-
-        // If the owning element of A and B differs, sort A and B by tree order of their corresponding owning elements.
-        if (lhsOwningElement != rhsOwningElement)
-            return compareDeclarativeAnimationOwningElementPositionsInDocumentTreeOrder(lhsOwningElement, rhsOwningElement);
-
-        // Otherwise, sort A and B based on their position in the computed value of the animation-name property of the (common) owning element.
-        return compareAnimationsByCompositeOrder(*lhs, *rhs, lhsOwningElement->ensureKeyframeEffectStack().cssAnimationList());
-    });
-
-    std::stable_sort(webAnimations.begin(), webAnimations.end(), [](auto& lhs, auto& rhs) {
-        return lhs->globalPosition() < rhs->globalPosition();
-    });
-
-    // Finally, we can concatenate the sorted CSS Transitions, CSS Animations and Web Animations in their relative composite order.
-    Vector<RefPtr<WebAnimation>> animations;
-    animations.appendRange(cssTransitions.begin(), cssTransitions.end());
-    animations.appendRange(cssAnimations.begin(), cssAnimations.end());
-    animations.appendRange(webAnimations.begin(), webAnimations.end());
-    return animations;
-}
-
 Seconds DocumentTimeline::animationInterval() const
 {
     if (!m_document || !m_document->page())
index 50792ba..f19fbc6 100644 (file)
@@ -46,8 +46,6 @@ public:
 
     bool isDocumentTimeline() const final { return true; }
 
-    Vector<RefPtr<WebAnimation>> getAnimations() const;
-
     Document* document() const { return m_document.get(); }
 
     Optional<Seconds> currentTime() override;
index 8082b65..7c0be0f 100644 (file)
@@ -98,7 +98,7 @@ void KeyframeEffectStack::ensureEffectsAreSorted()
         RELEASE_ASSERT(lhsAnimation);
         RELEASE_ASSERT(rhsAnimation);
 
-        return compareAnimationsByCompositeOrder(*lhsAnimation, *rhsAnimation, m_cssAnimationList.get());
+        return compareAnimationsByCompositeOrder(*lhsAnimation, *rhsAnimation);
     });
 
     m_isSorted = true;
index 3b7e966..f195428 100644 (file)
@@ -1415,7 +1415,6 @@ ExceptionOr<void> WebAnimation::commitStyles()
     inlineStyle->setCssText(styledElement.getAttribute("style"));
 
     auto& keyframeStack = styledElement.ensureKeyframeEffectStack();
-    auto* cssAnimationList = keyframeStack.cssAnimationList();
 
     // 2.5 For each property, property, in targeted properties:
     for (auto property : effect->animatedProperties()) {
@@ -1432,7 +1431,7 @@ ExceptionOr<void> WebAnimation::commitStyles()
         // effect stack and stop when we've found this animation's effect or when we've found an effect associated with an animation with a higher composite order.
         auto animatedStyle = RenderStyle::clonePtr(style);
         for (const auto& effectInStack : keyframeStack.sortedEffects()) {
-            if (effectInStack->animation() != this && !compareAnimationsByCompositeOrder(*effectInStack->animation(), *this, cssAnimationList))
+            if (effectInStack->animation() != this && !compareAnimationsByCompositeOrder(*effectInStack->animation(), *this))
                 break;
             if (effectInStack->animatedProperties().contains(property))
                 effectInStack->animation()->resolve(*animatedStyle);
index f7dac5c..e172d82 100644 (file)
 #include "CSSAnimation.h"
 #include "CSSTransition.h"
 #include "DeclarativeAnimation.h"
+#include "Element.h"
+#include "KeyframeEffectStack.h"
+#include "PseudoElement.h"
 #include "WebAnimation.h"
 
 namespace WebCore {
 
-bool compareAnimationsByCompositeOrder(WebAnimation& lhsAnimation, WebAnimation& rhsAnimation, const AnimationList* cssAnimationList)
+static bool compareDeclarativeAnimationOwningElementPositionsInDocumentTreeOrder(Element& a, Element& b)
+{
+    // We should not ever be calling this function with two Elements that are the same. If that were the case,
+    // then comparing objects of this kind would yield inconsistent results when comparing A == B and B == A.
+    // As such, this function should be called with std::stable_sort().
+    RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(&a != &b);
+
+    // With regard to pseudo-elements, the sort order is as follows:
+    //     - element
+    //     - ::before
+    //     - ::after
+    //     - element children
+
+    enum SortingIndex : uint8_t { NotPseudo, Before, After };
+
+    int aSortingIndex = NotPseudo;
+    Element* aReferenceElement = &a;
+    if (is<PseudoElement>(a)) {
+        auto& aPseudo = downcast<PseudoElement>(a);
+        aSortingIndex = aPseudo.isBeforePseudoElement() ? Before : After;
+        aReferenceElement = aPseudo.hostElement();
+        ASSERT(aReferenceElement);
+    }
+
+    int bSortingIndex = NotPseudo;
+    Element* bReferenceElement = &b;
+    if (is<PseudoElement>(b)) {
+        auto& bPseudo = downcast<PseudoElement>(b);
+        bSortingIndex = bPseudo.isBeforePseudoElement() ? Before : After;
+        bReferenceElement = bPseudo.hostElement();
+        ASSERT(bReferenceElement);
+    }
+
+    if (aReferenceElement == bReferenceElement)
+        return aSortingIndex < bSortingIndex;
+    return aReferenceElement->compareDocumentPosition(*bReferenceElement) & Node::DOCUMENT_POSITION_FOLLOWING;
+}
+
+static bool compareCSSTransitions(const CSSTransition& a, const CSSTransition& b)
+{
+    ASSERT(a.owningElement());
+    ASSERT(b.owningElement());
+    auto& aOwningElement = *a.owningElement();
+    auto& bOwningElement = *b.owningElement();
+
+    // If the owning element of A and B differs, sort A and B by tree order of their corresponding owning elements.
+    if (&aOwningElement != &bOwningElement)
+        return compareDeclarativeAnimationOwningElementPositionsInDocumentTreeOrder(aOwningElement, bOwningElement);
+
+    // Otherwise, if A and B have different transition generation values, sort by their corresponding transition generation in ascending order.
+    if (a.generationTime() != b.generationTime())
+        return a.generationTime() < b.generationTime();
+
+    // Otherwise, sort A and B in ascending order by the Unicode codepoints that make up the expanded transition property name of each transition
+    // (i.e. without attempting case conversion and such that ‘-moz-column-width’ sorts before ‘column-width’).
+    return a.transitionProperty().utf8() < b.transitionProperty().utf8();
+}
+
+static bool compareCSSAnimations(const CSSAnimation& a, const CSSAnimation& b)
+{
+    // https://drafts.csswg.org/css-animations-2/#animation-composite-order
+    ASSERT(a.owningElement());
+    ASSERT(b.owningElement());
+    auto& aOwningElement = *a.owningElement();
+    auto& bOwningElement = *b.owningElement();
+
+    // If the owning element of A and B differs, sort A and B by tree order of their corresponding owning elements.
+    if (&aOwningElement != &bOwningElement)
+        return compareDeclarativeAnimationOwningElementPositionsInDocumentTreeOrder(aOwningElement, bOwningElement);
+
+    // Sort A and B based on their position in the computed value of the animation-name property of the (common) owning element.
+    auto* cssAnimationList = aOwningElement.ensureKeyframeEffectStack().cssAnimationList();
+    ASSERT(cssAnimationList);
+    ASSERT(!cssAnimationList->isEmpty());
+
+    auto& aBackingAnimation = a.backingAnimation();
+    auto& bBackingAnimation = b.backingAnimation();
+    for (size_t i = 0; i < cssAnimationList->size(); ++i) {
+        auto& animation = cssAnimationList->animation(i);
+        if (animation == aBackingAnimation)
+            return true;
+        if (animation == bBackingAnimation)
+            return false;
+    }
+
+    // We should have found either of those CSS animations in the CSS animations list.
+    RELEASE_ASSERT_NOT_REACHED();
+}
+
+bool compareAnimationsByCompositeOrder(const WebAnimation& a, const WebAnimation& b)
 {
     // We should not ever be calling this function with two WebAnimation objects that are the same. If that were the case,
     // then comparing objects of this kind would yield inconsistent results when comparing A == B and B == A. As such,
     // this function should be called with std::stable_sort().
-    RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(&lhsAnimation != &rhsAnimation);
+    RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(&a != &b);
 
-    bool lhsHasOwningElement = is<DeclarativeAnimation>(lhsAnimation) && downcast<DeclarativeAnimation>(lhsAnimation).owningElement();
-    bool rhsHasOwningElement = is<DeclarativeAnimation>(rhsAnimation) && downcast<DeclarativeAnimation>(rhsAnimation).owningElement();
+    bool aHasOwningElement = is<DeclarativeAnimation>(a) && downcast<DeclarativeAnimation>(a).owningElement();
+    bool bHasOwningElement = is<DeclarativeAnimation>(b) && downcast<DeclarativeAnimation>(b).owningElement();
 
     // CSS Transitions sort first.
-    bool lhsIsCSSTransition = lhsHasOwningElement && is<CSSTransition>(lhsAnimation);
-    bool rhsIsCSSTransition = rhsHasOwningElement && is<CSSTransition>(rhsAnimation);
-    if (lhsIsCSSTransition || rhsIsCSSTransition) {
-        if (lhsIsCSSTransition != rhsIsCSSTransition)
-            return !rhsIsCSSTransition;
-
-        // Sort transitions first by their generation time, and then by transition-property.
-        // https://drafts.csswg.org/css-transitions-2/#animation-composite-order
-        auto& lhsCSSTransition = downcast<CSSTransition>(lhsAnimation);
-        auto& rhsCSSTransition = downcast<CSSTransition>(rhsAnimation);
-        if (lhsCSSTransition.generationTime() != rhsCSSTransition.generationTime())
-            return lhsCSSTransition.generationTime() < rhsCSSTransition.generationTime();
-        auto lhsCSSTransitionProperty = lhsCSSTransition.transitionProperty().utf8();
-        auto rhsCSSTransitionProperty = rhsCSSTransition.transitionProperty().utf8();
-        if (lhsCSSTransitionProperty != rhsCSSTransitionProperty)
-            return lhsCSSTransitionProperty < rhsCSSTransitionProperty;
+    bool aIsCSSTransition = aHasOwningElement && is<CSSTransition>(a);
+    bool bIsCSSTransition = bHasOwningElement && is<CSSTransition>(b);
+    if (aIsCSSTransition || bIsCSSTransition) {
+        if (aIsCSSTransition == bIsCSSTransition)
+            return compareCSSTransitions(downcast<CSSTransition>(a), downcast<CSSTransition>(b));
+        return !bIsCSSTransition;
     }
 
     // CSS Animations sort next.
-    bool lhsIsCSSAnimation = lhsHasOwningElement && is<CSSAnimation>(lhsAnimation);
-    bool rhsIsCSSAnimation = rhsHasOwningElement && is<CSSAnimation>(rhsAnimation);
-    if (lhsIsCSSAnimation || rhsIsCSSAnimation) {
-        if (lhsIsCSSAnimation != rhsIsCSSAnimation)
-            return !rhsIsCSSAnimation;
-
-        // We must have a list of CSS Animations if we have CSS Animations to sort through.
-        ASSERT(cssAnimationList);
-        ASSERT(!cssAnimationList->isEmpty());
-
-        // https://drafts.csswg.org/css-animations-2/#animation-composite-order
-        // Sort A and B based on their position in the computed value of the animation-name property of the (common) owning element.
-        auto& lhsBackingAnimation = downcast<CSSAnimation>(lhsAnimation).backingAnimation();
-        auto& rhsBackingAnimation = downcast<CSSAnimation>(rhsAnimation).backingAnimation();
-
-        for (size_t i = 0; i < cssAnimationList->size(); ++i) {
-            auto& animation = cssAnimationList->animation(i);
-            if (animation == lhsBackingAnimation)
-                return true;
-            if (animation == rhsBackingAnimation)
-                return false;
-        }
-
-        // We should have found either of those CSS animations in the CSS animations list.
-        RELEASE_ASSERT_NOT_REACHED();
+    bool aIsCSSAnimation = aHasOwningElement && is<CSSAnimation>(a);
+    bool bIsCSSAnimation = bHasOwningElement && is<CSSAnimation>(b);
+    if (aIsCSSAnimation || bIsCSSAnimation) {
+        if (aIsCSSAnimation == bIsCSSAnimation)
+            return compareCSSAnimations(downcast<CSSAnimation>(a), downcast<CSSAnimation>(b));
+        return !bIsCSSAnimation;
     }
 
     // JS-originated animations sort last based on their position in the global animation list.
     // https://drafts.csswg.org/web-animations-1/#animation-composite-order
-    RELEASE_ASSERT(lhsAnimation.globalPosition() != rhsAnimation.globalPosition() || &lhsAnimation == &rhsAnimation);
-    return lhsAnimation.globalPosition() < rhsAnimation.globalPosition();
+    RELEASE_ASSERT(a.globalPosition() != b.globalPosition());
+    return a.globalPosition() < b.globalPosition();
 }
 
 } // namespace WebCore
index fb91370..c85b979 100644 (file)
@@ -31,7 +31,7 @@
 
 namespace WebCore {
 
-class AnimationList;
+class Element;
 class WebAnimation;
 
 inline double secondsToWebAnimationsAPITime(const Seconds time)
@@ -50,7 +50,7 @@ inline double secondsToWebAnimationsAPITime(const Seconds time)
 
 const auto timeEpsilon = Seconds::fromMilliseconds(0.001);
 
-bool compareAnimationsByCompositeOrder(WebAnimation&, WebAnimation&, const AnimationList*);
+bool compareAnimationsByCompositeOrder(const WebAnimation&, const WebAnimation&);
 
 } // namespace WebCore
 
index 960dd60..6084dd7 100644 (file)
 #include "VisitedLinkState.h"
 #include "VisualViewport.h"
 #include "WebAnimation.h"
+#include "WebAnimationUtilities.h"
 #include "WheelEvent.h"
 #include "WindowEventLoop.h"
 #include "WindowFeatures.h"
@@ -8132,14 +8133,19 @@ Vector<RefPtr<WebAnimation>> Document::matchingAnimations(const WTF::Function<bo
         return { };
 
     Vector<RefPtr<WebAnimation>> animations;
-    for (auto& animation : m_timeline->getAnimations()) {
-        auto* effect = animation->effect();
-        ASSERT(is<KeyframeEffect>(animation->effect()));
-        auto* target = downcast<KeyframeEffect>(*effect).targetElementOrPseudoElement();
-        ASSERT(target);
-        if (function(*target))
+    for (auto& animation : m_timeline->relevantAnimations()) {
+        if (!animation || !animation->isRelevant() || !is<KeyframeEffect>(animation->effect()))
+            continue;
+
+        auto* target = downcast<KeyframeEffect>(*animation->effect()).targetElementOrPseudoElement();
+        if (target && target->isDescendantOf(this) && function(*target))
             animations.append(animation);
     }
+
+    std::stable_sort(animations.begin(), animations.end(), [](auto& lhs, auto& rhs) {
+        return compareAnimationsByCompositeOrder(*lhs, *rhs);
+    });
+
     return animations;
 }