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/. */
7 #ifndef mozilla_dom_CSSTransition_h
8 #define mozilla_dom_CSSTransition_h
10 #include "mozilla/ComputedTiming.h"
11 #include "mozilla/dom/Animation.h"
12 #include "mozilla/StyleAnimationValue.h"
13 #include "AnimationCommon.h"
15 class nsIGlobalObject
;
20 class CSSTransition final
: public Animation
{
22 explicit CSSTransition(nsIGlobalObject
* aGlobal
)
24 mPreviousTransitionPhase(TransitionPhase::Idle
),
25 mNeedsNewAnimationIndexWhenRun(false),
26 mTransitionProperty(eCSSProperty_UNKNOWN
) {}
28 JSObject
* WrapObject(JSContext
* aCx
,
29 JS::Handle
<JSObject
*> aGivenProto
) override
;
31 CSSTransition
* AsCSSTransition() override
{ return this; }
32 const CSSTransition
* AsCSSTransition() const override
{ return this; }
34 // CSSTransition interface
35 void GetTransitionProperty(nsString
& aRetVal
) const;
37 // Animation interface overrides
38 AnimationPlayState
PlayStateFromJS() const override
;
39 bool PendingFromJS() const override
;
40 void PlayFromJS(ErrorResult
& aRv
) override
;
42 // A variant of Play() that avoids posting style updates since this method
43 // is expected to be called whilst already updating style.
44 void PlayFromStyle() {
46 PlayNoUpdate(rv
, Animation::LimitBehavior::Continue
);
47 // play() should not throw when LimitBehavior is Continue
48 MOZ_ASSERT(!rv
.Failed(), "Unexpected exception playing transition");
51 void CancelFromStyle(PostRestyleMode aPostRestyle
) {
52 // The animation index to use for compositing will be established when
53 // this transition next transitions out of the idle state but we still
54 // update it now so that the sort order of this transition remains
55 // defined until that moment.
57 // See longer explanation in CSSAnimation::CancelFromStyle.
58 mAnimationIndex
= sNextAnimationIndex
++;
59 mNeedsNewAnimationIndexWhenRun
= true;
61 Animation::Cancel(aPostRestyle
);
63 // It is important we do this *after* calling Cancel().
64 // This is because Cancel() will end up posting a restyle and
65 // that restyle should target the *transitions* level of the cascade.
66 // However, once we clear the owning element, CascadeLevel() will begin
67 // returning CascadeLevel::Animations.
68 mOwningElement
= OwningElementRef();
71 void SetEffectFromStyle(KeyframeEffect
*);
75 nsCSSPropertyID
TransitionProperty() const;
76 AnimationValue
ToValue() const;
78 bool HasLowerCompositeOrderThan(const CSSTransition
& aOther
) const;
79 EffectCompositor::CascadeLevel
CascadeLevel() const override
{
80 return IsTiedToMarkup() ? EffectCompositor::CascadeLevel::Transitions
81 : EffectCompositor::CascadeLevel::Animations
;
84 void SetCreationSequence(uint64_t aIndex
) {
85 MOZ_ASSERT(IsTiedToMarkup());
86 mAnimationIndex
= aIndex
;
89 // Sets the owning element which is used for determining the composite
90 // oder of CSSTransition objects generated from CSS markup.
92 // @see mOwningElement
93 void SetOwningElement(const OwningElementRef
& aElement
) {
94 mOwningElement
= aElement
;
96 // True for transitions that are generated from CSS markup and continue to
97 // reflect changes to that markup.
98 bool IsTiedToMarkup() const { return mOwningElement
.IsSet(); }
100 // Return the animation current time based on a given TimeStamp, a given
101 // start time and a given playbackRate on a given timeline. This is useful
102 // when we estimate the current animated value running on the compositor
103 // because the animation on the compositor may be running ahead while
104 // main-thread is busy.
105 static Nullable
<TimeDuration
> GetCurrentTimeAt(
106 const AnimationTimeline
& aTimeline
, const TimeStamp
& aBaseTime
,
107 const TimeDuration
& aStartTime
, double aPlaybackRate
);
109 void MaybeQueueCancelEvent(const StickyTimeDuration
& aActiveTime
) override
{
110 QueueEvents(aActiveTime
);
113 // Compute the portion of the *value* space that we should be through
114 // at the current time. (The input to the transition timing function
115 // has time units, the output has value units.)
116 double CurrentValuePortion() const;
118 const AnimationValue
& StartForReversingTest() const {
119 return mStartForReversingTest
;
121 double ReversePortion() const { return mReversePortion
; }
123 void SetReverseParameters(AnimationValue
&& aStartForReversingTest
,
124 double aReversePortion
) {
125 mStartForReversingTest
= std::move(aStartForReversingTest
);
126 mReversePortion
= aReversePortion
;
129 struct ReplacedTransitionProperties
{
130 TimeDuration mStartTime
;
131 double mPlaybackRate
;
132 TimingParams mTiming
;
133 Maybe
<StyleComputedTimingFunction
> mTimingFunction
;
134 AnimationValue mFromValue
, mToValue
;
136 void SetReplacedTransition(
137 ReplacedTransitionProperties
&& aReplacedTransition
) {
138 mReplacedTransition
.emplace(std::move(aReplacedTransition
));
141 // For a new transition interrupting an existing transition on the
142 // compositor, update the start value to match the value of the replaced
143 // transitions at the current time.
144 void UpdateStartValueFromReplacedTransition();
147 virtual ~CSSTransition() {
148 MOZ_ASSERT(!mOwningElement
.IsSet(),
149 "Owning element should be cleared "
150 "before a CSS transition is destroyed");
153 // Animation overrides
154 void UpdateTiming(SeekFlag aSeekFlag
,
155 SyncNotifyFlag aSyncNotifyFlag
) override
;
157 void QueueEvents(const StickyTimeDuration
& activeTime
= StickyTimeDuration());
159 enum class TransitionPhase
;
161 // The (pseudo-)element whose computed transition-property refers to this
162 // transition (if any).
164 // This is used for determining the relative composite order of transitions
165 // generated from CSS markup.
167 // Typically this will be the same as the target element of the keyframe
168 // effect associated with this transition. However, it can differ in the
169 // following circumstances:
171 // a) If script removes or replaces the effect of this transition,
172 // b) If this transition is cancelled (e.g. by updating the
173 // transition-property or removing the owning element from the document),
174 // c) If this object is generated from script using the CSSTransition
177 // For (b) and (c) the owning element will return !IsSet().
178 OwningElementRef mOwningElement
;
180 // The 'transition phase' used to determine which transition events need
181 // to be queued on this tick.
182 // See: https://drafts.csswg.org/css-transitions-2/#transition-phase
183 enum class TransitionPhase
{
184 Idle
= static_cast<int>(ComputedTiming::AnimationPhase::Idle
),
185 Before
= static_cast<int>(ComputedTiming::AnimationPhase::Before
),
186 Active
= static_cast<int>(ComputedTiming::AnimationPhase::Active
),
187 After
= static_cast<int>(ComputedTiming::AnimationPhase::After
),
190 TransitionPhase mPreviousTransitionPhase
;
192 // When true, indicates that when this transition next leaves the idle state,
193 // its animation index should be updated.
194 bool mNeedsNewAnimationIndexWhenRun
;
196 // Store the transition property and to-value here since we need that
197 // information in order to determine if there is an existing transition
198 // for a given style change. We can't store that information on the
199 // effect however since it can be replaced using the Web Animations API.
200 nsCSSPropertyID mTransitionProperty
;
201 AnimationValue mTransitionToValue
;
203 // This is the start value to be used for a check for whether a
204 // transition is being reversed. Normally the same as
205 // mEffect->mProperties[0].mSegments[0].mFromValue, except when this
206 // transition started as the reversal of another in-progress transition
207 // or when the effect has been mutated using the Web Animations API.
209 // Needed so we can handle two reverses in a row.
210 AnimationValue mStartForReversingTest
;
212 // Likewise, the portion (in value space) of the "full" reversed
213 // transition that we're actually covering. For example, if a :hover
214 // effect has a transition that moves the element 10px to the right
215 // (by changing 'left' from 0px to 10px), and the mouse moves in to
216 // the element (starting the transition) but then moves out after the
217 // transition has advanced 4px, the second transition (from 10px/4px
218 // to 0px) will have mReversePortion of 0.4. (If the mouse then moves
219 // in again when the transition is back to 2px, the mReversePortion
220 // for the third transition (from 0px/2px to 10px) will be 0.8.
221 double mReversePortion
= 1.0;
223 Maybe
<ReplacedTransitionProperties
> mReplacedTransition
;
228 } // namespace mozilla
230 #endif // mozilla_dom_CSSTransition_h