1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/style/nsAnimationManager.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,265 @@ 1.4 +/* vim: set shiftwidth=2 tabstop=8 autoindent cindent expandtab: */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 +#ifndef nsAnimationManager_h_ 1.9 +#define nsAnimationManager_h_ 1.10 + 1.11 +#include "mozilla/Attributes.h" 1.12 +#include "mozilla/ContentEvents.h" 1.13 +#include "AnimationCommon.h" 1.14 +#include "nsCSSPseudoElements.h" 1.15 +#include "mozilla/MemoryReporting.h" 1.16 +#include "mozilla/TimeStamp.h" 1.17 + 1.18 +class nsCSSKeyframesRule; 1.19 +class nsStyleContext; 1.20 + 1.21 +namespace mozilla { 1.22 +namespace css { 1.23 +class Declaration; 1.24 +} 1.25 +} 1.26 + 1.27 +struct AnimationEventInfo { 1.28 + nsRefPtr<mozilla::dom::Element> mElement; 1.29 + mozilla::InternalAnimationEvent mEvent; 1.30 + 1.31 + AnimationEventInfo(mozilla::dom::Element *aElement, 1.32 + const nsString& aAnimationName, 1.33 + uint32_t aMessage, mozilla::TimeDuration aElapsedTime, 1.34 + const nsAString& aPseudoElement) 1.35 + : mElement(aElement), mEvent(true, aMessage) 1.36 + { 1.37 + // XXX Looks like nobody initialize WidgetEvent::time 1.38 + mEvent.animationName = aAnimationName; 1.39 + mEvent.elapsedTime = aElapsedTime.ToSeconds(); 1.40 + mEvent.pseudoElement = aPseudoElement; 1.41 + } 1.42 + 1.43 + // InternalAnimationEvent doesn't support copy-construction, so we need 1.44 + // to ourselves in order to work with nsTArray 1.45 + AnimationEventInfo(const AnimationEventInfo &aOther) 1.46 + : mElement(aOther.mElement), mEvent(true, aOther.mEvent.message) 1.47 + { 1.48 + mEvent.AssignAnimationEventData(aOther.mEvent, false); 1.49 + } 1.50 +}; 1.51 + 1.52 +typedef InfallibleTArray<AnimationEventInfo> EventArray; 1.53 + 1.54 +/** 1.55 + * Data about all of the animations running on an element. 1.56 + */ 1.57 +struct ElementAnimations MOZ_FINAL 1.58 + : public mozilla::css::CommonElementAnimationData 1.59 +{ 1.60 + typedef mozilla::TimeStamp TimeStamp; 1.61 + typedef mozilla::TimeDuration TimeDuration; 1.62 + 1.63 + ElementAnimations(mozilla::dom::Element *aElement, nsIAtom *aElementProperty, 1.64 + nsAnimationManager *aAnimationManager, TimeStamp aNow); 1.65 + 1.66 + // This function takes as input the start time, duration, and direction of an 1.67 + // animation and returns the position in the current iteration. Note that 1.68 + // this only works when we know that the animation is currently running. 1.69 + // This way of calling the function can be used from the compositor. Note 1.70 + // that if the animation has not started yet, has already ended, or is paused, 1.71 + // it should not be run from the compositor. When this function is called 1.72 + // from the main thread, we need the actual StyleAnimation* in order to 1.73 + // get correct animation-fill behavior and to fire animation events. 1.74 + // This function returns -1 for the position if the animation should not be 1.75 + // run (because it is not currently active and has no fill behavior), but 1.76 + // only does so if aAnimation is non-null; with a null aAnimation it is an 1.77 + // error to give aElapsedDuration < 0, and fill-forwards is assumed. 1.78 + // After calling GetPositionInIteration with non-null aAnimation and aEa, be 1.79 + // sure to call CheckNeedsRefresh on the animation manager afterwards. 1.80 + static double GetPositionInIteration(TimeDuration aElapsedDuration, 1.81 + TimeDuration aIterationDuration, 1.82 + double aIterationCount, 1.83 + uint32_t aDirection, 1.84 + mozilla::StyleAnimation* aAnimation = 1.85 + nullptr, 1.86 + ElementAnimations* aEa = nullptr, 1.87 + EventArray* aEventsToDispatch = nullptr); 1.88 + 1.89 + void EnsureStyleRuleFor(TimeStamp aRefreshTime, 1.90 + EventArray &aEventsToDispatch, 1.91 + bool aIsThrottled); 1.92 + 1.93 + bool IsForElement() const { // rather than for a pseudo-element 1.94 + return mElementProperty == nsGkAtoms::animationsProperty; 1.95 + } 1.96 + 1.97 + nsString PseudoElement() 1.98 + { 1.99 + return mElementProperty == nsGkAtoms::animationsProperty ? 1.100 + EmptyString() : 1.101 + mElementProperty == nsGkAtoms::animationsOfBeforeProperty ? 1.102 + NS_LITERAL_STRING("::before") : 1.103 + NS_LITERAL_STRING("::after"); 1.104 + } 1.105 + 1.106 + void PostRestyleForAnimation(nsPresContext *aPresContext) { 1.107 + nsRestyleHint styleHint = IsForElement() ? eRestyle_Self : eRestyle_Subtree; 1.108 + aPresContext->PresShell()->RestyleForAnimation(mElement, styleHint); 1.109 + } 1.110 + 1.111 + // If aFlags contains CanAnimate_AllowPartial, returns whether the 1.112 + // state of this element's animations at the current refresh driver 1.113 + // time contains animation data that can be done on the compositor 1.114 + // thread. (This is useful for determining whether a layer should be 1.115 + // active, or whether to send data to the layer.) 1.116 + // If aFlags does not contain CanAnimate_AllowPartial, returns whether 1.117 + // the state of this element's animations at the current refresh driver 1.118 + // time can be fully represented by data sent to the compositor. 1.119 + // (This is useful for determining whether throttle the animation 1.120 + // (suppress main-thread style updates).) 1.121 + // Note that when CanPerformOnCompositorThread returns true, it also, 1.122 + // as a side-effect, notifies the ActiveLayerTracker. FIXME: This 1.123 + // should probably move to the relevant callers. 1.124 + virtual bool CanPerformOnCompositorThread(CanAnimateFlags aFlags) const MOZ_OVERRIDE; 1.125 + 1.126 + virtual bool HasAnimationOfProperty(nsCSSProperty aProperty) const MOZ_OVERRIDE; 1.127 + 1.128 + // False when we know that our current style rule is valid 1.129 + // indefinitely into the future (because all of our animations are 1.130 + // either completed or paused). May be invalidated by a style change. 1.131 + bool mNeedsRefreshes; 1.132 + 1.133 + InfallibleTArray<mozilla::StyleAnimation> mAnimations; 1.134 +}; 1.135 + 1.136 +class nsAnimationManager MOZ_FINAL 1.137 + : public mozilla::css::CommonAnimationManager 1.138 +{ 1.139 +public: 1.140 + nsAnimationManager(nsPresContext *aPresContext) 1.141 + : mozilla::css::CommonAnimationManager(aPresContext) 1.142 + , mObservingRefreshDriver(false) 1.143 + { 1.144 + } 1.145 + 1.146 + static ElementAnimations* GetAnimationsForCompositor(nsIContent* aContent, 1.147 + nsCSSProperty aProperty) 1.148 + { 1.149 + if (!aContent->MayHaveAnimations()) 1.150 + return nullptr; 1.151 + ElementAnimations* animations = static_cast<ElementAnimations*>( 1.152 + aContent->GetProperty(nsGkAtoms::animationsProperty)); 1.153 + if (!animations) 1.154 + return nullptr; 1.155 + bool propertyMatches = animations->HasAnimationOfProperty(aProperty); 1.156 + return (propertyMatches && 1.157 + animations->CanPerformOnCompositorThread( 1.158 + mozilla::css::CommonElementAnimationData::CanAnimate_AllowPartial)) 1.159 + ? animations 1.160 + : nullptr; 1.161 + } 1.162 + 1.163 + // Returns true if aContent or any of its ancestors has an animation. 1.164 + static bool ContentOrAncestorHasAnimation(nsIContent* aContent) { 1.165 + do { 1.166 + if (aContent->GetProperty(nsGkAtoms::animationsProperty)) { 1.167 + return true; 1.168 + } 1.169 + } while ((aContent = aContent->GetParent())); 1.170 + 1.171 + return false; 1.172 + } 1.173 + 1.174 + void EnsureStyleRuleFor(ElementAnimations* aET); 1.175 + 1.176 + // nsIStyleRuleProcessor (parts) 1.177 + virtual void RulesMatching(ElementRuleProcessorData* aData) MOZ_OVERRIDE; 1.178 + virtual void RulesMatching(PseudoElementRuleProcessorData* aData) MOZ_OVERRIDE; 1.179 + virtual void RulesMatching(AnonBoxRuleProcessorData* aData) MOZ_OVERRIDE; 1.180 +#ifdef MOZ_XUL 1.181 + virtual void RulesMatching(XULTreeRuleProcessorData* aData) MOZ_OVERRIDE; 1.182 +#endif 1.183 + virtual size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) 1.184 + const MOZ_MUST_OVERRIDE MOZ_OVERRIDE; 1.185 + virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) 1.186 + const MOZ_MUST_OVERRIDE MOZ_OVERRIDE; 1.187 + 1.188 + // nsARefreshObserver 1.189 + virtual void WillRefresh(mozilla::TimeStamp aTime) MOZ_OVERRIDE; 1.190 + 1.191 + void FlushAnimations(FlushFlags aFlags); 1.192 + 1.193 + /** 1.194 + * Return the style rule that RulesMatching should add for 1.195 + * aStyleContext. This might be different from what RulesMatching 1.196 + * actually added during aStyleContext's construction because the 1.197 + * element's animation-name may have changed. (However, this does 1.198 + * return null during the non-animation restyling phase, as 1.199 + * RulesMatching does.) 1.200 + * 1.201 + * aStyleContext may be a style context for aElement or for its 1.202 + * :before or :after pseudo-element. 1.203 + */ 1.204 + nsIStyleRule* CheckAnimationRule(nsStyleContext* aStyleContext, 1.205 + mozilla::dom::Element* aElement); 1.206 + 1.207 + /** 1.208 + * Dispatch any pending events. We accumulate animationend and 1.209 + * animationiteration events only during refresh driver notifications 1.210 + * (and dispatch them at the end of such notifications), but we 1.211 + * accumulate animationstart events at other points when style 1.212 + * contexts are created. 1.213 + */ 1.214 + void DispatchEvents() { 1.215 + // Fast-path the common case: no events 1.216 + if (!mPendingEvents.IsEmpty()) { 1.217 + DoDispatchEvents(); 1.218 + } 1.219 + } 1.220 + 1.221 + ElementAnimations* GetElementAnimations(mozilla::dom::Element *aElement, 1.222 + nsCSSPseudoElements::Type aPseudoType, 1.223 + bool aCreateIfNeeded); 1.224 + 1.225 + // Updates styles on throttled animations. See note on nsTransitionManager 1.226 + void UpdateAllThrottledStyles(); 1.227 + 1.228 +protected: 1.229 + virtual void ElementDataRemoved() MOZ_OVERRIDE 1.230 + { 1.231 + CheckNeedsRefresh(); 1.232 + } 1.233 + virtual void AddElementData(mozilla::css::CommonElementAnimationData* aData) MOZ_OVERRIDE; 1.234 + 1.235 + /** 1.236 + * Check to see if we should stop or start observing the refresh driver 1.237 + */ 1.238 + void CheckNeedsRefresh(); 1.239 + 1.240 +private: 1.241 + void BuildAnimations(nsStyleContext* aStyleContext, 1.242 + InfallibleTArray<mozilla::StyleAnimation>& aAnimations); 1.243 + bool BuildSegment(InfallibleTArray<mozilla::AnimationPropertySegment>& 1.244 + aSegments, 1.245 + nsCSSProperty aProperty, const nsAnimation& aAnimation, 1.246 + float aFromKey, nsStyleContext* aFromContext, 1.247 + mozilla::css::Declaration* aFromDeclaration, 1.248 + float aToKey, nsStyleContext* aToContext); 1.249 + nsIStyleRule* GetAnimationRule(mozilla::dom::Element* aElement, 1.250 + nsCSSPseudoElements::Type aPseudoType); 1.251 + 1.252 + // Update the animated styles of an element and its descendants. 1.253 + // If the element has an animation, it is flushed back to its primary frame. 1.254 + // If the element does not have an animation, then its style is reparented. 1.255 + void UpdateThrottledStylesForSubtree(nsIContent* aContent, 1.256 + nsStyleContext* aParentStyle, 1.257 + nsStyleChangeList &aChangeList); 1.258 + void UpdateAllThrottledStylesInternal(); 1.259 + 1.260 + // The guts of DispatchEvents 1.261 + void DoDispatchEvents(); 1.262 + 1.263 + EventArray mPendingEvents; 1.264 + 1.265 + bool mObservingRefreshDriver; 1.266 +}; 1.267 + 1.268 +#endif /* !defined(nsAnimationManager_h_) */