CC Animations: Redirect all compositor animation requests to AnimationHost.

1) Use AnimationHost's AnimationRegistrar instance if new system enabled.
2) Use AnimationPlayer's LayerAnimationController instance if new system enabled.

Previous episode: https://codereview.chromium.org/947033002/
Next episode:
https://codereview.chromium.org/1009233002/

In general: The compositor should not need to worry about servicing animations.
A step towards AnimationHost/AnimationPlayer/AnimationTimeline decoupling.

BUG=394777
[email protected]
[email protected]
CQ_INCLUDE_TRYBOTS=tryserver.blink:linux_blink_rel

Review URL: https://codereview.chromium.org/1010663002

Cr-Commit-Position: refs/heads/master@{#337309}
diff --git a/cc/BUILD.gn b/cc/BUILD.gn
index 2d640ea..719fcf9 100644
--- a/cc/BUILD.gn
+++ b/cc/BUILD.gn
@@ -805,6 +805,7 @@
     "trees/layer_tree_host_pixeltest_tiles.cc",
     "trees/layer_tree_host_unittest.cc",
     "trees/layer_tree_host_unittest_animation.cc",
+    "trees/layer_tree_host_unittest_animation_timelines.cc",
     "trees/layer_tree_host_unittest_context.cc",
     "trees/layer_tree_host_unittest_copyrequest.cc",
     "trees/layer_tree_host_unittest_damage.cc",
diff --git a/cc/animation/animation_host.cc b/cc/animation/animation_host.cc
index 99e13e60..489c6f8 100644
--- a/cc/animation/animation_host.cc
+++ b/cc/animation/animation_host.cc
@@ -10,6 +10,7 @@
 #include "cc/animation/animation_registrar.h"
 #include "cc/animation/animation_timeline.h"
 #include "cc/animation/element_animations.h"
+#include "ui/gfx/geometry/box_f.h"
 
 namespace cc {
 
@@ -202,4 +203,179 @@
                                                         : iter->second;
 }
 
+void AnimationHost::SetSupportsScrollAnimations(
+    bool supports_scroll_animations) {
+  animation_registrar_->set_supports_scroll_animations(
+      supports_scroll_animations);
+}
+
+bool AnimationHost::SupportsScrollAnimations() const {
+  return animation_registrar_->supports_scroll_animations();
+}
+
+bool AnimationHost::NeedsAnimateLayers() const {
+  return animation_registrar_->needs_animate_layers();
+}
+
+bool AnimationHost::ActivateAnimations() {
+  return animation_registrar_->ActivateAnimations();
+}
+
+bool AnimationHost::AnimateLayers(base::TimeTicks monotonic_time) {
+  return animation_registrar_->AnimateLayers(monotonic_time);
+}
+
+bool AnimationHost::UpdateAnimationState(bool start_ready_animations,
+                                         AnimationEventsVector* events) {
+  return animation_registrar_->UpdateAnimationState(start_ready_animations,
+                                                    events);
+}
+
+scoped_ptr<AnimationEventsVector> AnimationHost::CreateEvents() {
+  return animation_registrar_->CreateEvents();
+}
+
+void AnimationHost::SetAnimationEvents(
+    scoped_ptr<AnimationEventsVector> events) {
+  return animation_registrar_->SetAnimationEvents(events.Pass());
+}
+
+bool AnimationHost::ScrollOffsetAnimationWasInterrupted(int layer_id) const {
+  LayerAnimationController* controller = GetControllerForLayerId(layer_id);
+  return controller ? controller->scroll_offset_animation_was_interrupted()
+                    : false;
+}
+
+bool AnimationHost::IsAnimatingFilterProperty(int layer_id) const {
+  LayerAnimationController* controller = GetControllerForLayerId(layer_id);
+  return controller ? controller->IsAnimatingProperty(Animation::FILTER)
+                    : false;
+}
+
+bool AnimationHost::IsAnimatingOpacityProperty(int layer_id) const {
+  LayerAnimationController* controller = GetControllerForLayerId(layer_id);
+  return controller ? controller->IsAnimatingProperty(Animation::OPACITY)
+                    : false;
+}
+
+bool AnimationHost::IsAnimatingTransformProperty(int layer_id) const {
+  LayerAnimationController* controller = GetControllerForLayerId(layer_id);
+  return controller ? controller->IsAnimatingProperty(Animation::TRANSFORM)
+                    : false;
+}
+
+bool AnimationHost::HasPotentiallyRunningOpacityAnimation(int layer_id) const {
+  LayerAnimationController* controller = GetControllerForLayerId(layer_id);
+  if (!controller)
+    return false;
+
+  Animation* animation = controller->GetAnimation(Animation::OPACITY);
+  return animation && !animation->is_finished();
+}
+
+bool AnimationHost::HasPotentiallyRunningTransformAnimation(
+    int layer_id) const {
+  LayerAnimationController* controller = GetControllerForLayerId(layer_id);
+  if (!controller)
+    return false;
+
+  Animation* animation = controller->GetAnimation(Animation::TRANSFORM);
+  return animation && !animation->is_finished();
+}
+
+bool AnimationHost::FilterIsAnimatingOnImplOnly(int layer_id) const {
+  LayerAnimationController* controller = GetControllerForLayerId(layer_id);
+  if (!controller)
+    return false;
+
+  Animation* animation = controller->GetAnimation(Animation::FILTER);
+  return animation && animation->is_impl_only();
+}
+
+bool AnimationHost::OpacityIsAnimatingOnImplOnly(int layer_id) const {
+  LayerAnimationController* controller = GetControllerForLayerId(layer_id);
+  if (!controller)
+    return false;
+
+  Animation* animation = controller->GetAnimation(Animation::OPACITY);
+  return animation && animation->is_impl_only();
+}
+
+bool AnimationHost::TransformIsAnimatingOnImplOnly(int layer_id) const {
+  LayerAnimationController* controller = GetControllerForLayerId(layer_id);
+  if (!controller)
+    return false;
+
+  Animation* animation = controller->GetAnimation(Animation::TRANSFORM);
+  return animation && animation->is_impl_only();
+}
+
+bool AnimationHost::HasFilterAnimationThatInflatesBounds(int layer_id) const {
+  LayerAnimationController* controller = GetControllerForLayerId(layer_id);
+  return controller ? controller->HasFilterAnimationThatInflatesBounds()
+                    : false;
+}
+
+bool AnimationHost::HasTransformAnimationThatInflatesBounds(
+    int layer_id) const {
+  LayerAnimationController* controller = GetControllerForLayerId(layer_id);
+  return controller ? controller->HasTransformAnimationThatInflatesBounds()
+                    : false;
+}
+
+bool AnimationHost::HasAnimationThatInflatesBounds(int layer_id) const {
+  LayerAnimationController* controller = GetControllerForLayerId(layer_id);
+  return controller ? controller->HasAnimationThatInflatesBounds() : false;
+}
+
+bool AnimationHost::FilterAnimationBoundsForBox(int layer_id,
+                                                const gfx::BoxF& box,
+                                                gfx::BoxF* bounds) const {
+  LayerAnimationController* controller = GetControllerForLayerId(layer_id);
+  return controller ? controller->FilterAnimationBoundsForBox(box, bounds)
+                    : false;
+}
+
+bool AnimationHost::TransformAnimationBoundsForBox(int layer_id,
+                                                   const gfx::BoxF& box,
+                                                   gfx::BoxF* bounds) const {
+  *bounds = gfx::BoxF();
+  LayerAnimationController* controller = GetControllerForLayerId(layer_id);
+  return controller ? controller->TransformAnimationBoundsForBox(box, bounds)
+                    : true;
+}
+
+bool AnimationHost::HasOnlyTranslationTransforms(int layer_id) const {
+  LayerAnimationController* controller = GetControllerForLayerId(layer_id);
+  return controller ? controller->HasOnlyTranslationTransforms() : true;
+}
+
+bool AnimationHost::AnimationsPreserveAxisAlignment(int layer_id) const {
+  LayerAnimationController* controller = GetControllerForLayerId(layer_id);
+  return controller ? controller->AnimationsPreserveAxisAlignment() : true;
+}
+
+bool AnimationHost::MaximumTargetScale(int layer_id, float* max_scale) const {
+  *max_scale = 0.f;
+  LayerAnimationController* controller = GetControllerForLayerId(layer_id);
+  return controller ? controller->MaximumTargetScale(max_scale) : true;
+}
+
+bool AnimationHost::AnimationStartScale(int layer_id,
+                                        float* start_scale) const {
+  *start_scale = 0.f;
+  LayerAnimationController* controller = GetControllerForLayerId(layer_id);
+  return controller ? controller->AnimationStartScale(start_scale) : true;
+}
+
+bool AnimationHost::HasAnyAnimation(int layer_id) const {
+  LayerAnimationController* controller = GetControllerForLayerId(layer_id);
+  return controller ? controller->has_any_animation() : false;
+}
+
+bool AnimationHost::HasActiveAnimation(int layer_id) const {
+  LayerAnimationController* controller = GetControllerForLayerId(layer_id);
+  return controller ? controller->HasActiveAnimation() : false;
+}
+
 }  // namespace cc
diff --git a/cc/animation/animation_host.h b/cc/animation/animation_host.h
index 5ae46ee..2887ad8 100644
--- a/cc/animation/animation_host.h
+++ b/cc/animation/animation_host.h
@@ -10,6 +10,8 @@
 #include "base/containers/scoped_ptr_hash_map.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/time/time.h"
+#include "cc/animation/animation_events.h"
 #include "cc/base/cc_export.h"
 #include "cc/trees/mutator_host_client.h"
 
@@ -73,6 +75,51 @@
     return animation_registrar_.get();
   }
 
+  void SetSupportsScrollAnimations(bool supports_scroll_animations);
+  bool SupportsScrollAnimations() const;
+  bool NeedsAnimateLayers() const;
+
+  bool ActivateAnimations();
+  bool AnimateLayers(base::TimeTicks monotonic_time);
+  bool UpdateAnimationState(bool start_ready_animations,
+                            AnimationEventsVector* events);
+
+  scoped_ptr<AnimationEventsVector> CreateEvents();
+  void SetAnimationEvents(scoped_ptr<AnimationEventsVector> events);
+
+  bool ScrollOffsetAnimationWasInterrupted(int layer_id) const;
+
+  bool IsAnimatingFilterProperty(int layer_id) const;
+  bool IsAnimatingOpacityProperty(int layer_id) const;
+  bool IsAnimatingTransformProperty(int layer_id) const;
+
+  bool HasPotentiallyRunningOpacityAnimation(int layer_id) const;
+  bool HasPotentiallyRunningTransformAnimation(int layer_id) const;
+
+  bool FilterIsAnimatingOnImplOnly(int layer_id) const;
+  bool OpacityIsAnimatingOnImplOnly(int layer_id) const;
+  bool TransformIsAnimatingOnImplOnly(int layer_id) const;
+
+  bool HasFilterAnimationThatInflatesBounds(int layer_id) const;
+  bool HasTransformAnimationThatInflatesBounds(int layer_id) const;
+  bool HasAnimationThatInflatesBounds(int layer_id) const;
+
+  bool FilterAnimationBoundsForBox(int layer_id,
+                                   const gfx::BoxF& box,
+                                   gfx::BoxF* bounds) const;
+  bool TransformAnimationBoundsForBox(int layer_id,
+                                      const gfx::BoxF& box,
+                                      gfx::BoxF* bounds) const;
+
+  bool HasOnlyTranslationTransforms(int layer_id) const;
+  bool AnimationsPreserveAxisAlignment(int layer_id) const;
+
+  bool MaximumTargetScale(int layer_id, float* max_scale) const;
+  bool AnimationStartScale(int layer_id, float* start_scale) const;
+
+  bool HasAnyAnimation(int layer_id) const;
+  bool HasActiveAnimation(int layer_id) const;
+
  private:
   explicit AnimationHost(ThreadInstance thread_instance);
 
