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