CCLayerAnimationController.cpp [plain text]
#include "config.h"
#include "cc/CCLayerAnimationController.h"
#include "GraphicsLayer.h" // for KeyframeValueList
#include "TransformationMatrix.h"
#include "cc/CCActiveAnimation.h"
#include "cc/CCKeyframedAnimationCurve.h"
#include <wtf/CurrentTime.h>
#include <wtf/HashMap.h>
namespace WebCore {
namespace {
template <class Value, class Keyframe, class Curve>
void appendKeyframe(Curve& curve, double keyTime, const Value* value, PassOwnPtr<CCTimingFunction> timingFunction)
{
curve.addKeyframe(Keyframe::create(keyTime, value->value(), timingFunction));
}
template <>
void appendKeyframe<TransformAnimationValue, CCTransformKeyframe, CCKeyframedTransformAnimationCurve>(CCKeyframedTransformAnimationCurve& curve, double keyTime, const TransformAnimationValue* value, PassOwnPtr<CCTimingFunction> timingFunction)
{
curve.addKeyframe(CCTransformKeyframe::create(keyTime, *value->value(), timingFunction));
}
template <class Value, class Keyframe, class Curve>
PassOwnPtr<CCActiveAnimation> createActiveAnimation(const KeyframeValueList& valueList, const Animation* animation, size_t animationId, size_t groupId, double timeOffset, CCActiveAnimation::TargetProperty targetProperty)
{
if (animation && animation->isDirectionSet() && animation->direction() != Animation::AnimationDirectionNormal)
return nullptr;
if (animation && animation->isFillModeSet() && (animation->fillsForwards() || animation->fillsBackwards()))
return nullptr;
OwnPtr<Curve> curve = Curve::create();
Vector<Keyframe> keyframes;
for (size_t i = 0; i < valueList.size(); i++) {
const Value* originalValue = static_cast<const Value*>(valueList.at(i));
OwnPtr<CCTimingFunction> timingFunction;
const TimingFunction* originalTimingFunction = originalValue->timingFunction();
if (!originalTimingFunction && animation->isTimingFunctionSet())
originalTimingFunction = animation->timingFunction().get();
if (originalTimingFunction) {
switch (originalTimingFunction->type()) {
case TimingFunction::StepsFunction:
return nullptr;
case TimingFunction::LinearFunction:
break;
case TimingFunction::CubicBezierFunction:
const CubicBezierTimingFunction* originalBezierTimingFunction = static_cast<const CubicBezierTimingFunction*>(originalTimingFunction);
timingFunction = CCCubicBezierTimingFunction::create(originalBezierTimingFunction->x1(), originalBezierTimingFunction->y1(), originalBezierTimingFunction->x2(), originalBezierTimingFunction->y2());
break;
} } else
timingFunction = CCEaseTimingFunction::create();
double duration = (animation && animation->isDurationSet()) ? animation->duration() : 1;
appendKeyframe<Value, Keyframe, Curve>(*curve, originalValue->keyTime() * duration, originalValue, timingFunction.release());
}
OwnPtr<CCActiveAnimation> anim = CCActiveAnimation::create(curve.release(), animationId, groupId, targetProperty);
ASSERT(anim.get());
if (anim.get()) {
int iterations = (animation && animation->isIterationCountSet()) ? animation->iterationCount() : 1;
anim->setIterations(iterations);
}
anim->setNeedsSynchronizedStartTime(true);
anim->setTimeOffset(timeOffset);
return anim.release();
}
}
CCLayerAnimationController::CCLayerAnimationController(CCLayerAnimationControllerClient* client)
: m_client(client)
{
}
CCLayerAnimationController::~CCLayerAnimationController()
{
}
PassOwnPtr<CCLayerAnimationController> CCLayerAnimationController::create(CCLayerAnimationControllerClient* client)
{
return adoptPtr(new CCLayerAnimationController(client));
}
bool CCLayerAnimationController::addAnimation(const KeyframeValueList& valueList, const IntSize&, const Animation* animation, int animationId, int groupId, double timeOffset)
{
if (!animation)
return false;
OwnPtr<CCActiveAnimation> toAdd;
if (valueList.property() == AnimatedPropertyWebkitTransform)
toAdd = createActiveAnimation<TransformAnimationValue, CCTransformKeyframe, CCKeyframedTransformAnimationCurve>(valueList, animation, animationId, groupId, timeOffset, CCActiveAnimation::Transform);
else if (valueList.property() == AnimatedPropertyOpacity)
toAdd = createActiveAnimation<FloatAnimationValue, CCFloatKeyframe, CCKeyframedFloatAnimationCurve>(valueList, animation, animationId, groupId, timeOffset, CCActiveAnimation::Opacity);
if (toAdd.get()) {
for (size_t i = 0; i < m_activeAnimations.size();) {
if (m_activeAnimations[i]->id() == animationId && m_activeAnimations[i]->targetProperty() == toAdd->targetProperty())
m_activeAnimations.remove(i);
else
i++;
}
m_activeAnimations.append(toAdd.release());
return true;
}
return false;
}
void CCLayerAnimationController::pauseAnimation(int animationId, double timeOffset)
{
for (size_t i = 0; i < m_activeAnimations.size(); ++i) {
if (m_activeAnimations[i]->id() == animationId)
m_activeAnimations[i]->setRunState(CCActiveAnimation::Paused, timeOffset + m_activeAnimations[i]->startTime());
}
}
void CCLayerAnimationController::removeAnimation(int animationId)
{
for (size_t i = 0; i < m_activeAnimations.size();) {
if (m_activeAnimations[i]->id() == animationId)
m_activeAnimations.remove(i);
else
i++;
}
}
void CCLayerAnimationController::suspendAnimations(double monotonicTime)
{
for (size_t i = 0; i < m_activeAnimations.size(); ++i) {
if (m_activeAnimations[i]->runState() != CCActiveAnimation::Finished && m_activeAnimations[i]->runState() != CCActiveAnimation::Aborted)
m_activeAnimations[i]->setRunState(CCActiveAnimation::Paused, monotonicTime);
}
}
void CCLayerAnimationController::resumeAnimations(double monotonicTime)
{
for (size_t i = 0; i < m_activeAnimations.size(); ++i) {
if (m_activeAnimations[i]->runState() == CCActiveAnimation::Paused)
m_activeAnimations[i]->setRunState(CCActiveAnimation::Running, monotonicTime);
}
}
void CCLayerAnimationController::pushAnimationUpdatesTo(CCLayerAnimationController* controllerImpl)
{
pushNewAnimationsToImplThread(controllerImpl);
removeAnimationsCompletedOnMainThread(controllerImpl);
pushPropertiesToImplThread(controllerImpl);
}
void CCLayerAnimationController::animate(double monotonicTime, CCAnimationEventsVector* events)
{
startAnimationsWaitingForNextTick(monotonicTime, events);
startAnimationsWaitingForStartTime(monotonicTime, events);
startAnimationsWaitingForTargetAvailability(monotonicTime, events);
resolveConflicts(monotonicTime);
tickAnimations(monotonicTime);
purgeFinishedAnimations(monotonicTime, events);
startAnimationsWaitingForTargetAvailability(monotonicTime, events);
}
void CCLayerAnimationController::add(PassOwnPtr<CCActiveAnimation> animation)
{
m_activeAnimations.append(animation);
}
CCActiveAnimation* CCLayerAnimationController::getActiveAnimation(int groupId, CCActiveAnimation::TargetProperty targetProperty) const
{
for (size_t i = 0; i < m_activeAnimations.size(); ++i)
if (m_activeAnimations[i]->group() == groupId && m_activeAnimations[i]->targetProperty() == targetProperty)
return m_activeAnimations[i].get();
return 0;
}
bool CCLayerAnimationController::hasActiveAnimation() const
{
for (size_t i = 0; i < m_activeAnimations.size(); ++i) {
if (m_activeAnimations[i]->runState() != CCActiveAnimation::Finished && m_activeAnimations[i]->runState() != CCActiveAnimation::Aborted)
return true;
}
return false;
}
bool CCLayerAnimationController::isAnimatingProperty(CCActiveAnimation::TargetProperty targetProperty) const
{
for (size_t i = 0; i < m_activeAnimations.size(); ++i) {
if (m_activeAnimations[i]->runState() != CCActiveAnimation::Finished && m_activeAnimations[i]->runState() != CCActiveAnimation::Aborted && m_activeAnimations[i]->targetProperty() == targetProperty)
return true;
}
return false;
}
void CCLayerAnimationController::notifyAnimationStarted(const CCAnimationEvent& event)
{
for (size_t i = 0; i < m_activeAnimations.size(); ++i) {
if (m_activeAnimations[i]->group() == event.groupId && m_activeAnimations[i]->targetProperty() == event.targetProperty) {
ASSERT(m_activeAnimations[i]->needsSynchronizedStartTime());
m_activeAnimations[i]->setNeedsSynchronizedStartTime(false);
m_activeAnimations[i]->setStartTime(event.monotonicTime);
return;
}
}
}
void CCLayerAnimationController::pushNewAnimationsToImplThread(CCLayerAnimationController* controllerImpl) const
{
for (size_t i = 0; i < m_activeAnimations.size(); ++i) {
if (controllerImpl->getActiveAnimation(m_activeAnimations[i]->group(), m_activeAnimations[i]->targetProperty()))
continue;
if (!m_activeAnimations[i]->needsSynchronizedStartTime())
continue;
OwnPtr<CCActiveAnimation> toAdd(m_activeAnimations[i]->cloneForImplThread());
ASSERT(!toAdd->needsSynchronizedStartTime());
toAdd->setRunState(CCActiveAnimation::WaitingForTargetAvailability, 0);
controllerImpl->add(toAdd.release());
}
}
void CCLayerAnimationController::removeAnimationsCompletedOnMainThread(CCLayerAnimationController* controllerImpl) const
{
for (size_t i = 0; i < controllerImpl->m_activeAnimations.size();) {
CCActiveAnimation* current = getActiveAnimation(controllerImpl->m_activeAnimations[i]->group(), controllerImpl->m_activeAnimations[i]->targetProperty());
if (!current)
controllerImpl->m_activeAnimations.remove(i);
else
i++;
}
}
void CCLayerAnimationController::pushPropertiesToImplThread(CCLayerAnimationController* controllerImpl) const
{
for (size_t i = 0; i < m_activeAnimations.size(); ++i) {
CCActiveAnimation* currentImpl = controllerImpl->getActiveAnimation(m_activeAnimations[i]->group(), m_activeAnimations[i]->targetProperty());
if (currentImpl)
m_activeAnimations[i]->pushPropertiesTo(currentImpl);
}
}
void CCLayerAnimationController::startAnimationsWaitingForNextTick(double monotonicTime, CCAnimationEventsVector* events)
{
for (size_t i = 0; i < m_activeAnimations.size(); ++i) {
if (m_activeAnimations[i]->runState() == CCActiveAnimation::WaitingForNextTick) {
m_activeAnimations[i]->setRunState(CCActiveAnimation::Running, monotonicTime);
if (!m_activeAnimations[i]->hasSetStartTime())
m_activeAnimations[i]->setStartTime(monotonicTime);
if (events)
events->append(CCAnimationEvent(CCAnimationEvent::Started, m_client->id(), m_activeAnimations[i]->group(), m_activeAnimations[i]->targetProperty(), monotonicTime));
}
}
}
void CCLayerAnimationController::startAnimationsWaitingForStartTime(double monotonicTime, CCAnimationEventsVector* events)
{
for (size_t i = 0; i < m_activeAnimations.size(); ++i) {
if (m_activeAnimations[i]->runState() == CCActiveAnimation::WaitingForStartTime && m_activeAnimations[i]->startTime() <= monotonicTime) {
m_activeAnimations[i]->setRunState(CCActiveAnimation::Running, monotonicTime);
if (events)
events->append(CCAnimationEvent(CCAnimationEvent::Started, m_client->id(), m_activeAnimations[i]->group(), m_activeAnimations[i]->targetProperty(), monotonicTime));
}
}
}
void CCLayerAnimationController::startAnimationsWaitingForTargetAvailability(double monotonicTime, CCAnimationEventsVector* events)
{
TargetProperties blockedProperties;
for (size_t i = 0; i < m_activeAnimations.size(); ++i) {
if (m_activeAnimations[i]->runState() == CCActiveAnimation::Running || m_activeAnimations[i]->runState() == CCActiveAnimation::Finished)
blockedProperties.add(m_activeAnimations[i]->targetProperty());
}
for (size_t i = 0; i < m_activeAnimations.size(); ++i) {
if (m_activeAnimations[i]->runState() == CCActiveAnimation::WaitingForTargetAvailability) {
TargetProperties enqueuedProperties;
enqueuedProperties.add(m_activeAnimations[i]->targetProperty());
for (size_t j = i + 1; j < m_activeAnimations.size(); ++j) {
if (m_activeAnimations[i]->group() == m_activeAnimations[j]->group())
enqueuedProperties.add(m_activeAnimations[j]->targetProperty());
}
bool nullIntersection = true;
for (TargetProperties::iterator pIter = enqueuedProperties.begin(); pIter != enqueuedProperties.end(); ++pIter) {
if (!blockedProperties.add(*pIter).isNewEntry)
nullIntersection = false;
}
if (nullIntersection) {
m_activeAnimations[i]->setRunState(CCActiveAnimation::Running, monotonicTime);
if (!m_activeAnimations[i]->hasSetStartTime())
m_activeAnimations[i]->setStartTime(monotonicTime);
if (events)
events->append(CCAnimationEvent(CCAnimationEvent::Started, m_client->id(), m_activeAnimations[i]->group(), m_activeAnimations[i]->targetProperty(), monotonicTime));
for (size_t j = i + 1; j < m_activeAnimations.size(); ++j) {
if (m_activeAnimations[i]->group() == m_activeAnimations[j]->group()) {
m_activeAnimations[j]->setRunState(CCActiveAnimation::Running, monotonicTime);
if (!m_activeAnimations[j]->hasSetStartTime())
m_activeAnimations[j]->setStartTime(monotonicTime);
}
}
}
}
}
}
void CCLayerAnimationController::resolveConflicts(double monotonicTime)
{
for (size_t i = 0; i < m_activeAnimations.size(); ++i) {
if (m_activeAnimations[i]->runState() == CCActiveAnimation::Running) {
for (size_t j = i + 1; j < m_activeAnimations.size(); ++j) {
if (m_activeAnimations[j]->runState() == CCActiveAnimation::Running && m_activeAnimations[i]->targetProperty() == m_activeAnimations[j]->targetProperty()) {
if (m_activeAnimations[i]->startTime() > m_activeAnimations[j]->startTime())
m_activeAnimations[j]->setRunState(CCActiveAnimation::Aborted, monotonicTime);
else
m_activeAnimations[i]->setRunState(CCActiveAnimation::Aborted, monotonicTime);
}
}
}
}
}
void CCLayerAnimationController::purgeFinishedAnimations(double monotonicTime, CCAnimationEventsVector* events)
{
size_t i = 0;
while (i < m_activeAnimations.size()) {
int groupId = m_activeAnimations[i]->group();
bool allAnimsWithSameIdAreFinished = false;
if (m_activeAnimations[i]->isFinished()) {
allAnimsWithSameIdAreFinished = true;
for (size_t j = 0; j < m_activeAnimations.size(); ++j) {
if (groupId == m_activeAnimations[j]->group() && !m_activeAnimations[j]->isFinished()) {
allAnimsWithSameIdAreFinished = false;
break;
}
}
}
if (allAnimsWithSameIdAreFinished) {
for (size_t j = i; j < m_activeAnimations.size();) {
if (groupId != m_activeAnimations[j]->group())
j++;
else {
if (events)
events->append(CCAnimationEvent(CCAnimationEvent::Finished, m_client->id(), m_activeAnimations[j]->group(), m_activeAnimations[j]->targetProperty(), monotonicTime));
m_activeAnimations.remove(j);
}
}
} else
i++;
}
}
void CCLayerAnimationController::tickAnimations(double monotonicTime)
{
for (size_t i = 0; i < m_activeAnimations.size(); ++i) {
if (m_activeAnimations[i]->runState() == CCActiveAnimation::Running || m_activeAnimations[i]->runState() == CCActiveAnimation::Paused) {
double trimmed = m_activeAnimations[i]->trimTimeToCurrentIteration(monotonicTime);
if (m_activeAnimations[i]->needsSynchronizedStartTime())
trimmed = 0;
switch (m_activeAnimations[i]->targetProperty()) {
case CCActiveAnimation::Transform: {
const CCTransformAnimationCurve* transformAnimationCurve = m_activeAnimations[i]->curve()->toTransformAnimationCurve();
const TransformationMatrix matrix = transformAnimationCurve->getValue(trimmed, m_client->bounds());
if (m_activeAnimations[i]->isFinishedAt(monotonicTime))
m_activeAnimations[i]->setRunState(CCActiveAnimation::Finished, monotonicTime);
m_client->setTransformFromAnimation(matrix);
break;
}
case CCActiveAnimation::Opacity: {
const CCFloatAnimationCurve* floatAnimationCurve = m_activeAnimations[i]->curve()->toFloatAnimationCurve();
const float opacity = floatAnimationCurve->getValue(trimmed);
if (m_activeAnimations[i]->isFinishedAt(monotonicTime))
m_activeAnimations[i]->setRunState(CCActiveAnimation::Finished, monotonicTime);
m_client->setOpacityFromAnimation(opacity);
break;
}
}
}
}
}
}