Upstream version 11.39.250.0
[platform/framework/web/crosswalk.git] / src / cc / animation / layer_animation_controller.cc
index acc16d3..73e3d5a 100644 (file)
@@ -5,12 +5,15 @@
 #include "cc/animation/layer_animation_controller.h"
 
 #include <algorithm>
+#include <vector>
 
 #include "cc/animation/animation.h"
 #include "cc/animation/animation_delegate.h"
 #include "cc/animation/animation_registrar.h"
 #include "cc/animation/keyframed_animation_curve.h"
 #include "cc/animation/layer_animation_value_observer.h"
+#include "cc/animation/layer_animation_value_provider.h"
+#include "cc/animation/scroll_offset_animation_curve.h"
 #include "cc/base/scoped_ptr_algorithm.h"
 #include "cc/output/filter_operations.h"
 #include "ui/gfx/box_f.h"
 namespace cc {
 
 LayerAnimationController::LayerAnimationController(int id)
-    : force_sync_(false),
-      registrar_(0),
+    : registrar_(0),
       id_(id),
       is_active_(false),
-      last_tick_time_(0),
-      layer_animation_delegate_(NULL) {}
+      value_provider_(NULL),
+      layer_animation_delegate_(NULL),
+      needs_to_start_animations_(false) {
+}
 
 LayerAnimationController::~LayerAnimationController() {
   if (registrar_)
@@ -37,11 +41,11 @@ scoped_refptr<LayerAnimationController> LayerAnimationController::Create(
 }
 
 void LayerAnimationController::PauseAnimation(int animation_id,
-                                              double time_offset) {
-  for (size_t i = 0; i < active_animations_.size(); ++i) {
-    if (active_animations_[i]->id() == animation_id) {
-      active_animations_[i]->SetRunState(
-          Animation::Paused, time_offset + active_animations_[i]->start_time());
+                                              base::TimeDelta time_offset) {
+  for (size_t i = 0; i < animations_.size(); ++i) {
+    if (animations_[i]->id() == animation_id) {
+      animations_[i]->SetRunState(Animation::Paused,
+                                  time_offset + animations_[i]->start_time());
     }
   }
 }
@@ -57,12 +61,11 @@ struct HasAnimationId {
 };
 
 void LayerAnimationController::RemoveAnimation(int animation_id) {
-  ScopedPtrVector<Animation>& animations = active_animations_;
-  animations.erase(cc::remove_if(&animations,
-                                 animations.begin(),
-                                 animations.end(),
-                                 HasAnimationId(animation_id)),
-                   animations.end());
+  animations_.erase(cc::remove_if(&animations_,
+                                  animations_.begin(),
+                                  animations_.end(),
+                                  HasAnimationId(animation_id)),
+                    animations_.end());
   UpdateActivation(NormalActivation);
 }
 
@@ -82,62 +85,70 @@ struct HasAnimationIdAndProperty {
 void LayerAnimationController::RemoveAnimation(
     int animation_id,
     Animation::TargetProperty target_property) {
-  ScopedPtrVector<Animation>& animations = active_animations_;
-  animations.erase(cc::remove_if(&animations,
-                                 animations.begin(),
-                                 animations.end(),
-                                 HasAnimationIdAndProperty(animation_id,
-                                                           target_property)),
-                   animations.end());
+  animations_.erase(
+      cc::remove_if(&animations_,
+                    animations_.begin(),
+                    animations_.end(),
+                    HasAnimationIdAndProperty(animation_id, target_property)),
+      animations_.end());
   UpdateActivation(NormalActivation);
 }
 
+void LayerAnimationController::AbortAnimations(
+    Animation::TargetProperty target_property) {
+  for (size_t i = 0; i < animations_.size(); ++i) {
+    if (animations_[i]->target_property() == target_property &&
+        !animations_[i]->is_finished())
+      animations_[i]->SetRunState(Animation::Aborted, last_tick_time_);
+  }
+}
+
 // Ensures that the list of active animations on the main thread and the impl
 // thread are kept in sync.
 void LayerAnimationController::PushAnimationUpdatesTo(
     LayerAnimationController* controller_impl) {
   DCHECK(this != controller_impl);
-  if (force_sync_) {
-    ReplaceImplThreadAnimations(controller_impl);
-    force_sync_ = false;
-  } else {
-    PurgeAnimationsMarkedForDeletion();
-    PushNewAnimationsToImplThread(controller_impl);
+  if (!has_any_animation() && !controller_impl->has_any_animation())
+    return;
+  PurgeAnimationsMarkedForDeletion();
+  PushNewAnimationsToImplThread(controller_impl);
 
-    // Remove finished impl side animations only after pushing,
-    // and only after the animations are deleted on the main thread
-    // this insures we will never push an animation twice.
-    RemoveAnimationsCompletedOnMainThread(controller_impl);
+  // Remove finished impl side animations only after pushing,
+  // and only after the animations are deleted on the main thread
+  // this insures we will never push an animation twice.
+  RemoveAnimationsCompletedOnMainThread(controller_impl);
 
-    PushPropertiesToImplThread(controller_impl);
-  }
+  PushPropertiesToImplThread(controller_impl);
   controller_impl->UpdateActivation(NormalActivation);
   UpdateActivation(NormalActivation);
 }
 
-void LayerAnimationController::Animate(double monotonic_time) {
+void LayerAnimationController::Animate(base::TimeTicks monotonic_time) {
+  DCHECK(!monotonic_time.is_null());
   if (!HasValueObserver())
     return;
 
-  StartAnimationsWaitingForNextTick(monotonic_time);
-  StartAnimationsWaitingForStartTime(monotonic_time);
-  StartAnimationsWaitingForTargetAvailability(monotonic_time);
-  ResolveConflicts(monotonic_time);
+  if (needs_to_start_animations_)
+    StartAnimations(monotonic_time);
   TickAnimations(monotonic_time);
   last_tick_time_ = monotonic_time;
 }
 
 void LayerAnimationController::AccumulatePropertyUpdates(
-    double monotonic_time,
+    base::TimeTicks monotonic_time,
     AnimationEventsVector* events) {
   if (!events)
     return;
 
-  for (size_t i = 0; i < active_animations_.size(); ++i) {
-    Animation* animation = active_animations_[i];
+  for (size_t i = 0; i < animations_.size(); ++i) {
+    Animation* animation = animations_[i];
     if (!animation->is_impl_only())
       continue;
 
+    if (!animation->InEffect(monotonic_time))
+      continue;
+
+    double trimmed = animation->TrimTimeToCurrentIteration(monotonic_time);
     switch (animation->target_property()) {
       case Animation::Opacity: {
         AnimationEvent event(AnimationEvent::PropertyUpdate,
@@ -145,8 +156,9 @@ void LayerAnimationController::AccumulatePropertyUpdates(
                              animation->group(),
                              Animation::Opacity,
                              monotonic_time);
-        event.opacity = animation->curve()->ToFloatAnimationCurve()->GetValue(
-            monotonic_time);
+        const FloatAnimationCurve* float_animation_curve =
+            animation->curve()->ToFloatAnimationCurve();
+        event.opacity = float_animation_curve->GetValue(trimmed);
         event.is_impl_only = true;
         events->push_back(event);
         break;
@@ -158,9 +170,9 @@ void LayerAnimationController::AccumulatePropertyUpdates(
                              animation->group(),
                              Animation::Transform,
                              monotonic_time);
-        event.transform =
-            animation->curve()->ToTransformAnimationCurve()->GetValue(
-                monotonic_time);
+        const TransformAnimationCurve* transform_animation_curve =
+            animation->curve()->ToTransformAnimationCurve();
+        event.transform = transform_animation_curve->GetValue(trimmed);
         event.is_impl_only = true;
         events->push_back(event);
         break;
@@ -172,8 +184,9 @@ void LayerAnimationController::AccumulatePropertyUpdates(
                              animation->group(),
                              Animation::Filter,
                              monotonic_time);
-        event.filters = animation->curve()->ToFilterAnimationCurve()->GetValue(
-            monotonic_time);
+        const FilterAnimationCurve* filter_animation_curve =
+            animation->curve()->ToFilterAnimationCurve();
+        event.filters = filter_animation_curve->GetValue(trimmed);
         event.is_impl_only = true;
         events->push_back(event);
         break;
@@ -181,6 +194,13 @@ void LayerAnimationController::AccumulatePropertyUpdates(
 
       case Animation::BackgroundColor: { break; }
 
+      case Animation::ScrollOffset: {
+        // Impl-side changes to scroll offset are already sent back to the
+        // main thread (e.g. for user-driven scrolling), so a PropertyUpdate
+        // isn't needed.
+        break;
+      }
+
       case Animation::TargetPropertyEnumSize:
         NOTREACHED();
     }
@@ -192,14 +212,15 @@ void LayerAnimationController::UpdateState(bool start_ready_animations,
   if (!HasActiveValueObserver())
     return;
 
+  DCHECK(last_tick_time_ != base::TimeTicks());
   if (start_ready_animations)
     PromoteStartedAnimations(last_tick_time_, events);
 
   MarkFinishedAnimations(last_tick_time_);
   MarkAnimationsForDeletion(last_tick_time_, events);
 
-  if (start_ready_animations) {
-    StartAnimationsWaitingForTargetAvailability(last_tick_time_);
+  if (needs_to_start_animations_ && start_ready_animations) {
+    StartAnimations(last_tick_time_);
     PromoteStartedAnimations(last_tick_time_, events);
   }
 
@@ -208,34 +229,55 @@ void LayerAnimationController::UpdateState(bool start_ready_animations,
   UpdateActivation(NormalActivation);
 }
 
+struct AffectsNoObservers {
+  bool operator()(Animation* animation) const {
+    return !animation->affects_active_observers() &&
+           !animation->affects_pending_observers();
+  }
+};
+
+void LayerAnimationController::ActivateAnimations() {
+  for (size_t i = 0; i < animations_.size(); ++i) {
+    animations_[i]->set_affects_active_observers(
+        animations_[i]->affects_pending_observers());
+  }
+  animations_.erase(cc::remove_if(&animations_,
+                                  animations_.begin(),
+                                  animations_.end(),
+                                  AffectsNoObservers()),
+                    animations_.end());
+  UpdateActivation(NormalActivation);
+}
+
 void LayerAnimationController::AddAnimation(scoped_ptr<Animation> animation) {
-  active_animations_.push_back(animation.Pass());
+  animations_.push_back(animation.Pass());
+  needs_to_start_animations_ = true;
   UpdateActivation(NormalActivation);
 }
 
 Animation* LayerAnimationController::GetAnimation(
     int group_id,
     Animation::TargetProperty target_property) const {
-  for (size_t i = 0; i < active_animations_.size(); ++i)
-    if (active_animations_[i]->group() == group_id &&
-        active_animations_[i]->target_property() == target_property)
-      return active_animations_[i];
+  for (size_t i = 0; i < animations_.size(); ++i)
+    if (animations_[i]->group() == group_id &&
+        animations_[i]->target_property() == target_property)
+      return animations_[i];
   return 0;
 }
 
 Animation* LayerAnimationController::GetAnimation(
     Animation::TargetProperty target_property) const {
-  for (size_t i = 0; i < active_animations_.size(); ++i) {
-    size_t index = active_animations_.size() - i - 1;
-    if (active_animations_[index]->target_property() == target_property)
-      return active_animations_[index];
+  for (size_t i = 0; i < animations_.size(); ++i) {
+    size_t index = animations_.size() - i - 1;
+    if (animations_[index]->target_property() == target_property)
+      return animations_[index];
   }
   return 0;
 }
 
 bool LayerAnimationController::HasActiveAnimation() const {
-  for (size_t i = 0; i < active_animations_.size(); ++i) {
-    if (!active_animations_[i]->is_finished())
+  for (size_t i = 0; i < animations_.size(); ++i) {
+    if (!animations_[i]->is_finished())
       return true;
   }
   return false;
@@ -243,9 +285,10 @@ bool LayerAnimationController::HasActiveAnimation() const {
 
 bool LayerAnimationController::IsAnimatingProperty(
     Animation::TargetProperty target_property) const {
-  for (size_t i = 0; i < active_animations_.size(); ++i) {
-    if (!active_animations_[i]->is_finished() &&
-        active_animations_[i]->target_property() == target_property)
+  for (size_t i = 0; i < animations_.size(); ++i) {
+    if (!animations_[i]->is_finished() &&
+        animations_[i]->InEffect(last_tick_time_) &&
+        animations_[i]->target_property() == target_property)
       return true;
   }
   return false;
@@ -267,28 +310,29 @@ void LayerAnimationController::SetAnimationRegistrar(
 }
 
 void LayerAnimationController::NotifyAnimationStarted(
-    const AnimationEvent& event,
-    double wall_clock_time) {
+    const AnimationEvent& event) {
   if (event.is_impl_only) {
     FOR_EACH_OBSERVER(LayerAnimationEventObserver, event_observers_,
                       OnAnimationStarted(event));
     if (layer_animation_delegate_)
-      layer_animation_delegate_->NotifyAnimationStarted(wall_clock_time);
-
+      layer_animation_delegate_->NotifyAnimationStarted(event.monotonic_time,
+                                                        event.target_property);
     return;
   }
 
-  for (size_t i = 0; i < active_animations_.size(); ++i) {
-    if (active_animations_[i]->group() == event.group_id &&
-        active_animations_[i]->target_property() == event.target_property &&
-        active_animations_[i]->needs_synchronized_start_time()) {
-      active_animations_[i]->set_needs_synchronized_start_time(false);
-      active_animations_[i]->set_start_time(event.monotonic_time);
+  for (size_t i = 0; i < animations_.size(); ++i) {
+    if (animations_[i]->group() == event.group_id &&
+        animations_[i]->target_property() == event.target_property &&
+        animations_[i]->needs_synchronized_start_time()) {
+      animations_[i]->set_needs_synchronized_start_time(false);
+      if (!animations_[i]->has_set_start_time())
+        animations_[i]->set_start_time(event.monotonic_time);
 
       FOR_EACH_OBSERVER(LayerAnimationEventObserver, event_observers_,
                         OnAnimationStarted(event));
       if (layer_animation_delegate_)
-        layer_animation_delegate_->NotifyAnimationStarted(wall_clock_time);
+        layer_animation_delegate_->NotifyAnimationStarted(
+            event.monotonic_time, event.target_property);
 
       return;
     }
@@ -296,34 +340,49 @@ void LayerAnimationController::NotifyAnimationStarted(
 }
 
 void LayerAnimationController::NotifyAnimationFinished(
-    const AnimationEvent& event,
-    double wall_clock_time) {
+    const AnimationEvent& event) {
   if (event.is_impl_only) {
     if (layer_animation_delegate_)
-      layer_animation_delegate_->NotifyAnimationFinished(wall_clock_time);
+      layer_animation_delegate_->NotifyAnimationFinished(event.monotonic_time,
+                                                         event.target_property);
     return;
   }
 
-  for (size_t i = 0; i < active_animations_.size(); ++i) {
-    if (active_animations_[i]->group() == event.group_id &&
-        active_animations_[i]->target_property() == event.target_property) {
-      active_animations_[i]->set_received_finished_event(true);
+  for (size_t i = 0; i < animations_.size(); ++i) {
+    if (animations_[i]->group() == event.group_id &&
+        animations_[i]->target_property() == event.target_property) {
+      animations_[i]->set_received_finished_event(true);
       if (layer_animation_delegate_)
-        layer_animation_delegate_->NotifyAnimationFinished(wall_clock_time);
+        layer_animation_delegate_->NotifyAnimationFinished(
+            event.monotonic_time, event.target_property);
 
       return;
     }
   }
 }
 
+void LayerAnimationController::NotifyAnimationAborted(
+    const AnimationEvent& event) {
+  for (size_t i = 0; i < animations_.size(); ++i) {
+    if (animations_[i]->group() == event.group_id &&
+        animations_[i]->target_property() == event.target_property) {
+      animations_[i]->SetRunState(Animation::Aborted, event.monotonic_time);
+    }
+  }
+}
+
 void LayerAnimationController::NotifyAnimationPropertyUpdate(
     const AnimationEvent& event) {
+  bool notify_active_observers = true;
+  bool notify_pending_observers = true;
   switch (event.target_property) {
     case Animation::Opacity:
-      NotifyObserversOpacityAnimated(event.opacity);
+      NotifyObserversOpacityAnimated(
+          event.opacity, notify_active_observers, notify_pending_observers);
       break;
     case Animation::Transform:
-      NotifyObserversTransformAnimated(event.transform);
+      NotifyObserversTransformAnimated(
+          event.transform, notify_active_observers, notify_pending_observers);
       break;
     default:
       NOTREACHED();
@@ -352,20 +411,50 @@ void LayerAnimationController::RemoveEventObserver(
   event_observers_.RemoveObserver(observer);
 }
 
-bool LayerAnimationController::AnimatedBoundsForBox(const gfx::BoxF& box,
-                                                    gfx::BoxF* bounds) {
+bool LayerAnimationController::HasFilterAnimationThatInflatesBounds() const {
+  for (size_t i = 0; i < animations_.size(); ++i) {
+    if (!animations_[i]->is_finished() &&
+        animations_[i]->target_property() == Animation::Filter &&
+        animations_[i]
+            ->curve()
+            ->ToFilterAnimationCurve()
+            ->HasFilterThatMovesPixels())
+      return true;
+  }
+
+  return false;
+}
+
+bool LayerAnimationController::HasTransformAnimationThatInflatesBounds() const {
+  return IsAnimatingProperty(Animation::Transform);
+}
+
+bool LayerAnimationController::FilterAnimationBoundsForBox(
+    const gfx::BoxF& box, gfx::BoxF* bounds) const {
+  // TODO(avallee): Implement.
+  return false;
+}
+
+bool LayerAnimationController::TransformAnimationBoundsForBox(
+    const gfx::BoxF& box,
+    gfx::BoxF* bounds) const {
+  DCHECK(HasTransformAnimationThatInflatesBounds())
+      << "TransformAnimationBoundsForBox will give incorrect results if there "
+      << "are no transform animations affecting bounds, non-animated transform "
+      << "is not known";
+
   // Compute bounds based on animations for which is_finished() is false.
   // Do nothing if there are no such animations; in this case, it is assumed
   // that callers will take care of computing bounds based on the owning layer's
   // actual transform.
   *bounds = gfx::BoxF();
-  for (size_t i = 0; i < active_animations_.size(); ++i) {
-    if (active_animations_[i]->is_finished() ||
-        active_animations_[i]->target_property() != Animation::Transform)
+  for (size_t i = 0; i < animations_.size(); ++i) {
+    if (animations_[i]->is_finished() ||
+        animations_[i]->target_property() != Animation::Transform)
       continue;
 
     const TransformAnimationCurve* transform_animation_curve =
-        active_animations_[i]->curve()->ToTransformAnimationCurve();
+        animations_[i]->curve()->ToTransformAnimationCurve();
     gfx::BoxF animation_bounds;
     bool success =
         transform_animation_curve->AnimatedBoundsForBox(box, &animation_bounds);
@@ -377,15 +466,76 @@ bool LayerAnimationController::AnimatedBoundsForBox(const gfx::BoxF& box,
   return true;
 }
 
+bool LayerAnimationController::HasAnimationThatAffectsScale() const {
+  for (size_t i = 0; i < animations_.size(); ++i) {
+    if (animations_[i]->is_finished() ||
+        animations_[i]->target_property() != Animation::Transform)
+      continue;
+
+    const TransformAnimationCurve* transform_animation_curve =
+        animations_[i]->curve()->ToTransformAnimationCurve();
+    if (transform_animation_curve->AffectsScale())
+      return true;
+  }
+
+  return false;
+}
+
+bool LayerAnimationController::HasOnlyTranslationTransforms() const {
+  for (size_t i = 0; i < animations_.size(); ++i) {
+    if (animations_[i]->is_finished() ||
+        animations_[i]->target_property() != Animation::Transform)
+      continue;
+
+    const TransformAnimationCurve* transform_animation_curve =
+        animations_[i]->curve()->ToTransformAnimationCurve();
+    if (!transform_animation_curve->IsTranslation())
+      return false;
+  }
+
+  return true;
+}
+
+bool LayerAnimationController::MaximumTargetScale(float* max_scale) const {
+  *max_scale = 0.f;
+  for (size_t i = 0; i < animations_.size(); ++i) {
+    if (animations_[i]->is_finished() ||
+        animations_[i]->target_property() != Animation::Transform)
+      continue;
+
+    bool forward_direction = true;
+    switch (animations_[i]->direction()) {
+      case Animation::Normal:
+      case Animation::Alternate:
+        forward_direction = animations_[i]->playback_rate() >= 0.0;
+        break;
+      case Animation::Reverse:
+      case Animation::AlternateReverse:
+        forward_direction = animations_[i]->playback_rate() < 0.0;
+        break;
+    }
+
+    const TransformAnimationCurve* transform_animation_curve =
+        animations_[i]->curve()->ToTransformAnimationCurve();
+    float animation_scale = 0.f;
+    if (!transform_animation_curve->MaximumTargetScale(forward_direction,
+                                                       &animation_scale))
+      return false;
+    *max_scale = std::max(*max_scale, animation_scale);
+  }
+
+  return true;
+}
+
 void LayerAnimationController::PushNewAnimationsToImplThread(
     LayerAnimationController* controller_impl) const {
   // Any new animations owned by the main thread's controller are cloned and
   // add to the impl thread's controller.
-  for (size_t i = 0; i < active_animations_.size(); ++i) {
+  for (size_t i = 0; i < animations_.size(); ++i) {
     // If the animation is already running on the impl thread, there is no
     // need to copy it over.
-    if (controller_impl->GetAnimation(active_animations_[i]->group(),
-                                      active_animations_[i]->target_property()))
+    if (controller_impl->GetAnimation(animations_[i]->group(),
+                                      animations_[i]->target_property()))
       continue;
 
     // If the animation is not running on the impl thread, it does not
@@ -394,220 +544,265 @@ void LayerAnimationController::PushNewAnimationsToImplThread(
     // have already notified that it has started and the main thread animation
     // will no longer need
     // a synchronized start time.
-    if (!active_animations_[i]->needs_synchronized_start_time())
+    if (!animations_[i]->needs_synchronized_start_time())
       continue;
 
+    // Scroll animations always start at the current scroll offset.
+    if (animations_[i]->target_property() == Animation::ScrollOffset) {
+      gfx::Vector2dF current_scroll_offset;
+      if (controller_impl->value_provider_) {
+        current_scroll_offset =
+            controller_impl->value_provider_->ScrollOffsetForAnimation();
+      } else {
+        // The owning layer isn't yet in the active tree, so the main thread
+        // scroll offset will be up-to-date.
+        current_scroll_offset = value_provider_->ScrollOffsetForAnimation();
+      }
+      animations_[i]->curve()->ToScrollOffsetAnimationCurve()->SetInitialValue(
+          current_scroll_offset);
+    }
+
     // The new animation should be set to run as soon as possible.
     Animation::RunState initial_run_state =
         Animation::WaitingForTargetAvailability;
-    double start_time = 0;
-    scoped_ptr<Animation> to_add(active_animations_[i]->CloneAndInitialize(
-        initial_run_state, start_time));
+    scoped_ptr<Animation> to_add(
+        animations_[i]->CloneAndInitialize(initial_run_state));
     DCHECK(!to_add->needs_synchronized_start_time());
+    to_add->set_affects_active_observers(false);
     controller_impl->AddAnimation(to_add.Pass());
   }
 }
 
-struct IsCompleted {
-  explicit IsCompleted(const LayerAnimationController& main_thread_controller)
-      : main_thread_controller_(main_thread_controller) {}
-  bool operator()(Animation* animation) const {
-    if (animation->is_impl_only()) {
-      return (animation->run_state() == Animation::WaitingForDeletion);
-    } else {
-      return !main_thread_controller_.GetAnimation(
-          animation->group(),
-          animation->target_property());
-    }
+static bool IsCompleted(
+    Animation* animation,
+    const LayerAnimationController* main_thread_controller) {
+  if (animation->is_impl_only()) {
+    return (animation->run_state() == Animation::WaitingForDeletion);
+  } else {
+    return !main_thread_controller->GetAnimation(animation->group(),
+                                                 animation->target_property());
   }
+}
 
- private:
-  const LayerAnimationController& main_thread_controller_;
-};
+static bool AffectsActiveOnlyAndIsWaitingForDeletion(Animation* animation) {
+  return animation->run_state() == Animation::WaitingForDeletion &&
+         !animation->affects_pending_observers();
+}
 
 void LayerAnimationController::RemoveAnimationsCompletedOnMainThread(
     LayerAnimationController* controller_impl) const {
-  // Delete all impl thread animations for which there is no corresponding
-  // main thread animation. Each iteration,
-  // controller->active_animations_.size() is decremented or i is incremented
-  // guaranteeing progress towards loop termination.
-  ScopedPtrVector<Animation>& animations =
-      controller_impl->active_animations_;
+  // Animations removed on the main thread should no longer affect pending
+  // observers, and should stop affecting active observers after the next call
+  // to ActivateAnimations. If already WaitingForDeletion, they can be removed
+  // immediately.
+  ScopedPtrVector<Animation>& animations = controller_impl->animations_;
+  for (size_t i = 0; i < animations.size(); ++i) {
+    if (IsCompleted(animations[i], this))
+      animations[i]->set_affects_pending_observers(false);
+  }
   animations.erase(cc::remove_if(&animations,
                                  animations.begin(),
                                  animations.end(),
-                                 IsCompleted(*this)),
+                                 AffectsActiveOnlyAndIsWaitingForDeletion),
                    animations.end());
 }
 
 void LayerAnimationController::PushPropertiesToImplThread(
     LayerAnimationController* controller_impl) const {
-  for (size_t i = 0; i < active_animations_.size(); ++i) {
-    Animation* current_impl =
-        controller_impl->GetAnimation(
-            active_animations_[i]->group(),
-            active_animations_[i]->target_property());
+  for (size_t i = 0; i < animations_.size(); ++i) {
+    Animation* current_impl = controller_impl->GetAnimation(
+        animations_[i]->group(), animations_[i]->target_property());
     if (current_impl)
-      active_animations_[i]->PushPropertiesTo(current_impl);
-  }
-}
-
-void LayerAnimationController::StartAnimationsWaitingForNextTick(
-    double monotonic_time) {
-  for (size_t i = 0; i < active_animations_.size(); ++i) {
-    if (active_animations_[i]->run_state() == Animation::WaitingForNextTick)
-      active_animations_[i]->SetRunState(Animation::Starting, monotonic_time);
+      animations_[i]->PushPropertiesTo(current_impl);
   }
 }
 
-void LayerAnimationController::StartAnimationsWaitingForStartTime(
-    double monotonic_time) {
-  for (size_t i = 0; i < active_animations_.size(); ++i) {
-    if (active_animations_[i]->run_state() == Animation::WaitingForStartTime &&
-        active_animations_[i]->start_time() <= monotonic_time)
-      active_animations_[i]->SetRunState(Animation::Starting, monotonic_time);
-  }
-}
-
-void LayerAnimationController::StartAnimationsWaitingForTargetAvailability(
-    double monotonic_time) {
-  // First collect running properties.
-  TargetProperties blocked_properties;
-  for (size_t i = 0; i < active_animations_.size(); ++i) {
-    if (active_animations_[i]->run_state() == Animation::Starting ||
-        active_animations_[i]->run_state() == Animation::Running)
-      blocked_properties.insert(active_animations_[i]->target_property());
+void LayerAnimationController::StartAnimations(base::TimeTicks monotonic_time) {
+  DCHECK(needs_to_start_animations_);
+  needs_to_start_animations_ = false;
+  // First collect running properties affecting each type of observer.
+  TargetProperties blocked_properties_for_active_observers;
+  TargetProperties blocked_properties_for_pending_observers;
+  std::vector<size_t> animations_waiting_for_target;
+
+  animations_waiting_for_target.reserve(animations_.size());
+  for (size_t i = 0; i < animations_.size(); ++i) {
+    if (animations_[i]->run_state() == Animation::Starting ||
+        animations_[i]->run_state() == Animation::Running) {
+      if (animations_[i]->affects_active_observers()) {
+        blocked_properties_for_active_observers.insert(
+            animations_[i]->target_property());
+      }
+      if (animations_[i]->affects_pending_observers()) {
+        blocked_properties_for_pending_observers.insert(
+            animations_[i]->target_property());
+      }
+    } else if (animations_[i]->run_state() ==
+               Animation::WaitingForTargetAvailability) {
+      animations_waiting_for_target.push_back(i);
+    }
   }
 
-  for (size_t i = 0; i < active_animations_.size(); ++i) {
-    if (active_animations_[i]->run_state() ==
-        Animation::WaitingForTargetAvailability) {
+  for (size_t i = 0; i < animations_waiting_for_target.size(); ++i) {
       // Collect all properties for animations with the same group id (they
       // should all also be in the list of animations).
+    size_t animation_index = animations_waiting_for_target[i];
+    Animation* animation_waiting_for_target = animations_[animation_index];
+    // Check for the run state again even though the animation was waiting
+    // for target because it might have changed the run state while handling
+    // previous animation in this loop (if they belong to same group).
+    if (animation_waiting_for_target->run_state() ==
+        Animation::WaitingForTargetAvailability) {
       TargetProperties enqueued_properties;
-      enqueued_properties.insert(active_animations_[i]->target_property());
-      for (size_t j = i + 1; j < active_animations_.size(); ++j) {
-        if (active_animations_[i]->group() == active_animations_[j]->group())
-          enqueued_properties.insert(active_animations_[j]->target_property());
+      bool affects_active_observers =
+          animation_waiting_for_target->affects_active_observers();
+      bool affects_pending_observers =
+          animation_waiting_for_target->affects_pending_observers();
+      enqueued_properties.insert(
+          animation_waiting_for_target->target_property());
+      for (size_t j = animation_index + 1; j < animations_.size(); ++j) {
+        if (animation_waiting_for_target->group() == animations_[j]->group()) {
+          enqueued_properties.insert(animations_[j]->target_property());
+          affects_active_observers |=
+              animations_[j]->affects_active_observers();
+          affects_pending_observers |=
+              animations_[j]->affects_pending_observers();
+        }
       }
 
       // Check to see if intersection of the list of properties affected by
-      // the group and the list of currently blocked properties is null. In
-      // any case, the group's target properties need to be added to the list
-      // of blocked properties.
+      // the group and the list of currently blocked properties is null, taking
+      // into account the type(s) of observers affected by the group. In any
+      // case, the group's target properties need to be added to the lists of
+      // blocked properties.
       bool null_intersection = true;
       for (TargetProperties::iterator p_iter = enqueued_properties.begin();
            p_iter != enqueued_properties.end();
            ++p_iter) {
-        if (!blocked_properties.insert(*p_iter).second)
+        if (affects_active_observers &&
+            !blocked_properties_for_active_observers.insert(*p_iter).second)
+          null_intersection = false;
+        if (affects_pending_observers &&
+            !blocked_properties_for_pending_observers.insert(*p_iter).second)
           null_intersection = false;
       }
 
       // If the intersection is null, then we are free to start the animations
       // in the group.
       if (null_intersection) {
-        active_animations_[i]->SetRunState(
-            Animation::Starting, monotonic_time);
-        for (size_t j = i + 1; j < active_animations_.size(); ++j) {
-          if (active_animations_[i]->group() ==
-              active_animations_[j]->group()) {
-            active_animations_[j]->SetRunState(
-                Animation::Starting, monotonic_time);
+        animation_waiting_for_target->SetRunState(Animation::Starting,
+                                                  monotonic_time);
+        for (size_t j = animation_index + 1; j < animations_.size(); ++j) {
+          if (animation_waiting_for_target->group() ==
+              animations_[j]->group()) {
+            animations_[j]->SetRunState(Animation::Starting, monotonic_time);
           }
         }
+      } else {
+        needs_to_start_animations_ = true;
       }
     }
   }
 }
 
 void LayerAnimationController::PromoteStartedAnimations(
-    double monotonic_time,
+    base::TimeTicks monotonic_time,
     AnimationEventsVector* events) {
-  for (size_t i = 0; i < active_animations_.size(); ++i) {
-    if (active_animations_[i]->run_state() == Animation::Starting) {
-      active_animations_[i]->SetRunState(Animation::Running, monotonic_time);
-      if (!active_animations_[i]->has_set_start_time())
-        active_animations_[i]->set_start_time(monotonic_time);
+  for (size_t i = 0; i < animations_.size(); ++i) {
+    if (animations_[i]->run_state() == Animation::Starting &&
+        animations_[i]->affects_active_observers()) {
+      animations_[i]->SetRunState(Animation::Running, monotonic_time);
+      if (!animations_[i]->has_set_start_time() &&
+          !animations_[i]->needs_synchronized_start_time())
+        animations_[i]->set_start_time(monotonic_time);
       if (events) {
-        AnimationEvent started_event(
-            AnimationEvent::Started,
-            id_,
-            active_animations_[i]->group(),
-            active_animations_[i]->target_property(),
-            monotonic_time);
-        started_event.is_impl_only = active_animations_[i]->is_impl_only();
-        events->push_back(started_event);
+        AnimationEvent started_event(AnimationEvent::Started,
+                                     id_,
+                                     animations_[i]->group(),
+                                     animations_[i]->target_property(),
+                                     monotonic_time);
+        started_event.is_impl_only = animations_[i]->is_impl_only();
+        if (started_event.is_impl_only)
+          NotifyAnimationStarted(started_event);
+        else
+          events->push_back(started_event);
       }
     }
   }
 }
 
-void LayerAnimationController::MarkFinishedAnimations(double monotonic_time) {
-  for (size_t i = 0; i < active_animations_.size(); ++i) {
-    if (active_animations_[i]->IsFinishedAt(monotonic_time) &&
-        active_animations_[i]->run_state() != Animation::WaitingForDeletion)
-      active_animations_[i]->SetRunState(Animation::Finished, monotonic_time);
-  }
-}
-
-void LayerAnimationController::ResolveConflicts(double monotonic_time) {
-  // Find any animations that are animating the same property and resolve the
-  // confict. We could eventually blend, but for now we'll just abort the
-  // previous animation (where 'previous' means: (1) has a prior start time or
-  // (2) has an equal start time, but was added to the queue earlier, i.e.,
-  // has a lower index in active_animations_).
-  for (size_t i = 0; i < active_animations_.size(); ++i) {
-    if (active_animations_[i]->run_state() == Animation::Starting ||
-        active_animations_[i]->run_state() == Animation::Running) {
-      for (size_t j = i + 1; j < active_animations_.size(); ++j) {
-        if ((active_animations_[j]->run_state() == Animation::Starting ||
-             active_animations_[j]->run_state() == Animation::Running) &&
-            active_animations_[i]->target_property() ==
-            active_animations_[j]->target_property()) {
-          if (active_animations_[i]->start_time() >
-              active_animations_[j]->start_time()) {
-            active_animations_[j]->SetRunState(Animation::Aborted,
-                                               monotonic_time);
-          } else {
-            active_animations_[i]->SetRunState(Animation::Aborted,
-                                               monotonic_time);
-          }
-        }
-      }
-    }
+void LayerAnimationController::MarkFinishedAnimations(
+    base::TimeTicks monotonic_time) {
+  for (size_t i = 0; i < animations_.size(); ++i) {
+    if (animations_[i]->IsFinishedAt(monotonic_time) &&
+        animations_[i]->run_state() != Animation::Aborted &&
+        animations_[i]->run_state() != Animation::WaitingForDeletion)
+      animations_[i]->SetRunState(Animation::Finished, monotonic_time);
   }
 }
 
 void LayerAnimationController::MarkAnimationsForDeletion(
-    double monotonic_time, AnimationEventsVector* events) {
+    base::TimeTicks monotonic_time,
+    AnimationEventsVector* events) {
+  bool marked_animations_for_deletions = false;
+  std::vector<size_t> animations_with_same_group_id;
+
+  animations_with_same_group_id.reserve(animations_.size());
   // Non-aborted animations are marked for deletion after a corresponding
   // AnimationEvent::Finished event is sent or received. This means that if
   // we don't have an events vector, we must ensure that non-aborted animations
   // have received a finished event before marking them for deletion.
-  for (size_t i = 0; i < active_animations_.size(); i++) {
-    int group_id = active_animations_[i]->group();
+  for (size_t i = 0; i < animations_.size(); i++) {
+    int group_id = animations_[i]->group();
+    if (animations_[i]->run_state() == Animation::Aborted) {
+      if (events && !animations_[i]->is_impl_only()) {
+        AnimationEvent aborted_event(AnimationEvent::Aborted,
+                                     id_,
+                                     group_id,
+                                     animations_[i]->target_property(),
+                                     monotonic_time);
+        events->push_back(aborted_event);
+      }
+      animations_[i]->SetRunState(Animation::WaitingForDeletion,
+                                  monotonic_time);
+      marked_animations_for_deletions = true;
+      continue;
+    }
+
     bool all_anims_with_same_id_are_finished = false;
 
     // Since deleting an animation on the main thread leads to its deletion
     // on the impl thread, we only mark a Finished main thread animation for
     // deletion once it has received a Finished event from the impl thread.
     bool animation_i_will_send_or_has_received_finish_event =
-        events || active_animations_[i]->received_finished_event();
+        events || animations_[i]->received_finished_event();
     // If an animation is finished, and not already marked for deletion,
     // find out if all other animations in the same group are also finished.
-    if (active_animations_[i]->run_state() == Animation::Aborted ||
-        (active_animations_[i]->run_state() == Animation::Finished &&
-         animation_i_will_send_or_has_received_finish_event)) {
+    if (animations_[i]->run_state() == Animation::Finished &&
+        animation_i_will_send_or_has_received_finish_event) {
+      // Clear the animations_with_same_group_id if it was added for
+      // the previous animation's iteration.
+      if (animations_with_same_group_id.size() > 0)
+        animations_with_same_group_id.clear();
       all_anims_with_same_id_are_finished = true;
-      for (size_t j = 0; j < active_animations_.size(); ++j) {
+      for (size_t j = 0; j < animations_.size(); ++j) {
         bool animation_j_will_send_or_has_received_finish_event =
-            events || active_animations_[j]->received_finished_event();
-        if (group_id == active_animations_[j]->group() &&
-            (!active_animations_[j]->is_finished() ||
-             (active_animations_[j]->run_state() == Animation::Finished &&
-              !animation_j_will_send_or_has_received_finish_event))) {
-          all_anims_with_same_id_are_finished = false;
-          break;
+            events || animations_[j]->received_finished_event();
+        if (group_id == animations_[j]->group()) {
+          if (!animations_[j]->is_finished() ||
+              (animations_[j]->run_state() == Animation::Finished &&
+               !animation_j_will_send_or_has_received_finish_event)) {
+            all_anims_with_same_id_are_finished = false;
+            break;
+          } else if (j >= i &&
+                     animations_[j]->run_state() != Animation::Aborted) {
+            // Mark down the animations which belong to the same group
+            // and is not yet aborted. If this current iteration finds that all
+            // animations with same ID are finished, then the marked
+            // animations below will be set to WaitingForDeletion in next
+            // iteration.
+            animations_with_same_group_id.push_back(j);
+          }
         }
       }
     }
@@ -615,24 +810,30 @@ void LayerAnimationController::MarkAnimationsForDeletion(
       // We now need to remove all animations with the same group id as
       // group_id (and send along animation finished notifications, if
       // necessary).
-      for (size_t j = i; j < active_animations_.size(); j++) {
-        if (group_id == active_animations_[j]->group()) {
+      for (size_t j = 0; j < animations_with_same_group_id.size(); j++) {
+        size_t animation_index = animations_with_same_group_id[j];
           if (events) {
             AnimationEvent finished_event(
                 AnimationEvent::Finished,
                 id_,
-                active_animations_[j]->group(),
-                active_animations_[j]->target_property(),
+                animations_[animation_index]->group(),
+                animations_[animation_index]->target_property(),
                 monotonic_time);
-            finished_event.is_impl_only = active_animations_[j]->is_impl_only();
-            events->push_back(finished_event);
+            finished_event.is_impl_only =
+                animations_[animation_index]->is_impl_only();
+            if (finished_event.is_impl_only)
+              NotifyAnimationFinished(finished_event);
+            else
+              events->push_back(finished_event);
           }
-          active_animations_[j]->SetRunState(Animation::WaitingForDeletion,
-                                             monotonic_time);
-        }
+          animations_[animation_index]->SetRunState(
+              Animation::WaitingForDeletion, monotonic_time);
       }
+      marked_animations_for_deletions = true;
     }
   }
+  if (marked_animations_for_deletions)
+    NotifyObserversAnimationWaitingForDeletion();
 }
 
 static bool IsWaitingForDeletion(Animation* animation) {
@@ -640,67 +841,58 @@ static bool IsWaitingForDeletion(Animation* animation) {
 }
 
 void LayerAnimationController::PurgeAnimationsMarkedForDeletion() {
-  ScopedPtrVector<Animation>& animations = active_animations_;
-  animations.erase(cc::remove_if(&animations,
-                                 animations.begin(),
-                                 animations.end(),
-                                 IsWaitingForDeletion),
-                   animations.end());
+  animations_.erase(cc::remove_if(&animations_,
+                                  animations_.begin(),
+                                  animations_.end(),
+                                  IsWaitingForDeletion),
+                    animations_.end());
 }
 
-void LayerAnimationController::ReplaceImplThreadAnimations(
-    LayerAnimationController* controller_impl) const {
-  controller_impl->active_animations_.clear();
-  for (size_t i = 0; i < active_animations_.size(); ++i) {
-    scoped_ptr<Animation> to_add;
-    if (active_animations_[i]->needs_synchronized_start_time()) {
-      // We haven't received an animation started notification yet, so it
-      // is important that we add it in a 'waiting' and not 'running' state.
-      Animation::RunState initial_run_state =
-          Animation::WaitingForTargetAvailability;
-      double start_time = 0;
-      to_add = active_animations_[i]->CloneAndInitialize(
-          initial_run_state, start_time).Pass();
-    } else {
-      to_add = active_animations_[i]->Clone().Pass();
-    }
+void LayerAnimationController::TickAnimations(base::TimeTicks monotonic_time) {
+  for (size_t i = 0; i < animations_.size(); ++i) {
+    if (animations_[i]->run_state() == Animation::Starting ||
+        animations_[i]->run_state() == Animation::Running ||
+        animations_[i]->run_state() == Animation::Paused) {
+      if (!animations_[i]->InEffect(monotonic_time))
+        continue;
 
-    controller_impl->AddAnimation(to_add.Pass());
-  }
-}
-
-void LayerAnimationController::TickAnimations(double monotonic_time) {
-  for (size_t i = 0; i < active_animations_.size(); ++i) {
-    if (active_animations_[i]->run_state() == Animation::Starting ||
-        active_animations_[i]->run_state() == Animation::Running ||
-        active_animations_[i]->run_state() == Animation::Paused) {
       double trimmed =
-          active_animations_[i]->TrimTimeToCurrentIteration(monotonic_time);
+          animations_[i]->TrimTimeToCurrentIteration(monotonic_time);
 
-      switch (active_animations_[i]->target_property()) {
+      switch (animations_[i]->target_property()) {
         case Animation::Transform: {
           const TransformAnimationCurve* transform_animation_curve =
-              active_animations_[i]->curve()->ToTransformAnimationCurve();
+              animations_[i]->curve()->ToTransformAnimationCurve();
           const gfx::Transform transform =
               transform_animation_curve->GetValue(trimmed);
-          NotifyObserversTransformAnimated(transform);
+          NotifyObserversTransformAnimated(
+              transform,
+              animations_[i]->affects_active_observers(),
+              animations_[i]->affects_pending_observers());
           break;
         }
 
         case Animation::Opacity: {
           const FloatAnimationCurve* float_animation_curve =
-              active_animations_[i]->curve()->ToFloatAnimationCurve();
-          const float opacity = float_animation_curve->GetValue(trimmed);
-          NotifyObserversOpacityAnimated(opacity);
+              animations_[i]->curve()->ToFloatAnimationCurve();
+          const float opacity = std::max(
+              std::min(float_animation_curve->GetValue(trimmed), 1.0f), 0.f);
+          NotifyObserversOpacityAnimated(
+              opacity,
+              animations_[i]->affects_active_observers(),
+              animations_[i]->affects_pending_observers());
           break;
         }
 
         case Animation::Filter: {
           const FilterAnimationCurve* filter_animation_curve =
-              active_animations_[i]->curve()->ToFilterAnimationCurve();
+              animations_[i]->curve()->ToFilterAnimationCurve();
           const FilterOperations filter =
               filter_animation_curve->GetValue(trimmed);
-          NotifyObserversFilterAnimated(filter);
+          NotifyObserversFilterAnimated(
+              filter,
+              animations_[i]->affects_active_observers(),
+              animations_[i]->affects_pending_observers());
           break;
         }
 
@@ -709,6 +901,18 @@ void LayerAnimationController::TickAnimations(double monotonic_time) {
           break;
         }
 
+        case Animation::ScrollOffset: {
+          const ScrollOffsetAnimationCurve* scroll_offset_animation_curve =
+              animations_[i]->curve()->ToScrollOffsetAnimationCurve();
+          const gfx::Vector2dF scroll_offset =
+              scroll_offset_animation_curve->GetValue(trimmed);
+          NotifyObserversScrollOffsetAnimated(
+              scroll_offset,
+              animations_[i]->affects_active_observers(),
+              animations_[i]->affects_pending_observers());
+          break;
+        }
+
         // Do nothing for sentinel value.
         case Animation::TargetPropertyEnumSize:
           NOTREACHED();
@@ -720,32 +924,94 @@ void LayerAnimationController::TickAnimations(double monotonic_time) {
 void LayerAnimationController::UpdateActivation(UpdateActivationType type) {
   bool force = type == ForceActivation;
   if (registrar_) {
-    if (!active_animations_.empty() && (!is_active_ || force))
+    bool was_active = is_active_;
+    is_active_ = false;
+    for (size_t i = 0; i < animations_.size(); ++i) {
+      if (animations_[i]->run_state() != Animation::WaitingForDeletion) {
+        is_active_ = true;
+        break;
+      }
+    }
+
+    if (is_active_ && (!was_active || force))
       registrar_->DidActivateAnimationController(this);
-    else if (active_animations_.empty() && (is_active_ || force))
+    else if (!is_active_ && (was_active || force))
       registrar_->DidDeactivateAnimationController(this);
-    is_active_ = !active_animations_.empty();
   }
 }
 
-void LayerAnimationController::NotifyObserversOpacityAnimated(float opacity) {
-  FOR_EACH_OBSERVER(LayerAnimationValueObserver,
-                    value_observers_,
-                    OnOpacityAnimated(opacity));
+void LayerAnimationController::NotifyObserversOpacityAnimated(
+    float opacity,
+    bool notify_active_observers,
+    bool notify_pending_observers) {
+  if (value_observers_.might_have_observers()) {
+    ObserverListBase<LayerAnimationValueObserver>::Iterator it(
+        value_observers_);
+    LayerAnimationValueObserver* obs;
+    while ((obs = it.GetNext()) != NULL) {
+      if ((notify_active_observers && notify_pending_observers) ||
+          (notify_active_observers && obs->IsActive()) ||
+          (notify_pending_observers && !obs->IsActive()))
+        obs->OnOpacityAnimated(opacity);
+    }
+  }
 }
 
 void LayerAnimationController::NotifyObserversTransformAnimated(
-    const gfx::Transform& transform) {
-  FOR_EACH_OBSERVER(LayerAnimationValueObserver,
-                    value_observers_,
-                    OnTransformAnimated(transform));
+    const gfx::Transform& transform,
+    bool notify_active_observers,
+    bool notify_pending_observers) {
+  if (value_observers_.might_have_observers()) {
+    ObserverListBase<LayerAnimationValueObserver>::Iterator it(
+        value_observers_);
+    LayerAnimationValueObserver* obs;
+    while ((obs = it.GetNext()) != NULL) {
+      if ((notify_active_observers && notify_pending_observers) ||
+          (notify_active_observers && obs->IsActive()) ||
+          (notify_pending_observers && !obs->IsActive()))
+        obs->OnTransformAnimated(transform);
+    }
+  }
 }
 
 void LayerAnimationController::NotifyObserversFilterAnimated(
-    const FilterOperations& filters) {
+    const FilterOperations& filters,
+    bool notify_active_observers,
+    bool notify_pending_observers) {
+  if (value_observers_.might_have_observers()) {
+    ObserverListBase<LayerAnimationValueObserver>::Iterator it(
+        value_observers_);
+    LayerAnimationValueObserver* obs;
+    while ((obs = it.GetNext()) != NULL) {
+      if ((notify_active_observers && notify_pending_observers) ||
+          (notify_active_observers && obs->IsActive()) ||
+          (notify_pending_observers && !obs->IsActive()))
+        obs->OnFilterAnimated(filters);
+    }
+  }
+}
+
+void LayerAnimationController::NotifyObserversScrollOffsetAnimated(
+    const gfx::Vector2dF& scroll_offset,
+    bool notify_active_observers,
+    bool notify_pending_observers) {
+  if (value_observers_.might_have_observers()) {
+    ObserverListBase<LayerAnimationValueObserver>::Iterator it(
+        value_observers_);
+    LayerAnimationValueObserver* obs;
+    while ((obs = it.GetNext()) != NULL) {
+      if ((notify_active_observers && notify_pending_observers) ||
+          (notify_active_observers && obs->IsActive()) ||
+          (notify_pending_observers && !obs->IsActive()))
+        obs->OnScrollOffsetAnimated(scroll_offset);
+    }
+  }
+}
+
+void LayerAnimationController::NotifyObserversAnimationWaitingForDeletion() {
   FOR_EACH_OBSERVER(LayerAnimationValueObserver,
                     value_observers_,
-                    OnFilterAnimated(filters));
+                    OnAnimationWaitingForDeletion());
 }
 
 bool LayerAnimationController::HasValueObserver() {