tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

SMILAnimationFunction.h (16960B)


      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 DOM_SMIL_SMILANIMATIONFUNCTION_H_
      8 #define DOM_SMIL_SMILANIMATIONFUNCTION_H_
      9 
     10 #include "mozilla/SMILAttr.h"
     11 #include "mozilla/SMILKeySpline.h"
     12 #include "mozilla/SMILTargetIdentifier.h"
     13 #include "mozilla/SMILTimeValue.h"
     14 #include "mozilla/SMILTypes.h"
     15 #include "mozilla/SMILValue.h"
     16 #include "nsAttrValue.h"
     17 #include "nsContentUtils.h"
     18 #include "nsGkAtoms.h"
     19 #include "nsString.h"
     20 #include "nsTArray.h"
     21 
     22 namespace mozilla {
     23 namespace dom {
     24 class SVGAnimationElement;
     25 }  // namespace dom
     26 
     27 //----------------------------------------------------------------------
     28 // SMILAnimationFunction
     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 SMILAnimationFunction {
     40 public:
     41  SMILAnimationFunction();
     42 
     43  /*
     44   * Sets the owning animation element which this class uses to query attribute
     45   * values and compare document positions.
     46   */
     47  void SetAnimationElement(
     48      mozilla::dom::SVGAnimationElement* aAnimationElement);
     49 
     50  bool HasSameAnimationElement(const SMILAnimationFunction* aOther) const {
     51    return aOther && aOther->mAnimationElement == mAnimationElement;
     52  };
     53 
     54  /*
     55   * Sets animation-specific attributes (or marks them dirty, in the case
     56   * of from/to/by/values).
     57   *
     58   * @param aAttribute The attribute being set
     59   * @param aValue     The updated value of the attribute.
     60   * @param aResult    The nsAttrValue object that may be used for storing the
     61   *                   parsed result.
     62   * @param aParseResult  Outparam used for reporting parse errors. Will be set
     63   *                      to NS_OK if everything succeeds.
     64   * @return  true if aAttribute is a recognized animation-related
     65   *          attribute; false otherwise.
     66   */
     67  virtual bool SetAttr(nsAtom* aAttribute, const nsAString& aValue,
     68                       nsAttrValue& aResult, nsresult* aParseResult = nullptr);
     69 
     70  /*
     71   * Unsets the given attribute.
     72   *
     73   * @returns true if aAttribute is a recognized animation-related
     74   *          attribute; false otherwise.
     75   */
     76  virtual bool UnsetAttr(nsAtom* aAttribute);
     77 
     78  /**
     79   * Indicate a new sample has occurred.
     80   *
     81   * @param aSampleTime The sample time for this timed element expressed in
     82   *                    simple time.
     83   * @param aSimpleDuration The simple duration for this timed element.
     84   * @param aRepeatIteration  The repeat iteration for this sample. The first
     85   *                          iteration has a value of 0.
     86   */
     87  void SampleAt(SMILTime aSampleTime, const SMILTimeValue& aSimpleDuration,
     88                uint32_t aRepeatIteration);
     89 
     90  /**
     91   * Indicate to sample using the last value defined for the animation function.
     92   * This value is not normally sampled due to the end-point exclusive timing
     93   * model but only occurs when the fill mode is "freeze" and the active
     94   * duration is an even multiple of the simple duration.
     95   *
     96   * @param aRepeatIteration  The repeat iteration for this sample. The first
     97   *                          iteration has a value of 0.
     98   */
     99  void SampleLastValue(uint32_t aRepeatIteration);
    100 
    101  /**
    102   * Indicate that this animation is now active. This is used to instruct the
    103   * animation function that it should now add its result to the animation
    104   * sandwich. The begin time is also provided for proper prioritization of
    105   * animation functions, and for this reason, this method must be called
    106   * before either of the Sample methods.
    107   *
    108   * @param aBeginTime The begin time for the newly active interval.
    109   */
    110  void Activate(SMILTime aBeginTime);
    111 
    112  /**
    113   * Indicate that this animation is no longer active. This is used to instruct
    114   * the animation function that it should no longer add its result to the
    115   * animation sandwich.
    116   *
    117   * @param aIsFrozen true if this animation should continue to contribute
    118   *                  to the animation sandwich using the most recent sample
    119   *                  parameters.
    120   */
    121  void Inactivate(bool aIsFrozen);
    122 
    123  /**
    124   * Combines the result of this animation function for the last sample with the
    125   * specified value.
    126   *
    127   * @param aSMILAttr This animation's target attribute. Used here for
    128   *                  doing attribute-specific parsing of from/to/by/values.
    129   *
    130   * @param aResult   The value to compose with.
    131   */
    132  void ComposeResult(const SMILAttr& aSMILAttr, SMILValue& aResult);
    133 
    134  /**
    135   * Returns the relative priority of this animation to another. The priority is
    136   * used for determining the position of the animation in the animation
    137   * sandwich -- higher priority animations are applied on top of lower
    138   * priority animations.
    139   *
    140   * @return a value < 0 if this animation has lower priority or > 0 if this
    141   *         animation has higher priority. Returns 0 if the elements are the
    142   *         same.
    143   */
    144  int32_t CompareTo(const SMILAnimationFunction* aOther,
    145                    nsContentUtils::NodeIndexCache& aCache) const;
    146 
    147  /*
    148   * The following methods are provided so that the compositor can optimize its
    149   * operations by only composing those animation that will affect the final
    150   * result.
    151   */
    152 
    153  /**
    154   * Indicates if the animation is currently active or frozen. Inactive
    155   * animations will not contribute to the composed result.
    156   *
    157   * @return  true if the animation is active or frozen, false otherwise.
    158   */
    159  bool IsActiveOrFrozen() const {
    160    /*
    161     * - Frozen animations should be considered active for the purposes of
    162     * compositing.
    163     * - This function does not assume that our SMILValues (by/from/to/values)
    164     * have already been parsed.
    165     */
    166    return mIsActive || mIsFrozen;
    167  }
    168 
    169  /**
    170   * Indicates if the animation is active.
    171   *
    172   * @return  true if the animation is active, false otherwise.
    173   */
    174  bool IsActive() const { return mIsActive; }
    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    MOZ_ASSERT(HasChanged(),
    209               "clearing mHasChanged flag, when it's already false");
    210    MOZ_ASSERT(!IsActiveOrFrozen(),
    211               "clearing mHasChanged flag for active animation");
    212    mHasChanged = false;
    213  }
    214 
    215  /**
    216   * Updates the cached record of our animation target, and returns a boolean
    217   * that indicates whether the target has changed since the last call to this
    218   * function. (This lets SMILCompositor check whether its animation
    219   * functions have changed value or target since the last sample.  If none of
    220   * them have, then the compositor doesn't need to do anything.)
    221   *
    222   * @param aNewTarget A SMILTargetIdentifier representing the animation
    223   *                   target of this function for this sample.
    224   * @return  true if |aNewTarget| is different from the old cached value;
    225   *          otherwise, false.
    226   */
    227  bool UpdateCachedTarget(const SMILTargetIdentifier& aNewTarget);
    228 
    229  /**
    230   * Returns true if this function was skipped in the previous sample (because
    231   * there was a higher-priority non-additive animation). If a skipped animation
    232   * function is later used, then the animation sandwich must be recomposited.
    233   */
    234  bool WasSkippedInPrevSample() const { return mWasSkippedInPrevSample; }
    235 
    236  /**
    237   * Mark this animation function as having been skipped. By marking the
    238   * function as skipped, if it is used in a subsequent sample we'll know to
    239   * recomposite the sandwich.
    240   */
    241  void SetWasSkipped() { mWasSkippedInPrevSample = true; }
    242 
    243  /**
    244   * Returns true if we need to recalculate the animation value on every sample.
    245   * (e.g. because it depends on context like the font-size)
    246   */
    247  bool ValueNeedsReparsingEverySample() const {
    248    return mValueNeedsReparsingEverySample;
    249  }
    250 
    251  // Comparator utility class, used for sorting SMILAnimationFunctions
    252  class MOZ_STACK_CLASS Comparator final {
    253   public:
    254    bool Equals(const SMILAnimationFunction* aElem1,
    255                const SMILAnimationFunction* aElem2) const {
    256      return aElem1->CompareTo(aElem2, mCache) == 0;
    257    }
    258    bool LessThan(const SMILAnimationFunction* aElem1,
    259                  const SMILAnimationFunction* aElem2) const {
    260      return aElem1->CompareTo(aElem2, mCache) < 0;
    261    }
    262 
    263   private:
    264    mutable nsContentUtils::NodeIndexCache mCache;
    265  };
    266 
    267 protected:
    268  // alias declarations
    269  using SMILValueArray = FallibleTArray<SMILValue>;
    270 
    271  // Types
    272  enum SMILCalcMode : uint8_t {
    273    CALC_LINEAR,
    274    CALC_DISCRETE,
    275    CALC_PACED,
    276    CALC_SPLINE
    277  };
    278 
    279  // Used for sorting SMILAnimationFunctions
    280  SMILTime GetBeginTime() const { return mBeginTime; }
    281 
    282  // Property getters
    283  bool GetAccumulate() const;
    284  bool GetAdditive() const;
    285  virtual SMILCalcMode GetCalcMode() const;
    286 
    287  // Property setters
    288  nsresult SetAccumulate(const nsAString& aAccumulate, nsAttrValue& aResult);
    289  nsresult SetAdditive(const nsAString& aAdditive, nsAttrValue& aResult);
    290  nsresult SetCalcMode(const nsAString& aCalcMode, nsAttrValue& aResult);
    291  nsresult SetKeyTimes(const nsAString& aKeyTimes, nsAttrValue& aResult);
    292  nsresult SetKeySplines(const nsAString& aKeySplines, nsAttrValue& aResult);
    293 
    294  // Property un-setters
    295  void UnsetAccumulate();
    296  void UnsetAdditive();
    297  void UnsetCalcMode();
    298  void UnsetKeyTimes();
    299  void UnsetKeySplines();
    300 
    301  // Helpers
    302  virtual bool IsDisallowedAttribute(const nsAtom* aAttribute) const {
    303    return false;
    304  }
    305  virtual nsresult InterpolateResult(const SMILValueArray& aValues,
    306                                     SMILValue& aResult, SMILValue& aBaseValue);
    307  nsresult AccumulateResult(const SMILValueArray& aValues, SMILValue& aResult);
    308 
    309  nsresult ComputePacedPosition(const SMILValueArray& aValues,
    310                                double aSimpleProgress,
    311                                double& aIntervalProgress,
    312                                const SMILValue*& aFrom, const SMILValue*& aTo);
    313  double ComputePacedTotalDistance(const SMILValueArray& aValues) const;
    314 
    315  /**
    316   * Adjust the simple progress, that is, the point within the simple duration,
    317   * by applying any keyTimes and number of values.
    318   */
    319  double ScaleSimpleProgress(double aProgress, SMILCalcMode aCalcMode,
    320                             double aValueMultiplier);
    321  /**
    322   * Adjust the progress within an interval, that is, between two animation
    323   * values, by applying any keySplines.
    324   */
    325  double ScaleIntervalProgress(double aProgress, uint32_t aIntervalIndex);
    326 
    327  // Convenience attribute getters
    328  bool HasAttr(nsAtom* aAttName) const;
    329  const nsAttrValue* GetAttr(nsAtom* aAttName) const;
    330  bool GetAttr(nsAtom* aAttName, nsAString& aResult) const;
    331 
    332  bool ParseAttr(nsAtom* aAttName, const SMILAttr& aSMILAttr,
    333                 SMILValue& aResult, bool& aPreventCachingOfSandwich) const;
    334 
    335  virtual nsresult GetValues(const SMILAttr& aSMILAttr,
    336                             SMILValueArray& aResult);
    337 
    338  virtual void CheckValueListDependentAttrs(uint32_t aNumValues);
    339  void CheckKeyTimes(uint32_t aNumValues);
    340  void CheckKeySplines(uint32_t aNumValues);
    341 
    342  virtual bool IsToAnimation() const {
    343    return !HasAttr(nsGkAtoms::values) && HasAttr(nsGkAtoms::to) &&
    344           !HasAttr(nsGkAtoms::from);
    345  }
    346 
    347  // Returns true if we know our composited value won't change over the
    348  // simple duration of this animation (for a fixed base value).
    349  virtual bool IsValueFixedForSimpleDuration() const;
    350 
    351  inline bool IsAdditive() const {
    352    /*
    353     * Animation is additive if:
    354     *
    355     * (1) additive = "sum" (GetAdditive() == true), or
    356     * (2) it is 'by animation' (by is set, from and values are not)
    357     *
    358     * Although animation is not additive if it is 'to animation'
    359     */
    360    bool isByAnimation = (!HasAttr(nsGkAtoms::values) &&
    361                          HasAttr(nsGkAtoms::by) && !HasAttr(nsGkAtoms::from));
    362    return !IsToAnimation() && (GetAdditive() || isByAnimation);
    363  }
    364 
    365  // Setters for error flags
    366  // These correspond to bit-indices in mErrorFlags, for tracking parse errors
    367  // in these attributes, when those parse errors should block us from doing
    368  // animation.
    369  enum AnimationAttributeIdx {
    370    BF_ACCUMULATE = 0,
    371    BF_ADDITIVE = 1,
    372    BF_CALC_MODE = 2,
    373    BF_KEY_TIMES = 3,
    374    BF_KEY_SPLINES = 4,
    375    BF_KEY_POINTS = 5  // <animateMotion> only
    376  };
    377 
    378  inline void SetAccumulateErrorFlag(bool aNewValue) {
    379    SetErrorFlag(BF_ACCUMULATE, aNewValue);
    380  }
    381  inline void SetAdditiveErrorFlag(bool aNewValue) {
    382    SetErrorFlag(BF_ADDITIVE, aNewValue);
    383  }
    384  inline void SetCalcModeErrorFlag(bool aNewValue) {
    385    SetErrorFlag(BF_CALC_MODE, aNewValue);
    386  }
    387  inline void SetKeyTimesErrorFlag(bool aNewValue) {
    388    SetErrorFlag(BF_KEY_TIMES, aNewValue);
    389  }
    390  inline void SetKeySplinesErrorFlag(bool aNewValue) {
    391    SetErrorFlag(BF_KEY_SPLINES, aNewValue);
    392  }
    393  inline void SetKeyPointsErrorFlag(bool aNewValue) {
    394    SetErrorFlag(BF_KEY_POINTS, aNewValue);
    395  }
    396  inline void SetErrorFlag(AnimationAttributeIdx aField, bool aValue) {
    397    if (aValue) {
    398      mErrorFlags |= (0x01 << aField);
    399    } else {
    400      mErrorFlags &= ~(0x01 << aField);
    401    }
    402  }
    403 
    404  // Members
    405  // -------
    406 
    407  static constexpr nsAttrValue::EnumTableEntry sAdditiveTable[] = {
    408      {"replace", false},
    409      {"sum", true},
    410  };
    411 
    412  static constexpr nsAttrValue::EnumTableEntry sAccumulateTable[] = {
    413      {"none", false},
    414      {"sum", true},
    415  };
    416 
    417  static constexpr nsAttrValue::EnumTableEntry sCalcModeTable[] = {
    418      {"linear", CALC_LINEAR},
    419      {"discrete", CALC_DISCRETE},
    420      {"paced", CALC_PACED},
    421      {"spline", CALC_SPLINE},
    422  };
    423 
    424  FallibleTArray<double> mKeyTimes;
    425  FallibleTArray<SMILKeySpline> mKeySplines;
    426 
    427  // These are the parameters provided by the previous sample. Currently we
    428  // perform lazy calculation. That is, we only calculate the result if and when
    429  // instructed by the compositor. This allows us to apply the result directly
    430  // to the animation value and allows the compositor to filter out functions
    431  // that it determines will not contribute to the final result.
    432  SMILTime mSampleTime;  // sample time within simple dur
    433  SMILTimeValue mSimpleDuration;
    434  uint32_t mRepeatIteration;
    435 
    436  SMILTime mBeginTime;  // document time
    437 
    438  // The owning animation element. This is used for sorting based on document
    439  // position and for fetching attribute values stored in the element.
    440  // Raw pointer is OK here, because this SMILAnimationFunction can't outlive
    441  // its owning animation element.
    442  mozilla::dom::SVGAnimationElement* mAnimationElement;
    443 
    444  // Which attributes have been set but have had errors. This is not used for
    445  // all attributes but only those which have specified error behaviour
    446  // associated with them.
    447  uint16_t mErrorFlags;
    448 
    449  // Allows us to check whether an animation function has changed target from
    450  // sample to sample (because if neither target nor animated value have
    451  // changed, we don't have to do anything).
    452  SMILWeakTargetIdentifier mLastTarget;
    453 
    454  // Boolean flags
    455  bool mIsActive : 1;
    456  bool mIsFrozen : 1;
    457  bool mLastValue : 1;
    458  bool mHasChanged : 1;
    459  bool mValueNeedsReparsingEverySample : 1;
    460  bool mPrevSampleWasSingleValueAnimation : 1;
    461  bool mWasSkippedInPrevSample : 1;
    462 };
    463 
    464 }  // namespace mozilla
    465 
    466 #endif  // DOM_SMIL_SMILANIMATIONFUNCTION_H_