From 95e4e1a0fda6929b47702e69e4ddfe384b5d014b Mon Sep 17 00:00:00 2001 From: "jamesr@chromium.org" Date: Mon, 18 Mar 2013 07:09:09 +0000 Subject: Part 3 of cc/ directory shuffles: animation Continuation of https://src.chromium.org/viewvc/chrome?view=rev&revision=188681 BUG=190824 TBR=enne@chromium.org, vollick@chromium.org Review URL: https://codereview.chromium.org/12822004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@188688 0039d316-1c4b-4281-b951-d872f2087c98 --- cc/animation.cc | 236 ------ cc/animation.h | 190 ----- cc/animation/animation.cc | 236 ++++++ cc/animation/animation.h | 190 +++++ cc/animation/animation_curve.cc | 30 + cc/animation/animation_curve.h | 56 ++ cc/animation/animation_events.h | 43 + cc/animation/animation_id_provider.cc | 19 + cc/animation/animation_id_provider.h | 21 + cc/animation/animation_registrar.cc | 51 ++ cc/animation/animation_registrar.h | 65 ++ cc/animation/animation_unittest.cc | 205 +++++ cc/animation/keyframed_animation_curve.cc | 200 +++++ cc/animation/keyframed_animation_curve.h | 129 +++ cc/animation/keyframed_animation_curve_unittest.cc | 243 ++++++ cc/animation/layer_animation_controller.cc | 628 ++++++++++++++ cc/animation/layer_animation_controller.h | 154 ++++ .../layer_animation_controller_unittest.cc | 901 +++++++++++++++++++++ cc/animation/layer_animation_event_observer.h | 18 + cc/animation/layer_animation_value_observer.h | 23 + cc/animation/scrollbar_animation_controller.h | 32 + .../scrollbar_animation_controller_linear_fade.cc | 94 +++ .../scrollbar_animation_controller_linear_fade.h | 50 ++ ...ar_animation_controller_linear_fade_unittest.cc | 168 ++++ cc/animation_curve.cc | 30 - cc/animation_curve.h | 56 -- cc/animation_events.h | 43 - cc/animation_id_provider.cc | 19 - cc/animation_id_provider.h | 21 - cc/animation_registrar.cc | 51 -- cc/animation_registrar.h | 65 -- cc/animation_unittest.cc | 205 ----- cc/cc.gyp | 36 +- cc/cc_tests.gyp | 8 +- cc/keyframed_animation_curve.cc | 200 ----- cc/keyframed_animation_curve.h | 129 --- cc/keyframed_animation_curve_unittest.cc | 243 ------ cc/layer.cc | 6 +- cc/layer.h | 6 +- cc/layer_animation_controller.cc | 628 -------------- cc/layer_animation_controller.h | 154 ---- cc/layer_animation_controller_unittest.cc | 901 --------------------- cc/layer_animation_event_observer.h | 18 - cc/layer_animation_value_observer.h | 23 - cc/layer_impl.cc | 6 +- cc/layer_impl.h | 4 +- cc/layer_tree_host.cc | 4 +- cc/layer_tree_host.h | 2 +- cc/layer_tree_host_common_unittest.cc | 2 +- cc/layer_tree_host_impl.cc | 2 +- cc/layer_tree_host_impl.h | 4 +- cc/layer_tree_host_unittest_animation.cc | 4 +- cc/layer_tree_impl.cc | 8 +- cc/layer_unittest.cc | 2 +- cc/occlusion_tracker_unittest.cc | 2 +- cc/scrollbar_animation_controller.h | 32 - cc/scrollbar_animation_controller_linear_fade.cc | 94 --- cc/scrollbar_animation_controller_linear_fade.h | 50 -- ...ar_animation_controller_linear_fade_unittest.cc | 168 ---- cc/scrollbar_layer_impl.cc | 2 +- cc/scrollbar_layer_unittest.cc | 2 +- cc/single_thread_proxy.h | 2 +- cc/test/animation_test_common.cc | 4 +- cc/test/animation_test_common.h | 8 +- cc/test/layer_tree_test_common.cc | 6 +- cc/thread_proxy.h | 2 +- cc/timing_function.h | 2 +- cc/top_controls_manager.cc | 2 +- cc/tree_synchronizer.cc | 2 +- cc/tree_synchronizer_unittest.cc | 2 +- 70 files changed, 3621 insertions(+), 3621 deletions(-) delete mode 100644 cc/animation.cc delete mode 100644 cc/animation.h create mode 100644 cc/animation/animation.cc create mode 100644 cc/animation/animation.h create mode 100644 cc/animation/animation_curve.cc create mode 100644 cc/animation/animation_curve.h create mode 100644 cc/animation/animation_events.h create mode 100644 cc/animation/animation_id_provider.cc create mode 100644 cc/animation/animation_id_provider.h create mode 100644 cc/animation/animation_registrar.cc create mode 100644 cc/animation/animation_registrar.h create mode 100644 cc/animation/animation_unittest.cc create mode 100644 cc/animation/keyframed_animation_curve.cc create mode 100644 cc/animation/keyframed_animation_curve.h create mode 100644 cc/animation/keyframed_animation_curve_unittest.cc create mode 100644 cc/animation/layer_animation_controller.cc create mode 100644 cc/animation/layer_animation_controller.h create mode 100644 cc/animation/layer_animation_controller_unittest.cc create mode 100644 cc/animation/layer_animation_event_observer.h create mode 100644 cc/animation/layer_animation_value_observer.h create mode 100644 cc/animation/scrollbar_animation_controller.h create mode 100644 cc/animation/scrollbar_animation_controller_linear_fade.cc create mode 100644 cc/animation/scrollbar_animation_controller_linear_fade.h create mode 100644 cc/animation/scrollbar_animation_controller_linear_fade_unittest.cc delete mode 100644 cc/animation_curve.cc delete mode 100644 cc/animation_curve.h delete mode 100644 cc/animation_events.h delete mode 100644 cc/animation_id_provider.cc delete mode 100644 cc/animation_id_provider.h delete mode 100644 cc/animation_registrar.cc delete mode 100644 cc/animation_registrar.h delete mode 100644 cc/animation_unittest.cc delete mode 100644 cc/keyframed_animation_curve.cc delete mode 100644 cc/keyframed_animation_curve.h delete mode 100644 cc/keyframed_animation_curve_unittest.cc delete mode 100644 cc/layer_animation_controller.cc delete mode 100644 cc/layer_animation_controller.h delete mode 100644 cc/layer_animation_controller_unittest.cc delete mode 100644 cc/layer_animation_event_observer.h delete mode 100644 cc/layer_animation_value_observer.h delete mode 100644 cc/scrollbar_animation_controller.h delete mode 100644 cc/scrollbar_animation_controller_linear_fade.cc delete mode 100644 cc/scrollbar_animation_controller_linear_fade.h delete mode 100644 cc/scrollbar_animation_controller_linear_fade_unittest.cc (limited to 'cc') diff --git a/cc/animation.cc b/cc/animation.cc deleted file mode 100644 index 9ce93af..0000000 --- a/cc/animation.cc +++ /dev/null @@ -1,236 +0,0 @@ -// 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/animation.h" - -#include - -#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", - "Starting", - "Running", - "Paused", - "Finished", - "Aborted" -}; - -COMPILE_ASSERT(static_cast(cc::Animation::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(cc::Animation::TargetPropertyEnumSize) == - arraysize(s_targetPropertyNames), - TargetProperty_names_match_enum); - -} // namespace - -namespace cc { - -scoped_ptr Animation::Create( - scoped_ptr curve, - int animation_id, - int group_id, - TargetProperty target_property) { - return make_scoped_ptr(new Animation(curve.Pass(), - animation_id, - group_id, - target_property)); } - -Animation::Animation(scoped_ptr curve, - int animation_id, - int group_id, - TargetProperty target_property) - : curve_(curve.Pass()), - id_(animation_id), - group_(group_id), - target_property_(target_property), - run_state_(WaitingForTargetAvailability), - iterations_(1), - start_time_(0), - alternates_direction_(false), - time_offset_(0), - needs_synchronized_start_time_(false), - suspended_(false), - pause_time_(0), - total_paused_time_(0), - is_controlling_instance_(false), - is_impl_only_(false) {} - -Animation::~Animation() { - if (run_state_ == Running || run_state_ == Paused) - SetRunState(Aborted, 0); -} - -void Animation::SetRunState(RunState run_state, double monotonic_time) { - if (suspended_) - return; - - char nameBuffer[256]; - base::snprintf(nameBuffer, - sizeof(nameBuffer), - "%s-%d%s", - s_targetPropertyNames[target_property_], - group_, - is_controlling_instance_ ? "(impl)" : ""); - - bool is_waiting_to_start = run_state_ == WaitingForNextTick || - run_state_ == WaitingForTargetAvailability || - run_state_ == WaitingForStartTime || - run_state_ == Starting; - - if (is_waiting_to_start && run_state == Running) { - TRACE_EVENT_ASYNC_BEGIN1( - "cc", "Animation", this, "Name", TRACE_STR_COPY(nameBuffer)); - } - - bool was_finished = is_finished(); - - const char* old_run_state_name = s_runStateNames[run_state_]; - - if (run_state == Running && run_state_ == Paused) - total_paused_time_ += monotonic_time - pause_time_; - else if (run_state == Paused) - pause_time_ = monotonic_time; - run_state_ = run_state; - - const char* new_run_state_name = s_runStateNames[run_state]; - - if (!was_finished && is_finished()) - TRACE_EVENT_ASYNC_END0("cc", "Animation", this); - - char stateBuffer[256]; - base::snprintf(stateBuffer, - sizeof(stateBuffer), - "%s->%s", - old_run_state_name, - new_run_state_name); - - TRACE_EVENT_INSTANT2("cc", - "LayerAnimationController::setRunState", - "Name", - TRACE_STR_COPY(nameBuffer), - "State", - TRACE_STR_COPY(stateBuffer)); -} - -void Animation::Suspend(double monotonic_time) { - SetRunState(Paused, monotonic_time); - suspended_ = true; -} - -void Animation::Resume(double monotonic_time) { - suspended_ = false; - SetRunState(Running, monotonic_time); -} - -bool Animation::IsFinishedAt(double monotonic_time) const { - if (is_finished()) - return true; - - if (needs_synchronized_start_time_) - return false; - - return run_state_ == Running && - iterations_ >= 0 && - iterations_ * curve_->Duration() <= (monotonic_time - - start_time() - - total_paused_time_); -} - -double Animation::TrimTimeToCurrentIteration(double monotonic_time) const { - double trimmed = monotonic_time + time_offset_; - - // If we're paused, time is 'stuck' at the pause time. - if (run_state_ == Paused) - trimmed = pause_time_; - - // Returned time should always be relative to the start time and should - // subtract all time spent paused. - trimmed -= start_time_ + total_paused_time_; - - // Zero is always the start of the animation. - if (trimmed <= 0) - return 0; - - // Always return zero if we have no iterations. - if (!iterations_) - return 0; - - // Don't attempt to trim if we have no duration. - if (curve_->Duration() <= 0) - return 0; - - // If less than an iteration duration, just return trimmed. - if (trimmed < curve_->Duration()) - return trimmed; - - // If greater than or equal to the total duration, return iteration duration. - if (iterations_ >= 0 && trimmed >= curve_->Duration() * iterations_) { - if (alternates_direction_ && !(iterations_ % 2)) - return 0; - return curve_->Duration(); - } - - // We need to know the current iteration if we're alternating. - int iteration = static_cast(trimmed / curve_->Duration()); - - // Calculate x where trimmed = x + n * curve_->Duration() for some positive - // integer n. - trimmed = fmod(trimmed, curve_->Duration()); - - // If we're alternating and on an odd iteration, reverse the direction. - if (alternates_direction_ && iteration % 2 == 1) - return curve_->Duration() - trimmed; - - return trimmed; -} - -scoped_ptr Animation::Clone(InstanceType instance_type) const { - return CloneAndInitialize(instance_type, run_state_, start_time_); -} - -scoped_ptr Animation::CloneAndInitialize(InstanceType instance_type, - RunState initial_run_state, - double start_time) const { - scoped_ptr to_return( - new Animation(curve_->Clone(), id_, group_, target_property_)); - to_return->run_state_ = initial_run_state; - to_return->iterations_ = iterations_; - to_return->start_time_ = start_time; - to_return->pause_time_ = pause_time_; - to_return->total_paused_time_ = total_paused_time_; - to_return->time_offset_ = time_offset_; - to_return->alternates_direction_ = alternates_direction_; - to_return->is_controlling_instance_ = instance_type == ControllingInstance; - return to_return.Pass(); -} - -void Animation::PushPropertiesTo(Animation* other) const { - // Currently, we only push changes due to pausing and resuming animations on - // the main thread. - if (run_state_ == Animation::Paused || - other->run_state_ == Animation::Paused) { - other->run_state_ = run_state_; - other->pause_time_ = pause_time_; - other->total_paused_time_ = total_paused_time_; - } -} - -} // namespace cc diff --git a/cc/animation.h b/cc/animation.h deleted file mode 100644 index 73682f1..0000000 --- a/cc/animation.h +++ /dev/null @@ -1,190 +0,0 @@ -// 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. - -#ifndef CC_ANIMATION_H_ -#define CC_ANIMATION_H_ - -#include "base/basictypes.h" -#include "base/memory/scoped_ptr.h" -#include "cc/base/cc_export.h" - -namespace cc { - -class AnimationCurve; - -// An Animation, contains all the state required to play an AnimationCurve. -// Specifically, the affected property, the run state (paused, finished, etc.), -// loop count, last pause time, and the total time spent paused. -class CC_EXPORT Animation { - public: - // 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 Starting state, and then 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 = 0, - WaitingForTargetAvailability, - WaitingForStartTime, - WaitingForDeletion, - Starting, - Running, - Paused, - Finished, - Aborted, - // This sentinel must be last. - RunStateEnumSize - }; - - enum TargetProperty { - Transform = 0, - Opacity, - // This sentinel must be last. - TargetPropertyEnumSize - }; - - static scoped_ptr Create(scoped_ptr curve, - int animation_id, - int group_id, - TargetProperty target_property); - - virtual ~Animation(); - - int id() const { return id_; } - int group() const { return group_; } - TargetProperty target_property() const { return target_property_; } - - RunState run_state() const { return run_state_; } - void SetRunState(RunState run_state, double monotonic_time); - - // 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 iterations_; } - void set_iterations(int n) { iterations_ = n; } - - double start_time() const { return start_time_; } - void set_start_time(double monotonic_time) { start_time_ = monotonic_time; } - bool has_set_start_time() const { return !!start_time_; } - - double time_offset() const { return time_offset_; } - void set_time_offset(double monotonic_time) { time_offset_ = monotonic_time; } - - void Suspend(double monotonic_time); - void Resume(double monotonic_time); - - // If alternatesDirection is true, on odd numbered iterations we reverse the - // curve. - bool alternates_direction() const { return alternates_direction_; } - void set_alternates_direction(bool alternates) { - alternates_direction_ = alternates; - } - - bool IsFinishedAt(double monotonic_time) const; - bool is_finished() const { - return run_state_ == Finished || - run_state_ == Aborted || - run_state_ == WaitingForDeletion; - } - - AnimationCurve* curve() { return curve_.get(); } - const AnimationCurve* curve() const { return curve_.get(); } - - // If this is true, even if the animation is running, it will not be tickable - // until it is given a start time. This is true for animations running on the - // main thread. - bool needs_synchronized_start_time() const { - return needs_synchronized_start_time_; - } - void set_needs_synchronized_start_time(bool needs_synchronized_start_time) { - needs_synchronized_start_time_ = needs_synchronized_start_time; - } - - // 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 monotonic_time) const; - - enum InstanceType { - ControllingInstance = 0, - NonControllingInstance - }; - - scoped_ptr Clone(InstanceType instance_type) const; - scoped_ptr CloneAndInitialize(InstanceType instance_type, - RunState initial_run_state, - double start_time) const; - bool is_controlling_instance() const { return is_controlling_instance_; } - - void PushPropertiesTo(Animation* other) const; - - void set_is_impl_only(bool is_impl_only) { is_impl_only_ = is_impl_only; } - bool is_impl_only() const { return is_impl_only_; } - - private: - Animation(scoped_ptr curve, - int animation_id, - int group_id, - TargetProperty target_property); - - scoped_ptr curve_; - - // IDs are not necessarily unique. - int id_; - - // Animations that must be run together are called 'grouped' and have the same - // group id. 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. - int group_; - - TargetProperty target_property_; - RunState run_state_; - int iterations_; - double start_time_; - bool alternates_direction_; - - // The time offset effectively pushes the start of the animation back in time. - // This is used for resuming paused animations -- an animation is added with a - // non-zero time offset, causing the animation to skip ahead to the desired - // point in time. - double time_offset_; - - bool needs_synchronized_start_time_; - - // When an animation is suspended, it behaves as if it is paused and it also - // ignores all run state changes until it is resumed. This is used for testing - // purposes. - bool suspended_; - - // 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 pause_time_; - double total_paused_time_; - - // Animations lead dual lives. An active animation will be conceptually owned - // by two controllers, one on the impl thread and one on the main. In reality, - // there will be two separate Animation instances for the same animation. They - // will have the same group id and the same target property (these two values - // uniquely identify an animation). The instance on the impl thread is the - // instance that ultimately controls the values of the animating layer and so - // we will refer to it as the 'controlling instance'. - bool is_controlling_instance_; - - bool is_impl_only_; - - DISALLOW_COPY_AND_ASSIGN(Animation); -}; - -} // namespace cc - -#endif // CC_ANIMATION_H_ diff --git a/cc/animation/animation.cc b/cc/animation/animation.cc new file mode 100644 index 0000000..d81713b --- /dev/null +++ b/cc/animation/animation.cc @@ -0,0 +1,236 @@ +// 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/animation/animation.h" + +#include + +#include "base/debug/trace_event.h" +#include "base/string_util.h" +#include "cc/animation/animation_curve.h" + +namespace { + +// This should match the RunState enum. +static const char* const s_runStateNames[] = { + "WaitingForNextTick", + "WaitingForTargetAvailability", + "WaitingForStartTime", + "WaitingForDeletion", + "Starting", + "Running", + "Paused", + "Finished", + "Aborted" +}; + +COMPILE_ASSERT(static_cast(cc::Animation::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(cc::Animation::TargetPropertyEnumSize) == + arraysize(s_targetPropertyNames), + TargetProperty_names_match_enum); + +} // namespace + +namespace cc { + +scoped_ptr Animation::Create( + scoped_ptr curve, + int animation_id, + int group_id, + TargetProperty target_property) { + return make_scoped_ptr(new Animation(curve.Pass(), + animation_id, + group_id, + target_property)); } + +Animation::Animation(scoped_ptr curve, + int animation_id, + int group_id, + TargetProperty target_property) + : curve_(curve.Pass()), + id_(animation_id), + group_(group_id), + target_property_(target_property), + run_state_(WaitingForTargetAvailability), + iterations_(1), + start_time_(0), + alternates_direction_(false), + time_offset_(0), + needs_synchronized_start_time_(false), + suspended_(false), + pause_time_(0), + total_paused_time_(0), + is_controlling_instance_(false), + is_impl_only_(false) {} + +Animation::~Animation() { + if (run_state_ == Running || run_state_ == Paused) + SetRunState(Aborted, 0); +} + +void Animation::SetRunState(RunState run_state, double monotonic_time) { + if (suspended_) + return; + + char nameBuffer[256]; + base::snprintf(nameBuffer, + sizeof(nameBuffer), + "%s-%d%s", + s_targetPropertyNames[target_property_], + group_, + is_controlling_instance_ ? "(impl)" : ""); + + bool is_waiting_to_start = run_state_ == WaitingForNextTick || + run_state_ == WaitingForTargetAvailability || + run_state_ == WaitingForStartTime || + run_state_ == Starting; + + if (is_waiting_to_start && run_state == Running) { + TRACE_EVENT_ASYNC_BEGIN1( + "cc", "Animation", this, "Name", TRACE_STR_COPY(nameBuffer)); + } + + bool was_finished = is_finished(); + + const char* old_run_state_name = s_runStateNames[run_state_]; + + if (run_state == Running && run_state_ == Paused) + total_paused_time_ += monotonic_time - pause_time_; + else if (run_state == Paused) + pause_time_ = monotonic_time; + run_state_ = run_state; + + const char* new_run_state_name = s_runStateNames[run_state]; + + if (!was_finished && is_finished()) + TRACE_EVENT_ASYNC_END0("cc", "Animation", this); + + char stateBuffer[256]; + base::snprintf(stateBuffer, + sizeof(stateBuffer), + "%s->%s", + old_run_state_name, + new_run_state_name); + + TRACE_EVENT_INSTANT2("cc", + "LayerAnimationController::setRunState", + "Name", + TRACE_STR_COPY(nameBuffer), + "State", + TRACE_STR_COPY(stateBuffer)); +} + +void Animation::Suspend(double monotonic_time) { + SetRunState(Paused, monotonic_time); + suspended_ = true; +} + +void Animation::Resume(double monotonic_time) { + suspended_ = false; + SetRunState(Running, monotonic_time); +} + +bool Animation::IsFinishedAt(double monotonic_time) const { + if (is_finished()) + return true; + + if (needs_synchronized_start_time_) + return false; + + return run_state_ == Running && + iterations_ >= 0 && + iterations_ * curve_->Duration() <= (monotonic_time - + start_time() - + total_paused_time_); +} + +double Animation::TrimTimeToCurrentIteration(double monotonic_time) const { + double trimmed = monotonic_time + time_offset_; + + // If we're paused, time is 'stuck' at the pause time. + if (run_state_ == Paused) + trimmed = pause_time_; + + // Returned time should always be relative to the start time and should + // subtract all time spent paused. + trimmed -= start_time_ + total_paused_time_; + + // Zero is always the start of the animation. + if (trimmed <= 0) + return 0; + + // Always return zero if we have no iterations. + if (!iterations_) + return 0; + + // Don't attempt to trim if we have no duration. + if (curve_->Duration() <= 0) + return 0; + + // If less than an iteration duration, just return trimmed. + if (trimmed < curve_->Duration()) + return trimmed; + + // If greater than or equal to the total duration, return iteration duration. + if (iterations_ >= 0 && trimmed >= curve_->Duration() * iterations_) { + if (alternates_direction_ && !(iterations_ % 2)) + return 0; + return curve_->Duration(); + } + + // We need to know the current iteration if we're alternating. + int iteration = static_cast(trimmed / curve_->Duration()); + + // Calculate x where trimmed = x + n * curve_->Duration() for some positive + // integer n. + trimmed = fmod(trimmed, curve_->Duration()); + + // If we're alternating and on an odd iteration, reverse the direction. + if (alternates_direction_ && iteration % 2 == 1) + return curve_->Duration() - trimmed; + + return trimmed; +} + +scoped_ptr Animation::Clone(InstanceType instance_type) const { + return CloneAndInitialize(instance_type, run_state_, start_time_); +} + +scoped_ptr Animation::CloneAndInitialize(InstanceType instance_type, + RunState initial_run_state, + double start_time) const { + scoped_ptr to_return( + new Animation(curve_->Clone(), id_, group_, target_property_)); + to_return->run_state_ = initial_run_state; + to_return->iterations_ = iterations_; + to_return->start_time_ = start_time; + to_return->pause_time_ = pause_time_; + to_return->total_paused_time_ = total_paused_time_; + to_return->time_offset_ = time_offset_; + to_return->alternates_direction_ = alternates_direction_; + to_return->is_controlling_instance_ = instance_type == ControllingInstance; + return to_return.Pass(); +} + +void Animation::PushPropertiesTo(Animation* other) const { + // Currently, we only push changes due to pausing and resuming animations on + // the main thread. + if (run_state_ == Animation::Paused || + other->run_state_ == Animation::Paused) { + other->run_state_ = run_state_; + other->pause_time_ = pause_time_; + other->total_paused_time_ = total_paused_time_; + } +} + +} // namespace cc diff --git a/cc/animation/animation.h b/cc/animation/animation.h new file mode 100644 index 0000000..f1692ad --- /dev/null +++ b/cc/animation/animation.h @@ -0,0 +1,190 @@ +// 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. + +#ifndef CC_ANIMATION_ANIMATION_H_ +#define CC_ANIMATION_ANIMATION_H_ + +#include "base/basictypes.h" +#include "base/memory/scoped_ptr.h" +#include "cc/base/cc_export.h" + +namespace cc { + +class AnimationCurve; + +// An Animation, contains all the state required to play an AnimationCurve. +// Specifically, the affected property, the run state (paused, finished, etc.), +// loop count, last pause time, and the total time spent paused. +class CC_EXPORT Animation { + public: + // 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 Starting state, and then 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 = 0, + WaitingForTargetAvailability, + WaitingForStartTime, + WaitingForDeletion, + Starting, + Running, + Paused, + Finished, + Aborted, + // This sentinel must be last. + RunStateEnumSize + }; + + enum TargetProperty { + Transform = 0, + Opacity, + // This sentinel must be last. + TargetPropertyEnumSize + }; + + static scoped_ptr Create(scoped_ptr curve, + int animation_id, + int group_id, + TargetProperty target_property); + + virtual ~Animation(); + + int id() const { return id_; } + int group() const { return group_; } + TargetProperty target_property() const { return target_property_; } + + RunState run_state() const { return run_state_; } + void SetRunState(RunState run_state, double monotonic_time); + + // 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 iterations_; } + void set_iterations(int n) { iterations_ = n; } + + double start_time() const { return start_time_; } + void set_start_time(double monotonic_time) { start_time_ = monotonic_time; } + bool has_set_start_time() const { return !!start_time_; } + + double time_offset() const { return time_offset_; } + void set_time_offset(double monotonic_time) { time_offset_ = monotonic_time; } + + void Suspend(double monotonic_time); + void Resume(double monotonic_time); + + // If alternatesDirection is true, on odd numbered iterations we reverse the + // curve. + bool alternates_direction() const { return alternates_direction_; } + void set_alternates_direction(bool alternates) { + alternates_direction_ = alternates; + } + + bool IsFinishedAt(double monotonic_time) const; + bool is_finished() const { + return run_state_ == Finished || + run_state_ == Aborted || + run_state_ == WaitingForDeletion; + } + + AnimationCurve* curve() { return curve_.get(); } + const AnimationCurve* curve() const { return curve_.get(); } + + // If this is true, even if the animation is running, it will not be tickable + // until it is given a start time. This is true for animations running on the + // main thread. + bool needs_synchronized_start_time() const { + return needs_synchronized_start_time_; + } + void set_needs_synchronized_start_time(bool needs_synchronized_start_time) { + needs_synchronized_start_time_ = needs_synchronized_start_time; + } + + // 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 monotonic_time) const; + + enum InstanceType { + ControllingInstance = 0, + NonControllingInstance + }; + + scoped_ptr Clone(InstanceType instance_type) const; + scoped_ptr CloneAndInitialize(InstanceType instance_type, + RunState initial_run_state, + double start_time) const; + bool is_controlling_instance() const { return is_controlling_instance_; } + + void PushPropertiesTo(Animation* other) const; + + void set_is_impl_only(bool is_impl_only) { is_impl_only_ = is_impl_only; } + bool is_impl_only() const { return is_impl_only_; } + + private: + Animation(scoped_ptr curve, + int animation_id, + int group_id, + TargetProperty target_property); + + scoped_ptr curve_; + + // IDs are not necessarily unique. + int id_; + + // Animations that must be run together are called 'grouped' and have the same + // group id. 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. + int group_; + + TargetProperty target_property_; + RunState run_state_; + int iterations_; + double start_time_; + bool alternates_direction_; + + // The time offset effectively pushes the start of the animation back in time. + // This is used for resuming paused animations -- an animation is added with a + // non-zero time offset, causing the animation to skip ahead to the desired + // point in time. + double time_offset_; + + bool needs_synchronized_start_time_; + + // When an animation is suspended, it behaves as if it is paused and it also + // ignores all run state changes until it is resumed. This is used for testing + // purposes. + bool suspended_; + + // 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 pause_time_; + double total_paused_time_; + + // Animations lead dual lives. An active animation will be conceptually owned + // by two controllers, one on the impl thread and one on the main. In reality, + // there will be two separate Animation instances for the same animation. They + // will have the same group id and the same target property (these two values + // uniquely identify an animation). The instance on the impl thread is the + // instance that ultimately controls the values of the animating layer and so + // we will refer to it as the 'controlling instance'. + bool is_controlling_instance_; + + bool is_impl_only_; + + DISALLOW_COPY_AND_ASSIGN(Animation); +}; + +} // namespace cc + +#endif // CC_ANIMATION_ANIMATION_H_ diff --git a/cc/animation/animation_curve.cc b/cc/animation/animation_curve.cc new file mode 100644 index 0000000..05cda9b --- /dev/null +++ b/cc/animation/animation_curve.cc @@ -0,0 +1,30 @@ +// 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/animation/animation_curve.h" + +#include "base/logging.h" + +namespace cc { + +const FloatAnimationCurve* AnimationCurve::ToFloatAnimationCurve() const { + DCHECK(Type() == AnimationCurve::Float); + return static_cast(this); +} + +AnimationCurve::CurveType FloatAnimationCurve::Type() const { + return Float; +} + +const TransformAnimationCurve* AnimationCurve::ToTransformAnimationCurve() + const { + DCHECK(Type() == AnimationCurve::Transform); + return static_cast(this); +} + +AnimationCurve::CurveType TransformAnimationCurve::Type() const { + return Transform; +} + +} // namespace cc diff --git a/cc/animation/animation_curve.h b/cc/animation/animation_curve.h new file mode 100644 index 0000000..13f95b4 --- /dev/null +++ b/cc/animation/animation_curve.h @@ -0,0 +1,56 @@ +// 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. + +#ifndef CC_ANIMATION_ANIMATION_CURVE_H_ +#define CC_ANIMATION_ANIMATION_CURVE_H_ + +#include "base/memory/scoped_ptr.h" +#include "cc/base/cc_export.h" +#include "ui/gfx/transform.h" + +namespace cc { + +class FloatAnimationCurve; +class TransformAnimationCurve; +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 CC_EXPORT AnimationCurve { + public: + enum CurveType { Float, Transform }; + + virtual ~AnimationCurve() {} + + virtual double Duration() const = 0; + virtual CurveType Type() const = 0; + virtual scoped_ptr Clone() const = 0; + + const FloatAnimationCurve* ToFloatAnimationCurve() const; + const TransformAnimationCurve* ToTransformAnimationCurve() const; +}; + +class CC_EXPORT FloatAnimationCurve : public AnimationCurve { + public: + virtual ~FloatAnimationCurve() {} + + virtual float GetValue(double t) const = 0; + + // Partial Animation implementation. + virtual CurveType Type() const OVERRIDE; +}; + +class CC_EXPORT TransformAnimationCurve : public AnimationCurve { + public: + virtual ~TransformAnimationCurve() {} + + virtual gfx::Transform GetValue(double t) const = 0; + + // Partial Animation implementation. + virtual CurveType Type() const OVERRIDE; +}; + +} // namespace cc + +#endif // CC_ANIMATION_ANIMATION_CURVE_H_ diff --git a/cc/animation/animation_events.h b/cc/animation/animation_events.h new file mode 100644 index 0000000..b279b4b --- /dev/null +++ b/cc/animation/animation_events.h @@ -0,0 +1,43 @@ +// 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. + +#ifndef CC_ANIMATION_ANIMATION_EVENTS_H_ +#define CC_ANIMATION_ANIMATION_EVENTS_H_ + +#include + +#include "cc/animation/animation.h" +#include "ui/gfx/transform.h" + +namespace cc { + +struct AnimationEvent { + enum Type { Started, Finished, PropertyUpdate }; + + AnimationEvent(Type type, + int layer_id, + int group_id, + Animation::TargetProperty target_property, + double monotonic_time) + : type(type), + layer_id(layer_id), + group_id(group_id), + target_property(target_property), + monotonic_time(monotonic_time), + opacity(0.f) {} + + Type type; + int layer_id; + int group_id; + Animation::TargetProperty target_property; + double monotonic_time; + float opacity; + gfx::Transform transform; +}; + +typedef std::vector AnimationEventsVector; + +} // namespace cc + +#endif // CC_ANIMATION_ANIMATION_EVENTS_H_ diff --git a/cc/animation/animation_id_provider.cc b/cc/animation/animation_id_provider.cc new file mode 100644 index 0000000..5c7afb6 --- /dev/null +++ b/cc/animation/animation_id_provider.cc @@ -0,0 +1,19 @@ +// Copyright (c) 2013 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/animation/animation_id_provider.h" + +namespace cc { + +int AnimationIdProvider::NextAnimationId() { + static int next_animation_id = 1; + return next_animation_id++; +} + +int AnimationIdProvider::NextGroupId() { + static int next_group_id = 1; + return next_group_id++; +} + +} // namespace cc diff --git a/cc/animation/animation_id_provider.h b/cc/animation/animation_id_provider.h new file mode 100644 index 0000000..da08c92 --- /dev/null +++ b/cc/animation/animation_id_provider.h @@ -0,0 +1,21 @@ +// Copyright (c) 2013 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. + +#ifndef CC_ANIMATION_ANIMATION_ID_PROVIDER_H_ +#define CC_ANIMATION_ANIMATION_ID_PROVIDER_H_ + +#include "cc/base/cc_export.h" + +namespace cc { + +class CC_EXPORT AnimationIdProvider { + public: + // These functions each return monotonically increasing values. + static int NextAnimationId(); + static int NextGroupId(); +}; + +} + +#endif // CC_ANIMATION_ANIMATION_ID_PROVIDER_H_ diff --git a/cc/animation/animation_registrar.cc b/cc/animation/animation_registrar.cc new file mode 100644 index 0000000..948a582 --- /dev/null +++ b/cc/animation/animation_registrar.cc @@ -0,0 +1,51 @@ +// 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/animation/animation_registrar.h" + +#include "cc/animation/layer_animation_controller.h" + +namespace cc { + +AnimationRegistrar::AnimationRegistrar() { } +AnimationRegistrar::~AnimationRegistrar() +{ + AnimationControllerMap copy = all_animation_controllers_; + for (AnimationControllerMap::iterator iter = copy.begin(); iter != copy.end(); ++iter) + (*iter).second->SetAnimationRegistrar(NULL); +} + +scoped_refptr +AnimationRegistrar::GetAnimationControllerForId(int id) +{ + scoped_refptr toReturn; + if (!ContainsKey(all_animation_controllers_, id)) { + toReturn = LayerAnimationController::Create(id); + toReturn->SetAnimationRegistrar(this); + all_animation_controllers_[id] = toReturn.get(); + } else + toReturn = all_animation_controllers_[id]; + return toReturn; +} + +void AnimationRegistrar::DidActivateAnimationController(LayerAnimationController* controller) { + active_animation_controllers_[controller->id()] = controller; +} + +void AnimationRegistrar::DidDeactivateAnimationController(LayerAnimationController* controller) { + if (ContainsKey(active_animation_controllers_, controller->id())) + active_animation_controllers_.erase(controller->id()); +} + +void AnimationRegistrar::RegisterAnimationController(LayerAnimationController* controller) { + all_animation_controllers_[controller->id()] = controller; +} + +void AnimationRegistrar::UnregisterAnimationController(LayerAnimationController* controller) { + if (ContainsKey(all_animation_controllers_, controller->id())) + all_animation_controllers_.erase(controller->id()); + DidDeactivateAnimationController(controller); +} + +} // namespace cc diff --git a/cc/animation/animation_registrar.h b/cc/animation/animation_registrar.h new file mode 100644 index 0000000..5d1eb44 --- /dev/null +++ b/cc/animation/animation_registrar.h @@ -0,0 +1,65 @@ +// 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. + +#ifndef CC_ANIMATION_ANIMATION_REGISTRAR_H_ +#define CC_ANIMATION_ANIMATION_REGISTRAR_H_ + +#include "base/hash_tables.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "cc/base/cc_export.h" + +namespace cc { + +class LayerAnimationController; + +class CC_EXPORT AnimationRegistrar { + public: + typedef base::hash_map AnimationControllerMap; + + static scoped_ptr create() { + return make_scoped_ptr(new AnimationRegistrar()); + } + + virtual ~AnimationRegistrar(); + + // If an animation has been registered for the given id, return it. Otherwise + // creates a new one and returns a scoped_refptr to it. + scoped_refptr GetAnimationControllerForId(int id); + + // Registers the given animation controller as active. An active animation + // controller is one that has a running animation that needs to be ticked. + void DidActivateAnimationController(LayerAnimationController*); + + // Unregisters the given animation controller. When this happens, the + // animation controller will no longer be ticked (since it's not active). It + // is not an error to call this function with a deactivated controller. + void DidDeactivateAnimationController(LayerAnimationController*); + + // Registers the given controller as alive. + void RegisterAnimationController(LayerAnimationController*); + + // Unregisters the given controller as alive. + void UnregisterAnimationController(LayerAnimationController*); + + const AnimationControllerMap& active_animation_controllers() const { + return active_animation_controllers_; + } + + const AnimationControllerMap& all_animation_controllers() const { + return all_animation_controllers_; + } + + private: + AnimationRegistrar(); + + AnimationControllerMap active_animation_controllers_; + AnimationControllerMap all_animation_controllers_; + + DISALLOW_COPY_AND_ASSIGN(AnimationRegistrar); +}; + +} // namespace cc + +#endif // CC_ANIMATION_ANIMATION_REGISTRAR_H_ diff --git a/cc/animation/animation_unittest.cc b/cc/animation/animation_unittest.cc new file mode 100644 index 0000000..337d3ee --- /dev/null +++ b/cc/animation/animation_unittest.cc @@ -0,0 +1,205 @@ +// 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/animation/animation.h" + +#include "cc/test/animation_test_common.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace cc { +namespace { + +scoped_ptr CreateAnimation(int iterations, double duration) { + scoped_ptr to_return(Animation::Create( + make_scoped_ptr( + new FakeFloatAnimationCurve(duration)).PassAs(), + 0, + 1, + Animation::Opacity)); + to_return->set_iterations(iterations); + return to_return.Pass(); +} + +scoped_ptr CreateAnimation(int iterations) { + return CreateAnimation(iterations, 1); +} + +TEST(AnimationTest, TrimTimeZeroIterations) { + scoped_ptr anim(CreateAnimation(0)); + EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(-1.0)); + EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(0.0)); + EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(1.0)); +} + +TEST(AnimationTest, TrimTimeOneIteration) { + scoped_ptr anim(CreateAnimation(1)); + EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(-1.0)); + EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(0.0)); + EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(1.0)); + EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(2.0)); +} + +TEST(AnimationTest, TrimTimeInfiniteIterations) { + scoped_ptr anim(CreateAnimation(-1)); + EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(0.0)); + EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(0.5)); + EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(1.0)); + EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(1.5)); +} + +TEST(AnimationTest, TrimTimeAlternating) { + scoped_ptr anim(CreateAnimation(-1)); + anim->set_alternates_direction(true); + EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(0.0)); + EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(0.5)); + EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(1.0)); + EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(1.25)); +} + +TEST(AnimationTest, TrimTimeStartTime) { + scoped_ptr anim(CreateAnimation(1)); + anim->set_start_time(4); + EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(0.0)); + EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(4.0)); + EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(4.5)); + EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(5.0)); + EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(6.0)); +} + +TEST(AnimationTest, TrimTimeTimeOffset) { + scoped_ptr anim(CreateAnimation(1)); + anim->set_time_offset(4); + anim->set_start_time(4); + EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(0.0)); + EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(0.5)); + EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(1.0)); + EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(1.0)); +} + +TEST(AnimationTest, TrimTimePauseResume) { + scoped_ptr anim(CreateAnimation(1)); + anim->SetRunState(Animation::Running, 0.0); + EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(0.0)); + EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(0.5)); + anim->SetRunState(Animation::Paused, 0.5); + EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(1024.0)); + anim->SetRunState(Animation::Running, 1024.0); + EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(1024.0)); + EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(1024.5)); +} + +TEST(AnimationTest, TrimTimeSuspendResume) { + scoped_ptr anim(CreateAnimation(1)); + anim->SetRunState(Animation::Running, 0.0); + EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(0.0)); + EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(0.5)); + anim->Suspend(0.5); + EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(1024.0)); + anim->Resume(1024); + EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(1024.0)); + EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(1024.5)); +} + +TEST(AnimationTest, TrimTimeZeroDuration) { + scoped_ptr anim(CreateAnimation(0, 0)); + anim->SetRunState(Animation::Running, 0.0); + EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(-1.0)); + EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(0.0)); + EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(1.0)); +} + +TEST(AnimationTest, IsFinishedAtZeroIterations) { + scoped_ptr anim(CreateAnimation(0)); + anim->SetRunState(Animation::Running, 0.0); + EXPECT_FALSE(anim->IsFinishedAt(-1.0)); + EXPECT_TRUE(anim->IsFinishedAt(0.0)); + EXPECT_TRUE(anim->IsFinishedAt(1.0)); +} + +TEST(AnimationTest, IsFinishedAtOneIteration) { + scoped_ptr anim(CreateAnimation(1)); + anim->SetRunState(Animation::Running, 0.0); + EXPECT_FALSE(anim->IsFinishedAt(-1.0)); + EXPECT_FALSE(anim->IsFinishedAt(0.0)); + EXPECT_TRUE(anim->IsFinishedAt(1.0)); + EXPECT_TRUE(anim->IsFinishedAt(2.0)); +} + +TEST(AnimationTest, IsFinishedAtInfiniteIterations) { + scoped_ptr anim(CreateAnimation(-1)); + anim->SetRunState(Animation::Running, 0.0); + EXPECT_FALSE(anim->IsFinishedAt(0.0)); + EXPECT_FALSE(anim->IsFinishedAt(0.5)); + EXPECT_FALSE(anim->IsFinishedAt(1.0)); + EXPECT_FALSE(anim->IsFinishedAt(1.5)); +} + +TEST(AnimationTest, IsFinishedAtNotRunning) { + scoped_ptr anim(CreateAnimation(0)); + anim->SetRunState(Animation::Running, 0.0); + EXPECT_TRUE(anim->IsFinishedAt(0.0)); + anim->SetRunState(Animation::Paused, 0.0); + EXPECT_FALSE(anim->IsFinishedAt(0.0)); + anim->SetRunState(Animation::WaitingForNextTick, 0.0); + EXPECT_FALSE(anim->IsFinishedAt(0.0)); + anim->SetRunState(Animation::WaitingForTargetAvailability, 0.0); + EXPECT_FALSE(anim->IsFinishedAt(0.0)); + anim->SetRunState(Animation::WaitingForStartTime, 0.0); + EXPECT_FALSE(anim->IsFinishedAt(0.0)); + anim->SetRunState(Animation::Finished, 0.0); + EXPECT_TRUE(anim->IsFinishedAt(0.0)); + anim->SetRunState(Animation::Aborted, 0.0); + EXPECT_TRUE(anim->IsFinishedAt(0.0)); +} + +TEST(AnimationTest, IsFinished) { + scoped_ptr anim(CreateAnimation(1)); + anim->SetRunState(Animation::Running, 0.0); + EXPECT_FALSE(anim->is_finished()); + anim->SetRunState(Animation::Paused, 0.0); + EXPECT_FALSE(anim->is_finished()); + anim->SetRunState(Animation::WaitingForNextTick, 0.0); + EXPECT_FALSE(anim->is_finished()); + anim->SetRunState(Animation::WaitingForTargetAvailability, 0.0); + EXPECT_FALSE(anim->is_finished()); + anim->SetRunState(Animation::WaitingForStartTime, 0.0); + EXPECT_FALSE(anim->is_finished()); + anim->SetRunState(Animation::Finished, 0.0); + EXPECT_TRUE(anim->is_finished()); + anim->SetRunState(Animation::Aborted, 0.0); + EXPECT_TRUE(anim->is_finished()); +} + +TEST(AnimationTest, IsFinishedNeedsSynchronizedStartTime) { + scoped_ptr anim(CreateAnimation(1)); + anim->SetRunState(Animation::Running, 2.0); + EXPECT_FALSE(anim->is_finished()); + anim->SetRunState(Animation::Paused, 2.0); + EXPECT_FALSE(anim->is_finished()); + anim->SetRunState(Animation::WaitingForNextTick, 2.0); + EXPECT_FALSE(anim->is_finished()); + anim->SetRunState(Animation::WaitingForTargetAvailability, 2.0); + EXPECT_FALSE(anim->is_finished()); + anim->SetRunState(Animation::WaitingForStartTime, 2.0); + EXPECT_FALSE(anim->is_finished()); + anim->SetRunState(Animation::Finished, 0.0); + EXPECT_TRUE(anim->is_finished()); + anim->SetRunState(Animation::Aborted, 0.0); + EXPECT_TRUE(anim->is_finished()); +} + +TEST(AnimationTest, RunStateChangesIgnoredWhileSuspended) { + scoped_ptr anim(CreateAnimation(1)); + anim->Suspend(0); + EXPECT_EQ(Animation::Paused, anim->run_state()); + anim->SetRunState(Animation::Running, 0.0); + EXPECT_EQ(Animation::Paused, anim->run_state()); + anim->Resume(0); + anim->SetRunState(Animation::Running, 0.0); + EXPECT_EQ(Animation::Running, anim->run_state()); +} + +} // namespace +} // namespace cc diff --git a/cc/animation/keyframed_animation_curve.cc b/cc/animation/keyframed_animation_curve.cc new file mode 100644 index 0000000..577737d --- /dev/null +++ b/cc/animation/keyframed_animation_curve.cc @@ -0,0 +1,200 @@ +// 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/animation/keyframed_animation_curve.h" + +namespace cc { + +namespace { + +template +void InsertKeyframe(scoped_ptr keyframe, + ScopedPtrVector& keyframes) { + // Usually, the keyframes will be added in order, so this loop would be + // unnecessary and we should skip it if possible. + if (!keyframes.empty() && keyframe->Time() < keyframes.back()->Time()) { + for (size_t i = 0; i < keyframes.size(); ++i) { + if (keyframe->Time() < keyframes[i]->Time()) { + keyframes.insert(keyframes.begin() + i, keyframe.Pass()); + return; + } + } + } + + keyframes.push_back(keyframe.Pass()); +} + +scoped_ptr CloneTimingFunction( + const TimingFunction* timing_function) { + DCHECK(timing_function); + scoped_ptr curve(timing_function->Clone()); + return scoped_ptr( + static_cast(curve.release())); +} + +} // namespace + +Keyframe::Keyframe(double time, scoped_ptr timing_function) + : time_(time), + timing_function_(timing_function.Pass()) {} + +Keyframe::~Keyframe() {} + +double Keyframe::Time() const { + return time_; +} + +scoped_ptr FloatKeyframe::Create( + double time, + float value, + scoped_ptr timing_function) { + return make_scoped_ptr( + new FloatKeyframe(time, value, timing_function.Pass())); +} + +FloatKeyframe::FloatKeyframe(double time, + float value, + scoped_ptr timing_function) + : Keyframe(time, timing_function.Pass()), + value_(value) {} + +FloatKeyframe::~FloatKeyframe() {} + +float FloatKeyframe::Value() const { + return value_; +} + +scoped_ptr FloatKeyframe::Clone() const { + scoped_ptr func; + if (timing_function()) + func = CloneTimingFunction(timing_function()); + return FloatKeyframe::Create(Time(), Value(), func.Pass()); +} + +scoped_ptr TransformKeyframe::Create( + double time, + const TransformOperations& value, + scoped_ptr timing_function) { + return make_scoped_ptr( + new TransformKeyframe(time, value, timing_function.Pass())); +} + +TransformKeyframe::TransformKeyframe(double time, + const TransformOperations& value, + scoped_ptr timing_function) + : Keyframe(time, timing_function.Pass()), + value_(value) {} + +TransformKeyframe::~TransformKeyframe() {} + +const TransformOperations& TransformKeyframe::Value() const { + return value_; +} + +scoped_ptr TransformKeyframe::Clone() const { + scoped_ptr func; + if (timing_function()) + func = CloneTimingFunction(timing_function()); + return TransformKeyframe::Create(Time(), Value(), func.Pass()); +} + +scoped_ptr KeyframedFloatAnimationCurve:: + Create() { + return make_scoped_ptr(new KeyframedFloatAnimationCurve); +} + +KeyframedFloatAnimationCurve::KeyframedFloatAnimationCurve() {} + +KeyframedFloatAnimationCurve::~KeyframedFloatAnimationCurve() {} + +void KeyframedFloatAnimationCurve::AddKeyframe( + scoped_ptr keyframe) { + InsertKeyframe(keyframe.Pass(), keyframes_); +} + +double KeyframedFloatAnimationCurve::Duration() const { + return keyframes_.back()->Time() - keyframes_.front()->Time(); +} + +scoped_ptr KeyframedFloatAnimationCurve::Clone() const { + scoped_ptr to_return( + KeyframedFloatAnimationCurve::Create()); + for (size_t i = 0; i < keyframes_.size(); ++i) + to_return->AddKeyframe(keyframes_[i]->Clone()); + return to_return.PassAs(); +} + +float KeyframedFloatAnimationCurve::GetValue(double t) const { + if (t <= keyframes_.front()->Time()) + return keyframes_.front()->Value(); + + if (t >= keyframes_.back()->Time()) + return keyframes_.back()->Value(); + + size_t i = 0; + for (; i < keyframes_.size() - 1; ++i) { + if (t < keyframes_[i+1]->Time()) + break; + } + + float progress = + static_cast((t - keyframes_[i]->Time()) / + (keyframes_[i+1]->Time() - keyframes_[i]->Time())); + + if (keyframes_[i]->timing_function()) + progress = keyframes_[i]->timing_function()->GetValue(progress); + + return keyframes_[i]->Value() + + (keyframes_[i+1]->Value() - keyframes_[i]->Value()) * progress; +} + +scoped_ptr KeyframedTransformAnimationCurve:: + Create() { + return make_scoped_ptr(new KeyframedTransformAnimationCurve); +} + +KeyframedTransformAnimationCurve::KeyframedTransformAnimationCurve() {} + +KeyframedTransformAnimationCurve::~KeyframedTransformAnimationCurve() {} + +void KeyframedTransformAnimationCurve::AddKeyframe( + scoped_ptr keyframe) { + InsertKeyframe(keyframe.Pass(), keyframes_); +} + +double KeyframedTransformAnimationCurve::Duration() const { + return keyframes_.back()->Time() - keyframes_.front()->Time(); +} + +scoped_ptr KeyframedTransformAnimationCurve::Clone() const { + scoped_ptr to_return( + KeyframedTransformAnimationCurve::Create()); + for (size_t i = 0; i < keyframes_.size(); ++i) + to_return->AddKeyframe(keyframes_[i]->Clone()); + return to_return.PassAs(); +} + +gfx::Transform KeyframedTransformAnimationCurve::GetValue(double t) const { + if (t <= keyframes_.front()->Time()) + return keyframes_.front()->Value().Apply(); + + if (t >= keyframes_.back()->Time()) + return keyframes_.back()->Value().Apply(); + + size_t i = 0; + for (; i < keyframes_.size() - 1; ++i) { + if (t < keyframes_[i+1]->Time()) + break; + } + + double progress = (t - keyframes_[i]->Time()) / + (keyframes_[i+1]->Time() - keyframes_[i]->Time()); + + if (keyframes_[i]->timing_function()) + progress = keyframes_[i]->timing_function()->GetValue(progress); + + return keyframes_[i+1]->Value().Blend(keyframes_[i]->Value(), progress); +} + +} // namespace cc diff --git a/cc/animation/keyframed_animation_curve.h b/cc/animation/keyframed_animation_curve.h new file mode 100644 index 0000000..aa53b67 --- /dev/null +++ b/cc/animation/keyframed_animation_curve.h @@ -0,0 +1,129 @@ +// 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. + +#ifndef CC_ANIMATION_KEYFRAMED_ANIMATION_CURVE_H_ +#define CC_ANIMATION_KEYFRAMED_ANIMATION_CURVE_H_ + +#include "cc/animation/animation_curve.h" +#include "cc/base/cc_export.h" +#include "cc/base/scoped_ptr_vector.h" +#include "cc/timing_function.h" +#include "cc/transform_operations.h" + +namespace cc { + +class CC_EXPORT Keyframe { + public: + double Time() const; + const TimingFunction* timing_function() const { + return timing_function_.get(); + } + + protected: + Keyframe(double time, scoped_ptr timing_function); + virtual ~Keyframe(); + + private: + double time_; + scoped_ptr timing_function_; + + DISALLOW_COPY_AND_ASSIGN(Keyframe); +}; + +class CC_EXPORT FloatKeyframe : public Keyframe { + public: + static scoped_ptr Create( + double time, + float value, + scoped_ptr timing_function); + virtual ~FloatKeyframe(); + + float Value() const; + + scoped_ptr Clone() const; + + private: + FloatKeyframe(double time, + float value, + scoped_ptr timing_function); + + float value_; +}; + +class CC_EXPORT TransformKeyframe : public Keyframe { + public: + static scoped_ptr Create( + double time, + const TransformOperations& value, + scoped_ptr timing_function); + virtual ~TransformKeyframe(); + + const TransformOperations& Value() const; + + scoped_ptr Clone() const; + + private: + TransformKeyframe( + double time, + const TransformOperations& value, + scoped_ptr timing_function); + + TransformOperations value_; +}; + +class CC_EXPORT KeyframedFloatAnimationCurve : public FloatAnimationCurve { + public: + // It is required that the keyframes be sorted by time. + static scoped_ptr Create(); + + virtual ~KeyframedFloatAnimationCurve(); + + void AddKeyframe(scoped_ptr keyframe); + + // AnimationCurve implementation + virtual double Duration() const OVERRIDE; + virtual scoped_ptr Clone() const OVERRIDE; + + // FloatAnimationCurve implementation + virtual float GetValue(double t) const OVERRIDE; + + private: + KeyframedFloatAnimationCurve(); + + // Always sorted in order of increasing time. No two keyframes have the + // same time. + ScopedPtrVector keyframes_; + + DISALLOW_COPY_AND_ASSIGN(KeyframedFloatAnimationCurve); +}; + +class CC_EXPORT KeyframedTransformAnimationCurve : public TransformAnimationCurve { + public: + // It is required that the keyframes be sorted by time. + static scoped_ptr Create(); + + virtual ~KeyframedTransformAnimationCurve(); + + void AddKeyframe(scoped_ptr keyframe); + + // AnimationCurve implementation + virtual double Duration() const OVERRIDE; + virtual scoped_ptr Clone() const OVERRIDE; + + // TransformAnimationCurve implementation + virtual gfx::Transform GetValue(double t) const OVERRIDE; + + private: + KeyframedTransformAnimationCurve(); + + // Always sorted in order of increasing time. No two keyframes have the + // same time. + ScopedPtrVector keyframes_; + + DISALLOW_COPY_AND_ASSIGN(KeyframedTransformAnimationCurve); +}; + +} // namespace cc + +#endif // CC_ANIMATION_KEYFRAMED_ANIMATION_CURVE_H_ diff --git a/cc/animation/keyframed_animation_curve_unittest.cc b/cc/animation/keyframed_animation_curve_unittest.cc new file mode 100644 index 0000000..446801d --- /dev/null +++ b/cc/animation/keyframed_animation_curve_unittest.cc @@ -0,0 +1,243 @@ +// 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/animation/keyframed_animation_curve.h" + +#include "cc/transform_operations.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace cc { +namespace { + +void expectTranslateX(double translateX, const gfx::Transform& transform) +{ + EXPECT_FLOAT_EQ(translateX, transform.matrix().getDouble(0, 3)); +} + +// Tests that a float animation with one keyframe works as expected. +TEST(KeyframedAnimationCurveTest, OneFloatKeyframe) +{ + scoped_ptr curve( + KeyframedFloatAnimationCurve::Create()); + curve->AddKeyframe( + FloatKeyframe::Create(0.0, 2.f, scoped_ptr())); + EXPECT_FLOAT_EQ(2.f, curve->GetValue(-1.f)); + EXPECT_FLOAT_EQ(2.f, curve->GetValue(0.f)); + EXPECT_FLOAT_EQ(2.f, curve->GetValue(0.5f)); + EXPECT_FLOAT_EQ(2.f, curve->GetValue(1.f)); + EXPECT_FLOAT_EQ(2.f, curve->GetValue(2.f)); +} + +// Tests that a float animation with two keyframes works as expected. +TEST(KeyframedAnimationCurveTest, TwoFloatKeyframe) +{ + scoped_ptr curve( + KeyframedFloatAnimationCurve::Create()); + curve->AddKeyframe( + FloatKeyframe::Create(0.0, 2.f, scoped_ptr())); + curve->AddKeyframe( + FloatKeyframe::Create(1.0, 4.f, scoped_ptr())); + EXPECT_FLOAT_EQ(2.f, curve->GetValue(-1.f)); + EXPECT_FLOAT_EQ(2.f, curve->GetValue(0.f)); + EXPECT_FLOAT_EQ(3.f, curve->GetValue(0.5f)); + EXPECT_FLOAT_EQ(4.f, curve->GetValue(1.f)); + EXPECT_FLOAT_EQ(4.f, curve->GetValue(2.f)); +} + +// Tests that a float animation with three keyframes works as expected. +TEST(KeyframedAnimationCurveTest, ThreeFloatKeyframe) +{ + scoped_ptr curve( + KeyframedFloatAnimationCurve::Create()); + curve->AddKeyframe( + FloatKeyframe::Create(0.0, 2.f, scoped_ptr())); + curve->AddKeyframe( + FloatKeyframe::Create(1.0, 4.f, scoped_ptr())); + curve->AddKeyframe( + FloatKeyframe::Create(2.0, 8.f, scoped_ptr())); + EXPECT_FLOAT_EQ(2.f, curve->GetValue(-1.f)); + EXPECT_FLOAT_EQ(2.f, curve->GetValue(0.f)); + EXPECT_FLOAT_EQ(3.f, curve->GetValue(0.5f)); + EXPECT_FLOAT_EQ(4.f, curve->GetValue(1.f)); + EXPECT_FLOAT_EQ(6.f, curve->GetValue(1.5f)); + EXPECT_FLOAT_EQ(8.f, curve->GetValue(2.f)); + EXPECT_FLOAT_EQ(8.f, curve->GetValue(3.f)); +} + +// Tests that a float animation with multiple keys at a given time works sanely. +TEST(KeyframedAnimationCurveTest, RepeatedFloatKeyTimes) +{ + scoped_ptr curve( + KeyframedFloatAnimationCurve::Create()); + curve->AddKeyframe( + FloatKeyframe::Create(0.0, 4.f, scoped_ptr())); + curve->AddKeyframe( + FloatKeyframe::Create(1.0, 4.f, scoped_ptr())); + curve->AddKeyframe( + FloatKeyframe::Create(1.0, 6.f, scoped_ptr())); + curve->AddKeyframe( + FloatKeyframe::Create(2.0, 6.f, scoped_ptr())); + + EXPECT_FLOAT_EQ(4.f, curve->GetValue(-1.f)); + EXPECT_FLOAT_EQ(4.f, curve->GetValue(0.f)); + EXPECT_FLOAT_EQ(4.f, curve->GetValue(0.5f)); + + // There is a discontinuity at 1. Any value between 4 and 6 is valid. + float value = curve->GetValue(1.f); + EXPECT_TRUE(value >= 4 && value <= 6); + + EXPECT_FLOAT_EQ(6.f, curve->GetValue(1.5f)); + EXPECT_FLOAT_EQ(6.f, curve->GetValue(2.f)); + EXPECT_FLOAT_EQ(6.f, curve->GetValue(3.f)); +} + + +// Tests that a transform animation with one keyframe works as expected. +TEST(KeyframedAnimationCurveTest, OneTransformKeyframe) +{ + scoped_ptr curve( + KeyframedTransformAnimationCurve::Create()); + TransformOperations operations; + operations.AppendTranslate(2.f, 0.f, 0.f); + curve->AddKeyframe( + TransformKeyframe::Create(0.f, operations, scoped_ptr())); + + expectTranslateX(2.f, curve->GetValue(-1.f)); + expectTranslateX(2.f, curve->GetValue(0.f)); + expectTranslateX(2.f, curve->GetValue(0.5f)); + expectTranslateX(2.f, curve->GetValue(1.f)); + expectTranslateX(2.f, curve->GetValue(2.f)); +} + +// Tests that a transform animation with two keyframes works as expected. +TEST(KeyframedAnimationCurveTest, TwoTransformKeyframe) +{ + scoped_ptr curve( + KeyframedTransformAnimationCurve::Create()); + TransformOperations operations1; + operations1.AppendTranslate(2.f, 0.f, 0.f); + TransformOperations operations2; + operations2.AppendTranslate(4.f, 0.f, 0.f); + + curve->AddKeyframe(TransformKeyframe::Create( + 0.f, operations1, scoped_ptr())); + curve->AddKeyframe(TransformKeyframe::Create( + 1.f, operations2, scoped_ptr())); + expectTranslateX(2.f, curve->GetValue(-1.f)); + expectTranslateX(2.f, curve->GetValue(0.f)); + expectTranslateX(3.f, curve->GetValue(0.5f)); + expectTranslateX(4.f, curve->GetValue(1.f)); + expectTranslateX(4.f, curve->GetValue(2.f)); +} + +// Tests that a transform animation with three keyframes works as expected. +TEST(KeyframedAnimationCurveTest, ThreeTransformKeyframe) +{ + scoped_ptr curve( + KeyframedTransformAnimationCurve::Create()); + TransformOperations operations1; + operations1.AppendTranslate(2.f, 0.f, 0.f); + TransformOperations operations2; + operations2.AppendTranslate(4.f, 0.f, 0.f); + TransformOperations operations3; + operations3.AppendTranslate(8.f, 0.f, 0.f); + curve->AddKeyframe(TransformKeyframe::Create( + 0.f, operations1, scoped_ptr())); + curve->AddKeyframe(TransformKeyframe::Create( + 1.f, operations2, scoped_ptr())); + curve->AddKeyframe(TransformKeyframe::Create( + 2.f, operations3, scoped_ptr())); + expectTranslateX(2.f, curve->GetValue(-1.f)); + expectTranslateX(2.f, curve->GetValue(0.f)); + expectTranslateX(3.f, curve->GetValue(0.5f)); + expectTranslateX(4.f, curve->GetValue(1.f)); + expectTranslateX(6.f, curve->GetValue(1.5f)); + expectTranslateX(8.f, curve->GetValue(2.f)); + expectTranslateX(8.f, curve->GetValue(3.f)); +} + +// Tests that a transform animation with multiple keys at a given time works +// sanely. +TEST(KeyframedAnimationCurveTest, RepeatedTransformKeyTimes) +{ + scoped_ptr curve( + KeyframedTransformAnimationCurve::Create()); + // A step function. + TransformOperations operations1; + operations1.AppendTranslate(4.f, 0.f, 0.f); + TransformOperations operations2; + operations2.AppendTranslate(4.f, 0.f, 0.f); + TransformOperations operations3; + operations3.AppendTranslate(6.f, 0.f, 0.f); + TransformOperations operations4; + operations4.AppendTranslate(6.f, 0.f, 0.f); + curve->AddKeyframe(TransformKeyframe::Create( + 0.f, operations1, scoped_ptr())); + curve->AddKeyframe(TransformKeyframe::Create( + 1.f, operations2, scoped_ptr())); + curve->AddKeyframe(TransformKeyframe::Create( + 1.f, operations3, scoped_ptr())); + curve->AddKeyframe(TransformKeyframe::Create( + 2.f, operations4, scoped_ptr())); + + expectTranslateX(4.f, curve->GetValue(-1.f)); + expectTranslateX(4.f, curve->GetValue(0.f)); + expectTranslateX(4.f, curve->GetValue(0.5f)); + + // There is a discontinuity at 1. Any value between 4 and 6 is valid. + gfx::Transform value = curve->GetValue(1.f); + EXPECT_TRUE(value.matrix().getDouble(0.f, 3.f) >= 4); + EXPECT_TRUE(value.matrix().getDouble(0.f, 3.f) <= 6); + + expectTranslateX(6.f, curve->GetValue(1.5f)); + expectTranslateX(6.f, curve->GetValue(2.f)); + expectTranslateX(6.f, curve->GetValue(3.f)); +} + +// Tests that the keyframes may be added out of order. +TEST(KeyframedAnimationCurveTest, UnsortedKeyframes) +{ + scoped_ptr curve( + KeyframedFloatAnimationCurve::Create()); + curve->AddKeyframe( + FloatKeyframe::Create(2.0, 8.f, scoped_ptr())); + curve->AddKeyframe( + FloatKeyframe::Create(0.0, 2.f, scoped_ptr())); + curve->AddKeyframe( + FloatKeyframe::Create(1.0, 4.f, scoped_ptr())); + EXPECT_FLOAT_EQ(2.f, curve->GetValue(-1.f)); + EXPECT_FLOAT_EQ(2.f, curve->GetValue(0.f)); + EXPECT_FLOAT_EQ(3.f, curve->GetValue(0.5f)); + EXPECT_FLOAT_EQ(4.f, curve->GetValue(1.f)); + EXPECT_FLOAT_EQ(6.f, curve->GetValue(1.5f)); + EXPECT_FLOAT_EQ(8.f, curve->GetValue(2.f)); + EXPECT_FLOAT_EQ(8.f, curve->GetValue(3.f)); +} + +// Tests that a cubic bezier timing function works as expected. +TEST(KeyframedAnimationCurveTest, CubicBezierTimingFunction) +{ + scoped_ptr curve( + KeyframedFloatAnimationCurve::Create()); + curve->AddKeyframe( + FloatKeyframe::Create( + 0.f, + 0, + CubicBezierTimingFunction::create( + 0.25f, 0.f, 0.75f, 1.f).PassAs())); + curve->AddKeyframe( + FloatKeyframe::Create(1.0, 1.f, scoped_ptr())); + + EXPECT_FLOAT_EQ(0.f, curve->GetValue(0.f)); + EXPECT_LT(0.f, curve->GetValue(0.25f)); + EXPECT_GT(0.25f, curve->GetValue(0.25f)); + EXPECT_NEAR(curve->GetValue(0.5f), 0.5f, 0.00015f); + EXPECT_LT(0.75f, curve->GetValue(0.75f)); + EXPECT_GT(1.f, curve->GetValue(0.75f)); + EXPECT_FLOAT_EQ(1.f, curve->GetValue(1.f)); +} + +} // namespace +} // namespace cc diff --git a/cc/animation/layer_animation_controller.cc b/cc/animation/layer_animation_controller.cc new file mode 100644 index 0000000..ef280d6 --- /dev/null +++ b/cc/animation/layer_animation_controller.cc @@ -0,0 +1,628 @@ +// 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/animation/layer_animation_controller.h" + +#include + +#include "cc/animation/animation.h" +#include "cc/animation/animation_registrar.h" +#include "cc/animation/keyframed_animation_curve.h" +#include "cc/animation/layer_animation_value_observer.h" +#include "cc/base/scoped_ptr_algorithm.h" +#include "ui/gfx/transform.h" + +namespace cc { + +LayerAnimationController::LayerAnimationController(int id) + : force_sync_(false), + registrar_(0), + id_(id), + is_active_(false), + last_tick_time_(0) {} + +LayerAnimationController::~LayerAnimationController() { + if (registrar_) + registrar_->UnregisterAnimationController(this); +} + +scoped_refptr LayerAnimationController::Create( + int id) { + return make_scoped_refptr(new LayerAnimationController(id)); +} + +void LayerAnimationController::PauseAnimation(int animation_id, + double time_offset) { + for (size_t i = 0; i < active_animations_.size(); ++i) { + if (active_animations_[i]->id() == animation_id) { + active_animations_[i]->SetRunState( + Animation::Paused, time_offset + active_animations_[i]->start_time()); + } + } +} + +struct HasAnimationId { + HasAnimationId(int id) : id_(id) {} + bool operator()(Animation* animation) const { + return animation->id() == id_; + } + + private: + int id_; +}; + +void LayerAnimationController::RemoveAnimation(int animation_id) { + ScopedPtrVector& animations = active_animations_; + animations.erase(cc::remove_if(animations, + animations.begin(), + animations.end(), + HasAnimationId(animation_id)), + animations.end()); + UpdateActivation(NormalActivation); +} + +struct HasAnimationIdAndProperty { + HasAnimationIdAndProperty(int id, Animation::TargetProperty target_property) + : id_(id), target_property_(target_property) {} + bool operator()(Animation* animation) const { + return animation->id() == id_ && + animation->target_property() == target_property_; + } + + private: + int id_; + Animation::TargetProperty target_property_; +}; + +void LayerAnimationController::RemoveAnimation( + int animation_id, + Animation::TargetProperty target_property) { + ScopedPtrVector& animations = active_animations_; + animations.erase(cc::remove_if(animations, + animations.begin(), + animations.end(), + HasAnimationIdAndProperty(animation_id, + target_property)), + animations.end()); + UpdateActivation(NormalActivation); +} + +// According to render layer backing, these are for testing only. +void LayerAnimationController::SuspendAnimations(double monotonic_time) { + for (size_t i = 0; i < active_animations_.size(); ++i) { + if (!active_animations_[i]->is_finished()) + active_animations_[i]->SetRunState(Animation::Paused, monotonic_time); + } +} + +// Looking at GraphicsLayerCA, this appears to be the analog to +// suspendAnimations, which is for testing. +void LayerAnimationController::ResumeAnimations(double monotonic_time) { + for (size_t i = 0; i < active_animations_.size(); ++i) { + if (active_animations_[i]->run_state() == Animation::Paused) + active_animations_[i]->SetRunState(Animation::Running, monotonic_time); + } +} + +// Ensures that the list of active animations on the main thread and the impl +// thread are kept in sync. +void LayerAnimationController::PushAnimationUpdatesTo( + LayerAnimationController* controller_impl) { + if (force_sync_) { + ReplaceImplThreadAnimations(controller_impl); + force_sync_ = false; + } else { + PurgeAnimationsMarkedForDeletion(); + PushNewAnimationsToImplThread(controller_impl); + + // 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(controller_impl); + + PushPropertiesToImplThread(controller_impl); + } + controller_impl->UpdateActivation(NormalActivation); + UpdateActivation(NormalActivation); +} + +void LayerAnimationController::Animate(double monotonic_time) { + if (!HasActiveObserver()) + return; + + StartAnimationsWaitingForNextTick(monotonic_time); + StartAnimationsWaitingForStartTime(monotonic_time); + StartAnimationsWaitingForTargetAvailability(monotonic_time); + ResolveConflicts(monotonic_time); + TickAnimations(monotonic_time); + last_tick_time_ = monotonic_time; +} + +void LayerAnimationController::AccumulatePropertyUpdates( + double monotonic_time, + AnimationEventsVector* events) { + if (!events) + return; + + for (size_t i = 0; i < active_animations_.size(); ++i) { + Animation* animation = active_animations_[i]; + if (!animation->is_impl_only()) + continue; + + if (animation->target_property() == Animation::Opacity) { + AnimationEvent event(AnimationEvent::PropertyUpdate, + id_, + animation->group(), + Animation::Opacity, + monotonic_time); + event.opacity = animation->curve()->ToFloatAnimationCurve()->GetValue( + monotonic_time); + + events->push_back(event); + } + else if (animation->target_property() == Animation::Transform) { + AnimationEvent event(AnimationEvent::PropertyUpdate, + id_, + animation->group(), + Animation::Transform, + monotonic_time); + event.transform = + animation->curve()->ToTransformAnimationCurve()->GetValue( + monotonic_time); + events->push_back(event); + } + } +} + +void LayerAnimationController::UpdateState(AnimationEventsVector* events) { + if (!HasActiveObserver()) + return; + + PromoteStartedAnimations(last_tick_time_, events); + MarkFinishedAnimations(last_tick_time_); + MarkAnimationsForDeletion(last_tick_time_, events); + StartAnimationsWaitingForTargetAvailability(last_tick_time_); + PromoteStartedAnimations(last_tick_time_, events); + + AccumulatePropertyUpdates(last_tick_time_, events); + + UpdateActivation(NormalActivation); +} + +void LayerAnimationController::AddAnimation(scoped_ptr animation) { + active_animations_.push_back(animation.Pass()); + UpdateActivation(NormalActivation); +} + +Animation* LayerAnimationController::GetAnimation( + int group_id, + Animation::TargetProperty target_property) const { + for (size_t i = 0; i < active_animations_.size(); ++i) + if (active_animations_[i]->group() == group_id && + active_animations_[i]->target_property() == target_property) + return active_animations_[i]; + return 0; +} + +Animation* LayerAnimationController::GetAnimation( + Animation::TargetProperty target_property) const { + for (size_t i = 0; i < active_animations_.size(); ++i) { + size_t index = active_animations_.size() - i - 1; + if (active_animations_[index]->target_property() == target_property) + return active_animations_[index]; + } + return 0; +} + +bool LayerAnimationController::HasActiveAnimation() const { + for (size_t i = 0; i < active_animations_.size(); ++i) { + if (!active_animations_[i]->is_finished()) + return true; + } + return false; +} + +bool LayerAnimationController::IsAnimatingProperty( + Animation::TargetProperty target_property) const { + for (size_t i = 0; i < active_animations_.size(); ++i) { + if (active_animations_[i]->run_state() != Animation::Finished && + active_animations_[i]->run_state() != Animation::Aborted && + active_animations_[i]->target_property() == target_property) + return true; + } + return false; +} + +void LayerAnimationController::OnAnimationStarted( + const AnimationEvent& event) { + for (size_t i = 0; i < active_animations_.size(); ++i) { + if (active_animations_[i]->group() == event.group_id && + active_animations_[i]->target_property() == event.target_property && + active_animations_[i]->needs_synchronized_start_time()) { + active_animations_[i]->set_needs_synchronized_start_time(false); + active_animations_[i]->set_start_time(event.monotonic_time); + return; + } + } +} + +void LayerAnimationController::SetAnimationRegistrar( + AnimationRegistrar* registrar) { + if (registrar_ == registrar) + return; + + if (registrar_) + registrar_->UnregisterAnimationController(this); + + registrar_ = registrar; + if (registrar_) + registrar_->RegisterAnimationController(this); + + UpdateActivation(ForceActivation); +} + +void LayerAnimationController::AddObserver( + LayerAnimationValueObserver* observer) { + if (!observers_.HasObserver(observer)) + observers_.AddObserver(observer); +} + +void LayerAnimationController::RemoveObserver( + LayerAnimationValueObserver* observer) { + observers_.RemoveObserver(observer); +} + +void LayerAnimationController::PushNewAnimationsToImplThread( + LayerAnimationController* controller_impl) const { + // Any new animations owned by the main thread's controller are cloned and + // add to the impl thread's controller. + for (size_t i = 0; i < active_animations_.size(); ++i) { + // If the animation is already running on the impl thread, there is no + // need to copy it over. + if (controller_impl->GetAnimation(active_animations_[i]->group(), + active_animations_[i]->target_property())) + 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 (!active_animations_[i]->needs_synchronized_start_time()) + continue; + + // The new animation should be set to run as soon as possible. + Animation::RunState initial_run_state = + Animation::WaitingForTargetAvailability; + double start_time = 0; + scoped_ptr to_add(active_animations_[i]->CloneAndInitialize( + Animation::ControllingInstance, initial_run_state, start_time)); + DCHECK(!to_add->needs_synchronized_start_time()); + controller_impl->AddAnimation(to_add.Pass()); + } +} + +struct IsCompleted { + IsCompleted(const LayerAnimationController& main_thread_controller) + : main_thread_controller_(main_thread_controller) {} + bool operator()(Animation* animation) const { + if (animation->is_impl_only()) + return false; + return !main_thread_controller_.GetAnimation(animation->group(), + animation->target_property()); + } + + private: + const LayerAnimationController& main_thread_controller_; +}; + +void LayerAnimationController::RemoveAnimationsCompletedOnMainThread( + LayerAnimationController* controller_impl) const { + // Delete all impl thread animations for which there is no corresponding + // main thread animation. Each iteration, + // controller->active_animations_.size() is decremented or i is incremented + // guaranteeing progress towards loop termination. + ScopedPtrVector& animations = + controller_impl->active_animations_; + animations.erase(cc::remove_if(animations, + animations.begin(), + animations.end(), + IsCompleted(*this)), + animations.end()); +} + +void LayerAnimationController::PushPropertiesToImplThread( + LayerAnimationController* controller_impl) const { + for (size_t i = 0; i < active_animations_.size(); ++i) { + Animation* current_impl = + controller_impl->GetAnimation( + active_animations_[i]->group(), + active_animations_[i]->target_property()); + if (current_impl) + active_animations_[i]->PushPropertiesTo(current_impl); + } +} + +void LayerAnimationController::StartAnimationsWaitingForNextTick( + double monotonic_time) { + for (size_t i = 0; i < active_animations_.size(); ++i) { + if (active_animations_[i]->run_state() == Animation::WaitingForNextTick) + active_animations_[i]->SetRunState(Animation::Starting, monotonic_time); + } +} + +void LayerAnimationController::StartAnimationsWaitingForStartTime( + double monotonic_time) { + for (size_t i = 0; i < active_animations_.size(); ++i) { + if (active_animations_[i]->run_state() == Animation::WaitingForStartTime && + active_animations_[i]->start_time() <= monotonic_time) + active_animations_[i]->SetRunState(Animation::Starting, monotonic_time); + } +} + +void LayerAnimationController::StartAnimationsWaitingForTargetAvailability( + double monotonic_time) { + // First collect running properties. + TargetProperties blocked_properties; + for (size_t i = 0; i < active_animations_.size(); ++i) { + if (active_animations_[i]->run_state() == Animation::Starting || + active_animations_[i]->run_state() == Animation::Running || + active_animations_[i]->run_state() == Animation::Finished) + blocked_properties.insert(active_animations_[i]->target_property()); + } + + for (size_t i = 0; i < active_animations_.size(); ++i) { + if (active_animations_[i]->run_state() == + Animation::WaitingForTargetAvailability) { + // Collect all properties for animations with the same group id (they + // should all also be in the list of animations). + TargetProperties enqueued_properties; + enqueued_properties.insert(active_animations_[i]->target_property()); + for (size_t j = i + 1; j < active_animations_.size(); ++j) { + if (active_animations_[i]->group() == active_animations_[j]->group()) + enqueued_properties.insert(active_animations_[j]->target_property()); + } + + // 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 null_intersection = true; + for (TargetProperties::iterator p_iter = enqueued_properties.begin(); + p_iter != enqueued_properties.end(); + ++p_iter) { + if (!blocked_properties.insert(*p_iter).second) + null_intersection = false; + } + + // If the intersection is null, then we are free to start the animations + // in the group. + if (null_intersection) { + active_animations_[i]->SetRunState( + Animation::Starting, monotonic_time); + for (size_t j = i + 1; j < active_animations_.size(); ++j) { + if (active_animations_[i]->group() == + active_animations_[j]->group()) { + active_animations_[j]->SetRunState( + Animation::Starting, monotonic_time); + } + } + } + } + } +} + +void LayerAnimationController::PromoteStartedAnimations( + double monotonic_time, + AnimationEventsVector* events) { + for (size_t i = 0; i < active_animations_.size(); ++i) { + if (active_animations_[i]->run_state() == Animation::Starting) { + active_animations_[i]->SetRunState(Animation::Running, monotonic_time); + if (!active_animations_[i]->has_set_start_time()) + active_animations_[i]->set_start_time(monotonic_time); + if (events) { + events->push_back(AnimationEvent( + AnimationEvent::Started, + id_, + active_animations_[i]->group(), + active_animations_[i]->target_property(), + monotonic_time)); + } + } + } +} + +void LayerAnimationController::MarkFinishedAnimations(double monotonic_time) { + for (size_t i = 0; i < active_animations_.size(); ++i) { + if (active_animations_[i]->IsFinishedAt(monotonic_time)) + active_animations_[i]->SetRunState(Animation::Finished, monotonic_time); + } +} + +void LayerAnimationController::ResolveConflicts(double monotonic_time) { + // 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 active_animations_). + for (size_t i = 0; i < active_animations_.size(); ++i) { + if (active_animations_[i]->run_state() == Animation::Starting || + active_animations_[i]->run_state() == Animation::Running) { + for (size_t j = i + 1; j < active_animations_.size(); ++j) { + if ((active_animations_[j]->run_state() == Animation::Starting || + active_animations_[j]->run_state() == Animation::Running) && + active_animations_[i]->target_property() == + active_animations_[j]->target_property()) { + if (active_animations_[i]->start_time() > + active_animations_[j]->start_time()) { + active_animations_[j]->SetRunState(Animation::Aborted, + monotonic_time); + } else { + active_animations_[i]->SetRunState(Animation::Aborted, + monotonic_time); + } + } + } + } + } +} + +void LayerAnimationController::MarkAnimationsForDeletion( + double monotonic_time, AnimationEventsVector* events) { + for (size_t i = 0; i < active_animations_.size(); i++) { + int group_id = active_animations_[i]->group(); + bool all_anims_with_same_id_are_finished = 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 (active_animations_[i]->is_finished() && + active_animations_[i]->run_state() != Animation::WaitingForDeletion) { + all_anims_with_same_id_are_finished = true; + for (size_t j = 0; j < active_animations_.size(); ++j) { + if (group_id == active_animations_[j]->group() && + !active_animations_[j]->is_finished()) { + all_anims_with_same_id_are_finished = false; + break; + } + } + } + if (all_anims_with_same_id_are_finished) { + // We now need to remove all animations with the same group id as + // group_id (and send along animation finished notifications, if + // necessary). + for (size_t j = i; j < active_animations_.size(); j++) { + if (group_id == active_animations_[j]->group()) { + if (events) { + events->push_back(AnimationEvent( + AnimationEvent::Finished, + id_, + active_animations_[j]->group(), + active_animations_[j]->target_property(), + monotonic_time)); + } + active_animations_[j]->SetRunState(Animation::WaitingForDeletion, + monotonic_time); + } + } + } + } +} + +static bool IsWaitingForDeletion(Animation* animation) { + return animation->run_state() == Animation::WaitingForDeletion; +} + +void LayerAnimationController::PurgeAnimationsMarkedForDeletion() { + ScopedPtrVector& animations = active_animations_; + animations.erase(cc::remove_if(animations, + animations.begin(), + animations.end(), + IsWaitingForDeletion), + animations.end()); +} + +void LayerAnimationController::ReplaceImplThreadAnimations( + LayerAnimationController* controller_impl) const { + controller_impl->active_animations_.clear(); + for (size_t i = 0; i < active_animations_.size(); ++i) { + scoped_ptr to_add; + if (active_animations_[i]->needs_synchronized_start_time()) { + // We haven't received an animation started notification yet, so it + // is important that we add it in a 'waiting' and not 'running' state. + Animation::RunState initial_run_state = + Animation::WaitingForTargetAvailability; + double start_time = 0; + to_add = active_animations_[i]->CloneAndInitialize( + Animation::ControllingInstance, + initial_run_state, start_time).Pass(); + } else { + to_add = active_animations_[i]->Clone( + Animation::ControllingInstance).Pass(); + } + + controller_impl->AddAnimation(to_add.Pass()); + } +} + +void LayerAnimationController::TickAnimations(double monotonic_time) { + for (size_t i = 0; i < active_animations_.size(); ++i) { + if (active_animations_[i]->run_state() == Animation::Starting || + active_animations_[i]->run_state() == Animation::Running || + active_animations_[i]->run_state() == Animation::Paused) { + double trimmed = + active_animations_[i]->TrimTimeToCurrentIteration(monotonic_time); + + // Animation assumes its initial value until it gets the synchronized + // start time from the impl thread and can start ticking. + if (active_animations_[i]->needs_synchronized_start_time()) + trimmed = 0; + + // A just-started animation assumes its initial value. + if (active_animations_[i]->run_state() == Animation::Starting && + !active_animations_[i]->has_set_start_time()) + trimmed = 0; + + switch (active_animations_[i]->target_property()) { + + case Animation::Transform: { + const TransformAnimationCurve* transform_animation_curve = + active_animations_[i]->curve()->ToTransformAnimationCurve(); + const gfx::Transform transform = + transform_animation_curve->GetValue(trimmed); + NotifyObserversTransformAnimated(transform); + break; + } + + case Animation::Opacity: { + const FloatAnimationCurve* float_animation_curve = + active_animations_[i]->curve()->ToFloatAnimationCurve(); + const float opacity = float_animation_curve->GetValue(trimmed); + NotifyObserversOpacityAnimated(opacity); + break; + } + + // Do nothing for sentinel value. + case Animation::TargetPropertyEnumSize: + NOTREACHED(); + } + } + } +} + +void LayerAnimationController::UpdateActivation(UpdateActivationType type) { + bool force = type == ForceActivation; + if (registrar_) { + if (!active_animations_.empty() && (!is_active_ || force)) + registrar_->DidActivateAnimationController(this); + else if (active_animations_.empty() && (is_active_ || force)) + registrar_->DidDeactivateAnimationController(this); + is_active_ = !active_animations_.empty(); + } +} + +void LayerAnimationController::NotifyObserversOpacityAnimated(float opacity) { + FOR_EACH_OBSERVER(LayerAnimationValueObserver, + observers_, + OnOpacityAnimated(opacity)); +} + +void LayerAnimationController::NotifyObserversTransformAnimated( + const gfx::Transform& transform) { + FOR_EACH_OBSERVER(LayerAnimationValueObserver, + observers_, + OnTransformAnimated(transform)); +} + +bool LayerAnimationController::HasActiveObserver() { + if (observers_.might_have_observers()) { + ObserverListBase::Iterator it(observers_); + LayerAnimationValueObserver* obs; + while ((obs = it.GetNext()) != NULL) + if (obs->IsActive()) + return true; + } + return false; +} + +} // namespace cc diff --git a/cc/animation/layer_animation_controller.h b/cc/animation/layer_animation_controller.h new file mode 100644 index 0000000..1de1131 --- /dev/null +++ b/cc/animation/layer_animation_controller.h @@ -0,0 +1,154 @@ +// 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. + +#ifndef CC_ANIMATION_LAYER_ANIMATION_CONTROLLER_H_ +#define CC_ANIMATION_LAYER_ANIMATION_CONTROLLER_H_ + +#include "base/basictypes.h" +#include "base/hash_tables.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "base/observer_list.h" +#include "base/time.h" +#include "cc/animation/animation_events.h" +#include "cc/animation/layer_animation_event_observer.h" +#include "cc/base/cc_export.h" +#include "cc/base/scoped_ptr_vector.h" +#include "ui/gfx/transform.h" + +namespace gfx { class Transform; } + +namespace cc { + +class Animation; +class AnimationRegistrar; +class KeyframeValueList; +class LayerAnimationValueObserver; + +class CC_EXPORT LayerAnimationController + : public base::RefCounted, + public LayerAnimationEventObserver { + public: + static scoped_refptr Create(int id); + + int id() const { return id_; } + + // These methods are virtual for testing. + virtual void AddAnimation(scoped_ptr animation); + virtual void PauseAnimation(int animation_id, double time_offset); + virtual void RemoveAnimation(int animation_id); + virtual void RemoveAnimation(int animation_id, + Animation::TargetProperty target_property); + virtual void SuspendAnimations(double monotonic_time); + virtual void ResumeAnimations(double monotonic_time); + + // Ensures that the list of active animations on the main thread and the impl + // thread are kept in sync. This function does not take ownership of the impl + // thread controller. + virtual void PushAnimationUpdatesTo( + LayerAnimationController* controller_impl); + + void Animate(double monotonic_time); + void AccumulatePropertyUpdates(double monotonic_time, + AnimationEventsVector* events); + void UpdateState(AnimationEventsVector* events); + + // Returns the active animation in the given group, animating the given + // property, if such an animation exists. + Animation* GetAnimation(int group_id, + Animation::TargetProperty target_property) const; + + // Returns the active animation animating the given property that is either + // running, or is next to run, if such an animation exists. + Animation* GetAnimation(Animation::TargetProperty target_property) const; + + // Returns true if there are any animations that have neither finished nor + // aborted. + bool HasActiveAnimation() const; + + // Returns true if there are any animations at all to process. + bool has_any_animation() const { return !active_animations_.empty(); } + + // Returns true if there is an animation currently animating the given + // property, or if there is an animation scheduled to animate this property in + // the future. + bool IsAnimatingProperty(Animation::TargetProperty target_property) const; + + // This is called in response to an animation being started on the impl + // thread. This function updates the corresponding main thread animation's + // start time. + virtual void OnAnimationStarted(const AnimationEvent& event) OVERRIDE; + + // If a sync is forced, then the next time animation updates are pushed to the + // impl thread, all animations will be transferred. + void set_force_sync() { force_sync_ = true; } + + void SetAnimationRegistrar(AnimationRegistrar* registrar); + AnimationRegistrar* animation_registrar() { return registrar_; } + + void AddObserver(LayerAnimationValueObserver* observer); + void RemoveObserver(LayerAnimationValueObserver* observer); + + protected: + friend class base::RefCounted; + + LayerAnimationController(int id); + virtual ~LayerAnimationController(); + + private: + typedef base::hash_set TargetProperties; + + void PushNewAnimationsToImplThread( + LayerAnimationController* controller_impl) const; + void RemoveAnimationsCompletedOnMainThread( + LayerAnimationController* controller_impl) const; + void PushPropertiesToImplThread( + LayerAnimationController* controller_impl) const; + void ReplaceImplThreadAnimations( + LayerAnimationController* controller_impl) const; + + void StartAnimationsWaitingForNextTick(double monotonic_time); + void StartAnimationsWaitingForStartTime(double monotonic_time); + void StartAnimationsWaitingForTargetAvailability(double monotonic_time); + void ResolveConflicts(double monotonic_time); + void PromoteStartedAnimations(double monotonic_time, + AnimationEventsVector* events); + void MarkFinishedAnimations(double monotonic_time); + void MarkAnimationsForDeletion(double monotonic_time, + AnimationEventsVector* events); + void PurgeAnimationsMarkedForDeletion(); + + void TickAnimations(double monotonic_time); + + enum UpdateActivationType { + NormalActivation, + ForceActivation + }; + void UpdateActivation(UpdateActivationType type); + + void NotifyObserversOpacityAnimated(float opacity); + void NotifyObserversTransformAnimated(const gfx::Transform& transform); + + bool HasActiveObserver(); + + // If this is true, we force a sync to the impl thread. + bool force_sync_; + + AnimationRegistrar* registrar_; + int id_; + ScopedPtrVector active_animations_; + + // This is used to ensure that we don't spam the registrar. + bool is_active_; + + double last_tick_time_; + + ObserverList observers_; + + DISALLOW_COPY_AND_ASSIGN(LayerAnimationController); +}; + +} // namespace cc + +#endif // CC_ANIMATION_LAYER_ANIMATION_CONTROLLER_H_ diff --git a/cc/animation/layer_animation_controller_unittest.cc b/cc/animation/layer_animation_controller_unittest.cc new file mode 100644 index 0000000..2e7c29b --- /dev/null +++ b/cc/animation/layer_animation_controller_unittest.cc @@ -0,0 +1,901 @@ +// 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/animation/layer_animation_controller.h" + +#include "cc/animation/animation.h" +#include "cc/animation/animation_curve.h" +#include "cc/animation/keyframed_animation_curve.h" +#include "cc/test/animation_test_common.h" +#include "cc/transform_operations.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/gfx/transform.h" + +namespace cc { +namespace { + +void ExpectTranslateX(double translate_x, const gfx::Transform& matrix) { + EXPECT_FLOAT_EQ(translate_x, matrix.matrix().getDouble(0, 3)); } + +scoped_ptr CreateAnimation(scoped_ptr curve, + int id, + Animation::TargetProperty property) { + return Animation::Create(curve.Pass(), 0, id, property); +} + +TEST(LayerAnimationControllerTest, SyncNewAnimation) { + FakeLayerAnimationValueObserver dummy_impl; + scoped_refptr controller_impl( + LayerAnimationController::Create(0)); + controller_impl->AddObserver(&dummy_impl); + FakeLayerAnimationValueObserver dummy; + scoped_refptr controller( + LayerAnimationController::Create(0)); + controller->AddObserver(&dummy); + + EXPECT_FALSE(controller_impl->GetAnimation(0, Animation::Opacity)); + + addOpacityTransitionToController(*controller, 1, 0, 1, false); + + controller->PushAnimationUpdatesTo(controller_impl.get()); + + EXPECT_TRUE(controller_impl->GetAnimation(0, Animation::Opacity)); + EXPECT_EQ(Animation::WaitingForTargetAvailability, + controller_impl->GetAnimation(0, Animation::Opacity)->run_state()); +} + +// If an animation is started on the impl thread before it is ticked on the main +// thread, we must be sure to respect the synchronized start time. +TEST(LayerAnimationControllerTest, DoNotClobberStartTimes) { + FakeLayerAnimationValueObserver dummy_impl; + scoped_refptr controller_impl( + LayerAnimationController::Create(0)); + controller_impl->AddObserver(&dummy_impl); + FakeLayerAnimationValueObserver dummy; + scoped_refptr controller( + LayerAnimationController::Create(0)); + controller->AddObserver(&dummy); + + EXPECT_FALSE(controller_impl->GetAnimation(0, Animation::Opacity)); + + addOpacityTransitionToController(*controller, 1, 0, 1, false); + + controller->PushAnimationUpdatesTo(controller_impl.get()); + + EXPECT_TRUE(controller_impl->GetAnimation(0, Animation::Opacity)); + EXPECT_EQ(Animation::WaitingForTargetAvailability, + controller_impl->GetAnimation(0, Animation::Opacity)->run_state()); + + AnimationEventsVector events; + controller_impl->Animate(1.0); + controller_impl->UpdateState(&events); + + // Synchronize the start times. + EXPECT_EQ(1u, events.size()); + controller->OnAnimationStarted(events[0]); + EXPECT_EQ(controller->GetAnimation(0, Animation::Opacity)->start_time(), + controller_impl->GetAnimation(0, Animation::Opacity)->start_time()); + + // Start the animation on the main thread. Should not affect the start time. + controller->Animate(1.5); + controller->UpdateState(NULL); + EXPECT_EQ(controller->GetAnimation(0, Animation::Opacity)->start_time(), + controller_impl->GetAnimation(0, Animation::Opacity)->start_time()); +} + +TEST(LayerAnimationControllerTest, SyncPauseAndResume) { + FakeLayerAnimationValueObserver dummy_impl; + scoped_refptr controller_impl( + LayerAnimationController::Create(0)); + controller_impl->AddObserver(&dummy_impl); + FakeLayerAnimationValueObserver dummy; + scoped_refptr controller( + LayerAnimationController::Create(0)); + controller->AddObserver(&dummy); + + EXPECT_FALSE(controller_impl->GetAnimation(0, Animation::Opacity)); + + addOpacityTransitionToController(*controller, 1, 0, 1, false); + + controller->PushAnimationUpdatesTo(controller_impl.get()); + + EXPECT_TRUE(controller_impl->GetAnimation(0, Animation::Opacity)); + EXPECT_EQ(Animation::WaitingForTargetAvailability, + controller_impl->GetAnimation(0, Animation::Opacity)->run_state()); + + // Start the animations on each controller. + AnimationEventsVector events; + controller_impl->Animate(0.0); + controller_impl->UpdateState(&events); + controller->Animate(0.0); + controller->UpdateState(NULL); + EXPECT_EQ(Animation::Running, + controller_impl->GetAnimation(0, Animation::Opacity)->run_state()); + EXPECT_EQ(Animation::Running, + controller->GetAnimation(0, Animation::Opacity)->run_state()); + + // Pause the main-thread animation. + controller->SuspendAnimations(1.0); + EXPECT_EQ(Animation::Paused, + controller->GetAnimation(0, Animation::Opacity)->run_state()); + + // The pause run state change should make it to the impl thread controller. + controller->PushAnimationUpdatesTo(controller_impl.get()); + EXPECT_EQ(Animation::Paused, + controller_impl->GetAnimation(0, Animation::Opacity)->run_state()); + + // Resume the main-thread animation. + controller->ResumeAnimations(2.0); + EXPECT_EQ(Animation::Running, + controller->GetAnimation(0, Animation::Opacity)->run_state()); + + // The pause run state change should make it to the impl thread controller. + controller->PushAnimationUpdatesTo(controller_impl.get()); + EXPECT_EQ(Animation::Running, + controller_impl->GetAnimation(0, Animation::Opacity)->run_state()); +} + +TEST(LayerAnimationControllerTest, DoNotSyncFinishedAnimation) { + FakeLayerAnimationValueObserver dummy_impl; + scoped_refptr controller_impl( + LayerAnimationController::Create(0)); + controller_impl->AddObserver(&dummy_impl); + FakeLayerAnimationValueObserver dummy; + scoped_refptr controller( + LayerAnimationController::Create(0)); + controller->AddObserver(&dummy); + + EXPECT_FALSE(controller_impl->GetAnimation(0, Animation::Opacity)); + + int animation_id = + addOpacityTransitionToController(*controller, 1, 0, 1, false); + + controller->PushAnimationUpdatesTo(controller_impl.get()); + + EXPECT_TRUE(controller_impl->GetAnimation(0, Animation::Opacity)); + EXPECT_EQ(Animation::WaitingForTargetAvailability, + controller_impl->GetAnimation(0, Animation::Opacity)->run_state()); + + // Notify main thread controller that the animation has started. + AnimationEvent animation_started_event( + AnimationEvent::Started, 0, 0, Animation::Opacity, 0); + controller->OnAnimationStarted(animation_started_event); + + // Force animation to complete on impl thread. + controller_impl->RemoveAnimation(animation_id); + + EXPECT_FALSE(controller_impl->GetAnimation(animation_id, Animation::Opacity)); + + controller->PushAnimationUpdatesTo(controller_impl.get()); + + // Even though the main thread has a 'new' animation, it should not be pushed + // because the animation has already completed on the impl thread. + EXPECT_FALSE(controller_impl->GetAnimation(animation_id, Animation::Opacity)); +} + +// Tests that transitioning opacity from 0 to 1 works as expected. + +static const AnimationEvent* GetMostRecentPropertyUpdateEvent( + const AnimationEventsVector* events) { + const AnimationEvent* event = 0; + for (size_t i = 0; i < events->size(); ++i) + if ((*events)[i].type == AnimationEvent::PropertyUpdate) + event = &(*events)[i]; + + return event; +} + +TEST(LayerAnimationControllerTest, TrivialTransition) { + scoped_ptr events( + make_scoped_ptr(new AnimationEventsVector)); + FakeLayerAnimationValueObserver dummy; + scoped_refptr controller( + LayerAnimationController::Create(0)); + controller->AddObserver(&dummy); + + scoped_ptr to_add(CreateAnimation( + scoped_ptr(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(), + 1, + Animation::Opacity)); + + controller->AddAnimation(to_add.Pass()); + controller->Animate(0.0); + controller->UpdateState(events.get()); + EXPECT_TRUE(controller->HasActiveAnimation()); + EXPECT_EQ(0.f, dummy.opacity()); + // A non-implOnly animation should not generate property updates. + const AnimationEvent* event = GetMostRecentPropertyUpdateEvent(events.get()); + EXPECT_FALSE(event); + controller->Animate(1.0); + controller->UpdateState(events.get()); + EXPECT_EQ(1.f, dummy.opacity()); + EXPECT_FALSE(controller->HasActiveAnimation()); + event = GetMostRecentPropertyUpdateEvent(events.get()); + EXPECT_FALSE(event); +} + +TEST(LayerAnimationControllerTest, TrivialTransitionOnImpl) { + scoped_ptr events( + make_scoped_ptr(new AnimationEventsVector)); + FakeLayerAnimationValueObserver dummy_impl; + scoped_refptr controller_impl( + LayerAnimationController::Create(0)); + controller_impl->AddObserver(&dummy_impl); + + scoped_ptr to_add(CreateAnimation( + scoped_ptr(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(), + 1, + Animation::Opacity)); + to_add->set_is_impl_only(true); + + controller_impl->AddAnimation(to_add.Pass()); + controller_impl->Animate(0.0); + controller_impl->UpdateState(events.get()); + EXPECT_TRUE(controller_impl->HasActiveAnimation()); + EXPECT_EQ(0.f, dummy_impl.opacity()); + EXPECT_EQ(2, events->size()); + const AnimationEvent* start_opacity_event = + GetMostRecentPropertyUpdateEvent(events.get()); + EXPECT_EQ(0, start_opacity_event->opacity); + + controller_impl->Animate(1.0); + controller_impl->UpdateState(events.get()); + EXPECT_EQ(1.f, dummy_impl.opacity()); + EXPECT_FALSE(controller_impl->HasActiveAnimation()); + EXPECT_EQ(4, events->size()); + const AnimationEvent* end_opacity_event = + GetMostRecentPropertyUpdateEvent(events.get()); + EXPECT_EQ(1, end_opacity_event->opacity); +} + +TEST(LayerAnimationControllerTest, TrivialTransformOnImpl) { + scoped_ptr events( + make_scoped_ptr(new AnimationEventsVector)); + FakeLayerAnimationValueObserver dummy_impl; + scoped_refptr controller_impl( + LayerAnimationController::Create(0)); + controller_impl->AddObserver(&dummy_impl); + + // Choose different values for x and y to avoid coincidental values in the + // observed transforms. + const float delta_x = 3; + const float delta_y = 4; + + scoped_ptr curve( + KeyframedTransformAnimationCurve::Create()); + + // Create simple Transform animation. + TransformOperations operations; + curve->AddKeyframe(TransformKeyframe::Create( + 0, operations, scoped_ptr())); + operations.AppendTranslate(delta_x, delta_y, 0); + curve->AddKeyframe(TransformKeyframe::Create( + 1, operations, scoped_ptr())); + + scoped_ptr animation(Animation::Create( + curve.PassAs(), 1, 0, Animation::Transform)); + animation->set_is_impl_only(true); + controller_impl->AddAnimation(animation.Pass()); + + // Run animation. + controller_impl->Animate(0.0); + controller_impl->UpdateState(events.get()); + EXPECT_TRUE(controller_impl->HasActiveAnimation()); + EXPECT_EQ(gfx::Transform(), dummy_impl.transform()); + EXPECT_EQ(2, events->size()); + const AnimationEvent* start_transform_event = + GetMostRecentPropertyUpdateEvent(events.get()); + ASSERT_TRUE(start_transform_event); + EXPECT_EQ(gfx::Transform(), start_transform_event->transform); + + gfx::Transform expected_transform; + expected_transform.Translate(delta_x, delta_y); + + controller_impl->Animate(1.0); + controller_impl->UpdateState(events.get()); + EXPECT_EQ(expected_transform, dummy_impl.transform()); + EXPECT_FALSE(controller_impl->HasActiveAnimation()); + EXPECT_EQ(4, events->size()); + const AnimationEvent* end_transform_event = + GetMostRecentPropertyUpdateEvent(events.get()); + EXPECT_EQ(expected_transform, end_transform_event->transform); +} + +// Tests animations that are waiting for a synchronized start time do not +// finish. +TEST(LayerAnimationControllerTest, + AnimationsWaitingForStartTimeDoNotFinishIfTheyWaitLongerToStartThanTheirDuration) { + scoped_ptr events( + make_scoped_ptr(new AnimationEventsVector)); + FakeLayerAnimationValueObserver dummy; + scoped_refptr controller( + LayerAnimationController::Create(0)); + controller->AddObserver(&dummy); + + scoped_ptr to_add(CreateAnimation( + scoped_ptr(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(), + 1, + Animation::Opacity)); + to_add->set_needs_synchronized_start_time(true); + + // We should pause at the first keyframe indefinitely waiting for that + // animation to start. + controller->AddAnimation(to_add.Pass()); + controller->Animate(0.0); + controller->UpdateState(events.get()); + EXPECT_TRUE(controller->HasActiveAnimation()); + EXPECT_EQ(0.f, dummy.opacity()); + controller->Animate(1.0); + controller->UpdateState(events.get()); + EXPECT_TRUE(controller->HasActiveAnimation()); + EXPECT_EQ(0.f, dummy.opacity()); + controller->Animate(2.0); + controller->UpdateState(events.get()); + EXPECT_TRUE(controller->HasActiveAnimation()); + EXPECT_EQ(0.f, dummy.opacity()); + + // Send the synchronized start time. + controller->OnAnimationStarted(AnimationEvent( + AnimationEvent::Started, 0, 1, Animation::Opacity, 2)); + controller->Animate(5.0); + controller->UpdateState(events.get()); + EXPECT_EQ(1.f, dummy.opacity()); + EXPECT_FALSE(controller->HasActiveAnimation()); +} + +// Tests that two queued animations affecting the same property run in sequence. +TEST(LayerAnimationControllerTest, TrivialQueuing) { + scoped_ptr events( + make_scoped_ptr(new AnimationEventsVector)); + FakeLayerAnimationValueObserver dummy; + scoped_refptr controller( + LayerAnimationController::Create(0)); + controller->AddObserver(&dummy); + + controller->AddAnimation(CreateAnimation( + scoped_ptr(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(), + 1, + Animation::Opacity)); + controller->AddAnimation(CreateAnimation( + scoped_ptr( + new FakeFloatTransition(1.0, 1.f, 0.5f)).Pass(), + 2, + Animation::Opacity)); + + controller->Animate(0.0); + controller->UpdateState(events.get()); + EXPECT_TRUE(controller->HasActiveAnimation()); + EXPECT_EQ(0.f, dummy.opacity()); + controller->Animate(1.0); + controller->UpdateState(events.get()); + EXPECT_TRUE(controller->HasActiveAnimation()); + EXPECT_EQ(1.f, dummy.opacity()); + controller->Animate(2.0); + controller->UpdateState(events.get()); + EXPECT_EQ(0.5f, dummy.opacity()); + EXPECT_FALSE(controller->HasActiveAnimation()); +} + +// Tests interrupting a transition with another transition. +TEST(LayerAnimationControllerTest, Interrupt) { + scoped_ptr events( + make_scoped_ptr(new AnimationEventsVector)); + FakeLayerAnimationValueObserver dummy; + scoped_refptr controller( + LayerAnimationController::Create(0)); + controller->AddObserver(&dummy); + controller->AddAnimation(CreateAnimation( + scoped_ptr(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(), + 1, + Animation::Opacity)); + controller->Animate(0.0); + controller->UpdateState(events.get()); + EXPECT_TRUE(controller->HasActiveAnimation()); + EXPECT_EQ(0.f, dummy.opacity()); + + scoped_ptr to_add(CreateAnimation( + scoped_ptr( + new FakeFloatTransition(1.0, 1.f, 0.5f)).Pass(), + 2, + Animation::Opacity)); + to_add->SetRunState(Animation::WaitingForNextTick, 0); + controller->AddAnimation(to_add.Pass()); + + // Since the animation was in the WaitingForNextTick state, it should start + // right in this call to animate. + controller->Animate(0.5); + controller->UpdateState(events.get()); + EXPECT_TRUE(controller->HasActiveAnimation()); + EXPECT_EQ(1.f, dummy.opacity()); + controller->Animate(1.5); + controller->UpdateState(events.get()); + EXPECT_EQ(0.5f, dummy.opacity()); + EXPECT_FALSE(controller->HasActiveAnimation()); +} + +// Tests scheduling two animations to run together when only one property is +// free. +TEST(LayerAnimationControllerTest, ScheduleTogetherWhenAPropertyIsBlocked) { + scoped_ptr events( + make_scoped_ptr(new AnimationEventsVector)); + FakeLayerAnimationValueObserver dummy; + scoped_refptr controller( + LayerAnimationController::Create(0)); + controller->AddObserver(&dummy); + + controller->AddAnimation(CreateAnimation( + scoped_ptr(new FakeTransformTransition(1)).Pass(), + 1, + Animation::Transform)); + controller->AddAnimation(CreateAnimation( + scoped_ptr(new FakeTransformTransition(1)).Pass(), + 2, + Animation::Transform)); + controller->AddAnimation(CreateAnimation( + scoped_ptr(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(), + 2, + Animation::Opacity)); + + controller->Animate(0.0); + controller->UpdateState(events.get()); + EXPECT_EQ(0.f, dummy.opacity()); + EXPECT_TRUE(controller->HasActiveAnimation()); + controller->Animate(1.0); + controller->UpdateState(events.get()); + // Should not have started the float transition yet. + EXPECT_TRUE(controller->HasActiveAnimation()); + EXPECT_EQ(0.f, dummy.opacity()); + // The float animation should have started at time 1 and should be done. + controller->Animate(2.0); + controller->UpdateState(events.get()); + EXPECT_EQ(1.f, 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(LayerAnimationControllerTest, ScheduleTogetherWithAnAnimWaiting) { + scoped_ptr events( + make_scoped_ptr(new AnimationEventsVector)); + FakeLayerAnimationValueObserver dummy; + scoped_refptr controller( + LayerAnimationController::Create(0)); + controller->AddObserver(&dummy); + + controller->AddAnimation(CreateAnimation( + scoped_ptr(new FakeTransformTransition(2)).Pass(), + 1, + Animation::Transform)); + controller->AddAnimation(CreateAnimation( + scoped_ptr(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(), + 1, + Animation::Opacity)); + controller->AddAnimation(CreateAnimation( + scoped_ptr( + new FakeFloatTransition(1.0, 1.f, 0.5f)).Pass(), + 2, + Animation::Opacity)); + + // Animations with id 1 should both start now. + controller->Animate(0.0); + controller->UpdateState(events.get()); + EXPECT_TRUE(controller->HasActiveAnimation()); + EXPECT_EQ(0.f, 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.0); + controller->UpdateState(events.get()); + // Should not have started the float transition yet. + EXPECT_TRUE(controller->HasActiveAnimation()); + EXPECT_EQ(1.f, dummy.opacity()); + + // The second opacity animation should start at time 2 and should be done by + // time 3. + controller->Animate(3.0); + controller->UpdateState(events.get()); + EXPECT_EQ(0.5f, dummy.opacity()); + EXPECT_FALSE(controller->HasActiveAnimation()); +} + +// Tests scheduling an animation to start in the future. +TEST(LayerAnimationControllerTest, ScheduleAnimation) { + scoped_ptr events( + make_scoped_ptr(new AnimationEventsVector)); + FakeLayerAnimationValueObserver dummy; + scoped_refptr controller( + LayerAnimationController::Create(0)); + controller->AddObserver(&dummy); + + scoped_ptr to_add(CreateAnimation( + scoped_ptr(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(), + 1, + Animation::Opacity)); + to_add->SetRunState(Animation::WaitingForStartTime, 0); + to_add->set_start_time(1.f); + controller->AddAnimation(to_add.Pass()); + + controller->Animate(0.0); + controller->UpdateState(events.get()); + EXPECT_TRUE(controller->HasActiveAnimation()); + EXPECT_EQ(0.f, dummy.opacity()); + controller->Animate(1.0); + controller->UpdateState(events.get()); + EXPECT_TRUE(controller->HasActiveAnimation()); + EXPECT_EQ(0.f, dummy.opacity()); + controller->Animate(2.0); + controller->UpdateState(events.get()); + EXPECT_EQ(1.f, dummy.opacity()); + EXPECT_FALSE(controller->HasActiveAnimation()); +} + +// Tests scheduling an animation to start in the future that's interrupting a +// running animation. +TEST(LayerAnimationControllerTest, + ScheduledAnimationInterruptsRunningAnimation) { + scoped_ptr events( + make_scoped_ptr(new AnimationEventsVector)); + FakeLayerAnimationValueObserver dummy; + scoped_refptr controller( + LayerAnimationController::Create(0)); + controller->AddObserver(&dummy); + + controller->AddAnimation(CreateAnimation( + scoped_ptr(new FakeFloatTransition(2.0, 0.f, 1.f)).Pass(), + 1, + Animation::Opacity)); + + scoped_ptr to_add(CreateAnimation( + scoped_ptr( + new FakeFloatTransition(1.0, 0.5f, 0.f)).Pass(), + 2, + Animation::Opacity)); + to_add->SetRunState(Animation::WaitingForStartTime, 0); + to_add->set_start_time(1.f); + controller->AddAnimation(to_add.Pass()); + + // First 2s opacity transition should start immediately. + controller->Animate(0.0); + controller->UpdateState(events.get()); + EXPECT_TRUE(controller->HasActiveAnimation()); + EXPECT_EQ(0.f, dummy.opacity()); + controller->Animate(0.5); + controller->UpdateState(events.get()); + EXPECT_TRUE(controller->HasActiveAnimation()); + EXPECT_EQ(0.25f, dummy.opacity()); + controller->Animate(1.0); + controller->UpdateState(events.get()); + EXPECT_TRUE(controller->HasActiveAnimation()); + EXPECT_EQ(0.5f, dummy.opacity()); + controller->Animate(2.0); + controller->UpdateState(events.get()); + EXPECT_EQ(0.f, 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(LayerAnimationControllerTest, + ScheduledAnimationInterruptsRunningAnimationWithAnimInQueue) { + scoped_ptr events( + make_scoped_ptr(new AnimationEventsVector)); + FakeLayerAnimationValueObserver dummy; + scoped_refptr controller( + LayerAnimationController::Create(0)); + controller->AddObserver(&dummy); + + controller->AddAnimation(CreateAnimation( + scoped_ptr(new FakeFloatTransition(2.0, 0.f, 1.f)).Pass(), + 1, + Animation::Opacity)); + + scoped_ptr to_add(CreateAnimation( + scoped_ptr( + new FakeFloatTransition(2.0, 0.5f, 0.f)).Pass(), + 2, + Animation::Opacity)); + to_add->SetRunState(Animation::WaitingForStartTime, 0); + to_add->set_start_time(1.f); + controller->AddAnimation(to_add.Pass()); + + controller->AddAnimation(CreateAnimation( + scoped_ptr( + new FakeFloatTransition(1.0, 0.f, 0.75f)).Pass(), + 3, + Animation::Opacity)); + + // First 2s opacity transition should start immediately. + controller->Animate(0.0); + controller->UpdateState(events.get()); + EXPECT_TRUE(controller->HasActiveAnimation()); + EXPECT_EQ(0.f, dummy.opacity()); + controller->Animate(0.5); + controller->UpdateState(events.get()); + EXPECT_TRUE(controller->HasActiveAnimation()); + EXPECT_EQ(0.25f, dummy.opacity()); + EXPECT_TRUE(controller->HasActiveAnimation()); + controller->Animate(1.0); + controller->UpdateState(events.get()); + EXPECT_TRUE(controller->HasActiveAnimation()); + EXPECT_EQ(0.5f, dummy.opacity()); + controller->Animate(3.0); + controller->UpdateState(events.get()); + EXPECT_TRUE(controller->HasActiveAnimation()); + EXPECT_EQ(0.f, dummy.opacity()); + controller->Animate(4.0); + controller->UpdateState(events.get()); + EXPECT_EQ(0.75f, dummy.opacity()); + EXPECT_FALSE(controller->HasActiveAnimation()); +} + +// Test that a looping animation loops and for the correct number of iterations. +TEST(LayerAnimationControllerTest, TrivialLooping) { + scoped_ptr events( + make_scoped_ptr(new AnimationEventsVector)); + FakeLayerAnimationValueObserver dummy; + scoped_refptr controller( + LayerAnimationController::Create(0)); + controller->AddObserver(&dummy); + + scoped_ptr to_add(CreateAnimation( + scoped_ptr(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(), + 1, + Animation::Opacity)); + to_add->set_iterations(3); + controller->AddAnimation(to_add.Pass()); + + controller->Animate(0.0); + controller->UpdateState(events.get()); + EXPECT_TRUE(controller->HasActiveAnimation()); + EXPECT_EQ(0.f, dummy.opacity()); + controller->Animate(1.25); + controller->UpdateState(events.get()); + EXPECT_TRUE(controller->HasActiveAnimation()); + EXPECT_EQ(0.25f, dummy.opacity()); + controller->Animate(1.75); + controller->UpdateState(events.get()); + EXPECT_TRUE(controller->HasActiveAnimation()); + EXPECT_EQ(0.75f, dummy.opacity()); + controller->Animate(2.25); + controller->UpdateState(events.get()); + EXPECT_TRUE(controller->HasActiveAnimation()); + EXPECT_EQ(0.25f, dummy.opacity()); + controller->Animate(2.75); + controller->UpdateState(events.get()); + EXPECT_TRUE(controller->HasActiveAnimation()); + EXPECT_EQ(0.75f, dummy.opacity()); + controller->Animate(3.0); + controller->UpdateState(events.get()); + EXPECT_FALSE(controller->HasActiveAnimation()); + EXPECT_EQ(1.f, dummy.opacity()); + + // Just be extra sure. + controller->Animate(4.0); + controller->UpdateState(events.get()); + EXPECT_EQ(1.f, dummy.opacity()); +} + +// Test that an infinitely looping animation does indeed go until aborted. +TEST(LayerAnimationControllerTest, InfiniteLooping) { + scoped_ptr events( + make_scoped_ptr(new AnimationEventsVector)); + FakeLayerAnimationValueObserver dummy; + scoped_refptr controller( + LayerAnimationController::Create(0)); + controller->AddObserver(&dummy); + + const int id = 1; + scoped_ptr to_add(CreateAnimation( + scoped_ptr(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(), + id, + Animation::Opacity)); + to_add->set_iterations(-1); + controller->AddAnimation(to_add.Pass()); + + controller->Animate(0.0); + controller->UpdateState(events.get()); + EXPECT_TRUE(controller->HasActiveAnimation()); + EXPECT_EQ(0.f, dummy.opacity()); + controller->Animate(1.25); + controller->UpdateState(events.get()); + EXPECT_TRUE(controller->HasActiveAnimation()); + EXPECT_EQ(0.25f, dummy.opacity()); + controller->Animate(1.75); + controller->UpdateState(events.get()); + EXPECT_TRUE(controller->HasActiveAnimation()); + EXPECT_EQ(0.75f, dummy.opacity()); + + controller->Animate(1073741824.25); + controller->UpdateState(events.get()); + EXPECT_TRUE(controller->HasActiveAnimation()); + EXPECT_EQ(0.25f, dummy.opacity()); + controller->Animate(1073741824.75); + controller->UpdateState(events.get()); + EXPECT_TRUE(controller->HasActiveAnimation()); + EXPECT_EQ(0.75f, dummy.opacity()); + + EXPECT_TRUE(controller->GetAnimation(id, Animation::Opacity)); + controller->GetAnimation(id, Animation::Opacity)->SetRunState( + Animation::Aborted, 0.75); + EXPECT_FALSE(controller->HasActiveAnimation()); + EXPECT_EQ(0.75f, dummy.opacity()); +} + +// Test that pausing and resuming work as expected. +TEST(LayerAnimationControllerTest, PauseResume) { + scoped_ptr events( + make_scoped_ptr(new AnimationEventsVector)); + FakeLayerAnimationValueObserver dummy; + scoped_refptr controller( + LayerAnimationController::Create(0)); + controller->AddObserver(&dummy); + + const int id = 1; + controller->AddAnimation(CreateAnimation( + scoped_ptr(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(), + id, + Animation::Opacity)); + + controller->Animate(0.0); + controller->UpdateState(events.get()); + EXPECT_TRUE(controller->HasActiveAnimation()); + EXPECT_EQ(0.f, dummy.opacity()); + controller->Animate(0.5); + controller->UpdateState(events.get()); + EXPECT_TRUE(controller->HasActiveAnimation()); + EXPECT_EQ(0.5f, dummy.opacity()); + + EXPECT_TRUE(controller->GetAnimation(id, Animation::Opacity)); + controller->GetAnimation(id, Animation::Opacity)->SetRunState( + Animation::Paused, 0.5); + + controller->Animate(1024); + controller->UpdateState(events.get()); + EXPECT_TRUE(controller->HasActiveAnimation()); + EXPECT_EQ(0.5f, dummy.opacity()); + + EXPECT_TRUE(controller->GetAnimation(id, Animation::Opacity)); + controller->GetAnimation(id, Animation::Opacity)->SetRunState( + Animation::Running, 1024); + + controller->Animate(1024.25); + controller->UpdateState(events.get()); + EXPECT_TRUE(controller->HasActiveAnimation()); + EXPECT_EQ(0.75f, dummy.opacity()); + controller->Animate(1024.5); + controller->UpdateState(events.get()); + EXPECT_FALSE(controller->HasActiveAnimation()); + EXPECT_EQ(1.f, dummy.opacity()); +} + +TEST(LayerAnimationControllerTest, AbortAGroupedAnimation) { + scoped_ptr events( + make_scoped_ptr(new AnimationEventsVector)); + FakeLayerAnimationValueObserver dummy; + scoped_refptr controller( + LayerAnimationController::Create(0)); + controller->AddObserver(&dummy); + + const int id = 1; + controller->AddAnimation(CreateAnimation( + scoped_ptr(new FakeTransformTransition(1)).Pass(), + id, + Animation::Transform)); + controller->AddAnimation(CreateAnimation( + scoped_ptr(new FakeFloatTransition(2.0, 0.f, 1.f)).Pass(), + id, + Animation::Opacity)); + controller->AddAnimation(CreateAnimation( + scoped_ptr( + new FakeFloatTransition(1.0, 1.f, 0.75f)).Pass(), + 2, + Animation::Opacity)); + + controller->Animate(0.0); + controller->UpdateState(events.get()); + EXPECT_TRUE(controller->HasActiveAnimation()); + EXPECT_EQ(0.f, dummy.opacity()); + controller->Animate(1.0); + controller->UpdateState(events.get()); + EXPECT_TRUE(controller->HasActiveAnimation()); + EXPECT_EQ(0.5f, dummy.opacity()); + + EXPECT_TRUE(controller->GetAnimation(id, Animation::Opacity)); + controller->GetAnimation(id, Animation::Opacity)->SetRunState( + Animation::Aborted, 1); + controller->Animate(1.0); + controller->UpdateState(events.get()); + EXPECT_TRUE(controller->HasActiveAnimation()); + EXPECT_EQ(1.f, dummy.opacity()); + controller->Animate(2.0); + controller->UpdateState(events.get()); + EXPECT_TRUE(!controller->HasActiveAnimation()); + EXPECT_EQ(0.75f, dummy.opacity()); +} + +TEST(LayerAnimationControllerTest, ForceSyncWhenSynchronizedStartTimeNeeded) { + FakeLayerAnimationValueObserver dummy_impl; + scoped_refptr controller_impl( + LayerAnimationController::Create(0)); + controller_impl->AddObserver(&dummy_impl); + scoped_ptr events( + make_scoped_ptr(new AnimationEventsVector)); + FakeLayerAnimationValueObserver dummy; + scoped_refptr controller( + LayerAnimationController::Create(0)); + controller->AddObserver(&dummy); + + scoped_ptr to_add(CreateAnimation( + scoped_ptr(new FakeFloatTransition(2.0, 0.f, 1.f)).Pass(), + 0, + Animation::Opacity)); + to_add->set_needs_synchronized_start_time(true); + controller->AddAnimation(to_add.Pass()); + + controller->Animate(0.0); + controller->UpdateState(events.get()); + EXPECT_TRUE(controller->HasActiveAnimation()); + Animation* active_animation = controller->GetAnimation(0, Animation::Opacity); + EXPECT_TRUE(active_animation); + EXPECT_TRUE(active_animation->needs_synchronized_start_time()); + + controller->set_force_sync(); + + controller->PushAnimationUpdatesTo(controller_impl.get()); + + active_animation = controller_impl->GetAnimation(0, Animation::Opacity); + EXPECT_TRUE(active_animation); + EXPECT_EQ(Animation::WaitingForTargetAvailability, + active_animation->run_state()); +} + +// Tests that skipping a call to updateState works as expected. +TEST(LayerAnimationControllerTest, SkipUpdateState) { + scoped_ptr events( + make_scoped_ptr(new AnimationEventsVector)); + FakeLayerAnimationValueObserver dummy; + scoped_refptr controller( + LayerAnimationController::Create(0)); + controller->AddObserver(&dummy); + + controller->AddAnimation(CreateAnimation( + scoped_ptr(new FakeTransformTransition(1)).Pass(), + 1, + Animation::Transform)); + + controller->Animate(0.0); + controller->UpdateState(events.get()); + + controller->AddAnimation(CreateAnimation( + scoped_ptr(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(), + 2, + Animation::Opacity)); + + // Animate but don't updateState. + controller->Animate(1.0); + + controller->Animate(2.0); + events.reset(new AnimationEventsVector); + controller->UpdateState(events.get()); + + // Should have one Started event and one Finished event. + EXPECT_EQ(2, events->size()); + EXPECT_NE((*events)[0].type, (*events)[1].type); + + // The float transition should still be at its starting point. + EXPECT_TRUE(controller->HasActiveAnimation()); + EXPECT_EQ(0.f, dummy.opacity()); + + controller->Animate(3.0); + controller->UpdateState(events.get()); + + // The float tranisition should now be done. + EXPECT_EQ(1.f, dummy.opacity()); + EXPECT_FALSE(controller->HasActiveAnimation()); +} + +} // namespace +} // namespace cc diff --git a/cc/animation/layer_animation_event_observer.h b/cc/animation/layer_animation_event_observer.h new file mode 100644 index 0000000..b20c590 --- /dev/null +++ b/cc/animation/layer_animation_event_observer.h @@ -0,0 +1,18 @@ +// 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. + +#ifndef CC_ANIMATION_LAYER_ANIMATION_EVENT_OBSERVER_H_ +#define CC_ANIMATION_LAYER_ANIMATION_EVENT_OBSERVER_H_ + +namespace cc { + +class CC_EXPORT LayerAnimationEventObserver { + public: + virtual void OnAnimationStarted(const AnimationEvent& event) = 0; +}; + +} // namespace cc + +#endif // CC_ANIMATION_LAYER_ANIMATION_EVENT_OBSERVER_H_ + diff --git a/cc/animation/layer_animation_value_observer.h b/cc/animation/layer_animation_value_observer.h new file mode 100644 index 0000000..9441c9e --- /dev/null +++ b/cc/animation/layer_animation_value_observer.h @@ -0,0 +1,23 @@ +// 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. + +#ifndef CC_ANIMATION_LAYER_ANIMATION_VALUE_OBSERVER_H_ +#define CC_ANIMATION_LAYER_ANIMATION_VALUE_OBSERVER_H_ + +namespace cc { + +class CC_EXPORT LayerAnimationValueObserver { + public: + virtual ~LayerAnimationValueObserver() { } + + virtual void OnOpacityAnimated(float) = 0; + virtual void OnTransformAnimated(const gfx::Transform&) = 0; + + virtual bool IsActive() const = 0; +}; + +} // namespace cc + +#endif // CC_ANIMATION_LAYER_ANIMATION_VALUE_OBSERVER_H_ + diff --git a/cc/animation/scrollbar_animation_controller.h b/cc/animation/scrollbar_animation_controller.h new file mode 100644 index 0000000..8c7aafe --- /dev/null +++ b/cc/animation/scrollbar_animation_controller.h @@ -0,0 +1,32 @@ +// 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. + +#ifndef CC_ANIMATION_SCROLLBAR_ANIMATION_CONTROLLER_H_ +#define CC_ANIMATION_SCROLLBAR_ANIMATION_CONTROLLER_H_ + +#include "base/time.h" +#include "cc/base/cc_export.h" +#include "ui/gfx/vector2d_f.h" + +namespace cc { + +// This abstract class represents the compositor-side analogy of ScrollbarAnimator. +// Individual platforms should subclass it to provide specialized implementation. +class CC_EXPORT ScrollbarAnimationController { +public: + virtual ~ScrollbarAnimationController() {} + + virtual bool isScrollGestureInProgress() const = 0; + virtual bool isAnimating() const = 0; + virtual base::TimeDelta delayBeforeStart(base::TimeTicks now) const = 0; + + virtual bool animate(base::TimeTicks) = 0; + virtual void didScrollGestureBegin() = 0; + virtual void didScrollGestureEnd(base::TimeTicks now) = 0; + virtual void didProgrammaticallyUpdateScroll(base::TimeTicks now) = 0; +}; + +} // namespace cc + +#endif // CC_ANIMATION_SCROLLBAR_ANIMATION_CONTROLLER_H_ diff --git a/cc/animation/scrollbar_animation_controller_linear_fade.cc b/cc/animation/scrollbar_animation_controller_linear_fade.cc new file mode 100644 index 0000000..63d2f6e --- /dev/null +++ b/cc/animation/scrollbar_animation_controller_linear_fade.cc @@ -0,0 +1,94 @@ +// 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/animation/scrollbar_animation_controller_linear_fade.h" + +#include "base/time.h" +#include "cc/layer_impl.h" + +namespace cc { + +scoped_ptr ScrollbarAnimationControllerLinearFade::create(LayerImpl* scrollLayer, base::TimeDelta fadeoutDelay, base::TimeDelta fadeoutLength) +{ + return make_scoped_ptr(new ScrollbarAnimationControllerLinearFade(scrollLayer, fadeoutDelay, fadeoutLength)); +} + +ScrollbarAnimationControllerLinearFade::ScrollbarAnimationControllerLinearFade(LayerImpl* scrollLayer, base::TimeDelta fadeoutDelay, base::TimeDelta fadeoutLength) + : ScrollbarAnimationController() + , m_scrollLayer(scrollLayer) + , m_scrollGestureInProgress(false) + , m_fadeoutDelay(fadeoutDelay) + , m_fadeoutLength(fadeoutLength) +{ +} + +ScrollbarAnimationControllerLinearFade::~ScrollbarAnimationControllerLinearFade() +{ +} + +bool ScrollbarAnimationControllerLinearFade::isScrollGestureInProgress() const +{ + return m_scrollGestureInProgress; +} + +bool ScrollbarAnimationControllerLinearFade::isAnimating() const +{ + return !m_lastAwakenTime.is_null(); +} + +base::TimeDelta ScrollbarAnimationControllerLinearFade::delayBeforeStart(base::TimeTicks now) const +{ + if (now > m_lastAwakenTime + m_fadeoutDelay) + return base::TimeDelta(); + return m_fadeoutDelay - (now - m_lastAwakenTime); +} + +bool ScrollbarAnimationControllerLinearFade::animate(base::TimeTicks now) +{ + float opacity = opacityAtTime(now); + m_scrollLayer->SetScrollbarOpacity(opacity); + if (!opacity) + m_lastAwakenTime = base::TimeTicks(); + return isAnimating() && delayBeforeStart(now) == base::TimeDelta(); +} + +void ScrollbarAnimationControllerLinearFade::didScrollGestureBegin() +{ + m_scrollLayer->SetScrollbarOpacity(1); + m_scrollGestureInProgress = true; + m_lastAwakenTime = base::TimeTicks(); +} + +void ScrollbarAnimationControllerLinearFade::didScrollGestureEnd(base::TimeTicks now) +{ + m_scrollGestureInProgress = false; + m_lastAwakenTime = now; +} + +void ScrollbarAnimationControllerLinearFade::didProgrammaticallyUpdateScroll(base::TimeTicks now) +{ + // Don't set m_scrollGestureInProgress as this scroll is not from a gesture + // and we won't receive ScrollEnd. + m_scrollLayer->SetScrollbarOpacity(1); + m_lastAwakenTime = now; +} + +float ScrollbarAnimationControllerLinearFade::opacityAtTime(base::TimeTicks now) +{ + if (m_scrollGestureInProgress) + return 1; + + if (m_lastAwakenTime.is_null()) + return 0; + + base::TimeDelta delta = now - m_lastAwakenTime; + + if (delta <= m_fadeoutDelay) + return 1; + if (delta < m_fadeoutDelay + m_fadeoutLength) + return (m_fadeoutDelay + m_fadeoutLength - delta).InSecondsF() / m_fadeoutLength.InSecondsF(); + return 0; +} + +} // namespace cc diff --git a/cc/animation/scrollbar_animation_controller_linear_fade.h b/cc/animation/scrollbar_animation_controller_linear_fade.h new file mode 100644 index 0000000..a126306 --- /dev/null +++ b/cc/animation/scrollbar_animation_controller_linear_fade.h @@ -0,0 +1,50 @@ +// 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. + +#ifndef CC_ANIMATION_SCROLLBAR_ANIMATION_CONTROLLER_LINEAR_FADE_H_ +#define CC_ANIMATION_SCROLLBAR_ANIMATION_CONTROLLER_LINEAR_FADE_H_ + +#include "base/memory/scoped_ptr.h" +#include "cc/animation/scrollbar_animation_controller.h" +#include "cc/base/cc_export.h" + +namespace cc { +class LayerImpl; + +class CC_EXPORT ScrollbarAnimationControllerLinearFade : public ScrollbarAnimationController { +public: + static scoped_ptr create(LayerImpl* scrollLayer, base::TimeDelta fadeoutDelay, base::TimeDelta fadeoutLength); + + virtual ~ScrollbarAnimationControllerLinearFade(); + + // ScrollbarAnimationController overrides. + virtual bool isScrollGestureInProgress() const OVERRIDE; + virtual bool isAnimating() const OVERRIDE; + virtual base::TimeDelta delayBeforeStart(base::TimeTicks now) const OVERRIDE; + + virtual bool animate(base::TimeTicks) OVERRIDE; + virtual void didScrollGestureBegin() OVERRIDE; + virtual void didScrollGestureEnd(base::TimeTicks now) OVERRIDE; + virtual void didProgrammaticallyUpdateScroll(base::TimeTicks now) OVERRIDE; + +protected: + ScrollbarAnimationControllerLinearFade(LayerImpl* scrollLayer, base::TimeDelta fadeoutDelay, base::TimeDelta fadeoutLength); + +private: + float opacityAtTime(base::TimeTicks); + + LayerImpl* m_scrollLayer; + + base::TimeTicks m_lastAwakenTime; + bool m_scrollGestureInProgress; + + base::TimeDelta m_fadeoutDelay; + base::TimeDelta m_fadeoutLength; + + double m_currentTimeForTesting; +}; + +} // namespace cc + +#endif // CC_ANIMATION_SCROLLBAR_ANIMATION_CONTROLLER_LINEAR_FADE_H_ diff --git a/cc/animation/scrollbar_animation_controller_linear_fade_unittest.cc b/cc/animation/scrollbar_animation_controller_linear_fade_unittest.cc new file mode 100644 index 0000000..26c32b2 --- /dev/null +++ b/cc/animation/scrollbar_animation_controller_linear_fade_unittest.cc @@ -0,0 +1,168 @@ +// 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/animation/scrollbar_animation_controller_linear_fade.h" + +#include "cc/scrollbar_layer_impl.h" +#include "cc/single_thread_proxy.h" +#include "cc/test/fake_impl_proxy.h" +#include "cc/test/fake_layer_tree_host_impl.h" +#include "cc/test/fake_web_scrollbar_theme_geometry.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace cc { +namespace { + +class ScrollbarAnimationControllerLinearFadeTest : public testing::Test { +public: + ScrollbarAnimationControllerLinearFadeTest() + : m_hostImpl(&m_proxy) + { + } + +protected: + virtual void SetUp() + { + m_scrollLayer = LayerImpl::Create(m_hostImpl.active_tree(), 1); + scoped_ptr geometry(ScrollbarGeometryFixedThumb::create(FakeWebScrollbarThemeGeometry::create(false))); + m_scrollbarLayer = ScrollbarLayerImpl::Create(m_hostImpl.active_tree(), 2, geometry.Pass()); + + m_scrollLayer->SetMaxScrollOffset(gfx::Vector2d(50, 50)); + m_scrollLayer->SetBounds(gfx::Size(50, 50)); + m_scrollLayer->SetHorizontalScrollbarLayer(m_scrollbarLayer.get()); + + m_scrollbarController = ScrollbarAnimationControllerLinearFade::create(m_scrollLayer.get(), base::TimeDelta::FromSeconds(2), base::TimeDelta::FromSeconds(3)); + } + + FakeImplProxy m_proxy; + FakeLayerTreeHostImpl m_hostImpl; + scoped_ptr m_scrollbarController; + scoped_ptr m_scrollLayer; + scoped_ptr m_scrollbarLayer; + +}; + +TEST_F(ScrollbarAnimationControllerLinearFadeTest, verifyHiddenInBegin) +{ + m_scrollbarController->animate(base::TimeTicks()); + EXPECT_FLOAT_EQ(0, m_scrollbarLayer->opacity()); +} + +TEST_F(ScrollbarAnimationControllerLinearFadeTest, verifyAwakenByScrollGesture) +{ + base::TimeTicks time; + time += base::TimeDelta::FromSeconds(1); + m_scrollbarController->didScrollGestureBegin(); + EXPECT_TRUE(m_scrollbarController->isScrollGestureInProgress()); + EXPECT_FALSE(m_scrollbarController->isAnimating()); + EXPECT_FLOAT_EQ(1, m_scrollbarLayer->opacity()); + + time += base::TimeDelta::FromSeconds(100); + m_scrollbarController->animate(time); + EXPECT_FLOAT_EQ(1, m_scrollbarLayer->opacity()); + m_scrollbarController->didScrollGestureEnd(time); + + EXPECT_FALSE(m_scrollbarController->isScrollGestureInProgress()); + EXPECT_TRUE(m_scrollbarController->isAnimating()); + EXPECT_EQ(2, m_scrollbarController->delayBeforeStart(time).InSeconds()); + + time += base::TimeDelta::FromSeconds(1); + m_scrollbarController->animate(time); + EXPECT_FLOAT_EQ(1, m_scrollbarLayer->opacity()); + + time += base::TimeDelta::FromSeconds(1); + m_scrollbarController->animate(time); + EXPECT_FLOAT_EQ(1, m_scrollbarLayer->opacity()); + + time += base::TimeDelta::FromSeconds(1); + m_scrollbarController->animate(time); + EXPECT_FLOAT_EQ(2.0f / 3.0f, m_scrollbarLayer->opacity()); + + time += base::TimeDelta::FromSeconds(1); + m_scrollbarController->animate(time); + EXPECT_FLOAT_EQ(1.0f / 3.0f, m_scrollbarLayer->opacity()); + + time += base::TimeDelta::FromSeconds(1); + + m_scrollbarController->didScrollGestureBegin(); + m_scrollbarController->didScrollGestureEnd(time); + + time += base::TimeDelta::FromSeconds(1); + m_scrollbarController->animate(time); + EXPECT_FLOAT_EQ(1, m_scrollbarLayer->opacity()); + + time += base::TimeDelta::FromSeconds(1); + m_scrollbarController->animate(time); + EXPECT_FLOAT_EQ(1, m_scrollbarLayer->opacity()); + + time += base::TimeDelta::FromSeconds(1); + m_scrollbarController->animate(time); + EXPECT_FLOAT_EQ(2.0f / 3.0f, m_scrollbarLayer->opacity()); + + time += base::TimeDelta::FromSeconds(1); + m_scrollbarController->animate(time); + EXPECT_FLOAT_EQ(1.0f / 3.0f, m_scrollbarLayer->opacity()); + + time += base::TimeDelta::FromSeconds(1); + m_scrollbarController->animate(time); + EXPECT_FLOAT_EQ(0, m_scrollbarLayer->opacity()); +} + +TEST_F(ScrollbarAnimationControllerLinearFadeTest, verifyAwakenByProgrammaticScroll) +{ + base::TimeTicks time; + time += base::TimeDelta::FromSeconds(1); + m_scrollbarController->didProgrammaticallyUpdateScroll(time); + EXPECT_FALSE(m_scrollbarController->isScrollGestureInProgress()); + EXPECT_TRUE(m_scrollbarController->isAnimating()); + EXPECT_EQ(2, m_scrollbarController->delayBeforeStart(time).InSeconds()); + m_scrollbarController->animate(time); + EXPECT_FLOAT_EQ(1, m_scrollbarLayer->opacity()); + + time += base::TimeDelta::FromSeconds(1); + m_scrollbarController->animate(time); + EXPECT_FLOAT_EQ(1, m_scrollbarLayer->opacity()); + m_scrollbarController->didProgrammaticallyUpdateScroll(time); + + time += base::TimeDelta::FromSeconds(1); + m_scrollbarController->animate(time); + EXPECT_FLOAT_EQ(1, m_scrollbarLayer->opacity()); + + time += base::TimeDelta::FromSeconds(1); + m_scrollbarController->animate(time); + EXPECT_FLOAT_EQ(1, m_scrollbarLayer->opacity()); + + time += base::TimeDelta::FromSeconds(1); + m_scrollbarController->animate(time); + EXPECT_FLOAT_EQ(2.0f / 3.0f, m_scrollbarLayer->opacity()); + + time += base::TimeDelta::FromSeconds(1); + m_scrollbarController->animate(time); + EXPECT_FLOAT_EQ(1.0f / 3.0f, m_scrollbarLayer->opacity()); + + time += base::TimeDelta::FromSeconds(1); + m_scrollbarController->didProgrammaticallyUpdateScroll(time); + time += base::TimeDelta::FromSeconds(1); + m_scrollbarController->animate(time); + EXPECT_FLOAT_EQ(1, m_scrollbarLayer->opacity()); + + time += base::TimeDelta::FromSeconds(1); + m_scrollbarController->animate(time); + EXPECT_FLOAT_EQ(1, m_scrollbarLayer->opacity()); + + time += base::TimeDelta::FromSeconds(1); + m_scrollbarController->animate(time); + EXPECT_FLOAT_EQ(2.0f / 3.0f, m_scrollbarLayer->opacity()); + + time += base::TimeDelta::FromSeconds(1); + m_scrollbarController->animate(time); + EXPECT_FLOAT_EQ(1.0f / 3.0f, m_scrollbarLayer->opacity()); + + time += base::TimeDelta::FromSeconds(1); + m_scrollbarController->animate(time); + EXPECT_FLOAT_EQ(0, m_scrollbarLayer->opacity()); +} + +} // namespace +} // namespace cc diff --git a/cc/animation_curve.cc b/cc/animation_curve.cc deleted file mode 100644 index 0fe49e9..0000000 --- a/cc/animation_curve.cc +++ /dev/null @@ -1,30 +0,0 @@ -// 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/animation_curve.h" - -#include "base/logging.h" - -namespace cc { - -const FloatAnimationCurve* AnimationCurve::ToFloatAnimationCurve() const { - DCHECK(Type() == AnimationCurve::Float); - return static_cast(this); -} - -AnimationCurve::CurveType FloatAnimationCurve::Type() const { - return Float; -} - -const TransformAnimationCurve* AnimationCurve::ToTransformAnimationCurve() - const { - DCHECK(Type() == AnimationCurve::Transform); - return static_cast(this); -} - -AnimationCurve::CurveType TransformAnimationCurve::Type() const { - return Transform; -} - -} // namespace cc diff --git a/cc/animation_curve.h b/cc/animation_curve.h deleted file mode 100644 index 0c54642..0000000 --- a/cc/animation_curve.h +++ /dev/null @@ -1,56 +0,0 @@ -// 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. - -#ifndef CC_ANIMATION_CURVE_H_ -#define CC_ANIMATION_CURVE_H_ - -#include "base/memory/scoped_ptr.h" -#include "cc/base/cc_export.h" -#include "ui/gfx/transform.h" - -namespace cc { - -class FloatAnimationCurve; -class TransformAnimationCurve; -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 CC_EXPORT AnimationCurve { - public: - enum CurveType { Float, Transform }; - - virtual ~AnimationCurve() {} - - virtual double Duration() const = 0; - virtual CurveType Type() const = 0; - virtual scoped_ptr Clone() const = 0; - - const FloatAnimationCurve* ToFloatAnimationCurve() const; - const TransformAnimationCurve* ToTransformAnimationCurve() const; -}; - -class CC_EXPORT FloatAnimationCurve : public AnimationCurve { - public: - virtual ~FloatAnimationCurve() {} - - virtual float GetValue(double t) const = 0; - - // Partial Animation implementation. - virtual CurveType Type() const OVERRIDE; -}; - -class CC_EXPORT TransformAnimationCurve : public AnimationCurve { - public: - virtual ~TransformAnimationCurve() {} - - virtual gfx::Transform GetValue(double t) const = 0; - - // Partial Animation implementation. - virtual CurveType Type() const OVERRIDE; -}; - -} // namespace cc - -#endif // CC_ANIMATION_CURVE_H_ diff --git a/cc/animation_events.h b/cc/animation_events.h deleted file mode 100644 index de1aa88..0000000 --- a/cc/animation_events.h +++ /dev/null @@ -1,43 +0,0 @@ -// 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. - -#ifndef CC_ANIMATION_EVENTS_H_ -#define CC_ANIMATION_EVENTS_H_ - -#include - -#include "cc/animation.h" -#include "ui/gfx/transform.h" - -namespace cc { - -struct AnimationEvent { - enum Type { Started, Finished, PropertyUpdate }; - - AnimationEvent(Type type, - int layer_id, - int group_id, - Animation::TargetProperty target_property, - double monotonic_time) - : type(type), - layer_id(layer_id), - group_id(group_id), - target_property(target_property), - monotonic_time(monotonic_time), - opacity(0.f) {} - - Type type; - int layer_id; - int group_id; - Animation::TargetProperty target_property; - double monotonic_time; - float opacity; - gfx::Transform transform; -}; - -typedef std::vector AnimationEventsVector; - -} // namespace cc - -#endif // CC_ANIMATION_EVENTS_H_ diff --git a/cc/animation_id_provider.cc b/cc/animation_id_provider.cc deleted file mode 100644 index bf30283..0000000 --- a/cc/animation_id_provider.cc +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) 2013 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/animation_id_provider.h" - -namespace cc { - -int AnimationIdProvider::NextAnimationId() { - static int next_animation_id = 1; - return next_animation_id++; -} - -int AnimationIdProvider::NextGroupId() { - static int next_group_id = 1; - return next_group_id++; -} - -} // namespace cc diff --git a/cc/animation_id_provider.h b/cc/animation_id_provider.h deleted file mode 100644 index faf8509..0000000 --- a/cc/animation_id_provider.h +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) 2013 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. - -#ifndef CC_ANIMATION_ID_PROVIDER -#define CC_ANIMATION_ID_PROVIDER - -#include "cc/base/cc_export.h" - -namespace cc { - -class CC_EXPORT AnimationIdProvider { - public: - // These functions each return monotonically increasing values. - static int NextAnimationId(); - static int NextGroupId(); -}; - -} - -#endif // CC_ANIMATION_ID_PROVIDER diff --git a/cc/animation_registrar.cc b/cc/animation_registrar.cc deleted file mode 100644 index 6b6629e..0000000 --- a/cc/animation_registrar.cc +++ /dev/null @@ -1,51 +0,0 @@ -// 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/animation_registrar.h" - -#include "cc/layer_animation_controller.h" - -namespace cc { - -AnimationRegistrar::AnimationRegistrar() { } -AnimationRegistrar::~AnimationRegistrar() -{ - AnimationControllerMap copy = all_animation_controllers_; - for (AnimationControllerMap::iterator iter = copy.begin(); iter != copy.end(); ++iter) - (*iter).second->SetAnimationRegistrar(NULL); -} - -scoped_refptr -AnimationRegistrar::GetAnimationControllerForId(int id) -{ - scoped_refptr toReturn; - if (!ContainsKey(all_animation_controllers_, id)) { - toReturn = LayerAnimationController::Create(id); - toReturn->SetAnimationRegistrar(this); - all_animation_controllers_[id] = toReturn.get(); - } else - toReturn = all_animation_controllers_[id]; - return toReturn; -} - -void AnimationRegistrar::DidActivateAnimationController(LayerAnimationController* controller) { - active_animation_controllers_[controller->id()] = controller; -} - -void AnimationRegistrar::DidDeactivateAnimationController(LayerAnimationController* controller) { - if (ContainsKey(active_animation_controllers_, controller->id())) - active_animation_controllers_.erase(controller->id()); -} - -void AnimationRegistrar::RegisterAnimationController(LayerAnimationController* controller) { - all_animation_controllers_[controller->id()] = controller; -} - -void AnimationRegistrar::UnregisterAnimationController(LayerAnimationController* controller) { - if (ContainsKey(all_animation_controllers_, controller->id())) - all_animation_controllers_.erase(controller->id()); - DidDeactivateAnimationController(controller); -} - -} // namespace cc diff --git a/cc/animation_registrar.h b/cc/animation_registrar.h deleted file mode 100644 index c51a126..0000000 --- a/cc/animation_registrar.h +++ /dev/null @@ -1,65 +0,0 @@ -// 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. - -#ifndef CC_ANIMATION_REGISTRAR_H_ -#define CC_ANIMATION_REGISTRAR_H_ - -#include "base/hash_tables.h" -#include "base/memory/ref_counted.h" -#include "base/memory/scoped_ptr.h" -#include "cc/base/cc_export.h" - -namespace cc { - -class LayerAnimationController; - -class CC_EXPORT AnimationRegistrar { - public: - typedef base::hash_map AnimationControllerMap; - - static scoped_ptr create() { - return make_scoped_ptr(new AnimationRegistrar()); - } - - virtual ~AnimationRegistrar(); - - // If an animation has been registered for the given id, return it. Otherwise - // creates a new one and returns a scoped_refptr to it. - scoped_refptr GetAnimationControllerForId(int id); - - // Registers the given animation controller as active. An active animation - // controller is one that has a running animation that needs to be ticked. - void DidActivateAnimationController(LayerAnimationController*); - - // Unregisters the given animation controller. When this happens, the - // animation controller will no longer be ticked (since it's not active). It - // is not an error to call this function with a deactivated controller. - void DidDeactivateAnimationController(LayerAnimationController*); - - // Registers the given controller as alive. - void RegisterAnimationController(LayerAnimationController*); - - // Unregisters the given controller as alive. - void UnregisterAnimationController(LayerAnimationController*); - - const AnimationControllerMap& active_animation_controllers() const { - return active_animation_controllers_; - } - - const AnimationControllerMap& all_animation_controllers() const { - return all_animation_controllers_; - } - - private: - AnimationRegistrar(); - - AnimationControllerMap active_animation_controllers_; - AnimationControllerMap all_animation_controllers_; - - DISALLOW_COPY_AND_ASSIGN(AnimationRegistrar); -}; - -} // namespace cc - -#endif // CC_ANIMATION_REGISTRAR_H_ diff --git a/cc/animation_unittest.cc b/cc/animation_unittest.cc deleted file mode 100644 index 638552d..0000000 --- a/cc/animation_unittest.cc +++ /dev/null @@ -1,205 +0,0 @@ -// 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/animation.h" - -#include "cc/test/animation_test_common.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace cc { -namespace { - -scoped_ptr CreateAnimation(int iterations, double duration) { - scoped_ptr to_return(Animation::Create( - make_scoped_ptr( - new FakeFloatAnimationCurve(duration)).PassAs(), - 0, - 1, - Animation::Opacity)); - to_return->set_iterations(iterations); - return to_return.Pass(); -} - -scoped_ptr CreateAnimation(int iterations) { - return CreateAnimation(iterations, 1); -} - -TEST(AnimationTest, TrimTimeZeroIterations) { - scoped_ptr anim(CreateAnimation(0)); - EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(-1.0)); - EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(0.0)); - EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(1.0)); -} - -TEST(AnimationTest, TrimTimeOneIteration) { - scoped_ptr anim(CreateAnimation(1)); - EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(-1.0)); - EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(0.0)); - EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(1.0)); - EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(2.0)); -} - -TEST(AnimationTest, TrimTimeInfiniteIterations) { - scoped_ptr anim(CreateAnimation(-1)); - EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(0.0)); - EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(0.5)); - EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(1.0)); - EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(1.5)); -} - -TEST(AnimationTest, TrimTimeAlternating) { - scoped_ptr anim(CreateAnimation(-1)); - anim->set_alternates_direction(true); - EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(0.0)); - EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(0.5)); - EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(1.0)); - EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(1.25)); -} - -TEST(AnimationTest, TrimTimeStartTime) { - scoped_ptr anim(CreateAnimation(1)); - anim->set_start_time(4); - EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(0.0)); - EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(4.0)); - EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(4.5)); - EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(5.0)); - EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(6.0)); -} - -TEST(AnimationTest, TrimTimeTimeOffset) { - scoped_ptr anim(CreateAnimation(1)); - anim->set_time_offset(4); - anim->set_start_time(4); - EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(0.0)); - EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(0.5)); - EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(1.0)); - EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(1.0)); -} - -TEST(AnimationTest, TrimTimePauseResume) { - scoped_ptr anim(CreateAnimation(1)); - anim->SetRunState(Animation::Running, 0.0); - EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(0.0)); - EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(0.5)); - anim->SetRunState(Animation::Paused, 0.5); - EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(1024.0)); - anim->SetRunState(Animation::Running, 1024.0); - EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(1024.0)); - EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(1024.5)); -} - -TEST(AnimationTest, TrimTimeSuspendResume) { - scoped_ptr anim(CreateAnimation(1)); - anim->SetRunState(Animation::Running, 0.0); - EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(0.0)); - EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(0.5)); - anim->Suspend(0.5); - EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(1024.0)); - anim->Resume(1024); - EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(1024.0)); - EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(1024.5)); -} - -TEST(AnimationTest, TrimTimeZeroDuration) { - scoped_ptr anim(CreateAnimation(0, 0)); - anim->SetRunState(Animation::Running, 0.0); - EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(-1.0)); - EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(0.0)); - EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(1.0)); -} - -TEST(AnimationTest, IsFinishedAtZeroIterations) { - scoped_ptr anim(CreateAnimation(0)); - anim->SetRunState(Animation::Running, 0.0); - EXPECT_FALSE(anim->IsFinishedAt(-1.0)); - EXPECT_TRUE(anim->IsFinishedAt(0.0)); - EXPECT_TRUE(anim->IsFinishedAt(1.0)); -} - -TEST(AnimationTest, IsFinishedAtOneIteration) { - scoped_ptr anim(CreateAnimation(1)); - anim->SetRunState(Animation::Running, 0.0); - EXPECT_FALSE(anim->IsFinishedAt(-1.0)); - EXPECT_FALSE(anim->IsFinishedAt(0.0)); - EXPECT_TRUE(anim->IsFinishedAt(1.0)); - EXPECT_TRUE(anim->IsFinishedAt(2.0)); -} - -TEST(AnimationTest, IsFinishedAtInfiniteIterations) { - scoped_ptr anim(CreateAnimation(-1)); - anim->SetRunState(Animation::Running, 0.0); - EXPECT_FALSE(anim->IsFinishedAt(0.0)); - EXPECT_FALSE(anim->IsFinishedAt(0.5)); - EXPECT_FALSE(anim->IsFinishedAt(1.0)); - EXPECT_FALSE(anim->IsFinishedAt(1.5)); -} - -TEST(AnimationTest, IsFinishedAtNotRunning) { - scoped_ptr anim(CreateAnimation(0)); - anim->SetRunState(Animation::Running, 0.0); - EXPECT_TRUE(anim->IsFinishedAt(0.0)); - anim->SetRunState(Animation::Paused, 0.0); - EXPECT_FALSE(anim->IsFinishedAt(0.0)); - anim->SetRunState(Animation::WaitingForNextTick, 0.0); - EXPECT_FALSE(anim->IsFinishedAt(0.0)); - anim->SetRunState(Animation::WaitingForTargetAvailability, 0.0); - EXPECT_FALSE(anim->IsFinishedAt(0.0)); - anim->SetRunState(Animation::WaitingForStartTime, 0.0); - EXPECT_FALSE(anim->IsFinishedAt(0.0)); - anim->SetRunState(Animation::Finished, 0.0); - EXPECT_TRUE(anim->IsFinishedAt(0.0)); - anim->SetRunState(Animation::Aborted, 0.0); - EXPECT_TRUE(anim->IsFinishedAt(0.0)); -} - -TEST(AnimationTest, IsFinished) { - scoped_ptr anim(CreateAnimation(1)); - anim->SetRunState(Animation::Running, 0.0); - EXPECT_FALSE(anim->is_finished()); - anim->SetRunState(Animation::Paused, 0.0); - EXPECT_FALSE(anim->is_finished()); - anim->SetRunState(Animation::WaitingForNextTick, 0.0); - EXPECT_FALSE(anim->is_finished()); - anim->SetRunState(Animation::WaitingForTargetAvailability, 0.0); - EXPECT_FALSE(anim->is_finished()); - anim->SetRunState(Animation::WaitingForStartTime, 0.0); - EXPECT_FALSE(anim->is_finished()); - anim->SetRunState(Animation::Finished, 0.0); - EXPECT_TRUE(anim->is_finished()); - anim->SetRunState(Animation::Aborted, 0.0); - EXPECT_TRUE(anim->is_finished()); -} - -TEST(AnimationTest, IsFinishedNeedsSynchronizedStartTime) { - scoped_ptr anim(CreateAnimation(1)); - anim->SetRunState(Animation::Running, 2.0); - EXPECT_FALSE(anim->is_finished()); - anim->SetRunState(Animation::Paused, 2.0); - EXPECT_FALSE(anim->is_finished()); - anim->SetRunState(Animation::WaitingForNextTick, 2.0); - EXPECT_FALSE(anim->is_finished()); - anim->SetRunState(Animation::WaitingForTargetAvailability, 2.0); - EXPECT_FALSE(anim->is_finished()); - anim->SetRunState(Animation::WaitingForStartTime, 2.0); - EXPECT_FALSE(anim->is_finished()); - anim->SetRunState(Animation::Finished, 0.0); - EXPECT_TRUE(anim->is_finished()); - anim->SetRunState(Animation::Aborted, 0.0); - EXPECT_TRUE(anim->is_finished()); -} - -TEST(AnimationTest, RunStateChangesIgnoredWhileSuspended) { - scoped_ptr anim(CreateAnimation(1)); - anim->Suspend(0); - EXPECT_EQ(Animation::Paused, anim->run_state()); - anim->SetRunState(Animation::Running, 0.0); - EXPECT_EQ(Animation::Paused, anim->run_state()); - anim->Resume(0); - anim->SetRunState(Animation::Running, 0.0); - EXPECT_EQ(Animation::Running, anim->run_state()); -} - -} // namespace -} // namespace cc diff --git a/cc/cc.gyp b/cc/cc.gyp index fb27f49..730ce44 100644 --- a/cc/cc.gyp +++ b/cc/cc.gyp @@ -5,15 +5,15 @@ { 'variables': { 'cc_source_files': [ - 'animation.cc', - 'animation.h', - 'animation_curve.cc', - 'animation_curve.h', - 'animation_events.h', - 'animation_id_provider.cc', - 'animation_id_provider.h', - 'animation_registrar.cc', - 'animation_registrar.h', + 'animation/animation.cc', + 'animation/animation.h', + 'animation/animation_curve.cc', + 'animation/animation_curve.h', + 'animation/animation_events.h', + 'animation/animation_id_provider.cc', + 'animation/animation_id_provider.h', + 'animation/animation_registrar.cc', + 'animation/animation_registrar.h', 'append_quads_data.h', 'bitmap_content_layer_updater.cc', 'bitmap_content_layer_updater.h', @@ -92,15 +92,15 @@ 'io_surface_layer.h', 'io_surface_layer_impl.cc', 'io_surface_layer_impl.h', - 'keyframed_animation_curve.cc', - 'keyframed_animation_curve.h', + 'animation/keyframed_animation_curve.cc', + 'animation/keyframed_animation_curve.h', 'latency_info.h', 'layer.cc', 'layer.h', - 'layer_animation_controller.cc', - 'layer_animation_controller.h', - 'layer_animation_event_observer.h', - 'layer_animation_value_observer.h', + 'animation/layer_animation_controller.cc', + 'animation/layer_animation_controller.h', + 'animation/layer_animation_event_observer.h', + 'animation/layer_animation_value_observer.h', 'layer_impl.cc', 'layer_impl.h', 'layer_iterator.cc', @@ -236,9 +236,9 @@ 'base/scoped_ptr_vector.h', 'scoped_resource.cc', 'scoped_resource.h', - 'scrollbar_animation_controller.h', - 'scrollbar_animation_controller_linear_fade.cc', - 'scrollbar_animation_controller_linear_fade.h', + 'animation/scrollbar_animation_controller.h', + 'animation/scrollbar_animation_controller_linear_fade.cc', + 'animation/scrollbar_animation_controller_linear_fade.h', 'scrollbar_geometry_fixed_thumb.cc', 'scrollbar_geometry_fixed_thumb.h', 'scrollbar_geometry_stub.cc', diff --git a/cc/cc_tests.gyp b/cc/cc_tests.gyp index 7ba94c7..a4e010d 100644 --- a/cc/cc_tests.gyp +++ b/cc/cc_tests.gyp @@ -6,7 +6,7 @@ 'variables': { 'chromium_code': 0, 'cc_unit_tests_source_files': [ - 'animation_unittest.cc', + 'animation/animation_unittest.cc', 'content_layer_unittest.cc', 'contents_scaling_layer_unittest.cc', 'damage_tracker_unittest.cc', @@ -20,8 +20,8 @@ 'gl_renderer_pixeltest.cc', 'base/hash_pair_unittest.cc', 'heads_up_display_unittest.cc', - 'keyframed_animation_curve_unittest.cc', - 'layer_animation_controller_unittest.cc', + 'animation/keyframed_animation_curve_unittest.cc', + 'animation/layer_animation_controller_unittest.cc', 'layer_impl_unittest.cc', 'layer_iterator_unittest.cc', 'layer_quad_unittest.cc', @@ -54,7 +54,7 @@ 'scheduler_state_machine_unittest.cc', 'scheduler_unittest.cc', 'scoped_resource_unittest.cc', - 'scrollbar_animation_controller_linear_fade_unittest.cc', + 'animation/scrollbar_animation_controller_linear_fade_unittest.cc', 'scrollbar_layer_unittest.cc', 'software_renderer_unittest.cc', 'solid_color_layer_impl_unittest.cc', diff --git a/cc/keyframed_animation_curve.cc b/cc/keyframed_animation_curve.cc deleted file mode 100644 index 5473f4e..0000000 --- a/cc/keyframed_animation_curve.cc +++ /dev/null @@ -1,200 +0,0 @@ -// 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/keyframed_animation_curve.h" - -namespace cc { - -namespace { - -template -void InsertKeyframe(scoped_ptr keyframe, - ScopedPtrVector& keyframes) { - // Usually, the keyframes will be added in order, so this loop would be - // unnecessary and we should skip it if possible. - if (!keyframes.empty() && keyframe->Time() < keyframes.back()->Time()) { - for (size_t i = 0; i < keyframes.size(); ++i) { - if (keyframe->Time() < keyframes[i]->Time()) { - keyframes.insert(keyframes.begin() + i, keyframe.Pass()); - return; - } - } - } - - keyframes.push_back(keyframe.Pass()); -} - -scoped_ptr CloneTimingFunction( - const TimingFunction* timing_function) { - DCHECK(timing_function); - scoped_ptr curve(timing_function->Clone()); - return scoped_ptr( - static_cast(curve.release())); -} - -} // namespace - -Keyframe::Keyframe(double time, scoped_ptr timing_function) - : time_(time), - timing_function_(timing_function.Pass()) {} - -Keyframe::~Keyframe() {} - -double Keyframe::Time() const { - return time_; -} - -scoped_ptr FloatKeyframe::Create( - double time, - float value, - scoped_ptr timing_function) { - return make_scoped_ptr( - new FloatKeyframe(time, value, timing_function.Pass())); -} - -FloatKeyframe::FloatKeyframe(double time, - float value, - scoped_ptr timing_function) - : Keyframe(time, timing_function.Pass()), - value_(value) {} - -FloatKeyframe::~FloatKeyframe() {} - -float FloatKeyframe::Value() const { - return value_; -} - -scoped_ptr FloatKeyframe::Clone() const { - scoped_ptr func; - if (timing_function()) - func = CloneTimingFunction(timing_function()); - return FloatKeyframe::Create(Time(), Value(), func.Pass()); -} - -scoped_ptr TransformKeyframe::Create( - double time, - const TransformOperations& value, - scoped_ptr timing_function) { - return make_scoped_ptr( - new TransformKeyframe(time, value, timing_function.Pass())); -} - -TransformKeyframe::TransformKeyframe(double time, - const TransformOperations& value, - scoped_ptr timing_function) - : Keyframe(time, timing_function.Pass()), - value_(value) {} - -TransformKeyframe::~TransformKeyframe() {} - -const TransformOperations& TransformKeyframe::Value() const { - return value_; -} - -scoped_ptr TransformKeyframe::Clone() const { - scoped_ptr func; - if (timing_function()) - func = CloneTimingFunction(timing_function()); - return TransformKeyframe::Create(Time(), Value(), func.Pass()); -} - -scoped_ptr KeyframedFloatAnimationCurve:: - Create() { - return make_scoped_ptr(new KeyframedFloatAnimationCurve); -} - -KeyframedFloatAnimationCurve::KeyframedFloatAnimationCurve() {} - -KeyframedFloatAnimationCurve::~KeyframedFloatAnimationCurve() {} - -void KeyframedFloatAnimationCurve::AddKeyframe( - scoped_ptr keyframe) { - InsertKeyframe(keyframe.Pass(), keyframes_); -} - -double KeyframedFloatAnimationCurve::Duration() const { - return keyframes_.back()->Time() - keyframes_.front()->Time(); -} - -scoped_ptr KeyframedFloatAnimationCurve::Clone() const { - scoped_ptr to_return( - KeyframedFloatAnimationCurve::Create()); - for (size_t i = 0; i < keyframes_.size(); ++i) - to_return->AddKeyframe(keyframes_[i]->Clone()); - return to_return.PassAs(); -} - -float KeyframedFloatAnimationCurve::GetValue(double t) const { - if (t <= keyframes_.front()->Time()) - return keyframes_.front()->Value(); - - if (t >= keyframes_.back()->Time()) - return keyframes_.back()->Value(); - - size_t i = 0; - for (; i < keyframes_.size() - 1; ++i) { - if (t < keyframes_[i+1]->Time()) - break; - } - - float progress = - static_cast((t - keyframes_[i]->Time()) / - (keyframes_[i+1]->Time() - keyframes_[i]->Time())); - - if (keyframes_[i]->timing_function()) - progress = keyframes_[i]->timing_function()->GetValue(progress); - - return keyframes_[i]->Value() + - (keyframes_[i+1]->Value() - keyframes_[i]->Value()) * progress; -} - -scoped_ptr KeyframedTransformAnimationCurve:: - Create() { - return make_scoped_ptr(new KeyframedTransformAnimationCurve); -} - -KeyframedTransformAnimationCurve::KeyframedTransformAnimationCurve() {} - -KeyframedTransformAnimationCurve::~KeyframedTransformAnimationCurve() {} - -void KeyframedTransformAnimationCurve::AddKeyframe( - scoped_ptr keyframe) { - InsertKeyframe(keyframe.Pass(), keyframes_); -} - -double KeyframedTransformAnimationCurve::Duration() const { - return keyframes_.back()->Time() - keyframes_.front()->Time(); -} - -scoped_ptr KeyframedTransformAnimationCurve::Clone() const { - scoped_ptr to_return( - KeyframedTransformAnimationCurve::Create()); - for (size_t i = 0; i < keyframes_.size(); ++i) - to_return->AddKeyframe(keyframes_[i]->Clone()); - return to_return.PassAs(); -} - -gfx::Transform KeyframedTransformAnimationCurve::GetValue(double t) const { - if (t <= keyframes_.front()->Time()) - return keyframes_.front()->Value().Apply(); - - if (t >= keyframes_.back()->Time()) - return keyframes_.back()->Value().Apply(); - - size_t i = 0; - for (; i < keyframes_.size() - 1; ++i) { - if (t < keyframes_[i+1]->Time()) - break; - } - - double progress = (t - keyframes_[i]->Time()) / - (keyframes_[i+1]->Time() - keyframes_[i]->Time()); - - if (keyframes_[i]->timing_function()) - progress = keyframes_[i]->timing_function()->GetValue(progress); - - return keyframes_[i+1]->Value().Blend(keyframes_[i]->Value(), progress); -} - -} // namespace cc diff --git a/cc/keyframed_animation_curve.h b/cc/keyframed_animation_curve.h deleted file mode 100644 index 3414927..0000000 --- a/cc/keyframed_animation_curve.h +++ /dev/null @@ -1,129 +0,0 @@ -// 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. - -#ifndef CC_KEYFRAMED_ANIMATION_CURVE_H_ -#define CC_KEYFRAMED_ANIMATION_CURVE_H_ - -#include "cc/animation_curve.h" -#include "cc/base/cc_export.h" -#include "cc/base/scoped_ptr_vector.h" -#include "cc/timing_function.h" -#include "cc/transform_operations.h" - -namespace cc { - -class CC_EXPORT Keyframe { - public: - double Time() const; - const TimingFunction* timing_function() const { - return timing_function_.get(); - } - - protected: - Keyframe(double time, scoped_ptr timing_function); - virtual ~Keyframe(); - - private: - double time_; - scoped_ptr timing_function_; - - DISALLOW_COPY_AND_ASSIGN(Keyframe); -}; - -class CC_EXPORT FloatKeyframe : public Keyframe { - public: - static scoped_ptr Create( - double time, - float value, - scoped_ptr timing_function); - virtual ~FloatKeyframe(); - - float Value() const; - - scoped_ptr Clone() const; - - private: - FloatKeyframe(double time, - float value, - scoped_ptr timing_function); - - float value_; -}; - -class CC_EXPORT TransformKeyframe : public Keyframe { - public: - static scoped_ptr Create( - double time, - const TransformOperations& value, - scoped_ptr timing_function); - virtual ~TransformKeyframe(); - - const TransformOperations& Value() const; - - scoped_ptr Clone() const; - - private: - TransformKeyframe( - double time, - const TransformOperations& value, - scoped_ptr timing_function); - - TransformOperations value_; -}; - -class CC_EXPORT KeyframedFloatAnimationCurve : public FloatAnimationCurve { - public: - // It is required that the keyframes be sorted by time. - static scoped_ptr Create(); - - virtual ~KeyframedFloatAnimationCurve(); - - void AddKeyframe(scoped_ptr keyframe); - - // AnimationCurve implementation - virtual double Duration() const OVERRIDE; - virtual scoped_ptr Clone() const OVERRIDE; - - // FloatAnimationCurve implementation - virtual float GetValue(double t) const OVERRIDE; - - private: - KeyframedFloatAnimationCurve(); - - // Always sorted in order of increasing time. No two keyframes have the - // same time. - ScopedPtrVector keyframes_; - - DISALLOW_COPY_AND_ASSIGN(KeyframedFloatAnimationCurve); -}; - -class CC_EXPORT KeyframedTransformAnimationCurve : public TransformAnimationCurve { - public: - // It is required that the keyframes be sorted by time. - static scoped_ptr Create(); - - virtual ~KeyframedTransformAnimationCurve(); - - void AddKeyframe(scoped_ptr keyframe); - - // AnimationCurve implementation - virtual double Duration() const OVERRIDE; - virtual scoped_ptr Clone() const OVERRIDE; - - // TransformAnimationCurve implementation - virtual gfx::Transform GetValue(double t) const OVERRIDE; - - private: - KeyframedTransformAnimationCurve(); - - // Always sorted in order of increasing time. No two keyframes have the - // same time. - ScopedPtrVector keyframes_; - - DISALLOW_COPY_AND_ASSIGN(KeyframedTransformAnimationCurve); -}; - -} // namespace cc - -#endif // CC_KEYFRAMED_ANIMATION_CURVE_H_ diff --git a/cc/keyframed_animation_curve_unittest.cc b/cc/keyframed_animation_curve_unittest.cc deleted file mode 100644 index 543edc6..0000000 --- a/cc/keyframed_animation_curve_unittest.cc +++ /dev/null @@ -1,243 +0,0 @@ -// 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/keyframed_animation_curve.h" - -#include "cc/transform_operations.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace cc { -namespace { - -void expectTranslateX(double translateX, const gfx::Transform& transform) -{ - EXPECT_FLOAT_EQ(translateX, transform.matrix().getDouble(0, 3)); -} - -// Tests that a float animation with one keyframe works as expected. -TEST(KeyframedAnimationCurveTest, OneFloatKeyframe) -{ - scoped_ptr curve( - KeyframedFloatAnimationCurve::Create()); - curve->AddKeyframe( - FloatKeyframe::Create(0.0, 2.f, scoped_ptr())); - EXPECT_FLOAT_EQ(2.f, curve->GetValue(-1.f)); - EXPECT_FLOAT_EQ(2.f, curve->GetValue(0.f)); - EXPECT_FLOAT_EQ(2.f, curve->GetValue(0.5f)); - EXPECT_FLOAT_EQ(2.f, curve->GetValue(1.f)); - EXPECT_FLOAT_EQ(2.f, curve->GetValue(2.f)); -} - -// Tests that a float animation with two keyframes works as expected. -TEST(KeyframedAnimationCurveTest, TwoFloatKeyframe) -{ - scoped_ptr curve( - KeyframedFloatAnimationCurve::Create()); - curve->AddKeyframe( - FloatKeyframe::Create(0.0, 2.f, scoped_ptr())); - curve->AddKeyframe( - FloatKeyframe::Create(1.0, 4.f, scoped_ptr())); - EXPECT_FLOAT_EQ(2.f, curve->GetValue(-1.f)); - EXPECT_FLOAT_EQ(2.f, curve->GetValue(0.f)); - EXPECT_FLOAT_EQ(3.f, curve->GetValue(0.5f)); - EXPECT_FLOAT_EQ(4.f, curve->GetValue(1.f)); - EXPECT_FLOAT_EQ(4.f, curve->GetValue(2.f)); -} - -// Tests that a float animation with three keyframes works as expected. -TEST(KeyframedAnimationCurveTest, ThreeFloatKeyframe) -{ - scoped_ptr curve( - KeyframedFloatAnimationCurve::Create()); - curve->AddKeyframe( - FloatKeyframe::Create(0.0, 2.f, scoped_ptr())); - curve->AddKeyframe( - FloatKeyframe::Create(1.0, 4.f, scoped_ptr())); - curve->AddKeyframe( - FloatKeyframe::Create(2.0, 8.f, scoped_ptr())); - EXPECT_FLOAT_EQ(2.f, curve->GetValue(-1.f)); - EXPECT_FLOAT_EQ(2.f, curve->GetValue(0.f)); - EXPECT_FLOAT_EQ(3.f, curve->GetValue(0.5f)); - EXPECT_FLOAT_EQ(4.f, curve->GetValue(1.f)); - EXPECT_FLOAT_EQ(6.f, curve->GetValue(1.5f)); - EXPECT_FLOAT_EQ(8.f, curve->GetValue(2.f)); - EXPECT_FLOAT_EQ(8.f, curve->GetValue(3.f)); -} - -// Tests that a float animation with multiple keys at a given time works sanely. -TEST(KeyframedAnimationCurveTest, RepeatedFloatKeyTimes) -{ - scoped_ptr curve( - KeyframedFloatAnimationCurve::Create()); - curve->AddKeyframe( - FloatKeyframe::Create(0.0, 4.f, scoped_ptr())); - curve->AddKeyframe( - FloatKeyframe::Create(1.0, 4.f, scoped_ptr())); - curve->AddKeyframe( - FloatKeyframe::Create(1.0, 6.f, scoped_ptr())); - curve->AddKeyframe( - FloatKeyframe::Create(2.0, 6.f, scoped_ptr())); - - EXPECT_FLOAT_EQ(4.f, curve->GetValue(-1.f)); - EXPECT_FLOAT_EQ(4.f, curve->GetValue(0.f)); - EXPECT_FLOAT_EQ(4.f, curve->GetValue(0.5f)); - - // There is a discontinuity at 1. Any value between 4 and 6 is valid. - float value = curve->GetValue(1.f); - EXPECT_TRUE(value >= 4 && value <= 6); - - EXPECT_FLOAT_EQ(6.f, curve->GetValue(1.5f)); - EXPECT_FLOAT_EQ(6.f, curve->GetValue(2.f)); - EXPECT_FLOAT_EQ(6.f, curve->GetValue(3.f)); -} - - -// Tests that a transform animation with one keyframe works as expected. -TEST(KeyframedAnimationCurveTest, OneTransformKeyframe) -{ - scoped_ptr curve( - KeyframedTransformAnimationCurve::Create()); - TransformOperations operations; - operations.AppendTranslate(2.f, 0.f, 0.f); - curve->AddKeyframe( - TransformKeyframe::Create(0.f, operations, scoped_ptr())); - - expectTranslateX(2.f, curve->GetValue(-1.f)); - expectTranslateX(2.f, curve->GetValue(0.f)); - expectTranslateX(2.f, curve->GetValue(0.5f)); - expectTranslateX(2.f, curve->GetValue(1.f)); - expectTranslateX(2.f, curve->GetValue(2.f)); -} - -// Tests that a transform animation with two keyframes works as expected. -TEST(KeyframedAnimationCurveTest, TwoTransformKeyframe) -{ - scoped_ptr curve( - KeyframedTransformAnimationCurve::Create()); - TransformOperations operations1; - operations1.AppendTranslate(2.f, 0.f, 0.f); - TransformOperations operations2; - operations2.AppendTranslate(4.f, 0.f, 0.f); - - curve->AddKeyframe(TransformKeyframe::Create( - 0.f, operations1, scoped_ptr())); - curve->AddKeyframe(TransformKeyframe::Create( - 1.f, operations2, scoped_ptr())); - expectTranslateX(2.f, curve->GetValue(-1.f)); - expectTranslateX(2.f, curve->GetValue(0.f)); - expectTranslateX(3.f, curve->GetValue(0.5f)); - expectTranslateX(4.f, curve->GetValue(1.f)); - expectTranslateX(4.f, curve->GetValue(2.f)); -} - -// Tests that a transform animation with three keyframes works as expected. -TEST(KeyframedAnimationCurveTest, ThreeTransformKeyframe) -{ - scoped_ptr curve( - KeyframedTransformAnimationCurve::Create()); - TransformOperations operations1; - operations1.AppendTranslate(2.f, 0.f, 0.f); - TransformOperations operations2; - operations2.AppendTranslate(4.f, 0.f, 0.f); - TransformOperations operations3; - operations3.AppendTranslate(8.f, 0.f, 0.f); - curve->AddKeyframe(TransformKeyframe::Create( - 0.f, operations1, scoped_ptr())); - curve->AddKeyframe(TransformKeyframe::Create( - 1.f, operations2, scoped_ptr())); - curve->AddKeyframe(TransformKeyframe::Create( - 2.f, operations3, scoped_ptr())); - expectTranslateX(2.f, curve->GetValue(-1.f)); - expectTranslateX(2.f, curve->GetValue(0.f)); - expectTranslateX(3.f, curve->GetValue(0.5f)); - expectTranslateX(4.f, curve->GetValue(1.f)); - expectTranslateX(6.f, curve->GetValue(1.5f)); - expectTranslateX(8.f, curve->GetValue(2.f)); - expectTranslateX(8.f, curve->GetValue(3.f)); -} - -// Tests that a transform animation with multiple keys at a given time works -// sanely. -TEST(KeyframedAnimationCurveTest, RepeatedTransformKeyTimes) -{ - scoped_ptr curve( - KeyframedTransformAnimationCurve::Create()); - // A step function. - TransformOperations operations1; - operations1.AppendTranslate(4.f, 0.f, 0.f); - TransformOperations operations2; - operations2.AppendTranslate(4.f, 0.f, 0.f); - TransformOperations operations3; - operations3.AppendTranslate(6.f, 0.f, 0.f); - TransformOperations operations4; - operations4.AppendTranslate(6.f, 0.f, 0.f); - curve->AddKeyframe(TransformKeyframe::Create( - 0.f, operations1, scoped_ptr())); - curve->AddKeyframe(TransformKeyframe::Create( - 1.f, operations2, scoped_ptr())); - curve->AddKeyframe(TransformKeyframe::Create( - 1.f, operations3, scoped_ptr())); - curve->AddKeyframe(TransformKeyframe::Create( - 2.f, operations4, scoped_ptr())); - - expectTranslateX(4.f, curve->GetValue(-1.f)); - expectTranslateX(4.f, curve->GetValue(0.f)); - expectTranslateX(4.f, curve->GetValue(0.5f)); - - // There is a discontinuity at 1. Any value between 4 and 6 is valid. - gfx::Transform value = curve->GetValue(1.f); - EXPECT_TRUE(value.matrix().getDouble(0.f, 3.f) >= 4); - EXPECT_TRUE(value.matrix().getDouble(0.f, 3.f) <= 6); - - expectTranslateX(6.f, curve->GetValue(1.5f)); - expectTranslateX(6.f, curve->GetValue(2.f)); - expectTranslateX(6.f, curve->GetValue(3.f)); -} - -// Tests that the keyframes may be added out of order. -TEST(KeyframedAnimationCurveTest, UnsortedKeyframes) -{ - scoped_ptr curve( - KeyframedFloatAnimationCurve::Create()); - curve->AddKeyframe( - FloatKeyframe::Create(2.0, 8.f, scoped_ptr())); - curve->AddKeyframe( - FloatKeyframe::Create(0.0, 2.f, scoped_ptr())); - curve->AddKeyframe( - FloatKeyframe::Create(1.0, 4.f, scoped_ptr())); - EXPECT_FLOAT_EQ(2.f, curve->GetValue(-1.f)); - EXPECT_FLOAT_EQ(2.f, curve->GetValue(0.f)); - EXPECT_FLOAT_EQ(3.f, curve->GetValue(0.5f)); - EXPECT_FLOAT_EQ(4.f, curve->GetValue(1.f)); - EXPECT_FLOAT_EQ(6.f, curve->GetValue(1.5f)); - EXPECT_FLOAT_EQ(8.f, curve->GetValue(2.f)); - EXPECT_FLOAT_EQ(8.f, curve->GetValue(3.f)); -} - -// Tests that a cubic bezier timing function works as expected. -TEST(KeyframedAnimationCurveTest, CubicBezierTimingFunction) -{ - scoped_ptr curve( - KeyframedFloatAnimationCurve::Create()); - curve->AddKeyframe( - FloatKeyframe::Create( - 0.f, - 0, - CubicBezierTimingFunction::create( - 0.25f, 0.f, 0.75f, 1.f).PassAs())); - curve->AddKeyframe( - FloatKeyframe::Create(1.0, 1.f, scoped_ptr())); - - EXPECT_FLOAT_EQ(0.f, curve->GetValue(0.f)); - EXPECT_LT(0.f, curve->GetValue(0.25f)); - EXPECT_GT(0.25f, curve->GetValue(0.25f)); - EXPECT_NEAR(curve->GetValue(0.5f), 0.5f, 0.00015f); - EXPECT_LT(0.75f, curve->GetValue(0.75f)); - EXPECT_GT(1.f, curve->GetValue(0.75f)); - EXPECT_FLOAT_EQ(1.f, curve->GetValue(1.f)); -} - -} // namespace -} // namespace cc diff --git a/cc/layer.cc b/cc/layer.cc index 00699e5..5925a68 100644 --- a/cc/layer.cc +++ b/cc/layer.cc @@ -4,9 +4,9 @@ #include "cc/layer.h" -#include "cc/animation.h" -#include "cc/animation_events.h" -#include "cc/layer_animation_controller.h" +#include "cc/animation/animation.h" +#include "cc/animation/animation_events.h" +#include "cc/animation/layer_animation_controller.h" #include "cc/layer_impl.h" #include "cc/layer_tree_host.h" #include "cc/layer_tree_impl.h" diff --git a/cc/layer.h b/cc/layer.h index 5019979e..2c765c0 100644 --- a/cc/layer.h +++ b/cc/layer.h @@ -10,12 +10,12 @@ #include "base/memory/ref_counted.h" #include "base/observer_list.h" +#include "cc/animation/layer_animation_controller.h" +#include "cc/animation/layer_animation_event_observer.h" +#include "cc/animation/layer_animation_value_observer.h" #include "cc/base/cc_export.h" #include "cc/base/region.h" #include "cc/draw_properties.h" -#include "cc/layer_animation_controller.h" -#include "cc/layer_animation_event_observer.h" -#include "cc/layer_animation_value_observer.h" #include "cc/occlusion_tracker.h" #include "cc/render_surface.h" #include "skia/ext/refptr.h" diff --git a/cc/layer_animation_controller.cc b/cc/layer_animation_controller.cc deleted file mode 100644 index 7dec464..0000000 --- a/cc/layer_animation_controller.cc +++ /dev/null @@ -1,628 +0,0 @@ -// 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/layer_animation_controller.h" - -#include - -#include "cc/animation.h" -#include "cc/animation_registrar.h" -#include "cc/base/scoped_ptr_algorithm.h" -#include "cc/keyframed_animation_curve.h" -#include "cc/layer_animation_value_observer.h" -#include "ui/gfx/transform.h" - -namespace cc { - -LayerAnimationController::LayerAnimationController(int id) - : force_sync_(false), - registrar_(0), - id_(id), - is_active_(false), - last_tick_time_(0) {} - -LayerAnimationController::~LayerAnimationController() { - if (registrar_) - registrar_->UnregisterAnimationController(this); -} - -scoped_refptr LayerAnimationController::Create( - int id) { - return make_scoped_refptr(new LayerAnimationController(id)); -} - -void LayerAnimationController::PauseAnimation(int animation_id, - double time_offset) { - for (size_t i = 0; i < active_animations_.size(); ++i) { - if (active_animations_[i]->id() == animation_id) { - active_animations_[i]->SetRunState( - Animation::Paused, time_offset + active_animations_[i]->start_time()); - } - } -} - -struct HasAnimationId { - HasAnimationId(int id) : id_(id) {} - bool operator()(Animation* animation) const { - return animation->id() == id_; - } - - private: - int id_; -}; - -void LayerAnimationController::RemoveAnimation(int animation_id) { - ScopedPtrVector& animations = active_animations_; - animations.erase(cc::remove_if(animations, - animations.begin(), - animations.end(), - HasAnimationId(animation_id)), - animations.end()); - UpdateActivation(NormalActivation); -} - -struct HasAnimationIdAndProperty { - HasAnimationIdAndProperty(int id, Animation::TargetProperty target_property) - : id_(id), target_property_(target_property) {} - bool operator()(Animation* animation) const { - return animation->id() == id_ && - animation->target_property() == target_property_; - } - - private: - int id_; - Animation::TargetProperty target_property_; -}; - -void LayerAnimationController::RemoveAnimation( - int animation_id, - Animation::TargetProperty target_property) { - ScopedPtrVector& animations = active_animations_; - animations.erase(cc::remove_if(animations, - animations.begin(), - animations.end(), - HasAnimationIdAndProperty(animation_id, - target_property)), - animations.end()); - UpdateActivation(NormalActivation); -} - -// According to render layer backing, these are for testing only. -void LayerAnimationController::SuspendAnimations(double monotonic_time) { - for (size_t i = 0; i < active_animations_.size(); ++i) { - if (!active_animations_[i]->is_finished()) - active_animations_[i]->SetRunState(Animation::Paused, monotonic_time); - } -} - -// Looking at GraphicsLayerCA, this appears to be the analog to -// suspendAnimations, which is for testing. -void LayerAnimationController::ResumeAnimations(double monotonic_time) { - for (size_t i = 0; i < active_animations_.size(); ++i) { - if (active_animations_[i]->run_state() == Animation::Paused) - active_animations_[i]->SetRunState(Animation::Running, monotonic_time); - } -} - -// Ensures that the list of active animations on the main thread and the impl -// thread are kept in sync. -void LayerAnimationController::PushAnimationUpdatesTo( - LayerAnimationController* controller_impl) { - if (force_sync_) { - ReplaceImplThreadAnimations(controller_impl); - force_sync_ = false; - } else { - PurgeAnimationsMarkedForDeletion(); - PushNewAnimationsToImplThread(controller_impl); - - // 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(controller_impl); - - PushPropertiesToImplThread(controller_impl); - } - controller_impl->UpdateActivation(NormalActivation); - UpdateActivation(NormalActivation); -} - -void LayerAnimationController::Animate(double monotonic_time) { - if (!HasActiveObserver()) - return; - - StartAnimationsWaitingForNextTick(monotonic_time); - StartAnimationsWaitingForStartTime(monotonic_time); - StartAnimationsWaitingForTargetAvailability(monotonic_time); - ResolveConflicts(monotonic_time); - TickAnimations(monotonic_time); - last_tick_time_ = monotonic_time; -} - -void LayerAnimationController::AccumulatePropertyUpdates( - double monotonic_time, - AnimationEventsVector* events) { - if (!events) - return; - - for (size_t i = 0; i < active_animations_.size(); ++i) { - Animation* animation = active_animations_[i]; - if (!animation->is_impl_only()) - continue; - - if (animation->target_property() == Animation::Opacity) { - AnimationEvent event(AnimationEvent::PropertyUpdate, - id_, - animation->group(), - Animation::Opacity, - monotonic_time); - event.opacity = animation->curve()->ToFloatAnimationCurve()->GetValue( - monotonic_time); - - events->push_back(event); - } - else if (animation->target_property() == Animation::Transform) { - AnimationEvent event(AnimationEvent::PropertyUpdate, - id_, - animation->group(), - Animation::Transform, - monotonic_time); - event.transform = - animation->curve()->ToTransformAnimationCurve()->GetValue( - monotonic_time); - events->push_back(event); - } - } -} - -void LayerAnimationController::UpdateState(AnimationEventsVector* events) { - if (!HasActiveObserver()) - return; - - PromoteStartedAnimations(last_tick_time_, events); - MarkFinishedAnimations(last_tick_time_); - MarkAnimationsForDeletion(last_tick_time_, events); - StartAnimationsWaitingForTargetAvailability(last_tick_time_); - PromoteStartedAnimations(last_tick_time_, events); - - AccumulatePropertyUpdates(last_tick_time_, events); - - UpdateActivation(NormalActivation); -} - -void LayerAnimationController::AddAnimation(scoped_ptr animation) { - active_animations_.push_back(animation.Pass()); - UpdateActivation(NormalActivation); -} - -Animation* LayerAnimationController::GetAnimation( - int group_id, - Animation::TargetProperty target_property) const { - for (size_t i = 0; i < active_animations_.size(); ++i) - if (active_animations_[i]->group() == group_id && - active_animations_[i]->target_property() == target_property) - return active_animations_[i]; - return 0; -} - -Animation* LayerAnimationController::GetAnimation( - Animation::TargetProperty target_property) const { - for (size_t i = 0; i < active_animations_.size(); ++i) { - size_t index = active_animations_.size() - i - 1; - if (active_animations_[index]->target_property() == target_property) - return active_animations_[index]; - } - return 0; -} - -bool LayerAnimationController::HasActiveAnimation() const { - for (size_t i = 0; i < active_animations_.size(); ++i) { - if (!active_animations_[i]->is_finished()) - return true; - } - return false; -} - -bool LayerAnimationController::IsAnimatingProperty( - Animation::TargetProperty target_property) const { - for (size_t i = 0; i < active_animations_.size(); ++i) { - if (active_animations_[i]->run_state() != Animation::Finished && - active_animations_[i]->run_state() != Animation::Aborted && - active_animations_[i]->target_property() == target_property) - return true; - } - return false; -} - -void LayerAnimationController::OnAnimationStarted( - const AnimationEvent& event) { - for (size_t i = 0; i < active_animations_.size(); ++i) { - if (active_animations_[i]->group() == event.group_id && - active_animations_[i]->target_property() == event.target_property && - active_animations_[i]->needs_synchronized_start_time()) { - active_animations_[i]->set_needs_synchronized_start_time(false); - active_animations_[i]->set_start_time(event.monotonic_time); - return; - } - } -} - -void LayerAnimationController::SetAnimationRegistrar( - AnimationRegistrar* registrar) { - if (registrar_ == registrar) - return; - - if (registrar_) - registrar_->UnregisterAnimationController(this); - - registrar_ = registrar; - if (registrar_) - registrar_->RegisterAnimationController(this); - - UpdateActivation(ForceActivation); -} - -void LayerAnimationController::AddObserver( - LayerAnimationValueObserver* observer) { - if (!observers_.HasObserver(observer)) - observers_.AddObserver(observer); -} - -void LayerAnimationController::RemoveObserver( - LayerAnimationValueObserver* observer) { - observers_.RemoveObserver(observer); -} - -void LayerAnimationController::PushNewAnimationsToImplThread( - LayerAnimationController* controller_impl) const { - // Any new animations owned by the main thread's controller are cloned and - // add to the impl thread's controller. - for (size_t i = 0; i < active_animations_.size(); ++i) { - // If the animation is already running on the impl thread, there is no - // need to copy it over. - if (controller_impl->GetAnimation(active_animations_[i]->group(), - active_animations_[i]->target_property())) - 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 (!active_animations_[i]->needs_synchronized_start_time()) - continue; - - // The new animation should be set to run as soon as possible. - Animation::RunState initial_run_state = - Animation::WaitingForTargetAvailability; - double start_time = 0; - scoped_ptr to_add(active_animations_[i]->CloneAndInitialize( - Animation::ControllingInstance, initial_run_state, start_time)); - DCHECK(!to_add->needs_synchronized_start_time()); - controller_impl->AddAnimation(to_add.Pass()); - } -} - -struct IsCompleted { - IsCompleted(const LayerAnimationController& main_thread_controller) - : main_thread_controller_(main_thread_controller) {} - bool operator()(Animation* animation) const { - if (animation->is_impl_only()) - return false; - return !main_thread_controller_.GetAnimation(animation->group(), - animation->target_property()); - } - - private: - const LayerAnimationController& main_thread_controller_; -}; - -void LayerAnimationController::RemoveAnimationsCompletedOnMainThread( - LayerAnimationController* controller_impl) const { - // Delete all impl thread animations for which there is no corresponding - // main thread animation. Each iteration, - // controller->active_animations_.size() is decremented or i is incremented - // guaranteeing progress towards loop termination. - ScopedPtrVector& animations = - controller_impl->active_animations_; - animations.erase(cc::remove_if(animations, - animations.begin(), - animations.end(), - IsCompleted(*this)), - animations.end()); -} - -void LayerAnimationController::PushPropertiesToImplThread( - LayerAnimationController* controller_impl) const { - for (size_t i = 0; i < active_animations_.size(); ++i) { - Animation* current_impl = - controller_impl->GetAnimation( - active_animations_[i]->group(), - active_animations_[i]->target_property()); - if (current_impl) - active_animations_[i]->PushPropertiesTo(current_impl); - } -} - -void LayerAnimationController::StartAnimationsWaitingForNextTick( - double monotonic_time) { - for (size_t i = 0; i < active_animations_.size(); ++i) { - if (active_animations_[i]->run_state() == Animation::WaitingForNextTick) - active_animations_[i]->SetRunState(Animation::Starting, monotonic_time); - } -} - -void LayerAnimationController::StartAnimationsWaitingForStartTime( - double monotonic_time) { - for (size_t i = 0; i < active_animations_.size(); ++i) { - if (active_animations_[i]->run_state() == Animation::WaitingForStartTime && - active_animations_[i]->start_time() <= monotonic_time) - active_animations_[i]->SetRunState(Animation::Starting, monotonic_time); - } -} - -void LayerAnimationController::StartAnimationsWaitingForTargetAvailability( - double monotonic_time) { - // First collect running properties. - TargetProperties blocked_properties; - for (size_t i = 0; i < active_animations_.size(); ++i) { - if (active_animations_[i]->run_state() == Animation::Starting || - active_animations_[i]->run_state() == Animation::Running || - active_animations_[i]->run_state() == Animation::Finished) - blocked_properties.insert(active_animations_[i]->target_property()); - } - - for (size_t i = 0; i < active_animations_.size(); ++i) { - if (active_animations_[i]->run_state() == - Animation::WaitingForTargetAvailability) { - // Collect all properties for animations with the same group id (they - // should all also be in the list of animations). - TargetProperties enqueued_properties; - enqueued_properties.insert(active_animations_[i]->target_property()); - for (size_t j = i + 1; j < active_animations_.size(); ++j) { - if (active_animations_[i]->group() == active_animations_[j]->group()) - enqueued_properties.insert(active_animations_[j]->target_property()); - } - - // 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 null_intersection = true; - for (TargetProperties::iterator p_iter = enqueued_properties.begin(); - p_iter != enqueued_properties.end(); - ++p_iter) { - if (!blocked_properties.insert(*p_iter).second) - null_intersection = false; - } - - // If the intersection is null, then we are free to start the animations - // in the group. - if (null_intersection) { - active_animations_[i]->SetRunState( - Animation::Starting, monotonic_time); - for (size_t j = i + 1; j < active_animations_.size(); ++j) { - if (active_animations_[i]->group() == - active_animations_[j]->group()) { - active_animations_[j]->SetRunState( - Animation::Starting, monotonic_time); - } - } - } - } - } -} - -void LayerAnimationController::PromoteStartedAnimations( - double monotonic_time, - AnimationEventsVector* events) { - for (size_t i = 0; i < active_animations_.size(); ++i) { - if (active_animations_[i]->run_state() == Animation::Starting) { - active_animations_[i]->SetRunState(Animation::Running, monotonic_time); - if (!active_animations_[i]->has_set_start_time()) - active_animations_[i]->set_start_time(monotonic_time); - if (events) { - events->push_back(AnimationEvent( - AnimationEvent::Started, - id_, - active_animations_[i]->group(), - active_animations_[i]->target_property(), - monotonic_time)); - } - } - } -} - -void LayerAnimationController::MarkFinishedAnimations(double monotonic_time) { - for (size_t i = 0; i < active_animations_.size(); ++i) { - if (active_animations_[i]->IsFinishedAt(monotonic_time)) - active_animations_[i]->SetRunState(Animation::Finished, monotonic_time); - } -} - -void LayerAnimationController::ResolveConflicts(double monotonic_time) { - // 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 active_animations_). - for (size_t i = 0; i < active_animations_.size(); ++i) { - if (active_animations_[i]->run_state() == Animation::Starting || - active_animations_[i]->run_state() == Animation::Running) { - for (size_t j = i + 1; j < active_animations_.size(); ++j) { - if ((active_animations_[j]->run_state() == Animation::Starting || - active_animations_[j]->run_state() == Animation::Running) && - active_animations_[i]->target_property() == - active_animations_[j]->target_property()) { - if (active_animations_[i]->start_time() > - active_animations_[j]->start_time()) { - active_animations_[j]->SetRunState(Animation::Aborted, - monotonic_time); - } else { - active_animations_[i]->SetRunState(Animation::Aborted, - monotonic_time); - } - } - } - } - } -} - -void LayerAnimationController::MarkAnimationsForDeletion( - double monotonic_time, AnimationEventsVector* events) { - for (size_t i = 0; i < active_animations_.size(); i++) { - int group_id = active_animations_[i]->group(); - bool all_anims_with_same_id_are_finished = 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 (active_animations_[i]->is_finished() && - active_animations_[i]->run_state() != Animation::WaitingForDeletion) { - all_anims_with_same_id_are_finished = true; - for (size_t j = 0; j < active_animations_.size(); ++j) { - if (group_id == active_animations_[j]->group() && - !active_animations_[j]->is_finished()) { - all_anims_with_same_id_are_finished = false; - break; - } - } - } - if (all_anims_with_same_id_are_finished) { - // We now need to remove all animations with the same group id as - // group_id (and send along animation finished notifications, if - // necessary). - for (size_t j = i; j < active_animations_.size(); j++) { - if (group_id == active_animations_[j]->group()) { - if (events) { - events->push_back(AnimationEvent( - AnimationEvent::Finished, - id_, - active_animations_[j]->group(), - active_animations_[j]->target_property(), - monotonic_time)); - } - active_animations_[j]->SetRunState(Animation::WaitingForDeletion, - monotonic_time); - } - } - } - } -} - -static bool IsWaitingForDeletion(Animation* animation) { - return animation->run_state() == Animation::WaitingForDeletion; -} - -void LayerAnimationController::PurgeAnimationsMarkedForDeletion() { - ScopedPtrVector& animations = active_animations_; - animations.erase(cc::remove_if(animations, - animations.begin(), - animations.end(), - IsWaitingForDeletion), - animations.end()); -} - -void LayerAnimationController::ReplaceImplThreadAnimations( - LayerAnimationController* controller_impl) const { - controller_impl->active_animations_.clear(); - for (size_t i = 0; i < active_animations_.size(); ++i) { - scoped_ptr to_add; - if (active_animations_[i]->needs_synchronized_start_time()) { - // We haven't received an animation started notification yet, so it - // is important that we add it in a 'waiting' and not 'running' state. - Animation::RunState initial_run_state = - Animation::WaitingForTargetAvailability; - double start_time = 0; - to_add = active_animations_[i]->CloneAndInitialize( - Animation::ControllingInstance, - initial_run_state, start_time).Pass(); - } else { - to_add = active_animations_[i]->Clone( - Animation::ControllingInstance).Pass(); - } - - controller_impl->AddAnimation(to_add.Pass()); - } -} - -void LayerAnimationController::TickAnimations(double monotonic_time) { - for (size_t i = 0; i < active_animations_.size(); ++i) { - if (active_animations_[i]->run_state() == Animation::Starting || - active_animations_[i]->run_state() == Animation::Running || - active_animations_[i]->run_state() == Animation::Paused) { - double trimmed = - active_animations_[i]->TrimTimeToCurrentIteration(monotonic_time); - - // Animation assumes its initial value until it gets the synchronized - // start time from the impl thread and can start ticking. - if (active_animations_[i]->needs_synchronized_start_time()) - trimmed = 0; - - // A just-started animation assumes its initial value. - if (active_animations_[i]->run_state() == Animation::Starting && - !active_animations_[i]->has_set_start_time()) - trimmed = 0; - - switch (active_animations_[i]->target_property()) { - - case Animation::Transform: { - const TransformAnimationCurve* transform_animation_curve = - active_animations_[i]->curve()->ToTransformAnimationCurve(); - const gfx::Transform transform = - transform_animation_curve->GetValue(trimmed); - NotifyObserversTransformAnimated(transform); - break; - } - - case Animation::Opacity: { - const FloatAnimationCurve* float_animation_curve = - active_animations_[i]->curve()->ToFloatAnimationCurve(); - const float opacity = float_animation_curve->GetValue(trimmed); - NotifyObserversOpacityAnimated(opacity); - break; - } - - // Do nothing for sentinel value. - case Animation::TargetPropertyEnumSize: - NOTREACHED(); - } - } - } -} - -void LayerAnimationController::UpdateActivation(UpdateActivationType type) { - bool force = type == ForceActivation; - if (registrar_) { - if (!active_animations_.empty() && (!is_active_ || force)) - registrar_->DidActivateAnimationController(this); - else if (active_animations_.empty() && (is_active_ || force)) - registrar_->DidDeactivateAnimationController(this); - is_active_ = !active_animations_.empty(); - } -} - -void LayerAnimationController::NotifyObserversOpacityAnimated(float opacity) { - FOR_EACH_OBSERVER(LayerAnimationValueObserver, - observers_, - OnOpacityAnimated(opacity)); -} - -void LayerAnimationController::NotifyObserversTransformAnimated( - const gfx::Transform& transform) { - FOR_EACH_OBSERVER(LayerAnimationValueObserver, - observers_, - OnTransformAnimated(transform)); -} - -bool LayerAnimationController::HasActiveObserver() { - if (observers_.might_have_observers()) { - ObserverListBase::Iterator it(observers_); - LayerAnimationValueObserver* obs; - while ((obs = it.GetNext()) != NULL) - if (obs->IsActive()) - return true; - } - return false; -} - -} // namespace cc diff --git a/cc/layer_animation_controller.h b/cc/layer_animation_controller.h deleted file mode 100644 index bb8fc56..0000000 --- a/cc/layer_animation_controller.h +++ /dev/null @@ -1,154 +0,0 @@ -// 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. - -#ifndef CC_LAYER_ANIMATION_CONTROLLER_H_ -#define CC_LAYER_ANIMATION_CONTROLLER_H_ - -#include "base/basictypes.h" -#include "base/hash_tables.h" -#include "base/memory/ref_counted.h" -#include "base/memory/scoped_ptr.h" -#include "base/observer_list.h" -#include "base/time.h" -#include "cc/animation_events.h" -#include "cc/base/cc_export.h" -#include "cc/base/scoped_ptr_vector.h" -#include "cc/layer_animation_event_observer.h" -#include "ui/gfx/transform.h" - -namespace gfx { class Transform; } - -namespace cc { - -class Animation; -class AnimationRegistrar; -class KeyframeValueList; -class LayerAnimationValueObserver; - -class CC_EXPORT LayerAnimationController - : public base::RefCounted, - public LayerAnimationEventObserver { - public: - static scoped_refptr Create(int id); - - int id() const { return id_; } - - // These methods are virtual for testing. - virtual void AddAnimation(scoped_ptr animation); - virtual void PauseAnimation(int animation_id, double time_offset); - virtual void RemoveAnimation(int animation_id); - virtual void RemoveAnimation(int animation_id, - Animation::TargetProperty target_property); - virtual void SuspendAnimations(double monotonic_time); - virtual void ResumeAnimations(double monotonic_time); - - // Ensures that the list of active animations on the main thread and the impl - // thread are kept in sync. This function does not take ownership of the impl - // thread controller. - virtual void PushAnimationUpdatesTo( - LayerAnimationController* controller_impl); - - void Animate(double monotonic_time); - void AccumulatePropertyUpdates(double monotonic_time, - AnimationEventsVector* events); - void UpdateState(AnimationEventsVector* events); - - // Returns the active animation in the given group, animating the given - // property, if such an animation exists. - Animation* GetAnimation(int group_id, - Animation::TargetProperty target_property) const; - - // Returns the active animation animating the given property that is either - // running, or is next to run, if such an animation exists. - Animation* GetAnimation(Animation::TargetProperty target_property) const; - - // Returns true if there are any animations that have neither finished nor - // aborted. - bool HasActiveAnimation() const; - - // Returns true if there are any animations at all to process. - bool has_any_animation() const { return !active_animations_.empty(); } - - // Returns true if there is an animation currently animating the given - // property, or if there is an animation scheduled to animate this property in - // the future. - bool IsAnimatingProperty(Animation::TargetProperty target_property) const; - - // This is called in response to an animation being started on the impl - // thread. This function updates the corresponding main thread animation's - // start time. - virtual void OnAnimationStarted(const AnimationEvent& event) OVERRIDE; - - // If a sync is forced, then the next time animation updates are pushed to the - // impl thread, all animations will be transferred. - void set_force_sync() { force_sync_ = true; } - - void SetAnimationRegistrar(AnimationRegistrar* registrar); - AnimationRegistrar* animation_registrar() { return registrar_; } - - void AddObserver(LayerAnimationValueObserver* observer); - void RemoveObserver(LayerAnimationValueObserver* observer); - - protected: - friend class base::RefCounted; - - LayerAnimationController(int id); - virtual ~LayerAnimationController(); - - private: - typedef base::hash_set TargetProperties; - - void PushNewAnimationsToImplThread( - LayerAnimationController* controller_impl) const; - void RemoveAnimationsCompletedOnMainThread( - LayerAnimationController* controller_impl) const; - void PushPropertiesToImplThread( - LayerAnimationController* controller_impl) const; - void ReplaceImplThreadAnimations( - LayerAnimationController* controller_impl) const; - - void StartAnimationsWaitingForNextTick(double monotonic_time); - void StartAnimationsWaitingForStartTime(double monotonic_time); - void StartAnimationsWaitingForTargetAvailability(double monotonic_time); - void ResolveConflicts(double monotonic_time); - void PromoteStartedAnimations(double monotonic_time, - AnimationEventsVector* events); - void MarkFinishedAnimations(double monotonic_time); - void MarkAnimationsForDeletion(double monotonic_time, - AnimationEventsVector* events); - void PurgeAnimationsMarkedForDeletion(); - - void TickAnimations(double monotonic_time); - - enum UpdateActivationType { - NormalActivation, - ForceActivation - }; - void UpdateActivation(UpdateActivationType type); - - void NotifyObserversOpacityAnimated(float opacity); - void NotifyObserversTransformAnimated(const gfx::Transform& transform); - - bool HasActiveObserver(); - - // If this is true, we force a sync to the impl thread. - bool force_sync_; - - AnimationRegistrar* registrar_; - int id_; - ScopedPtrVector active_animations_; - - // This is used to ensure that we don't spam the registrar. - bool is_active_; - - double last_tick_time_; - - ObserverList observers_; - - DISALLOW_COPY_AND_ASSIGN(LayerAnimationController); -}; - -} // namespace cc - -#endif // CC_LAYER_ANIMATION_CONTROLLER_H_ diff --git a/cc/layer_animation_controller_unittest.cc b/cc/layer_animation_controller_unittest.cc deleted file mode 100644 index dc75f38..0000000 --- a/cc/layer_animation_controller_unittest.cc +++ /dev/null @@ -1,901 +0,0 @@ -// 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/layer_animation_controller.h" - -#include "cc/animation.h" -#include "cc/animation_curve.h" -#include "cc/keyframed_animation_curve.h" -#include "cc/test/animation_test_common.h" -#include "cc/transform_operations.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "ui/gfx/transform.h" - -namespace cc { -namespace { - -void ExpectTranslateX(double translate_x, const gfx::Transform& matrix) { - EXPECT_FLOAT_EQ(translate_x, matrix.matrix().getDouble(0, 3)); } - -scoped_ptr CreateAnimation(scoped_ptr curve, - int id, - Animation::TargetProperty property) { - return Animation::Create(curve.Pass(), 0, id, property); -} - -TEST(LayerAnimationControllerTest, SyncNewAnimation) { - FakeLayerAnimationValueObserver dummy_impl; - scoped_refptr controller_impl( - LayerAnimationController::Create(0)); - controller_impl->AddObserver(&dummy_impl); - FakeLayerAnimationValueObserver dummy; - scoped_refptr controller( - LayerAnimationController::Create(0)); - controller->AddObserver(&dummy); - - EXPECT_FALSE(controller_impl->GetAnimation(0, Animation::Opacity)); - - addOpacityTransitionToController(*controller, 1, 0, 1, false); - - controller->PushAnimationUpdatesTo(controller_impl.get()); - - EXPECT_TRUE(controller_impl->GetAnimation(0, Animation::Opacity)); - EXPECT_EQ(Animation::WaitingForTargetAvailability, - controller_impl->GetAnimation(0, Animation::Opacity)->run_state()); -} - -// If an animation is started on the impl thread before it is ticked on the main -// thread, we must be sure to respect the synchronized start time. -TEST(LayerAnimationControllerTest, DoNotClobberStartTimes) { - FakeLayerAnimationValueObserver dummy_impl; - scoped_refptr controller_impl( - LayerAnimationController::Create(0)); - controller_impl->AddObserver(&dummy_impl); - FakeLayerAnimationValueObserver dummy; - scoped_refptr controller( - LayerAnimationController::Create(0)); - controller->AddObserver(&dummy); - - EXPECT_FALSE(controller_impl->GetAnimation(0, Animation::Opacity)); - - addOpacityTransitionToController(*controller, 1, 0, 1, false); - - controller->PushAnimationUpdatesTo(controller_impl.get()); - - EXPECT_TRUE(controller_impl->GetAnimation(0, Animation::Opacity)); - EXPECT_EQ(Animation::WaitingForTargetAvailability, - controller_impl->GetAnimation(0, Animation::Opacity)->run_state()); - - AnimationEventsVector events; - controller_impl->Animate(1.0); - controller_impl->UpdateState(&events); - - // Synchronize the start times. - EXPECT_EQ(1u, events.size()); - controller->OnAnimationStarted(events[0]); - EXPECT_EQ(controller->GetAnimation(0, Animation::Opacity)->start_time(), - controller_impl->GetAnimation(0, Animation::Opacity)->start_time()); - - // Start the animation on the main thread. Should not affect the start time. - controller->Animate(1.5); - controller->UpdateState(NULL); - EXPECT_EQ(controller->GetAnimation(0, Animation::Opacity)->start_time(), - controller_impl->GetAnimation(0, Animation::Opacity)->start_time()); -} - -TEST(LayerAnimationControllerTest, SyncPauseAndResume) { - FakeLayerAnimationValueObserver dummy_impl; - scoped_refptr controller_impl( - LayerAnimationController::Create(0)); - controller_impl->AddObserver(&dummy_impl); - FakeLayerAnimationValueObserver dummy; - scoped_refptr controller( - LayerAnimationController::Create(0)); - controller->AddObserver(&dummy); - - EXPECT_FALSE(controller_impl->GetAnimation(0, Animation::Opacity)); - - addOpacityTransitionToController(*controller, 1, 0, 1, false); - - controller->PushAnimationUpdatesTo(controller_impl.get()); - - EXPECT_TRUE(controller_impl->GetAnimation(0, Animation::Opacity)); - EXPECT_EQ(Animation::WaitingForTargetAvailability, - controller_impl->GetAnimation(0, Animation::Opacity)->run_state()); - - // Start the animations on each controller. - AnimationEventsVector events; - controller_impl->Animate(0.0); - controller_impl->UpdateState(&events); - controller->Animate(0.0); - controller->UpdateState(NULL); - EXPECT_EQ(Animation::Running, - controller_impl->GetAnimation(0, Animation::Opacity)->run_state()); - EXPECT_EQ(Animation::Running, - controller->GetAnimation(0, Animation::Opacity)->run_state()); - - // Pause the main-thread animation. - controller->SuspendAnimations(1.0); - EXPECT_EQ(Animation::Paused, - controller->GetAnimation(0, Animation::Opacity)->run_state()); - - // The pause run state change should make it to the impl thread controller. - controller->PushAnimationUpdatesTo(controller_impl.get()); - EXPECT_EQ(Animation::Paused, - controller_impl->GetAnimation(0, Animation::Opacity)->run_state()); - - // Resume the main-thread animation. - controller->ResumeAnimations(2.0); - EXPECT_EQ(Animation::Running, - controller->GetAnimation(0, Animation::Opacity)->run_state()); - - // The pause run state change should make it to the impl thread controller. - controller->PushAnimationUpdatesTo(controller_impl.get()); - EXPECT_EQ(Animation::Running, - controller_impl->GetAnimation(0, Animation::Opacity)->run_state()); -} - -TEST(LayerAnimationControllerTest, DoNotSyncFinishedAnimation) { - FakeLayerAnimationValueObserver dummy_impl; - scoped_refptr controller_impl( - LayerAnimationController::Create(0)); - controller_impl->AddObserver(&dummy_impl); - FakeLayerAnimationValueObserver dummy; - scoped_refptr controller( - LayerAnimationController::Create(0)); - controller->AddObserver(&dummy); - - EXPECT_FALSE(controller_impl->GetAnimation(0, Animation::Opacity)); - - int animation_id = - addOpacityTransitionToController(*controller, 1, 0, 1, false); - - controller->PushAnimationUpdatesTo(controller_impl.get()); - - EXPECT_TRUE(controller_impl->GetAnimation(0, Animation::Opacity)); - EXPECT_EQ(Animation::WaitingForTargetAvailability, - controller_impl->GetAnimation(0, Animation::Opacity)->run_state()); - - // Notify main thread controller that the animation has started. - AnimationEvent animation_started_event( - AnimationEvent::Started, 0, 0, Animation::Opacity, 0); - controller->OnAnimationStarted(animation_started_event); - - // Force animation to complete on impl thread. - controller_impl->RemoveAnimation(animation_id); - - EXPECT_FALSE(controller_impl->GetAnimation(animation_id, Animation::Opacity)); - - controller->PushAnimationUpdatesTo(controller_impl.get()); - - // Even though the main thread has a 'new' animation, it should not be pushed - // because the animation has already completed on the impl thread. - EXPECT_FALSE(controller_impl->GetAnimation(animation_id, Animation::Opacity)); -} - -// Tests that transitioning opacity from 0 to 1 works as expected. - -static const AnimationEvent* GetMostRecentPropertyUpdateEvent( - const AnimationEventsVector* events) { - const AnimationEvent* event = 0; - for (size_t i = 0; i < events->size(); ++i) - if ((*events)[i].type == AnimationEvent::PropertyUpdate) - event = &(*events)[i]; - - return event; -} - -TEST(LayerAnimationControllerTest, TrivialTransition) { - scoped_ptr events( - make_scoped_ptr(new AnimationEventsVector)); - FakeLayerAnimationValueObserver dummy; - scoped_refptr controller( - LayerAnimationController::Create(0)); - controller->AddObserver(&dummy); - - scoped_ptr to_add(CreateAnimation( - scoped_ptr(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(), - 1, - Animation::Opacity)); - - controller->AddAnimation(to_add.Pass()); - controller->Animate(0.0); - controller->UpdateState(events.get()); - EXPECT_TRUE(controller->HasActiveAnimation()); - EXPECT_EQ(0.f, dummy.opacity()); - // A non-implOnly animation should not generate property updates. - const AnimationEvent* event = GetMostRecentPropertyUpdateEvent(events.get()); - EXPECT_FALSE(event); - controller->Animate(1.0); - controller->UpdateState(events.get()); - EXPECT_EQ(1.f, dummy.opacity()); - EXPECT_FALSE(controller->HasActiveAnimation()); - event = GetMostRecentPropertyUpdateEvent(events.get()); - EXPECT_FALSE(event); -} - -TEST(LayerAnimationControllerTest, TrivialTransitionOnImpl) { - scoped_ptr events( - make_scoped_ptr(new AnimationEventsVector)); - FakeLayerAnimationValueObserver dummy_impl; - scoped_refptr controller_impl( - LayerAnimationController::Create(0)); - controller_impl->AddObserver(&dummy_impl); - - scoped_ptr to_add(CreateAnimation( - scoped_ptr(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(), - 1, - Animation::Opacity)); - to_add->set_is_impl_only(true); - - controller_impl->AddAnimation(to_add.Pass()); - controller_impl->Animate(0.0); - controller_impl->UpdateState(events.get()); - EXPECT_TRUE(controller_impl->HasActiveAnimation()); - EXPECT_EQ(0.f, dummy_impl.opacity()); - EXPECT_EQ(2, events->size()); - const AnimationEvent* start_opacity_event = - GetMostRecentPropertyUpdateEvent(events.get()); - EXPECT_EQ(0, start_opacity_event->opacity); - - controller_impl->Animate(1.0); - controller_impl->UpdateState(events.get()); - EXPECT_EQ(1.f, dummy_impl.opacity()); - EXPECT_FALSE(controller_impl->HasActiveAnimation()); - EXPECT_EQ(4, events->size()); - const AnimationEvent* end_opacity_event = - GetMostRecentPropertyUpdateEvent(events.get()); - EXPECT_EQ(1, end_opacity_event->opacity); -} - -TEST(LayerAnimationControllerTest, TrivialTransformOnImpl) { - scoped_ptr events( - make_scoped_ptr(new AnimationEventsVector)); - FakeLayerAnimationValueObserver dummy_impl; - scoped_refptr controller_impl( - LayerAnimationController::Create(0)); - controller_impl->AddObserver(&dummy_impl); - - // Choose different values for x and y to avoid coincidental values in the - // observed transforms. - const float delta_x = 3; - const float delta_y = 4; - - scoped_ptr curve( - KeyframedTransformAnimationCurve::Create()); - - // Create simple Transform animation. - TransformOperations operations; - curve->AddKeyframe(TransformKeyframe::Create( - 0, operations, scoped_ptr())); - operations.AppendTranslate(delta_x, delta_y, 0); - curve->AddKeyframe(TransformKeyframe::Create( - 1, operations, scoped_ptr())); - - scoped_ptr animation(Animation::Create( - curve.PassAs(), 1, 0, Animation::Transform)); - animation->set_is_impl_only(true); - controller_impl->AddAnimation(animation.Pass()); - - // Run animation. - controller_impl->Animate(0.0); - controller_impl->UpdateState(events.get()); - EXPECT_TRUE(controller_impl->HasActiveAnimation()); - EXPECT_EQ(gfx::Transform(), dummy_impl.transform()); - EXPECT_EQ(2, events->size()); - const AnimationEvent* start_transform_event = - GetMostRecentPropertyUpdateEvent(events.get()); - ASSERT_TRUE(start_transform_event); - EXPECT_EQ(gfx::Transform(), start_transform_event->transform); - - gfx::Transform expected_transform; - expected_transform.Translate(delta_x, delta_y); - - controller_impl->Animate(1.0); - controller_impl->UpdateState(events.get()); - EXPECT_EQ(expected_transform, dummy_impl.transform()); - EXPECT_FALSE(controller_impl->HasActiveAnimation()); - EXPECT_EQ(4, events->size()); - const AnimationEvent* end_transform_event = - GetMostRecentPropertyUpdateEvent(events.get()); - EXPECT_EQ(expected_transform, end_transform_event->transform); -} - -// Tests animations that are waiting for a synchronized start time do not -// finish. -TEST(LayerAnimationControllerTest, - AnimationsWaitingForStartTimeDoNotFinishIfTheyWaitLongerToStartThanTheirDuration) { - scoped_ptr events( - make_scoped_ptr(new AnimationEventsVector)); - FakeLayerAnimationValueObserver dummy; - scoped_refptr controller( - LayerAnimationController::Create(0)); - controller->AddObserver(&dummy); - - scoped_ptr to_add(CreateAnimation( - scoped_ptr(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(), - 1, - Animation::Opacity)); - to_add->set_needs_synchronized_start_time(true); - - // We should pause at the first keyframe indefinitely waiting for that - // animation to start. - controller->AddAnimation(to_add.Pass()); - controller->Animate(0.0); - controller->UpdateState(events.get()); - EXPECT_TRUE(controller->HasActiveAnimation()); - EXPECT_EQ(0.f, dummy.opacity()); - controller->Animate(1.0); - controller->UpdateState(events.get()); - EXPECT_TRUE(controller->HasActiveAnimation()); - EXPECT_EQ(0.f, dummy.opacity()); - controller->Animate(2.0); - controller->UpdateState(events.get()); - EXPECT_TRUE(controller->HasActiveAnimation()); - EXPECT_EQ(0.f, dummy.opacity()); - - // Send the synchronized start time. - controller->OnAnimationStarted(AnimationEvent( - AnimationEvent::Started, 0, 1, Animation::Opacity, 2)); - controller->Animate(5.0); - controller->UpdateState(events.get()); - EXPECT_EQ(1.f, dummy.opacity()); - EXPECT_FALSE(controller->HasActiveAnimation()); -} - -// Tests that two queued animations affecting the same property run in sequence. -TEST(LayerAnimationControllerTest, TrivialQueuing) { - scoped_ptr events( - make_scoped_ptr(new AnimationEventsVector)); - FakeLayerAnimationValueObserver dummy; - scoped_refptr controller( - LayerAnimationController::Create(0)); - controller->AddObserver(&dummy); - - controller->AddAnimation(CreateAnimation( - scoped_ptr(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(), - 1, - Animation::Opacity)); - controller->AddAnimation(CreateAnimation( - scoped_ptr( - new FakeFloatTransition(1.0, 1.f, 0.5f)).Pass(), - 2, - Animation::Opacity)); - - controller->Animate(0.0); - controller->UpdateState(events.get()); - EXPECT_TRUE(controller->HasActiveAnimation()); - EXPECT_EQ(0.f, dummy.opacity()); - controller->Animate(1.0); - controller->UpdateState(events.get()); - EXPECT_TRUE(controller->HasActiveAnimation()); - EXPECT_EQ(1.f, dummy.opacity()); - controller->Animate(2.0); - controller->UpdateState(events.get()); - EXPECT_EQ(0.5f, dummy.opacity()); - EXPECT_FALSE(controller->HasActiveAnimation()); -} - -// Tests interrupting a transition with another transition. -TEST(LayerAnimationControllerTest, Interrupt) { - scoped_ptr events( - make_scoped_ptr(new AnimationEventsVector)); - FakeLayerAnimationValueObserver dummy; - scoped_refptr controller( - LayerAnimationController::Create(0)); - controller->AddObserver(&dummy); - controller->AddAnimation(CreateAnimation( - scoped_ptr(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(), - 1, - Animation::Opacity)); - controller->Animate(0.0); - controller->UpdateState(events.get()); - EXPECT_TRUE(controller->HasActiveAnimation()); - EXPECT_EQ(0.f, dummy.opacity()); - - scoped_ptr to_add(CreateAnimation( - scoped_ptr( - new FakeFloatTransition(1.0, 1.f, 0.5f)).Pass(), - 2, - Animation::Opacity)); - to_add->SetRunState(Animation::WaitingForNextTick, 0); - controller->AddAnimation(to_add.Pass()); - - // Since the animation was in the WaitingForNextTick state, it should start - // right in this call to animate. - controller->Animate(0.5); - controller->UpdateState(events.get()); - EXPECT_TRUE(controller->HasActiveAnimation()); - EXPECT_EQ(1.f, dummy.opacity()); - controller->Animate(1.5); - controller->UpdateState(events.get()); - EXPECT_EQ(0.5f, dummy.opacity()); - EXPECT_FALSE(controller->HasActiveAnimation()); -} - -// Tests scheduling two animations to run together when only one property is -// free. -TEST(LayerAnimationControllerTest, ScheduleTogetherWhenAPropertyIsBlocked) { - scoped_ptr events( - make_scoped_ptr(new AnimationEventsVector)); - FakeLayerAnimationValueObserver dummy; - scoped_refptr controller( - LayerAnimationController::Create(0)); - controller->AddObserver(&dummy); - - controller->AddAnimation(CreateAnimation( - scoped_ptr(new FakeTransformTransition(1)).Pass(), - 1, - Animation::Transform)); - controller->AddAnimation(CreateAnimation( - scoped_ptr(new FakeTransformTransition(1)).Pass(), - 2, - Animation::Transform)); - controller->AddAnimation(CreateAnimation( - scoped_ptr(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(), - 2, - Animation::Opacity)); - - controller->Animate(0.0); - controller->UpdateState(events.get()); - EXPECT_EQ(0.f, dummy.opacity()); - EXPECT_TRUE(controller->HasActiveAnimation()); - controller->Animate(1.0); - controller->UpdateState(events.get()); - // Should not have started the float transition yet. - EXPECT_TRUE(controller->HasActiveAnimation()); - EXPECT_EQ(0.f, dummy.opacity()); - // The float animation should have started at time 1 and should be done. - controller->Animate(2.0); - controller->UpdateState(events.get()); - EXPECT_EQ(1.f, 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(LayerAnimationControllerTest, ScheduleTogetherWithAnAnimWaiting) { - scoped_ptr events( - make_scoped_ptr(new AnimationEventsVector)); - FakeLayerAnimationValueObserver dummy; - scoped_refptr controller( - LayerAnimationController::Create(0)); - controller->AddObserver(&dummy); - - controller->AddAnimation(CreateAnimation( - scoped_ptr(new FakeTransformTransition(2)).Pass(), - 1, - Animation::Transform)); - controller->AddAnimation(CreateAnimation( - scoped_ptr(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(), - 1, - Animation::Opacity)); - controller->AddAnimation(CreateAnimation( - scoped_ptr( - new FakeFloatTransition(1.0, 1.f, 0.5f)).Pass(), - 2, - Animation::Opacity)); - - // Animations with id 1 should both start now. - controller->Animate(0.0); - controller->UpdateState(events.get()); - EXPECT_TRUE(controller->HasActiveAnimation()); - EXPECT_EQ(0.f, 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.0); - controller->UpdateState(events.get()); - // Should not have started the float transition yet. - EXPECT_TRUE(controller->HasActiveAnimation()); - EXPECT_EQ(1.f, dummy.opacity()); - - // The second opacity animation should start at time 2 and should be done by - // time 3. - controller->Animate(3.0); - controller->UpdateState(events.get()); - EXPECT_EQ(0.5f, dummy.opacity()); - EXPECT_FALSE(controller->HasActiveAnimation()); -} - -// Tests scheduling an animation to start in the future. -TEST(LayerAnimationControllerTest, ScheduleAnimation) { - scoped_ptr events( - make_scoped_ptr(new AnimationEventsVector)); - FakeLayerAnimationValueObserver dummy; - scoped_refptr controller( - LayerAnimationController::Create(0)); - controller->AddObserver(&dummy); - - scoped_ptr to_add(CreateAnimation( - scoped_ptr(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(), - 1, - Animation::Opacity)); - to_add->SetRunState(Animation::WaitingForStartTime, 0); - to_add->set_start_time(1.f); - controller->AddAnimation(to_add.Pass()); - - controller->Animate(0.0); - controller->UpdateState(events.get()); - EXPECT_TRUE(controller->HasActiveAnimation()); - EXPECT_EQ(0.f, dummy.opacity()); - controller->Animate(1.0); - controller->UpdateState(events.get()); - EXPECT_TRUE(controller->HasActiveAnimation()); - EXPECT_EQ(0.f, dummy.opacity()); - controller->Animate(2.0); - controller->UpdateState(events.get()); - EXPECT_EQ(1.f, dummy.opacity()); - EXPECT_FALSE(controller->HasActiveAnimation()); -} - -// Tests scheduling an animation to start in the future that's interrupting a -// running animation. -TEST(LayerAnimationControllerTest, - ScheduledAnimationInterruptsRunningAnimation) { - scoped_ptr events( - make_scoped_ptr(new AnimationEventsVector)); - FakeLayerAnimationValueObserver dummy; - scoped_refptr controller( - LayerAnimationController::Create(0)); - controller->AddObserver(&dummy); - - controller->AddAnimation(CreateAnimation( - scoped_ptr(new FakeFloatTransition(2.0, 0.f, 1.f)).Pass(), - 1, - Animation::Opacity)); - - scoped_ptr to_add(CreateAnimation( - scoped_ptr( - new FakeFloatTransition(1.0, 0.5f, 0.f)).Pass(), - 2, - Animation::Opacity)); - to_add->SetRunState(Animation::WaitingForStartTime, 0); - to_add->set_start_time(1.f); - controller->AddAnimation(to_add.Pass()); - - // First 2s opacity transition should start immediately. - controller->Animate(0.0); - controller->UpdateState(events.get()); - EXPECT_TRUE(controller->HasActiveAnimation()); - EXPECT_EQ(0.f, dummy.opacity()); - controller->Animate(0.5); - controller->UpdateState(events.get()); - EXPECT_TRUE(controller->HasActiveAnimation()); - EXPECT_EQ(0.25f, dummy.opacity()); - controller->Animate(1.0); - controller->UpdateState(events.get()); - EXPECT_TRUE(controller->HasActiveAnimation()); - EXPECT_EQ(0.5f, dummy.opacity()); - controller->Animate(2.0); - controller->UpdateState(events.get()); - EXPECT_EQ(0.f, 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(LayerAnimationControllerTest, - ScheduledAnimationInterruptsRunningAnimationWithAnimInQueue) { - scoped_ptr events( - make_scoped_ptr(new AnimationEventsVector)); - FakeLayerAnimationValueObserver dummy; - scoped_refptr controller( - LayerAnimationController::Create(0)); - controller->AddObserver(&dummy); - - controller->AddAnimation(CreateAnimation( - scoped_ptr(new FakeFloatTransition(2.0, 0.f, 1.f)).Pass(), - 1, - Animation::Opacity)); - - scoped_ptr to_add(CreateAnimation( - scoped_ptr( - new FakeFloatTransition(2.0, 0.5f, 0.f)).Pass(), - 2, - Animation::Opacity)); - to_add->SetRunState(Animation::WaitingForStartTime, 0); - to_add->set_start_time(1.f); - controller->AddAnimation(to_add.Pass()); - - controller->AddAnimation(CreateAnimation( - scoped_ptr( - new FakeFloatTransition(1.0, 0.f, 0.75f)).Pass(), - 3, - Animation::Opacity)); - - // First 2s opacity transition should start immediately. - controller->Animate(0.0); - controller->UpdateState(events.get()); - EXPECT_TRUE(controller->HasActiveAnimation()); - EXPECT_EQ(0.f, dummy.opacity()); - controller->Animate(0.5); - controller->UpdateState(events.get()); - EXPECT_TRUE(controller->HasActiveAnimation()); - EXPECT_EQ(0.25f, dummy.opacity()); - EXPECT_TRUE(controller->HasActiveAnimation()); - controller->Animate(1.0); - controller->UpdateState(events.get()); - EXPECT_TRUE(controller->HasActiveAnimation()); - EXPECT_EQ(0.5f, dummy.opacity()); - controller->Animate(3.0); - controller->UpdateState(events.get()); - EXPECT_TRUE(controller->HasActiveAnimation()); - EXPECT_EQ(0.f, dummy.opacity()); - controller->Animate(4.0); - controller->UpdateState(events.get()); - EXPECT_EQ(0.75f, dummy.opacity()); - EXPECT_FALSE(controller->HasActiveAnimation()); -} - -// Test that a looping animation loops and for the correct number of iterations. -TEST(LayerAnimationControllerTest, TrivialLooping) { - scoped_ptr events( - make_scoped_ptr(new AnimationEventsVector)); - FakeLayerAnimationValueObserver dummy; - scoped_refptr controller( - LayerAnimationController::Create(0)); - controller->AddObserver(&dummy); - - scoped_ptr to_add(CreateAnimation( - scoped_ptr(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(), - 1, - Animation::Opacity)); - to_add->set_iterations(3); - controller->AddAnimation(to_add.Pass()); - - controller->Animate(0.0); - controller->UpdateState(events.get()); - EXPECT_TRUE(controller->HasActiveAnimation()); - EXPECT_EQ(0.f, dummy.opacity()); - controller->Animate(1.25); - controller->UpdateState(events.get()); - EXPECT_TRUE(controller->HasActiveAnimation()); - EXPECT_EQ(0.25f, dummy.opacity()); - controller->Animate(1.75); - controller->UpdateState(events.get()); - EXPECT_TRUE(controller->HasActiveAnimation()); - EXPECT_EQ(0.75f, dummy.opacity()); - controller->Animate(2.25); - controller->UpdateState(events.get()); - EXPECT_TRUE(controller->HasActiveAnimation()); - EXPECT_EQ(0.25f, dummy.opacity()); - controller->Animate(2.75); - controller->UpdateState(events.get()); - EXPECT_TRUE(controller->HasActiveAnimation()); - EXPECT_EQ(0.75f, dummy.opacity()); - controller->Animate(3.0); - controller->UpdateState(events.get()); - EXPECT_FALSE(controller->HasActiveAnimation()); - EXPECT_EQ(1.f, dummy.opacity()); - - // Just be extra sure. - controller->Animate(4.0); - controller->UpdateState(events.get()); - EXPECT_EQ(1.f, dummy.opacity()); -} - -// Test that an infinitely looping animation does indeed go until aborted. -TEST(LayerAnimationControllerTest, InfiniteLooping) { - scoped_ptr events( - make_scoped_ptr(new AnimationEventsVector)); - FakeLayerAnimationValueObserver dummy; - scoped_refptr controller( - LayerAnimationController::Create(0)); - controller->AddObserver(&dummy); - - const int id = 1; - scoped_ptr to_add(CreateAnimation( - scoped_ptr(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(), - id, - Animation::Opacity)); - to_add->set_iterations(-1); - controller->AddAnimation(to_add.Pass()); - - controller->Animate(0.0); - controller->UpdateState(events.get()); - EXPECT_TRUE(controller->HasActiveAnimation()); - EXPECT_EQ(0.f, dummy.opacity()); - controller->Animate(1.25); - controller->UpdateState(events.get()); - EXPECT_TRUE(controller->HasActiveAnimation()); - EXPECT_EQ(0.25f, dummy.opacity()); - controller->Animate(1.75); - controller->UpdateState(events.get()); - EXPECT_TRUE(controller->HasActiveAnimation()); - EXPECT_EQ(0.75f, dummy.opacity()); - - controller->Animate(1073741824.25); - controller->UpdateState(events.get()); - EXPECT_TRUE(controller->HasActiveAnimation()); - EXPECT_EQ(0.25f, dummy.opacity()); - controller->Animate(1073741824.75); - controller->UpdateState(events.get()); - EXPECT_TRUE(controller->HasActiveAnimation()); - EXPECT_EQ(0.75f, dummy.opacity()); - - EXPECT_TRUE(controller->GetAnimation(id, Animation::Opacity)); - controller->GetAnimation(id, Animation::Opacity)->SetRunState( - Animation::Aborted, 0.75); - EXPECT_FALSE(controller->HasActiveAnimation()); - EXPECT_EQ(0.75f, dummy.opacity()); -} - -// Test that pausing and resuming work as expected. -TEST(LayerAnimationControllerTest, PauseResume) { - scoped_ptr events( - make_scoped_ptr(new AnimationEventsVector)); - FakeLayerAnimationValueObserver dummy; - scoped_refptr controller( - LayerAnimationController::Create(0)); - controller->AddObserver(&dummy); - - const int id = 1; - controller->AddAnimation(CreateAnimation( - scoped_ptr(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(), - id, - Animation::Opacity)); - - controller->Animate(0.0); - controller->UpdateState(events.get()); - EXPECT_TRUE(controller->HasActiveAnimation()); - EXPECT_EQ(0.f, dummy.opacity()); - controller->Animate(0.5); - controller->UpdateState(events.get()); - EXPECT_TRUE(controller->HasActiveAnimation()); - EXPECT_EQ(0.5f, dummy.opacity()); - - EXPECT_TRUE(controller->GetAnimation(id, Animation::Opacity)); - controller->GetAnimation(id, Animation::Opacity)->SetRunState( - Animation::Paused, 0.5); - - controller->Animate(1024); - controller->UpdateState(events.get()); - EXPECT_TRUE(controller->HasActiveAnimation()); - EXPECT_EQ(0.5f, dummy.opacity()); - - EXPECT_TRUE(controller->GetAnimation(id, Animation::Opacity)); - controller->GetAnimation(id, Animation::Opacity)->SetRunState( - Animation::Running, 1024); - - controller->Animate(1024.25); - controller->UpdateState(events.get()); - EXPECT_TRUE(controller->HasActiveAnimation()); - EXPECT_EQ(0.75f, dummy.opacity()); - controller->Animate(1024.5); - controller->UpdateState(events.get()); - EXPECT_FALSE(controller->HasActiveAnimation()); - EXPECT_EQ(1.f, dummy.opacity()); -} - -TEST(LayerAnimationControllerTest, AbortAGroupedAnimation) { - scoped_ptr events( - make_scoped_ptr(new AnimationEventsVector)); - FakeLayerAnimationValueObserver dummy; - scoped_refptr controller( - LayerAnimationController::Create(0)); - controller->AddObserver(&dummy); - - const int id = 1; - controller->AddAnimation(CreateAnimation( - scoped_ptr(new FakeTransformTransition(1)).Pass(), - id, - Animation::Transform)); - controller->AddAnimation(CreateAnimation( - scoped_ptr(new FakeFloatTransition(2.0, 0.f, 1.f)).Pass(), - id, - Animation::Opacity)); - controller->AddAnimation(CreateAnimation( - scoped_ptr( - new FakeFloatTransition(1.0, 1.f, 0.75f)).Pass(), - 2, - Animation::Opacity)); - - controller->Animate(0.0); - controller->UpdateState(events.get()); - EXPECT_TRUE(controller->HasActiveAnimation()); - EXPECT_EQ(0.f, dummy.opacity()); - controller->Animate(1.0); - controller->UpdateState(events.get()); - EXPECT_TRUE(controller->HasActiveAnimation()); - EXPECT_EQ(0.5f, dummy.opacity()); - - EXPECT_TRUE(controller->GetAnimation(id, Animation::Opacity)); - controller->GetAnimation(id, Animation::Opacity)->SetRunState( - Animation::Aborted, 1); - controller->Animate(1.0); - controller->UpdateState(events.get()); - EXPECT_TRUE(controller->HasActiveAnimation()); - EXPECT_EQ(1.f, dummy.opacity()); - controller->Animate(2.0); - controller->UpdateState(events.get()); - EXPECT_TRUE(!controller->HasActiveAnimation()); - EXPECT_EQ(0.75f, dummy.opacity()); -} - -TEST(LayerAnimationControllerTest, ForceSyncWhenSynchronizedStartTimeNeeded) { - FakeLayerAnimationValueObserver dummy_impl; - scoped_refptr controller_impl( - LayerAnimationController::Create(0)); - controller_impl->AddObserver(&dummy_impl); - scoped_ptr events( - make_scoped_ptr(new AnimationEventsVector)); - FakeLayerAnimationValueObserver dummy; - scoped_refptr controller( - LayerAnimationController::Create(0)); - controller->AddObserver(&dummy); - - scoped_ptr to_add(CreateAnimation( - scoped_ptr(new FakeFloatTransition(2.0, 0.f, 1.f)).Pass(), - 0, - Animation::Opacity)); - to_add->set_needs_synchronized_start_time(true); - controller->AddAnimation(to_add.Pass()); - - controller->Animate(0.0); - controller->UpdateState(events.get()); - EXPECT_TRUE(controller->HasActiveAnimation()); - Animation* active_animation = controller->GetAnimation(0, Animation::Opacity); - EXPECT_TRUE(active_animation); - EXPECT_TRUE(active_animation->needs_synchronized_start_time()); - - controller->set_force_sync(); - - controller->PushAnimationUpdatesTo(controller_impl.get()); - - active_animation = controller_impl->GetAnimation(0, Animation::Opacity); - EXPECT_TRUE(active_animation); - EXPECT_EQ(Animation::WaitingForTargetAvailability, - active_animation->run_state()); -} - -// Tests that skipping a call to updateState works as expected. -TEST(LayerAnimationControllerTest, SkipUpdateState) { - scoped_ptr events( - make_scoped_ptr(new AnimationEventsVector)); - FakeLayerAnimationValueObserver dummy; - scoped_refptr controller( - LayerAnimationController::Create(0)); - controller->AddObserver(&dummy); - - controller->AddAnimation(CreateAnimation( - scoped_ptr(new FakeTransformTransition(1)).Pass(), - 1, - Animation::Transform)); - - controller->Animate(0.0); - controller->UpdateState(events.get()); - - controller->AddAnimation(CreateAnimation( - scoped_ptr(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(), - 2, - Animation::Opacity)); - - // Animate but don't updateState. - controller->Animate(1.0); - - controller->Animate(2.0); - events.reset(new AnimationEventsVector); - controller->UpdateState(events.get()); - - // Should have one Started event and one Finished event. - EXPECT_EQ(2, events->size()); - EXPECT_NE((*events)[0].type, (*events)[1].type); - - // The float transition should still be at its starting point. - EXPECT_TRUE(controller->HasActiveAnimation()); - EXPECT_EQ(0.f, dummy.opacity()); - - controller->Animate(3.0); - controller->UpdateState(events.get()); - - // The float tranisition should now be done. - EXPECT_EQ(1.f, dummy.opacity()); - EXPECT_FALSE(controller->HasActiveAnimation()); -} - -} // namespace -} // namespace cc diff --git a/cc/layer_animation_event_observer.h b/cc/layer_animation_event_observer.h deleted file mode 100644 index a66d026..0000000 --- a/cc/layer_animation_event_observer.h +++ /dev/null @@ -1,18 +0,0 @@ -// 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. - -#ifndef CC_LAYER_ANIMATION_EVENT_OBSERVER_H_ -#define CC_LAYER_ANIMATION_EVENT_OBSERVER_H_ - -namespace cc { - -class CC_EXPORT LayerAnimationEventObserver { - public: - virtual void OnAnimationStarted(const AnimationEvent& event) = 0; -}; - -} // namespace cc - -#endif // CC_LAYER_ANIMATION_EVENT_OBSERVER_H_ - diff --git a/cc/layer_animation_value_observer.h b/cc/layer_animation_value_observer.h deleted file mode 100644 index 859e8a2..0000000 --- a/cc/layer_animation_value_observer.h +++ /dev/null @@ -1,23 +0,0 @@ -// 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. - -#ifndef CC_LAYER_ANIMATION_VALUE_OBSERVER_H_ -#define CC_LAYER_ANIMATION_VALUE_OBSERVER_H_ - -namespace cc { - -class CC_EXPORT LayerAnimationValueObserver { - public: - virtual ~LayerAnimationValueObserver() { } - - virtual void OnOpacityAnimated(float) = 0; - virtual void OnTransformAnimated(const gfx::Transform&) = 0; - - virtual bool IsActive() const = 0; -}; - -} // namespace cc - -#endif // CC_LAYER_ANIMATION_VALUE_OBSERVER_H_ - diff --git a/cc/layer_impl.cc b/cc/layer_impl.cc index 530882b..03c45f2 100644 --- a/cc/layer_impl.cc +++ b/cc/layer_impl.cc @@ -7,7 +7,9 @@ #include "base/debug/trace_event.h" #include "base/stringprintf.h" #include "base/values.h" -#include "cc/animation_registrar.h" +#include "cc/animation/animation_registrar.h" +#include "cc/animation/scrollbar_animation_controller.h" +#include "cc/animation/scrollbar_animation_controller_linear_fade.h" #include "cc/base/math_util.h" #include "cc/debug/debug_colors.h" #include "cc/debug/layer_tree_debug_state.h" @@ -16,8 +18,6 @@ #include "cc/layer_tree_settings.h" #include "cc/proxy.h" #include "cc/quad_sink.h" -#include "cc/scrollbar_animation_controller.h" -#include "cc/scrollbar_animation_controller_linear_fade.h" #include "cc/scrollbar_layer_impl.h" #include "ui/gfx/point_conversions.h" #include "ui/gfx/quad_f.h" diff --git a/cc/layer_impl.h b/cc/layer_impl.h index 2d09d33..39c7c8a 100644 --- a/cc/layer_impl.h +++ b/cc/layer_impl.h @@ -10,13 +10,13 @@ #include "base/logging.h" #include "base/memory/scoped_ptr.h" #include "base/values.h" +#include "cc/animation/layer_animation_controller.h" +#include "cc/animation/layer_animation_value_observer.h" #include "cc/base/cc_export.h" #include "cc/base/region.h" #include "cc/base/scoped_ptr_vector.h" #include "cc/draw_properties.h" #include "cc/input_handler.h" -#include "cc/layer_animation_controller.h" -#include "cc/layer_animation_value_observer.h" #include "cc/render_pass.h" #include "cc/render_surface_impl.h" #include "cc/resource_provider.h" diff --git a/cc/layer_tree_host.cc b/cc/layer_tree_host.cc index 48e2370..1934e57 100644 --- a/cc/layer_tree_host.cc +++ b/cc/layer_tree_host.cc @@ -10,7 +10,8 @@ #include "base/message_loop.h" #include "base/stl_util.h" #include "base/string_number_conversions.h" -#include "cc/animation_registrar.h" +#include "cc/animation/animation_registrar.h" +#include "cc/animation/layer_animation_controller.h" #include "cc/base/math_util.h" #include "cc/base/switches.h" #include "cc/base/thread.h" @@ -18,7 +19,6 @@ #include "cc/heads_up_display_layer.h" #include "cc/heads_up_display_layer_impl.h" #include "cc/layer.h" -#include "cc/layer_animation_controller.h" #include "cc/layer_iterator.h" #include "cc/layer_tree_host_client.h" #include "cc/layer_tree_host_common.h" diff --git a/cc/layer_tree_host.h b/cc/layer_tree_host.h index cd626d4..1a2774d 100644 --- a/cc/layer_tree_host.h +++ b/cc/layer_tree_host.h @@ -14,7 +14,7 @@ #include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" #include "base/time.h" -#include "cc/animation_events.h" +#include "cc/animation/animation_events.h" #include "cc/base/cc_export.h" #include "cc/base/scoped_ptr_vector.h" #include "cc/debug/rendering_stats.h" diff --git a/cc/layer_tree_host_common_unittest.cc b/cc/layer_tree_host_common_unittest.cc index 5400f7d..f7bc6e5 100644 --- a/cc/layer_tree_host_common_unittest.cc +++ b/cc/layer_tree_host_common_unittest.cc @@ -4,13 +4,13 @@ #include "cc/layer_tree_host_common.h" +#include "cc/animation/layer_animation_controller.h" #include "cc/base/math_util.h" #include "cc/base/thread.h" #include "cc/content_layer.h" #include "cc/content_layer_client.h" #include "cc/heads_up_display_layer_impl.h" #include "cc/layer.h" -#include "cc/layer_animation_controller.h" #include "cc/layer_impl.h" #include "cc/layer_tree_impl.h" #include "cc/proxy.h" diff --git a/cc/layer_tree_host_impl.cc b/cc/layer_tree_host_impl.cc index a2f7a17..a0a26a8 100644 --- a/cc/layer_tree_host_impl.cc +++ b/cc/layer_tree_host_impl.cc @@ -12,6 +12,7 @@ #include "base/metrics/histogram.h" #include "base/stl_util.h" #include "base/stringprintf.h" +#include "cc/animation/scrollbar_animation_controller.h" #include "cc/append_quads_data.h" #include "cc/base/math_util.h" #include "cc/base/util.h" @@ -36,7 +37,6 @@ #include "cc/prioritized_resource_manager.h" #include "cc/quad_culler.h" #include "cc/render_pass_draw_quad.h" -#include "cc/scrollbar_animation_controller.h" #include "cc/scrollbar_layer_impl.h" #include "cc/shared_quad_state.h" #include "cc/single_thread_proxy.h" diff --git a/cc/layer_tree_host_impl.h b/cc/layer_tree_host_impl.h index a6ecfa9..bc8a8d7 100644 --- a/cc/layer_tree_host_impl.h +++ b/cc/layer_tree_host_impl.h @@ -8,8 +8,8 @@ #include "base/basictypes.h" #include "base/memory/scoped_ptr.h" #include "base/time.h" -#include "cc/animation_events.h" -#include "cc/animation_registrar.h" +#include "cc/animation/animation_events.h" +#include "cc/animation/animation_registrar.h" #include "cc/base/cc_export.h" #include "cc/input_handler.h" #include "cc/output_surface_client.h" diff --git a/cc/layer_tree_host_unittest_animation.cc b/cc/layer_tree_host_unittest_animation.cc index 837e8cb..3027bde 100644 --- a/cc/layer_tree_host_unittest_animation.cc +++ b/cc/layer_tree_host_unittest_animation.cc @@ -4,9 +4,9 @@ #include "cc/layer_tree_host.h" -#include "cc/animation_curve.h" +#include "cc/animation/animation_curve.h" +#include "cc/animation/layer_animation_controller.h" #include "cc/layer.h" -#include "cc/layer_animation_controller.h" #include "cc/layer_impl.h" #include "cc/test/fake_content_layer.h" #include "cc/test/fake_content_layer_client.h" diff --git a/cc/layer_tree_impl.cc b/cc/layer_tree_impl.cc index 10747b8..05ce890 100644 --- a/cc/layer_tree_impl.cc +++ b/cc/layer_tree_impl.cc @@ -5,15 +5,15 @@ #include "cc/layer_tree_impl.h" #include "base/debug/trace_event.h" -#include "cc/animation.h" -#include "cc/animation_id_provider.h" +#include "cc/animation/animation.h" +#include "cc/animation/animation_id_provider.h" +#include "cc/animation/keyframed_animation_curve.h" +#include "cc/animation/scrollbar_animation_controller.h" #include "cc/heads_up_display_layer_impl.h" -#include "cc/keyframed_animation_curve.h" #include "cc/layer.h" #include "cc/layer_tree_host_common.h" #include "cc/layer_tree_host_impl.h" #include "cc/pinch_zoom_scrollbar.h" -#include "cc/scrollbar_animation_controller.h" #include "cc/scrollbar_layer_impl.h" #include "ui/gfx/size_conversions.h" #include "ui/gfx/vector2d_conversions.h" diff --git a/cc/layer_unittest.cc b/cc/layer_unittest.cc index e5f097d..3083296 100644 --- a/cc/layer_unittest.cc +++ b/cc/layer_unittest.cc @@ -4,9 +4,9 @@ #include "cc/layer.h" +#include "cc/animation/keyframed_animation_curve.h" #include "cc/base/math_util.h" #include "cc/base/thread.h" -#include "cc/keyframed_animation_curve.h" #include "cc/layer_impl.h" #include "cc/layer_painter.h" #include "cc/layer_tree_host.h" diff --git a/cc/occlusion_tracker_unittest.cc b/cc/occlusion_tracker_unittest.cc index ce8939c..6bf9fa7 100644 --- a/cc/occlusion_tracker_unittest.cc +++ b/cc/occlusion_tracker_unittest.cc @@ -4,10 +4,10 @@ #include "cc/occlusion_tracker.h" +#include "cc/animation/layer_animation_controller.h" #include "cc/base/math_util.h" #include "cc/debug/overdraw_metrics.h" #include "cc/layer.h" -#include "cc/layer_animation_controller.h" #include "cc/layer_impl.h" #include "cc/layer_tree_host_common.h" #include "cc/single_thread_proxy.h" diff --git a/cc/scrollbar_animation_controller.h b/cc/scrollbar_animation_controller.h deleted file mode 100644 index e660e8f..0000000 --- a/cc/scrollbar_animation_controller.h +++ /dev/null @@ -1,32 +0,0 @@ -// 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. - -#ifndef CC_SCROLLBAR_ANIMATION_CONTROLLER_H_ -#define CC_SCROLLBAR_ANIMATION_CONTROLLER_H_ - -#include "base/time.h" -#include "cc/base/cc_export.h" -#include "ui/gfx/vector2d_f.h" - -namespace cc { - -// This abstract class represents the compositor-side analogy of ScrollbarAnimator. -// Individual platforms should subclass it to provide specialized implementation. -class CC_EXPORT ScrollbarAnimationController { -public: - virtual ~ScrollbarAnimationController() {} - - virtual bool isScrollGestureInProgress() const = 0; - virtual bool isAnimating() const = 0; - virtual base::TimeDelta delayBeforeStart(base::TimeTicks now) const = 0; - - virtual bool animate(base::TimeTicks) = 0; - virtual void didScrollGestureBegin() = 0; - virtual void didScrollGestureEnd(base::TimeTicks now) = 0; - virtual void didProgrammaticallyUpdateScroll(base::TimeTicks now) = 0; -}; - -} // namespace cc - -#endif // CC_SCROLLBAR_ANIMATION_CONTROLLER_H_ diff --git a/cc/scrollbar_animation_controller_linear_fade.cc b/cc/scrollbar_animation_controller_linear_fade.cc deleted file mode 100644 index f4f4acf..0000000 --- a/cc/scrollbar_animation_controller_linear_fade.cc +++ /dev/null @@ -1,94 +0,0 @@ -// 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/scrollbar_animation_controller_linear_fade.h" - -#include "base/time.h" -#include "cc/layer_impl.h" - -namespace cc { - -scoped_ptr ScrollbarAnimationControllerLinearFade::create(LayerImpl* scrollLayer, base::TimeDelta fadeoutDelay, base::TimeDelta fadeoutLength) -{ - return make_scoped_ptr(new ScrollbarAnimationControllerLinearFade(scrollLayer, fadeoutDelay, fadeoutLength)); -} - -ScrollbarAnimationControllerLinearFade::ScrollbarAnimationControllerLinearFade(LayerImpl* scrollLayer, base::TimeDelta fadeoutDelay, base::TimeDelta fadeoutLength) - : ScrollbarAnimationController() - , m_scrollLayer(scrollLayer) - , m_scrollGestureInProgress(false) - , m_fadeoutDelay(fadeoutDelay) - , m_fadeoutLength(fadeoutLength) -{ -} - -ScrollbarAnimationControllerLinearFade::~ScrollbarAnimationControllerLinearFade() -{ -} - -bool ScrollbarAnimationControllerLinearFade::isScrollGestureInProgress() const -{ - return m_scrollGestureInProgress; -} - -bool ScrollbarAnimationControllerLinearFade::isAnimating() const -{ - return !m_lastAwakenTime.is_null(); -} - -base::TimeDelta ScrollbarAnimationControllerLinearFade::delayBeforeStart(base::TimeTicks now) const -{ - if (now > m_lastAwakenTime + m_fadeoutDelay) - return base::TimeDelta(); - return m_fadeoutDelay - (now - m_lastAwakenTime); -} - -bool ScrollbarAnimationControllerLinearFade::animate(base::TimeTicks now) -{ - float opacity = opacityAtTime(now); - m_scrollLayer->SetScrollbarOpacity(opacity); - if (!opacity) - m_lastAwakenTime = base::TimeTicks(); - return isAnimating() && delayBeforeStart(now) == base::TimeDelta(); -} - -void ScrollbarAnimationControllerLinearFade::didScrollGestureBegin() -{ - m_scrollLayer->SetScrollbarOpacity(1); - m_scrollGestureInProgress = true; - m_lastAwakenTime = base::TimeTicks(); -} - -void ScrollbarAnimationControllerLinearFade::didScrollGestureEnd(base::TimeTicks now) -{ - m_scrollGestureInProgress = false; - m_lastAwakenTime = now; -} - -void ScrollbarAnimationControllerLinearFade::didProgrammaticallyUpdateScroll(base::TimeTicks now) -{ - // Don't set m_scrollGestureInProgress as this scroll is not from a gesture - // and we won't receive ScrollEnd. - m_scrollLayer->SetScrollbarOpacity(1); - m_lastAwakenTime = now; -} - -float ScrollbarAnimationControllerLinearFade::opacityAtTime(base::TimeTicks now) -{ - if (m_scrollGestureInProgress) - return 1; - - if (m_lastAwakenTime.is_null()) - return 0; - - base::TimeDelta delta = now - m_lastAwakenTime; - - if (delta <= m_fadeoutDelay) - return 1; - if (delta < m_fadeoutDelay + m_fadeoutLength) - return (m_fadeoutDelay + m_fadeoutLength - delta).InSecondsF() / m_fadeoutLength.InSecondsF(); - return 0; -} - -} // namespace cc diff --git a/cc/scrollbar_animation_controller_linear_fade.h b/cc/scrollbar_animation_controller_linear_fade.h deleted file mode 100644 index 81dba25..0000000 --- a/cc/scrollbar_animation_controller_linear_fade.h +++ /dev/null @@ -1,50 +0,0 @@ -// 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. - -#ifndef CC_SCROLLBAR_ANIMATION_CONTROLLER_LINEAR_FADE_H_ -#define CC_SCROLLBAR_ANIMATION_CONTROLLER_LINEAR_FADE_H_ - -#include "base/memory/scoped_ptr.h" -#include "cc/base/cc_export.h" -#include "cc/scrollbar_animation_controller.h" - -namespace cc { -class LayerImpl; - -class CC_EXPORT ScrollbarAnimationControllerLinearFade : public ScrollbarAnimationController { -public: - static scoped_ptr create(LayerImpl* scrollLayer, base::TimeDelta fadeoutDelay, base::TimeDelta fadeoutLength); - - virtual ~ScrollbarAnimationControllerLinearFade(); - - // ScrollbarAnimationController overrides. - virtual bool isScrollGestureInProgress() const OVERRIDE; - virtual bool isAnimating() const OVERRIDE; - virtual base::TimeDelta delayBeforeStart(base::TimeTicks now) const OVERRIDE; - - virtual bool animate(base::TimeTicks) OVERRIDE; - virtual void didScrollGestureBegin() OVERRIDE; - virtual void didScrollGestureEnd(base::TimeTicks now) OVERRIDE; - virtual void didProgrammaticallyUpdateScroll(base::TimeTicks now) OVERRIDE; - -protected: - ScrollbarAnimationControllerLinearFade(LayerImpl* scrollLayer, base::TimeDelta fadeoutDelay, base::TimeDelta fadeoutLength); - -private: - float opacityAtTime(base::TimeTicks); - - LayerImpl* m_scrollLayer; - - base::TimeTicks m_lastAwakenTime; - bool m_scrollGestureInProgress; - - base::TimeDelta m_fadeoutDelay; - base::TimeDelta m_fadeoutLength; - - double m_currentTimeForTesting; -}; - -} // namespace cc - -#endif // CC_SCROLLBAR_ANIMATION_CONTROLLER_LINEAR_FADE_H_ diff --git a/cc/scrollbar_animation_controller_linear_fade_unittest.cc b/cc/scrollbar_animation_controller_linear_fade_unittest.cc deleted file mode 100644 index 0513190..0000000 --- a/cc/scrollbar_animation_controller_linear_fade_unittest.cc +++ /dev/null @@ -1,168 +0,0 @@ -// 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/scrollbar_animation_controller_linear_fade.h" - -#include "cc/scrollbar_layer_impl.h" -#include "cc/single_thread_proxy.h" -#include "cc/test/fake_impl_proxy.h" -#include "cc/test/fake_layer_tree_host_impl.h" -#include "cc/test/fake_web_scrollbar_theme_geometry.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace cc { -namespace { - -class ScrollbarAnimationControllerLinearFadeTest : public testing::Test { -public: - ScrollbarAnimationControllerLinearFadeTest() - : m_hostImpl(&m_proxy) - { - } - -protected: - virtual void SetUp() - { - m_scrollLayer = LayerImpl::Create(m_hostImpl.active_tree(), 1); - scoped_ptr geometry(ScrollbarGeometryFixedThumb::create(FakeWebScrollbarThemeGeometry::create(false))); - m_scrollbarLayer = ScrollbarLayerImpl::Create(m_hostImpl.active_tree(), 2, geometry.Pass()); - - m_scrollLayer->SetMaxScrollOffset(gfx::Vector2d(50, 50)); - m_scrollLayer->SetBounds(gfx::Size(50, 50)); - m_scrollLayer->SetHorizontalScrollbarLayer(m_scrollbarLayer.get()); - - m_scrollbarController = ScrollbarAnimationControllerLinearFade::create(m_scrollLayer.get(), base::TimeDelta::FromSeconds(2), base::TimeDelta::FromSeconds(3)); - } - - FakeImplProxy m_proxy; - FakeLayerTreeHostImpl m_hostImpl; - scoped_ptr m_scrollbarController; - scoped_ptr m_scrollLayer; - scoped_ptr m_scrollbarLayer; - -}; - -TEST_F(ScrollbarAnimationControllerLinearFadeTest, verifyHiddenInBegin) -{ - m_scrollbarController->animate(base::TimeTicks()); - EXPECT_FLOAT_EQ(0, m_scrollbarLayer->opacity()); -} - -TEST_F(ScrollbarAnimationControllerLinearFadeTest, verifyAwakenByScrollGesture) -{ - base::TimeTicks time; - time += base::TimeDelta::FromSeconds(1); - m_scrollbarController->didScrollGestureBegin(); - EXPECT_TRUE(m_scrollbarController->isScrollGestureInProgress()); - EXPECT_FALSE(m_scrollbarController->isAnimating()); - EXPECT_FLOAT_EQ(1, m_scrollbarLayer->opacity()); - - time += base::TimeDelta::FromSeconds(100); - m_scrollbarController->animate(time); - EXPECT_FLOAT_EQ(1, m_scrollbarLayer->opacity()); - m_scrollbarController->didScrollGestureEnd(time); - - EXPECT_FALSE(m_scrollbarController->isScrollGestureInProgress()); - EXPECT_TRUE(m_scrollbarController->isAnimating()); - EXPECT_EQ(2, m_scrollbarController->delayBeforeStart(time).InSeconds()); - - time += base::TimeDelta::FromSeconds(1); - m_scrollbarController->animate(time); - EXPECT_FLOAT_EQ(1, m_scrollbarLayer->opacity()); - - time += base::TimeDelta::FromSeconds(1); - m_scrollbarController->animate(time); - EXPECT_FLOAT_EQ(1, m_scrollbarLayer->opacity()); - - time += base::TimeDelta::FromSeconds(1); - m_scrollbarController->animate(time); - EXPECT_FLOAT_EQ(2.0f / 3.0f, m_scrollbarLayer->opacity()); - - time += base::TimeDelta::FromSeconds(1); - m_scrollbarController->animate(time); - EXPECT_FLOAT_EQ(1.0f / 3.0f, m_scrollbarLayer->opacity()); - - time += base::TimeDelta::FromSeconds(1); - - m_scrollbarController->didScrollGestureBegin(); - m_scrollbarController->didScrollGestureEnd(time); - - time += base::TimeDelta::FromSeconds(1); - m_scrollbarController->animate(time); - EXPECT_FLOAT_EQ(1, m_scrollbarLayer->opacity()); - - time += base::TimeDelta::FromSeconds(1); - m_scrollbarController->animate(time); - EXPECT_FLOAT_EQ(1, m_scrollbarLayer->opacity()); - - time += base::TimeDelta::FromSeconds(1); - m_scrollbarController->animate(time); - EXPECT_FLOAT_EQ(2.0f / 3.0f, m_scrollbarLayer->opacity()); - - time += base::TimeDelta::FromSeconds(1); - m_scrollbarController->animate(time); - EXPECT_FLOAT_EQ(1.0f / 3.0f, m_scrollbarLayer->opacity()); - - time += base::TimeDelta::FromSeconds(1); - m_scrollbarController->animate(time); - EXPECT_FLOAT_EQ(0, m_scrollbarLayer->opacity()); -} - -TEST_F(ScrollbarAnimationControllerLinearFadeTest, verifyAwakenByProgrammaticScroll) -{ - base::TimeTicks time; - time += base::TimeDelta::FromSeconds(1); - m_scrollbarController->didProgrammaticallyUpdateScroll(time); - EXPECT_FALSE(m_scrollbarController->isScrollGestureInProgress()); - EXPECT_TRUE(m_scrollbarController->isAnimating()); - EXPECT_EQ(2, m_scrollbarController->delayBeforeStart(time).InSeconds()); - m_scrollbarController->animate(time); - EXPECT_FLOAT_EQ(1, m_scrollbarLayer->opacity()); - - time += base::TimeDelta::FromSeconds(1); - m_scrollbarController->animate(time); - EXPECT_FLOAT_EQ(1, m_scrollbarLayer->opacity()); - m_scrollbarController->didProgrammaticallyUpdateScroll(time); - - time += base::TimeDelta::FromSeconds(1); - m_scrollbarController->animate(time); - EXPECT_FLOAT_EQ(1, m_scrollbarLayer->opacity()); - - time += base::TimeDelta::FromSeconds(1); - m_scrollbarController->animate(time); - EXPECT_FLOAT_EQ(1, m_scrollbarLayer->opacity()); - - time += base::TimeDelta::FromSeconds(1); - m_scrollbarController->animate(time); - EXPECT_FLOAT_EQ(2.0f / 3.0f, m_scrollbarLayer->opacity()); - - time += base::TimeDelta::FromSeconds(1); - m_scrollbarController->animate(time); - EXPECT_FLOAT_EQ(1.0f / 3.0f, m_scrollbarLayer->opacity()); - - time += base::TimeDelta::FromSeconds(1); - m_scrollbarController->didProgrammaticallyUpdateScroll(time); - time += base::TimeDelta::FromSeconds(1); - m_scrollbarController->animate(time); - EXPECT_FLOAT_EQ(1, m_scrollbarLayer->opacity()); - - time += base::TimeDelta::FromSeconds(1); - m_scrollbarController->animate(time); - EXPECT_FLOAT_EQ(1, m_scrollbarLayer->opacity()); - - time += base::TimeDelta::FromSeconds(1); - m_scrollbarController->animate(time); - EXPECT_FLOAT_EQ(2.0f / 3.0f, m_scrollbarLayer->opacity()); - - time += base::TimeDelta::FromSeconds(1); - m_scrollbarController->animate(time); - EXPECT_FLOAT_EQ(1.0f / 3.0f, m_scrollbarLayer->opacity()); - - time += base::TimeDelta::FromSeconds(1); - m_scrollbarController->animate(time); - EXPECT_FLOAT_EQ(0, m_scrollbarLayer->opacity()); -} - -} // namespace -} // namespace cc diff --git a/cc/scrollbar_layer_impl.cc b/cc/scrollbar_layer_impl.cc index 0d3c38e..09be44c 100644 --- a/cc/scrollbar_layer_impl.cc +++ b/cc/scrollbar_layer_impl.cc @@ -4,11 +4,11 @@ #include "cc/scrollbar_layer_impl.h" +#include "cc/animation/scrollbar_animation_controller.h" #include "cc/layer.h" #include "cc/layer_tree_impl.h" #include "cc/layer_tree_settings.h" #include "cc/quad_sink.h" -#include "cc/scrollbar_animation_controller.h" #include "cc/solid_color_draw_quad.h" #include "cc/texture_draw_quad.h" #include "ui/gfx/rect_conversions.h" diff --git a/cc/scrollbar_layer_unittest.cc b/cc/scrollbar_layer_unittest.cc index 493bf8b..6fe4e97 100644 --- a/cc/scrollbar_layer_unittest.cc +++ b/cc/scrollbar_layer_unittest.cc @@ -4,12 +4,12 @@ #include "cc/scrollbar_layer.h" +#include "cc/animation/scrollbar_animation_controller.h" #include "cc/append_quads_data.h" #include "cc/layer_tree_impl.h" #include "cc/prioritized_resource_manager.h" #include "cc/priority_calculator.h" #include "cc/resource_update_queue.h" -#include "cc/scrollbar_animation_controller.h" #include "cc/scrollbar_layer_impl.h" #include "cc/single_thread_proxy.h" #include "cc/solid_color_draw_quad.h" diff --git a/cc/single_thread_proxy.h b/cc/single_thread_proxy.h index 6a19006..7cc440e 100644 --- a/cc/single_thread_proxy.h +++ b/cc/single_thread_proxy.h @@ -8,7 +8,7 @@ #include #include "base/time.h" -#include "cc/animation_events.h" +#include "cc/animation/animation_events.h" #include "cc/layer_tree_host_impl.h" #include "cc/proxy.h" diff --git a/cc/test/animation_test_common.cc b/cc/test/animation_test_common.cc index 50c3a1b..37710db 100644 --- a/cc/test/animation_test_common.cc +++ b/cc/test/animation_test_common.cc @@ -4,9 +4,9 @@ #include "cc/test/animation_test_common.h" -#include "cc/keyframed_animation_curve.h" +#include "cc/animation/keyframed_animation_curve.h" +#include "cc/animation/layer_animation_controller.h" #include "cc/layer.h" -#include "cc/layer_animation_controller.h" #include "cc/layer_impl.h" #include "cc/transform_operations.h" diff --git a/cc/test/animation_test_common.h b/cc/test/animation_test_common.h index 1afbc06..c4bbe15 100644 --- a/cc/test/animation_test_common.h +++ b/cc/test/animation_test_common.h @@ -5,10 +5,10 @@ #ifndef CC_TEST_ANIMATION_TEST_COMMON_H_ #define CC_TEST_ANIMATION_TEST_COMMON_H_ -#include "cc/animation.h" -#include "cc/animation_curve.h" -#include "cc/layer_animation_controller.h" -#include "cc/layer_animation_value_observer.h" +#include "cc/animation/animation.h" +#include "cc/animation/animation_curve.h" +#include "cc/animation/layer_animation_controller.h" +#include "cc/animation/layer_animation_value_observer.h" namespace cc { class LayerImpl; diff --git a/cc/test/layer_tree_test_common.cc b/cc/test/layer_tree_test_common.cc index 35274e8..ca39cb6 100644 --- a/cc/test/layer_tree_test_common.cc +++ b/cc/test/layer_tree_test_common.cc @@ -4,13 +4,13 @@ #include "cc/test/layer_tree_test_common.h" -#include "cc/animation.h" -#include "cc/animation_registrar.h" +#include "cc/animation/animation.h" +#include "cc/animation/animation_registrar.h" +#include "cc/animation/layer_animation_controller.h" #include "cc/base/thread_impl.h" #include "cc/content_layer.h" #include "cc/input_handler.h" #include "cc/layer.h" -#include "cc/layer_animation_controller.h" #include "cc/layer_impl.h" #include "cc/layer_tree_host_impl.h" #include "cc/single_thread_proxy.h" diff --git a/cc/thread_proxy.h b/cc/thread_proxy.h index 9415475..ac3423b 100644 --- a/cc/thread_proxy.h +++ b/cc/thread_proxy.h @@ -8,7 +8,7 @@ #include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" #include "base/time.h" -#include "cc/animation_events.h" +#include "cc/animation/animation_events.h" #include "cc/base/completion_event.h" #include "cc/layer_tree_host_impl.h" #include "cc/proxy.h" diff --git a/cc/timing_function.h b/cc/timing_function.h index 4768543..529fdce 100644 --- a/cc/timing_function.h +++ b/cc/timing_function.h @@ -5,7 +5,7 @@ #ifndef CC_TIMING_FUNCTION_H_ #define CC_TIMING_FUNCTION_H_ -#include "cc/animation_curve.h" +#include "cc/animation/animation_curve.h" #include "cc/base/cc_export.h" #include "third_party/skia/include/core/SkScalar.h" diff --git a/cc/top_controls_manager.cc b/cc/top_controls_manager.cc index 3c9f960..eee9531 100644 --- a/cc/top_controls_manager.cc +++ b/cc/top_controls_manager.cc @@ -8,7 +8,7 @@ #include "base/logging.h" #include "base/time.h" -#include "cc/keyframed_animation_curve.h" +#include "cc/animation/keyframed_animation_curve.h" #include "cc/layer_tree_impl.h" #include "cc/timing_function.h" #include "cc/top_controls_manager_client.h" diff --git a/cc/tree_synchronizer.cc b/cc/tree_synchronizer.cc index 4f511de..66c2222 100644 --- a/cc/tree_synchronizer.cc +++ b/cc/tree_synchronizer.cc @@ -6,9 +6,9 @@ #include "base/debug/trace_event.h" #include "base/logging.h" +#include "cc/animation/scrollbar_animation_controller.h" #include "cc/layer.h" #include "cc/layer_impl.h" -#include "cc/scrollbar_animation_controller.h" #include "cc/scrollbar_layer.h" #include "cc/scrollbar_layer_impl.h" diff --git a/cc/tree_synchronizer_unittest.cc b/cc/tree_synchronizer_unittest.cc index d2acd186..993183c 100644 --- a/cc/tree_synchronizer_unittest.cc +++ b/cc/tree_synchronizer_unittest.cc @@ -6,8 +6,8 @@ #include +#include "cc/animation/layer_animation_controller.h" #include "cc/layer.h" -#include "cc/layer_animation_controller.h" #include "cc/layer_impl.h" #include "cc/proxy.h" #include "cc/single_thread_proxy.h" -- cgit v1.1