Commit 41512b04 authored by ajuma@chromium.org's avatar ajuma@chromium.org

Allow animations with inactive observers to reach the Starting state

Currently, when a LayerAnimationController only has an observer in the
pending tree, we early-out from Animate and UpdateState in order to prevent
animating a layer before it's drawn.

However, this means that the position of a layer can change immediately
after tree activation (even before a draw), if an animation is started on
that layer. This means that tile priorities calculated by UpdateTilePriorites
before tree activation can immediately become stale.

This CL allows animations with only inactive observers to reach the Starting
state and get ticked at their starting point, but progress no further. This
means we still won't have running animations on layers before they're drawn.
However, this change means that if we ensure that animation always happens
before tree activation in each frame (in a follow-up CL), then the tile
priorities calculated during tree activation will still be valid when the
frame is drawn.

BUG=242966

Review URL: https://chromiumcodereview.appspot.com/15732013

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@202473 0039d316-1c4b-4281-b951-d872f2087c98
parent f37e941d
......@@ -142,7 +142,7 @@ void LayerAnimationController::TransferAnimationsTo(
}
void LayerAnimationController::Animate(double monotonic_time) {
if (!HasActiveValueObserver())
if (!HasValueObserver())
return;
StartAnimationsWaitingForNextTick(monotonic_time);
......@@ -716,6 +716,15 @@ void LayerAnimationController::NotifyObserversTransformAnimated(
OnTransformAnimated(transform));
}
bool LayerAnimationController::HasValueObserver() {
if (value_observers_.might_have_observers()) {
ObserverListBase<LayerAnimationValueObserver>::Iterator it(
value_observers_);
return it.GetNext() != NULL;
}
return false;
}
bool LayerAnimationController::HasActiveValueObserver() {
if (value_observers_.might_have_observers()) {
ObserverListBase<LayerAnimationValueObserver>::Iterator it(
......
......@@ -151,6 +151,7 @@ class CC_EXPORT LayerAnimationController
void NotifyObserversOpacityAnimated(float opacity);
void NotifyObserversTransformAnimated(const gfx::Transform& transform);
bool HasValueObserver();
bool HasActiveValueObserver();
// If this is true, we force a sync to the impl thread.
......
......@@ -1093,5 +1093,68 @@ TEST(LayerAnimationControllerTest, SkipUpdateState) {
EXPECT_FALSE(controller->HasActiveAnimation());
}
// Tests that an animation controller with only an inactive observer gets ticked
// but doesn't progress animations past the Starting state.
TEST(LayerAnimationControllerTest, InactiveObserverGetsTicked) {
scoped_ptr<AnimationEventsVector> events(
make_scoped_ptr(new AnimationEventsVector));
FakeLayerAnimationValueObserver dummy;
FakeInactiveLayerAnimationValueObserver inactive_dummy;
scoped_refptr<LayerAnimationController> controller(
LayerAnimationController::Create(0));
const int id = 1;
controller->AddAnimation(CreateAnimation(scoped_ptr<AnimationCurve>(
new FakeFloatTransition(1.0, 0.5f, 1.f)).Pass(),
id,
Animation::Opacity));
// Without an observer, the animation shouldn't progress to the Starting
// state.
controller->Animate(0.0);
controller->UpdateState(true, events.get());
EXPECT_EQ(0u, events->size());
EXPECT_EQ(Animation::WaitingForTargetAvailability,
controller->GetAnimation(id, Animation::Opacity)->run_state());
controller->AddValueObserver(&inactive_dummy);
// With only an inactive observer, the animation should progress to the
// Starting state and get ticked at its starting point, but should not
// progress to Running.
controller->Animate(1.0);
controller->UpdateState(true, events.get());
EXPECT_EQ(0u, events->size());
EXPECT_EQ(Animation::Starting,
controller->GetAnimation(id, Animation::Opacity)->run_state());
EXPECT_EQ(0.5f, inactive_dummy.opacity());
// Even when already in the Starting state, the animation should stay
// there, and shouldn't be ticked past its starting point.
controller->Animate(2.0);
controller->UpdateState(true, events.get());
EXPECT_EQ(0u, events->size());
EXPECT_EQ(Animation::Starting,
controller->GetAnimation(id, Animation::Opacity)->run_state());
EXPECT_EQ(0.5f, inactive_dummy.opacity());
controller->AddValueObserver(&dummy);
// Now that an active observer has been added, the animation should still
// initially tick at its starting point, but should now progress to Running.
controller->Animate(3.0);
controller->UpdateState(true, events.get());
EXPECT_EQ(1u, events->size());
EXPECT_EQ(Animation::Running,
controller->GetAnimation(id, Animation::Opacity)->run_state());
EXPECT_EQ(0.5f, inactive_dummy.opacity());
EXPECT_EQ(0.5f, dummy.opacity());
// The animation should now tick past its starting point.
controller->Animate(3.5);
EXPECT_NE(0.5f, inactive_dummy.opacity());
EXPECT_NE(0.5f, dummy.opacity());
}
} // namespace
} // namespace cc
......@@ -164,6 +164,10 @@ bool FakeLayerAnimationValueObserver::IsActive() const {
return true;
}
bool FakeInactiveLayerAnimationValueObserver::IsActive() const {
return false;
}
scoped_ptr<cc::AnimationCurve> FakeFloatTransition::Clone() const {
return make_scoped_ptr(
new FakeFloatTransition(*this)).PassAs<cc::AnimationCurve>();
......
......@@ -79,6 +79,12 @@ class FakeLayerAnimationValueObserver : public LayerAnimationValueObserver {
gfx::Transform transform_;
};
class FakeInactiveLayerAnimationValueObserver
: public FakeLayerAnimationValueObserver {
public:
virtual bool IsActive() const OVERRIDE;
};
int AddOpacityTransitionToController(LayerAnimationController* controller,
double duration,
float start_opacity,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment