Coverage Report

Created: 2018-09-25 14:53

/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_