|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
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 NS_SMILANIMATIONFUNCTION_H_ |
|
7 #define NS_SMILANIMATIONFUNCTION_H_ |
|
8 |
|
9 #include "nsISMILAttr.h" |
|
10 #include "nsGkAtoms.h" |
|
11 #include "nsString.h" |
|
12 #include "nsSMILTargetIdentifier.h" |
|
13 #include "nsSMILTimeValue.h" |
|
14 #include "nsSMILKeySpline.h" |
|
15 #include "nsSMILValue.h" |
|
16 #include "nsAutoPtr.h" |
|
17 #include "nsTArray.h" |
|
18 #include "nsAttrValue.h" |
|
19 #include "nsSMILTypes.h" |
|
20 |
|
21 namespace mozilla { |
|
22 namespace dom { |
|
23 class SVGAnimationElement; |
|
24 } |
|
25 } |
|
26 |
|
27 //---------------------------------------------------------------------- |
|
28 // nsSMILAnimationFunction |
|
29 // |
|
30 // The animation function calculates animation values. It it is provided with |
|
31 // time parameters (sample time, repeat iteration etc.) and it uses this to |
|
32 // build an appropriate animation value by performing interpolation and |
|
33 // addition operations. |
|
34 // |
|
35 // It is responsible for implementing the animation parameters of an animation |
|
36 // element (e.g. from, by, to, values, calcMode, additive, accumulate, keyTimes, |
|
37 // keySplines) |
|
38 // |
|
39 class nsSMILAnimationFunction |
|
40 { |
|
41 public: |
|
42 nsSMILAnimationFunction(); |
|
43 |
|
44 /* |
|
45 * Sets the owning animation element which this class uses to query attribute |
|
46 * values and compare document positions. |
|
47 */ |
|
48 void SetAnimationElement(mozilla::dom::SVGAnimationElement* aAnimationElement); |
|
49 |
|
50 /* |
|
51 * Sets animation-specific attributes (or marks them dirty, in the case |
|
52 * of from/to/by/values). |
|
53 * |
|
54 * @param aAttribute The attribute being set |
|
55 * @param aValue The updated value of the attribute. |
|
56 * @param aResult The nsAttrValue object that may be used for storing the |
|
57 * parsed result. |
|
58 * @param aParseResult Outparam used for reporting parse errors. Will be set |
|
59 * to NS_OK if everything succeeds. |
|
60 * @return true if aAttribute is a recognized animation-related |
|
61 * attribute; false otherwise. |
|
62 */ |
|
63 virtual bool SetAttr(nsIAtom* aAttribute, const nsAString& aValue, |
|
64 nsAttrValue& aResult, nsresult* aParseResult = nullptr); |
|
65 |
|
66 /* |
|
67 * Unsets the given attribute. |
|
68 * |
|
69 * @returns true if aAttribute is a recognized animation-related |
|
70 * attribute; false otherwise. |
|
71 */ |
|
72 virtual bool UnsetAttr(nsIAtom* aAttribute); |
|
73 |
|
74 /** |
|
75 * Indicate a new sample has occurred. |
|
76 * |
|
77 * @param aSampleTime The sample time for this timed element expressed in |
|
78 * simple time. |
|
79 * @param aSimpleDuration The simple duration for this timed element. |
|
80 * @param aRepeatIteration The repeat iteration for this sample. The first |
|
81 * iteration has a value of 0. |
|
82 */ |
|
83 void SampleAt(nsSMILTime aSampleTime, |
|
84 const nsSMILTimeValue& aSimpleDuration, |
|
85 uint32_t aRepeatIteration); |
|
86 |
|
87 /** |
|
88 * Indicate to sample using the last value defined for the animation function. |
|
89 * This value is not normally sampled due to the end-point exclusive timing |
|
90 * model but only occurs when the fill mode is "freeze" and the active |
|
91 * duration is an even multiple of the simple duration. |
|
92 * |
|
93 * @param aRepeatIteration The repeat iteration for this sample. The first |
|
94 * iteration has a value of 0. |
|
95 */ |
|
96 void SampleLastValue(uint32_t aRepeatIteration); |
|
97 |
|
98 /** |
|
99 * Indicate that this animation is now active. This is used to instruct the |
|
100 * animation function that it should now add its result to the animation |
|
101 * sandwich. The begin time is also provided for proper prioritization of |
|
102 * animation functions, and for this reason, this method must be called |
|
103 * before either of the Sample methods. |
|
104 * |
|
105 * @param aBeginTime The begin time for the newly active interval. |
|
106 */ |
|
107 void Activate(nsSMILTime aBeginTime); |
|
108 |
|
109 /** |
|
110 * Indicate that this animation is no longer active. This is used to instruct |
|
111 * the animation function that it should no longer add its result to the |
|
112 * animation sandwich. |
|
113 * |
|
114 * @param aIsFrozen true if this animation should continue to contribute |
|
115 * to the animation sandwich using the most recent sample |
|
116 * parameters. |
|
117 */ |
|
118 void Inactivate(bool aIsFrozen); |
|
119 |
|
120 /** |
|
121 * Combines the result of this animation function for the last sample with the |
|
122 * specified value. |
|
123 * |
|
124 * @param aSMILAttr This animation's target attribute. Used here for |
|
125 * doing attribute-specific parsing of from/to/by/values. |
|
126 * |
|
127 * @param aResult The value to compose with. |
|
128 */ |
|
129 void ComposeResult(const nsISMILAttr& aSMILAttr, nsSMILValue& aResult); |
|
130 |
|
131 /** |
|
132 * Returns the relative priority of this animation to another. The priority is |
|
133 * used for determining the position of the animation in the animation |
|
134 * sandwich -- higher priority animations are applied on top of lower |
|
135 * priority animations. |
|
136 * |
|
137 * @return -1 if this animation has lower priority or 1 if this animation has |
|
138 * higher priority |
|
139 * |
|
140 * This method should never return any other value, including 0. |
|
141 */ |
|
142 int8_t CompareTo(const nsSMILAnimationFunction* aOther) const; |
|
143 |
|
144 /* |
|
145 * The following methods are provided so that the compositor can optimize its |
|
146 * operations by only composing those animation that will affect the final |
|
147 * result. |
|
148 */ |
|
149 |
|
150 /** |
|
151 * Indicates if the animation is currently active or frozen. Inactive |
|
152 * animations will not contribute to the composed result. |
|
153 * |
|
154 * @return true if the animation is active or frozen, false otherwise. |
|
155 */ |
|
156 bool IsActiveOrFrozen() const |
|
157 { |
|
158 /* |
|
159 * - Frozen animations should be considered active for the purposes of |
|
160 * compositing. |
|
161 * - This function does not assume that our nsSMILValues (by/from/to/values) |
|
162 * have already been parsed. |
|
163 */ |
|
164 return (mIsActive || mIsFrozen); |
|
165 } |
|
166 |
|
167 /** |
|
168 * Indicates if the animation is active. |
|
169 * |
|
170 * @return true if the animation is active, false otherwise. |
|
171 */ |
|
172 bool IsActive() const { |
|
173 return mIsActive; |
|
174 } |
|
175 |
|
176 /** |
|
177 * Indicates if this animation will replace the passed in result rather than |
|
178 * adding to it. Animations that replace the underlying value may be called |
|
179 * without first calling lower priority animations. |
|
180 * |
|
181 * @return True if the animation will replace, false if it will add or |
|
182 * otherwise build on the passed in value. |
|
183 */ |
|
184 virtual bool WillReplace() const; |
|
185 |
|
186 /** |
|
187 * Indicates if the parameters for this animation have changed since the last |
|
188 * time it was composited. This allows rendering to be performed only when |
|
189 * necessary, particularly when no animations are active. |
|
190 * |
|
191 * Note that the caller is responsible for determining if the animation |
|
192 * target has changed (with help from my UpdateCachedTarget() method). |
|
193 * |
|
194 * @return true if the animation parameters have changed, false |
|
195 * otherwise. |
|
196 */ |
|
197 bool HasChanged() const; |
|
198 |
|
199 /** |
|
200 * This method lets us clear the 'HasChanged' flag for inactive animations |
|
201 * after we've reacted to their change to the 'inactive' state, so that we |
|
202 * won't needlessly recompose their targets in every sample. |
|
203 * |
|
204 * This should only be called on an animation function that is inactive and |
|
205 * that returns true from HasChanged(). |
|
206 */ |
|
207 void ClearHasChanged() |
|
208 { |
|
209 NS_ABORT_IF_FALSE(HasChanged(), |
|
210 "clearing mHasChanged flag, when it's already false"); |
|
211 NS_ABORT_IF_FALSE(!IsActiveOrFrozen(), |
|
212 "clearing mHasChanged flag for active animation"); |
|
213 mHasChanged = false; |
|
214 } |
|
215 |
|
216 /** |
|
217 * Updates the cached record of our animation target, and returns a boolean |
|
218 * that indicates whether the target has changed since the last call to this |
|
219 * function. (This lets nsSMILCompositor check whether its animation |
|
220 * functions have changed value or target since the last sample. If none of |
|
221 * them have, then the compositor doesn't need to do anything.) |
|
222 * |
|
223 * @param aNewTarget A nsSMILTargetIdentifier representing the animation |
|
224 * target of this function for this sample. |
|
225 * @return true if |aNewTarget| is different from the old cached value; |
|
226 * otherwise, false. |
|
227 */ |
|
228 bool UpdateCachedTarget(const nsSMILTargetIdentifier& aNewTarget); |
|
229 |
|
230 /** |
|
231 * Returns true if this function was skipped in the previous sample (because |
|
232 * there was a higher-priority non-additive animation). If a skipped animation |
|
233 * function is later used, then the animation sandwich must be recomposited. |
|
234 */ |
|
235 bool WasSkippedInPrevSample() const { |
|
236 return mWasSkippedInPrevSample; |
|
237 } |
|
238 |
|
239 /** |
|
240 * Mark this animation function as having been skipped. By marking the |
|
241 * function as skipped, if it is used in a subsequent sample we'll know to |
|
242 * recomposite the sandwich. |
|
243 */ |
|
244 void SetWasSkipped() { |
|
245 mWasSkippedInPrevSample = true; |
|
246 } |
|
247 |
|
248 // Comparator utility class, used for sorting nsSMILAnimationFunctions |
|
249 class Comparator { |
|
250 public: |
|
251 bool Equals(const nsSMILAnimationFunction* aElem1, |
|
252 const nsSMILAnimationFunction* aElem2) const { |
|
253 return (aElem1->CompareTo(aElem2) == 0); |
|
254 } |
|
255 bool LessThan(const nsSMILAnimationFunction* aElem1, |
|
256 const nsSMILAnimationFunction* aElem2) const { |
|
257 return (aElem1->CompareTo(aElem2) < 0); |
|
258 } |
|
259 }; |
|
260 |
|
261 protected: |
|
262 // Typedefs |
|
263 typedef FallibleTArray<nsSMILValue> nsSMILValueArray; |
|
264 |
|
265 // Types |
|
266 enum nsSMILCalcMode |
|
267 { |
|
268 CALC_LINEAR, |
|
269 CALC_DISCRETE, |
|
270 CALC_PACED, |
|
271 CALC_SPLINE |
|
272 }; |
|
273 |
|
274 // Used for sorting nsSMILAnimationFunctions |
|
275 nsSMILTime GetBeginTime() const { return mBeginTime; } |
|
276 |
|
277 // Property getters |
|
278 bool GetAccumulate() const; |
|
279 bool GetAdditive() const; |
|
280 virtual nsSMILCalcMode GetCalcMode() const; |
|
281 |
|
282 // Property setters |
|
283 nsresult SetAccumulate(const nsAString& aAccumulate, nsAttrValue& aResult); |
|
284 nsresult SetAdditive(const nsAString& aAdditive, nsAttrValue& aResult); |
|
285 nsresult SetCalcMode(const nsAString& aCalcMode, nsAttrValue& aResult); |
|
286 nsresult SetKeyTimes(const nsAString& aKeyTimes, nsAttrValue& aResult); |
|
287 nsresult SetKeySplines(const nsAString& aKeySplines, nsAttrValue& aResult); |
|
288 |
|
289 // Property un-setters |
|
290 void UnsetAccumulate(); |
|
291 void UnsetAdditive(); |
|
292 void UnsetCalcMode(); |
|
293 void UnsetKeyTimes(); |
|
294 void UnsetKeySplines(); |
|
295 |
|
296 // Helpers |
|
297 virtual nsresult InterpolateResult(const nsSMILValueArray& aValues, |
|
298 nsSMILValue& aResult, |
|
299 nsSMILValue& aBaseValue); |
|
300 nsresult AccumulateResult(const nsSMILValueArray& aValues, |
|
301 nsSMILValue& aResult); |
|
302 |
|
303 nsresult ComputePacedPosition(const nsSMILValueArray& aValues, |
|
304 double aSimpleProgress, |
|
305 double& aIntervalProgress, |
|
306 const nsSMILValue*& aFrom, |
|
307 const nsSMILValue*& aTo); |
|
308 double ComputePacedTotalDistance(const nsSMILValueArray& aValues) const; |
|
309 |
|
310 /** |
|
311 * Adjust the simple progress, that is, the point within the simple duration, |
|
312 * by applying any keyTimes. |
|
313 */ |
|
314 double ScaleSimpleProgress(double aProgress, nsSMILCalcMode aCalcMode); |
|
315 /** |
|
316 * Adjust the progress within an interval, that is, between two animation |
|
317 * values, by applying any keySplines. |
|
318 */ |
|
319 double ScaleIntervalProgress(double aProgress, uint32_t aIntervalIndex); |
|
320 |
|
321 // Convenience attribute getters -- use these instead of querying |
|
322 // mAnimationElement as these may need to be overridden by subclasses |
|
323 virtual bool HasAttr(nsIAtom* aAttName) const; |
|
324 virtual const nsAttrValue* GetAttr(nsIAtom* aAttName) const; |
|
325 virtual bool GetAttr(nsIAtom* aAttName, |
|
326 nsAString& aResult) const; |
|
327 |
|
328 bool ParseAttr(nsIAtom* aAttName, const nsISMILAttr& aSMILAttr, |
|
329 nsSMILValue& aResult, |
|
330 bool& aPreventCachingOfSandwich) const; |
|
331 |
|
332 virtual nsresult GetValues(const nsISMILAttr& aSMILAttr, |
|
333 nsSMILValueArray& aResult); |
|
334 |
|
335 virtual void CheckValueListDependentAttrs(uint32_t aNumValues); |
|
336 void CheckKeyTimes(uint32_t aNumValues); |
|
337 void CheckKeySplines(uint32_t aNumValues); |
|
338 |
|
339 virtual bool IsToAnimation() const { |
|
340 return !HasAttr(nsGkAtoms::values) && |
|
341 HasAttr(nsGkAtoms::to) && |
|
342 !HasAttr(nsGkAtoms::from); |
|
343 } |
|
344 |
|
345 // Returns true if we know our composited value won't change over the |
|
346 // simple duration of this animation (for a fixed base value). |
|
347 virtual bool IsValueFixedForSimpleDuration() const; |
|
348 |
|
349 inline bool IsAdditive() const { |
|
350 /* |
|
351 * Animation is additive if: |
|
352 * |
|
353 * (1) additive = "sum" (GetAdditive() == true), or |
|
354 * (2) it is 'by animation' (by is set, from and values are not) |
|
355 * |
|
356 * Although animation is not additive if it is 'to animation' |
|
357 */ |
|
358 bool isByAnimation = (!HasAttr(nsGkAtoms::values) && |
|
359 HasAttr(nsGkAtoms::by) && |
|
360 !HasAttr(nsGkAtoms::from)); |
|
361 return !IsToAnimation() && (GetAdditive() || isByAnimation); |
|
362 } |
|
363 |
|
364 // Setters for error flags |
|
365 // These correspond to bit-indices in mErrorFlags, for tracking parse errors |
|
366 // in these attributes, when those parse errors should block us from doing |
|
367 // animation. |
|
368 enum AnimationAttributeIdx { |
|
369 BF_ACCUMULATE = 0, |
|
370 BF_ADDITIVE = 1, |
|
371 BF_CALC_MODE = 2, |
|
372 BF_KEY_TIMES = 3, |
|
373 BF_KEY_SPLINES = 4, |
|
374 BF_KEY_POINTS = 5 // <animateMotion> only |
|
375 }; |
|
376 |
|
377 inline void SetAccumulateErrorFlag(bool aNewValue) { |
|
378 SetErrorFlag(BF_ACCUMULATE, aNewValue); |
|
379 } |
|
380 inline void SetAdditiveErrorFlag(bool aNewValue) { |
|
381 SetErrorFlag(BF_ADDITIVE, aNewValue); |
|
382 } |
|
383 inline void SetCalcModeErrorFlag(bool aNewValue) { |
|
384 SetErrorFlag(BF_CALC_MODE, aNewValue); |
|
385 } |
|
386 inline void SetKeyTimesErrorFlag(bool aNewValue) { |
|
387 SetErrorFlag(BF_KEY_TIMES, aNewValue); |
|
388 } |
|
389 inline void SetKeySplinesErrorFlag(bool aNewValue) { |
|
390 SetErrorFlag(BF_KEY_SPLINES, aNewValue); |
|
391 } |
|
392 inline void SetKeyPointsErrorFlag(bool aNewValue) { |
|
393 SetErrorFlag(BF_KEY_POINTS, aNewValue); |
|
394 } |
|
395 inline void SetErrorFlag(AnimationAttributeIdx aField, bool aValue) { |
|
396 if (aValue) { |
|
397 mErrorFlags |= (0x01 << aField); |
|
398 } else { |
|
399 mErrorFlags &= ~(0x01 << aField); |
|
400 } |
|
401 } |
|
402 |
|
403 // Members |
|
404 // ------- |
|
405 |
|
406 static nsAttrValue::EnumTable sAdditiveTable[]; |
|
407 static nsAttrValue::EnumTable sCalcModeTable[]; |
|
408 static nsAttrValue::EnumTable sAccumulateTable[]; |
|
409 |
|
410 FallibleTArray<double> mKeyTimes; |
|
411 FallibleTArray<nsSMILKeySpline> mKeySplines; |
|
412 |
|
413 // These are the parameters provided by the previous sample. Currently we |
|
414 // perform lazy calculation. That is, we only calculate the result if and when |
|
415 // instructed by the compositor. This allows us to apply the result directly |
|
416 // to the animation value and allows the compositor to filter out functions |
|
417 // that it determines will not contribute to the final result. |
|
418 nsSMILTime mSampleTime; // sample time within simple dur |
|
419 nsSMILTimeValue mSimpleDuration; |
|
420 uint32_t mRepeatIteration; |
|
421 |
|
422 nsSMILTime mBeginTime; // document time |
|
423 |
|
424 // The owning animation element. This is used for sorting based on document |
|
425 // position and for fetching attribute values stored in the element. |
|
426 // Raw pointer is OK here, because this nsSMILAnimationFunction can't outlive |
|
427 // its owning animation element. |
|
428 mozilla::dom::SVGAnimationElement* mAnimationElement; |
|
429 |
|
430 // Which attributes have been set but have had errors. This is not used for |
|
431 // all attributes but only those which have specified error behaviour |
|
432 // associated with them. |
|
433 uint16_t mErrorFlags; |
|
434 |
|
435 // Allows us to check whether an animation function has changed target from |
|
436 // sample to sample (because if neither target nor animated value have |
|
437 // changed, we don't have to do anything). |
|
438 nsSMILWeakTargetIdentifier mLastTarget; |
|
439 |
|
440 // Boolean flags |
|
441 bool mIsActive:1; |
|
442 bool mIsFrozen:1; |
|
443 bool mLastValue:1; |
|
444 bool mHasChanged:1; |
|
445 bool mValueNeedsReparsingEverySample:1; |
|
446 bool mPrevSampleWasSingleValueAnimation:1; |
|
447 bool mWasSkippedInPrevSample:1; |
|
448 }; |
|
449 |
|
450 #endif // NS_SMILANIMATIONFUNCTION_H_ |