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

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

Issue 8247009: Explicit animation support (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Added new preemption strategy: replace queued animations. Created 9 years, 2 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
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "ui/gfx/compositor/layer_animator.h" 5 #include "ui/gfx/compositor/layer_animator.h"
6 6
7 #include "base/debug/trace_event.h"
7 #include "base/logging.h" 8 #include "base/logging.h"
8 #include "base/stl_util.h" 9 #include "base/memory/scoped_ptr.h"
9 #include "ui/base/animation/animation_container.h"
10 #include "ui/base/animation/animation.h" 10 #include "ui/base/animation/animation.h"
11 #include "ui/base/animation/tween.h"
12 #include "ui/gfx/compositor/compositor.h" 11 #include "ui/gfx/compositor/compositor.h"
13 #include "ui/gfx/compositor/layer.h" 12 #include "ui/gfx/compositor/layer.h"
14 #include "ui/gfx/compositor/layer_animator_delegate.h" 13 #include "ui/gfx/compositor/layer_animation_sequence.h"
15 #include "ui/gfx/transform.h" 14
16 #include "ui/gfx/rect.h" 15 namespace ui {
16
17 class LayerAnimator;
17 18
18 namespace { 19 namespace {
19 20
20 void SetMatrixElement(SkMatrix44& matrix, int index, SkMScalar value) { 21 static const int kDefaultTransitionDurationMs = 250;
21 int row = index / 4; 22 static const int kDefaultFramerateHz = 10;
22 int col = index % 4; 23
23 matrix.set(row, col, value); 24 class LayerAnimation : public Animation {
24 } 25 public:
25 26 // The layer animation does not own the animator.
26 SkMScalar GetMatrixElement(const SkMatrix44& matrix, int index) { 27 explicit LayerAnimation(LayerAnimator* animator)
27 int row = index / 4; 28 : Animation(base::TimeDelta::FromMilliseconds(kDefaultFramerateHz)),
28 int col = index % 4; 29 animator_(animator) {
29 return matrix.get(row, col); 30 }
30 } 31 virtual ~LayerAnimation() {}
31 32
32 } // anonymous namespace 33 private:
33 34 // Implementation of Animation
34 namespace ui { 35 double GetCurrentValue() const { return 0.0; }
sky 2011/10/19 00:06:33 virtual/OVERRIDE
35 36 virtual void Step(base::TimeTicks time_now) { animator_->Step(time_now); }
sky 2011/10/19 00:06:33 OVERRIDE
36 LayerAnimator::LayerAnimator(Layer* layer) 37
37 : layer_(layer), 38 LayerAnimator* animator_;
38 got_initial_tick_(false) { 39 };
sky 2011/10/19 00:06:33 DISALLOW_COPY_AND_ASSIGN
40
41 } // namespace;
42
43 /* static */
sky 2011/10/19 00:06:33 /* static */ -> // static
44 LayerAnimator* LayerAnimator::CreateDefaultAnimator() {
45 return new LayerAnimator(base::TimeDelta::FromMilliseconds(0));
46 }
47
48 /* static */
49 LayerAnimator* LayerAnimator::CreateImplicitAnimator() {
50 return new LayerAnimator(
51 base::TimeDelta::FromMilliseconds(kDefaultTransitionDurationMs));
52 }
53
54 LayerAnimator::LayerAnimator(base::TimeDelta transition_duration)
55 : delegate_(NULL),
56 preemption_strategy_(IMMEDIATELY_SET_NEW_TARGET),
57 transition_duration_(transition_duration),
58 ALLOW_THIS_IN_INITIALIZER_LIST(animation_(new LayerAnimation(this))) {
39 } 59 }
40 60
41 LayerAnimator::~LayerAnimator() { 61 LayerAnimator::~LayerAnimator() {
42 } 62 ClearAnimations();
43 63 }
44 void LayerAnimator::SetAnimation(Animation* animation) { 64
65 void LayerAnimator::SetTransform(const Transform& transform) {
66 StartAnimation(new LayerAnimationSequence(
67 LayerAnimationElement::CreateTransformElement(transform,
68 transition_duration_)));
69 }
70
71 void LayerAnimator::SetBounds(const gfx::Rect& bounds) {
72 StartAnimation(new LayerAnimationSequence(
73 LayerAnimationElement::CreateBoundsElement(bounds,
74 transition_duration_)));
75 }
76
77 void LayerAnimator::SetOpacity(float opacity) {
78 StartAnimation(new LayerAnimationSequence(
79 LayerAnimationElement::CreateOpacityElement(opacity,
80 transition_duration_)));
81 }
82
83 void LayerAnimator::SetDelegate(LayerAnimationDelegate* delegate) {
84 delegate_ = delegate;
85 if (!delegate_) {
sky 2011/10/19 15:43:25 remove {} Why does no delegate imply you need to c
86 ClearAnimations();
87 }
88 }
89
90 void LayerAnimator::StartAnimation(LayerAnimationSequence* animation) {
91 if (!StartSequenceImmediately(animation)) {
92 // Attempt to preempt a running animation.
93 switch (preemption_strategy_) {
94 case IMMEDIATELY_SET_NEW_TARGET:
95 ImmediatelySetNewTarget(animation);
96 break;
97 case IMMEDIATELY_ANIMATE_TO_NEW_TARGET:
98 ImmediatelyAnimateToNewTarget(animation);
99 break;
100 case ENQUEUE_NEW_ANIMATION:
101 EnqueueNewAnimation(animation);
102 break;
103 case REPLACE_QUEUED_ANIMATIONS:
104 ReplaceQueuedAnimations(animation);
105 break;
106 case BLEND_WITH_CURRENT_ANIMATION: {
107 // TODO(vollick) Add support for blended sequences and use them here.
108 NOTIMPLEMENTED();
109 break;
110 }
111 }
112 }
113 FinishAnyAnimationWithZeroDuration();
114 }
115
116 void LayerAnimator::ScheduleAnimation(LayerAnimationSequence* animation) {
117 animation_queue_.push_back(animation);
118 ProcessQueue();
119 }
120
121 void LayerAnimator::ScheduleTogether(
122 const std::vector<LayerAnimationSequence*>& animations) {
sky 2011/10/19 15:43:25 nit: spacing
123 // Collect all the affected properties.
124 LayerAnimationElement::AnimatableProperties animated_properties;
125 std::vector<LayerAnimationSequence*>::const_iterator iter =
sky 2011/10/19 15:43:25 move iterator into for loop.
126 animations.begin();
127 while (iter != animations.end()) {
128 LayerAnimationElement::AnimatableProperties::const_iterator prop_iter =
sky 2011/10/19 15:43:25 Can this be animated_properties.insert((*iter)->pr
129 (*iter)->properties().begin();
130 while (prop_iter != (*iter)->properties().end()) {
131 animated_properties.insert(*prop_iter);
132 ++prop_iter;
133 }
134 ++iter;
135 }
136
137 // Scheduling a zero duration pause that affects all the animated properties
138 // will prevent any of the sequences from animating until all the properties
139 // are free.
sky 2011/10/19 15:43:25 free? Do you mean existing animations done?
140 ScheduleAnimation(
141 new LayerAnimationSequence(
142 LayerAnimationElement::CreatePauseElement(animated_properties,
143 base::TimeDelta())));
144
145 // These animations (provided they don't animate any common properties) will
146 // now animate together if trivially scheduled.
147 iter = animations.begin();
148 while (iter != animations.end()) {
149 ScheduleAnimation(*iter);
150 ++iter;
151 }
152 }
153
154 bool LayerAnimator::IsAnimating() const {
155 return animation_queue_.size() > 0;
sky 2011/10/19 15:43:25 !empty(). You can inline this if you want.
156 }
157
158 void LayerAnimator::StopAnimatingProperty(
159 LayerAnimationElement::AnimatableProperty property) {
160 while (true) {
161 RunningAnimation* running = GetRunningAnimation(property);
162 if (!running)
163 break;
164 FinishAnimation(running->sequence);
165 }
166 }
167
168 void LayerAnimator::StopAnimating() {
169 while (IsAnimating())
170 FinishAnimation(running_animations_[0].sequence);
171 }
172
173 void LayerAnimator::Step(base::TimeTicks now) {
174 TRACE_EVENT0("LayerAnimator", "Step");
175 last_step_time_ = now;
176 RunningAnimations running_animations_copy = running_animations_;
sky 2011/10/19 15:43:25 Document why you need to make a copy.
177 RunningAnimations::iterator iter = running_animations_copy.begin();
sky 2011/10/19 15:43:25 move iterator into for lop.
178 while (iter != running_animations_copy.end()) {
179 base::TimeDelta delta = now - (*iter).start_time;
180 if (delta >= (*iter).sequence->duration() &&
181 !(*iter).sequence->is_cyclic()) {
182 FinishAnimation((*iter).sequence);
183 } else {
184 (*iter).sequence->Progress(delta, delegate());
185 }
186 ++iter;
187 }
188 }
189
190 void LayerAnimator::SetAnimationForTest(Animation* animation) {
45 animation_.reset(animation); 191 animation_.reset(animation);
46 if (animation_.get()) { 192 }
47 static ui::AnimationContainer* container = NULL; 193
48 if (!container) { 194 void LayerAnimator::UpdateAnimationState() {
49 container = new AnimationContainer; 195 if (!animation_.get())
50 container->AddRef();
51 }
52 animation_->set_delegate(this);
53 animation_->SetContainer(container);
sky 2011/10/19 00:06:33 Make all animations share the same container like
54 got_initial_tick_ = false;
55 }
56 }
57
58 void LayerAnimator::AnimateToPoint(const gfx::Point& target) {
59 StopAnimating(LOCATION);
60 const gfx::Rect& layer_bounds = layer_->bounds();
61 if (target == layer_bounds.origin())
62 return; // Already there.
63
64 Params& element = elements_[LOCATION];
65 element.location.target_x = target.x();
66 element.location.target_y = target.y();
67 element.location.start_x = layer_bounds.origin().x();
68 element.location.start_y = layer_bounds.origin().y();
69 }
70
71 void LayerAnimator::AnimateTransform(const Transform& transform) {
72 StopAnimating(TRANSFORM);
73 const Transform& layer_transform = layer_->transform();
74 if (transform == layer_transform)
75 return; // Already there.
76
77 Params& element = elements_[TRANSFORM];
78 for (int i = 0; i < 16; ++i) {
79 element.transform.start[i] =
80 GetMatrixElement(layer_transform.matrix(), i);
81 element.transform.target[i] =
82 GetMatrixElement(transform.matrix(), i);
83 }
84 }
85
86 void LayerAnimator::AnimateOpacity(float target_opacity) {
87 StopAnimating(OPACITY);
88 if (layer_->opacity() == target_opacity)
89 return; 196 return;
90 197
91 Params& element = elements_[OPACITY]; 198 if (IsAnimating())
92 element.opacity.start = layer_->opacity(); 199 animation_->Start();
93 element.opacity.target = target_opacity; 200 else
94 } 201 animation_->Stop();
95 202 }
96 gfx::Point LayerAnimator::GetTargetPoint() { 203
97 return IsAnimating(LOCATION) ? 204 void LayerAnimator::RemoveAnimation(LayerAnimationSequence* sequence) {
98 gfx::Point(elements_[LOCATION].location.target_x, 205 // First remove from running animations
99 elements_[LOCATION].location.target_y) : 206 RunningAnimations::iterator iter = running_animations_.begin();
sky 2011/10/19 15:43:25 move into for loop.
100 layer_->bounds().origin(); 207 while (iter != running_animations_.end()) {
101 } 208 if ((*iter).sequence == sequence) {
102 209 running_animations_.erase(iter);
103 float LayerAnimator::GetTargetOpacity() { 210 break;
104 return IsAnimating(OPACITY) ? 211 }
105 elements_[OPACITY].opacity.target : layer_->opacity(); 212 ++iter;
106 } 213 }
107 214
108 ui::Transform LayerAnimator::GetTargetTransform() { 215 // Then remove from the queue
109 if (IsAnimating(TRANSFORM)) { 216 AnimationQueue::iterator queue_iter = animation_queue_.begin();
110 Transform transform; 217 while (queue_iter != animation_queue_.end()) {
111 for (int i = 0; i < 16; ++i) { 218 if ((*queue_iter) == sequence) {
112 SetMatrixElement(transform.matrix(), i, 219 animation_queue_.erase(queue_iter);
113 elements_[TRANSFORM].transform.target[i]); 220 break;
114 } 221 }
115 return transform; 222 ++queue_iter;
116 } 223 }
117 return layer_->transform(); 224 }
118 } 225
119 226 void LayerAnimator::FinishAnimation(LayerAnimationSequence* sequence) {
120 bool LayerAnimator::IsAnimating(AnimationProperty property) const { 227 sequence->Progress(sequence->duration(), delegate());
121 return elements_.count(property) > 0; 228 RemoveAnimation(sequence);
122 } 229 ProcessQueue();
123 230 UpdateAnimationState();
124 bool LayerAnimator::IsRunning() const { 231 }
125 return animation_.get() && animation_->is_animating(); 232
126 } 233 void LayerAnimator::FinishAnyAnimationWithZeroDuration() {
127 234 // Special case: if we've started a 0 duration animation, just finish it now
128 void LayerAnimator::AnimationProgressed(const ui::Animation* animation) { 235 // and get rid of it.
129 got_initial_tick_ = true; 236 RunningAnimations copy = running_animations_;
130 for (Elements::const_iterator i = elements_.begin(); i != elements_.end(); 237 RunningAnimations::iterator iter = copy.begin();
131 ++i) { 238 while (iter != copy.end()) {
132 switch (i->first) { 239 if ((*iter).sequence->duration() == base::TimeDelta()) {
133 case LOCATION: { 240 (*iter).sequence->Progress((*iter).sequence->duration(), delegate());
134 const gfx::Rect& current_bounds(layer_->bounds()); 241 RemoveAnimation((*iter).sequence);
135 gfx::Rect new_bounds = animation_->CurrentValueBetween( 242 }
136 gfx::Rect(gfx::Point(i->second.location.start_x, 243 ++iter;
137 i->second.location.start_y), 244 }
138 current_bounds.size()), 245 ProcessQueue();
139 gfx::Rect(gfx::Point(i->second.location.target_x, 246 UpdateAnimationState();
140 i->second.location.target_y), 247 }
141 current_bounds.size())); 248
142 delegate()->SetBoundsFromAnimator(new_bounds); 249 void LayerAnimator::ClearAnimations() {
250 RunningAnimations::iterator iter = running_animations_.begin();
251 while (iter != running_animations_.end()) {
252 (*iter).sequence->Abort();
253 ++iter;
254 }
255 running_animations_.clear();
256 animation_queue_.reset();
257 UpdateAnimationState();
258 }
259
260 LayerAnimator::RunningAnimation* LayerAnimator::GetRunningAnimation(
261 LayerAnimationElement::AnimatableProperty property) {
262 RunningAnimations::iterator iter = running_animations_.begin();
sky 2011/10/19 15:43:25 move into for loop.
263 while (iter != running_animations_.end()) {
264 if ((*iter).sequence->properties().find(property) !=
265 (*iter).sequence->properties().end())
266 return &(*iter);
267 ++iter;
268 }
269 return NULL;
270 }
271
272 void LayerAnimator::AddToQueueIfNotPresent(LayerAnimationSequence* animation) {
273 // If we don't have the animation in the queue yet, add it.
274 bool found_sequence = false;
275 AnimationQueue::iterator queue_iter = animation_queue_.begin();
276 while (queue_iter != animation_queue_.end()) {
277 if ((*queue_iter) == animation) {
278 found_sequence = true;
279 break;
280 }
281 ++queue_iter;
282 }
283
284 if (!found_sequence)
285 animation_queue_.insert(animation_queue_.begin(), animation);
286 }
287
288 void LayerAnimator::RemoveAllAnimationsWithACommonProperty(
289 LayerAnimationSequence* sequence,
290 bool abort) {
291 // For all the running animations, if they animate the same property,
292 // progress them to the end and remove them.
293 RunningAnimations copy = running_animations_;
294 RunningAnimations::const_iterator iter = copy.begin();
295 while (iter != copy.end()) {
296 if ((*iter).sequence->HasCommonProperty(sequence->properties())) {
297 // Finish the animation.
298 if (abort)
299 (*iter).sequence->Abort();
300 else
301 (*iter).sequence->Progress((*iter).sequence->duration(), delegate());
302 RemoveAnimation((*iter).sequence);
303 }
304 ++iter;
305 }
306 // Same for the queued animations.
307 AnimationQueue::size_type i = 0;
308 while (i < animation_queue_.size()) {
309 if (animation_queue_[i]->HasCommonProperty(sequence->properties())) {
310 // Finish the animation.
311 if (abort)
312 animation_queue_[i]->Abort();
313 else
314 animation_queue_[i]->Progress(animation_queue_[i]->duration(),
315 delegate());
316 RemoveAnimation(animation_queue_[i]);
317 } else {
318 ++i;
319 }
320 }
321 }
322
323 void LayerAnimator::ImmediatelySetNewTarget(LayerAnimationSequence* sequence) {
324 const bool abort = false;
325 RemoveAllAnimationsWithACommonProperty(sequence, abort);
326 sequence->Progress(sequence->duration(), delegate());
327 RemoveAnimation(sequence);
328 }
329
330 void LayerAnimator::ImmediatelyAnimateToNewTarget(
331 LayerAnimationSequence* sequence) {
332 const bool abort = true;
333 RemoveAllAnimationsWithACommonProperty(sequence, abort);
334 AddToQueueIfNotPresent(sequence);
335 StartSequenceImmediately(sequence);
336 }
337
338 void LayerAnimator::EnqueueNewAnimation(LayerAnimationSequence* sequence) {
339 // It is assumed that if there was no conflicting animation, we would
340 // not have been called. No need to check for a collision; just
341 // add to the queue.
342 animation_queue_.push_back(sequence);
343 ProcessQueue();
344 }
345
346 void LayerAnimator::ReplaceQueuedAnimations(LayerAnimationSequence* sequence) {
347 // Remove all animations that aren't running.
348 AnimationQueue::size_type i = 0;
349 while (i < animation_queue_.size()) {
350 bool is_running = false;
351 RunningAnimations::const_iterator iter =
352 running_animations_.begin();
353 while (iter != running_animations_.end()) {
354 if ((*iter).sequence == animation_queue_[i]) {
355 is_running = true;
143 break; 356 break;
144 } 357 }
145 358 ++iter;
146 case TRANSFORM: { 359 }
147 Transform transform; 360 if (!is_running)
148 for (int j = 0; j < 16; ++j) { 361 RemoveAnimation(animation_queue_[i]);
149 SkMScalar value = animation_->CurrentValueBetween( 362 else
150 i->second.transform.start[j], 363 ++i;
151 i->second.transform.target[j]); 364 }
152 SetMatrixElement(transform.matrix(), j, value); 365 animation_queue_.push_back(sequence);
153 } 366 ProcessQueue();
154 delegate()->SetTransformFromAnimator(transform); 367 }
155 break; 368
369 void LayerAnimator::ProcessQueue() {
370 bool started_sequence = false;
371
372 do {
373 started_sequence = false;
374
375 // Build a list of all currently animated properties.
376 LayerAnimationElement::AnimatableProperties animated;
377 RunningAnimations::const_iterator iter = running_animations_.begin();
378 while (iter != running_animations_.end()) {
379 LayerAnimationElement::AnimatableProperties::const_iterator prop_iter =
380 (*iter).sequence->properties().begin();
381 while (prop_iter != (*iter).sequence->properties().end()) {
382 animated.insert(*prop_iter);
383 ++prop_iter;
156 } 384 }
157 385 ++iter;
158 case OPACITY: { 386 }
159 delegate()->SetOpacityFromAnimator(animation_->CurrentValueBetween( 387
160 i->second.opacity.start, i->second.opacity.target)); 388 // Try to find an animation that doesn't conflict with an animated
389 // property or a property that will be animated before it.
390 AnimationQueue::iterator queue_iter = animation_queue_.begin();
391 while (queue_iter != animation_queue_.end()) {
392 if (!(*queue_iter)->HasCommonProperty(animated)) {
393 StartSequenceImmediately(*queue_iter);
394 started_sequence = true;
161 break; 395 break;
162 } 396 }
163 397 // Animation couldn't be started. Add its properties to the collection so
164 default: 398 // that we don't start a conflicting animation. For example, if our queue
165 NOTREACHED(); 399 // has the elements { {T,B}, {B} } (that is, an element that animates both
166 } 400 // the transform and the bounds followed by an element that animates the
167 } 401 // bounds), and we're currently animating the transform, we can't start
168 layer_->ScheduleDraw(); 402 // the first element because it animates the transform, too. We cannot
169 } 403 // start the second element, either, because the first element animates
170 404 // bounds too, and needs to go first.
171 void LayerAnimator::AnimationEnded(const ui::Animation* animation) { 405 LayerAnimationElement::AnimatableProperties::const_iterator prop_iter =
172 AnimationProgressed(animation); 406 (*queue_iter)->properties().begin();
173 } 407 while (prop_iter != (*queue_iter)->properties().end()) {
174 408 animated.insert(*prop_iter);
175 void LayerAnimator::StopAnimating(AnimationProperty property) { 409 ++prop_iter;
176 if (!IsAnimating(property)) 410 }
177 return; 411 ++queue_iter;
178 412 }
179 elements_.erase(property); 413
180 } 414 // If we started a sequence, try again. We may be able to start several.
181 415 } while (started_sequence);
182 LayerAnimatorDelegate* LayerAnimator::delegate() { 416 }
183 return static_cast<LayerAnimatorDelegate*>(layer_); 417
418 bool LayerAnimator::StartSequenceImmediately(LayerAnimationSequence* sequence) {
419 // Ensure that no one is animating one of the sequence's properties already.
420 RunningAnimations::const_iterator iter = running_animations_.begin();
421 while (iter != running_animations_.end()) {
422 if ((*iter).sequence->HasCommonProperty(sequence->properties()))
423 return false;
424 ++iter;
425 }
426
427 // All clear, actually start the sequence. Note: base::TimeTicks::Now has
428 // a resolution that can be as bad as 15ms. If this causes glitches in the
429 // animations, this can be switched to HighResNow() (animation uses Now()
430 // internally).
431 base::TimeTicks start_time = IsAnimating()
432 ? last_step_time_
433 : base::TimeTicks::Now();
sky 2011/10/19 15:43:25 For the animating case this effectively starts the
434
435 running_animations_.push_back(RunningAnimation(sequence, start_time));
436
437 // Need to keep a reference to the animation.
438 AddToQueueIfNotPresent(sequence);
439
440 // Ensure that animations get stepped at their start time.
441 Step(start_time);
442
443 return true;
184 } 444 }
185 445
186 } // namespace ui 446 } // namespace ui
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698