blob: d76e9821a5e26b35256ce2b2663b69e5a27deabf [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "cc/animation/animation_timeline.h"
#include <algorithm>
#include "cc/animation/animation_host.h"
#include "cc/animation/animation_player.h"
namespace cc {
scoped_refptr<AnimationTimeline> AnimationTimeline::Create(int id) {
return make_scoped_refptr(new AnimationTimeline(id));
}
AnimationTimeline::AnimationTimeline(int id)
: id_(id),
animation_host_(),
needs_push_properties_(false),
is_impl_only_(false) {}
AnimationTimeline::~AnimationTimeline() {
for (auto& kv : id_to_player_map_)
kv.second->SetAnimationTimeline(nullptr);
}
scoped_refptr<AnimationTimeline> AnimationTimeline::CreateImplInstance() const {
scoped_refptr<AnimationTimeline> timeline = AnimationTimeline::Create(id());
return timeline;
}
void AnimationTimeline::SetAnimationHost(AnimationHost* animation_host) {
if (animation_host_ == animation_host)
return;
animation_host_ = animation_host;
for (auto& kv : id_to_player_map_)
kv.second->SetAnimationHost(animation_host);
SetNeedsPushProperties();
}
void AnimationTimeline::AttachPlayer(scoped_refptr<AnimationPlayer> player) {
DCHECK(player->id());
player->SetAnimationHost(animation_host_);
player->SetAnimationTimeline(this);
id_to_player_map_.insert(std::make_pair(player->id(), std::move(player)));
SetNeedsPushProperties();
}
void AnimationTimeline::DetachPlayer(scoped_refptr<AnimationPlayer> player) {
DCHECK(player->id());
ErasePlayer(player);
id_to_player_map_.erase(player->id());
SetNeedsPushProperties();
}
AnimationPlayer* AnimationTimeline::GetPlayerById(int player_id) const {
auto f = id_to_player_map_.find(player_id);
return f == id_to_player_map_.end() ? nullptr : f->second.get();
}
void AnimationTimeline::ClearPlayers() {
for (auto& kv : id_to_player_map_)
ErasePlayer(kv.second);
id_to_player_map_.clear();
SetNeedsPushProperties();
}
void AnimationTimeline::SetNeedsPushProperties() {
needs_push_properties_ = true;
if (animation_host_)
animation_host_->SetNeedsPushProperties();
}
void AnimationTimeline::PushPropertiesTo(AnimationTimeline* timeline_impl) {
if (needs_push_properties_) {
needs_push_properties_ = false;
PushAttachedPlayersToImplThread(timeline_impl);
RemoveDetachedPlayersFromImplThread(timeline_impl);
PushPropertiesToImplThread(timeline_impl);
}
}
void AnimationTimeline::PushAttachedPlayersToImplThread(
AnimationTimeline* timeline_impl) const {
for (auto& kv : id_to_player_map_) {
auto& player = kv.second;
AnimationPlayer* player_impl = timeline_impl->GetPlayerById(player->id());
if (player_impl)
continue;
scoped_refptr<AnimationPlayer> to_add = player->CreateImplInstance();
timeline_impl->AttachPlayer(to_add.get());
}
}
void AnimationTimeline::RemoveDetachedPlayersFromImplThread(
AnimationTimeline* timeline_impl) const {
IdToPlayerMap& players_impl = timeline_impl->id_to_player_map_;
// Erase all the impl players which |this| doesn't have.
for (auto it = players_impl.begin(); it != players_impl.end();) {
if (GetPlayerById(it->second->id())) {
++it;
} else {
timeline_impl->ErasePlayer(it->second);
it = players_impl.erase(it);
}
}
}
void AnimationTimeline::ErasePlayer(scoped_refptr<AnimationPlayer> player) {
if (player->element_animations())
player->DetachElement();
player->SetAnimationTimeline(nullptr);
player->SetAnimationHost(nullptr);
}
void AnimationTimeline::PushPropertiesToImplThread(
AnimationTimeline* timeline_impl) {
for (auto& kv : id_to_player_map_) {
AnimationPlayer* player = kv.second.get();
if (player->needs_push_properties()) {
AnimationPlayer* player_impl = timeline_impl->GetPlayerById(player->id());
if (player_impl)
player->PushPropertiesTo(player_impl);
}
}
}
} // namespace cc