Add support for different tween types in ui::Layer animations
[chromium-blink-merge.git] / ui / gfx / compositor / layer_animator.cc
blobd442dd6bb992491eb539614ebc5bd8f86f60a461
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.
5 #include "ui/gfx/compositor/layer_animator.h"
7 #include "base/debug/trace_event.h"
8 #include "base/logging.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "ui/base/animation/animation_container.h"
11 #include "ui/gfx/compositor/compositor.h"
12 #include "ui/gfx/compositor/layer.h"
13 #include "ui/gfx/compositor/layer_animation_delegate.h"
14 #include "ui/gfx/compositor/layer_animation_observer.h"
15 #include "ui/gfx/compositor/layer_animation_sequence.h"
17 namespace ui {
19 class LayerAnimator;
21 namespace {
23 static const base::TimeDelta kDefaultTransitionDuration =
24 base::TimeDelta::FromMilliseconds(120);
26 static const base::TimeDelta kTimerInterval =
27 base::TimeDelta::FromMilliseconds(10);
29 } // namespace;
31 // LayerAnimator public --------------------------------------------------------
33 LayerAnimator::LayerAnimator(base::TimeDelta transition_duration)
34 : delegate_(NULL),
35 preemption_strategy_(IMMEDIATELY_SET_NEW_TARGET),
36 transition_duration_(transition_duration),
37 tween_type_(Tween::LINEAR),
38 is_started_(false),
39 disable_timer_for_test_(false) {
42 LayerAnimator::~LayerAnimator() {
43 for (size_t i = 0; i < running_animations_.size(); ++i)
44 running_animations_[i].sequence->OnAnimatorDestroyed();
45 ClearAnimations();
48 // static
49 bool LayerAnimator::disable_animations_for_test_ = false;
51 // static
52 LayerAnimator* LayerAnimator::CreateDefaultAnimator() {
53 return new LayerAnimator(base::TimeDelta::FromMilliseconds(0));
56 // static
57 LayerAnimator* LayerAnimator::CreateImplicitAnimator() {
58 return new LayerAnimator(kDefaultTransitionDuration);
61 void LayerAnimator::SetTransform(const Transform& transform) {
62 base::TimeDelta duration = transition_duration_;
63 if (disable_animations_for_test_)
64 duration = base::TimeDelta();
65 scoped_ptr<LayerAnimationElement> element(
66 LayerAnimationElement::CreateTransformElement(transform, duration));
67 element->set_tween_type(tween_type_);
68 StartAnimation(new LayerAnimationSequence(element.release()));
71 Transform LayerAnimator::GetTargetTransform() const {
72 LayerAnimationElement::TargetValue target(delegate());
73 GetTargetValue(&target);
74 return target.transform;
77 void LayerAnimator::SetBounds(const gfx::Rect& bounds) {
78 base::TimeDelta duration = transition_duration_;
79 if (disable_animations_for_test_)
80 duration = base::TimeDelta();
81 scoped_ptr<LayerAnimationElement> element(
82 LayerAnimationElement::CreateBoundsElement(bounds, duration));
83 element->set_tween_type(tween_type_);
84 StartAnimation(new LayerAnimationSequence(element.release()));
87 gfx::Rect LayerAnimator::GetTargetBounds() const {
88 LayerAnimationElement::TargetValue target(delegate());
89 GetTargetValue(&target);
90 return target.bounds;
93 void LayerAnimator::SetOpacity(float opacity) {
94 base::TimeDelta duration = transition_duration_;
95 if (disable_animations_for_test_)
96 duration = base::TimeDelta();
97 scoped_ptr<LayerAnimationElement> element(
98 LayerAnimationElement::CreateOpacityElement(opacity, duration));
99 element->set_tween_type(tween_type_);
100 StartAnimation(new LayerAnimationSequence(element.release()));
103 float LayerAnimator::GetTargetOpacity() const {
104 LayerAnimationElement::TargetValue target(delegate());
105 GetTargetValue(&target);
106 return target.opacity;
109 void LayerAnimator::SetVisibility(bool visibility) {
110 base::TimeDelta duration = transition_duration_;
111 if (disable_animations_for_test_)
112 duration = base::TimeDelta();
114 // Tween type doesn't matter for visibility.
115 StartAnimation(new LayerAnimationSequence(
116 LayerAnimationElement::CreateVisibilityElement(
117 visibility, duration)));
120 bool LayerAnimator::GetTargetVisibility() const {
121 LayerAnimationElement::TargetValue target(delegate());
122 GetTargetValue(&target);
123 return target.visibility;
126 void LayerAnimator::SetDelegate(LayerAnimationDelegate* delegate) {
127 DCHECK(delegate);
128 delegate_ = delegate;
131 void LayerAnimator::StartAnimation(LayerAnimationSequence* animation) {
132 OnScheduled(animation);
133 if (!StartSequenceImmediately(animation)) {
134 // Attempt to preempt a running animation.
135 switch (preemption_strategy_) {
136 case IMMEDIATELY_SET_NEW_TARGET:
137 ImmediatelySetNewTarget(animation);
138 break;
139 case IMMEDIATELY_ANIMATE_TO_NEW_TARGET:
140 ImmediatelyAnimateToNewTarget(animation);
141 break;
142 case ENQUEUE_NEW_ANIMATION:
143 EnqueueNewAnimation(animation);
144 break;
145 case REPLACE_QUEUED_ANIMATIONS:
146 ReplaceQueuedAnimations(animation);
147 break;
148 case BLEND_WITH_CURRENT_ANIMATION: {
149 // TODO(vollick) Add support for blended sequences and use them here.
150 NOTIMPLEMENTED();
151 break;
155 FinishAnyAnimationWithZeroDuration();
156 UpdateAnimationState();
159 void LayerAnimator::ScheduleAnimation(LayerAnimationSequence* animation) {
160 OnScheduled(animation);
161 if (is_animating()) {
162 animation_queue_.push_back(make_linked_ptr(animation));
163 ProcessQueue();
164 } else {
165 StartSequenceImmediately(animation);
167 UpdateAnimationState();
170 void LayerAnimator::ScheduleTogether(
171 const std::vector<LayerAnimationSequence*>& animations) {
172 // Collect all the affected properties.
173 LayerAnimationElement::AnimatableProperties animated_properties;
174 std::vector<LayerAnimationSequence*>::const_iterator iter;
175 for (iter = animations.begin(); iter != animations.end(); ++iter) {
176 animated_properties.insert((*iter)->properties().begin(),
177 (*iter)->properties().end());
180 // Scheduling a zero duration pause that affects all the animated properties
181 // will prevent any of the sequences from animating until there are no
182 // running animations that affect any of these properties.
183 ScheduleAnimation(new LayerAnimationSequence(
184 LayerAnimationElement::CreatePauseElement(animated_properties,
185 base::TimeDelta())));
187 // These animations (provided they don't animate any common properties) will
188 // now animate together if trivially scheduled.
189 for (iter = animations.begin(); iter != animations.end(); ++iter) {
190 ScheduleAnimation(*iter);
193 UpdateAnimationState();
196 bool LayerAnimator::IsAnimatingProperty(
197 LayerAnimationElement::AnimatableProperty property) const {
198 for (AnimationQueue::const_iterator queue_iter = animation_queue_.begin();
199 queue_iter != animation_queue_.end(); ++queue_iter) {
200 if ((*queue_iter)->properties().find(property) !=
201 (*queue_iter)->properties().end()) {
202 return true;
205 return false;
208 void LayerAnimator::StopAnimatingProperty(
209 LayerAnimationElement::AnimatableProperty property) {
210 while (true) {
211 RunningAnimation* running = GetRunningAnimation(property);
212 if (!running)
213 break;
214 FinishAnimation(running->sequence);
218 void LayerAnimator::StopAnimating() {
219 while (is_animating())
220 FinishAnimation(running_animations_[0].sequence);
223 void LayerAnimator::AddObserver(LayerAnimationObserver* observer) {
224 if (!observers_.HasObserver(observer))
225 observers_.AddObserver(observer);
228 void LayerAnimator::RemoveObserver(LayerAnimationObserver* observer) {
229 observers_.RemoveObserver(observer);
230 // Remove the observer from all sequences as well.
231 for (AnimationQueue::iterator queue_iter = animation_queue_.begin();
232 queue_iter != animation_queue_.end(); ++queue_iter) {
233 (*queue_iter)->RemoveObserver(observer);
237 // LayerAnimator private -------------------------------------------------------
239 void LayerAnimator::Step(base::TimeTicks now) {
240 TRACE_EVENT0("ui", "LayerAnimator::Step");
242 last_step_time_ = now;
243 // We need to make a copy of the running animations because progressing them
244 // and finishing them may indirectly affect the collection of running
245 // animations.
246 RunningAnimations running_animations_copy = running_animations_;
247 bool needs_redraw = false;
248 for (size_t i = 0; i < running_animations_copy.size(); ++i) {
249 base::TimeDelta delta = now - running_animations_copy[i].start_time;
250 if (delta >= running_animations_copy[i].sequence->duration() &&
251 !running_animations_copy[i].sequence->is_cyclic()) {
252 FinishAnimation(running_animations_copy[i].sequence);
253 } else {
254 if (running_animations_copy[i].sequence->Progress(delta, delegate()))
255 needs_redraw = true;
259 if (needs_redraw)
260 delegate()->ScheduleDrawForAnimation();
263 void LayerAnimator::SetStartTime(base::TimeTicks start_time) {
264 // Do nothing.
267 base::TimeDelta LayerAnimator::GetTimerInterval() const {
268 return kTimerInterval;
271 void LayerAnimator::UpdateAnimationState() {
272 if (disable_timer_for_test_)
273 return;
275 static ui::AnimationContainer* container = NULL;
276 if (!container) {
277 container = new AnimationContainer();
278 container->AddRef();
281 const bool should_start = is_animating();
282 if (should_start && !is_started_)
283 container->Start(this);
284 else if (!should_start && is_started_)
285 container->Stop(this);
287 is_started_ = should_start;
290 LayerAnimationSequence* LayerAnimator::RemoveAnimation(
291 LayerAnimationSequence* sequence) {
292 linked_ptr<LayerAnimationSequence> to_return;
294 // First remove from running animations
295 for (RunningAnimations::iterator iter = running_animations_.begin();
296 iter != running_animations_.end(); ++iter) {
297 if ((*iter).sequence == sequence) {
298 running_animations_.erase(iter);
299 break;
303 // Then remove from the queue
304 for (AnimationQueue::iterator queue_iter = animation_queue_.begin();
305 queue_iter != animation_queue_.end(); ++queue_iter) {
306 if ((*queue_iter) == sequence) {
307 to_return = *queue_iter;
308 animation_queue_.erase(queue_iter);
309 break;
313 return to_return.release();
316 void LayerAnimator::FinishAnimation(LayerAnimationSequence* sequence) {
317 scoped_ptr<LayerAnimationSequence> removed(RemoveAnimation(sequence));
318 sequence->Progress(sequence->duration(), delegate());
319 ProcessQueue();
320 UpdateAnimationState();
323 void LayerAnimator::FinishAnyAnimationWithZeroDuration() {
324 // Special case: if we've started a 0 duration animation, just finish it now
325 // and get rid of it. We need to make a copy because Progress may indirectly
326 // cause new animations to start running.
327 RunningAnimations running_animations_copy = running_animations_;
328 for (size_t i = 0; i < running_animations_copy.size(); ++i) {
329 if (running_animations_copy[i].sequence->duration() == base::TimeDelta()) {
330 running_animations_copy[i].sequence->Progress(
331 running_animations_copy[i].sequence->duration(), delegate());
332 scoped_ptr<LayerAnimationSequence> removed(
333 RemoveAnimation(running_animations_copy[i].sequence));
336 ProcessQueue();
337 UpdateAnimationState();
340 void LayerAnimator::ClearAnimations() {
341 // Abort should never affect the set of running animations, but just in case
342 // clients are badly behaved, we will use a copy of the running animations.
343 RunningAnimations running_animations_copy = running_animations_;
344 for (size_t i = 0; i < running_animations_copy.size(); ++i) {
345 scoped_ptr<LayerAnimationSequence> removed(
346 RemoveAnimation(running_animations_copy[i].sequence));
347 if (removed.get())
348 removed->Abort();
350 // This *should* have cleared the list of running animations.
351 DCHECK(running_animations_.empty());
352 running_animations_.clear();
353 animation_queue_.clear();
354 UpdateAnimationState();
357 LayerAnimator::RunningAnimation* LayerAnimator::GetRunningAnimation(
358 LayerAnimationElement::AnimatableProperty property) {
359 for (RunningAnimations::iterator iter = running_animations_.begin();
360 iter != running_animations_.end(); ++iter) {
361 if ((*iter).sequence->properties().find(property) !=
362 (*iter).sequence->properties().end())
363 return &(*iter);
365 return NULL;
368 void LayerAnimator::AddToQueueIfNotPresent(LayerAnimationSequence* animation) {
369 // If we don't have the animation in the queue yet, add it.
370 bool found_sequence = false;
371 for (AnimationQueue::iterator queue_iter = animation_queue_.begin();
372 queue_iter != animation_queue_.end(); ++queue_iter) {
373 if ((*queue_iter) == animation) {
374 found_sequence = true;
375 break;
379 if (!found_sequence)
380 animation_queue_.push_front(make_linked_ptr(animation));
383 void LayerAnimator::RemoveAllAnimationsWithACommonProperty(
384 LayerAnimationSequence* sequence, bool abort) {
385 // For all the running animations, if they animate the same property,
386 // progress them to the end and remove them. Note, Aborting or Progressing
387 // animations may affect the collection of running animations, so we need to
388 // operate on a copy.
389 RunningAnimations running_animations_copy = running_animations_;
390 for (size_t i = 0; i < running_animations_copy.size(); ++i) {
391 if (running_animations_copy[i].sequence->HasCommonProperty(
392 sequence->properties())) {
393 scoped_ptr<LayerAnimationSequence> removed(
394 RemoveAnimation(running_animations_copy[i].sequence));
395 if (abort)
396 running_animations_copy[i].sequence->Abort();
397 else
398 running_animations_copy[i].sequence->Progress(
399 running_animations_copy[i].sequence->duration(), delegate());
403 // Same for the queued animations that haven't been started. Again, we'll
404 // need to operate on a copy.
405 std::vector<LayerAnimationSequence*> sequences;
406 for (AnimationQueue::iterator queue_iter = animation_queue_.begin();
407 queue_iter != animation_queue_.end(); ++queue_iter)
408 sequences.push_back((*queue_iter).get());
410 for (size_t i = 0; i < sequences.size(); ++i) {
411 if (sequences[i]->HasCommonProperty(sequence->properties())) {
412 scoped_ptr<LayerAnimationSequence> removed(
413 RemoveAnimation(sequences[i]));
414 if (abort)
415 sequences[i]->Abort();
416 else
417 sequences[i]->Progress(sequences[i]->duration(), delegate());
422 void LayerAnimator::ImmediatelySetNewTarget(LayerAnimationSequence* sequence) {
423 // Ensure that sequence is disposed of when this function completes.
424 scoped_ptr<LayerAnimationSequence> to_dispose(sequence);
425 const bool abort = false;
426 RemoveAllAnimationsWithACommonProperty(sequence, abort);
427 LayerAnimationSequence* removed = RemoveAnimation(sequence);
428 DCHECK(removed == NULL || removed == sequence);
429 sequence->Progress(sequence->duration(), delegate());
432 void LayerAnimator::ImmediatelyAnimateToNewTarget(
433 LayerAnimationSequence* sequence) {
434 const bool abort = true;
435 RemoveAllAnimationsWithACommonProperty(sequence, abort);
436 AddToQueueIfNotPresent(sequence);
437 StartSequenceImmediately(sequence);
440 void LayerAnimator::EnqueueNewAnimation(LayerAnimationSequence* sequence) {
441 // It is assumed that if there was no conflicting animation, we would
442 // not have been called. No need to check for a collision; just
443 // add to the queue.
444 animation_queue_.push_back(make_linked_ptr(sequence));
445 ProcessQueue();
448 void LayerAnimator::ReplaceQueuedAnimations(LayerAnimationSequence* sequence) {
449 // Remove all animations that aren't running. Note: at each iteration i is
450 // incremented or an element is removed from the queue, so
451 // animation_queue_.size() - i is always decreasing and we are always making
452 // progress towards the loop terminating.
453 for (size_t i = 0; i < animation_queue_.size();) {
454 bool is_running = false;
455 for (RunningAnimations::const_iterator iter = running_animations_.begin();
456 iter != running_animations_.end(); ++iter) {
457 if ((*iter).sequence == animation_queue_[i]) {
458 is_running = true;
459 break;
462 if (!is_running)
463 scoped_ptr<LayerAnimationSequence>(
464 RemoveAnimation(animation_queue_[i].get()));
465 else
466 ++i;
468 animation_queue_.push_back(make_linked_ptr(sequence));
469 ProcessQueue();
472 void LayerAnimator::ProcessQueue() {
473 bool started_sequence = false;
474 do {
475 started_sequence = false;
476 // Build a list of all currently animated properties.
477 LayerAnimationElement::AnimatableProperties animated;
478 for (RunningAnimations::const_iterator iter = running_animations_.begin();
479 iter != running_animations_.end(); ++iter) {
480 animated.insert((*iter).sequence->properties().begin(),
481 (*iter).sequence->properties().end());
484 // Try to find an animation that doesn't conflict with an animated
485 // property or a property that will be animated before it. Note: starting
486 // the animation may indirectly cause more animations to be started, so we
487 // need to operate on a copy.
488 std::vector<LayerAnimationSequence*> sequences;
489 for (AnimationQueue::iterator queue_iter = animation_queue_.begin();
490 queue_iter != animation_queue_.end(); ++queue_iter)
491 sequences.push_back((*queue_iter).get());
493 for (size_t i = 0; i < sequences.size(); ++i) {
494 if (!sequences[i]->HasCommonProperty(animated)) {
495 StartSequenceImmediately(sequences[i]);
496 started_sequence = true;
497 break;
500 // Animation couldn't be started. Add its properties to the collection so
501 // that we don't start a conflicting animation. For example, if our queue
502 // has the elements { {T,B}, {B} } (that is, an element that animates both
503 // the transform and the bounds followed by an element that animates the
504 // bounds), and we're currently animating the transform, we can't start
505 // the first element because it animates the transform, too. We cannot
506 // start the second element, either, because the first element animates
507 // bounds too, and needs to go first.
508 animated.insert(sequences[i]->properties().begin(),
509 sequences[i]->properties().end());
512 // If we started a sequence, try again. We may be able to start several.
513 } while (started_sequence);
516 bool LayerAnimator::StartSequenceImmediately(LayerAnimationSequence* sequence) {
517 // Ensure that no one is animating one of the sequence's properties already.
518 for (RunningAnimations::const_iterator iter = running_animations_.begin();
519 iter != running_animations_.end(); ++iter) {
520 if ((*iter).sequence->HasCommonProperty(sequence->properties()))
521 return false;
524 // All clear, actually start the sequence. Note: base::TimeTicks::Now has
525 // a resolution that can be as bad as 15ms. If this causes glitches in the
526 // animations, this can be switched to HighResNow() (animation uses Now()
527 // internally).
528 base::TimeTicks start_time = is_animating()
529 ? last_step_time_
530 : base::TimeTicks::Now();
532 running_animations_.push_back(RunningAnimation(sequence, start_time));
534 // Need to keep a reference to the animation.
535 AddToQueueIfNotPresent(sequence);
537 // Ensure that animations get stepped at their start time.
538 Step(start_time);
540 return true;
543 void LayerAnimator::GetTargetValue(
544 LayerAnimationElement::TargetValue* target) const {
545 for (RunningAnimations::const_iterator iter = running_animations_.begin();
546 iter != running_animations_.end(); ++iter) {
547 (*iter).sequence->GetTargetValue(target);
551 void LayerAnimator::OnScheduled(LayerAnimationSequence* sequence) {
552 if (observers_.might_have_observers()) {
553 ObserverListBase<LayerAnimationObserver>::Iterator it(observers_);
554 LayerAnimationObserver* obs;
555 while ((obs = it.GetNext()) != NULL) {
556 sequence->AddObserver(obs);
559 sequence->OnScheduled();
562 } // namespace ui