blob: bdc2c8dd363e3cdb581c0d6afb1edfdfe5d9642d [file] [log] [blame]
// Copyright 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "cc/active_animation.h"
#include <cmath>
#include "base/debug/trace_event.h"
#include "base/string_util.h"
#include "cc/animation_curve.h"
namespace {
// This should match the RunState enum.
static const char* const s_runStateNames[] = {
"WaitingForNextTick",
"WaitingForTargetAvailability",
"WaitingForStartTime",
"WaitingForDeletion",
"Running",
"Paused",
"Finished",
"Aborted"
};
COMPILE_ASSERT(static_cast<int>(cc::ActiveAnimation::RunStateEnumSize) == arraysize(s_runStateNames), RunState_names_match_enum);
// This should match the TargetProperty enum.
static const char* const s_targetPropertyNames[] = {
"Transform",
"Opacity"
};
COMPILE_ASSERT(static_cast<int>(cc::ActiveAnimation::TargetPropertyEnumSize) == arraysize(s_targetPropertyNames), TargetProperty_names_match_enum);
} // namespace
namespace cc {
scoped_ptr<ActiveAnimation> ActiveAnimation::create(scoped_ptr<AnimationCurve> curve, int animationId, int groupId, TargetProperty targetProperty)
{
return make_scoped_ptr(new ActiveAnimation(curve.Pass(), animationId, groupId, targetProperty));
}
ActiveAnimation::ActiveAnimation(scoped_ptr<AnimationCurve> curve, int animationId, int groupId, TargetProperty targetProperty)
: m_curve(curve.Pass())
, m_id(animationId)
, m_group(groupId)
, m_targetProperty(targetProperty)
, m_runState(WaitingForTargetAvailability)
, m_iterations(1)
, m_startTime(0)
, m_alternatesDirection(false)
, m_timeOffset(0)
, m_needsSynchronizedStartTime(false)
, m_suspended(false)
, m_pauseTime(0)
, m_totalPausedTime(0)
, m_isControllingInstance(false)
{
}
ActiveAnimation::~ActiveAnimation()
{
if (m_runState == Running || m_runState == Paused)
setRunState(Aborted, 0);
}
void ActiveAnimation::setRunState(RunState runState, double monotonicTime)
{
if (m_suspended)
return;
char nameBuffer[256];
base::snprintf(nameBuffer, sizeof(nameBuffer), "%s-%d%s", s_targetPropertyNames[m_targetProperty], m_group, m_isControllingInstance ? "(impl)" : "");
bool isWaitingToStart = m_runState == WaitingForNextTick
|| m_runState == WaitingForTargetAvailability
|| m_runState == WaitingForStartTime;
if (isWaitingToStart && runState == Running)
TRACE_EVENT_ASYNC_BEGIN1("cc", "ActiveAnimation", this, "Name", TRACE_STR_COPY(nameBuffer));
bool wasFinished = isFinished();
const char* oldRunStateName = s_runStateNames[m_runState];
if (runState == Running && m_runState == Paused)
m_totalPausedTime += monotonicTime - m_pauseTime;
else if (runState == Paused)
m_pauseTime = monotonicTime;
m_runState = runState;
const char* newRunStateName = s_runStateNames[runState];
if (!wasFinished && isFinished())
TRACE_EVENT_ASYNC_END0("cc", "ActiveAnimation", this);
char stateBuffer[256];
base::snprintf(stateBuffer, sizeof(stateBuffer), "%s->%s", oldRunStateName, newRunStateName);
TRACE_EVENT_INSTANT2("cc", "LayerAnimationController::setRunState", "Name", TRACE_STR_COPY(nameBuffer), "State", TRACE_STR_COPY(stateBuffer));
}
void ActiveAnimation::suspend(double monotonicTime)
{
setRunState(Paused, monotonicTime);
m_suspended = true;
}
void ActiveAnimation::resume(double monotonicTime)
{
m_suspended = false;
setRunState(Running, monotonicTime);
}
bool ActiveAnimation::isFinishedAt(double monotonicTime) const
{
if (isFinished())
return true;
if (m_needsSynchronizedStartTime)
return false;
return m_runState == Running
&& m_iterations >= 0
&& m_iterations * m_curve->duration() <= monotonicTime - startTime() - m_totalPausedTime;
}
double ActiveAnimation::trimTimeToCurrentIteration(double monotonicTime) const
{
double trimmed = monotonicTime + m_timeOffset;
// If we're paused, time is 'stuck' at the pause time.
if (m_runState == Paused)
trimmed = m_pauseTime;
// Returned time should always be relative to the start time and should subtract
// all time spent paused.
trimmed -= m_startTime + m_totalPausedTime;
// Zero is always the start of the animation.
if (trimmed <= 0)
return 0;
// Always return zero if we have no iterations.
if (!m_iterations)
return 0;
// Don't attempt to trim if we have no duration.
if (m_curve->duration() <= 0)
return 0;
// If less than an iteration duration, just return trimmed.
if (trimmed < m_curve->duration())
return trimmed;
// If greater than or equal to the total duration, return iteration duration.
if (m_iterations >= 0 && trimmed >= m_curve->duration() * m_iterations) {
if (m_alternatesDirection && !(m_iterations % 2))
return 0;
return m_curve->duration();
}
// We need to know the current iteration if we're alternating.
int iteration = static_cast<int>(trimmed / m_curve->duration());
// Calculate x where trimmed = x + n * m_curve->duration() for some positive integer n.
trimmed = fmod(trimmed, m_curve->duration());
// If we're alternating and on an odd iteration, reverse the direction.
if (m_alternatesDirection && iteration % 2 == 1)
return m_curve->duration() - trimmed;
return trimmed;
}
scoped_ptr<ActiveAnimation> ActiveAnimation::clone(InstanceType instanceType) const
{
return cloneAndInitialize(instanceType, m_runState, m_startTime);
}
scoped_ptr<ActiveAnimation> ActiveAnimation::cloneAndInitialize(InstanceType instanceType, RunState initialRunState, double startTime) const
{
scoped_ptr<ActiveAnimation> toReturn(new ActiveAnimation(m_curve->clone(), m_id, m_group, m_targetProperty));
toReturn->m_runState = initialRunState;
toReturn->m_iterations = m_iterations;
toReturn->m_startTime = startTime;
toReturn->m_pauseTime = m_pauseTime;
toReturn->m_totalPausedTime = m_totalPausedTime;
toReturn->m_timeOffset = m_timeOffset;
toReturn->m_alternatesDirection = m_alternatesDirection;
toReturn->m_isControllingInstance = instanceType == ControllingInstance;
return toReturn.Pass();
}
void ActiveAnimation::pushPropertiesTo(ActiveAnimation* other) const
{
// Currently, we only push changes due to pausing and resuming animations on the main thread.
if (m_runState == ActiveAnimation::Paused || other->m_runState == ActiveAnimation::Paused) {
other->m_runState = m_runState;
other->m_pauseTime = m_pauseTime;
other->m_totalPausedTime = m_totalPausedTime;
}
}
} // namespace cc