summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorajuma@chromium.org <ajuma@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-02-23 01:54:16 +0000
committerajuma@chromium.org <ajuma@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-02-23 01:54:16 +0000
commitbf91227ca2796661a6b17176dc50f4db002a7b49 (patch)
treeeb055c21ce79191091dfb52422b958d1118b3840
parentfe3b57cceb3381de3b8a9e83d52f6829c14317c0 (diff)
downloadchromium_src-bf91227ca2796661a6b17176dc50f4db002a7b49.zip
chromium_src-bf91227ca2796661a6b17176dc50f4db002a7b49.tar.gz
chromium_src-bf91227ca2796661a6b17176dc50f4db002a7b49.tar.bz2
Thread ui opacity animations
BUG=164206 Review URL: https://chromiumcodereview.appspot.com/11896017 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@184254 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--ash/ash.gyp2
-rw-r--r--ash/desktop_background/desktop_background_controller_unittest.cc8
-rw-r--r--ash/rotator/screen_rotation.cc2
-rw-r--r--ash/rotator/screen_rotation.h2
-rw-r--r--cc/animation_id_provider.cc19
-rw-r--r--cc/animation_id_provider.h21
-rw-r--r--cc/cc.gyp2
-rw-r--r--ui/compositor/compositor.gyp2
-rw-r--r--ui/compositor/layer.cc35
-rw-r--r--ui/compositor/layer.h14
-rw-r--r--ui/compositor/layer_animation_delegate.h4
-rw-r--r--ui/compositor/layer_animation_element.cc219
-rw-r--r--ui/compositor/layer_animation_element.h62
-rw-r--r--ui/compositor/layer_animation_element_unittest.cc103
-rw-r--r--ui/compositor/layer_animation_sequence.cc77
-rw-r--r--ui/compositor/layer_animation_sequence.h48
-rw-r--r--ui/compositor/layer_animation_sequence_unittest.cc117
-rw-r--r--ui/compositor/layer_animator.cc110
-rw-r--r--ui/compositor/layer_animator.h20
-rw-r--r--ui/compositor/layer_animator_unittest.cc810
-rw-r--r--ui/compositor/test/layer_animator_test_controller.cc52
-rw-r--r--ui/compositor/test/layer_animator_test_controller.h34
-rw-r--r--ui/compositor/test/test_layer_animation_delegate.cc7
-rw-r--r--ui/compositor/test/test_layer_animation_delegate.h3
-rw-r--r--webkit/compositor_bindings/compositor_bindings.gyp2
-rw-r--r--webkit/compositor_bindings/web_animation_id_provider.cc19
-rw-r--r--webkit/compositor_bindings/web_animation_id_provider.h19
-rw-r--r--webkit/compositor_bindings/web_animation_impl.cc8
28 files changed, 1461 insertions, 360 deletions
diff --git a/ash/ash.gyp b/ash/ash.gyp
index dd22c5b..e7f1b7e 100644
--- a/ash/ash.gyp
+++ b/ash/ash.gyp
@@ -573,6 +573,8 @@
'ash_test_support',
],
'sources': [
+ '../ui/compositor/test/layer_animator_test_controller.cc',
+ '../ui/compositor/test/layer_animator_test_controller.h',
'../ui/views/test/test_views_delegate.cc',
'../ui/views/test/test_views_delegate.h',
'accelerators/accelerator_controller_unittest.cc',
diff --git a/ash/desktop_background/desktop_background_controller_unittest.cc b/ash/desktop_background/desktop_background_controller_unittest.cc
index 7857231..237126e 100644
--- a/ash/desktop_background/desktop_background_controller_unittest.cc
+++ b/ash/desktop_background/desktop_background_controller_unittest.cc
@@ -9,6 +9,7 @@
#include "ash/shell_window_ids.h"
#include "ash/test/ash_test_base.h"
#include "ui/aura/root_window.h"
+#include "ui/compositor/test/layer_animator_test_controller.h"
using aura::RootWindow;
using aura::Window;
@@ -35,12 +36,13 @@ void RunAnimationForWidget(views::Widget* widget) {
DCHECK(!ui::LayerAnimator::disable_animations_for_test());
ui::Layer* layer = widget->GetNativeView()->layer();
- ui::LayerAnimator* animator = layer->GetAnimator();
+ ui::LayerAnimatorTestController controller(layer->GetAnimator());
ui::AnimationContainerElement* element = layer->GetAnimator();
// Multiple steps are required to complete complex animations.
// TODO(vollick): This should not be necessary. crbug.com/154017
- while (animator->is_animating()) {
- base::TimeTicks step_time = animator->last_step_time();
+ while (controller.animator()->is_animating()) {
+ controller.StartThreadedAnimationsIfNeeded();
+ base::TimeTicks step_time = controller.animator()->last_step_time();
element->Step(step_time + base::TimeDelta::FromMilliseconds(1000));
}
}
diff --git a/ash/rotator/screen_rotation.cc b/ash/rotator/screen_rotation.cc
index 686bc89..2f0dc850 100644
--- a/ash/rotator/screen_rotation.cc
+++ b/ash/rotator/screen_rotation.cc
@@ -117,7 +117,7 @@ void ScreenRotation::OnGetTarget(TargetValue* target) const {
target->transform = interpolated_transform_->Interpolate(1.0);
}
-void ScreenRotation::OnAbort() {
+void ScreenRotation::OnAbort(ui::LayerAnimationDelegate* delegate) {
}
// static
diff --git a/ash/rotator/screen_rotation.h b/ash/rotator/screen_rotation.h
index 339b99f..2f9616a 100644
--- a/ash/rotator/screen_rotation.h
+++ b/ash/rotator/screen_rotation.h
@@ -43,7 +43,7 @@ class ASH_EXPORT ScreenRotation : public ui::LayerAnimationElement {
virtual bool OnProgress(double t,
ui::LayerAnimationDelegate* delegate) OVERRIDE;
virtual void OnGetTarget(TargetValue* target) const OVERRIDE;
- virtual void OnAbort() OVERRIDE;
+ virtual void OnAbort(ui::LayerAnimationDelegate* delegate) OVERRIDE;
static const ui::LayerAnimationElement::AnimatableProperties&
GetProperties();
diff --git a/cc/animation_id_provider.cc b/cc/animation_id_provider.cc
new file mode 100644
index 0000000..bf30283
--- /dev/null
+++ b/cc/animation_id_provider.cc
@@ -0,0 +1,19 @@
+// Copyright (c) 2013 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/animation_id_provider.h"
+
+namespace cc {
+
+int AnimationIdProvider::NextAnimationId() {
+ static int next_animation_id = 1;
+ return next_animation_id++;
+}
+
+int AnimationIdProvider::NextGroupId() {
+ static int next_group_id = 1;
+ return next_group_id++;
+}
+
+} // namespace cc
diff --git a/cc/animation_id_provider.h b/cc/animation_id_provider.h
new file mode 100644
index 0000000..07a2452
--- /dev/null
+++ b/cc/animation_id_provider.h
@@ -0,0 +1,21 @@
+// Copyright (c) 2013 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.
+
+#ifndef CC_ANIMATION_ID_PROVIDER
+#define CC_ANIMATION_ID_PROVIDER
+
+#include "cc/cc_export.h"
+
+namespace cc {
+
+class CC_EXPORT AnimationIdProvider {
+ public:
+ // These functions each return monotonically increasing values.
+ static int NextAnimationId();
+ static int NextGroupId();
+};
+
+}
+
+#endif // CC_ANIMATION_ID_PROVIDER
diff --git a/cc/cc.gyp b/cc/cc.gyp
index 5a8d084..060104bc 100644
--- a/cc/cc.gyp
+++ b/cc/cc.gyp
@@ -10,6 +10,8 @@
'animation_curve.cc',
'animation_curve.h',
'animation_events.h',
+ 'animation_id_provider.cc',
+ 'animation_id_provider.h',
'animation_registrar.cc',
'animation_registrar.h',
'append_quads_data.h',
diff --git a/ui/compositor/compositor.gyp b/ui/compositor/compositor.gyp
index 13278f8..e8a6eae 100644
--- a/ui/compositor/compositor.gyp
+++ b/ui/compositor/compositor.gyp
@@ -118,6 +118,8 @@
'layer_animator_unittest.cc',
'layer_unittest.cc',
'run_all_unittests.cc',
+ 'test/layer_animator_test_controller.cc',
+ 'test/layer_animator_test_controller.h',
'test/test_compositor_host.h',
'test/test_compositor_host_linux.cc',
'test/test_compositor_host_mac.mm',
diff --git a/ui/compositor/layer.cc b/ui/compositor/layer.cc
index 6c7e075..b73419a 100644
--- a/ui/compositor/layer.cc
+++ b/ui/compositor/layer.cc
@@ -47,7 +47,6 @@ Layer::Layer()
force_render_surface_(false),
fills_bounds_opaquely_(true),
layer_updated_externally_(false),
- opacity_(1.0f),
background_blur_radius_(0),
layer_saturation_(0.0f),
layer_brightness_(0.0f),
@@ -75,7 +74,6 @@ Layer::Layer(LayerType type)
force_render_surface_(false),
fills_bounds_opaquely_(true),
layer_updated_externally_(false),
- opacity_(1.0f),
background_blur_radius_(0),
layer_saturation_(0.0f),
layer_brightness_(0.0f),
@@ -110,6 +108,7 @@ Layer::~Layer() {
layer_mask_back_link_->SetMaskLayer(NULL);
for (size_t i = 0; i < children_.size(); ++i)
children_[i]->parent_ = NULL;
+ cc_layer_->removeLayerAnimationEventObserver(this);
cc_layer_->removeFromParent();
}
@@ -117,6 +116,10 @@ Compositor* Layer::GetCompositor() {
return GetRoot(this)->compositor_;
}
+float Layer::opacity() const {
+ return cc_layer_->opacity();
+}
+
void Layer::SetCompositor(Compositor* compositor) {
// This function must only be called to set the compositor on the root layer,
// or to reset it.
@@ -225,10 +228,10 @@ void Layer::SetOpacity(float opacity) {
}
float Layer::GetCombinedOpacity() const {
- float opacity = opacity_;
+ float opacity = this->opacity();
Layer* current = this->parent_;
while (current) {
- opacity *= current->opacity_;
+ opacity *= current->opacity();
current = current->parent_;
}
return opacity;
@@ -355,7 +358,7 @@ float Layer::GetTargetOpacity() const {
if (animator_.get() && animator_->IsAnimatingProperty(
LayerAnimationElement::OPACITY))
return animator_->GetTargetOpacity();
- return opacity_;
+ return opacity();
}
void Layer::SetVisible(bool visible) {
@@ -444,7 +447,10 @@ void Layer::SetExternalTexture(Texture* texture) {
DCHECK(parent_->cc_layer_);
parent_->cc_layer_->replaceChild(cc_layer_, new_layer);
}
+ cc_layer_->removeLayerAnimationEventObserver(this);
+ new_layer->setOpacity(cc_layer_->opacity());
cc_layer_= new_layer;
+ cc_layer_->addLayerAnimationEventObserver(this);
cc_layer_is_accelerated_ = layer_updated_externally_;
for (size_t i = 0; i < children_.size(); ++i) {
DCHECK(children_[i]->cc_layer_);
@@ -452,7 +458,6 @@ void Layer::SetExternalTexture(Texture* texture) {
}
cc_layer_->setAnchorPoint(gfx::PointF());
cc_layer_->setContentsOpaque(fills_bounds_opaquely_);
- cc_layer_->setOpacity(opacity_);
cc_layer_->setForceRenderSurface(force_render_surface_);
cc_layer_->setIsDrawable(IsDrawn());
RecomputeTransform();
@@ -564,6 +569,11 @@ void Layer::SetForceRenderSurface(bool force) {
cc_layer_->setForceRenderSurface(force_render_surface_);
}
+void Layer::OnAnimationStarted(const cc::AnimationEvent& event) {
+ if (animator_)
+ animator_->OnThreadedAnimationStarted(event);
+}
+
void Layer::StackRelativeTo(Layer* child, Layer* other, bool above) {
DCHECK_NE(child, other);
DCHECK_EQ(this, child->parent());
@@ -656,8 +666,6 @@ void Layer::SetTransformImmediately(const gfx::Transform& transform) {
}
void Layer::SetOpacityImmediately(float opacity) {
- opacity_ = opacity;
-
cc_layer_->setOpacity(opacity);
ScheduleDraw();
}
@@ -751,6 +759,16 @@ SkColor Layer::GetColorForAnimation() const {
solid_color_layer_->backgroundColor() : SK_ColorBLACK;
}
+void Layer::AddThreadedAnimation(scoped_ptr<cc::Animation> animation) {
+ DCHECK(cc_layer_);
+ cc_layer_->addAnimation(animation.Pass());
+}
+
+void Layer::RemoveThreadedAnimation(int animation_id) {
+ DCHECK(cc_layer_);
+ cc_layer_->removeAnimation(animation_id);
+}
+
void Layer::CreateWebLayer() {
if (type_ == LAYER_SOLID_COLOR) {
solid_color_layer_ = cc::SolidColorLayer::create();
@@ -763,6 +781,7 @@ void Layer::CreateWebLayer() {
cc_layer_->setAnchorPoint(gfx::PointF());
cc_layer_->setContentsOpaque(true);
cc_layer_->setIsDrawable(type_ != LAYER_NOT_DRAWN);
+ cc_layer_->addLayerAnimationEventObserver(this);
}
void Layer::RecomputeTransform() {
diff --git a/ui/compositor/layer.h b/ui/compositor/layer.h
index 3bd460c2..2c322d0 100644
--- a/ui/compositor/layer.h
+++ b/ui/compositor/layer.h
@@ -12,7 +12,9 @@
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop.h"
+#include "cc/animation_events.h"
#include "cc/content_layer_client.h"
+#include "cc/layer_animation_event_observer.h"
#include "cc/texture_layer_client.h"
#include "third_party/skia/include/core/SkColor.h"
#include "third_party/skia/include/core/SkRegion.h"
@@ -52,7 +54,8 @@ class Texture;
class COMPOSITOR_EXPORT Layer
: public LayerAnimationDelegate,
NON_EXPORTED_BASE(public cc::ContentLayerClient),
- NON_EXPORTED_BASE(public cc::TextureLayerClient) {
+ NON_EXPORTED_BASE(public cc::TextureLayerClient),
+ NON_EXPORTED_BASE(public cc::LayerAnimationEventObserver) {
public:
Layer();
explicit Layer(LayerType type);
@@ -134,7 +137,7 @@ class COMPOSITOR_EXPORT Layer
// The opacity of the layer. The opacity is applied to each pixel of the
// texture (resulting alpha = opacity * alpha).
- float opacity() const { return opacity_; }
+ float opacity() const;
void SetOpacity(float opacity);
// Returns the actual opacity, which the opacity of this layer multipled by
@@ -287,6 +290,9 @@ class COMPOSITOR_EXPORT Layer
void SetForceRenderSurface(bool force);
bool force_render_surface() const { return force_render_surface_; }
+ // LayerAnimationEventObserver
+ virtual void OnAnimationStarted(const cc::AnimationEvent& event) OVERRIDE;
+
private:
// Stacks |child| above or below |other|. Helper method for StackAbove() and
// StackBelow().
@@ -330,6 +336,9 @@ class COMPOSITOR_EXPORT Layer
virtual float GetBrightnessForAnimation() const OVERRIDE;
virtual float GetGrayscaleForAnimation() const OVERRIDE;
virtual SkColor GetColorForAnimation() const OVERRIDE;
+ virtual void AddThreadedAnimation(
+ scoped_ptr<cc::Animation> animation) OVERRIDE;
+ virtual void RemoveThreadedAnimation(int animation_id) OVERRIDE;
void CreateWebLayer();
void RecomputeTransform();
@@ -375,7 +384,6 @@ class COMPOSITOR_EXPORT Layer
// compositor is ready to paint the content.
SkRegion damaged_region_;
- float opacity_;
int background_blur_radius_;
// Several variables which will change the visible representation of
diff --git a/ui/compositor/layer_animation_delegate.h b/ui/compositor/layer_animation_delegate.h
index 223eca2..8d144d3 100644
--- a/ui/compositor/layer_animation_delegate.h
+++ b/ui/compositor/layer_animation_delegate.h
@@ -5,6 +5,8 @@
#ifndef UI_COMPOSITOR_LAYER_ANIMATION_DELEGATE_H_
#define UI_COMPOSITOR_LAYER_ANIMATION_DELEGATE_H_
+#include "base/memory/scoped_ptr.h"
+#include "cc/animation.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/compositor/compositor_export.h"
#include "ui/gfx/rect.h"
@@ -30,6 +32,8 @@ class COMPOSITOR_EXPORT LayerAnimationDelegate {
virtual float GetBrightnessForAnimation() const = 0;
virtual float GetGrayscaleForAnimation() const = 0;
virtual SkColor GetColorForAnimation() const = 0;
+ virtual void AddThreadedAnimation(scoped_ptr<cc::Animation> animation) = 0;
+ virtual void RemoveThreadedAnimation(int animation_id) = 0;
protected:
virtual ~LayerAnimationDelegate() {}
diff --git a/ui/compositor/layer_animation_element.cc b/ui/compositor/layer_animation_element.cc
index 6c9aa39..81aeca5 100644
--- a/ui/compositor/layer_animation_element.cc
+++ b/ui/compositor/layer_animation_element.cc
@@ -5,7 +5,10 @@
#include "ui/compositor/layer_animation_element.h"
#include "base/compiler_specific.h"
+#include "cc/animation.h"
+#include "cc/animation_id_provider.h"
#include "ui/base/animation/tween.h"
+#include "ui/compositor/float_animation_curve_adapter.h"
#include "ui/compositor/layer_animation_delegate.h"
#include "ui/compositor/layer_animator.h"
#include "ui/gfx/interpolated_transform.h"
@@ -29,7 +32,7 @@ class Pause : public LayerAnimationElement {
return false;
}
virtual void OnGetTarget(TargetValue* target) const OVERRIDE {}
- virtual void OnAbort() OVERRIDE {}
+ virtual void OnAbort(LayerAnimationDelegate* delegate) OVERRIDE {}
DISALLOW_COPY_AND_ASSIGN(Pause);
};
@@ -59,7 +62,7 @@ class TransformTransition : public LayerAnimationElement {
target->transform = target_;
}
- virtual void OnAbort() OVERRIDE {}
+ virtual void OnAbort(LayerAnimationDelegate* delegate) OVERRIDE {}
private:
static AnimatableProperties GetProperties() {
@@ -99,7 +102,7 @@ class InterpolatedTransformTransition : public LayerAnimationElement {
target->transform = interpolated_transform_->Interpolate(1.0f);
}
- virtual void OnAbort() OVERRIDE {}
+ virtual void OnAbort(LayerAnimationDelegate* delegate) OVERRIDE {}
private:
static AnimatableProperties GetProperties() {
@@ -137,7 +140,7 @@ class BoundsTransition : public LayerAnimationElement {
target->bounds = target_;
}
- virtual void OnAbort() OVERRIDE {}
+ virtual void OnAbort(LayerAnimationDelegate* delegate) OVERRIDE {}
private:
static AnimatableProperties GetProperties() {
@@ -177,7 +180,7 @@ class OpacityTransition : public LayerAnimationElement {
target->opacity = target_;
}
- virtual void OnAbort() OVERRIDE {}
+ virtual void OnAbort(LayerAnimationDelegate* delegate) OVERRIDE {}
private:
static AnimatableProperties GetProperties() {
@@ -217,7 +220,7 @@ class VisibilityTransition : public LayerAnimationElement {
target->visibility = target_;
}
- virtual void OnAbort() OVERRIDE {}
+ virtual void OnAbort(LayerAnimationDelegate* delegate) OVERRIDE {}
private:
static AnimatableProperties GetProperties() {
@@ -258,7 +261,7 @@ class BrightnessTransition : public LayerAnimationElement {
target->brightness = target_;
}
- virtual void OnAbort() OVERRIDE {}
+ virtual void OnAbort(LayerAnimationDelegate* delegate) OVERRIDE {}
private:
static AnimatableProperties GetProperties() {
@@ -299,7 +302,7 @@ class GrayscaleTransition : public LayerAnimationElement {
target->grayscale = target_;
}
- virtual void OnAbort() OVERRIDE {}
+ virtual void OnAbort(LayerAnimationDelegate* delegate) OVERRIDE {}
private:
static AnimatableProperties GetProperties() {
@@ -352,7 +355,7 @@ class ColorTransition : public LayerAnimationElement {
target->color = target_;
}
- virtual void OnAbort() OVERRIDE {}
+ virtual void OnAbort(LayerAnimationDelegate* delegate) OVERRIDE {}
private:
static AnimatableProperties GetProperties() {
@@ -367,6 +370,120 @@ class ColorTransition : public LayerAnimationElement {
DISALLOW_COPY_AND_ASSIGN(ColorTransition);
};
+// ThreadedLayerAnimationElement -----------------------------------------------
+
+class ThreadedLayerAnimationElement : public LayerAnimationElement {
+ public:
+ ThreadedLayerAnimationElement(const AnimatableProperties& properties,
+ base::TimeDelta duration)
+ : LayerAnimationElement(properties, duration) {
+ }
+ virtual ~ThreadedLayerAnimationElement() {}
+
+ virtual bool IsThreaded() const OVERRIDE {
+ return (duration() != base::TimeDelta());
+ }
+
+ protected:
+ virtual bool OnProgress(double t,
+ LayerAnimationDelegate* delegate) OVERRIDE {
+ if (t < 1.0)
+ return false;
+
+ if (Started()) {
+ delegate->RemoveThreadedAnimation(animation_id());
+ }
+
+ OnEnd(delegate);
+ return true;
+ }
+
+ virtual void OnAbort(LayerAnimationDelegate* delegate) OVERRIDE {
+ if (delegate && Started()) {
+ delegate->RemoveThreadedAnimation(animation_id());
+ }
+ }
+
+ virtual void RequestEffectiveStart(
+ LayerAnimationDelegate* delegate) OVERRIDE {
+ DCHECK(animation_group_id());
+ if (duration() == base::TimeDelta()) {
+ set_effective_start_time(requested_start_time());
+ return;
+ }
+ set_effective_start_time(base::TimeTicks());
+ scoped_ptr<cc::Animation> animation = CreateCCAnimation();
+ animation->setNeedsSynchronizedStartTime(true);
+ delegate->AddThreadedAnimation(animation.Pass());
+ }
+
+ virtual void OnEnd(LayerAnimationDelegate* delegate) = 0;
+
+ virtual scoped_ptr<cc::Animation> CreateCCAnimation() = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ThreadedLayerAnimationElement);
+};
+
+// ThreadedOpacityTransition ---------------------------------------------------
+
+class ThreadedOpacityTransition : public ThreadedLayerAnimationElement {
+ public:
+ ThreadedOpacityTransition(float target, base::TimeDelta duration)
+ : ThreadedLayerAnimationElement(GetProperties(), duration),
+ start_(0.0f),
+ target_(target) {
+ }
+ virtual ~ThreadedOpacityTransition() {}
+
+ protected:
+ virtual void OnStart(LayerAnimationDelegate* delegate) OVERRIDE {
+ start_ = delegate->GetOpacityForAnimation();
+ }
+
+ virtual void OnAbort(LayerAnimationDelegate* delegate) OVERRIDE {
+ if (delegate && Started()) {
+ ThreadedLayerAnimationElement::OnAbort(delegate);
+ delegate->SetOpacityFromAnimation(
+ Tween::ValueBetween(last_progressed_fraction(), start_, target_));
+ }
+ }
+
+ virtual void OnEnd(LayerAnimationDelegate* delegate) OVERRIDE {
+ delegate->SetOpacityFromAnimation(target_);
+ }
+
+ virtual scoped_ptr<cc::Animation> CreateCCAnimation() OVERRIDE {
+ scoped_ptr<cc::AnimationCurve> animation_curve(
+ new FloatAnimationCurveAdapter(tween_type(),
+ start_,
+ target_,
+ duration()));
+ scoped_ptr<cc::Animation> animation(
+ cc::Animation::create(animation_curve.Pass(),
+ animation_id(),
+ animation_group_id(),
+ cc::Animation::Opacity));
+ return animation.Pass();
+ }
+
+ virtual void OnGetTarget(TargetValue* target) const OVERRIDE {
+ target->opacity = target_;
+ }
+
+ private:
+ static AnimatableProperties GetProperties() {
+ AnimatableProperties properties;
+ properties.insert(LayerAnimationElement::OPACITY);
+ return properties;
+ }
+
+ float start_;
+ const float target_;
+
+ DISALLOW_COPY_AND_ASSIGN(ThreadedOpacityTransition);
+};
+
} // namespace
// LayerAnimationElement::TargetValue ------------------------------------------
@@ -399,31 +516,65 @@ LayerAnimationElement::LayerAnimationElement(
: first_frame_(true),
properties_(properties),
duration_(GetEffectiveDuration(duration)),
- tween_type_(Tween::LINEAR) {
+ tween_type_(Tween::LINEAR),
+ animation_id_(cc::AnimationIdProvider::NextAnimationId()),
+ animation_group_id_(0),
+ last_progressed_fraction_(0.0) {
}
LayerAnimationElement::~LayerAnimationElement() {
}
+void LayerAnimationElement::Start(LayerAnimationDelegate* delegate,
+ int animation_group_id) {
+ DCHECK(requested_start_time_ != base::TimeTicks());
+ DCHECK(first_frame_);
+ animation_group_id_ = animation_group_id;
+ last_progressed_fraction_ = 0.0;
+ OnStart(delegate);
+ RequestEffectiveStart(delegate);
+ first_frame_ = false;
+}
+
bool LayerAnimationElement::Progress(base::TimeTicks now,
LayerAnimationDelegate* delegate) {
- DCHECK(start_time_ != base::TimeTicks());
- base::TimeDelta elapsed = now - start_time_;
- if (first_frame_)
- OnStart(delegate);
+ DCHECK(requested_start_time_ != base::TimeTicks());
+ DCHECK(!first_frame_);
+
+ bool need_draw;
double t = 1.0;
+
+ if (effective_start_time_ == base::TimeTicks()) {
+ // This hasn't actually started yet.
+ need_draw = false;
+ last_progressed_fraction_ = 0.0;
+ return need_draw;
+ }
+
+ base::TimeDelta elapsed = now - effective_start_time_;
if ((duration_ > base::TimeDelta()) && (elapsed < duration_))
t = elapsed.InMillisecondsF() / duration_.InMillisecondsF();
- bool need_draw = OnProgress(Tween::CalculateValue(tween_type_, t), delegate);
+ need_draw = OnProgress(Tween::CalculateValue(tween_type_, t), delegate);
first_frame_ = t == 1.0;
+ last_progressed_fraction_ = t;
return need_draw;
}
bool LayerAnimationElement::IsFinished(base::TimeTicks time,
base::TimeDelta* total_duration) {
- base::TimeDelta elapsed = time - start_time_;
- if (elapsed >= duration_) {
- *total_duration = duration_;
+ // If an effective start has been requested but the effective start time
+ // hasn't yet been set, the animation is not finished, regardless of the
+ // value of |time|.
+ if (!first_frame_ && (effective_start_time_ == base::TimeTicks()))
+ return false;
+
+ base::TimeDelta queueing_delay;
+ if (!first_frame_)
+ queueing_delay = effective_start_time_ - requested_start_time_;
+
+ base::TimeDelta elapsed = time - requested_start_time_;
+ if (elapsed >= duration_ + queueing_delay) {
+ *total_duration = duration_ + queueing_delay;
return true;
}
return false;
@@ -433,6 +584,7 @@ bool LayerAnimationElement::ProgressToEnd(LayerAnimationDelegate* delegate) {
if (first_frame_)
OnStart(delegate);
bool need_draw = OnProgress(1.0, delegate);
+ last_progressed_fraction_ = 1.0;
first_frame_ = true;
return need_draw;
}
@@ -441,9 +593,34 @@ void LayerAnimationElement::GetTargetValue(TargetValue* target) const {
OnGetTarget(target);
}
-void LayerAnimationElement::Abort() {
+bool LayerAnimationElement::IsThreaded() const {
+ return false;
+}
+
+void LayerAnimationElement::Abort(LayerAnimationDelegate* delegate) {
+ OnAbort(delegate);
first_frame_ = true;
- OnAbort();
+}
+
+void LayerAnimationElement::RequestEffectiveStart(
+ LayerAnimationDelegate* delegate) {
+ DCHECK(requested_start_time_ != base::TimeTicks());
+ effective_start_time_ = requested_start_time_;
+}
+
+// static
+LayerAnimationElement::AnimatableProperty
+LayerAnimationElement::ToAnimatableProperty(
+ cc::Animation::TargetProperty property) {
+ switch (property) {
+ case cc::Animation::Transform:
+ return TRANSFORM;
+ case cc::Animation::Opacity:
+ return OPACITY;
+ default:
+ NOTREACHED();
+ return AnimatableProperty();
+ }
}
// static
@@ -484,7 +661,7 @@ LayerAnimationElement* LayerAnimationElement::CreateBoundsElement(
LayerAnimationElement* LayerAnimationElement::CreateOpacityElement(
float opacity,
base::TimeDelta duration) {
- return new OpacityTransition(opacity, duration);
+ return new ThreadedOpacityTransition(opacity, duration);
}
// static
diff --git a/ui/compositor/layer_animation_element.h b/ui/compositor/layer_animation_element.h
index 9b65844..419092c 100644
--- a/ui/compositor/layer_animation_element.h
+++ b/ui/compositor/layer_animation_element.h
@@ -8,6 +8,8 @@
#include <set>
#include "base/time.h"
+#include "cc/animation.h"
+#include "cc/animation_events.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/base/animation/tween.h"
#include "ui/compositor/compositor_export.h"
@@ -34,6 +36,9 @@ class COMPOSITOR_EXPORT LayerAnimationElement {
COLOR,
};
+ static AnimatableProperty ToAnimatableProperty(
+ cc::Animation::TargetProperty property);
+
struct COMPOSITOR_EXPORT TargetValue {
TargetValue();
// Initializes the target value to match the delegate. NULL may be supplied.
@@ -114,10 +119,28 @@ class COMPOSITOR_EXPORT LayerAnimationElement {
base::TimeDelta duration);
// Sets the start time for the animation. This must be called before the first
- // call to {Progress, IsFinished}. Once the animation is finished, this must
+ // call to {Start, IsFinished}. Once the animation is finished, this must
// be called again in order to restart the animation.
- void set_start_time(base::TimeTicks start_time) { start_time_ = start_time; }
- base::TimeTicks start_time() const { return start_time_; }
+ void set_requested_start_time(base::TimeTicks start_time) {
+ requested_start_time_ = start_time;
+ }
+ base::TimeTicks requested_start_time() const { return requested_start_time_; }
+
+ // Sets the actual start time for the animation, taking into account any
+ // queueing delays.
+ void set_effective_start_time(base::TimeTicks start_time) {
+ effective_start_time_ = start_time;
+ }
+ base::TimeTicks effective_start_time() const { return effective_start_time_; }
+
+ // This must be called before the first call to Progress. If starting the
+ // animation involves dispatching to another thread, then this will proceed
+ // with that dispatch, ultimately resulting in the animation getting an
+ // effective start time (the time the animation starts on the other thread).
+ void Start(LayerAnimationDelegate* delegate, int animation_group_id);
+
+ // Returns true if the animation has started but hasn't finished.
+ bool Started() { return !first_frame_; }
// Updates the delegate to the appropriate value for |now|. Returns true
// if a redraw is required.
@@ -134,7 +157,7 @@ class COMPOSITOR_EXPORT LayerAnimationElement {
// Called if the animation is not allowed to complete. This may be called
// before OnStarted or Progress.
- void Abort();
+ void Abort(LayerAnimationDelegate* delegate);
// Assigns the target value to |target|.
void GetTargetValue(TargetValue* target) const;
@@ -142,16 +165,35 @@ class COMPOSITOR_EXPORT LayerAnimationElement {
// The properties that the element modifies.
const AnimatableProperties& properties() const { return properties_; }
+ // Whether this element animates on the compositor thread.
+ virtual bool IsThreaded() const;
+
Tween::Type tween_type() const { return tween_type_; }
void set_tween_type(Tween::Type tween_type) { tween_type_ = tween_type; }
+ // Each LayerAnimationElement has a unique animation_id. Elements belonging
+ // to sequences that are supposed to start together have the same
+ // animation_group_id.
+ int animation_id() const { return animation_id_; }
+ int animation_group_id() const { return animation_group_id_; }
+ void set_animation_group_id(int id) { animation_group_id_ = id; }
+
+ // The fraction of the animation that has been completed after the last
+ // call made to {Progress, ProgressToEnd}.
+ double last_progressed_fraction() const { return last_progressed_fraction_; }
+
protected:
// Called once each time the animation element is run before any call to
// OnProgress.
virtual void OnStart(LayerAnimationDelegate* delegate) = 0;
virtual bool OnProgress(double t, LayerAnimationDelegate* delegate) = 0;
virtual void OnGetTarget(TargetValue* target) const = 0;
- virtual void OnAbort() = 0;
+ virtual void OnAbort(LayerAnimationDelegate* delegate) = 0;
+
+ base::TimeDelta duration() const { return duration_; }
+
+ // Actually start the animation, dispatching to another thread if needed.
+ virtual void RequestEffectiveStart(LayerAnimationDelegate* delegate);
private:
// For debugging purposes, we sometimes alter the duration we actually use.
@@ -161,10 +203,18 @@ class COMPOSITOR_EXPORT LayerAnimationElement {
bool first_frame_;
const AnimatableProperties properties_;
- base::TimeTicks start_time_;
+ base::TimeTicks requested_start_time_;
+
+ // When the animation actually started, taking into account queueing delays.
+ base::TimeTicks effective_start_time_;
const base::TimeDelta duration_;
Tween::Type tween_type_;
+ const int animation_id_;
+ int animation_group_id_;
+
+ double last_progressed_fraction_;
+
DISALLOW_COPY_AND_ASSIGN(LayerAnimationElement);
};
diff --git a/ui/compositor/layer_animation_element_unittest.cc b/ui/compositor/layer_animation_element_unittest.cc
index 5912023..9964436 100644
--- a/ui/compositor/layer_animation_element_unittest.cc
+++ b/ui/compositor/layer_animation_element_unittest.cc
@@ -34,14 +34,20 @@ TEST(LayerAnimationElementTest, TransformElement) {
for (int i = 0; i < 2; ++i) {
start_time += delta;
- element->set_start_time(start_time);
+ element->set_requested_start_time(start_time);
delegate.SetTransformFromAnimation(start_transform);
+ element->Start(&delegate, 1);
element->Progress(start_time, &delegate);
CheckApproximatelyEqual(start_transform,
delegate.GetTransformForAnimation());
element->Progress(start_time + delta/2, &delegate);
CheckApproximatelyEqual(middle_transform,
delegate.GetTransformForAnimation());
+
+ base::TimeDelta element_duration;
+ EXPECT_TRUE(element->IsFinished(start_time + delta, &element_duration));
+ EXPECT_EQ(delta, element_duration);
+
element->Progress(start_time + delta, &delegate);
CheckApproximatelyEqual(target_transform,
delegate.GetTransformForAnimation());
@@ -50,10 +56,6 @@ TEST(LayerAnimationElementTest, TransformElement) {
LayerAnimationElement::TargetValue target_value(&delegate);
element->GetTargetValue(&target_value);
CheckApproximatelyEqual(target_transform, target_value.transform);
-
- base::TimeDelta element_duration;
- EXPECT_TRUE(element->IsFinished(start_time + delta, &element_duration));
- EXPECT_EQ(delta, element_duration);
}
// Check that the bounds element progresses the delegate as expected and
@@ -72,12 +74,18 @@ TEST(LayerAnimationElementTest, BoundsElement) {
for (int i = 0; i < 2; ++i) {
start_time += delta;
- element->set_start_time(start_time);
+ element->set_requested_start_time(start_time);
delegate.SetBoundsFromAnimation(start);
+ element->Start(&delegate, 1);
element->Progress(start_time, &delegate);
CheckApproximatelyEqual(start, delegate.GetBoundsForAnimation());
element->Progress(start_time + delta/2, &delegate);
CheckApproximatelyEqual(middle, delegate.GetBoundsForAnimation());
+
+ base::TimeDelta element_duration;
+ EXPECT_TRUE(element->IsFinished(start_time + delta, &element_duration));
+ EXPECT_EQ(delta, element_duration);
+
element->Progress(start_time + delta, &delegate);
CheckApproximatelyEqual(target, delegate.GetBoundsForAnimation());
}
@@ -85,10 +93,6 @@ TEST(LayerAnimationElementTest, BoundsElement) {
LayerAnimationElement::TargetValue target_value(&delegate);
element->GetTargetValue(&target_value);
CheckApproximatelyEqual(target, target_value.bounds);
-
- base::TimeDelta element_duration;
- EXPECT_TRUE(element->IsFinished(start_time + delta, &element_duration));
- EXPECT_EQ(delta, element_duration);
}
// Check that the opacity element progresses the delegate as expected and
@@ -99,29 +103,38 @@ TEST(LayerAnimationElementTest, OpacityElement) {
float middle = 0.5;
float target = 1.0;
base::TimeTicks start_time;
+ base::TimeTicks effective_start_time;
base::TimeDelta delta = base::TimeDelta::FromSeconds(1);
scoped_ptr<LayerAnimationElement> element(
LayerAnimationElement::CreateOpacityElement(target, delta));
for (int i = 0; i < 2; ++i) {
- start_time += delta;
- element->set_start_time(start_time);
+ start_time = effective_start_time + delta;
+ element->set_requested_start_time(start_time);
delegate.SetOpacityFromAnimation(start);
+ element->Start(&delegate, 1);
element->Progress(start_time, &delegate);
- EXPECT_FLOAT_EQ(start, delegate.GetOpacityForAnimation());
- element->Progress(start_time + delta/2, &delegate);
- EXPECT_FLOAT_EQ(middle, delegate.GetOpacityForAnimation());
- element->Progress(start_time + delta, &delegate);
+ EXPECT_FLOAT_EQ(start, element->last_progressed_fraction());
+ effective_start_time = start_time + delta;
+ element->set_effective_start_time(effective_start_time);
+ element->Progress(effective_start_time, &delegate);
+ EXPECT_FLOAT_EQ(start, element->last_progressed_fraction());
+ element->Progress(effective_start_time + delta/2, &delegate);
+ EXPECT_FLOAT_EQ(middle, element->last_progressed_fraction());
+
+ base::TimeDelta element_duration;
+ EXPECT_TRUE(element->IsFinished(effective_start_time + delta,
+ &element_duration));
+ EXPECT_EQ(2 * delta, element_duration);
+
+ element->Progress(effective_start_time + delta, &delegate);
+ EXPECT_FLOAT_EQ(target, element->last_progressed_fraction());
EXPECT_FLOAT_EQ(target, delegate.GetOpacityForAnimation());
}
LayerAnimationElement::TargetValue target_value(&delegate);
element->GetTargetValue(&target_value);
EXPECT_FLOAT_EQ(target, target_value.opacity);
-
- base::TimeDelta element_duration;
- EXPECT_TRUE(element->IsFinished(start_time + delta, &element_duration));
- EXPECT_EQ(delta, element_duration);
}
// Check that the visibility element progresses the delegate as expected and
@@ -137,12 +150,18 @@ TEST(LayerAnimationElementTest, VisibilityElement) {
for (int i = 0; i < 2; ++i) {
start_time += delta;
- element->set_start_time(start_time);
+ element->set_requested_start_time(start_time);
delegate.SetVisibilityFromAnimation(start);
+ element->Start(&delegate, 1);
element->Progress(start_time, &delegate);
EXPECT_TRUE(delegate.GetVisibilityForAnimation());
element->Progress(start_time + delta/2, &delegate);
EXPECT_TRUE(delegate.GetVisibilityForAnimation());
+
+ base::TimeDelta element_duration;
+ EXPECT_TRUE(element->IsFinished(start_time + delta, &element_duration));
+ EXPECT_EQ(delta, element_duration);
+
element->Progress(start_time + delta, &delegate);
EXPECT_FALSE(delegate.GetVisibilityForAnimation());
}
@@ -150,10 +169,6 @@ TEST(LayerAnimationElementTest, VisibilityElement) {
LayerAnimationElement::TargetValue target_value(&delegate);
element->GetTargetValue(&target_value);
EXPECT_FALSE(target_value.visibility);
-
- base::TimeDelta element_duration;
- EXPECT_TRUE(element->IsFinished(start_time + delta, &element_duration));
- EXPECT_EQ(delta, element_duration);
}
// Check that the Brightness element progresses the delegate as expected and
@@ -170,12 +185,18 @@ TEST(LayerAnimationElementTest, BrightnessElement) {
for (int i = 0; i < 2; ++i) {
start_time += delta;
- element->set_start_time(start_time);
+ element->set_requested_start_time(start_time);
delegate.SetBrightnessFromAnimation(start);
+ element->Start(&delegate, 1);
element->Progress(start_time, &delegate);
EXPECT_FLOAT_EQ(start, delegate.GetBrightnessForAnimation());
element->Progress(start_time + delta/2, &delegate);
EXPECT_FLOAT_EQ(middle, delegate.GetBrightnessForAnimation());
+
+ base::TimeDelta element_duration;
+ EXPECT_TRUE(element->IsFinished(start_time + delta, &element_duration));
+ EXPECT_EQ(delta, element_duration);
+
element->Progress(start_time + delta, &delegate);
EXPECT_FLOAT_EQ(target, delegate.GetBrightnessForAnimation());
}
@@ -183,10 +204,6 @@ TEST(LayerAnimationElementTest, BrightnessElement) {
LayerAnimationElement::TargetValue target_value(&delegate);
element->GetTargetValue(&target_value);
EXPECT_FLOAT_EQ(target, target_value.brightness);
-
- base::TimeDelta element_duration;
- EXPECT_TRUE(element->IsFinished(start_time + delta, &element_duration));
- EXPECT_EQ(delta, element_duration);
}
// Check that the Grayscale element progresses the delegate as expected and
@@ -203,12 +220,18 @@ TEST(LayerAnimationElementTest, GrayscaleElement) {
for (int i = 0; i < 2; ++i) {
start_time += delta;
- element->set_start_time(start_time);
+ element->set_requested_start_time(start_time);
delegate.SetGrayscaleFromAnimation(start);
+ element->Start(&delegate, 1);
element->Progress(start_time, &delegate);
EXPECT_FLOAT_EQ(start, delegate.GetGrayscaleForAnimation());
element->Progress(start_time + delta/2, &delegate);
EXPECT_FLOAT_EQ(middle, delegate.GetGrayscaleForAnimation());
+
+ base::TimeDelta element_duration;
+ EXPECT_TRUE(element->IsFinished(start_time + delta, &element_duration));
+ EXPECT_EQ(delta, element_duration);
+
element->Progress(start_time + delta, &delegate);
EXPECT_FLOAT_EQ(target, delegate.GetGrayscaleForAnimation());
}
@@ -216,10 +239,6 @@ TEST(LayerAnimationElementTest, GrayscaleElement) {
LayerAnimationElement::TargetValue target_value(&delegate);
element->GetTargetValue(&target_value);
EXPECT_FLOAT_EQ(target, target_value.grayscale);
-
- base::TimeDelta element_duration;
- EXPECT_TRUE(element->IsFinished(start_time + delta, &element_duration));
- EXPECT_EQ(delta, element_duration);
}
// Check that the pause element progresses the delegate as expected and
@@ -241,7 +260,14 @@ TEST(LayerAnimationElementTest, PauseElement) {
TestLayerAnimationDelegate copy = delegate;
start_time += delta;
- element->set_start_time(start_time);
+ element->set_requested_start_time(start_time);
+ element->Start(&delegate, 1);
+
+ // Pause should last for |delta|.
+ base::TimeDelta element_duration;
+ EXPECT_TRUE(element->IsFinished(start_time + delta, &element_duration));
+ EXPECT_EQ(delta, element_duration);
+
element->Progress(start_time + delta, &delegate);
// Nothing should have changed.
@@ -255,11 +281,6 @@ TEST(LayerAnimationElementTest, PauseElement) {
copy.GetBrightnessForAnimation());
EXPECT_FLOAT_EQ(delegate.GetGrayscaleForAnimation(),
copy.GetGrayscaleForAnimation());
-
- // Pause should last for |delta|.
- base::TimeDelta element_duration;
- EXPECT_TRUE(element->IsFinished(start_time + delta, &element_duration));
- EXPECT_EQ(delta, element_duration);
}
} // namespace
diff --git a/ui/compositor/layer_animation_sequence.cc b/ui/compositor/layer_animation_sequence.cc
index a997c38..10ba702 100644
--- a/ui/compositor/layer_animation_sequence.cc
+++ b/ui/compositor/layer_animation_sequence.cc
@@ -16,12 +16,18 @@ namespace ui {
LayerAnimationSequence::LayerAnimationSequence()
: is_cyclic_(false),
- last_element_(0) {
+ last_element_(0),
+ waiting_for_group_start_(false),
+ animation_group_id_(0),
+ last_progressed_fraction_(0.0) {
}
LayerAnimationSequence::LayerAnimationSequence(LayerAnimationElement* element)
: is_cyclic_(false),
- last_element_(0) {
+ last_element_(0),
+ waiting_for_group_start_(false),
+ animation_group_id_(0),
+ last_progressed_fraction_(0.0) {
AddElement(element);
}
@@ -31,8 +37,19 @@ LayerAnimationSequence::~LayerAnimationSequence() {
DetachedFromSequence(this, true));
}
+void LayerAnimationSequence::Start(LayerAnimationDelegate* delegate) {
+ DCHECK(start_time_ != base::TimeTicks());
+ last_progressed_fraction_ = 0.0;
+ if (elements_.empty())
+ return;
+
+ elements_[0]->set_requested_start_time(start_time_);
+ elements_[0]->Start(delegate, animation_group_id_);
+}
+
void LayerAnimationSequence::Progress(base::TimeTicks now,
LayerAnimationDelegate* delegate) {
+ DCHECK(start_time_ != base::TimeTicks());
bool redraw_required = false;
if (elements_.empty())
@@ -44,21 +61,27 @@ void LayerAnimationSequence::Progress(base::TimeTicks now,
size_t current_index = last_element_ % elements_.size();
base::TimeDelta element_duration;
while (is_cyclic_ || last_element_ < elements_.size()) {
- elements_[current_index]->set_start_time(last_start_);
+ elements_[current_index]->set_requested_start_time(last_start_);
if (!elements_[current_index]->IsFinished(now, &element_duration))
break;
// Let the element we're passing finish.
- if (elements_[current_index]->Progress(now, delegate))
+ if (elements_[current_index]->ProgressToEnd(delegate))
redraw_required = true;
last_start_ += element_duration;
++last_element_;
+ last_progressed_fraction_ =
+ elements_[current_index]->last_progressed_fraction();
current_index = last_element_ % elements_.size();
}
if (is_cyclic_ || last_element_ < elements_.size()) {
+ if (!elements_[current_index]->Started())
+ elements_[current_index]->Start(delegate, animation_group_id_);
if (elements_[current_index]->Progress(now, delegate))
redraw_required = true;
+ last_progressed_fraction_ =
+ elements_[current_index]->last_progressed_fraction();
}
// Since the delegate may be deleted due to the notifications below, it is
@@ -68,12 +91,14 @@ void LayerAnimationSequence::Progress(base::TimeTicks now,
if (!is_cyclic_ && last_element_ == elements_.size()) {
last_element_ = 0;
+ waiting_for_group_start_ = false;
+ animation_group_id_ = 0;
NotifyEnded();
}
}
bool LayerAnimationSequence::IsFinished(base::TimeTicks time) {
- if (is_cyclic_)
+ if (is_cyclic_ || waiting_for_group_start_)
return false;
if (elements_.empty())
@@ -86,7 +111,7 @@ bool LayerAnimationSequence::IsFinished(base::TimeTicks time) {
size_t current_index = last_element_;
base::TimeDelta element_duration;
while (current_index < elements_.size()) {
- elements_[current_index]->set_start_time(current_start);
+ elements_[current_index]->set_requested_start_time(current_start);
if (!elements_[current_index]->IsFinished(time, &element_duration))
break;
@@ -107,6 +132,8 @@ void LayerAnimationSequence::ProgressToEnd(LayerAnimationDelegate* delegate) {
while (current_index < elements_.size()) {
if (elements_[current_index]->ProgressToEnd(delegate))
redraw_required = true;
+ last_progressed_fraction_ =
+ elements_[current_index]->last_progressed_fraction();
++current_index;
++last_element_;
}
@@ -116,6 +143,8 @@ void LayerAnimationSequence::ProgressToEnd(LayerAnimationDelegate* delegate) {
if (!is_cyclic_) {
last_element_ = 0;
+ waiting_for_group_start_ = false;
+ animation_group_id_ = 0;
NotifyEnded();
}
}
@@ -129,13 +158,14 @@ void LayerAnimationSequence::GetTargetValue(
elements_[i]->GetTargetValue(target);
}
-void LayerAnimationSequence::Abort() {
+void LayerAnimationSequence::Abort(LayerAnimationDelegate* delegate) {
size_t current_index = last_element_ % elements_.size();
while (current_index < elements_.size()) {
- elements_[current_index]->Abort();
+ elements_[current_index]->Abort(delegate);
++current_index;
}
last_element_ = 0;
+ waiting_for_group_start_ = false;
NotifyAborted();
}
@@ -156,6 +186,13 @@ bool LayerAnimationSequence::HasCommonProperty(
return intersection.size() > 0;
}
+bool LayerAnimationSequence::IsFirstElementThreaded() const {
+ if (!elements_.empty())
+ return elements_[0]->IsThreaded();
+
+ return false;
+}
+
void LayerAnimationSequence::AddObserver(LayerAnimationObserver* observer) {
if (!observers_.HasObserver(observer)) {
observers_.AddObserver(observer);
@@ -168,6 +205,22 @@ void LayerAnimationSequence::RemoveObserver(LayerAnimationObserver* observer) {
observer->DetachedFromSequence(this, true);
}
+void LayerAnimationSequence::OnThreadedAnimationStarted(
+ const cc::AnimationEvent& event) {
+ if (elements_.empty() || event.groupId != animation_group_id_)
+ return;
+
+ size_t current_index = last_element_ % elements_.size();
+ const LayerAnimationElement::AnimatableProperties& element_properties =
+ elements_[current_index]->properties();
+ LayerAnimationElement::AnimatableProperty event_property =
+ LayerAnimationElement::ToAnimatableProperty(event.targetProperty);
+ DCHECK(element_properties.find(event_property) != element_properties.end());
+ elements_[current_index]->set_effective_start_time(
+ base::TimeTicks::FromInternalValue(
+ event.monotonicTime * base::Time::kMicrosecondsPerSecond));
+}
+
void LayerAnimationSequence::OnScheduled() {
NotifyScheduled();
}
@@ -204,4 +257,12 @@ void LayerAnimationSequence::NotifyAborted() {
OnLayerAnimationAborted(this));
}
+LayerAnimationElement* LayerAnimationSequence::CurrentElement() {
+ if (elements_.empty())
+ return NULL;
+
+ size_t current_index = last_element_ % elements_.size();
+ return elements_[current_index].get();
+}
+
} // namespace ui
diff --git a/ui/compositor/layer_animation_sequence.h b/ui/compositor/layer_animation_sequence.h
index 9691ee7..6f7c96e 100644
--- a/ui/compositor/layer_animation_sequence.h
+++ b/ui/compositor/layer_animation_sequence.h
@@ -42,11 +42,25 @@ class COMPOSITOR_EXPORT LayerAnimationSequence
virtual ~LayerAnimationSequence();
// Sets the start time for the animation. This must be called before the
- // first call to {Progress, IsFinished}. Once the animation is finished, this
+ // first call to {Start, IsFinished}. Once the animation is finished, this
// must be called again in order to restart the animation.
void set_start_time(base::TimeTicks start_time) { start_time_ = start_time; }
base::TimeTicks start_time() const { return start_time_; }
+ // Sets a flag indicating that this sequence will start together with other
+ // sequences, and at least one of the sequences in this group has a threaded
+ // first element.
+ void set_waiting_for_group_start(bool waiting) {
+ waiting_for_group_start_ = waiting;
+ }
+ bool waiting_for_group_start() { return waiting_for_group_start_; }
+
+ // This must be called before the first call to Progress. If starting the
+ // animation involves dispatching to another thread, then this will proceed
+ // with that dispatch, ultimately resulting in the animation getting an
+ // effective start time (the time the animation starts on the other thread).
+ void Start(LayerAnimationDelegate* delegate);
+
// Updates the delegate to the appropriate value for |now|. Requests a
// redraw if it is required.
void Progress(base::TimeTicks now, LayerAnimationDelegate* delegate);
@@ -64,7 +78,7 @@ class COMPOSITOR_EXPORT LayerAnimationSequence
void GetTargetValue(LayerAnimationElement::TargetValue* target) const;
// Aborts the given animation.
- void Abort();
+ void Abort(LayerAnimationDelegate* delegate);
// All properties modified by the sequence.
const LayerAnimationElement::AnimatableProperties& properties() const {
@@ -84,18 +98,34 @@ class COMPOSITOR_EXPORT LayerAnimationSequence
bool HasCommonProperty(
const LayerAnimationElement::AnimatableProperties& other) const;
+ // Returns true if the first element animates on the compositor thread.
+ bool IsFirstElementThreaded() const;
+
+ // Used to identify groups of sequences that are supposed to start together.
+ int animation_group_id() const { return animation_group_id_; }
+ void set_animation_group_id(int id) { animation_group_id_ = id; }
+
// These functions are used for adding or removing observers from the observer
// list. The observers are notified when animations end.
void AddObserver(LayerAnimationObserver* observer);
void RemoveObserver(LayerAnimationObserver* observer);
+ // Called when a threaded animation is actually started.
+ void OnThreadedAnimationStarted(const cc::AnimationEvent& event);
+
// Called when the animator schedules this sequence.
void OnScheduled();
// Called when the animator is destroyed.
void OnAnimatorDestroyed();
+ // The last_progressed_fraction of the element most recently progressed by
+ // by this sequence. Returns 0.0 if no elements have been progressed.
+ double last_progressed_fraction() const { return last_progressed_fraction_; }
+
private:
+ friend class LayerAnimatorTestController;
+
typedef std::vector<linked_ptr<LayerAnimationElement> > Elements;
FRIEND_TEST_ALL_PREFIXES(LayerAnimatorTest,
@@ -110,6 +140,9 @@ class COMPOSITOR_EXPORT LayerAnimationSequence
// Notifies the observers that this sequence has been aborted.
void NotifyAborted();
+ // The currently animating element.
+ LayerAnimationElement* CurrentElement();
+
// The union of all the properties modified by all elements in the sequence.
LayerAnimationElement::AnimatableProperties properties_;
@@ -126,9 +159,20 @@ class COMPOSITOR_EXPORT LayerAnimationSequence
// The start time of the current run of the sequence.
base::TimeTicks start_time_;
+ // True if this sequence will start together with other sequences, and at
+ // least one of the sequences in this group has a threaded first element.
+ bool waiting_for_group_start_;
+
+ // Identifies groups of sequences that are supposed to start together.
+ int animation_group_id_;
+
// These parties are notified when layer animations end.
ObserverList<LayerAnimationObserver> observers_;
+ // Tracks the last_progressed_fraction() of the most recently progressed
+ // element.
+ double last_progressed_fraction_;
+
DISALLOW_COPY_AND_ASSIGN(LayerAnimationSequence);
};
diff --git a/ui/compositor/layer_animation_sequence_unittest.cc b/ui/compositor/layer_animation_sequence_unittest.cc
index a6bb402..e32e9b1 100644
--- a/ui/compositor/layer_animation_sequence_unittest.cc
+++ b/ui/compositor/layer_animation_sequence_unittest.cc
@@ -34,7 +34,7 @@ TEST(LayerAnimationSequenceTest, NoElement) {
}
// Check that the sequences progresses the delegate as expected when it contains
-// a single element.
+// a single non-threaded element.
TEST(LayerAnimationSequenceTest, SingleElement) {
LayerAnimationSequence sequence;
TestLayerAnimationDelegate delegate;
@@ -44,26 +44,70 @@ TEST(LayerAnimationSequenceTest, SingleElement) {
base::TimeTicks start_time;
base::TimeDelta delta = base::TimeDelta::FromSeconds(1);
sequence.AddElement(
- LayerAnimationElement::CreateOpacityElement(target, delta));
+ LayerAnimationElement::CreateBrightnessElement(target, delta));
for (int i = 0; i < 2; ++i) {
start_time += delta;
sequence.set_start_time(start_time);
- delegate.SetOpacityFromAnimation(start);
+ delegate.SetBrightnessFromAnimation(start);
+ sequence.Start(&delegate);
sequence.Progress(start_time, &delegate);
- EXPECT_FLOAT_EQ(start, delegate.GetOpacityForAnimation());
+ EXPECT_FLOAT_EQ(start, delegate.GetBrightnessForAnimation());
sequence.Progress(start_time + base::TimeDelta::FromMilliseconds(500),
&delegate);
- EXPECT_FLOAT_EQ(middle, delegate.GetOpacityForAnimation());
+ EXPECT_FLOAT_EQ(middle, delegate.GetBrightnessForAnimation());
+ EXPECT_TRUE(sequence.IsFinished(start_time + delta));
sequence.Progress(start_time + base::TimeDelta::FromMilliseconds(1000),
&delegate);
+ EXPECT_FLOAT_EQ(target, delegate.GetBrightnessForAnimation());
+ }
+
+ EXPECT_TRUE(sequence.properties().size() == 1);
+ EXPECT_TRUE(sequence.properties().find(LayerAnimationElement::BRIGHTNESS) !=
+ sequence.properties().end());
+}
+
+// Check that the sequences progresses the delegate as expected when it contains
+// a single threaded element.
+TEST(LayerAnimationSequenceTest, SingleThreadedElement) {
+ LayerAnimationSequence sequence;
+ TestLayerAnimationDelegate delegate;
+ float start = 0.0f;
+ float middle = 0.5f;
+ float target = 1.0f;
+ base::TimeTicks start_time;
+ base::TimeTicks effective_start;
+ base::TimeDelta delta = base::TimeDelta::FromSeconds(1);
+ sequence.AddElement(
+ LayerAnimationElement::CreateOpacityElement(target, delta));
+
+ for (int i = 0; i < 2; ++i) {
+ int group_id = 1;
+ sequence.set_animation_group_id(group_id);
+ start_time = effective_start + delta;
+ sequence.set_start_time(start_time);
+ delegate.SetOpacityFromAnimation(start);
+ sequence.Start(&delegate);
+ sequence.Progress(start_time, &delegate);
+ EXPECT_FLOAT_EQ(start, sequence.last_progressed_fraction());
+ effective_start = start_time + delta;
+ sequence.OnThreadedAnimationStarted(cc::AnimationEvent(
+ cc::AnimationEvent::Started,
+ 0,
+ group_id,
+ cc::Animation::Opacity,
+ (effective_start - base::TimeTicks()).InSecondsF()));
+ sequence.Progress(effective_start + delta/2, &delegate);
+ EXPECT_FLOAT_EQ(middle, sequence.last_progressed_fraction());
+ EXPECT_TRUE(sequence.IsFinished(effective_start + delta));
+ sequence.Progress(effective_start + delta, &delegate);
+ EXPECT_FLOAT_EQ(target, sequence.last_progressed_fraction());
EXPECT_FLOAT_EQ(target, delegate.GetOpacityForAnimation());
}
EXPECT_TRUE(sequence.properties().size() == 1);
EXPECT_TRUE(sequence.properties().find(LayerAnimationElement::OPACITY) !=
sequence.properties().end());
- EXPECT_TRUE(sequence.IsFinished(start_time + delta));
}
// Check that the sequences progresses the delegate as expected when it contains
@@ -72,9 +116,9 @@ TEST(LayerAnimationSequenceTest, MultipleElement) {
LayerAnimationSequence sequence;
TestLayerAnimationDelegate delegate;
float start_opacity = 0.0f;
- float middle_opacity = 0.5f;
float target_opacity = 1.0f;
base::TimeTicks start_time;
+ base::TimeTicks effective_start;
base::TimeDelta delta = base::TimeDelta::FromSeconds(1);
sequence.AddElement(
LayerAnimationElement::CreateOpacityElement(target_opacity, delta));
@@ -94,23 +138,34 @@ TEST(LayerAnimationSequenceTest, MultipleElement) {
LayerAnimationElement::CreateTransformElement(target_transform, delta));
for (int i = 0; i < 2; ++i) {
- start_time += delta + delta + delta;
+ int group_id = 1;
+ sequence.set_animation_group_id(group_id);
+ start_time = effective_start + 3 * delta;
sequence.set_start_time(start_time);
delegate.SetOpacityFromAnimation(start_opacity);
delegate.SetTransformFromAnimation(start_transform);
+ sequence.Start(&delegate);
sequence.Progress(start_time, &delegate);
- EXPECT_FLOAT_EQ(start_opacity, delegate.GetOpacityForAnimation());
- sequence.Progress(start_time + base::TimeDelta::FromMilliseconds(500),
- &delegate);
- EXPECT_FLOAT_EQ(middle_opacity, delegate.GetOpacityForAnimation());
- sequence.Progress(start_time + base::TimeDelta::FromMilliseconds(1000),
- &delegate);
+ EXPECT_FLOAT_EQ(0.0, sequence.last_progressed_fraction());
+ effective_start = start_time + delta;
+ sequence.OnThreadedAnimationStarted(cc::AnimationEvent(
+ cc::AnimationEvent::Started,
+ 0,
+ group_id,
+ cc::Animation::Opacity,
+ (effective_start - base::TimeTicks()).InSecondsF()));
+ sequence.Progress(effective_start + delta/2, &delegate);
+ EXPECT_FLOAT_EQ(0.5, sequence.last_progressed_fraction());
+ sequence.Progress(effective_start + delta, &delegate);
EXPECT_FLOAT_EQ(target_opacity, delegate.GetOpacityForAnimation());
+
+ // Now at the start of the pause.
+ EXPECT_FLOAT_EQ(0.0, sequence.last_progressed_fraction());
TestLayerAnimationDelegate copy = delegate;
// In the middle of the pause -- nothing should have changed.
- sequence.Progress(start_time + base::TimeDelta::FromMilliseconds(1500),
+ sequence.Progress(effective_start + delta + delta/2,
&delegate);
CheckApproximatelyEqual(delegate.GetBoundsForAnimation(),
copy.GetBoundsForAnimation());
@@ -120,16 +175,14 @@ TEST(LayerAnimationSequenceTest, MultipleElement) {
copy.GetOpacityForAnimation());
- sequence.Progress(start_time + base::TimeDelta::FromMilliseconds(2000),
- &delegate);
+ sequence.Progress(effective_start + 2 * delta, &delegate);
CheckApproximatelyEqual(start_transform,
delegate.GetTransformForAnimation());
- sequence.Progress(start_time + base::TimeDelta::FromMilliseconds(2500),
- &delegate);
+ sequence.Progress(effective_start + 2 * delta + delta/2, &delegate);
CheckApproximatelyEqual(middle_transform,
delegate.GetTransformForAnimation());
- sequence.Progress(start_time + base::TimeDelta::FromMilliseconds(3000),
- &delegate);
+ EXPECT_TRUE(sequence.IsFinished(effective_start + 3 * delta));
+ sequence.Progress(effective_start + 3 * delta, &delegate);
CheckApproximatelyEqual(target_transform,
delegate.GetTransformForAnimation());
}
@@ -141,41 +194,41 @@ TEST(LayerAnimationSequenceTest, MultipleElement) {
sequence.properties().end());
EXPECT_TRUE(sequence.properties().find(LayerAnimationElement::BOUNDS) !=
sequence.properties().end());
- EXPECT_TRUE(sequence.IsFinished(start_time + delta + delta + delta));
}
// Check that a sequence can still be aborted if it has cycled many times.
TEST(LayerAnimationSequenceTest, AbortingCyclicSequence) {
LayerAnimationSequence sequence;
TestLayerAnimationDelegate delegate;
- float start_opacity = 0.0f;
- float target_opacity = 1.0f;
+ float start_brightness = 0.0f;
+ float target_brightness = 1.0f;
base::TimeTicks start_time;
base::TimeDelta delta = base::TimeDelta::FromSeconds(1);
sequence.AddElement(
- LayerAnimationElement::CreateOpacityElement(target_opacity, delta));
+ LayerAnimationElement::CreateBrightnessElement(target_brightness, delta));
sequence.AddElement(
- LayerAnimationElement::CreateOpacityElement(start_opacity, delta));
+ LayerAnimationElement::CreateBrightnessElement(start_brightness, delta));
sequence.set_is_cyclic(true);
- delegate.SetOpacityFromAnimation(start_opacity);
+ delegate.SetBrightnessFromAnimation(start_brightness);
start_time += delta;
sequence.set_start_time(start_time);
+ sequence.Start(&delegate);
sequence.Progress(start_time + base::TimeDelta::FromMilliseconds(101000),
&delegate);
- EXPECT_FLOAT_EQ(target_opacity, delegate.GetOpacityForAnimation());
- sequence.Abort();
+ EXPECT_FLOAT_EQ(target_brightness, delegate.GetBrightnessForAnimation());
+ sequence.Abort(&delegate);
// Should be able to reuse the sequence after aborting.
- delegate.SetOpacityFromAnimation(start_opacity);
+ delegate.SetBrightnessFromAnimation(start_brightness);
start_time += base::TimeDelta::FromMilliseconds(101000);
sequence.set_start_time(start_time);
sequence.Progress(start_time + base::TimeDelta::FromMilliseconds(100000),
&delegate);
- EXPECT_FLOAT_EQ(start_opacity, delegate.GetOpacityForAnimation());
+ EXPECT_FLOAT_EQ(start_brightness, delegate.GetBrightnessForAnimation());
}
// Check that a sequence can be 'fast-forwarded' to the end and the target set.
@@ -205,7 +258,7 @@ TEST(LayerAnimationSequenceTest, AddObserver) {
base::TimeDelta delta = base::TimeDelta::FromSeconds(1);
LayerAnimationSequence sequence;
sequence.AddElement(
- LayerAnimationElement::CreateOpacityElement(1.0f, delta));
+ LayerAnimationElement::CreateBrightnessElement(1.0f, delta));
for (int i = 0; i < 2; ++i) {
start_time += delta;
sequence.set_start_time(start_time);
diff --git a/ui/compositor/layer_animator.cc b/ui/compositor/layer_animator.cc
index e6e663d..e18c796 100644
--- a/ui/compositor/layer_animator.cc
+++ b/ui/compositor/layer_animator.cc
@@ -7,6 +7,7 @@
#include "base/debug/trace_event.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
+#include "cc/animation_id_provider.h"
#include "ui/base/animation/animation_container.h"
#include "ui/compositor/compositor.h"
#include "ui/compositor/layer.h"
@@ -202,9 +203,17 @@ void LayerAnimator::StartTogether(
LayerAnimationElement::CreatePauseElement(animated_properties,
base::TimeDelta())));
+ bool wait_for_group_start = false;
+ for (iter = animations.begin(); iter != animations.end(); ++iter)
+ wait_for_group_start |= (*iter)->IsFirstElementThreaded();
+
+ int group_id = cc::AnimationIdProvider::NextGroupId();
+
// These animations (provided they don't animate any common properties) will
// now animate together if trivially scheduled.
for (iter = animations.begin(); iter != animations.end(); ++iter) {
+ (*iter)->set_animation_group_id(group_id);
+ (*iter)->set_waiting_for_group_start(wait_for_group_start);
ScheduleAnimation(*iter);
}
@@ -232,9 +241,17 @@ void LayerAnimator::ScheduleTogether(
LayerAnimationElement::CreatePauseElement(animated_properties,
base::TimeDelta())));
+ bool wait_for_group_start = false;
+ for (iter = animations.begin(); iter != animations.end(); ++iter)
+ wait_for_group_start |= (*iter)->IsFirstElementThreaded();
+
+ int group_id = cc::AnimationIdProvider::NextGroupId();
+
// These animations (provided they don't animate any common properties) will
// now animate together if trivially scheduled.
for (iter = animations.begin(); iter != animations.end(); ++iter) {
+ (*iter)->set_animation_group_id(group_id);
+ (*iter)->set_waiting_for_group_start(wait_for_group_start);
ScheduleAnimation(*iter);
}
@@ -299,11 +316,50 @@ void LayerAnimator::RemoveObserver(LayerAnimationObserver* observer) {
}
}
+void LayerAnimator::OnThreadedAnimationStarted(
+ const cc::AnimationEvent& event) {
+ LayerAnimationElement::AnimatableProperty property =
+ LayerAnimationElement::ToAnimatableProperty(event.targetProperty);
+
+ RunningAnimation* running = GetRunningAnimation(property);
+ if (!running)
+ return;
+ DCHECK(running->is_sequence_alive());
+
+ if (running->sequence()->animation_group_id() != event.groupId)
+ return;
+
+ running->sequence()->OnThreadedAnimationStarted(event);
+ if (!running->sequence()->waiting_for_group_start())
+ return;
+
+ base::TimeTicks start_time = base::TimeTicks::FromInternalValue(
+ event.monotonicTime * base::Time::kMicrosecondsPerSecond);
+
+ running->sequence()->set_waiting_for_group_start(false);
+
+ // The call to GetRunningAnimation made above already purged deleted
+ // animations, so we are guaranteed that all the animations we iterate
+ // over now are alive.
+ for (RunningAnimations::iterator iter = running_animations_.begin();
+ iter != running_animations_.end(); ++iter) {
+ // Ensure that each sequence is only Started once, regardless of the
+ // number of sequences in the group that have threaded first elements.
+ if (((*iter).sequence()->animation_group_id() == event.groupId) &&
+ !(*iter).sequence()->IsFirstElementThreaded() &&
+ (*iter).sequence()->waiting_for_group_start()) {
+ (*iter).sequence()->set_start_time(start_time);
+ (*iter).sequence()->set_waiting_for_group_start(false);
+ (*iter).sequence()->Start(delegate());
+ }
+ }
+}
+
// LayerAnimator protected -----------------------------------------------------
void LayerAnimator::ProgressAnimation(LayerAnimationSequence* sequence,
base::TimeTicks now) {
- if (!delegate())
+ if (!delegate() || sequence->waiting_for_group_start())
return;
sequence->Progress(now, delegate());
@@ -399,11 +455,14 @@ LayerAnimationSequence* LayerAnimator::RemoveAnimation(
LayerAnimationSequence* sequence) {
linked_ptr<LayerAnimationSequence> to_return;
+ bool is_running = false;
+
// First remove from running animations
for (RunningAnimations::iterator iter = running_animations_.begin();
iter != running_animations_.end(); ++iter) {
if ((*iter).sequence() == sequence) {
running_animations_.erase(iter);
+ is_running = true;
break;
}
}
@@ -418,6 +477,39 @@ LayerAnimationSequence* LayerAnimator::RemoveAnimation(
}
}
+ if (!to_return.get() ||
+ !to_return->waiting_for_group_start() ||
+ !to_return->IsFirstElementThreaded())
+ return to_return.release();
+
+ // The removed sequence may have been responsible for making other sequences
+ // wait for a group start. If no other sequences in the group have a
+ // threaded first element, the group no longer needs the additional wait.
+ bool is_wait_still_needed = false;
+ int group_id = to_return->animation_group_id();
+ for (AnimationQueue::iterator queue_iter = animation_queue_.begin();
+ queue_iter != animation_queue_.end(); ++queue_iter) {
+ if (((*queue_iter)->animation_group_id() == group_id) &&
+ (*queue_iter)->IsFirstElementThreaded()) {
+ is_wait_still_needed = true;
+ break;
+ }
+ }
+
+ if (is_wait_still_needed)
+ return to_return.release();
+
+ for (AnimationQueue::iterator queue_iter = animation_queue_.begin();
+ queue_iter != animation_queue_.end(); ++queue_iter) {
+ if ((*queue_iter)->animation_group_id() == group_id &&
+ (*queue_iter)->waiting_for_group_start()) {
+ (*queue_iter)->set_waiting_for_group_start(false);
+ if (is_running) {
+ (*queue_iter)->set_start_time(last_step_time_);
+ (*queue_iter)->Start(delegate());
+ }
+ }
+ }
return to_return.release();
}
@@ -426,7 +518,7 @@ void LayerAnimator::FinishAnimation(
scoped_refptr<LayerAnimator> retain(this);
scoped_ptr<LayerAnimationSequence> removed(RemoveAnimation(sequence));
if (abort)
- sequence->Abort();
+ sequence->Abort(delegate());
else
ProgressAnimationToEnd(sequence);
ProcessQueue();
@@ -502,7 +594,7 @@ void LayerAnimator::RemoveAllAnimationsWithACommonProperty(
scoped_ptr<LayerAnimationSequence> removed(
SAFE_INVOKE_PTR(RemoveAnimation, running_animations_copy[i]));
if (abort)
- running_animations_copy[i].sequence()->Abort();
+ running_animations_copy[i].sequence()->Abort(delegate());
else
SAFE_INVOKE_VOID(ProgressAnimationToEnd, running_animations_copy[i]);
}
@@ -522,7 +614,7 @@ void LayerAnimator::RemoveAllAnimationsWithACommonProperty(
if (sequences[i]->HasCommonProperty(sequence->properties())) {
scoped_ptr<LayerAnimationSequence> removed(RemoveAnimation(sequences[i]));
if (abort)
- sequences[i]->Abort();
+ sequences[i]->Abort(delegate());
else
ProgressAnimationToEnd(sequences[i]);
}
@@ -684,7 +776,13 @@ bool LayerAnimator::StartSequenceImmediately(LayerAnimationSequence* sequence) {
else
start_time = base::TimeTicks::Now();
- sequence->set_start_time(start_time);
+ if (!sequence->animation_group_id())
+ sequence->set_animation_group_id(cc::AnimationIdProvider::NextGroupId());
+ if (!sequence->waiting_for_group_start() ||
+ sequence->IsFirstElementThreaded()) {
+ sequence->set_start_time(start_time);
+ sequence->Start(delegate());
+ }
running_animations_.push_back(
RunningAnimation(sequence->AsWeakPtr()));
@@ -733,7 +831,7 @@ void LayerAnimator::ClearAnimationsInternal() {
scoped_ptr<LayerAnimationSequence> removed(
RemoveAnimation(running_animations_copy[i].sequence()));
if (removed.get())
- removed->Abort();
+ removed->Abort(delegate());
}
// This *should* have cleared the list of running animations.
DCHECK(running_animations_.empty());
diff --git a/ui/compositor/layer_animator.h b/ui/compositor/layer_animator.h
index bf8ee7c..27cb9db 100644
--- a/ui/compositor/layer_animator.h
+++ b/ui/compositor/layer_animator.h
@@ -113,14 +113,20 @@ class COMPOSITOR_EXPORT LayerAnimator
// of this animation sequence.
void ScheduleAnimation(LayerAnimationSequence* animation);
- // Starts the animations to be run together. Obviously will not work if
- // they animate any common properties. The animator takes ownership of the
+ // Starts the animations to be run together, ensuring that the first elements
+ // in these sequences have the same effective start time even when some of
+ // them start on the compositor thread (but there is no such guarantee for
+ // the effective start time of subsequent elements). Obviously will not work
+ // if they animate any common properties. The animator takes ownership of the
// animation sequences. Takes PreemptionStrategy into account.
void StartTogether(const std::vector<LayerAnimationSequence*>& animations);
- // Schedules the animations to be run together. Obviously will not work if
- // they animate any common properties. The animator takes ownership of the
- // animation sequences.
+ // Schedules the animations to be run together, ensuring that the first
+ // elements in these sequences have the same effective start time even when
+ // some of them start on the compositor thread (but there is no such guarantee
+ // for the effective start time of subsequent elements). Obviously will not
+ // work if they animate any common properties. The animator takes ownership
+ // of the animation sequences.
void ScheduleTogether(const std::vector<LayerAnimationSequence*>& animations);
// Schedules a pause for length |duration| of all the specified properties.
@@ -159,6 +165,9 @@ class COMPOSITOR_EXPORT LayerAnimator
void AddObserver(LayerAnimationObserver* observer);
void RemoveObserver(LayerAnimationObserver* observer);
+ // Called when a threaded animation is actually started.
+ void OnThreadedAnimationStarted(const cc::AnimationEvent& event);
+
// This determines how implicit animations will be tweened. This has no
// effect on animations that are explicitly started or scheduled. The default
// is Tween::LINEAR.
@@ -216,6 +225,7 @@ class COMPOSITOR_EXPORT LayerAnimator
private:
friend class base::RefCounted<LayerAnimator>;
friend class ScopedLayerAnimationSettings;
+ friend class LayerAnimatorTestController;
class RunningAnimation {
public:
diff --git a/ui/compositor/layer_animator_unittest.cc b/ui/compositor/layer_animator_unittest.cc
index c93d117..5ecb031 100644
--- a/ui/compositor/layer_animator_unittest.cc
+++ b/ui/compositor/layer_animator_unittest.cc
@@ -14,6 +14,7 @@
#include "ui/compositor/layer_animation_element.h"
#include "ui/compositor/layer_animation_sequence.h"
#include "ui/compositor/scoped_layer_animation_settings.h"
+#include "ui/compositor/test/layer_animator_test_controller.h"
#include "ui/compositor/test/test_layer_animation_delegate.h"
#include "ui/compositor/test/test_layer_animation_observer.h"
#include "ui/compositor/test/test_utils.h"
@@ -155,10 +156,10 @@ TEST(LayerAnimatorTest, ImplicitAnimation) {
TestLayerAnimationDelegate delegate;
animator->SetDelegate(&delegate);
base::TimeTicks now = base::TimeTicks::Now();
- animator->SetOpacity(0.5);
+ animator->SetBrightness(0.5);
EXPECT_TRUE(animator->is_animating());
element->Step(now + base::TimeDelta::FromSeconds(1));
- EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), 0.5);
+ EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), 0.5);
}
// Checks that if the animator is a default animator, that implicit animations
@@ -168,9 +169,9 @@ TEST(LayerAnimatorTest, NoImplicitAnimation) {
animator->set_disable_timer_for_test(true);
TestLayerAnimationDelegate delegate;
animator->SetDelegate(&delegate);
- animator->SetOpacity(0.5);
+ animator->SetBrightness(0.5);
EXPECT_FALSE(animator->is_animating());
- EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), 0.5);
+ EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), 0.5);
}
// Checks that StopAnimatingProperty stops animation for that property, and also
@@ -235,8 +236,8 @@ TEST(LayerAnimatorTest, AbortAllAnimations) {
CheckApproximatelyEqual(initial_bounds, delegate.GetBoundsForAnimation());
}
-// Schedule an animation that can run immediately. This is the trivial case and
-// should result in the animation being started immediately.
+// Schedule a non-threaded animation that can run immediately. This is the
+// trivial case and should result in the animation being started immediately.
TEST(LayerAnimatorTest, ScheduleAnimationThatCanRunImmediately) {
scoped_refptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator());
AnimationContainerElement* element = animator.get();
@@ -244,36 +245,85 @@ TEST(LayerAnimatorTest, ScheduleAnimationThatCanRunImmediately) {
TestLayerAnimationDelegate delegate;
animator->SetDelegate(&delegate);
- double start_opacity(0.0);
- double middle_opacity(0.5);
- double target_opacity(1.0);
+ double start_brightness(0.0);
+ double middle_brightness(0.5);
+ double target_brightness(1.0);
base::TimeDelta delta = base::TimeDelta::FromSeconds(1);
- delegate.SetOpacityFromAnimation(start_opacity);
+ delegate.SetBrightnessFromAnimation(start_brightness);
animator->ScheduleAnimation(
new LayerAnimationSequence(
- LayerAnimationElement::CreateOpacityElement(target_opacity, delta)));
+ LayerAnimationElement::CreateBrightnessElement(target_brightness,
+ delta)));
EXPECT_TRUE(animator->is_animating());
- EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), start_opacity);
+ EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), start_brightness);
base::TimeTicks start_time = animator->last_step_time();
element->Step(start_time + base::TimeDelta::FromMilliseconds(500));
EXPECT_TRUE(animator->is_animating());
- EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), middle_opacity);
+ EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), middle_brightness);
element->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
EXPECT_FALSE(animator->is_animating());
+ EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), target_brightness);
+}
+
+// Schedule a threaded animation that can run immediately.
+TEST(LayerAnimatorTest, ScheduleThreadedAnimationThatCanRunImmediately) {
+ LayerAnimatorTestController test_controller(
+ LayerAnimator::CreateDefaultAnimator());
+ AnimationContainerElement* element = test_controller.animator();
+ test_controller.animator()->set_disable_timer_for_test(true);
+ TestLayerAnimationDelegate delegate;
+ test_controller.animator()->SetDelegate(&delegate);
+
+ double start_opacity(0.0);
+ double target_opacity(1.0);
+
+ base::TimeDelta delta = base::TimeDelta::FromSeconds(1);
+
+ delegate.SetOpacityFromAnimation(start_opacity);
+
+ test_controller.animator()->ScheduleAnimation(
+ new LayerAnimationSequence(
+ LayerAnimationElement::CreateOpacityElement(target_opacity, delta)));
+
+ EXPECT_TRUE(test_controller.animator()->is_animating());
+ EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), start_opacity);
+
+ base::TimeTicks start_time = test_controller.animator()->last_step_time();
+ base::TimeTicks effective_start = start_time + delta;
+
+ test_controller.animator()->OnThreadedAnimationStarted(cc::AnimationEvent(
+ cc::AnimationEvent::Started,
+ 0,
+ test_controller.GetRunningSequence(LayerAnimationElement::OPACITY)->
+ animation_group_id(),
+ cc::Animation::Opacity,
+ (effective_start - base::TimeTicks()).InSecondsF()));
+
+ element->Step(effective_start + delta/2);
+
+ EXPECT_TRUE(test_controller.animator()->is_animating());
+ EXPECT_FLOAT_EQ(
+ 0.5,
+ test_controller.GetRunningSequence(LayerAnimationElement::OPACITY)->
+ last_progressed_fraction());
+
+ element->Step(effective_start + delta);
+
+ EXPECT_FALSE(test_controller.animator()->is_animating());
EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), target_opacity);
}
-// Schedule two animations on separate properties. Both animations should
-// start immediately and should progress in lock step.
+// Schedule two non-threaded animations on separate properties. Both animations
+// should start immediately and should progress in lock step.
TEST(LayerAnimatorTest, ScheduleTwoAnimationsThatCanRunImmediately) {
scoped_refptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator());
AnimationContainerElement* element = animator.get();
@@ -281,9 +331,9 @@ TEST(LayerAnimatorTest, ScheduleTwoAnimationsThatCanRunImmediately) {
TestLayerAnimationDelegate delegate;
animator->SetDelegate(&delegate);
- double start_opacity(0.0);
- double middle_opacity(0.5);
- double target_opacity(1.0);
+ double start_brightness(0.0);
+ double middle_brightness(0.5);
+ double target_brightness(1.0);
gfx::Rect start_bounds, target_bounds, middle_bounds;
start_bounds = target_bounds = middle_bounds = gfx::Rect(0, 0, 50, 50);
@@ -292,19 +342,20 @@ TEST(LayerAnimatorTest, ScheduleTwoAnimationsThatCanRunImmediately) {
base::TimeDelta delta = base::TimeDelta::FromSeconds(1);
- delegate.SetOpacityFromAnimation(start_opacity);
+ delegate.SetBrightnessFromAnimation(start_brightness);
delegate.SetBoundsFromAnimation(start_bounds);
animator->ScheduleAnimation(
new LayerAnimationSequence(
- LayerAnimationElement::CreateOpacityElement(target_opacity, delta)));
+ LayerAnimationElement::CreateBrightnessElement(target_brightness,
+ delta)));
animator->ScheduleAnimation(
new LayerAnimationSequence(
LayerAnimationElement::CreateBoundsElement(target_bounds, delta)));
EXPECT_TRUE(animator->is_animating());
- EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), start_opacity);
+ EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), start_brightness);
CheckApproximatelyEqual(delegate.GetBoundsForAnimation(), start_bounds);
base::TimeTicks start_time = animator->last_step_time();
@@ -312,12 +363,77 @@ TEST(LayerAnimatorTest, ScheduleTwoAnimationsThatCanRunImmediately) {
element->Step(start_time + base::TimeDelta::FromMilliseconds(500));
EXPECT_TRUE(animator->is_animating());
- EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), middle_opacity);
+ EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), middle_brightness);
CheckApproximatelyEqual(delegate.GetBoundsForAnimation(), middle_bounds);
element->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
EXPECT_FALSE(animator->is_animating());
+ EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), target_brightness);
+ CheckApproximatelyEqual(delegate.GetBoundsForAnimation(), target_bounds);
+}
+
+// Schedule a threaded and a non-threaded animation on separate properties. Both
+// animations should progress in lock step.
+TEST(LayerAnimatorTest, ScheduleThreadedAndNonThreadedAnimations) {
+ LayerAnimatorTestController test_controller(
+ LayerAnimator::CreateDefaultAnimator());
+ AnimationContainerElement* element = test_controller.animator();
+ test_controller.animator()->set_disable_timer_for_test(true);
+ TestLayerAnimationDelegate delegate;
+ test_controller.animator()->SetDelegate(&delegate);
+
+ double start_opacity(0.0);
+ double target_opacity(1.0);
+
+ gfx::Rect start_bounds, target_bounds, middle_bounds;
+ start_bounds = target_bounds = middle_bounds = gfx::Rect(0, 0, 50, 50);
+ start_bounds.set_x(-90);
+ target_bounds.set_x(90);
+
+ base::TimeDelta delta = base::TimeDelta::FromSeconds(1);
+
+ delegate.SetOpacityFromAnimation(start_opacity);
+ delegate.SetBoundsFromAnimation(start_bounds);
+
+ std::vector<LayerAnimationSequence*> animations;
+ animations.push_back(
+ new LayerAnimationSequence(
+ LayerAnimationElement::CreateOpacityElement(target_opacity, delta)));
+
+ animations.push_back(
+ new LayerAnimationSequence(
+ LayerAnimationElement::CreateBoundsElement(target_bounds, delta)));
+
+ test_controller.animator()->ScheduleTogether(animations);
+
+ EXPECT_TRUE(test_controller.animator()->is_animating());
+ EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), start_opacity);
+ CheckApproximatelyEqual(delegate.GetBoundsForAnimation(), start_bounds);
+
+ base::TimeTicks start_time = test_controller.animator()->last_step_time();
+ base::TimeTicks effective_start = start_time + delta;
+
+ test_controller.animator()->OnThreadedAnimationStarted(cc::AnimationEvent(
+ cc::AnimationEvent::Started,
+ 0,
+ test_controller.GetRunningSequence(LayerAnimationElement::OPACITY)->
+ animation_group_id(),
+ cc::Animation::Opacity,
+ (effective_start - base::TimeTicks()).InSecondsF()));
+
+ element->Step(effective_start + delta/2);
+
+ EXPECT_TRUE(test_controller.animator()->is_animating());
+ EXPECT_FLOAT_EQ(
+ 0.5,
+ test_controller.GetRunningSequence(LayerAnimationElement::OPACITY)->
+ last_progressed_fraction());
+ CheckApproximatelyEqual(delegate.GetBoundsForAnimation(), middle_bounds);
+
+ element->Step(effective_start + delta);
+
+ EXPECT_FALSE(test_controller.animator()->is_animating());
EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), target_opacity);
CheckApproximatelyEqual(delegate.GetBoundsForAnimation(), target_bounds);
}
@@ -331,49 +447,51 @@ TEST(LayerAnimatorTest, ScheduleTwoAnimationsOnSameProperty) {
TestLayerAnimationDelegate delegate;
animator->SetDelegate(&delegate);
- double start_opacity(0.0);
- double middle_opacity(0.5);
- double target_opacity(1.0);
+ double start_brightness(0.0);
+ double middle_brightness(0.5);
+ double target_brightness(1.0);
base::TimeDelta delta = base::TimeDelta::FromSeconds(1);
- delegate.SetOpacityFromAnimation(start_opacity);
+ delegate.SetBrightnessFromAnimation(start_brightness);
animator->ScheduleAnimation(
new LayerAnimationSequence(
- LayerAnimationElement::CreateOpacityElement(target_opacity, delta)));
+ LayerAnimationElement::CreateBrightnessElement(target_brightness,
+ delta)));
animator->ScheduleAnimation(
new LayerAnimationSequence(
- LayerAnimationElement::CreateOpacityElement(start_opacity, delta)));
+ LayerAnimationElement::CreateBrightnessElement(start_brightness,
+ delta)));
EXPECT_TRUE(animator->is_animating());
- EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), start_opacity);
+ EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), start_brightness);
base::TimeTicks start_time = animator->last_step_time();
element->Step(start_time + base::TimeDelta::FromMilliseconds(500));
EXPECT_TRUE(animator->is_animating());
- EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), middle_opacity);
+ EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), middle_brightness);
element->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
EXPECT_TRUE(animator->is_animating());
- EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), target_opacity);
+ EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), target_brightness);
element->Step(start_time + base::TimeDelta::FromMilliseconds(1500));
EXPECT_TRUE(animator->is_animating());
- EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), middle_opacity);
+ EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), middle_brightness);
element->Step(start_time + base::TimeDelta::FromMilliseconds(2000));
EXPECT_FALSE(animator->is_animating());
- EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), start_opacity);
+ EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), start_brightness);
}
-// Schedule [{o}, {o,b}, {b}] and ensure that {b} doesn't run right away. That
+// Schedule [{g}, {g,b}, {b}] and ensure that {b} doesn't run right away. That
// is, ensure that all animations targetting a particular property are run in
// order.
TEST(LayerAnimatorTest, ScheduleBlockedAnimation) {
@@ -383,9 +501,9 @@ TEST(LayerAnimatorTest, ScheduleBlockedAnimation) {
TestLayerAnimationDelegate delegate;
animator->SetDelegate(&delegate);
- double start_opacity(0.0);
- double middle_opacity(0.5);
- double target_opacity(1.0);
+ double start_grayscale(0.0);
+ double middle_grayscale(0.5);
+ double target_grayscale(1.0);
gfx::Rect start_bounds, target_bounds, middle_bounds;
start_bounds = target_bounds = middle_bounds = gfx::Rect(0, 0, 50, 50);
@@ -394,28 +512,30 @@ TEST(LayerAnimatorTest, ScheduleBlockedAnimation) {
base::TimeDelta delta = base::TimeDelta::FromSeconds(1);
- delegate.SetOpacityFromAnimation(start_opacity);
+ delegate.SetGrayscaleFromAnimation(start_grayscale);
delegate.SetBoundsFromAnimation(start_bounds);
animator->ScheduleAnimation(
new LayerAnimationSequence(
- LayerAnimationElement::CreateOpacityElement(target_opacity, delta)));
+ LayerAnimationElement::CreateGrayscaleElement(target_grayscale,
+ delta)));
- scoped_ptr<LayerAnimationSequence> bounds_and_opacity(
+ scoped_ptr<LayerAnimationSequence> bounds_and_grayscale(
new LayerAnimationSequence(
- LayerAnimationElement::CreateOpacityElement(start_opacity, delta)));
+ LayerAnimationElement::CreateGrayscaleElement(start_grayscale,
+ delta)));
- bounds_and_opacity->AddElement(
+ bounds_and_grayscale->AddElement(
LayerAnimationElement::CreateBoundsElement(target_bounds, delta));
- animator->ScheduleAnimation(bounds_and_opacity.release());
+ animator->ScheduleAnimation(bounds_and_grayscale.release());
animator->ScheduleAnimation(
new LayerAnimationSequence(
LayerAnimationElement::CreateBoundsElement(start_bounds, delta)));
EXPECT_TRUE(animator->is_animating());
- EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), start_opacity);
+ EXPECT_FLOAT_EQ(delegate.GetGrayscaleForAnimation(), start_grayscale);
CheckApproximatelyEqual(delegate.GetBoundsForAnimation(), start_bounds);
base::TimeTicks start_time = animator->last_step_time();
@@ -423,37 +543,37 @@ TEST(LayerAnimatorTest, ScheduleBlockedAnimation) {
element->Step(start_time + base::TimeDelta::FromMilliseconds(500));
EXPECT_TRUE(animator->is_animating());
- EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), middle_opacity);
+ EXPECT_FLOAT_EQ(delegate.GetGrayscaleForAnimation(), middle_grayscale);
CheckApproximatelyEqual(delegate.GetBoundsForAnimation(), start_bounds);
element->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
EXPECT_TRUE(animator->is_animating());
- EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), target_opacity);
+ EXPECT_FLOAT_EQ(delegate.GetGrayscaleForAnimation(), target_grayscale);
CheckApproximatelyEqual(delegate.GetBoundsForAnimation(), start_bounds);
element->Step(start_time + base::TimeDelta::FromMilliseconds(2000));
EXPECT_TRUE(animator->is_animating());
- EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), start_opacity);
+ EXPECT_FLOAT_EQ(delegate.GetGrayscaleForAnimation(), start_grayscale);
CheckApproximatelyEqual(delegate.GetBoundsForAnimation(), start_bounds);
element->Step(start_time + base::TimeDelta::FromMilliseconds(3000));
EXPECT_TRUE(animator->is_animating());
- EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), start_opacity);
+ EXPECT_FLOAT_EQ(delegate.GetGrayscaleForAnimation(), start_grayscale);
CheckApproximatelyEqual(delegate.GetBoundsForAnimation(), target_bounds);
element->Step(start_time + base::TimeDelta::FromMilliseconds(4000));
EXPECT_FALSE(animator->is_animating());
- EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), start_opacity);
+ EXPECT_FLOAT_EQ(delegate.GetGrayscaleForAnimation(), start_grayscale);
CheckApproximatelyEqual(delegate.GetBoundsForAnimation(), start_bounds);
}
-// Schedule {o} and then schedule {o} and {b} together. In this case, since
+// Schedule {g} and then schedule {g} and {b} together. In this case, since
// ScheduleTogether is being used, the bounds animation should not start until
-// the second opacity animation starts.
+// the second grayscale animation starts.
TEST(LayerAnimatorTest, ScheduleTogether) {
scoped_refptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator());
AnimationContainerElement* element = animator.get();
@@ -461,8 +581,8 @@ TEST(LayerAnimatorTest, ScheduleTogether) {
TestLayerAnimationDelegate delegate;
animator->SetDelegate(&delegate);
- double start_opacity(0.0);
- double target_opacity(1.0);
+ double start_grayscale(0.0);
+ double target_grayscale(1.0);
gfx::Rect start_bounds, target_bounds, middle_bounds;
start_bounds = target_bounds = gfx::Rect(0, 0, 50, 50);
@@ -471,23 +591,24 @@ TEST(LayerAnimatorTest, ScheduleTogether) {
base::TimeDelta delta = base::TimeDelta::FromSeconds(1);
- delegate.SetOpacityFromAnimation(start_opacity);
+ delegate.SetGrayscaleFromAnimation(start_grayscale);
delegate.SetBoundsFromAnimation(start_bounds);
animator->ScheduleAnimation(
new LayerAnimationSequence(
- LayerAnimationElement::CreateOpacityElement(target_opacity, delta)));
+ LayerAnimationElement::CreateGrayscaleElement(target_grayscale,
+ delta)));
std::vector<LayerAnimationSequence*> sequences;
sequences.push_back(new LayerAnimationSequence(
- LayerAnimationElement::CreateOpacityElement(start_opacity, delta)));
+ LayerAnimationElement::CreateGrayscaleElement(start_grayscale, delta)));
sequences.push_back(new LayerAnimationSequence(
LayerAnimationElement::CreateBoundsElement(target_bounds, delta)));
animator->ScheduleTogether(sequences);
EXPECT_TRUE(animator->is_animating());
- EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), start_opacity);
+ EXPECT_FLOAT_EQ(delegate.GetGrayscaleForAnimation(), start_grayscale);
CheckApproximatelyEqual(delegate.GetBoundsForAnimation(), start_bounds);
base::TimeTicks start_time = animator->last_step_time();
@@ -495,18 +616,18 @@ TEST(LayerAnimatorTest, ScheduleTogether) {
element->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
EXPECT_TRUE(animator->is_animating());
- EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), target_opacity);
+ EXPECT_FLOAT_EQ(delegate.GetGrayscaleForAnimation(), target_grayscale);
CheckApproximatelyEqual(delegate.GetBoundsForAnimation(), start_bounds);
element->Step(start_time + base::TimeDelta::FromMilliseconds(2000));
EXPECT_FALSE(animator->is_animating());
- EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), start_opacity);
+ EXPECT_FLOAT_EQ(delegate.GetGrayscaleForAnimation(), start_grayscale);
CheckApproximatelyEqual(delegate.GetBoundsForAnimation(), target_bounds);
}
-// Start animation (that can run immediately). This is the trivial case (see
-// the trival case for ScheduleAnimation).
+// Start non-threaded animation (that can run immediately). This is the trivial
+// case (see the trival case for ScheduleAnimation).
TEST(LayerAnimatorTest, StartAnimationThatCanRunImmediately) {
scoped_refptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator());
AnimationContainerElement* element = animator.get();
@@ -514,31 +635,79 @@ TEST(LayerAnimatorTest, StartAnimationThatCanRunImmediately) {
TestLayerAnimationDelegate delegate;
animator->SetDelegate(&delegate);
- double start_opacity(0.0);
- double middle_opacity(0.5);
- double target_opacity(1.0);
+ double start_brightness(0.0);
+ double middle_brightness(0.5);
+ double target_brightness(1.0);
base::TimeDelta delta = base::TimeDelta::FromSeconds(1);
- delegate.SetOpacityFromAnimation(start_opacity);
+ delegate.SetBrightnessFromAnimation(start_brightness);
animator->StartAnimation(
new LayerAnimationSequence(
- LayerAnimationElement::CreateOpacityElement(target_opacity, delta)));
+ LayerAnimationElement::CreateBrightnessElement(target_brightness,
+ delta)));
EXPECT_TRUE(animator->is_animating());
- EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), start_opacity);
+ EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), start_brightness);
base::TimeTicks start_time = animator->last_step_time();
element->Step(start_time + base::TimeDelta::FromMilliseconds(500));
EXPECT_TRUE(animator->is_animating());
- EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), middle_opacity);
+ EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), middle_brightness);
element->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
EXPECT_FALSE(animator->is_animating());
+ EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), target_brightness);
+}
+
+// Start threaded animation (that can run immediately).
+TEST(LayerAnimatorTest, StartThreadedAnimationThatCanRunImmediately) {
+ LayerAnimatorTestController test_controller(
+ LayerAnimator::CreateDefaultAnimator());
+ AnimationContainerElement* element = test_controller.animator();
+ test_controller.animator()->set_disable_timer_for_test(true);
+ TestLayerAnimationDelegate delegate;
+ test_controller.animator()->SetDelegate(&delegate);
+
+ double start_opacity(0.0);
+ double target_opacity(1.0);
+
+ base::TimeDelta delta = base::TimeDelta::FromSeconds(1);
+
+ delegate.SetOpacityFromAnimation(start_opacity);
+
+ test_controller.animator()->StartAnimation(
+ new LayerAnimationSequence(
+ LayerAnimationElement::CreateOpacityElement(target_opacity, delta)));
+
+ EXPECT_TRUE(test_controller.animator()->is_animating());
+ EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), start_opacity);
+
+ base::TimeTicks start_time = test_controller.animator()->last_step_time();
+ base::TimeTicks effective_start = start_time + delta;
+
+ test_controller.animator()->OnThreadedAnimationStarted(cc::AnimationEvent(
+ cc::AnimationEvent::Started,
+ 0,
+ test_controller.GetRunningSequence(LayerAnimationElement::OPACITY)->
+ animation_group_id(),
+ cc::Animation::Opacity,
+ (effective_start - base::TimeTicks()).InSecondsF()));
+
+ element->Step(effective_start + delta/2);
+
+ EXPECT_TRUE(test_controller.animator()->is_animating());
+ EXPECT_FLOAT_EQ(
+ 0.5,
+ test_controller.GetRunningSequence(LayerAnimationElement::OPACITY)->
+ last_progressed_fraction());
+
+ element->Step(effective_start + delta);
+ EXPECT_FALSE(test_controller.animator()->is_animating());
EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), target_opacity);
}
@@ -570,7 +739,7 @@ TEST(LayerAnimatorTest, PreemptBySettingNewTarget) {
EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), start_opacity);
}
-// Preempt by animating to new target.
+// Preempt by animating to new target, with a non-threaded animation.
TEST(LayerAnimatorTest, PreemptByImmediatelyAnimatingToNewTarget) {
scoped_refptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator());
AnimationContainerElement* element = animator.get();
@@ -578,20 +747,21 @@ TEST(LayerAnimatorTest, PreemptByImmediatelyAnimatingToNewTarget) {
TestLayerAnimationDelegate delegate;
animator->SetDelegate(&delegate);
- double start_opacity(0.0);
- double middle_opacity(0.5);
- double target_opacity(1.0);
+ double start_brightness(0.0);
+ double middle_brightness(0.5);
+ double target_brightness(1.0);
base::TimeDelta delta = base::TimeDelta::FromSeconds(1);
- delegate.SetOpacityFromAnimation(start_opacity);
+ delegate.SetBrightnessFromAnimation(start_brightness);
animator->set_preemption_strategy(
LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
animator->StartAnimation(
new LayerAnimationSequence(
- LayerAnimationElement::CreateOpacityElement(target_opacity, delta)));
+ LayerAnimationElement::CreateBrightnessElement(target_brightness,
+ delta)));
base::TimeTicks start_time = animator->last_step_time();
@@ -599,26 +769,102 @@ TEST(LayerAnimatorTest, PreemptByImmediatelyAnimatingToNewTarget) {
animator->StartAnimation(
new LayerAnimationSequence(
- LayerAnimationElement::CreateOpacityElement(start_opacity, delta)));
+ LayerAnimationElement::CreateBrightnessElement(start_brightness,
+ delta)));
EXPECT_TRUE(animator->is_animating());
- EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), middle_opacity);
+ EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), middle_brightness);
animator->StartAnimation(
new LayerAnimationSequence(
- LayerAnimationElement::CreateOpacityElement(start_opacity, delta)));
+ LayerAnimationElement::CreateBrightnessElement(start_brightness,
+ delta)));
EXPECT_TRUE(animator->is_animating());
element->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
EXPECT_TRUE(animator->is_animating());
- EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(),
- 0.5 * (start_opacity + middle_opacity));
+ EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(),
+ 0.5 * (start_brightness + middle_brightness));
element->Step(start_time + base::TimeDelta::FromMilliseconds(1500));
EXPECT_FALSE(animator->is_animating());
+ EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), start_brightness);
+}
+
+// Preempt by animating to new target, with a threaded animation.
+TEST(LayerAnimatorTest, PreemptThreadedByImmediatelyAnimatingToNewTarget) {
+ LayerAnimatorTestController test_controller(
+ LayerAnimator::CreateDefaultAnimator());
+ AnimationContainerElement* element = test_controller.animator();
+ test_controller.animator()->set_disable_timer_for_test(true);
+ TestLayerAnimationDelegate delegate;
+ test_controller.animator()->SetDelegate(&delegate);
+
+ double start_opacity(0.0);
+ double middle_opacity(0.5);
+ double target_opacity(1.0);
+
+ base::TimeDelta delta = base::TimeDelta::FromSeconds(1);
+
+ delegate.SetOpacityFromAnimation(start_opacity);
+
+ test_controller.animator()->set_preemption_strategy(
+ LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
+
+ test_controller.animator()->StartAnimation(
+ new LayerAnimationSequence(
+ LayerAnimationElement::CreateOpacityElement(target_opacity, delta)));
+
+ base::TimeTicks start_time = test_controller.animator()->last_step_time();
+ base::TimeTicks effective_start = start_time + delta;
+
+ test_controller.animator()->OnThreadedAnimationStarted(cc::AnimationEvent(
+ cc::AnimationEvent::Started,
+ 0,
+ test_controller.GetRunningSequence(LayerAnimationElement::OPACITY)->
+ animation_group_id(),
+ cc::Animation::Opacity,
+ (effective_start - base::TimeTicks()).InSecondsF()));
+
+ element->Step(effective_start + delta/2);
+
+ test_controller.animator()->StartAnimation(
+ new LayerAnimationSequence(
+ LayerAnimationElement::CreateOpacityElement(start_opacity, delta)));
+
+ EXPECT_TRUE(test_controller.animator()->is_animating());
+ EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), middle_opacity);
+
+ test_controller.animator()->StartAnimation(
+ new LayerAnimationSequence(
+ LayerAnimationElement::CreateOpacityElement(start_opacity, delta)));
+
+ EXPECT_TRUE(test_controller.animator()->is_animating());
+
+ base::TimeTicks second_effective_start = effective_start + delta;
+
+ test_controller.animator()->OnThreadedAnimationStarted(cc::AnimationEvent(
+ cc::AnimationEvent::Started,
+ 0,
+ test_controller.GetRunningSequence(LayerAnimationElement::OPACITY)->
+ animation_group_id(),
+ cc::Animation::Opacity,
+ (second_effective_start - base::TimeTicks()).InSecondsF()));
+
+ element->Step(second_effective_start + delta/2);
+
+ EXPECT_TRUE(test_controller.animator()->is_animating());
+ EXPECT_FLOAT_EQ(
+ 0.5,
+ test_controller.GetRunningSequence(LayerAnimationElement::OPACITY)->
+ last_progressed_fraction());
+
+ element->Step(second_effective_start + delta);
+
+ EXPECT_FALSE(test_controller.animator()->is_animating());
EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), start_opacity);
}
@@ -630,19 +876,20 @@ TEST(LayerAnimatorTest, PreemptEnqueueNewAnimation) {
TestLayerAnimationDelegate delegate;
animator->SetDelegate(&delegate);
- double start_opacity(0.0);
- double middle_opacity(0.5);
- double target_opacity(1.0);
+ double start_brightness(0.0);
+ double middle_brightness(0.5);
+ double target_brightness(1.0);
base::TimeDelta delta = base::TimeDelta::FromSeconds(1);
- delegate.SetOpacityFromAnimation(start_opacity);
+ delegate.SetBrightnessFromAnimation(start_brightness);
animator->set_preemption_strategy(LayerAnimator::ENQUEUE_NEW_ANIMATION);
animator->StartAnimation(
new LayerAnimationSequence(
- LayerAnimationElement::CreateOpacityElement(target_opacity, delta)));
+ LayerAnimationElement::CreateBrightnessElement(target_brightness,
+ delta)));
base::TimeTicks start_time = animator->last_step_time();
@@ -650,27 +897,28 @@ TEST(LayerAnimatorTest, PreemptEnqueueNewAnimation) {
animator->StartAnimation(
new LayerAnimationSequence(
- LayerAnimationElement::CreateOpacityElement(start_opacity, delta)));
+ LayerAnimationElement::CreateBrightnessElement(start_brightness,
+ delta)));
EXPECT_TRUE(animator->is_animating());
- EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), middle_opacity);
+ EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), middle_brightness);
EXPECT_TRUE(animator->is_animating());
element->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
EXPECT_TRUE(animator->is_animating());
- EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), target_opacity);
+ EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), target_brightness);
element->Step(start_time + base::TimeDelta::FromMilliseconds(1500));
EXPECT_TRUE(animator->is_animating());
- EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), middle_opacity);
+ EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), middle_brightness);
element->Step(start_time + base::TimeDelta::FromMilliseconds(2000));
EXPECT_FALSE(animator->is_animating());
- EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), start_opacity);
+ EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), start_brightness);
}
// Start an animation when there are sequences waiting in the queue. In this
@@ -683,19 +931,20 @@ TEST(LayerAnimatorTest, PreemptyByReplacingQueuedAnimations) {
TestLayerAnimationDelegate delegate;
animator->SetDelegate(&delegate);
- double start_opacity(0.0);
- double middle_opacity(0.5);
- double target_opacity(1.0);
+ double start_brightness(0.0);
+ double middle_brightness(0.5);
+ double target_brightness(1.0);
base::TimeDelta delta = base::TimeDelta::FromSeconds(1);
- delegate.SetOpacityFromAnimation(start_opacity);
+ delegate.SetBrightnessFromAnimation(start_brightness);
animator->set_preemption_strategy(LayerAnimator::REPLACE_QUEUED_ANIMATIONS);
animator->StartAnimation(
new LayerAnimationSequence(
- LayerAnimationElement::CreateOpacityElement(target_opacity, delta)));
+ LayerAnimationElement::CreateBrightnessElement(target_brightness,
+ delta)));
base::TimeTicks start_time = animator->last_step_time();
@@ -703,31 +952,33 @@ TEST(LayerAnimatorTest, PreemptyByReplacingQueuedAnimations) {
animator->StartAnimation(
new LayerAnimationSequence(
- LayerAnimationElement::CreateOpacityElement(middle_opacity, delta)));
+ LayerAnimationElement::CreateBrightnessElement(middle_brightness,
+ delta)));
// Queue should now have two animations. Starting a third should replace the
// second.
animator->StartAnimation(
new LayerAnimationSequence(
- LayerAnimationElement::CreateOpacityElement(start_opacity, delta)));
+ LayerAnimationElement::CreateBrightnessElement(start_brightness,
+ delta)));
EXPECT_TRUE(animator->is_animating());
- EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), middle_opacity);
+ EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), middle_brightness);
element->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
EXPECT_TRUE(animator->is_animating());
- EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), target_opacity);
+ EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), target_brightness);
element->Step(start_time + base::TimeDelta::FromMilliseconds(1500));
EXPECT_TRUE(animator->is_animating());
- EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), middle_opacity);
+ EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), middle_brightness);
element->Step(start_time + base::TimeDelta::FromMilliseconds(2000));
EXPECT_FALSE(animator->is_animating());
- EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), start_opacity);
+ EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), start_brightness);
}
TEST(LayerAnimatorTest, StartTogetherSetsLastStepTime) {
@@ -736,14 +987,14 @@ TEST(LayerAnimatorTest, StartTogetherSetsLastStepTime) {
TestLayerAnimationDelegate delegate;
animator->SetDelegate(&delegate);
- double start_opacity(0.0);
- double target_opacity(1.0);
+ double start_grayscale(0.0);
+ double target_grayscale(1.0);
double start_brightness(0.1);
double target_brightness(0.9);
base::TimeDelta delta = base::TimeDelta::FromSeconds(1);
- delegate.SetOpacityFromAnimation(start_opacity);
+ delegate.SetGrayscaleFromAnimation(start_grayscale);
delegate.SetBrightnessFromAnimation(start_brightness);
animator->set_preemption_strategy(
@@ -753,7 +1004,8 @@ TEST(LayerAnimatorTest, StartTogetherSetsLastStepTime) {
animator->StartTogether(
CreateMultiSequence(
- LayerAnimationElement::CreateOpacityElement(target_opacity, delta),
+ LayerAnimationElement::CreateGrayscaleElement(target_grayscale,
+ delta),
LayerAnimationElement::CreateBrightnessElement(target_brightness,
delta)
));
@@ -813,9 +1065,9 @@ TEST(LayerAnimatorTest, MultiPreemptByImmediatelyAnimatingToNewTarget) {
TestLayerAnimationDelegate delegate;
animator->SetDelegate(&delegate);
- double start_opacity(0.0);
- double middle_opacity(0.5);
- double target_opacity(1.0);
+ double start_grayscale(0.0);
+ double middle_grayscale(0.5);
+ double target_grayscale(1.0);
double start_brightness(0.1);
double middle_brightness(0.2);
@@ -823,7 +1075,7 @@ TEST(LayerAnimatorTest, MultiPreemptByImmediatelyAnimatingToNewTarget) {
base::TimeDelta delta = base::TimeDelta::FromSeconds(1);
- delegate.SetOpacityFromAnimation(start_opacity);
+ delegate.SetGrayscaleFromAnimation(start_grayscale);
delegate.SetBrightnessFromAnimation(start_brightness);
animator->set_preemption_strategy(
@@ -831,7 +1083,8 @@ TEST(LayerAnimatorTest, MultiPreemptByImmediatelyAnimatingToNewTarget) {
animator->StartTogether(
CreateMultiSequence(
- LayerAnimationElement::CreateOpacityElement(target_opacity, delta),
+ LayerAnimationElement::CreateGrayscaleElement(target_grayscale,
+ delta),
LayerAnimationElement::CreateBrightnessElement(target_brightness,
delta)
));
@@ -842,17 +1095,17 @@ TEST(LayerAnimatorTest, MultiPreemptByImmediatelyAnimatingToNewTarget) {
animator->StartTogether(
CreateMultiSequence(
- LayerAnimationElement::CreateOpacityElement(start_opacity, delta),
+ LayerAnimationElement::CreateGrayscaleElement(start_grayscale, delta),
LayerAnimationElement::CreateBrightnessElement(start_brightness,
delta)));
EXPECT_TRUE(animator->is_animating());
- EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), middle_opacity);
+ EXPECT_FLOAT_EQ(delegate.GetGrayscaleForAnimation(), middle_grayscale);
EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), middle_brightness);
animator->StartTogether(
CreateMultiSequence(
- LayerAnimationElement::CreateOpacityElement(start_opacity, delta),
+ LayerAnimationElement::CreateGrayscaleElement(start_grayscale, delta),
LayerAnimationElement::CreateBrightnessElement(start_brightness,
delta)));
@@ -861,14 +1114,104 @@ TEST(LayerAnimatorTest, MultiPreemptByImmediatelyAnimatingToNewTarget) {
element->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
EXPECT_TRUE(animator->is_animating());
- EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(),
- 0.5 * (start_opacity + middle_opacity));
+ EXPECT_FLOAT_EQ(delegate.GetGrayscaleForAnimation(),
+ 0.5 * (start_grayscale + middle_grayscale));
EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(),
0.5 * (start_brightness + middle_brightness));
element->Step(start_time + base::TimeDelta::FromMilliseconds(1500));
EXPECT_FALSE(animator->is_animating());
+ EXPECT_FLOAT_EQ(delegate.GetGrayscaleForAnimation(), start_grayscale);
+ EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), start_brightness);
+}
+
+// Preempt a threaded animation by animating to new target.
+TEST(LayerAnimatorTest, MultiPreemptThreadedByImmediatelyAnimatingToNewTarget) {
+ LayerAnimatorTestController test_controller(
+ LayerAnimator::CreateDefaultAnimator());
+ AnimationContainerElement* element = test_controller.animator();
+ test_controller.animator()->set_disable_timer_for_test(true);
+ TestLayerAnimationDelegate delegate;
+ test_controller.animator()->SetDelegate(&delegate);
+
+ double start_opacity(0.0);
+ double middle_opacity(0.5);
+ double target_opacity(1.0);
+
+ double start_brightness(0.1);
+ double middle_brightness(0.2);
+ double target_brightness(0.3);
+
+ base::TimeDelta delta = base::TimeDelta::FromSeconds(1);
+
+ delegate.SetOpacityFromAnimation(start_opacity);
+ delegate.SetBrightnessFromAnimation(start_brightness);
+
+ test_controller.animator()->set_preemption_strategy(
+ LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
+
+ test_controller.animator()->StartTogether(
+ CreateMultiSequence(
+ LayerAnimationElement::CreateOpacityElement(target_opacity, delta),
+ LayerAnimationElement::CreateBrightnessElement(target_brightness,
+ delta)
+ ));
+
+ base::TimeTicks start_time = test_controller.animator()->last_step_time();
+ base::TimeTicks effective_start = start_time + delta;
+
+ test_controller.animator()->OnThreadedAnimationStarted(cc::AnimationEvent(
+ cc::AnimationEvent::Started,
+ 0,
+ test_controller.GetRunningSequence(LayerAnimationElement::OPACITY)->
+ animation_group_id(),
+ cc::Animation::Opacity,
+ (effective_start - base::TimeTicks()).InSecondsF()));
+
+ element->Step(effective_start + delta/2);
+
+ test_controller.animator()->StartTogether(
+ CreateMultiSequence(
+ LayerAnimationElement::CreateOpacityElement(start_opacity, delta),
+ LayerAnimationElement::CreateBrightnessElement(start_brightness,
+ delta)));
+
+ EXPECT_TRUE(test_controller.animator()->is_animating());
+ EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), middle_opacity);
+ EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), middle_brightness);
+
+ test_controller.animator()->StartTogether(
+ CreateMultiSequence(
+ LayerAnimationElement::CreateOpacityElement(start_opacity, delta),
+ LayerAnimationElement::CreateBrightnessElement(start_brightness,
+ delta)));
+
+ EXPECT_TRUE(test_controller.animator()->is_animating());
+
+ base::TimeTicks second_effective_start = effective_start + delta;
+
+ test_controller.animator()->OnThreadedAnimationStarted(cc::AnimationEvent(
+ cc::AnimationEvent::Started,
+ 0,
+ test_controller.GetRunningSequence(LayerAnimationElement::OPACITY)->
+ animation_group_id(),
+ cc::Animation::Opacity,
+ (second_effective_start - base::TimeTicks()).InSecondsF()));
+
+ element->Step(second_effective_start + delta/2);
+
+ EXPECT_TRUE(test_controller.animator()->is_animating());
+ EXPECT_FLOAT_EQ(
+ 0.5,
+ test_controller.GetRunningSequence(LayerAnimationElement::OPACITY)->
+ last_progressed_fraction());
+ EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(),
+ 0.5 * (start_brightness + middle_brightness));
+
+ element->Step(second_effective_start + delta);
+
+ EXPECT_FALSE(test_controller.animator()->is_animating());
EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), start_opacity);
EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), start_brightness);
}
@@ -881,9 +1224,9 @@ TEST(LayerAnimatorTest, MultiPreemptEnqueueNewAnimation) {
TestLayerAnimationDelegate delegate;
animator->SetDelegate(&delegate);
- double start_opacity(0.0);
- double middle_opacity(0.5);
- double target_opacity(1.0);
+ double start_grayscale(0.0);
+ double middle_grayscale(0.5);
+ double target_grayscale(1.0);
double start_brightness(0.1);
double middle_brightness(0.2);
@@ -891,14 +1234,15 @@ TEST(LayerAnimatorTest, MultiPreemptEnqueueNewAnimation) {
base::TimeDelta delta = base::TimeDelta::FromSeconds(1);
- delegate.SetOpacityFromAnimation(start_opacity);
+ delegate.SetGrayscaleFromAnimation(start_grayscale);
delegate.SetBrightnessFromAnimation(start_brightness);
animator->set_preemption_strategy(LayerAnimator::ENQUEUE_NEW_ANIMATION);
animator->StartTogether(
CreateMultiSequence(
- LayerAnimationElement::CreateOpacityElement(target_opacity, delta),
+ LayerAnimationElement::CreateGrayscaleElement(target_grayscale,
+ delta),
LayerAnimationElement::CreateBrightnessElement(target_brightness,
delta)));
@@ -908,12 +1252,12 @@ TEST(LayerAnimatorTest, MultiPreemptEnqueueNewAnimation) {
animator->StartTogether(
CreateMultiSequence(
- LayerAnimationElement::CreateOpacityElement(start_opacity, delta),
+ LayerAnimationElement::CreateGrayscaleElement(start_grayscale, delta),
LayerAnimationElement::CreateBrightnessElement(start_brightness,
delta)));
EXPECT_TRUE(animator->is_animating());
- EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), middle_opacity);
+ EXPECT_FLOAT_EQ(delegate.GetGrayscaleForAnimation(), middle_grayscale);
EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), middle_brightness);
EXPECT_TRUE(animator->is_animating());
@@ -921,19 +1265,19 @@ TEST(LayerAnimatorTest, MultiPreemptEnqueueNewAnimation) {
element->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
EXPECT_TRUE(animator->is_animating());
- EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), target_opacity);
+ EXPECT_FLOAT_EQ(delegate.GetGrayscaleForAnimation(), target_grayscale);
EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), target_brightness);
element->Step(start_time + base::TimeDelta::FromMilliseconds(1500));
EXPECT_TRUE(animator->is_animating());
- EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), middle_opacity);
+ EXPECT_FLOAT_EQ(delegate.GetGrayscaleForAnimation(), middle_grayscale);
EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), middle_brightness);
element->Step(start_time + base::TimeDelta::FromMilliseconds(2000));
EXPECT_FALSE(animator->is_animating());
- EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), start_opacity);
+ EXPECT_FLOAT_EQ(delegate.GetGrayscaleForAnimation(), start_grayscale);
EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), start_brightness);
}
@@ -947,9 +1291,9 @@ TEST(LayerAnimatorTest, MultiPreemptByReplacingQueuedAnimations) {
TestLayerAnimationDelegate delegate;
animator->SetDelegate(&delegate);
- double start_opacity(0.0);
- double middle_opacity(0.5);
- double target_opacity(1.0);
+ double start_grayscale(0.0);
+ double middle_grayscale(0.5);
+ double target_grayscale(1.0);
double start_brightness(0.1);
double middle_brightness(0.2);
@@ -957,14 +1301,15 @@ TEST(LayerAnimatorTest, MultiPreemptByReplacingQueuedAnimations) {
base::TimeDelta delta = base::TimeDelta::FromSeconds(1);
- delegate.SetOpacityFromAnimation(start_opacity);
+ delegate.SetGrayscaleFromAnimation(start_grayscale);
delegate.SetBrightnessFromAnimation(start_brightness);
animator->set_preemption_strategy(LayerAnimator::REPLACE_QUEUED_ANIMATIONS);
animator->StartTogether(
CreateMultiSequence(
- LayerAnimationElement::CreateOpacityElement(target_opacity, delta),
+ LayerAnimationElement::CreateGrayscaleElement(target_grayscale,
+ delta),
LayerAnimationElement::CreateBrightnessElement(target_brightness,
delta)));
@@ -974,7 +1319,8 @@ TEST(LayerAnimatorTest, MultiPreemptByReplacingQueuedAnimations) {
animator->StartTogether(
CreateMultiSequence(
- LayerAnimationElement::CreateOpacityElement(middle_opacity, delta),
+ LayerAnimationElement::CreateGrayscaleElement(middle_grayscale,
+ delta),
LayerAnimationElement::CreateBrightnessElement(middle_brightness,
delta)));
@@ -982,34 +1328,34 @@ TEST(LayerAnimatorTest, MultiPreemptByReplacingQueuedAnimations) {
// second.
animator->StartTogether(
CreateMultiSequence(
- LayerAnimationElement::CreateOpacityElement(start_opacity, delta),
+ LayerAnimationElement::CreateGrayscaleElement(start_grayscale, delta),
LayerAnimationElement::CreateBrightnessElement(start_brightness,
delta)));
EXPECT_TRUE(animator->is_animating());
- EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), middle_opacity);
+ EXPECT_FLOAT_EQ(delegate.GetGrayscaleForAnimation(), middle_grayscale);
EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), middle_brightness);
element->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
EXPECT_TRUE(animator->is_animating());
- EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), target_opacity);
+ EXPECT_FLOAT_EQ(delegate.GetGrayscaleForAnimation(), target_grayscale);
EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), target_brightness);
element->Step(start_time + base::TimeDelta::FromMilliseconds(1500));
EXPECT_TRUE(animator->is_animating());
- EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), middle_opacity);
+ EXPECT_FLOAT_EQ(delegate.GetGrayscaleForAnimation(), middle_grayscale);
EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), middle_brightness);
element->Step(start_time + base::TimeDelta::FromMilliseconds(2000));
EXPECT_FALSE(animator->is_animating());
- EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), start_opacity);
+ EXPECT_FLOAT_EQ(delegate.GetGrayscaleForAnimation(), start_grayscale);
EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), start_brightness);
}
//-------------------------------------------------------
-// Test that cyclic sequences continue to animate.
+// Test that non-threaded cyclic sequences continue to animate.
TEST(LayerAnimatorTest, CyclicSequences) {
scoped_refptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator());
AnimationContainerElement* element = animator.get();
@@ -1017,19 +1363,20 @@ TEST(LayerAnimatorTest, CyclicSequences) {
TestLayerAnimationDelegate delegate;
animator->SetDelegate(&delegate);
- double start_opacity(0.0);
- double target_opacity(1.0);
+ double start_brightness(0.0);
+ double target_brightness(1.0);
base::TimeDelta delta = base::TimeDelta::FromSeconds(1);
- delegate.SetOpacityFromAnimation(start_opacity);
+ delegate.SetBrightnessFromAnimation(start_brightness);
scoped_ptr<LayerAnimationSequence> sequence(
new LayerAnimationSequence(
- LayerAnimationElement::CreateOpacityElement(target_opacity, delta)));
+ LayerAnimationElement::CreateBrightnessElement(target_brightness,
+ delta)));
sequence->AddElement(
- LayerAnimationElement::CreateOpacityElement(start_opacity, delta));
+ LayerAnimationElement::CreateBrightnessElement(start_brightness, delta));
sequence->set_is_cyclic(true);
@@ -1040,35 +1387,140 @@ TEST(LayerAnimatorTest, CyclicSequences) {
element->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
EXPECT_TRUE(animator->is_animating());
- EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), target_opacity);
+ EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), target_brightness);
element->Step(start_time + base::TimeDelta::FromMilliseconds(2000));
EXPECT_TRUE(animator->is_animating());
- EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), start_opacity);
+ EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), start_brightness);
element->Step(start_time + base::TimeDelta::FromMilliseconds(3000));
EXPECT_TRUE(animator->is_animating());
- EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), target_opacity);
+ EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), target_brightness);
// Skip ahead by a lot.
element->Step(start_time + base::TimeDelta::FromMilliseconds(1000000000));
EXPECT_TRUE(animator->is_animating());
- EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), start_opacity);
+ EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), start_brightness);
// Skip ahead by a lot.
element->Step(start_time + base::TimeDelta::FromMilliseconds(1000001000));
EXPECT_TRUE(animator->is_animating());
- EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), target_opacity);
+ EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), target_brightness);
- animator->StopAnimatingProperty(LayerAnimationElement::OPACITY);
+ animator->StopAnimatingProperty(LayerAnimationElement::BRIGHTNESS);
EXPECT_FALSE(animator->is_animating());
}
+// Test that threaded cyclic sequences continue to animate.
+TEST(LayerAnimatorTest, ThreadedCyclicSequences) {
+ LayerAnimatorTestController test_controller(
+ LayerAnimator::CreateDefaultAnimator());
+ AnimationContainerElement* element = test_controller.animator();
+ test_controller.animator()->set_disable_timer_for_test(true);
+ TestLayerAnimationDelegate delegate;
+ test_controller.animator()->SetDelegate(&delegate);
+
+ double start_opacity(0.0);
+ double target_opacity(1.0);
+
+ base::TimeDelta delta = base::TimeDelta::FromSeconds(1);
+
+ delegate.SetOpacityFromAnimation(start_opacity);
+
+ scoped_ptr<LayerAnimationSequence> sequence(
+ new LayerAnimationSequence(
+ LayerAnimationElement::CreateOpacityElement(target_opacity, delta)));
+
+ sequence->AddElement(
+ LayerAnimationElement::CreateOpacityElement(start_opacity, delta));
+
+ sequence->set_is_cyclic(true);
+
+ test_controller.animator()->StartAnimation(sequence.release());
+
+ base::TimeTicks start_time = test_controller.animator()->last_step_time();
+ base::TimeTicks effective_start = start_time + delta;
+
+ test_controller.animator()->OnThreadedAnimationStarted(cc::AnimationEvent(
+ cc::AnimationEvent::Started,
+ 0,
+ test_controller.GetRunningSequence(LayerAnimationElement::OPACITY)->
+ animation_group_id(),
+ cc::Animation::Opacity,
+ (effective_start - base::TimeTicks()).InSecondsF()));
+
+ element->Step(effective_start + delta);
+ EXPECT_TRUE(test_controller.animator()->is_animating());
+ EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), target_opacity);
+
+ base::TimeTicks second_effective_start = effective_start + 2 * delta;
+ test_controller.animator()->OnThreadedAnimationStarted(cc::AnimationEvent(
+ cc::AnimationEvent::Started,
+ 0,
+ test_controller.GetRunningSequence(LayerAnimationElement::OPACITY)->
+ animation_group_id(),
+ cc::Animation::Opacity,
+ (second_effective_start - base::TimeTicks()).InSecondsF()));
+
+ element->Step(second_effective_start + delta);
+
+ EXPECT_TRUE(test_controller.animator()->is_animating());
+ EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), start_opacity);
+
+ base::TimeTicks third_effective_start = second_effective_start + 2 * delta;
+ test_controller.animator()->OnThreadedAnimationStarted(cc::AnimationEvent(
+ cc::AnimationEvent::Started,
+ 0,
+ test_controller.GetRunningSequence(LayerAnimationElement::OPACITY)->
+ animation_group_id(),
+ cc::Animation::Opacity,
+ (third_effective_start - base::TimeTicks()).InSecondsF()));
+
+ element->Step(third_effective_start + delta);
+ EXPECT_TRUE(test_controller.animator()->is_animating());
+ EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), target_opacity);
+
+ base::TimeTicks fourth_effective_start = third_effective_start + 2 * delta;
+ test_controller.animator()->OnThreadedAnimationStarted(cc::AnimationEvent(
+ cc::AnimationEvent::Started,
+ 0,
+ test_controller.GetRunningSequence(LayerAnimationElement::OPACITY)->
+ animation_group_id(),
+ cc::Animation::Opacity,
+ (fourth_effective_start - base::TimeTicks()).InSecondsF()));
+
+ // Skip ahead by a lot.
+ element->Step(fourth_effective_start + 1000 * delta);
+
+ EXPECT_TRUE(test_controller.animator()->is_animating());
+ EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), target_opacity);
+
+ base::TimeTicks fifth_effective_start = fourth_effective_start + 1001 * delta;
+ test_controller.animator()->OnThreadedAnimationStarted(cc::AnimationEvent(
+ cc::AnimationEvent::Started,
+ 0,
+ test_controller.GetRunningSequence(LayerAnimationElement::OPACITY)->
+ animation_group_id(),
+ cc::Animation::Opacity,
+ (fifth_effective_start - base::TimeTicks()).InSecondsF()));
+
+ // Skip ahead by a lot.
+ element->Step(fifth_effective_start + 999 * delta);
+
+ EXPECT_TRUE(test_controller.animator()->is_animating());
+ EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), start_opacity);
+
+ test_controller.animator()->StopAnimatingProperty(
+ LayerAnimationElement::OPACITY);
+
+ EXPECT_FALSE(test_controller.animator()->is_animating());
+}
+
TEST(LayerAnimatorTest, AddObserverExplicit) {
scoped_refptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator());
AnimationContainerElement* element = animator.get();
@@ -1083,10 +1535,10 @@ TEST(LayerAnimatorTest, AddObserverExplicit) {
base::TimeDelta delta = base::TimeDelta::FromSeconds(1);
- delegate.SetOpacityFromAnimation(0.0f);
+ delegate.SetBrightnessFromAnimation(0.0f);
LayerAnimationSequence* sequence = new LayerAnimationSequence(
- LayerAnimationElement::CreateOpacityElement(1.0f, delta));
+ LayerAnimationElement::CreateBrightnessElement(1.0f, delta));
animator->StartAnimation(sequence);
@@ -1100,7 +1552,7 @@ TEST(LayerAnimatorTest, AddObserverExplicit) {
// |sequence| has been destroyed. Recreate it to test abort.
sequence = new LayerAnimationSequence(
- LayerAnimationElement::CreateOpacityElement(1.0f, delta));
+ LayerAnimationElement::CreateBrightnessElement(1.0f, delta));
animator->StartAnimation(sequence);
@@ -1120,19 +1572,19 @@ TEST(LayerAnimatorTest, ImplicitAnimationObservers) {
animator->SetDelegate(&delegate);
EXPECT_FALSE(observer.animations_completed());
- animator->SetOpacity(1.0f);
+ animator->SetBrightness(1.0f);
{
ScopedLayerAnimationSettings settings(animator.get());
settings.AddObserver(&observer);
- animator->SetOpacity(0.0f);
+ animator->SetBrightness(0.0f);
}
EXPECT_FALSE(observer.animations_completed());
base::TimeTicks start_time = animator->last_step_time();
element->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
EXPECT_TRUE(observer.animations_completed());
- EXPECT_FLOAT_EQ(0.0f, delegate.GetOpacityForAnimation());
+ EXPECT_FLOAT_EQ(0.0f, delegate.GetBrightnessForAnimation());
}
// Tests that an observer added to a scoped settings object is still notified
@@ -1145,20 +1597,20 @@ TEST(LayerAnimatorTest, InterruptedImplicitAnimationObservers) {
animator->SetDelegate(&delegate);
EXPECT_FALSE(observer.animations_completed());
- animator->SetOpacity(1.0f);
+ animator->SetBrightness(1.0f);
{
ScopedLayerAnimationSettings settings(animator.get());
settings.AddObserver(&observer);
- animator->SetOpacity(0.0f);
+ animator->SetBrightness(0.0f);
}
EXPECT_FALSE(observer.animations_completed());
// This should interrupt the implicit animation causing the observer to be
// notified immediately.
- animator->SetOpacity(1.0f);
+ animator->SetBrightness(1.0f);
EXPECT_TRUE(observer.animations_completed());
- EXPECT_FLOAT_EQ(1.0f, delegate.GetOpacityForAnimation());
+ EXPECT_FLOAT_EQ(1.0f, delegate.GetBrightnessForAnimation());
}
// Tests that an observer added to a scoped settings object is not notified
@@ -1174,13 +1626,13 @@ TEST(LayerAnimatorTest, ImplicitObserversAtAnimatorDestruction) {
EXPECT_FALSE(observer_notify.animations_completed());
EXPECT_FALSE(observer_do_not_notify.animations_completed());
- animator->SetOpacity(1.0f);
+ animator->SetBrightness(1.0f);
{
ScopedLayerAnimationSettings settings(animator.get());
settings.AddObserver(&observer_notify);
settings.AddObserver(&observer_do_not_notify);
- animator->SetOpacity(0.0f);
+ animator->SetBrightness(0.0f);
}
EXPECT_FALSE(observer_notify.animations_completed());
@@ -1203,7 +1655,7 @@ TEST(LayerAnimatorTest, RemoveObserverShouldRemoveFromSequences) {
base::TimeDelta delta = base::TimeDelta::FromSeconds(1);
LayerAnimationSequence* sequence = new LayerAnimationSequence(
- LayerAnimationElement::CreateOpacityElement(1.0f, delta));
+ LayerAnimationElement::CreateBrightnessElement(1.0f, delta));
sequence->AddObserver(&observer);
sequence->AddObserver(&removed_observer);
@@ -1227,12 +1679,12 @@ TEST(LayerAnimatorTest, RemoveObserverShouldRemoveFromSequences) {
}
TEST(LayerAnimatorTest, ObserverReleasedBeforeAnimationSequenceEnds) {
+ TestLayerAnimationDelegate delegate;
scoped_refptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator());
animator->set_disable_timer_for_test(true);
scoped_ptr<TestLayerAnimationObserver> observer(
new TestLayerAnimationObserver);
- TestLayerAnimationDelegate delegate;
animator->SetDelegate(&delegate);
animator->AddObserver(observer.get());
@@ -1263,14 +1715,14 @@ TEST(LayerAnimatorTest, ObserverAttachedAfterAnimationStarted) {
TestLayerAnimationDelegate delegate;
animator->SetDelegate(&delegate);
- delegate.SetOpacityFromAnimation(0.0f);
+ delegate.SetBrightnessFromAnimation(0.0f);
{
ScopedLayerAnimationSettings setter(animator.get());
base::TimeDelta delta = base::TimeDelta::FromSeconds(1);
LayerAnimationSequence* sequence = new LayerAnimationSequence(
- LayerAnimationElement::CreateOpacityElement(1.0f, delta));
+ LayerAnimationElement::CreateBrightnessElement(1.0f, delta));
animator->StartAnimation(sequence);
base::TimeTicks start_time = animator->last_step_time();
@@ -1296,10 +1748,10 @@ TEST(LayerAnimatorTest, ObserverDetachedBeforeAnimationFinished) {
TestLayerAnimationDelegate delegate;
animator->SetDelegate(&delegate);
- delegate.SetOpacityFromAnimation(0.0f);
+ delegate.SetBrightnessFromAnimation(0.0f);
base::TimeDelta delta = base::TimeDelta::FromSeconds(1);
LayerAnimationSequence* sequence = new LayerAnimationSequence(
- LayerAnimationElement::CreateOpacityElement(1.0f, delta));
+ LayerAnimationElement::CreateBrightnessElement(1.0f, delta));
{
ScopedLayerAnimationSettings setter(animator.get());
@@ -1331,16 +1783,16 @@ TEST(LayerAnimatorTest, ObserverDeletesAnimations) {
TestLayerAnimationDelegate delegate;
animator->SetDelegate(&delegate);
- double start_opacity(0.0);
- double target_opacity(1.0);
+ double start_brightness(0.0);
+ double target_brightness(1.0);
gfx::Rect start_bounds(0, 0, 50, 50);
gfx::Rect target_bounds(5, 5, 5, 5);
- delegate.SetOpacityFromAnimation(start_opacity);
+ delegate.SetBrightnessFromAnimation(start_brightness);
delegate.SetBoundsFromAnimation(start_bounds);
- base::TimeDelta opacity_delta = base::TimeDelta::FromSeconds(1);
+ base::TimeDelta brightness_delta = base::TimeDelta::FromSeconds(1);
base::TimeDelta halfway_delta = base::TimeDelta::FromSeconds(2);
base::TimeDelta bounds_delta = base::TimeDelta::FromSeconds(3);
@@ -1354,8 +1806,8 @@ TEST(LayerAnimatorTest, ObserverDeletesAnimations) {
animator->StartAnimation(
new LayerAnimationSequence(
- LayerAnimationElement::CreateOpacityElement(
- target_opacity, opacity_delta)));
+ LayerAnimationElement::CreateBrightnessElement(
+ target_brightness, brightness_delta)));
animator->StartAnimation(to_delete);
@@ -1435,10 +1887,10 @@ TEST(LayerAnimatorTest, ImmediatelySettingNewTargetDoesNotLeak) {
// Verifies GetTargetOpacity() works when multiple sequences are scheduled.
TEST(LayerAnimatorTest, GetTargetOpacity) {
+ TestLayerAnimationDelegate delegate;
scoped_refptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator());
animator->set_preemption_strategy(LayerAnimator::ENQUEUE_NEW_ANIMATION);
animator->set_disable_timer_for_test(true);
- TestLayerAnimationDelegate delegate;
animator->SetDelegate(&delegate);
delegate.SetOpacityFromAnimation(0.0);
@@ -1641,7 +2093,7 @@ TEST(LayerAnimatorTest, ObserverDeletesAnimatorAfterFinishingAnimation) {
TestLayerAnimationDelegate delegate;
animator->SetDelegate(&delegate);
- delegate.SetOpacityFromAnimation(0.0f);
+ delegate.SetBrightnessFromAnimation(0.0f);
gfx::Rect start_bounds(0, 0, 50, 50);
gfx::Rect target_bounds(10, 10, 100, 100);
@@ -1649,9 +2101,9 @@ TEST(LayerAnimatorTest, ObserverDeletesAnimatorAfterFinishingAnimation) {
delegate.SetBoundsFromAnimation(start_bounds);
base::TimeDelta delta = base::TimeDelta::FromSeconds(1);
- LayerAnimationSequence* opacity_sequence = new LayerAnimationSequence(
- LayerAnimationElement::CreateOpacityElement(1.0f, delta));
- animator->StartAnimation(opacity_sequence);
+ LayerAnimationSequence* brightness_sequence = new LayerAnimationSequence(
+ LayerAnimationElement::CreateBrightnessElement(1.0f, delta));
+ animator->StartAnimation(brightness_sequence);
delta = base::TimeDelta::FromSeconds(2);
LayerAnimationSequence* bounds_sequence = new LayerAnimationSequence(
@@ -1698,11 +2150,11 @@ TEST(LayerAnimatorTest, ObserverDeletesAnimatorAfterStoppingAnimating) {
TEST(LayerAnimatorTest, ObserverDeletesAnimatorAfterScheduling) {
bool observer_was_deleted = false;
+ TestLayerAnimationDelegate delegate;
DeletingObserver* observer = new DeletingObserver(&observer_was_deleted);
observer->set_delete_on_animation_scheduled(true);
LayerAnimator* animator = observer->animator();
animator->set_disable_timer_for_test(true);
- TestLayerAnimationDelegate delegate;
animator->SetDelegate(&delegate);
delegate.SetOpacityFromAnimation(0.0f);
@@ -1730,12 +2182,12 @@ TEST(LayerAnimatorTest, ObserverDeletesAnimatorAfterScheduling) {
TEST(LayerAnimatorTest, ObserverDeletesAnimatorAfterAborted) {
bool observer_was_deleted = false;
DeletingObserver* observer = new DeletingObserver(&observer_was_deleted);
+ TestLayerAnimationDelegate delegate;
observer->set_delete_on_animation_aborted(true);
LayerAnimator* animator = observer->animator();
animator->set_preemption_strategy(
LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
animator->set_disable_timer_for_test(true);
- TestLayerAnimationDelegate delegate;
animator->SetDelegate(&delegate);
delegate.SetOpacityFromAnimation(0.0f);
@@ -1767,10 +2219,10 @@ TEST(LayerAnimatorTest, ObserverDeletesAnimatorAfterAborted) {
TEST(LayerAnimatorTest, TestSetterRespectEnqueueStrategy) {
+ TestLayerAnimationDelegate delegate;
scoped_refptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator());
animator->set_disable_timer_for_test(true);
- TestLayerAnimationDelegate delegate;
animator->SetDelegate(&delegate);
float start_opacity = 0.0f;
diff --git a/ui/compositor/test/layer_animator_test_controller.cc b/ui/compositor/test/layer_animator_test_controller.cc
new file mode 100644
index 0000000..5721cce
--- /dev/null
+++ b/ui/compositor/test/layer_animator_test_controller.cc
@@ -0,0 +1,52 @@
+// Copyright (c) 2013 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 "ui/compositor/test/layer_animator_test_controller.h"
+#include "ui/compositor/layer_animation_sequence.h"
+
+namespace ui {
+
+LayerAnimatorTestController::LayerAnimatorTestController(
+ scoped_refptr<LayerAnimator> animator)
+ : animator_(animator) {
+}
+
+LayerAnimatorTestController::~LayerAnimatorTestController() {
+}
+
+LayerAnimationSequence* LayerAnimatorTestController::GetRunningSequence(
+ LayerAnimationElement::AnimatableProperty property) {
+ LayerAnimator::RunningAnimation* running_animation =
+ animator_->GetRunningAnimation(property);
+ if (running_animation)
+ return running_animation->sequence();
+ else
+ return NULL;
+}
+
+void LayerAnimatorTestController::StartThreadedAnimationsIfNeeded() {
+ LayerAnimationSequence* sequence =
+ GetRunningSequence(LayerAnimationElement::OPACITY);
+
+ if (!sequence)
+ return;
+
+ LayerAnimationElement* element = sequence->CurrentElement();
+ if (element->properties().find(LayerAnimationElement::OPACITY) ==
+ element->properties().end())
+ return;
+
+ if (!element->Started() ||
+ element->effective_start_time() != base::TimeTicks())
+ return;
+
+ animator_->OnThreadedAnimationStarted(cc::AnimationEvent(
+ cc::AnimationEvent::Started,
+ 0,
+ element->animation_group_id(),
+ cc::Animation::Opacity,
+ (base::TimeTicks::Now() - base::TimeTicks()).InSecondsF()));
+}
+
+} // namespace ui
diff --git a/ui/compositor/test/layer_animator_test_controller.h b/ui/compositor/test/layer_animator_test_controller.h
new file mode 100644
index 0000000..0f8d1e8
--- /dev/null
+++ b/ui/compositor/test/layer_animator_test_controller.h
@@ -0,0 +1,34 @@
+// Copyright (c) 2013 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.
+
+#ifndef UI_COMPOSITOR_TEST_LAYER_ANIMATOR_TEST_CONTROLLER_H_
+#define UI_COMPOSITOR_TEST_LAYER_ANIMATOR_TEST_CONTROLLER_H_
+
+#include "ui/compositor/layer_animator.h"
+
+namespace ui {
+
+// Allows tests to access sequences owned by the animator.
+class LayerAnimatorTestController {
+ public:
+ LayerAnimatorTestController(scoped_refptr<LayerAnimator> animator);
+
+ ~LayerAnimatorTestController();
+
+ LayerAnimator* animator() { return animator_.get(); }
+
+ // Returns the running sequence animating the given property, if any.
+ LayerAnimationSequence* GetRunningSequence(
+ LayerAnimationElement::AnimatableProperty property);
+
+ // Starts threaded animations that are waiting for an effective start time.
+ void StartThreadedAnimationsIfNeeded();
+
+ private:
+ scoped_refptr<LayerAnimator> animator_;
+};
+
+} // namespace ui
+
+#endif // UI_COMPOSITOR_TEST_LAYER_ANIMATOR_TEST_CONTROLLER_H_
diff --git a/ui/compositor/test/test_layer_animation_delegate.cc b/ui/compositor/test/test_layer_animation_delegate.cc
index a3d7f67..d452fc0 100644
--- a/ui/compositor/test/test_layer_animation_delegate.cc
+++ b/ui/compositor/test/test_layer_animation_delegate.cc
@@ -88,4 +88,11 @@ SkColor TestLayerAnimationDelegate::GetColorForAnimation() const {
return color_;
}
+void TestLayerAnimationDelegate::AddThreadedAnimation(
+ scoped_ptr<cc::Animation> animation) {
+}
+
+void TestLayerAnimationDelegate::RemoveThreadedAnimation(int animation_id) {
+}
+
} // namespace ui
diff --git a/ui/compositor/test/test_layer_animation_delegate.h b/ui/compositor/test/test_layer_animation_delegate.h
index 2c21aa5..3370f72 100644
--- a/ui/compositor/test/test_layer_animation_delegate.h
+++ b/ui/compositor/test/test_layer_animation_delegate.h
@@ -35,6 +35,9 @@ class TestLayerAnimationDelegate : public LayerAnimationDelegate {
virtual float GetBrightnessForAnimation() const OVERRIDE;
virtual float GetGrayscaleForAnimation() const OVERRIDE;
virtual SkColor GetColorForAnimation() const OVERRIDE;
+ virtual void AddThreadedAnimation(
+ scoped_ptr<cc::Animation> animation) OVERRIDE;
+ virtual void RemoveThreadedAnimation(int animation_id) OVERRIDE;
private:
gfx::Rect bounds_;
diff --git a/webkit/compositor_bindings/compositor_bindings.gyp b/webkit/compositor_bindings/compositor_bindings.gyp
index df98e44..51d2575 100644
--- a/webkit/compositor_bindings/compositor_bindings.gyp
+++ b/webkit/compositor_bindings/compositor_bindings.gyp
@@ -7,8 +7,6 @@
'webkit_compositor_bindings_sources': [
'web_animation_curve_common.cc',
'web_animation_curve_common.h',
- 'web_animation_id_provider.cc',
- 'web_animation_id_provider.h',
'web_animation_impl.cc',
'web_animation_impl.h',
'web_compositor_support_software_output_device.cc',
diff --git a/webkit/compositor_bindings/web_animation_id_provider.cc b/webkit/compositor_bindings/web_animation_id_provider.cc
deleted file mode 100644
index efd3f0f..0000000
--- a/webkit/compositor_bindings/web_animation_id_provider.cc
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright (c) 2012 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 "webkit/compositor_bindings/web_animation_id_provider.h"
-
-namespace webkit {
-
-int WebAnimationIdProvider::NextAnimationId() {
- static int next_animation_id = 1;
- return next_animation_id++;
-}
-
-int WebAnimationIdProvider::NextGroupId() {
- static int next_group_id = 1;
- return next_group_id++;
-}
-
-} // namespace webkit
diff --git a/webkit/compositor_bindings/web_animation_id_provider.h b/webkit/compositor_bindings/web_animation_id_provider.h
deleted file mode 100644
index 631785c..0000000
--- a/webkit/compositor_bindings/web_animation_id_provider.h
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright (c) 2012 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.
-
-#ifndef WEBKIT_COMPOSITOR_BINDINGS_WEB_ANIMATION_ID_PROVIDER
-#define WEBKIT_COMPOSITOR_BINDINGS_WEB_ANIMATION_ID_PROVIDER
-
-namespace webkit {
-
-class WebAnimationIdProvider {
- public:
- // These functions each return monotonically increasing values.
- static int NextAnimationId();
- static int NextGroupId();
-};
-
-}
-
-#endif // WEBKIT_COMPOSITOR_BINDINGS_WEB_ANIMATION_ID_PROVIDER
diff --git a/webkit/compositor_bindings/web_animation_impl.cc b/webkit/compositor_bindings/web_animation_impl.cc
index 21b0bc8..961df4d 100644
--- a/webkit/compositor_bindings/web_animation_impl.cc
+++ b/webkit/compositor_bindings/web_animation_impl.cc
@@ -6,23 +6,23 @@
#include "cc/animation.h"
#include "cc/animation_curve.h"
+#include "cc/animation_id_provider.h"
#include "third_party/WebKit/Source/Platform/chromium/public/WebAnimationCurve.h"
#include "third_party/WebKit/Source/Platform/chromium/public/WebAnimation.h"
-#include "webkit/compositor_bindings/web_animation_id_provider.h"
#include "webkit/compositor_bindings/web_float_animation_curve_impl.h"
#include "webkit/compositor_bindings/web_transform_animation_curve_impl.h"
using cc::Animation;
-using webkit::WebAnimationIdProvider;
+using cc::AnimationIdProvider;
namespace WebKit {
WebAnimationImpl::WebAnimationImpl(const WebAnimationCurve& webCurve, TargetProperty targetProperty, int animationId, int groupId)
{
if (!animationId)
- animationId = WebAnimationIdProvider::NextAnimationId();
+ animationId = AnimationIdProvider::NextAnimationId();
if (!groupId)
- groupId = WebAnimationIdProvider::NextGroupId();
+ groupId = AnimationIdProvider::NextGroupId();
WebAnimationCurve::AnimationCurveType curveType = webCurve.type();
scoped_ptr<cc::AnimationCurve> curve;