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