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