// Copyright (c) 2012 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.
#ifndef UI_COMPOSITOR_LAYER_ANIMATION_SEQUENCE_H_
#define UI_COMPOSITOR_LAYER_ANIMATION_SEQUENCE_H_
#include <vector>
#include "base/gtest_prod_util.h"
#include "base/memory/linked_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/time/time.h"
#include "ui/compositor/compositor_export.h"
#include "ui/compositor/layer_animation_element.h"
namespace ui {
class LayerAnimationDelegate;
class LayerAnimationObserver;
// Contains a collection of layer animation elements to be played one after
// another. Although it has a similar interface to LayerAnimationElement, it is
// not a LayerAnimationElement (i.e., it is not permitted to have a sequence in
// a sequence). Sequences own their elements, and sequences are themselves owned
// by a LayerAnimator.
//
// TODO(vollick) Create a 'blended' sequence for transitioning between
// sequences.
// TODO(vollick) Eventually, the LayerAnimator will switch to a model where new
// work is scheduled rather than calling methods directly. This should make it
// impossible for temporary pointers to running animations to go stale. When
// this happens, there will be no need for LayerAnimationSequences to support
// weak pointers.
class COMPOSITOR_EXPORT LayerAnimationSequence
: public base::SupportsWeakPtr<LayerAnimationSequence> {
public:
LayerAnimationSequence();
// Takes ownership of the given element and adds it to the sequence.
explicit LayerAnimationSequence(LayerAnimationElement* element);
virtual ~LayerAnimationSequence();
// Sets the start time for the animation. This must be called before the
// first call to {Start, IsFinished}. Once the animation is finished, this
// must be called again in order to restart the animation.
void set_start_time(base::TimeTicks start_time) { start_time_ = start_time; }
base::TimeTicks start_time() const { return start_time_; }
// Sets a flag indicating that this sequence will start together with other
// sequences, and at least one of the sequences in this group has a threaded
// first element.
void set_waiting_for_group_start(bool waiting) {
waiting_for_group_start_ = waiting;
}
bool waiting_for_group_start() { return waiting_for_group_start_; }
// This must be called before the first call to Progress. If starting the
// animation involves dispatching to another thread, then this will proceed
// with that dispatch, ultimately resulting in the animation getting an
// effective start time (the time the animation starts on the other thread).
void Start(LayerAnimationDelegate* delegate);
// Updates the delegate to the appropriate value for |now|. Requests a
// redraw if it is required.
void Progress(base::TimeTicks now, LayerAnimationDelegate* delegate);
// Returns true if calling Progress now, with the given time, will finish
// the animation.
bool IsFinished(base::TimeTicks time);
// Updates the delegate to the end of the animation; if this sequence is
// cyclic, updates the delegate to the end of one cycle of the sequence.
void ProgressToEnd(LayerAnimationDelegate* delegate);
// Sets the target value to the value that would have been set had
// the sequence completed. Does nothing if the sequence is cyclic.
void GetTargetValue(LayerAnimationElement::TargetValue* target) const;
// Aborts the given animation.
void Abort(LayerAnimationDelegate* delegate);
// All properties modified by the sequence.
const LayerAnimationElement::AnimatableProperties& properties() const {
return properties_;
}
// Adds an element to the sequence. The sequences takes ownership of this
// element.
void AddElement(LayerAnimationElement* element);
// Sequences can be looped indefinitely.
void set_is_cyclic(bool is_cyclic) { is_cyclic_ = is_cyclic; }
bool is_cyclic() const { return is_cyclic_; }
// Returns true if this sequence has at least one element conflicting with a
// property in |other|.
bool HasConflictingProperty(
const LayerAnimationElement::AnimatableProperties& other) const;
// Returns true if the first element animates on the compositor thread.
bool IsFirstElementThreaded() const;
// Used to identify groups of sequences that are supposed to start together.
// Once started, used to identify the sequence that owns a particular
// threaded animation.
int animation_group_id() const { return animation_group_id_; }
void set_animation_group_id(int id) { animation_group_id_ = id; }
// These functions are used for adding or removing observers from the observer
// list. The observers are notified when animations end.
void AddObserver(LayerAnimationObserver* observer);
void RemoveObserver(LayerAnimationObserver* observer);
// Called when a threaded animation is actually started.
void OnThreadedAnimationStarted(const cc::AnimationEvent& event);
// Called when the animator schedules this sequence.
void OnScheduled();
// Called when the animator is destroyed.
void OnAnimatorDestroyed();
// The last_progressed_fraction of the element most recently progressed by
// by this sequence. Returns 0.0 if no elements have been progressed.
double last_progressed_fraction() const { return last_progressed_fraction_; }
size_t size() const;
LayerAnimationElement* FirstElement() const;
private:
friend class LayerAnimatorTestController;
typedef std::vector<linked_ptr<LayerAnimationElement> > Elements;
FRIEND_TEST_ALL_PREFIXES(LayerAnimatorTest,
ObserverReleasedBeforeAnimationSequenceEnds);
// Notifies the observers that this sequence has been scheduled.
void NotifyScheduled();
// Notifies the observers that this sequence has ended.
void NotifyEnded();
// Notifies the observers that this sequence has been aborted.
void NotifyAborted();
// The currently animating element.
LayerAnimationElement* CurrentElement() const;
// The union of all the properties modified by all elements in the sequence.
LayerAnimationElement::AnimatableProperties properties_;
// The elements in the sequence.
Elements elements_;
// True if the sequence should be looped forever.
bool is_cyclic_;
// These are used when animating to efficiently find the next element.
size_t last_element_;
base::TimeTicks last_start_;
// The start time of the current run of the sequence.
base::TimeTicks start_time_;
// True if this sequence will start together with other sequences, and at
// least one of the sequences in this group has a threaded first element.
bool waiting_for_group_start_;
// Identifies groups of sequences that are supposed to start together.
// Also used to identify the owner of a particular threaded animation; any
// in-progress threaded animation owned by this sequence will have this
// group id.
int animation_group_id_;
// These parties are notified when layer animations end.
ObserverList<LayerAnimationObserver> observers_;
// Tracks the last_progressed_fraction() of the most recently progressed
// element.
double last_progressed_fraction_;
base::WeakPtrFactory<LayerAnimationSequence> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(LayerAnimationSequence);
};
} // namespace ui
#endif // UI_COMPOSITOR_LAYER_ANIMATION_SEQUENCE_H_