skia2/gm/SkAnimTimer.h
benjaminwagner ec4d4d784d Change SkTime::GetMSecs to double; ensure values stored in SkMSec do not overflow.
The following are currently unused in Android, Google3, Chromium, and Mozilla:
  - SkEvent
  - SkTime::GetMSecs
  - SK_TIME_FACTOR (also unused in Skia)
  - SkAutoTime

I left uses of SkMSec more-or-less intact for SkEvent, SkAnimator, and SkInterpolator. SkInterpolator is used in Chromium, so I did not want to change the API. The views/ and animator/ code is crufty, so it didn't seem worthwhile to refactor it. Instead, I added SkEvent::GetMSecsSinceStartup, which is likely to be adequate for use in SampleApp.

I also left SkMSec where it is used to measure a duration rather than a timestamp. With the exception of SkMovie, which is used in Android, all of the uses appear to measure the execution time of a piece of code, which I would hope does not exceed 2^31 milliseconds.

Added skiatest::Timer to support a common idiom in tests where we want to measure the wallclock time in integer milliseconds. (Not used in tests/PathOpsSkpClipTest.cpp because it redefines things in Test.h.)

Removed tabs in tests/StrokerTest.cpp.

BUG=skia:4632
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1811613004

Review URL: https://codereview.chromium.org/1811613004
2016-03-25 12:59:53 -07:00

143 lines
4.3 KiB
C++

/*
* Copyright 2015 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkTime.h"
#ifndef SkAnimTimer_DEFINED
#define SkAnimTimer_DEFINED
/**
* Class to track a "timer". It supports 3 states: stopped, paused, running.
*
* The caller must call updateTime() to resync with the clock (typically just before
* using the timer). Forcing the caller to do this ensures that the timer's return values
* are consistent if called repeatedly, as they only reflect the time since the last
* calle to updateTimer().
*/
class SkAnimTimer {
public:
enum State {
kStopped_State,
kPaused_State,
kRunning_State
};
/**
* Class begins in the "stopped" state.
*/
SkAnimTimer() : fBaseTimeNanos(0), fCurrTimeNanos(0), fState(kStopped_State) {}
bool isStopped() const { return kStopped_State == fState; }
bool isRunning() const { return kRunning_State == fState; }
bool isPaused() const { return kPaused_State == fState; }
/**
* Stops the timer, and resets it, such that the next call to run or togglePauseResume
* will begin at time 0.
*/
void stop() {
this->setState(kStopped_State);
}
/**
* If the timer is paused or stopped, it will resume (or start if it was stopped).
*/
void run() {
this->setState(kRunning_State);
}
/**
* If the timer is stopped, this has no effect, else it toggles between paused and running.
*/
void togglePauseResume() {
if (kRunning_State == fState) {
this->setState(kPaused_State);
} else {
this->setState(kRunning_State);
}
}
/**
* Call this each time you want to sample the clock for the timer. This is NOT done
* automatically, so that repeated calls to msec() or secs() will always return the
* same value.
*
* This may safely be called with the timer in any state.
*/
void updateTime() {
if (kRunning_State == fState) {
fCurrTimeNanos = SkTime::GetNSecs();
}
}
/**
* Return the time in milliseconds the timer has been in the running state.
* Returns 0 if the timer is stopped. Behavior is undefined if the timer
* has been running longer than SK_MSecMax.
*/
SkMSec msec() const {
const double msec = (fCurrTimeNanos - fBaseTimeNanos) * 1e-6;
SkASSERT(SK_MSecMax >= msec);
return static_cast<SkMSec>(msec);
}
/**
* Return the time in seconds the timer has been in the running state.
* Returns 0 if the timer is stopped.
*/
double secs() const { return (fCurrTimeNanos - fBaseTimeNanos) * 1e-9; }
/**
* Return the time in seconds the timer has been in the running state,
* scaled by "speed" and (if not zero) mod by period.
* Returns 0 if the timer is stopped.
*/
SkScalar scaled(SkScalar speed, SkScalar period = 0) const {
double value = this->secs() * speed;
if (period) {
value = ::fmod(value, SkScalarToDouble(period));
}
return SkDoubleToScalar(value);
}
private:
double fBaseTimeNanos;
double fCurrTimeNanos;
State fState;
void setState(State newState) {
switch (newState) {
case kStopped_State:
fBaseTimeNanos = fCurrTimeNanos = 0;
fState = kStopped_State;
break;
case kPaused_State:
if (kRunning_State == fState) {
fState = kPaused_State;
} // else stay stopped or paused
break;
case kRunning_State:
switch (fState) {
case kStopped_State:
fBaseTimeNanos = fCurrTimeNanos = SkTime::GetNSecs();
break;
case kPaused_State: {// they want "resume"
double now = SkTime::GetNSecs();
fBaseTimeNanos += now - fCurrTimeNanos;
fCurrTimeNanos = now;
} break;
case kRunning_State:
break;
}
fState = kRunning_State;
break;
}
}
};
#endif