gecko/dom/animation/Animation.h
L. David Baron 5ff37bf6f6 Bug 960465 patch 14 - Retain finished transitions until the next style change or until removed from transition-property. r=birtles
Note that this increases memory use for completed transitions since we
don't throw away the data when the transitions complete.  That said,
this matches what we do for CSS Animations, and it's needed (once we
switch to the new rules for starting transitions) to maintain the
invariant that unrelated style changes don't trigger transitions.

The storage issues could be optimized in the future if it turns out to
be a problem, but I think that's unlikely, given that we'll never store
more than one for any element+property combination.
2015-02-17 11:15:04 +13:00

294 lines
9.2 KiB
C++

/* vim: set shiftwidth=2 tabstop=8 autoindent cindent expandtab: */
/* 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 mozilla_dom_Animation_h
#define mozilla_dom_Animation_h
#include "nsAutoPtr.h"
#include "nsCycleCollectionParticipant.h"
#include "nsCSSPseudoElements.h"
#include "nsIDocument.h"
#include "nsWrapperCache.h"
#include "mozilla/Attributes.h"
#include "mozilla/StickyTimeDuration.h"
#include "mozilla/StyleAnimationValue.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/Nullable.h"
#include "nsSMILKeySpline.h"
#include "nsStyleStruct.h" // for nsTimingFunction
struct JSContext;
class nsCSSPropertySet;
namespace mozilla {
namespace css {
class AnimValuesStyleRule;
} // namespace css
/**
* Input timing parameters.
*
* Eventually this will represent all the input timing parameters specified
* by content but for now it encapsulates just the subset of those
* parameters passed to GetPositionInIteration.
*/
struct AnimationTiming
{
TimeDuration mIterationDuration;
TimeDuration mDelay;
float mIterationCount; // mozilla::PositiveInfinity<float>() means infinite
uint8_t mDirection;
uint8_t mFillMode;
bool FillsForwards() const {
return mFillMode == NS_STYLE_ANIMATION_FILL_MODE_BOTH ||
mFillMode == NS_STYLE_ANIMATION_FILL_MODE_FORWARDS;
}
bool FillsBackwards() const {
return mFillMode == NS_STYLE_ANIMATION_FILL_MODE_BOTH ||
mFillMode == NS_STYLE_ANIMATION_FILL_MODE_BACKWARDS;
}
};
/**
* Stores the results of calculating the timing properties of an animation
* at a given sample time.
*/
struct ComputedTiming
{
ComputedTiming()
: mTimeFraction(kNullTimeFraction)
, mCurrentIteration(0)
, mPhase(AnimationPhase_Null)
{ }
static const double kNullTimeFraction;
// The total duration of the animation including all iterations.
// Will equal StickyTimeDuration::Forever() if the animation repeats
// indefinitely.
StickyTimeDuration mActiveDuration;
// Will be kNullTimeFraction if the animation is neither animating nor
// filling at the sampled time.
double mTimeFraction;
// Zero-based iteration index (meaningless if mTimeFraction is
// kNullTimeFraction).
uint64_t mCurrentIteration;
enum {
// Not sampled (null sample time)
AnimationPhase_Null,
// Sampled prior to the start of the active interval
AnimationPhase_Before,
// Sampled within the active interval
AnimationPhase_Active,
// Sampled after (or at) the end of the active interval
AnimationPhase_After
} mPhase;
};
class ComputedTimingFunction
{
public:
typedef nsTimingFunction::Type Type;
void Init(const nsTimingFunction &aFunction);
double GetValue(double aPortion) const;
const nsSMILKeySpline* GetFunction() const {
NS_ASSERTION(mType == nsTimingFunction::Function, "Type mismatch");
return &mTimingFunction;
}
Type GetType() const { return mType; }
uint32_t GetSteps() const { return mSteps; }
private:
Type mType;
nsSMILKeySpline mTimingFunction;
uint32_t mSteps;
};
struct AnimationPropertySegment
{
float mFromKey, mToKey;
StyleAnimationValue mFromValue, mToValue;
ComputedTimingFunction mTimingFunction;
};
struct AnimationProperty
{
nsCSSProperty mProperty;
InfallibleTArray<AnimationPropertySegment> mSegments;
};
struct ElementPropertyTransition;
namespace dom {
class AnimationEffect;
class Animation : public nsWrapperCache
{
public:
Animation(nsIDocument* aDocument,
Element* aTarget,
nsCSSPseudoElements::Type aPseudoType,
const AnimationTiming &aTiming,
const nsSubstring& aName)
: mDocument(aDocument)
, mTarget(aTarget)
, mTiming(aTiming)
, mName(aName)
, mIsFinishedTransition(false)
, mPseudoType(aPseudoType)
{
MOZ_ASSERT(aTarget, "null animation target is not yet supported");
}
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(Animation)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(Animation)
nsIDocument* GetParentObject() const { return mDocument; }
virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
// FIXME: If we succeed in moving transition-specific code to a type of
// AnimationEffect (as per the Web Animations API) we should remove these
// virtual methods.
virtual ElementPropertyTransition* AsTransition() { return nullptr; }
virtual const ElementPropertyTransition* AsTransition() const {
return nullptr;
}
// Animation interface
// This currently returns a new object each time when used from C++ but is
// cached when used from JS.
already_AddRefed<AnimationEffect> GetEffect();
Element* GetTarget() const {
// Currently we only implement Element.getAnimationPlayers() which only
// returns animations targetting Elements so this should never
// be called for an animation that targets a pseudo-element.
MOZ_ASSERT(mPseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement,
"Requesting the target of an Animation that targets a"
" pseudo-element is not yet supported.");
return mTarget;
}
// Temporary workaround to return both the target element and pseudo-type
// until we implement PseudoElement.
void GetTarget(Element*& aTarget,
nsCSSPseudoElements::Type& aPseudoType) const {
aTarget = mTarget;
aPseudoType = mPseudoType;
}
void SetParentTime(Nullable<TimeDuration> aParentTime);
const AnimationTiming& Timing() const {
return mTiming;
}
AnimationTiming& Timing() {
return mTiming;
}
const nsString& Name() const {
return mName;
}
// Return the duration from the start the active interval to the point where
// the animation begins playback. This is zero unless the animation has
// a negative delay in which case it is the absolute value of the delay.
// This is used for setting the elapsedTime member of CSS AnimationEvents.
TimeDuration InitialAdvance() const {
return std::max(TimeDuration(), mTiming.mDelay * -1);
}
Nullable<TimeDuration> GetLocalTime() const {
// Since the *animation* start time is currently always zero, the local
// time is equal to the parent time.
return mParentTime;
}
// This function takes as input the timing parameters of an animation and
// returns the computed timing at the specified local time.
//
// The local time may be null in which case only static parameters such as the
// active duration are calculated. All other members of the returned object
// are given a null/initial value.
//
// This function returns ComputedTiming::kNullTimeFraction for the
// mTimeFraction member of the return value if the animation should not be
// run (because it is not currently active and is not filling at this time).
static ComputedTiming
GetComputedTimingAt(const Nullable<TimeDuration>& aLocalTime,
const AnimationTiming& aTiming);
// Shortcut for that gets the computed timing using the current local time as
// calculated from the timeline time.
ComputedTiming GetComputedTiming(const AnimationTiming* aTiming
= nullptr) const {
return GetComputedTimingAt(GetLocalTime(), aTiming ? *aTiming : mTiming);
}
// Return the duration of the active interval for the given timing parameters.
static StickyTimeDuration
ActiveDuration(const AnimationTiming& aTiming);
// After transitions finish they need to be retained in order to
// address the issue described in
// https://lists.w3.org/Archives/Public/www-style/2015Jan/0444.html .
// However, finished transitions are ignored for many purposes.
bool IsFinishedTransition() const {
return mIsFinishedTransition;
}
void SetIsFinishedTransition() {
MOZ_ASSERT(AsTransition(),
"Calling SetIsFinishedTransition but it's not a transition");
mIsFinishedTransition = true;
}
bool IsCurrent() const;
bool IsInEffect() const;
bool HasAnimationOfProperty(nsCSSProperty aProperty) const;
const InfallibleTArray<AnimationProperty>& Properties() const {
return mProperties;
}
InfallibleTArray<AnimationProperty>& Properties() {
return mProperties;
}
// Updates |aStyleRule| with the animation values produced by this
// Animation for the current time except any properties already contained
// in |aSetProperties|.
// Any updated properties are added to |aSetProperties|.
void ComposeStyle(nsRefPtr<css::AnimValuesStyleRule>& aStyleRule,
nsCSSPropertySet& aSetProperties);
protected:
virtual ~Animation() { }
// We use a document for a parent object since the other likely candidate,
// the target element, can be empty.
nsCOMPtr<nsIDocument> mDocument;
nsCOMPtr<Element> mTarget;
Nullable<TimeDuration> mParentTime;
AnimationTiming mTiming;
nsString mName;
// A flag to mark transitions that have finished and are due to
// be removed on the next throttle-able cycle.
bool mIsFinishedTransition;
nsCSSPseudoElements::Type mPseudoType;
InfallibleTArray<AnimationProperty> mProperties;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_Animation_h