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_