a0e600b242bd1f468fc4f56025b31619eb4fc11c
[WebKit-https.git] / Source / WebCore / platform / graphics / chromium / cc / CCLayerAnimationController.cpp
1 /*
2  * Copyright (C) 2012 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1.  Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  * 2.  Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16  * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
17  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  */
24
25 #include "config.h"
26
27 #include "cc/CCLayerAnimationController.h"
28
29 #include "GraphicsLayer.h" // for KeyframeValueList
30 #include "TransformationMatrix.h"
31 #include "cc/CCActiveAnimation.h"
32 #include "cc/CCKeyframedAnimationCurve.h"
33 #include <wtf/CurrentTime.h>
34 #include <wtf/HashMap.h>
35
36 namespace WebCore {
37
38 namespace {
39
40 template <class Value, class Keyframe, class Curve>
41 void appendKeyframe(Curve& curve, double keyTime, const Value* value, PassOwnPtr<CCTimingFunction> timingFunction)
42 {
43     curve.addKeyframe(Keyframe::create(keyTime, value->value(), timingFunction));
44 }
45
46 template <>
47 void appendKeyframe<TransformAnimationValue, CCTransformKeyframe, CCKeyframedTransformAnimationCurve>(CCKeyframedTransformAnimationCurve& curve, double keyTime, const TransformAnimationValue* value, PassOwnPtr<CCTimingFunction> timingFunction)
48 {
49     curve.addKeyframe(CCTransformKeyframe::create(keyTime, *value->value(), timingFunction));
50 }
51
52 template <class Value, class Keyframe, class Curve>
53 PassOwnPtr<CCActiveAnimation> createActiveAnimation(const KeyframeValueList& valueList, const Animation* animation, size_t animationId, size_t groupId, double timeOffset, CCActiveAnimation::TargetProperty targetProperty)
54 {
55     // FIXME: add support for different directions.
56     if (animation && animation->isDirectionSet() && animation->direction() == Animation::AnimationDirectionAlternate)
57         return nullptr;
58
59     // FIXME: add support for fills forwards and fills backwards
60     if (animation && animation->isFillModeSet() && (animation->fillsForwards() || animation->fillsBackwards()))
61         return nullptr;
62
63     OwnPtr<Curve> curve = Curve::create();
64     Vector<Keyframe> keyframes;
65
66     for (size_t i = 0; i < valueList.size(); i++) {
67         const Value* originalValue = static_cast<const Value*>(valueList.at(i));
68
69         OwnPtr<CCTimingFunction> timingFunction;
70         if (originalValue->timingFunction()) {
71             switch (originalValue->timingFunction()->type()) {
72             case TimingFunction::StepsFunction:
73                 // FIXME: add support for steps timing function.
74                 return nullptr;
75             case TimingFunction::LinearFunction:
76                 // Don't set the timing function. Keyframes are interpolated linearly if there is no timing function.
77                 break;
78             case TimingFunction::CubicBezierFunction:
79                 const CubicBezierTimingFunction* originalTimingFunction = static_cast<const CubicBezierTimingFunction*>(originalValue->timingFunction());
80                 timingFunction = CCCubicBezierTimingFunction::create(originalTimingFunction->x1(), originalTimingFunction->y1(), originalTimingFunction->x2(), originalTimingFunction->y2());
81                 break;
82             } // switch
83         } else
84             timingFunction = CCEaseTimingFunction::create();
85
86         double duration = (animation && animation->isDurationSet()) ? animation->duration() : 1;
87         appendKeyframe<Value, Keyframe, Curve>(*curve, originalValue->keyTime() * duration, originalValue, timingFunction.release());
88     }
89
90     OwnPtr<CCActiveAnimation> anim = CCActiveAnimation::create(curve.release(), animationId, groupId, targetProperty);
91
92     ASSERT(anim.get());
93
94     if (anim.get()) {
95         int iterations = (animation && animation->isIterationCountSet()) ? animation->iterationCount() : 1;
96         anim->setIterations(iterations);
97     }
98
99     return anim.release();
100 }
101
102 } // namepace
103
104 CCLayerAnimationController::CCLayerAnimationController(CCLayerAnimationControllerClient* client)
105     : m_client(client)
106 {
107 }
108
109 CCLayerAnimationController::~CCLayerAnimationController()
110 {
111 }
112
113 PassOwnPtr<CCLayerAnimationController> CCLayerAnimationController::create(CCLayerAnimationControllerClient* client)
114 {
115     return adoptPtr(new CCLayerAnimationController(client));
116 }
117
118 bool CCLayerAnimationController::addAnimation(const KeyframeValueList& valueList, const IntSize&, const Animation* animation, int animationId, int groupId, double timeOffset)
119 {
120     if (!animation)
121         return false;
122
123     OwnPtr<CCActiveAnimation> toAdd;
124     if (valueList.property() == AnimatedPropertyWebkitTransform)
125         toAdd = createActiveAnimation<TransformAnimationValue, CCTransformKeyframe, CCKeyframedTransformAnimationCurve>(valueList, animation, animationId, groupId, timeOffset, CCActiveAnimation::Transform);
126     else if (valueList.property() == AnimatedPropertyOpacity)
127         toAdd = createActiveAnimation<FloatAnimationValue, CCFloatKeyframe, CCKeyframedFloatAnimationCurve>(valueList, animation, animationId, groupId, timeOffset, CCActiveAnimation::Opacity);
128
129     if (toAdd.get()) {
130         m_activeAnimations.append(toAdd.release());
131         return true;
132     }
133
134     return false;
135 }
136
137 void CCLayerAnimationController::pauseAnimation(int animationId, double timeOffset)
138 {
139     for (size_t i = 0; i < m_activeAnimations.size(); ++i) {
140         if (m_activeAnimations[i]->id() == animationId)
141             m_activeAnimations[i]->setRunState(CCActiveAnimation::Paused, timeOffset);
142     }
143 }
144
145 void CCLayerAnimationController::removeAnimation(int animationId)
146 {
147     for (size_t i = 0; i < m_activeAnimations.size();) {
148         if (m_activeAnimations[i]->id() == animationId)
149             m_activeAnimations.remove(i);
150         else
151             i++;
152     }
153 }
154
155 // According to render layer backing, these are for testing only.
156 void CCLayerAnimationController::suspendAnimations(double time)
157 {
158 }
159
160 // Looking at GraphicsLayerCA, this appears to be the analog to suspendAnimations, which is for testing.
161 void CCLayerAnimationController::resumeAnimations()
162 {
163 }
164
165 // Ensures that the list of active animations on the main thread and the impl thread
166 // are kept in sync.
167 void CCLayerAnimationController::pushAnimationUpdatesTo(CCLayerAnimationController* controllerImpl)
168 {
169     pushNewAnimationsToImplThread(controllerImpl);
170     removeAnimationsCompletedOnMainThread(controllerImpl);
171 }
172
173 void CCLayerAnimationController::animate(double monotonicTime, CCAnimationEventsVector* events)
174 {
175     startAnimationsWaitingForNextTick(monotonicTime, events);
176     startAnimationsWaitingForStartTime(monotonicTime, events);
177     startAnimationsWaitingForTargetAvailability(monotonicTime, events);
178     resolveConflicts(monotonicTime);
179     tickAnimations(monotonicTime);
180     purgeFinishedAnimations(events);
181     startAnimationsWaitingForTargetAvailability(monotonicTime, events);
182 }
183
184 void CCLayerAnimationController::add(PassOwnPtr<CCActiveAnimation> animation)
185 {
186     m_activeAnimations.append(animation);
187 }
188
189 CCActiveAnimation* CCLayerAnimationController::getActiveAnimation(int groupId, CCActiveAnimation::TargetProperty targetProperty)
190 {
191     for (size_t i = 0; i < m_activeAnimations.size(); ++i)
192         if (m_activeAnimations[i]->group() == groupId && m_activeAnimations[i]->targetProperty() == targetProperty)
193             return m_activeAnimations[i].get();
194     return 0;
195 }
196
197 bool CCLayerAnimationController::hasActiveAnimation() const
198 {
199     for (size_t i = 0; i < m_activeAnimations.size(); ++i) {
200         if (m_activeAnimations[i]->runState() != CCActiveAnimation::Finished && m_activeAnimations[i]->runState() != CCActiveAnimation::Aborted)
201             return true;
202     }
203     return false;
204 }
205
206 bool CCLayerAnimationController::isAnimatingProperty(CCActiveAnimation::TargetProperty targetProperty) const
207 {
208     for (size_t i = 0; i < m_activeAnimations.size(); ++i) {
209         if (m_activeAnimations[i]->runState() != CCActiveAnimation::Finished && m_activeAnimations[i]->runState() != CCActiveAnimation::Aborted && m_activeAnimations[i]->targetProperty() == targetProperty)
210             return true;
211     }
212     return false;
213 }
214
215 void CCLayerAnimationController::pushNewAnimationsToImplThread(CCLayerAnimationController* controllerImpl)
216 {
217     // Any new animations owned by the main thread's controller are cloned and adde to the impl thread's controller.
218     for (size_t i = 0; i < m_activeAnimations.size(); ++i) {
219         if (!controllerImpl->getActiveAnimation(m_activeAnimations[i]->group(), m_activeAnimations[i]->targetProperty())) {
220             OwnPtr<CCActiveAnimation> toAdd(m_activeAnimations[i]->cloneForImplThread());
221             // If the animation is already in progress -- set it to be waiting until the target is available.
222             // That way, it will have a chance to start on the impl thread. Otherwise, we will never tick at the
223             // very beginning of the animation.
224             if (toAdd->runState() == CCActiveAnimation::Running || toAdd->runState() == CCActiveAnimation::Paused)
225                 toAdd->setRunState(CCActiveAnimation::WaitingForTargetAvailability, 0);
226             controllerImpl->add(toAdd.release());
227         }
228     }
229 }
230
231 void CCLayerAnimationController::removeAnimationsCompletedOnMainThread(CCLayerAnimationController* controllerImpl)
232 {
233     // Delete all impl thread animations for which there is no corresponding main thread animation.
234     // Each iteration, controller->m_activeAnimations.size() is decremented or i is incremented
235     // guaranteeing progress towards loop termination.
236     for (size_t i = 0; i < controllerImpl->m_activeAnimations.size();) {
237         CCActiveAnimation* current = getActiveAnimation(controllerImpl->m_activeAnimations[i]->group(), controllerImpl->m_activeAnimations[i]->targetProperty());
238         if (!current)
239             controllerImpl->m_activeAnimations.remove(i);
240         else
241             i++;
242     }
243 }
244
245 void CCLayerAnimationController::startAnimationsWaitingForNextTick(double monotonicTime, CCAnimationEventsVector* events)
246 {
247     for (size_t i = 0; i < m_activeAnimations.size(); ++i) {
248         if (m_activeAnimations[i]->runState() == CCActiveAnimation::WaitingForNextTick) {
249             m_activeAnimations[i]->setRunState(CCActiveAnimation::Running, monotonicTime);
250             m_activeAnimations[i]->setStartTime(monotonicTime);
251             if (events)
252                 events->append(CCAnimationStartedEvent::create(m_client->id(), m_activeAnimations[i]->targetProperty()));
253         }
254     }
255 }
256
257 void CCLayerAnimationController::startAnimationsWaitingForStartTime(double monotonicTime, CCAnimationEventsVector* events)
258 {
259     for (size_t i = 0; i < m_activeAnimations.size(); ++i) {
260         if (m_activeAnimations[i]->runState() == CCActiveAnimation::WaitingForStartTime && m_activeAnimations[i]->startTime() <= monotonicTime) {
261             m_activeAnimations[i]->setRunState(CCActiveAnimation::Running, monotonicTime);
262             if (events)
263                 events->append(CCAnimationStartedEvent::create(m_client->id(), m_activeAnimations[i]->targetProperty()));
264         }
265     }
266 }
267
268 void CCLayerAnimationController::startAnimationsWaitingForTargetAvailability(double monotonicTime, CCAnimationEventsVector* events)
269 {
270     // First collect running properties.
271     TargetProperties blockedProperties;
272     for (size_t i = 0; i < m_activeAnimations.size(); ++i) {
273         if (m_activeAnimations[i]->runState() == CCActiveAnimation::Running || m_activeAnimations[i]->runState() == CCActiveAnimation::Finished)
274             blockedProperties.add(m_activeAnimations[i]->targetProperty());
275     }
276
277     for (size_t i = 0; i < m_activeAnimations.size(); ++i) {
278         if (m_activeAnimations[i]->runState() == CCActiveAnimation::WaitingForTargetAvailability) {
279             // Collect all properties for animations with the same group id (they should all also be in the list of animations).
280             TargetProperties enqueuedProperties;
281             enqueuedProperties.add(m_activeAnimations[i]->targetProperty());
282             for (size_t j = i + 1; j < m_activeAnimations.size(); ++j) {
283                 if (m_activeAnimations[i]->group() == m_activeAnimations[j]->group())
284                     enqueuedProperties.add(m_activeAnimations[j]->targetProperty());
285             }
286
287             // Check to see if intersection of the list of properties affected by the group and the list of currently
288             // blocked properties is null. In any case, the group's target properties need to be added to the list
289             // of blocked properties.
290             bool nullIntersection = true;
291             for (TargetProperties::iterator pIter = enqueuedProperties.begin(); pIter != enqueuedProperties.end(); ++pIter) {
292                 if (!blockedProperties.add(*pIter).second)
293                     nullIntersection = false;
294             }
295
296             // If the intersection is null, then we are free to start the animations in the group.
297             if (nullIntersection) {
298                 m_activeAnimations[i]->setRunState(CCActiveAnimation::Running, monotonicTime);
299                 m_activeAnimations[i]->setStartTime(monotonicTime);
300                 if (events)
301                     events->append(CCAnimationStartedEvent::create(m_client->id(), m_activeAnimations[i]->targetProperty()));
302                 for (size_t j = i + 1; j < m_activeAnimations.size(); ++j) {
303                     if (m_activeAnimations[i]->group() == m_activeAnimations[j]->group()) {
304                         m_activeAnimations[j]->setRunState(CCActiveAnimation::Running, monotonicTime);
305                         m_activeAnimations[j]->setStartTime(monotonicTime);
306                     }
307                 }
308             }
309         }
310     }
311 }
312
313 void CCLayerAnimationController::resolveConflicts(double monotonicTime)
314 {
315     // Find any animations that are animating the same property and resolve the
316     // confict. We could eventually blend, but for now we'll just abort the
317     // previous animation (where 'previous' means: (1) has a prior start time or
318     // (2) has an equal start time, but was added to the queue earlier, i.e.,
319     // has a lower index in m_activeAnimations).
320     for (size_t i = 0; i < m_activeAnimations.size(); ++i) {
321         if (m_activeAnimations[i]->runState() == CCActiveAnimation::Running) {
322             for (size_t j = i + 1; j < m_activeAnimations.size(); ++j) {
323                 if (m_activeAnimations[j]->runState() == CCActiveAnimation::Running && m_activeAnimations[i]->targetProperty() == m_activeAnimations[j]->targetProperty()) {
324                     if (m_activeAnimations[i]->startTime() > m_activeAnimations[j]->startTime())
325                         m_activeAnimations[j]->setRunState(CCActiveAnimation::Aborted, monotonicTime);
326                     else
327                         m_activeAnimations[i]->setRunState(CCActiveAnimation::Aborted, monotonicTime);
328                 }
329             }
330         }
331     }
332 }
333
334 void CCLayerAnimationController::purgeFinishedAnimations(CCAnimationEventsVector* events)
335 {
336     // Each iteration, m_activeAnimations.size() decreases or i increments,
337     // guaranteeing progress towards loop termination.
338     size_t i = 0;
339     while (i < m_activeAnimations.size()) {
340         int groupId = m_activeAnimations[i]->group();
341         bool allAnimsWithSameIdAreFinished = false;
342         if (m_activeAnimations[i]->isFinished()) {
343             allAnimsWithSameIdAreFinished = true;
344             for (size_t j = 0; j < m_activeAnimations.size(); ++j) {
345                 if (groupId == m_activeAnimations[j]->group() && !m_activeAnimations[j]->isFinished()) {
346                     allAnimsWithSameIdAreFinished = false;
347                     break;
348                 }
349             }
350         }
351         if (allAnimsWithSameIdAreFinished) {
352             // We now need to remove all animations with the same group id as groupId
353             // (and send along animation finished notifications, if necessary).
354             // Each iteration, m_activeAnimations.size() decreases or j increments,
355             // guaranteeing progress towards loop termination. Also, we are guaranteed
356             // to remove at least one active animation.
357             for (size_t j = i; j < m_activeAnimations.size();) {
358                 if (groupId != m_activeAnimations[j]->group())
359                     j++;
360                 else {
361                     if (events) {
362                         switch (m_activeAnimations[j]->targetProperty()) {
363                         case CCActiveAnimation::Opacity:
364                             events->append(CCFloatAnimationFinishedEvent::create(m_client->id(), CCActiveAnimation::Opacity, m_client->opacity()));
365                             break;
366                         case CCActiveAnimation::Transform:
367                             events->append(CCTransformAnimationFinishedEvent::create(m_client->id(), CCActiveAnimation::Transform, m_client->transform()));
368                             break;
369                         }
370                     }
371                     m_activeAnimations.remove(j);
372                 }
373             }
374         } else
375             i++;
376     }
377 }
378
379 void CCLayerAnimationController::tickAnimations(double monotonicTime)
380 {
381     for (size_t i = 0; i < m_activeAnimations.size(); ++i) {
382         if (m_activeAnimations[i]->runState() == CCActiveAnimation::Running) {
383             double trimmed = m_activeAnimations[i]->trimTimeToCurrentIteration(monotonicTime);
384
385             switch (m_activeAnimations[i]->targetProperty()) {
386
387             case CCActiveAnimation::Transform: {
388                 const CCTransformAnimationCurve* transformAnimationCurve = m_activeAnimations[i]->curve()->toTransformAnimationCurve();
389                 const TransformationMatrix matrix = transformAnimationCurve->getValue(trimmed, m_client->bounds());
390                 if (m_activeAnimations[i]->isFinishedAt(monotonicTime))
391                     m_activeAnimations[i]->setRunState(CCActiveAnimation::Finished, monotonicTime);
392
393                 m_client->setTransformFromAnimation(matrix);
394                 break;
395             }
396
397             case CCActiveAnimation::Opacity: {
398                 const CCFloatAnimationCurve* floatAnimationCurve = m_activeAnimations[i]->curve()->toFloatAnimationCurve();
399                 const float opacity = floatAnimationCurve->getValue(trimmed);
400                 if (m_activeAnimations[i]->isFinishedAt(monotonicTime))
401                     m_activeAnimations[i]->setRunState(CCActiveAnimation::Finished, monotonicTime);
402
403                 m_client->setOpacityFromAnimation(opacity);
404                 break;
405             }
406
407             }
408         }
409     }
410 }
411
412 } // namespace WebCore