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