#include "ui/compositor/layer_animator.h"
#include <stddef.h>
#include <memory>
#include <vector>
#include "base/check_op.h"
#include "base/observer_list.h"
#include "base/trace_event/trace_event.h"
#include "cc/animation/animation.h"
#include "cc/animation/animation_host.h"
#include "cc/animation/animation_id_provider.h"
#include "cc/animation/animation_timeline.h"
#include "cc/animation/element_animations.h"
#include "components/viz/common/frame_sinks/begin_frame_args.h"
#include "ui/compositor/compositor.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/layer_animation_delegate.h"
#include "ui/compositor/layer_animation_observer.h"
#include "ui/compositor/layer_animation_sequence.h"
#include "ui/compositor/layer_animator_collection.h"
#define SAFE_INVOKE_VOID(function, running_anim, ...) \
if (running_anim.is_sequence_alive()) \
function(running_anim.sequence(), ##__VA_ARGS__)
#define SAFE_INVOKE_BOOL(function, running_anim) \
((running_anim.is_sequence_alive()) \
? function(running_anim.sequence()) \
: false)
#define SAFE_INVOKE_PTR(function, running_anim) \
((running_anim.is_sequence_alive()) ? function(running_anim.sequence()) \
: nullptr)
namespace ui {
namespace {
const int kLayerAnimatorDefaultTransitionDurationMs = 120;
}
LayerAnimator::LayerAnimator(base::TimeDelta transition_duration)
: transition_duration_(transition_duration) {
animation_ =
cc::Animation::Create(cc::AnimationIdProvider::NextAnimationId());
}
LayerAnimator::~LayerAnimator() {
for (size_t i = 0; i < running_animations_.size(); ++i) {
if (running_animations_[i].is_sequence_alive())
running_animations_[i].sequence()->OnAnimatorDestroyed();
}
ClearAnimationsInternal();
delegate_ = nullptr;
DCHECK(!animation_->animation_timeline());
}
scoped_refptr<LayerAnimator> LayerAnimator::CreateDefaultAnimator() {
return base::MakeRefCounted<LayerAnimator>(base::Milliseconds(0));
}
scoped_refptr<LayerAnimator> LayerAnimator::CreateImplicitAnimator() {
return base::MakeRefCounted<LayerAnimator>(
base::Milliseconds(kLayerAnimatorDefaultTransitionDurationMs));
}
#define ANIMATED_PROPERTY(type, property, name, member_type, member) \
void LayerAnimator::Set##name(type value) { \
base::TimeDelta duration = GetTransitionDuration(); \
if (duration.is_zero() && delegate() && \
(preemption_strategy_ != ENQUEUE_NEW_ANIMATION)) { \
\
const auto weak_ptr = weak_ptr_factory_.GetWeakPtr(); \
StopAnimatingProperty(LayerAnimationElement::property); \
if (!weak_ptr || !delegate()) \
return; \
delegate()->Set##name##FromAnimation( \
value, PropertyChangeReason::NOT_FROM_ANIMATION); \
return; \
} \
std::unique_ptr<LayerAnimationElement> element = \
LayerAnimationElement::Create##name##Element(value, duration); \
element->set_tween_type(tween_type_); \
StartAnimation(new LayerAnimationSequence(std::move(element))); \
} \
\
member_type LayerAnimator::GetTarget##name() const { \
LayerAnimationElement::TargetValue target(delegate()); \
GetTargetValue(&target); \
return target.member; \
}
ANIMATED_PROPERTY(const gfx::Transform&,
TRANSFORM,
Transform,
gfx::Transform,
transform)
ANIMATED_PROPERTY(const gfx::Rect&, BOUNDS, Bounds, gfx::Rect, bounds)
ANIMATED_PROPERTY(float, OPACITY, Opacity, float, opacity)
ANIMATED_PROPERTY(bool, VISIBILITY, Visibility, bool, visibility)
ANIMATED_PROPERTY(float, BRIGHTNESS, Brightness, float, brightness)
ANIMATED_PROPERTY(float, GRAYSCALE, Grayscale, float, grayscale)
ANIMATED_PROPERTY(SkColor4f, COLOR, Color, SkColor4f, color)
ANIMATED_PROPERTY(const gfx::Rect&, CLIP, ClipRect, gfx::Rect, clip_rect)
ANIMATED_PROPERTY(const gfx::RoundedCornersF&,
ROUNDED_CORNERS,
RoundedCorners,
gfx::RoundedCornersF,
rounded_corners)
ANIMATED_PROPERTY(const gfx::LinearGradient&,
GRADIENT_MASK,
GradientMask,
gfx::LinearGradient,
gradient_mask)
#undef ANIMATED_PROPERTY
base::TimeDelta LayerAnimator::GetTransitionDuration() const {
return transition_duration_;
}
void LayerAnimator::SetDelegate(LayerAnimationDelegate* delegate) {
if (delegate_ && is_started_) {
LayerAnimatorCollection* collection = GetLayerAnimatorCollection();
if (collection)
collection->StopAnimator(this);
}
SwitchToLayer(delegate ? delegate->GetCcLayer() : nullptr);
delegate_ = delegate;
if (delegate_ && is_started_) {
LayerAnimatorCollection* collection = GetLayerAnimatorCollection();
if (collection)
collection->StartAnimator(this);
}
}
void LayerAnimator::SwitchToLayer(scoped_refptr<cc::Layer> new_layer) {
if (delegate_)
DetachLayerFromAnimation();
if (new_layer)
AttachLayerToAnimation(new_layer->id());
}
void LayerAnimator::AttachLayerAndTimeline(Compositor* compositor) {
DCHECK(compositor);
cc::AnimationTimeline* timeline = compositor->GetAnimationTimeline();
DCHECK(timeline);
timeline->AttachAnimation(animation_);
DCHECK(delegate_->GetCcLayer());
AttachLayerToAnimation(delegate_->GetCcLayer()->id());
for (auto& layer_animation_sequence : animation_queue_)
layer_animation_sequence->OnAnimatorAttached(delegate());
}
void LayerAnimator::DetachLayerAndTimeline(Compositor* compositor) {
DCHECK(compositor);
cc::AnimationTimeline* timeline = compositor->GetAnimationTimeline();
DCHECK(timeline);
DetachLayerFromAnimation();
timeline->DetachAnimation(animation_);
for (auto& layer_animation_sequence : animation_queue_)
layer_animation_sequence->OnAnimatorDetached();
}
void LayerAnimator::AttachLayerToAnimation(int layer_id) {
cc::ElementId element_id(layer_id);
if (!animation_->element_id())
animation_->AttachElement(element_id);
else
DCHECK_EQ(animation_->element_id(), element_id);
animation_->set_animation_delegate(this);
}
void LayerAnimator::DetachLayerFromAnimation() {
animation_->set_animation_delegate(nullptr);
if (animation_->element_id())
animation_->DetachElement();
}
void LayerAnimator::AddThreadedAnimation(
std::unique_ptr<cc::KeyframeModel> animation) {
animation_->AddKeyframeModel(std::move(animation));
}
void LayerAnimator::RemoveThreadedAnimation(int keyframe_model_id) {
animation_->RemoveKeyframeModel(keyframe_model_id);
}
cc::Animation* LayerAnimator::GetAnimationForTesting() const {
return animation_.get();
}
void LayerAnimator::StartAnimation(LayerAnimationSequence* animation) {
scoped_refptr<LayerAnimator> retain(this);
OnScheduled(animation);
if (!StartSequenceImmediately(animation)) {
switch (preemption_strategy_) {
case IMMEDIATELY_SET_NEW_TARGET:
ImmediatelySetNewTarget(animation);
break;
case IMMEDIATELY_ANIMATE_TO_NEW_TARGET:
ImmediatelyAnimateToNewTarget(animation);
break;
case ENQUEUE_NEW_ANIMATION:
EnqueueNewAnimation(animation);
break;
case REPLACE_QUEUED_ANIMATIONS:
ReplaceQueuedAnimations(animation);
break;
}
}
FinishAnyAnimationWithZeroDuration();
UpdateAnimationState();
}
void LayerAnimator::ScheduleAnimation(LayerAnimationSequence* animation) {
scoped_refptr<LayerAnimator> retain(this);
OnScheduled(animation);
if (is_animating()) {
animation_queue_.push_back(
std::unique_ptr<LayerAnimationSequence>(animation));
ProcessQueue();
} else {
StartSequenceImmediately(animation);
}
UpdateAnimationState();
}
void LayerAnimator::StartTogether(
const std::vector<LayerAnimationSequence*>& animations) {
scoped_refptr<LayerAnimator> retain(this);
if (preemption_strategy_ == IMMEDIATELY_SET_NEW_TARGET) {
std::vector<LayerAnimationSequence*>::const_iterator iter;
for (iter = animations.begin(); iter != animations.end(); ++iter) {
StartAnimation(*iter);
}
return;
}
adding_animations_ = true;
if (!is_animating()) {
LayerAnimatorCollection* collection = GetLayerAnimatorCollection();
if (collection && collection->HasActiveAnimators())
last_step_time_ = collection->last_tick_time();
else
last_step_time_ = base::TimeTicks::Now();
}
LayerAnimationElement::AnimatableProperties animated_properties =
LayerAnimationElement::UNKNOWN;
std::vector<LayerAnimationSequence*>::const_iterator iter;
for (iter = animations.begin(); iter != animations.end(); ++iter)
animated_properties |= (*iter)->properties();
StartAnimation(new LayerAnimationSequence(
LayerAnimationElement::CreatePauseElement(animated_properties,
base::TimeDelta())));
bool wait_for_group_start = false;
for (iter = animations.begin(); iter != animations.end(); ++iter)
wait_for_group_start |=
delegate_ && (*iter)->IsFirstElementThreaded(delegate_);
int group_id = cc::AnimationIdProvider::NextGroupId();
for (iter = animations.begin(); iter != animations.end(); ++iter) {
(*iter)->set_animation_group_id(group_id);
(*iter)->set_waiting_for_group_start(wait_for_group_start);
ScheduleAnimation(*iter);
}
adding_animations_ = false;
UpdateAnimationState();
}
void LayerAnimator::ScheduleTogether(
const std::vector<LayerAnimationSequence*>& animations) {
scoped_refptr<LayerAnimator> retain(this);
LayerAnimationElement::AnimatableProperties animated_properties =
LayerAnimationElement::UNKNOWN;
std::vector<LayerAnimationSequence*>::const_iterator iter;
for (iter = animations.begin(); iter != animations.end(); ++iter)
animated_properties |= (*iter)->properties();
ScheduleAnimation(new LayerAnimationSequence(
LayerAnimationElement::CreatePauseElement(animated_properties,
base::TimeDelta())));
bool wait_for_group_start = false;
for (iter = animations.begin(); iter != animations.end(); ++iter)
wait_for_group_start |=
delegate_ && (*iter)->IsFirstElementThreaded(delegate_);
int group_id = cc::AnimationIdProvider::NextGroupId();
for (iter = animations.begin(); iter != animations.end(); ++iter) {
(*iter)->set_animation_group_id(group_id);
(*iter)->set_waiting_for_group_start(wait_for_group_start);
ScheduleAnimation(*iter);
}
UpdateAnimationState();
}
void LayerAnimator::SchedulePauseForProperties(
base::TimeDelta duration,
LayerAnimationElement::AnimatableProperties properties_to_pause) {
ScheduleAnimation(new ui::LayerAnimationSequence(
ui::LayerAnimationElement::CreatePauseElement(
properties_to_pause, duration)));
}
bool LayerAnimator::IsAnimatingOnePropertyOf(
LayerAnimationElement::AnimatableProperties properties) const {
for (auto& layer_animation_sequence : animation_queue_) {
if (layer_animation_sequence->properties() & properties)
return true;
}
return false;
}
void LayerAnimator::StopAnimatingProperty(
LayerAnimationElement::AnimatableProperty property) {
scoped_refptr<LayerAnimator> retain(this);
while (true) {
RunningAnimation* running = GetRunningAnimation(property);
if (!running)
break;
DCHECK(running->is_sequence_alive());
FinishAnimation(running->sequence(), false);
}
}
void LayerAnimator::AddObserver(LayerAnimationObserver* observer) {
if (!observers_.HasObserver(observer)) {
observers_.AddObserver(observer);
for (auto& layer_animation_sequence : animation_queue_)
layer_animation_sequence->AddObserver(observer);
}
}
void LayerAnimator::RemoveObserver(LayerAnimationObserver* observer) {
observers_.RemoveObserver(observer);
for (AnimationQueue::iterator queue_iter = animation_queue_.begin();
queue_iter != animation_queue_.end(); ++queue_iter) {
(*queue_iter)->RemoveObserver(observer);
}
}
void LayerAnimator::AddOwnedObserver(
std::unique_ptr<ImplicitAnimationObserver> animation_observer) {
owned_observer_list_.push_back(std::move(animation_observer));
}
void LayerAnimator::RemoveAndDestroyOwnedObserver(
ImplicitAnimationObserver* animation_observer) {
std::erase_if(owned_observer_list_,
[animation_observer](
const std::unique_ptr<ImplicitAnimationObserver>& other) {
return other.get() == animation_observer;
});
}
base::CallbackListSubscription LayerAnimator::AddSequenceScheduledCallback(
SequenceScheduledCallback callback) {
return sequence_scheduled_callbacks_.Add(std::move(callback));
}
void LayerAnimator::OnThreadedAnimationStarted(
base::TimeTicks monotonic_time,
cc::TargetProperty::Type target_property,
int group_id) {
LayerAnimationElement::AnimatableProperty property =
LayerAnimationElement::ToAnimatableProperty(target_property);
RunningAnimation* running = GetRunningAnimation(property);
if (!running)
return;
DCHECK(running->is_sequence_alive());
if (running->sequence()->animation_group_id() != group_id)
return;
running->sequence()->OnThreadedAnimationStarted(monotonic_time,
target_property, group_id);
if (!running->sequence()->waiting_for_group_start())
return;
base::TimeTicks start_time = monotonic_time;
running->sequence()->set_waiting_for_group_start(false);
for (auto iter = running_animations_.begin();
iter != running_animations_.end(); ++iter) {
if (((*iter).sequence()->animation_group_id() == group_id) &&
!(*iter).sequence()->IsFirstElementThreaded(delegate_) &&
(*iter).sequence()->waiting_for_group_start()) {
(*iter).sequence()->set_start_time(start_time);
(*iter).sequence()->set_waiting_for_group_start(false);
(*iter).sequence()->Start(delegate());
}
}
}
void LayerAnimator::AddToCollection(LayerAnimatorCollection* collection) {
DCHECK_EQ(collection, GetLayerAnimatorCollection());
if (is_animating() && !is_started_) {
collection->StartAnimator(this);
is_started_ = true;
}
}
void LayerAnimator::RemoveFromCollection(LayerAnimatorCollection* collection) {
DCHECK_EQ(collection, GetLayerAnimatorCollection());
if (is_started_) {
collection->StopAnimator(this);
is_started_ = false;
}
DCHECK(!animation_->element_animations() ||
!animation_->element_animations()->HasTickingKeyframeEffect());
}
void LayerAnimator::ProgressAnimation(LayerAnimationSequence* sequence,
base::TimeTicks now) {
if (!delegate() || sequence->waiting_for_group_start())
return;
sequence->Progress(now, delegate());
}
void LayerAnimator::ProgressAnimationToEnd(LayerAnimationSequence* sequence) {
if (!delegate())
return;
sequence->ProgressToEnd(delegate());
}
bool LayerAnimator::HasAnimation(LayerAnimationSequence* sequence) const {
for (AnimationQueue::const_iterator queue_iter = animation_queue_.begin();
queue_iter != animation_queue_.end(); ++queue_iter) {
if ((*queue_iter).get() == sequence)
return true;
}
return false;
}
void LayerAnimator::Step(base::TimeTicks now) {
TRACE_EVENT0("ui", "LayerAnimator::Step");
scoped_refptr<LayerAnimator> retain(this);
last_step_time_ = now;
PurgeDeletedAnimations();
RunningAnimations running_animations_copy = running_animations_;
for (size_t i = 0; i < running_animations_copy.size(); ++i) {
if (!SAFE_INVOKE_BOOL(HasAnimation, running_animations_copy[i]))
continue;
if (running_animations_copy[i].sequence()->IsFinished(now)) {
SAFE_INVOKE_VOID(FinishAnimation, running_animations_copy[i], false);
} else {
SAFE_INVOKE_VOID(ProgressAnimation, running_animations_copy[i], now);
}
}
}
void LayerAnimator::StopAnimatingInternal(bool abort) {
scoped_refptr<LayerAnimator> retain(this);
while (is_animating() && delegate()) {
PurgeDeletedAnimations();
if (running_animations_.empty())
ProcessQueue();
DCHECK(!running_animations_.empty());
if (running_animations_.empty()) {
ClearAnimationsInternal();
break;
}
SAFE_INVOKE_VOID(FinishAnimation, running_animations_[0], abort);
}
}
void LayerAnimator::UpdateAnimationState() {
if (disable_timer_for_test_)
return;
const bool should_start = is_animating();
LayerAnimatorCollection* collection = GetLayerAnimatorCollection();
if (collection) {
if (should_start && !is_started_)
collection->StartAnimator(this);
else if (!should_start && is_started_)
collection->StopAnimator(this);
is_started_ = should_start;
} else {
is_started_ = false;
}
}
LayerAnimationSequence* LayerAnimator::RemoveAnimation(
LayerAnimationSequence* sequence) {
std::unique_ptr<LayerAnimationSequence> to_return;
bool is_running = false;
for (auto iter = running_animations_.begin();
iter != running_animations_.end(); ++iter) {
if ((*iter).sequence() == sequence) {
running_animations_.erase(iter);
is_running = true;
break;
}
}
for (AnimationQueue::iterator queue_iter = animation_queue_.begin();
queue_iter != animation_queue_.end(); ++queue_iter) {
if (queue_iter->get() == sequence) {
to_return = std::move(*queue_iter);
animation_queue_.erase(queue_iter);
break;
}
}
if (!delegate())
return to_return.release();
if (!to_return.get() || !to_return->waiting_for_group_start() ||
!to_return->IsFirstElementThreaded(delegate_))
return to_return.release();
bool is_wait_still_needed = false;
int group_id = to_return->animation_group_id();
for (AnimationQueue::iterator queue_iter = animation_queue_.begin();
queue_iter != animation_queue_.end(); ++queue_iter) {
if (((*queue_iter)->animation_group_id() == group_id) &&
(*queue_iter)->IsFirstElementThreaded(delegate_)) {
is_wait_still_needed = true;
break;
}
}
if (is_wait_still_needed)
return to_return.release();
for (AnimationQueue::iterator queue_iter = animation_queue_.begin();
queue_iter != animation_queue_.end(); ++queue_iter) {
if ((*queue_iter)->animation_group_id() == group_id &&
(*queue_iter)->waiting_for_group_start()) {
(*queue_iter)->set_waiting_for_group_start(false);
if (is_running) {
(*queue_iter)->set_start_time(last_step_time_);
(*queue_iter)->Start(delegate());
}
}
}
return to_return.release();
}
void LayerAnimator::FinishAnimation(
LayerAnimationSequence* sequence, bool abort) {
scoped_refptr<LayerAnimator> retain(this);
std::unique_ptr<LayerAnimationSequence> removed(RemoveAnimation(sequence));
if (abort)
sequence->Abort(delegate());
else
ProgressAnimationToEnd(sequence);
if (!delegate())
return;
ProcessQueue();
UpdateAnimationState();
}
void LayerAnimator::FinishAnyAnimationWithZeroDuration() {
scoped_refptr<LayerAnimator> retain(this);
RunningAnimations running_animations_copy = running_animations_;
for (size_t i = 0; i < running_animations_copy.size(); ++i) {
if (!SAFE_INVOKE_BOOL(HasAnimation, running_animations_copy[i]))
continue;
if (running_animations_copy[i].sequence()->IsFinished(
running_animations_copy[i].sequence()->start_time())) {
SAFE_INVOKE_VOID(ProgressAnimationToEnd, running_animations_copy[i]);
std::unique_ptr<LayerAnimationSequence> removed(
SAFE_INVOKE_PTR(RemoveAnimation, running_animations_copy[i]));
}
}
ProcessQueue();
UpdateAnimationState();
}
void LayerAnimator::ClearAnimations() {
scoped_refptr<LayerAnimator> retain(this);
ClearAnimationsInternal();
}
LayerAnimator::RunningAnimation* LayerAnimator::GetRunningAnimation(
LayerAnimationElement::AnimatableProperty property) {
PurgeDeletedAnimations();
for (auto iter = running_animations_.begin();
iter != running_animations_.end(); ++iter) {
if ((*iter).sequence()->properties() & property)
return &(*iter);
}
return nullptr;
}
void LayerAnimator::AddToQueueIfNotPresent(LayerAnimationSequence* animation) {
bool found_sequence = false;
for (AnimationQueue::iterator queue_iter = animation_queue_.begin();
queue_iter != animation_queue_.end(); ++queue_iter) {
if (queue_iter->get() == animation) {
found_sequence = true;
break;
}
}
if (!found_sequence) {
animation_queue_.push_front(
std::unique_ptr<LayerAnimationSequence>(animation));
}
}
void LayerAnimator::RemoveAllAnimationsWithACommonProperty(
LayerAnimationSequence* sequence, bool abort) {
RunningAnimations running_animations_copy = running_animations_;
for (size_t i = 0; i < running_animations_copy.size(); ++i) {
if (!SAFE_INVOKE_BOOL(HasAnimation, running_animations_copy[i]))
continue;
if (running_animations_copy[i].sequence()->HasConflictingProperty(
sequence->properties())) {
std::unique_ptr<LayerAnimationSequence> removed(
SAFE_INVOKE_PTR(RemoveAnimation, running_animations_copy[i]));
if (abort)
running_animations_copy[i].sequence()->Abort(delegate());
else
SAFE_INVOKE_VOID(ProgressAnimationToEnd, running_animations_copy[i]);
}
}
std::vector<base::WeakPtr<LayerAnimationSequence> > sequences;
for (AnimationQueue::iterator queue_iter = animation_queue_.begin();
queue_iter != animation_queue_.end(); ++queue_iter)
sequences.push_back((*queue_iter)->AsWeakPtr());
for (size_t i = 0; i < sequences.size(); ++i) {
if (!sequences[i].get() || !HasAnimation(sequences[i].get()))
continue;
if (sequences[i]->HasConflictingProperty(sequence->properties())) {
std::unique_ptr<LayerAnimationSequence> removed(
RemoveAnimation(sequences[i].get()));
if (abort)
sequences[i]->Abort(delegate());
else
ProgressAnimationToEnd(sequences[i].get());
}
}
}
void LayerAnimator::ImmediatelySetNewTarget(LayerAnimationSequence* sequence) {
base::WeakPtr<LayerAnimationSequence> weak_sequence_ptr =
sequence->AsWeakPtr();
const bool abort = false;
RemoveAllAnimationsWithACommonProperty(sequence, abort);
if (!weak_sequence_ptr.get())
return;
LayerAnimationSequence* removed = RemoveAnimation(sequence);
DCHECK(removed == nullptr || removed == sequence);
if (!weak_sequence_ptr.get())
return;
ProgressAnimationToEnd(sequence);
if (!weak_sequence_ptr.get())
return;
delete sequence;
}
void LayerAnimator::ImmediatelyAnimateToNewTarget(
LayerAnimationSequence* sequence) {
base::WeakPtr<LayerAnimationSequence> weak_sequence_ptr =
sequence->AsWeakPtr();
const bool abort = true;
RemoveAllAnimationsWithACommonProperty(sequence, abort);
if (!weak_sequence_ptr.get())
return;
AddToQueueIfNotPresent(sequence);
if (!weak_sequence_ptr.get())
return;
StartSequenceImmediately(sequence);
}
void LayerAnimator::EnqueueNewAnimation(LayerAnimationSequence* sequence) {
animation_queue_.push_back(std::unique_ptr<LayerAnimationSequence>(sequence));
ProcessQueue();
}
void LayerAnimator::ReplaceQueuedAnimations(LayerAnimationSequence* sequence) {
base::WeakPtr<LayerAnimationSequence> weak_sequence_ptr =
sequence->AsWeakPtr();
for (size_t i = 0; i < animation_queue_.size();) {
if (!weak_sequence_ptr.get())
break;
PurgeDeletedAnimations();
bool is_running = false;
for (RunningAnimations::const_iterator iter = running_animations_.begin();
iter != running_animations_.end(); ++iter) {
if ((*iter).sequence() == animation_queue_[i].get()) {
is_running = true;
break;
}
}
if (!is_running)
delete RemoveAnimation(animation_queue_[i].get());
else
++i;
}
animation_queue_.push_back(std::unique_ptr<LayerAnimationSequence>(sequence));
ProcessQueue();
}
void LayerAnimator::ProcessQueue() {
bool started_sequence = false;
do {
started_sequence = false;
LayerAnimationElement::AnimatableProperties animated =
LayerAnimationElement::UNKNOWN;
for (RunningAnimations::const_iterator iter = running_animations_.begin();
iter != running_animations_.end(); ++iter) {
if (!(*iter).is_sequence_alive())
continue;
animated |= (*iter).sequence()->properties();
}
std::vector<base::WeakPtr<LayerAnimationSequence> > sequences;
for (AnimationQueue::iterator queue_iter = animation_queue_.begin();
queue_iter != animation_queue_.end(); ++queue_iter)
sequences.push_back((*queue_iter)->AsWeakPtr());
for (size_t i = 0; i < sequences.size(); ++i) {
if (!sequences[i].get() || !HasAnimation(sequences[i].get()))
continue;
if (!sequences[i]->HasConflictingProperty(animated)) {
StartSequenceImmediately(sequences[i].get());
started_sequence = true;
break;
}
animated |= sequences[i]->properties();
}
} while (started_sequence);
}
bool LayerAnimator::StartSequenceImmediately(LayerAnimationSequence* sequence) {
PurgeDeletedAnimations();
for (RunningAnimations::const_iterator iter = running_animations_.begin();
iter != running_animations_.end(); ++iter) {
if ((*iter).sequence()->HasConflictingProperty(sequence->properties()))
return false;
}
base::TimeTicks start_time;
LayerAnimatorCollection* collection = GetLayerAnimatorCollection();
if (is_animating() || adding_animations_)
start_time = last_step_time_;
else if (collection && collection->HasActiveAnimators())
start_time = collection->last_tick_time();
else
start_time = base::TimeTicks::Now();
if (!sequence->animation_group_id())
sequence->set_animation_group_id(cc::AnimationIdProvider::NextGroupId());
running_animations_.push_back(
RunningAnimation(sequence->AsWeakPtr()));
AddToQueueIfNotPresent(sequence);
if (!sequence->waiting_for_group_start() ||
sequence->IsFirstElementThreaded(delegate_)) {
sequence->set_start_time(start_time);
sequence->Start(delegate());
}
Step(start_time);
return true;
}
void LayerAnimator::GetTargetValue(
LayerAnimationElement::TargetValue* target) const {
for (AnimationQueue::const_iterator iter = animation_queue_.begin();
iter != animation_queue_.end(); ++iter) {
(*iter)->GetTargetValue(target);
}
}
void LayerAnimator::OnScheduled(LayerAnimationSequence* sequence) {
sequence_scheduled_callbacks_.Notify(sequence);
for (LayerAnimationObserver& observer : observers_)
sequence->AddObserver(&observer);
sequence->OnScheduled();
}
void LayerAnimator::SetTransitionDuration(base::TimeDelta duration) {
if (is_transition_duration_locked_)
return;
transition_duration_ = duration;
}
void LayerAnimator::ClearAnimationsInternal() {
PurgeDeletedAnimations();
RunningAnimations running_animations_copy = running_animations_;
for (size_t i = 0; i < running_animations_copy.size(); ++i) {
if (!SAFE_INVOKE_BOOL(HasAnimation, running_animations_copy[i]))
continue;
std::unique_ptr<LayerAnimationSequence> removed(
RemoveAnimation(running_animations_copy[i].sequence()));
if (removed.get())
removed->Abort(delegate());
}
DCHECK(running_animations_.empty());
running_animations_.clear();
animation_queue_.clear();
UpdateAnimationState();
}
void LayerAnimator::PurgeDeletedAnimations() {
for (size_t i = 0; i < running_animations_.size();) {
if (!running_animations_[i].is_sequence_alive())
running_animations_.erase(running_animations_.begin() + i);
else
i++;
}
}
LayerAnimatorCollection* LayerAnimator::GetLayerAnimatorCollection() {
return delegate_ ? delegate_->GetLayerAnimatorCollection() : nullptr;
}
void LayerAnimator::NotifyAnimationStarted(base::TimeTicks monotonic_time,
int target_property,
int group) {
OnThreadedAnimationStarted(
monotonic_time, static_cast<cc::TargetProperty::Type>(target_property),
group);
}
LayerAnimator::RunningAnimation::RunningAnimation(
const base::WeakPtr<LayerAnimationSequence>& sequence)
: sequence_(sequence) {
}
LayerAnimator::RunningAnimation::RunningAnimation(
const RunningAnimation& other) = default;
LayerAnimator::RunningAnimation::~RunningAnimation() { }
}