summaryrefslogtreecommitdiffstats
path: root/dom/smil/SMILAnimationFunction.h
diff options
context:
space:
mode:
Diffstat (limited to 'dom/smil/SMILAnimationFunction.h')
-rw-r--r--dom/smil/SMILAnimationFunction.h444
1 files changed, 444 insertions, 0 deletions
diff --git a/dom/smil/SMILAnimationFunction.h b/dom/smil/SMILAnimationFunction.h
new file mode 100644
index 0000000000..8e85da76f6
--- /dev/null
+++ b/dom/smil/SMILAnimationFunction.h
@@ -0,0 +1,444 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef DOM_SMIL_SMILANIMATIONFUNCTION_H_
+#define DOM_SMIL_SMILANIMATIONFUNCTION_H_
+
+#include "mozilla/SMILAttr.h"
+#include "mozilla/SMILKeySpline.h"
+#include "mozilla/SMILTargetIdentifier.h"
+#include "mozilla/SMILTimeValue.h"
+#include "mozilla/SMILTypes.h"
+#include "mozilla/SMILValue.h"
+#include "nsAttrValue.h"
+#include "nsGkAtoms.h"
+#include "nsString.h"
+#include "nsTArray.h"
+
+namespace mozilla {
+namespace dom {
+class SVGAnimationElement;
+} // namespace dom
+
+//----------------------------------------------------------------------
+// SMILAnimationFunction
+//
+// The animation function calculates animation values. It it is provided with
+// time parameters (sample time, repeat iteration etc.) and it uses this to
+// build an appropriate animation value by performing interpolation and
+// addition operations.
+//
+// It is responsible for implementing the animation parameters of an animation
+// element (e.g. from, by, to, values, calcMode, additive, accumulate, keyTimes,
+// keySplines)
+//
+class SMILAnimationFunction {
+ public:
+ SMILAnimationFunction();
+
+ /*
+ * Sets the owning animation element which this class uses to query attribute
+ * values and compare document positions.
+ */
+ void SetAnimationElement(
+ mozilla::dom::SVGAnimationElement* aAnimationElement);
+
+ /*
+ * Sets animation-specific attributes (or marks them dirty, in the case
+ * of from/to/by/values).
+ *
+ * @param aAttribute The attribute being set
+ * @param aValue The updated value of the attribute.
+ * @param aResult The nsAttrValue object that may be used for storing the
+ * parsed result.
+ * @param aParseResult Outparam used for reporting parse errors. Will be set
+ * to NS_OK if everything succeeds.
+ * @return true if aAttribute is a recognized animation-related
+ * attribute; false otherwise.
+ */
+ virtual bool SetAttr(nsAtom* aAttribute, const nsAString& aValue,
+ nsAttrValue& aResult, nsresult* aParseResult = nullptr);
+
+ /*
+ * Unsets the given attribute.
+ *
+ * @returns true if aAttribute is a recognized animation-related
+ * attribute; false otherwise.
+ */
+ virtual bool UnsetAttr(nsAtom* aAttribute);
+
+ /**
+ * Indicate a new sample has occurred.
+ *
+ * @param aSampleTime The sample time for this timed element expressed in
+ * simple time.
+ * @param aSimpleDuration The simple duration for this timed element.
+ * @param aRepeatIteration The repeat iteration for this sample. The first
+ * iteration has a value of 0.
+ */
+ void SampleAt(SMILTime aSampleTime, const SMILTimeValue& aSimpleDuration,
+ uint32_t aRepeatIteration);
+
+ /**
+ * Indicate to sample using the last value defined for the animation function.
+ * This value is not normally sampled due to the end-point exclusive timing
+ * model but only occurs when the fill mode is "freeze" and the active
+ * duration is an even multiple of the simple duration.
+ *
+ * @param aRepeatIteration The repeat iteration for this sample. The first
+ * iteration has a value of 0.
+ */
+ void SampleLastValue(uint32_t aRepeatIteration);
+
+ /**
+ * Indicate that this animation is now active. This is used to instruct the
+ * animation function that it should now add its result to the animation
+ * sandwich. The begin time is also provided for proper prioritization of
+ * animation functions, and for this reason, this method must be called
+ * before either of the Sample methods.
+ *
+ * @param aBeginTime The begin time for the newly active interval.
+ */
+ void Activate(SMILTime aBeginTime);
+
+ /**
+ * Indicate that this animation is no longer active. This is used to instruct
+ * the animation function that it should no longer add its result to the
+ * animation sandwich.
+ *
+ * @param aIsFrozen true if this animation should continue to contribute
+ * to the animation sandwich using the most recent sample
+ * parameters.
+ */
+ void Inactivate(bool aIsFrozen);
+
+ /**
+ * Combines the result of this animation function for the last sample with the
+ * specified value.
+ *
+ * @param aSMILAttr This animation's target attribute. Used here for
+ * doing attribute-specific parsing of from/to/by/values.
+ *
+ * @param aResult The value to compose with.
+ */
+ void ComposeResult(const SMILAttr& aSMILAttr, SMILValue& aResult);
+
+ /**
+ * Returns the relative priority of this animation to another. The priority is
+ * used for determining the position of the animation in the animation
+ * sandwich -- higher priority animations are applied on top of lower
+ * priority animations.
+ *
+ * @return -1 if this animation has lower priority or 1 if this animation has
+ * higher priority
+ *
+ * This method should never return any other value, including 0.
+ */
+ int8_t CompareTo(const SMILAnimationFunction* aOther) const;
+
+ /*
+ * The following methods are provided so that the compositor can optimize its
+ * operations by only composing those animation that will affect the final
+ * result.
+ */
+
+ /**
+ * Indicates if the animation is currently active or frozen. Inactive
+ * animations will not contribute to the composed result.
+ *
+ * @return true if the animation is active or frozen, false otherwise.
+ */
+ bool IsActiveOrFrozen() const {
+ /*
+ * - Frozen animations should be considered active for the purposes of
+ * compositing.
+ * - This function does not assume that our SMILValues (by/from/to/values)
+ * have already been parsed.
+ */
+ return (mIsActive || mIsFrozen);
+ }
+
+ /**
+ * Indicates if the animation is active.
+ *
+ * @return true if the animation is active, false otherwise.
+ */
+ bool IsActive() const { return mIsActive; }
+
+ /**
+ * Indicates if this animation will replace the passed in result rather than
+ * adding to it. Animations that replace the underlying value may be called
+ * without first calling lower priority animations.
+ *
+ * @return True if the animation will replace, false if it will add or
+ * otherwise build on the passed in value.
+ */
+ virtual bool WillReplace() const;
+
+ /**
+ * Indicates if the parameters for this animation have changed since the last
+ * time it was composited. This allows rendering to be performed only when
+ * necessary, particularly when no animations are active.
+ *
+ * Note that the caller is responsible for determining if the animation
+ * target has changed (with help from my UpdateCachedTarget() method).
+ *
+ * @return true if the animation parameters have changed, false
+ * otherwise.
+ */
+ bool HasChanged() const;
+
+ /**
+ * This method lets us clear the 'HasChanged' flag for inactive animations
+ * after we've reacted to their change to the 'inactive' state, so that we
+ * won't needlessly recompose their targets in every sample.
+ *
+ * This should only be called on an animation function that is inactive and
+ * that returns true from HasChanged().
+ */
+ void ClearHasChanged() {
+ MOZ_ASSERT(HasChanged(),
+ "clearing mHasChanged flag, when it's already false");
+ MOZ_ASSERT(!IsActiveOrFrozen(),
+ "clearing mHasChanged flag for active animation");
+ mHasChanged = false;
+ }
+
+ /**
+ * Updates the cached record of our animation target, and returns a boolean
+ * that indicates whether the target has changed since the last call to this
+ * function. (This lets SMILCompositor check whether its animation
+ * functions have changed value or target since the last sample. If none of
+ * them have, then the compositor doesn't need to do anything.)
+ *
+ * @param aNewTarget A SMILTargetIdentifier representing the animation
+ * target of this function for this sample.
+ * @return true if |aNewTarget| is different from the old cached value;
+ * otherwise, false.
+ */
+ bool UpdateCachedTarget(const SMILTargetIdentifier& aNewTarget);
+
+ /**
+ * Returns true if this function was skipped in the previous sample (because
+ * there was a higher-priority non-additive animation). If a skipped animation
+ * function is later used, then the animation sandwich must be recomposited.
+ */
+ bool WasSkippedInPrevSample() const { return mWasSkippedInPrevSample; }
+
+ /**
+ * Mark this animation function as having been skipped. By marking the
+ * function as skipped, if it is used in a subsequent sample we'll know to
+ * recomposite the sandwich.
+ */
+ void SetWasSkipped() { mWasSkippedInPrevSample = true; }
+
+ /**
+ * Returns true if we need to recalculate the animation value on every sample.
+ * (e.g. because it depends on context like the font-size)
+ */
+ bool ValueNeedsReparsingEverySample() const {
+ return mValueNeedsReparsingEverySample;
+ }
+
+ // Comparator utility class, used for sorting SMILAnimationFunctions
+ class Comparator {
+ public:
+ bool Equals(const SMILAnimationFunction* aElem1,
+ const SMILAnimationFunction* aElem2) const {
+ return (aElem1->CompareTo(aElem2) == 0);
+ }
+ bool LessThan(const SMILAnimationFunction* aElem1,
+ const SMILAnimationFunction* aElem2) const {
+ return (aElem1->CompareTo(aElem2) < 0);
+ }
+ };
+
+ protected:
+ // alias declarations
+ using SMILValueArray = FallibleTArray<SMILValue>;
+
+ // Types
+ enum SMILCalcMode : uint8_t {
+ CALC_LINEAR,
+ CALC_DISCRETE,
+ CALC_PACED,
+ CALC_SPLINE
+ };
+
+ // Used for sorting SMILAnimationFunctions
+ SMILTime GetBeginTime() const { return mBeginTime; }
+
+ // Property getters
+ bool GetAccumulate() const;
+ bool GetAdditive() const;
+ virtual SMILCalcMode GetCalcMode() const;
+
+ // Property setters
+ nsresult SetAccumulate(const nsAString& aAccumulate, nsAttrValue& aResult);
+ nsresult SetAdditive(const nsAString& aAdditive, nsAttrValue& aResult);
+ nsresult SetCalcMode(const nsAString& aCalcMode, nsAttrValue& aResult);
+ nsresult SetKeyTimes(const nsAString& aKeyTimes, nsAttrValue& aResult);
+ nsresult SetKeySplines(const nsAString& aKeySplines, nsAttrValue& aResult);
+
+ // Property un-setters
+ void UnsetAccumulate();
+ void UnsetAdditive();
+ void UnsetCalcMode();
+ void UnsetKeyTimes();
+ void UnsetKeySplines();
+
+ // Helpers
+ virtual bool IsDisallowedAttribute(const nsAtom* aAttribute) const {
+ return false;
+ }
+ virtual nsresult InterpolateResult(const SMILValueArray& aValues,
+ SMILValue& aResult, SMILValue& aBaseValue);
+ nsresult AccumulateResult(const SMILValueArray& aValues, SMILValue& aResult);
+
+ nsresult ComputePacedPosition(const SMILValueArray& aValues,
+ double aSimpleProgress,
+ double& aIntervalProgress,
+ const SMILValue*& aFrom, const SMILValue*& aTo);
+ double ComputePacedTotalDistance(const SMILValueArray& aValues) const;
+
+ /**
+ * Adjust the simple progress, that is, the point within the simple duration,
+ * by applying any keyTimes.
+ */
+ double ScaleSimpleProgress(double aProgress, SMILCalcMode aCalcMode);
+ /**
+ * Adjust the progress within an interval, that is, between two animation
+ * values, by applying any keySplines.
+ */
+ double ScaleIntervalProgress(double aProgress, uint32_t aIntervalIndex);
+
+ // Convenience attribute getters
+ bool HasAttr(nsAtom* aAttName) const;
+ const nsAttrValue* GetAttr(nsAtom* aAttName) const;
+ bool GetAttr(nsAtom* aAttName, nsAString& aResult) const;
+
+ bool ParseAttr(nsAtom* aAttName, const SMILAttr& aSMILAttr,
+ SMILValue& aResult, bool& aPreventCachingOfSandwich) const;
+
+ virtual nsresult GetValues(const SMILAttr& aSMILAttr,
+ SMILValueArray& aResult);
+
+ virtual void CheckValueListDependentAttrs(uint32_t aNumValues);
+ void CheckKeyTimes(uint32_t aNumValues);
+ void CheckKeySplines(uint32_t aNumValues);
+
+ virtual bool IsToAnimation() const {
+ return !HasAttr(nsGkAtoms::values) && HasAttr(nsGkAtoms::to) &&
+ !HasAttr(nsGkAtoms::from);
+ }
+
+ // Returns true if we know our composited value won't change over the
+ // simple duration of this animation (for a fixed base value).
+ virtual bool IsValueFixedForSimpleDuration() const;
+
+ inline bool IsAdditive() const {
+ /*
+ * Animation is additive if:
+ *
+ * (1) additive = "sum" (GetAdditive() == true), or
+ * (2) it is 'by animation' (by is set, from and values are not)
+ *
+ * Although animation is not additive if it is 'to animation'
+ */
+ bool isByAnimation = (!HasAttr(nsGkAtoms::values) &&
+ HasAttr(nsGkAtoms::by) && !HasAttr(nsGkAtoms::from));
+ return !IsToAnimation() && (GetAdditive() || isByAnimation);
+ }
+
+ // Setters for error flags
+ // These correspond to bit-indices in mErrorFlags, for tracking parse errors
+ // in these attributes, when those parse errors should block us from doing
+ // animation.
+ enum AnimationAttributeIdx {
+ BF_ACCUMULATE = 0,
+ BF_ADDITIVE = 1,
+ BF_CALC_MODE = 2,
+ BF_KEY_TIMES = 3,
+ BF_KEY_SPLINES = 4,
+ BF_KEY_POINTS = 5 // <animateMotion> only
+ };
+
+ inline void SetAccumulateErrorFlag(bool aNewValue) {
+ SetErrorFlag(BF_ACCUMULATE, aNewValue);
+ }
+ inline void SetAdditiveErrorFlag(bool aNewValue) {
+ SetErrorFlag(BF_ADDITIVE, aNewValue);
+ }
+ inline void SetCalcModeErrorFlag(bool aNewValue) {
+ SetErrorFlag(BF_CALC_MODE, aNewValue);
+ }
+ inline void SetKeyTimesErrorFlag(bool aNewValue) {
+ SetErrorFlag(BF_KEY_TIMES, aNewValue);
+ }
+ inline void SetKeySplinesErrorFlag(bool aNewValue) {
+ SetErrorFlag(BF_KEY_SPLINES, aNewValue);
+ }
+ inline void SetKeyPointsErrorFlag(bool aNewValue) {
+ SetErrorFlag(BF_KEY_POINTS, aNewValue);
+ }
+ inline void SetErrorFlag(AnimationAttributeIdx aField, bool aValue) {
+ if (aValue) {
+ mErrorFlags |= (0x01 << aField);
+ } else {
+ mErrorFlags &= ~(0x01 << aField);
+ }
+ }
+
+ // Members
+ // -------
+
+ static nsAttrValue::EnumTable sAdditiveTable[];
+ static nsAttrValue::EnumTable sCalcModeTable[];
+ static nsAttrValue::EnumTable sAccumulateTable[];
+
+ FallibleTArray<double> mKeyTimes;
+ FallibleTArray<SMILKeySpline> mKeySplines;
+
+ // These are the parameters provided by the previous sample. Currently we
+ // perform lazy calculation. That is, we only calculate the result if and when
+ // instructed by the compositor. This allows us to apply the result directly
+ // to the animation value and allows the compositor to filter out functions
+ // that it determines will not contribute to the final result.
+ SMILTime mSampleTime; // sample time within simple dur
+ SMILTimeValue mSimpleDuration;
+ uint32_t mRepeatIteration;
+
+ SMILTime mBeginTime; // document time
+
+ // The owning animation element. This is used for sorting based on document
+ // position and for fetching attribute values stored in the element.
+ // Raw pointer is OK here, because this SMILAnimationFunction can't outlive
+ // its owning animation element.
+ mozilla::dom::SVGAnimationElement* mAnimationElement;
+
+ // Which attributes have been set but have had errors. This is not used for
+ // all attributes but only those which have specified error behaviour
+ // associated with them.
+ uint16_t mErrorFlags;
+
+ // Allows us to check whether an animation function has changed target from
+ // sample to sample (because if neither target nor animated value have
+ // changed, we don't have to do anything).
+ SMILWeakTargetIdentifier mLastTarget;
+
+ // Boolean flags
+ bool mIsActive : 1;
+ bool mIsFrozen : 1;
+ bool mLastValue : 1;
+ bool mHasChanged : 1;
+ bool mValueNeedsReparsingEverySample : 1;
+ bool mPrevSampleWasSingleValueAnimation : 1;
+ bool mWasSkippedInPrevSample : 1;
+};
+
+} // namespace mozilla
+
+#endif // DOM_SMIL_SMILANIMATIONFUNCTION_H_