Skip to content

Commit

Permalink
compositor: Tick the UI animations from cc, instead of from timer cal…
Browse files Browse the repository at this point in the history
…lbacks.

Update the animations in the UI in response to the animation step in the compositor,
instead of from a timer callback. This should make it more difficult for rogue UI
animations to negatively impact the system too much.

BUG=371071
R=ajuma@chromium.org, sky@chromium.org

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

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@274988 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
sadrul@chromium.org committed Jun 5, 2014
1 parent 71a04b9 commit 9034a28
Show file tree
Hide file tree
Showing 21 changed files with 658 additions and 192 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,13 @@ void RunAnimationForWidget(views::Widget* widget) {

ui::Layer* layer = widget->GetNativeView()->layer();
ui::LayerAnimatorTestController controller(layer->GetAnimator());
gfx::AnimationContainerElement* element = layer->GetAnimator();
// Multiple steps are required to complete complex animations.
// TODO(vollick): This should not be necessary. crbug.com/154017
while (controller.animator()->is_animating()) {
controller.StartThreadedAnimationsIfNeeded();
base::TimeTicks step_time = controller.animator()->last_step_time();
element->Step(step_time + base::TimeDelta::FromMilliseconds(1000));
layer->GetAnimator()->Step(step_time +
base::TimeDelta::FromMilliseconds(1000));
}
}

