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

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