blob: 7c00d452a0e4e4559a4829541af4c1c9f4797e77 [file] [log] [blame]
[email protected]b7a1b662012-01-18 14:12:181// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]710a98d2011-06-23 20:13:292// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]116302fc2012-05-05 21:45:415#include "ui/compositor/layer_animator.h"
[email protected]710a98d2011-06-23 20:13:296
[email protected]b4db9372011-10-24 14:44:197#include "base/debug/trace_event.h"
[email protected]710a98d2011-06-23 20:13:298#include "base/logging.h"
[email protected]b4db9372011-10-24 14:44:199#include "base/memory/scoped_ptr.h"
[email protected]710a98d2011-06-23 20:13:2910#include "ui/base/animation/animation_container.h"
[email protected]116302fc2012-05-05 21:45:4111#include "ui/compositor/compositor.h"
12#include "ui/compositor/layer.h"
13#include "ui/compositor/layer_animation_delegate.h"
14#include "ui/compositor/layer_animation_observer.h"
15#include "ui/compositor/layer_animation_sequence.h"
[email protected]0ed187e2011-10-21 20:07:4216
[email protected]21445e472011-10-21 20:36:3217namespace ui {
[email protected]0ed187e2011-10-21 20:07:4218
[email protected]b4db9372011-10-24 14:44:1919class LayerAnimator;
20
21namespace {
22
23static const base::TimeDelta kDefaultTransitionDuration =
[email protected]6e7c1562012-01-20 15:49:2424 base::TimeDelta::FromMilliseconds(120);
[email protected]b4db9372011-10-24 14:44:1925
26static const base::TimeDelta kTimerInterval =
27 base::TimeDelta::FromMilliseconds(10);
28
[email protected]9861f1752012-06-01 07:16:1429} // namespace
30
31// static
32bool LayerAnimator::disable_animations_for_test_ = false;
33// static
34bool LayerAnimator::slow_animation_mode_ = false;
[email protected]77ff4382012-06-25 23:20:4735// static
36int LayerAnimator::slow_animation_scale_factor_ = 4;
[email protected]b4db9372011-10-24 14:44:1937
38// LayerAnimator public --------------------------------------------------------
39
40LayerAnimator::LayerAnimator(base::TimeDelta transition_duration)
41 : delegate_(NULL),
42 preemption_strategy_(IMMEDIATELY_SET_NEW_TARGET),
43 transition_duration_(transition_duration),
[email protected]e4cbcc772012-03-07 18:59:3144 tween_type_(Tween::LINEAR),
[email protected]b4db9372011-10-24 14:44:1945 is_started_(false),
46 disable_timer_for_test_(false) {
[email protected]710a98d2011-06-23 20:13:2947}
48
49LayerAnimator::~LayerAnimator() {
[email protected]0b3d7b62012-01-26 19:51:3050 for (size_t i = 0; i < running_animations_.size(); ++i)
51 running_animations_[i].sequence->OnAnimatorDestroyed();
[email protected]b4db9372011-10-24 14:44:1952 ClearAnimations();
[email protected]710a98d2011-06-23 20:13:2953}
54
[email protected]b4db9372011-10-24 14:44:1955// static
56LayerAnimator* LayerAnimator::CreateDefaultAnimator() {
57 return new LayerAnimator(base::TimeDelta::FromMilliseconds(0));
58}
59
60// static
61LayerAnimator* LayerAnimator::CreateImplicitAnimator() {
62 return new LayerAnimator(kDefaultTransitionDuration);
63}
64
65void LayerAnimator::SetTransform(const Transform& transform) {
[email protected]9861f1752012-06-01 07:16:1466 base::TimeDelta duration = GetTransitionDuration();
[email protected]e4cbcc772012-03-07 18:59:3167 scoped_ptr<LayerAnimationElement> element(
68 LayerAnimationElement::CreateTransformElement(transform, duration));
69 element->set_tween_type(tween_type_);
70 StartAnimation(new LayerAnimationSequence(element.release()));
[email protected]fe7074c62011-10-28 15:22:5471}
72
73Transform LayerAnimator::GetTargetTransform() const {
[email protected]f5cd9e52011-11-03 21:38:0874 LayerAnimationElement::TargetValue target(delegate());
[email protected]fe7074c62011-10-28 15:22:5475 GetTargetValue(&target);
76 return target.transform;
[email protected]b4db9372011-10-24 14:44:1977}
78
79void LayerAnimator::SetBounds(const gfx::Rect& bounds) {
[email protected]9861f1752012-06-01 07:16:1480 base::TimeDelta duration = GetTransitionDuration();
[email protected]e4cbcc772012-03-07 18:59:3181 scoped_ptr<LayerAnimationElement> element(
82 LayerAnimationElement::CreateBoundsElement(bounds, duration));
83 element->set_tween_type(tween_type_);
84 StartAnimation(new LayerAnimationSequence(element.release()));
[email protected]fe7074c62011-10-28 15:22:5485}
86
87gfx::Rect LayerAnimator::GetTargetBounds() const {
[email protected]f5cd9e52011-11-03 21:38:0888 LayerAnimationElement::TargetValue target(delegate());
[email protected]fe7074c62011-10-28 15:22:5489 GetTargetValue(&target);
90 return target.bounds;
[email protected]b4db9372011-10-24 14:44:1991}
92
93void LayerAnimator::SetOpacity(float opacity) {
[email protected]9861f1752012-06-01 07:16:1494 base::TimeDelta duration = GetTransitionDuration();
[email protected]e4cbcc772012-03-07 18:59:3195 scoped_ptr<LayerAnimationElement> element(
96 LayerAnimationElement::CreateOpacityElement(opacity, duration));
97 element->set_tween_type(tween_type_);
98 StartAnimation(new LayerAnimationSequence(element.release()));
[email protected]b4db9372011-10-24 14:44:1999}
100
[email protected]fe7074c62011-10-28 15:22:54101float LayerAnimator::GetTargetOpacity() const {
[email protected]f5cd9e52011-11-03 21:38:08102 LayerAnimationElement::TargetValue target(delegate());
[email protected]fe7074c62011-10-28 15:22:54103 GetTargetValue(&target);
104 return target.opacity;
105}
106
[email protected]a67935f2012-02-10 14:26:24107void LayerAnimator::SetVisibility(bool visibility) {
[email protected]9861f1752012-06-01 07:16:14108 base::TimeDelta duration = GetTransitionDuration();
[email protected]e4cbcc772012-03-07 18:59:31109
110 // Tween type doesn't matter for visibility.
[email protected]a67935f2012-02-10 14:26:24111 StartAnimation(new LayerAnimationSequence(
112 LayerAnimationElement::CreateVisibilityElement(
113 visibility, duration)));
114}
115
116bool LayerAnimator::GetTargetVisibility() const {
117 LayerAnimationElement::TargetValue target(delegate());
118 GetTargetValue(&target);
119 return target.visibility;
120}
121
[email protected]e876c2712011-11-02 16:42:45122void LayerAnimator::SetDelegate(LayerAnimationDelegate* delegate) {
[email protected]b4db9372011-10-24 14:44:19123 DCHECK(delegate);
124 delegate_ = delegate;
125}
126
127void LayerAnimator::StartAnimation(LayerAnimationSequence* animation) {
[email protected]e876c2712011-11-02 16:42:45128 OnScheduled(animation);
[email protected]b4db9372011-10-24 14:44:19129 if (!StartSequenceImmediately(animation)) {
130 // Attempt to preempt a running animation.
131 switch (preemption_strategy_) {
132 case IMMEDIATELY_SET_NEW_TARGET:
133 ImmediatelySetNewTarget(animation);
134 break;
135 case IMMEDIATELY_ANIMATE_TO_NEW_TARGET:
136 ImmediatelyAnimateToNewTarget(animation);
137 break;
138 case ENQUEUE_NEW_ANIMATION:
139 EnqueueNewAnimation(animation);
140 break;
141 case REPLACE_QUEUED_ANIMATIONS:
142 ReplaceQueuedAnimations(animation);
143 break;
144 case BLEND_WITH_CURRENT_ANIMATION: {
145 // TODO(vollick) Add support for blended sequences and use them here.
146 NOTIMPLEMENTED();
147 break;
148 }
[email protected]7fca53d42011-09-29 15:38:12149 }
[email protected]b4db9372011-10-24 14:44:19150 }
151 FinishAnyAnimationWithZeroDuration();
[email protected]fe7074c62011-10-28 15:22:54152 UpdateAnimationState();
[email protected]b4db9372011-10-24 14:44:19153}
154
155void LayerAnimator::ScheduleAnimation(LayerAnimationSequence* animation) {
[email protected]e876c2712011-11-02 16:42:45156 OnScheduled(animation);
[email protected]b4db9372011-10-24 14:44:19157 if (is_animating()) {
158 animation_queue_.push_back(make_linked_ptr(animation));
159 ProcessQueue();
160 } else {
161 StartSequenceImmediately(animation);
[email protected]7fca53d42011-09-29 15:38:12162 }
[email protected]fe7074c62011-10-28 15:22:54163 UpdateAnimationState();
[email protected]710a98d2011-06-23 20:13:29164}
165
[email protected]b4db9372011-10-24 14:44:19166void LayerAnimator::ScheduleTogether(
167 const std::vector<LayerAnimationSequence*>& animations) {
168 // Collect all the affected properties.
169 LayerAnimationElement::AnimatableProperties animated_properties;
170 std::vector<LayerAnimationSequence*>::const_iterator iter;
171 for (iter = animations.begin(); iter != animations.end(); ++iter) {
172 animated_properties.insert((*iter)->properties().begin(),
173 (*iter)->properties().end());
174 }
[email protected]710a98d2011-06-23 20:13:29175
[email protected]b4db9372011-10-24 14:44:19176 // Scheduling a zero duration pause that affects all the animated properties
177 // will prevent any of the sequences from animating until there are no
178 // running animations that affect any of these properties.
[email protected]e4cbcc772012-03-07 18:59:31179 ScheduleAnimation(new LayerAnimationSequence(
180 LayerAnimationElement::CreatePauseElement(animated_properties,
181 base::TimeDelta())));
[email protected]710a98d2011-06-23 20:13:29182
[email protected]b4db9372011-10-24 14:44:19183 // These animations (provided they don't animate any common properties) will
184 // now animate together if trivially scheduled.
185 for (iter = animations.begin(); iter != animations.end(); ++iter) {
186 ScheduleAnimation(*iter);
[email protected]710a98d2011-06-23 20:13:29187 }
[email protected]fe7074c62011-10-28 15:22:54188
189 UpdateAnimationState();
190}
191
[email protected]e876c2712011-11-02 16:42:45192bool LayerAnimator::IsAnimatingProperty(
193 LayerAnimationElement::AnimatableProperty property) const {
194 for (AnimationQueue::const_iterator queue_iter = animation_queue_.begin();
195 queue_iter != animation_queue_.end(); ++queue_iter) {
196 if ((*queue_iter)->properties().find(property) !=
197 (*queue_iter)->properties().end()) {
198 return true;
199 }
200 }
201 return false;
[email protected]7fca53d42011-09-29 15:38:12202}
203
[email protected]b4db9372011-10-24 14:44:19204void LayerAnimator::StopAnimatingProperty(
205 LayerAnimationElement::AnimatableProperty property) {
206 while (true) {
207 RunningAnimation* running = GetRunningAnimation(property);
208 if (!running)
209 break;
210 FinishAnimation(running->sequence);
211 }
212}
213
214void LayerAnimator::StopAnimating() {
215 while (is_animating())
216 FinishAnimation(running_animations_[0].sequence);
217}
218
[email protected]e876c2712011-11-02 16:42:45219void LayerAnimator::AddObserver(LayerAnimationObserver* observer) {
220 if (!observers_.HasObserver(observer))
221 observers_.AddObserver(observer);
222}
223
224void LayerAnimator::RemoveObserver(LayerAnimationObserver* observer) {
225 observers_.RemoveObserver(observer);
[email protected]5cc8538d2011-11-07 15:24:54226 // Remove the observer from all sequences as well.
227 for (AnimationQueue::iterator queue_iter = animation_queue_.begin();
228 queue_iter != animation_queue_.end(); ++queue_iter) {
229 (*queue_iter)->RemoveObserver(observer);
230 }
[email protected]e876c2712011-11-02 16:42:45231}
232
[email protected]d59a3692012-04-10 20:27:31233// LayerAnimator protected -----------------------------------------------------
234
235bool LayerAnimator::ProgressAnimation(LayerAnimationSequence* sequence,
236 base::TimeDelta delta) {
237 return sequence->Progress(delta, delegate());
238}
239
240
241bool LayerAnimator::HasAnimation(LayerAnimationSequence* sequence) const {
242 for (AnimationQueue::const_iterator queue_iter = animation_queue_.begin();
243 queue_iter != animation_queue_.end(); ++queue_iter) {
244 if ((*queue_iter).get() == sequence)
245 return true;
246 }
247 return false;
248}
249
[email protected]b4db9372011-10-24 14:44:19250// LayerAnimator private -------------------------------------------------------
251
252void LayerAnimator::Step(base::TimeTicks now) {
[email protected]e4cbcc772012-03-07 18:59:31253 TRACE_EVENT0("ui", "LayerAnimator::Step");
254
[email protected]b4db9372011-10-24 14:44:19255 last_step_time_ = now;
[email protected]f5cd9e52011-11-03 21:38:08256 // We need to make a copy of the running animations because progressing them
257 // and finishing them may indirectly affect the collection of running
258 // animations.
259 RunningAnimations running_animations_copy = running_animations_;
[email protected]e4cbcc772012-03-07 18:59:31260 bool needs_redraw = false;
[email protected]f5cd9e52011-11-03 21:38:08261 for (size_t i = 0; i < running_animations_copy.size(); ++i) {
[email protected]d59a3692012-04-10 20:27:31262 if (!HasAnimation(running_animations_copy[i].sequence))
263 continue;
264
[email protected]f5cd9e52011-11-03 21:38:08265 base::TimeDelta delta = now - running_animations_copy[i].start_time;
266 if (delta >= running_animations_copy[i].sequence->duration() &&
267 !running_animations_copy[i].sequence->is_cyclic()) {
268 FinishAnimation(running_animations_copy[i].sequence);
[email protected]d59a3692012-04-10 20:27:31269 } else if (ProgressAnimation(running_animations_copy[i].sequence, delta))
270 needs_redraw = true;
[email protected]b4db9372011-10-24 14:44:19271 }
[email protected]e4cbcc772012-03-07 18:59:31272
273 if (needs_redraw)
274 delegate()->ScheduleDrawForAnimation();
[email protected]b4db9372011-10-24 14:44:19275}
276
277void LayerAnimator::SetStartTime(base::TimeTicks start_time) {
[email protected]f5cd9e52011-11-03 21:38:08278 // Do nothing.
[email protected]b4db9372011-10-24 14:44:19279}
280
281base::TimeDelta LayerAnimator::GetTimerInterval() const {
282 return kTimerInterval;
283}
284
285void LayerAnimator::UpdateAnimationState() {
286 if (disable_timer_for_test_)
[email protected]7fca53d42011-09-29 15:38:12287 return;
288
[email protected]b4db9372011-10-24 14:44:19289 static ui::AnimationContainer* container = NULL;
290 if (!container) {
291 container = new AnimationContainer();
292 container->AddRef();
[email protected]710a98d2011-06-23 20:13:29293 }
[email protected]b4db9372011-10-24 14:44:19294
295 const bool should_start = is_animating();
296 if (should_start && !is_started_)
297 container->Start(this);
298 else if (!should_start && is_started_)
299 container->Stop(this);
300
301 is_started_ = should_start;
[email protected]710a98d2011-06-23 20:13:29302}
303
[email protected]f5cd9e52011-11-03 21:38:08304LayerAnimationSequence* LayerAnimator::RemoveAnimation(
305 LayerAnimationSequence* sequence) {
306 linked_ptr<LayerAnimationSequence> to_return;
307
308 // First remove from running animations
[email protected]b4db9372011-10-24 14:44:19309 for (RunningAnimations::iterator iter = running_animations_.begin();
310 iter != running_animations_.end(); ++iter) {
311 if ((*iter).sequence == sequence) {
312 running_animations_.erase(iter);
313 break;
[email protected]21445e472011-10-21 20:36:32314 }
315 }
[email protected]b4db9372011-10-24 14:44:19316
317 // Then remove from the queue
318 for (AnimationQueue::iterator queue_iter = animation_queue_.begin();
319 queue_iter != animation_queue_.end(); ++queue_iter) {
320 if ((*queue_iter) == sequence) {
[email protected]f5cd9e52011-11-03 21:38:08321 to_return = *queue_iter;
[email protected]b4db9372011-10-24 14:44:19322 animation_queue_.erase(queue_iter);
323 break;
324 }
325 }
[email protected]f5cd9e52011-11-03 21:38:08326
327 return to_return.release();
[email protected]0ed187e2011-10-21 20:07:42328}
329
[email protected]b4db9372011-10-24 14:44:19330void LayerAnimator::FinishAnimation(LayerAnimationSequence* sequence) {
[email protected]f5cd9e52011-11-03 21:38:08331 scoped_ptr<LayerAnimationSequence> removed(RemoveAnimation(sequence));
[email protected]b4db9372011-10-24 14:44:19332 sequence->Progress(sequence->duration(), delegate());
[email protected]b4db9372011-10-24 14:44:19333 ProcessQueue();
334 UpdateAnimationState();
[email protected]21445e472011-10-21 20:36:32335}
[email protected]0ed187e2011-10-21 20:07:42336
[email protected]b4db9372011-10-24 14:44:19337void LayerAnimator::FinishAnyAnimationWithZeroDuration() {
[email protected]2ddfe432011-11-07 19:26:30338 // Special case: if we've started a 0 duration animation, just finish it now
339 // and get rid of it. We need to make a copy because Progress may indirectly
340 // cause new animations to start running.
[email protected]f5cd9e52011-11-03 21:38:08341 RunningAnimations running_animations_copy = running_animations_;
342 for (size_t i = 0; i < running_animations_copy.size(); ++i) {
[email protected]d59a3692012-04-10 20:27:31343 if (!HasAnimation(running_animations_copy[i].sequence))
344 continue;
345
[email protected]f5cd9e52011-11-03 21:38:08346 if (running_animations_copy[i].sequence->duration() == base::TimeDelta()) {
347 running_animations_copy[i].sequence->Progress(
348 running_animations_copy[i].sequence->duration(), delegate());
349 scoped_ptr<LayerAnimationSequence> removed(
350 RemoveAnimation(running_animations_copy[i].sequence));
[email protected]b4db9372011-10-24 14:44:19351 }
352 }
353 ProcessQueue();
354 UpdateAnimationState();
[email protected]21445e472011-10-21 20:36:32355}
[email protected]0ed187e2011-10-21 20:07:42356
[email protected]b4db9372011-10-24 14:44:19357void LayerAnimator::ClearAnimations() {
[email protected]f5cd9e52011-11-03 21:38:08358 // Abort should never affect the set of running animations, but just in case
359 // clients are badly behaved, we will use a copy of the running animations.
360 RunningAnimations running_animations_copy = running_animations_;
361 for (size_t i = 0; i < running_animations_copy.size(); ++i) {
[email protected]d59a3692012-04-10 20:27:31362 if (!HasAnimation(running_animations_copy[i].sequence))
363 continue;
364
[email protected]f5cd9e52011-11-03 21:38:08365 scoped_ptr<LayerAnimationSequence> removed(
366 RemoveAnimation(running_animations_copy[i].sequence));
367 if (removed.get())
368 removed->Abort();
[email protected]b4db9372011-10-24 14:44:19369 }
[email protected]f5cd9e52011-11-03 21:38:08370 // This *should* have cleared the list of running animations.
371 DCHECK(running_animations_.empty());
[email protected]b4db9372011-10-24 14:44:19372 running_animations_.clear();
373 animation_queue_.clear();
374 UpdateAnimationState();
375}
376
377LayerAnimator::RunningAnimation* LayerAnimator::GetRunningAnimation(
378 LayerAnimationElement::AnimatableProperty property) {
379 for (RunningAnimations::iterator iter = running_animations_.begin();
380 iter != running_animations_.end(); ++iter) {
381 if ((*iter).sequence->properties().find(property) !=
382 (*iter).sequence->properties().end())
383 return &(*iter);
384 }
385 return NULL;
386}
387
388void LayerAnimator::AddToQueueIfNotPresent(LayerAnimationSequence* animation) {
389 // If we don't have the animation in the queue yet, add it.
390 bool found_sequence = false;
391 for (AnimationQueue::iterator queue_iter = animation_queue_.begin();
392 queue_iter != animation_queue_.end(); ++queue_iter) {
393 if ((*queue_iter) == animation) {
394 found_sequence = true;
395 break;
396 }
397 }
398
399 if (!found_sequence)
400 animation_queue_.push_front(make_linked_ptr(animation));
401}
402
403void LayerAnimator::RemoveAllAnimationsWithACommonProperty(
[email protected]f5cd9e52011-11-03 21:38:08404 LayerAnimationSequence* sequence, bool abort) {
[email protected]b4db9372011-10-24 14:44:19405 // For all the running animations, if they animate the same property,
[email protected]f5cd9e52011-11-03 21:38:08406 // progress them to the end and remove them. Note, Aborting or Progressing
407 // animations may affect the collection of running animations, so we need to
408 // operate on a copy.
409 RunningAnimations running_animations_copy = running_animations_;
410 for (size_t i = 0; i < running_animations_copy.size(); ++i) {
[email protected]d59a3692012-04-10 20:27:31411 if (!HasAnimation(running_animations_copy[i].sequence))
412 continue;
413
[email protected]f5cd9e52011-11-03 21:38:08414 if (running_animations_copy[i].sequence->HasCommonProperty(
[email protected]b4db9372011-10-24 14:44:19415 sequence->properties())) {
[email protected]f5cd9e52011-11-03 21:38:08416 scoped_ptr<LayerAnimationSequence> removed(
417 RemoveAnimation(running_animations_copy[i].sequence));
418 if (abort)
419 running_animations_copy[i].sequence->Abort();
420 else
421 running_animations_copy[i].sequence->Progress(
422 running_animations_copy[i].sequence->duration(), delegate());
[email protected]b4db9372011-10-24 14:44:19423 }
424 }
425
[email protected]f5cd9e52011-11-03 21:38:08426 // Same for the queued animations that haven't been started. Again, we'll
427 // need to operate on a copy.
428 std::vector<LayerAnimationSequence*> sequences;
429 for (AnimationQueue::iterator queue_iter = animation_queue_.begin();
430 queue_iter != animation_queue_.end(); ++queue_iter)
431 sequences.push_back((*queue_iter).get());
432
433 for (size_t i = 0; i < sequences.size(); ++i) {
[email protected]d59a3692012-04-10 20:27:31434 if (!HasAnimation(sequences[i]))
435 continue;
436
[email protected]f5cd9e52011-11-03 21:38:08437 if (sequences[i]->HasCommonProperty(sequence->properties())) {
438 scoped_ptr<LayerAnimationSequence> removed(
439 RemoveAnimation(sequences[i]));
[email protected]b4db9372011-10-24 14:44:19440 if (abort)
[email protected]f5cd9e52011-11-03 21:38:08441 sequences[i]->Abort();
[email protected]b4db9372011-10-24 14:44:19442 else
[email protected]f5cd9e52011-11-03 21:38:08443 sequences[i]->Progress(sequences[i]->duration(), delegate());
[email protected]b4db9372011-10-24 14:44:19444 }
445 }
446}
447
448void LayerAnimator::ImmediatelySetNewTarget(LayerAnimationSequence* sequence) {
[email protected]d3ba37ab2012-02-09 19:53:13449 // Ensure that sequence is disposed of when this function completes.
450 scoped_ptr<LayerAnimationSequence> to_dispose(sequence);
[email protected]b4db9372011-10-24 14:44:19451 const bool abort = false;
452 RemoveAllAnimationsWithACommonProperty(sequence, abort);
[email protected]d3ba37ab2012-02-09 19:53:13453 LayerAnimationSequence* removed = RemoveAnimation(sequence);
454 DCHECK(removed == NULL || removed == sequence);
[email protected]b4db9372011-10-24 14:44:19455 sequence->Progress(sequence->duration(), delegate());
[email protected]b4db9372011-10-24 14:44:19456}
457
458void LayerAnimator::ImmediatelyAnimateToNewTarget(
459 LayerAnimationSequence* sequence) {
460 const bool abort = true;
461 RemoveAllAnimationsWithACommonProperty(sequence, abort);
462 AddToQueueIfNotPresent(sequence);
463 StartSequenceImmediately(sequence);
464}
465
466void LayerAnimator::EnqueueNewAnimation(LayerAnimationSequence* sequence) {
467 // It is assumed that if there was no conflicting animation, we would
468 // not have been called. No need to check for a collision; just
469 // add to the queue.
470 animation_queue_.push_back(make_linked_ptr(sequence));
471 ProcessQueue();
472}
473
474void LayerAnimator::ReplaceQueuedAnimations(LayerAnimationSequence* sequence) {
475 // Remove all animations that aren't running. Note: at each iteration i is
476 // incremented or an element is removed from the queue, so
477 // animation_queue_.size() - i is always decreasing and we are always making
478 // progress towards the loop terminating.
479 for (size_t i = 0; i < animation_queue_.size();) {
480 bool is_running = false;
481 for (RunningAnimations::const_iterator iter = running_animations_.begin();
482 iter != running_animations_.end(); ++iter) {
483 if ((*iter).sequence == animation_queue_[i]) {
484 is_running = true;
485 break;
486 }
487 }
488 if (!is_running)
[email protected]300548c2012-06-17 08:54:55489 delete RemoveAnimation(animation_queue_[i].get());
[email protected]b4db9372011-10-24 14:44:19490 else
491 ++i;
492 }
493 animation_queue_.push_back(make_linked_ptr(sequence));
494 ProcessQueue();
495}
496
497void LayerAnimator::ProcessQueue() {
498 bool started_sequence = false;
499 do {
500 started_sequence = false;
[email protected]b4db9372011-10-24 14:44:19501 // Build a list of all currently animated properties.
502 LayerAnimationElement::AnimatableProperties animated;
[email protected]b4db9372011-10-24 14:44:19503 for (RunningAnimations::const_iterator iter = running_animations_.begin();
504 iter != running_animations_.end(); ++iter) {
505 animated.insert((*iter).sequence->properties().begin(),
506 (*iter).sequence->properties().end());
507 }
508
509 // Try to find an animation that doesn't conflict with an animated
[email protected]f5cd9e52011-11-03 21:38:08510 // property or a property that will be animated before it. Note: starting
511 // the animation may indirectly cause more animations to be started, so we
512 // need to operate on a copy.
513 std::vector<LayerAnimationSequence*> sequences;
[email protected]b4db9372011-10-24 14:44:19514 for (AnimationQueue::iterator queue_iter = animation_queue_.begin();
[email protected]f5cd9e52011-11-03 21:38:08515 queue_iter != animation_queue_.end(); ++queue_iter)
516 sequences.push_back((*queue_iter).get());
517
518 for (size_t i = 0; i < sequences.size(); ++i) {
519 if (!sequences[i]->HasCommonProperty(animated)) {
520 StartSequenceImmediately(sequences[i]);
[email protected]b4db9372011-10-24 14:44:19521 started_sequence = true;
522 break;
523 }
524
525 // Animation couldn't be started. Add its properties to the collection so
526 // that we don't start a conflicting animation. For example, if our queue
527 // has the elements { {T,B}, {B} } (that is, an element that animates both
528 // the transform and the bounds followed by an element that animates the
529 // bounds), and we're currently animating the transform, we can't start
530 // the first element because it animates the transform, too. We cannot
531 // start the second element, either, because the first element animates
532 // bounds too, and needs to go first.
[email protected]f5cd9e52011-11-03 21:38:08533 animated.insert(sequences[i]->properties().begin(),
534 sequences[i]->properties().end());
[email protected]b4db9372011-10-24 14:44:19535 }
536
537 // If we started a sequence, try again. We may be able to start several.
538 } while (started_sequence);
539}
540
541bool LayerAnimator::StartSequenceImmediately(LayerAnimationSequence* sequence) {
542 // Ensure that no one is animating one of the sequence's properties already.
543 for (RunningAnimations::const_iterator iter = running_animations_.begin();
544 iter != running_animations_.end(); ++iter) {
545 if ((*iter).sequence->HasCommonProperty(sequence->properties()))
546 return false;
547 }
548
549 // All clear, actually start the sequence. Note: base::TimeTicks::Now has
550 // a resolution that can be as bad as 15ms. If this causes glitches in the
551 // animations, this can be switched to HighResNow() (animation uses Now()
552 // internally).
553 base::TimeTicks start_time = is_animating()
554 ? last_step_time_
555 : base::TimeTicks::Now();
556
557 running_animations_.push_back(RunningAnimation(sequence, start_time));
558
559 // Need to keep a reference to the animation.
560 AddToQueueIfNotPresent(sequence);
561
562 // Ensure that animations get stepped at their start time.
563 Step(start_time);
564
565 return true;
[email protected]710a98d2011-06-23 20:13:29566}
567
[email protected]fe7074c62011-10-28 15:22:54568void LayerAnimator::GetTargetValue(
569 LayerAnimationElement::TargetValue* target) const {
[email protected]b1c37fc2012-03-22 03:36:13570 for (AnimationQueue::const_iterator iter = animation_queue_.begin();
571 iter != animation_queue_.end(); ++iter) {
572 (*iter)->GetTargetValue(target);
[email protected]fe7074c62011-10-28 15:22:54573 }
574}
575
[email protected]e876c2712011-11-02 16:42:45576void LayerAnimator::OnScheduled(LayerAnimationSequence* sequence) {
577 if (observers_.might_have_observers()) {
578 ObserverListBase<LayerAnimationObserver>::Iterator it(observers_);
579 LayerAnimationObserver* obs;
580 while ((obs = it.GetNext()) != NULL) {
581 sequence->AddObserver(obs);
582 }
583 }
584 sequence->OnScheduled();
585}
586
[email protected]9861f1752012-06-01 07:16:14587base::TimeDelta LayerAnimator::GetTransitionDuration() const {
[email protected]9861f1752012-06-01 07:16:14588 return transition_duration_;
589}
590
[email protected]710a98d2011-06-23 20:13:29591} // namespace ui