blob: c265c641349b7ff90122ecaed7a33f979c4940cb [file] [log] [blame]
// Copyright 2015 The Cobalt Authors. All Rights Reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.
#include <memory>
#include <set>
#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "base/memory/ref_counted.h"
#include "base/optional.h"
#include "base/time/time.h"
#include "cobalt/script/wrappable.h"
#include "cobalt/web_animations/animation_effect_read_only.h"
#include "cobalt/web_animations/animation_timeline.h"
namespace cobalt {
namespace web_animations {
class AnimationSet;
// Animations are represented in the Web Animations API by the Animation
// interface.
// This class introduces levers to pause/play/reverse an animation. The
// Animation object provides functionality for converting from timeline time
// to the animation's local time, given its current state (e.g. start time,
// is the animation paused, etc...). Additionally, it also links to the
// underlying effect which contains the rest of the data needed to fully
// specify an effect animation.
class Animation : public script::Wrappable {
// Most of the internal Animation information is stored here in
// Animation::Data. This separate Data class exists to make it possible to
// copy Animation information out of the non-thread-safe ref-counted
// script-wrappable Animation object. The class BakedAnimation takes
// advantage of the Data object by storing an independent immutable instance
// of the animation data that does not reference script objects and can be
// passed to other threads.
class Data {
Data() : playback_rate_(1.0) {}
const base::Optional<base::TimeDelta>& start_time() const {
return start_time_;
void set_start_time(const base::Optional<base::TimeDelta>& start_time) {
start_time_ = start_time;
double playback_rate() const { return playback_rate_; }
void set_playback_rate(double playback_rate) {
playback_rate_ = playback_rate;
// Converts the animation's timeline's time into the animation's local
// time, which takes into account this animation's start_time().
base::Optional<base::TimeDelta> ComputeLocalTimeFromTimelineTime(
const base::Optional<base::TimeDelta>& timeline_time) const;
base::Optional<base::TimeDelta> ComputeTimelineTimeFromLocalTime(
const base::Optional<base::TimeDelta>& local_time) const;
base::Optional<base::TimeDelta> start_time_;
double playback_rate_;
// EventHandler objects can be created via Animation::AttachEventHandler().
// Once created, they represent the connection of a set of Animation event
// callbacks which may get called as the animation is updated, until the
// EventHandler is destructed.
class EventHandler {
EventHandler(const scoped_refptr<Animation>& animation,
const base::Closure& on_enter_after_phase)
: animation_(animation), on_enter_after_phase_(on_enter_after_phase) {}
~EventHandler() { animation_->RemoveEventHandler(this); }
const base::Closure& on_enter_after_phase() const {
return on_enter_after_phase_;
// The animation we are handling events from.
scoped_refptr<Animation> animation_;
// Called when the Animation's effect enters the "after phase".
base::Closure on_enter_after_phase_;
Animation(const scoped_refptr<AnimationEffectReadOnly>& effect,
const scoped_refptr<AnimationTimeline>& timeline);
// Web API: Animation
const scoped_refptr<AnimationEffectReadOnly>& effect() const {
return effect_;
void set_effect(const scoped_refptr<AnimationEffectReadOnly>& effect) {
effect_ = effect;
const scoped_refptr<AnimationTimeline>& timeline() const { return timeline_; }
void set_timeline(const scoped_refptr<AnimationTimeline>& timeline);
base::Optional<double> start_time() const {
return data_.start_time()
? base::Optional<double>(data_.start_time()->InMillisecondsF())
: base::nullopt;
void set_start_time(const base::Optional<double>& start_time) {
if (!start_time) {
} else {
base::Optional<double> current_time() const;
base::Optional<base::TimeDelta> current_time_as_time_delta() const;
void set_current_time(const base::Optional<double>& current_time);
double playback_rate() const { return data_.playback_rate(); }
void set_playback_rate(double playback_rate) {
void Cancel();
void Finish() {}
void Play();
void Pause() {}
void Reverse() {}
// Custom, not in any spec.
const Data& data() const { return data_; }
// Connects a set of events (currently only the event where the Animation's
// effect enters its "after phase") to the provided callbacks, and returns
// an object that represents the connection.
std::unique_ptr<EventHandler> AttachEventHandler(
const base::Closure& on_enter_after_phase);
void TraceMembers(script::Tracer* tracer) override;
~Animation() override;
// This will be called by EventHandler's destructor.
void RemoveEventHandler(EventHandler* handler);
// This method will update all timing-based tasks based on the current state
// of the Animation object (and all referenced objects) when this function
// is called.
void UpdatePendingTasks();
// Called when the animation's effect enters its after phase.
void OnEnterAfterPhase();
// It is possible for an Animation to be inserted into a AnimationSet, such
// that is not discoverable by Web APIs, so we track all our references from
// all AnimationSets so that we can remove ourselves from them when the
// animation is ready to destroy itself.
void OnAddedToAnimationSet(const scoped_refptr<AnimationSet>& set);
// Called by AnimationSet when removed from an AnimationSet.
void OnRemovedFromAnimationSet(const scoped_refptr<AnimationSet>& set);
scoped_refptr<AnimationEffectReadOnly> effect_;
scoped_refptr<AnimationTimeline> timeline_;
// A list of animation sets that contain this animation.
std::set<scoped_refptr<AnimationSet>> contained_in_animation_sets_;
Data data_;
// A list of event handlers that are interested in receiving callbacks when
// animation events occur.
std::set<EventHandler*> event_handlers_;
// When a specific animation event occurs, we will copy event_handlers_ into
// this and then call each event one by one. This way we can manage the set
// being modified as event handlers are called.
std::set<EventHandler*> event_handlers_being_called_;
// When active, this task will be setup to fire after we enter the after
// phase.
std::unique_ptr<TimedTaskQueue::Task> on_enter_after_phase_;
friend class EventHandler;
// So that we can track which AnimationSets this animation is added to.
friend class AnimationSet;
} // namespace web_animations
} // namespace cobalt