layer_animation_sequence.cc revision c2e0dbddbe15c98d52c4786dac06cb8952a8ae6d
1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "ui/compositor/layer_animation_sequence.h"
6
7#include <algorithm>
8#include <iterator>
9
10#include "base/debug/trace_event.h"
11#include "ui/compositor/layer_animation_delegate.h"
12#include "ui/compositor/layer_animation_element.h"
13#include "ui/compositor/layer_animation_observer.h"
14
15namespace ui {
16
17LayerAnimationSequence::LayerAnimationSequence()
18    : is_cyclic_(false),
19      last_element_(0),
20      waiting_for_group_start_(false),
21      animation_group_id_(0),
22      last_progressed_fraction_(0.0) {
23}
24
25LayerAnimationSequence::LayerAnimationSequence(LayerAnimationElement* element)
26    : is_cyclic_(false),
27      last_element_(0),
28      waiting_for_group_start_(false),
29      animation_group_id_(0),
30      last_progressed_fraction_(0.0) {
31  AddElement(element);
32}
33
34LayerAnimationSequence::~LayerAnimationSequence() {
35  FOR_EACH_OBSERVER(LayerAnimationObserver,
36                    observers_,
37                    DetachedFromSequence(this, true));
38}
39
40void LayerAnimationSequence::Start(LayerAnimationDelegate* delegate) {
41  DCHECK(start_time_ != base::TimeTicks());
42  last_progressed_fraction_ = 0.0;
43  if (elements_.empty())
44    return;
45
46  elements_[0]->set_requested_start_time(start_time_);
47  elements_[0]->Start(delegate, animation_group_id_);
48}
49
50void LayerAnimationSequence::Progress(base::TimeTicks now,
51                                      LayerAnimationDelegate* delegate) {
52  DCHECK(start_time_ != base::TimeTicks());
53  bool redraw_required = false;
54
55  if (elements_.empty())
56    return;
57
58  if (last_element_ == 0)
59    last_start_ = start_time_;
60
61  size_t current_index = last_element_ % elements_.size();
62  base::TimeDelta element_duration;
63  while (is_cyclic_ || last_element_ < elements_.size()) {
64    elements_[current_index]->set_requested_start_time(last_start_);
65    if (!elements_[current_index]->IsFinished(now, &element_duration))
66      break;
67
68    // Let the element we're passing finish.
69    if (elements_[current_index]->ProgressToEnd(delegate))
70      redraw_required = true;
71    last_start_ += element_duration;
72    ++last_element_;
73    last_progressed_fraction_ =
74        elements_[current_index]->last_progressed_fraction();
75    current_index = last_element_ % elements_.size();
76  }
77
78  if (is_cyclic_ || last_element_ < elements_.size()) {
79    if (!elements_[current_index]->Started())
80      elements_[current_index]->Start(delegate, animation_group_id_);
81    if (elements_[current_index]->Progress(now, delegate))
82      redraw_required = true;
83    last_progressed_fraction_ =
84        elements_[current_index]->last_progressed_fraction();
85  }
86
87  // Since the delegate may be deleted due to the notifications below, it is
88  // important that we schedule a draw before sending them.
89  if (redraw_required)
90    delegate->ScheduleDrawForAnimation();
91
92  if (!is_cyclic_ && last_element_ == elements_.size()) {
93    last_element_ = 0;
94    waiting_for_group_start_ = false;
95    animation_group_id_ = 0;
96    NotifyEnded();
97  }
98}
99
100bool LayerAnimationSequence::IsFinished(base::TimeTicks time) {
101  if (is_cyclic_ || waiting_for_group_start_)
102    return false;
103
104  if (elements_.empty())
105    return true;
106
107  if (last_element_ == 0)
108    last_start_ = start_time_;
109
110  base::TimeTicks current_start = last_start_;
111  size_t current_index = last_element_;
112  base::TimeDelta element_duration;
113  while (current_index < elements_.size()) {
114    elements_[current_index]->set_requested_start_time(current_start);
115    if (!elements_[current_index]->IsFinished(time, &element_duration))
116      break;
117
118    current_start += element_duration;
119    ++current_index;
120  }
121
122  return (current_index == elements_.size());
123}
124
125void LayerAnimationSequence::ProgressToEnd(LayerAnimationDelegate* delegate) {
126  bool redraw_required = false;
127
128  if (elements_.empty())
129    return;
130
131  size_t current_index = last_element_ % elements_.size();
132  while (current_index < elements_.size()) {
133    if (elements_[current_index]->ProgressToEnd(delegate))
134      redraw_required = true;
135    last_progressed_fraction_ =
136        elements_[current_index]->last_progressed_fraction();
137    ++current_index;
138    ++last_element_;
139  }
140
141  if (redraw_required)
142    delegate->ScheduleDrawForAnimation();
143
144  if (!is_cyclic_) {
145    last_element_ = 0;
146    waiting_for_group_start_ = false;
147    animation_group_id_ = 0;
148    NotifyEnded();
149  }
150}
151
152void LayerAnimationSequence::GetTargetValue(
153    LayerAnimationElement::TargetValue* target) const {
154  if (is_cyclic_)
155    return;
156
157  for (size_t i = last_element_; i < elements_.size(); ++i)
158    elements_[i]->GetTargetValue(target);
159}
160
161void LayerAnimationSequence::Abort(LayerAnimationDelegate* delegate) {
162  size_t current_index = last_element_ % elements_.size();
163  while (current_index < elements_.size()) {
164    elements_[current_index]->Abort(delegate);
165    ++current_index;
166  }
167  last_element_ = 0;
168  waiting_for_group_start_ = false;
169  NotifyAborted();
170}
171
172void LayerAnimationSequence::AddElement(LayerAnimationElement* element) {
173  properties_.insert(element->properties().begin(),
174                     element->properties().end());
175  elements_.push_back(make_linked_ptr(element));
176}
177
178bool LayerAnimationSequence::HasConflictingProperty(
179    const LayerAnimationElement::AnimatableProperties& other) const {
180  LayerAnimationElement::AnimatableProperties intersection;
181  std::insert_iterator<LayerAnimationElement::AnimatableProperties> ii(
182      intersection, intersection.begin());
183  std::set_intersection(properties_.begin(), properties_.end(),
184                        other.begin(), other.end(),
185                        ii);
186  return (intersection.size() > 0);
187}
188
189bool LayerAnimationSequence::IsFirstElementThreaded() const {
190  if (!elements_.empty())
191    return elements_[0]->IsThreaded();
192
193  return false;
194}
195
196void LayerAnimationSequence::AddObserver(LayerAnimationObserver* observer) {
197  if (!observers_.HasObserver(observer)) {
198    observers_.AddObserver(observer);
199    observer->AttachedToSequence(this);
200  }
201}
202
203void LayerAnimationSequence::RemoveObserver(LayerAnimationObserver* observer) {
204  observers_.RemoveObserver(observer);
205  observer->DetachedFromSequence(this, true);
206}
207
208void LayerAnimationSequence::OnThreadedAnimationStarted(
209    const cc::AnimationEvent& event) {
210  if (elements_.empty() || event.group_id != animation_group_id_)
211    return;
212
213  size_t current_index = last_element_ % elements_.size();
214  const LayerAnimationElement::AnimatableProperties& element_properties =
215    elements_[current_index]->properties();
216  LayerAnimationElement::AnimatableProperty event_property =
217      LayerAnimationElement::ToAnimatableProperty(event.target_property);
218  DCHECK(element_properties.find(event_property) != element_properties.end());
219  elements_[current_index]->set_effective_start_time(
220      base::TimeTicks::FromInternalValue(
221          event.monotonic_time * base::Time::kMicrosecondsPerSecond));
222}
223
224void LayerAnimationSequence::OnScheduled() {
225  NotifyScheduled();
226}
227
228void LayerAnimationSequence::OnAnimatorDestroyed() {
229  if (observers_.might_have_observers()) {
230    ObserverListBase<LayerAnimationObserver>::Iterator it(observers_);
231    LayerAnimationObserver* obs;
232    while ((obs = it.GetNext()) != NULL) {
233      if (!obs->RequiresNotificationWhenAnimatorDestroyed()) {
234        // Remove the observer, but do not allow notifications to be sent.
235        observers_.RemoveObserver(obs);
236        obs->DetachedFromSequence(this, false);
237      }
238    }
239  }
240}
241
242void LayerAnimationSequence::NotifyScheduled() {
243  FOR_EACH_OBSERVER(LayerAnimationObserver,
244                    observers_,
245                    OnLayerAnimationScheduled(this));
246}
247
248void LayerAnimationSequence::NotifyEnded() {
249  FOR_EACH_OBSERVER(LayerAnimationObserver,
250                    observers_,
251                    OnLayerAnimationEnded(this));
252}
253
254void LayerAnimationSequence::NotifyAborted() {
255  FOR_EACH_OBSERVER(LayerAnimationObserver,
256                    observers_,
257                    OnLayerAnimationAborted(this));
258}
259
260LayerAnimationElement* LayerAnimationSequence::CurrentElement() {
261  if (elements_.empty())
262    return NULL;
263
264  size_t current_index = last_element_ % elements_.size();
265  return elements_[current_index].get();
266}
267
268}  // namespace ui
269