|
1 /* vim: set shiftwidth=2 tabstop=8 autoindent cindent expandtab: */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 #ifndef nsAnimationManager_h_ |
|
6 #define nsAnimationManager_h_ |
|
7 |
|
8 #include "mozilla/Attributes.h" |
|
9 #include "mozilla/ContentEvents.h" |
|
10 #include "AnimationCommon.h" |
|
11 #include "nsCSSPseudoElements.h" |
|
12 #include "mozilla/MemoryReporting.h" |
|
13 #include "mozilla/TimeStamp.h" |
|
14 |
|
15 class nsCSSKeyframesRule; |
|
16 class nsStyleContext; |
|
17 |
|
18 namespace mozilla { |
|
19 namespace css { |
|
20 class Declaration; |
|
21 } |
|
22 } |
|
23 |
|
24 struct AnimationEventInfo { |
|
25 nsRefPtr<mozilla::dom::Element> mElement; |
|
26 mozilla::InternalAnimationEvent mEvent; |
|
27 |
|
28 AnimationEventInfo(mozilla::dom::Element *aElement, |
|
29 const nsString& aAnimationName, |
|
30 uint32_t aMessage, mozilla::TimeDuration aElapsedTime, |
|
31 const nsAString& aPseudoElement) |
|
32 : mElement(aElement), mEvent(true, aMessage) |
|
33 { |
|
34 // XXX Looks like nobody initialize WidgetEvent::time |
|
35 mEvent.animationName = aAnimationName; |
|
36 mEvent.elapsedTime = aElapsedTime.ToSeconds(); |
|
37 mEvent.pseudoElement = aPseudoElement; |
|
38 } |
|
39 |
|
40 // InternalAnimationEvent doesn't support copy-construction, so we need |
|
41 // to ourselves in order to work with nsTArray |
|
42 AnimationEventInfo(const AnimationEventInfo &aOther) |
|
43 : mElement(aOther.mElement), mEvent(true, aOther.mEvent.message) |
|
44 { |
|
45 mEvent.AssignAnimationEventData(aOther.mEvent, false); |
|
46 } |
|
47 }; |
|
48 |
|
49 typedef InfallibleTArray<AnimationEventInfo> EventArray; |
|
50 |
|
51 /** |
|
52 * Data about all of the animations running on an element. |
|
53 */ |
|
54 struct ElementAnimations MOZ_FINAL |
|
55 : public mozilla::css::CommonElementAnimationData |
|
56 { |
|
57 typedef mozilla::TimeStamp TimeStamp; |
|
58 typedef mozilla::TimeDuration TimeDuration; |
|
59 |
|
60 ElementAnimations(mozilla::dom::Element *aElement, nsIAtom *aElementProperty, |
|
61 nsAnimationManager *aAnimationManager, TimeStamp aNow); |
|
62 |
|
63 // This function takes as input the start time, duration, and direction of an |
|
64 // animation and returns the position in the current iteration. Note that |
|
65 // this only works when we know that the animation is currently running. |
|
66 // This way of calling the function can be used from the compositor. Note |
|
67 // that if the animation has not started yet, has already ended, or is paused, |
|
68 // it should not be run from the compositor. When this function is called |
|
69 // from the main thread, we need the actual StyleAnimation* in order to |
|
70 // get correct animation-fill behavior and to fire animation events. |
|
71 // This function returns -1 for the position if the animation should not be |
|
72 // run (because it is not currently active and has no fill behavior), but |
|
73 // only does so if aAnimation is non-null; with a null aAnimation it is an |
|
74 // error to give aElapsedDuration < 0, and fill-forwards is assumed. |
|
75 // After calling GetPositionInIteration with non-null aAnimation and aEa, be |
|
76 // sure to call CheckNeedsRefresh on the animation manager afterwards. |
|
77 static double GetPositionInIteration(TimeDuration aElapsedDuration, |
|
78 TimeDuration aIterationDuration, |
|
79 double aIterationCount, |
|
80 uint32_t aDirection, |
|
81 mozilla::StyleAnimation* aAnimation = |
|
82 nullptr, |
|
83 ElementAnimations* aEa = nullptr, |
|
84 EventArray* aEventsToDispatch = nullptr); |
|
85 |
|
86 void EnsureStyleRuleFor(TimeStamp aRefreshTime, |
|
87 EventArray &aEventsToDispatch, |
|
88 bool aIsThrottled); |
|
89 |
|
90 bool IsForElement() const { // rather than for a pseudo-element |
|
91 return mElementProperty == nsGkAtoms::animationsProperty; |
|
92 } |
|
93 |
|
94 nsString PseudoElement() |
|
95 { |
|
96 return mElementProperty == nsGkAtoms::animationsProperty ? |
|
97 EmptyString() : |
|
98 mElementProperty == nsGkAtoms::animationsOfBeforeProperty ? |
|
99 NS_LITERAL_STRING("::before") : |
|
100 NS_LITERAL_STRING("::after"); |
|
101 } |
|
102 |
|
103 void PostRestyleForAnimation(nsPresContext *aPresContext) { |
|
104 nsRestyleHint styleHint = IsForElement() ? eRestyle_Self : eRestyle_Subtree; |
|
105 aPresContext->PresShell()->RestyleForAnimation(mElement, styleHint); |
|
106 } |
|
107 |
|
108 // If aFlags contains CanAnimate_AllowPartial, returns whether the |
|
109 // state of this element's animations at the current refresh driver |
|
110 // time contains animation data that can be done on the compositor |
|
111 // thread. (This is useful for determining whether a layer should be |
|
112 // active, or whether to send data to the layer.) |
|
113 // If aFlags does not contain CanAnimate_AllowPartial, returns whether |
|
114 // the state of this element's animations at the current refresh driver |
|
115 // time can be fully represented by data sent to the compositor. |
|
116 // (This is useful for determining whether throttle the animation |
|
117 // (suppress main-thread style updates).) |
|
118 // Note that when CanPerformOnCompositorThread returns true, it also, |
|
119 // as a side-effect, notifies the ActiveLayerTracker. FIXME: This |
|
120 // should probably move to the relevant callers. |
|
121 virtual bool CanPerformOnCompositorThread(CanAnimateFlags aFlags) const MOZ_OVERRIDE; |
|
122 |
|
123 virtual bool HasAnimationOfProperty(nsCSSProperty aProperty) const MOZ_OVERRIDE; |
|
124 |
|
125 // False when we know that our current style rule is valid |
|
126 // indefinitely into the future (because all of our animations are |
|
127 // either completed or paused). May be invalidated by a style change. |
|
128 bool mNeedsRefreshes; |
|
129 |
|
130 InfallibleTArray<mozilla::StyleAnimation> mAnimations; |
|
131 }; |
|
132 |
|
133 class nsAnimationManager MOZ_FINAL |
|
134 : public mozilla::css::CommonAnimationManager |
|
135 { |
|
136 public: |
|
137 nsAnimationManager(nsPresContext *aPresContext) |
|
138 : mozilla::css::CommonAnimationManager(aPresContext) |
|
139 , mObservingRefreshDriver(false) |
|
140 { |
|
141 } |
|
142 |
|
143 static ElementAnimations* GetAnimationsForCompositor(nsIContent* aContent, |
|
144 nsCSSProperty aProperty) |
|
145 { |
|
146 if (!aContent->MayHaveAnimations()) |
|
147 return nullptr; |
|
148 ElementAnimations* animations = static_cast<ElementAnimations*>( |
|
149 aContent->GetProperty(nsGkAtoms::animationsProperty)); |
|
150 if (!animations) |
|
151 return nullptr; |
|
152 bool propertyMatches = animations->HasAnimationOfProperty(aProperty); |
|
153 return (propertyMatches && |
|
154 animations->CanPerformOnCompositorThread( |
|
155 mozilla::css::CommonElementAnimationData::CanAnimate_AllowPartial)) |
|
156 ? animations |
|
157 : nullptr; |
|
158 } |
|
159 |
|
160 // Returns true if aContent or any of its ancestors has an animation. |
|
161 static bool ContentOrAncestorHasAnimation(nsIContent* aContent) { |
|
162 do { |
|
163 if (aContent->GetProperty(nsGkAtoms::animationsProperty)) { |
|
164 return true; |
|
165 } |
|
166 } while ((aContent = aContent->GetParent())); |
|
167 |
|
168 return false; |
|
169 } |
|
170 |
|
171 void EnsureStyleRuleFor(ElementAnimations* aET); |
|
172 |
|
173 // nsIStyleRuleProcessor (parts) |
|
174 virtual void RulesMatching(ElementRuleProcessorData* aData) MOZ_OVERRIDE; |
|
175 virtual void RulesMatching(PseudoElementRuleProcessorData* aData) MOZ_OVERRIDE; |
|
176 virtual void RulesMatching(AnonBoxRuleProcessorData* aData) MOZ_OVERRIDE; |
|
177 #ifdef MOZ_XUL |
|
178 virtual void RulesMatching(XULTreeRuleProcessorData* aData) MOZ_OVERRIDE; |
|
179 #endif |
|
180 virtual size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) |
|
181 const MOZ_MUST_OVERRIDE MOZ_OVERRIDE; |
|
182 virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) |
|
183 const MOZ_MUST_OVERRIDE MOZ_OVERRIDE; |
|
184 |
|
185 // nsARefreshObserver |
|
186 virtual void WillRefresh(mozilla::TimeStamp aTime) MOZ_OVERRIDE; |
|
187 |
|
188 void FlushAnimations(FlushFlags aFlags); |
|
189 |
|
190 /** |
|
191 * Return the style rule that RulesMatching should add for |
|
192 * aStyleContext. This might be different from what RulesMatching |
|
193 * actually added during aStyleContext's construction because the |
|
194 * element's animation-name may have changed. (However, this does |
|
195 * return null during the non-animation restyling phase, as |
|
196 * RulesMatching does.) |
|
197 * |
|
198 * aStyleContext may be a style context for aElement or for its |
|
199 * :before or :after pseudo-element. |
|
200 */ |
|
201 nsIStyleRule* CheckAnimationRule(nsStyleContext* aStyleContext, |
|
202 mozilla::dom::Element* aElement); |
|
203 |
|
204 /** |
|
205 * Dispatch any pending events. We accumulate animationend and |
|
206 * animationiteration events only during refresh driver notifications |
|
207 * (and dispatch them at the end of such notifications), but we |
|
208 * accumulate animationstart events at other points when style |
|
209 * contexts are created. |
|
210 */ |
|
211 void DispatchEvents() { |
|
212 // Fast-path the common case: no events |
|
213 if (!mPendingEvents.IsEmpty()) { |
|
214 DoDispatchEvents(); |
|
215 } |
|
216 } |
|
217 |
|
218 ElementAnimations* GetElementAnimations(mozilla::dom::Element *aElement, |
|
219 nsCSSPseudoElements::Type aPseudoType, |
|
220 bool aCreateIfNeeded); |
|
221 |
|
222 // Updates styles on throttled animations. See note on nsTransitionManager |
|
223 void UpdateAllThrottledStyles(); |
|
224 |
|
225 protected: |
|
226 virtual void ElementDataRemoved() MOZ_OVERRIDE |
|
227 { |
|
228 CheckNeedsRefresh(); |
|
229 } |
|
230 virtual void AddElementData(mozilla::css::CommonElementAnimationData* aData) MOZ_OVERRIDE; |
|
231 |
|
232 /** |
|
233 * Check to see if we should stop or start observing the refresh driver |
|
234 */ |
|
235 void CheckNeedsRefresh(); |
|
236 |
|
237 private: |
|
238 void BuildAnimations(nsStyleContext* aStyleContext, |
|
239 InfallibleTArray<mozilla::StyleAnimation>& aAnimations); |
|
240 bool BuildSegment(InfallibleTArray<mozilla::AnimationPropertySegment>& |
|
241 aSegments, |
|
242 nsCSSProperty aProperty, const nsAnimation& aAnimation, |
|
243 float aFromKey, nsStyleContext* aFromContext, |
|
244 mozilla::css::Declaration* aFromDeclaration, |
|
245 float aToKey, nsStyleContext* aToContext); |
|
246 nsIStyleRule* GetAnimationRule(mozilla::dom::Element* aElement, |
|
247 nsCSSPseudoElements::Type aPseudoType); |
|
248 |
|
249 // Update the animated styles of an element and its descendants. |
|
250 // If the element has an animation, it is flushed back to its primary frame. |
|
251 // If the element does not have an animation, then its style is reparented. |
|
252 void UpdateThrottledStylesForSubtree(nsIContent* aContent, |
|
253 nsStyleContext* aParentStyle, |
|
254 nsStyleChangeList &aChangeList); |
|
255 void UpdateAllThrottledStylesInternal(); |
|
256 |
|
257 // The guts of DispatchEvents |
|
258 void DoDispatchEvents(); |
|
259 |
|
260 EventArray mPendingEvents; |
|
261 |
|
262 bool mObservingRefreshDriver; |
|
263 }; |
|
264 |
|
265 #endif /* !defined(nsAnimationManager_h_) */ |