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"
23 static const base::TimeDelta kDefaultTransitionDuration
=
24 base::TimeDelta::FromMilliseconds(120);
26 static const base::TimeDelta kTimerInterval
=
27 base::TimeDelta::FromMilliseconds(10);
31 // LayerAnimator public --------------------------------------------------------
33 LayerAnimator::LayerAnimator(base::TimeDelta transition_duration
)
35 preemption_strategy_(IMMEDIATELY_SET_NEW_TARGET
),
36 transition_duration_(transition_duration
),
37 tween_type_(Tween::LINEAR
),
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();
49 bool LayerAnimator::disable_animations_for_test_
= false;
52 LayerAnimator
* LayerAnimator::CreateDefaultAnimator() {
53 return new LayerAnimator(base::TimeDelta::FromMilliseconds(0));
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
);
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
) {
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
);
139 case IMMEDIATELY_ANIMATE_TO_NEW_TARGET
:
140 ImmediatelyAnimateToNewTarget(animation
);
142 case ENQUEUE_NEW_ANIMATION
:
143 EnqueueNewAnimation(animation
);
145 case REPLACE_QUEUED_ANIMATIONS
:
146 ReplaceQueuedAnimations(animation
);
148 case BLEND_WITH_CURRENT_ANIMATION
: {
149 // TODO(vollick) Add support for blended sequences and use them here.
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
));
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()) {
208 void LayerAnimator::StopAnimatingProperty(
209 LayerAnimationElement::AnimatableProperty property
) {
211 RunningAnimation
* running
= GetRunningAnimation(property
);
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
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
);
254 if (running_animations_copy
[i
].sequence
->Progress(delta
, delegate()))
260 delegate()->ScheduleDrawForAnimation();
263 void LayerAnimator::SetStartTime(base::TimeTicks start_time
) {
267 base::TimeDelta
LayerAnimator::GetTimerInterval() const {
268 return kTimerInterval
;
271 void LayerAnimator::UpdateAnimationState() {
272 if (disable_timer_for_test_
)
275 static ui::AnimationContainer
* container
= NULL
;
277 container
= new AnimationContainer();
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
);
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
);
313 return to_return
.release();
316 void LayerAnimator::FinishAnimation(LayerAnimationSequence
* sequence
) {
317 scoped_ptr
<LayerAnimationSequence
> removed(RemoveAnimation(sequence
));
318 sequence
->Progress(sequence
->duration(), delegate());
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
));
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
));
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())
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;
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
));
396 running_animations_copy
[i
].sequence
->Abort();
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
]));
415 sequences
[i
]->Abort();
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
444 animation_queue_
.push_back(make_linked_ptr(sequence
));
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
]) {
463 scoped_ptr
<LayerAnimationSequence
>(
464 RemoveAnimation(animation_queue_
[i
].get()));
468 animation_queue_
.push_back(make_linked_ptr(sequence
));
472 void LayerAnimator::ProcessQueue() {
473 bool started_sequence
= false;
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;
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()))
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()
528 base::TimeTicks start_time
= is_animating()
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.
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();