EffectCompositor.h (11112B)
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 #ifndef mozilla_EffectCompositor_h 8 #define mozilla_EffectCompositor_h 9 10 #include "NonCustomCSSPropertyId.h" 11 #include "mozilla/AnimationPerformanceWarning.h" 12 #include "mozilla/AnimationTarget.h" 13 #include "mozilla/EnumeratedArray.h" 14 #include "mozilla/HashTable.h" 15 #include "mozilla/Maybe.h" 16 #include "mozilla/OwningNonNull.h" 17 #include "mozilla/PseudoElementHashEntry.h" 18 #include "mozilla/RefPtr.h" 19 #include "mozilla/ServoTypes.h" 20 #include "mozilla/dom/EndpointBehavior.h" 21 #include "nsCycleCollectionParticipant.h" 22 #include "nsTArray.h" 23 #include "nsTHashMap.h" 24 25 class nsCSSPropertyIDSet; 26 class nsAtom; 27 class nsIFrame; 28 class nsPresContext; 29 enum class DisplayItemType : uint8_t; 30 31 namespace mozilla { 32 33 class ComputedStyle; 34 class EffectSet; 35 class RestyleTracker; 36 struct StyleAnimationValue; 37 struct StyleAnimationValueMap; 38 struct AnimationProperty; 39 struct NonOwningAnimationTarget; 40 41 namespace dom { 42 class Animation; 43 class Element; 44 class KeyframeEffect; 45 } // namespace dom 46 47 class EffectCompositor { 48 public: 49 explicit EffectCompositor(nsPresContext* aPresContext) 50 : mPresContext(aPresContext) {} 51 52 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(EffectCompositor) 53 NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(EffectCompositor) 54 55 void Disconnect() { mPresContext = nullptr; } 56 57 // Animations can be applied at two different levels in the CSS cascade: 58 enum class CascadeLevel : uint32_t { 59 // The animations sheet (CSS animations, script-generated animations, 60 // and CSS transitions that are no longer tied to CSS markup) 61 Animations = 0, 62 // The transitions sheet (CSS transitions that are tied to CSS markup) 63 Transitions = 1 64 }; 65 // We don't define this as part of CascadeLevel as then we'd have to add 66 // explicit checks for the Count enum value everywhere CascadeLevel is used. 67 static const size_t kCascadeLevelCount = 68 static_cast<size_t>(CascadeLevel::Transitions) + 1; 69 70 // NOTE: This can return null after Disconnect(). 71 nsPresContext* PresContext() const { return mPresContext; } 72 73 enum class RestyleType { 74 // Animation style has changed but the compositor is applying the same 75 // change so we might be able to defer updating the main thread until it 76 // becomes necessary. 77 Throttled, 78 // Animation style has changed and needs to be updated on the main thread. 79 Standard, 80 // Animation style has changed and needs to be updated on the main thread 81 // as well as forcing animations on layers to be updated. 82 // This is needed in cases such as when an animation becomes paused or has 83 // its playback rate changed. In such cases, although the computed style 84 // and refresh driver time might not change, we still need to ensure the 85 // corresponding animations on layers are updated to reflect the new 86 // configuration of the animation. 87 Layer 88 }; 89 90 // Notifies the compositor that the animation rule for the specified 91 // (pseudo-)element at the specified cascade level needs to be updated. 92 // The specified steps taken to update the animation rule depend on 93 // |aRestyleType| whose values are described above. 94 void RequestRestyle(dom::Element* aElement, 95 const PseudoStyleRequest& aPseudoRequest, 96 RestyleType aRestyleType, CascadeLevel aCascadeLevel); 97 98 // Schedule an animation restyle. This is called automatically by 99 // RequestRestyle when necessary. However, it is exposed here since we also 100 // need to perform this step when triggering transitions *without* also 101 // invalidating the animation style rule (which RequestRestyle would do). 102 void PostRestyleForAnimation(dom::Element* aElement, 103 const PseudoStyleRequest& aPseudoRequest, 104 CascadeLevel aCascadeLevel); 105 106 // Posts an animation restyle for any elements whose animation style rule 107 // is out of date but for which an animation restyle has not yet been 108 // posted because updates on the main thread are throttled. 109 void PostRestyleForThrottledAnimations(); 110 111 // Called when computed style on the specified (pseudo-) element might 112 // have changed so that any context-sensitive values stored within 113 // animation effects (e.g. em-based endpoints used in keyframe effects) 114 // can be re-resolved to computed values. 115 void UpdateEffectProperties(const ComputedStyle* aStyle, 116 dom::Element* aElement, 117 const PseudoStyleRequest& aPseudoRequest); 118 119 // Get the animation rule for the appropriate level of the cascade for 120 // a (pseudo-)element. Called from the Servo side. 121 // 122 // The animation rule is stored in |StyleAnimationValueMap|. 123 // We need to be careful while doing any modification because it may cause 124 // some thread-safe issues. 125 bool GetServoAnimationRule(const dom::Element* aElement, 126 const PseudoStyleRequest& aPseudoRequest, 127 CascadeLevel aCascadeLevel, 128 StyleAnimationValueMap* aAnimationValues); 129 130 // A variant on GetServoAnimationRule that composes all the effects for an 131 // element up to and including |aEffect|. 132 // 133 // Note that |aEffect| might not be in the EffectSet since we can use this for 134 // committing the computed style of a removed Animation. 135 bool ComposeServoAnimationRuleForEffect( 136 dom::KeyframeEffect& aEffect, CascadeLevel aCascadeLevel, 137 StyleAnimationValueMap* aAnimationValues, 138 dom::EndpointBehavior aEndpointBehavior = 139 dom::EndpointBehavior::Exclusive); 140 141 bool HasPendingStyleUpdates() const; 142 143 static bool HasAnimationsForCompositor(const nsIFrame* aFrame, 144 DisplayItemType aType); 145 146 static nsTArray<RefPtr<dom::Animation>> GetAnimationsForCompositor( 147 const nsIFrame* aFrame, const nsCSSPropertyIDSet& aPropertySet); 148 149 static void ClearIsRunningOnCompositor(const nsIFrame* aFrame, 150 DisplayItemType aType); 151 152 // Update animation cascade results for the specified (pseudo-)element 153 // but only if we have marked the cascade as needing an update due a 154 // the change in the set of effects or a change in one of the effects' 155 // "in effect" state. 156 // 157 // This method does NOT detect if other styles that apply above the 158 // animation level of the cascade have changed. 159 static void MaybeUpdateCascadeResults( 160 dom::Element* aElement, const PseudoStyleRequest& aPseudoRequest); 161 162 // Update the mPropertiesWithImportantRules and 163 // mPropertiesForAnimationsLevel members of the given EffectSet, and also 164 // request any restyles required by changes to the cascade result. 165 // 166 // NOTE: This can be expensive so we should only call it if styles that apply 167 // above the animation level of the cascade might have changed. For all 168 // other cases we should call MaybeUpdateCascadeResults. 169 // 170 // This is typically reserved for internal callers but is public here since 171 // when we detect changes to the cascade on the Servo side we can't call 172 // MarkCascadeNeedsUpdate during the traversal so instead we call this as part 173 // of a follow-up sequential task. 174 static void UpdateCascadeResults(EffectSet& aEffectSet, 175 dom::Element* aElement, 176 const PseudoStyleRequest& aPseudoRequest); 177 178 // Helper to fetch the corresponding element and pseudo-type from a frame. 179 // 180 // For frames corresponding to pseudo-elements, the returned element is the 181 // element on which we store the animations (i.e. the EffectSet and/or 182 // AnimationCollection), *not* the generated content. 183 // 184 // For display:table content, which maintains a distinction between primary 185 // frame (table wrapper frame) and style frame (inner table frame), animations 186 // are stored on the content associated with the _style_ frame even though 187 // some (particularly transform-like animations) may be applied to the 188 // _primary_ frame. As a result, callers will typically want to pass the style 189 // frame to this function. 190 // 191 // Returns an empty result when a suitable element cannot be found including 192 // when the frame represents a pseudo-element on which we do not support 193 // animations. 194 static Maybe<NonOwningAnimationTarget> GetAnimationElementAndPseudoForFrame( 195 const nsIFrame* aFrame); 196 197 // Associates a performance warning with effects on |aFrame| that animate 198 // properties in |aPropertySet|. 199 static void SetPerformanceWarning( 200 const nsIFrame* aFrame, const nsCSSPropertyIDSet& aPropertySet, 201 const AnimationPerformanceWarning& aWarning); 202 203 // Do a bunch of stuff that we should avoid doing during the parallel 204 // traversal (e.g. changing member variables) for all elements that we expect 205 // to restyle on the next traversal. 206 // 207 // Returns true if there are elements needing a restyle for animation. 208 bool PreTraverse(ServoTraversalFlags aFlags); 209 210 // Similar to the above but for all elements in the subtree rooted 211 // at aElement. 212 bool PreTraverseInSubtree(ServoTraversalFlags aFlags, dom::Element* aRoot); 213 214 // Record a (pseudo-)element that may have animations that can be removed. 215 void NoteElementForReducing(const NonOwningAnimationTarget& aTarget); 216 217 bool NeedsReducing() const { return !mElementsToReduce.empty(); } 218 void ReduceAnimations(); 219 220 // Returns true if any type of compositor animations on |aFrame| allow 221 // runnning on the compositor. 222 // Sets the reason in |aWarning| if the result is false. 223 static bool AllowCompositorAnimationsOnFrame( 224 const nsIFrame* aFrame, 225 AnimationPerformanceWarning::Type& aWarning /* out */); 226 227 private: 228 ~EffectCompositor() = default; 229 230 // Get the properties in |aEffectSet| that we are able to animate on the 231 // compositor but which are also specified at a higher level in the cascade 232 // than the animations level. 233 static nsCSSPropertyIDSet GetOverriddenProperties( 234 EffectSet& aEffectSet, dom::Element* aElement, 235 const PseudoStyleRequest& aPseudoRequest); 236 237 static nsPresContext* GetPresContext(dom::Element* aElement); 238 239 nsPresContext* mPresContext; 240 241 // Elements with a pending animation restyle. The associated bool value is 242 // true if a pending animation restyle has also been dispatched. For 243 // animations that can be throttled, we will add an entry to the hashtable to 244 // indicate that the style rule on the element is out of date but without 245 // posting a restyle to update it. 246 EnumeratedArray<CascadeLevel, nsTHashMap<PseudoElementHashEntry, bool>, 247 kCascadeLevelCount> 248 mElementsToRestyle; 249 250 bool mIsInPreTraverse = false; 251 252 HashSet<OwningAnimationTarget> mElementsToReduce; 253 }; 254 255 } // namespace mozilla 256 257 #endif // mozilla_EffectCompositor_h