diff options
author | enne@chromium.org <enne@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-10-12 22:43:41 +0000 |
---|---|---|
committer | enne@chromium.org <enne@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-10-12 22:43:41 +0000 |
commit | cd57cc5a246367c2558fefa04ae9eca8f4d545d2 (patch) | |
tree | a2235045e9c5e4ff028d641b76f5d01aa5461b26 /cc/layer_animation_controller.cc | |
parent | 3fe7ba055be580443445895c0ee01ada3b628487 (diff) | |
download | chromium_src-cd57cc5a246367c2558fefa04ae9eca8f4d545d2.zip chromium_src-cd57cc5a246367c2558fefa04ae9eca8f4d545d2.tar.gz chromium_src-cd57cc5a246367c2558fefa04ae9eca8f4d545d2.tar.bz2 |
[cc] Rename all cc/ filenames to Chromium style
BUG=155413
Review URL: https://codereview.chromium.org/11122003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@161671 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'cc/layer_animation_controller.cc')
-rw-r--r-- | cc/layer_animation_controller.cc | 407 |
1 files changed, 407 insertions, 0 deletions
diff --git a/cc/layer_animation_controller.cc b/cc/layer_animation_controller.cc new file mode 100644 index 0000000..2025db8 --- /dev/null +++ b/cc/layer_animation_controller.cc @@ -0,0 +1,407 @@ +// 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 "config.h" + +#include "CCLayerAnimationController.h" + +#include "CCActiveAnimation.h" +#include "CCKeyframedAnimationCurve.h" +#include <public/WebTransformationMatrix.h> +#include <wtf/CurrentTime.h> +#include <wtf/HashMap.h> + +using WebKit::WebTransformationMatrix; + +namespace cc { + +CCLayerAnimationController::CCLayerAnimationController(CCLayerAnimationControllerClient* client) + : m_forceSync(false) + , m_client(client) +{ +} + +CCLayerAnimationController::~CCLayerAnimationController() +{ +} + +scoped_ptr<CCLayerAnimationController> CCLayerAnimationController::create(CCLayerAnimationControllerClient* client) +{ + return make_scoped_ptr(new CCLayerAnimationController(client)); +} + +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::removeAnimation(int animationId, CCActiveAnimation::TargetProperty targetProperty) +{ + for (size_t i = 0; i < m_activeAnimations.size();) { + if (m_activeAnimations[i]->id() == animationId && m_activeAnimations[i]->targetProperty() == targetProperty) + m_activeAnimations.remove(i); + else + i++; + } +} + +// According to render layer backing, these are for testing only. +void CCLayerAnimationController::suspendAnimations(double monotonicTime) +{ + for (size_t i = 0; i < m_activeAnimations.size(); ++i) { + if (!m_activeAnimations[i]->isFinished()) + m_activeAnimations[i]->setRunState(CCActiveAnimation::Paused, monotonicTime); + } +} + +// Looking at GraphicsLayerCA, this appears to be the analog to suspendAnimations, which is for testing. +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); + } +} + +// Ensures that the list of active animations on the main thread and the impl thread +// are kept in sync. +void CCLayerAnimationController::pushAnimationUpdatesTo(CCLayerAnimationController* controllerImpl) +{ + if (m_forceSync) { + replaceImplThreadAnimations(controllerImpl); + m_forceSync = false; + } else { + purgeAnimationsMarkedForDeletion(); + pushNewAnimationsToImplThread(controllerImpl); + + // Remove finished impl side animations only after pushing, + // and only after the animations are deleted on the main thread + // this insures we will never push an animation twice. + removeAnimationsCompletedOnMainThread(controllerImpl); + + pushPropertiesToImplThread(controllerImpl); + } +} + +void CCLayerAnimationController::animate(double monotonicTime, CCAnimationEventsVector* events) +{ + startAnimationsWaitingForNextTick(monotonicTime, events); + startAnimationsWaitingForStartTime(monotonicTime, events); + startAnimationsWaitingForTargetAvailability(monotonicTime, events); + resolveConflicts(monotonicTime); + tickAnimations(monotonicTime); + markAnimationsForDeletion(monotonicTime, events); + startAnimationsWaitingForTargetAvailability(monotonicTime, events); +} + +void CCLayerAnimationController::addAnimation(scoped_ptr<CCActiveAnimation> animation) +{ + m_activeAnimations.append(animation.Pass()); +} + +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]; + return 0; +} + +CCActiveAnimation* CCLayerAnimationController::getActiveAnimation(CCActiveAnimation::TargetProperty targetProperty) const +{ + for (size_t i = 0; i < m_activeAnimations.size(); ++i) { + size_t index = m_activeAnimations.size() - i - 1; + if (m_activeAnimations[index]->targetProperty() == targetProperty) + return m_activeAnimations[index]; + } + return 0; +} + +bool CCLayerAnimationController::hasActiveAnimation() const +{ + for (size_t i = 0; i < m_activeAnimations.size(); ++i) { + if (!m_activeAnimations[i]->isFinished()) + 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 && m_activeAnimations[i]->needsSynchronizedStartTime()) { + m_activeAnimations[i]->setNeedsSynchronizedStartTime(false); + m_activeAnimations[i]->setStartTime(event.monotonicTime); + return; + } + } +} + +void CCLayerAnimationController::setClient(CCLayerAnimationControllerClient* client) +{ + m_client = client; +} + +void CCLayerAnimationController::pushNewAnimationsToImplThread(CCLayerAnimationController* controllerImpl) const +{ + // Any new animations owned by the main thread's controller are cloned and adde to the impl thread's controller. + for (size_t i = 0; i < m_activeAnimations.size(); ++i) { + // If the animation is already running on the impl thread, there is no need to copy it over. + if (controllerImpl->getActiveAnimation(m_activeAnimations[i]->group(), m_activeAnimations[i]->targetProperty())) + continue; + + // If the animation is not running on the impl thread, it does not necessarily mean that it needs + // to be copied over and started; it may have already finished. In this case, the impl thread animation + // will have already notified that it has started and the main thread animation will no longer need + // a synchronized start time. + if (!m_activeAnimations[i]->needsSynchronizedStartTime()) + continue; + + // The new animation should be set to run as soon as possible. + CCActiveAnimation::RunState initialRunState = CCActiveAnimation::WaitingForTargetAvailability; + double startTime = 0; + scoped_ptr<CCActiveAnimation> toAdd(m_activeAnimations[i]->cloneAndInitialize(CCActiveAnimation::ControllingInstance, initialRunState, startTime)); + ASSERT(!toAdd->needsSynchronizedStartTime()); + controllerImpl->addAnimation(toAdd.Pass()); + } +} + +void CCLayerAnimationController::removeAnimationsCompletedOnMainThread(CCLayerAnimationController* controllerImpl) const +{ + // Delete all impl thread animations for which there is no corresponding main thread animation. + // Each iteration, controller->m_activeAnimations.size() is decremented or i is incremented + // guaranteeing progress towards loop termination. + 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->push_back(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->push_back(CCAnimationEvent(CCAnimationEvent::Started, m_client->id(), m_activeAnimations[i]->group(), m_activeAnimations[i]->targetProperty(), monotonicTime)); + } + } +} + +void CCLayerAnimationController::startAnimationsWaitingForTargetAvailability(double monotonicTime, CCAnimationEventsVector* events) +{ + // First collect running properties. + 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.insert(m_activeAnimations[i]->targetProperty()); + } + + for (size_t i = 0; i < m_activeAnimations.size(); ++i) { + if (m_activeAnimations[i]->runState() == CCActiveAnimation::WaitingForTargetAvailability) { + // Collect all properties for animations with the same group id (they should all also be in the list of animations). + TargetProperties enqueuedProperties; + enqueuedProperties.insert(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.insert(m_activeAnimations[j]->targetProperty()); + } + + // Check to see if intersection of the list of properties affected by the group and the list of currently + // blocked properties is null. In any case, the group's target properties need to be added to the list + // of blocked properties. + bool nullIntersection = true; + for (TargetProperties::iterator pIter = enqueuedProperties.begin(); pIter != enqueuedProperties.end(); ++pIter) { + if (!blockedProperties.insert(*pIter).second) + nullIntersection = false; + } + + // If the intersection is null, then we are free to start the animations in the group. + if (nullIntersection) { + m_activeAnimations[i]->setRunState(CCActiveAnimation::Running, monotonicTime); + if (!m_activeAnimations[i]->hasSetStartTime()) + m_activeAnimations[i]->setStartTime(monotonicTime); + if (events) + events->push_back(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) +{ + // Find any animations that are animating the same property and resolve the + // confict. We could eventually blend, but for now we'll just abort the + // previous animation (where 'previous' means: (1) has a prior start time or + // (2) has an equal start time, but was added to the queue earlier, i.e., + // has a lower index in m_activeAnimations). + 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::markAnimationsForDeletion(double monotonicTime, CCAnimationEventsVector* events) +{ + for (size_t i = 0; i < m_activeAnimations.size(); i++) { + int groupId = m_activeAnimations[i]->group(); + bool allAnimsWithSameIdAreFinished = false; + // If an animation is finished, and not already marked for deletion, + // Find out if all other animations in the same group are also finished. + 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) { + // We now need to remove all animations with the same group id as groupId + // (and send along animation finished notifications, if necessary). + for (size_t j = i; j < m_activeAnimations.size(); j++) { + if (groupId == m_activeAnimations[j]->group()) { + if (events) + events->push_back(CCAnimationEvent(CCAnimationEvent::Finished, m_client->id(), m_activeAnimations[j]->group(), m_activeAnimations[j]->targetProperty(), monotonicTime)); + m_activeAnimations[j]->setRunState(CCActiveAnimation::WaitingForDeletion, monotonicTime); + } + } + } + } +} + +void CCLayerAnimationController::purgeAnimationsMarkedForDeletion() +{ + for (size_t i = 0; i < m_activeAnimations.size();) { + if (m_activeAnimations[i]->runState() == CCActiveAnimation::WaitingForDeletion) + m_activeAnimations.remove(i); + else + i++; + } +} + +void CCLayerAnimationController::replaceImplThreadAnimations(CCLayerAnimationController* controllerImpl) const +{ + controllerImpl->m_activeAnimations.clear(); + for (size_t i = 0; i < m_activeAnimations.size(); ++i) { + scoped_ptr<CCActiveAnimation> toAdd; + if (m_activeAnimations[i]->needsSynchronizedStartTime()) { + // We haven't received an animation started notification yet, so it + // is important that we add it in a 'waiting' and not 'running' state. + CCActiveAnimation::RunState initialRunState = CCActiveAnimation::WaitingForTargetAvailability; + double startTime = 0; + toAdd = m_activeAnimations[i]->cloneAndInitialize(CCActiveAnimation::ControllingInstance, initialRunState, startTime).Pass(); + } else + toAdd = m_activeAnimations[i]->clone(CCActiveAnimation::ControllingInstance).Pass(); + + controllerImpl->addAnimation(toAdd.Pass()); + } +} + +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); + + // Animation assumes its initial value until it gets the synchronized start time + // from the impl thread and can start ticking. + if (m_activeAnimations[i]->needsSynchronizedStartTime()) + trimmed = 0; + + switch (m_activeAnimations[i]->targetProperty()) { + + case CCActiveAnimation::Transform: { + const CCTransformAnimationCurve* transformAnimationCurve = m_activeAnimations[i]->curve()->toTransformAnimationCurve(); + const WebTransformationMatrix matrix = transformAnimationCurve->getValue(trimmed); + 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; + } + + // Do nothing for sentinel value. + case CCActiveAnimation::TargetPropertyEnumSize: + ASSERT_NOT_REACHED(); + + } + } + } +} + +} // namespace cc |