Line data Source code
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 0 : 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 0 : 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 0 : 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 0 : bool IsActive() const {
173 0 : 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 0 : void ClearHasChanged()
208 : {
209 0 : MOZ_ASSERT(HasChanged(),
210 : "clearing mHasChanged flag, when it's already false");
211 0 : MOZ_ASSERT(!IsActiveOrFrozen(),
212 : "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 : }
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 : }
255 :
256 : // Comparator utility class, used for sorting nsSMILAnimationFunctions
257 : class Comparator {
258 : public:
259 0 : bool Equals(const nsSMILAnimationFunction* aElem1,
260 : const nsSMILAnimationFunction* aElem2) const {
261 0 : return (aElem1->CompareTo(aElem2) == 0);
262 : }
263 0 : bool LessThan(const nsSMILAnimationFunction* aElem1,
264 : const nsSMILAnimationFunction* aElem2) const {
265 0 : return (aElem1->CompareTo(aElem2) < 0);
266 : }
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(nsIAtom* aAttName) const;
332 : virtual const nsAttrValue* GetAttr(nsIAtom* aAttName) const;
333 : virtual bool GetAttr(nsIAtom* aAttName,
334 : nsAString& aResult) const;
335 :
336 : bool ParseAttr(nsIAtom* 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 : }
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 : /*
359 : * Animation is additive if:
360 : *
361 : * (1) additive = "sum" (GetAdditive() == true), or
362 : * (2) it is 'by animation' (by is set, from and values are not)
363 : *
364 : * Although animation is not additive if it is 'to animation'
365 : */
366 0 : bool isByAnimation = (!HasAttr(nsGkAtoms::values) &&
367 0 : HasAttr(nsGkAtoms::by) &&
368 0 : !HasAttr(nsGkAtoms::from));
369 0 : return !IsToAnimation() && (GetAdditive() || isByAnimation);
370 : }
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 : } else {
407 0 : mErrorFlags &= ~(0x01 << aField);
408 : }
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_
|