OLD | NEW |
---|---|
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 |
OLD | NEW |