Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(436)

Side by Side Diff: ui/gfx/compositor/layer_animator.cc

Issue 10365007: ui: Move compositor/ directory out of gfx/, up to ui/. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fix DEPS Created 8 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « ui/gfx/compositor/layer_animator.h ('k') | ui/gfx/compositor/layer_animator_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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/gfx/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 "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"
16
17 namespace ui {
18
19 class LayerAnimator;
20
21 namespace {
22
23 static const base::TimeDelta kDefaultTransitionDuration =
24 base::TimeDelta::FromMilliseconds(120);
25
26 static const base::TimeDelta kTimerInterval =
27 base::TimeDelta::FromMilliseconds(10);
28
29 } // namespace;
30
31 // LayerAnimator public --------------------------------------------------------
32
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) {
40 }
41
42 LayerAnimator::~LayerAnimator() {
43 for (size_t i = 0; i < running_animations_.size(); ++i)
44 running_animations_[i].sequence->OnAnimatorDestroyed();
45 ClearAnimations();
46 }
47
48 // static
49 bool LayerAnimator::disable_animations_for_test_ = false;
50
51 // static
52 LayerAnimator* LayerAnimator::CreateDefaultAnimator() {
53 return new LayerAnimator(base::TimeDelta::FromMilliseconds(0));
54 }
55
56 // static
57 LayerAnimator* LayerAnimator::CreateImplicitAnimator() {
58 return new LayerAnimator(kDefaultTransitionDuration);
59 }
60
61 void LayerAnimator::SetTransform(const Transform& transform) {
62 base::TimeDelta duration = transition_duration_;
63 scoped_ptr<LayerAnimationElement> element(
64 LayerAnimationElement::CreateTransformElement(transform, duration));
65 element->set_tween_type(tween_type_);
66 StartAnimation(new LayerAnimationSequence(element.release()));
67 }
68
69 Transform LayerAnimator::GetTargetTransform() const {
70 LayerAnimationElement::TargetValue target(delegate());
71 GetTargetValue(&target);
72 return target.transform;
73 }
74
75 void LayerAnimator::SetBounds(const gfx::Rect& bounds) {
76 base::TimeDelta duration = transition_duration_;
77 scoped_ptr<LayerAnimationElement> element(
78 LayerAnimationElement::CreateBoundsElement(bounds, duration));
79 element->set_tween_type(tween_type_);
80 StartAnimation(new LayerAnimationSequence(element.release()));
81 }
82
83 gfx::Rect LayerAnimator::GetTargetBounds() const {
84 LayerAnimationElement::TargetValue target(delegate());
85 GetTargetValue(&target);
86 return target.bounds;
87 }
88
89 void LayerAnimator::SetOpacity(float opacity) {
90 base::TimeDelta duration = transition_duration_;
91 scoped_ptr<LayerAnimationElement> element(
92 LayerAnimationElement::CreateOpacityElement(opacity, duration));
93 element->set_tween_type(tween_type_);
94 StartAnimation(new LayerAnimationSequence(element.release()));
95 }
96
97 float LayerAnimator::GetTargetOpacity() const {
98 LayerAnimationElement::TargetValue target(delegate());
99 GetTargetValue(&target);
100 return target.opacity;
101 }
102
103 void LayerAnimator::SetVisibility(bool visibility) {
104 base::TimeDelta duration = transition_duration_;
105
106 // Tween type doesn't matter for visibility.
107 StartAnimation(new LayerAnimationSequence(
108 LayerAnimationElement::CreateVisibilityElement(
109 visibility, duration)));
110 }
111
112 bool LayerAnimator::GetTargetVisibility() const {
113 LayerAnimationElement::TargetValue target(delegate());
114 GetTargetValue(&target);
115 return target.visibility;
116 }
117
118 void LayerAnimator::SetDelegate(LayerAnimationDelegate* delegate) {
119 DCHECK(delegate);
120 delegate_ = delegate;
121 }
122
123 void LayerAnimator::StartAnimation(LayerAnimationSequence* animation) {
124 OnScheduled(animation);
125 if (!StartSequenceImmediately(animation)) {
126 // Attempt to preempt a running animation.
127 switch (preemption_strategy_) {
128 case IMMEDIATELY_SET_NEW_TARGET:
129 ImmediatelySetNewTarget(animation);
130 break;
131 case IMMEDIATELY_ANIMATE_TO_NEW_TARGET:
132 ImmediatelyAnimateToNewTarget(animation);
133 break;
134 case ENQUEUE_NEW_ANIMATION:
135 EnqueueNewAnimation(animation);
136 break;
137 case REPLACE_QUEUED_ANIMATIONS:
138 ReplaceQueuedAnimations(animation);
139 break;
140 case BLEND_WITH_CURRENT_ANIMATION: {
141 // TODO(vollick) Add support for blended sequences and use them here.
142 NOTIMPLEMENTED();
143 break;
144 }
145 }
146 }
147 FinishAnyAnimationWithZeroDuration();
148 UpdateAnimationState();
149 }
150
151 void LayerAnimator::ScheduleAnimation(LayerAnimationSequence* animation) {
152 OnScheduled(animation);
153 if (is_animating()) {
154 animation_queue_.push_back(make_linked_ptr(animation));
155 ProcessQueue();
156 } else {
157 StartSequenceImmediately(animation);
158 }
159 UpdateAnimationState();
160 }
161
162 void LayerAnimator::ScheduleTogether(
163 const std::vector<LayerAnimationSequence*>& animations) {
164 // Collect all the affected properties.
165 LayerAnimationElement::AnimatableProperties animated_properties;
166 std::vector<LayerAnimationSequence*>::const_iterator iter;
167 for (iter = animations.begin(); iter != animations.end(); ++iter) {
168 animated_properties.insert((*iter)->properties().begin(),
169 (*iter)->properties().end());
170 }
171
172 // Scheduling a zero duration pause that affects all the animated properties
173 // will prevent any of the sequences from animating until there are no
174 // running animations that affect any of these properties.
175 ScheduleAnimation(new LayerAnimationSequence(
176 LayerAnimationElement::CreatePauseElement(animated_properties,
177 base::TimeDelta())));
178
179 // These animations (provided they don't animate any common properties) will
180 // now animate together if trivially scheduled.
181 for (iter = animations.begin(); iter != animations.end(); ++iter) {
182 ScheduleAnimation(*iter);
183 }
184
185 UpdateAnimationState();
186 }
187
188 bool LayerAnimator::IsAnimatingProperty(
189 LayerAnimationElement::AnimatableProperty property) const {
190 for (AnimationQueue::const_iterator queue_iter = animation_queue_.begin();
191 queue_iter != animation_queue_.end(); ++queue_iter) {
192 if ((*queue_iter)->properties().find(property) !=
193 (*queue_iter)->properties().end()) {
194 return true;
195 }
196 }
197 return false;
198 }
199
200 void LayerAnimator::StopAnimatingProperty(
201 LayerAnimationElement::AnimatableProperty property) {
202 while (true) {
203 RunningAnimation* running = GetRunningAnimation(property);
204 if (!running)
205 break;
206 FinishAnimation(running->sequence);
207 }
208 }
209
210 void LayerAnimator::StopAnimating() {
211 while (is_animating())
212 FinishAnimation(running_animations_[0].sequence);
213 }
214
215 void LayerAnimator::AddObserver(LayerAnimationObserver* observer) {
216 if (!observers_.HasObserver(observer))
217 observers_.AddObserver(observer);
218 }
219
220 void LayerAnimator::RemoveObserver(LayerAnimationObserver* observer) {
221 observers_.RemoveObserver(observer);
222 // Remove the observer from all sequences as well.
223 for (AnimationQueue::iterator queue_iter = animation_queue_.begin();
224 queue_iter != animation_queue_.end(); ++queue_iter) {
225 (*queue_iter)->RemoveObserver(observer);
226 }
227 }
228
229 // LayerAnimator protected -----------------------------------------------------
230
231 bool LayerAnimator::ProgressAnimation(LayerAnimationSequence* sequence,
232 base::TimeDelta delta) {
233 return sequence->Progress(delta, delegate());
234 }
235
236
237 bool LayerAnimator::HasAnimation(LayerAnimationSequence* sequence) const {
238 for (AnimationQueue::const_iterator queue_iter = animation_queue_.begin();
239 queue_iter != animation_queue_.end(); ++queue_iter) {
240 if ((*queue_iter).get() == sequence)
241 return true;
242 }
243 return false;
244 }
245
246 // LayerAnimator private -------------------------------------------------------
247
248 void LayerAnimator::Step(base::TimeTicks now) {
249 TRACE_EVENT0("ui", "LayerAnimator::Step");
250
251 last_step_time_ = now;
252 // We need to make a copy of the running animations because progressing them
253 // and finishing them may indirectly affect the collection of running
254 // animations.
255 RunningAnimations running_animations_copy = running_animations_;
256 bool needs_redraw = false;
257 for (size_t i = 0; i < running_animations_copy.size(); ++i) {
258 if (!HasAnimation(running_animations_copy[i].sequence))
259 continue;
260
261 base::TimeDelta delta = now - running_animations_copy[i].start_time;
262 if (delta >= running_animations_copy[i].sequence->duration() &&
263 !running_animations_copy[i].sequence->is_cyclic()) {
264 FinishAnimation(running_animations_copy[i].sequence);
265 } else if (ProgressAnimation(running_animations_copy[i].sequence, delta))
266 needs_redraw = true;
267 }
268
269 if (needs_redraw)
270 delegate()->ScheduleDrawForAnimation();
271 }
272
273 void LayerAnimator::SetStartTime(base::TimeTicks start_time) {
274 // Do nothing.
275 }
276
277 base::TimeDelta LayerAnimator::GetTimerInterval() const {
278 return kTimerInterval;
279 }
280
281 void LayerAnimator::UpdateAnimationState() {
282 if (disable_timer_for_test_)
283 return;
284
285 static ui::AnimationContainer* container = NULL;
286 if (!container) {
287 container = new AnimationContainer();
288 container->AddRef();
289 }
290
291 const bool should_start = is_animating();
292 if (should_start && !is_started_)
293 container->Start(this);
294 else if (!should_start && is_started_)
295 container->Stop(this);
296
297 is_started_ = should_start;
298 }
299
300 LayerAnimationSequence* LayerAnimator::RemoveAnimation(
301 LayerAnimationSequence* sequence) {
302 linked_ptr<LayerAnimationSequence> to_return;
303
304 // First remove from running animations
305 for (RunningAnimations::iterator iter = running_animations_.begin();
306 iter != running_animations_.end(); ++iter) {
307 if ((*iter).sequence == sequence) {
308 running_animations_.erase(iter);
309 break;
310 }
311 }
312
313 // Then remove from the queue
314 for (AnimationQueue::iterator queue_iter = animation_queue_.begin();
315 queue_iter != animation_queue_.end(); ++queue_iter) {
316 if ((*queue_iter) == sequence) {
317 to_return = *queue_iter;
318 animation_queue_.erase(queue_iter);
319 break;
320 }
321 }
322
323 return to_return.release();
324 }
325
326 void LayerAnimator::FinishAnimation(LayerAnimationSequence* sequence) {
327 scoped_ptr<LayerAnimationSequence> removed(RemoveAnimation(sequence));
328 sequence->Progress(sequence->duration(), delegate());
329 ProcessQueue();
330 UpdateAnimationState();
331 }
332
333 void LayerAnimator::FinishAnyAnimationWithZeroDuration() {
334 // Special case: if we've started a 0 duration animation, just finish it now
335 // and get rid of it. We need to make a copy because Progress may indirectly
336 // cause new animations to start running.
337 RunningAnimations running_animations_copy = running_animations_;
338 for (size_t i = 0; i < running_animations_copy.size(); ++i) {
339 if (!HasAnimation(running_animations_copy[i].sequence))
340 continue;
341
342 if (running_animations_copy[i].sequence->duration() == base::TimeDelta()) {
343 running_animations_copy[i].sequence->Progress(
344 running_animations_copy[i].sequence->duration(), delegate());
345 scoped_ptr<LayerAnimationSequence> removed(
346 RemoveAnimation(running_animations_copy[i].sequence));
347 }
348 }
349 ProcessQueue();
350 UpdateAnimationState();
351 }
352
353 void LayerAnimator::ClearAnimations() {
354 // Abort should never affect the set of running animations, but just in case
355 // clients are badly behaved, we will use a copy of the running animations.
356 RunningAnimations running_animations_copy = running_animations_;
357 for (size_t i = 0; i < running_animations_copy.size(); ++i) {
358 if (!HasAnimation(running_animations_copy[i].sequence))
359 continue;
360
361 scoped_ptr<LayerAnimationSequence> removed(
362 RemoveAnimation(running_animations_copy[i].sequence));
363 if (removed.get())
364 removed->Abort();
365 }
366 // This *should* have cleared the list of running animations.
367 DCHECK(running_animations_.empty());
368 running_animations_.clear();
369 animation_queue_.clear();
370 UpdateAnimationState();
371 }
372
373 LayerAnimator::RunningAnimation* LayerAnimator::GetRunningAnimation(
374 LayerAnimationElement::AnimatableProperty property) {
375 for (RunningAnimations::iterator iter = running_animations_.begin();
376 iter != running_animations_.end(); ++iter) {
377 if ((*iter).sequence->properties().find(property) !=
378 (*iter).sequence->properties().end())
379 return &(*iter);
380 }
381 return NULL;
382 }
383
384 void LayerAnimator::AddToQueueIfNotPresent(LayerAnimationSequence* animation) {
385 // If we don't have the animation in the queue yet, add it.
386 bool found_sequence = false;
387 for (AnimationQueue::iterator queue_iter = animation_queue_.begin();
388 queue_iter != animation_queue_.end(); ++queue_iter) {
389 if ((*queue_iter) == animation) {
390 found_sequence = true;
391 break;
392 }
393 }
394
395 if (!found_sequence)
396 animation_queue_.push_front(make_linked_ptr(animation));
397 }
398
399 void LayerAnimator::RemoveAllAnimationsWithACommonProperty(
400 LayerAnimationSequence* sequence, bool abort) {
401 // For all the running animations, if they animate the same property,
402 // progress them to the end and remove them. Note, Aborting or Progressing
403 // animations may affect the collection of running animations, so we need to
404 // operate on a copy.
405 RunningAnimations running_animations_copy = running_animations_;
406 for (size_t i = 0; i < running_animations_copy.size(); ++i) {
407 if (!HasAnimation(running_animations_copy[i].sequence))
408 continue;
409
410 if (running_animations_copy[i].sequence->HasCommonProperty(
411 sequence->properties())) {
412 scoped_ptr<LayerAnimationSequence> removed(
413 RemoveAnimation(running_animations_copy[i].sequence));
414 if (abort)
415 running_animations_copy[i].sequence->Abort();
416 else
417 running_animations_copy[i].sequence->Progress(
418 running_animations_copy[i].sequence->duration(), delegate());
419 }
420 }
421
422 // Same for the queued animations that haven't been started. Again, we'll
423 // need to operate on a copy.
424 std::vector<LayerAnimationSequence*> sequences;
425 for (AnimationQueue::iterator queue_iter = animation_queue_.begin();
426 queue_iter != animation_queue_.end(); ++queue_iter)
427 sequences.push_back((*queue_iter).get());
428
429 for (size_t i = 0; i < sequences.size(); ++i) {
430 if (!HasAnimation(sequences[i]))
431 continue;
432
433 if (sequences[i]->HasCommonProperty(sequence->properties())) {
434 scoped_ptr<LayerAnimationSequence> removed(
435 RemoveAnimation(sequences[i]));
436 if (abort)
437 sequences[i]->Abort();
438 else
439 sequences[i]->Progress(sequences[i]->duration(), delegate());
440 }
441 }
442 }
443
444 void LayerAnimator::ImmediatelySetNewTarget(LayerAnimationSequence* sequence) {
445 // Ensure that sequence is disposed of when this function completes.
446 scoped_ptr<LayerAnimationSequence> to_dispose(sequence);
447 const bool abort = false;
448 RemoveAllAnimationsWithACommonProperty(sequence, abort);
449 LayerAnimationSequence* removed = RemoveAnimation(sequence);
450 DCHECK(removed == NULL || removed == sequence);
451 sequence->Progress(sequence->duration(), delegate());
452 }
453
454 void LayerAnimator::ImmediatelyAnimateToNewTarget(
455 LayerAnimationSequence* sequence) {
456 const bool abort = true;
457 RemoveAllAnimationsWithACommonProperty(sequence, abort);
458 AddToQueueIfNotPresent(sequence);
459 StartSequenceImmediately(sequence);
460 }
461
462 void LayerAnimator::EnqueueNewAnimation(LayerAnimationSequence* sequence) {
463 // It is assumed that if there was no conflicting animation, we would
464 // not have been called. No need to check for a collision; just
465 // add to the queue.
466 animation_queue_.push_back(make_linked_ptr(sequence));
467 ProcessQueue();
468 }
469
470 void LayerAnimator::ReplaceQueuedAnimations(LayerAnimationSequence* sequence) {
471 // Remove all animations that aren't running. Note: at each iteration i is
472 // incremented or an element is removed from the queue, so
473 // animation_queue_.size() - i is always decreasing and we are always making
474 // progress towards the loop terminating.
475 for (size_t i = 0; i < animation_queue_.size();) {
476 bool is_running = false;
477 for (RunningAnimations::const_iterator iter = running_animations_.begin();
478 iter != running_animations_.end(); ++iter) {
479 if ((*iter).sequence == animation_queue_[i]) {
480 is_running = true;
481 break;
482 }
483 }
484 if (!is_running)
485 scoped_ptr<LayerAnimationSequence>(
486 RemoveAnimation(animation_queue_[i].get()));
487 else
488 ++i;
489 }
490 animation_queue_.push_back(make_linked_ptr(sequence));
491 ProcessQueue();
492 }
493
494 void LayerAnimator::ProcessQueue() {
495 bool started_sequence = false;
496 do {
497 started_sequence = false;
498 // Build a list of all currently animated properties.
499 LayerAnimationElement::AnimatableProperties animated;
500 for (RunningAnimations::const_iterator iter = running_animations_.begin();
501 iter != running_animations_.end(); ++iter) {
502 animated.insert((*iter).sequence->properties().begin(),
503 (*iter).sequence->properties().end());
504 }
505
506 // Try to find an animation that doesn't conflict with an animated
507 // property or a property that will be animated before it. Note: starting
508 // the animation may indirectly cause more animations to be started, so we
509 // need to operate on a copy.
510 std::vector<LayerAnimationSequence*> sequences;
511 for (AnimationQueue::iterator queue_iter = animation_queue_.begin();
512 queue_iter != animation_queue_.end(); ++queue_iter)
513 sequences.push_back((*queue_iter).get());
514
515 for (size_t i = 0; i < sequences.size(); ++i) {
516 if (!sequences[i]->HasCommonProperty(animated)) {
517 StartSequenceImmediately(sequences[i]);
518 started_sequence = true;
519 break;
520 }
521
522 // Animation couldn't be started. Add its properties to the collection so
523 // that we don't start a conflicting animation. For example, if our queue
524 // has the elements { {T,B}, {B} } (that is, an element that animates both
525 // the transform and the bounds followed by an element that animates the
526 // bounds), and we're currently animating the transform, we can't start
527 // the first element because it animates the transform, too. We cannot
528 // start the second element, either, because the first element animates
529 // bounds too, and needs to go first.
530 animated.insert(sequences[i]->properties().begin(),
531 sequences[i]->properties().end());
532 }
533
534 // If we started a sequence, try again. We may be able to start several.
535 } while (started_sequence);
536 }
537
538 bool LayerAnimator::StartSequenceImmediately(LayerAnimationSequence* sequence) {
539 // Ensure that no one is animating one of the sequence's properties already.
540 for (RunningAnimations::const_iterator iter = running_animations_.begin();
541 iter != running_animations_.end(); ++iter) {
542 if ((*iter).sequence->HasCommonProperty(sequence->properties()))
543 return false;
544 }
545
546 // All clear, actually start the sequence. Note: base::TimeTicks::Now has
547 // a resolution that can be as bad as 15ms. If this causes glitches in the
548 // animations, this can be switched to HighResNow() (animation uses Now()
549 // internally).
550 base::TimeTicks start_time = is_animating()
551 ? last_step_time_
552 : base::TimeTicks::Now();
553
554 running_animations_.push_back(RunningAnimation(sequence, start_time));
555
556 // Need to keep a reference to the animation.
557 AddToQueueIfNotPresent(sequence);
558
559 // Ensure that animations get stepped at their start time.
560 Step(start_time);
561
562 return true;
563 }
564
565 void LayerAnimator::GetTargetValue(
566 LayerAnimationElement::TargetValue* target) const {
567 for (AnimationQueue::const_iterator iter = animation_queue_.begin();
568 iter != animation_queue_.end(); ++iter) {
569 (*iter)->GetTargetValue(target);
570 }
571 }
572
573 void LayerAnimator::OnScheduled(LayerAnimationSequence* sequence) {
574 if (observers_.might_have_observers()) {
575 ObserverListBase<LayerAnimationObserver>::Iterator it(observers_);
576 LayerAnimationObserver* obs;
577 while ((obs = it.GetNext()) != NULL) {
578 sequence->AddObserver(obs);
579 }
580 }
581 sequence->OnScheduled();
582 }
583
584 } // namespace ui
OLDNEW
« no previous file with comments | « ui/gfx/compositor/layer_animator.h ('k') | ui/gfx/compositor/layer_animator_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698