|
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 |
|
6 #ifndef mozilla_css_AnimationCommon_h |
|
7 #define mozilla_css_AnimationCommon_h |
|
8 |
|
9 #include "nsIStyleRuleProcessor.h" |
|
10 #include "nsIStyleRule.h" |
|
11 #include "nsRefreshDriver.h" |
|
12 #include "prclist.h" |
|
13 #include "nsStyleAnimation.h" |
|
14 #include "nsCSSProperty.h" |
|
15 #include "mozilla/MemoryReporting.h" |
|
16 #include "mozilla/dom/Element.h" |
|
17 #include "nsSMILKeySpline.h" |
|
18 #include "nsStyleStruct.h" |
|
19 #include "mozilla/Attributes.h" |
|
20 #include "nsCSSPseudoElements.h" |
|
21 |
|
22 class nsPresContext; |
|
23 class nsIFrame; |
|
24 |
|
25 |
|
26 namespace mozilla { |
|
27 namespace css { |
|
28 |
|
29 bool IsGeometricProperty(nsCSSProperty aProperty); |
|
30 |
|
31 struct CommonElementAnimationData; |
|
32 |
|
33 class CommonAnimationManager : public nsIStyleRuleProcessor, |
|
34 public nsARefreshObserver { |
|
35 public: |
|
36 CommonAnimationManager(nsPresContext *aPresContext); |
|
37 virtual ~CommonAnimationManager(); |
|
38 |
|
39 // nsISupports |
|
40 NS_DECL_ISUPPORTS |
|
41 |
|
42 // nsIStyleRuleProcessor (parts) |
|
43 virtual nsRestyleHint HasStateDependentStyle(StateRuleProcessorData* aData) MOZ_OVERRIDE; |
|
44 virtual nsRestyleHint HasStateDependentStyle(PseudoElementStateRuleProcessorData* aData) MOZ_OVERRIDE; |
|
45 virtual bool HasDocumentStateDependentStyle(StateRuleProcessorData* aData) MOZ_OVERRIDE; |
|
46 virtual nsRestyleHint |
|
47 HasAttributeDependentStyle(AttributeRuleProcessorData* aData) MOZ_OVERRIDE; |
|
48 virtual bool MediumFeaturesChanged(nsPresContext* aPresContext) MOZ_OVERRIDE; |
|
49 virtual size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) |
|
50 const MOZ_MUST_OVERRIDE MOZ_OVERRIDE; |
|
51 virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) |
|
52 const MOZ_MUST_OVERRIDE MOZ_OVERRIDE; |
|
53 |
|
54 /** |
|
55 * Notify the manager that the pres context is going away. |
|
56 */ |
|
57 void Disconnect(); |
|
58 |
|
59 enum FlushFlags { |
|
60 Can_Throttle, |
|
61 Cannot_Throttle |
|
62 }; |
|
63 |
|
64 static bool ExtractComputedValueForTransition( |
|
65 nsCSSProperty aProperty, |
|
66 nsStyleContext* aStyleContext, |
|
67 nsStyleAnimation::Value& aComputedValue); |
|
68 protected: |
|
69 friend struct CommonElementAnimationData; // for ElementDataRemoved |
|
70 |
|
71 virtual void AddElementData(CommonElementAnimationData* aData) = 0; |
|
72 virtual void ElementDataRemoved() = 0; |
|
73 void RemoveAllElementData(); |
|
74 |
|
75 // Update the style on aElement from the transition stored in this manager and |
|
76 // the new parent style - aParentStyle. aElement must be transitioning or |
|
77 // animated. Returns the updated style. |
|
78 nsStyleContext* UpdateThrottledStyle(mozilla::dom::Element* aElement, |
|
79 nsStyleContext* aParentStyle, |
|
80 nsStyleChangeList &aChangeList); |
|
81 // Reparent the style of aContent and any :before and :after pseudo-elements. |
|
82 already_AddRefed<nsStyleContext> ReparentContent(nsIContent* aContent, |
|
83 nsStyleContext* aParentStyle); |
|
84 // reparent :before and :after pseudo elements of aElement |
|
85 static void ReparentBeforeAndAfter(dom::Element* aElement, |
|
86 nsIFrame* aPrimaryFrame, |
|
87 nsStyleContext* aNewStyle, |
|
88 nsStyleSet* aStyleSet); |
|
89 |
|
90 PRCList mElementData; |
|
91 nsPresContext *mPresContext; // weak (non-null from ctor to Disconnect) |
|
92 }; |
|
93 |
|
94 // The internals of UpdateAllThrottledStyles, used by nsAnimationManager and |
|
95 // nsTransitionManager, see the comments in the declaration of the latter. |
|
96 #define IMPL_UPDATE_ALL_THROTTLED_STYLES_INTERNAL(class_, animations_getter_) \ |
|
97 void \ |
|
98 class_::UpdateAllThrottledStylesInternal() \ |
|
99 { \ |
|
100 TimeStamp now = mPresContext->RefreshDriver()->MostRecentRefresh(); \ |
|
101 \ |
|
102 nsStyleChangeList changeList; \ |
|
103 \ |
|
104 /* update each transitioning element by finding its root-most ancestor |
|
105 with a transition, and flushing the style on that ancestor and all |
|
106 its descendants*/ \ |
|
107 PRCList *next = PR_LIST_HEAD(&mElementData); \ |
|
108 while (next != &mElementData) { \ |
|
109 CommonElementAnimationData* ea = \ |
|
110 static_cast<CommonElementAnimationData*>(next); \ |
|
111 next = PR_NEXT_LINK(next); \ |
|
112 \ |
|
113 if (ea->mFlushGeneration == now) { \ |
|
114 /* this element has been ticked already */ \ |
|
115 continue; \ |
|
116 } \ |
|
117 \ |
|
118 /* element is initialised to the starting element (i.e., one we know has |
|
119 an animation) and ends up with the root-most animated ancestor, |
|
120 that is, the element where we begin updates. */ \ |
|
121 dom::Element* element = ea->mElement; \ |
|
122 /* make a list of ancestors */ \ |
|
123 nsTArray<dom::Element*> ancestors; \ |
|
124 do { \ |
|
125 ancestors.AppendElement(element); \ |
|
126 } while ((element = element->GetParentElement())); \ |
|
127 \ |
|
128 /* walk down the ancestors until we find one with a throttled transition */\ |
|
129 for (int32_t i = ancestors.Length() - 1; i >= 0; --i) { \ |
|
130 if (animations_getter_(ancestors[i], \ |
|
131 nsCSSPseudoElements::ePseudo_NotPseudoElement, \ |
|
132 false)) { \ |
|
133 element = ancestors[i]; \ |
|
134 break; \ |
|
135 } \ |
|
136 } \ |
|
137 \ |
|
138 nsIFrame* primaryFrame; \ |
|
139 if (element && \ |
|
140 (primaryFrame = nsLayoutUtils::GetStyleFrame(element))) { \ |
|
141 UpdateThrottledStylesForSubtree(element, \ |
|
142 primaryFrame->StyleContext()->GetParent(), changeList); \ |
|
143 } \ |
|
144 } \ |
|
145 \ |
|
146 RestyleManager* restyleManager = mPresContext->RestyleManager(); \ |
|
147 restyleManager->ProcessRestyledFrames(changeList); \ |
|
148 restyleManager->FlushOverflowChangedTracker(); \ |
|
149 } |
|
150 |
|
151 /** |
|
152 * A style rule that maps property-nsStyleAnimation::Value pairs. |
|
153 */ |
|
154 class AnimValuesStyleRule MOZ_FINAL : public nsIStyleRule |
|
155 { |
|
156 public: |
|
157 // nsISupports implementation |
|
158 NS_DECL_ISUPPORTS |
|
159 |
|
160 // nsIStyleRule implementation |
|
161 virtual void MapRuleInfoInto(nsRuleData* aRuleData) MOZ_OVERRIDE; |
|
162 #ifdef DEBUG |
|
163 virtual void List(FILE* out = stdout, int32_t aIndent = 0) const MOZ_OVERRIDE; |
|
164 #endif |
|
165 |
|
166 void AddValue(nsCSSProperty aProperty, nsStyleAnimation::Value &aStartValue) |
|
167 { |
|
168 PropertyValuePair v = { aProperty, aStartValue }; |
|
169 mPropertyValuePairs.AppendElement(v); |
|
170 } |
|
171 |
|
172 // Caller must fill in returned value. |
|
173 nsStyleAnimation::Value* AddEmptyValue(nsCSSProperty aProperty) |
|
174 { |
|
175 PropertyValuePair *p = mPropertyValuePairs.AppendElement(); |
|
176 p->mProperty = aProperty; |
|
177 return &p->mValue; |
|
178 } |
|
179 |
|
180 struct PropertyValuePair { |
|
181 nsCSSProperty mProperty; |
|
182 nsStyleAnimation::Value mValue; |
|
183 }; |
|
184 |
|
185 private: |
|
186 InfallibleTArray<PropertyValuePair> mPropertyValuePairs; |
|
187 }; |
|
188 |
|
189 class ComputedTimingFunction { |
|
190 public: |
|
191 typedef nsTimingFunction::Type Type; |
|
192 void Init(const nsTimingFunction &aFunction); |
|
193 double GetValue(double aPortion) const; |
|
194 const nsSMILKeySpline* GetFunction() const { |
|
195 NS_ASSERTION(mType == nsTimingFunction::Function, "Type mismatch"); |
|
196 return &mTimingFunction; |
|
197 } |
|
198 Type GetType() const { return mType; } |
|
199 uint32_t GetSteps() const { return mSteps; } |
|
200 private: |
|
201 Type mType; |
|
202 nsSMILKeySpline mTimingFunction; |
|
203 uint32_t mSteps; |
|
204 }; |
|
205 |
|
206 } /* end css sub-namespace */ |
|
207 |
|
208 struct AnimationPropertySegment |
|
209 { |
|
210 float mFromKey, mToKey; |
|
211 nsStyleAnimation::Value mFromValue, mToValue; |
|
212 mozilla::css::ComputedTimingFunction mTimingFunction; |
|
213 }; |
|
214 |
|
215 struct AnimationProperty |
|
216 { |
|
217 nsCSSProperty mProperty; |
|
218 InfallibleTArray<AnimationPropertySegment> mSegments; |
|
219 }; |
|
220 |
|
221 /** |
|
222 * Data about one animation (i.e., one of the values of |
|
223 * 'animation-name') running on an element. |
|
224 */ |
|
225 struct StyleAnimation |
|
226 { |
|
227 StyleAnimation() |
|
228 : mIsRunningOnCompositor(false) |
|
229 , mLastNotification(LAST_NOTIFICATION_NONE) |
|
230 { |
|
231 } |
|
232 |
|
233 nsString mName; // empty string for 'none' |
|
234 float mIterationCount; // NS_IEEEPositiveInfinity() means infinite |
|
235 uint8_t mDirection; |
|
236 uint8_t mFillMode; |
|
237 uint8_t mPlayState; |
|
238 |
|
239 bool FillsForwards() const { |
|
240 return mFillMode == NS_STYLE_ANIMATION_FILL_MODE_BOTH || |
|
241 mFillMode == NS_STYLE_ANIMATION_FILL_MODE_FORWARDS; |
|
242 } |
|
243 bool FillsBackwards() const { |
|
244 return mFillMode == NS_STYLE_ANIMATION_FILL_MODE_BOTH || |
|
245 mFillMode == NS_STYLE_ANIMATION_FILL_MODE_BACKWARDS; |
|
246 } |
|
247 |
|
248 bool IsPaused() const { |
|
249 return mPlayState == NS_STYLE_ANIMATION_PLAY_STATE_PAUSED; |
|
250 } |
|
251 |
|
252 bool HasAnimationOfProperty(nsCSSProperty aProperty) const; |
|
253 bool IsRunningAt(mozilla::TimeStamp aTime) const; |
|
254 |
|
255 // Return the duration, at aTime (or, if paused, mPauseStart), since |
|
256 // the *end* of the delay period. May be negative. |
|
257 mozilla::TimeDuration ElapsedDurationAt(mozilla::TimeStamp aTime) const { |
|
258 NS_ABORT_IF_FALSE(!IsPaused() || aTime >= mPauseStart, |
|
259 "if paused, aTime must be at least mPauseStart"); |
|
260 return (IsPaused() ? mPauseStart : aTime) - mStartTime - mDelay; |
|
261 } |
|
262 |
|
263 // The beginning of the delay period. This is also used by |
|
264 // ElementPropertyTransition in its IsRemovedSentinel and |
|
265 // SetRemovedSentinel methods. |
|
266 mozilla::TimeStamp mStartTime; |
|
267 mozilla::TimeStamp mPauseStart; |
|
268 mozilla::TimeDuration mDelay; |
|
269 mozilla::TimeDuration mIterationDuration; |
|
270 bool mIsRunningOnCompositor; |
|
271 |
|
272 enum { |
|
273 LAST_NOTIFICATION_NONE = uint32_t(-1), |
|
274 LAST_NOTIFICATION_END = uint32_t(-2) |
|
275 }; |
|
276 // One of the above constants, or an integer for the iteration |
|
277 // whose start we last notified on. |
|
278 uint32_t mLastNotification; |
|
279 |
|
280 InfallibleTArray<AnimationProperty> mProperties; |
|
281 }; |
|
282 |
|
283 namespace css { |
|
284 |
|
285 struct CommonElementAnimationData : public PRCList |
|
286 { |
|
287 CommonElementAnimationData(dom::Element *aElement, nsIAtom *aElementProperty, |
|
288 CommonAnimationManager *aManager, TimeStamp aNow) |
|
289 : mElement(aElement) |
|
290 , mElementProperty(aElementProperty) |
|
291 , mManager(aManager) |
|
292 , mAnimationGeneration(0) |
|
293 , mFlushGeneration(aNow) |
|
294 #ifdef DEBUG |
|
295 , mCalledPropertyDtor(false) |
|
296 #endif |
|
297 { |
|
298 MOZ_COUNT_CTOR(CommonElementAnimationData); |
|
299 PR_INIT_CLIST(this); |
|
300 } |
|
301 ~CommonElementAnimationData() |
|
302 { |
|
303 NS_ABORT_IF_FALSE(mCalledPropertyDtor, |
|
304 "must call destructor through element property dtor"); |
|
305 MOZ_COUNT_DTOR(CommonElementAnimationData); |
|
306 PR_REMOVE_LINK(this); |
|
307 mManager->ElementDataRemoved(); |
|
308 } |
|
309 |
|
310 void Destroy() |
|
311 { |
|
312 // This will call our destructor. |
|
313 mElement->DeleteProperty(mElementProperty); |
|
314 } |
|
315 |
|
316 bool CanThrottleTransformChanges(mozilla::TimeStamp aTime); |
|
317 |
|
318 bool CanThrottleAnimation(mozilla::TimeStamp aTime); |
|
319 |
|
320 enum CanAnimateFlags { |
|
321 // Testing for width, height, top, right, bottom, or left. |
|
322 CanAnimate_HasGeometricProperty = 1, |
|
323 // Allow the case where OMTA is allowed in general, but not for the |
|
324 // specified property. |
|
325 CanAnimate_AllowPartial = 2 |
|
326 }; |
|
327 |
|
328 static bool |
|
329 CanAnimatePropertyOnCompositor(const dom::Element *aElement, |
|
330 nsCSSProperty aProperty, |
|
331 CanAnimateFlags aFlags); |
|
332 |
|
333 static bool IsCompositorAnimationDisabledForFrame(nsIFrame* aFrame); |
|
334 |
|
335 // True if this animation can be performed on the compositor thread. |
|
336 // Do not pass CanAnimate_AllowPartial to make sure that all properties of this |
|
337 // animation are supported by the compositor. |
|
338 virtual bool CanPerformOnCompositorThread(CanAnimateFlags aFlags) const = 0; |
|
339 virtual bool HasAnimationOfProperty(nsCSSProperty aProperty) const = 0; |
|
340 |
|
341 static void LogAsyncAnimationFailure(nsCString& aMessage, |
|
342 const nsIContent* aContent = nullptr); |
|
343 |
|
344 dom::Element *mElement; |
|
345 |
|
346 // the atom we use in mElement's prop table (must be a static atom, |
|
347 // i.e., in an atom list) |
|
348 nsIAtom *mElementProperty; |
|
349 |
|
350 CommonAnimationManager *mManager; |
|
351 |
|
352 // This style rule contains the style data for currently animating |
|
353 // values. It only matches when styling with animation. When we |
|
354 // style without animation, we need to not use it so that we can |
|
355 // detect any new changes; if necessary we restyle immediately |
|
356 // afterwards with animation. |
|
357 // NOTE: If we don't need to apply any styles, mStyleRule will be |
|
358 // null, but mStyleRuleRefreshTime will still be valid. |
|
359 nsRefPtr<mozilla::css::AnimValuesStyleRule> mStyleRule; |
|
360 |
|
361 // RestyleManager keeps track of the number of animation |
|
362 // 'mini-flushes' (see nsTransitionManager::UpdateAllThrottledStyles()). |
|
363 // mAnimationGeneration is the sequence number of the last flush where a |
|
364 // transition/animation changed. We keep a similar count on the |
|
365 // corresponding layer so we can check that the layer is up to date with |
|
366 // the animation manager. |
|
367 uint64_t mAnimationGeneration; |
|
368 // Update mAnimationGeneration to nsCSSFrameConstructor's count |
|
369 void UpdateAnimationGeneration(nsPresContext* aPresContext); |
|
370 |
|
371 // The refresh time associated with mStyleRule. |
|
372 TimeStamp mStyleRuleRefreshTime; |
|
373 |
|
374 // Generation counter for flushes of throttled animations. |
|
375 // Used to prevent updating the styles twice for a given element during |
|
376 // UpdateAllThrottledStyles. |
|
377 TimeStamp mFlushGeneration; |
|
378 |
|
379 #ifdef DEBUG |
|
380 bool mCalledPropertyDtor; |
|
381 #endif |
|
382 }; |
|
383 |
|
384 } |
|
385 } |
|
386 |
|
387 #endif /* !defined(mozilla_css_AnimationCommon_h) */ |