| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 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 "ui/compositor/layer_animator.h" | |
| 6 | |
| 7 #include "base/debug/trace_event.h" | |
| 8 #include "base/logging.h" | |
| 9 #include "base/memory/scoped_ptr.h" | |
| 10 #include "cc/animation/animation_id_provider.h" | |
| 11 #include "cc/output/begin_frame_args.h" | |
| 12 #include "ui/compositor/compositor.h" | |
| 13 #include "ui/compositor/layer.h" | |
| 14 #include "ui/compositor/layer_animation_delegate.h" | |
| 15 #include "ui/compositor/layer_animation_observer.h" | |
| 16 #include "ui/compositor/layer_animation_sequence.h" | |
| 17 #include "ui/compositor/layer_animator_collection.h" | |
| 18 #include "ui/gfx/frame_time.h" | |
| 19 | |
| 20 #define SAFE_INVOKE_VOID(function, running_anim, ...) \ | |
| 21 if (running_anim.is_sequence_alive()) \ | |
| 22 function(running_anim.sequence(), ##__VA_ARGS__) | |
| 23 #define SAFE_INVOKE_BOOL(function, running_anim) \ | |
| 24 ((running_anim.is_sequence_alive()) \ | |
| 25 ? function(running_anim.sequence()) \ | |
| 26 : false) | |
| 27 #define SAFE_INVOKE_PTR(function, running_anim) \ | |
| 28 ((running_anim.is_sequence_alive()) \ | |
| 29 ? function(running_anim.sequence()) \ | |
| 30 : NULL) | |
| 31 | |
| 32 namespace ui { | |
| 33 | |
| 34 namespace { | |
| 35 | |
| 36 const int kDefaultTransitionDurationMs = 120; | |
| 37 | |
| 38 } // namespace | |
| 39 | |
| 40 // LayerAnimator public -------------------------------------------------------- | |
| 41 | |
| 42 LayerAnimator::LayerAnimator(base::TimeDelta transition_duration) | |
| 43 : delegate_(NULL), | |
| 44 preemption_strategy_(IMMEDIATELY_SET_NEW_TARGET), | |
| 45 is_transition_duration_locked_(false), | |
| 46 transition_duration_(transition_duration), | |
| 47 tween_type_(gfx::Tween::LINEAR), | |
| 48 is_started_(false), | |
| 49 disable_timer_for_test_(false), | |
| 50 adding_animations_(false) { | |
| 51 } | |
| 52 | |
| 53 LayerAnimator::~LayerAnimator() { | |
| 54 for (size_t i = 0; i < running_animations_.size(); ++i) { | |
| 55 if (running_animations_[i].is_sequence_alive()) | |
| 56 running_animations_[i].sequence()->OnAnimatorDestroyed(); | |
| 57 } | |
| 58 ClearAnimationsInternal(); | |
| 59 delegate_ = NULL; | |
| 60 } | |
| 61 | |
| 62 // static | |
| 63 LayerAnimator* LayerAnimator::CreateDefaultAnimator() { | |
| 64 return new LayerAnimator(base::TimeDelta::FromMilliseconds(0)); | |
| 65 } | |
| 66 | |
| 67 // static | |
| 68 LayerAnimator* LayerAnimator::CreateImplicitAnimator() { | |
| 69 return new LayerAnimator( | |
| 70 base::TimeDelta::FromMilliseconds(kDefaultTransitionDurationMs)); | |
| 71 } | |
| 72 | |
| 73 // This macro provides the implementation for the setter and getter (well, | |
| 74 // the getter of the target value) for an animated property. For example, | |
| 75 // it is used for the implementations of SetTransform and GetTargetTransform. | |
| 76 // It is worth noting that SetFoo avoids invoking the usual animation machinery | |
| 77 // if the transition duration is zero -- in this case we just set the property | |
| 78 // on the layer animation delegate immediately. | |
| 79 #define ANIMATED_PROPERTY(type, property, name, member_type, member) \ | |
| 80 void LayerAnimator::Set##name(type value) { \ | |
| 81 base::TimeDelta duration = GetTransitionDuration(); \ | |
| 82 if (duration == base::TimeDelta() && delegate() && \ | |
| 83 (preemption_strategy_ != ENQUEUE_NEW_ANIMATION)) { \ | |
| 84 StopAnimatingProperty(LayerAnimationElement::property); \ | |
| 85 delegate()->Set##name##FromAnimation(value); \ | |
| 86 return; \ | |
| 87 } \ | |
| 88 scoped_ptr<LayerAnimationElement> element( \ | |
| 89 LayerAnimationElement::Create##name##Element(value, duration)); \ | |
| 90 element->set_tween_type(tween_type_); \ | |
| 91 StartAnimation(new LayerAnimationSequence(element.release())); \ | |
| 92 } \ | |
| 93 \ | |
| 94 member_type LayerAnimator::GetTarget##name() const { \ | |
| 95 LayerAnimationElement::TargetValue target(delegate()); \ | |
| 96 GetTargetValue(&target); \ | |
| 97 return target.member; \ | |
| 98 } | |
| 99 | |
| 100 ANIMATED_PROPERTY( | |
| 101 const gfx::Transform&, TRANSFORM, Transform, gfx::Transform, transform); | |
| 102 ANIMATED_PROPERTY(const gfx::Rect&, BOUNDS, Bounds, gfx::Rect, bounds); | |
| 103 ANIMATED_PROPERTY(float, OPACITY, Opacity, float, opacity); | |
| 104 ANIMATED_PROPERTY(bool, VISIBILITY, Visibility, bool, visibility); | |
| 105 ANIMATED_PROPERTY(float, BRIGHTNESS, Brightness, float, brightness); | |
| 106 ANIMATED_PROPERTY(float, GRAYSCALE, Grayscale, float, grayscale); | |
| 107 ANIMATED_PROPERTY(SkColor, COLOR, Color, SkColor, color); | |
| 108 | |
| 109 base::TimeDelta LayerAnimator::GetTransitionDuration() const { | |
| 110 return transition_duration_; | |
| 111 } | |
| 112 | |
| 113 void LayerAnimator::SetDelegate(LayerAnimationDelegate* delegate) { | |
| 114 if (delegate_ && is_started_) { | |
| 115 LayerAnimatorCollection* collection = GetLayerAnimatorCollection(); | |
| 116 if (collection) | |
| 117 collection->StopAnimator(this); | |
| 118 } | |
| 119 delegate_ = delegate; | |
| 120 if (delegate_ && is_started_) { | |
| 121 LayerAnimatorCollection* collection = GetLayerAnimatorCollection(); | |
| 122 if (collection) | |
| 123 collection->StartAnimator(this); | |
| 124 } | |
| 125 } | |
| 126 | |
| 127 void LayerAnimator::StartAnimation(LayerAnimationSequence* animation) { | |
| 128 scoped_refptr<LayerAnimator> retain(this); | |
| 129 OnScheduled(animation); | |
| 130 if (!StartSequenceImmediately(animation)) { | |
| 131 // Attempt to preempt a running animation. | |
| 132 switch (preemption_strategy_) { | |
| 133 case IMMEDIATELY_SET_NEW_TARGET: | |
| 134 ImmediatelySetNewTarget(animation); | |
| 135 break; | |
| 136 case IMMEDIATELY_ANIMATE_TO_NEW_TARGET: | |
| 137 ImmediatelyAnimateToNewTarget(animation); | |
| 138 break; | |
| 139 case ENQUEUE_NEW_ANIMATION: | |
| 140 EnqueueNewAnimation(animation); | |
| 141 break; | |
| 142 case REPLACE_QUEUED_ANIMATIONS: | |
| 143 ReplaceQueuedAnimations(animation); | |
| 144 break; | |
| 145 case BLEND_WITH_CURRENT_ANIMATION: { | |
| 146 // TODO(vollick) Add support for blended sequences and use them here. | |
| 147 NOTIMPLEMENTED(); | |
| 148 break; | |
| 149 } | |
| 150 } | |
| 151 } | |
| 152 FinishAnyAnimationWithZeroDuration(); | |
| 153 UpdateAnimationState(); | |
| 154 } | |
| 155 | |
| 156 void LayerAnimator::ScheduleAnimation(LayerAnimationSequence* animation) { | |
| 157 scoped_refptr<LayerAnimator> retain(this); | |
| 158 OnScheduled(animation); | |
| 159 if (is_animating()) { | |
| 160 animation_queue_.push_back(make_linked_ptr(animation)); | |
| 161 ProcessQueue(); | |
| 162 } else { | |
| 163 StartSequenceImmediately(animation); | |
| 164 } | |
| 165 UpdateAnimationState(); | |
| 166 } | |
| 167 | |
| 168 void LayerAnimator::StartTogether( | |
| 169 const std::vector<LayerAnimationSequence*>& animations) { | |
| 170 scoped_refptr<LayerAnimator> retain(this); | |
| 171 if (preemption_strategy_ == IMMEDIATELY_SET_NEW_TARGET) { | |
| 172 std::vector<LayerAnimationSequence*>::const_iterator iter; | |
| 173 for (iter = animations.begin(); iter != animations.end(); ++iter) { | |
| 174 StartAnimation(*iter); | |
| 175 } | |
| 176 return; | |
| 177 } | |
| 178 | |
| 179 adding_animations_ = true; | |
| 180 if (!is_animating()) { | |
| 181 LayerAnimatorCollection* collection = GetLayerAnimatorCollection(); | |
| 182 if (collection && collection->HasActiveAnimators()) | |
| 183 last_step_time_ = collection->last_tick_time(); | |
| 184 else | |
| 185 last_step_time_ = gfx::FrameTime::Now(); | |
| 186 } | |
| 187 | |
| 188 // Collect all the affected properties. | |
| 189 LayerAnimationElement::AnimatableProperties animated_properties = | |
| 190 LayerAnimationElement::UNKNOWN; | |
| 191 | |
| 192 std::vector<LayerAnimationSequence*>::const_iterator iter; | |
| 193 for (iter = animations.begin(); iter != animations.end(); ++iter) | |
| 194 animated_properties |= (*iter)->properties(); | |
| 195 | |
| 196 // Starting a zero duration pause that affects all the animated properties | |
| 197 // will prevent any of the sequences from animating until there are no | |
| 198 // running animations that affect any of these properties, as well as | |
| 199 // handle preemption strategy. | |
| 200 StartAnimation(new LayerAnimationSequence( | |
| 201 LayerAnimationElement::CreatePauseElement(animated_properties, | |
| 202 base::TimeDelta()))); | |
| 203 | |
| 204 bool wait_for_group_start = false; | |
| 205 for (iter = animations.begin(); iter != animations.end(); ++iter) | |
| 206 wait_for_group_start |= (*iter)->IsFirstElementThreaded(); | |
| 207 | |
| 208 int group_id = cc::AnimationIdProvider::NextGroupId(); | |
| 209 | |
| 210 // These animations (provided they don't animate any common properties) will | |
| 211 // now animate together if trivially scheduled. | |
| 212 for (iter = animations.begin(); iter != animations.end(); ++iter) { | |
| 213 (*iter)->set_animation_group_id(group_id); | |
| 214 (*iter)->set_waiting_for_group_start(wait_for_group_start); | |
| 215 ScheduleAnimation(*iter); | |
| 216 } | |
| 217 | |
| 218 adding_animations_ = false; | |
| 219 UpdateAnimationState(); | |
| 220 } | |
| 221 | |
| 222 | |
| 223 void LayerAnimator::ScheduleTogether( | |
| 224 const std::vector<LayerAnimationSequence*>& animations) { | |
| 225 scoped_refptr<LayerAnimator> retain(this); | |
| 226 | |
| 227 // Collect all the affected properties. | |
| 228 LayerAnimationElement::AnimatableProperties animated_properties = | |
| 229 LayerAnimationElement::UNKNOWN; | |
| 230 | |
| 231 std::vector<LayerAnimationSequence*>::const_iterator iter; | |
| 232 for (iter = animations.begin(); iter != animations.end(); ++iter) | |
| 233 animated_properties |= (*iter)->properties(); | |
| 234 | |
| 235 // Scheduling a zero duration pause that affects all the animated properties | |
| 236 // will prevent any of the sequences from animating until there are no | |
| 237 // running animations that affect any of these properties. | |
| 238 ScheduleAnimation(new LayerAnimationSequence( | |
| 239 LayerAnimationElement::CreatePauseElement(animated_properties, | |
| 240 base::TimeDelta()))); | |
| 241 | |
| 242 bool wait_for_group_start = false; | |
| 243 for (iter = animations.begin(); iter != animations.end(); ++iter) | |
| 244 wait_for_group_start |= (*iter)->IsFirstElementThreaded(); | |
| 245 | |
| 246 int group_id = cc::AnimationIdProvider::NextGroupId(); | |
| 247 | |
| 248 // These animations (provided they don't animate any common properties) will | |
| 249 // now animate together if trivially scheduled. | |
| 250 for (iter = animations.begin(); iter != animations.end(); ++iter) { | |
| 251 (*iter)->set_animation_group_id(group_id); | |
| 252 (*iter)->set_waiting_for_group_start(wait_for_group_start); | |
| 253 ScheduleAnimation(*iter); | |
| 254 } | |
| 255 | |
| 256 UpdateAnimationState(); | |
| 257 } | |
| 258 | |
| 259 void LayerAnimator::SchedulePauseForProperties( | |
| 260 base::TimeDelta duration, | |
| 261 LayerAnimationElement::AnimatableProperties properties_to_pause) { | |
| 262 ScheduleAnimation(new ui::LayerAnimationSequence( | |
| 263 ui::LayerAnimationElement::CreatePauseElement( | |
| 264 properties_to_pause, duration))); | |
| 265 } | |
| 266 | |
| 267 bool LayerAnimator::IsAnimatingProperty( | |
| 268 LayerAnimationElement::AnimatableProperty property) const { | |
| 269 for (AnimationQueue::const_iterator queue_iter = animation_queue_.begin(); | |
| 270 queue_iter != animation_queue_.end(); ++queue_iter) { | |
| 271 if ((*queue_iter)->properties() & property) | |
| 272 return true; | |
| 273 } | |
| 274 return false; | |
| 275 } | |
| 276 | |
| 277 void LayerAnimator::StopAnimatingProperty( | |
| 278 LayerAnimationElement::AnimatableProperty property) { | |
| 279 scoped_refptr<LayerAnimator> retain(this); | |
| 280 while (true) { | |
| 281 // GetRunningAnimation purges deleted animations before searching, so we are | |
| 282 // guaranteed to find a live animation if any is returned at all. | |
| 283 RunningAnimation* running = GetRunningAnimation(property); | |
| 284 if (!running) | |
| 285 break; | |
| 286 // As was mentioned above, this sequence must be alive. | |
| 287 DCHECK(running->is_sequence_alive()); | |
| 288 FinishAnimation(running->sequence(), false); | |
| 289 } | |
| 290 } | |
| 291 | |
| 292 void LayerAnimator::AddObserver(LayerAnimationObserver* observer) { | |
| 293 if (!observers_.HasObserver(observer)) | |
| 294 observers_.AddObserver(observer); | |
| 295 } | |
| 296 | |
| 297 void LayerAnimator::RemoveObserver(LayerAnimationObserver* observer) { | |
| 298 observers_.RemoveObserver(observer); | |
| 299 // Remove the observer from all sequences as well. | |
| 300 for (AnimationQueue::iterator queue_iter = animation_queue_.begin(); | |
| 301 queue_iter != animation_queue_.end(); ++queue_iter) { | |
| 302 (*queue_iter)->RemoveObserver(observer); | |
| 303 } | |
| 304 } | |
| 305 | |
| 306 void LayerAnimator::OnThreadedAnimationStarted( | |
| 307 const cc::AnimationEvent& event) { | |
| 308 LayerAnimationElement::AnimatableProperty property = | |
| 309 LayerAnimationElement::ToAnimatableProperty(event.target_property); | |
| 310 | |
| 311 RunningAnimation* running = GetRunningAnimation(property); | |
| 312 if (!running) | |
| 313 return; | |
| 314 DCHECK(running->is_sequence_alive()); | |
| 315 | |
| 316 if (running->sequence()->animation_group_id() != event.group_id) | |
| 317 return; | |
| 318 | |
| 319 running->sequence()->OnThreadedAnimationStarted(event); | |
| 320 if (!running->sequence()->waiting_for_group_start()) | |
| 321 return; | |
| 322 | |
| 323 base::TimeTicks start_time = event.monotonic_time; | |
| 324 | |
| 325 running->sequence()->set_waiting_for_group_start(false); | |
| 326 | |
| 327 // The call to GetRunningAnimation made above already purged deleted | |
| 328 // animations, so we are guaranteed that all the animations we iterate | |
| 329 // over now are alive. | |
| 330 for (RunningAnimations::iterator iter = running_animations_.begin(); | |
| 331 iter != running_animations_.end(); ++iter) { | |
| 332 // Ensure that each sequence is only Started once, regardless of the | |
| 333 // number of sequences in the group that have threaded first elements. | |
| 334 if (((*iter).sequence()->animation_group_id() == event.group_id) && | |
| 335 !(*iter).sequence()->IsFirstElementThreaded() && | |
| 336 (*iter).sequence()->waiting_for_group_start()) { | |
| 337 (*iter).sequence()->set_start_time(start_time); | |
| 338 (*iter).sequence()->set_waiting_for_group_start(false); | |
| 339 (*iter).sequence()->Start(delegate()); | |
| 340 } | |
| 341 } | |
| 342 } | |
| 343 | |
| 344 void LayerAnimator::AddToCollection(LayerAnimatorCollection* collection) { | |
| 345 if (is_animating() && !is_started_) { | |
| 346 collection->StartAnimator(this); | |
| 347 is_started_ = true; | |
| 348 } | |
| 349 } | |
| 350 | |
| 351 void LayerAnimator::RemoveFromCollection(LayerAnimatorCollection* collection) { | |
| 352 if (is_animating() && is_started_) { | |
| 353 collection->StopAnimator(this); | |
| 354 is_started_ = false; | |
| 355 } | |
| 356 } | |
| 357 | |
| 358 // LayerAnimator protected ----------------------------------------------------- | |
| 359 | |
| 360 void LayerAnimator::ProgressAnimation(LayerAnimationSequence* sequence, | |
| 361 base::TimeTicks now) { | |
| 362 if (!delegate() || sequence->waiting_for_group_start()) | |
| 363 return; | |
| 364 | |
| 365 sequence->Progress(now, delegate()); | |
| 366 } | |
| 367 | |
| 368 void LayerAnimator::ProgressAnimationToEnd(LayerAnimationSequence* sequence) { | |
| 369 if (!delegate()) | |
| 370 return; | |
| 371 | |
| 372 sequence->ProgressToEnd(delegate()); | |
| 373 } | |
| 374 | |
| 375 bool LayerAnimator::HasAnimation(LayerAnimationSequence* sequence) const { | |
| 376 for (AnimationQueue::const_iterator queue_iter = animation_queue_.begin(); | |
| 377 queue_iter != animation_queue_.end(); ++queue_iter) { | |
| 378 if ((*queue_iter).get() == sequence) | |
| 379 return true; | |
| 380 } | |
| 381 return false; | |
| 382 } | |
| 383 | |
| 384 // LayerAnimator private ------------------------------------------------------- | |
| 385 | |
| 386 void LayerAnimator::Step(base::TimeTicks now) { | |
| 387 TRACE_EVENT0("ui", "LayerAnimator::Step"); | |
| 388 scoped_refptr<LayerAnimator> retain(this); | |
| 389 | |
| 390 last_step_time_ = now; | |
| 391 | |
| 392 PurgeDeletedAnimations(); | |
| 393 | |
| 394 // We need to make a copy of the running animations because progressing them | |
| 395 // and finishing them may indirectly affect the collection of running | |
| 396 // animations. | |
| 397 RunningAnimations running_animations_copy = running_animations_; | |
| 398 for (size_t i = 0; i < running_animations_copy.size(); ++i) { | |
| 399 if (!SAFE_INVOKE_BOOL(HasAnimation, running_animations_copy[i])) | |
| 400 continue; | |
| 401 | |
| 402 if (running_animations_copy[i].sequence()->IsFinished(now)) { | |
| 403 SAFE_INVOKE_VOID(FinishAnimation, running_animations_copy[i], false); | |
| 404 } else { | |
| 405 SAFE_INVOKE_VOID(ProgressAnimation, running_animations_copy[i], now); | |
| 406 } | |
| 407 } | |
| 408 } | |
| 409 | |
| 410 void LayerAnimator::StopAnimatingInternal(bool abort) { | |
| 411 scoped_refptr<LayerAnimator> retain(this); | |
| 412 while (is_animating()) { | |
| 413 // We're going to attempt to finish the first running animation. Let's | |
| 414 // ensure that it's valid. | |
| 415 PurgeDeletedAnimations(); | |
| 416 | |
| 417 // If we've purged all running animations, attempt to start one up. | |
| 418 if (running_animations_.empty()) | |
| 419 ProcessQueue(); | |
| 420 | |
| 421 DCHECK(!running_animations_.empty()); | |
| 422 | |
| 423 // Still no luck, let's just bail and clear all animations. | |
| 424 if (running_animations_.empty()) { | |
| 425 ClearAnimationsInternal(); | |
| 426 break; | |
| 427 } | |
| 428 | |
| 429 SAFE_INVOKE_VOID(FinishAnimation, running_animations_[0], abort); | |
| 430 } | |
| 431 } | |
| 432 | |
| 433 void LayerAnimator::UpdateAnimationState() { | |
| 434 if (disable_timer_for_test_) | |
| 435 return; | |
| 436 | |
| 437 const bool should_start = is_animating(); | |
| 438 LayerAnimatorCollection* collection = GetLayerAnimatorCollection(); | |
| 439 if (collection) { | |
| 440 if (should_start && !is_started_) | |
| 441 collection->StartAnimator(this); | |
| 442 else if (!should_start && is_started_) | |
| 443 collection->StopAnimator(this); | |
| 444 is_started_ = should_start; | |
| 445 } else { | |
| 446 is_started_ = false; | |
| 447 } | |
| 448 } | |
| 449 | |
| 450 LayerAnimationSequence* LayerAnimator::RemoveAnimation( | |
| 451 LayerAnimationSequence* sequence) { | |
| 452 linked_ptr<LayerAnimationSequence> to_return; | |
| 453 | |
| 454 bool is_running = false; | |
| 455 | |
| 456 // First remove from running animations | |
| 457 for (RunningAnimations::iterator iter = running_animations_.begin(); | |
| 458 iter != running_animations_.end(); ++iter) { | |
| 459 if ((*iter).sequence() == sequence) { | |
| 460 running_animations_.erase(iter); | |
| 461 is_running = true; | |
| 462 break; | |
| 463 } | |
| 464 } | |
| 465 | |
| 466 // Then remove from the queue | |
| 467 for (AnimationQueue::iterator queue_iter = animation_queue_.begin(); | |
| 468 queue_iter != animation_queue_.end(); ++queue_iter) { | |
| 469 if ((*queue_iter) == sequence) { | |
| 470 to_return = *queue_iter; | |
| 471 animation_queue_.erase(queue_iter); | |
| 472 break; | |
| 473 } | |
| 474 } | |
| 475 | |
| 476 if (!to_return.get() || | |
| 477 !to_return->waiting_for_group_start() || | |
| 478 !to_return->IsFirstElementThreaded()) | |
| 479 return to_return.release(); | |
| 480 | |
| 481 // The removed sequence may have been responsible for making other sequences | |
| 482 // wait for a group start. If no other sequences in the group have a | |
| 483 // threaded first element, the group no longer needs the additional wait. | |
| 484 bool is_wait_still_needed = false; | |
| 485 int group_id = to_return->animation_group_id(); | |
| 486 for (AnimationQueue::iterator queue_iter = animation_queue_.begin(); | |
| 487 queue_iter != animation_queue_.end(); ++queue_iter) { | |
| 488 if (((*queue_iter)->animation_group_id() == group_id) && | |
| 489 (*queue_iter)->IsFirstElementThreaded()) { | |
| 490 is_wait_still_needed = true; | |
| 491 break; | |
| 492 } | |
| 493 } | |
| 494 | |
| 495 if (is_wait_still_needed) | |
| 496 return to_return.release(); | |
| 497 | |
| 498 for (AnimationQueue::iterator queue_iter = animation_queue_.begin(); | |
| 499 queue_iter != animation_queue_.end(); ++queue_iter) { | |
| 500 if ((*queue_iter)->animation_group_id() == group_id && | |
| 501 (*queue_iter)->waiting_for_group_start()) { | |
| 502 (*queue_iter)->set_waiting_for_group_start(false); | |
| 503 if (is_running) { | |
| 504 (*queue_iter)->set_start_time(last_step_time_); | |
| 505 (*queue_iter)->Start(delegate()); | |
| 506 } | |
| 507 } | |
| 508 } | |
| 509 return to_return.release(); | |
| 510 } | |
| 511 | |
| 512 void LayerAnimator::FinishAnimation( | |
| 513 LayerAnimationSequence* sequence, bool abort) { | |
| 514 scoped_refptr<LayerAnimator> retain(this); | |
| 515 scoped_ptr<LayerAnimationSequence> removed(RemoveAnimation(sequence)); | |
| 516 if (abort) | |
| 517 sequence->Abort(delegate()); | |
| 518 else | |
| 519 ProgressAnimationToEnd(sequence); | |
| 520 ProcessQueue(); | |
| 521 UpdateAnimationState(); | |
| 522 } | |
| 523 | |
| 524 void LayerAnimator::FinishAnyAnimationWithZeroDuration() { | |
| 525 scoped_refptr<LayerAnimator> retain(this); | |
| 526 // Special case: if we've started a 0 duration animation, just finish it now | |
| 527 // and get rid of it. We need to make a copy because Progress may indirectly | |
| 528 // cause new animations to start running. | |
| 529 RunningAnimations running_animations_copy = running_animations_; | |
| 530 for (size_t i = 0; i < running_animations_copy.size(); ++i) { | |
| 531 if (!SAFE_INVOKE_BOOL(HasAnimation, running_animations_copy[i])) | |
| 532 continue; | |
| 533 | |
| 534 if (running_animations_copy[i].sequence()->IsFinished( | |
| 535 running_animations_copy[i].sequence()->start_time())) { | |
| 536 SAFE_INVOKE_VOID(ProgressAnimationToEnd, running_animations_copy[i]); | |
| 537 scoped_ptr<LayerAnimationSequence> removed( | |
| 538 SAFE_INVOKE_PTR(RemoveAnimation, running_animations_copy[i])); | |
| 539 } | |
| 540 } | |
| 541 ProcessQueue(); | |
| 542 UpdateAnimationState(); | |
| 543 } | |
| 544 | |
| 545 void LayerAnimator::ClearAnimations() { | |
| 546 scoped_refptr<LayerAnimator> retain(this); | |
| 547 ClearAnimationsInternal(); | |
| 548 } | |
| 549 | |
| 550 LayerAnimator::RunningAnimation* LayerAnimator::GetRunningAnimation( | |
| 551 LayerAnimationElement::AnimatableProperty property) { | |
| 552 PurgeDeletedAnimations(); | |
| 553 for (RunningAnimations::iterator iter = running_animations_.begin(); | |
| 554 iter != running_animations_.end(); ++iter) { | |
| 555 if ((*iter).sequence()->properties() & property) | |
| 556 return &(*iter); | |
| 557 } | |
| 558 return NULL; | |
| 559 } | |
| 560 | |
| 561 void LayerAnimator::AddToQueueIfNotPresent(LayerAnimationSequence* animation) { | |
| 562 // If we don't have the animation in the queue yet, add it. | |
| 563 bool found_sequence = false; | |
| 564 for (AnimationQueue::iterator queue_iter = animation_queue_.begin(); | |
| 565 queue_iter != animation_queue_.end(); ++queue_iter) { | |
| 566 if ((*queue_iter) == animation) { | |
| 567 found_sequence = true; | |
| 568 break; | |
| 569 } | |
| 570 } | |
| 571 | |
| 572 if (!found_sequence) | |
| 573 animation_queue_.push_front(make_linked_ptr(animation)); | |
| 574 } | |
| 575 | |
| 576 void LayerAnimator::RemoveAllAnimationsWithACommonProperty( | |
| 577 LayerAnimationSequence* sequence, bool abort) { | |
| 578 // For all the running animations, if they animate the same property, | |
| 579 // progress them to the end and remove them. Note, Aborting or Progressing | |
| 580 // animations may affect the collection of running animations, so we need to | |
| 581 // operate on a copy. | |
| 582 RunningAnimations running_animations_copy = running_animations_; | |
| 583 for (size_t i = 0; i < running_animations_copy.size(); ++i) { | |
| 584 if (!SAFE_INVOKE_BOOL(HasAnimation, running_animations_copy[i])) | |
| 585 continue; | |
| 586 | |
| 587 if (running_animations_copy[i].sequence()->HasConflictingProperty( | |
| 588 sequence->properties())) { | |
| 589 scoped_ptr<LayerAnimationSequence> removed( | |
| 590 SAFE_INVOKE_PTR(RemoveAnimation, running_animations_copy[i])); | |
| 591 if (abort) | |
| 592 running_animations_copy[i].sequence()->Abort(delegate()); | |
| 593 else | |
| 594 SAFE_INVOKE_VOID(ProgressAnimationToEnd, running_animations_copy[i]); | |
| 595 } | |
| 596 } | |
| 597 | |
| 598 // Same for the queued animations that haven't been started. Again, we'll | |
| 599 // need to operate on a copy. | |
| 600 std::vector<base::WeakPtr<LayerAnimationSequence> > sequences; | |
| 601 for (AnimationQueue::iterator queue_iter = animation_queue_.begin(); | |
| 602 queue_iter != animation_queue_.end(); ++queue_iter) | |
| 603 sequences.push_back((*queue_iter)->AsWeakPtr()); | |
| 604 | |
| 605 for (size_t i = 0; i < sequences.size(); ++i) { | |
| 606 if (!sequences[i].get() || !HasAnimation(sequences[i].get())) | |
| 607 continue; | |
| 608 | |
| 609 if (sequences[i]->HasConflictingProperty(sequence->properties())) { | |
| 610 scoped_ptr<LayerAnimationSequence> removed( | |
| 611 RemoveAnimation(sequences[i].get())); | |
| 612 if (abort) | |
| 613 sequences[i]->Abort(delegate()); | |
| 614 else | |
| 615 ProgressAnimationToEnd(sequences[i].get()); | |
| 616 } | |
| 617 } | |
| 618 } | |
| 619 | |
| 620 void LayerAnimator::ImmediatelySetNewTarget(LayerAnimationSequence* sequence) { | |
| 621 // Need to detect if our sequence gets destroyed. | |
| 622 base::WeakPtr<LayerAnimationSequence> weak_sequence_ptr = | |
| 623 sequence->AsWeakPtr(); | |
| 624 | |
| 625 const bool abort = false; | |
| 626 RemoveAllAnimationsWithACommonProperty(sequence, abort); | |
| 627 if (!weak_sequence_ptr.get()) | |
| 628 return; | |
| 629 | |
| 630 LayerAnimationSequence* removed = RemoveAnimation(sequence); | |
| 631 DCHECK(removed == NULL || removed == sequence); | |
| 632 if (!weak_sequence_ptr.get()) | |
| 633 return; | |
| 634 | |
| 635 ProgressAnimationToEnd(sequence); | |
| 636 if (!weak_sequence_ptr.get()) | |
| 637 return; | |
| 638 | |
| 639 delete sequence; | |
| 640 } | |
| 641 | |
| 642 void LayerAnimator::ImmediatelyAnimateToNewTarget( | |
| 643 LayerAnimationSequence* sequence) { | |
| 644 // Need to detect if our sequence gets destroyed. | |
| 645 base::WeakPtr<LayerAnimationSequence> weak_sequence_ptr = | |
| 646 sequence->AsWeakPtr(); | |
| 647 | |
| 648 const bool abort = true; | |
| 649 RemoveAllAnimationsWithACommonProperty(sequence, abort); | |
| 650 if (!weak_sequence_ptr.get()) | |
| 651 return; | |
| 652 | |
| 653 AddToQueueIfNotPresent(sequence); | |
| 654 if (!weak_sequence_ptr.get()) | |
| 655 return; | |
| 656 | |
| 657 StartSequenceImmediately(sequence); | |
| 658 } | |
| 659 | |
| 660 void LayerAnimator::EnqueueNewAnimation(LayerAnimationSequence* sequence) { | |
| 661 // It is assumed that if there was no conflicting animation, we would | |
| 662 // not have been called. No need to check for a collision; just | |
| 663 // add to the queue. | |
| 664 animation_queue_.push_back(make_linked_ptr(sequence)); | |
| 665 ProcessQueue(); | |
| 666 } | |
| 667 | |
| 668 void LayerAnimator::ReplaceQueuedAnimations(LayerAnimationSequence* sequence) { | |
| 669 // Need to detect if our sequence gets destroyed. | |
| 670 base::WeakPtr<LayerAnimationSequence> weak_sequence_ptr = | |
| 671 sequence->AsWeakPtr(); | |
| 672 | |
| 673 // Remove all animations that aren't running. Note: at each iteration i is | |
| 674 // incremented or an element is removed from the queue, so | |
| 675 // animation_queue_.size() - i is always decreasing and we are always making | |
| 676 // progress towards the loop terminating. | |
| 677 for (size_t i = 0; i < animation_queue_.size();) { | |
| 678 if (!weak_sequence_ptr.get()) | |
| 679 break; | |
| 680 | |
| 681 PurgeDeletedAnimations(); | |
| 682 | |
| 683 bool is_running = false; | |
| 684 for (RunningAnimations::const_iterator iter = running_animations_.begin(); | |
| 685 iter != running_animations_.end(); ++iter) { | |
| 686 if ((*iter).sequence() == animation_queue_[i].get()) { | |
| 687 is_running = true; | |
| 688 break; | |
| 689 } | |
| 690 } | |
| 691 | |
| 692 if (!is_running) | |
| 693 delete RemoveAnimation(animation_queue_[i].get()); | |
| 694 else | |
| 695 ++i; | |
| 696 } | |
| 697 animation_queue_.push_back(make_linked_ptr(sequence)); | |
| 698 ProcessQueue(); | |
| 699 } | |
| 700 | |
| 701 void LayerAnimator::ProcessQueue() { | |
| 702 bool started_sequence = false; | |
| 703 do { | |
| 704 started_sequence = false; | |
| 705 // Build a list of all currently animated properties. | |
| 706 LayerAnimationElement::AnimatableProperties animated = | |
| 707 LayerAnimationElement::UNKNOWN; | |
| 708 for (RunningAnimations::const_iterator iter = running_animations_.begin(); | |
| 709 iter != running_animations_.end(); ++iter) { | |
| 710 if (!(*iter).is_sequence_alive()) | |
| 711 continue; | |
| 712 | |
| 713 animated |= (*iter).sequence()->properties(); | |
| 714 } | |
| 715 | |
| 716 // Try to find an animation that doesn't conflict with an animated | |
| 717 // property or a property that will be animated before it. Note: starting | |
| 718 // the animation may indirectly cause more animations to be started, so we | |
| 719 // need to operate on a copy. | |
| 720 std::vector<base::WeakPtr<LayerAnimationSequence> > sequences; | |
| 721 for (AnimationQueue::iterator queue_iter = animation_queue_.begin(); | |
| 722 queue_iter != animation_queue_.end(); ++queue_iter) | |
| 723 sequences.push_back((*queue_iter)->AsWeakPtr()); | |
| 724 | |
| 725 for (size_t i = 0; i < sequences.size(); ++i) { | |
| 726 if (!sequences[i].get() || !HasAnimation(sequences[i].get())) | |
| 727 continue; | |
| 728 | |
| 729 if (!sequences[i]->HasConflictingProperty(animated)) { | |
| 730 StartSequenceImmediately(sequences[i].get()); | |
| 731 started_sequence = true; | |
| 732 break; | |
| 733 } | |
| 734 | |
| 735 // Animation couldn't be started. Add its properties to the collection so | |
| 736 // that we don't start a conflicting animation. For example, if our queue | |
| 737 // has the elements { {T,B}, {B} } (that is, an element that animates both | |
| 738 // the transform and the bounds followed by an element that animates the | |
| 739 // bounds), and we're currently animating the transform, we can't start | |
| 740 // the first element because it animates the transform, too. We cannot | |
| 741 // start the second element, either, because the first element animates | |
| 742 // bounds too, and needs to go first. | |
| 743 animated |= sequences[i]->properties(); | |
| 744 } | |
| 745 | |
| 746 // If we started a sequence, try again. We may be able to start several. | |
| 747 } while (started_sequence); | |
| 748 } | |
| 749 | |
| 750 bool LayerAnimator::StartSequenceImmediately(LayerAnimationSequence* sequence) { | |
| 751 PurgeDeletedAnimations(); | |
| 752 | |
| 753 // Ensure that no one is animating one of the sequence's properties already. | |
| 754 for (RunningAnimations::const_iterator iter = running_animations_.begin(); | |
| 755 iter != running_animations_.end(); ++iter) { | |
| 756 if ((*iter).sequence()->HasConflictingProperty(sequence->properties())) | |
| 757 return false; | |
| 758 } | |
| 759 | |
| 760 // All clear, actually start the sequence. Note: base::TimeTicks::Now has | |
| 761 // a resolution that can be as bad as 15ms. If this causes glitches in the | |
| 762 // animations, this can be switched to HighResNow() (animation uses Now() | |
| 763 // internally). | |
| 764 // All LayerAnimators share the same LayerAnimatorCollection. Use the | |
| 765 // last_tick_time() from there to ensure animations started during the same | |
| 766 // event complete at the same time. | |
| 767 base::TimeTicks start_time; | |
| 768 LayerAnimatorCollection* collection = GetLayerAnimatorCollection(); | |
| 769 if (is_animating() || adding_animations_) | |
| 770 start_time = last_step_time_; | |
| 771 else if (collection && collection->HasActiveAnimators()) | |
| 772 start_time = collection->last_tick_time(); | |
| 773 else | |
| 774 start_time = gfx::FrameTime::Now(); | |
| 775 | |
| 776 if (!sequence->animation_group_id()) | |
| 777 sequence->set_animation_group_id(cc::AnimationIdProvider::NextGroupId()); | |
| 778 if (!sequence->waiting_for_group_start() || | |
| 779 sequence->IsFirstElementThreaded()) { | |
| 780 sequence->set_start_time(start_time); | |
| 781 sequence->Start(delegate()); | |
| 782 } | |
| 783 running_animations_.push_back( | |
| 784 RunningAnimation(sequence->AsWeakPtr())); | |
| 785 | |
| 786 // Need to keep a reference to the animation. | |
| 787 AddToQueueIfNotPresent(sequence); | |
| 788 | |
| 789 // Ensure that animations get stepped at their start time. | |
| 790 Step(start_time); | |
| 791 | |
| 792 return true; | |
| 793 } | |
| 794 | |
| 795 void LayerAnimator::GetTargetValue( | |
| 796 LayerAnimationElement::TargetValue* target) const { | |
| 797 for (AnimationQueue::const_iterator iter = animation_queue_.begin(); | |
| 798 iter != animation_queue_.end(); ++iter) { | |
| 799 (*iter)->GetTargetValue(target); | |
| 800 } | |
| 801 } | |
| 802 | |
| 803 void LayerAnimator::OnScheduled(LayerAnimationSequence* sequence) { | |
| 804 if (observers_.might_have_observers()) { | |
| 805 ObserverListBase<LayerAnimationObserver>::Iterator it(observers_); | |
| 806 LayerAnimationObserver* obs; | |
| 807 while ((obs = it.GetNext()) != NULL) { | |
| 808 sequence->AddObserver(obs); | |
| 809 } | |
| 810 } | |
| 811 sequence->OnScheduled(); | |
| 812 } | |
| 813 | |
| 814 void LayerAnimator::SetTransitionDuration(base::TimeDelta duration) { | |
| 815 if (is_transition_duration_locked_) | |
| 816 return; | |
| 817 transition_duration_ = duration; | |
| 818 } | |
| 819 | |
| 820 void LayerAnimator::ClearAnimationsInternal() { | |
| 821 PurgeDeletedAnimations(); | |
| 822 | |
| 823 // Abort should never affect the set of running animations, but just in case | |
| 824 // clients are badly behaved, we will use a copy of the running animations. | |
| 825 RunningAnimations running_animations_copy = running_animations_; | |
| 826 for (size_t i = 0; i < running_animations_copy.size(); ++i) { | |
| 827 if (!SAFE_INVOKE_BOOL(HasAnimation, running_animations_copy[i])) | |
| 828 continue; | |
| 829 | |
| 830 scoped_ptr<LayerAnimationSequence> removed( | |
| 831 RemoveAnimation(running_animations_copy[i].sequence())); | |
| 832 if (removed.get()) | |
| 833 removed->Abort(delegate()); | |
| 834 } | |
| 835 // This *should* have cleared the list of running animations. | |
| 836 DCHECK(running_animations_.empty()); | |
| 837 running_animations_.clear(); | |
| 838 animation_queue_.clear(); | |
| 839 UpdateAnimationState(); | |
| 840 } | |
| 841 | |
| 842 void LayerAnimator::PurgeDeletedAnimations() { | |
| 843 for (size_t i = 0; i < running_animations_.size();) { | |
| 844 if (!running_animations_[i].is_sequence_alive()) | |
| 845 running_animations_.erase(running_animations_.begin() + i); | |
| 846 else | |
| 847 i++; | |
| 848 } | |
| 849 } | |
| 850 | |
| 851 LayerAnimatorCollection* LayerAnimator::GetLayerAnimatorCollection() { | |
| 852 return delegate_ ? delegate_->GetLayerAnimatorCollection() : NULL; | |
| 853 } | |
| 854 | |
| 855 LayerAnimator::RunningAnimation::RunningAnimation( | |
| 856 const base::WeakPtr<LayerAnimationSequence>& sequence) | |
| 857 : sequence_(sequence) { | |
| 858 } | |
| 859 | |
| 860 LayerAnimator::RunningAnimation::~RunningAnimation() { } | |
| 861 | |
| 862 } // namespace ui | |
| OLD | NEW |