LCOV - code coverage report
Current view: top level - dom/animation - EffectCompositor.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 233 499 46.7 %
Date: 2017-07-14 16:53:18 Functions: 33 50 66.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "EffectCompositor.h"
       8             : 
       9             : #include "mozilla/dom/Animation.h"
      10             : #include "mozilla/dom/Element.h"
      11             : #include "mozilla/dom/KeyframeEffectReadOnly.h"
      12             : #include "mozilla/AnimationComparator.h"
      13             : #include "mozilla/AnimationPerformanceWarning.h"
      14             : #include "mozilla/AnimationTarget.h"
      15             : #include "mozilla/AnimationUtils.h"
      16             : #include "mozilla/AutoRestore.h"
      17             : #include "mozilla/EffectSet.h"
      18             : #include "mozilla/GeckoStyleContext.h"
      19             : #include "mozilla/LayerAnimationInfo.h"
      20             : #include "mozilla/RestyleManager.h"
      21             : #include "mozilla/RestyleManagerInlines.h"
      22             : #include "mozilla/ServoBindings.h" // Servo_GetProperties_Overriding_Animation
      23             : #include "mozilla/ServoStyleSet.h"
      24             : #include "mozilla/StyleAnimationValue.h"
      25             : #include "mozilla/TypeTraits.h" // For Forward<>
      26             : #include "nsComputedDOMStyle.h" // nsComputedDOMStyle::GetPresShellForContent
      27             : #include "nsContentUtils.h"
      28             : #include "nsCSSPseudoElements.h"
      29             : #include "nsCSSPropertyIDSet.h"
      30             : #include "nsCSSProps.h"
      31             : #include "nsIAtom.h"
      32             : #include "nsIPresShell.h"
      33             : #include "nsIPresShellInlines.h"
      34             : #include "nsLayoutUtils.h"
      35             : #include "nsRuleNode.h" // For nsRuleNode::ComputePropertiesOverridingAnimation
      36             : #include "nsRuleProcessorData.h" // For ElementRuleProcessorData etc.
      37             : #include "nsStyleContextInlines.h"
      38             : #include "nsTArray.h"
      39             : #include <bitset>
      40             : #include <initializer_list>
      41             : 
      42             : using mozilla::dom::Animation;
      43             : using mozilla::dom::Element;
      44             : using mozilla::dom::KeyframeEffectReadOnly;
      45             : 
      46             : namespace mozilla {
      47             : 
      48             : NS_IMPL_CYCLE_COLLECTION_CLASS(EffectCompositor)
      49             : 
      50           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(EffectCompositor)
      51           0 :   for (auto& elementSet : tmp->mElementsToRestyle) {
      52           0 :     elementSet.Clear();
      53             :   }
      54           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
      55             : 
      56           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(EffectCompositor)
      57           0 :   for (auto& elementSet : tmp->mElementsToRestyle) {
      58           0 :     for (auto iter = elementSet.Iter(); !iter.Done(); iter.Next()) {
      59           0 :       CycleCollectionNoteChild(cb, iter.Key().mElement,
      60             :                                "EffectCompositor::mElementsToRestyle[]",
      61           0 :                                cb.Flags());
      62             :     }
      63             :   }
      64           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
      65             : 
      66           0 : NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(EffectCompositor, AddRef)
      67           0 : NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(EffectCompositor, Release)
      68             : 
      69             : namespace {
      70             : enum class MatchForCompositor {
      71             :   // This animation matches and should run on the compositor if possible.
      72             :   Yes,
      73             :   // This (not currently playing) animation matches and can be run on the
      74             :   // compositor if there are other animations for this property that return
      75             :   // 'Yes'.
      76             :   IfNeeded,
      77             :   // This animation does not match or can't be run on the compositor.
      78             :   No,
      79             :   // This animation does not match or can't be run on the compositor and,
      80             :   // furthermore, its presence means we should not run any animations for this
      81             :   // property on the compositor.
      82             :   NoAndBlockThisProperty
      83             : };
      84             : }
      85             : 
      86             : static MatchForCompositor
      87           0 : IsMatchForCompositor(const KeyframeEffectReadOnly& aEffect,
      88             :                      nsCSSPropertyID aProperty,
      89             :                      const nsIFrame* aFrame)
      90             : {
      91           0 :   const Animation* animation = aEffect.GetAnimation();
      92           0 :   MOZ_ASSERT(animation);
      93             : 
      94           0 :   if (!animation->IsRelevant()) {
      95           0 :     return MatchForCompositor::No;
      96             :   }
      97             : 
      98             :   AnimationPerformanceWarning::Type warningType;
      99           0 :   if (animation->ShouldBeSynchronizedWithMainThread(aProperty, aFrame,
     100             :                                                     warningType)) {
     101             :     EffectCompositor::SetPerformanceWarning(
     102             :       aFrame, aProperty,
     103           0 :       AnimationPerformanceWarning(warningType));
     104             :     // For a given |aFrame|, we don't want some animations of |aProperty| to
     105             :     // run on the compositor and others to run on the main thread, so if any
     106             :     // need to be synchronized with the main thread, run them all there.
     107           0 :     return MatchForCompositor::NoAndBlockThisProperty;
     108             :   }
     109             : 
     110           0 :   if (!aEffect.HasEffectiveAnimationOfProperty(aProperty)) {
     111           0 :     return MatchForCompositor::No;
     112             :   }
     113             : 
     114           0 :   return animation->IsPlaying()
     115           0 :          ? MatchForCompositor::Yes
     116           0 :          : MatchForCompositor::IfNeeded;
     117             : }
     118             : 
     119             : // Helper function to factor out the common logic from
     120             : // GetAnimationsForCompositor and HasAnimationsForCompositor.
     121             : //
     122             : // Takes an optional array to fill with eligible animations.
     123             : //
     124             : // Returns true if there are eligible animations, false otherwise.
     125             : bool
     126         425 : FindAnimationsForCompositor(const nsIFrame* aFrame,
     127             :                             nsCSSPropertyID aProperty,
     128             :                             nsTArray<RefPtr<dom::Animation>>* aMatches /*out*/)
     129             : {
     130         425 :   MOZ_ASSERT(!aMatches || aMatches->IsEmpty(),
     131             :              "Matches array, if provided, should be empty");
     132             : 
     133         425 :   EffectSet* effects = EffectSet::GetEffectSet(aFrame);
     134         425 :   if (!effects || effects->IsEmpty()) {
     135         425 :     return false;
     136             :   }
     137             : 
     138             :   // First check for newly-started transform animations that should be
     139             :   // synchronized with geometric animations. We need to do this before any
     140             :   // other early returns (the one above is ok) since we can only check this
     141             :   // state when the animation is newly-started.
     142           0 :   if (aProperty == eCSSProperty_transform) {
     143             :     PendingAnimationTracker* tracker =
     144           0 :       aFrame->PresContext()->Document()->GetPendingAnimationTracker();
     145           0 :     if (tracker) {
     146           0 :       tracker->MarkAnimationsThatMightNeedSynchronization();
     147             :     }
     148             :   }
     149             : 
     150             :   // If the property will be added to the animations level of the cascade but
     151             :   // there is an !important rule for that property in the cascade then the
     152             :   // animation will not be applied since the !important rule overrides it.
     153           0 :   if (effects->PropertiesWithImportantRules().HasProperty(aProperty) &&
     154           0 :       effects->PropertiesForAnimationsLevel().HasProperty(aProperty)) {
     155           0 :     return false;
     156             :   }
     157             : 
     158           0 :   if (aFrame->RefusedAsyncAnimation()) {
     159           0 :     return false;
     160             :   }
     161             : 
     162             :   // The animation cascade will almost always be up-to-date by this point
     163             :   // but there are some cases such as when we are restoring the refresh driver
     164             :   // from test control after seeking where it might not be the case.
     165             :   //
     166             :   // Those cases are probably not important but just to be safe, let's make
     167             :   // sure the cascade is up to date since if it *is* up to date, this is
     168             :   // basically a no-op.
     169             :   Maybe<NonOwningAnimationTarget> pseudoElement =
     170           0 :     EffectCompositor::GetAnimationElementAndPseudoForFrame(aFrame);
     171           0 :   if (pseudoElement) {
     172             :     StyleBackendType backend =
     173           0 :       aFrame->StyleContext()->IsServo()
     174           0 :       ? StyleBackendType::Servo
     175           0 :       : StyleBackendType::Gecko;
     176           0 :     EffectCompositor::MaybeUpdateCascadeResults(backend,
     177           0 :                                                 pseudoElement->mElement,
     178           0 :                                                 pseudoElement->mPseudoType,
     179           0 :                                                 aFrame->StyleContext());
     180             :   }
     181             : 
     182           0 :   if (!nsLayoutUtils::AreAsyncAnimationsEnabled()) {
     183           0 :     if (nsLayoutUtils::IsAnimationLoggingEnabled()) {
     184           0 :       nsCString message;
     185             :       message.AppendLiteral("Performance warning: Async animations are "
     186           0 :                             "disabled");
     187           0 :       AnimationUtils::LogAsyncAnimationFailure(message);
     188             :     }
     189           0 :     return false;
     190             :   }
     191             : 
     192             :   // Disable async animations if we have a rendering observer that
     193             :   // depends on our content (svg masking, -moz-element etc) so that
     194             :   // it gets updated correctly.
     195           0 :   nsIContent* content = aFrame->GetContent();
     196           0 :   while (content) {
     197           0 :     if (content->HasRenderingObservers()) {
     198             :       EffectCompositor::SetPerformanceWarning(
     199             :         aFrame, aProperty,
     200           0 :         AnimationPerformanceWarning(
     201           0 :           AnimationPerformanceWarning::Type::HasRenderingObserver));
     202           0 :       return false;
     203             :     }
     204           0 :     content = content->GetParent();
     205             :   }
     206             : 
     207           0 :   bool foundRunningAnimations = false;
     208           0 :   for (KeyframeEffectReadOnly* effect : *effects) {
     209             :     MatchForCompositor matchResult =
     210           0 :       IsMatchForCompositor(*effect, aProperty, aFrame);
     211             : 
     212           0 :     if (matchResult == MatchForCompositor::NoAndBlockThisProperty) {
     213             :       // For a given |aFrame|, we don't want some animations of |aProperty| to
     214             :       // run on the compositor and others to run on the main thread, so if any
     215             :       // need to be synchronized with the main thread, run them all there.
     216           0 :       if (aMatches) {
     217           0 :         aMatches->Clear();
     218             :       }
     219           0 :       return false;
     220             :     }
     221             : 
     222           0 :     if (matchResult == MatchForCompositor::No) {
     223           0 :       continue;
     224             :     }
     225             : 
     226           0 :     if (aMatches) {
     227           0 :       aMatches->AppendElement(effect->GetAnimation());
     228             :     }
     229             : 
     230           0 :     if (matchResult == MatchForCompositor::Yes) {
     231           0 :       foundRunningAnimations = true;
     232             :     }
     233             :   }
     234             : 
     235             :   // If all animations we added were not currently playing animations, don't
     236             :   // send them to the compositor.
     237           0 :   if (aMatches && !foundRunningAnimations) {
     238           0 :     aMatches->Clear();
     239             :   }
     240             : 
     241           0 :   MOZ_ASSERT(!foundRunningAnimations || !aMatches || !aMatches->IsEmpty(),
     242             :              "If return value is true, matches array should be non-empty");
     243             : 
     244           0 :   if (aMatches && foundRunningAnimations) {
     245           0 :     aMatches->Sort(AnimationPtrComparator<RefPtr<dom::Animation>>());
     246             :   }
     247             : 
     248           0 :   return foundRunningAnimations;
     249             : }
     250             : 
     251             : void
     252           8 : EffectCompositor::RequestRestyle(dom::Element* aElement,
     253             :                                  CSSPseudoElementType aPseudoType,
     254             :                                  RestyleType aRestyleType,
     255             :                                  CascadeLevel aCascadeLevel)
     256             : {
     257           8 :   if (!mPresContext) {
     258             :     // Pres context will be null after the effect compositor is disconnected.
     259           0 :     return;
     260             :   }
     261             : 
     262             :   // Ignore animations on orphaned elements and elements in documents without
     263             :   // a pres shell (e.g. XMLHttpRequest responseXML documents).
     264           8 :   if (!nsComputedDOMStyle::GetPresShellForContent(aElement)) {
     265           0 :     return;
     266             :   }
     267             : 
     268           8 :   auto& elementsToRestyle = mElementsToRestyle[aCascadeLevel];
     269           8 :   PseudoElementHashEntry::KeyType key = { aElement, aPseudoType };
     270             : 
     271           8 :   if (aRestyleType == RestyleType::Throttled) {
     272           0 :     elementsToRestyle.LookupForAdd(key).OrInsert([]() { return false; });
     273           0 :     mPresContext->PresShell()->SetNeedThrottledAnimationFlush();
     274             :   } else {
     275             :     bool skipRestyle;
     276             :     // Update hashtable first in case PostRestyleForAnimation mutates it.
     277             :     // (It shouldn't, but just to be sure.)
     278          16 :     if (auto p = elementsToRestyle.LookupForAdd(key)) {
     279           2 :       skipRestyle = p.Data();
     280           2 :       p.Data() = true;
     281             :     } else {
     282           6 :       skipRestyle = false;
     283          12 :       p.OrInsert([]() { return true; });
     284             :     }
     285             : 
     286           8 :     if (!skipRestyle) {
     287           6 :       PostRestyleForAnimation(aElement, aPseudoType, aCascadeLevel);
     288             :     }
     289             :   }
     290             : 
     291           8 :   if (aRestyleType == RestyleType::Layer) {
     292           2 :     mPresContext->RestyleManager()->IncrementAnimationGeneration();
     293             :     EffectSet* effectSet =
     294           2 :       EffectSet::GetEffectSet(aElement, aPseudoType);
     295           2 :     if (effectSet) {
     296           0 :       effectSet->UpdateAnimationGeneration(mPresContext);
     297             :     }
     298             :   }
     299             : }
     300             : 
     301             : void
     302          16 : EffectCompositor::PostRestyleForAnimation(dom::Element* aElement,
     303             :                                           CSSPseudoElementType aPseudoType,
     304             :                                           CascadeLevel aCascadeLevel)
     305             : {
     306          16 :   if (!mPresContext) {
     307           0 :     return;
     308             :   }
     309             : 
     310          16 :   dom::Element* element = GetElementToRestyle(aElement, aPseudoType);
     311          16 :   if (!element) {
     312           0 :     return;
     313             :   }
     314             : 
     315          16 :   nsRestyleHint hint = aCascadeLevel == CascadeLevel::Transitions ?
     316             :                                         eRestyle_CSSTransitions :
     317          16 :                                         eRestyle_CSSAnimations;
     318             : 
     319          16 :   if (mPresContext->StyleSet()->IsServo()) {
     320           0 :     MOZ_ASSERT(NS_IsMainThread(),
     321             :                "Restyle request during restyling should be requested only on "
     322             :                "the main-thread. e.g. after the parallel traversal");
     323           0 :     if (ServoStyleSet::IsInServoTraversal() || mIsInPreTraverse) {
     324           0 :       MOZ_ASSERT(hint == eRestyle_CSSAnimations ||
     325             :                  hint == eRestyle_CSSTransitions);
     326             : 
     327             :       // We can't call Servo_NoteExplicitHints here since AtomicRefCell does not
     328             :       // allow us mutate ElementData of the |aElement| in SequentialTask.
     329             :       // Instead we call Servo_NoteExplicitHints for the element in PreTraverse()
     330             :       // which will be called right before the second traversal that we do for
     331             :       // updating CSS animations.
     332             :       // In that case PreTraverse() will return true so that we know to do the
     333             :       // second traversal so we don't need to post any restyle requests to the
     334             :       // PresShell.
     335           0 :       return;
     336             :     } else {
     337           0 :       MOZ_ASSERT(!mPresContext->RestyleManager()->IsInStyleRefresh());
     338             :     }
     339             :   }
     340          16 :   mPresContext->PresShell()->RestyleForAnimation(element, hint);
     341             : }
     342             : 
     343             : void
     344          67 : EffectCompositor::PostRestyleForThrottledAnimations()
     345             : {
     346         201 :   for (size_t i = 0; i < kCascadeLevelCount; i++) {
     347         134 :     CascadeLevel cascadeLevel = CascadeLevel(i);
     348         134 :     auto& elementSet = mElementsToRestyle[cascadeLevel];
     349             : 
     350         134 :     for (auto iter = elementSet.Iter(); !iter.Done(); iter.Next()) {
     351           0 :       bool& postedRestyle = iter.Data();
     352           0 :       if (postedRestyle) {
     353           0 :         continue;
     354             :       }
     355             : 
     356           0 :       PostRestyleForAnimation(iter.Key().mElement,
     357           0 :                               iter.Key().mPseudoType,
     358           0 :                               cascadeLevel);
     359           0 :       postedRestyle = true;
     360             :     }
     361             :   }
     362          67 : }
     363             : 
     364             : template<typename StyleType>
     365             : void
     366        2834 : EffectCompositor::UpdateEffectProperties(StyleType* aStyleType,
     367             :                                          Element* aElement,
     368             :                                          CSSPseudoElementType aPseudoType)
     369             : {
     370        2834 :   EffectSet* effectSet = EffectSet::GetEffectSet(aElement, aPseudoType);
     371        2834 :   if (!effectSet) {
     372        2828 :     return;
     373             :   }
     374             : 
     375             :   // Style context (Gecko) or computed values (Stylo) change might cause CSS
     376             :   // cascade level, e.g removing !important, so we should update the cascading
     377             :   // result.
     378           6 :   effectSet->MarkCascadeNeedsUpdate();
     379             : 
     380          12 :   for (KeyframeEffectReadOnly* effect : *effectSet) {
     381           6 :     effect->UpdateProperties(aStyleType);
     382             :   }
     383             : }
     384             : 
     385             : void
     386       10264 : EffectCompositor::MaybeUpdateAnimationRule(dom::Element* aElement,
     387             :                                            CSSPseudoElementType aPseudoType,
     388             :                                            CascadeLevel aCascadeLevel,
     389             :                                            nsStyleContext* aStyleContext)
     390             : {
     391             :   // First update cascade results since that may cause some elements to
     392             :   // be marked as needing a restyle.
     393             :   MaybeUpdateCascadeResults(StyleBackendType::Gecko,
     394             :                             aElement, aPseudoType,
     395       10264 :                             aStyleContext);
     396             : 
     397       10264 :   auto& elementsToRestyle = mElementsToRestyle[aCascadeLevel];
     398       10264 :   PseudoElementHashEntry::KeyType key = { aElement, aPseudoType };
     399             : 
     400       10264 :   if (!elementsToRestyle.Contains(key)) {
     401       10260 :     return;
     402             :   }
     403             : 
     404           4 :   ComposeAnimationRule(aElement, aPseudoType, aCascadeLevel);
     405             : 
     406           4 :   elementsToRestyle.Remove(key);
     407             : }
     408             : 
     409             : nsIStyleRule*
     410       10262 : EffectCompositor::GetAnimationRule(dom::Element* aElement,
     411             :                                    CSSPseudoElementType aPseudoType,
     412             :                                    CascadeLevel aCascadeLevel,
     413             :                                    nsStyleContext* aStyleContext)
     414             : {
     415             :   // NOTE: We need to be careful about early returns in this method where
     416             :   // we *don't* update mElementsToRestyle. When we get a call to
     417             :   // RequestRestyle that results in a call to PostRestyleForAnimation, we
     418             :   // will set a bool flag in mElementsToRestyle indicating that we've
     419             :   // called PostRestyleForAnimation so we don't need to call it again
     420             :   // until that restyle happens. During that restyle, if we arrive here
     421             :   // and *don't* update mElementsToRestyle we'll continue to skip calling
     422             :   // PostRestyleForAnimation from RequestRestyle.
     423             : 
     424       10262 :   if (!mPresContext || !mPresContext->IsDynamic()) {
     425             :     // For print or print preview, ignore animations.
     426           0 :     return nullptr;
     427             :   }
     428             : 
     429       10262 :   MOZ_ASSERT(mPresContext->RestyleManager()->IsGecko(),
     430             :              "stylo: Servo-backed style system should not be using "
     431             :              "EffectCompositor");
     432       10262 :   if (mPresContext->RestyleManager()->AsGecko()->SkipAnimationRules()) {
     433             :     // We don't need to worry about updating mElementsToRestyle in this case
     434             :     // since this is not the animation restyle we requested when we called
     435             :     // PostRestyleForAnimation (see comment at start of this method).
     436           8 :     return nullptr;
     437             :   }
     438             : 
     439       10254 :   MaybeUpdateAnimationRule(aElement, aPseudoType, aCascadeLevel, aStyleContext);
     440             : 
     441             : #ifdef DEBUG
     442             :   {
     443       10254 :     auto& elementsToRestyle = mElementsToRestyle[aCascadeLevel];
     444       10254 :     PseudoElementHashEntry::KeyType key = { aElement, aPseudoType };
     445       10254 :     MOZ_ASSERT(!elementsToRestyle.Contains(key),
     446             :                "Element should no longer require a restyle after its "
     447             :                "animation rule has been updated");
     448             :   }
     449             : #endif
     450             : 
     451       10254 :   EffectSet* effectSet = EffectSet::GetEffectSet(aElement, aPseudoType);
     452       10254 :   if (!effectSet) {
     453       10228 :     return nullptr;
     454             :   }
     455             : 
     456          26 :   return effectSet->AnimationRule(aCascadeLevel);
     457             : }
     458             : 
     459             : namespace {
     460             :   class EffectCompositeOrderComparator {
     461             :   public:
     462           0 :     bool Equals(const KeyframeEffectReadOnly* a,
     463             :                 const KeyframeEffectReadOnly* b) const
     464             :     {
     465           0 :       return a == b;
     466             :     }
     467             : 
     468           0 :     bool LessThan(const KeyframeEffectReadOnly* a,
     469             :                   const KeyframeEffectReadOnly* b) const
     470             :     {
     471           0 :       MOZ_ASSERT(a->GetAnimation() && b->GetAnimation());
     472           0 :       MOZ_ASSERT(
     473             :         Equals(a, b) ||
     474             :         a->GetAnimation()->HasLowerCompositeOrderThan(*b->GetAnimation()) !=
     475             :           b->GetAnimation()->HasLowerCompositeOrderThan(*a->GetAnimation()));
     476           0 :       return a->GetAnimation()->HasLowerCompositeOrderThan(*b->GetAnimation());
     477             :     }
     478             :   };
     479             : }
     480             : 
     481             : bool
     482           0 : EffectCompositor::GetServoAnimationRule(
     483             :   const dom::Element* aElement,
     484             :   CSSPseudoElementType aPseudoType,
     485             :   CascadeLevel aCascadeLevel,
     486             :   RawServoAnimationValueMapBorrowedMut aAnimationValues)
     487             : {
     488           0 :   MOZ_ASSERT(aAnimationValues);
     489           0 :   MOZ_ASSERT(mPresContext && mPresContext->IsDynamic(),
     490             :              "Should not be in print preview");
     491             :   // Gecko_GetAnimationRule should have already checked this
     492           0 :   MOZ_ASSERT(nsComputedDOMStyle::GetPresShellForContent(aElement),
     493             :              "Should not be trying to run animations on elements in documents"
     494             :              " without a pres shell (e.g. XMLHttpRequest documents)");
     495             : 
     496           0 :   EffectSet* effectSet = EffectSet::GetEffectSet(aElement, aPseudoType);
     497           0 :   if (!effectSet) {
     498           0 :     return false;
     499             :   }
     500             : 
     501             :   // Get a list of effects sorted by composite order.
     502           0 :   nsTArray<KeyframeEffectReadOnly*> sortedEffectList(effectSet->Count());
     503           0 :   for (KeyframeEffectReadOnly* effect : *effectSet) {
     504           0 :     sortedEffectList.AppendElement(effect);
     505             :   }
     506           0 :   sortedEffectList.Sort(EffectCompositeOrderComparator());
     507             : 
     508             :   // If multiple animations affect the same property, animations with higher
     509             :   // composite order (priority) override or add or animations with lower
     510             :   // priority.
     511             :   const nsCSSPropertyIDSet propertiesToSkip =
     512             :     aCascadeLevel == CascadeLevel::Animations
     513           0 :       ? effectSet->PropertiesForAnimationsLevel().Inverse()
     514           0 :       : effectSet->PropertiesForAnimationsLevel();
     515           0 :   for (KeyframeEffectReadOnly* effect : sortedEffectList) {
     516           0 :     effect->GetAnimation()->ComposeStyle(*aAnimationValues, propertiesToSkip);
     517             :   }
     518             : 
     519           0 :   MOZ_ASSERT(effectSet == EffectSet::GetEffectSet(aElement, aPseudoType),
     520             :              "EffectSet should not change while composing style");
     521             : 
     522           0 :   return true;
     523             : }
     524             : 
     525             : /* static */ dom::Element*
     526          26 : EffectCompositor::GetElementToRestyle(dom::Element* aElement,
     527             :                                       CSSPseudoElementType aPseudoType)
     528             : {
     529          26 :   if (aPseudoType == CSSPseudoElementType::NotPseudo) {
     530          26 :     return aElement;
     531             :   }
     532             : 
     533           0 :   if (aPseudoType == CSSPseudoElementType::before) {
     534           0 :     return nsLayoutUtils::GetBeforePseudo(aElement);
     535             :   }
     536             : 
     537           0 :   if (aPseudoType == CSSPseudoElementType::after) {
     538           0 :     return nsLayoutUtils::GetAfterPseudo(aElement);
     539             :   }
     540             : 
     541           0 :   NS_NOTREACHED("Should not try to get the element to restyle for a pseudo "
     542             :                 "other that :before or :after");
     543           0 :   return nullptr;
     544             : }
     545             : 
     546             : bool
     547          33 : EffectCompositor::HasPendingStyleUpdates() const
     548             : {
     549          98 :   for (auto& elementSet : mElementsToRestyle) {
     550          66 :     if (elementSet.Count()) {
     551           1 :       return true;
     552             :     }
     553             :   }
     554             : 
     555          32 :   return false;
     556             : }
     557             : 
     558             : bool
     559          72 : EffectCompositor::HasThrottledStyleUpdates() const
     560             : {
     561         216 :   for (auto& elementSet : mElementsToRestyle) {
     562         144 :     for (auto iter = elementSet.ConstIter(); !iter.Done(); iter.Next()) {
     563           0 :       if (!iter.Data()) {
     564           0 :         return true;
     565             :       }
     566             :     }
     567             :   }
     568             : 
     569          72 :   return false;
     570             : }
     571             : 
     572             : void
     573           1 : EffectCompositor::AddStyleUpdatesTo(RestyleTracker& aTracker)
     574             : {
     575           1 :   if (!mPresContext) {
     576           0 :     return;
     577             :   }
     578             : 
     579           3 :   for (size_t i = 0; i < kCascadeLevelCount; i++) {
     580           2 :     CascadeLevel cascadeLevel = CascadeLevel(i);
     581           2 :     auto& elementSet = mElementsToRestyle[cascadeLevel];
     582             : 
     583             :     // Copy the list of elements to restyle to a separate array that we can
     584             :     // iterate over. This is because we need to call MaybeUpdateCascadeResults
     585             :     // on each element, but doing that can mutate elementSet. In this case
     586             :     // it will only mutate the bool value associated with each element in the
     587             :     // set but even doing that will cause assertions in PLDHashTable to fail
     588             :     // if we are iterating over the hashtable at the same time.
     589             :     nsTArray<PseudoElementHashEntry::KeyType> elementsToRestyle(
     590           4 :       elementSet.Count());
     591           4 :     for (auto iter = elementSet.Iter(); !iter.Done(); iter.Next()) {
     592             :       // Skip animations on elements that have been orphaned since they
     593             :       // requested a restyle.
     594           2 :       if (iter.Key().mElement->IsInComposedDoc()) {
     595           2 :         elementsToRestyle.AppendElement(iter.Key());
     596             :       }
     597             :     }
     598             : 
     599           4 :     for (auto& pseudoElem : elementsToRestyle) {
     600           2 :       MaybeUpdateCascadeResults(StyleBackendType::Gecko,
     601             :                                 pseudoElem.mElement,
     602             :                                 pseudoElem.mPseudoType,
     603           2 :                                 nullptr);
     604             : 
     605           2 :       ComposeAnimationRule(pseudoElem.mElement,
     606             :                            pseudoElem.mPseudoType,
     607           2 :                            cascadeLevel);
     608             : 
     609             :       dom::Element* elementToRestyle =
     610           2 :         GetElementToRestyle(pseudoElem.mElement, pseudoElem.mPseudoType);
     611           2 :       if (elementToRestyle) {
     612           2 :         nsRestyleHint rshint = cascadeLevel == CascadeLevel::Transitions ?
     613             :                                eRestyle_CSSTransitions :
     614           2 :                                eRestyle_CSSAnimations;
     615           2 :         aTracker.AddPendingRestyle(elementToRestyle, rshint, nsChangeHint(0));
     616             :       }
     617             :     }
     618             : 
     619           2 :     elementSet.Clear();
     620             :     // Note: mElement pointers in elementsToRestyle might now dangle
     621             :   }
     622             : }
     623             : 
     624             : /* static */ bool
     625         425 : EffectCompositor::HasAnimationsForCompositor(const nsIFrame* aFrame,
     626             :                                              nsCSSPropertyID aProperty)
     627             : {
     628         425 :   return FindAnimationsForCompositor(aFrame, aProperty, nullptr);
     629             : }
     630             : 
     631             : /* static */ nsTArray<RefPtr<dom::Animation>>
     632           0 : EffectCompositor::GetAnimationsForCompositor(const nsIFrame* aFrame,
     633             :                                              nsCSSPropertyID aProperty)
     634             : {
     635           0 :   nsTArray<RefPtr<dom::Animation>> result;
     636             : 
     637             : #ifdef DEBUG
     638             :   bool foundSome =
     639             : #endif
     640           0 :     FindAnimationsForCompositor(aFrame, aProperty, &result);
     641           0 :   MOZ_ASSERT(!foundSome || !result.IsEmpty(),
     642             :              "If return value is true, matches array should be non-empty");
     643             : 
     644           0 :   return result;
     645             : }
     646             : 
     647             : /* static */ void
     648           2 : EffectCompositor::ClearIsRunningOnCompositor(const nsIFrame *aFrame,
     649             :                                              nsCSSPropertyID aProperty)
     650             : {
     651           2 :   EffectSet* effects = EffectSet::GetEffectSet(aFrame);
     652           2 :   if (!effects) {
     653           2 :     return;
     654             :   }
     655             : 
     656           0 :   for (KeyframeEffectReadOnly* effect : *effects) {
     657           0 :     effect->SetIsRunningOnCompositor(aProperty, false);
     658             :   }
     659             : }
     660             : 
     661             : /* static */ void
     662       10266 : EffectCompositor::MaybeUpdateCascadeResults(StyleBackendType aBackendType,
     663             :                                             Element* aElement,
     664             :                                             CSSPseudoElementType aPseudoType,
     665             :                                             nsStyleContext* aStyleContext)
     666             : {
     667       10266 :   EffectSet* effects = EffectSet::GetEffectSet(aElement, aPseudoType);
     668       10266 :   if (!effects || !effects->CascadeNeedsUpdate()) {
     669       10258 :     return;
     670             :   }
     671             : 
     672             :   UpdateCascadeResults(aBackendType, *effects, aElement, aPseudoType,
     673           8 :                        aStyleContext);
     674             : 
     675           8 :   MOZ_ASSERT(!effects->CascadeNeedsUpdate(), "Failed to update cascade state");
     676             : }
     677             : 
     678             : /* static */ Maybe<NonOwningAnimationTarget>
     679       12099 : EffectCompositor::GetAnimationElementAndPseudoForFrame(const nsIFrame* aFrame)
     680             : {
     681             :   // Always return the same object to benefit from return-value optimization.
     682       12099 :   Maybe<NonOwningAnimationTarget> result;
     683             : 
     684             :   CSSPseudoElementType pseudoType =
     685       12099 :     aFrame->StyleContext()->GetPseudoType();
     686             : 
     687       15286 :   if (pseudoType != CSSPseudoElementType::NotPseudo &&
     688        6209 :       pseudoType != CSSPseudoElementType::before &&
     689        3022 :       pseudoType != CSSPseudoElementType::after) {
     690        2774 :     return result;
     691             :   }
     692             : 
     693        9325 :   nsIContent* content = aFrame->GetContent();
     694        9325 :   if (!content) {
     695           0 :     return result;
     696             :   }
     697             : 
     698       18485 :   if (pseudoType == CSSPseudoElementType::before ||
     699        9160 :       pseudoType == CSSPseudoElementType::after) {
     700         413 :     content = content->GetParent();
     701         413 :     if (!content) {
     702           0 :       return result;
     703             :     }
     704             :   }
     705             : 
     706        9325 :   if (!content->IsElement()) {
     707           0 :     return result;
     708             :   }
     709             : 
     710        9325 :   result.emplace(content->AsElement(), pseudoType);
     711             : 
     712        9325 :   return result;
     713             : }
     714             : 
     715             : /* static */ void
     716           6 : EffectCompositor::ComposeAnimationRule(dom::Element* aElement,
     717             :                                        CSSPseudoElementType aPseudoType,
     718             :                                        CascadeLevel aCascadeLevel)
     719             : {
     720           6 :   EffectSet* effects = EffectSet::GetEffectSet(aElement, aPseudoType);
     721           6 :   if (!effects) {
     722           2 :     return;
     723             :   }
     724             : 
     725             :   // The caller is responsible for calling MaybeUpdateCascadeResults first.
     726           4 :   MOZ_ASSERT(!effects->CascadeNeedsUpdate(),
     727             :              "Animation cascade out of date when composing animation rule");
     728             : 
     729             :   // Get a list of effects sorted by composite order.
     730           8 :   nsTArray<KeyframeEffectReadOnly*> sortedEffectList(effects->Count());
     731           8 :   for (KeyframeEffectReadOnly* effect : *effects) {
     732           4 :     sortedEffectList.AppendElement(effect);
     733             :   }
     734           4 :   sortedEffectList.Sort(EffectCompositeOrderComparator());
     735             : 
     736           4 :   RefPtr<AnimValuesStyleRule>& animRule = effects->AnimationRule(aCascadeLevel);
     737           4 :   animRule = nullptr;
     738             : 
     739             :   // If multiple animations affect the same property, animations with higher
     740             :   // composite order (priority) override or add or animations with lower
     741             :   // priority except properties in propertiesToSkip.
     742             :   const nsCSSPropertyIDSet& propertiesToSkip =
     743             :     aCascadeLevel == CascadeLevel::Animations
     744           0 :     ? effects->PropertiesForAnimationsLevel().Inverse()
     745           4 :     : effects->PropertiesForAnimationsLevel();
     746           8 :   for (KeyframeEffectReadOnly* effect : sortedEffectList) {
     747           4 :     effect->GetAnimation()->WillComposeStyle();
     748           4 :     effect->GetAnimation()->ComposeStyle(animRule, propertiesToSkip);
     749             :   }
     750             : 
     751           4 :   MOZ_ASSERT(effects == EffectSet::GetEffectSet(aElement, aPseudoType),
     752             :              "EffectSet should not change while composing style");
     753             : }
     754             : 
     755             : /* static */ nsCSSPropertyIDSet
     756           8 : EffectCompositor::GetOverriddenProperties(StyleBackendType aBackendType,
     757             :                                           EffectSet& aEffectSet,
     758             :                                           Element* aElement,
     759             :                                           CSSPseudoElementType aPseudoType,
     760             :                                           nsStyleContext* aStyleContext)
     761             : {
     762           8 :   MOZ_ASSERT(aBackendType != StyleBackendType::Servo || aElement,
     763             :              "Should have an element to get style data from if we are using"
     764             :              " the Servo backend");
     765             : 
     766           8 :   nsCSSPropertyIDSet result;
     767             : 
     768           8 :   Element* elementToRestyle = GetElementToRestyle(aElement, aPseudoType);
     769           8 :   if (aBackendType == StyleBackendType::Gecko && !aStyleContext) {
     770           0 :     if (elementToRestyle) {
     771           0 :       nsIFrame* frame = elementToRestyle->GetPrimaryFrame();
     772           0 :       if (frame) {
     773           0 :         aStyleContext = frame->StyleContext();
     774             :       }
     775             :     }
     776             : 
     777           0 :     if (!aStyleContext) {
     778           0 :       return result;
     779           0 :     }
     780           8 :   } else if (aBackendType == StyleBackendType::Servo && !elementToRestyle) {
     781           0 :     return result;
     782             :   }
     783             : 
     784          16 :   AutoTArray<nsCSSPropertyID, LayerAnimationInfo::kRecords> propertiesToTrack;
     785             :   {
     786           8 :     nsCSSPropertyIDSet propertiesToTrackAsSet;
     787          16 :     for (KeyframeEffectReadOnly* effect : aEffectSet) {
     788          16 :       for (const AnimationProperty& property : effect->Properties()) {
     789          16 :         if (nsCSSProps::PropHasFlags(property.mProperty,
     790          16 :                                      CSS_PROPERTY_CAN_ANIMATE_ON_COMPOSITOR) &&
     791           8 :             !propertiesToTrackAsSet.HasProperty(property.mProperty)) {
     792           8 :           propertiesToTrackAsSet.AddProperty(property.mProperty);
     793           8 :           propertiesToTrack.AppendElement(property.mProperty);
     794             :         }
     795             :       }
     796             :       // Skip iterating over the rest of the effects if we've already
     797             :       // found all the compositor-animatable properties.
     798           8 :       if (propertiesToTrack.Length() == LayerAnimationInfo::kRecords) {
     799           0 :         break;
     800             :       }
     801             :     }
     802             :   }
     803             : 
     804           8 :   if (propertiesToTrack.IsEmpty()) {
     805           0 :     return result;
     806             :   }
     807             : 
     808           8 :   switch (aBackendType) {
     809             :     case StyleBackendType::Servo:
     810             :       Servo_GetProperties_Overriding_Animation(elementToRestyle,
     811             :                                                &propertiesToTrack,
     812           0 :                                                &result);
     813           0 :       break;
     814             :     case StyleBackendType::Gecko:
     815           8 :       nsRuleNode::ComputePropertiesOverridingAnimation(propertiesToTrack,
     816             :                                                        aStyleContext->AsGecko(),
     817           8 :                                                        result);
     818           8 :       break;
     819             : 
     820             :     default:
     821           0 :       MOZ_ASSERT_UNREACHABLE("Unsupported style backend");
     822             :   }
     823             : 
     824           8 :   return result;
     825             : }
     826             : 
     827             : /* static */ void
     828           8 : EffectCompositor::UpdateCascadeResults(StyleBackendType aBackendType,
     829             :                                        EffectSet& aEffectSet,
     830             :                                        Element* aElement,
     831             :                                        CSSPseudoElementType aPseudoType,
     832             :                                        nsStyleContext* aStyleContext)
     833             : {
     834           8 :   MOZ_ASSERT(EffectSet::GetEffectSet(aElement, aPseudoType) == &aEffectSet,
     835             :              "Effect set should correspond to the specified (pseudo-)element");
     836           8 :   if (aEffectSet.IsEmpty()) {
     837           0 :     aEffectSet.MarkCascadeUpdated();
     838           0 :     return;
     839             :   }
     840             : 
     841             :   // Get a list of effects sorted by composite order.
     842          16 :   nsTArray<KeyframeEffectReadOnly*> sortedEffectList(aEffectSet.Count());
     843          16 :   for (KeyframeEffectReadOnly* effect : aEffectSet) {
     844           8 :     sortedEffectList.AppendElement(effect);
     845             :   }
     846           8 :   sortedEffectList.Sort(EffectCompositeOrderComparator());
     847             : 
     848             :   // Get properties that override the *animations* level of the cascade.
     849             :   //
     850             :   // We only do this for properties that we can animate on the compositor
     851             :   // since we will apply other properties on the main thread where the usual
     852             :   // cascade applies.
     853             :   nsCSSPropertyIDSet overriddenProperties =
     854             :     GetOverriddenProperties(aBackendType,
     855             :                             aEffectSet,
     856             :                             aElement, aPseudoType,
     857           8 :                             aStyleContext);
     858             : 
     859             :   // Returns a bitset the represents which properties from
     860             :   // LayerAnimationInfo::sRecords are present in |aPropertySet|.
     861             :   auto compositorPropertiesInSet =
     862             :     [](nsCSSPropertyIDSet& aPropertySet) ->
     863          32 :       std::bitset<LayerAnimationInfo::kRecords> {
     864          32 :         std::bitset<LayerAnimationInfo::kRecords> result;
     865          96 :         for (size_t i = 0; i < LayerAnimationInfo::kRecords; i++) {
     866          64 :           if (aPropertySet.HasProperty(
     867          64 :                 LayerAnimationInfo::sRecords[i].mProperty)) {
     868           0 :             result.set(i);
     869             :           }
     870             :         }
     871          32 :       return result;
     872             :     };
     873             : 
     874             :   nsCSSPropertyIDSet& propertiesWithImportantRules =
     875           8 :     aEffectSet.PropertiesWithImportantRules();
     876             :   nsCSSPropertyIDSet& propertiesForAnimationsLevel =
     877           8 :     aEffectSet.PropertiesForAnimationsLevel();
     878             : 
     879             :   // Record which compositor-animatable properties were originally set so we can
     880             :   // compare for changes later.
     881             :   std::bitset<LayerAnimationInfo::kRecords>
     882             :     prevCompositorPropertiesWithImportantRules =
     883           8 :       compositorPropertiesInSet(propertiesWithImportantRules);
     884             :   std::bitset<LayerAnimationInfo::kRecords>
     885             :     prevCompositorPropertiesForAnimationsLevel =
     886           8 :       compositorPropertiesInSet(propertiesForAnimationsLevel);
     887             : 
     888           8 :   propertiesWithImportantRules.Empty();
     889           8 :   propertiesForAnimationsLevel.Empty();
     890             : 
     891           8 :   bool hasCompositorPropertiesForTransition = false;
     892             : 
     893          16 :   for (const KeyframeEffectReadOnly* effect : sortedEffectList) {
     894           8 :     MOZ_ASSERT(effect->GetAnimation(),
     895             :                "Effects on a target element should have an Animation");
     896           8 :     CascadeLevel cascadeLevel = effect->GetAnimation()->CascadeLevel();
     897             : 
     898          16 :     for (const AnimationProperty& prop : effect->Properties()) {
     899           8 :       if (overriddenProperties.HasProperty(prop.mProperty)) {
     900           0 :         propertiesWithImportantRules.AddProperty(prop.mProperty);
     901             :       }
     902           8 :       if (cascadeLevel == EffectCompositor::CascadeLevel::Animations) {
     903           0 :         propertiesForAnimationsLevel.AddProperty(prop.mProperty);
     904             :       }
     905             : 
     906          16 :       if (nsCSSProps::PropHasFlags(prop.mProperty,
     907           8 :                                    CSS_PROPERTY_CAN_ANIMATE_ON_COMPOSITOR) &&
     908             :           cascadeLevel == EffectCompositor::CascadeLevel::Transitions) {
     909           8 :         hasCompositorPropertiesForTransition = true;
     910             :       }
     911             :     }
     912             :   }
     913             : 
     914           8 :   aEffectSet.MarkCascadeUpdated();
     915             : 
     916           8 :   nsPresContext* presContext = nsContentUtils::GetContextForContent(aElement);
     917           8 :   if (!presContext) {
     918           0 :     return;
     919             :   }
     920             : 
     921             :   // If properties for compositor are newly overridden by !important rules, or
     922             :   // released from being overridden by !important rules, we need to update
     923             :   // layers for animations level because it's a trigger to send animations to
     924             :   // the compositor or pull animations back from the compositor.
     925          16 :   if (prevCompositorPropertiesWithImportantRules !=
     926          16 :         compositorPropertiesInSet(propertiesWithImportantRules)) {
     927             :     presContext->EffectCompositor()->
     928           0 :       RequestRestyle(aElement, aPseudoType,
     929             :                      EffectCompositor::RestyleType::Layer,
     930           0 :                      EffectCompositor::CascadeLevel::Animations);
     931             :   }
     932             :   // If we have transition properties for compositor and if the same propery
     933             :   // for animations level is newly added or removed, we need to update layers
     934             :   // for transitions level because composite order has been changed now.
     935          32 :   if (hasCompositorPropertiesForTransition &&
     936           8 :       prevCompositorPropertiesForAnimationsLevel !=
     937          24 :         compositorPropertiesInSet(propertiesForAnimationsLevel)) {
     938             :     presContext->EffectCompositor()->
     939           0 :       RequestRestyle(aElement, aPseudoType,
     940             :                      EffectCompositor::RestyleType::Layer,
     941           0 :                      EffectCompositor::CascadeLevel::Transitions);
     942             :   }
     943             : }
     944             : 
     945             : /* static */ void
     946          24 : EffectCompositor::SetPerformanceWarning(
     947             :   const nsIFrame *aFrame,
     948             :   nsCSSPropertyID aProperty,
     949             :   const AnimationPerformanceWarning& aWarning)
     950             : {
     951          24 :   EffectSet* effects = EffectSet::GetEffectSet(aFrame);
     952          24 :   if (!effects) {
     953          24 :     return;
     954             :   }
     955             : 
     956           0 :   for (KeyframeEffectReadOnly* effect : *effects) {
     957           0 :     effect->SetPerformanceWarning(aProperty, aWarning);
     958             :   }
     959             : }
     960             : 
     961             : bool
     962           0 : EffectCompositor::PreTraverse(AnimationRestyleType aRestyleType)
     963             : {
     964           0 :   return PreTraverseInSubtree(nullptr, aRestyleType);
     965             : }
     966             : 
     967             : bool
     968           0 : EffectCompositor::PreTraverseInSubtree(Element* aRoot,
     969             :                                        AnimationRestyleType aRestyleType)
     970             : {
     971           0 :   MOZ_ASSERT(NS_IsMainThread());
     972           0 :   MOZ_ASSERT(mPresContext->RestyleManager()->IsServo());
     973           0 :   MOZ_ASSERT(!aRoot || nsComputedDOMStyle::GetPresShellForContent(aRoot),
     974             :              "Traversal root, if provided, should be bound to a display "
     975             :              "document");
     976             : 
     977           0 :   AutoRestore<bool> guard(mIsInPreTraverse);
     978           0 :   mIsInPreTraverse = true;
     979             : 
     980             :   // We need to force flush all throttled animations if we also have
     981             :   // non-animation restyles (since we'll want the up-to-date animation style
     982             :   // when we go to process them so we can trigger transitions correctly), and
     983             :   // if we are currently flushing all throttled animation restyles.
     984             :   bool flushThrottledRestyles =
     985           0 :     (aRoot && aRoot->HasDirtyDescendantsForServo()) ||
     986           0 :     aRestyleType == AnimationRestyleType::Full;
     987             : 
     988             :   using ElementsToRestyleIterType =
     989             :     nsDataHashtable<PseudoElementHashEntry, bool>::Iterator;
     990             :   auto getNeededRestyleTarget = [&](const ElementsToRestyleIterType& aIter)
     991           0 :                                 -> NonOwningAnimationTarget {
     992           0 :     NonOwningAnimationTarget returnTarget;
     993             : 
     994             :     // If aIter.Data() is false, the element only requested a throttled
     995             :     // (skippable) restyle, so we can skip it if flushThrottledRestyles is not
     996             :     // true.
     997           0 :     if (!flushThrottledRestyles && !aIter.Data()) {
     998           0 :       return returnTarget;
     999             :     }
    1000             : 
    1001           0 :     const NonOwningAnimationTarget& target = aIter.Key();
    1002             : 
    1003             :     // Skip elements in documents without a pres shell. Normally we filter out
    1004             :     // such elements in RequestRestyle but it can happen that, after adding
    1005             :     // them to mElementsToRestyle, they are transferred to a different document.
    1006             :     //
    1007             :     // We will drop them from mElementsToRestyle at the end of the next full
    1008             :     // document restyle (at the end of this function) but for consistency with
    1009             :     // how we treat such elements in RequestRestyle, we just ignore them here.
    1010           0 :     if (!nsComputedDOMStyle::GetPresShellForContent(target.mElement)) {
    1011           0 :       return returnTarget;
    1012             :     }
    1013             : 
    1014             :     // Ignore restyles that aren't in the flattened tree subtree rooted at
    1015             :     // aRoot.
    1016           0 :     if (aRoot &&
    1017           0 :         !nsContentUtils::ContentIsFlattenedTreeDescendantOf(target.mElement,
    1018             :                                                             aRoot)) {
    1019           0 :       return returnTarget;
    1020             :     }
    1021             : 
    1022           0 :     returnTarget = target;
    1023           0 :     return returnTarget;
    1024           0 :   };
    1025             : 
    1026           0 :   bool foundElementsNeedingRestyle = false;
    1027             : 
    1028           0 :   nsTArray<NonOwningAnimationTarget> elementsWithCascadeUpdates;
    1029           0 :   for (size_t i = 0; i < kCascadeLevelCount; ++i) {
    1030           0 :     CascadeLevel cascadeLevel = CascadeLevel(i);
    1031           0 :     auto& elementSet = mElementsToRestyle[cascadeLevel];
    1032           0 :     for (auto iter = elementSet.Iter(); !iter.Done(); iter.Next()) {
    1033           0 :       const NonOwningAnimationTarget& target = getNeededRestyleTarget(iter);
    1034           0 :       if (!target.mElement) {
    1035           0 :         continue;
    1036             :       }
    1037             : 
    1038           0 :       EffectSet* effects = EffectSet::GetEffectSet(target.mElement,
    1039           0 :                                                    target.mPseudoType);
    1040           0 :       if (!effects || !effects->CascadeNeedsUpdate()) {
    1041           0 :         continue;
    1042             :       }
    1043             : 
    1044           0 :       elementsWithCascadeUpdates.AppendElement(target);
    1045             :     }
    1046             :   }
    1047             : 
    1048           0 :   for (const NonOwningAnimationTarget& target: elementsWithCascadeUpdates) {
    1049             :       MaybeUpdateCascadeResults(StyleBackendType::Servo,
    1050           0 :                                 target.mElement,
    1051           0 :                                 target.mPseudoType,
    1052           0 :                                 nullptr);
    1053             :   }
    1054           0 :   elementsWithCascadeUpdates.Clear();
    1055             : 
    1056           0 :   for (size_t i = 0; i < kCascadeLevelCount; ++i) {
    1057           0 :     CascadeLevel cascadeLevel = CascadeLevel(i);
    1058           0 :     auto& elementSet = mElementsToRestyle[cascadeLevel];
    1059           0 :     for (auto iter = elementSet.Iter(); !iter.Done(); iter.Next()) {
    1060           0 :       const NonOwningAnimationTarget& target = getNeededRestyleTarget(iter);
    1061           0 :       if (!target.mElement) {
    1062           0 :         continue;
    1063             :       }
    1064             : 
    1065             :       // We need to post restyle hints even if the target is not in EffectSet to
    1066             :       // ensure the final restyling for removed animations.
    1067             :       // We can't call PostRestyleEvent directly here since we are still in the
    1068             :       // middle of the servo traversal.
    1069           0 :       mPresContext->RestyleManager()->AsServo()->
    1070           0 :         PostRestyleEventForAnimations(target.mElement,
    1071           0 :                                       target.mPseudoType,
    1072             :                                       cascadeLevel == CascadeLevel::Transitions
    1073             :                                         ? eRestyle_CSSTransitions
    1074           0 :                                         : eRestyle_CSSAnimations);
    1075             : 
    1076           0 :       foundElementsNeedingRestyle = true;
    1077             : 
    1078           0 :       EffectSet* effects = EffectSet::GetEffectSet(target.mElement,
    1079           0 :                                                    target.mPseudoType);
    1080           0 :       if (!effects) {
    1081             :         // Drop EffectSets that have been destroyed.
    1082           0 :         iter.Remove();
    1083           0 :         continue;
    1084             :       }
    1085             : 
    1086           0 :       for (KeyframeEffectReadOnly* effect : *effects) {
    1087           0 :         effect->GetAnimation()->WillComposeStyle();
    1088             :       }
    1089             : 
    1090             :       // Remove the element from the list of elements to restyle since we are
    1091             :       // about to restyle it.
    1092           0 :       iter.Remove();
    1093             :     }
    1094             : 
    1095             :     // If this is a full document restyle, then unconditionally clear
    1096             :     // elementSet in case there are any elements that didn't match above
    1097             :     // because they were moved to a document without a pres shell after
    1098             :     // posting an animation restyle.
    1099           0 :     if (!aRoot && flushThrottledRestyles) {
    1100           0 :       elementSet.Clear();
    1101             :     }
    1102             :   }
    1103             : 
    1104           0 :   return foundElementsNeedingRestyle;
    1105             : }
    1106             : 
    1107             : bool
    1108           0 : EffectCompositor::PreTraverse(dom::Element* aElement,
    1109             :                               CSSPseudoElementType aPseudoType)
    1110             : {
    1111           0 :   MOZ_ASSERT(NS_IsMainThread());
    1112           0 :   MOZ_ASSERT(mPresContext->RestyleManager()->IsServo());
    1113             : 
    1114             :   // If |aElement|'s document does not have a pres shell, e.g. it is document
    1115             :   // without a browsing context such as we might get from an XMLHttpRequest, we
    1116             :   // should not run animations on it.
    1117           0 :   if (!nsComputedDOMStyle::GetPresShellForContent(aElement)) {
    1118           0 :     return false;
    1119             :   }
    1120             : 
    1121           0 :   bool found = false;
    1122           0 :   if (aPseudoType != CSSPseudoElementType::NotPseudo &&
    1123           0 :       aPseudoType != CSSPseudoElementType::before &&
    1124             :       aPseudoType != CSSPseudoElementType::after) {
    1125           0 :     return found;
    1126             :   }
    1127             : 
    1128           0 :   AutoRestore<bool> guard(mIsInPreTraverse);
    1129           0 :   mIsInPreTraverse = true;
    1130             : 
    1131           0 :   PseudoElementHashEntry::KeyType key = { aElement, aPseudoType };
    1132             : 
    1133             :   // We need to flush all throttled animation restyles too if we also have
    1134             :   // non-animation restyles (since we'll want the up-to-date animation style
    1135             :   // when we go to process them so we can trigger transitions correctly).
    1136           0 :   Element* elementToRestyle = GetElementToRestyle(aElement, aPseudoType);
    1137           0 :   bool flushThrottledRestyles = elementToRestyle &&
    1138           0 :                                 elementToRestyle->HasDirtyDescendantsForServo();
    1139             : 
    1140           0 :   for (size_t i = 0; i < kCascadeLevelCount; ++i) {
    1141           0 :     CascadeLevel cascadeLevel = CascadeLevel(i);
    1142           0 :     auto& elementSet = mElementsToRestyle[cascadeLevel];
    1143             : 
    1144             :     // Skip if we don't have a restyle, or if we only have a throttled
    1145             :     // (skippable) restyle and we're not required to flush throttled restyles.
    1146           0 :     bool hasUnthrottledRestyle = false;
    1147           0 :     if (!elementSet.Get(key, &hasUnthrottledRestyle) ||
    1148           0 :         (!flushThrottledRestyles && !hasUnthrottledRestyle)) {
    1149           0 :       continue;
    1150             :     }
    1151             : 
    1152           0 :     mPresContext->RestyleManager()->AsServo()->
    1153             :       PostRestyleEventForAnimations(aElement,
    1154             :                                     aPseudoType,
    1155             :                                     cascadeLevel == CascadeLevel::Transitions
    1156             :                                       ? eRestyle_CSSTransitions
    1157           0 :                                       : eRestyle_CSSAnimations);
    1158             : 
    1159           0 :     EffectSet* effects = EffectSet::GetEffectSet(aElement, aPseudoType);
    1160           0 :     if (effects) {
    1161             :       MaybeUpdateCascadeResults(StyleBackendType::Servo,
    1162             :                                 aElement, aPseudoType,
    1163           0 :                                 nullptr);
    1164             : 
    1165           0 :       for (KeyframeEffectReadOnly* effect : *effects) {
    1166           0 :         effect->GetAnimation()->WillComposeStyle();
    1167             :       }
    1168             :     }
    1169             : 
    1170           0 :     elementSet.Remove(key);
    1171           0 :     found = true;
    1172             :   }
    1173           0 :   return found;
    1174             : }
    1175             : 
    1176             : // ---------------------------------------------------------
    1177             : //
    1178             : // Nested class: AnimationStyleRuleProcessor
    1179             : //
    1180             : // ---------------------------------------------------------
    1181             : 
    1182         300 : NS_IMPL_ISUPPORTS(EffectCompositor::AnimationStyleRuleProcessor,
    1183             :                   nsIStyleRuleProcessor)
    1184             : 
    1185             : nsRestyleHint
    1186         102 : EffectCompositor::AnimationStyleRuleProcessor::HasStateDependentStyle(
    1187             :   StateRuleProcessorData* aData)
    1188             : {
    1189         102 :   return nsRestyleHint(0);
    1190             : }
    1191             : 
    1192             : nsRestyleHint
    1193           0 : EffectCompositor::AnimationStyleRuleProcessor::HasStateDependentStyle(
    1194             :   PseudoElementStateRuleProcessorData* aData)
    1195             : {
    1196           0 :   return nsRestyleHint(0);
    1197             : }
    1198             : 
    1199             : bool
    1200           4 : EffectCompositor::AnimationStyleRuleProcessor::HasDocumentStateDependentStyle(
    1201             :   StateRuleProcessorData* aData)
    1202             : {
    1203           4 :   return false;
    1204             : }
    1205             : 
    1206             : nsRestyleHint
    1207        1296 : EffectCompositor::AnimationStyleRuleProcessor::HasAttributeDependentStyle(
    1208             :                         AttributeRuleProcessorData* aData,
    1209             :                         RestyleHintData& aRestyleHintDataResult)
    1210             : {
    1211        1296 :   return nsRestyleHint(0);
    1212             : }
    1213             : 
    1214             : bool
    1215          42 : EffectCompositor::AnimationStyleRuleProcessor::MediumFeaturesChanged(
    1216             :   nsPresContext* aPresContext)
    1217             : {
    1218          42 :   return false;
    1219             : }
    1220             : 
    1221             : void
    1222        5002 : EffectCompositor::AnimationStyleRuleProcessor::RulesMatching(
    1223             :   ElementRuleProcessorData* aData)
    1224             : {
    1225             :   nsIStyleRule *rule =
    1226        5002 :     mCompositor->GetAnimationRule(aData->mElement,
    1227             :                                   CSSPseudoElementType::NotPseudo,
    1228             :                                   mCascadeLevel,
    1229        5002 :                                   nullptr);
    1230        5002 :   if (rule) {
    1231           6 :     aData->mRuleWalker->Forward(rule);
    1232           6 :     aData->mRuleWalker->CurrentNode()->SetIsAnimationRule();
    1233             :   }
    1234        5002 : }
    1235             : 
    1236             : void
    1237        2576 : EffectCompositor::AnimationStyleRuleProcessor::RulesMatching(
    1238             :   PseudoElementRuleProcessorData* aData)
    1239             : {
    1240        3992 :   if (aData->mPseudoType != CSSPseudoElementType::before &&
    1241        1416 :       aData->mPseudoType != CSSPseudoElementType::after) {
    1242         174 :     return;
    1243             :   }
    1244             : 
    1245             :   nsIStyleRule *rule =
    1246        2402 :     mCompositor->GetAnimationRule(aData->mElement,
    1247             :                                   aData->mPseudoType,
    1248             :                                   mCascadeLevel,
    1249        2402 :                                   nullptr);
    1250        2402 :   if (rule) {
    1251           0 :     aData->mRuleWalker->Forward(rule);
    1252           0 :     aData->mRuleWalker->CurrentNode()->SetIsAnimationRule();
    1253             :   }
    1254             : }
    1255             : 
    1256             : void
    1257         420 : EffectCompositor::AnimationStyleRuleProcessor::RulesMatching(
    1258             :   AnonBoxRuleProcessorData* aData)
    1259             : {
    1260         420 : }
    1261             : 
    1262             : #ifdef MOZ_XUL
    1263             : void
    1264           0 : EffectCompositor::AnimationStyleRuleProcessor::RulesMatching(
    1265             :   XULTreeRuleProcessorData* aData)
    1266             : {
    1267           0 : }
    1268             : #endif
    1269             : 
    1270             : size_t
    1271          42 : EffectCompositor::AnimationStyleRuleProcessor::SizeOfExcludingThis(
    1272             :   MallocSizeOf aMallocSizeOf) const
    1273             : {
    1274          42 :   return 0;
    1275             : }
    1276             : 
    1277             : size_t
    1278          42 : EffectCompositor::AnimationStyleRuleProcessor::SizeOfIncludingThis(
    1279             :   MallocSizeOf aMallocSizeOf) const
    1280             : {
    1281          42 :   return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
    1282             : }
    1283             : 
    1284             : template
    1285             : void
    1286             : EffectCompositor::UpdateEffectProperties(
    1287             :   nsStyleContext* aStyleContext,
    1288             :   Element* aElement,
    1289             :   CSSPseudoElementType aPseudoType);
    1290             : 
    1291             : template
    1292             : void
    1293             : EffectCompositor::UpdateEffectProperties(
    1294             :   const ServoComputedValues* aServoValues,
    1295             :   Element* aElement,
    1296             :   CSSPseudoElementType aPseudoType);
    1297             : 
    1298             : } // namespace mozilla

Generated by: LCOV version 1.13