| OLD | NEW |
| (Empty) |
| 1 // Copyright 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 "cc/animation/layer_animation_controller.h" | |
| 6 | |
| 7 #include <algorithm> | |
| 8 #include <vector> | |
| 9 | |
| 10 #include "cc/animation/animation.h" | |
| 11 #include "cc/animation/animation_delegate.h" | |
| 12 #include "cc/animation/animation_registrar.h" | |
| 13 #include "cc/animation/keyframed_animation_curve.h" | |
| 14 #include "cc/animation/layer_animation_value_observer.h" | |
| 15 #include "cc/animation/layer_animation_value_provider.h" | |
| 16 #include "cc/animation/scroll_offset_animation_curve.h" | |
| 17 #include "cc/base/scoped_ptr_algorithm.h" | |
| 18 #include "cc/output/filter_operations.h" | |
| 19 #include "ui/gfx/geometry/box_f.h" | |
| 20 #include "ui/gfx/transform.h" | |
| 21 | |
| 22 namespace cc { | |
| 23 | |
| 24 LayerAnimationController::LayerAnimationController(int id) | |
| 25 : registrar_(0), | |
| 26 id_(id), | |
| 27 is_active_(false), | |
| 28 value_provider_(nullptr), | |
| 29 layer_animation_delegate_(nullptr), | |
| 30 needs_to_start_animations_(false), | |
| 31 scroll_offset_animation_was_interrupted_(false) { | |
| 32 } | |
| 33 | |
| 34 LayerAnimationController::~LayerAnimationController() { | |
| 35 if (registrar_) | |
| 36 registrar_->UnregisterAnimationController(this); | |
| 37 } | |
| 38 | |
| 39 scoped_refptr<LayerAnimationController> LayerAnimationController::Create( | |
| 40 int id) { | |
| 41 return make_scoped_refptr(new LayerAnimationController(id)); | |
| 42 } | |
| 43 | |
| 44 void LayerAnimationController::PauseAnimation(int animation_id, | |
| 45 base::TimeDelta time_offset) { | |
| 46 for (size_t i = 0; i < animations_.size(); ++i) { | |
| 47 if (animations_[i]->id() == animation_id) { | |
| 48 animations_[i]->SetRunState(Animation::PAUSED, | |
| 49 time_offset + animations_[i]->start_time()); | |
| 50 } | |
| 51 } | |
| 52 } | |
| 53 | |
| 54 struct HasAnimationId { | |
| 55 explicit HasAnimationId(int id) : id_(id) {} | |
| 56 bool operator()(Animation* animation) const { | |
| 57 return animation->id() == id_; | |
| 58 } | |
| 59 | |
| 60 private: | |
| 61 int id_; | |
| 62 }; | |
| 63 | |
| 64 void LayerAnimationController::RemoveAnimation(int animation_id) { | |
| 65 auto animations_to_remove = | |
| 66 animations_.remove_if(HasAnimationId(animation_id)); | |
| 67 for (auto it = animations_to_remove; it != animations_.end(); ++it) { | |
| 68 if ((*it)->target_property() == Animation::SCROLL_OFFSET) { | |
| 69 scroll_offset_animation_was_interrupted_ = true; | |
| 70 break; | |
| 71 } | |
| 72 } | |
| 73 animations_.erase(animations_to_remove, animations_.end()); | |
| 74 UpdateActivation(NORMAL_ACTIVATION); | |
| 75 } | |
| 76 | |
| 77 struct HasAnimationIdAndProperty { | |
| 78 HasAnimationIdAndProperty(int id, Animation::TargetProperty target_property) | |
| 79 : id_(id), target_property_(target_property) {} | |
| 80 bool operator()(Animation* animation) const { | |
| 81 return animation->id() == id_ && | |
| 82 animation->target_property() == target_property_; | |
| 83 } | |
| 84 | |
| 85 private: | |
| 86 int id_; | |
| 87 Animation::TargetProperty target_property_; | |
| 88 }; | |
| 89 | |
| 90 void LayerAnimationController::RemoveAnimation( | |
| 91 int animation_id, | |
| 92 Animation::TargetProperty target_property) { | |
| 93 auto animations_to_remove = animations_.remove_if( | |
| 94 HasAnimationIdAndProperty(animation_id, target_property)); | |
| 95 if (target_property == Animation::SCROLL_OFFSET && | |
| 96 animations_to_remove != animations_.end()) | |
| 97 scroll_offset_animation_was_interrupted_ = true; | |
| 98 | |
| 99 animations_.erase(animations_to_remove, animations_.end()); | |
| 100 UpdateActivation(NORMAL_ACTIVATION); | |
| 101 } | |
| 102 | |
| 103 void LayerAnimationController::AbortAnimations( | |
| 104 Animation::TargetProperty target_property) { | |
| 105 for (size_t i = 0; i < animations_.size(); ++i) { | |
| 106 if (animations_[i]->target_property() == target_property && | |
| 107 !animations_[i]->is_finished()) | |
| 108 animations_[i]->SetRunState(Animation::ABORTED, last_tick_time_); | |
| 109 } | |
| 110 } | |
| 111 | |
| 112 // Ensures that the list of active animations on the main thread and the impl | |
| 113 // thread are kept in sync. | |
| 114 void LayerAnimationController::PushAnimationUpdatesTo( | |
| 115 LayerAnimationController* controller_impl) { | |
| 116 DCHECK(this != controller_impl); | |
| 117 if (!has_any_animation() && !controller_impl->has_any_animation()) | |
| 118 return; | |
| 119 PurgeAnimationsMarkedForDeletion(); | |
| 120 PushNewAnimationsToImplThread(controller_impl); | |
| 121 | |
| 122 // Remove finished impl side animations only after pushing, | |
| 123 // and only after the animations are deleted on the main thread | |
| 124 // this insures we will never push an animation twice. | |
| 125 RemoveAnimationsCompletedOnMainThread(controller_impl); | |
| 126 | |
| 127 PushPropertiesToImplThread(controller_impl); | |
| 128 controller_impl->UpdateActivation(NORMAL_ACTIVATION); | |
| 129 UpdateActivation(NORMAL_ACTIVATION); | |
| 130 } | |
| 131 | |
| 132 void LayerAnimationController::Animate(base::TimeTicks monotonic_time) { | |
| 133 DCHECK(!monotonic_time.is_null()); | |
| 134 if (!HasValueObserver()) | |
| 135 return; | |
| 136 | |
| 137 if (needs_to_start_animations_) | |
| 138 StartAnimations(monotonic_time); | |
| 139 TickAnimations(monotonic_time); | |
| 140 last_tick_time_ = monotonic_time; | |
| 141 } | |
| 142 | |
| 143 void LayerAnimationController::AccumulatePropertyUpdates( | |
| 144 base::TimeTicks monotonic_time, | |
| 145 AnimationEventsVector* events) { | |
| 146 if (!events) | |
| 147 return; | |
| 148 | |
| 149 for (size_t i = 0; i < animations_.size(); ++i) { | |
| 150 Animation* animation = animations_[i]; | |
| 151 if (!animation->is_impl_only()) | |
| 152 continue; | |
| 153 | |
| 154 if (!animation->InEffect(monotonic_time)) | |
| 155 continue; | |
| 156 | |
| 157 base::TimeDelta trimmed = | |
| 158 animation->TrimTimeToCurrentIteration(monotonic_time); | |
| 159 switch (animation->target_property()) { | |
| 160 case Animation::OPACITY: { | |
| 161 AnimationEvent event(AnimationEvent::PROPERTY_UPDATE, id_, | |
| 162 animation->group(), Animation::OPACITY, | |
| 163 monotonic_time); | |
| 164 const FloatAnimationCurve* float_animation_curve = | |
| 165 animation->curve()->ToFloatAnimationCurve(); | |
| 166 event.opacity = float_animation_curve->GetValue(trimmed); | |
| 167 event.is_impl_only = true; | |
| 168 events->push_back(event); | |
| 169 break; | |
| 170 } | |
| 171 | |
| 172 case Animation::TRANSFORM: { | |
| 173 AnimationEvent event(AnimationEvent::PROPERTY_UPDATE, id_, | |
| 174 animation->group(), Animation::TRANSFORM, | |
| 175 monotonic_time); | |
| 176 const TransformAnimationCurve* transform_animation_curve = | |
| 177 animation->curve()->ToTransformAnimationCurve(); | |
| 178 event.transform = transform_animation_curve->GetValue(trimmed); | |
| 179 event.is_impl_only = true; | |
| 180 events->push_back(event); | |
| 181 break; | |
| 182 } | |
| 183 | |
| 184 case Animation::FILTER: { | |
| 185 AnimationEvent event(AnimationEvent::PROPERTY_UPDATE, id_, | |
| 186 animation->group(), Animation::FILTER, | |
| 187 monotonic_time); | |
| 188 const FilterAnimationCurve* filter_animation_curve = | |
| 189 animation->curve()->ToFilterAnimationCurve(); | |
| 190 event.filters = filter_animation_curve->GetValue(trimmed); | |
| 191 event.is_impl_only = true; | |
| 192 events->push_back(event); | |
| 193 break; | |
| 194 } | |
| 195 | |
| 196 case Animation::BACKGROUND_COLOR: { | |
| 197 break; | |
| 198 } | |
| 199 | |
| 200 case Animation::SCROLL_OFFSET: { | |
| 201 // Impl-side changes to scroll offset are already sent back to the | |
| 202 // main thread (e.g. for user-driven scrolling), so a PROPERTY_UPDATE | |
| 203 // isn't needed. | |
| 204 break; | |
| 205 } | |
| 206 } | |
| 207 } | |
| 208 } | |
| 209 | |
| 210 void LayerAnimationController::UpdateState(bool start_ready_animations, | |
| 211 AnimationEventsVector* events) { | |
| 212 if (!HasActiveValueObserver()) | |
| 213 return; | |
| 214 | |
| 215 // Animate hasn't been called, this happens if an observer has been added | |
| 216 // between the Commit and Draw phases. | |
| 217 if (last_tick_time_ == base::TimeTicks()) | |
| 218 return; | |
| 219 | |
| 220 if (start_ready_animations) | |
| 221 PromoteStartedAnimations(last_tick_time_, events); | |
| 222 | |
| 223 MarkFinishedAnimations(last_tick_time_); | |
| 224 MarkAnimationsForDeletion(last_tick_time_, events); | |
| 225 | |
| 226 if (needs_to_start_animations_ && start_ready_animations) { | |
| 227 StartAnimations(last_tick_time_); | |
| 228 PromoteStartedAnimations(last_tick_time_, events); | |
| 229 } | |
| 230 | |
| 231 AccumulatePropertyUpdates(last_tick_time_, events); | |
| 232 | |
| 233 UpdateActivation(NORMAL_ACTIVATION); | |
| 234 } | |
| 235 | |
| 236 struct AffectsNoObservers { | |
| 237 bool operator()(Animation* animation) const { | |
| 238 return !animation->affects_active_observers() && | |
| 239 !animation->affects_pending_observers(); | |
| 240 } | |
| 241 }; | |
| 242 | |
| 243 void LayerAnimationController::ActivateAnimations() { | |
| 244 for (size_t i = 0; i < animations_.size(); ++i) { | |
| 245 animations_[i]->set_affects_active_observers( | |
| 246 animations_[i]->affects_pending_observers()); | |
| 247 } | |
| 248 animations_.erase(cc::remove_if(&animations_, | |
| 249 animations_.begin(), | |
| 250 animations_.end(), | |
| 251 AffectsNoObservers()), | |
| 252 animations_.end()); | |
| 253 scroll_offset_animation_was_interrupted_ = false; | |
| 254 UpdateActivation(NORMAL_ACTIVATION); | |
| 255 } | |
| 256 | |
| 257 void LayerAnimationController::AddAnimation(scoped_ptr<Animation> animation) { | |
| 258 animations_.push_back(animation.Pass()); | |
| 259 needs_to_start_animations_ = true; | |
| 260 UpdateActivation(NORMAL_ACTIVATION); | |
| 261 } | |
| 262 | |
| 263 Animation* LayerAnimationController::GetAnimation( | |
| 264 Animation::TargetProperty target_property) const { | |
| 265 for (size_t i = 0; i < animations_.size(); ++i) { | |
| 266 size_t index = animations_.size() - i - 1; | |
| 267 if (animations_[index]->target_property() == target_property) | |
| 268 return animations_[index]; | |
| 269 } | |
| 270 return 0; | |
| 271 } | |
| 272 | |
| 273 Animation* LayerAnimationController::GetAnimationById(int animation_id) const { | |
| 274 for (size_t i = 0; i < animations_.size(); ++i) | |
| 275 if (animations_[i]->id() == animation_id) | |
| 276 return animations_[i]; | |
| 277 return nullptr; | |
| 278 } | |
| 279 | |
| 280 bool LayerAnimationController::HasActiveAnimation() const { | |
| 281 for (size_t i = 0; i < animations_.size(); ++i) { | |
| 282 if (!animations_[i]->is_finished()) | |
| 283 return true; | |
| 284 } | |
| 285 return false; | |
| 286 } | |
| 287 | |
| 288 bool LayerAnimationController::IsAnimatingProperty( | |
| 289 Animation::TargetProperty target_property) const { | |
| 290 for (size_t i = 0; i < animations_.size(); ++i) { | |
| 291 if (!animations_[i]->is_finished() && | |
| 292 animations_[i]->InEffect(last_tick_time_) && | |
| 293 animations_[i]->target_property() == target_property) | |
| 294 return true; | |
| 295 } | |
| 296 return false; | |
| 297 } | |
| 298 | |
| 299 void LayerAnimationController::SetAnimationRegistrar( | |
| 300 AnimationRegistrar* registrar) { | |
| 301 if (registrar_ == registrar) | |
| 302 return; | |
| 303 | |
| 304 if (registrar_) | |
| 305 registrar_->UnregisterAnimationController(this); | |
| 306 | |
| 307 registrar_ = registrar; | |
| 308 if (registrar_) | |
| 309 registrar_->RegisterAnimationController(this); | |
| 310 | |
| 311 UpdateActivation(FORCE_ACTIVATION); | |
| 312 } | |
| 313 | |
| 314 void LayerAnimationController::NotifyAnimationStarted( | |
| 315 const AnimationEvent& event) { | |
| 316 if (event.is_impl_only) { | |
| 317 FOR_EACH_OBSERVER(LayerAnimationEventObserver, event_observers_, | |
| 318 OnAnimationStarted(event)); | |
| 319 if (layer_animation_delegate_) | |
| 320 layer_animation_delegate_->NotifyAnimationStarted( | |
| 321 event.monotonic_time, event.target_property, event.group_id); | |
| 322 return; | |
| 323 } | |
| 324 | |
| 325 for (size_t i = 0; i < animations_.size(); ++i) { | |
| 326 if (animations_[i]->group() == event.group_id && | |
| 327 animations_[i]->target_property() == event.target_property && | |
| 328 animations_[i]->needs_synchronized_start_time()) { | |
| 329 animations_[i]->set_needs_synchronized_start_time(false); | |
| 330 if (!animations_[i]->has_set_start_time()) | |
| 331 animations_[i]->set_start_time(event.monotonic_time); | |
| 332 | |
| 333 FOR_EACH_OBSERVER(LayerAnimationEventObserver, event_observers_, | |
| 334 OnAnimationStarted(event)); | |
| 335 if (layer_animation_delegate_) | |
| 336 layer_animation_delegate_->NotifyAnimationStarted( | |
| 337 event.monotonic_time, event.target_property, event.group_id); | |
| 338 | |
| 339 return; | |
| 340 } | |
| 341 } | |
| 342 } | |
| 343 | |
| 344 void LayerAnimationController::NotifyAnimationFinished( | |
| 345 const AnimationEvent& event) { | |
| 346 if (event.is_impl_only) { | |
| 347 if (layer_animation_delegate_) | |
| 348 layer_animation_delegate_->NotifyAnimationFinished( | |
| 349 event.monotonic_time, event.target_property, event.group_id); | |
| 350 return; | |
| 351 } | |
| 352 | |
| 353 for (size_t i = 0; i < animations_.size(); ++i) { | |
| 354 if (animations_[i]->group() == event.group_id && | |
| 355 animations_[i]->target_property() == event.target_property) { | |
| 356 animations_[i]->set_received_finished_event(true); | |
| 357 if (layer_animation_delegate_) | |
| 358 layer_animation_delegate_->NotifyAnimationFinished( | |
| 359 event.monotonic_time, event.target_property, event.group_id); | |
| 360 | |
| 361 return; | |
| 362 } | |
| 363 } | |
| 364 } | |
| 365 | |
| 366 void LayerAnimationController::NotifyAnimationAborted( | |
| 367 const AnimationEvent& event) { | |
| 368 for (size_t i = 0; i < animations_.size(); ++i) { | |
| 369 if (animations_[i]->group() == event.group_id && | |
| 370 animations_[i]->target_property() == event.target_property) { | |
| 371 animations_[i]->SetRunState(Animation::ABORTED, event.monotonic_time); | |
| 372 } | |
| 373 } | |
| 374 } | |
| 375 | |
| 376 void LayerAnimationController::NotifyAnimationPropertyUpdate( | |
| 377 const AnimationEvent& event) { | |
| 378 bool notify_active_observers = true; | |
| 379 bool notify_pending_observers = true; | |
| 380 switch (event.target_property) { | |
| 381 case Animation::OPACITY: | |
| 382 NotifyObserversOpacityAnimated( | |
| 383 event.opacity, notify_active_observers, notify_pending_observers); | |
| 384 break; | |
| 385 case Animation::TRANSFORM: | |
| 386 NotifyObserversTransformAnimated( | |
| 387 event.transform, notify_active_observers, notify_pending_observers); | |
| 388 break; | |
| 389 default: | |
| 390 NOTREACHED(); | |
| 391 } | |
| 392 } | |
| 393 | |
| 394 void LayerAnimationController::AddValueObserver( | |
| 395 LayerAnimationValueObserver* observer) { | |
| 396 if (!value_observers_.HasObserver(observer)) | |
| 397 value_observers_.AddObserver(observer); | |
| 398 } | |
| 399 | |
| 400 void LayerAnimationController::RemoveValueObserver( | |
| 401 LayerAnimationValueObserver* observer) { | |
| 402 value_observers_.RemoveObserver(observer); | |
| 403 } | |
| 404 | |
| 405 void LayerAnimationController::AddEventObserver( | |
| 406 LayerAnimationEventObserver* observer) { | |
| 407 if (!event_observers_.HasObserver(observer)) | |
| 408 event_observers_.AddObserver(observer); | |
| 409 } | |
| 410 | |
| 411 void LayerAnimationController::RemoveEventObserver( | |
| 412 LayerAnimationEventObserver* observer) { | |
| 413 event_observers_.RemoveObserver(observer); | |
| 414 } | |
| 415 | |
| 416 bool LayerAnimationController::HasFilterAnimationThatInflatesBounds() const { | |
| 417 for (size_t i = 0; i < animations_.size(); ++i) { | |
| 418 if (!animations_[i]->is_finished() && | |
| 419 animations_[i]->target_property() == Animation::FILTER && | |
| 420 animations_[i] | |
| 421 ->curve() | |
| 422 ->ToFilterAnimationCurve() | |
| 423 ->HasFilterThatMovesPixels()) | |
| 424 return true; | |
| 425 } | |
| 426 | |
| 427 return false; | |
| 428 } | |
| 429 | |
| 430 bool LayerAnimationController::HasTransformAnimationThatInflatesBounds() const { | |
| 431 return IsAnimatingProperty(Animation::TRANSFORM); | |
| 432 } | |
| 433 | |
| 434 bool LayerAnimationController::FilterAnimationBoundsForBox( | |
| 435 const gfx::BoxF& box, gfx::BoxF* bounds) const { | |
| 436 // TODO(avallee): Implement. | |
| 437 return false; | |
| 438 } | |
| 439 | |
| 440 bool LayerAnimationController::TransformAnimationBoundsForBox( | |
| 441 const gfx::BoxF& box, | |
| 442 gfx::BoxF* bounds) const { | |
| 443 DCHECK(HasTransformAnimationThatInflatesBounds()) | |
| 444 << "TransformAnimationBoundsForBox will give incorrect results if there " | |
| 445 << "are no transform animations affecting bounds, non-animated transform " | |
| 446 << "is not known"; | |
| 447 | |
| 448 // Compute bounds based on animations for which is_finished() is false. | |
| 449 // Do nothing if there are no such animations; in this case, it is assumed | |
| 450 // that callers will take care of computing bounds based on the owning layer's | |
| 451 // actual transform. | |
| 452 *bounds = gfx::BoxF(); | |
| 453 for (size_t i = 0; i < animations_.size(); ++i) { | |
| 454 if (animations_[i]->is_finished() || | |
| 455 animations_[i]->target_property() != Animation::TRANSFORM) | |
| 456 continue; | |
| 457 | |
| 458 const TransformAnimationCurve* transform_animation_curve = | |
| 459 animations_[i]->curve()->ToTransformAnimationCurve(); | |
| 460 gfx::BoxF animation_bounds; | |
| 461 bool success = | |
| 462 transform_animation_curve->AnimatedBoundsForBox(box, &animation_bounds); | |
| 463 if (!success) | |
| 464 return false; | |
| 465 bounds->Union(animation_bounds); | |
| 466 } | |
| 467 | |
| 468 return true; | |
| 469 } | |
| 470 | |
| 471 bool LayerAnimationController::HasAnimationThatAffectsScale() const { | |
| 472 for (size_t i = 0; i < animations_.size(); ++i) { | |
| 473 if (animations_[i]->is_finished() || | |
| 474 animations_[i]->target_property() != Animation::TRANSFORM) | |
| 475 continue; | |
| 476 | |
| 477 const TransformAnimationCurve* transform_animation_curve = | |
| 478 animations_[i]->curve()->ToTransformAnimationCurve(); | |
| 479 if (transform_animation_curve->AffectsScale()) | |
| 480 return true; | |
| 481 } | |
| 482 | |
| 483 return false; | |
| 484 } | |
| 485 | |
| 486 bool LayerAnimationController::HasOnlyTranslationTransforms() const { | |
| 487 for (size_t i = 0; i < animations_.size(); ++i) { | |
| 488 if (animations_[i]->is_finished() || | |
| 489 animations_[i]->target_property() != Animation::TRANSFORM) | |
| 490 continue; | |
| 491 | |
| 492 const TransformAnimationCurve* transform_animation_curve = | |
| 493 animations_[i]->curve()->ToTransformAnimationCurve(); | |
| 494 if (!transform_animation_curve->IsTranslation()) | |
| 495 return false; | |
| 496 } | |
| 497 | |
| 498 return true; | |
| 499 } | |
| 500 | |
| 501 bool LayerAnimationController::AnimationsPreserveAxisAlignment() const { | |
| 502 for (size_t i = 0; i < animations_.size(); ++i) { | |
| 503 if (animations_[i]->is_finished() || | |
| 504 animations_[i]->target_property() != Animation::TRANSFORM) | |
| 505 continue; | |
| 506 | |
| 507 const TransformAnimationCurve* transform_animation_curve = | |
| 508 animations_[i]->curve()->ToTransformAnimationCurve(); | |
| 509 if (!transform_animation_curve->PreservesAxisAlignment()) | |
| 510 return false; | |
| 511 } | |
| 512 | |
| 513 return true; | |
| 514 } | |
| 515 | |
| 516 bool LayerAnimationController::MaximumTargetScale(float* max_scale) const { | |
| 517 *max_scale = 0.f; | |
| 518 for (size_t i = 0; i < animations_.size(); ++i) { | |
| 519 if (animations_[i]->is_finished() || | |
| 520 animations_[i]->target_property() != Animation::TRANSFORM) | |
| 521 continue; | |
| 522 | |
| 523 bool forward_direction = true; | |
| 524 switch (animations_[i]->direction()) { | |
| 525 case Animation::DIRECTION_NORMAL: | |
| 526 case Animation::DIRECTION_ALTERNATE: | |
| 527 forward_direction = animations_[i]->playback_rate() >= 0.0; | |
| 528 break; | |
| 529 case Animation::DIRECTION_REVERSE: | |
| 530 case Animation::DIRECTION_ALTERNATE_REVERSE: | |
| 531 forward_direction = animations_[i]->playback_rate() < 0.0; | |
| 532 break; | |
| 533 } | |
| 534 | |
| 535 const TransformAnimationCurve* transform_animation_curve = | |
| 536 animations_[i]->curve()->ToTransformAnimationCurve(); | |
| 537 float animation_scale = 0.f; | |
| 538 if (!transform_animation_curve->MaximumTargetScale(forward_direction, | |
| 539 &animation_scale)) | |
| 540 return false; | |
| 541 *max_scale = std::max(*max_scale, animation_scale); | |
| 542 } | |
| 543 | |
| 544 return true; | |
| 545 } | |
| 546 | |
| 547 void LayerAnimationController::PushNewAnimationsToImplThread( | |
| 548 LayerAnimationController* controller_impl) const { | |
| 549 // Any new animations owned by the main thread's controller are cloned and | |
| 550 // add to the impl thread's controller. | |
| 551 for (size_t i = 0; i < animations_.size(); ++i) { | |
| 552 // If the animation is already running on the impl thread, there is no | |
| 553 // need to copy it over. | |
| 554 if (controller_impl->GetAnimationById(animations_[i]->id())) | |
| 555 continue; | |
| 556 | |
| 557 // If the animation is not running on the impl thread, it does not | |
| 558 // necessarily mean that it needs to be copied over and started; it may | |
| 559 // have already finished. In this case, the impl thread animation will | |
| 560 // have already notified that it has started and the main thread animation | |
| 561 // will no longer need | |
| 562 // a synchronized start time. | |
| 563 if (!animations_[i]->needs_synchronized_start_time()) | |
| 564 continue; | |
| 565 | |
| 566 // Scroll animations always start at the current scroll offset. | |
| 567 if (animations_[i]->target_property() == Animation::SCROLL_OFFSET) { | |
| 568 gfx::ScrollOffset current_scroll_offset; | |
| 569 if (controller_impl->value_provider_) { | |
| 570 current_scroll_offset = | |
| 571 controller_impl->value_provider_->ScrollOffsetForAnimation(); | |
| 572 } else { | |
| 573 // The owning layer isn't yet in the active tree, so the main thread | |
| 574 // scroll offset will be up-to-date. | |
| 575 current_scroll_offset = value_provider_->ScrollOffsetForAnimation(); | |
| 576 } | |
| 577 animations_[i]->curve()->ToScrollOffsetAnimationCurve()->SetInitialValue( | |
| 578 current_scroll_offset); | |
| 579 } | |
| 580 | |
| 581 // The new animation should be set to run as soon as possible. | |
| 582 Animation::RunState initial_run_state = | |
| 583 Animation::WAITING_FOR_TARGET_AVAILABILITY; | |
| 584 scoped_ptr<Animation> to_add( | |
| 585 animations_[i]->CloneAndInitialize(initial_run_state)); | |
| 586 DCHECK(!to_add->needs_synchronized_start_time()); | |
| 587 to_add->set_affects_active_observers(false); | |
| 588 controller_impl->AddAnimation(to_add.Pass()); | |
| 589 } | |
| 590 } | |
| 591 | |
| 592 static bool IsCompleted( | |
| 593 Animation* animation, | |
| 594 const LayerAnimationController* main_thread_controller) { | |
| 595 if (animation->is_impl_only()) { | |
| 596 return (animation->run_state() == Animation::WAITING_FOR_DELETION); | |
| 597 } else { | |
| 598 return !main_thread_controller->GetAnimationById(animation->id()); | |
| 599 } | |
| 600 } | |
| 601 | |
| 602 static bool AffectsActiveOnlyAndIsWaitingForDeletion(Animation* animation) { | |
| 603 return animation->run_state() == Animation::WAITING_FOR_DELETION && | |
| 604 !animation->affects_pending_observers(); | |
| 605 } | |
| 606 | |
| 607 void LayerAnimationController::RemoveAnimationsCompletedOnMainThread( | |
| 608 LayerAnimationController* controller_impl) const { | |
| 609 // Animations removed on the main thread should no longer affect pending | |
| 610 // observers, and should stop affecting active observers after the next call | |
| 611 // to ActivateAnimations. If already WAITING_FOR_DELETION, they can be removed | |
| 612 // immediately. | |
| 613 ScopedPtrVector<Animation>& animations = controller_impl->animations_; | |
| 614 for (size_t i = 0; i < animations.size(); ++i) { | |
| 615 if (IsCompleted(animations[i], this)) | |
| 616 animations[i]->set_affects_pending_observers(false); | |
| 617 } | |
| 618 animations.erase(cc::remove_if(&animations, | |
| 619 animations.begin(), | |
| 620 animations.end(), | |
| 621 AffectsActiveOnlyAndIsWaitingForDeletion), | |
| 622 animations.end()); | |
| 623 } | |
| 624 | |
| 625 void LayerAnimationController::PushPropertiesToImplThread( | |
| 626 LayerAnimationController* controller_impl) { | |
| 627 for (size_t i = 0; i < animations_.size(); ++i) { | |
| 628 Animation* current_impl = | |
| 629 controller_impl->GetAnimationById(animations_[i]->id()); | |
| 630 if (current_impl) | |
| 631 animations_[i]->PushPropertiesTo(current_impl); | |
| 632 } | |
| 633 controller_impl->scroll_offset_animation_was_interrupted_ = | |
| 634 scroll_offset_animation_was_interrupted_; | |
| 635 scroll_offset_animation_was_interrupted_ = false; | |
| 636 } | |
| 637 | |
| 638 void LayerAnimationController::StartAnimations(base::TimeTicks monotonic_time) { | |
| 639 DCHECK(needs_to_start_animations_); | |
| 640 needs_to_start_animations_ = false; | |
| 641 // First collect running properties affecting each type of observer. | |
| 642 TargetProperties blocked_properties_for_active_observers; | |
| 643 TargetProperties blocked_properties_for_pending_observers; | |
| 644 std::vector<size_t> animations_waiting_for_target; | |
| 645 | |
| 646 animations_waiting_for_target.reserve(animations_.size()); | |
| 647 for (size_t i = 0; i < animations_.size(); ++i) { | |
| 648 if (animations_[i]->run_state() == Animation::STARTING || | |
| 649 animations_[i]->run_state() == Animation::RUNNING) { | |
| 650 if (animations_[i]->affects_active_observers()) { | |
| 651 blocked_properties_for_active_observers.insert( | |
| 652 animations_[i]->target_property()); | |
| 653 } | |
| 654 if (animations_[i]->affects_pending_observers()) { | |
| 655 blocked_properties_for_pending_observers.insert( | |
| 656 animations_[i]->target_property()); | |
| 657 } | |
| 658 } else if (animations_[i]->run_state() == | |
| 659 Animation::WAITING_FOR_TARGET_AVAILABILITY) { | |
| 660 animations_waiting_for_target.push_back(i); | |
| 661 } | |
| 662 } | |
| 663 | |
| 664 for (size_t i = 0; i < animations_waiting_for_target.size(); ++i) { | |
| 665 // Collect all properties for animations with the same group id (they | |
| 666 // should all also be in the list of animations). | |
| 667 size_t animation_index = animations_waiting_for_target[i]; | |
| 668 Animation* animation_waiting_for_target = animations_[animation_index]; | |
| 669 // Check for the run state again even though the animation was waiting | |
| 670 // for target because it might have changed the run state while handling | |
| 671 // previous animation in this loop (if they belong to same group). | |
| 672 if (animation_waiting_for_target->run_state() == | |
| 673 Animation::WAITING_FOR_TARGET_AVAILABILITY) { | |
| 674 TargetProperties enqueued_properties; | |
| 675 bool affects_active_observers = | |
| 676 animation_waiting_for_target->affects_active_observers(); | |
| 677 bool affects_pending_observers = | |
| 678 animation_waiting_for_target->affects_pending_observers(); | |
| 679 enqueued_properties.insert( | |
| 680 animation_waiting_for_target->target_property()); | |
| 681 for (size_t j = animation_index + 1; j < animations_.size(); ++j) { | |
| 682 if (animation_waiting_for_target->group() == animations_[j]->group()) { | |
| 683 enqueued_properties.insert(animations_[j]->target_property()); | |
| 684 affects_active_observers |= | |
| 685 animations_[j]->affects_active_observers(); | |
| 686 affects_pending_observers |= | |
| 687 animations_[j]->affects_pending_observers(); | |
| 688 } | |
| 689 } | |
| 690 | |
| 691 // Check to see if intersection of the list of properties affected by | |
| 692 // the group and the list of currently blocked properties is null, taking | |
| 693 // into account the type(s) of observers affected by the group. In any | |
| 694 // case, the group's target properties need to be added to the lists of | |
| 695 // blocked properties. | |
| 696 bool null_intersection = true; | |
| 697 for (TargetProperties::iterator p_iter = enqueued_properties.begin(); | |
| 698 p_iter != enqueued_properties.end(); | |
| 699 ++p_iter) { | |
| 700 if (affects_active_observers && | |
| 701 !blocked_properties_for_active_observers.insert(*p_iter).second) | |
| 702 null_intersection = false; | |
| 703 if (affects_pending_observers && | |
| 704 !blocked_properties_for_pending_observers.insert(*p_iter).second) | |
| 705 null_intersection = false; | |
| 706 } | |
| 707 | |
| 708 // If the intersection is null, then we are free to start the animations | |
| 709 // in the group. | |
| 710 if (null_intersection) { | |
| 711 animation_waiting_for_target->SetRunState(Animation::STARTING, | |
| 712 monotonic_time); | |
| 713 for (size_t j = animation_index + 1; j < animations_.size(); ++j) { | |
| 714 if (animation_waiting_for_target->group() == | |
| 715 animations_[j]->group()) { | |
| 716 animations_[j]->SetRunState(Animation::STARTING, monotonic_time); | |
| 717 } | |
| 718 } | |
| 719 } else { | |
| 720 needs_to_start_animations_ = true; | |
| 721 } | |
| 722 } | |
| 723 } | |
| 724 } | |
| 725 | |
| 726 void LayerAnimationController::PromoteStartedAnimations( | |
| 727 base::TimeTicks monotonic_time, | |
| 728 AnimationEventsVector* events) { | |
| 729 for (size_t i = 0; i < animations_.size(); ++i) { | |
| 730 if (animations_[i]->run_state() == Animation::STARTING && | |
| 731 animations_[i]->affects_active_observers()) { | |
| 732 animations_[i]->SetRunState(Animation::RUNNING, monotonic_time); | |
| 733 if (!animations_[i]->has_set_start_time() && | |
| 734 !animations_[i]->needs_synchronized_start_time()) | |
| 735 animations_[i]->set_start_time(monotonic_time); | |
| 736 if (events) { | |
| 737 AnimationEvent started_event( | |
| 738 AnimationEvent::STARTED, id_, animations_[i]->group(), | |
| 739 animations_[i]->target_property(), monotonic_time); | |
| 740 started_event.is_impl_only = animations_[i]->is_impl_only(); | |
| 741 if (started_event.is_impl_only) | |
| 742 NotifyAnimationStarted(started_event); | |
| 743 else | |
| 744 events->push_back(started_event); | |
| 745 } | |
| 746 } | |
| 747 } | |
| 748 } | |
| 749 | |
| 750 void LayerAnimationController::MarkFinishedAnimations( | |
| 751 base::TimeTicks monotonic_time) { | |
| 752 for (size_t i = 0; i < animations_.size(); ++i) { | |
| 753 if (animations_[i]->IsFinishedAt(monotonic_time) && | |
| 754 animations_[i]->run_state() != Animation::ABORTED && | |
| 755 animations_[i]->run_state() != Animation::WAITING_FOR_DELETION) | |
| 756 animations_[i]->SetRunState(Animation::FINISHED, monotonic_time); | |
| 757 } | |
| 758 } | |
| 759 | |
| 760 void LayerAnimationController::MarkAnimationsForDeletion( | |
| 761 base::TimeTicks monotonic_time, | |
| 762 AnimationEventsVector* events) { | |
| 763 bool marked_animations_for_deletions = false; | |
| 764 std::vector<size_t> animations_with_same_group_id; | |
| 765 | |
| 766 animations_with_same_group_id.reserve(animations_.size()); | |
| 767 // Non-aborted animations are marked for deletion after a corresponding | |
| 768 // AnimationEvent::FINISHED event is sent or received. This means that if | |
| 769 // we don't have an events vector, we must ensure that non-aborted animations | |
| 770 // have received a finished event before marking them for deletion. | |
| 771 for (size_t i = 0; i < animations_.size(); i++) { | |
| 772 int group_id = animations_[i]->group(); | |
| 773 if (animations_[i]->run_state() == Animation::ABORTED) { | |
| 774 if (events && !animations_[i]->is_impl_only()) { | |
| 775 AnimationEvent aborted_event(AnimationEvent::ABORTED, id_, group_id, | |
| 776 animations_[i]->target_property(), | |
| 777 monotonic_time); | |
| 778 events->push_back(aborted_event); | |
| 779 } | |
| 780 animations_[i]->SetRunState(Animation::WAITING_FOR_DELETION, | |
| 781 monotonic_time); | |
| 782 marked_animations_for_deletions = true; | |
| 783 continue; | |
| 784 } | |
| 785 | |
| 786 bool all_anims_with_same_id_are_finished = false; | |
| 787 | |
| 788 // Since deleting an animation on the main thread leads to its deletion | |
| 789 // on the impl thread, we only mark a FINISHED main thread animation for | |
| 790 // deletion once it has received a FINISHED event from the impl thread. | |
| 791 bool animation_i_will_send_or_has_received_finish_event = | |
| 792 events || animations_[i]->received_finished_event(); | |
| 793 // If an animation is finished, and not already marked for deletion, | |
| 794 // find out if all other animations in the same group are also finished. | |
| 795 if (animations_[i]->run_state() == Animation::FINISHED && | |
| 796 animation_i_will_send_or_has_received_finish_event) { | |
| 797 // Clear the animations_with_same_group_id if it was added for | |
| 798 // the previous animation's iteration. | |
| 799 if (animations_with_same_group_id.size() > 0) | |
| 800 animations_with_same_group_id.clear(); | |
| 801 all_anims_with_same_id_are_finished = true; | |
| 802 for (size_t j = 0; j < animations_.size(); ++j) { | |
| 803 bool animation_j_will_send_or_has_received_finish_event = | |
| 804 events || animations_[j]->received_finished_event(); | |
| 805 if (group_id == animations_[j]->group()) { | |
| 806 if (!animations_[j]->is_finished() || | |
| 807 (animations_[j]->run_state() == Animation::FINISHED && | |
| 808 !animation_j_will_send_or_has_received_finish_event)) { | |
| 809 all_anims_with_same_id_are_finished = false; | |
| 810 break; | |
| 811 } else if (j >= i && | |
| 812 animations_[j]->run_state() != Animation::ABORTED) { | |
| 813 // Mark down the animations which belong to the same group | |
| 814 // and is not yet aborted. If this current iteration finds that all | |
| 815 // animations with same ID are finished, then the marked | |
| 816 // animations below will be set to WAITING_FOR_DELETION in next | |
| 817 // iteration. | |
| 818 animations_with_same_group_id.push_back(j); | |
| 819 } | |
| 820 } | |
| 821 } | |
| 822 } | |
| 823 if (all_anims_with_same_id_are_finished) { | |
| 824 // We now need to remove all animations with the same group id as | |
| 825 // group_id (and send along animation finished notifications, if | |
| 826 // necessary). | |
| 827 for (size_t j = 0; j < animations_with_same_group_id.size(); j++) { | |
| 828 size_t animation_index = animations_with_same_group_id[j]; | |
| 829 if (events) { | |
| 830 AnimationEvent finished_event( | |
| 831 AnimationEvent::FINISHED, id_, | |
| 832 animations_[animation_index]->group(), | |
| 833 animations_[animation_index]->target_property(), | |
| 834 monotonic_time); | |
| 835 finished_event.is_impl_only = | |
| 836 animations_[animation_index]->is_impl_only(); | |
| 837 if (finished_event.is_impl_only) | |
| 838 NotifyAnimationFinished(finished_event); | |
| 839 else | |
| 840 events->push_back(finished_event); | |
| 841 } | |
| 842 animations_[animation_index]->SetRunState( | |
| 843 Animation::WAITING_FOR_DELETION, monotonic_time); | |
| 844 } | |
| 845 marked_animations_for_deletions = true; | |
| 846 } | |
| 847 } | |
| 848 if (marked_animations_for_deletions) | |
| 849 NotifyObserversAnimationWaitingForDeletion(); | |
| 850 } | |
| 851 | |
| 852 static bool IsWaitingForDeletion(Animation* animation) { | |
| 853 return animation->run_state() == Animation::WAITING_FOR_DELETION; | |
| 854 } | |
| 855 | |
| 856 void LayerAnimationController::PurgeAnimationsMarkedForDeletion() { | |
| 857 animations_.erase(cc::remove_if(&animations_, | |
| 858 animations_.begin(), | |
| 859 animations_.end(), | |
| 860 IsWaitingForDeletion), | |
| 861 animations_.end()); | |
| 862 } | |
| 863 | |
| 864 void LayerAnimationController::TickAnimations(base::TimeTicks monotonic_time) { | |
| 865 for (size_t i = 0; i < animations_.size(); ++i) { | |
| 866 if (animations_[i]->run_state() == Animation::STARTING || | |
| 867 animations_[i]->run_state() == Animation::RUNNING || | |
| 868 animations_[i]->run_state() == Animation::PAUSED) { | |
| 869 if (!animations_[i]->InEffect(monotonic_time)) | |
| 870 continue; | |
| 871 | |
| 872 base::TimeDelta trimmed = | |
| 873 animations_[i]->TrimTimeToCurrentIteration(monotonic_time); | |
| 874 | |
| 875 switch (animations_[i]->target_property()) { | |
| 876 case Animation::TRANSFORM: { | |
| 877 const TransformAnimationCurve* transform_animation_curve = | |
| 878 animations_[i]->curve()->ToTransformAnimationCurve(); | |
| 879 const gfx::Transform transform = | |
| 880 transform_animation_curve->GetValue(trimmed); | |
| 881 NotifyObserversTransformAnimated( | |
| 882 transform, | |
| 883 animations_[i]->affects_active_observers(), | |
| 884 animations_[i]->affects_pending_observers()); | |
| 885 break; | |
| 886 } | |
| 887 | |
| 888 case Animation::OPACITY: { | |
| 889 const FloatAnimationCurve* float_animation_curve = | |
| 890 animations_[i]->curve()->ToFloatAnimationCurve(); | |
| 891 const float opacity = std::max( | |
| 892 std::min(float_animation_curve->GetValue(trimmed), 1.0f), 0.f); | |
| 893 NotifyObserversOpacityAnimated( | |
| 894 opacity, | |
| 895 animations_[i]->affects_active_observers(), | |
| 896 animations_[i]->affects_pending_observers()); | |
| 897 break; | |
| 898 } | |
| 899 | |
| 900 case Animation::FILTER: { | |
| 901 const FilterAnimationCurve* filter_animation_curve = | |
| 902 animations_[i]->curve()->ToFilterAnimationCurve(); | |
| 903 const FilterOperations filter = | |
| 904 filter_animation_curve->GetValue(trimmed); | |
| 905 NotifyObserversFilterAnimated( | |
| 906 filter, | |
| 907 animations_[i]->affects_active_observers(), | |
| 908 animations_[i]->affects_pending_observers()); | |
| 909 break; | |
| 910 } | |
| 911 | |
| 912 case Animation::BACKGROUND_COLOR: { | |
| 913 // Not yet implemented. | |
| 914 break; | |
| 915 } | |
| 916 | |
| 917 case Animation::SCROLL_OFFSET: { | |
| 918 const ScrollOffsetAnimationCurve* scroll_offset_animation_curve = | |
| 919 animations_[i]->curve()->ToScrollOffsetAnimationCurve(); | |
| 920 const gfx::ScrollOffset scroll_offset = | |
| 921 scroll_offset_animation_curve->GetValue(trimmed); | |
| 922 NotifyObserversScrollOffsetAnimated( | |
| 923 scroll_offset, | |
| 924 animations_[i]->affects_active_observers(), | |
| 925 animations_[i]->affects_pending_observers()); | |
| 926 break; | |
| 927 } | |
| 928 } | |
| 929 } | |
| 930 } | |
| 931 } | |
| 932 | |
| 933 void LayerAnimationController::UpdateActivation(UpdateActivationType type) { | |
| 934 bool force = type == FORCE_ACTIVATION; | |
| 935 if (registrar_) { | |
| 936 bool was_active = is_active_; | |
| 937 is_active_ = false; | |
| 938 for (size_t i = 0; i < animations_.size(); ++i) { | |
| 939 if (animations_[i]->run_state() != Animation::WAITING_FOR_DELETION) { | |
| 940 is_active_ = true; | |
| 941 break; | |
| 942 } | |
| 943 } | |
| 944 | |
| 945 if (is_active_ && (!was_active || force)) | |
| 946 registrar_->DidActivateAnimationController(this); | |
| 947 else if (!is_active_ && (was_active || force)) | |
| 948 registrar_->DidDeactivateAnimationController(this); | |
| 949 } | |
| 950 } | |
| 951 | |
| 952 void LayerAnimationController::NotifyObserversOpacityAnimated( | |
| 953 float opacity, | |
| 954 bool notify_active_observers, | |
| 955 bool notify_pending_observers) { | |
| 956 if (value_observers_.might_have_observers()) { | |
| 957 ObserverListBase<LayerAnimationValueObserver>::Iterator it( | |
| 958 &value_observers_); | |
| 959 LayerAnimationValueObserver* obs; | |
| 960 while ((obs = it.GetNext()) != nullptr) { | |
| 961 if ((notify_active_observers && notify_pending_observers) || | |
| 962 (notify_active_observers && obs->IsActive()) || | |
| 963 (notify_pending_observers && !obs->IsActive())) | |
| 964 obs->OnOpacityAnimated(opacity); | |
| 965 } | |
| 966 } | |
| 967 } | |
| 968 | |
| 969 void LayerAnimationController::NotifyObserversTransformAnimated( | |
| 970 const gfx::Transform& transform, | |
| 971 bool notify_active_observers, | |
| 972 bool notify_pending_observers) { | |
| 973 if (value_observers_.might_have_observers()) { | |
| 974 ObserverListBase<LayerAnimationValueObserver>::Iterator it( | |
| 975 &value_observers_); | |
| 976 LayerAnimationValueObserver* obs; | |
| 977 while ((obs = it.GetNext()) != nullptr) { | |
| 978 if ((notify_active_observers && notify_pending_observers) || | |
| 979 (notify_active_observers && obs->IsActive()) || | |
| 980 (notify_pending_observers && !obs->IsActive())) | |
| 981 obs->OnTransformAnimated(transform); | |
| 982 } | |
| 983 } | |
| 984 } | |
| 985 | |
| 986 void LayerAnimationController::NotifyObserversFilterAnimated( | |
| 987 const FilterOperations& filters, | |
| 988 bool notify_active_observers, | |
| 989 bool notify_pending_observers) { | |
| 990 if (value_observers_.might_have_observers()) { | |
| 991 ObserverListBase<LayerAnimationValueObserver>::Iterator it( | |
| 992 &value_observers_); | |
| 993 LayerAnimationValueObserver* obs; | |
| 994 while ((obs = it.GetNext()) != nullptr) { | |
| 995 if ((notify_active_observers && notify_pending_observers) || | |
| 996 (notify_active_observers && obs->IsActive()) || | |
| 997 (notify_pending_observers && !obs->IsActive())) | |
| 998 obs->OnFilterAnimated(filters); | |
| 999 } | |
| 1000 } | |
| 1001 } | |
| 1002 | |
| 1003 void LayerAnimationController::NotifyObserversScrollOffsetAnimated( | |
| 1004 const gfx::ScrollOffset& scroll_offset, | |
| 1005 bool notify_active_observers, | |
| 1006 bool notify_pending_observers) { | |
| 1007 if (value_observers_.might_have_observers()) { | |
| 1008 ObserverListBase<LayerAnimationValueObserver>::Iterator it( | |
| 1009 &value_observers_); | |
| 1010 LayerAnimationValueObserver* obs; | |
| 1011 while ((obs = it.GetNext()) != nullptr) { | |
| 1012 if ((notify_active_observers && notify_pending_observers) || | |
| 1013 (notify_active_observers && obs->IsActive()) || | |
| 1014 (notify_pending_observers && !obs->IsActive())) | |
| 1015 obs->OnScrollOffsetAnimated(scroll_offset); | |
| 1016 } | |
| 1017 } | |
| 1018 } | |
| 1019 | |
| 1020 void LayerAnimationController::NotifyObserversAnimationWaitingForDeletion() { | |
| 1021 FOR_EACH_OBSERVER(LayerAnimationValueObserver, | |
| 1022 value_observers_, | |
| 1023 OnAnimationWaitingForDeletion()); | |
| 1024 } | |
| 1025 | |
| 1026 bool LayerAnimationController::HasValueObserver() { | |
| 1027 if (value_observers_.might_have_observers()) { | |
| 1028 ObserverListBase<LayerAnimationValueObserver>::Iterator it( | |
| 1029 &value_observers_); | |
| 1030 return it.GetNext() != nullptr; | |
| 1031 } | |
| 1032 return false; | |
| 1033 } | |
| 1034 | |
| 1035 bool LayerAnimationController::HasActiveValueObserver() { | |
| 1036 if (value_observers_.might_have_observers()) { | |
| 1037 ObserverListBase<LayerAnimationValueObserver>::Iterator it( | |
| 1038 &value_observers_); | |
| 1039 LayerAnimationValueObserver* obs; | |
| 1040 while ((obs = it.GetNext()) != nullptr) | |
| 1041 if (obs->IsActive()) | |
| 1042 return true; | |
| 1043 } | |
| 1044 return false; | |
| 1045 } | |
| 1046 | |
| 1047 } // namespace cc | |
| OLD | NEW |