dom/smil/nsSMILAnimationFunction.h

branch
TOR_BUG_9701
changeset 8
97036ab72558
equal deleted inserted replaced
-1:000000000000 0:8bdf22fd1e80
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_

mercurial