Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(40)

Side by Side Diff: ui/gfx/compositor/layer_animator.cc

Issue 8247009: Explicit animation support (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Updated views desktop demo. Created 9 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "ui/gfx/compositor/layer_animator.h" 5 #include "ui/gfx/compositor/layer_animator.h"
6 6
7 #include "base/logging.h" 7 #include "base/logging.h"
8 #include "base/stl_util.h" 8 #include "base/memory/scoped_ptr.h"
9 #include "ui/base/animation/animation_container.h"
10 #include "ui/base/animation/animation.h" 9 #include "ui/base/animation/animation.h"
11 #include "ui/base/animation/tween.h"
12 #include "ui/gfx/compositor/compositor.h" 10 #include "ui/gfx/compositor/compositor.h"
13 #include "ui/gfx/compositor/layer.h" 11 #include "ui/gfx/compositor/layer.h"
14 #include "ui/gfx/compositor/layer_animator_delegate.h" 12 #include "ui/gfx/compositor/layer_animation_preemption_strategy.h"
15 #include "ui/gfx/transform.h" 13 #include "ui/gfx/compositor/layer_animation_sequence.h"
16 #include "ui/gfx/rect.h" 14
15 namespace ui {
16
17 class LayerAnimator;
17 18
18 namespace { 19 namespace {
19 20
20 void SetMatrixElement(SkMatrix44& matrix, int index, SkMScalar value) { 21 // TODO(vollick) match kennedy theme.
sky 2011/10/14 16:39:52 ?
21 int row = index / 4; 22 static const int kDefaultTransitionDurationMs = 250;
22 int col = index % 4; 23 static const int kDefaultFramerateHz = 50;
23 matrix.set(row, col, value); 24
24 } 25 class LayerAnimation : public Animation {
sky 2011/10/14 16:39:52 I think you'll be better off implementating Animat
25 26 public:
26 SkMScalar GetMatrixElement(const SkMatrix44& matrix, int index) { 27 // The layer animation does not own the animator.
27 int row = index / 4; 28 explicit LayerAnimation(LayerAnimator* animator)
28 int col = index % 4; 29 : Animation(base::TimeDelta::FromMilliseconds(kDefaultFramerateHz)),
29 return matrix.get(row, col); 30 animator_(animator) {
30 } 31 }
31 32 virtual ~LayerAnimation() {}
32 } // anonymous namespace 33
33 34 private:
34 namespace ui { 35 // Implementation of Animation
35 36 double GetCurrentValue() const { return 0.0; }
36 LayerAnimator::LayerAnimator(Layer* layer) 37 virtual void Step(base::TimeTicks time_now) { animator_->Step(time_now); }
37 : layer_(layer), 38
38 got_initial_tick_(false) { 39 LayerAnimator* animator_;
40 };
41
42 } // namespace;
43
44 /* static */
45 LayerAnimator* LayerAnimator::CreateDefaultAnimator() {
46 return new LayerAnimator(base::TimeDelta::FromMilliseconds(0));
47 }
48
49 /* static */
50 LayerAnimator* LayerAnimator::CreateImplicitAnimator() {
51 return new LayerAnimator(
52 base::TimeDelta::FromMilliseconds(kDefaultTransitionDurationMs));
53 }
54
55 LayerAnimator::LayerAnimator(base::TimeDelta transition_duration)
56 : layer_(NULL),
57 preemption_strategy_(
58 LayerAnimationPreemptionStrategy::GetImmediatelySetNewTarget()),
59 transition_duration_(transition_duration),
60 ALLOW_THIS_IN_INITIALIZER_LIST(animation_(new LayerAnimation(this))) {
39 } 61 }
40 62
41 LayerAnimator::~LayerAnimator() { 63 LayerAnimator::~LayerAnimator() {
42 } 64 ClearAnimations();
43 65 }
44 void LayerAnimator::SetAnimation(Animation* animation) { 66
45 animation_.reset(animation); 67 void LayerAnimator::SetTransform(const Transform& transform) {
46 if (animation_.get()) { 68 SetAnimation(new LayerAnimationSequence(
47 static ui::AnimationContainer* container = NULL; 69 LayerAnimationElement::CreateTransformElement(transform,
48 if (!container) { 70 transition_duration_)));
49 container = new AnimationContainer; 71 }
50 container->AddRef(); 72
51 } 73 void LayerAnimator::SetBounds(const gfx::Rect& bounds) {
52 animation_->set_delegate(this); 74 SetAnimation(new LayerAnimationSequence(
53 animation_->SetContainer(container); 75 LayerAnimationElement::CreateBoundsElement(bounds,
54 got_initial_tick_ = false; 76 transition_duration_)));
55 } 77 }
56 } 78
57 79 void LayerAnimator::SetOpacity(float opacity) {
58 void LayerAnimator::AnimateToPoint(const gfx::Point& target) { 80 SetAnimation(new LayerAnimationSequence(
59 StopAnimating(LOCATION); 81 LayerAnimationElement::CreateOpacityElement(opacity,
60 const gfx::Rect& layer_bounds = layer_->bounds(); 82 transition_duration_)));
61 if (target == layer_bounds.origin()) 83 }
62 return; // Already there. 84
63 85 void LayerAnimator::SetLayer(Layer* layer) {
64 Params& element = elements_[LOCATION]; 86 layer_ = layer;
65 element.location.target_x = target.x(); 87 if (!layer_) {
66 element.location.target_y = target.y(); 88 ClearAnimations();
67 element.location.start_x = layer_bounds.origin().x(); 89 }
68 element.location.start_y = layer_bounds.origin().y(); 90 }
69 } 91
70 92 void LayerAnimator::SetAnimation(LayerAnimationSequence* animation) {
71 void LayerAnimator::AnimateTransform(const Transform& transform) { 93 if (!StartSequence(animation)) {
72 StopAnimating(TRANSFORM); 94 preemption_strategy_->Preempt(layer(),
73 const Transform& layer_transform = layer_->transform(); 95 animation,
74 if (transform == layer_transform) 96 &running_animations_,
75 return; // Already there. 97 &animation_queue_);
76 98 }
77 Params& element = elements_[TRANSFORM]; 99 FinishAnyAnimationWithZeroDuration();
78 for (int i = 0; i < 16; ++i) { 100 }
79 element.transform.start[i] = 101
80 GetMatrixElement(layer_transform.matrix(), i); 102 void LayerAnimator::EnqueueAnimation(LayerAnimationSequence* animation) {
81 element.transform.target[i] = 103 animation_queue_.push_back(make_scoped_refptr(animation));
82 GetMatrixElement(transform.matrix(), i); 104 if (animation_queue_.size() == 1) {
83 } 105 SetAnimation(animation);
84 } 106 }
85 107 }
86 void LayerAnimator::AnimateOpacity(float target_opacity) { 108
87 StopAnimating(OPACITY); 109 bool LayerAnimator::IsAnimating() const {
88 if (layer_->opacity() == target_opacity) 110 return running_animations_.size() > 0;
89 return; 111 }
90 112
91 Params& element = elements_[OPACITY]; 113 void LayerAnimator::StopAnimatingProperty(
92 element.opacity.start = layer_->opacity(); 114 LayerAnimationElement::AnimatableProperty property) {
93 element.opacity.target = target_opacity; 115 while (true) {
94 } 116 RunningAnimation* running = GetRunningAnimation(property);
95 117 if (!running)
96 gfx::Point LayerAnimator::GetTargetPoint() { 118 break;
97 return IsAnimating(LOCATION) ? 119 FinishAnimation(running->sequence);
98 gfx::Point(elements_[LOCATION].location.target_x, 120 }
99 elements_[LOCATION].location.target_y) : 121 }
100 layer_->bounds().origin(); 122
101 } 123 void LayerAnimator::StopAnimating() {
102 124 while (IsAnimating())
103 float LayerAnimator::GetTargetOpacity() { 125 FinishAnimation(running_animations_[0].sequence);
104 return IsAnimating(OPACITY) ? 126 }
105 elements_[OPACITY].opacity.target : layer_->opacity(); 127
106 } 128 void LayerAnimator::Step(base::TimeTicks now) {
107 129 RunningAnimations running_animations_copy = running_animations_;
108 ui::Transform LayerAnimator::GetTargetTransform() { 130 RunningAnimations::iterator iter = running_animations_copy.begin();
109 if (IsAnimating(TRANSFORM)) { 131 while (iter != running_animations_copy.end()) {
110 Transform transform; 132 base::TimeDelta delta = now - (*iter).start_time;
111 for (int i = 0; i < 16; ++i) { 133 if (delta > (*iter).sequence->duration()) {
112 SetMatrixElement(transform.matrix(), i, 134 FinishAnimation((*iter).sequence);
113 elements_[TRANSFORM].transform.target[i]); 135 } else {
114 } 136 (*iter).sequence->Progress(delta, layer());
115 return transform; 137 }
116 } 138 ++iter;
117 return layer_->transform(); 139 }
118 } 140 }
119 141
120 bool LayerAnimator::IsAnimating(AnimationProperty property) const { 142 void LayerAnimator::UpdateAnimationState() {
121 return elements_.count(property) > 0; 143 if (IsAnimating())
122 } 144 animation_->Start();
123 145 else
124 bool LayerAnimator::IsRunning() const { 146 animation_->Stop();
125 return animation_.get() && animation_->is_animating(); 147 }
126 } 148
127 149 void LayerAnimator::RemoveAnimation(LayerAnimationSequence* sequence) {
128 void LayerAnimator::AnimationProgressed(const ui::Animation* animation) { 150 // First remove from running animations
129 got_initial_tick_ = true; 151 RunningAnimations::iterator iter = running_animations_.begin();
130 for (Elements::const_iterator i = elements_.begin(); i != elements_.end(); 152 while (iter != running_animations_.end()) {
131 ++i) { 153 if ((*iter).sequence == sequence) {
132 switch (i->first) { 154 running_animations_.erase(iter);
133 case LOCATION: { 155 break;
134 const gfx::Rect& current_bounds(layer_->bounds()); 156 }
135 gfx::Rect new_bounds = animation_->CurrentValueBetween( 157 ++iter;
136 gfx::Rect(gfx::Point(i->second.location.start_x, 158 }
137 i->second.location.start_y), 159
138 current_bounds.size()), 160 // Then remove from the queue
139 gfx::Rect(gfx::Point(i->second.location.target_x, 161 AnimationQueue::iterator queue_iter = animation_queue_.begin();
140 i->second.location.target_y), 162 while (queue_iter != animation_queue_.end()) {
141 current_bounds.size())); 163 if ((*queue_iter).get() == sequence) {
142 delegate()->SetBoundsFromAnimator(new_bounds); 164 animation_queue_.erase(queue_iter);
165 break;
166 }
167 ++queue_iter;
168 }
169 }
170
171 void LayerAnimator::FinishAnimation(LayerAnimationSequence* sequence) {
172 sequence->Progress(sequence->duration(), layer());
173 RemoveAnimation(sequence);
174 ProcessQueue();
175 UpdateAnimationState();
176 }
177
178 void LayerAnimator::FinishAnyAnimationWithZeroDuration() {
179 // Special case: if we've started a 0 duration animation, just finish it now
180 // and get rid of it.
181 RunningAnimations copy = running_animations_;
182 RunningAnimations::iterator iter = copy.begin();
183 while (iter != copy.end()) {
184 if ((*iter).sequence->duration() == base::TimeDelta()) {
185 (*iter).sequence->Progress((*iter).sequence->duration(), layer());
186 RemoveAnimation((*iter).sequence);
187 }
188 ++iter;
189 }
190 ProcessQueue();
191 UpdateAnimationState();
192 }
193
194 void LayerAnimator::ClearAnimations() {
195 RunningAnimations::iterator iter = running_animations_.begin();
196 while (iter != running_animations_.end()) {
197 (*iter).sequence->Abort();
198 ++iter;
199 }
200 running_animations_.clear();
201 animation_queue_.clear();
202 UpdateAnimationState();
203 }
204
205 LayerAnimator::RunningAnimation* LayerAnimator::GetRunningAnimation(
206 LayerAnimationElement::AnimatableProperty property) {
207 RunningAnimations::iterator iter = running_animations_.begin();
208 while (iter != running_animations_.end()) {
209 if ((*iter).sequence->properties().find(property) !=
210 (*iter).sequence->properties().end())
211 return &(*iter);
212 ++iter;
213 }
214 return NULL;
215 }
216
217 void LayerAnimator::AddToQueueIfNotPresent(LayerAnimationSequence* animation) {
218 // If we don't have the animation in the queue yet, add it.
219 bool found_sequence = false;
220 AnimationQueue::iterator queue_iter = animation_queue_.begin();
221 while (queue_iter != animation_queue_.end()) {
222 if ((*queue_iter).get() == animation) {
223 found_sequence = true;
224 break;
225 }
226 ++queue_iter;
227 }
228
229 if (!found_sequence)
230 animation_queue_.push_front(make_scoped_refptr(animation));
231 }
232
233 void LayerAnimator::ProcessQueue() {
234 bool started_sequence = false;
235 do {
236 started_sequence = false;
237 LayerAnimator::AnimationQueue::iterator iter = animation_queue_.begin();
238 while (iter != animation_queue_.end()) {
239 if (StartSequence((*iter).get())) {
240 started_sequence = true;
143 break; 241 break;
144 } 242 }
145 243 ++iter;
146 case TRANSFORM: { 244 }
147 Transform transform; 245 } while (started_sequence);
148 for (int j = 0; j < 16; ++j) { 246 }
149 SkMScalar value = animation_->CurrentValueBetween( 247
150 i->second.transform.start[j], 248 bool LayerAnimator::StartSequence(LayerAnimationSequence* sequence) {
151 i->second.transform.target[j]); 249 // Ensure that no one is animating one of the sequence's properties already.
152 SetMatrixElement(transform.matrix(), j, value); 250 RunningAnimations::const_iterator iter = running_animations_.begin();
153 } 251 while (iter != running_animations_.end()) {
154 delegate()->SetTransformFromAnimator(transform); 252 if ((*iter).sequence->HasCommonProperty(*sequence))
155 break; 253 return false;
156 } 254 ++iter;
157 255 }
158 case OPACITY: { 256
159 delegate()->SetOpacityFromAnimator(animation_->CurrentValueBetween( 257 // All clear, actually start the sequence. Note: base::TimeTicks::Now has
160 i->second.opacity.start, i->second.opacity.target)); 258 // a resolution that can be as bad as 15ms. If this causes glitches in the
161 break; 259 // animations, this can be switched to HighResNow() (animation uses Now()
162 } 260 // internally).
163 261 running_animations_.push_back(
164 default: 262 RunningAnimation(sequence, base::TimeTicks::Now()));
sky 2011/10/14 16:39:52 The expectations of multiple calls to start an ani
165 NOTREACHED(); 263
166 } 264 // Need to keep a reference to the animation.
167 } 265 AddToQueueIfNotPresent(sequence);
168 layer_->ScheduleDraw(); 266 return true;
169 }
170
171 void LayerAnimator::AnimationEnded(const ui::Animation* animation) {
172 AnimationProgressed(animation);
173 }
174
175 void LayerAnimator::StopAnimating(AnimationProperty property) {
176 if (!IsAnimating(property))
177 return;
178
179 elements_.erase(property);
180 }
181
182 LayerAnimatorDelegate* LayerAnimator::delegate() {
183 return static_cast<LayerAnimatorDelegate*>(layer_);
184 } 267 }
185 268
186 } // namespace ui 269 } // namespace ui
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698