diff --git a/cc/cc_tests.gyp b/cc/cc_tests.gyp
index 58c71018..b115e3b 100644
--- a/cc/cc_tests.gyp
+++ b/cc/cc_tests.gyp
@@ -120,6 +120,7 @@
       'trees/layer_tree_host_pixeltest_tiles.cc',
       'trees/layer_tree_host_unittest.cc',
       'trees/layer_tree_host_unittest_animation.cc',
+      'trees/layer_tree_host_unittest_animation_timelines.cc',
       'trees/layer_tree_host_unittest_context.cc',
       'trees/layer_tree_host_unittest_copyrequest.cc',
       'trees/layer_tree_host_unittest_damage.cc',
diff --git a/cc/layers/layer.cc b/cc/layers/layer.cc
index 6476b28..b9867d6 100644
--- a/cc/layers/layer.cc
+++ b/cc/layers/layer.cc
@@ -156,7 +156,13 @@
   if (host)
     RegisterForAnimations(host->animation_registrar());
 
-  if (host && layer_animation_controller_->has_any_animation())
+  bool has_any_animation = false;
+  if (layer_animation_controller_)
+    has_any_animation = layer_animation_controller_->has_any_animation();
+  else if (layer_tree_host_)
+    has_any_animation = layer_tree_host_->HasAnyAnimation(this);
+
+  if (host && has_any_animation)
     host->SetNeedsCommit();
 }
 
