| 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 |