Chromium Code Reviews| 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 |