@@ -502,7 +508,11 @@
 }
 
 bool Layer::FilterIsAnimating() const {
-  return layer_animation_controller_->IsAnimatingProperty(Animation::FILTER);
+  DCHECK(layer_tree_host_);
+  return layer_animation_controller_
+             ? layer_animation_controller_->IsAnimatingProperty(
+                   Animation::FILTER)
+             : layer_tree_host_->IsAnimatingFilterProperty(this);
 }
 
 void Layer::SetBackgroundFilters(const FilterOperations& filters) {
@@ -522,7 +532,24 @@
 }
 
 bool Layer::OpacityIsAnimating() const {
-  return layer_animation_controller_->IsAnimatingProperty(Animation::OPACITY);
+  DCHECK(layer_tree_host_);
+  return layer_animation_controller_
+             ? layer_animation_controller_->IsAnimatingProperty(
+                   Animation::OPACITY)
+             : layer_tree_host_->IsAnimatingOpacityProperty(this);
+}
+
+bool Layer::HasPotentiallyRunningOpacityAnimation() const {
+  if (layer_animation_controller_) {
+    if (Animation* animation =
+            layer_animation_controller()->GetAnimation(Animation::OPACITY)) {
+      return !animation->is_finished();
+    }
+    return false;
+  } else {
+    DCHECK(layer_tree_host_);
+    return layer_tree_host_->HasPotentiallyRunningOpacityAnimation(this);
+  }
 }
 
 bool Layer::OpacityCanAnimateOnImplThread() const {
@@ -706,11 +733,39 @@
 }
 
 bool Layer::AnimationsPreserveAxisAlignment() const {
-  return layer_animation_controller_->AnimationsPreserveAxisAlignment();
+  DCHECK(layer_tree_host_);
+  return layer_animation_controller_
+             ? layer_animation_controller_->AnimationsPreserveAxisAlignment()
+             : layer_tree_host_->AnimationsPreserveAxisAlignment(this);
 }
 
 bool Layer::TransformIsAnimating() const {
-  return layer_animation_controller_->IsAnimatingProperty(Animation::TRANSFORM);
+  DCHECK(layer_tree_host_);
+  return layer_animation_controller_
+             ? layer_animation_controller_->IsAnimatingProperty(
+                   Animation::TRANSFORM)
+             : layer_tree_host_->IsAnimatingTransformProperty(this);
+}
+
+bool Layer::HasPotentiallyRunningTransformAnimation() const {
+  if (layer_animation_controller_) {
+    if (Animation* animation =
+            layer_animation_controller()->GetAnimation(Animation::TRANSFORM)) {
+      return !animation->is_finished();
+    }
+    return false;
+  } else {
+    DCHECK(layer_tree_host_);
+    return layer_tree_host_->HasPotentiallyRunningTransformAnimation(this);
+  }
+}
+
+bool Layer::ScrollOffsetAnimationWasInterrupted() const {
+  DCHECK(layer_tree_host_);
+  return layer_animation_controller_
+             ? layer_animation_controller_
+                   ->scroll_offset_animation_was_interrupted()
+             : layer_tree_host_->ScrollOffsetAnimationWasInterrupted(this);
 }
 
 void Layer::SetScrollParent(Layer* parent) {
@@ -1220,7 +1275,7 @@
   // the pending tree will clobber any impl-side scrolling occuring on the
   // active tree. To do so, avoid scrolling the pending tree along with it
   // instead of trying to undo that scrolling later.
-  if (layer_animation_controller_->scroll_offset_animation_was_interrupted())
+  if (ScrollOffsetAnimationWasInterrupted())
     layer->PushScrollOffsetFromMainThreadAndClobberActiveValue(scroll_offset_);
   else
     layer->PushScrollOffsetFromMainThread(scroll_offset_);
@@ -1260,8 +1315,9 @@
 
   layer->SetStackingOrderChanged(stacking_order_changed_);
 
-  layer_animation_controller_->PushAnimationUpdatesTo(
-      layer->layer_animation_controller());
+  if (layer->layer_animation_controller() && layer_animation_controller_)
+    layer_animation_controller_->PushAnimationUpdatesTo(
+        layer->layer_animation_controller());
 
   if (frame_timing_requests_dirty_) {
     layer->SetFrameTimingRequests(frame_timing_requests_);
@@ -1476,6 +1532,7 @@
 
 void Layer::SetLayerAnimationControllerForTest(
     scoped_refptr<LayerAnimationController> controller) {
+  DCHECK(layer_animation_controller_);
   layer_animation_controller_->RemoveValueObserver(this);
   layer_animation_controller_ = controller;
   layer_animation_controller_->AddValueObserver(this);
@@ -1483,8 +1540,10 @@
 }
 
 bool Layer::HasActiveAnimation() const {
-  DCHECK(layer_animation_controller_);
-  return layer_animation_controller_->HasActiveAnimation();
+  DCHECK(layer_tree_host_);
+  return layer_animation_controller_
+             ? layer_animation_controller_->HasActiveAnimation()
+             : layer_tree_host_->HasActiveAnimation(this);
 }
 
 void Layer::RegisterForAnimations(AnimationRegistrar* registrar) {
diff --git a/cc/layers/layer.h b/cc/layers/layer.h
index 7452ba9..3ff2810c 100644
--- a/cc/layers/layer.h
+++ b/cc/layers/layer.h
@@ -135,6 +135,7 @@
   void SetOpacity(float opacity);
   float opacity() const { return opacity_; }
   bool OpacityIsAnimating() const;
+  bool HasPotentiallyRunningOpacityAnimation() const;
   virtual bool OpacityCanAnimateOnImplThread() const;
 
   void SetBlendMode(SkXfermode::Mode blend_mode);
@@ -188,12 +189,15 @@
   void SetTransform(const gfx::Transform& transform);
   const gfx::Transform& transform() const { return transform_; }
   bool TransformIsAnimating() const;
+  bool HasPotentiallyRunningTransformAnimation() const;
   bool AnimationsPreserveAxisAlignment() const;
   bool transform_is_invertible() const { return transform_is_invertible_; }
 
   void SetTransformOrigin(const gfx::Point3F&);
   gfx::Point3F transform_origin() const { return transform_origin_; }
 
+  bool ScrollOffsetAnimationWasInterrupted() const;
+
   void SetScrollParent(Layer* parent);
 
   Layer* scroll_parent() { return scroll_parent_; }
@@ -400,8 +404,7 @@
   void PauseAnimation(int animation_id, double time_offset);
   void RemoveAnimation(int animation_id);
   void RemoveAnimation(int animation_id, Animation::TargetProperty property);
-
-  LayerAnimationController* layer_animation_controller() {
+  LayerAnimationController* layer_animation_controller() const {
     return layer_animation_controller_.get();
   }
   void SetLayerAnimationControllerForTest(
diff --git a/cc/layers/layer_impl.cc b/cc/layers/layer_impl.cc
index b1778ea..3b9a7555 100644
--- a/cc/layers/layer_impl.cc
+++ b/cc/layers/layer_impl.cc
@@ -90,13 +90,16 @@
   DCHECK_GT(layer_id_, 0);
   DCHECK(layer_tree_impl_);
   layer_tree_impl_->RegisterLayer(this);
-  AnimationRegistrar* registrar = layer_tree_impl_->GetAnimationRegistrar();
-  layer_animation_controller_ =
-      registrar->GetAnimationControllerForId(layer_id_);
-  layer_animation_controller_->AddValueObserver(this);
-  if (IsActive()) {
-    layer_animation_controller_->set_value_provider(this);
-    layer_animation_controller_->set_layer_animation_delegate(this);
+
+  if (!layer_tree_impl_->settings().use_compositor_animation_timelines) {
+    AnimationRegistrar* registrar = layer_tree_impl_->GetAnimationRegistrar();
+    layer_animation_controller_ =
+        registrar->GetAnimationControllerForId(layer_id_);
+    layer_animation_controller_->AddValueObserver(this);
+    if (IsActive()) {
+      layer_animation_controller_->set_value_provider(this);
+      layer_animation_controller_->set_layer_animation_delegate(this);
+    }
   }
   SetNeedsPushProperties();
 }
@@ -104,9 +107,11 @@
 LayerImpl::~LayerImpl() {
   DCHECK_EQ(DRAW_MODE_NONE, current_draw_mode_);
 
-  layer_animation_controller_->RemoveValueObserver(this);
-  layer_animation_controller_->remove_value_provider(this);
-  layer_animation_controller_->remove_layer_animation_delegate(this);
+  if (layer_animation_controller_) {
+    layer_animation_controller_->RemoveValueObserver(this);
+    layer_animation_controller_->remove_value_provider(this);
+    layer_animation_controller_->remove_layer_animation_delegate(this);
+  }
 
   if (!copy_requests_.empty() && layer_tree_impl_->IsActiveTree())
     layer_tree_impl()->RemoveLayerWithCopyOutputRequest(this);
@@ -1008,10 +1013,16 @@
 }
 
 bool LayerImpl::FilterIsAnimating() const {
-  return layer_animation_controller_->IsAnimatingProperty(Animation::FILTER);
+  return layer_animation_controller_
+             ? layer_animation_controller_->IsAnimatingProperty(
+                   Animation::FILTER)
+             : layer_tree_impl_->IsAnimatingFilterProperty(this);
 }
 
 bool LayerImpl::FilterIsAnimatingOnImplOnly() const {
+  if (!layer_animation_controller_)
+    return layer_tree_impl_->FilterIsAnimatingOnImplOnly(this);
+
   Animation* filter_animation =
       layer_animation_controller_->GetAnimation(Animation::FILTER);
   return filter_animation && filter_animation->is_impl_only();
@@ -1051,10 +1062,28 @@
 }
 
 bool LayerImpl::OpacityIsAnimating() const {
-  return layer_animation_controller_->IsAnimatingProperty(Animation::OPACITY);
+  return layer_animation_controller_
+             ? layer_animation_controller_->IsAnimatingProperty(
+                   Animation::OPACITY)
+             : layer_tree_impl_->IsAnimatingOpacityProperty(this);
+}
+
+bool LayerImpl::HasPotentiallyRunningOpacityAnimation() const {
+  if (layer_animation_controller_) {
+    if (Animation* animation =
+            layer_animation_controller()->GetAnimation(Animation::OPACITY)) {
+      return !animation->is_finished();
+    }
+    return false;
+  } else {
+    return layer_tree_impl_->HasPotentiallyRunningOpacityAnimation(this);
+  }
 }
 
 bool LayerImpl::OpacityIsAnimatingOnImplOnly() const {
+  if (!layer_animation_controller_)
+    return layer_tree_impl_->OpacityIsAnimatingOnImplOnly(this);
+
   Animation* opacity_animation =
       layer_animation_controller_->GetAnimation(Animation::OPACITY);
   return opacity_animation && opacity_animation->is_impl_only();
@@ -1133,15 +1162,92 @@
 }
 
 bool LayerImpl::TransformIsAnimating() const {
-  return layer_animation_controller_->IsAnimatingProperty(Animation::TRANSFORM);
+  return layer_animation_controller_
+             ? layer_animation_controller_->IsAnimatingProperty(
+                   Animation::TRANSFORM)
+             : layer_tree_impl_->IsAnimatingTransformProperty(this);
+}
+
+bool LayerImpl::HasPotentiallyRunningTransformAnimation() const {
+  if (layer_animation_controller_) {
+    if (Animation* animation =
+            layer_animation_controller()->GetAnimation(Animation::TRANSFORM)) {
+      return !animation->is_finished();
+    }
+    return false;
+  } else {
+    return layer_tree_impl_->HasPotentiallyRunningTransformAnimation(this);
+  }
 }
 
 bool LayerImpl::TransformIsAnimatingOnImplOnly() const {
+  if (!layer_animation_controller_)
+    return layer_tree_impl_->TransformIsAnimatingOnImplOnly(this);
+
   Animation* transform_animation =
       layer_animation_controller_->GetAnimation(Animation::TRANSFORM);
   return transform_animation && transform_animation->is_impl_only();
 }
 
+bool LayerImpl::HasOnlyTranslationTransforms() const {
+  if (!layer_animation_controller_)
+    return layer_tree_impl_->HasOnlyTranslationTransforms(this);
+
+  return layer_animation_controller_->HasOnlyTranslationTransforms();
+}
+
+bool LayerImpl::MaximumTargetScale(float* max_scale) const {
+  if (!layer_animation_controller_)
+    return layer_tree_impl_->MaximumTargetScale(this, max_scale);
+
+  return layer_animation_controller_->MaximumTargetScale(max_scale);
+}
+
+bool LayerImpl::AnimationStartScale(float* start_scale) const {
+  if (!layer_animation_controller_)
+    return layer_tree_impl_->AnimationStartScale(this, start_scale);
+
+  return layer_animation_controller_->AnimationStartScale(start_scale);
+}
+
+bool LayerImpl::HasFilterAnimationThatInflatesBounds() const {
+  if (!layer_animation_controller_)
+    return layer_tree_impl_->HasFilterAnimationThatInflatesBounds(this);
+
+  return layer_animation_controller_->HasFilterAnimationThatInflatesBounds();
+}
+
+bool LayerImpl::HasTransformAnimationThatInflatesBounds() const {
+  if (!layer_animation_controller_)
+    return layer_tree_impl_->HasTransformAnimationThatInflatesBounds(this);
+
+  return layer_animation_controller_->HasTransformAnimationThatInflatesBounds();
+}
+
+bool LayerImpl::HasAnimationThatInflatesBounds() const {
+  if (!layer_animation_controller_)
+    return layer_tree_impl_->HasAnimationThatInflatesBounds(this);
+
+  return layer_animation_controller_->HasAnimationThatInflatesBounds();
+}
+
+bool LayerImpl::FilterAnimationBoundsForBox(const gfx::BoxF& box,
+                                            gfx::BoxF* bounds) const {
+  if (!layer_animation_controller_)
+    return layer_tree_impl_->FilterAnimationBoundsForBox(this, box, bounds);
+
+  return layer_animation_controller_->FilterAnimationBoundsForBox(box, bounds);
+}
+
+bool LayerImpl::TransformAnimationBoundsForBox(const gfx::BoxF& box,
+                                               gfx::BoxF* bounds) const {
+  if (!layer_animation_controller_)
+    return layer_tree_impl_->TransformAnimationBoundsForBox(this, box, bounds);
+
+  return layer_animation_controller_->TransformAnimationBoundsForBox(box,
+                                                                     bounds);
+}
+
 void LayerImpl::SetUpdateRect(const gfx::Rect& update_rect) {
   update_rect_ = update_rect;
   SetNeedsPushProperties();
@@ -1594,7 +1700,9 @@
 
   state->SetBoolean(
       "has_animation_bounds",
-      layer_animation_controller()->HasAnimationThatInflatesBounds());
+      layer_animation_controller_
+          ? layer_animation_controller_->HasAnimationThatInflatesBounds()
+          : layer_tree_impl_->HasAnimationThatInflatesBounds(this));
 
   gfx::BoxF box;
   if (LayerUtils::GetAnimationBounds(*this, &box))
diff --git a/cc/layers/layer_impl.h b/cc/layers/layer_impl.h
index 262dbcb..3635a3ab 100644
--- a/cc/layers/layer_impl.h
+++ b/cc/layers/layer_impl.h
@@ -300,6 +300,7 @@
   void SetOpacity(float opacity);
   float opacity() const { return opacity_; }
   bool OpacityIsAnimating() const;
+  bool HasPotentiallyRunningOpacityAnimation() const;
   bool OpacityIsAnimatingOnImplOnly() const;
 
   void SetBlendMode(SkXfermode::Mode);
@@ -535,11 +536,25 @@
   void SetTransform(const gfx::Transform& transform);
   const gfx::Transform& transform() const { return transform_; }
   bool TransformIsAnimating() const;
+  bool HasPotentiallyRunningTransformAnimation() const;
   bool TransformIsAnimatingOnImplOnly() const;
+  bool HasOnlyTranslationTransforms() const;
   void SetTransformAndInvertibility(const gfx::Transform& transform,
                                     bool transform_is_invertible);
   bool transform_is_invertible() const { return transform_is_invertible_; }
 
+  bool MaximumTargetScale(float* max_scale) const;
+  bool AnimationStartScale(float* start_scale) const;
+
+  bool HasFilterAnimationThatInflatesBounds() const;
+  bool HasTransformAnimationThatInflatesBounds() const;
+  bool HasAnimationThatInflatesBounds() const;
+
+  bool FilterAnimationBoundsForBox(const gfx::BoxF& box,
+                                   gfx::BoxF* bounds) const;
+  bool TransformAnimationBoundsForBox(const gfx::BoxF& box,
+                                      gfx::BoxF* bounds) const;
+
   // Note this rect is in layer space (not content space).
   void SetUpdateRect(const gfx::Rect& update_rect);
   gfx::Rect update_rect() const { return update_rect_; }
diff --git a/cc/layers/layer_utils.cc b/cc/layers/layer_utils.cc
index 888174a..42d0e1b 100644
--- a/cc/layers/layer_utils.cc
+++ b/cc/layers/layer_utils.cc
@@ -13,17 +13,15 @@
 namespace {
 
 bool HasAnimationThatInflatesBounds(const LayerImpl& layer) {
-  return layer.layer_animation_controller()->HasAnimationThatInflatesBounds();
+  return layer.HasAnimationThatInflatesBounds();
 }
 
 bool HasFilterAnimationThatInflatesBounds(const LayerImpl& layer) {
-  return layer.layer_animation_controller()
-      ->HasFilterAnimationThatInflatesBounds();
+  return layer.HasFilterAnimationThatInflatesBounds();
 }
 
 bool HasTransformAnimationThatInflatesBounds(const LayerImpl& layer) {
-  return layer.layer_animation_controller()
-      ->HasTransformAnimationThatInflatesBounds();
+  return layer.HasTransformAnimationThatInflatesBounds();
 }
 
 inline bool HasAncestorTransformAnimation(const LayerImpl& layer) {
@@ -112,16 +110,14 @@
     // Perform the inflation
     if (HasFilterAnimationThatInflatesBounds(*layer)) {
       gfx::BoxF inflated;
-      if (!layer->layer_animation_controller()->FilterAnimationBoundsForBox(
-              box, &inflated))
+      if (!layer->FilterAnimationBoundsForBox(box, &inflated))
         return false;
       box = inflated;
     }
 
     if (HasTransformAnimationThatInflatesBounds(*layer)) {
       gfx::BoxF inflated;
-      if (!layer->layer_animation_controller()->TransformAnimationBoundsForBox(
-              box, &inflated))
+      if (!layer->TransformAnimationBoundsForBox(box, &inflated))
         return false;
       box = inflated;
     }
diff --git a/cc/test/layer_tree_test.cc b/cc/test/layer_tree_test.cc
index d3ee22f..95e2478 100644
--- a/cc/test/layer_tree_test.cc
+++ b/cc/test/layer_tree_test.cc
@@ -9,6 +9,7 @@
 #include "base/single_thread_task_runner.h"
 #include "base/thread_task_runner_handle.h"
 #include "cc/animation/animation.h"
+#include "cc/animation/animation_host.h"
 #include "cc/animation/animation_registrar.h"
 #include "cc/animation/layer_animation_controller.h"
 #include "cc/animation/timing_function.h"
@@ -358,8 +359,11 @@
   void UpdateAnimationState(bool start_ready_animations) override {
     LayerTreeHostImpl::UpdateAnimationState(start_ready_animations);
     bool has_unfinished_animation = false;
+    AnimationRegistrar* registrar =
+        animation_registrar() ? animation_registrar()
+                              : animation_host()->animation_registrar();
     for (const auto& it :
-         animation_registrar()->active_animation_controllers_for_testing()) {
+         registrar->active_animation_controllers_for_testing()) {
       if (it.second->HasActiveAnimation()) {
         has_unfinished_animation = true;
         break;
@@ -596,6 +600,33 @@
                  1.0));
 }
 
+void LayerTreeTest::PostAddAnimationToMainThreadPlayer(
+    AnimationPlayer* player_to_receive_animation) {
+  main_task_runner_->PostTask(
+      FROM_HERE,
+      base::Bind(&LayerTreeTest::DispatchAddAnimationToPlayer,
+                 main_thread_weak_ptr_,
+                 base::Unretained(player_to_receive_animation), 0.000004));
+}
+
+void LayerTreeTest::PostAddInstantAnimationToMainThreadPlayer(
+    AnimationPlayer* player_to_receive_animation) {
+  main_task_runner_->PostTask(
+      FROM_HERE,
+      base::Bind(&LayerTreeTest::DispatchAddAnimationToPlayer,
+                 main_thread_weak_ptr_,
+                 base::Unretained(player_to_receive_animation), 0.0));
+}
+
+void LayerTreeTest::PostAddLongAnimationToMainThreadPlayer(
+    AnimationPlayer* player_to_receive_animation) {
+  main_task_runner_->PostTask(
+      FROM_HERE,
+      base::Bind(&LayerTreeTest::DispatchAddAnimationToPlayer,
+                 main_thread_weak_ptr_,
+                 base::Unretained(player_to_receive_animation), 1.0));
+}
+
 void LayerTreeTest::PostSetDeferCommitsToMainThread(bool defer_commits) {
   main_task_runner_->PostTask(
       FROM_HERE,
@@ -734,6 +765,17 @@
   }
 }
 
+void LayerTreeTest::DispatchAddAnimationToPlayer(
+    AnimationPlayer* player_to_receive_animation,
+    double animation_duration) {
+  DCHECK(!proxy() || proxy()->IsMainThread());
+
+  if (player_to_receive_animation) {
+    AddOpacityTransitionToPlayer(player_to_receive_animation,
+                                 animation_duration, 0, 0.5, true);
+  }
+}
+
 void LayerTreeTest::DispatchSetDeferCommits(bool defer_commits) {
   DCHECK(!proxy() || proxy()->IsMainThread());
 
diff --git a/cc/test/layer_tree_test.h b/cc/test/layer_tree_test.h
index 44e3915c..68d8c9a 100644
--- a/cc/test/layer_tree_test.h
+++ b/cc/test/layer_tree_test.h
@@ -13,6 +13,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace cc {
+class AnimationPlayer;
 class FakeExternalBeginFrameSource;
 class FakeLayerTreeHostClient;
 class FakeOutputSurface;
@@ -137,6 +138,12 @@
   void PostAddAnimationToMainThread(Layer* layer_to_receive_animation);
   void PostAddInstantAnimationToMainThread(Layer* layer_to_receive_animation);
   void PostAddLongAnimationToMainThread(Layer* layer_to_receive_animation);
+  void PostAddAnimationToMainThreadPlayer(
+      AnimationPlayer* player_to_receive_animation);
+  void PostAddInstantAnimationToMainThreadPlayer(
+      AnimationPlayer* player_to_receive_animation);
+  void PostAddLongAnimationToMainThreadPlayer(
+      AnimationPlayer* player_to_receive_animation);
   void PostSetDeferCommitsToMainThread(bool defer_commits);
   void PostSetNeedsCommitToMainThread();
   void PostSetNeedsUpdateLayersToMainThread();
@@ -166,6 +173,9 @@
 
   virtual void DispatchAddAnimation(Layer* layer_to_receive_animation,
                                     double animation_duration);
+  virtual void DispatchAddAnimationToPlayer(
+      AnimationPlayer* player_to_receive_animation,
+      double animation_duration);
   void DispatchSetDeferCommits(bool defer_commits);
   void DispatchSetNeedsCommit();
   void DispatchSetNeedsUpdateLayers();
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc
index 79e6b24..62d730b5 100644
--- a/cc/trees/layer_tree_host.cc
+++ b/cc/trees/layer_tree_host.cc
@@ -121,15 +121,18 @@
       surface_id_namespace_(0u),
       next_surface_sequence_(1u) {
   DCHECK(task_graph_runner_);
-  if (settings_.accelerated_animation_enabled)
-    animation_registrar_ = AnimationRegistrar::Create();
+
+  if (settings_.accelerated_animation_enabled) {
+    if (settings_.use_compositor_animation_timelines) {
+      animation_host_ = AnimationHost::Create(ThreadInstance::MAIN);
+      animation_host_->SetMutatorHostClient(this);
+    } else {
+      animation_registrar_ = AnimationRegistrar::Create();
+    }
+  }
+
   rendering_stats_instrumentation_->set_record_rendering_stats(
       debug_state_.RecordRenderingStats());
-
-  if (settings_.use_compositor_animation_timelines) {
-    animation_host_ = AnimationHost::Create(ThreadInstance::MAIN);
-    animation_host_->SetMutatorHostClient(this);
-  }
 }
 
 void LayerTreeHost::InitializeThreaded(
@@ -163,8 +166,12 @@
   proxy_ = proxy.Pass();
   proxy_->Start();
   if (settings_.accelerated_animation_enabled) {
-    animation_registrar_->set_supports_scroll_animations(
-        proxy_->SupportsImplScrolling());
+    if (animation_host_)
+      animation_host_->SetSupportsScrollAnimations(
+          proxy_->SupportsImplScrolling());
+    else
+      animation_registrar_->set_supports_scroll_animations(
+          proxy_->SupportsImplScrolling());
   }
 }
 
@@ -513,7 +520,10 @@
 void LayerTreeHost::SetAnimationEvents(
     scoped_ptr<AnimationEventsVector> events) {
   DCHECK(proxy_->IsMainThread());
-  animation_registrar_->SetAnimationEvents(events.Pass());
+  if (animation_host_)
+    animation_host_->SetAnimationEvents(events.Pass());
+  else
+    animation_registrar_->SetAnimationEvents(events.Pass());
 }
 
 void LayerTreeHost::SetRootLayer(scoped_refptr<Layer> root_layer) {
@@ -921,11 +931,16 @@
     return;
 
   AnimationEventsVector events;
-  if (animation_registrar_->AnimateLayers(monotonic_time)) {
-    animation_registrar_->UpdateAnimationState(true, &events);
-    if (!events.empty())
-      property_trees_.needs_rebuild = true;
+  if (animation_host_) {
+    if (animation_host_->AnimateLayers(monotonic_time))
+      animation_host_->UpdateAnimationState(true, &events);
+  } else {
+    if (animation_registrar_->AnimateLayers(monotonic_time))
+      animation_registrar_->UpdateAnimationState(true, &events);
   }
+
+  if (!events.empty())
+    property_trees_.needs_rebuild = true;
 }
 
 UIResourceId LayerTreeHost::CreateUIResource(UIResourceClient* client) {
@@ -1134,4 +1149,61 @@
   layer->OnScrollOffsetAnimated(scroll_offset);
 }
 
+bool LayerTreeHost::ScrollOffsetAnimationWasInterrupted(
+    const Layer* layer) const {
+  return animation_host_
+             ? animation_host_->ScrollOffsetAnimationWasInterrupted(layer->id())
+             : false;
+}
+
+bool LayerTreeHost::IsAnimatingFilterProperty(const Layer* layer) const {
+  return animation_host_
+             ? animation_host_->IsAnimatingFilterProperty(layer->id())
+             : false;
+}
+
+bool LayerTreeHost::IsAnimatingOpacityProperty(const Layer* layer) const {
+  return animation_host_
+             ? animation_host_->IsAnimatingOpacityProperty(layer->id())
+             : false;
+}
+
+bool LayerTreeHost::IsAnimatingTransformProperty(const Layer* layer) const {
+  return animation_host_
+             ? animation_host_->IsAnimatingTransformProperty(layer->id())
+             : false;
+}
+
+bool LayerTreeHost::HasPotentiallyRunningOpacityAnimation(
+    const Layer* layer) const {
+  return animation_host_
+             ? animation_host_->HasPotentiallyRunningOpacityAnimation(
+                   layer->id())
+             : false;
+}
+
+bool LayerTreeHost::HasPotentiallyRunningTransformAnimation(
+    const Layer* layer) const {
+  return animation_host_
+             ? animation_host_->HasPotentiallyRunningTransformAnimation(
+                   layer->id())
+             : false;
+}
+
+bool LayerTreeHost::AnimationsPreserveAxisAlignment(const Layer* layer) const {
+  return animation_host_
+             ? animation_host_->AnimationsPreserveAxisAlignment(layer->id())
+             : true;
+}
+
+bool LayerTreeHost::HasAnyAnimation(const Layer* layer) const {
+  return animation_host_ ? animation_host_->HasAnyAnimation(layer->id())
+                         : false;
+}
+
+bool LayerTreeHost::HasActiveAnimation(const Layer* layer) const {
+  return animation_host_ ? animation_host_->HasActiveAnimation(layer->id())
+                         : false;
+}
+
 }  // namespace cc
diff --git a/cc/trees/layer_tree_host.h b/cc/trees/layer_tree_host.h
index d18d7dab..8a6f270b 100644
--- a/cc/trees/layer_tree_host.h
+++ b/cc/trees/layer_tree_host.h
@@ -256,7 +256,6 @@
   HeadsUpDisplayLayer* hud_layer() const { return hud_layer_.get(); }
 
   Proxy* proxy() const { return proxy_.get(); }
-
   AnimationRegistrar* animation_registrar() const {
     return animation_registrar_.get();
   }
@@ -341,6 +340,16 @@
       LayerTreeType tree_type,
       const gfx::ScrollOffset& scroll_offset) override;
 
+  bool ScrollOffsetAnimationWasInterrupted(const Layer* layer) const;
+  bool IsAnimatingFilterProperty(const Layer* layer) const;
+  bool IsAnimatingOpacityProperty(const Layer* layer) const;
+  bool IsAnimatingTransformProperty(const Layer* layer) const;
+  bool HasPotentiallyRunningOpacityAnimation(const Layer* layer) const;
+  bool HasPotentiallyRunningTransformAnimation(const Layer* layer) const;
+  bool AnimationsPreserveAxisAlignment(const Layer* layer) const;
+  bool HasAnyAnimation(const Layer* layer) const;
+  bool HasActiveAnimation(const Layer* layer) const;
+
  protected:
   explicit LayerTreeHost(InitParams* params);
   void InitializeThreaded(
diff --git a/cc/trees/layer_tree_host_common.cc b/cc/trees/layer_tree_host_common.cc
index 8e80a727..ffd16907d 100644
--- a/cc/trees/layer_tree_host_common.cc
+++ b/cc/trees/layer_tree_host_common.cc
@@ -964,8 +964,7 @@
   // scales and translations. We treat all non-translations as potentially
   // affecting scale. Animations that include non-translation/scale components
   // will cause the computation of MaximumScale below to fail.
-  bool layer_is_animating_scale =
-      !layer->layer_animation_controller()->HasOnlyTranslationTransforms();
+  bool layer_is_animating_scale = !layer->HasOnlyTranslationTransforms();
 
   if (!layer_is_animating_scale && !ancestor_is_animating_scale) {
     *combined_maximum_animation_contents_scale = 0.f;
@@ -1002,13 +1001,11 @@
 
   float layer_maximum_animated_scale = 0.f;
   float layer_start_animated_scale = 0.f;
-  if (!layer->layer_animation_controller()->MaximumTargetScale(
-          &layer_maximum_animated_scale)) {
+  if (!layer->MaximumTargetScale(&layer_maximum_animated_scale)) {
     *combined_maximum_animation_contents_scale = 0.f;
     return;
   }
-  if (!layer->layer_animation_controller()->AnimationStartScale(
-          &layer_start_animated_scale)) {
+  if (!layer->AnimationStartScale(&layer_start_animated_scale)) {
     *combined_starting_animation_contents_scale = 0.f;
     return;
   }
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index 4533bab..d403004 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -230,7 +230,7 @@
       max_memory_needed_bytes_(0),
       device_scale_factor_(1.f),
       resourceless_software_draw_(false),
-      animation_registrar_(AnimationRegistrar::Create()),
+      animation_registrar_(),
       rendering_stats_instrumentation_(rendering_stats_instrumentation),
       micro_benchmark_controller_(this),
       shared_bitmap_manager_(shared_bitmap_manager),
@@ -241,16 +241,22 @@
       is_likely_to_require_a_draw_(false),
       frame_timing_tracker_(FrameTimingTracker::Create(this)) {
   if (settings.use_compositor_animation_timelines) {
-    animation_host_ = AnimationHost::Create(ThreadInstance::IMPL);
-    animation_host_->SetMutatorHostClient(this);
+    if (settings.accelerated_animation_enabled) {
+      animation_host_ = AnimationHost::Create(ThreadInstance::IMPL);
+      animation_host_->SetMutatorHostClient(this);
+      animation_host_->SetSupportsScrollAnimations(
+          proxy_->SupportsImplScrolling());
+    }
+  } else {
+    animation_registrar_ = AnimationRegistrar::Create();
+    animation_registrar_->set_supports_scroll_animations(
+        proxy_->SupportsImplScrolling());
   }
 
   DCHECK(proxy_->IsImplThread());
   DCHECK_IMPLIES(settings.use_one_copy, !settings.use_zero_copy);
   DCHECK_IMPLIES(settings.use_zero_copy, !settings.use_one_copy);
   DidVisibilityChange(this, visible_);
-  animation_registrar_->set_supports_scroll_animations(
-      proxy_->SupportsImplScrolling());
 
   SetDebugState(settings.initial_debug_state);
 
@@ -294,6 +300,12 @@
   recycle_tree_ = nullptr;
   pending_tree_ = nullptr;
   active_tree_ = nullptr;
+
+  if (animation_host_) {
+    animation_host_->ClearTimelines();
+    animation_host_->SetMutatorHostClient(nullptr);
+  }
+
   DestroyTileManager();
 }
 
@@ -1563,7 +1575,9 @@
 
   if (draw_mode == DRAW_MODE_RESOURCELESS_SOFTWARE) {
     bool disable_picture_quad_image_filtering =
-        IsActivelyScrolling() || animation_registrar_->needs_animate_layers();
+        IsActivelyScrolling() ||
+        (animation_host_ ? animation_host_->NeedsAnimateLayers()
+                         : animation_registrar_->needs_animate_layers());
 
     scoped_ptr<SoftwareRenderer> temp_software_renderer =
         SoftwareRenderer::Create(this, &settings_.renderer_settings,
@@ -3103,18 +3117,31 @@
   if (!settings_.accelerated_animation_enabled || !active_tree_->root_layer())
     return;
 
-  if (animation_registrar_->AnimateLayers(monotonic_time))
-    SetNeedsAnimate();
+  if (animation_host_) {
+    if (animation_host_->AnimateLayers(monotonic_time))
+      SetNeedsAnimate();
+  } else {
+    if (animation_registrar_->AnimateLayers(monotonic_time))
+      SetNeedsAnimate();
+  }
 }
 
 void LayerTreeHostImpl::UpdateAnimationState(bool start_ready_animations) {
   if (!settings_.accelerated_animation_enabled || !active_tree_->root_layer())
     return;
 
-  scoped_ptr<AnimationEventsVector> events =
-      animation_registrar_->CreateEvents();
-  const bool has_active_animations = animation_registrar_->UpdateAnimationState(
-      start_ready_animations, events.get());
+  bool has_active_animations = false;
+  scoped_ptr<AnimationEventsVector> events;
+
+  if (animation_host_) {
+    events = animation_host_->CreateEvents();
+    has_active_animations = animation_host_->UpdateAnimationState(
+        start_ready_animations, events.get());
+  } else {
+    events = animation_registrar_->CreateEvents();
+    has_active_animations = animation_registrar_->UpdateAnimationState(
+        start_ready_animations, events.get());
+  }
 
   if (!events->empty())
     client_->PostAnimationEventsToMainThreadOnImplThread(events.Pass());
@@ -3127,8 +3154,13 @@
   if (!settings_.accelerated_animation_enabled || !active_tree_->root_layer())
     return;
 
-  if (animation_registrar_->ActivateAnimations())
-    SetNeedsAnimate();
+  if (animation_host_) {
+    if (animation_host_->ActivateAnimations())
+      SetNeedsAnimate();
+  } else {
+    if (animation_registrar_->ActivateAnimations())
+      SetNeedsAnimate();
+  }
 }
 
 std::string LayerTreeHostImpl::LayerTreeAsJson() const {
diff --git a/cc/trees/layer_tree_host_unittest_animation_timelines.cc b/cc/trees/layer_tree_host_unittest_animation_timelines.cc
new file mode 100644
index 0000000..c8513744
--- /dev/null
+++ b/cc/trees/layer_tree_host_unittest_animation_timelines.cc
@@ -0,0 +1,745 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/trees/layer_tree_host.h"
+
+#include "cc/animation/animation_curve.h"
+#include "cc/animation/animation_host.h"
+#include "cc/animation/animation_id_provider.h"
+#include "cc/animation/animation_player.h"
+#include "cc/animation/animation_timeline.h"
+#include "cc/animation/element_animations.h"
+#include "cc/animation/layer_animation_controller.h"
+#include "cc/animation/scroll_offset_animation_curve.h"
+#include "cc/animation/timing_function.h"
+#include "cc/base/time_util.h"
+#include "cc/layers/layer.h"
+#include "cc/layers/layer_impl.h"
+#include "cc/test/animation_test_common.h"
+#include "cc/test/fake_content_layer_client.h"
+#include "cc/test/fake_picture_layer.h"
+#include "cc/test/layer_tree_test.h"
+#include "cc/trees/layer_tree_impl.h"
+
+namespace cc {
+namespace {
+
+class LayerTreeHostTimelinesTest : public LayerTreeTest {
+ public:
+  LayerTreeHostTimelinesTest()
+      : timeline_id_(AnimationIdProvider::NextTimelineId()),
+        player_id_(AnimationIdProvider::NextPlayerId()),
+        player_child_id_(AnimationIdProvider::NextPlayerId()) {
+    timeline_ = AnimationTimeline::Create(timeline_id_);
+    player_ = AnimationPlayer::Create(player_id_);
+    player_child_ = AnimationPlayer::Create(player_child_id_);
+
+    player_->set_layer_animation_delegate(this);
+  }
+
+  void InitializeSettings(LayerTreeSettings* settings) override {
+    settings->use_compositor_animation_timelines = true;
+  }
+
+  void InitializeLayerSettings(LayerSettings* layer_settings) override {
+    layer_settings->use_compositor_animation_timelines = true;
+  }
+
+  void SetupTree() override { LayerTreeTest::SetupTree(); }
+
+  void AttachPlayersToTimeline() {
+    layer_tree_host()->animation_host()->AddAnimationTimeline(timeline_.get());
+    timeline_->AttachPlayer(player_.get());
+    timeline_->AttachPlayer(player_child_.get());
+  }
+
+ protected:
+  scoped_refptr<AnimationTimeline> timeline_;
+  scoped_refptr<AnimationPlayer> player_;
+  scoped_refptr<AnimationPlayer> player_child_;
+
+  const int timeline_id_;
+  const int player_id_;
+  const int player_child_id_;
+};
+
+// Add a layer animation and confirm that
+// LayerTreeHostImpl::UpdateAnimationState does get called.
+// Evolved frome LayerTreeHostAnimationTestAddAnimation
+class LayerTreeHostTimelinesTestAddAnimation
+    : public LayerTreeHostTimelinesTest {
+ public:
+  LayerTreeHostTimelinesTestAddAnimation()
+      : update_animation_state_was_called_(false) {}
+
+  void BeginTest() override {
+    AttachPlayersToTimeline();
+    player_->AttachLayer(layer_tree_host()->root_layer()->id());
+    PostAddInstantAnimationToMainThreadPlayer(player_.get());
+  }
+
+  void UpdateAnimationState(LayerTreeHostImpl* host_impl,
+                            bool has_unfinished_animation) override {
+    EXPECT_FALSE(has_unfinished_animation);
+    update_animation_state_was_called_ = true;
+  }
+
+  void NotifyAnimationStarted(base::TimeTicks monotonic_time,
+                              Animation::TargetProperty target_property,
+                              int group) override {
+    EXPECT_LT(base::TimeTicks(), monotonic_time);
+
+    LayerAnimationController* controller =
+        player_->element_animations()->layer_animation_controller();
+    Animation* animation = controller->GetAnimation(Animation::OPACITY);
+    if (animation)
+      player_->RemoveAnimation(animation->id());
+
+    EndTest();
+  }
+
+  void AfterTest() override { EXPECT_TRUE(update_animation_state_was_called_); }
+
+ private:
+  bool update_animation_state_was_called_;
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTimelinesTestAddAnimation);
+
+// Add a layer animation to a layer, but continually fail to draw. Confirm that
+// after a while, we do eventually force a draw.
+// Evolved from LayerTreeHostAnimationTestCheckerboardDoesNotStarveDraws.
+class LayerTreeHostTimelinesTestCheckerboardDoesNotStarveDraws
+    : public LayerTreeHostTimelinesTest {
+ public:
+  LayerTreeHostTimelinesTestCheckerboardDoesNotStarveDraws()
+      : started_animating_(false) {}
+
+  void BeginTest() override {
+    AttachPlayersToTimeline();
+    player_->AttachLayer(layer_tree_host()->root_layer()->id());
+    PostAddAnimationToMainThreadPlayer(player_.get());
+  }
+
+  void AnimateLayers(LayerTreeHostImpl* host_impl,
+                     base::TimeTicks monotonic_time) override {
+    started_animating_ = true;
+  }
+
+  void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override {
+    if (started_animating_)
+      EndTest();
+  }
+
+  DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
+                                   LayerTreeHostImpl::FrameData* frame,
+                                   DrawResult draw_result) override {
+    return DRAW_ABORTED_CHECKERBOARD_ANIMATIONS;
+  }
+
+  void AfterTest() override {}
+
+ private:
+  bool started_animating_;
+};
+
+// Starvation can only be an issue with the MT compositor.
+MULTI_THREAD_TEST_F(LayerTreeHostTimelinesTestCheckerboardDoesNotStarveDraws);
+
+// Ensures that animations eventually get deleted.
+// Evolved from LayerTreeHostAnimationTestAnimationsGetDeleted.
+class LayerTreeHostTimelinesTestAnimationsGetDeleted
+    : public LayerTreeHostTimelinesTest {
+ public:
+  LayerTreeHostTimelinesTestAnimationsGetDeleted()
+      : started_animating_(false) {}
+
+  void BeginTest() override {
+    AttachPlayersToTimeline();
+    player_->AttachLayer(layer_tree_host()->root_layer()->id());
+    PostAddAnimationToMainThreadPlayer(player_.get());
+  }
+
+  void AnimateLayers(LayerTreeHostImpl* host_impl,
+                     base::TimeTicks monotonic_time) override {
+    bool have_animations = !host_impl->animation_host()
+                                ->animation_registrar()
+                                ->active_animation_controllers_for_testing()
+                                .empty();
+    if (!started_animating_ && have_animations) {
+      started_animating_ = true;
+      return;
+    }
+
+    if (started_animating_ && !have_animations)
+      EndTest();
+  }
+
+  void NotifyAnimationFinished(base::TimeTicks monotonic_time,
+                               Animation::TargetProperty target_property,
+                               int group) override {
+    // Animations on the impl-side controller only get deleted during a commit,
+    // so we need to schedule a commit.
+    layer_tree_host()->SetNeedsCommit();
+  }
+
+  void AfterTest() override {}
+
+ private:
+  bool started_animating_;
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTimelinesTestAnimationsGetDeleted);
+
+// Ensure that an animation's timing function is respected.
+// Evolved from LayerTreeHostAnimationTestAddAnimationWithTimingFunction.
+class LayerTreeHostTimelinesTestAddAnimationWithTimingFunction
+    : public LayerTreeHostTimelinesTest {
+ public:
+  LayerTreeHostTimelinesTestAddAnimationWithTimingFunction() {}
+
+  void SetupTree() override {
+    LayerTreeHostTimelinesTest::SetupTree();
+    picture_ = FakePictureLayer::Create(layer_settings(), &client_);
+    picture_->SetBounds(gfx::Size(4, 4));
+    layer_tree_host()->root_layer()->AddChild(picture_);
+
+    AttachPlayersToTimeline();
+    player_child_->AttachLayer(picture_->id());
+  }
+
+  void BeginTest() override {
+    PostAddAnimationToMainThreadPlayer(player_child_.get());
+  }
+
+  void AnimateLayers(LayerTreeHostImpl* host_impl,
+                     base::TimeTicks monotonic_time) override {
+    scoped_refptr<AnimationTimeline> timeline_impl =
+        host_impl->animation_host()->GetTimelineById(timeline_id_);
+    scoped_refptr<AnimationPlayer> player_child_impl =
+        timeline_impl->GetPlayerById(player_child_id_);
+
+    LayerAnimationController* controller_impl =
+        player_child_impl->element_animations()->layer_animation_controller();
+    if (!controller_impl)
+      return;
+
+    Animation* animation = controller_impl->GetAnimation(Animation::OPACITY);
+    if (!animation)
+      return;
+
+    const FloatAnimationCurve* curve =
+        animation->curve()->ToFloatAnimationCurve();
+    float start_opacity = curve->GetValue(base::TimeDelta());
+    float end_opacity = curve->GetValue(curve->Duration());
+    float linearly_interpolated_opacity =
+        0.25f * end_opacity + 0.75f * start_opacity;
+    base::TimeDelta time = TimeUtil::Scale(curve->Duration(), 0.25f);
+    // If the linear timing function associated with this animation was not
+    // picked up, then the linearly interpolated opacity would be different
+    // because of the default ease timing function.
+    EXPECT_FLOAT_EQ(linearly_interpolated_opacity, curve->GetValue(time));
+
+    EndTest();
+  }
+
+  void AfterTest() override {}
+
+  FakeContentLayerClient client_;
+  scoped_refptr<FakePictureLayer> picture_;
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(
+    LayerTreeHostTimelinesTestAddAnimationWithTimingFunction);
+
+// Ensures that main thread animations have their start times synchronized with
+// impl thread animations.
+// Evolved from LayerTreeHostAnimationTestSynchronizeAnimationStartTimes.
+class LayerTreeHostTimelinesTestSynchronizeAnimationStartTimes
+    : public LayerTreeHostTimelinesTest {
+ public:
+  LayerTreeHostTimelinesTestSynchronizeAnimationStartTimes() {}
+
+  void SetupTree() override {
+    LayerTreeHostTimelinesTest::SetupTree();
+    picture_ = FakePictureLayer::Create(layer_settings(), &client_);
+    picture_->SetBounds(gfx::Size(4, 4));
+
+    layer_tree_host()->root_layer()->AddChild(picture_);
+
+    AttachPlayersToTimeline();
+    player_child_->set_layer_animation_delegate(this);
+    player_child_->AttachLayer(picture_->id());
+  }
+
+  void BeginTest() override {
+    PostAddAnimationToMainThreadPlayer(player_child_.get());
+  }
+
+  void NotifyAnimationStarted(base::TimeTicks monotonic_time,
+                              Animation::TargetProperty target_property,
+                              int group) override {
+    LayerAnimationController* controller =
+        player_child_->element_animations()->layer_animation_controller();
+    Animation* animation = controller->GetAnimation(Animation::OPACITY);
+    main_start_time_ = animation->start_time();
+    controller->RemoveAnimation(animation->id());
+    EndTest();
+  }
+
+  void UpdateAnimationState(LayerTreeHostImpl* impl_host,
+                            bool has_unfinished_animation) override {
+    scoped_refptr<AnimationTimeline> timeline_impl =
+        impl_host->animation_host()->GetTimelineById(timeline_id_);
+    scoped_refptr<AnimationPlayer> player_child_impl =
+        timeline_impl->GetPlayerById(player_child_id_);
+
+    LayerAnimationController* controller =
+        player_child_impl->element_animations()->layer_animation_controller();
+    Animation* animation = controller->GetAnimation(Animation::OPACITY);
+    if (!animation)
+      return;
+
+    impl_start_time_ = animation->start_time();
+  }
+
+  void AfterTest() override {
+    EXPECT_EQ(impl_start_time_, main_start_time_);
+    EXPECT_LT(base::TimeTicks(), impl_start_time_);
+  }
+
+ private:
+  base::TimeTicks main_start_time_;
+  base::TimeTicks impl_start_time_;
+  FakeContentLayerClient client_;
+  scoped_refptr<FakePictureLayer> picture_;
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(
+    LayerTreeHostTimelinesTestSynchronizeAnimationStartTimes);
+
+// Ensures that notify animation finished is called.
+// Evolved from LayerTreeHostAnimationTestAnimationFinishedEvents.
+class LayerTreeHostTimelinesTestAnimationFinishedEvents
+    : public LayerTreeHostTimelinesTest {
+ public:
+  LayerTreeHostTimelinesTestAnimationFinishedEvents() {}
+
+  void BeginTest() override {
+    AttachPlayersToTimeline();
+    player_->AttachLayer(layer_tree_host()->root_layer()->id());
+    PostAddInstantAnimationToMainThreadPlayer(player_.get());
+  }
+
+  void NotifyAnimationFinished(base::TimeTicks monotonic_time,
+                               Animation::TargetProperty target_property,
+                               int group) override {
+    LayerAnimationController* controller =
+        player_->element_animations()->layer_animation_controller();
+    Animation* animation = controller->GetAnimation(Animation::OPACITY);
+    if (animation)
+      controller->RemoveAnimation(animation->id());
+    EndTest();
+  }
+
+  void AfterTest() override {}
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(
+    LayerTreeHostTimelinesTestAnimationFinishedEvents);
+
+// Ensures that when opacity is being animated, this value does not cause the
+// subtree to be skipped.
+// Evolved from LayerTreeHostAnimationTestDoNotSkipLayersWithAnimatedOpacity.
+class LayerTreeHostTimelinesTestDoNotSkipLayersWithAnimatedOpacity
+    : public LayerTreeHostTimelinesTest {
+ public:
+  LayerTreeHostTimelinesTestDoNotSkipLayersWithAnimatedOpacity()
+      : update_check_layer_(
+            FakePictureLayer::Create(layer_settings(), &client_)) {}
+
+  void SetupTree() override {
+    update_check_layer_->SetOpacity(0.f);
+    layer_tree_host()->SetRootLayer(update_check_layer_);
+    LayerTreeHostTimelinesTest::SetupTree();
+
+    AttachPlayersToTimeline();
+    player_->AttachLayer(update_check_layer_->id());
+  }
+
+  void BeginTest() override {
+    PostAddAnimationToMainThreadPlayer(player_.get());
+  }
+
+  void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override {
+    scoped_refptr<AnimationTimeline> timeline_impl =
+        host_impl->animation_host()->GetTimelineById(timeline_id_);
+    scoped_refptr<AnimationPlayer> player_impl =
+        timeline_impl->GetPlayerById(player_id_);
+
+    LayerAnimationController* controller_impl =
+        player_impl->element_animations()->layer_animation_controller();
+    Animation* animation_impl =
+        controller_impl->GetAnimation(Animation::OPACITY);
+    controller_impl->RemoveAnimation(animation_impl->id());
+    EndTest();
+  }
+
+  void AfterTest() override {
+    // Update() should have been called once, proving that the layer was not
+    // skipped.
+    EXPECT_EQ(1, update_check_layer_->update_count());
+
+    // clear update_check_layer_ so LayerTreeHost dies.
+    update_check_layer_ = NULL;
+  }
+
+ private:
+  FakeContentLayerClient client_;
+  scoped_refptr<FakePictureLayer> update_check_layer_;
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(
+    LayerTreeHostTimelinesTestDoNotSkipLayersWithAnimatedOpacity);
+
+// Layers added to tree with existing active animations should have the
+// animation correctly recognized.
+// Evolved from LayerTreeHostAnimationTestLayerAddedWithAnimation.
+class LayerTreeHostTimelinesTestLayerAddedWithAnimation
+    : public LayerTreeHostTimelinesTest {
+ public:
+  LayerTreeHostTimelinesTestLayerAddedWithAnimation() {}
+
+  void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+
+  void DidCommit() override {
+    if (layer_tree_host()->source_frame_number() == 1) {
+      AttachPlayersToTimeline();
+
+      scoped_refptr<Layer> layer = Layer::Create(layer_settings());
+      player_->AttachLayer(layer->id());
+      player_->set_layer_animation_delegate(this);
+
+      // Any valid AnimationCurve will do here.
+      scoped_ptr<AnimationCurve> curve(new FakeFloatAnimationCurve());
+      scoped_ptr<Animation> animation(
+          Animation::Create(curve.Pass(), 1, 1, Animation::OPACITY));
+      player_->AddAnimation(animation.Pass());
+
+      // We add the animation *before* attaching the layer to the tree.
+      layer_tree_host()->root_layer()->AddChild(layer);
+    }
+  }
+
+  void AnimateLayers(LayerTreeHostImpl* impl_host,
+                     base::TimeTicks monotonic_time) override {
+    EndTest();
+  }
+
+  void AfterTest() override {}
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(
+    LayerTreeHostTimelinesTestLayerAddedWithAnimation);
+
+// Make sure the main thread can still execute animations when CanDraw() is not
+// true.
+// Evolved from LayerTreeHostAnimationTestRunAnimationWhenNotCanDraw
+class LayerTreeHostTimelinesTestRunAnimationWhenNotCanDraw
+    : public LayerTreeHostTimelinesTest {
+ public:
+  LayerTreeHostTimelinesTestRunAnimationWhenNotCanDraw() : started_times_(0) {}
+
+  void SetupTree() override {
+    LayerTreeHostTimelinesTest::SetupTree();
+    picture_ = FakePictureLayer::Create(layer_settings(), &client_);
+    picture_->SetBounds(gfx::Size(4, 4));
+    layer_tree_host()->root_layer()->AddChild(picture_);
+
+    AttachPlayersToTimeline();
+    player_child_->AttachLayer(picture_->id());
+    player_child_->set_layer_animation_delegate(this);
+  }
+
+  void BeginTest() override {
+    layer_tree_host()->SetViewportSize(gfx::Size());
+    PostAddAnimationToMainThreadPlayer(player_child_.get());
+  }
+
+  void NotifyAnimationStarted(base::TimeTicks monotonic_time,
+                              Animation::TargetProperty target_property,
+                              int group) override {
+    started_times_++;
+  }
+
+  void NotifyAnimationFinished(base::TimeTicks monotonic_time,
+                               Animation::TargetProperty target_property,
+                               int group) override {
+    EndTest();
+  }
+
+  void AfterTest() override { EXPECT_EQ(1, started_times_); }
+
+ private:
+  int started_times_;
+  FakeContentLayerClient client_;
+  scoped_refptr<FakePictureLayer> picture_;
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(
+    LayerTreeHostTimelinesTestRunAnimationWhenNotCanDraw);
+
+// Animations should not be started when frames are being skipped due to
+// checkerboard.
+// Evolved from LayerTreeHostAnimationTestCheckerboardDoesntStartAnimations.
+class LayerTreeHostTimelinesTestCheckerboardDoesntStartAnimations
+    : public LayerTreeHostTimelinesTest {
+  void SetupTree() override {
+    LayerTreeHostTimelinesTest::SetupTree();
+    picture_ = FakePictureLayer::Create(layer_settings(), &client_);
+    picture_->SetBounds(gfx::Size(4, 4));
+    layer_tree_host()->root_layer()->AddChild(picture_);
+
+    AttachPlayersToTimeline();
+    player_child_->AttachLayer(picture_->id());
+    player_child_->set_layer_animation_delegate(this);
+  }
+
+  void InitializeSettings(LayerTreeSettings* settings) override {
+    // Make sure that drawing many times doesn't cause a checkerboarded
+    // animation to start so we avoid flake in this test.
+    settings->timeout_and_draw_when_animation_checkerboards = false;
+    LayerTreeHostTimelinesTest::InitializeSettings(settings);
+  }
+
+  void BeginTest() override {
+    prevented_draw_ = 0;
+    added_animations_ = 0;
+    started_times_ = 0;
+
+    PostSetNeedsCommitToMainThread();
+  }
+
+  DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
+                                   LayerTreeHostImpl::FrameData* frame_data,
+                                   DrawResult draw_result) override {
+    if (added_animations_ < 2)
+      return draw_result;
+    if (TestEnded())
+      return draw_result;
+    // Act like there is checkerboard when the second animation wants to draw.
+    ++prevented_draw_;
+    if (prevented_draw_ > 2)
+      EndTest();
+    return DRAW_ABORTED_CHECKERBOARD_ANIMATIONS;
+  }
+
+  void DidCommitAndDrawFrame() override {
+    switch (layer_tree_host()->source_frame_number()) {
+      case 1:
+        // The animation is longer than 1 BeginFrame interval.
+        AddOpacityTransitionToPlayer(player_child_.get(), 0.1, 0.2f, 0.8f,
+                                     false);
+        added_animations_++;
+        break;
+      case 2:
+        // This second animation will not be drawn so it should not start.
+        AddAnimatedTransformToPlayer(player_child_.get(), 0.1, 5, 5);
+        added_animations_++;
+        break;
+    }
+  }
+
+  void NotifyAnimationStarted(base::TimeTicks monotonic_time,
+                              Animation::TargetProperty target_property,
+                              int group) override {
+    if (TestEnded())
+      return;
+    started_times_++;
+  }
+
+  void AfterTest() override {
+    // Make sure we tried to draw the second animation but failed.
+    EXPECT_LT(0, prevented_draw_);
+    // The first animation should be started, but the second should not because
+    // of checkerboard.
+    EXPECT_EQ(1, started_times_);
+  }
+
+  int prevented_draw_;
+  int added_animations_;
+  int started_times_;
+  FakeContentLayerClient client_;
+  scoped_refptr<FakePictureLayer> picture_;
+};
+
+MULTI_THREAD_TEST_F(
+    LayerTreeHostTimelinesTestCheckerboardDoesntStartAnimations);
+
+// When animations are simultaneously added to an existing layer and to a new
+// layer, they should start at the same time, even when there's already a
+// running animation on the existing layer.
+// Evolved from LayerTreeHostAnimationTestAnimationsAddedToNewAndExistingLayers.
+class LayerTreeHostTimelinesTestAnimationsAddedToNewAndExistingLayers
+    : public LayerTreeHostTimelinesTest {
+ public:
+  LayerTreeHostTimelinesTestAnimationsAddedToNewAndExistingLayers()
+      : frame_count_with_pending_tree_(0) {}
+
+  void BeginTest() override {
+    AttachPlayersToTimeline();
+    PostSetNeedsCommitToMainThread();
+  }
+
+  void DidCommit() override {
+    if (layer_tree_host()->source_frame_number() == 1) {
+      player_->AttachLayer(layer_tree_host()->root_layer()->id());
+      AddAnimatedTransformToPlayer(player_.get(), 4, 1, 1);
+    } else if (layer_tree_host()->source_frame_number() == 2) {
+      AddOpacityTransitionToPlayer(player_.get(), 1, 0.f, 0.5f, true);
+
+      scoped_refptr<Layer> layer = Layer::Create(layer_settings());
+      layer_tree_host()->root_layer()->AddChild(layer);
+      layer->SetBounds(gfx::Size(4, 4));
+
+      player_child_->AttachLayer(layer->id());
+      player_child_->set_layer_animation_delegate(this);
+      AddOpacityTransitionToPlayer(player_child_.get(), 1, 0.f, 0.5f, true);
+    }
+  }
+
+  void BeginCommitOnThread(LayerTreeHostImpl* host_impl) override {
+    host_impl->BlockNotifyReadyToActivateForTesting(true);
+  }
+
+  void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override {
+    // For the commit that added animations to new and existing layers, keep
+    // blocking activation. We want to verify that even with activation blocked,
+    // the animation on the layer that's already in the active tree won't get a
+    // head start.
+    if (host_impl->pending_tree()->source_frame_number() != 2) {
+      host_impl->BlockNotifyReadyToActivateForTesting(false);
+    }
+  }
+
+  void WillBeginImplFrameOnThread(LayerTreeHostImpl* host_impl,
+                                  const BeginFrameArgs& args) override {
+    if (!host_impl->pending_tree() ||
+        host_impl->pending_tree()->source_frame_number() != 2)
+      return;
+
+    frame_count_with_pending_tree_++;
+    if (frame_count_with_pending_tree_ == 2) {
+      host_impl->BlockNotifyReadyToActivateForTesting(false);
+    }
+  }
+
+  void UpdateAnimationState(LayerTreeHostImpl* host_impl,
+                            bool has_unfinished_animation) override {
+    scoped_refptr<AnimationTimeline> timeline_impl =
+        host_impl->animation_host()->GetTimelineById(timeline_id_);
+    scoped_refptr<AnimationPlayer> player_impl =
+        timeline_impl->GetPlayerById(player_id_);
+    scoped_refptr<AnimationPlayer> player_child_impl =
+        timeline_impl->GetPlayerById(player_child_id_);
+
+    // wait for tree activation.
+    if (!player_impl->element_animations())
+      return;
+
+    LayerAnimationController* root_controller_impl =
+        player_impl->element_animations()->layer_animation_controller();
+    Animation* root_animation =
+        root_controller_impl->GetAnimation(Animation::OPACITY);
+    if (!root_animation || root_animation->run_state() != Animation::RUNNING)
+      return;
+
+    LayerAnimationController* child_controller_impl =
+        player_child_impl->element_animations()->layer_animation_controller();
+    Animation* child_animation =
+        child_controller_impl->GetAnimation(Animation::OPACITY);
+    EXPECT_EQ(Animation::RUNNING, child_animation->run_state());
+    EXPECT_EQ(root_animation->start_time(), child_animation->start_time());
+    root_controller_impl->AbortAnimations(Animation::OPACITY);
+    root_controller_impl->AbortAnimations(Animation::TRANSFORM);
+    child_controller_impl->AbortAnimations(Animation::OPACITY);
+    EndTest();
+  }
+
+  void AfterTest() override {}
+
+ private:
+  int frame_count_with_pending_tree_;
+};
+
+// This test blocks activation which is not supported for single thread mode.
+MULTI_THREAD_BLOCKNOTIFY_TEST_F(
+    LayerTreeHostTimelinesTestAnimationsAddedToNewAndExistingLayers);
+
+// Evolved from LayerTreeHostAnimationTestAddAnimationAfterAnimating.
+class LayerTreeHostTimelinesTestAddAnimationAfterAnimating
+    : public LayerTreeHostTimelinesTest {
+ public:
+  void SetupTree() override {
+    LayerTreeHostTimelinesTest::SetupTree();
+    content_ = Layer::Create(layer_settings());
+    content_->SetBounds(gfx::Size(4, 4));
+    layer_tree_host()->root_layer()->AddChild(content_);
+
+    AttachPlayersToTimeline();
+
+    player_->AttachLayer(layer_tree_host()->root_layer()->id());
+    player_child_->AttachLayer(content_->id());
+  }
+
+  void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+
+  void DidCommit() override {
+    switch (layer_tree_host()->source_frame_number()) {
+      case 1:
+        // First frame: add an animation to the root layer.
+        AddAnimatedTransformToPlayer(player_.get(), 0.1, 5, 5);
+        break;
+      case 2:
+        // Second frame: add an animation to the content layer. The root layer
+        // animation has caused us to animate already during this frame.
+        AddOpacityTransitionToPlayer(player_child_.get(), 0.1, 5, 5, false);
+        break;
+    }
+  }
+
+  void SwapBuffersOnThread(LayerTreeHostImpl* host_impl, bool result) override {
+    // After both animations have started, verify that they have valid
+    // start times.
+    if (host_impl->active_tree()->source_frame_number() < 2)
+      return;
+    AnimationRegistrar::AnimationControllerMap controllers_copy =
+        host_impl->animation_host()
+            ->animation_registrar()
+            ->active_animation_controllers_for_testing();
+    EXPECT_EQ(2u, controllers_copy.size());
+    for (auto& it : controllers_copy) {
+      int id = it.first;
+      if (id == host_impl->RootLayer()->id()) {
+        Animation* anim = it.second->GetAnimation(Animation::TRANSFORM);
+        EXPECT_GT((anim->start_time() - base::TimeTicks()).InSecondsF(), 0);
+      } else if (id == host_impl->RootLayer()->children()[0]->id()) {
+        Animation* anim = it.second->GetAnimation(Animation::OPACITY);
+        EXPECT_GT((anim->start_time() - base::TimeTicks()).InSecondsF(), 0);
+      }
+      EndTest();
+    }
+  }
+
+  void AfterTest() override {}
+
+ private:
+  scoped_refptr<Layer> content_;
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(
+    LayerTreeHostTimelinesTestAddAnimationAfterAnimating);
+
+}  // namespace
+}  // namespace cc
diff --git a/cc/trees/layer_tree_impl.cc b/cc/trees/layer_tree_impl.cc
index 3fc54411..d4d2dee 100644
--- a/cc/trees/layer_tree_impl.cc
+++ b/cc/trees/layer_tree_impl.cc
@@ -32,6 +32,7 @@
 #include "cc/trees/occlusion_tracker.h"
 #include "cc/trees/property_tree.h"
 #include "cc/trees/property_tree_builder.h"
+#include "ui/gfx/geometry/box_f.h"
 #include "ui/gfx/geometry/point_conversions.h"
 #include "ui/gfx/geometry/size_conversions.h"
 #include "ui/gfx/geometry/vector2d_conversions.h"
@@ -1625,4 +1626,131 @@
   return pending_page_scale_animation_.Pass();
 }
 
+bool LayerTreeImpl::IsAnimatingFilterProperty(const LayerImpl* layer) const {
+  return layer_tree_host_impl_->animation_host()
+             ? layer_tree_host_impl_->animation_host()
+                   ->IsAnimatingFilterProperty(layer->id())
+             : false;
+}
+
+bool LayerTreeImpl::IsAnimatingOpacityProperty(const LayerImpl* layer) const {
+  return layer_tree_host_impl_->animation_host()
+             ? layer_tree_host_impl_->animation_host()
+                   ->IsAnimatingOpacityProperty(layer->id())
+             : false;
+}
+
+bool LayerTreeImpl::IsAnimatingTransformProperty(const LayerImpl* layer) const {
+  return layer_tree_host_impl_->animation_host()
+             ? layer_tree_host_impl_->animation_host()
+                   ->IsAnimatingTransformProperty(layer->id())
+             : false;
+}
+
+bool LayerTreeImpl::HasPotentiallyRunningOpacityAnimation(
+    const LayerImpl* layer) const {
+  return layer_tree_host_impl_->animation_host()
+             ? layer_tree_host_impl_->animation_host()
+                   ->HasPotentiallyRunningOpacityAnimation(layer->id())
+             : false;
+}
+
+bool LayerTreeImpl::HasPotentiallyRunningTransformAnimation(
+    const LayerImpl* layer) const {
+  return layer_tree_host_impl_->animation_host()
+             ? layer_tree_host_impl_->animation_host()
+                   ->HasPotentiallyRunningTransformAnimation(layer->id())
+             : false;
+}
+
+bool LayerTreeImpl::FilterIsAnimatingOnImplOnly(const LayerImpl* layer) const {
+  return layer_tree_host_impl_->animation_host()
+             ? layer_tree_host_impl_->animation_host()
+                   ->FilterIsAnimatingOnImplOnly(layer->id())
+             : false;
+}
+
+bool LayerTreeImpl::OpacityIsAnimatingOnImplOnly(const LayerImpl* layer) const {
+  return layer_tree_host_impl_->animation_host()
+             ? layer_tree_host_impl_->animation_host()
+                   ->OpacityIsAnimatingOnImplOnly(layer->id())
+             : false;
+}
+
+bool LayerTreeImpl::TransformIsAnimatingOnImplOnly(
+    const LayerImpl* layer) const {
+  return layer_tree_host_impl_->animation_host()
+             ? layer_tree_host_impl_->animation_host()
+                   ->TransformIsAnimatingOnImplOnly(layer->id())
+             : false;
+}
+
+bool LayerTreeImpl::HasOnlyTranslationTransforms(const LayerImpl* layer) const {
+  return layer_tree_host_impl_->animation_host()
+             ? layer_tree_host_impl_->animation_host()
+                   ->HasOnlyTranslationTransforms(layer->id())
+             : true;
+}
+
+bool LayerTreeImpl::MaximumTargetScale(const LayerImpl* layer,
+                                       float* max_scale) const {
+  *max_scale = 0.f;
+  return layer_tree_host_impl_->animation_host()
+             ? layer_tree_host_impl_->animation_host()->MaximumTargetScale(
+                   layer->id(), max_scale)
+             : true;
+}
+
+bool LayerTreeImpl::AnimationStartScale(const LayerImpl* layer,
+                                        float* start_scale) const {
+  *start_scale = 0.f;
+  return layer_tree_host_impl_->animation_host()
+             ? layer_tree_host_impl_->animation_host()->AnimationStartScale(
+                   layer->id(), start_scale)
+             : true;
+}
+
+bool LayerTreeImpl::HasFilterAnimationThatInflatesBounds(
+    const LayerImpl* layer) const {
+  return layer_tree_host_impl_->animation_host()
+             ? layer_tree_host_impl_->animation_host()
+                   ->HasFilterAnimationThatInflatesBounds(layer->id())
+             : false;
+}
+
+bool LayerTreeImpl::HasTransformAnimationThatInflatesBounds(
+    const LayerImpl* layer) const {
+  return layer_tree_host_impl_->animation_host()
+             ? layer_tree_host_impl_->animation_host()
+                   ->HasTransformAnimationThatInflatesBounds(layer->id())
+             : false;
+}
+
+bool LayerTreeImpl::HasAnimationThatInflatesBounds(
+    const LayerImpl* layer) const {
+  return layer_tree_host_impl_->animation_host()
+             ? layer_tree_host_impl_->animation_host()
+                   ->HasAnimationThatInflatesBounds(layer->id())
+             : false;
+}
+
+bool LayerTreeImpl::FilterAnimationBoundsForBox(const LayerImpl* layer,
+                                                const gfx::BoxF& box,
+                                                gfx::BoxF* bounds) const {
+  return layer_tree_host_impl_->animation_host()
+             ? layer_tree_host_impl_->animation_host()
+                   ->FilterAnimationBoundsForBox(layer->id(), box, bounds)
+             : false;
+}
+
+bool LayerTreeImpl::TransformAnimationBoundsForBox(const LayerImpl* layer,
+                                                   const gfx::BoxF& box,
+                                                   gfx::BoxF* bounds) const {
+  *bounds = gfx::BoxF();
+  return layer_tree_host_impl_->animation_host()
+             ? layer_tree_host_impl_->animation_host()
+                   ->TransformAnimationBoundsForBox(layer->id(), box, bounds)
+             : true;
+}
+
 }  // namespace cc
diff --git a/cc/trees/layer_tree_impl.h b/cc/trees/layer_tree_impl.h
index 11a59f7..973df977 100644
--- a/cc/trees/layer_tree_impl.h
+++ b/cc/trees/layer_tree_impl.h
@@ -345,6 +345,33 @@
   bool IsExternalScrollActive() const;
   void DidUpdateScrollOffset(int layer_id);
 
+  bool IsAnimatingFilterProperty(const LayerImpl* layer) const;
+  bool IsAnimatingOpacityProperty(const LayerImpl* layer) const;
+  bool IsAnimatingTransformProperty(const LayerImpl* layer) const;
+
+  bool HasPotentiallyRunningOpacityAnimation(const LayerImpl* layer) const;
+  bool HasPotentiallyRunningTransformAnimation(const LayerImpl* layer) const;
+
+  bool FilterIsAnimatingOnImplOnly(const LayerImpl* layer) const;
+  bool OpacityIsAnimatingOnImplOnly(const LayerImpl* layer) const;
+  bool TransformIsAnimatingOnImplOnly(const LayerImpl* layer) const;
+
+  bool HasOnlyTranslationTransforms(const LayerImpl* layer) const;
+
+  bool MaximumTargetScale(const LayerImpl* layer, float* max_scale) const;
+  bool AnimationStartScale(const LayerImpl* layer, float* start_scale) const;
+
+  bool HasFilterAnimationThatInflatesBounds(const LayerImpl* layer) const;
+  bool HasTransformAnimationThatInflatesBounds(const LayerImpl* layer) const;
+  bool HasAnimationThatInflatesBounds(const LayerImpl* layer) const;
+
+  bool FilterAnimationBoundsForBox(const LayerImpl* layer,
+                                   const gfx::BoxF& box,
+                                   gfx::BoxF* bounds) const;
+  bool TransformAnimationBoundsForBox(const LayerImpl* layer,
+                                      const gfx::BoxF& box,
+                                      gfx::BoxF* bounds) const;
+
  protected:
   explicit LayerTreeImpl(
       LayerTreeHostImpl* layer_tree_host_impl,
diff --git a/cc/trees/property_tree_builder.cc b/cc/trees/property_tree_builder.cc
index 1a63331..28ad43f 100644
--- a/cc/trees/property_tree_builder.cc
+++ b/cc/trees/property_tree_builder.cc
@@ -63,16 +63,6 @@
 }
 
 template <typename LayerType>
-static bool HasPotentiallyRunningAnimation(LayerType* layer,
-                                           Animation::TargetProperty property) {
-  if (Animation* animation =
-          layer->layer_animation_controller()->GetAnimation(property)) {
-    return !animation->is_finished();
-  }
-  return false;
-}
-
-template <typename LayerType>
 static bool RequiresClipNode(LayerType* layer,
                              const DataForRecursion<LayerType>& data,
                              int parent_transform_id,
@@ -174,11 +164,8 @@
       !layer->transform().IsIdentityOr2DTranslation();
 
   const bool has_potentially_animated_transform =
-      HasPotentiallyRunningAnimation(layer, Animation::TRANSFORM);
-
-  const bool has_animated_transform =
-      layer->layer_animation_controller()->IsAnimatingProperty(
-          Animation::TRANSFORM);
+      layer->HasPotentiallyRunningTransformAnimation();
+  const bool has_animated_transform = layer->TransformIsAnimating();
 
   const bool has_surface = !!layer->render_surface();
 
@@ -343,12 +330,12 @@
 }
 
 bool IsAnimatingOpacity(Layer* layer) {
-  return HasPotentiallyRunningAnimation(layer, Animation::OPACITY) ||
+  return layer->HasPotentiallyRunningOpacityAnimation() ||
          layer->OpacityCanAnimateOnImplThread();
 }
 
 bool IsAnimatingOpacity(LayerImpl* layer) {
-  return HasPotentiallyRunningAnimation(layer, Animation::OPACITY);
+  return layer->HasPotentiallyRunningOpacityAnimation();
 }
 
 template <typename LayerType>