| Index: cc/animation/element_animations.cc
|
| diff --git a/cc/animation/element_animations.cc b/cc/animation/element_animations.cc
|
| index b1bd59e03a808fee891acdf2864d5f87255a83bb..35de36725d0732d55d31f11a50e2434867524243 100644
|
| --- a/cc/animation/element_animations.cc
|
| +++ b/cc/animation/element_animations.cc
|
| @@ -14,7 +14,6 @@
|
| #include "cc/animation/animation_host.h"
|
| #include "cc/animation/animation_player.h"
|
| #include "cc/animation/keyframed_animation_curve.h"
|
| -#include "cc/animation/scroll_offset_animation_curve.h"
|
| #include "cc/output/filter_operations.h"
|
| #include "cc/trees/mutator_host_client.h"
|
| #include "ui/gfx/geometry/box_f.h"
|
| @@ -32,9 +31,10 @@ ElementAnimations::ElementAnimations()
|
| is_active_(false),
|
| has_element_in_active_list_(false),
|
| has_element_in_pending_list_(false),
|
| - needs_to_start_animations_(false),
|
| scroll_offset_animation_was_interrupted_(false),
|
| - needs_push_properties_(false) {}
|
| + needs_push_properties_(false) {
|
| + ClearNeedsUpdateImplClientState();
|
| +}
|
|
|
| ElementAnimations::~ElementAnimations() {}
|
|
|
| @@ -50,7 +50,7 @@ void ElementAnimations::InitAffectedElementTypes() {
|
| DCHECK(element_id_);
|
| DCHECK(animation_host_);
|
|
|
| - UpdateActivation(FORCE_ACTIVATION);
|
| + UpdateActivation(ActivationType::FORCE);
|
|
|
| DCHECK(animation_host_->mutator_host_client());
|
| if (animation_host_->mutator_host_client()->IsElementInList(
|
| @@ -83,7 +83,7 @@ void ElementAnimations::ClearAffectedElementTypes() {
|
| set_has_element_in_pending_list(false);
|
|
|
| animation_host_->DidDeactivateElementAnimations(this);
|
| - UpdateActivation(FORCE_ACTIVATION);
|
| + UpdateActivation(ActivationType::FORCE);
|
| }
|
|
|
| void ElementAnimations::ElementRegistered(ElementId element_id,
|
| @@ -91,7 +91,7 @@ void ElementAnimations::ElementRegistered(ElementId element_id,
|
| DCHECK_EQ(element_id_, element_id);
|
|
|
| if (!has_element_in_any_list())
|
| - UpdateActivation(FORCE_ACTIVATION);
|
| + UpdateActivation(ActivationType::FORCE);
|
|
|
| if (list_type == ElementListType::ACTIVE)
|
| set_has_element_in_active_list(true);
|
| @@ -135,39 +135,56 @@ void ElementAnimations::PushPropertiesTo(
|
| return;
|
| needs_push_properties_ = false;
|
|
|
| - if (!HasAnyAnimation() && !element_animations_impl->HasAnyAnimation())
|
| - return;
|
| - MarkAbortedAnimationsForDeletion(element_animations_impl.get());
|
| - PurgeAnimationsMarkedForDeletion();
|
| - PushNewAnimationsToImplThread(element_animations_impl.get());
|
| -
|
| - // Remove finished impl side animations only after pushing,
|
| - // and only after the animations are deleted on the main thread
|
| - // this insures we will never push an animation twice.
|
| - RemoveAnimationsCompletedOnMainThread(element_animations_impl.get());
|
| -
|
| - PushPropertiesToImplThread(element_animations_impl.get());
|
| - element_animations_impl->UpdateActivation(NORMAL_ACTIVATION);
|
| - UpdateActivation(NORMAL_ACTIVATION);
|
| + element_animations_impl->scroll_offset_animation_was_interrupted_ =
|
| + scroll_offset_animation_was_interrupted_;
|
| + scroll_offset_animation_was_interrupted_ = false;
|
| +
|
| + // Update impl client state.
|
| + element_animations_impl->UpdateClientAnimationState(
|
| + needs_update_impl_client_state_transform_,
|
| + needs_update_impl_client_state_opacity_,
|
| + needs_update_impl_client_state_filter_);
|
| + ClearNeedsUpdateImplClientState();
|
| +
|
| + element_animations_impl->UpdateActivation(ActivationType::NORMAL);
|
| + UpdateActivation(ActivationType::NORMAL);
|
| }
|
|
|
| -void ElementAnimations::AddAnimation(std::unique_ptr<Animation> animation) {
|
| - DCHECK(!animation->is_impl_only() ||
|
| - animation->target_property() == TargetProperty::SCROLL_OFFSET);
|
| - TargetProperty::Type target_property = animation->target_property();
|
| - animations_.push_back(std::move(animation));
|
| - needs_to_start_animations_ = true;
|
| - UpdateActivation(NORMAL_ACTIVATION);
|
| +void ElementAnimations::UpdateClientAnimationState(
|
| + TargetProperty::Type target_property) {
|
| switch (target_property) {
|
| case TargetProperty::TRANSFORM:
|
| case TargetProperty::OPACITY:
|
| case TargetProperty::FILTER:
|
| - UpdateClientAnimationState(target_property);
|
| + UpdateClientAnimationStateInternal(target_property);
|
| break;
|
| default:
|
| + // Do not update for other properties.
|
| break;
|
| }
|
| - SetNeedsPushProperties();
|
| +}
|
| +
|
| +void ElementAnimations::UpdateClientAnimationState(bool transform,
|
| + bool opacity,
|
| + bool filter) {
|
| + if (transform)
|
| + UpdateClientAnimationStateInternal(TargetProperty::TRANSFORM);
|
| + if (opacity)
|
| + UpdateClientAnimationStateInternal(TargetProperty::OPACITY);
|
| + if (filter)
|
| + UpdateClientAnimationStateInternal(TargetProperty::FILTER);
|
| +}
|
| +
|
| +void ElementAnimations::AddAnimation(std::unique_ptr<Animation> animation) {
|
| + // TODO(loyso): Erase this. Rewrite element_animations_unittest to use
|
| + // AnimationPlayer::AddAnimation.
|
| +
|
| + // Add animation to the first player.
|
| + DCHECK(players_list_->might_have_observers());
|
| + ElementAnimations::PlayersList::Iterator it(players_list_.get());
|
| + AnimationPlayer* player = it.GetNext();
|
| + DCHECK(player);
|
| + player->AddAnimation(std::move(animation));
|
| }
|
|
|
| void ElementAnimations::Animate(base::TimeTicks monotonic_time) {
|
| @@ -175,13 +192,27 @@ void ElementAnimations::Animate(base::TimeTicks monotonic_time) {
|
| if (!has_element_in_active_list() && !has_element_in_pending_list())
|
| return;
|
|
|
| - if (needs_to_start_animations_)
|
| - StartAnimations(monotonic_time);
|
| - TickAnimations(monotonic_time);
|
| + {
|
| + // TODO(crbug.com/634916): Shouldn't manually iterate through the list if
|
| + // base::ObserverList has a callback mechanism.
|
| + ElementAnimations::PlayersList::Iterator it(players_list_.get());
|
| + AnimationPlayer* player;
|
| + while ((player = it.GetNext()) != nullptr) {
|
| + if (player->needs_to_start_animations())
|
| + player->StartAnimations(monotonic_time);
|
| + }
|
| + }
|
| + {
|
| + ElementAnimations::PlayersList::Iterator it(players_list_.get());
|
| + AnimationPlayer* player;
|
| + while ((player = it.GetNext()) != nullptr)
|
| + player->TickAnimations(monotonic_time);
|
| + }
|
| last_tick_time_ = monotonic_time;
|
| - UpdateClientAnimationState(TargetProperty::OPACITY);
|
| - UpdateClientAnimationState(TargetProperty::TRANSFORM);
|
| - UpdateClientAnimationState(TargetProperty::FILTER);
|
| +
|
| + UpdateClientAnimationStateInternal(TargetProperty::OPACITY);
|
| + UpdateClientAnimationStateInternal(TargetProperty::TRANSFORM);
|
| + UpdateClientAnimationStateInternal(TargetProperty::FILTER);
|
| }
|
|
|
| void ElementAnimations::UpdateState(bool start_ready_animations,
|
| @@ -194,130 +225,106 @@ void ElementAnimations::UpdateState(bool start_ready_animations,
|
| if (last_tick_time_ == base::TimeTicks())
|
| return;
|
|
|
| - if (start_ready_animations)
|
| - PromoteStartedAnimations(last_tick_time_, events);
|
| -
|
| - MarkFinishedAnimations(last_tick_time_);
|
| - MarkAnimationsForDeletion(last_tick_time_, events);
|
| -
|
| - if (needs_to_start_animations_ && start_ready_animations) {
|
| - StartAnimations(last_tick_time_);
|
| - PromoteStartedAnimations(last_tick_time_, events);
|
| + if (start_ready_animations) {
|
| + ElementAnimations::PlayersList::Iterator it(players_list_.get());
|
| + AnimationPlayer* player;
|
| + while ((player = it.GetNext()) != nullptr)
|
| + player->PromoteStartedAnimations(last_tick_time_, events);
|
| + }
|
| +
|
| + {
|
| + ElementAnimations::PlayersList::Iterator it(players_list_.get());
|
| + AnimationPlayer* player;
|
| + while ((player = it.GetNext()) != nullptr)
|
| + player->MarkFinishedAnimations(last_tick_time_);
|
| + }
|
| + {
|
| + ElementAnimations::PlayersList::Iterator it(players_list_.get());
|
| + AnimationPlayer* player;
|
| + while ((player = it.GetNext()) != nullptr)
|
| + player->MarkAnimationsForDeletion(last_tick_time_, events);
|
| + }
|
| +
|
| + if (start_ready_animations) {
|
| + ElementAnimations::PlayersList::Iterator it(players_list_.get());
|
| + AnimationPlayer* player;
|
| + while ((player = it.GetNext()) != nullptr) {
|
| + if (player->needs_to_start_animations()) {
|
| + player->StartAnimations(last_tick_time_);
|
| + player->PromoteStartedAnimations(last_tick_time_, events);
|
| + }
|
| + }
|
| }
|
|
|
| - UpdateActivation(NORMAL_ACTIVATION);
|
| + UpdateActivation(ActivationType::NORMAL);
|
| }
|
|
|
| void ElementAnimations::ActivateAnimations() {
|
| bool changed_transform_animation = false;
|
| bool changed_opacity_animation = false;
|
| bool changed_filter_animation = false;
|
| - for (size_t i = 0; i < animations_.size(); ++i) {
|
| - if (animations_[i]->affects_active_elements() !=
|
| - animations_[i]->affects_pending_elements()) {
|
| - if (animations_[i]->target_property() == TargetProperty::TRANSFORM)
|
| - changed_transform_animation = true;
|
| - else if (animations_[i]->target_property() == TargetProperty::OPACITY)
|
| - changed_opacity_animation = true;
|
| - else if (animations_[i]->target_property() == TargetProperty::FILTER)
|
| - changed_filter_animation = true;
|
| - }
|
| - animations_[i]->set_affects_active_elements(
|
| - animations_[i]->affects_pending_elements());
|
| +
|
| + ElementAnimations::PlayersList::Iterator it(players_list_.get());
|
| + AnimationPlayer* player;
|
| + while ((player = it.GetNext()) != nullptr) {
|
| + player->ActivateAnimations(&changed_transform_animation,
|
| + &changed_opacity_animation,
|
| + &changed_filter_animation);
|
| }
|
| - auto affects_no_elements = [](const std::unique_ptr<Animation>& animation) {
|
| - return !animation->affects_active_elements() &&
|
| - !animation->affects_pending_elements();
|
| - };
|
| - animations_.erase(std::remove_if(animations_.begin(), animations_.end(),
|
| - affects_no_elements),
|
| - animations_.end());
|
| +
|
| scroll_offset_animation_was_interrupted_ = false;
|
| - UpdateActivation(NORMAL_ACTIVATION);
|
| - if (changed_transform_animation)
|
| - UpdateClientAnimationState(TargetProperty::TRANSFORM);
|
| - if (changed_opacity_animation)
|
| - UpdateClientAnimationState(TargetProperty::OPACITY);
|
| - if (changed_filter_animation)
|
| - UpdateClientAnimationState(TargetProperty::FILTER);
|
| + UpdateActivation(ActivationType::NORMAL);
|
| + UpdateClientAnimationState(changed_transform_animation,
|
| + changed_opacity_animation,
|
| + changed_filter_animation);
|
| }
|
|
|
| void ElementAnimations::NotifyAnimationStarted(const AnimationEvent& event) {
|
| - if (event.is_impl_only) {
|
| - NotifyPlayersAnimationStarted(event.monotonic_time, event.target_property,
|
| - event.group_id);
|
| - return;
|
| - }
|
| -
|
| - for (size_t i = 0; i < animations_.size(); ++i) {
|
| - if (animations_[i]->group() == event.group_id &&
|
| - animations_[i]->target_property() == event.target_property &&
|
| - animations_[i]->needs_synchronized_start_time()) {
|
| - animations_[i]->set_needs_synchronized_start_time(false);
|
| - if (!animations_[i]->has_set_start_time())
|
| - animations_[i]->set_start_time(event.monotonic_time);
|
| -
|
| - NotifyPlayersAnimationStarted(event.monotonic_time, event.target_property,
|
| - event.group_id);
|
| -
|
| - return;
|
| - }
|
| + DCHECK(!event.is_impl_only);
|
| + ElementAnimations::PlayersList::Iterator it(players_list_.get());
|
| + AnimationPlayer* player;
|
| + while ((player = it.GetNext()) != nullptr) {
|
| + if (player->NotifyAnimationStarted(event))
|
| + break;
|
| }
|
| }
|
|
|
| void ElementAnimations::NotifyAnimationFinished(const AnimationEvent& event) {
|
| - if (event.is_impl_only) {
|
| - NotifyPlayersAnimationFinished(event.monotonic_time, event.target_property,
|
| - event.group_id);
|
| - return;
|
| - }
|
| -
|
| - for (size_t i = 0; i < animations_.size(); ++i) {
|
| - if (animations_[i]->group() == event.group_id &&
|
| - animations_[i]->target_property() == event.target_property) {
|
| - animations_[i]->set_received_finished_event(true);
|
| - NotifyPlayersAnimationFinished(event.monotonic_time,
|
| - event.target_property, event.group_id);
|
| -
|
| - return;
|
| - }
|
| + DCHECK(!event.is_impl_only);
|
| + ElementAnimations::PlayersList::Iterator it(players_list_.get());
|
| + AnimationPlayer* player;
|
| + while ((player = it.GetNext()) != nullptr) {
|
| + if (player->NotifyAnimationFinished(event))
|
| + break;
|
| }
|
| }
|
|
|
| void ElementAnimations::NotifyAnimationTakeover(const AnimationEvent& event) {
|
| + DCHECK(!event.is_impl_only);
|
| DCHECK(event.target_property == TargetProperty::SCROLL_OFFSET);
|
| - if (!IsEmpty()) {
|
| - std::unique_ptr<AnimationCurve> animation_curve = event.curve->Clone();
|
| - NotifyPlayersAnimationTakeover(event.monotonic_time, event.target_property,
|
| - event.animation_start_time,
|
| - std::move(animation_curve));
|
| - }
|
| +
|
| + ElementAnimations::PlayersList::Iterator it(players_list_.get());
|
| + AnimationPlayer* player;
|
| + while ((player = it.GetNext()) != nullptr)
|
| + player->NotifyAnimationTakeover(event);
|
| }
|
|
|
| void ElementAnimations::NotifyAnimationAborted(const AnimationEvent& event) {
|
| - for (size_t i = 0; i < animations_.size(); ++i) {
|
| - if (animations_[i]->group() == event.group_id &&
|
| - animations_[i]->target_property() == event.target_property) {
|
| - animations_[i]->SetRunState(Animation::ABORTED, event.monotonic_time);
|
| - animations_[i]->set_received_finished_event(true);
|
| - NotifyPlayersAnimationAborted(event.monotonic_time, event.target_property,
|
| - event.group_id);
|
| - break;
|
| - }
|
| - }
|
| - switch (event.target_property) {
|
| - case TargetProperty::TRANSFORM:
|
| - case TargetProperty::OPACITY:
|
| - case TargetProperty::FILTER:
|
| - UpdateClientAnimationState(event.target_property);
|
| - break;
|
| - default:
|
| + DCHECK(!event.is_impl_only);
|
| +
|
| + ElementAnimations::PlayersList::Iterator it(players_list_.get());
|
| + AnimationPlayer* player;
|
| + while ((player = it.GetNext()) != nullptr) {
|
| + if (player->NotifyAnimationAborted(event))
|
| break;
|
| }
|
| +
|
| + UpdateClientAnimationState(event.target_property);
|
| }
|
|
|
| void ElementAnimations::NotifyAnimationPropertyUpdate(
|
| const AnimationEvent& event) {
|
| + DCHECK(!event.is_impl_only);
|
| bool notify_active_elements = true;
|
| bool notify_pending_elements = true;
|
| switch (event.target_property) {
|
| @@ -335,24 +342,23 @@ void ElementAnimations::NotifyAnimationPropertyUpdate(
|
| }
|
|
|
| bool ElementAnimations::HasFilterAnimationThatInflatesBounds() const {
|
| - for (size_t i = 0; i < animations_.size(); ++i) {
|
| - if (!animations_[i]->is_finished() &&
|
| - animations_[i]->target_property() == TargetProperty::FILTER &&
|
| - animations_[i]
|
| - ->curve()
|
| - ->ToFilterAnimationCurve()
|
| - ->HasFilterThatMovesPixels())
|
| + ElementAnimations::PlayersList::Iterator it(players_list_.get());
|
| + AnimationPlayer* player;
|
| + while ((player = it.GetNext()) != nullptr) {
|
| + if (player->HasFilterAnimationThatInflatesBounds())
|
| return true;
|
| }
|
| -
|
| return false;
|
| }
|
|
|
| bool ElementAnimations::HasTransformAnimationThatInflatesBounds() const {
|
| - return IsCurrentlyAnimatingProperty(TargetProperty::TRANSFORM,
|
| - ElementListType::ACTIVE) ||
|
| - IsCurrentlyAnimatingProperty(TargetProperty::TRANSFORM,
|
| - ElementListType::PENDING);
|
| + ElementAnimations::PlayersList::Iterator it(players_list_.get());
|
| + AnimationPlayer* player;
|
| + while ((player = it.GetNext()) != nullptr) {
|
| + if (player->HasTransformAnimationThatInflatesBounds())
|
| + return true;
|
| + }
|
| + return false;
|
| }
|
|
|
| bool ElementAnimations::FilterAnimationBoundsForBox(const gfx::BoxF& box,
|
| @@ -364,662 +370,119 @@ bool ElementAnimations::FilterAnimationBoundsForBox(const gfx::BoxF& box,
|
| bool ElementAnimations::TransformAnimationBoundsForBox(
|
| const gfx::BoxF& box,
|
| gfx::BoxF* bounds) const {
|
| - DCHECK(HasTransformAnimationThatInflatesBounds())
|
| - << "TransformAnimationBoundsForBox will give incorrect results if there "
|
| - << "are no transform animations affecting bounds, non-animated transform "
|
| - << "is not known";
|
| -
|
| - // Compute bounds based on animations for which is_finished() is false.
|
| - // Do nothing if there are no such animations; in this case, it is assumed
|
| - // that callers will take care of computing bounds based on the owning layer's
|
| - // actual transform.
|
| *bounds = gfx::BoxF();
|
| - for (size_t i = 0; i < animations_.size(); ++i) {
|
| - if (animations_[i]->is_finished() ||
|
| - animations_[i]->target_property() != TargetProperty::TRANSFORM)
|
| - continue;
|
| -
|
| - const TransformAnimationCurve* transform_animation_curve =
|
| - animations_[i]->curve()->ToTransformAnimationCurve();
|
| - gfx::BoxF animation_bounds;
|
| - bool success =
|
| - transform_animation_curve->AnimatedBoundsForBox(box, &animation_bounds);
|
| +
|
| + ElementAnimations::PlayersList::Iterator it(players_list_.get());
|
| + AnimationPlayer* player;
|
| + while ((player = it.GetNext()) != nullptr) {
|
| + gfx::BoxF player_bounds;
|
| + bool success = player->TransformAnimationBoundsForBox(box, &player_bounds);
|
| if (!success)
|
| return false;
|
| - bounds->Union(animation_bounds);
|
| + bounds->Union(player_bounds);
|
| }
|
| -
|
| return true;
|
| }
|
|
|
| bool ElementAnimations::HasAnimationThatAffectsScale() const {
|
| - for (size_t i = 0; i < animations_.size(); ++i) {
|
| - if (animations_[i]->is_finished() ||
|
| - animations_[i]->target_property() != TargetProperty::TRANSFORM)
|
| - continue;
|
| -
|
| - const TransformAnimationCurve* transform_animation_curve =
|
| - animations_[i]->curve()->ToTransformAnimationCurve();
|
| - if (transform_animation_curve->AffectsScale())
|
| + ElementAnimations::PlayersList::Iterator it(players_list_.get());
|
| + AnimationPlayer* player;
|
| + while ((player = it.GetNext()) != nullptr) {
|
| + if (player->HasAnimationThatAffectsScale())
|
| return true;
|
| }
|
| -
|
| return false;
|
| }
|
|
|
| bool ElementAnimations::HasOnlyTranslationTransforms(
|
| ElementListType list_type) const {
|
| - for (size_t i = 0; i < animations_.size(); ++i) {
|
| - if (animations_[i]->is_finished() ||
|
| - animations_[i]->target_property() != TargetProperty::TRANSFORM)
|
| - continue;
|
| -
|
| - if ((list_type == ElementListType::ACTIVE &&
|
| - !animations_[i]->affects_active_elements()) ||
|
| - (list_type == ElementListType::PENDING &&
|
| - !animations_[i]->affects_pending_elements()))
|
| - continue;
|
| -
|
| - const TransformAnimationCurve* transform_animation_curve =
|
| - animations_[i]->curve()->ToTransformAnimationCurve();
|
| - if (!transform_animation_curve->IsTranslation())
|
| + ElementAnimations::PlayersList::Iterator it(players_list_.get());
|
| + AnimationPlayer* player;
|
| + while ((player = it.GetNext()) != nullptr) {
|
| + if (!player->HasOnlyTranslationTransforms(list_type))
|
| return false;
|
| }
|
| -
|
| return true;
|
| }
|
|
|
| bool ElementAnimations::AnimationsPreserveAxisAlignment() const {
|
| - for (size_t i = 0; i < animations_.size(); ++i) {
|
| - if (animations_[i]->is_finished() ||
|
| - animations_[i]->target_property() != TargetProperty::TRANSFORM)
|
| - continue;
|
| -
|
| - const TransformAnimationCurve* transform_animation_curve =
|
| - animations_[i]->curve()->ToTransformAnimationCurve();
|
| - if (!transform_animation_curve->PreservesAxisAlignment())
|
| + ElementAnimations::PlayersList::Iterator it(players_list_.get());
|
| + AnimationPlayer* player;
|
| + while ((player = it.GetNext()) != nullptr) {
|
| + if (!player->AnimationsPreserveAxisAlignment())
|
| return false;
|
| }
|
| -
|
| return true;
|
| }
|
|
|
| bool ElementAnimations::AnimationStartScale(ElementListType list_type,
|
| float* start_scale) const {
|
| *start_scale = 0.f;
|
| - for (size_t i = 0; i < animations_.size(); ++i) {
|
| - if (animations_[i]->is_finished() ||
|
| - animations_[i]->target_property() != TargetProperty::TRANSFORM)
|
| - continue;
|
| -
|
| - if ((list_type == ElementListType::ACTIVE &&
|
| - !animations_[i]->affects_active_elements()) ||
|
| - (list_type == ElementListType::PENDING &&
|
| - !animations_[i]->affects_pending_elements()))
|
| - continue;
|
| -
|
| - bool forward_direction = true;
|
| - switch (animations_[i]->direction()) {
|
| - case Animation::Direction::NORMAL:
|
| - case Animation::Direction::ALTERNATE_NORMAL:
|
| - forward_direction = animations_[i]->playback_rate() >= 0.0;
|
| - break;
|
| - case Animation::Direction::REVERSE:
|
| - case Animation::Direction::ALTERNATE_REVERSE:
|
| - forward_direction = animations_[i]->playback_rate() < 0.0;
|
| - break;
|
| - }
|
|
|
| - const TransformAnimationCurve* transform_animation_curve =
|
| - animations_[i]->curve()->ToTransformAnimationCurve();
|
| - float animation_start_scale = 0.f;
|
| - if (!transform_animation_curve->AnimationStartScale(forward_direction,
|
| - &animation_start_scale))
|
| + ElementAnimations::PlayersList::Iterator it(players_list_.get());
|
| + AnimationPlayer* player;
|
| + while ((player = it.GetNext()) != nullptr) {
|
| + float player_start_scale = 0.f;
|
| + bool success = player->AnimationStartScale(list_type, &player_start_scale);
|
| + if (!success)
|
| return false;
|
| - *start_scale = std::max(*start_scale, animation_start_scale);
|
| + // Union: a maximum.
|
| + *start_scale = std::max(*start_scale, player_start_scale);
|
| }
|
| +
|
| return true;
|
| }
|
|
|
| bool ElementAnimations::MaximumTargetScale(ElementListType list_type,
|
| float* max_scale) const {
|
| *max_scale = 0.f;
|
| - for (size_t i = 0; i < animations_.size(); ++i) {
|
| - if (animations_[i]->is_finished() ||
|
| - animations_[i]->target_property() != TargetProperty::TRANSFORM)
|
| - continue;
|
| -
|
| - if ((list_type == ElementListType::ACTIVE &&
|
| - !animations_[i]->affects_active_elements()) ||
|
| - (list_type == ElementListType::PENDING &&
|
| - !animations_[i]->affects_pending_elements()))
|
| - continue;
|
| -
|
| - bool forward_direction = true;
|
| - switch (animations_[i]->direction()) {
|
| - case Animation::Direction::NORMAL:
|
| - case Animation::Direction::ALTERNATE_NORMAL:
|
| - forward_direction = animations_[i]->playback_rate() >= 0.0;
|
| - break;
|
| - case Animation::Direction::REVERSE:
|
| - case Animation::Direction::ALTERNATE_REVERSE:
|
| - forward_direction = animations_[i]->playback_rate() < 0.0;
|
| - break;
|
| - }
|
|
|
| - const TransformAnimationCurve* transform_animation_curve =
|
| - animations_[i]->curve()->ToTransformAnimationCurve();
|
| - float animation_scale = 0.f;
|
| - if (!transform_animation_curve->MaximumTargetScale(forward_direction,
|
| - &animation_scale))
|
| + ElementAnimations::PlayersList::Iterator it(players_list_.get());
|
| + AnimationPlayer* player;
|
| + while ((player = it.GetNext()) != nullptr) {
|
| + float player_max_scale = 0.f;
|
| + bool success = player->MaximumTargetScale(list_type, &player_max_scale);
|
| + if (!success)
|
| return false;
|
| - *max_scale = std::max(*max_scale, animation_scale);
|
| + // Union: a maximum.
|
| + *max_scale = std::max(*max_scale, player_max_scale);
|
| }
|
|
|
| return true;
|
| }
|
|
|
| -void ElementAnimations::PushNewAnimationsToImplThread(
|
| - ElementAnimations* element_animations_impl) const {
|
| - // Any new animations owned by the main thread's ElementAnimations are cloned
|
| - // and added to the impl thread's ElementAnimations.
|
| - for (size_t i = 0; i < animations_.size(); ++i) {
|
| - // If the animation is already running on the impl thread, there is no
|
| - // need to copy it over.
|
| - if (element_animations_impl->GetAnimationById(animations_[i]->id()))
|
| - continue;
|
| -
|
| - if (animations_[i]->target_property() == TargetProperty::SCROLL_OFFSET &&
|
| - !animations_[i]
|
| - ->curve()
|
| - ->ToScrollOffsetAnimationCurve()
|
| - ->HasSetInitialValue()) {
|
| - gfx::ScrollOffset current_scroll_offset;
|
| - if (element_animations_impl->has_element_in_active_list()) {
|
| - current_scroll_offset =
|
| - element_animations_impl->ScrollOffsetForAnimation();
|
| - } else {
|
| - // The owning layer isn't yet in the active tree, so the main thread
|
| - // scroll offset will be up to date.
|
| - current_scroll_offset = ScrollOffsetForAnimation();
|
| - }
|
| - animations_[i]->curve()->ToScrollOffsetAnimationCurve()->SetInitialValue(
|
| - current_scroll_offset);
|
| - }
|
| -
|
| - // The new animation should be set to run as soon as possible.
|
| - Animation::RunState initial_run_state =
|
| - Animation::WAITING_FOR_TARGET_AVAILABILITY;
|
| - std::unique_ptr<Animation> to_add(
|
| - animations_[i]->CloneAndInitialize(initial_run_state));
|
| - DCHECK(!to_add->needs_synchronized_start_time());
|
| - to_add->set_affects_active_elements(false);
|
| - element_animations_impl->AddAnimation(std::move(to_add));
|
| - }
|
| -}
|
| -
|
| -static bool IsCompleted(
|
| - Animation* animation,
|
| - const ElementAnimations* main_thread_element_animations) {
|
| - if (animation->is_impl_only()) {
|
| - return (animation->run_state() == Animation::WAITING_FOR_DELETION);
|
| - } else {
|
| - return !main_thread_element_animations->GetAnimationById(animation->id());
|
| - }
|
| -}
|
| -
|
| -void ElementAnimations::RemoveAnimationsCompletedOnMainThread(
|
| - ElementAnimations* element_animations_impl) const {
|
| - bool removed_transform_animation = false;
|
| - bool removed_opacity_animation = false;
|
| - bool removed_filter_animation = false;
|
| - // Animations removed on the main thread should no longer affect pending
|
| - // elements, and should stop affecting active elements after the next call
|
| - // to ActivateAnimations. If already WAITING_FOR_DELETION, they can be removed
|
| - // immediately.
|
| - auto& animations = element_animations_impl->animations_;
|
| - for (const auto& animation : animations) {
|
| - if (IsCompleted(animation.get(), this)) {
|
| - animation->set_affects_pending_elements(false);
|
| - if (animation->target_property() == TargetProperty::TRANSFORM)
|
| - removed_transform_animation = true;
|
| - else if (animation->target_property() == TargetProperty::OPACITY)
|
| - removed_opacity_animation = true;
|
| - else if (animation->target_property() == TargetProperty::FILTER)
|
| - removed_filter_animation = true;
|
| - }
|
| - }
|
| - auto affects_active_only_and_is_waiting_for_deletion =
|
| - [](const std::unique_ptr<Animation>& animation) {
|
| - return animation->run_state() == Animation::WAITING_FOR_DELETION &&
|
| - !animation->affects_pending_elements();
|
| - };
|
| - animations.erase(
|
| - std::remove_if(animations.begin(), animations.end(),
|
| - affects_active_only_and_is_waiting_for_deletion),
|
| - animations.end());
|
| -
|
| - if (removed_transform_animation) {
|
| - element_animations_impl->UpdateClientAnimationState(
|
| - TargetProperty::TRANSFORM);
|
| - }
|
| - if (removed_opacity_animation) {
|
| - element_animations_impl->UpdateClientAnimationState(
|
| - TargetProperty::OPACITY);
|
| - }
|
| - if (removed_filter_animation) {
|
| - element_animations_impl->UpdateClientAnimationState(TargetProperty::FILTER);
|
| - }
|
| -}
|
| -
|
| -void ElementAnimations::PushPropertiesToImplThread(
|
| - ElementAnimations* element_animations_impl) {
|
| - for (size_t i = 0; i < animations_.size(); ++i) {
|
| - Animation* current_impl =
|
| - element_animations_impl->GetAnimationById(animations_[i]->id());
|
| - if (current_impl)
|
| - animations_[i]->PushPropertiesTo(current_impl);
|
| - }
|
| - element_animations_impl->scroll_offset_animation_was_interrupted_ =
|
| - scroll_offset_animation_was_interrupted_;
|
| - scroll_offset_animation_was_interrupted_ = false;
|
| -}
|
| -
|
| -void ElementAnimations::StartAnimations(base::TimeTicks monotonic_time) {
|
| - DCHECK(needs_to_start_animations_);
|
| - needs_to_start_animations_ = false;
|
| - // First collect running properties affecting each type of element.
|
| - TargetProperties blocked_properties_for_active_elements;
|
| - TargetProperties blocked_properties_for_pending_elements;
|
| - std::vector<size_t> animations_waiting_for_target;
|
| -
|
| - animations_waiting_for_target.reserve(animations_.size());
|
| - for (size_t i = 0; i < animations_.size(); ++i) {
|
| - if (animations_[i]->run_state() == Animation::STARTING ||
|
| - animations_[i]->run_state() == Animation::RUNNING) {
|
| - if (animations_[i]->affects_active_elements()) {
|
| - blocked_properties_for_active_elements[animations_[i]
|
| - ->target_property()] = true;
|
| - }
|
| - if (animations_[i]->affects_pending_elements()) {
|
| - blocked_properties_for_pending_elements[animations_[i]
|
| - ->target_property()] = true;
|
| - }
|
| - } else if (animations_[i]->run_state() ==
|
| - Animation::WAITING_FOR_TARGET_AVAILABILITY) {
|
| - animations_waiting_for_target.push_back(i);
|
| - }
|
| - }
|
| -
|
| - for (size_t i = 0; i < animations_waiting_for_target.size(); ++i) {
|
| - // Collect all properties for animations with the same group id (they
|
| - // should all also be in the list of animations).
|
| - size_t animation_index = animations_waiting_for_target[i];
|
| - Animation* animation_waiting_for_target =
|
| - animations_[animation_index].get();
|
| - // Check for the run state again even though the animation was waiting
|
| - // for target because it might have changed the run state while handling
|
| - // previous animation in this loop (if they belong to same group).
|
| - if (animation_waiting_for_target->run_state() ==
|
| - Animation::WAITING_FOR_TARGET_AVAILABILITY) {
|
| - TargetProperties enqueued_properties;
|
| - bool affects_active_elements =
|
| - animation_waiting_for_target->affects_active_elements();
|
| - bool affects_pending_elements =
|
| - animation_waiting_for_target->affects_pending_elements();
|
| - enqueued_properties[animation_waiting_for_target->target_property()] =
|
| - true;
|
| - for (size_t j = animation_index + 1; j < animations_.size(); ++j) {
|
| - if (animation_waiting_for_target->group() == animations_[j]->group()) {
|
| - enqueued_properties[animations_[j]->target_property()] = true;
|
| - affects_active_elements |= animations_[j]->affects_active_elements();
|
| - affects_pending_elements |=
|
| - animations_[j]->affects_pending_elements();
|
| - }
|
| - }
|
| -
|
| - // Check to see if intersection of the list of properties affected by
|
| - // the group and the list of currently blocked properties is null, taking
|
| - // into account the type(s) of elements affected by the group. In any
|
| - // case, the group's target properties need to be added to the lists of
|
| - // blocked properties.
|
| - bool null_intersection = true;
|
| - static_assert(TargetProperty::FIRST_TARGET_PROPERTY == 0,
|
| - "TargetProperty must be 0-based enum");
|
| - for (int property = TargetProperty::FIRST_TARGET_PROPERTY;
|
| - property <= TargetProperty::LAST_TARGET_PROPERTY; ++property) {
|
| - if (enqueued_properties[property]) {
|
| - if (affects_active_elements) {
|
| - if (blocked_properties_for_active_elements[property])
|
| - null_intersection = false;
|
| - else
|
| - blocked_properties_for_active_elements[property] = true;
|
| - }
|
| - if (affects_pending_elements) {
|
| - if (blocked_properties_for_pending_elements[property])
|
| - null_intersection = false;
|
| - else
|
| - blocked_properties_for_pending_elements[property] = true;
|
| - }
|
| - }
|
| - }
|
| -
|
| - // If the intersection is null, then we are free to start the animations
|
| - // in the group.
|
| - if (null_intersection) {
|
| - animation_waiting_for_target->SetRunState(Animation::STARTING,
|
| - monotonic_time);
|
| - for (size_t j = animation_index + 1; j < animations_.size(); ++j) {
|
| - if (animation_waiting_for_target->group() ==
|
| - animations_[j]->group()) {
|
| - animations_[j]->SetRunState(Animation::STARTING, monotonic_time);
|
| - }
|
| - }
|
| - } else {
|
| - needs_to_start_animations_ = true;
|
| - }
|
| - }
|
| - }
|
| -}
|
| -
|
| -void ElementAnimations::PromoteStartedAnimations(base::TimeTicks monotonic_time,
|
| - AnimationEvents* events) {
|
| - for (size_t i = 0; i < animations_.size(); ++i) {
|
| - if (animations_[i]->run_state() == Animation::STARTING &&
|
| - animations_[i]->affects_active_elements()) {
|
| - animations_[i]->SetRunState(Animation::RUNNING, monotonic_time);
|
| - if (!animations_[i]->has_set_start_time() &&
|
| - !animations_[i]->needs_synchronized_start_time())
|
| - animations_[i]->set_start_time(monotonic_time);
|
| - if (events) {
|
| - base::TimeTicks start_time;
|
| - if (animations_[i]->has_set_start_time())
|
| - start_time = animations_[i]->start_time();
|
| - else
|
| - start_time = monotonic_time;
|
| - AnimationEvent started_event(
|
| - AnimationEvent::STARTED, element_id_, animations_[i]->group(),
|
| - animations_[i]->target_property(), start_time);
|
| - started_event.is_impl_only = animations_[i]->is_impl_only();
|
| - if (started_event.is_impl_only)
|
| - NotifyAnimationStarted(started_event);
|
| - else
|
| - events->events_.push_back(started_event);
|
| - }
|
| - }
|
| - }
|
| -}
|
| +void ElementAnimations::SetNeedsUpdateImplClientState(bool transform,
|
| + bool opacity,
|
| + bool filter) {
|
| + if (transform)
|
| + needs_update_impl_client_state_transform_ = true;
|
| + if (opacity)
|
| + needs_update_impl_client_state_opacity_ = true;
|
| + if (filter)
|
| + needs_update_impl_client_state_filter_ = true;
|
|
|
| -void ElementAnimations::MarkFinishedAnimations(base::TimeTicks monotonic_time) {
|
| - bool finished_transform_animation = false;
|
| - bool finished_opacity_animation = false;
|
| - bool finished_filter_animation = false;
|
| - for (size_t i = 0; i < animations_.size(); ++i) {
|
| - if (!animations_[i]->is_finished() &&
|
| - animations_[i]->IsFinishedAt(monotonic_time)) {
|
| - animations_[i]->SetRunState(Animation::FINISHED, monotonic_time);
|
| - if (animations_[i]->target_property() == TargetProperty::TRANSFORM)
|
| - finished_transform_animation = true;
|
| - else if (animations_[i]->target_property() == TargetProperty::OPACITY)
|
| - finished_opacity_animation = true;
|
| - else if (animations_[i]->target_property() == TargetProperty::FILTER)
|
| - finished_filter_animation = true;
|
| - }
|
| - }
|
| - if (finished_transform_animation)
|
| - UpdateClientAnimationState(TargetProperty::TRANSFORM);
|
| - if (finished_opacity_animation)
|
| - UpdateClientAnimationState(TargetProperty::OPACITY);
|
| - if (finished_filter_animation)
|
| - UpdateClientAnimationState(TargetProperty::FILTER);
|
| + if (needs_update_impl_client_state_transform_ ||
|
| + needs_update_impl_client_state_opacity_ ||
|
| + needs_update_impl_client_state_filter_)
|
| + SetNeedsPushProperties();
|
| }
|
|
|
| -void ElementAnimations::MarkAnimationsForDeletion(
|
| - base::TimeTicks monotonic_time,
|
| - AnimationEvents* events) {
|
| - bool marked_animations_for_deletions = false;
|
| - std::vector<size_t> animations_with_same_group_id;
|
| -
|
| - animations_with_same_group_id.reserve(animations_.size());
|
| - // Non-aborted animations are marked for deletion after a corresponding
|
| - // AnimationEvent::FINISHED event is sent or received. This means that if
|
| - // we don't have an events vector, we must ensure that non-aborted animations
|
| - // have received a finished event before marking them for deletion.
|
| - for (size_t i = 0; i < animations_.size(); i++) {
|
| - int group_id = animations_[i]->group();
|
| - if (animations_[i]->run_state() == Animation::ABORTED) {
|
| - if (events && !animations_[i]->is_impl_only()) {
|
| - AnimationEvent aborted_event(
|
| - AnimationEvent::ABORTED, element_id_, group_id,
|
| - animations_[i]->target_property(), monotonic_time);
|
| - events->events_.push_back(aborted_event);
|
| - }
|
| - // If on the compositor or on the main thread and received finish event,
|
| - // animation can be marked for deletion.
|
| - if (events || animations_[i]->received_finished_event()) {
|
| - animations_[i]->SetRunState(Animation::WAITING_FOR_DELETION,
|
| - monotonic_time);
|
| - marked_animations_for_deletions = true;
|
| - }
|
| - continue;
|
| - }
|
| -
|
| - // If running on the compositor and need to complete an aborted animation
|
| - // on the main thread.
|
| - if (events &&
|
| - animations_[i]->run_state() ==
|
| - Animation::ABORTED_BUT_NEEDS_COMPLETION) {
|
| - AnimationEvent aborted_event(AnimationEvent::TAKEOVER, element_id_,
|
| - group_id, animations_[i]->target_property(),
|
| - monotonic_time);
|
| - aborted_event.animation_start_time =
|
| - (animations_[i]->start_time() - base::TimeTicks()).InSecondsF();
|
| - const ScrollOffsetAnimationCurve* scroll_offset_animation_curve =
|
| - animations_[i]->curve()->ToScrollOffsetAnimationCurve();
|
| - aborted_event.curve = scroll_offset_animation_curve->Clone();
|
| - // Notify the compositor that the animation is finished.
|
| - NotifyPlayersAnimationFinished(aborted_event.monotonic_time,
|
| - aborted_event.target_property,
|
| - aborted_event.group_id);
|
| - // Notify main thread.
|
| - events->events_.push_back(aborted_event);
|
| -
|
| - // Remove the animation from the compositor.
|
| - animations_[i]->SetRunState(Animation::WAITING_FOR_DELETION,
|
| - monotonic_time);
|
| - marked_animations_for_deletions = true;
|
| - continue;
|
| - }
|
| -
|
| - bool all_anims_with_same_id_are_finished = false;
|
| -
|
| - // Since deleting an animation on the main thread leads to its deletion
|
| - // on the impl thread, we only mark a FINISHED main thread animation for
|
| - // deletion once it has received a FINISHED event from the impl thread.
|
| - bool animation_i_will_send_or_has_received_finish_event =
|
| - animations_[i]->is_controlling_instance() ||
|
| - animations_[i]->is_impl_only() ||
|
| - animations_[i]->received_finished_event();
|
| - // If an animation is finished, and not already marked for deletion,
|
| - // find out if all other animations in the same group are also finished.
|
| - if (animations_[i]->run_state() == Animation::FINISHED &&
|
| - animation_i_will_send_or_has_received_finish_event) {
|
| - // Clear the animations_with_same_group_id if it was added for
|
| - // the previous animation's iteration.
|
| - if (animations_with_same_group_id.size() > 0)
|
| - animations_with_same_group_id.clear();
|
| - all_anims_with_same_id_are_finished = true;
|
| - for (size_t j = 0; j < animations_.size(); ++j) {
|
| - bool animation_j_will_send_or_has_received_finish_event =
|
| - animations_[j]->is_controlling_instance() ||
|
| - animations_[j]->is_impl_only() ||
|
| - animations_[j]->received_finished_event();
|
| - if (group_id == animations_[j]->group()) {
|
| - if (!animations_[j]->is_finished() ||
|
| - (animations_[j]->run_state() == Animation::FINISHED &&
|
| - !animation_j_will_send_or_has_received_finish_event)) {
|
| - all_anims_with_same_id_are_finished = false;
|
| - break;
|
| - } else if (j >= i &&
|
| - animations_[j]->run_state() != Animation::ABORTED) {
|
| - // Mark down the animations which belong to the same group
|
| - // and is not yet aborted. If this current iteration finds that all
|
| - // animations with same ID are finished, then the marked
|
| - // animations below will be set to WAITING_FOR_DELETION in next
|
| - // iteration.
|
| - animations_with_same_group_id.push_back(j);
|
| - }
|
| - }
|
| - }
|
| - }
|
| - if (all_anims_with_same_id_are_finished) {
|
| - // We now need to remove all animations with the same group id as
|
| - // group_id (and send along animation finished notifications, if
|
| - // necessary).
|
| - for (size_t j = 0; j < animations_with_same_group_id.size(); j++) {
|
| - size_t animation_index = animations_with_same_group_id[j];
|
| - if (events) {
|
| - AnimationEvent finished_event(
|
| - AnimationEvent::FINISHED, element_id_,
|
| - animations_[animation_index]->group(),
|
| - animations_[animation_index]->target_property(), monotonic_time);
|
| - finished_event.is_impl_only =
|
| - animations_[animation_index]->is_impl_only();
|
| - if (finished_event.is_impl_only)
|
| - NotifyAnimationFinished(finished_event);
|
| - else
|
| - events->events_.push_back(finished_event);
|
| - }
|
| - animations_[animation_index]->SetRunState(
|
| - Animation::WAITING_FOR_DELETION, monotonic_time);
|
| - }
|
| - marked_animations_for_deletions = true;
|
| - }
|
| - }
|
| - if (marked_animations_for_deletions)
|
| - NotifyPlayersAnimationWaitingForDeletion();
|
| +void ElementAnimations::ClearNeedsUpdateImplClientState() {
|
| + needs_update_impl_client_state_transform_ = false;
|
| + needs_update_impl_client_state_opacity_ = false;
|
| + needs_update_impl_client_state_filter_ = false;
|
| }
|
|
|
| -void ElementAnimations::MarkAbortedAnimationsForDeletion(
|
| - ElementAnimations* element_animations_impl) const {
|
| - bool aborted_transform_animation = false;
|
| - bool aborted_opacity_animation = false;
|
| - bool aborted_filter_animation = false;
|
| - auto& animations_impl = element_animations_impl->animations_;
|
| - for (const auto& animation_impl : animations_impl) {
|
| - // If the animation has been aborted on the main thread, mark it for
|
| - // deletion.
|
| - if (Animation* animation = GetAnimationById(animation_impl->id())) {
|
| - if (animation->run_state() == Animation::ABORTED) {
|
| - animation_impl->SetRunState(Animation::WAITING_FOR_DELETION,
|
| - element_animations_impl->last_tick_time_);
|
| - animation->SetRunState(Animation::WAITING_FOR_DELETION,
|
| - last_tick_time_);
|
| - if (animation_impl->target_property() == TargetProperty::TRANSFORM)
|
| - aborted_transform_animation = true;
|
| - else if (animation_impl->target_property() == TargetProperty::OPACITY)
|
| - aborted_opacity_animation = true;
|
| - else if (animation_impl->target_property() == TargetProperty::FILTER)
|
| - aborted_filter_animation = true;
|
| - }
|
| - }
|
| - }
|
| -
|
| - if (aborted_transform_animation) {
|
| - element_animations_impl->UpdateClientAnimationState(
|
| - TargetProperty::TRANSFORM);
|
| - }
|
| - if (aborted_opacity_animation) {
|
| - element_animations_impl->UpdateClientAnimationState(
|
| - TargetProperty::OPACITY);
|
| - }
|
| - if (aborted_filter_animation) {
|
| - element_animations_impl->UpdateClientAnimationState(TargetProperty::FILTER);
|
| - }
|
| -}
|
| -
|
| -void ElementAnimations::PurgeAnimationsMarkedForDeletion() {
|
| - animations_.erase(
|
| - std::remove_if(animations_.begin(), animations_.end(),
|
| - [](const std::unique_ptr<Animation>& animation) {
|
| - return animation->run_state() ==
|
| - Animation::WAITING_FOR_DELETION;
|
| - }),
|
| - animations_.end());
|
| -}
|
| -
|
| -void ElementAnimations::TickAnimations(base::TimeTicks monotonic_time) {
|
| - for (size_t i = 0; i < animations_.size(); ++i) {
|
| - if (animations_[i]->run_state() == Animation::STARTING ||
|
| - animations_[i]->run_state() == Animation::RUNNING ||
|
| - animations_[i]->run_state() == Animation::PAUSED) {
|
| - if (!animations_[i]->InEffect(monotonic_time))
|
| - continue;
|
| -
|
| - base::TimeDelta trimmed =
|
| - animations_[i]->TrimTimeToCurrentIteration(monotonic_time);
|
| -
|
| - switch (animations_[i]->target_property()) {
|
| - case TargetProperty::TRANSFORM: {
|
| - const TransformAnimationCurve* transform_animation_curve =
|
| - animations_[i]->curve()->ToTransformAnimationCurve();
|
| - const gfx::Transform transform =
|
| - transform_animation_curve->GetValue(trimmed);
|
| - NotifyClientTransformAnimated(
|
| - transform, animations_[i]->affects_active_elements(),
|
| - animations_[i]->affects_pending_elements());
|
| - break;
|
| - }
|
| -
|
| - case TargetProperty::OPACITY: {
|
| - const FloatAnimationCurve* float_animation_curve =
|
| - animations_[i]->curve()->ToFloatAnimationCurve();
|
| - const float opacity = std::max(
|
| - std::min(float_animation_curve->GetValue(trimmed), 1.0f), 0.f);
|
| - NotifyClientOpacityAnimated(
|
| - opacity, animations_[i]->affects_active_elements(),
|
| - animations_[i]->affects_pending_elements());
|
| - break;
|
| - }
|
| -
|
| - case TargetProperty::FILTER: {
|
| - const FilterAnimationCurve* filter_animation_curve =
|
| - animations_[i]->curve()->ToFilterAnimationCurve();
|
| - const FilterOperations filter =
|
| - filter_animation_curve->GetValue(trimmed);
|
| - NotifyClientFilterAnimated(
|
| - filter, animations_[i]->affects_active_elements(),
|
| - animations_[i]->affects_pending_elements());
|
| - break;
|
| - }
|
| -
|
| - case TargetProperty::BACKGROUND_COLOR: {
|
| - // Not yet implemented.
|
| - break;
|
| - }
|
| -
|
| - case TargetProperty::SCROLL_OFFSET: {
|
| - const ScrollOffsetAnimationCurve* scroll_offset_animation_curve =
|
| - animations_[i]->curve()->ToScrollOffsetAnimationCurve();
|
| - const gfx::ScrollOffset scroll_offset =
|
| - scroll_offset_animation_curve->GetValue(trimmed);
|
| - NotifyClientScrollOffsetAnimated(
|
| - scroll_offset, animations_[i]->affects_active_elements(),
|
| - animations_[i]->affects_pending_elements());
|
| - break;
|
| - }
|
| - }
|
| - }
|
| - }
|
| -}
|
| -
|
| -void ElementAnimations::UpdateActivation(UpdateActivationType type) {
|
| - bool force = type == FORCE_ACTIVATION;
|
| +void ElementAnimations::UpdateActivation(ActivationType type) {
|
| + bool force = type == ActivationType::FORCE;
|
| if (animation_host_) {
|
| bool was_active = is_active_;
|
| is_active_ = false;
|
| - for (size_t i = 0; i < animations_.size(); ++i) {
|
| - if (animations_[i]->run_state() != Animation::WAITING_FOR_DELETION) {
|
| +
|
| + ElementAnimations::PlayersList::Iterator it(players_list_.get());
|
| + AnimationPlayer* player;
|
| + while ((player = it.GetNext()) != nullptr) {
|
| + if (player->HasNonDeletedAnimation()) {
|
| is_active_ = true;
|
| break;
|
| }
|
| @@ -1036,6 +499,10 @@ void ElementAnimations::UpdateActivation(UpdateActivationType type) {
|
| }
|
| }
|
|
|
| +void ElementAnimations::UpdateActivationNormal() {
|
| + UpdateActivation(ActivationType::NORMAL);
|
| +}
|
| +
|
| void ElementAnimations::NotifyClientOpacityAnimated(
|
| float opacity,
|
| bool notify_active_elements,
|
| @@ -1126,7 +593,7 @@ void ElementAnimations::NotifyClientAnimationChanged(
|
| }
|
| }
|
|
|
| -void ElementAnimations::UpdateClientAnimationState(
|
| +void ElementAnimations::UpdateClientAnimationStateInternal(
|
| TargetProperty::Type property) {
|
| struct PropertyAnimationState* animation_state = nullptr;
|
| switch (property) {
|
| @@ -1158,18 +625,23 @@ void ElementAnimations::UpdateClientAnimationState(
|
| DCHECK(was_potentially_animating_for_pending_elements ||
|
| !was_currently_running_animation_for_pending_elements);
|
|
|
| - for (const auto& animation : animations_) {
|
| - if (!animation->is_finished() && animation->target_property() == property) {
|
| - animation_state->potentially_animating_for_active_elements |=
|
| - animation->affects_active_elements();
|
| - animation_state->potentially_animating_for_pending_elements |=
|
| - animation->affects_pending_elements();
|
| - animation_state->currently_running_for_active_elements =
|
| - animation_state->potentially_animating_for_active_elements &&
|
| - animation->InEffect(last_tick_time_);
|
| - animation_state->currently_running_for_pending_elements =
|
| - animation_state->potentially_animating_for_pending_elements &&
|
| - animation->InEffect(last_tick_time_);
|
| + ElementAnimations::PlayersList::Iterator it(players_list_.get());
|
| + AnimationPlayer* player;
|
| + while ((player = it.GetNext()) != nullptr) {
|
| + for (const auto& animation : player->animations()) {
|
| + if (!animation->is_finished() &&
|
| + animation->target_property() == property) {
|
| + animation_state->potentially_animating_for_active_elements |=
|
| + animation->affects_active_elements();
|
| + animation_state->potentially_animating_for_pending_elements |=
|
| + animation->affects_pending_elements();
|
| + animation_state->currently_running_for_active_elements =
|
| + animation_state->potentially_animating_for_active_elements &&
|
| + animation->InEffect(last_tick_time_);
|
| + animation_state->currently_running_for_pending_elements =
|
| + animation_state->potentially_animating_for_pending_elements &&
|
| + animation->InEffect(last_tick_time_);
|
| + }
|
| }
|
| }
|
|
|
| @@ -1203,169 +675,116 @@ void ElementAnimations::UpdateClientAnimationState(
|
| }
|
|
|
| bool ElementAnimations::HasActiveAnimation() const {
|
| - for (size_t i = 0; i < animations_.size(); ++i) {
|
| - if (!animations_[i]->is_finished())
|
| + ElementAnimations::PlayersList::Iterator it(players_list_.get());
|
| + AnimationPlayer* player;
|
| + while ((player = it.GetNext()) != nullptr) {
|
| + if (player->HasActiveAnimation())
|
| return true;
|
| }
|
| +
|
| return false;
|
| }
|
|
|
| bool ElementAnimations::HasAnyAnimation() const {
|
| - return !animations_.empty();
|
| + ElementAnimations::PlayersList::Iterator it(players_list_.get());
|
| + AnimationPlayer* player;
|
| + while ((player = it.GetNext()) != nullptr) {
|
| + if (player->has_any_animation())
|
| + return true;
|
| + }
|
| +
|
| + return false;
|
| }
|
|
|
| bool ElementAnimations::IsPotentiallyAnimatingProperty(
|
| TargetProperty::Type target_property,
|
| ElementListType list_type) const {
|
| - for (size_t i = 0; i < animations_.size(); ++i) {
|
| - if (!animations_[i]->is_finished() &&
|
| - animations_[i]->target_property() == target_property) {
|
| - if ((list_type == ElementListType::ACTIVE &&
|
| - animations_[i]->affects_active_elements()) ||
|
| - (list_type == ElementListType::PENDING &&
|
| - animations_[i]->affects_pending_elements()))
|
| - return true;
|
| - }
|
| + ElementAnimations::PlayersList::Iterator it(players_list_.get());
|
| + AnimationPlayer* player;
|
| + while ((player = it.GetNext()) != nullptr) {
|
| + if (player->IsPotentiallyAnimatingProperty(target_property, list_type))
|
| + return true;
|
| }
|
| +
|
| return false;
|
| }
|
|
|
| bool ElementAnimations::IsCurrentlyAnimatingProperty(
|
| TargetProperty::Type target_property,
|
| ElementListType list_type) const {
|
| - for (size_t i = 0; i < animations_.size(); ++i) {
|
| - if (!animations_[i]->is_finished() &&
|
| - animations_[i]->InEffect(last_tick_time_) &&
|
| - animations_[i]->target_property() == target_property) {
|
| - if ((list_type == ElementListType::ACTIVE &&
|
| - animations_[i]->affects_active_elements()) ||
|
| - (list_type == ElementListType::PENDING &&
|
| - animations_[i]->affects_pending_elements()))
|
| - return true;
|
| - }
|
| + ElementAnimations::PlayersList::Iterator it(players_list_.get());
|
| + AnimationPlayer* player;
|
| + while ((player = it.GetNext()) != nullptr) {
|
| + if (player->IsCurrentlyAnimatingProperty(target_property, list_type))
|
| + return true;
|
| }
|
| +
|
| return false;
|
| }
|
|
|
| -void ElementAnimations::PauseAnimation(int animation_id,
|
| - base::TimeDelta time_offset) {
|
| - for (size_t i = 0; i < animations_.size(); ++i) {
|
| - if (animations_[i]->id() == animation_id) {
|
| - animations_[i]->SetRunState(Animation::PAUSED,
|
| - time_offset + animations_[i]->start_time() +
|
| - animations_[i]->time_offset());
|
| - }
|
| - }
|
| - SetNeedsPushProperties();
|
| +void ElementAnimations::SetScrollOffsetAnimationWasInterrupted() {
|
| + scroll_offset_animation_was_interrupted_ = true;
|
| }
|
|
|
| -void ElementAnimations::RemoveAnimation(int animation_id) {
|
| - bool removed_transform_animation = false;
|
| - bool removed_opacity_animation = false;
|
| - bool removed_filter_animation = false;
|
| - // Since we want to use the animations that we're going to remove, we need to
|
| - // use a stable_parition here instead of remove_if. Remove_if leaves the
|
| - // removed items in an unspecified state.
|
| - auto animations_to_remove = std::stable_partition(
|
| - animations_.begin(), animations_.end(),
|
| - [animation_id](const std::unique_ptr<Animation>& animation) {
|
| - return animation->id() != animation_id;
|
| - });
|
| - for (auto it = animations_to_remove; it != animations_.end(); ++it) {
|
| - if ((*it)->target_property() == TargetProperty::SCROLL_OFFSET) {
|
| - scroll_offset_animation_was_interrupted_ = true;
|
| - } else if ((*it)->target_property() == TargetProperty::TRANSFORM &&
|
| - !(*it)->is_finished()) {
|
| - removed_transform_animation = true;
|
| - } else if ((*it)->target_property() == TargetProperty::OPACITY &&
|
| - !(*it)->is_finished()) {
|
| - removed_opacity_animation = true;
|
| - } else if ((*it)->target_property() == TargetProperty::FILTER &&
|
| - !(*it)->is_finished()) {
|
| - removed_filter_animation = true;
|
| - }
|
| +bool ElementAnimations::needs_to_start_animations_for_testing() const {
|
| + ElementAnimations::PlayersList::Iterator it(players_list_.get());
|
| + AnimationPlayer* player;
|
| + while ((player = it.GetNext()) != nullptr) {
|
| + if (player->needs_to_start_animations())
|
| + return true;
|
| }
|
|
|
| - animations_.erase(animations_to_remove, animations_.end());
|
| - UpdateActivation(NORMAL_ACTIVATION);
|
| - if (removed_transform_animation)
|
| - UpdateClientAnimationState(TargetProperty::TRANSFORM);
|
| - if (removed_opacity_animation)
|
| - UpdateClientAnimationState(TargetProperty::OPACITY);
|
| - if (removed_filter_animation)
|
| - UpdateClientAnimationState(TargetProperty::FILTER);
|
| + return false;
|
| +}
|
|
|
| - SetNeedsPushProperties();
|
| +void ElementAnimations::PauseAnimation(int animation_id,
|
| + base::TimeDelta time_offset) {
|
| + ElementAnimations::PlayersList::Iterator it(players_list_.get());
|
| + AnimationPlayer* player;
|
| + while ((player = it.GetNext()) != nullptr)
|
| + player->PauseAnimation(animation_id, time_offset.InSecondsF());
|
| }
|
|
|
| -void ElementAnimations::AbortAnimation(int animation_id) {
|
| - if (Animation* animation = GetAnimationById(animation_id)) {
|
| - if (!animation->is_finished()) {
|
| - animation->SetRunState(Animation::ABORTED, last_tick_time_);
|
| - switch (animation->target_property()) {
|
| - case TargetProperty::TRANSFORM:
|
| - case TargetProperty::OPACITY:
|
| - case TargetProperty::FILTER:
|
| - UpdateClientAnimationState(animation->target_property());
|
| - break;
|
| - default:
|
| - break;
|
| - }
|
| - }
|
| - }
|
| +void ElementAnimations::RemoveAnimation(int animation_id) {
|
| + ElementAnimations::PlayersList::Iterator it(players_list_.get());
|
| + AnimationPlayer* player;
|
| + while ((player = it.GetNext()) != nullptr)
|
| + player->RemoveAnimation(animation_id);
|
| +}
|
|
|
| - SetNeedsPushProperties();
|
| +void ElementAnimations::AbortAnimation(int animation_id) {
|
| + ElementAnimations::PlayersList::Iterator it(players_list_.get());
|
| + AnimationPlayer* player;
|
| + while ((player = it.GetNext()) != nullptr)
|
| + player->AbortAnimation(animation_id);
|
| }
|
|
|
| void ElementAnimations::AbortAnimations(TargetProperty::Type target_property,
|
| bool needs_completion) {
|
| - if (needs_completion)
|
| - DCHECK(target_property == TargetProperty::SCROLL_OFFSET);
|
| -
|
| - bool aborted_animation = false;
|
| - for (size_t i = 0; i < animations_.size(); ++i) {
|
| - if (animations_[i]->target_property() == target_property &&
|
| - !animations_[i]->is_finished()) {
|
| - // Currently only impl-only scroll offset animations can be completed on
|
| - // the main thread.
|
| - if (needs_completion && animations_[i]->is_impl_only()) {
|
| - animations_[i]->SetRunState(Animation::ABORTED_BUT_NEEDS_COMPLETION,
|
| - last_tick_time_);
|
| - } else {
|
| - animations_[i]->SetRunState(Animation::ABORTED, last_tick_time_);
|
| - }
|
| - aborted_animation = true;
|
| - }
|
| - }
|
| - if (aborted_animation) {
|
| - switch (target_property) {
|
| - case TargetProperty::TRANSFORM:
|
| - case TargetProperty::OPACITY:
|
| - case TargetProperty::FILTER:
|
| - UpdateClientAnimationState(target_property);
|
| - break;
|
| - default:
|
| - break;
|
| - }
|
| - }
|
| -
|
| - SetNeedsPushProperties();
|
| + ElementAnimations::PlayersList::Iterator it(players_list_.get());
|
| + AnimationPlayer* player;
|
| + while ((player = it.GetNext()) != nullptr)
|
| + player->AbortAnimations(target_property, needs_completion);
|
| }
|
|
|
| Animation* ElementAnimations::GetAnimation(
|
| TargetProperty::Type target_property) const {
|
| - for (size_t i = 0; i < animations_.size(); ++i) {
|
| - size_t index = animations_.size() - i - 1;
|
| - if (animations_[index]->target_property() == target_property)
|
| - return animations_[index].get();
|
| + ElementAnimations::PlayersList::Iterator it(players_list_.get());
|
| + AnimationPlayer* player;
|
| + while ((player = it.GetNext()) != nullptr) {
|
| + if (Animation* animation = player->GetAnimation(target_property))
|
| + return animation;
|
| }
|
| return nullptr;
|
| }
|
|
|
| Animation* ElementAnimations::GetAnimationById(int animation_id) const {
|
| - for (size_t i = 0; i < animations_.size(); ++i)
|
| - if (animations_[i]->id() == animation_id)
|
| - return animations_[i].get();
|
| + ElementAnimations::PlayersList::Iterator it(players_list_.get());
|
| + AnimationPlayer* player;
|
| + while ((player = it.GetNext()) != nullptr) {
|
| + if (Animation* animation = player->GetAnimationById(animation_id))
|
| + return animation;
|
| + }
|
| return nullptr;
|
| }
|
|
|
| @@ -1440,61 +859,6 @@ void ElementAnimations::IsAnimatingChanged(ElementListType list_type,
|
| }
|
| }
|
|
|
| -void ElementAnimations::NotifyPlayersAnimationStarted(
|
| - base::TimeTicks monotonic_time,
|
| - TargetProperty::Type target_property,
|
| - int group) {
|
| - ElementAnimations::PlayersList::Iterator it(players_list_.get());
|
| - AnimationPlayer* player;
|
| - // TODO(crbug.com/634916): Shouldn't manually iterate through the list if
|
| - // base::ObserverList has a callback mechanism.
|
| - while ((player = it.GetNext()) != nullptr)
|
| - player->NotifyAnimationStarted(monotonic_time, target_property, group);
|
| -}
|
| -
|
| -void ElementAnimations::NotifyPlayersAnimationFinished(
|
| - base::TimeTicks monotonic_time,
|
| - TargetProperty::Type target_property,
|
| - int group) {
|
| - ElementAnimations::PlayersList::Iterator it(players_list_.get());
|
| - AnimationPlayer* player;
|
| - while ((player = it.GetNext()) != nullptr)
|
| - player->NotifyAnimationFinished(monotonic_time, target_property, group);
|
| -}
|
| -
|
| -void ElementAnimations::NotifyPlayersAnimationAborted(
|
| - base::TimeTicks monotonic_time,
|
| - TargetProperty::Type target_property,
|
| - int group) {
|
| - ElementAnimations::PlayersList::Iterator it(players_list_.get());
|
| - AnimationPlayer* player;
|
| - while ((player = it.GetNext()) != nullptr)
|
| - player->NotifyAnimationAborted(monotonic_time, target_property, group);
|
| -}
|
| -
|
| -void ElementAnimations::NotifyPlayersAnimationWaitingForDeletion() {
|
| - ElementAnimations::PlayersList::Iterator it(players_list_.get());
|
| - AnimationPlayer* player;
|
| - while ((player = it.GetNext()) != nullptr)
|
| - player->NotifyAnimationWaitingForDeletion();
|
| -}
|
| -
|
| -void ElementAnimations::NotifyPlayersAnimationTakeover(
|
| - base::TimeTicks monotonic_time,
|
| - TargetProperty::Type target_property,
|
| - double animation_start_time,
|
| - std::unique_ptr<AnimationCurve> curve) {
|
| - DCHECK(curve);
|
| - ElementAnimations::PlayersList::Iterator it(players_list_.get());
|
| - AnimationPlayer* player;
|
| - while ((player = it.GetNext()) != nullptr) {
|
| - std::unique_ptr<AnimationCurve> animation_curve = curve->Clone();
|
| - player->NotifyAnimationTakeover(monotonic_time, target_property,
|
| - animation_start_time,
|
| - std::move(animation_curve));
|
| - }
|
| -}
|
| -
|
| gfx::ScrollOffset ElementAnimations::ScrollOffsetForAnimation() const {
|
| if (animation_host()) {
|
| DCHECK(animation_host()->mutator_host_client());
|
|
|