OLD | NEW |
| (Empty) |
1 // Copyright 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 "config.h" | |
6 | |
7 #include "CCLayerAnimationController.h" | |
8 | |
9 #include "CCActiveAnimation.h" | |
10 #include "CCKeyframedAnimationCurve.h" | |
11 #include <public/WebTransformationMatrix.h> | |
12 #include <wtf/CurrentTime.h> | |
13 #include <wtf/HashMap.h> | |
14 | |
15 using WebKit::WebTransformationMatrix; | |
16 | |
17 namespace cc { | |
18 | |
19 CCLayerAnimationController::CCLayerAnimationController(CCLayerAnimationControlle
rClient* client) | |
20 : m_forceSync(false) | |
21 , m_client(client) | |
22 { | |
23 } | |
24 | |
25 CCLayerAnimationController::~CCLayerAnimationController() | |
26 { | |
27 } | |
28 | |
29 scoped_ptr<CCLayerAnimationController> CCLayerAnimationController::create(CCLaye
rAnimationControllerClient* client) | |
30 { | |
31 return make_scoped_ptr(new CCLayerAnimationController(client)); | |
32 } | |
33 | |
34 void CCLayerAnimationController::pauseAnimation(int animationId, double timeOffs
et) | |
35 { | |
36 for (size_t i = 0; i < m_activeAnimations.size(); ++i) { | |
37 if (m_activeAnimations[i]->id() == animationId) | |
38 m_activeAnimations[i]->setRunState(CCActiveAnimation::Paused, timeOf
fset + m_activeAnimations[i]->startTime()); | |
39 } | |
40 } | |
41 | |
42 void CCLayerAnimationController::removeAnimation(int animationId) | |
43 { | |
44 for (size_t i = 0; i < m_activeAnimations.size();) { | |
45 if (m_activeAnimations[i]->id() == animationId) | |
46 m_activeAnimations.remove(i); | |
47 else | |
48 i++; | |
49 } | |
50 } | |
51 | |
52 void CCLayerAnimationController::removeAnimation(int animationId, CCActiveAnimat
ion::TargetProperty targetProperty) | |
53 { | |
54 for (size_t i = 0; i < m_activeAnimations.size();) { | |
55 if (m_activeAnimations[i]->id() == animationId && m_activeAnimations[i]-
>targetProperty() == targetProperty) | |
56 m_activeAnimations.remove(i); | |
57 else | |
58 i++; | |
59 } | |
60 } | |
61 | |
62 // According to render layer backing, these are for testing only. | |
63 void CCLayerAnimationController::suspendAnimations(double monotonicTime) | |
64 { | |
65 for (size_t i = 0; i < m_activeAnimations.size(); ++i) { | |
66 if (!m_activeAnimations[i]->isFinished()) | |
67 m_activeAnimations[i]->setRunState(CCActiveAnimation::Paused, monoto
nicTime); | |
68 } | |
69 } | |
70 | |
71 // Looking at GraphicsLayerCA, this appears to be the analog to suspendAnimation
s, which is for testing. | |
72 void CCLayerAnimationController::resumeAnimations(double monotonicTime) | |
73 { | |
74 for (size_t i = 0; i < m_activeAnimations.size(); ++i) { | |
75 if (m_activeAnimations[i]->runState() == CCActiveAnimation::Paused) | |
76 m_activeAnimations[i]->setRunState(CCActiveAnimation::Running, monot
onicTime); | |
77 } | |
78 } | |
79 | |
80 // Ensures that the list of active animations on the main thread and the impl th
read | |
81 // are kept in sync. | |
82 void CCLayerAnimationController::pushAnimationUpdatesTo(CCLayerAnimationControll
er* controllerImpl) | |
83 { | |
84 if (m_forceSync) { | |
85 replaceImplThreadAnimations(controllerImpl); | |
86 m_forceSync = false; | |
87 } else { | |
88 purgeAnimationsMarkedForDeletion(); | |
89 pushNewAnimationsToImplThread(controllerImpl); | |
90 | |
91 // Remove finished impl side animations only after pushing, | |
92 // and only after the animations are deleted on the main thread | |
93 // this insures we will never push an animation twice. | |
94 removeAnimationsCompletedOnMainThread(controllerImpl); | |
95 | |
96 pushPropertiesToImplThread(controllerImpl); | |
97 } | |
98 } | |
99 | |
100 void CCLayerAnimationController::animate(double monotonicTime, CCAnimationEvents
Vector* events) | |
101 { | |
102 startAnimationsWaitingForNextTick(monotonicTime, events); | |
103 startAnimationsWaitingForStartTime(monotonicTime, events); | |
104 startAnimationsWaitingForTargetAvailability(monotonicTime, events); | |
105 resolveConflicts(monotonicTime); | |
106 tickAnimations(monotonicTime); | |
107 markAnimationsForDeletion(monotonicTime, events); | |
108 startAnimationsWaitingForTargetAvailability(monotonicTime, events); | |
109 } | |
110 | |
111 void CCLayerAnimationController::addAnimation(scoped_ptr<CCActiveAnimation> anim
ation) | |
112 { | |
113 m_activeAnimations.append(animation.Pass()); | |
114 } | |
115 | |
116 CCActiveAnimation* CCLayerAnimationController::getActiveAnimation(int groupId, C
CActiveAnimation::TargetProperty targetProperty) const | |
117 { | |
118 for (size_t i = 0; i < m_activeAnimations.size(); ++i) | |
119 if (m_activeAnimations[i]->group() == groupId && m_activeAnimations[i]->
targetProperty() == targetProperty) | |
120 return m_activeAnimations[i]; | |
121 return 0; | |
122 } | |
123 | |
124 CCActiveAnimation* CCLayerAnimationController::getActiveAnimation(CCActiveAnimat
ion::TargetProperty targetProperty) const | |
125 { | |
126 for (size_t i = 0; i < m_activeAnimations.size(); ++i) { | |
127 size_t index = m_activeAnimations.size() - i - 1; | |
128 if (m_activeAnimations[index]->targetProperty() == targetProperty) | |
129 return m_activeAnimations[index]; | |
130 } | |
131 return 0; | |
132 } | |
133 | |
134 bool CCLayerAnimationController::hasActiveAnimation() const | |
135 { | |
136 for (size_t i = 0; i < m_activeAnimations.size(); ++i) { | |
137 if (!m_activeAnimations[i]->isFinished()) | |
138 return true; | |
139 } | |
140 return false; | |
141 } | |
142 | |
143 bool CCLayerAnimationController::isAnimatingProperty(CCActiveAnimation::TargetPr
operty targetProperty) const | |
144 { | |
145 for (size_t i = 0; i < m_activeAnimations.size(); ++i) { | |
146 if (m_activeAnimations[i]->runState() != CCActiveAnimation::Finished &&
m_activeAnimations[i]->runState() != CCActiveAnimation::Aborted && m_activeAnima
tions[i]->targetProperty() == targetProperty) | |
147 return true; | |
148 } | |
149 return false; | |
150 } | |
151 | |
152 void CCLayerAnimationController::notifyAnimationStarted(const CCAnimationEvent&
event) | |
153 { | |
154 for (size_t i = 0; i < m_activeAnimations.size(); ++i) { | |
155 if (m_activeAnimations[i]->group() == event.groupId && m_activeAnimation
s[i]->targetProperty() == event.targetProperty && m_activeAnimations[i]->needsSy
nchronizedStartTime()) { | |
156 m_activeAnimations[i]->setNeedsSynchronizedStartTime(false); | |
157 m_activeAnimations[i]->setStartTime(event.monotonicTime); | |
158 return; | |
159 } | |
160 } | |
161 } | |
162 | |
163 void CCLayerAnimationController::setClient(CCLayerAnimationControllerClient* cli
ent) | |
164 { | |
165 m_client = client; | |
166 } | |
167 | |
168 void CCLayerAnimationController::pushNewAnimationsToImplThread(CCLayerAnimationC
ontroller* controllerImpl) const | |
169 { | |
170 // Any new animations owned by the main thread's controller are cloned and a
dde to the impl thread's controller. | |
171 for (size_t i = 0; i < m_activeAnimations.size(); ++i) { | |
172 // If the animation is already running on the impl thread, there is no n
eed to copy it over. | |
173 if (controllerImpl->getActiveAnimation(m_activeAnimations[i]->group(), m
_activeAnimations[i]->targetProperty())) | |
174 continue; | |
175 | |
176 // If the animation is not running on the impl thread, it does not neces
sarily mean that it needs | |
177 // to be copied over and started; it may have already finished. In this
case, the impl thread animation | |
178 // will have already notified that it has started and the main thread an
imation will no longer need | |
179 // a synchronized start time. | |
180 if (!m_activeAnimations[i]->needsSynchronizedStartTime()) | |
181 continue; | |
182 | |
183 // The new animation should be set to run as soon as possible. | |
184 CCActiveAnimation::RunState initialRunState = CCActiveAnimation::Waiting
ForTargetAvailability; | |
185 double startTime = 0; | |
186 scoped_ptr<CCActiveAnimation> toAdd(m_activeAnimations[i]->cloneAndIniti
alize(CCActiveAnimation::ControllingInstance, initialRunState, startTime)); | |
187 ASSERT(!toAdd->needsSynchronizedStartTime()); | |
188 controllerImpl->addAnimation(toAdd.Pass()); | |
189 } | |
190 } | |
191 | |
192 void CCLayerAnimationController::removeAnimationsCompletedOnMainThread(CCLayerAn
imationController* controllerImpl) const | |
193 { | |
194 // Delete all impl thread animations for which there is no corresponding mai
n thread animation. | |
195 // Each iteration, controller->m_activeAnimations.size() is decremented or i
is incremented | |
196 // guaranteeing progress towards loop termination. | |
197 for (size_t i = 0; i < controllerImpl->m_activeAnimations.size();) { | |
198 CCActiveAnimation* current = getActiveAnimation(controllerImpl->m_active
Animations[i]->group(), controllerImpl->m_activeAnimations[i]->targetProperty())
; | |
199 if (!current) | |
200 controllerImpl->m_activeAnimations.remove(i); | |
201 else | |
202 i++; | |
203 } | |
204 } | |
205 | |
206 void CCLayerAnimationController::pushPropertiesToImplThread(CCLayerAnimationCont
roller* controllerImpl) const | |
207 { | |
208 for (size_t i = 0; i < m_activeAnimations.size(); ++i) { | |
209 CCActiveAnimation* currentImpl = controllerImpl->getActiveAnimation(m_ac
tiveAnimations[i]->group(), m_activeAnimations[i]->targetProperty()); | |
210 if (currentImpl) | |
211 m_activeAnimations[i]->pushPropertiesTo(currentImpl); | |
212 } | |
213 } | |
214 | |
215 void CCLayerAnimationController::startAnimationsWaitingForNextTick(double monoto
nicTime, CCAnimationEventsVector* events) | |
216 { | |
217 for (size_t i = 0; i < m_activeAnimations.size(); ++i) { | |
218 if (m_activeAnimations[i]->runState() == CCActiveAnimation::WaitingForNe
xtTick) { | |
219 m_activeAnimations[i]->setRunState(CCActiveAnimation::Running, monot
onicTime); | |
220 if (!m_activeAnimations[i]->hasSetStartTime()) | |
221 m_activeAnimations[i]->setStartTime(monotonicTime); | |
222 if (events) | |
223 events->push_back(CCAnimationEvent(CCAnimationEvent::Started, m_
client->id(), m_activeAnimations[i]->group(), m_activeAnimations[i]->targetPrope
rty(), monotonicTime)); | |
224 } | |
225 } | |
226 } | |
227 | |
228 void CCLayerAnimationController::startAnimationsWaitingForStartTime(double monot
onicTime, CCAnimationEventsVector* events) | |
229 { | |
230 for (size_t i = 0; i < m_activeAnimations.size(); ++i) { | |
231 if (m_activeAnimations[i]->runState() == CCActiveAnimation::WaitingForSt
artTime && m_activeAnimations[i]->startTime() <= monotonicTime) { | |
232 m_activeAnimations[i]->setRunState(CCActiveAnimation::Running, monot
onicTime); | |
233 if (events) | |
234 events->push_back(CCAnimationEvent(CCAnimationEvent::Started, m_
client->id(), m_activeAnimations[i]->group(), m_activeAnimations[i]->targetPrope
rty(), monotonicTime)); | |
235 } | |
236 } | |
237 } | |
238 | |
239 void CCLayerAnimationController::startAnimationsWaitingForTargetAvailability(dou
ble monotonicTime, CCAnimationEventsVector* events) | |
240 { | |
241 // First collect running properties. | |
242 TargetProperties blockedProperties; | |
243 for (size_t i = 0; i < m_activeAnimations.size(); ++i) { | |
244 if (m_activeAnimations[i]->runState() == CCActiveAnimation::Running || m
_activeAnimations[i]->runState() == CCActiveAnimation::Finished) | |
245 blockedProperties.insert(m_activeAnimations[i]->targetProperty()); | |
246 } | |
247 | |
248 for (size_t i = 0; i < m_activeAnimations.size(); ++i) { | |
249 if (m_activeAnimations[i]->runState() == CCActiveAnimation::WaitingForTa
rgetAvailability) { | |
250 // Collect all properties for animations with the same group id (the
y should all also be in the list of animations). | |
251 TargetProperties enqueuedProperties; | |
252 enqueuedProperties.insert(m_activeAnimations[i]->targetProperty()); | |
253 for (size_t j = i + 1; j < m_activeAnimations.size(); ++j) { | |
254 if (m_activeAnimations[i]->group() == m_activeAnimations[j]->gro
up()) | |
255 enqueuedProperties.insert(m_activeAnimations[j]->targetPrope
rty()); | |
256 } | |
257 | |
258 // Check to see if intersection of the list of properties affected b
y the group and the list of currently | |
259 // blocked properties is null. In any case, the group's target prope
rties need to be added to the list | |
260 // of blocked properties. | |
261 bool nullIntersection = true; | |
262 for (TargetProperties::iterator pIter = enqueuedProperties.begin();
pIter != enqueuedProperties.end(); ++pIter) { | |
263 if (!blockedProperties.insert(*pIter).second) | |
264 nullIntersection = false; | |
265 } | |
266 | |
267 // If the intersection is null, then we are free to start the animat
ions in the group. | |
268 if (nullIntersection) { | |
269 m_activeAnimations[i]->setRunState(CCActiveAnimation::Running, m
onotonicTime); | |
270 if (!m_activeAnimations[i]->hasSetStartTime()) | |
271 m_activeAnimations[i]->setStartTime(monotonicTime); | |
272 if (events) | |
273 events->push_back(CCAnimationEvent(CCAnimationEvent::Started
, m_client->id(), m_activeAnimations[i]->group(), m_activeAnimations[i]->targetP
roperty(), monotonicTime)); | |
274 for (size_t j = i + 1; j < m_activeAnimations.size(); ++j) { | |
275 if (m_activeAnimations[i]->group() == m_activeAnimations[j]-
>group()) { | |
276 m_activeAnimations[j]->setRunState(CCActiveAnimation::Ru
nning, monotonicTime); | |
277 if (!m_activeAnimations[j]->hasSetStartTime()) | |
278 m_activeAnimations[j]->setStartTime(monotonicTime); | |
279 } | |
280 } | |
281 } | |
282 } | |
283 } | |
284 } | |
285 | |
286 void CCLayerAnimationController::resolveConflicts(double monotonicTime) | |
287 { | |
288 // Find any animations that are animating the same property and resolve the | |
289 // confict. We could eventually blend, but for now we'll just abort the | |
290 // previous animation (where 'previous' means: (1) has a prior start time or | |
291 // (2) has an equal start time, but was added to the queue earlier, i.e., | |
292 // has a lower index in m_activeAnimations). | |
293 for (size_t i = 0; i < m_activeAnimations.size(); ++i) { | |
294 if (m_activeAnimations[i]->runState() == CCActiveAnimation::Running) { | |
295 for (size_t j = i + 1; j < m_activeAnimations.size(); ++j) { | |
296 if (m_activeAnimations[j]->runState() == CCActiveAnimation::Runn
ing && m_activeAnimations[i]->targetProperty() == m_activeAnimations[j]->targetP
roperty()) { | |
297 if (m_activeAnimations[i]->startTime() > m_activeAnimations[
j]->startTime()) | |
298 m_activeAnimations[j]->setRunState(CCActiveAnimation::Ab
orted, monotonicTime); | |
299 else | |
300 m_activeAnimations[i]->setRunState(CCActiveAnimation::Ab
orted, monotonicTime); | |
301 } | |
302 } | |
303 } | |
304 } | |
305 } | |
306 | |
307 void CCLayerAnimationController::markAnimationsForDeletion(double monotonicTime,
CCAnimationEventsVector* events) | |
308 { | |
309 for (size_t i = 0; i < m_activeAnimations.size(); i++) { | |
310 int groupId = m_activeAnimations[i]->group(); | |
311 bool allAnimsWithSameIdAreFinished = false; | |
312 // If an animation is finished, and not already marked for deletion, | |
313 // Find out if all other animations in the same group are also finished. | |
314 if (m_activeAnimations[i]->isFinished()) { | |
315 allAnimsWithSameIdAreFinished = true; | |
316 for (size_t j = 0; j < m_activeAnimations.size(); ++j) { | |
317 if (groupId == m_activeAnimations[j]->group() && !m_activeAnimat
ions[j]->isFinished()) { | |
318 allAnimsWithSameIdAreFinished = false; | |
319 break; | |
320 } | |
321 } | |
322 } | |
323 if (allAnimsWithSameIdAreFinished) { | |
324 // We now need to remove all animations with the same group id as gr
oupId | |
325 // (and send along animation finished notifications, if necessary). | |
326 for (size_t j = i; j < m_activeAnimations.size(); j++) { | |
327 if (groupId == m_activeAnimations[j]->group()) { | |
328 if (events) | |
329 events->push_back(CCAnimationEvent(CCAnimationEvent::Fin
ished, m_client->id(), m_activeAnimations[j]->group(), m_activeAnimations[j]->ta
rgetProperty(), monotonicTime)); | |
330 m_activeAnimations[j]->setRunState(CCActiveAnimation::Waitin
gForDeletion, monotonicTime); | |
331 } | |
332 } | |
333 } | |
334 } | |
335 } | |
336 | |
337 void CCLayerAnimationController::purgeAnimationsMarkedForDeletion() | |
338 { | |
339 for (size_t i = 0; i < m_activeAnimations.size();) { | |
340 if (m_activeAnimations[i]->runState() == CCActiveAnimation::WaitingForDe
letion) | |
341 m_activeAnimations.remove(i); | |
342 else | |
343 i++; | |
344 } | |
345 } | |
346 | |
347 void CCLayerAnimationController::replaceImplThreadAnimations(CCLayerAnimationCon
troller* controllerImpl) const | |
348 { | |
349 controllerImpl->m_activeAnimations.clear(); | |
350 for (size_t i = 0; i < m_activeAnimations.size(); ++i) { | |
351 scoped_ptr<CCActiveAnimation> toAdd; | |
352 if (m_activeAnimations[i]->needsSynchronizedStartTime()) { | |
353 // We haven't received an animation started notification yet, so it | |
354 // is important that we add it in a 'waiting' and not 'running' stat
e. | |
355 CCActiveAnimation::RunState initialRunState = CCActiveAnimation::Wai
tingForTargetAvailability; | |
356 double startTime = 0; | |
357 toAdd = m_activeAnimations[i]->cloneAndInitialize(CCActiveAnimation:
:ControllingInstance, initialRunState, startTime).Pass(); | |
358 } else | |
359 toAdd = m_activeAnimations[i]->clone(CCActiveAnimation::ControllingI
nstance).Pass(); | |
360 | |
361 controllerImpl->addAnimation(toAdd.Pass()); | |
362 } | |
363 } | |
364 | |
365 void CCLayerAnimationController::tickAnimations(double monotonicTime) | |
366 { | |
367 for (size_t i = 0; i < m_activeAnimations.size(); ++i) { | |
368 if (m_activeAnimations[i]->runState() == CCActiveAnimation::Running || m
_activeAnimations[i]->runState() == CCActiveAnimation::Paused) { | |
369 double trimmed = m_activeAnimations[i]->trimTimeToCurrentIteration(m
onotonicTime); | |
370 | |
371 // Animation assumes its initial value until it gets the synchronize
d start time | |
372 // from the impl thread and can start ticking. | |
373 if (m_activeAnimations[i]->needsSynchronizedStartTime()) | |
374 trimmed = 0; | |
375 | |
376 switch (m_activeAnimations[i]->targetProperty()) { | |
377 | |
378 case CCActiveAnimation::Transform: { | |
379 const CCTransformAnimationCurve* transformAnimationCurve = m_act
iveAnimations[i]->curve()->toTransformAnimationCurve(); | |
380 const WebTransformationMatrix matrix = transformAnimationCurve->
getValue(trimmed); | |
381 if (m_activeAnimations[i]->isFinishedAt(monotonicTime)) | |
382 m_activeAnimations[i]->setRunState(CCActiveAnimation::Finish
ed, monotonicTime); | |
383 | |
384 m_client->setTransformFromAnimation(matrix); | |
385 break; | |
386 } | |
387 | |
388 case CCActiveAnimation::Opacity: { | |
389 const CCFloatAnimationCurve* floatAnimationCurve = m_activeAnima
tions[i]->curve()->toFloatAnimationCurve(); | |
390 const float opacity = floatAnimationCurve->getValue(trimmed); | |
391 if (m_activeAnimations[i]->isFinishedAt(monotonicTime)) | |
392 m_activeAnimations[i]->setRunState(CCActiveAnimation::Finish
ed, monotonicTime); | |
393 | |
394 m_client->setOpacityFromAnimation(opacity); | |
395 break; | |
396 } | |
397 | |
398 // Do nothing for sentinel value. | |
399 case CCActiveAnimation::TargetPropertyEnumSize: | |
400 ASSERT_NOT_REACHED(); | |
401 | |
402 } | |
403 } | |
404 } | |
405 } | |
406 | |
407 } // namespace cc | |
OLD | NEW |