summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorajuma@chromium.org <ajuma@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-04-11 18:59:17 +0000
committerajuma@chromium.org <ajuma@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-04-11 18:59:17 +0000
commit79eb14f69953b8a9a021c87ee3788c4904caf6d4 (patch)
tree37814e07db721c39dd80a365a852d40bb7b67b5f
parent1d93c487c97f5ca53b8004dd7842f1ee39ba8783 (diff)
downloadchromium_src-79eb14f69953b8a9a021c87ee3788c4904caf6d4.zip
chromium_src-79eb14f69953b8a9a021c87ee3788c4904caf6d4.tar.gz
chromium_src-79eb14f69953b8a9a021c87ee3788c4904caf6d4.tar.bz2
Fix main-thread event handling for impl-only animations
Since impl-only animations have no main-thread counterpart, the main thread (more specifically, LayerTreeHost::SetAnimationEvents, LayerAnimationController::NotifyAnimationStarted, and LayerAnimationController::NotifyAnimationFinished) should not assume that incoming events will be for animations that are running on the main thread. BUG=196284 Review URL: https://chromiumcodereview.appspot.com/14137009 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@193700 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--cc/animation/animation_events.cc23
-rw-r--r--cc/animation/animation_events.h12
-rw-r--r--cc/animation/layer_animation_controller.cc30
-rw-r--r--cc/animation/layer_animation_controller_unittest.cc84
-rw-r--r--cc/cc.gyp1
-rw-r--r--cc/trees/layer_tree_host.cc54
6 files changed, 164 insertions, 40 deletions
diff --git a/cc/animation/animation_events.cc b/cc/animation/animation_events.cc
new file mode 100644
index 0000000..95b0e07
--- /dev/null
+++ b/cc/animation/animation_events.cc
@@ -0,0 +1,23 @@
+// Copyright 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/animation_events.h"
+
+namespace cc {
+
+AnimationEvent::AnimationEvent(AnimationEvent::Type type,
+ int layer_id,
+ int group_id,
+ Animation::TargetProperty target_property,
+ double monotonic_time)
+ : type(type),
+ layer_id(layer_id),
+ group_id(group_id),
+ target_property(target_property),
+ monotonic_time(monotonic_time),
+ is_impl_only(false),
+ opacity(0.f) {
+}
+
+} // namespace cc
diff --git a/cc/animation/animation_events.h b/cc/animation/animation_events.h
index b279b4b..1fd742c 100644
--- a/cc/animation/animation_events.h
+++ b/cc/animation/animation_events.h
@@ -8,30 +8,26 @@
#include <vector>
#include "cc/animation/animation.h"
+#include "cc/base/cc_export.h"
#include "ui/gfx/transform.h"
namespace cc {
-struct AnimationEvent {
+struct CC_EXPORT AnimationEvent {
enum Type { Started, Finished, PropertyUpdate };
AnimationEvent(Type type,
int layer_id,
int group_id,
Animation::TargetProperty target_property,
- double monotonic_time)
- : type(type),
- layer_id(layer_id),
- group_id(group_id),
- target_property(target_property),
- monotonic_time(monotonic_time),
- opacity(0.f) {}
+ double monotonic_time);
Type type;
int layer_id;
int group_id;
Animation::TargetProperty target_property;
double monotonic_time;
+ bool is_impl_only;
float opacity;
gfx::Transform transform;
};
diff --git a/cc/animation/layer_animation_controller.cc b/cc/animation/layer_animation_controller.cc
index a026cce..5e20dd5 100644
--- a/cc/animation/layer_animation_controller.cc
+++ b/cc/animation/layer_animation_controller.cc
@@ -172,7 +172,7 @@ void LayerAnimationController::AccumulatePropertyUpdates(
monotonic_time);
event.opacity = animation->curve()->ToFloatAnimationCurve()->GetValue(
monotonic_time);
-
+ event.is_impl_only = true;
events->push_back(event);
} else if (animation->target_property() == Animation::Transform) {
AnimationEvent event(AnimationEvent::PropertyUpdate,
@@ -183,6 +183,7 @@ void LayerAnimationController::AccumulatePropertyUpdates(
event.transform =
animation->curve()->ToTransformAnimationCurve()->GetValue(
monotonic_time);
+ event.is_impl_only = true;
events->push_back(event);
}
}
@@ -270,6 +271,15 @@ void LayerAnimationController::SetAnimationRegistrar(
void LayerAnimationController::NotifyAnimationStarted(
const AnimationEvent& event,
double wall_clock_time) {
+ if (event.is_impl_only) {
+ FOR_EACH_OBSERVER(LayerAnimationEventObserver, event_observers_,
+ OnAnimationStarted(event));
+ if (layer_animation_delegate_)
+ layer_animation_delegate_->notifyAnimationStarted(wall_clock_time);
+
+ return;
+ }
+
for (size_t i = 0; i < active_animations_.size(); ++i) {
if (active_animations_[i]->group() == event.group_id &&
active_animations_[i]->target_property() == event.target_property &&
@@ -290,6 +300,12 @@ void LayerAnimationController::NotifyAnimationStarted(
void LayerAnimationController::NotifyAnimationFinished(
const AnimationEvent& event,
double wall_clock_time) {
+ if (event.is_impl_only) {
+ if (layer_animation_delegate_)
+ layer_animation_delegate_->notifyAnimationFinished(wall_clock_time);
+ return;
+ }
+
for (size_t i = 0; i < active_animations_.size(); ++i) {
if (active_animations_[i]->group() == event.group_id &&
active_animations_[i]->target_property() == event.target_property) {
@@ -490,12 +506,14 @@ void LayerAnimationController::PromoteStartedAnimations(
if (!active_animations_[i]->has_set_start_time())
active_animations_[i]->set_start_time(monotonic_time);
if (events) {
- events->push_back(AnimationEvent(
+ AnimationEvent started_event(
AnimationEvent::Started,
id_,
active_animations_[i]->group(),
active_animations_[i]->target_property(),
- monotonic_time));
+ monotonic_time);
+ started_event.is_impl_only = active_animations_[i]->is_impl_only();
+ events->push_back(started_event);
}
}
}
@@ -577,12 +595,14 @@ void LayerAnimationController::MarkAnimationsForDeletion(
for (size_t j = i; j < active_animations_.size(); j++) {
if (group_id == active_animations_[j]->group()) {
if (events) {
- events->push_back(AnimationEvent(
+ AnimationEvent finished_event(
AnimationEvent::Finished,
id_,
active_animations_[j]->group(),
active_animations_[j]->target_property(),
- monotonic_time));
+ monotonic_time);
+ finished_event.is_impl_only = active_animations_[j]->is_impl_only();
+ events->push_back(finished_event);
}
active_animations_[j]->SetRunState(Animation::WaitingForDeletion,
monotonic_time);
diff --git a/cc/animation/layer_animation_controller_unittest.cc b/cc/animation/layer_animation_controller_unittest.cc
index 5ef57ad..a5c815b 100644
--- a/cc/animation/layer_animation_controller_unittest.cc
+++ b/cc/animation/layer_animation_controller_unittest.cc
@@ -11,6 +11,7 @@
#include "cc/test/animation_test_common.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/Source/Platform/chromium/public/WebAnimationDelegate.h"
#include "ui/gfx/transform.h"
namespace cc {
@@ -382,6 +383,7 @@ TEST(LayerAnimationControllerTest, TrivialTransformOnImpl) {
GetMostRecentPropertyUpdateEvent(events.get());
ASSERT_TRUE(start_transform_event);
EXPECT_EQ(gfx::Transform(), start_transform_event->transform);
+ EXPECT_TRUE(start_transform_event->is_impl_only);
gfx::Transform expected_transform;
expected_transform.Translate(delta_x, delta_y);
@@ -394,6 +396,88 @@ TEST(LayerAnimationControllerTest, TrivialTransformOnImpl) {
const AnimationEvent* end_transform_event =
GetMostRecentPropertyUpdateEvent(events.get());
EXPECT_EQ(expected_transform, end_transform_event->transform);
+ EXPECT_TRUE(end_transform_event->is_impl_only);
+}
+
+class FakeWebAnimationDelegate : public WebKit::WebAnimationDelegate {
+ public:
+ FakeWebAnimationDelegate()
+ : started_(false),
+ finished_(false) {}
+
+ virtual void notifyAnimationStarted(double time) OVERRIDE {
+ started_ = true;
+ }
+
+ virtual void notifyAnimationFinished(double time) OVERRIDE {
+ finished_ = true;
+ }
+
+ bool started() { return started_; }
+
+ bool finished() { return finished_; }
+
+ private:
+ bool started_;
+ bool finished_;
+};
+
+// Tests that impl-only animations lead to start and finished notifications
+// being sent to the main thread controller's animation delegate.
+TEST(LayerAnimationControllerTest,
+ NotificationsForImplOnlyAnimationsAreSentToMainThreadDelegate) {
+ FakeLayerAnimationValueObserver dummy_impl;
+ scoped_refptr<LayerAnimationController> controller_impl(
+ LayerAnimationController::Create(0));
+ controller_impl->AddValueObserver(&dummy_impl);
+ scoped_ptr<AnimationEventsVector> events(
+ make_scoped_ptr(new AnimationEventsVector));
+ FakeLayerAnimationValueObserver dummy;
+ scoped_refptr<LayerAnimationController> controller(
+ LayerAnimationController::Create(0));
+ controller->AddValueObserver(&dummy);
+ FakeWebAnimationDelegate delegate;
+ controller->set_layer_animation_delegate(&delegate);
+
+ scoped_ptr<Animation> to_add(CreateAnimation(
+ scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(),
+ 1,
+ Animation::Opacity));
+ to_add->set_is_impl_only(true);
+ controller_impl->AddAnimation(to_add.Pass());
+
+ controller_impl->Animate(0.0);
+ controller_impl->UpdateState(true, events.get());
+
+ // We should receive 2 events (a started notification and a property update).
+ EXPECT_EQ(2u, events->size());
+ EXPECT_EQ(AnimationEvent::Started, (*events)[0].type);
+ EXPECT_TRUE((*events)[0].is_impl_only);
+ EXPECT_EQ(AnimationEvent::PropertyUpdate, (*events)[1].type);
+ EXPECT_TRUE((*events)[1].is_impl_only);
+
+ // Passing on the start event to the main thread controller should cause the
+ // delegate to get notified.
+ EXPECT_FALSE(delegate.started());
+ controller->NotifyAnimationStarted((*events)[0], 0.0);
+ EXPECT_TRUE(delegate.started());
+
+ events.reset(new AnimationEventsVector);
+ controller_impl->Animate(1.0);
+ controller_impl->UpdateState(true, events.get());
+
+ // We should receive 2 events (a finished notification and a property update).
+ EXPECT_EQ(2u, events->size());
+ EXPECT_EQ(AnimationEvent::Finished, (*events)[0].type);
+ EXPECT_TRUE((*events)[0].is_impl_only);
+ EXPECT_EQ(AnimationEvent::PropertyUpdate, (*events)[1].type);
+ EXPECT_TRUE((*events)[1].is_impl_only);
+
+ // Passing on the finished event to the main thread controller should cause
+ // the delegate to get notified.
+ EXPECT_FALSE(delegate.finished());
+ controller->NotifyAnimationFinished((*events)[0], 0.0);
+ EXPECT_TRUE(delegate.finished());
}
// Tests animations that are waiting for a synchronized start time do not
diff --git a/cc/cc.gyp b/cc/cc.gyp
index 474ca6e..8858891 100644
--- a/cc/cc.gyp
+++ b/cc/cc.gyp
@@ -10,6 +10,7 @@
'animation/animation.h',
'animation/animation_curve.cc',
'animation/animation_curve.h',
+ 'animation/animation_events.cc',
'animation/animation_events.h',
'animation/animation_id_provider.cc',
'animation/animation_id_provider.h',
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc
index cca8c67..81f9051 100644
--- a/cc/trees/layer_tree_host.cc
+++ b/cc/trees/layer_tree_host.cc
@@ -567,33 +567,33 @@ bool LayerTreeHost::CommitRequested() const {
void LayerTreeHost::SetAnimationEvents(scoped_ptr<AnimationEventsVector> events,
base::Time wall_clock_time) {
DCHECK(proxy_->IsMainThread());
- AnimationRegistrar::AnimationControllerMap copy =
- animation_registrar_->active_animation_controllers();
- for (AnimationRegistrar::AnimationControllerMap::iterator iter = copy.begin();
- iter != copy.end();
- ++iter) {
- for (size_t event_index = 0; event_index < events->size(); ++event_index) {
- if ((*iter).second->id() == (*events)[event_index].layer_id) {
- switch ((*events)[event_index].type) {
- case AnimationEvent::Started:
- (*iter).second->NotifyAnimationStarted((*events)[event_index],
- wall_clock_time.ToDoubleT());
- break;
-
- case AnimationEvent::Finished:
- (*iter).second->NotifyAnimationFinished(
- (*events)[event_index],
- wall_clock_time.ToDoubleT());
- break;
-
- case AnimationEvent::PropertyUpdate:
- (*iter).second->NotifyAnimationPropertyUpdate(
- (*events)[event_index]);
- break;
-
- default:
- NOTREACHED();
- }
+ for (size_t event_index = 0; event_index < events->size(); ++event_index) {
+ int event_layer_id = (*events)[event_index].layer_id;
+
+ // Use the map of all controllers, not just active ones, since non-active
+ // controllers may still receive events for impl-only animations.
+ const AnimationRegistrar::AnimationControllerMap& animation_controllers =
+ animation_registrar_->all_animation_controllers();
+ AnimationRegistrar::AnimationControllerMap::const_iterator iter =
+ animation_controllers.find(event_layer_id);
+ if (iter != animation_controllers.end()) {
+ switch ((*events)[event_index].type) {
+ case AnimationEvent::Started:
+ (*iter).second->NotifyAnimationStarted((*events)[event_index],
+ wall_clock_time.ToDoubleT());
+ break;
+
+ case AnimationEvent::Finished:
+ (*iter).second->NotifyAnimationFinished((*events)[event_index],
+ wall_clock_time.ToDoubleT());
+ break;
+
+ case AnimationEvent::PropertyUpdate:
+ (*iter).second->NotifyAnimationPropertyUpdate((*events)[event_index]);
+ break;
+
+ default:
+ NOTREACHED();
}
}
}