dom/smil/nsSMILAnimationFunction.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/dom/smil/nsSMILAnimationFunction.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,450 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#ifndef NS_SMILANIMATIONFUNCTION_H_
    1.10 +#define NS_SMILANIMATIONFUNCTION_H_
    1.11 +
    1.12 +#include "nsISMILAttr.h"
    1.13 +#include "nsGkAtoms.h"
    1.14 +#include "nsString.h"
    1.15 +#include "nsSMILTargetIdentifier.h"
    1.16 +#include "nsSMILTimeValue.h"
    1.17 +#include "nsSMILKeySpline.h"
    1.18 +#include "nsSMILValue.h"
    1.19 +#include "nsAutoPtr.h"
    1.20 +#include "nsTArray.h"
    1.21 +#include "nsAttrValue.h"
    1.22 +#include "nsSMILTypes.h"
    1.23 +
    1.24 +namespace mozilla {
    1.25 +namespace dom {
    1.26 +class SVGAnimationElement;
    1.27 +}
    1.28 +}
    1.29 +
    1.30 +//----------------------------------------------------------------------
    1.31 +// nsSMILAnimationFunction
    1.32 +//
    1.33 +// The animation function calculates animation values. It it is provided with
    1.34 +// time parameters (sample time, repeat iteration etc.) and it uses this to
    1.35 +// build an appropriate animation value by performing interpolation and
    1.36 +// addition operations.
    1.37 +//
    1.38 +// It is responsible for implementing the animation parameters of an animation
    1.39 +// element (e.g. from, by, to, values, calcMode, additive, accumulate, keyTimes,
    1.40 +// keySplines)
    1.41 +//
    1.42 +class nsSMILAnimationFunction
    1.43 +{
    1.44 +public:
    1.45 +  nsSMILAnimationFunction();
    1.46 +
    1.47 +  /*
    1.48 +   * Sets the owning animation element which this class uses to query attribute
    1.49 +   * values and compare document positions.
    1.50 +   */
    1.51 +  void SetAnimationElement(mozilla::dom::SVGAnimationElement* aAnimationElement);
    1.52 +
    1.53 +  /*
    1.54 +   * Sets animation-specific attributes (or marks them dirty, in the case
    1.55 +   * of from/to/by/values).
    1.56 +   *
    1.57 +   * @param aAttribute The attribute being set
    1.58 +   * @param aValue     The updated value of the attribute.
    1.59 +   * @param aResult    The nsAttrValue object that may be used for storing the
    1.60 +   *                   parsed result.
    1.61 +   * @param aParseResult  Outparam used for reporting parse errors. Will be set
    1.62 +   *                      to NS_OK if everything succeeds.
    1.63 +   * @return  true if aAttribute is a recognized animation-related
    1.64 +   *          attribute; false otherwise.
    1.65 +   */
    1.66 +  virtual bool SetAttr(nsIAtom* aAttribute, const nsAString& aValue,
    1.67 +                         nsAttrValue& aResult, nsresult* aParseResult = nullptr);
    1.68 +
    1.69 +  /*
    1.70 +   * Unsets the given attribute.
    1.71 +   *
    1.72 +   * @returns true if aAttribute is a recognized animation-related
    1.73 +   *          attribute; false otherwise.
    1.74 +   */
    1.75 +  virtual bool UnsetAttr(nsIAtom* aAttribute);
    1.76 +
    1.77 +  /**
    1.78 +   * Indicate a new sample has occurred.
    1.79 +   *
    1.80 +   * @param aSampleTime The sample time for this timed element expressed in
    1.81 +   *                    simple time.
    1.82 +   * @param aSimpleDuration The simple duration for this timed element.
    1.83 +   * @param aRepeatIteration  The repeat iteration for this sample. The first
    1.84 +   *                          iteration has a value of 0.
    1.85 +   */
    1.86 +  void SampleAt(nsSMILTime aSampleTime,
    1.87 +                const nsSMILTimeValue& aSimpleDuration,
    1.88 +                uint32_t aRepeatIteration);
    1.89 +
    1.90 +  /**
    1.91 +   * Indicate to sample using the last value defined for the animation function.
    1.92 +   * This value is not normally sampled due to the end-point exclusive timing
    1.93 +   * model but only occurs when the fill mode is "freeze" and the active
    1.94 +   * duration is an even multiple of the simple duration.
    1.95 +   *
    1.96 +   * @param aRepeatIteration  The repeat iteration for this sample. The first
    1.97 +   *                          iteration has a value of 0.
    1.98 +   */
    1.99 +  void SampleLastValue(uint32_t aRepeatIteration);
   1.100 +
   1.101 +  /**
   1.102 +   * Indicate that this animation is now active. This is used to instruct the
   1.103 +   * animation function that it should now add its result to the animation
   1.104 +   * sandwich. The begin time is also provided for proper prioritization of
   1.105 +   * animation functions, and for this reason, this method must be called
   1.106 +   * before either of the Sample methods.
   1.107 +   *
   1.108 +   * @param aBeginTime The begin time for the newly active interval.
   1.109 +   */
   1.110 +  void Activate(nsSMILTime aBeginTime);
   1.111 +
   1.112 +  /**
   1.113 +   * Indicate that this animation is no longer active. This is used to instruct
   1.114 +   * the animation function that it should no longer add its result to the
   1.115 +   * animation sandwich.
   1.116 +   *
   1.117 +   * @param aIsFrozen true if this animation should continue to contribute
   1.118 +   *                  to the animation sandwich using the most recent sample
   1.119 +   *                  parameters.
   1.120 +   */
   1.121 +  void Inactivate(bool aIsFrozen);
   1.122 +
   1.123 +  /**
   1.124 +   * Combines the result of this animation function for the last sample with the
   1.125 +   * specified value.
   1.126 +   *
   1.127 +   * @param aSMILAttr This animation's target attribute. Used here for
   1.128 +   *                  doing attribute-specific parsing of from/to/by/values.
   1.129 +   *
   1.130 +   * @param aResult   The value to compose with.
   1.131 +   */
   1.132 +  void ComposeResult(const nsISMILAttr& aSMILAttr, nsSMILValue& aResult);
   1.133 +
   1.134 +  /**
   1.135 +   * Returns the relative priority of this animation to another. The priority is
   1.136 +   * used for determining the position of the animation in the animation
   1.137 +   * sandwich -- higher priority animations are applied on top of lower
   1.138 +   * priority animations.
   1.139 +   *
   1.140 +   * @return  -1 if this animation has lower priority or 1 if this animation has
   1.141 +   *          higher priority
   1.142 +   *
   1.143 +   * This method should never return any other value, including 0.
   1.144 +   */
   1.145 +  int8_t CompareTo(const nsSMILAnimationFunction* aOther) const;
   1.146 +
   1.147 +  /*
   1.148 +   * The following methods are provided so that the compositor can optimize its
   1.149 +   * operations by only composing those animation that will affect the final
   1.150 +   * result.
   1.151 +   */
   1.152 +
   1.153 +  /**
   1.154 +   * Indicates if the animation is currently active or frozen. Inactive
   1.155 +   * animations will not contribute to the composed result.
   1.156 +   *
   1.157 +   * @return  true if the animation is active or frozen, false otherwise.
   1.158 +   */
   1.159 +  bool IsActiveOrFrozen() const
   1.160 +  {
   1.161 +    /*
   1.162 +     * - Frozen animations should be considered active for the purposes of
   1.163 +     * compositing.
   1.164 +     * - This function does not assume that our nsSMILValues (by/from/to/values)
   1.165 +     * have already been parsed.
   1.166 +     */
   1.167 +    return (mIsActive || mIsFrozen);
   1.168 +  }
   1.169 +
   1.170 +  /**
   1.171 +   * Indicates if the animation is active.
   1.172 +   *
   1.173 +   * @return  true if the animation is active, false otherwise.
   1.174 +   */
   1.175 +  bool IsActive() const {
   1.176 +    return mIsActive;
   1.177 +  }
   1.178 +
   1.179 +  /**
   1.180 +   * Indicates if this animation will replace the passed in result rather than
   1.181 +   * adding to it. Animations that replace the underlying value may be called
   1.182 +   * without first calling lower priority animations.
   1.183 +   *
   1.184 +   * @return  True if the animation will replace, false if it will add or
   1.185 +   *          otherwise build on the passed in value.
   1.186 +   */
   1.187 +  virtual bool WillReplace() const;
   1.188 +
   1.189 +  /**
   1.190 +   * Indicates if the parameters for this animation have changed since the last
   1.191 +   * time it was composited. This allows rendering to be performed only when
   1.192 +   * necessary, particularly when no animations are active.
   1.193 +   *
   1.194 +   * Note that the caller is responsible for determining if the animation
   1.195 +   * target has changed (with help from my UpdateCachedTarget() method).
   1.196 +   *
   1.197 +   * @return  true if the animation parameters have changed, false
   1.198 +   *          otherwise.
   1.199 +   */
   1.200 +  bool HasChanged() const;
   1.201 +
   1.202 +  /**
   1.203 +   * This method lets us clear the 'HasChanged' flag for inactive animations
   1.204 +   * after we've reacted to their change to the 'inactive' state, so that we
   1.205 +   * won't needlessly recompose their targets in every sample.
   1.206 +   *
   1.207 +   * This should only be called on an animation function that is inactive and
   1.208 +   * that returns true from HasChanged().
   1.209 +   */
   1.210 +  void ClearHasChanged()
   1.211 +  {
   1.212 +    NS_ABORT_IF_FALSE(HasChanged(),
   1.213 +                      "clearing mHasChanged flag, when it's already false");
   1.214 +    NS_ABORT_IF_FALSE(!IsActiveOrFrozen(),
   1.215 +                      "clearing mHasChanged flag for active animation");
   1.216 +    mHasChanged = false;
   1.217 +  }
   1.218 +
   1.219 +  /**
   1.220 +   * Updates the cached record of our animation target, and returns a boolean
   1.221 +   * that indicates whether the target has changed since the last call to this
   1.222 +   * function. (This lets nsSMILCompositor check whether its animation
   1.223 +   * functions have changed value or target since the last sample.  If none of
   1.224 +   * them have, then the compositor doesn't need to do anything.)
   1.225 +   *
   1.226 +   * @param aNewTarget A nsSMILTargetIdentifier representing the animation
   1.227 +   *                   target of this function for this sample.
   1.228 +   * @return  true if |aNewTarget| is different from the old cached value;
   1.229 +   *          otherwise, false.
   1.230 +   */
   1.231 +  bool UpdateCachedTarget(const nsSMILTargetIdentifier& aNewTarget);
   1.232 +
   1.233 +  /**
   1.234 +   * Returns true if this function was skipped in the previous sample (because
   1.235 +   * there was a higher-priority non-additive animation). If a skipped animation
   1.236 +   * function is later used, then the animation sandwich must be recomposited.
   1.237 +   */
   1.238 +  bool WasSkippedInPrevSample() const {
   1.239 +    return mWasSkippedInPrevSample;
   1.240 +  }
   1.241 +
   1.242 +  /**
   1.243 +   * Mark this animation function as having been skipped. By marking the
   1.244 +   * function as skipped, if it is used in a subsequent sample we'll know to
   1.245 +   * recomposite the sandwich.
   1.246 +   */
   1.247 +  void SetWasSkipped() {
   1.248 +    mWasSkippedInPrevSample = true;
   1.249 +  }
   1.250 +
   1.251 +  // Comparator utility class, used for sorting nsSMILAnimationFunctions
   1.252 +  class Comparator {
   1.253 +    public:
   1.254 +      bool Equals(const nsSMILAnimationFunction* aElem1,
   1.255 +                    const nsSMILAnimationFunction* aElem2) const {
   1.256 +        return (aElem1->CompareTo(aElem2) == 0);
   1.257 +      }
   1.258 +      bool LessThan(const nsSMILAnimationFunction* aElem1,
   1.259 +                      const nsSMILAnimationFunction* aElem2) const {
   1.260 +        return (aElem1->CompareTo(aElem2) < 0);
   1.261 +      }
   1.262 +  };
   1.263 +
   1.264 +protected:
   1.265 +  // Typedefs
   1.266 +  typedef FallibleTArray<nsSMILValue> nsSMILValueArray;
   1.267 +
   1.268 +  // Types
   1.269 +  enum nsSMILCalcMode
   1.270 +  {
   1.271 +    CALC_LINEAR,
   1.272 +    CALC_DISCRETE,
   1.273 +    CALC_PACED,
   1.274 +    CALC_SPLINE
   1.275 +  };
   1.276 +
   1.277 +  // Used for sorting nsSMILAnimationFunctions
   1.278 +  nsSMILTime GetBeginTime() const { return mBeginTime; }
   1.279 +
   1.280 +  // Property getters
   1.281 +  bool                   GetAccumulate() const;
   1.282 +  bool                   GetAdditive() const;
   1.283 +  virtual nsSMILCalcMode GetCalcMode() const;
   1.284 +
   1.285 +  // Property setters
   1.286 +  nsresult SetAccumulate(const nsAString& aAccumulate, nsAttrValue& aResult);
   1.287 +  nsresult SetAdditive(const nsAString& aAdditive, nsAttrValue& aResult);
   1.288 +  nsresult SetCalcMode(const nsAString& aCalcMode, nsAttrValue& aResult);
   1.289 +  nsresult SetKeyTimes(const nsAString& aKeyTimes, nsAttrValue& aResult);
   1.290 +  nsresult SetKeySplines(const nsAString& aKeySplines, nsAttrValue& aResult);
   1.291 +
   1.292 +  // Property un-setters
   1.293 +  void     UnsetAccumulate();
   1.294 +  void     UnsetAdditive();
   1.295 +  void     UnsetCalcMode();
   1.296 +  void     UnsetKeyTimes();
   1.297 +  void     UnsetKeySplines();
   1.298 +
   1.299 +  // Helpers
   1.300 +  virtual nsresult InterpolateResult(const nsSMILValueArray& aValues,
   1.301 +                                     nsSMILValue& aResult,
   1.302 +                                     nsSMILValue& aBaseValue);
   1.303 +  nsresult AccumulateResult(const nsSMILValueArray& aValues,
   1.304 +                            nsSMILValue& aResult);
   1.305 +
   1.306 +  nsresult ComputePacedPosition(const nsSMILValueArray& aValues,
   1.307 +                                double aSimpleProgress,
   1.308 +                                double& aIntervalProgress,
   1.309 +                                const nsSMILValue*& aFrom,
   1.310 +                                const nsSMILValue*& aTo);
   1.311 +  double   ComputePacedTotalDistance(const nsSMILValueArray& aValues) const;
   1.312 +
   1.313 +  /**
   1.314 +   * Adjust the simple progress, that is, the point within the simple duration,
   1.315 +   * by applying any keyTimes.
   1.316 +   */
   1.317 +  double   ScaleSimpleProgress(double aProgress, nsSMILCalcMode aCalcMode);
   1.318 +  /**
   1.319 +   * Adjust the progress within an interval, that is, between two animation
   1.320 +   * values, by applying any keySplines.
   1.321 +   */
   1.322 +  double   ScaleIntervalProgress(double aProgress, uint32_t aIntervalIndex);
   1.323 +
   1.324 +  // Convenience attribute getters -- use these instead of querying
   1.325 +  // mAnimationElement as these may need to be overridden by subclasses
   1.326 +  virtual bool               HasAttr(nsIAtom* aAttName) const;
   1.327 +  virtual const nsAttrValue* GetAttr(nsIAtom* aAttName) const;
   1.328 +  virtual bool               GetAttr(nsIAtom* aAttName,
   1.329 +                                     nsAString& aResult) const;
   1.330 +
   1.331 +  bool     ParseAttr(nsIAtom* aAttName, const nsISMILAttr& aSMILAttr,
   1.332 +                     nsSMILValue& aResult,
   1.333 +                     bool& aPreventCachingOfSandwich) const;
   1.334 +
   1.335 +  virtual nsresult GetValues(const nsISMILAttr& aSMILAttr,
   1.336 +                             nsSMILValueArray& aResult);
   1.337 +
   1.338 +  virtual void CheckValueListDependentAttrs(uint32_t aNumValues);
   1.339 +  void         CheckKeyTimes(uint32_t aNumValues);
   1.340 +  void         CheckKeySplines(uint32_t aNumValues);
   1.341 +
   1.342 +  virtual bool IsToAnimation() const {
   1.343 +    return !HasAttr(nsGkAtoms::values) &&
   1.344 +            HasAttr(nsGkAtoms::to) &&
   1.345 +           !HasAttr(nsGkAtoms::from);
   1.346 +  }
   1.347 +
   1.348 +  // Returns true if we know our composited value won't change over the
   1.349 +  // simple duration of this animation (for a fixed base value).
   1.350 +  virtual bool IsValueFixedForSimpleDuration() const;
   1.351 +
   1.352 +  inline bool IsAdditive() const {
   1.353 +    /*
   1.354 +     * Animation is additive if:
   1.355 +     *
   1.356 +     * (1) additive = "sum" (GetAdditive() == true), or
   1.357 +     * (2) it is 'by animation' (by is set, from and values are not)
   1.358 +     *
   1.359 +     * Although animation is not additive if it is 'to animation'
   1.360 +     */
   1.361 +    bool isByAnimation = (!HasAttr(nsGkAtoms::values) &&
   1.362 +                             HasAttr(nsGkAtoms::by) &&
   1.363 +                            !HasAttr(nsGkAtoms::from));
   1.364 +    return !IsToAnimation() && (GetAdditive() || isByAnimation);
   1.365 +  }
   1.366 +
   1.367 +  // Setters for error flags
   1.368 +  // These correspond to bit-indices in mErrorFlags, for tracking parse errors
   1.369 +  // in these attributes, when those parse errors should block us from doing
   1.370 +  // animation.
   1.371 +  enum AnimationAttributeIdx {
   1.372 +    BF_ACCUMULATE  = 0,
   1.373 +    BF_ADDITIVE    = 1,
   1.374 +    BF_CALC_MODE   = 2,
   1.375 +    BF_KEY_TIMES   = 3,
   1.376 +    BF_KEY_SPLINES = 4,
   1.377 +    BF_KEY_POINTS  = 5 // <animateMotion> only
   1.378 +  };
   1.379 +
   1.380 +  inline void SetAccumulateErrorFlag(bool aNewValue) {
   1.381 +    SetErrorFlag(BF_ACCUMULATE, aNewValue);
   1.382 +  }
   1.383 +  inline void SetAdditiveErrorFlag(bool aNewValue) {
   1.384 +    SetErrorFlag(BF_ADDITIVE, aNewValue);
   1.385 +  }
   1.386 +  inline void SetCalcModeErrorFlag(bool aNewValue) {
   1.387 +    SetErrorFlag(BF_CALC_MODE, aNewValue);
   1.388 +  }
   1.389 +  inline void SetKeyTimesErrorFlag(bool aNewValue) {
   1.390 +    SetErrorFlag(BF_KEY_TIMES, aNewValue);
   1.391 +  }
   1.392 +  inline void SetKeySplinesErrorFlag(bool aNewValue) {
   1.393 +    SetErrorFlag(BF_KEY_SPLINES, aNewValue);
   1.394 +  }
   1.395 +  inline void SetKeyPointsErrorFlag(bool aNewValue) {
   1.396 +    SetErrorFlag(BF_KEY_POINTS, aNewValue);
   1.397 +  }
   1.398 +  inline void SetErrorFlag(AnimationAttributeIdx aField, bool aValue) {
   1.399 +    if (aValue) {
   1.400 +      mErrorFlags |=  (0x01 << aField);
   1.401 +    } else {
   1.402 +      mErrorFlags &= ~(0x01 << aField);
   1.403 +    }
   1.404 +  }
   1.405 +
   1.406 +  // Members
   1.407 +  // -------
   1.408 +
   1.409 +  static nsAttrValue::EnumTable sAdditiveTable[];
   1.410 +  static nsAttrValue::EnumTable sCalcModeTable[];
   1.411 +  static nsAttrValue::EnumTable sAccumulateTable[];
   1.412 +
   1.413 +  FallibleTArray<double>          mKeyTimes;
   1.414 +  FallibleTArray<nsSMILKeySpline> mKeySplines;
   1.415 +
   1.416 +  // These are the parameters provided by the previous sample. Currently we
   1.417 +  // perform lazy calculation. That is, we only calculate the result if and when
   1.418 +  // instructed by the compositor. This allows us to apply the result directly
   1.419 +  // to the animation value and allows the compositor to filter out functions
   1.420 +  // that it determines will not contribute to the final result.
   1.421 +  nsSMILTime                    mSampleTime; // sample time within simple dur
   1.422 +  nsSMILTimeValue               mSimpleDuration;
   1.423 +  uint32_t                      mRepeatIteration;
   1.424 +
   1.425 +  nsSMILTime                    mBeginTime; // document time
   1.426 +
   1.427 +  // The owning animation element. This is used for sorting based on document
   1.428 +  // position and for fetching attribute values stored in the element.
   1.429 +  // Raw pointer is OK here, because this nsSMILAnimationFunction can't outlive
   1.430 +  // its owning animation element.
   1.431 +  mozilla::dom::SVGAnimationElement* mAnimationElement;
   1.432 +
   1.433 +  // Which attributes have been set but have had errors. This is not used for
   1.434 +  // all attributes but only those which have specified error behaviour
   1.435 +  // associated with them.
   1.436 +  uint16_t                      mErrorFlags;
   1.437 +
   1.438 +  // Allows us to check whether an animation function has changed target from
   1.439 +  // sample to sample (because if neither target nor animated value have
   1.440 +  // changed, we don't have to do anything).
   1.441 +  nsSMILWeakTargetIdentifier    mLastTarget;
   1.442 +
   1.443 +  // Boolean flags
   1.444 +  bool mIsActive:1;
   1.445 +  bool mIsFrozen:1;
   1.446 +  bool mLastValue:1;
   1.447 +  bool mHasChanged:1;
   1.448 +  bool mValueNeedsReparsingEverySample:1;
   1.449 +  bool mPrevSampleWasSingleValueAnimation:1;
   1.450 +  bool mWasSkippedInPrevSample:1;
   1.451 +};
   1.452 +
   1.453 +#endif // NS_SMILANIMATIONFUNCTION_H_

mercurial