/src/mozilla-central/dom/smil/nsSMILAnimationFunction.h
Line | Count | Source (jump to first uncovered line) |
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 NS_SMILANIMATIONFUNCTION_H_ |
8 | | #define NS_SMILANIMATIONFUNCTION_H_ |
9 | | |
10 | | #include "nsISMILAttr.h" |
11 | | #include "nsGkAtoms.h" |
12 | | #include "nsString.h" |
13 | | #include "nsSMILTargetIdentifier.h" |
14 | | #include "nsSMILTimeValue.h" |
15 | | #include "nsSMILKeySpline.h" |
16 | | #include "nsSMILValue.h" |
17 | | #include "nsTArray.h" |
18 | | #include "nsAttrValue.h" |
19 | | #include "nsSMILTypes.h" |
20 | | |
21 | | namespace mozilla { |
22 | | namespace dom { |
23 | | class SVGAnimationElement; |
24 | | } // namespace dom |
25 | | } // namespace mozilla |
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(nsAtom* 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(nsAtom* 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 | 0 | { |
158 | 0 | /* |
159 | 0 | * - Frozen animations should be considered active for the purposes of |
160 | 0 | * compositing. |
161 | 0 | * - This function does not assume that our nsSMILValues (by/from/to/values) |
162 | 0 | * have already been parsed. |
163 | 0 | */ |
164 | 0 | return (mIsActive || mIsFrozen); |
165 | 0 | } |
166 | | |
167 | | /** |
168 | | * Indicates if the animation is active. |
169 | | * |
170 | | * @return true if the animation is active, false otherwise. |
171 | | */ |
172 | 0 | bool IsActive() const { |
173 | 0 | return mIsActive; |
174 | 0 | } |
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 | 0 | { |
209 | 0 | MOZ_ASSERT(HasChanged(), |
210 | 0 | "clearing mHasChanged flag, when it's already false"); |
211 | 0 | MOZ_ASSERT(!IsActiveOrFrozen(), |
212 | 0 | "clearing mHasChanged flag for active animation"); |
213 | 0 | mHasChanged = false; |
214 | 0 | } |
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 | 0 | bool WasSkippedInPrevSample() const { |
236 | 0 | return mWasSkippedInPrevSample; |
237 | 0 | } |
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 | 0 | void SetWasSkipped() { |
245 | 0 | mWasSkippedInPrevSample = true; |
246 | 0 | } |
247 | | |
248 | | /** |
249 | | * Returns true if we need to recalculate the animation value on every sample. |
250 | | * (e.g. because it depends on context like the font-size) |
251 | | */ |
252 | 0 | bool ValueNeedsReparsingEverySample() const { |
253 | 0 | return mValueNeedsReparsingEverySample; |
254 | 0 | } |
255 | | |
256 | | // Comparator utility class, used for sorting nsSMILAnimationFunctions |
257 | | class Comparator { |
258 | | public: |
259 | | bool Equals(const nsSMILAnimationFunction* aElem1, |
260 | 0 | const nsSMILAnimationFunction* aElem2) const { |
261 | 0 | return (aElem1->CompareTo(aElem2) == 0); |
262 | 0 | } |
263 | | bool LessThan(const nsSMILAnimationFunction* aElem1, |
264 | 0 | const nsSMILAnimationFunction* aElem2) const { |
265 | 0 | return (aElem1->CompareTo(aElem2) < 0); |
266 | 0 | } |
267 | | }; |
268 | | |
269 | | protected: |
270 | | // Typedefs |
271 | | typedef FallibleTArray<nsSMILValue> nsSMILValueArray; |
272 | | |
273 | | // Types |
274 | | enum nsSMILCalcMode : uint8_t |
275 | | { |
276 | | CALC_LINEAR, |
277 | | CALC_DISCRETE, |
278 | | CALC_PACED, |
279 | | CALC_SPLINE |
280 | | }; |
281 | | |
282 | | // Used for sorting nsSMILAnimationFunctions |
283 | 0 | nsSMILTime GetBeginTime() const { return mBeginTime; } |
284 | | |
285 | | // Property getters |
286 | | bool GetAccumulate() const; |
287 | | bool GetAdditive() const; |
288 | | virtual nsSMILCalcMode GetCalcMode() const; |
289 | | |
290 | | // Property setters |
291 | | nsresult SetAccumulate(const nsAString& aAccumulate, nsAttrValue& aResult); |
292 | | nsresult SetAdditive(const nsAString& aAdditive, nsAttrValue& aResult); |
293 | | nsresult SetCalcMode(const nsAString& aCalcMode, nsAttrValue& aResult); |
294 | | nsresult SetKeyTimes(const nsAString& aKeyTimes, nsAttrValue& aResult); |
295 | | nsresult SetKeySplines(const nsAString& aKeySplines, nsAttrValue& aResult); |
296 | | |
297 | | // Property un-setters |
298 | | void UnsetAccumulate(); |
299 | | void UnsetAdditive(); |
300 | | void UnsetCalcMode(); |
301 | | void UnsetKeyTimes(); |
302 | | void UnsetKeySplines(); |
303 | | |
304 | | // Helpers |
305 | | virtual nsresult InterpolateResult(const nsSMILValueArray& aValues, |
306 | | nsSMILValue& aResult, |
307 | | nsSMILValue& aBaseValue); |
308 | | nsresult AccumulateResult(const nsSMILValueArray& aValues, |
309 | | nsSMILValue& aResult); |
310 | | |
311 | | nsresult ComputePacedPosition(const nsSMILValueArray& aValues, |
312 | | double aSimpleProgress, |
313 | | double& aIntervalProgress, |
314 | | const nsSMILValue*& aFrom, |
315 | | const nsSMILValue*& aTo); |
316 | | double ComputePacedTotalDistance(const nsSMILValueArray& aValues) const; |
317 | | |
318 | | /** |
319 | | * Adjust the simple progress, that is, the point within the simple duration, |
320 | | * by applying any keyTimes. |
321 | | */ |
322 | | double ScaleSimpleProgress(double aProgress, nsSMILCalcMode aCalcMode); |
323 | | /** |
324 | | * Adjust the progress within an interval, that is, between two animation |
325 | | * values, by applying any keySplines. |
326 | | */ |
327 | | double ScaleIntervalProgress(double aProgress, uint32_t aIntervalIndex); |
328 | | |
329 | | // Convenience attribute getters -- use these instead of querying |
330 | | // mAnimationElement as these may need to be overridden by subclasses |
331 | | virtual bool HasAttr(nsAtom* aAttName) const; |
332 | | virtual const nsAttrValue* GetAttr(nsAtom* aAttName) const; |
333 | | virtual bool GetAttr(nsAtom* aAttName, |
334 | | nsAString& aResult) const; |
335 | | |
336 | | bool ParseAttr(nsAtom* aAttName, const nsISMILAttr& aSMILAttr, |
337 | | nsSMILValue& aResult, |
338 | | bool& aPreventCachingOfSandwich) const; |
339 | | |
340 | | virtual nsresult GetValues(const nsISMILAttr& aSMILAttr, |
341 | | nsSMILValueArray& aResult); |
342 | | |
343 | | virtual void CheckValueListDependentAttrs(uint32_t aNumValues); |
344 | | void CheckKeyTimes(uint32_t aNumValues); |
345 | | void CheckKeySplines(uint32_t aNumValues); |
346 | | |
347 | 0 | virtual bool IsToAnimation() const { |
348 | 0 | return !HasAttr(nsGkAtoms::values) && |
349 | 0 | HasAttr(nsGkAtoms::to) && |
350 | 0 | !HasAttr(nsGkAtoms::from); |
351 | 0 | } |
352 | | |
353 | | // Returns true if we know our composited value won't change over the |
354 | | // simple duration of this animation (for a fixed base value). |
355 | | virtual bool IsValueFixedForSimpleDuration() const; |
356 | | |
357 | 0 | inline bool IsAdditive() const { |
358 | 0 | /* |
359 | 0 | * Animation is additive if: |
360 | 0 | * |
361 | 0 | * (1) additive = "sum" (GetAdditive() == true), or |
362 | 0 | * (2) it is 'by animation' (by is set, from and values are not) |
363 | 0 | * |
364 | 0 | * Although animation is not additive if it is 'to animation' |
365 | 0 | */ |
366 | 0 | bool isByAnimation = (!HasAttr(nsGkAtoms::values) && |
367 | 0 | HasAttr(nsGkAtoms::by) && |
368 | 0 | !HasAttr(nsGkAtoms::from)); |
369 | 0 | return !IsToAnimation() && (GetAdditive() || isByAnimation); |
370 | 0 | } |
371 | | |
372 | | // Setters for error flags |
373 | | // These correspond to bit-indices in mErrorFlags, for tracking parse errors |
374 | | // in these attributes, when those parse errors should block us from doing |
375 | | // animation. |
376 | | enum AnimationAttributeIdx { |
377 | | BF_ACCUMULATE = 0, |
378 | | BF_ADDITIVE = 1, |
379 | | BF_CALC_MODE = 2, |
380 | | BF_KEY_TIMES = 3, |
381 | | BF_KEY_SPLINES = 4, |
382 | | BF_KEY_POINTS = 5 // <animateMotion> only |
383 | | }; |
384 | | |
385 | 0 | inline void SetAccumulateErrorFlag(bool aNewValue) { |
386 | 0 | SetErrorFlag(BF_ACCUMULATE, aNewValue); |
387 | 0 | } |
388 | 0 | inline void SetAdditiveErrorFlag(bool aNewValue) { |
389 | 0 | SetErrorFlag(BF_ADDITIVE, aNewValue); |
390 | 0 | } |
391 | 0 | inline void SetCalcModeErrorFlag(bool aNewValue) { |
392 | 0 | SetErrorFlag(BF_CALC_MODE, aNewValue); |
393 | 0 | } |
394 | 0 | inline void SetKeyTimesErrorFlag(bool aNewValue) { |
395 | 0 | SetErrorFlag(BF_KEY_TIMES, aNewValue); |
396 | 0 | } |
397 | 0 | inline void SetKeySplinesErrorFlag(bool aNewValue) { |
398 | 0 | SetErrorFlag(BF_KEY_SPLINES, aNewValue); |
399 | 0 | } |
400 | 0 | inline void SetKeyPointsErrorFlag(bool aNewValue) { |
401 | 0 | SetErrorFlag(BF_KEY_POINTS, aNewValue); |
402 | 0 | } |
403 | 0 | inline void SetErrorFlag(AnimationAttributeIdx aField, bool aValue) { |
404 | 0 | if (aValue) { |
405 | 0 | mErrorFlags |= (0x01 << aField); |
406 | 0 | } else { |
407 | 0 | mErrorFlags &= ~(0x01 << aField); |
408 | 0 | } |
409 | 0 | } |
410 | | |
411 | | // Members |
412 | | // ------- |
413 | | |
414 | | static nsAttrValue::EnumTable sAdditiveTable[]; |
415 | | static nsAttrValue::EnumTable sCalcModeTable[]; |
416 | | static nsAttrValue::EnumTable sAccumulateTable[]; |
417 | | |
418 | | FallibleTArray<double> mKeyTimes; |
419 | | FallibleTArray<nsSMILKeySpline> mKeySplines; |
420 | | |
421 | | // These are the parameters provided by the previous sample. Currently we |
422 | | // perform lazy calculation. That is, we only calculate the result if and when |
423 | | // instructed by the compositor. This allows us to apply the result directly |
424 | | // to the animation value and allows the compositor to filter out functions |
425 | | // that it determines will not contribute to the final result. |
426 | | nsSMILTime mSampleTime; // sample time within simple dur |
427 | | nsSMILTimeValue mSimpleDuration; |
428 | | uint32_t mRepeatIteration; |
429 | | |
430 | | nsSMILTime mBeginTime; // document time |
431 | | |
432 | | // The owning animation element. This is used for sorting based on document |
433 | | // position and for fetching attribute values stored in the element. |
434 | | // Raw pointer is OK here, because this nsSMILAnimationFunction can't outlive |
435 | | // its owning animation element. |
436 | | mozilla::dom::SVGAnimationElement* mAnimationElement; |
437 | | |
438 | | // Which attributes have been set but have had errors. This is not used for |
439 | | // all attributes but only those which have specified error behaviour |
440 | | // associated with them. |
441 | | uint16_t mErrorFlags; |
442 | | |
443 | | // Allows us to check whether an animation function has changed target from |
444 | | // sample to sample (because if neither target nor animated value have |
445 | | // changed, we don't have to do anything). |
446 | | nsSMILWeakTargetIdentifier mLastTarget; |
447 | | |
448 | | // Boolean flags |
449 | | bool mIsActive:1; |
450 | | bool mIsFrozen:1; |
451 | | bool mLastValue:1; |
452 | | bool mHasChanged:1; |
453 | | bool mValueNeedsReparsingEverySample:1; |
454 | | bool mPrevSampleWasSingleValueAnimation:1; |
455 | | bool mWasSkippedInPrevSample:1; |
456 | | }; |
457 | | |
458 | | #endif // NS_SMILANIMATIONFUNCTION_H_ |