1 /*
2  * Copyright 2015 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "include/core/SkScalar.h"
9 #include "include/core/SkTime.h"
10 
11 #ifndef AnimTimer_DEFINED
12 #define AnimTimer_DEFINED
13 
14 /**
15  *  Class to track a "timer". It supports 3 states: stopped, paused, and running.
16  *  Playback speed is variable.
17  *
18  *  The caller must call updateTime() to resync with the clock (typically just before
19  *  using the timer). Forcing the caller to do this ensures that the timer's return values
20  *  are consistent if called repeatedly, as they only reflect the time since the last
21  *  calle to updateTimer().
22  */
23 class AnimTimer {
24 public:
25     /**
26      *  Class begins in the "stopped" state.
27      */
AnimTimer()28     AnimTimer() {}
29 
30     enum State { kStopped_State, kPaused_State, kRunning_State };
31 
state()32     State state() const { return fState; }
33 
nanos()34     double nanos() const { return fElapsedNanos; }
35 
36     /**
37      *  Control the rate at which time advances.
38      */
getSpeed()39     float getSpeed() const { return fSpeed; }
setSpeed(float speed)40     void  setSpeed(float speed) { fSpeed = speed; }
41 
42     /**
43      *  If the timer is paused or stopped, it will resume (or start if it was stopped).
44      */
run()45     void run() {
46         switch (this->state()) {
47             case kStopped_State:
48                 fPreviousNanos = SkTime::GetNSecs();
49                 fElapsedNanos  = 0;
50                 break;
51             case kPaused_State:  // they want "resume"
52                 fPreviousNanos = SkTime::GetNSecs();
53                 break;
54             case kRunning_State: break;
55         }
56         fState = kRunning_State;
57     }
58 
pause()59     void pause() {
60         if (kRunning_State == this->state()) {
61             fState = kPaused_State;
62         }  // else stay stopped or paused
63     }
64 
65     /**
66      *  If the timer is stopped, start running, else it toggles between paused and running.
67      */
togglePauseResume()68     void togglePauseResume() {
69         if (kRunning_State == this->state()) {
70             this->pause();
71         } else {
72             this->run();
73         }
74     }
75 
76     /**
77      *  Call this each time you want to sample the clock for the timer. This is NOT done
78      *  automatically, so that repeated calls to msec() or secs() will always return the
79      *  same value.
80      *
81      *  This may safely be called with the timer in any state.
82      */
updateTime()83     void updateTime() {
84         if (kRunning_State == this->state()) {
85             double now = SkTime::GetNSecs();
86             fElapsedNanos += (now - fPreviousNanos) * fSpeed;
87             fPreviousNanos = now;
88         }
89     }
90 
91 private:
92     double fPreviousNanos = 0;
93     double fElapsedNanos = 0;
94     float  fSpeed = 1;
95     State fState = kStopped_State;
96 };
97 
98 #endif
99