+2012-01-18 Ian Vollick <vollick@chromium.org>
+
+ [chromium] Create a base-class CCAnimation to represent compositor animations
+ https://bugs.webkit.org/show_bug.cgi?id=73233
+
+ Adds a kernel for running animations on the chromium compositor
+ thread.
+
+ Reviewed by Kenneth Russell.
+
+ * WebCore.gypi:
+ * platform/graphics/chromium/cc/CCActiveAnimation.cpp: Added.
+ (WebCore::CCActiveAnimation::CCActiveAnimation):
+ (WebCore::CCActiveAnimation::setRunState):
+ (WebCore::CCActiveAnimation::isFinishedAt):
+ (WebCore::CCActiveAnimation::trimTimeToCurrentIteration):
+ * platform/graphics/chromium/cc/CCActiveAnimation.h: Added.
+ (WebCore::CCActiveAnimation::create):
+ (WebCore::CCActiveAnimation::~CCActiveAnimation):
+ (WebCore::CCActiveAnimation::group):
+ (WebCore::CCActiveAnimation::targetProperty):
+ (WebCore::CCActiveAnimation::runState):
+ (WebCore::CCActiveAnimation::iterations):
+ (WebCore::CCActiveAnimation::setIterations):
+ (WebCore::CCActiveAnimation::startTime):
+ (WebCore::CCActiveAnimation::setStartTime):
+ (WebCore::CCActiveAnimation::isFinished):
+ (WebCore::CCActiveAnimation::animationCurve):
+ * platform/graphics/chromium/cc/CCAnimationCurve.cpp: Added.
+ (WebCore::CCAnimationCurve::toFloatAnimationCurve):
+ (WebCore::CCAnimationCurve::toTransformAnimationCurve):
+ * platform/graphics/chromium/cc/CCAnimationCurve.h: Added.
+ (WebCore::CCAnimationCurve::~CCAnimationCurve):
+ (WebCore::CCFloatAnimationCurve::~CCFloatAnimationCurve):
+ (WebCore::CCFloatAnimationCurve::type):
+ (WebCore::CCTransformAnimationCurve::~CCTransformAnimationCurve):
+ (WebCore::CCTransformAnimationCurve::type):
+ * platform/graphics/chromium/cc/CCLayerAnimationControllerImpl.cpp: Added.
+ (WebCore::CCLayerAnimationControllerImpl::create):
+ (WebCore::CCLayerAnimationControllerImpl::CCLayerAnimationControllerImpl):
+ (WebCore::CCLayerAnimationControllerImpl::animate):
+ (WebCore::CCLayerAnimationControllerImpl::add):
+ (WebCore::CCLayerAnimationControllerImpl::getActiveAnimation):
+ (WebCore::CCLayerAnimationControllerImpl::hasActiveAnimation):
+ (WebCore::CCLayerAnimationControllerImpl::startAnimationsWaitingForNextTick):
+ (WebCore::CCLayerAnimationControllerImpl::startAnimationsWaitingForStartTime):
+ (WebCore::CCLayerAnimationControllerImpl::startAnimationsWaitingForTargetAvailability):
+ (WebCore::CCLayerAnimationControllerImpl::resolveConflicts):
+ (WebCore::CCLayerAnimationControllerImpl::purgeFinishedAnimations):
+ (WebCore::CCLayerAnimationControllerImpl::tickAnimations):
+ * platform/graphics/chromium/cc/CCLayerAnimationControllerImpl.h: Added.
+ (WebCore::CCLayerAnimationControllerImplClient::~CCLayerAnimationControllerImplClient):
+
2012-01-18 Sheriff Bot <webkit.review.bot@gmail.com>
Unreviewed, rolling out r105331.
'platform/graphics/chromium/VideoLayerChromium.h',
'platform/graphics/chromium/WebGLLayerChromium.cpp',
'platform/graphics/chromium/WebGLLayerChromium.h',
+ 'platform/graphics/chromium/cc/CCActiveAnimation.cpp',
+ 'platform/graphics/chromium/cc/CCActiveAnimation.h',
+ 'platform/graphics/chromium/cc/CCAnimationCurve.cpp',
+ 'platform/graphics/chromium/cc/CCAnimationCurve.h',
'platform/graphics/chromium/cc/CCCanvasDrawQuad.cpp',
'platform/graphics/chromium/cc/CCCanvasDrawQuad.h',
'platform/graphics/chromium/cc/CCCanvasLayerImpl.cpp',
'platform/graphics/chromium/cc/CCHeadsUpDisplay.cpp',
'platform/graphics/chromium/cc/CCHeadsUpDisplay.h',
'platform/graphics/chromium/cc/CCInputHandler.h',
+ 'platform/graphics/chromium/cc/CCLayerAnimationControllerImpl.h',
+ 'platform/graphics/chromium/cc/CCLayerAnimationControllerImpl.cpp',
'platform/graphics/chromium/cc/CCLayerImpl.cpp',
'platform/graphics/chromium/cc/CCLayerImpl.h',
'platform/graphics/chromium/cc/CCLayerIterator.cpp',
--- /dev/null
+/*
+ * Copyright (C) 2012 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "cc/CCActiveAnimation.h"
+
+#include "cc/CCAnimationCurve.h"
+
+#include <cmath>
+
+namespace WebCore {
+
+CCActiveAnimation::CCActiveAnimation(PassOwnPtr<CCAnimationCurve> curve, GroupID group, TargetProperty targetProperty)
+ : m_animationCurve(curve)
+ , m_group(group)
+ , m_targetProperty(targetProperty)
+ , m_runState(WaitingForTargetAvailability)
+ , m_iterations(1)
+ , m_startTime(0)
+ , m_pauseTime(0)
+ , m_totalPausedTime(0)
+{
+}
+
+void CCActiveAnimation::setRunState(RunState runState, double now)
+{
+ if (runState == Running && m_runState == Paused)
+ m_totalPausedTime += now - m_pauseTime;
+ else if (runState == Paused)
+ m_pauseTime = now;
+ m_runState = runState;
+}
+
+bool CCActiveAnimation::isFinishedAt(double time) const
+{
+ if (m_runState == Finished || m_runState == Aborted)
+ return true;
+
+ return m_runState == Running
+ && m_iterations >= 0
+ && m_iterations * m_animationCurve->duration() <= time - startTime() - m_totalPausedTime;
+}
+
+double CCActiveAnimation::trimTimeToCurrentIteration(double now) const
+{
+ double trimmed = now;
+
+ // If we're paused, time is 'stuck' at the pause time.
+ if (m_runState == Paused && trimmed > m_pauseTime)
+ 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;
+
+ // If less than an iteration duration, just return trimmed.
+ if (trimmed < m_animationCurve->duration())
+ return trimmed;
+
+ // If greater than or equal to the total duration, return iteration duration.
+ if (m_iterations >= 0 && trimmed >= m_animationCurve->duration() * m_iterations)
+ return m_animationCurve->duration();
+
+ // Finally, return x where trimmed = x + n * m_animation->duration() for some positive integer n.
+ return fmod(trimmed, m_animationCurve->duration());
+}
+
+} // namespace WebCore
--- /dev/null
+/*
+ * Copyright (C) 2012 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef CCActiveAnimation_h
+#define CCActiveAnimation_h
+
+#include <wtf/OwnPtr.h>
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+class CCAnimationCurve;
+
+// A CCActiveAnimation, contains all the state required to play a CCAnimationCurve.
+// Specifically, the affected property, the run state (paused, finished, etc.),
+// loop count, last pause time, and the total time spent paused.
+class CCActiveAnimation {
+public:
+ // Animations that must be run together are called 'grouped' and have the same GroupID
+ // Grouped animations are guaranteed to start at the same time and no other animations
+ // may animate any of the group's target properties until all animations in the
+ // group have finished animating. Note: an active animation's group id and target
+ // property uniquely identify that animation.
+ typedef int GroupID;
+
+ // Animations begin in one of the 'waiting' states. Animations waiting for the next tick
+ // will start the next time the controller animates. Animations waiting for target
+ // availibility will run as soon as their target property is free (and all the animations
+ // animating with it are also able to run). Animations waiting for their start time to
+ // come have be scheduled to run at a particular point in time. When this time arrives,
+ // the controller will move the animations into the Running state. Running animations
+ // may toggle between Running and Paused, and may be stopped by moving into either the
+ // Aborted or Finished states. A Finished animation was allowed to run to completion, but
+ // an Aborted animation was not.
+ enum RunState {
+ WaitingForNextTick = 1,
+ WaitingForTargetAvailability,
+ WaitingForStartTime,
+ Running,
+ Paused,
+ Finished,
+ Aborted
+ };
+
+ enum TargetProperty {
+ Transform = 1,
+ Opacity
+ };
+
+ static PassOwnPtr<CCActiveAnimation> create(PassOwnPtr<CCAnimationCurve> curve, GroupID group, TargetProperty targetProperty)
+ {
+ return adoptPtr(new CCActiveAnimation(curve, group, targetProperty));
+ }
+
+ virtual ~CCActiveAnimation() { }
+
+ GroupID group() const { return m_group; }
+ TargetProperty targetProperty() const { return m_targetProperty; }
+
+ RunState runState() const { return m_runState; }
+ void setRunState(RunState, double now);
+
+ // This is the number of times that the animation will play. If this
+ // value is zero the animation will not play. If it is negative, then
+ // the animation will loop indefinitely.
+ int iterations() const { return m_iterations; }
+ void setIterations(int n) { m_iterations = n; }
+
+ double startTime() const { return m_startTime; }
+ void setStartTime(double startTime) { m_startTime = startTime; }
+
+ bool isFinishedAt(double time) const;
+ bool isFinished() const { return m_runState == Finished || m_runState == Aborted; }
+
+ CCAnimationCurve* animationCurve() { return m_animationCurve.get(); }
+ const CCAnimationCurve* animationCurve() const { return m_animationCurve.get(); }
+
+ // Takes the given absolute time, and using the start time and the number
+ // of iterations, returns the relative time in the current iteration.
+ double trimTimeToCurrentIteration(double now) const;
+
+private:
+ CCActiveAnimation(PassOwnPtr<CCAnimationCurve>, GroupID, TargetProperty);
+
+ OwnPtr<CCAnimationCurve> m_animationCurve;
+ GroupID m_group;
+ TargetProperty m_targetProperty;
+ RunState m_runState;
+ int m_iterations;
+ double m_startTime;
+
+ // These are used in trimTimeToCurrentIteration to account for time
+ // spent while paused. This is not included in AnimationState since it
+ // there is absolutely no need for clients of this controller to know
+ // about these values.
+ double m_pauseTime;
+ double m_totalPausedTime;
+};
+
+} // namespace WebCore
+
+#endif // CCActiveAnimation_h
--- /dev/null
+/*
+ * Copyright (C) 2012 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "cc/CCAnimationCurve.h"
+
+namespace WebCore {
+
+const CCFloatAnimationCurve* CCAnimationCurve::toFloatAnimationCurve() const
+{
+ ASSERT(type() == CCAnimationCurve::Float);
+ return static_cast<const CCFloatAnimationCurve*>(this);
+}
+
+const CCTransformAnimationCurve* CCAnimationCurve::toTransformAnimationCurve() const
+{
+ ASSERT(type() == CCAnimationCurve::Transform);
+ return static_cast<const CCTransformAnimationCurve*>(this);
+}
+
+} // namespace WebCore
--- /dev/null
+/*
+ * Copyright (C) 2012 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef CCAnimationCurve_h
+#define CCAnimationCurve_h
+
+namespace WebCore {
+
+class CCFloatAnimationCurve;
+class CCTransformAnimationCurve;
+class TransformOperations;
+
+// An animation curve is a function that returns a value given a time.
+// There are currently only two types of curve, float and transform.
+class CCAnimationCurve {
+public:
+ enum Type { Float, Transform };
+
+ virtual ~CCAnimationCurve() { }
+
+ virtual double duration() const = 0;
+ virtual Type type() const = 0;
+
+ const CCFloatAnimationCurve* toFloatAnimationCurve() const;
+ const CCTransformAnimationCurve* toTransformAnimationCurve() const;
+};
+
+class CCFloatAnimationCurve : public CCAnimationCurve {
+public:
+ virtual ~CCFloatAnimationCurve() { }
+
+ virtual float getValue(double t) const = 0;
+
+ // Partial CCAnimation implementation.
+ virtual Type type() const { return Float; }
+};
+
+class CCTransformAnimationCurve : public CCAnimationCurve {
+public:
+ virtual ~CCTransformAnimationCurve() { }
+
+ virtual TransformOperations getValue(double t) const = 0;
+
+ // Partial CCAnimation implementation.
+ virtual Type type() const { return Transform; }
+};
+
+} // namespace WebCore
+
+#endif // CCAnimation_h
--- /dev/null
+/*
+ * Copyright (C) 2012 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "cc/CCLayerAnimationControllerImpl.h"
+
+#include "TransformOperations.h"
+
+namespace WebCore {
+
+// A collection of properties. Used when deterimining if animations waiting for target
+// availibility are able to run.
+typedef HashSet<int> TargetProperties;
+
+PassOwnPtr<CCLayerAnimationControllerImpl> CCLayerAnimationControllerImpl::create(CCLayerAnimationControllerImplClient* client)
+{
+ return adoptPtr(new CCLayerAnimationControllerImpl(client));
+}
+
+CCLayerAnimationControllerImpl::CCLayerAnimationControllerImpl(CCLayerAnimationControllerImplClient* client)
+ : m_client(client)
+{
+}
+
+void CCLayerAnimationControllerImpl::animate(double frameBeginTimeSecs)
+{
+ startAnimationsWaitingForNextTick(frameBeginTimeSecs);
+ startAnimationsWaitingForStartTime(frameBeginTimeSecs);
+ startAnimationsWaitingForTargetAvailability(frameBeginTimeSecs);
+ resolveConflicts(frameBeginTimeSecs);
+ tickAnimations(frameBeginTimeSecs);
+ purgeFinishedAnimations();
+ startAnimationsWaitingForTargetAvailability(frameBeginTimeSecs);
+}
+
+void CCLayerAnimationControllerImpl::add(PassOwnPtr<CCActiveAnimation> anim)
+{
+ m_activeAnimations.append(anim);
+ if (m_client)
+ m_client->animationControllerImplDidActivate(this);
+}
+
+CCActiveAnimation* CCLayerAnimationControllerImpl::getActiveAnimation(CCActiveAnimation::GroupID group, CCActiveAnimation::TargetProperty property)
+{
+ for (size_t i = 0; i < m_activeAnimations.size(); ++i) {
+ if (m_activeAnimations[i]->group() == group && m_activeAnimations[i]->targetProperty() == property)
+ return m_activeAnimations[i].get();
+ }
+ return 0;
+}
+
+bool CCLayerAnimationControllerImpl::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;
+}
+
+void CCLayerAnimationControllerImpl::startAnimationsWaitingForNextTick(double now)
+{
+ for (size_t i = 0; i < m_activeAnimations.size(); ++i) {
+ if (m_activeAnimations[i]->runState() == CCActiveAnimation::WaitingForNextTick) {
+ m_activeAnimations[i]->setRunState(CCActiveAnimation::Running, now);
+ m_activeAnimations[i]->setStartTime(now);
+ }
+ }
+}
+
+void CCLayerAnimationControllerImpl::startAnimationsWaitingForStartTime(double now)
+{
+ for (size_t i = 0; i < m_activeAnimations.size(); ++i) {
+ if (m_activeAnimations[i]->runState() == CCActiveAnimation::WaitingForStartTime && m_activeAnimations[i]->startTime() <= now)
+ m_activeAnimations[i]->setRunState(CCActiveAnimation::Running, now);
+ }
+}
+
+void CCLayerAnimationControllerImpl::startAnimationsWaitingForTargetAvailability(double now)
+{
+ // 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.add(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.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());
+ }
+
+ // 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.add(*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, now);
+ m_activeAnimations[i]->setStartTime(now);
+ 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, now);
+ m_activeAnimations[j]->setStartTime(now);
+ }
+ }
+ }
+ }
+ }
+}
+
+void CCLayerAnimationControllerImpl::resolveConflicts(double now)
+{
+ // 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, now);
+ else
+ m_activeAnimations[i]->setRunState(CCActiveAnimation::Aborted, now);
+ }
+ }
+ }
+ }
+}
+
+void CCLayerAnimationControllerImpl::purgeFinishedAnimations()
+{
+ // Each iteration, m_activeAnimations.size() decreases or i increments,
+ // guaranteeing progress towards loop termination.
+ size_t i = 0;
+ while (i < m_activeAnimations.size()) {
+ bool allAnimsWithSameIdAreFinished = false;
+ if (m_activeAnimations[i]->isFinished()) {
+ allAnimsWithSameIdAreFinished = true;
+ for (size_t j = i + 1; j < m_activeAnimations.size(); ++j) {
+ if (m_activeAnimations[i]->group() == m_activeAnimations[j]->group() && !m_activeAnimations[j]->isFinished()) {
+ allAnimsWithSameIdAreFinished = false;
+ break;
+ }
+ }
+ }
+ if (allAnimsWithSameIdAreFinished)
+ m_activeAnimations.remove(i);
+ else
+ i++;
+ }
+}
+
+void CCLayerAnimationControllerImpl::tickAnimations(double now)
+{
+ for (size_t i = 0; i < m_activeAnimations.size(); ++i) {
+ if (m_activeAnimations[i]->runState() == CCActiveAnimation::Running) {
+ double trimmed = m_activeAnimations[i]->trimTimeToCurrentIteration(now);
+ switch (m_activeAnimations[i]->targetProperty()) {
+
+ case CCActiveAnimation::Transform: {
+ const CCTransformAnimationCurve* transformAnimationCurve = m_activeAnimations[i]->animationCurve()->toTransformAnimationCurve();
+ const TransformOperations operations = transformAnimationCurve->getValue(trimmed);
+ if (m_activeAnimations[i]->isFinishedAt(now))
+ m_activeAnimations[i]->setRunState(CCActiveAnimation::Finished, now);
+
+ // Decide here if absolute or relative. Absolute for now.
+ TransformationMatrix toApply;
+ operations.apply(FloatSize(), toApply);
+ m_client->setTransform(toApply);
+ break;
+ }
+
+ case CCActiveAnimation::Opacity: {
+ const CCFloatAnimationCurve* floatAnimationCurve = m_activeAnimations[i]->animationCurve()->toFloatAnimationCurve();
+ const float opacity = floatAnimationCurve->getValue(trimmed);
+ if (m_activeAnimations[i]->isFinishedAt(now))
+ m_activeAnimations[i]->setRunState(CCActiveAnimation::Finished, now);
+
+ m_client->setOpacity(opacity);
+ break;
+ }
+
+ } // switch
+ } // if running
+ } // for each animation
+}
+
+} // namespace WebCore
--- /dev/null
+/*
+ * Copyright (C) 2012 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef CCLayerAnimationControllerImpl_h
+#define CCLayerAnimationControllerImpl_h
+
+#include "cc/CCActiveAnimation.h"
+#include "cc/CCAnimationCurve.h"
+
+#include <wtf/HashSet.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class CCLayerAnimationControllerImpl;
+class IntSize;
+class TransformationMatrix;
+class TransformOperations;
+
+class CCLayerAnimationControllerImplClient {
+public:
+ virtual ~CCLayerAnimationControllerImplClient() { }
+
+ virtual float opacity() const = 0;
+ virtual void setOpacity(float) = 0;
+ virtual const TransformationMatrix& transform() const = 0;
+ virtual void setTransform(const TransformationMatrix&) = 0;
+ virtual void animationControllerImplDidActivate(CCLayerAnimationControllerImpl*) = 0;
+};
+
+class CCLayerAnimationControllerImpl {
+public:
+ static PassOwnPtr<CCLayerAnimationControllerImpl> create(CCLayerAnimationControllerImplClient*);
+
+ void animate(double frameBeginTimeSecs);
+
+ void add(PassOwnPtr<CCActiveAnimation>);
+
+ // Returns the active animation in the given group, animating the given property if such an
+ // animation exists.
+ CCActiveAnimation* getActiveAnimation(CCActiveAnimation::GroupID, CCActiveAnimation::TargetProperty);
+
+ // Returns true if there are any animations that are neither finished nor aborted.
+ bool hasActiveAnimation() const;
+
+private:
+ // The animator is owned by the layer.
+ explicit CCLayerAnimationControllerImpl(CCLayerAnimationControllerImplClient*);
+
+ void startAnimationsWaitingForNextTick(double now);
+ void startAnimationsWaitingForStartTime(double now);
+ void startAnimationsWaitingForTargetAvailability(double now);
+ void resolveConflicts(double now);
+ void purgeFinishedAnimations();
+
+ void tickAnimations(double now);
+
+ CCLayerAnimationControllerImplClient* m_client;
+ Vector<OwnPtr<CCActiveAnimation> > m_activeAnimations;
+};
+
+} // namespace WebCore
+
+#endif // CCLayerAnimationControllerImpl_h
+
+2012-01-18 Ian Vollick <vollick@chromium.org>
+
+ [chromium] Create a base-class CCAnimation to represent compositor animations
+ https://bugs.webkit.org/show_bug.cgi?id=73233
+
+ Reviewed by Kenneth Russell.
+
+ * WebKit.gypi:
+ * tests/CCActiveAnimationTest.cpp: Added.
+ (WebCore::FakeFloatAnimation::duration):
+ (WebCore::FakeFloatAnimation::getValue):
+ (WebCore::createActiveAnimation):
+ (WebCore::TEST):
+ * tests/CCLayerAnimationControllerImplTest.cpp: Added.
+ (WebCore::FakeControllerClient::FakeControllerClient):
+ (WebCore::FakeControllerClient::~FakeControllerClient):
+ (WebCore::FakeControllerClient::opacity):
+ (WebCore::FakeControllerClient::setOpacity):
+ (WebCore::FakeControllerClient::transform):
+ (WebCore::FakeControllerClient::setTransform):
+ (WebCore::FakeControllerClient::animationControllerImplDidActivate):
+ (WebCore::FakeControllerClient::activeControllers):
+ (WebCore::FakeTransformTransition::FakeTransformTransition):
+ (WebCore::FakeTransformTransition::duration):
+ (WebCore::FakeTransformTransition::getValue):
+ (WebCore::FakeFloatTransition::FakeFloatTransition):
+ (WebCore::FakeFloatTransition::duration):
+ (WebCore::FakeFloatTransition::getValue):
+ (WebCore::TEST):
+
2012-01-18 James Robinson <jamesr@chromium.org>
Unreviewed, rolling out r105366.
'tests/ArenaTestHelpers.h',
'tests/AssociatedURLLoaderTest.cpp',
'tests/Canvas2DLayerChromiumTest.cpp',
+ 'tests/CCActiveAnimationTest.cpp',
'tests/CCDamageTrackerTest.cpp',
'tests/CCDelayBasedTimeSourceTest.cpp',
'tests/CCFrameRateControllerTest.cpp',
+ 'tests/CCLayerAnimationControllerImplTest.cpp',
'tests/CCLayerImplTest.cpp',
'tests/CCLayerIteratorTest.cpp',
'tests/CCLayerQuadTest.cpp',
--- /dev/null
+/*
+ * Copyright (C) 2012 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "cc/CCActiveAnimation.h"
+
+#include "cc/CCAnimationCurve.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class FakeFloatAnimation : public CCFloatAnimationCurve {
+public:
+ virtual double duration() const { return 1; }
+ virtual float getValue(double now) const { return 0; }
+};
+
+PassOwnPtr<CCActiveAnimation> createActiveAnimation(int iterations)
+{
+ OwnPtr<CCActiveAnimation> toReturn(CCActiveAnimation::create(adoptPtr(new FakeFloatAnimation), 1, CCActiveAnimation::Opacity));
+ toReturn->setIterations(iterations);
+ return toReturn.release();
+}
+
+TEST(CCActiveAnimationTest, TrimTimeZeroIterations)
+{
+ OwnPtr<CCActiveAnimation> anim(createActiveAnimation(0));
+ EXPECT_EQ(0, anim->trimTimeToCurrentIteration(-1));
+ EXPECT_EQ(0, anim->trimTimeToCurrentIteration(0));
+ EXPECT_EQ(0, anim->trimTimeToCurrentIteration(1));
+}
+
+TEST(CCActiveAnimationTest, TrimTimeOneIteration)
+{
+ OwnPtr<CCActiveAnimation> anim(createActiveAnimation(1));
+ EXPECT_EQ(0, anim->trimTimeToCurrentIteration(-1));
+ EXPECT_EQ(0, anim->trimTimeToCurrentIteration(0));
+ EXPECT_EQ(1, anim->trimTimeToCurrentIteration(1));
+ EXPECT_EQ(1, anim->trimTimeToCurrentIteration(2));
+}
+
+TEST(CCActiveAnimationTest, TrimTimeInfiniteIterations)
+{
+ OwnPtr<CCActiveAnimation> anim(createActiveAnimation(-1));
+ EXPECT_EQ(0, anim->trimTimeToCurrentIteration(0));
+ EXPECT_EQ(0.5, anim->trimTimeToCurrentIteration(0.5));
+ EXPECT_EQ(0, anim->trimTimeToCurrentIteration(1));
+ EXPECT_EQ(0.5, anim->trimTimeToCurrentIteration(1.5));
+}
+
+TEST(CCActiveAnimationTest, TrimTimeStartTime)
+{
+ OwnPtr<CCActiveAnimation> anim(createActiveAnimation(1));
+ anim->setStartTime(4);
+ EXPECT_EQ(0, anim->trimTimeToCurrentIteration(0));
+ EXPECT_EQ(0, anim->trimTimeToCurrentIteration(4));
+ EXPECT_EQ(0.5, anim->trimTimeToCurrentIteration(4.5));
+ EXPECT_EQ(1, anim->trimTimeToCurrentIteration(5));
+ EXPECT_EQ(1, anim->trimTimeToCurrentIteration(6));
+}
+
+TEST(CCActiveAnimationTest, TrimTimePauseResume)
+{
+ OwnPtr<CCActiveAnimation> anim(createActiveAnimation(1));
+ anim->setRunState(CCActiveAnimation::Running, 0);
+ EXPECT_EQ(0, anim->trimTimeToCurrentIteration(0));
+ EXPECT_EQ(0.5, anim->trimTimeToCurrentIteration(0.5));
+ anim->setRunState(CCActiveAnimation::Paused, 0.5);
+ EXPECT_EQ(0.5, anim->trimTimeToCurrentIteration(1024));
+ anim->setRunState(CCActiveAnimation::Running, 1024);
+ EXPECT_EQ(0.5, anim->trimTimeToCurrentIteration(1024));
+ EXPECT_EQ(1, anim->trimTimeToCurrentIteration(1024.5));
+}
+
+TEST(CCActiveAnimationTest, IsFinishedAtZeroIterations)
+{
+ OwnPtr<CCActiveAnimation> anim(createActiveAnimation(0));
+ anim->setRunState(CCActiveAnimation::Running, 0);
+ EXPECT_FALSE(anim->isFinishedAt(-1));
+ EXPECT_TRUE(anim->isFinishedAt(0));
+ EXPECT_TRUE(anim->isFinishedAt(1));
+}
+
+TEST(CCActiveAnimationTest, IsFinishedAtOneIteration)
+{
+ OwnPtr<CCActiveAnimation> anim(createActiveAnimation(1));
+ anim->setRunState(CCActiveAnimation::Running, 0);
+ EXPECT_FALSE(anim->isFinishedAt(-1));
+ EXPECT_FALSE(anim->isFinishedAt(0));
+ EXPECT_TRUE(anim->isFinishedAt(1));
+ EXPECT_TRUE(anim->isFinishedAt(2));
+}
+
+TEST(CCActiveAnimationTest, IsFinishedAtInfiniteIterations)
+{
+ OwnPtr<CCActiveAnimation> anim(createActiveAnimation(-1));
+ anim->setRunState(CCActiveAnimation::Running, 0);
+ EXPECT_FALSE(anim->isFinishedAt(0));
+ EXPECT_FALSE(anim->isFinishedAt(0.5));
+ EXPECT_FALSE(anim->isFinishedAt(1));
+ EXPECT_FALSE(anim->isFinishedAt(1.5));
+}
+
+TEST(CCActiveAnimationTest, IsFinishedAtNotRunning)
+{
+ OwnPtr<CCActiveAnimation> anim(createActiveAnimation(0));
+ anim->setRunState(CCActiveAnimation::Running, 0);
+ EXPECT_TRUE(anim->isFinishedAt(0));
+ anim->setRunState(CCActiveAnimation::Paused, 0);
+ EXPECT_FALSE(anim->isFinishedAt(0));
+ anim->setRunState(CCActiveAnimation::WaitingForNextTick, 0);
+ EXPECT_FALSE(anim->isFinishedAt(0));
+ anim->setRunState(CCActiveAnimation::WaitingForTargetAvailability, 0);
+ EXPECT_FALSE(anim->isFinishedAt(0));
+ anim->setRunState(CCActiveAnimation::WaitingForStartTime, 0);
+ EXPECT_FALSE(anim->isFinishedAt(0));
+ anim->setRunState(CCActiveAnimation::Finished, 0);
+ EXPECT_TRUE(anim->isFinishedAt(0));
+ anim->setRunState(CCActiveAnimation::Aborted, 0);
+ EXPECT_TRUE(anim->isFinishedAt(0));
+}
+
+TEST(CCActiveAnimationTest, IsFinished)
+{
+ OwnPtr<CCActiveAnimation> anim(createActiveAnimation(1));
+ anim->setRunState(CCActiveAnimation::Running, 0);
+ EXPECT_FALSE(anim->isFinished());
+ anim->setRunState(CCActiveAnimation::Paused, 0);
+ EXPECT_FALSE(anim->isFinished());
+ anim->setRunState(CCActiveAnimation::WaitingForNextTick, 0);
+ EXPECT_FALSE(anim->isFinished());
+ anim->setRunState(CCActiveAnimation::WaitingForTargetAvailability, 0);
+ EXPECT_FALSE(anim->isFinished());
+ anim->setRunState(CCActiveAnimation::WaitingForStartTime, 0);
+ EXPECT_FALSE(anim->isFinished());
+ anim->setRunState(CCActiveAnimation::Finished, 0);
+ EXPECT_TRUE(anim->isFinished());
+ anim->setRunState(CCActiveAnimation::Aborted, 0);
+ EXPECT_TRUE(anim->isFinished());
+}
+
+} // namespace WebCore
--- /dev/null
+/*
+ * Copyright (C) 2012 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "cc/CCLayerAnimationControllerImpl.h"
+
+#include "TransformOperations.h"
+#include "cc/CCAnimationCurve.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <wtf/Vector.h>
+
+using namespace WebCore;
+
+namespace {
+
+class FakeControllerClient : public CCLayerAnimationControllerImplClient {
+public:
+ FakeControllerClient() : m_opacity(0) { }
+ virtual ~FakeControllerClient() { }
+
+ virtual float opacity() const { return m_opacity; }
+ virtual void setOpacity(float opacity) { m_opacity = opacity; }
+ virtual const TransformationMatrix& transform() const { return m_transform; }
+ virtual void setTransform(const TransformationMatrix& transform) { m_transform = transform; }
+ virtual void animationControllerImplDidActivate(CCLayerAnimationControllerImpl* controller)
+ {
+ m_activeControllers.append(controller);
+ }
+
+ Vector<CCLayerAnimationControllerImpl*>& activeControllers() { return m_activeControllers; }
+
+private:
+ float m_opacity;
+ TransformationMatrix m_transform;
+ Vector<CCLayerAnimationControllerImpl*> m_activeControllers;
+};
+
+class FakeTransformTransition : public CCTransformAnimationCurve {
+public:
+ FakeTransformTransition(double duration) : m_duration(duration) { }
+ virtual double duration() const { return m_duration; }
+ virtual TransformOperations getValue(double time) const
+ {
+ return TransformOperations();
+ }
+
+private:
+ double m_duration;
+};
+
+class FakeFloatTransition : public CCFloatAnimationCurve {
+public:
+ FakeFloatTransition(double duration, float from, float to)
+ : m_duration(duration)
+ , m_from(from)
+ , m_to(to)
+ {
+ }
+
+ virtual double duration() const { return m_duration; }
+ virtual float getValue(double time) const
+ {
+ time /= m_duration;
+ if (time >= 1)
+ time = 1;
+ return (1 - time) * m_from + time * m_to;
+ }
+
+private:
+ double m_duration;
+ float m_from;
+ float m_to;
+};
+
+// Tests that transitioning opacity from 0 to 1 works as expected.
+TEST(CCLayerAnimationControllerImplTest, TrivialTransition)
+{
+ FakeControllerClient dummy;
+ OwnPtr<CCLayerAnimationControllerImpl> controller(
+ CCLayerAnimationControllerImpl::create(&dummy));
+
+ OwnPtr<CCActiveAnimation> toAdd(CCActiveAnimation::create(adoptPtr(new FakeFloatTransition(1, 0, 1)), 1, CCActiveAnimation::Opacity));
+
+ controller->add(toAdd.release());
+ controller->animate(0);
+ EXPECT_TRUE(controller->hasActiveAnimation());
+ EXPECT_EQ(0, dummy.opacity());
+ controller->animate(1);
+ EXPECT_EQ(1, dummy.opacity());
+ EXPECT_FALSE(controller->hasActiveAnimation());
+}
+
+// Tests that two queued animations affecting the same property run in sequence.
+TEST(CCLayerAnimationControllerImplTest, TrivialQueuing)
+{
+ FakeControllerClient dummy;
+ OwnPtr<CCLayerAnimationControllerImpl> controller(
+ CCLayerAnimationControllerImpl::create(&dummy));
+
+ controller->add(CCActiveAnimation::create(adoptPtr(new FakeFloatTransition(1, 0, 1)), 1, CCActiveAnimation::Opacity));
+ controller->add(CCActiveAnimation::create(adoptPtr(new FakeFloatTransition(1, 1, 0.5f)), 2, CCActiveAnimation::Opacity));
+
+ controller->animate(0);
+ EXPECT_TRUE(controller->hasActiveAnimation());
+ EXPECT_EQ(0, dummy.opacity());
+ controller->animate(1);
+ EXPECT_TRUE(controller->hasActiveAnimation());
+ EXPECT_EQ(1, dummy.opacity());
+ controller->animate(2);
+ EXPECT_EQ(0.5f, dummy.opacity());
+ EXPECT_FALSE(controller->hasActiveAnimation());
+}
+
+// Tests interrupting a transition with another transition.
+TEST(CCLayerAnimationControllerImplTest, Interrupt)
+{
+ FakeControllerClient dummy;
+ OwnPtr<CCLayerAnimationControllerImpl> controller(
+ CCLayerAnimationControllerImpl::create(&dummy));
+ controller->add(CCActiveAnimation::create(adoptPtr(new FakeFloatTransition(1, 0, 1)), 1, CCActiveAnimation::Opacity));
+ controller->animate(0);
+ EXPECT_TRUE(controller->hasActiveAnimation());
+ EXPECT_EQ(0, dummy.opacity());
+
+ OwnPtr<CCActiveAnimation> toAdd(CCActiveAnimation::create(adoptPtr(new FakeFloatTransition(1, 1, 0.5f)), 2, CCActiveAnimation::Opacity));
+ toAdd->setRunState(CCActiveAnimation::WaitingForNextTick, 0);
+ controller->add(toAdd.release());
+
+ controller->animate(0.5); // second anim starts NOW.
+ EXPECT_TRUE(controller->hasActiveAnimation());
+ EXPECT_EQ(1, dummy.opacity());
+ controller->animate(1.5);
+ EXPECT_EQ(0.5f, dummy.opacity());
+ EXPECT_FALSE(controller->hasActiveAnimation());
+}
+
+// Tests scheduling two animations to run together when only one property is free.
+TEST(CCLayerAnimationControllerImplTest, ScheduleTogetherWhenAPropertyIsBlocked)
+{
+ FakeControllerClient dummy;
+ OwnPtr<CCLayerAnimationControllerImpl> controller(
+ CCLayerAnimationControllerImpl::create(&dummy));
+
+ controller->add(CCActiveAnimation::create(adoptPtr(new FakeTransformTransition(1)), 1, CCActiveAnimation::Transform));
+ controller->add(CCActiveAnimation::create(adoptPtr(new FakeTransformTransition(1)), 2, CCActiveAnimation::Transform));
+ controller->add(CCActiveAnimation::create(adoptPtr(new FakeFloatTransition(1, 0, 1)), 2, CCActiveAnimation::Opacity));
+
+ controller->animate(0);
+ EXPECT_EQ(0, dummy.opacity());
+ EXPECT_TRUE(controller->hasActiveAnimation());
+ controller->animate(1);
+ // Should not have started the float transition yet.
+ EXPECT_TRUE(controller->hasActiveAnimation());
+ EXPECT_EQ(0, dummy.opacity());
+ // The the float animation should have started at time 1 and should be done.
+ controller->animate(2);
+ EXPECT_EQ(1, dummy.opacity());
+ EXPECT_FALSE(controller->hasActiveAnimation());
+}
+
+// Tests scheduling two animations to run together with different lengths and another
+// animation queued to start when the shorter animation finishes (should wait
+// for both to finish).
+TEST(CCLayerAnimationControllerImplTest, ScheduleTogetherWithAnAnimWaiting)
+{
+ FakeControllerClient dummy;
+ OwnPtr<CCLayerAnimationControllerImpl> controller(
+ CCLayerAnimationControllerImpl::create(&dummy));
+
+ controller->add(CCActiveAnimation::create(adoptPtr(new FakeTransformTransition(2)), 1, CCActiveAnimation::Transform));
+ controller->add(CCActiveAnimation::create(adoptPtr(new FakeFloatTransition(1, 0, 1)), 1, CCActiveAnimation::Opacity));
+ controller->add(CCActiveAnimation::create(adoptPtr(new FakeFloatTransition(1, 1, 0.5f)), 2, CCActiveAnimation::Opacity));
+
+ // Anims with id 1 should both start now.
+ controller->animate(0);
+ EXPECT_TRUE(controller->hasActiveAnimation());
+ EXPECT_EQ(0, dummy.opacity());
+ // The opacity animation should have finished at time 1, but the group
+ // of animations with id 1 don't finish until time 2 because of the length
+ // of the transform animation.
+ controller->animate(2);
+ // Should not have started the float transition yet.
+ EXPECT_TRUE(controller->hasActiveAnimation());
+ EXPECT_EQ(1, dummy.opacity());
+
+ // The the second opacity animation should start at time 2 and should be
+ // done by time 3
+ controller->animate(3);
+ EXPECT_EQ(0.5f, dummy.opacity());
+ EXPECT_FALSE(controller->hasActiveAnimation());
+}
+
+// Tests scheduling an animation to start in the future.
+TEST(CCLayerAnimationControllerImplTest, ScheduleAnimation)
+{
+ FakeControllerClient dummy;
+ OwnPtr<CCLayerAnimationControllerImpl> controller(
+ CCLayerAnimationControllerImpl::create(&dummy));
+
+ OwnPtr<CCActiveAnimation> toAdd(CCActiveAnimation::create(adoptPtr(new FakeFloatTransition(1, 0, 1)), 1, CCActiveAnimation::Opacity));
+ toAdd->setRunState(CCActiveAnimation::WaitingForStartTime, 0);
+ toAdd->setStartTime(1);
+ controller->add(toAdd.release());
+
+ controller->animate(0);
+ EXPECT_TRUE(controller->hasActiveAnimation());
+ EXPECT_EQ(0, dummy.opacity());
+ controller->animate(1);
+ EXPECT_TRUE(controller->hasActiveAnimation());
+ EXPECT_EQ(0, dummy.opacity());
+ controller->animate(2);
+ EXPECT_EQ(1, dummy.opacity());
+ EXPECT_FALSE(controller->hasActiveAnimation());
+}
+
+// Tests scheduling an animation to start in the future that's interrupting a running animation.
+TEST(CCLayerAnimationControllerImplTest, ScheduledAnimationInterruptsRunningAnimation)
+{
+ FakeControllerClient dummy;
+ OwnPtr<CCLayerAnimationControllerImpl> controller(
+ CCLayerAnimationControllerImpl::create(&dummy));
+
+ controller->add(CCActiveAnimation::create(adoptPtr(new FakeFloatTransition(2, 0, 1)), 1, CCActiveAnimation::Opacity));
+
+ OwnPtr<CCActiveAnimation> toAdd(CCActiveAnimation::create(adoptPtr(new FakeFloatTransition(1, 0.5f, 0)), 2, CCActiveAnimation::Opacity));
+ toAdd->setRunState(CCActiveAnimation::WaitingForStartTime, 0);
+ toAdd->setStartTime(1);
+ controller->add(toAdd.release());
+
+ // First 2s opacity transition should start immediately.
+ controller->animate(0);
+ EXPECT_TRUE(controller->hasActiveAnimation());
+ EXPECT_EQ(0, dummy.opacity());
+ controller->animate(0.5);
+ EXPECT_TRUE(controller->hasActiveAnimation());
+ EXPECT_EQ(0.25f, dummy.opacity());
+ controller->animate(1);
+ EXPECT_TRUE(controller->hasActiveAnimation());
+ EXPECT_EQ(0.5f, dummy.opacity());
+ controller->animate(2);
+ EXPECT_EQ(0, dummy.opacity());
+ EXPECT_FALSE(controller->hasActiveAnimation());
+}
+
+// Tests scheduling an animation to start in the future that interrupts a running animation
+// and there is yet another animation queued to start later.
+TEST(CCLayerAnimationControllerImplTest, ScheduledAnimationInterruptsRunningAnimationWithAnimInQueue)
+{
+ FakeControllerClient dummy;
+ OwnPtr<CCLayerAnimationControllerImpl> controller(
+ CCLayerAnimationControllerImpl::create(&dummy));
+
+ controller->add(CCActiveAnimation::create(adoptPtr(new FakeFloatTransition(2, 0, 1)), 1, CCActiveAnimation::Opacity));
+
+ OwnPtr<CCActiveAnimation> toAdd(CCActiveAnimation::create(adoptPtr(new FakeFloatTransition(2, 0.5f, 0)), 2, CCActiveAnimation::Opacity));
+ toAdd->setRunState(CCActiveAnimation::WaitingForStartTime, 0);
+ toAdd->setStartTime(1);
+ controller->add(toAdd.release());
+
+ controller->add(CCActiveAnimation::create(adoptPtr(new FakeFloatTransition(1, 0, 0.75f)), 3, CCActiveAnimation::Opacity));
+
+ // First 2s opacity transition should start immediately.
+ controller->animate(0);
+ EXPECT_TRUE(controller->hasActiveAnimation());
+ EXPECT_EQ(0, dummy.opacity());
+ controller->animate(0.5);
+ EXPECT_TRUE(controller->hasActiveAnimation());
+ EXPECT_EQ(0.25f, dummy.opacity());
+ EXPECT_TRUE(controller->hasActiveAnimation());
+ controller->animate(1);
+ EXPECT_TRUE(controller->hasActiveAnimation());
+ EXPECT_EQ(0.5f, dummy.opacity());
+ controller->animate(3);
+ EXPECT_TRUE(controller->hasActiveAnimation());
+ EXPECT_EQ(0, dummy.opacity());
+ controller->animate(4);
+ EXPECT_EQ(0.75f, dummy.opacity());
+ EXPECT_FALSE(controller->hasActiveAnimation());
+}
+
+// Test that a looping animation loops and for the correct number of iterations.
+TEST(CCLayerAnimationControllerImplTest, TrivialLooping)
+{
+ FakeControllerClient dummy;
+ OwnPtr<CCLayerAnimationControllerImpl> controller(
+ CCLayerAnimationControllerImpl::create(&dummy));
+
+ OwnPtr<CCActiveAnimation> toAdd(CCActiveAnimation::create(adoptPtr(new FakeFloatTransition(1, 0, 1)), 1, CCActiveAnimation::Opacity));
+ toAdd->setIterations(3);
+ controller->add(toAdd.release());
+
+ controller->animate(0);
+ EXPECT_TRUE(controller->hasActiveAnimation());
+ EXPECT_EQ(0, dummy.opacity());
+ controller->animate(1.25);
+ EXPECT_TRUE(controller->hasActiveAnimation());
+ EXPECT_EQ(0.25f, dummy.opacity());
+ controller->animate(1.75);
+ EXPECT_TRUE(controller->hasActiveAnimation());
+ EXPECT_EQ(0.75f, dummy.opacity());
+ controller->animate(2.25);
+ EXPECT_TRUE(controller->hasActiveAnimation());
+ EXPECT_EQ(0.25f, dummy.opacity());
+ controller->animate(2.75);
+ EXPECT_TRUE(controller->hasActiveAnimation());
+ EXPECT_EQ(0.75f, dummy.opacity());
+ controller->animate(3);
+ EXPECT_FALSE(controller->hasActiveAnimation());
+ EXPECT_EQ(1, dummy.opacity());
+
+ // Just be extra sure.
+ controller->animate(4);
+ EXPECT_EQ(1, dummy.opacity());
+}
+
+// Test that an infinitely looping animation does indeed go until aborted.
+TEST(CCLayerAnimationControllerImplTest, InfiniteLooping)
+{
+ FakeControllerClient dummy;
+ OwnPtr<CCLayerAnimationControllerImpl> controller(
+ CCLayerAnimationControllerImpl::create(&dummy));
+
+ const int id = 1;
+ OwnPtr<CCActiveAnimation> toAdd(CCActiveAnimation::create(adoptPtr(new FakeFloatTransition(1, 0, 1)), id, CCActiveAnimation::Opacity));
+ toAdd->setIterations(-1);
+ controller->add(toAdd.release());
+
+ controller->animate(0);
+ EXPECT_TRUE(controller->hasActiveAnimation());
+ EXPECT_EQ(0, dummy.opacity());
+ controller->animate(1.25);
+ EXPECT_TRUE(controller->hasActiveAnimation());
+ EXPECT_EQ(0.25f, dummy.opacity());
+ controller->animate(1.75);
+ EXPECT_TRUE(controller->hasActiveAnimation());
+ EXPECT_EQ(0.75f, dummy.opacity());
+
+ controller->animate(1073741824.25);
+ EXPECT_TRUE(controller->hasActiveAnimation());
+ EXPECT_EQ(0.25f, dummy.opacity());
+ controller->animate(1073741824.75);
+ EXPECT_TRUE(controller->hasActiveAnimation());
+ EXPECT_EQ(0.75f, dummy.opacity());
+
+ EXPECT_TRUE(controller->getActiveAnimation(id, CCActiveAnimation::Opacity));
+ controller->getActiveAnimation(id, CCActiveAnimation::Opacity)->setRunState(CCActiveAnimation::Aborted, 0.75f);
+ EXPECT_FALSE(controller->hasActiveAnimation());
+ EXPECT_EQ(0.75f, dummy.opacity());
+}
+
+// Test that pausing and resuming work as expected.
+TEST(CCLayerAnimationControllerImplTest, PauseResume)
+{
+ FakeControllerClient dummy;
+ OwnPtr<CCLayerAnimationControllerImpl> controller(
+ CCLayerAnimationControllerImpl::create(&dummy));
+
+ const int id = 1;
+ controller->add(CCActiveAnimation::create(adoptPtr(new FakeFloatTransition(1, 0, 1)), id, CCActiveAnimation::Opacity));
+
+ controller->animate(0);
+ EXPECT_TRUE(controller->hasActiveAnimation());
+ EXPECT_EQ(0, dummy.opacity());
+ controller->animate(0.5);
+ EXPECT_TRUE(controller->hasActiveAnimation());
+ EXPECT_EQ(0.5f, dummy.opacity());
+
+ EXPECT_TRUE(controller->getActiveAnimation(id, CCActiveAnimation::Opacity));
+ controller->getActiveAnimation(id, CCActiveAnimation::Opacity)->setRunState(CCActiveAnimation::Paused, 0.5f);
+
+ controller->animate(1024);
+ EXPECT_TRUE(controller->hasActiveAnimation());
+ EXPECT_EQ(0.5f, dummy.opacity());
+
+ EXPECT_TRUE(controller->getActiveAnimation(id, CCActiveAnimation::Opacity));
+ controller->getActiveAnimation(id, CCActiveAnimation::Opacity)->setRunState(CCActiveAnimation::Running, 1024);
+
+ controller->animate(1024.25);
+ EXPECT_TRUE(controller->hasActiveAnimation());
+ EXPECT_EQ(0.75f, dummy.opacity());
+ controller->animate(1024.5);
+ EXPECT_FALSE(controller->hasActiveAnimation());
+ EXPECT_EQ(1, dummy.opacity());
+}
+
+TEST(CCLayerAnimationControllerImplTest, AbortAGroupedAnimation)
+{
+ FakeControllerClient dummy;
+ OwnPtr<CCLayerAnimationControllerImpl> controller(
+ CCLayerAnimationControllerImpl::create(&dummy));
+
+ const int id = 1;
+ controller->add(CCActiveAnimation::create(adoptPtr(new FakeTransformTransition(1)), id, CCActiveAnimation::Transform));
+ controller->add(CCActiveAnimation::create(adoptPtr(new FakeFloatTransition(2, 0, 1)), id, CCActiveAnimation::Opacity));
+ controller->add(CCActiveAnimation::create(adoptPtr(new FakeFloatTransition(1, 1, 0.75f)), 2, CCActiveAnimation::Opacity));
+
+ controller->animate(0);
+ EXPECT_TRUE(controller->hasActiveAnimation());
+ EXPECT_EQ(0, dummy.opacity());
+ controller->animate(1);
+ EXPECT_TRUE(controller->hasActiveAnimation());
+ EXPECT_EQ(0.5f, dummy.opacity());
+
+ EXPECT_TRUE(controller->getActiveAnimation(id, CCActiveAnimation::Opacity));
+ controller->getActiveAnimation(id, CCActiveAnimation::Opacity)->setRunState(CCActiveAnimation::Aborted, 1);
+ controller->animate(1);
+ EXPECT_TRUE(controller->hasActiveAnimation());
+ EXPECT_EQ(1, dummy.opacity());
+ controller->animate(2);
+ EXPECT_TRUE(!controller->hasActiveAnimation());
+ EXPECT_EQ(0.75f, dummy.opacity());
+}
+
+// Tests that adding an animation to the controller calls the appropriate callback on the controller client
+// (in this case, adding the controller to the list of active controller).
+TEST(CCLayerAnimationControllerImplTest, DidActivate)
+{
+ FakeControllerClient dummy;
+ OwnPtr<CCLayerAnimationControllerImpl> controller(
+ CCLayerAnimationControllerImpl::create(&dummy));
+
+ EXPECT_EQ(size_t(0), dummy.activeControllers().size());
+
+ controller->add(CCActiveAnimation::create(adoptPtr(new FakeFloatTransition(1, 0, 1)), 1, CCActiveAnimation::Opacity));
+
+ EXPECT_EQ(size_t(1), dummy.activeControllers().size());
+ EXPECT_EQ(controller.get(), dummy.activeControllers()[0]);
+}
+
+} // namespace