Expand Down
7 changes: 2 additions & 5 deletions ash/shelf/shelf_layout_manager_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
#include "ui/compositor/layer_animator.h"
#include "ui/compositor/scoped_animation_duration_scale_mode.h"
#include "ui/events/gestures/gesture_configuration.h"
#include "ui/gfx/animation/animation_container_element.h"
#include "ui/gfx/display.h"
#include "ui/gfx/screen.h"
#include "ui/views/controls/label.h"
Expand All @@ -50,10 +49,8 @@ namespace ash {
namespace {

void StepWidgetLayerAnimatorToEnd(views::Widget* widget) {
gfx::AnimationContainerElement* element =
static_cast<gfx::AnimationContainerElement*>(
widget->GetNativeView()->layer()->GetAnimator());
element->Step(base::TimeTicks::Now() + base::TimeDelta::FromSeconds(1));
widget->GetNativeView()->layer()->GetAnimator()->Step(
base::TimeTicks::Now() + base::TimeDelta::FromSeconds(1));
}

ShelfWidget* GetShelfWidget() {
Expand Down
24 changes: 10 additions & 14 deletions ash/wm/window_animations_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
#include "ui/compositor/layer_animator.h"
#include "ui/compositor/scoped_animation_duration_scale_mode.h"
#include "ui/compositor/scoped_layer_animation_settings.h"
#include "ui/gfx/animation/animation_container_element.h"

using aura::Window;
using ui::Layer;
Expand Down Expand Up @@ -89,11 +88,8 @@ TEST_F(WindowAnimationsTest, HideShowBrightnessGrayscaleAnimation) {
EXPECT_TRUE(window->layer()->visible());

// Stays shown.
gfx::AnimationContainerElement* element =
static_cast<gfx::AnimationContainerElement*>(
window->layer()->GetAnimator());
element->Step(base::TimeTicks::Now() +
base::TimeDelta::FromSeconds(5));
window->layer()->GetAnimator()->Step(base::TimeTicks::Now() +
base::TimeDelta::FromSeconds(5));
EXPECT_EQ(0.0f, window->layer()->GetTargetBrightness());
EXPECT_EQ(0.0f, window->layer()->GetTargetGrayscale());
EXPECT_TRUE(window->layer()->visible());
Expand Down Expand Up @@ -141,10 +137,10 @@ TEST_F(WindowAnimationsTest, CrossFadeToBounds) {
EXPECT_EQ(gfx::Transform(), window->layer()->GetTargetTransform());

// Run the animations to completion.
static_cast<gfx::AnimationContainerElement*>(old_layer->GetAnimator())->Step(
base::TimeTicks::Now() + base::TimeDelta::FromSeconds(1));
static_cast<gfx::AnimationContainerElement*>(window->layer()->GetAnimator())->
Step(base::TimeTicks::Now() + base::TimeDelta::FromSeconds(1));
old_layer->GetAnimator()->Step(base::TimeTicks::Now() +
base::TimeDelta::FromSeconds(1));
window->layer()->GetAnimator()->Step(base::TimeTicks::Now() +
base::TimeDelta::FromSeconds(1));

// Cross fade to a smaller size, as in a restore animation.
old_layer = window->layer();
Expand All @@ -163,10 +159,10 @@ TEST_F(WindowAnimationsTest, CrossFadeToBounds) {
EXPECT_EQ(1.0f, window->layer()->GetTargetOpacity());
EXPECT_EQ(gfx::Transform(), window->layer()->GetTargetTransform());

static_cast<gfx::AnimationContainerElement*>(old_layer->GetAnimator())->Step(
base::TimeTicks::Now() + base::TimeDelta::FromSeconds(1));
static_cast<gfx::AnimationContainerElement*>(window->layer()->GetAnimator())->
Step(base::TimeTicks::Now() + base::TimeDelta::FromSeconds(1));
old_layer->GetAnimator()->Step(base::TimeTicks::Now() +
base::TimeDelta::FromSeconds(1));
window->layer()->GetAnimator()->Step(base::TimeTicks::Now() +
base::TimeDelta::FromSeconds(1));
}

} // namespace wm
Expand Down
8 changes: 3 additions & 5 deletions content/browser/web_contents/aura/window_slider_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,6 @@ TEST_F(WindowSliderTest, WindowSlideInterruptedThenContinues) {
ui::ScopedAnimationDurationScaleMode normal_duration_(
ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION);
ui::LayerAnimator* animator = window->layer()->GetAnimator();
gfx::AnimationContainerElement* element = animator;
animator->set_disable_timer_for_test(true);
ui::LayerAnimatorTestController test_controller(animator);

Expand Down Expand Up @@ -428,7 +427,7 @@ TEST_F(WindowSliderTest, WindowSlideInterruptedThenContinues) {
ui::ScopedLayerAnimationSettings settings(animator);
base::TimeDelta duration = settings.GetTransitionDuration();
test_controller.StartThreadedAnimationsIfNeeded();
element->Step(gfx::FrameTime::Now() + duration);
animator->Step(gfx::FrameTime::Now() + duration);

EXPECT_TRUE(slider_delegate.slide_completed());
EXPECT_FALSE(slider_delegate.slider_destroyed());
Expand Down Expand Up @@ -596,7 +595,6 @@ TEST_F(WindowSliderTest, SwipeDuringSwipeAnimation) {
ui::ScopedAnimationDurationScaleMode normal_duration_(
ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION);
ui::LayerAnimator* animator = window->layer()->GetAnimator();
gfx::AnimationContainerElement* element = animator;
animator->set_disable_timer_for_test(true);
ui::LayerAnimatorTestController test_controller(animator);

Expand All @@ -619,7 +617,7 @@ TEST_F(WindowSliderTest, SwipeDuringSwipeAnimation) {
test_controller.StartThreadedAnimationsIfNeeded();
base::TimeTicks start_time1 = gfx::FrameTime::Now();

element->Step(start_time1 + duration/2);
animator->Step(start_time1 + duration / 2);
EXPECT_FALSE(slider_delegate.slide_completed());
slider_delegate.Reset();
// Generate another horizontal swipe while the animation from the previous
Expand All @@ -640,7 +638,7 @@ TEST_F(WindowSliderTest, SwipeDuringSwipeAnimation) {
test_controller.StartThreadedAnimationsIfNeeded();
base::TimeTicks start_time2 = gfx::FrameTime::Now();
slider_delegate.Reset();
element->Step(start_time2 + duration);
animator->Step(start_time2 + duration);
// The animation for the second slide should now be completed.
EXPECT_TRUE(slider_delegate.slide_completed());
slider_delegate.Reset();
Expand Down
5 changes: 4 additions & 1 deletion ui/aura/window.cc
Original file line number Diff line number Diff line change
Expand Up @@ -217,8 +217,11 @@ Window::Window(WindowDelegate* delegate)

Window::~Window() {
// |layer()| can be NULL during tests, or if this Window is layerless.
if (layer())
if (layer()) {
if (layer()->owner() == this)
layer()->CompleteAllAnimations();
layer()->SuppressPaint();
}

// Let the delegate know we're in the processing of destroying.
if (delegate_)
Expand Down
103 changes: 97 additions & 6 deletions ui/aura/window_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include "ui/aura/window_tree_host.h"
#include "ui/base/hit_test.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/layer_animation_observer.h"
#include "ui/compositor/scoped_animation_duration_scale_mode.h"
#include "ui/compositor/scoped_layer_animation_settings.h"
#include "ui/compositor/test/test_layers.h"
Expand Down Expand Up @@ -1625,7 +1626,7 @@ TEST_F(WindowTest, SetBoundsInternalShouldCheckTargetBounds) {

EXPECT_FALSE(!w1->layer());
w1->layer()->GetAnimator()->set_disable_timer_for_test(true);
gfx::AnimationContainerElement* element = w1->layer()->GetAnimator();
ui::LayerAnimator* animator = w1->layer()->GetAnimator();

EXPECT_EQ("0,0 100x100", w1->bounds().ToString());
EXPECT_EQ("0,0 100x100", w1->layer()->GetTargetBounds().ToString());
Expand Down Expand Up @@ -1655,7 +1656,7 @@ TEST_F(WindowTest, SetBoundsInternalShouldCheckTargetBounds) {
base::TimeTicks start_time =
w1->layer()->GetAnimator()->last_step_time();

element->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
animator->Step(start_time + base::TimeDelta::FromMilliseconds(1000));

EXPECT_EQ("0,0 100x100", w1->bounds().ToString());
}
Expand Down Expand Up @@ -2374,8 +2375,8 @@ TEST_F(WindowTest, DelegateNotifiedAsBoundsChange) {
// Animate to the end, which should notify of the change.
base::TimeTicks start_time =
window->layer()->GetAnimator()->last_step_time();
gfx::AnimationContainerElement* element = window->layer()->GetAnimator();
element->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
ui::LayerAnimator* animator = window->layer()->GetAnimator();
animator->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
EXPECT_TRUE(delegate.bounds_changed());
EXPECT_NE("0,0 100x100", window->bounds().ToString());
}
Expand Down Expand Up @@ -2416,8 +2417,8 @@ TEST_F(WindowTest, DelegateNotifiedAsBoundsChangeInHiddenLayer) {
// Animate to the end: will *not* notify of the change since we are hidden.
base::TimeTicks start_time =
window->layer()->GetAnimator()->last_step_time();
gfx::AnimationContainerElement* element = window->layer()->GetAnimator();
element->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
ui::LayerAnimator* animator = window->layer()->GetAnimator();
animator->Step(start_time + base::TimeDelta::FromMilliseconds(1000));

// No bounds changed notification at the end of animation since layer
// delegate is NULL.
Expand Down Expand Up @@ -3347,5 +3348,95 @@ TEST_F(WindowTest, StackChildAtLayerless) {
}
}

namespace {

class TestLayerAnimationObserver : public ui::LayerAnimationObserver {
public:
TestLayerAnimationObserver()
: animation_completed_(false),
animation_aborted_(false) {}
virtual ~TestLayerAnimationObserver() {}

bool animation_completed() const { return animation_completed_; }
bool animation_aborted() const { return animation_aborted_; }

void Reset() {
animation_completed_ = false;
animation_aborted_ = false;
}

private:
// ui::LayerAnimationObserver:
virtual void OnLayerAnimationEnded(
ui::LayerAnimationSequence* sequence) OVERRIDE {
animation_completed_ = true;
}

virtual void OnLayerAnimationAborted(
ui::LayerAnimationSequence* sequence) OVERRIDE {
animation_aborted_ = true;
}

virtual void OnLayerAnimationScheduled(
ui::LayerAnimationSequence* sequence) OVERRIDE {
}

bool animation_completed_;
bool animation_aborted_;

DISALLOW_COPY_AND_ASSIGN(TestLayerAnimationObserver);
};

}

TEST_F(WindowTest, WindowDestroyCompletesAnimations) {
ui::ScopedAnimationDurationScaleMode normal_duration_mode(
ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION);
scoped_refptr<ui::LayerAnimator> animator =
ui::LayerAnimator::CreateImplicitAnimator();
TestLayerAnimationObserver observer;
animator->AddObserver(&observer);
// Make sure destroying a Window completes the animation.
{
scoped_ptr<Window> window(CreateTestWindowWithId(1, root_window()));
window->layer()->SetAnimator(animator);

gfx::Transform transform;
transform.Scale(0.5f, 0.5f);
window->SetTransform(transform);

EXPECT_TRUE(animator->is_animating());
EXPECT_FALSE(observer.animation_completed());
}
EXPECT_TRUE(animator);
EXPECT_FALSE(animator->is_animating());
EXPECT_TRUE(observer.animation_completed());
EXPECT_FALSE(observer.animation_aborted());
animator->RemoveObserver(&observer);
observer.Reset();

animator = ui::LayerAnimator::CreateImplicitAnimator();
animator->AddObserver(&observer);
ui::Layer layer;
layer.SetAnimator(animator);
{
scoped_ptr<Window> window(CreateTestWindowWithId(1, root_window()));
window->layer()->Add(&layer);

gfx::Transform transform;
transform.Scale(0.5f, 0.5f);
layer.SetTransform(transform);

EXPECT_TRUE(animator->is_animating());
EXPECT_FALSE(observer.animation_completed());
}

EXPECT_TRUE(animator);
EXPECT_FALSE(animator->is_animating());
EXPECT_TRUE(observer.animation_completed());
EXPECT_FALSE(observer.animation_aborted());
animator->RemoveObserver(&observer);
}

} // namespace test
} // namespace aura
16 changes: 15 additions & 1 deletion ui/compositor/compositor.cc
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "ui/compositor/compositor_vsync_manager.h"
#include "ui/compositor/dip_util.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/layer_animator_collection.h"
#include "ui/gfx/frame_time.h"
#include "ui/gl/gl_context.h"
#include "ui/gl/gl_switches.h"
Expand Down Expand Up @@ -84,6 +85,7 @@ Compositor::Compositor(gfx::AcceleratedWidget widget,
waiting_on_compositing_end_(false),
draw_on_compositing_end_(false),
swap_state_(SWAP_NONE),
layer_animator_collection_(this),
schedule_draw_factory_(this) {
root_web_layer_ = cc::Layer::Create();
root_web_layer_->SetAnchorPoint(gfx::PointF(0.f, 0.f));
Expand Down Expand Up @@ -217,8 +219,10 @@ void Compositor::Draw() {
if (!IsLocked()) {
// TODO(nduca): Temporary while compositor calls
// compositeImmediately() directly.
base::TimeTicks now = gfx::FrameTime::Now();
Animate(now);
Layout();
host_->Composite(gfx::FrameTime::Now());
host_->Composite(now);
}
if (swap_state_ == SWAP_NONE)
NotifyEnd();
Expand Down Expand Up @@ -278,6 +282,12 @@ bool Compositor::HasObserver(CompositorObserver* observer) {
return observer_list_.HasObserver(observer);
}

void Compositor::Animate(base::TimeTicks frame_begin_time) {
layer_animator_collection_.Progress(frame_begin_time);
if (layer_animator_collection_.HasActiveAnimators())
host_->SetNeedsAnimate();
}

void Compositor::Layout() {
// We're sending damage that will be addressed during this composite
// cycle, so we don't need to schedule another composite to address it.
Expand Down Expand Up @@ -343,6 +353,10 @@ void Compositor::DidAbortSwapBuffers() {
OnCompositingAborted(this));
}

void Compositor::ScheduleAnimationForLayerCollection() {
host_->SetNeedsAnimate();
}

const cc::LayerTreeDebugState& Compositor::GetLayerTreeDebugState() const {
return host_->debug_state();
}
Expand Down
2 changes: 2 additions & 0 deletions ui/compositor/compositor.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@
'layer_animation_sequence.h',
'layer_animator.cc',
'layer_animator.h',
'layer_animator_collection.cc',
'layer_animator_collection.h',
'layer_delegate.h',
'layer_owner.cc',
'layer_owner.h',
Expand Down
Loading

0 comments on commit 9034a28

Please sign in to comment.