OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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 "cc/animation/element_animations.h" | 5 #include "cc/animation/element_animations.h" |
6 | 6 |
7 #include <stddef.h> | 7 #include <stddef.h> |
8 | 8 |
9 #include <algorithm> | 9 #include <algorithm> |
10 | 10 |
11 #include "base/macros.h" | 11 #include "base/macros.h" |
12 #include "base/memory/ptr_util.h" | 12 #include "base/memory/ptr_util.h" |
13 #include "cc/animation/animation_delegate.h" | 13 #include "cc/animation/animation_delegate.h" |
14 #include "cc/animation/animation_host.h" | 14 #include "cc/animation/animation_host.h" |
15 #include "cc/animation/animation_player.h" | 15 #include "cc/animation/animation_player.h" |
16 #include "cc/animation/keyframed_animation_curve.h" | 16 #include "cc/animation/keyframed_animation_curve.h" |
17 #include "cc/animation/scroll_offset_animation_curve.h" | |
18 #include "cc/output/filter_operations.h" | 17 #include "cc/output/filter_operations.h" |
19 #include "cc/trees/mutator_host_client.h" | 18 #include "cc/trees/mutator_host_client.h" |
20 #include "ui/gfx/geometry/box_f.h" | 19 #include "ui/gfx/geometry/box_f.h" |
21 | 20 |
22 namespace cc { | 21 namespace cc { |
23 | 22 |
24 scoped_refptr<ElementAnimations> ElementAnimations::Create() { | 23 scoped_refptr<ElementAnimations> ElementAnimations::Create() { |
25 return make_scoped_refptr(new ElementAnimations()); | 24 return make_scoped_refptr(new ElementAnimations()); |
26 } | 25 } |
27 | 26 |
28 ElementAnimations::ElementAnimations() | 27 ElementAnimations::ElementAnimations() |
29 : players_list_(new PlayersList()), | 28 : players_list_(new PlayersList()), |
30 animation_host_(), | 29 animation_host_(), |
31 element_id_(), | 30 element_id_(), |
32 is_active_(false), | 31 is_active_(false), |
33 has_element_in_active_list_(false), | 32 has_element_in_active_list_(false), |
34 has_element_in_pending_list_(false), | 33 has_element_in_pending_list_(false), |
35 needs_to_start_animations_(false), | |
36 scroll_offset_animation_was_interrupted_(false), | 34 scroll_offset_animation_was_interrupted_(false), |
37 needs_push_properties_(false) {} | 35 needs_push_properties_(false) { |
| 36 ClearNeedsUpdateImplClientState(); |
| 37 } |
38 | 38 |
39 ElementAnimations::~ElementAnimations() {} | 39 ElementAnimations::~ElementAnimations() {} |
40 | 40 |
41 void ElementAnimations::SetAnimationHost(AnimationHost* host) { | 41 void ElementAnimations::SetAnimationHost(AnimationHost* host) { |
42 animation_host_ = host; | 42 animation_host_ = host; |
43 } | 43 } |
44 | 44 |
45 void ElementAnimations::SetElementId(ElementId element_id) { | 45 void ElementAnimations::SetElementId(ElementId element_id) { |
46 element_id_ = element_id; | 46 element_id_ = element_id; |
47 } | 47 } |
48 | 48 |
49 void ElementAnimations::InitAffectedElementTypes() { | 49 void ElementAnimations::InitAffectedElementTypes() { |
50 DCHECK(element_id_); | 50 DCHECK(element_id_); |
51 DCHECK(animation_host_); | 51 DCHECK(animation_host_); |
52 | 52 |
53 UpdateActivation(FORCE_ACTIVATION); | 53 UpdateActivation(ActivationType::FORCE); |
54 | 54 |
55 DCHECK(animation_host_->mutator_host_client()); | 55 DCHECK(animation_host_->mutator_host_client()); |
56 if (animation_host_->mutator_host_client()->IsElementInList( | 56 if (animation_host_->mutator_host_client()->IsElementInList( |
57 element_id_, ElementListType::ACTIVE)) { | 57 element_id_, ElementListType::ACTIVE)) { |
58 set_has_element_in_active_list(true); | 58 set_has_element_in_active_list(true); |
59 } | 59 } |
60 if (animation_host_->mutator_host_client()->IsElementInList( | 60 if (animation_host_->mutator_host_client()->IsElementInList( |
61 element_id_, ElementListType::PENDING)) { | 61 element_id_, ElementListType::PENDING)) { |
62 set_has_element_in_pending_list(true); | 62 set_has_element_in_pending_list(true); |
63 } | 63 } |
(...skipping 12 matching lines...) Expand all Loading... |
76 | 76 |
77 if (has_element_in_pending_list()) { | 77 if (has_element_in_pending_list()) { |
78 IsAnimatingChanged(ElementListType::PENDING, TargetProperty::TRANSFORM, | 78 IsAnimatingChanged(ElementListType::PENDING, TargetProperty::TRANSFORM, |
79 AnimationChangeType::BOTH, false); | 79 AnimationChangeType::BOTH, false); |
80 IsAnimatingChanged(ElementListType::PENDING, TargetProperty::OPACITY, | 80 IsAnimatingChanged(ElementListType::PENDING, TargetProperty::OPACITY, |
81 AnimationChangeType::BOTH, false); | 81 AnimationChangeType::BOTH, false); |
82 } | 82 } |
83 set_has_element_in_pending_list(false); | 83 set_has_element_in_pending_list(false); |
84 | 84 |
85 animation_host_->DidDeactivateElementAnimations(this); | 85 animation_host_->DidDeactivateElementAnimations(this); |
86 UpdateActivation(FORCE_ACTIVATION); | 86 UpdateActivation(ActivationType::FORCE); |
87 } | 87 } |
88 | 88 |
89 void ElementAnimations::ElementRegistered(ElementId element_id, | 89 void ElementAnimations::ElementRegistered(ElementId element_id, |
90 ElementListType list_type) { | 90 ElementListType list_type) { |
91 DCHECK_EQ(element_id_, element_id); | 91 DCHECK_EQ(element_id_, element_id); |
92 | 92 |
93 if (!has_element_in_any_list()) | 93 if (!has_element_in_any_list()) |
94 UpdateActivation(FORCE_ACTIVATION); | 94 UpdateActivation(ActivationType::FORCE); |
95 | 95 |
96 if (list_type == ElementListType::ACTIVE) | 96 if (list_type == ElementListType::ACTIVE) |
97 set_has_element_in_active_list(true); | 97 set_has_element_in_active_list(true); |
98 else | 98 else |
99 set_has_element_in_pending_list(true); | 99 set_has_element_in_pending_list(true); |
100 } | 100 } |
101 | 101 |
102 void ElementAnimations::ElementUnregistered(ElementId element_id, | 102 void ElementAnimations::ElementUnregistered(ElementId element_id, |
103 ElementListType list_type) { | 103 ElementListType list_type) { |
104 DCHECK_EQ(this->element_id(), element_id); | 104 DCHECK_EQ(this->element_id(), element_id); |
(...skipping 23 matching lines...) Expand all Loading... |
128 } | 128 } |
129 | 129 |
130 void ElementAnimations::PushPropertiesTo( | 130 void ElementAnimations::PushPropertiesTo( |
131 scoped_refptr<ElementAnimations> element_animations_impl) { | 131 scoped_refptr<ElementAnimations> element_animations_impl) { |
132 DCHECK_NE(this, element_animations_impl); | 132 DCHECK_NE(this, element_animations_impl); |
133 | 133 |
134 if (!needs_push_properties_) | 134 if (!needs_push_properties_) |
135 return; | 135 return; |
136 needs_push_properties_ = false; | 136 needs_push_properties_ = false; |
137 | 137 |
138 if (!HasAnyAnimation() && !element_animations_impl->HasAnyAnimation()) | 138 element_animations_impl->scroll_offset_animation_was_interrupted_ = |
139 return; | 139 scroll_offset_animation_was_interrupted_; |
140 MarkAbortedAnimationsForDeletion(element_animations_impl.get()); | 140 scroll_offset_animation_was_interrupted_ = false; |
141 PurgeAnimationsMarkedForDeletion(); | |
142 PushNewAnimationsToImplThread(element_animations_impl.get()); | |
143 | 141 |
144 // Remove finished impl side animations only after pushing, | 142 // Update impl client state. |
145 // and only after the animations are deleted on the main thread | 143 element_animations_impl->UpdateClientAnimationState( |
146 // this insures we will never push an animation twice. | 144 needs_update_impl_client_state_transform_, |
147 RemoveAnimationsCompletedOnMainThread(element_animations_impl.get()); | 145 needs_update_impl_client_state_opacity_, |
| 146 needs_update_impl_client_state_filter_); |
| 147 ClearNeedsUpdateImplClientState(); |
148 | 148 |
149 PushPropertiesToImplThread(element_animations_impl.get()); | 149 element_animations_impl->UpdateActivation(ActivationType::NORMAL); |
150 element_animations_impl->UpdateActivation(NORMAL_ACTIVATION); | 150 UpdateActivation(ActivationType::NORMAL); |
151 UpdateActivation(NORMAL_ACTIVATION); | |
152 } | 151 } |
153 | 152 |
154 void ElementAnimations::AddAnimation(std::unique_ptr<Animation> animation) { | 153 void ElementAnimations::UpdateClientAnimationState( |
155 DCHECK(!animation->is_impl_only() || | 154 TargetProperty::Type target_property) { |
156 animation->target_property() == TargetProperty::SCROLL_OFFSET); | |
157 TargetProperty::Type target_property = animation->target_property(); | |
158 animations_.push_back(std::move(animation)); | |
159 needs_to_start_animations_ = true; | |
160 UpdateActivation(NORMAL_ACTIVATION); | |
161 switch (target_property) { | 155 switch (target_property) { |
162 case TargetProperty::TRANSFORM: | 156 case TargetProperty::TRANSFORM: |
163 case TargetProperty::OPACITY: | 157 case TargetProperty::OPACITY: |
164 case TargetProperty::FILTER: | 158 case TargetProperty::FILTER: |
165 UpdateClientAnimationState(target_property); | 159 UpdateClientAnimationStateInternal(target_property); |
166 break; | 160 break; |
167 default: | 161 default: |
| 162 // Do not update for other properties. |
168 break; | 163 break; |
169 } | 164 } |
170 SetNeedsPushProperties(); | 165 } |
| 166 |
| 167 void ElementAnimations::UpdateClientAnimationState(bool transform, |
| 168 bool opacity, |
| 169 bool filter) { |
| 170 if (transform) |
| 171 UpdateClientAnimationStateInternal(TargetProperty::TRANSFORM); |
| 172 if (opacity) |
| 173 UpdateClientAnimationStateInternal(TargetProperty::OPACITY); |
| 174 if (filter) |
| 175 UpdateClientAnimationStateInternal(TargetProperty::FILTER); |
| 176 } |
| 177 |
| 178 void ElementAnimations::AddAnimation(std::unique_ptr<Animation> animation) { |
| 179 // TODO(loyso): Erase this. Rewrite element_animations_unittest to use |
| 180 // AnimationPlayer::AddAnimation. |
| 181 |
| 182 // Add animation to the first player. |
| 183 DCHECK(players_list_->might_have_observers()); |
| 184 ElementAnimations::PlayersList::Iterator it(players_list_.get()); |
| 185 AnimationPlayer* player = it.GetNext(); |
| 186 DCHECK(player); |
| 187 player->AddAnimation(std::move(animation)); |
171 } | 188 } |
172 | 189 |
173 void ElementAnimations::Animate(base::TimeTicks monotonic_time) { | 190 void ElementAnimations::Animate(base::TimeTicks monotonic_time) { |
174 DCHECK(!monotonic_time.is_null()); | 191 DCHECK(!monotonic_time.is_null()); |
175 if (!has_element_in_active_list() && !has_element_in_pending_list()) | 192 if (!has_element_in_active_list() && !has_element_in_pending_list()) |
176 return; | 193 return; |
177 | 194 |
178 if (needs_to_start_animations_) | 195 { |
179 StartAnimations(monotonic_time); | 196 // TODO(crbug.com/634916): Shouldn't manually iterate through the list if |
180 TickAnimations(monotonic_time); | 197 // base::ObserverList has a callback mechanism. |
| 198 ElementAnimations::PlayersList::Iterator it(players_list_.get()); |
| 199 AnimationPlayer* player; |
| 200 while ((player = it.GetNext()) != nullptr) { |
| 201 if (player->needs_to_start_animations()) |
| 202 player->StartAnimations(monotonic_time); |
| 203 } |
| 204 } |
| 205 { |
| 206 ElementAnimations::PlayersList::Iterator it(players_list_.get()); |
| 207 AnimationPlayer* player; |
| 208 while ((player = it.GetNext()) != nullptr) |
| 209 player->TickAnimations(monotonic_time); |
| 210 } |
181 last_tick_time_ = monotonic_time; | 211 last_tick_time_ = monotonic_time; |
182 UpdateClientAnimationState(TargetProperty::OPACITY); | 212 |
183 UpdateClientAnimationState(TargetProperty::TRANSFORM); | 213 UpdateClientAnimationStateInternal(TargetProperty::OPACITY); |
184 UpdateClientAnimationState(TargetProperty::FILTER); | 214 UpdateClientAnimationStateInternal(TargetProperty::TRANSFORM); |
| 215 UpdateClientAnimationStateInternal(TargetProperty::FILTER); |
185 } | 216 } |
186 | 217 |
187 void ElementAnimations::UpdateState(bool start_ready_animations, | 218 void ElementAnimations::UpdateState(bool start_ready_animations, |
188 AnimationEvents* events) { | 219 AnimationEvents* events) { |
189 if (!has_element_in_active_list()) | 220 if (!has_element_in_active_list()) |
190 return; | 221 return; |
191 | 222 |
192 // Animate hasn't been called, this happens if an element has been added | 223 // Animate hasn't been called, this happens if an element has been added |
193 // between the Commit and Draw phases. | 224 // between the Commit and Draw phases. |
194 if (last_tick_time_ == base::TimeTicks()) | 225 if (last_tick_time_ == base::TimeTicks()) |
195 return; | 226 return; |
196 | 227 |
197 if (start_ready_animations) | 228 if (start_ready_animations) { |
198 PromoteStartedAnimations(last_tick_time_, events); | 229 ElementAnimations::PlayersList::Iterator it(players_list_.get()); |
199 | 230 AnimationPlayer* player; |
200 MarkFinishedAnimations(last_tick_time_); | 231 while ((player = it.GetNext()) != nullptr) |
201 MarkAnimationsForDeletion(last_tick_time_, events); | 232 player->PromoteStartedAnimations(last_tick_time_, events); |
202 | |
203 if (needs_to_start_animations_ && start_ready_animations) { | |
204 StartAnimations(last_tick_time_); | |
205 PromoteStartedAnimations(last_tick_time_, events); | |
206 } | 233 } |
207 | 234 |
208 UpdateActivation(NORMAL_ACTIVATION); | 235 { |
| 236 ElementAnimations::PlayersList::Iterator it(players_list_.get()); |
| 237 AnimationPlayer* player; |
| 238 while ((player = it.GetNext()) != nullptr) |
| 239 player->MarkFinishedAnimations(last_tick_time_); |
| 240 } |
| 241 { |
| 242 ElementAnimations::PlayersList::Iterator it(players_list_.get()); |
| 243 AnimationPlayer* player; |
| 244 while ((player = it.GetNext()) != nullptr) |
| 245 player->MarkAnimationsForDeletion(last_tick_time_, events); |
| 246 } |
| 247 |
| 248 if (start_ready_animations) { |
| 249 ElementAnimations::PlayersList::Iterator it(players_list_.get()); |
| 250 AnimationPlayer* player; |
| 251 while ((player = it.GetNext()) != nullptr) { |
| 252 if (player->needs_to_start_animations()) { |
| 253 player->StartAnimations(last_tick_time_); |
| 254 player->PromoteStartedAnimations(last_tick_time_, events); |
| 255 } |
| 256 } |
| 257 } |
| 258 |
| 259 UpdateActivation(ActivationType::NORMAL); |
209 } | 260 } |
210 | 261 |
211 void ElementAnimations::ActivateAnimations() { | 262 void ElementAnimations::ActivateAnimations() { |
212 bool changed_transform_animation = false; | 263 bool changed_transform_animation = false; |
213 bool changed_opacity_animation = false; | 264 bool changed_opacity_animation = false; |
214 bool changed_filter_animation = false; | 265 bool changed_filter_animation = false; |
215 for (size_t i = 0; i < animations_.size(); ++i) { | 266 |
216 if (animations_[i]->affects_active_elements() != | 267 ElementAnimations::PlayersList::Iterator it(players_list_.get()); |
217 animations_[i]->affects_pending_elements()) { | 268 AnimationPlayer* player; |
218 if (animations_[i]->target_property() == TargetProperty::TRANSFORM) | 269 while ((player = it.GetNext()) != nullptr) { |
219 changed_transform_animation = true; | 270 player->ActivateAnimations(&changed_transform_animation, |
220 else if (animations_[i]->target_property() == TargetProperty::OPACITY) | 271 &changed_opacity_animation, |
221 changed_opacity_animation = true; | 272 &changed_filter_animation); |
222 else if (animations_[i]->target_property() == TargetProperty::FILTER) | |
223 changed_filter_animation = true; | |
224 } | |
225 animations_[i]->set_affects_active_elements( | |
226 animations_[i]->affects_pending_elements()); | |
227 } | 273 } |
228 auto affects_no_elements = [](const std::unique_ptr<Animation>& animation) { | 274 |
229 return !animation->affects_active_elements() && | |
230 !animation->affects_pending_elements(); | |
231 }; | |
232 animations_.erase(std::remove_if(animations_.begin(), animations_.end(), | |
233 affects_no_elements), | |
234 animations_.end()); | |
235 scroll_offset_animation_was_interrupted_ = false; | 275 scroll_offset_animation_was_interrupted_ = false; |
236 UpdateActivation(NORMAL_ACTIVATION); | 276 UpdateActivation(ActivationType::NORMAL); |
237 if (changed_transform_animation) | 277 UpdateClientAnimationState(changed_transform_animation, |
238 UpdateClientAnimationState(TargetProperty::TRANSFORM); | 278 changed_opacity_animation, |
239 if (changed_opacity_animation) | 279 changed_filter_animation); |
240 UpdateClientAnimationState(TargetProperty::OPACITY); | |
241 if (changed_filter_animation) | |
242 UpdateClientAnimationState(TargetProperty::FILTER); | |
243 } | 280 } |
244 | 281 |
245 void ElementAnimations::NotifyAnimationStarted(const AnimationEvent& event) { | 282 void ElementAnimations::NotifyAnimationStarted(const AnimationEvent& event) { |
246 if (event.is_impl_only) { | 283 DCHECK(!event.is_impl_only); |
247 NotifyPlayersAnimationStarted(event.monotonic_time, event.target_property, | 284 ElementAnimations::PlayersList::Iterator it(players_list_.get()); |
248 event.group_id); | 285 AnimationPlayer* player; |
249 return; | 286 while ((player = it.GetNext()) != nullptr) { |
250 } | 287 if (player->NotifyAnimationStarted(event)) |
251 | 288 break; |
252 for (size_t i = 0; i < animations_.size(); ++i) { | |
253 if (animations_[i]->group() == event.group_id && | |
254 animations_[i]->target_property() == event.target_property && | |
255 animations_[i]->needs_synchronized_start_time()) { | |
256 animations_[i]->set_needs_synchronized_start_time(false); | |
257 if (!animations_[i]->has_set_start_time()) | |
258 animations_[i]->set_start_time(event.monotonic_time); | |
259 | |
260 NotifyPlayersAnimationStarted(event.monotonic_time, event.target_property, | |
261 event.group_id); | |
262 | |
263 return; | |
264 } | |
265 } | 289 } |
266 } | 290 } |
267 | 291 |
268 void ElementAnimations::NotifyAnimationFinished(const AnimationEvent& event) { | 292 void ElementAnimations::NotifyAnimationFinished(const AnimationEvent& event) { |
269 if (event.is_impl_only) { | 293 DCHECK(!event.is_impl_only); |
270 NotifyPlayersAnimationFinished(event.monotonic_time, event.target_property, | 294 ElementAnimations::PlayersList::Iterator it(players_list_.get()); |
271 event.group_id); | 295 AnimationPlayer* player; |
272 return; | 296 while ((player = it.GetNext()) != nullptr) { |
273 } | 297 if (player->NotifyAnimationFinished(event)) |
274 | 298 break; |
275 for (size_t i = 0; i < animations_.size(); ++i) { | |
276 if (animations_[i]->group() == event.group_id && | |
277 animations_[i]->target_property() == event.target_property) { | |
278 animations_[i]->set_received_finished_event(true); | |
279 NotifyPlayersAnimationFinished(event.monotonic_time, | |
280 event.target_property, event.group_id); | |
281 | |
282 return; | |
283 } | |
284 } | 299 } |
285 } | 300 } |
286 | 301 |
287 void ElementAnimations::NotifyAnimationTakeover(const AnimationEvent& event) { | 302 void ElementAnimations::NotifyAnimationTakeover(const AnimationEvent& event) { |
| 303 DCHECK(!event.is_impl_only); |
288 DCHECK(event.target_property == TargetProperty::SCROLL_OFFSET); | 304 DCHECK(event.target_property == TargetProperty::SCROLL_OFFSET); |
289 if (!IsEmpty()) { | 305 |
290 std::unique_ptr<AnimationCurve> animation_curve = event.curve->Clone(); | 306 ElementAnimations::PlayersList::Iterator it(players_list_.get()); |
291 NotifyPlayersAnimationTakeover(event.monotonic_time, event.target_property, | 307 AnimationPlayer* player; |
292 event.animation_start_time, | 308 while ((player = it.GetNext()) != nullptr) |
293 std::move(animation_curve)); | 309 player->NotifyAnimationTakeover(event); |
294 } | |
295 } | 310 } |
296 | 311 |
297 void ElementAnimations::NotifyAnimationAborted(const AnimationEvent& event) { | 312 void ElementAnimations::NotifyAnimationAborted(const AnimationEvent& event) { |
298 for (size_t i = 0; i < animations_.size(); ++i) { | 313 DCHECK(!event.is_impl_only); |
299 if (animations_[i]->group() == event.group_id && | 314 |
300 animations_[i]->target_property() == event.target_property) { | 315 ElementAnimations::PlayersList::Iterator it(players_list_.get()); |
301 animations_[i]->SetRunState(Animation::ABORTED, event.monotonic_time); | 316 AnimationPlayer* player; |
302 animations_[i]->set_received_finished_event(true); | 317 while ((player = it.GetNext()) != nullptr) { |
303 NotifyPlayersAnimationAborted(event.monotonic_time, event.target_property, | 318 if (player->NotifyAnimationAborted(event)) |
304 event.group_id); | |
305 break; | |
306 } | |
307 } | |
308 switch (event.target_property) { | |
309 case TargetProperty::TRANSFORM: | |
310 case TargetProperty::OPACITY: | |
311 case TargetProperty::FILTER: | |
312 UpdateClientAnimationState(event.target_property); | |
313 break; | |
314 default: | |
315 break; | 319 break; |
316 } | 320 } |
| 321 |
| 322 UpdateClientAnimationState(event.target_property); |
317 } | 323 } |
318 | 324 |
319 void ElementAnimations::NotifyAnimationPropertyUpdate( | 325 void ElementAnimations::NotifyAnimationPropertyUpdate( |
320 const AnimationEvent& event) { | 326 const AnimationEvent& event) { |
| 327 DCHECK(!event.is_impl_only); |
321 bool notify_active_elements = true; | 328 bool notify_active_elements = true; |
322 bool notify_pending_elements = true; | 329 bool notify_pending_elements = true; |
323 switch (event.target_property) { | 330 switch (event.target_property) { |
324 case TargetProperty::OPACITY: | 331 case TargetProperty::OPACITY: |
325 NotifyClientOpacityAnimated(event.opacity, notify_active_elements, | 332 NotifyClientOpacityAnimated(event.opacity, notify_active_elements, |
326 notify_pending_elements); | 333 notify_pending_elements); |
327 break; | 334 break; |
328 case TargetProperty::TRANSFORM: | 335 case TargetProperty::TRANSFORM: |
329 NotifyClientTransformAnimated(event.transform, notify_active_elements, | 336 NotifyClientTransformAnimated(event.transform, notify_active_elements, |
330 notify_pending_elements); | 337 notify_pending_elements); |
331 break; | 338 break; |
332 default: | 339 default: |
333 NOTREACHED(); | 340 NOTREACHED(); |
334 } | 341 } |
335 } | 342 } |
336 | 343 |
337 bool ElementAnimations::HasFilterAnimationThatInflatesBounds() const { | 344 bool ElementAnimations::HasFilterAnimationThatInflatesBounds() const { |
338 for (size_t i = 0; i < animations_.size(); ++i) { | 345 ElementAnimations::PlayersList::Iterator it(players_list_.get()); |
339 if (!animations_[i]->is_finished() && | 346 AnimationPlayer* player; |
340 animations_[i]->target_property() == TargetProperty::FILTER && | 347 while ((player = it.GetNext()) != nullptr) { |
341 animations_[i] | 348 if (player->HasFilterAnimationThatInflatesBounds()) |
342 ->curve() | |
343 ->ToFilterAnimationCurve() | |
344 ->HasFilterThatMovesPixels()) | |
345 return true; | 349 return true; |
346 } | 350 } |
347 | |
348 return false; | 351 return false; |
349 } | 352 } |
350 | 353 |
351 bool ElementAnimations::HasTransformAnimationThatInflatesBounds() const { | 354 bool ElementAnimations::HasTransformAnimationThatInflatesBounds() const { |
352 return IsCurrentlyAnimatingProperty(TargetProperty::TRANSFORM, | 355 ElementAnimations::PlayersList::Iterator it(players_list_.get()); |
353 ElementListType::ACTIVE) || | 356 AnimationPlayer* player; |
354 IsCurrentlyAnimatingProperty(TargetProperty::TRANSFORM, | 357 while ((player = it.GetNext()) != nullptr) { |
355 ElementListType::PENDING); | 358 if (player->HasTransformAnimationThatInflatesBounds()) |
| 359 return true; |
| 360 } |
| 361 return false; |
356 } | 362 } |
357 | 363 |
358 bool ElementAnimations::FilterAnimationBoundsForBox(const gfx::BoxF& box, | 364 bool ElementAnimations::FilterAnimationBoundsForBox(const gfx::BoxF& box, |
359 gfx::BoxF* bounds) const { | 365 gfx::BoxF* bounds) const { |
360 // TODO(avallee): Implement. | 366 // TODO(avallee): Implement. |
361 return false; | 367 return false; |
362 } | 368 } |
363 | 369 |
364 bool ElementAnimations::TransformAnimationBoundsForBox( | 370 bool ElementAnimations::TransformAnimationBoundsForBox( |
365 const gfx::BoxF& box, | 371 const gfx::BoxF& box, |
366 gfx::BoxF* bounds) const { | 372 gfx::BoxF* bounds) const { |
367 DCHECK(HasTransformAnimationThatInflatesBounds()) | 373 *bounds = gfx::BoxF(); |
368 << "TransformAnimationBoundsForBox will give incorrect results if there " | |
369 << "are no transform animations affecting bounds, non-animated transform " | |
370 << "is not known"; | |
371 | 374 |
372 // Compute bounds based on animations for which is_finished() is false. | 375 ElementAnimations::PlayersList::Iterator it(players_list_.get()); |
373 // Do nothing if there are no such animations; in this case, it is assumed | 376 AnimationPlayer* player; |
374 // that callers will take care of computing bounds based on the owning layer's | 377 while ((player = it.GetNext()) != nullptr) { |
375 // actual transform. | 378 gfx::BoxF player_bounds; |
376 *bounds = gfx::BoxF(); | 379 bool success = player->TransformAnimationBoundsForBox(box, &player_bounds); |
377 for (size_t i = 0; i < animations_.size(); ++i) { | |
378 if (animations_[i]->is_finished() || | |
379 animations_[i]->target_property() != TargetProperty::TRANSFORM) | |
380 continue; | |
381 | |
382 const TransformAnimationCurve* transform_animation_curve = | |
383 animations_[i]->curve()->ToTransformAnimationCurve(); | |
384 gfx::BoxF animation_bounds; | |
385 bool success = | |
386 transform_animation_curve->AnimatedBoundsForBox(box, &animation_bounds); | |
387 if (!success) | 380 if (!success) |
388 return false; | 381 return false; |
389 bounds->Union(animation_bounds); | 382 bounds->Union(player_bounds); |
390 } | 383 } |
391 | |
392 return true; | 384 return true; |
393 } | 385 } |
394 | 386 |
395 bool ElementAnimations::HasAnimationThatAffectsScale() const { | 387 bool ElementAnimations::HasAnimationThatAffectsScale() const { |
396 for (size_t i = 0; i < animations_.size(); ++i) { | 388 ElementAnimations::PlayersList::Iterator it(players_list_.get()); |
397 if (animations_[i]->is_finished() || | 389 AnimationPlayer* player; |
398 animations_[i]->target_property() != TargetProperty::TRANSFORM) | 390 while ((player = it.GetNext()) != nullptr) { |
399 continue; | 391 if (player->HasAnimationThatAffectsScale()) |
400 | |
401 const TransformAnimationCurve* transform_animation_curve = | |
402 animations_[i]->curve()->ToTransformAnimationCurve(); | |
403 if (transform_animation_curve->AffectsScale()) | |
404 return true; | 392 return true; |
405 } | 393 } |
406 | |
407 return false; | 394 return false; |
408 } | 395 } |
409 | 396 |
410 bool ElementAnimations::HasOnlyTranslationTransforms( | 397 bool ElementAnimations::HasOnlyTranslationTransforms( |
411 ElementListType list_type) const { | 398 ElementListType list_type) const { |
412 for (size_t i = 0; i < animations_.size(); ++i) { | 399 ElementAnimations::PlayersList::Iterator it(players_list_.get()); |
413 if (animations_[i]->is_finished() || | 400 AnimationPlayer* player; |
414 animations_[i]->target_property() != TargetProperty::TRANSFORM) | 401 while ((player = it.GetNext()) != nullptr) { |
415 continue; | 402 if (!player->HasOnlyTranslationTransforms(list_type)) |
416 | |
417 if ((list_type == ElementListType::ACTIVE && | |
418 !animations_[i]->affects_active_elements()) || | |
419 (list_type == ElementListType::PENDING && | |
420 !animations_[i]->affects_pending_elements())) | |
421 continue; | |
422 | |
423 const TransformAnimationCurve* transform_animation_curve = | |
424 animations_[i]->curve()->ToTransformAnimationCurve(); | |
425 if (!transform_animation_curve->IsTranslation()) | |
426 return false; | 403 return false; |
427 } | 404 } |
428 | |
429 return true; | 405 return true; |
430 } | 406 } |
431 | 407 |
432 bool ElementAnimations::AnimationsPreserveAxisAlignment() const { | 408 bool ElementAnimations::AnimationsPreserveAxisAlignment() const { |
433 for (size_t i = 0; i < animations_.size(); ++i) { | 409 ElementAnimations::PlayersList::Iterator it(players_list_.get()); |
434 if (animations_[i]->is_finished() || | 410 AnimationPlayer* player; |
435 animations_[i]->target_property() != TargetProperty::TRANSFORM) | 411 while ((player = it.GetNext()) != nullptr) { |
436 continue; | 412 if (!player->AnimationsPreserveAxisAlignment()) |
437 | |
438 const TransformAnimationCurve* transform_animation_curve = | |
439 animations_[i]->curve()->ToTransformAnimationCurve(); | |
440 if (!transform_animation_curve->PreservesAxisAlignment()) | |
441 return false; | 413 return false; |
442 } | 414 } |
443 | |
444 return true; | 415 return true; |
445 } | 416 } |
446 | 417 |
447 bool ElementAnimations::AnimationStartScale(ElementListType list_type, | 418 bool ElementAnimations::AnimationStartScale(ElementListType list_type, |
448 float* start_scale) const { | 419 float* start_scale) const { |
449 *start_scale = 0.f; | 420 *start_scale = 0.f; |
450 for (size_t i = 0; i < animations_.size(); ++i) { | |
451 if (animations_[i]->is_finished() || | |
452 animations_[i]->target_property() != TargetProperty::TRANSFORM) | |
453 continue; | |
454 | 421 |
455 if ((list_type == ElementListType::ACTIVE && | 422 ElementAnimations::PlayersList::Iterator it(players_list_.get()); |
456 !animations_[i]->affects_active_elements()) || | 423 AnimationPlayer* player; |
457 (list_type == ElementListType::PENDING && | 424 while ((player = it.GetNext()) != nullptr) { |
458 !animations_[i]->affects_pending_elements())) | 425 float player_start_scale = 0.f; |
459 continue; | 426 bool success = player->AnimationStartScale(list_type, &player_start_scale); |
| 427 if (!success) |
| 428 return false; |
| 429 // Union: a maximum. |
| 430 *start_scale = std::max(*start_scale, player_start_scale); |
| 431 } |
460 | 432 |
461 bool forward_direction = true; | |
462 switch (animations_[i]->direction()) { | |
463 case Animation::Direction::NORMAL: | |
464 case Animation::Direction::ALTERNATE_NORMAL: | |
465 forward_direction = animations_[i]->playback_rate() >= 0.0; | |
466 break; | |
467 case Animation::Direction::REVERSE: | |
468 case Animation::Direction::ALTERNATE_REVERSE: | |
469 forward_direction = animations_[i]->playback_rate() < 0.0; | |
470 break; | |
471 } | |
472 | |
473 const TransformAnimationCurve* transform_animation_curve = | |
474 animations_[i]->curve()->ToTransformAnimationCurve(); | |
475 float animation_start_scale = 0.f; | |
476 if (!transform_animation_curve->AnimationStartScale(forward_direction, | |
477 &animation_start_scale)) | |
478 return false; | |
479 *start_scale = std::max(*start_scale, animation_start_scale); | |
480 } | |
481 return true; | 433 return true; |
482 } | 434 } |
483 | 435 |
484 bool ElementAnimations::MaximumTargetScale(ElementListType list_type, | 436 bool ElementAnimations::MaximumTargetScale(ElementListType list_type, |
485 float* max_scale) const { | 437 float* max_scale) const { |
486 *max_scale = 0.f; | 438 *max_scale = 0.f; |
487 for (size_t i = 0; i < animations_.size(); ++i) { | |
488 if (animations_[i]->is_finished() || | |
489 animations_[i]->target_property() != TargetProperty::TRANSFORM) | |
490 continue; | |
491 | 439 |
492 if ((list_type == ElementListType::ACTIVE && | 440 ElementAnimations::PlayersList::Iterator it(players_list_.get()); |
493 !animations_[i]->affects_active_elements()) || | 441 AnimationPlayer* player; |
494 (list_type == ElementListType::PENDING && | 442 while ((player = it.GetNext()) != nullptr) { |
495 !animations_[i]->affects_pending_elements())) | 443 float player_max_scale = 0.f; |
496 continue; | 444 bool success = player->MaximumTargetScale(list_type, &player_max_scale); |
497 | 445 if (!success) |
498 bool forward_direction = true; | |
499 switch (animations_[i]->direction()) { | |
500 case Animation::Direction::NORMAL: | |
501 case Animation::Direction::ALTERNATE_NORMAL: | |
502 forward_direction = animations_[i]->playback_rate() >= 0.0; | |
503 break; | |
504 case Animation::Direction::REVERSE: | |
505 case Animation::Direction::ALTERNATE_REVERSE: | |
506 forward_direction = animations_[i]->playback_rate() < 0.0; | |
507 break; | |
508 } | |
509 | |
510 const TransformAnimationCurve* transform_animation_curve = | |
511 animations_[i]->curve()->ToTransformAnimationCurve(); | |
512 float animation_scale = 0.f; | |
513 if (!transform_animation_curve->MaximumTargetScale(forward_direction, | |
514 &animation_scale)) | |
515 return false; | 446 return false; |
516 *max_scale = std::max(*max_scale, animation_scale); | 447 // Union: a maximum. |
| 448 *max_scale = std::max(*max_scale, player_max_scale); |
517 } | 449 } |
518 | 450 |
519 return true; | 451 return true; |
520 } | 452 } |
521 | 453 |
522 void ElementAnimations::PushNewAnimationsToImplThread( | 454 void ElementAnimations::SetNeedsUpdateImplClientState(bool transform, |
523 ElementAnimations* element_animations_impl) const { | 455 bool opacity, |
524 // Any new animations owned by the main thread's ElementAnimations are cloned | 456 bool filter) { |
525 // and added to the impl thread's ElementAnimations. | 457 if (transform) |
526 for (size_t i = 0; i < animations_.size(); ++i) { | 458 needs_update_impl_client_state_transform_ = true; |
527 // If the animation is already running on the impl thread, there is no | 459 if (opacity) |
528 // need to copy it over. | 460 needs_update_impl_client_state_opacity_ = true; |
529 if (element_animations_impl->GetAnimationById(animations_[i]->id())) | 461 if (filter) |
530 continue; | 462 needs_update_impl_client_state_filter_ = true; |
531 | 463 |
532 if (animations_[i]->target_property() == TargetProperty::SCROLL_OFFSET && | 464 if (needs_update_impl_client_state_transform_ || |
533 !animations_[i] | 465 needs_update_impl_client_state_opacity_ || |
534 ->curve() | 466 needs_update_impl_client_state_filter_) |
535 ->ToScrollOffsetAnimationCurve() | 467 SetNeedsPushProperties(); |
536 ->HasSetInitialValue()) { | |
537 gfx::ScrollOffset current_scroll_offset; | |
538 if (element_animations_impl->has_element_in_active_list()) { | |
539 current_scroll_offset = | |
540 element_animations_impl->ScrollOffsetForAnimation(); | |
541 } else { | |
542 // The owning layer isn't yet in the active tree, so the main thread | |
543 // scroll offset will be up to date. | |
544 current_scroll_offset = ScrollOffsetForAnimation(); | |
545 } | |
546 animations_[i]->curve()->ToScrollOffsetAnimationCurve()->SetInitialValue( | |
547 current_scroll_offset); | |
548 } | |
549 | |
550 // The new animation should be set to run as soon as possible. | |
551 Animation::RunState initial_run_state = | |
552 Animation::WAITING_FOR_TARGET_AVAILABILITY; | |
553 std::unique_ptr<Animation> to_add( | |
554 animations_[i]->CloneAndInitialize(initial_run_state)); | |
555 DCHECK(!to_add->needs_synchronized_start_time()); | |
556 to_add->set_affects_active_elements(false); | |
557 element_animations_impl->AddAnimation(std::move(to_add)); | |
558 } | |
559 } | 468 } |
560 | 469 |
561 static bool IsCompleted( | 470 void ElementAnimations::ClearNeedsUpdateImplClientState() { |
562 Animation* animation, | 471 needs_update_impl_client_state_transform_ = false; |
563 const ElementAnimations* main_thread_element_animations) { | 472 needs_update_impl_client_state_opacity_ = false; |
564 if (animation->is_impl_only()) { | 473 needs_update_impl_client_state_filter_ = false; |
565 return (animation->run_state() == Animation::WAITING_FOR_DELETION); | |
566 } else { | |
567 return !main_thread_element_animations->GetAnimationById(animation->id()); | |
568 } | |
569 } | 474 } |
570 | 475 |
571 void ElementAnimations::RemoveAnimationsCompletedOnMainThread( | 476 void ElementAnimations::UpdateActivation(ActivationType type) { |
572 ElementAnimations* element_animations_impl) const { | 477 bool force = type == ActivationType::FORCE; |
573 bool removed_transform_animation = false; | |
574 bool removed_opacity_animation = false; | |
575 bool removed_filter_animation = false; | |
576 // Animations removed on the main thread should no longer affect pending | |
577 // elements, and should stop affecting active elements after the next call | |
578 // to ActivateAnimations. If already WAITING_FOR_DELETION, they can be removed | |
579 // immediately. | |
580 auto& animations = element_animations_impl->animations_; | |
581 for (const auto& animation : animations) { | |
582 if (IsCompleted(animation.get(), this)) { | |
583 animation->set_affects_pending_elements(false); | |
584 if (animation->target_property() == TargetProperty::TRANSFORM) | |
585 removed_transform_animation = true; | |
586 else if (animation->target_property() == TargetProperty::OPACITY) | |
587 removed_opacity_animation = true; | |
588 else if (animation->target_property() == TargetProperty::FILTER) | |
589 removed_filter_animation = true; | |
590 } | |
591 } | |
592 auto affects_active_only_and_is_waiting_for_deletion = | |
593 [](const std::unique_ptr<Animation>& animation) { | |
594 return animation->run_state() == Animation::WAITING_FOR_DELETION && | |
595 !animation->affects_pending_elements(); | |
596 }; | |
597 animations.erase( | |
598 std::remove_if(animations.begin(), animations.end(), | |
599 affects_active_only_and_is_waiting_for_deletion), | |
600 animations.end()); | |
601 | |
602 if (removed_transform_animation) { | |
603 element_animations_impl->UpdateClientAnimationState( | |
604 TargetProperty::TRANSFORM); | |
605 } | |
606 if (removed_opacity_animation) { | |
607 element_animations_impl->UpdateClientAnimationState( | |
608 TargetProperty::OPACITY); | |
609 } | |
610 if (removed_filter_animation) { | |
611 element_animations_impl->UpdateClientAnimationState(TargetProperty::FILTER); | |
612 } | |
613 } | |
614 | |
615 void ElementAnimations::PushPropertiesToImplThread( | |
616 ElementAnimations* element_animations_impl) { | |
617 for (size_t i = 0; i < animations_.size(); ++i) { | |
618 Animation* current_impl = | |
619 element_animations_impl->GetAnimationById(animations_[i]->id()); | |
620 if (current_impl) | |
621 animations_[i]->PushPropertiesTo(current_impl); | |
622 } | |
623 element_animations_impl->scroll_offset_animation_was_interrupted_ = | |
624 scroll_offset_animation_was_interrupted_; | |
625 scroll_offset_animation_was_interrupted_ = false; | |
626 } | |
627 | |
628 void ElementAnimations::StartAnimations(base::TimeTicks monotonic_time) { | |
629 DCHECK(needs_to_start_animations_); | |
630 needs_to_start_animations_ = false; | |
631 // First collect running properties affecting each type of element. | |
632 TargetProperties blocked_properties_for_active_elements; | |
633 TargetProperties blocked_properties_for_pending_elements; | |
634 std::vector<size_t> animations_waiting_for_target; | |
635 | |
636 animations_waiting_for_target.reserve(animations_.size()); | |
637 for (size_t i = 0; i < animations_.size(); ++i) { | |
638 if (animations_[i]->run_state() == Animation::STARTING || | |
639 animations_[i]->run_state() == Animation::RUNNING) { | |
640 if (animations_[i]->affects_active_elements()) { | |
641 blocked_properties_for_active_elements[animations_[i] | |
642 ->target_property()] = true; | |
643 } | |
644 if (animations_[i]->affects_pending_elements()) { | |
645 blocked_properties_for_pending_elements[animations_[i] | |
646 ->target_property()] = true; | |
647 } | |
648 } else if (animations_[i]->run_state() == | |
649 Animation::WAITING_FOR_TARGET_AVAILABILITY) { | |
650 animations_waiting_for_target.push_back(i); | |
651 } | |
652 } | |
653 | |
654 for (size_t i = 0; i < animations_waiting_for_target.size(); ++i) { | |
655 // Collect all properties for animations with the same group id (they | |
656 // should all also be in the list of animations). | |
657 size_t animation_index = animations_waiting_for_target[i]; | |
658 Animation* animation_waiting_for_target = | |
659 animations_[animation_index].get(); | |
660 // Check for the run state again even though the animation was waiting | |
661 // for target because it might have changed the run state while handling | |
662 // previous animation in this loop (if they belong to same group). | |
663 if (animation_waiting_for_target->run_state() == | |
664 Animation::WAITING_FOR_TARGET_AVAILABILITY) { | |
665 TargetProperties enqueued_properties; | |
666 bool affects_active_elements = | |
667 animation_waiting_for_target->affects_active_elements(); | |
668 bool affects_pending_elements = | |
669 animation_waiting_for_target->affects_pending_elements(); | |
670 enqueued_properties[animation_waiting_for_target->target_property()] = | |
671 true; | |
672 for (size_t j = animation_index + 1; j < animations_.size(); ++j) { | |
673 if (animation_waiting_for_target->group() == animations_[j]->group()) { | |
674 enqueued_properties[animations_[j]->target_property()] = true; | |
675 affects_active_elements |= animations_[j]->affects_active_elements(); | |
676 affects_pending_elements |= | |
677 animations_[j]->affects_pending_elements(); | |
678 } | |
679 } | |
680 | |
681 // Check to see if intersection of the list of properties affected by | |
682 // the group and the list of currently blocked properties is null, taking | |
683 // into account the type(s) of elements affected by the group. In any | |
684 // case, the group's target properties need to be added to the lists of | |
685 // blocked properties. | |
686 bool null_intersection = true; | |
687 static_assert(TargetProperty::FIRST_TARGET_PROPERTY == 0, | |
688 "TargetProperty must be 0-based enum"); | |
689 for (int property = TargetProperty::FIRST_TARGET_PROPERTY; | |
690 property <= TargetProperty::LAST_TARGET_PROPERTY; ++property) { | |
691 if (enqueued_properties[property]) { | |
692 if (affects_active_elements) { | |
693 if (blocked_properties_for_active_elements[property]) | |
694 null_intersection = false; | |
695 else | |
696 blocked_properties_for_active_elements[property] = true; | |
697 } | |
698 if (affects_pending_elements) { | |
699 if (blocked_properties_for_pending_elements[property]) | |
700 null_intersection = false; | |
701 else | |
702 blocked_properties_for_pending_elements[property] = true; | |
703 } | |
704 } | |
705 } | |
706 | |
707 // If the intersection is null, then we are free to start the animations | |
708 // in the group. | |
709 if (null_intersection) { | |
710 animation_waiting_for_target->SetRunState(Animation::STARTING, | |
711 monotonic_time); | |
712 for (size_t j = animation_index + 1; j < animations_.size(); ++j) { | |
713 if (animation_waiting_for_target->group() == | |
714 animations_[j]->group()) { | |
715 animations_[j]->SetRunState(Animation::STARTING, monotonic_time); | |
716 } | |
717 } | |
718 } else { | |
719 needs_to_start_animations_ = true; | |
720 } | |
721 } | |
722 } | |
723 } | |
724 | |
725 void ElementAnimations::PromoteStartedAnimations(base::TimeTicks monotonic_time, | |
726 AnimationEvents* events) { | |
727 for (size_t i = 0; i < animations_.size(); ++i) { | |
728 if (animations_[i]->run_state() == Animation::STARTING && | |
729 animations_[i]->affects_active_elements()) { | |
730 animations_[i]->SetRunState(Animation::RUNNING, monotonic_time); | |
731 if (!animations_[i]->has_set_start_time() && | |
732 !animations_[i]->needs_synchronized_start_time()) | |
733 animations_[i]->set_start_time(monotonic_time); | |
734 if (events) { | |
735 base::TimeTicks start_time; | |
736 if (animations_[i]->has_set_start_time()) | |
737 start_time = animations_[i]->start_time(); | |
738 else | |
739 start_time = monotonic_time; | |
740 AnimationEvent started_event( | |
741 AnimationEvent::STARTED, element_id_, animations_[i]->group(), | |
742 animations_[i]->target_property(), start_time); | |
743 started_event.is_impl_only = animations_[i]->is_impl_only(); | |
744 if (started_event.is_impl_only) | |
745 NotifyAnimationStarted(started_event); | |
746 else | |
747 events->events_.push_back(started_event); | |
748 } | |
749 } | |
750 } | |
751 } | |
752 | |
753 void ElementAnimations::MarkFinishedAnimations(base::TimeTicks monotonic_time) { | |
754 bool finished_transform_animation = false; | |
755 bool finished_opacity_animation = false; | |
756 bool finished_filter_animation = false; | |
757 for (size_t i = 0; i < animations_.size(); ++i) { | |
758 if (!animations_[i]->is_finished() && | |
759 animations_[i]->IsFinishedAt(monotonic_time)) { | |
760 animations_[i]->SetRunState(Animation::FINISHED, monotonic_time); | |
761 if (animations_[i]->target_property() == TargetProperty::TRANSFORM) | |
762 finished_transform_animation = true; | |
763 else if (animations_[i]->target_property() == TargetProperty::OPACITY) | |
764 finished_opacity_animation = true; | |
765 else if (animations_[i]->target_property() == TargetProperty::FILTER) | |
766 finished_filter_animation = true; | |
767 } | |
768 } | |
769 if (finished_transform_animation) | |
770 UpdateClientAnimationState(TargetProperty::TRANSFORM); | |
771 if (finished_opacity_animation) | |
772 UpdateClientAnimationState(TargetProperty::OPACITY); | |
773 if (finished_filter_animation) | |
774 UpdateClientAnimationState(TargetProperty::FILTER); | |
775 } | |
776 | |
777 void ElementAnimations::MarkAnimationsForDeletion( | |
778 base::TimeTicks monotonic_time, | |
779 AnimationEvents* events) { | |
780 bool marked_animations_for_deletions = false; | |
781 std::vector<size_t> animations_with_same_group_id; | |
782 | |
783 animations_with_same_group_id.reserve(animations_.size()); | |
784 // Non-aborted animations are marked for deletion after a corresponding | |
785 // AnimationEvent::FINISHED event is sent or received. This means that if | |
786 // we don't have an events vector, we must ensure that non-aborted animations | |
787 // have received a finished event before marking them for deletion. | |
788 for (size_t i = 0; i < animations_.size(); i++) { | |
789 int group_id = animations_[i]->group(); | |
790 if (animations_[i]->run_state() == Animation::ABORTED) { | |
791 if (events && !animations_[i]->is_impl_only()) { | |
792 AnimationEvent aborted_event( | |
793 AnimationEvent::ABORTED, element_id_, group_id, | |
794 animations_[i]->target_property(), monotonic_time); | |
795 events->events_.push_back(aborted_event); | |
796 } | |
797 // If on the compositor or on the main thread and received finish event, | |
798 // animation can be marked for deletion. | |
799 if (events || animations_[i]->received_finished_event()) { | |
800 animations_[i]->SetRunState(Animation::WAITING_FOR_DELETION, | |
801 monotonic_time); | |
802 marked_animations_for_deletions = true; | |
803 } | |
804 continue; | |
805 } | |
806 | |
807 // If running on the compositor and need to complete an aborted animation | |
808 // on the main thread. | |
809 if (events && | |
810 animations_[i]->run_state() == | |
811 Animation::ABORTED_BUT_NEEDS_COMPLETION) { | |
812 AnimationEvent aborted_event(AnimationEvent::TAKEOVER, element_id_, | |
813 group_id, animations_[i]->target_property(), | |
814 monotonic_time); | |
815 aborted_event.animation_start_time = | |
816 (animations_[i]->start_time() - base::TimeTicks()).InSecondsF(); | |
817 const ScrollOffsetAnimationCurve* scroll_offset_animation_curve = | |
818 animations_[i]->curve()->ToScrollOffsetAnimationCurve(); | |
819 aborted_event.curve = scroll_offset_animation_curve->Clone(); | |
820 // Notify the compositor that the animation is finished. | |
821 NotifyPlayersAnimationFinished(aborted_event.monotonic_time, | |
822 aborted_event.target_property, | |
823 aborted_event.group_id); | |
824 // Notify main thread. | |
825 events->events_.push_back(aborted_event); | |
826 | |
827 // Remove the animation from the compositor. | |
828 animations_[i]->SetRunState(Animation::WAITING_FOR_DELETION, | |
829 monotonic_time); | |
830 marked_animations_for_deletions = true; | |
831 continue; | |
832 } | |
833 | |
834 bool all_anims_with_same_id_are_finished = false; | |
835 | |
836 // Since deleting an animation on the main thread leads to its deletion | |
837 // on the impl thread, we only mark a FINISHED main thread animation for | |
838 // deletion once it has received a FINISHED event from the impl thread. | |
839 bool animation_i_will_send_or_has_received_finish_event = | |
840 animations_[i]->is_controlling_instance() || | |
841 animations_[i]->is_impl_only() || | |
842 animations_[i]->received_finished_event(); | |
843 // If an animation is finished, and not already marked for deletion, | |
844 // find out if all other animations in the same group are also finished. | |
845 if (animations_[i]->run_state() == Animation::FINISHED && | |
846 animation_i_will_send_or_has_received_finish_event) { | |
847 // Clear the animations_with_same_group_id if it was added for | |
848 // the previous animation's iteration. | |
849 if (animations_with_same_group_id.size() > 0) | |
850 animations_with_same_group_id.clear(); | |
851 all_anims_with_same_id_are_finished = true; | |
852 for (size_t j = 0; j < animations_.size(); ++j) { | |
853 bool animation_j_will_send_or_has_received_finish_event = | |
854 animations_[j]->is_controlling_instance() || | |
855 animations_[j]->is_impl_only() || | |
856 animations_[j]->received_finished_event(); | |
857 if (group_id == animations_[j]->group()) { | |
858 if (!animations_[j]->is_finished() || | |
859 (animations_[j]->run_state() == Animation::FINISHED && | |
860 !animation_j_will_send_or_has_received_finish_event)) { | |
861 all_anims_with_same_id_are_finished = false; | |
862 break; | |
863 } else if (j >= i && | |
864 animations_[j]->run_state() != Animation::ABORTED) { | |
865 // Mark down the animations which belong to the same group | |
866 // and is not yet aborted. If this current iteration finds that all | |
867 // animations with same ID are finished, then the marked | |
868 // animations below will be set to WAITING_FOR_DELETION in next | |
869 // iteration. | |
870 animations_with_same_group_id.push_back(j); | |
871 } | |
872 } | |
873 } | |
874 } | |
875 if (all_anims_with_same_id_are_finished) { | |
876 // We now need to remove all animations with the same group id as | |
877 // group_id (and send along animation finished notifications, if | |
878 // necessary). | |
879 for (size_t j = 0; j < animations_with_same_group_id.size(); j++) { | |
880 size_t animation_index = animations_with_same_group_id[j]; | |
881 if (events) { | |
882 AnimationEvent finished_event( | |
883 AnimationEvent::FINISHED, element_id_, | |
884 animations_[animation_index]->group(), | |
885 animations_[animation_index]->target_property(), monotonic_time); | |
886 finished_event.is_impl_only = | |
887 animations_[animation_index]->is_impl_only(); | |
888 if (finished_event.is_impl_only) | |
889 NotifyAnimationFinished(finished_event); | |
890 else | |
891 events->events_.push_back(finished_event); | |
892 } | |
893 animations_[animation_index]->SetRunState( | |
894 Animation::WAITING_FOR_DELETION, monotonic_time); | |
895 } | |
896 marked_animations_for_deletions = true; | |
897 } | |
898 } | |
899 if (marked_animations_for_deletions) | |
900 NotifyPlayersAnimationWaitingForDeletion(); | |
901 } | |
902 | |
903 void ElementAnimations::MarkAbortedAnimationsForDeletion( | |
904 ElementAnimations* element_animations_impl) const { | |
905 bool aborted_transform_animation = false; | |
906 bool aborted_opacity_animation = false; | |
907 bool aborted_filter_animation = false; | |
908 auto& animations_impl = element_animations_impl->animations_; | |
909 for (const auto& animation_impl : animations_impl) { | |
910 // If the animation has been aborted on the main thread, mark it for | |
911 // deletion. | |
912 if (Animation* animation = GetAnimationById(animation_impl->id())) { | |
913 if (animation->run_state() == Animation::ABORTED) { | |
914 animation_impl->SetRunState(Animation::WAITING_FOR_DELETION, | |
915 element_animations_impl->last_tick_time_); | |
916 animation->SetRunState(Animation::WAITING_FOR_DELETION, | |
917 last_tick_time_); | |
918 if (animation_impl->target_property() == TargetProperty::TRANSFORM) | |
919 aborted_transform_animation = true; | |
920 else if (animation_impl->target_property() == TargetProperty::OPACITY) | |
921 aborted_opacity_animation = true; | |
922 else if (animation_impl->target_property() == TargetProperty::FILTER) | |
923 aborted_filter_animation = true; | |
924 } | |
925 } | |
926 } | |
927 | |
928 if (aborted_transform_animation) { | |
929 element_animations_impl->UpdateClientAnimationState( | |
930 TargetProperty::TRANSFORM); | |
931 } | |
932 if (aborted_opacity_animation) { | |
933 element_animations_impl->UpdateClientAnimationState( | |
934 TargetProperty::OPACITY); | |
935 } | |
936 if (aborted_filter_animation) { | |
937 element_animations_impl->UpdateClientAnimationState(TargetProperty::FILTER); | |
938 } | |
939 } | |
940 | |
941 void ElementAnimations::PurgeAnimationsMarkedForDeletion() { | |
942 animations_.erase( | |
943 std::remove_if(animations_.begin(), animations_.end(), | |
944 [](const std::unique_ptr<Animation>& animation) { | |
945 return animation->run_state() == | |
946 Animation::WAITING_FOR_DELETION; | |
947 }), | |
948 animations_.end()); | |
949 } | |
950 | |
951 void ElementAnimations::TickAnimations(base::TimeTicks monotonic_time) { | |
952 for (size_t i = 0; i < animations_.size(); ++i) { | |
953 if (animations_[i]->run_state() == Animation::STARTING || | |
954 animations_[i]->run_state() == Animation::RUNNING || | |
955 animations_[i]->run_state() == Animation::PAUSED) { | |
956 if (!animations_[i]->InEffect(monotonic_time)) | |
957 continue; | |
958 | |
959 base::TimeDelta trimmed = | |
960 animations_[i]->TrimTimeToCurrentIteration(monotonic_time); | |
961 | |
962 switch (animations_[i]->target_property()) { | |
963 case TargetProperty::TRANSFORM: { | |
964 const TransformAnimationCurve* transform_animation_curve = | |
965 animations_[i]->curve()->ToTransformAnimationCurve(); | |
966 const gfx::Transform transform = | |
967 transform_animation_curve->GetValue(trimmed); | |
968 NotifyClientTransformAnimated( | |
969 transform, animations_[i]->affects_active_elements(), | |
970 animations_[i]->affects_pending_elements()); | |
971 break; | |
972 } | |
973 | |
974 case TargetProperty::OPACITY: { | |
975 const FloatAnimationCurve* float_animation_curve = | |
976 animations_[i]->curve()->ToFloatAnimationCurve(); | |
977 const float opacity = std::max( | |
978 std::min(float_animation_curve->GetValue(trimmed), 1.0f), 0.f); | |
979 NotifyClientOpacityAnimated( | |
980 opacity, animations_[i]->affects_active_elements(), | |
981 animations_[i]->affects_pending_elements()); | |
982 break; | |
983 } | |
984 | |
985 case TargetProperty::FILTER: { | |
986 const FilterAnimationCurve* filter_animation_curve = | |
987 animations_[i]->curve()->ToFilterAnimationCurve(); | |
988 const FilterOperations filter = | |
989 filter_animation_curve->GetValue(trimmed); | |
990 NotifyClientFilterAnimated( | |
991 filter, animations_[i]->affects_active_elements(), | |
992 animations_[i]->affects_pending_elements()); | |
993 break; | |
994 } | |
995 | |
996 case TargetProperty::BACKGROUND_COLOR: { | |
997 // Not yet implemented. | |
998 break; | |
999 } | |
1000 | |
1001 case TargetProperty::SCROLL_OFFSET: { | |
1002 const ScrollOffsetAnimationCurve* scroll_offset_animation_curve = | |
1003 animations_[i]->curve()->ToScrollOffsetAnimationCurve(); | |
1004 const gfx::ScrollOffset scroll_offset = | |
1005 scroll_offset_animation_curve->GetValue(trimmed); | |
1006 NotifyClientScrollOffsetAnimated( | |
1007 scroll_offset, animations_[i]->affects_active_elements(), | |
1008 animations_[i]->affects_pending_elements()); | |
1009 break; | |
1010 } | |
1011 } | |
1012 } | |
1013 } | |
1014 } | |
1015 | |
1016 void ElementAnimations::UpdateActivation(UpdateActivationType type) { | |
1017 bool force = type == FORCE_ACTIVATION; | |
1018 if (animation_host_) { | 478 if (animation_host_) { |
1019 bool was_active = is_active_; | 479 bool was_active = is_active_; |
1020 is_active_ = false; | 480 is_active_ = false; |
1021 for (size_t i = 0; i < animations_.size(); ++i) { | 481 |
1022 if (animations_[i]->run_state() != Animation::WAITING_FOR_DELETION) { | 482 ElementAnimations::PlayersList::Iterator it(players_list_.get()); |
| 483 AnimationPlayer* player; |
| 484 while ((player = it.GetNext()) != nullptr) { |
| 485 if (player->HasNonDeletedAnimation()) { |
1023 is_active_ = true; | 486 is_active_ = true; |
1024 break; | 487 break; |
1025 } | 488 } |
1026 } | 489 } |
1027 | 490 |
1028 if (is_active_ && (!was_active || force)) { | 491 if (is_active_ && (!was_active || force)) { |
1029 animation_host_->DidActivateElementAnimations(this); | 492 animation_host_->DidActivateElementAnimations(this); |
1030 } else if (!is_active_ && (was_active || force)) { | 493 } else if (!is_active_ && (was_active || force)) { |
1031 // Resetting last_tick_time_ here ensures that calling ::UpdateState | 494 // Resetting last_tick_time_ here ensures that calling ::UpdateState |
1032 // before ::Animate doesn't start an animation. | 495 // before ::Animate doesn't start an animation. |
1033 last_tick_time_ = base::TimeTicks(); | 496 last_tick_time_ = base::TimeTicks(); |
1034 animation_host_->DidDeactivateElementAnimations(this); | 497 animation_host_->DidDeactivateElementAnimations(this); |
1035 } | 498 } |
1036 } | 499 } |
1037 } | 500 } |
1038 | 501 |
| 502 void ElementAnimations::UpdateActivationNormal() { |
| 503 UpdateActivation(ActivationType::NORMAL); |
| 504 } |
| 505 |
1039 void ElementAnimations::NotifyClientOpacityAnimated( | 506 void ElementAnimations::NotifyClientOpacityAnimated( |
1040 float opacity, | 507 float opacity, |
1041 bool notify_active_elements, | 508 bool notify_active_elements, |
1042 bool notify_pending_elements) { | 509 bool notify_pending_elements) { |
1043 if (notify_active_elements && has_element_in_active_list()) | 510 if (notify_active_elements && has_element_in_active_list()) |
1044 OnOpacityAnimated(ElementListType::ACTIVE, opacity); | 511 OnOpacityAnimated(ElementListType::ACTIVE, opacity); |
1045 if (notify_pending_elements && has_element_in_pending_list()) | 512 if (notify_pending_elements && has_element_in_pending_list()) |
1046 OnOpacityAnimated(ElementListType::PENDING, opacity); | 513 OnOpacityAnimated(ElementListType::PENDING, opacity); |
1047 } | 514 } |
1048 | 515 |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1119 potentially_animating); | 586 potentially_animating); |
1120 } else if (notify_elements_about_running_animation) { | 587 } else if (notify_elements_about_running_animation) { |
1121 bool currently_animating = | 588 bool currently_animating = |
1122 active ? animation_state->currently_running_for_active_elements | 589 active ? animation_state->currently_running_for_active_elements |
1123 : animation_state->currently_running_for_pending_elements; | 590 : animation_state->currently_running_for_pending_elements; |
1124 IsAnimatingChanged(list_type, property, AnimationChangeType::RUNNING, | 591 IsAnimatingChanged(list_type, property, AnimationChangeType::RUNNING, |
1125 currently_animating); | 592 currently_animating); |
1126 } | 593 } |
1127 } | 594 } |
1128 | 595 |
1129 void ElementAnimations::UpdateClientAnimationState( | 596 void ElementAnimations::UpdateClientAnimationStateInternal( |
1130 TargetProperty::Type property) { | 597 TargetProperty::Type property) { |
1131 struct PropertyAnimationState* animation_state = nullptr; | 598 struct PropertyAnimationState* animation_state = nullptr; |
1132 switch (property) { | 599 switch (property) { |
1133 case TargetProperty::OPACITY: | 600 case TargetProperty::OPACITY: |
1134 animation_state = &opacity_animation_state_; | 601 animation_state = &opacity_animation_state_; |
1135 break; | 602 break; |
1136 case TargetProperty::TRANSFORM: | 603 case TargetProperty::TRANSFORM: |
1137 animation_state = &transform_animation_state_; | 604 animation_state = &transform_animation_state_; |
1138 break; | 605 break; |
1139 case TargetProperty::FILTER: | 606 case TargetProperty::FILTER: |
(...skipping 11 matching lines...) Expand all Loading... |
1151 animation_state->potentially_animating_for_active_elements; | 618 animation_state->potentially_animating_for_active_elements; |
1152 bool was_potentially_animating_for_pending_elements = | 619 bool was_potentially_animating_for_pending_elements = |
1153 animation_state->potentially_animating_for_pending_elements; | 620 animation_state->potentially_animating_for_pending_elements; |
1154 | 621 |
1155 animation_state->Clear(); | 622 animation_state->Clear(); |
1156 DCHECK(was_potentially_animating_for_active_elements || | 623 DCHECK(was_potentially_animating_for_active_elements || |
1157 !was_currently_running_animation_for_active_elements); | 624 !was_currently_running_animation_for_active_elements); |
1158 DCHECK(was_potentially_animating_for_pending_elements || | 625 DCHECK(was_potentially_animating_for_pending_elements || |
1159 !was_currently_running_animation_for_pending_elements); | 626 !was_currently_running_animation_for_pending_elements); |
1160 | 627 |
1161 for (const auto& animation : animations_) { | 628 ElementAnimations::PlayersList::Iterator it(players_list_.get()); |
1162 if (!animation->is_finished() && animation->target_property() == property) { | 629 AnimationPlayer* player; |
1163 animation_state->potentially_animating_for_active_elements |= | 630 while ((player = it.GetNext()) != nullptr) { |
1164 animation->affects_active_elements(); | 631 for (const auto& animation : player->animations()) { |
1165 animation_state->potentially_animating_for_pending_elements |= | 632 if (!animation->is_finished() && |
1166 animation->affects_pending_elements(); | 633 animation->target_property() == property) { |
1167 animation_state->currently_running_for_active_elements = | 634 animation_state->potentially_animating_for_active_elements |= |
1168 animation_state->potentially_animating_for_active_elements && | 635 animation->affects_active_elements(); |
1169 animation->InEffect(last_tick_time_); | 636 animation_state->potentially_animating_for_pending_elements |= |
1170 animation_state->currently_running_for_pending_elements = | 637 animation->affects_pending_elements(); |
1171 animation_state->potentially_animating_for_pending_elements && | 638 animation_state->currently_running_for_active_elements = |
1172 animation->InEffect(last_tick_time_); | 639 animation_state->potentially_animating_for_active_elements && |
| 640 animation->InEffect(last_tick_time_); |
| 641 animation_state->currently_running_for_pending_elements = |
| 642 animation_state->potentially_animating_for_pending_elements && |
| 643 animation->InEffect(last_tick_time_); |
| 644 } |
1173 } | 645 } |
1174 } | 646 } |
1175 | 647 |
1176 bool potentially_animating_changed_for_active_elements = | 648 bool potentially_animating_changed_for_active_elements = |
1177 was_potentially_animating_for_active_elements != | 649 was_potentially_animating_for_active_elements != |
1178 animation_state->potentially_animating_for_active_elements; | 650 animation_state->potentially_animating_for_active_elements; |
1179 bool potentially_animating_changed_for_pending_elements = | 651 bool potentially_animating_changed_for_pending_elements = |
1180 was_potentially_animating_for_pending_elements != | 652 was_potentially_animating_for_pending_elements != |
1181 animation_state->potentially_animating_for_pending_elements; | 653 animation_state->potentially_animating_for_pending_elements; |
1182 bool currently_running_animation_changed_for_active_elements = | 654 bool currently_running_animation_changed_for_active_elements = |
(...skipping 13 matching lines...) Expand all Loading... |
1196 potentially_animating_changed_for_active_elements, | 668 potentially_animating_changed_for_active_elements, |
1197 currently_running_animation_changed_for_active_elements); | 669 currently_running_animation_changed_for_active_elements); |
1198 if (has_element_in_pending_list()) | 670 if (has_element_in_pending_list()) |
1199 NotifyClientAnimationChanged( | 671 NotifyClientAnimationChanged( |
1200 property, ElementListType::PENDING, | 672 property, ElementListType::PENDING, |
1201 potentially_animating_changed_for_pending_elements, | 673 potentially_animating_changed_for_pending_elements, |
1202 currently_running_animation_changed_for_pending_elements); | 674 currently_running_animation_changed_for_pending_elements); |
1203 } | 675 } |
1204 | 676 |
1205 bool ElementAnimations::HasActiveAnimation() const { | 677 bool ElementAnimations::HasActiveAnimation() const { |
1206 for (size_t i = 0; i < animations_.size(); ++i) { | 678 ElementAnimations::PlayersList::Iterator it(players_list_.get()); |
1207 if (!animations_[i]->is_finished()) | 679 AnimationPlayer* player; |
| 680 while ((player = it.GetNext()) != nullptr) { |
| 681 if (player->HasActiveAnimation()) |
1208 return true; | 682 return true; |
1209 } | 683 } |
| 684 |
1210 return false; | 685 return false; |
1211 } | 686 } |
1212 | 687 |
1213 bool ElementAnimations::HasAnyAnimation() const { | 688 bool ElementAnimations::HasAnyAnimation() const { |
1214 return !animations_.empty(); | 689 ElementAnimations::PlayersList::Iterator it(players_list_.get()); |
| 690 AnimationPlayer* player; |
| 691 while ((player = it.GetNext()) != nullptr) { |
| 692 if (player->has_any_animation()) |
| 693 return true; |
| 694 } |
| 695 |
| 696 return false; |
1215 } | 697 } |
1216 | 698 |
1217 bool ElementAnimations::IsPotentiallyAnimatingProperty( | 699 bool ElementAnimations::IsPotentiallyAnimatingProperty( |
1218 TargetProperty::Type target_property, | 700 TargetProperty::Type target_property, |
1219 ElementListType list_type) const { | 701 ElementListType list_type) const { |
1220 for (size_t i = 0; i < animations_.size(); ++i) { | 702 ElementAnimations::PlayersList::Iterator it(players_list_.get()); |
1221 if (!animations_[i]->is_finished() && | 703 AnimationPlayer* player; |
1222 animations_[i]->target_property() == target_property) { | 704 while ((player = it.GetNext()) != nullptr) { |
1223 if ((list_type == ElementListType::ACTIVE && | 705 if (player->IsPotentiallyAnimatingProperty(target_property, list_type)) |
1224 animations_[i]->affects_active_elements()) || | 706 return true; |
1225 (list_type == ElementListType::PENDING && | |
1226 animations_[i]->affects_pending_elements())) | |
1227 return true; | |
1228 } | |
1229 } | 707 } |
| 708 |
1230 return false; | 709 return false; |
1231 } | 710 } |
1232 | 711 |
1233 bool ElementAnimations::IsCurrentlyAnimatingProperty( | 712 bool ElementAnimations::IsCurrentlyAnimatingProperty( |
1234 TargetProperty::Type target_property, | 713 TargetProperty::Type target_property, |
1235 ElementListType list_type) const { | 714 ElementListType list_type) const { |
1236 for (size_t i = 0; i < animations_.size(); ++i) { | 715 ElementAnimations::PlayersList::Iterator it(players_list_.get()); |
1237 if (!animations_[i]->is_finished() && | 716 AnimationPlayer* player; |
1238 animations_[i]->InEffect(last_tick_time_) && | 717 while ((player = it.GetNext()) != nullptr) { |
1239 animations_[i]->target_property() == target_property) { | 718 if (player->IsCurrentlyAnimatingProperty(target_property, list_type)) |
1240 if ((list_type == ElementListType::ACTIVE && | 719 return true; |
1241 animations_[i]->affects_active_elements()) || | |
1242 (list_type == ElementListType::PENDING && | |
1243 animations_[i]->affects_pending_elements())) | |
1244 return true; | |
1245 } | |
1246 } | 720 } |
| 721 |
| 722 return false; |
| 723 } |
| 724 |
| 725 void ElementAnimations::SetScrollOffsetAnimationWasInterrupted() { |
| 726 scroll_offset_animation_was_interrupted_ = true; |
| 727 } |
| 728 |
| 729 bool ElementAnimations::needs_to_start_animations_for_testing() const { |
| 730 ElementAnimations::PlayersList::Iterator it(players_list_.get()); |
| 731 AnimationPlayer* player; |
| 732 while ((player = it.GetNext()) != nullptr) { |
| 733 if (player->needs_to_start_animations()) |
| 734 return true; |
| 735 } |
| 736 |
1247 return false; | 737 return false; |
1248 } | 738 } |
1249 | 739 |
1250 void ElementAnimations::PauseAnimation(int animation_id, | 740 void ElementAnimations::PauseAnimation(int animation_id, |
1251 base::TimeDelta time_offset) { | 741 base::TimeDelta time_offset) { |
1252 for (size_t i = 0; i < animations_.size(); ++i) { | 742 ElementAnimations::PlayersList::Iterator it(players_list_.get()); |
1253 if (animations_[i]->id() == animation_id) { | 743 AnimationPlayer* player; |
1254 animations_[i]->SetRunState(Animation::PAUSED, | 744 while ((player = it.GetNext()) != nullptr) |
1255 time_offset + animations_[i]->start_time() + | 745 player->PauseAnimation(animation_id, time_offset.InSecondsF()); |
1256 animations_[i]->time_offset()); | |
1257 } | |
1258 } | |
1259 SetNeedsPushProperties(); | |
1260 } | 746 } |
1261 | 747 |
1262 void ElementAnimations::RemoveAnimation(int animation_id) { | 748 void ElementAnimations::RemoveAnimation(int animation_id) { |
1263 bool removed_transform_animation = false; | 749 ElementAnimations::PlayersList::Iterator it(players_list_.get()); |
1264 bool removed_opacity_animation = false; | 750 AnimationPlayer* player; |
1265 bool removed_filter_animation = false; | 751 while ((player = it.GetNext()) != nullptr) |
1266 // Since we want to use the animations that we're going to remove, we need to | 752 player->RemoveAnimation(animation_id); |
1267 // use a stable_parition here instead of remove_if. Remove_if leaves the | |
1268 // removed items in an unspecified state. | |
1269 auto animations_to_remove = std::stable_partition( | |
1270 animations_.begin(), animations_.end(), | |
1271 [animation_id](const std::unique_ptr<Animation>& animation) { | |
1272 return animation->id() != animation_id; | |
1273 }); | |
1274 for (auto it = animations_to_remove; it != animations_.end(); ++it) { | |
1275 if ((*it)->target_property() == TargetProperty::SCROLL_OFFSET) { | |
1276 scroll_offset_animation_was_interrupted_ = true; | |
1277 } else if ((*it)->target_property() == TargetProperty::TRANSFORM && | |
1278 !(*it)->is_finished()) { | |
1279 removed_transform_animation = true; | |
1280 } else if ((*it)->target_property() == TargetProperty::OPACITY && | |
1281 !(*it)->is_finished()) { | |
1282 removed_opacity_animation = true; | |
1283 } else if ((*it)->target_property() == TargetProperty::FILTER && | |
1284 !(*it)->is_finished()) { | |
1285 removed_filter_animation = true; | |
1286 } | |
1287 } | |
1288 | |
1289 animations_.erase(animations_to_remove, animations_.end()); | |
1290 UpdateActivation(NORMAL_ACTIVATION); | |
1291 if (removed_transform_animation) | |
1292 UpdateClientAnimationState(TargetProperty::TRANSFORM); | |
1293 if (removed_opacity_animation) | |
1294 UpdateClientAnimationState(TargetProperty::OPACITY); | |
1295 if (removed_filter_animation) | |
1296 UpdateClientAnimationState(TargetProperty::FILTER); | |
1297 | |
1298 SetNeedsPushProperties(); | |
1299 } | 753 } |
1300 | 754 |
1301 void ElementAnimations::AbortAnimation(int animation_id) { | 755 void ElementAnimations::AbortAnimation(int animation_id) { |
1302 if (Animation* animation = GetAnimationById(animation_id)) { | 756 ElementAnimations::PlayersList::Iterator it(players_list_.get()); |
1303 if (!animation->is_finished()) { | 757 AnimationPlayer* player; |
1304 animation->SetRunState(Animation::ABORTED, last_tick_time_); | 758 while ((player = it.GetNext()) != nullptr) |
1305 switch (animation->target_property()) { | 759 player->AbortAnimation(animation_id); |
1306 case TargetProperty::TRANSFORM: | |
1307 case TargetProperty::OPACITY: | |
1308 case TargetProperty::FILTER: | |
1309 UpdateClientAnimationState(animation->target_property()); | |
1310 break; | |
1311 default: | |
1312 break; | |
1313 } | |
1314 } | |
1315 } | |
1316 | |
1317 SetNeedsPushProperties(); | |
1318 } | 760 } |
1319 | 761 |
1320 void ElementAnimations::AbortAnimations(TargetProperty::Type target_property, | 762 void ElementAnimations::AbortAnimations(TargetProperty::Type target_property, |
1321 bool needs_completion) { | 763 bool needs_completion) { |
1322 if (needs_completion) | 764 ElementAnimations::PlayersList::Iterator it(players_list_.get()); |
1323 DCHECK(target_property == TargetProperty::SCROLL_OFFSET); | 765 AnimationPlayer* player; |
1324 | 766 while ((player = it.GetNext()) != nullptr) |
1325 bool aborted_animation = false; | 767 player->AbortAnimations(target_property, needs_completion); |
1326 for (size_t i = 0; i < animations_.size(); ++i) { | |
1327 if (animations_[i]->target_property() == target_property && | |
1328 !animations_[i]->is_finished()) { | |
1329 // Currently only impl-only scroll offset animations can be completed on | |
1330 // the main thread. | |
1331 if (needs_completion && animations_[i]->is_impl_only()) { | |
1332 animations_[i]->SetRunState(Animation::ABORTED_BUT_NEEDS_COMPLETION, | |
1333 last_tick_time_); | |
1334 } else { | |
1335 animations_[i]->SetRunState(Animation::ABORTED, last_tick_time_); | |
1336 } | |
1337 aborted_animation = true; | |
1338 } | |
1339 } | |
1340 if (aborted_animation) { | |
1341 switch (target_property) { | |
1342 case TargetProperty::TRANSFORM: | |
1343 case TargetProperty::OPACITY: | |
1344 case TargetProperty::FILTER: | |
1345 UpdateClientAnimationState(target_property); | |
1346 break; | |
1347 default: | |
1348 break; | |
1349 } | |
1350 } | |
1351 | |
1352 SetNeedsPushProperties(); | |
1353 } | 768 } |
1354 | 769 |
1355 Animation* ElementAnimations::GetAnimation( | 770 Animation* ElementAnimations::GetAnimation( |
1356 TargetProperty::Type target_property) const { | 771 TargetProperty::Type target_property) const { |
1357 for (size_t i = 0; i < animations_.size(); ++i) { | 772 ElementAnimations::PlayersList::Iterator it(players_list_.get()); |
1358 size_t index = animations_.size() - i - 1; | 773 AnimationPlayer* player; |
1359 if (animations_[index]->target_property() == target_property) | 774 while ((player = it.GetNext()) != nullptr) { |
1360 return animations_[index].get(); | 775 if (Animation* animation = player->GetAnimation(target_property)) |
| 776 return animation; |
1361 } | 777 } |
1362 return nullptr; | 778 return nullptr; |
1363 } | 779 } |
1364 | 780 |
1365 Animation* ElementAnimations::GetAnimationById(int animation_id) const { | 781 Animation* ElementAnimations::GetAnimationById(int animation_id) const { |
1366 for (size_t i = 0; i < animations_.size(); ++i) | 782 ElementAnimations::PlayersList::Iterator it(players_list_.get()); |
1367 if (animations_[i]->id() == animation_id) | 783 AnimationPlayer* player; |
1368 return animations_[i].get(); | 784 while ((player = it.GetNext()) != nullptr) { |
| 785 if (Animation* animation = player->GetAnimationById(animation_id)) |
| 786 return animation; |
| 787 } |
1369 return nullptr; | 788 return nullptr; |
1370 } | 789 } |
1371 | 790 |
1372 void ElementAnimations::OnFilterAnimated(ElementListType list_type, | 791 void ElementAnimations::OnFilterAnimated(ElementListType list_type, |
1373 const FilterOperations& filters) { | 792 const FilterOperations& filters) { |
1374 DCHECK(element_id()); | 793 DCHECK(element_id()); |
1375 DCHECK(animation_host()); | 794 DCHECK(animation_host()); |
1376 DCHECK(animation_host()->mutator_host_client()); | 795 DCHECK(animation_host()->mutator_host_client()); |
1377 animation_host()->mutator_host_client()->SetElementFilterMutated( | 796 animation_host()->mutator_host_client()->SetElementFilterMutated( |
1378 element_id(), list_type, filters); | 797 element_id(), list_type, filters); |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1433 ->ElementFilterIsAnimatingChanged(element_id(), list_type, | 852 ->ElementFilterIsAnimatingChanged(element_id(), list_type, |
1434 change_type, is_animating); | 853 change_type, is_animating); |
1435 break; | 854 break; |
1436 default: | 855 default: |
1437 NOTREACHED(); | 856 NOTREACHED(); |
1438 break; | 857 break; |
1439 } | 858 } |
1440 } | 859 } |
1441 } | 860 } |
1442 | 861 |
1443 void ElementAnimations::NotifyPlayersAnimationStarted( | |
1444 base::TimeTicks monotonic_time, | |
1445 TargetProperty::Type target_property, | |
1446 int group) { | |
1447 ElementAnimations::PlayersList::Iterator it(players_list_.get()); | |
1448 AnimationPlayer* player; | |
1449 // TODO(crbug.com/634916): Shouldn't manually iterate through the list if | |
1450 // base::ObserverList has a callback mechanism. | |
1451 while ((player = it.GetNext()) != nullptr) | |
1452 player->NotifyAnimationStarted(monotonic_time, target_property, group); | |
1453 } | |
1454 | |
1455 void ElementAnimations::NotifyPlayersAnimationFinished( | |
1456 base::TimeTicks monotonic_time, | |
1457 TargetProperty::Type target_property, | |
1458 int group) { | |
1459 ElementAnimations::PlayersList::Iterator it(players_list_.get()); | |
1460 AnimationPlayer* player; | |
1461 while ((player = it.GetNext()) != nullptr) | |
1462 player->NotifyAnimationFinished(monotonic_time, target_property, group); | |
1463 } | |
1464 | |
1465 void ElementAnimations::NotifyPlayersAnimationAborted( | |
1466 base::TimeTicks monotonic_time, | |
1467 TargetProperty::Type target_property, | |
1468 int group) { | |
1469 ElementAnimations::PlayersList::Iterator it(players_list_.get()); | |
1470 AnimationPlayer* player; | |
1471 while ((player = it.GetNext()) != nullptr) | |
1472 player->NotifyAnimationAborted(monotonic_time, target_property, group); | |
1473 } | |
1474 | |
1475 void ElementAnimations::NotifyPlayersAnimationWaitingForDeletion() { | |
1476 ElementAnimations::PlayersList::Iterator it(players_list_.get()); | |
1477 AnimationPlayer* player; | |
1478 while ((player = it.GetNext()) != nullptr) | |
1479 player->NotifyAnimationWaitingForDeletion(); | |
1480 } | |
1481 | |
1482 void ElementAnimations::NotifyPlayersAnimationTakeover( | |
1483 base::TimeTicks monotonic_time, | |
1484 TargetProperty::Type target_property, | |
1485 double animation_start_time, | |
1486 std::unique_ptr<AnimationCurve> curve) { | |
1487 DCHECK(curve); | |
1488 ElementAnimations::PlayersList::Iterator it(players_list_.get()); | |
1489 AnimationPlayer* player; | |
1490 while ((player = it.GetNext()) != nullptr) { | |
1491 std::unique_ptr<AnimationCurve> animation_curve = curve->Clone(); | |
1492 player->NotifyAnimationTakeover(monotonic_time, target_property, | |
1493 animation_start_time, | |
1494 std::move(animation_curve)); | |
1495 } | |
1496 } | |
1497 | |
1498 gfx::ScrollOffset ElementAnimations::ScrollOffsetForAnimation() const { | 862 gfx::ScrollOffset ElementAnimations::ScrollOffsetForAnimation() const { |
1499 if (animation_host()) { | 863 if (animation_host()) { |
1500 DCHECK(animation_host()->mutator_host_client()); | 864 DCHECK(animation_host()->mutator_host_client()); |
1501 return animation_host()->mutator_host_client()->GetScrollOffsetForAnimation( | 865 return animation_host()->mutator_host_client()->GetScrollOffsetForAnimation( |
1502 element_id()); | 866 element_id()); |
1503 } | 867 } |
1504 | 868 |
1505 return gfx::ScrollOffset(); | 869 return gfx::ScrollOffset(); |
1506 } | 870 } |
1507 | 871 |
1508 } // namespace cc | 872 } // namespace cc |
OLD | NEW |