LCOV - code coverage report
Current view: top level - dom/animation - Animation.h (source / functions) Hit Total Coverage
Test: output.info Lines: 22 55 40.0 %
Date: 2017-07-14 16:53:18 Functions: 10 35 28.6 %
Legend: Lines: hit not hit

          Line data    Source code
       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_Animation_h
       8             : #define mozilla_dom_Animation_h
       9             : 
      10             : #include "nsWrapperCache.h"
      11             : #include "nsCycleCollectionParticipant.h"
      12             : #include "mozilla/AnimationPerformanceWarning.h"
      13             : #include "mozilla/Attributes.h"
      14             : #include "mozilla/DOMEventTargetHelper.h"
      15             : #include "mozilla/EffectCompositor.h" // For EffectCompositor::CascadeLevel
      16             : #include "mozilla/LinkedList.h"
      17             : #include "mozilla/TimeStamp.h" // for TimeStamp, TimeDuration
      18             : #include "mozilla/dom/AnimationBinding.h" // for AnimationPlayState
      19             : #include "mozilla/dom/AnimationEffectReadOnly.h"
      20             : #include "mozilla/dom/AnimationTimeline.h"
      21             : #include "mozilla/dom/Promise.h"
      22             : #include "nsCSSPropertyID.h"
      23             : #include "nsIGlobalObject.h"
      24             : 
      25             : // X11 has a #define for CurrentTime.
      26             : #ifdef CurrentTime
      27             : #undef CurrentTime
      28             : #endif
      29             : 
      30             : // GetCurrentTime is defined in winbase.h as zero argument macro forwarding to
      31             : // GetTickCount().
      32             : #ifdef GetCurrentTime
      33             : #undef GetCurrentTime
      34             : #endif
      35             : 
      36             : struct JSContext;
      37             : class nsCSSPropertyIDSet;
      38             : class nsIDocument;
      39             : class nsIFrame;
      40             : 
      41             : namespace mozilla {
      42             : 
      43             : struct AnimationRule;
      44             : 
      45             : namespace dom {
      46             : 
      47             : class CSSAnimation;
      48             : class CSSTransition;
      49             : 
      50             : class Animation
      51             :   : public DOMEventTargetHelper
      52             :   , public LinkedListElement<Animation>
      53             : {
      54             : protected:
      55           0 :   virtual ~Animation() {}
      56             : 
      57             : public:
      58           2 :   explicit Animation(nsIGlobalObject* aGlobal)
      59           2 :     : DOMEventTargetHelper(aGlobal)
      60             :     , mPlaybackRate(1.0)
      61             :     , mPendingState(PendingState::NotPending)
      62           2 :     , mAnimationIndex(sNextAnimationIndex++)
      63             :     , mFinishedAtLastComposeStyle(false)
      64             :     , mIsRelevant(false)
      65             :     , mFinishedIsResolved(false)
      66           4 :     , mSyncWithGeometricAnimations(false)
      67             :   {
      68           2 :   }
      69             : 
      70             :   NS_DECL_ISUPPORTS_INHERITED
      71           2 :   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(Animation,
      72             :                                            DOMEventTargetHelper)
      73             : 
      74           0 :   nsIGlobalObject* GetParentObject() const { return GetOwnerGlobal(); }
      75             :   virtual JSObject* WrapObject(JSContext* aCx,
      76             :                                JS::Handle<JSObject*> aGivenProto) override;
      77             : 
      78           0 :   virtual CSSAnimation* AsCSSAnimation() { return nullptr; }
      79           0 :   virtual const CSSAnimation* AsCSSAnimation() const { return nullptr; }
      80           0 :   virtual CSSTransition* AsCSSTransition() { return nullptr; }
      81           0 :   virtual const CSSTransition* AsCSSTransition() const { return nullptr; }
      82             : 
      83             :   /**
      84             :    * Flag to pass to Play to indicate whether or not it should automatically
      85             :    * rewind the current time to the start point if the animation is finished.
      86             :    * For regular calls to play() from script we should do this, but when a CSS
      87             :    * animation's animation-play-state changes we shouldn't rewind the animation.
      88             :    */
      89             :   enum class LimitBehavior {
      90             :     AutoRewind,
      91             :     Continue
      92             :   };
      93             : 
      94             :   // Animation interface methods
      95             :   static already_AddRefed<Animation>
      96             :   Constructor(const GlobalObject& aGlobal,
      97             :               AnimationEffectReadOnly* aEffect,
      98             :               const Optional<AnimationTimeline*>& aTimeline,
      99             :               ErrorResult& aRv);
     100           0 :   void GetId(nsAString& aResult) const { aResult = mId; }
     101             :   void SetId(const nsAString& aId);
     102         102 :   AnimationEffectReadOnly* GetEffect() const { return mEffect; }
     103             :   void SetEffect(AnimationEffectReadOnly* aEffect);
     104          34 :   AnimationTimeline* GetTimeline() const { return mTimeline; }
     105             :   void SetTimeline(AnimationTimeline* aTimeline);
     106           0 :   Nullable<TimeDuration> GetStartTime() const { return mStartTime; }
     107             :   void SetStartTime(const Nullable<TimeDuration>& aNewStartTime);
     108             :   Nullable<TimeDuration> GetCurrentTime() const;
     109             :   void SetCurrentTime(const TimeDuration& aNewCurrentTime);
     110         186 :   double PlaybackRate() const { return mPlaybackRate; }
     111             :   void SetPlaybackRate(double aPlaybackRate);
     112             :   AnimationPlayState PlayState() const;
     113             :   virtual Promise* GetReady(ErrorResult& aRv);
     114             :   virtual Promise* GetFinished(ErrorResult& aRv);
     115             :   void Cancel();
     116             :   virtual void Finish(ErrorResult& aRv);
     117             :   virtual void Play(ErrorResult& aRv, LimitBehavior aLimitBehavior);
     118             :   virtual void Pause(ErrorResult& aRv);
     119             :   virtual void Reverse(ErrorResult& aRv);
     120             :   bool IsRunningOnCompositor() const;
     121           0 :   IMPL_EVENT_HANDLER(finish);
     122           0 :   IMPL_EVENT_HANDLER(cancel);
     123             : 
     124             :   // Wrapper functions for Animation DOM methods when called
     125             :   // from script.
     126             :   //
     127             :   // We often use the same methods internally and from script but when called
     128             :   // from script we (or one of our subclasses) perform extra steps such as
     129             :   // flushing style or converting the return type.
     130             :   Nullable<double> GetStartTimeAsDouble() const;
     131             :   void SetStartTimeAsDouble(const Nullable<double>& aStartTime);
     132             :   Nullable<double> GetCurrentTimeAsDouble() const;
     133             :   void SetCurrentTimeAsDouble(const Nullable<double>& aCurrentTime,
     134             :                               ErrorResult& aRv);
     135           0 :   virtual AnimationPlayState PlayStateFromJS() const { return PlayState(); }
     136           0 :   virtual void PlayFromJS(ErrorResult& aRv)
     137             :   {
     138           0 :     Play(aRv, LimitBehavior::AutoRewind);
     139           0 :   }
     140             :   /**
     141             :    * PauseFromJS is currently only here for symmetry with PlayFromJS but
     142             :    * in future we will likely have to flush style in
     143             :    * CSSAnimation::PauseFromJS so we leave it for now.
     144             :    */
     145           0 :   void PauseFromJS(ErrorResult& aRv) { Pause(aRv); }
     146             : 
     147             :   // Wrapper functions for Animation DOM methods when called from style.
     148             : 
     149           0 :   virtual void CancelFromStyle() { CancelNoUpdate(); }
     150             :   void SetTimelineNoUpdate(AnimationTimeline* aTimeline);
     151             :   void SetEffectNoUpdate(AnimationEffectReadOnly* aEffect);
     152             : 
     153             :   virtual void Tick();
     154          26 :   bool NeedsTicks() const
     155             :   {
     156          26 :     AnimationPlayState playState = PlayState();
     157          26 :     return playState == AnimationPlayState::Running ||
     158          26 :            playState == AnimationPlayState::Pending;
     159             :   }
     160             : 
     161             :   /**
     162             :    * Set the time to use for starting or pausing a pending animation.
     163             :    *
     164             :    * Typically, when an animation is played, it does not start immediately but
     165             :    * is added to a table of pending animations on the document of its effect.
     166             :    * In the meantime it sets its hold time to the time from which playback
     167             :    * should begin.
     168             :    *
     169             :    * When the document finishes painting, any pending animations in its table
     170             :    * are marked as being ready to start by calling StartOnNextTick.
     171             :    * The moment when the paint completed is also recorded, converted to a
     172             :    * timeline time, and passed to StartOnTick. This is so that when these
     173             :    * animations do start, they can be timed from the point when painting
     174             :    * completed.
     175             :    *
     176             :    * After calling TriggerOnNextTick, animations remain in the pending state
     177             :    * until the next refresh driver tick. At that time they transition out of
     178             :    * the pending state using the time passed to TriggerOnNextTick as the
     179             :    * effective time at which they resumed.
     180             :    *
     181             :    * This approach means that any setup time required for performing the
     182             :    * initial paint of an animation such as layerization is not deducted from
     183             :    * the running time of the animation. Without this we can easily drop the
     184             :    * first few frames of an animation, or, on slower devices, the whole
     185             :    * animation.
     186             :    *
     187             :    * Furthermore:
     188             :    *
     189             :    * - Starting the animation immediately when painting finishes is problematic
     190             :    *   because the start time of the animation will be ahead of its timeline
     191             :    *   (since the timeline time is based on the refresh driver time).
     192             :    *   That's a problem because the animation is playing but its timing
     193             :    *   suggests it starts in the future. We could update the timeline to match
     194             :    *   the start time of the animation but then we'd also have to update the
     195             :    *   timing and style of all animations connected to that timeline or else be
     196             :    *   stuck in an inconsistent state until the next refresh driver tick.
     197             :    *
     198             :    * - If we simply use the refresh driver time on its next tick, the lag
     199             :    *   between triggering an animation and its effective start is unacceptably
     200             :    *   long.
     201             :    *
     202             :    * For pausing, we apply the same asynchronous approach. This is so that we
     203             :    * synchronize with animations that are running on the compositor. Otherwise
     204             :    * if the main thread lags behind the compositor there will be a noticeable
     205             :    * jump backwards when the main thread takes over. Even though main thread
     206             :    * animations could be paused immediately, we do it asynchronously for
     207             :    * consistency and so that animations paused together end up in step.
     208             :    *
     209             :    * Note that the caller of this method is responsible for removing the
     210             :    * animation from any PendingAnimationTracker it may have been added to.
     211             :    */
     212             :   void TriggerOnNextTick(const Nullable<TimeDuration>& aReadyTime);
     213             :   /**
     214             :    * Testing only: Start or pause a pending animation using the current
     215             :    * timeline time. This is used to support existing tests that expect
     216             :    * animations to begin immediately. Ideally we would rewrite the those tests
     217             :    * and get rid of this method, but there are a lot of them.
     218             :    *
     219             :    * As with TriggerOnNextTick, the caller of this method is responsible for
     220             :    * removing the animation from any PendingAnimationTracker it may have been
     221             :    * added to.
     222             :    */
     223             :   void TriggerNow();
     224             :   /**
     225             :    * When StartOnNextTick is called, we store the ready time but we don't apply
     226             :    * it until the next tick. In the meantime, GetStartTime() will return null.
     227             :    *
     228             :    * However, if we build layer animations again before the next tick, we
     229             :    * should initialize them with the start time that GetStartTime() will return
     230             :    * on the next tick.
     231             :    *
     232             :    * If we were to simply set the start time of layer animations to null, their
     233             :    * start time would be updated to the current wallclock time when rendering
     234             :    * finishes, thus making them out of sync with the start time stored here.
     235             :    * This, in turn, will make the animation jump backwards when we build
     236             :    * animations on the next tick and apply the start time stored here.
     237             :    *
     238             :    * This method returns the start time, if resolved. Otherwise, if we have
     239             :    * a pending ready time, it returns the corresponding start time. If neither
     240             :    * of those are available, it returns null.
     241             :    */
     242             :   Nullable<TimeDuration> GetCurrentOrPendingStartTime() const;
     243             : 
     244             :   /**
     245             :    * Calculates the corresponding start time to use for an animation that is
     246             :    * currently pending with current time |mHoldTime| but should behave
     247             :    * as if it began or resumed playback at timeline time |aReadyTime|.
     248             :    */
     249             :   TimeDuration StartTimeFromReadyTime(const TimeDuration& aReadyTime) const;
     250             : 
     251             :   /**
     252             :    * Converts a time in the timescale of this Animation's currentTime, to a
     253             :    * TimeStamp. Returns a null TimeStamp if the conversion cannot be performed
     254             :    * because of the current state of this Animation (e.g. it has no timeline, a
     255             :    * zero playbackRate, an unresolved start time etc.) or the value of the time
     256             :    * passed-in (e.g. an infinite time).
     257             :    */
     258             :   TimeStamp AnimationTimeToTimeStamp(const StickyTimeDuration& aTime) const;
     259             : 
     260             :   // Converts an AnimationEvent's elapsedTime value to an equivalent TimeStamp
     261             :   // that can be used to sort events by when they occurred.
     262             :   TimeStamp ElapsedTimeToTimeStamp(const StickyTimeDuration& aElapsedTime) const;
     263             : 
     264           0 :   bool IsPausedOrPausing() const
     265             :   {
     266           0 :     return PlayState() == AnimationPlayState::Paused ||
     267           0 :            mPendingState == PendingState::PausePending;
     268             :   }
     269             : 
     270          32 :   bool HasCurrentEffect() const
     271             :   {
     272          32 :     return GetEffect() && GetEffect()->IsCurrent();
     273             :   }
     274           6 :   bool IsInEffect() const
     275             :   {
     276           6 :     return GetEffect() && GetEffect()->IsInEffect();
     277             :   }
     278             : 
     279           0 :   bool IsPlaying() const
     280             :   {
     281           0 :     return mPlaybackRate != 0.0 &&
     282           0 :            mTimeline &&
     283           0 :            (PlayState() == AnimationPlayState::Running ||
     284           0 :             mPendingState == PendingState::PlayPending);
     285             :   }
     286             : 
     287             :   bool ShouldBeSynchronizedWithMainThread(
     288             :     nsCSSPropertyID aProperty,
     289             :     const nsIFrame* aFrame,
     290             :     AnimationPerformanceWarning::Type& aPerformanceWarning) const;
     291             : 
     292          90 :   bool IsRelevant() const { return mIsRelevant; }
     293             :   void UpdateRelevance();
     294             : 
     295             :   /**
     296             :    * Returns true if this Animation has a lower composite order than aOther.
     297             :    */
     298             :   bool HasLowerCompositeOrderThan(const Animation& aOther) const;
     299             : 
     300             :    /**
     301             :    * Returns the level at which the effect(s) associated with this Animation
     302             :    * are applied to the CSS cascade.
     303             :    */
     304           0 :   virtual EffectCompositor::CascadeLevel CascadeLevel() const
     305             :   {
     306           0 :     return EffectCompositor::CascadeLevel::Animations;
     307             :   }
     308             : 
     309             :   /**
     310             :    * Returns true if this animation does not currently need to update
     311             :    * style on the main thread (e.g. because it is empty, or is
     312             :    * running on the compositor).
     313             :    */
     314             :   bool CanThrottle() const;
     315             : 
     316             :   /**
     317             :    * Updates various bits of state that we need to update as the result of
     318             :    * running ComposeStyle().
     319             :    * See the comment of KeyframeEffectReadOnly::WillComposeStyle for more detail.
     320             :    */
     321             :   void WillComposeStyle();
     322             : 
     323             :   /**
     324             :    * Updates |aComposeResult| with the animation values of this animation's
     325             :    * effect, if any.
     326             :    * Any properties contained in |aPropertiesToSkip| will not be added or
     327             :    * updated in |aComposeResult|.
     328             :    */
     329             :   template<typename ComposeAnimationResult>
     330             :   void ComposeStyle(ComposeAnimationResult&& aComposeResult,
     331             :                     const nsCSSPropertyIDSet& aPropertiesToSkip);
     332             : 
     333             :   void NotifyEffectTimingUpdated();
     334             :   void NotifyGeometricAnimationsStartingThisFrame();
     335             : 
     336             :   /**
     337             :    * Used by subclasses to synchronously queue a cancel event in situations
     338             :    * where the Animation may have been cancelled.
     339             :    *
     340             :    * We need to do this synchronously because after a CSS animation/transition
     341             :    * is canceled, it will be released by its owning element and may not still
     342             :    * exist when we would normally go to queue events on the next tick.
     343             :    */
     344           0 :   virtual void MaybeQueueCancelEvent(StickyTimeDuration aActiveTime) {};
     345             : 
     346             : protected:
     347             :   void SilentlySetCurrentTime(const TimeDuration& aNewCurrentTime);
     348             :   void SilentlySetPlaybackRate(double aPlaybackRate);
     349             :   void CancelNoUpdate();
     350             :   void PlayNoUpdate(ErrorResult& aRv, LimitBehavior aLimitBehavior);
     351             :   void PauseNoUpdate(ErrorResult& aRv);
     352             :   void ResumeAt(const TimeDuration& aReadyTime);
     353             :   void PauseAt(const TimeDuration& aReadyTime);
     354           2 :   void FinishPendingAt(const TimeDuration& aReadyTime)
     355             :   {
     356           2 :     if (mPendingState == PendingState::PlayPending) {
     357           2 :       ResumeAt(aReadyTime);
     358           0 :     } else if (mPendingState == PendingState::PausePending) {
     359           0 :       PauseAt(aReadyTime);
     360             :     } else {
     361           0 :       NS_NOTREACHED("Can't finish pending if we're not in a pending state");
     362             :     }
     363           2 :   }
     364             : 
     365             :   /**
     366             :    * Finishing behavior depends on if changes to timing occurred due
     367             :    * to a seek or regular playback.
     368             :    */
     369             :   enum class SeekFlag {
     370             :     NoSeek,
     371             :     DidSeek
     372             :   };
     373             : 
     374             :   enum class SyncNotifyFlag {
     375             :     Sync,
     376             :     Async
     377             :   };
     378             : 
     379             :   virtual void UpdateTiming(SeekFlag aSeekFlag,
     380             :                             SyncNotifyFlag aSyncNotifyFlag);
     381             :   void UpdateFinishedState(SeekFlag aSeekFlag,
     382             :                            SyncNotifyFlag aSyncNotifyFlag);
     383             :   void UpdateEffect();
     384             :   void FlushStyle() const;
     385             :   void PostUpdate();
     386             :   void ResetFinishedPromise();
     387             :   void MaybeResolveFinishedPromise();
     388             :   void DoFinishNotification(SyncNotifyFlag aSyncNotifyFlag);
     389             :   void DoFinishNotificationImmediately();
     390             :   void DispatchPlaybackEvent(const nsAString& aName);
     391             : 
     392             :   /**
     393             :    * Remove this animation from the pending animation tracker and reset
     394             :    * mPendingState as necessary. The caller is responsible for resolving or
     395             :    * aborting the mReady promise as necessary.
     396             :    */
     397             :   void CancelPendingTasks();
     398             : 
     399             :   /**
     400             :    * Performs the same steps as CancelPendingTasks and also rejects and
     401             :    * recreates the ready promise if the animation was pending.
     402             :    */
     403             :   void ResetPendingTasks();
     404             : 
     405             :   /**
     406             :    * Returns true if this animation is not only play-pending, but has
     407             :    * yet to be given a pending ready time. This roughly corresponds to
     408             :    * animations that are waiting to be painted (since we set the pending
     409             :    * ready time at the end of painting). Identifying such animations is
     410             :    * useful because in some cases animations that are painted together
     411             :    * may need to be synchronized.
     412             :    */
     413           0 :   bool IsNewlyStarted() const {
     414           0 :     return mPendingState == PendingState::PlayPending &&
     415           0 :            mPendingReadyTime.IsNull();
     416             :   }
     417             :   bool IsPossiblyOrphanedPendingAnimation() const;
     418             :   StickyTimeDuration EffectEnd() const;
     419             : 
     420             :   nsIDocument* GetRenderedDocument() const;
     421             : 
     422             :   RefPtr<AnimationTimeline> mTimeline;
     423             :   RefPtr<AnimationEffectReadOnly> mEffect;
     424             :   // The beginning of the delay period.
     425             :   Nullable<TimeDuration> mStartTime; // Timeline timescale
     426             :   Nullable<TimeDuration> mHoldTime;  // Animation timescale
     427             :   Nullable<TimeDuration> mPendingReadyTime; // Timeline timescale
     428             :   Nullable<TimeDuration> mPreviousCurrentTime; // Animation timescale
     429             :   double mPlaybackRate;
     430             : 
     431             :   // A Promise that is replaced on each call to Play()
     432             :   // and fulfilled when Play() is successfully completed.
     433             :   // This object is lazily created by GetReady.
     434             :   // See http://w3c.github.io/web-animations/#current-ready-promise
     435             :   RefPtr<Promise> mReady;
     436             : 
     437             :   // A Promise that is resolved when we reach the end of the effect, or
     438             :   // 0 when playing backwards. The Promise is replaced if the animation is
     439             :   // finished but then a state change makes it not finished.
     440             :   // This object is lazily created by GetFinished.
     441             :   // See http://w3c.github.io/web-animations/#current-finished-promise
     442             :   RefPtr<Promise> mFinished;
     443             : 
     444             :   // Indicates if the animation is in the pending state (and what state it is
     445             :   // waiting to enter when it finished pending). We use this rather than
     446             :   // checking if this animation is tracked by a PendingAnimationTracker because
     447             :   // the animation will continue to be pending even after it has been removed
     448             :   // from the PendingAnimationTracker while it is waiting for the next tick
     449             :   // (see TriggerOnNextTick for details).
     450             :   enum class PendingState { NotPending, PlayPending, PausePending };
     451             :   PendingState mPendingState;
     452             : 
     453             :   static uint64_t sNextAnimationIndex;
     454             : 
     455             :   // The relative position of this animation within the global animation list.
     456             :   // This is kNoIndex while the animation is in the idle state and is updated
     457             :   // each time the animation transitions out of the idle state.
     458             :   //
     459             :   // Note that subclasses such as CSSTransition and CSSAnimation may repurpose
     460             :   // this member to implement their own brand of sorting. As a result, it is
     461             :   // possible for two different objects to have the same index.
     462             :   uint64_t mAnimationIndex;
     463             : 
     464             :   bool mFinishedAtLastComposeStyle;
     465             :   // Indicates that the animation should be exposed in an element's
     466             :   // getAnimations() list.
     467             :   bool mIsRelevant;
     468             : 
     469             :   nsRevocableEventPtr<nsRunnableMethod<Animation>> mFinishNotificationTask;
     470             :   // True if mFinished is resolved or would be resolved if mFinished has
     471             :   // yet to be created. This is not set when mFinished is rejected since
     472             :   // in that case mFinished is immediately reset to represent a new current
     473             :   // finished promise.
     474             :   bool mFinishedIsResolved;
     475             : 
     476             :   // True if this animation was triggered at the same time as one or more
     477             :   // geometric animations and hence we should run any transform animations on
     478             :   // the main thread.
     479             :   bool mSyncWithGeometricAnimations;
     480             : 
     481             :   nsString mId;
     482             : };
     483             : 
     484             : } // namespace dom
     485             : } // namespace mozilla
     486             : 
     487             : #endif // mozilla_dom_Animation_h

Generated by: LCOV version 1.13