1 // Copyright 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "cc/animation/animation.h" 6 7 #include <cmath> 8 9 #include "base/debug/trace_event.h" 10 #include "base/strings/string_util.h" 11 #include "cc/animation/animation_curve.h" 12 13 namespace { 14 15 // This should match the RunState enum. 16 static const char* const s_runStateNames[] = { 17 "WaitingForNextTick", 18 "WaitingForTargetAvailability", 19 "WaitingForStartTime", 20 "WaitingForDeletion", 21 "Starting", 22 "Running", 23 "Paused", 24 "Finished", 25 "Aborted" 26 }; 27 28 COMPILE_ASSERT(static_cast<int>(cc::Animation::RunStateEnumSize) == 29 arraysize(s_runStateNames), 30 RunState_names_match_enum); 31 32 // This should match the TargetProperty enum. 33 static const char* const s_targetPropertyNames[] = { 34 "Transform", 35 "Opacity" 36 }; 37 38 COMPILE_ASSERT(static_cast<int>(cc::Animation::TargetPropertyEnumSize) == 39 arraysize(s_targetPropertyNames), 40 TargetProperty_names_match_enum); 41 42 } // namespace 43 44 namespace cc { 45 46 scoped_ptr<Animation> Animation::Create( 47 scoped_ptr<AnimationCurve> curve, 48 int animation_id, 49 int group_id, 50 TargetProperty target_property) { 51 return make_scoped_ptr(new Animation(curve.Pass(), 52 animation_id, 53 group_id, 54 target_property)); } 55 56 Animation::Animation(scoped_ptr<AnimationCurve> curve, 57 int animation_id, 58 int group_id, 59 TargetProperty target_property) 60 : curve_(curve.Pass()), 61 id_(animation_id), 62 group_(group_id), 63 target_property_(target_property), 64 run_state_(WaitingForTargetAvailability), 65 iterations_(1), 66 start_time_(0), 67 alternates_direction_(false), 68 time_offset_(0), 69 needs_synchronized_start_time_(false), 70 received_finished_event_(false), 71 suspended_(false), 72 pause_time_(0), 73 total_paused_time_(0), 74 is_controlling_instance_(false), 75 is_impl_only_(false) {} 76 77 Animation::~Animation() { 78 if (run_state_ == Running || run_state_ == Paused) 79 SetRunState(Aborted, 0); 80 } 81 82 void Animation::SetRunState(RunState run_state, double monotonic_time) { 83 if (suspended_) 84 return; 85 86 char name_buffer[256]; 87 base::snprintf(name_buffer, 88 sizeof(name_buffer), 89 "%s-%d%s", 90 s_targetPropertyNames[target_property_], 91 group_, 92 is_controlling_instance_ ? "(impl)" : ""); 93 94 bool is_waiting_to_start = run_state_ == WaitingForNextTick || 95 run_state_ == WaitingForTargetAvailability || 96 run_state_ == WaitingForStartTime || 97 run_state_ == Starting; 98 99 if (is_waiting_to_start && run_state == Running) { 100 TRACE_EVENT_ASYNC_BEGIN1( 101 "cc", "Animation", this, "Name", TRACE_STR_COPY(name_buffer)); 102 } 103 104 bool was_finished = is_finished(); 105 106 const char* old_run_state_name = s_runStateNames[run_state_]; 107 108 if (run_state == Running && run_state_ == Paused) 109 total_paused_time_ += monotonic_time - pause_time_; 110 else if (run_state == Paused) 111 pause_time_ = monotonic_time; 112 run_state_ = run_state; 113 114 const char* new_run_state_name = s_runStateNames[run_state]; 115 116 if (!was_finished && is_finished()) 117 TRACE_EVENT_ASYNC_END0("cc", "Animation", this); 118 119 char state_buffer[256]; 120 base::snprintf(state_buffer, 121 sizeof(state_buffer), 122 "%s->%s", 123 old_run_state_name, 124 new_run_state_name); 125 126 TRACE_EVENT_INSTANT2("cc", 127 "LayerAnimationController::SetRunState", 128 TRACE_EVENT_SCOPE_THREAD, 129 "Name", 130 TRACE_STR_COPY(name_buffer), 131 "State", 132 TRACE_STR_COPY(state_buffer)); 133 } 134 135 void Animation::Suspend(double monotonic_time) { 136 SetRunState(Paused, monotonic_time); 137 suspended_ = true; 138 } 139 140 void Animation::Resume(double monotonic_time) { 141 suspended_ = false; 142 SetRunState(Running, monotonic_time); 143 } 144 145 bool Animation::IsFinishedAt(double monotonic_time) const { 146 if (is_finished()) 147 return true; 148 149 if (needs_synchronized_start_time_) 150 return false; 151 152 return run_state_ == Running && 153 iterations_ >= 0 && 154 iterations_ * curve_->Duration() <= (monotonic_time - 155 start_time() - 156 total_paused_time_); 157 } 158 159 double Animation::TrimTimeToCurrentIteration(double monotonic_time) const { 160 double trimmed = monotonic_time + time_offset_; 161 162 // If we're paused, time is 'stuck' at the pause time. 163 if (run_state_ == Paused) 164 trimmed = pause_time_; 165 166 // Returned time should always be relative to the start time and should 167 // subtract all time spent paused. 168 trimmed -= start_time_ + total_paused_time_; 169 170 // Zero is always the start of the animation. 171 if (trimmed <= 0) 172 return 0; 173 174 // Always return zero if we have no iterations. 175 if (!iterations_) 176 return 0; 177 178 // Don't attempt to trim if we have no duration. 179 if (curve_->Duration() <= 0) 180 return 0; 181 182 // If less than an iteration duration, just return trimmed. 183 if (trimmed < curve_->Duration()) 184 return trimmed; 185 186 // If greater than or equal to the total duration, return iteration duration. 187 if (iterations_ >= 0 && trimmed >= curve_->Duration() * iterations_) { 188 if (alternates_direction_ && !(iterations_ % 2)) 189 return 0; 190 return curve_->Duration(); 191 } 192 193 // We need to know the current iteration if we're alternating. 194 int iteration = static_cast<int>(trimmed / curve_->Duration()); 195 196 // Calculate x where trimmed = x + n * curve_->Duration() for some positive 197 // integer n. 198 trimmed = fmod(trimmed, curve_->Duration()); 199 200 // If we're alternating and on an odd iteration, reverse the direction. 201 if (alternates_direction_ && iteration % 2 == 1) 202 return curve_->Duration() - trimmed; 203 204 return trimmed; 205 } 206 207 scoped_ptr<Animation> Animation::Clone(InstanceType instance_type) const { 208 return CloneAndInitialize(instance_type, run_state_, start_time_); 209 } 210 211 scoped_ptr<Animation> Animation::CloneAndInitialize(InstanceType instance_type, 212 RunState initial_run_state, 213 double start_time) const { 214 scoped_ptr<Animation> to_return( 215 new Animation(curve_->Clone(), id_, group_, target_property_)); 216 to_return->run_state_ = initial_run_state; 217 to_return->iterations_ = iterations_; 218 to_return->start_time_ = start_time; 219 to_return->pause_time_ = pause_time_; 220 to_return->total_paused_time_ = total_paused_time_; 221 to_return->time_offset_ = time_offset_; 222 to_return->alternates_direction_ = alternates_direction_; 223 to_return->is_controlling_instance_ = instance_type == ControllingInstance; 224 return to_return.Pass(); 225 } 226 227 void Animation::PushPropertiesTo(Animation* other) const { 228 // Currently, we only push changes due to pausing and resuming animations on 229 // the main thread. 230 if (run_state_ == Animation::Paused || 231 other->run_state_ == Animation::Paused) { 232 other->run_state_ = run_state_; 233 other->pause_time_ = pause_time_; 234 other->total_paused_time_ = total_paused_time_; 235 } 236 } 237 238 } // namespace cc 239