Upstream version 5.34.98.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / frame / animation / KeyframeAnimation.cpp
1 /*
2  * Copyright (C) 2007, 2012 Apple 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  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution.
13  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include "config.h"
30 #include "core/frame/animation/KeyframeAnimation.h"
31
32 #include "CSSPropertyNames.h"
33 #include "core/css/resolver/StyleResolver.h"
34 #include "core/events/ThreadLocalEventNames.h"
35 #include "core/frame/UseCounter.h"
36 #include "core/frame/animation/AnimationControllerPrivate.h"
37 #include "core/frame/animation/CSSPropertyAnimation.h"
38 #include "core/frame/animation/CompositeAnimation.h"
39 #include "core/rendering/RenderBoxModelObject.h"
40 #include "core/rendering/style/RenderStyle.h"
41 #include "public/platform/Platform.h"
42
43 using namespace std;
44
45 namespace WebCore {
46
47 KeyframeAnimation::KeyframeAnimation(const CSSAnimationData* animation, RenderObject& renderer, int index, CompositeAnimation* compAnim, RenderStyle& unanimatedStyle)
48     : AnimationBase(animation, renderer, compAnim)
49     , m_keyframes(renderer, animation->name())
50     , m_index(index)
51     , m_startEventDispatched(false)
52     , m_unanimatedStyle(unanimatedStyle)
53 {
54     // Get the keyframe RenderStyles
55     if (m_object && m_object->node() && m_object->node()->isElementNode())
56         m_object->document().ensureStyleResolver().keyframeStylesForAnimation(toElement(m_object->node()), unanimatedStyle, m_keyframes);
57
58     // Update the m_transformFunctionListValid flag based on whether the function lists in the keyframes match.
59     validateTransformFunctionList();
60     checkForMatchingFilterFunctionLists();
61     HashSet<CSSPropertyID>::const_iterator endProperties = m_keyframes.endProperties();
62     for (HashSet<CSSPropertyID>::const_iterator it = m_keyframes.beginProperties(); it != endProperties; ++it)
63         blink::Platform::current()->histogramSparse("WebCore.Animation.CSSProperties", UseCounter::mapCSSPropertyIdToCSSSampleIdForHistogram(*it));
64 }
65
66 KeyframeAnimation::~KeyframeAnimation()
67 {
68     // Make sure to tell the renderer that we are ending. This will make sure any accelerated animations are removed.
69     if (!postActive())
70         endAnimation();
71 }
72
73 void KeyframeAnimation::fetchIntervalEndpointsForProperty(CSSPropertyID property, const RenderStyle*& fromStyle, const RenderStyle*& toStyle, double& prog) const
74 {
75     // Find the first key
76     double elapsedTime = getElapsedTime();
77     if (m_animation->duration() && m_animation->iterationCount() != CSSAnimationData::IterationCountInfinite)
78         elapsedTime = min(elapsedTime, m_animation->duration() * m_animation->iterationCount());
79
80     const double fractionalTime = this->fractionalTime(1, elapsedTime, 0);
81
82     size_t numKeyframes = m_keyframes.size();
83     if (!numKeyframes)
84         return;
85
86     ASSERT(!m_keyframes[0].key());
87     ASSERT(m_keyframes[m_keyframes.size() - 1].key() == 1);
88
89     size_t currentIndex = 0;
90     size_t firstIndex = 0;
91     size_t lastIndex = numKeyframes - 1;
92     size_t distance = numKeyframes;
93
94     // Find keyframe that is closest to elapsed time.
95     while (distance > 1) {
96         currentIndex = (lastIndex + firstIndex) >> 1;
97         double key = m_keyframes[currentIndex].key();
98         distance = lastIndex - currentIndex;
99
100         if (key < fractionalTime) {
101             if (distance < 2)
102                 currentIndex++;
103             firstIndex = currentIndex;
104         } else {
105             lastIndex = currentIndex;
106         }
107     }
108
109     int prevIndex = -1;
110     int nextIndex = -1;
111
112     // Iterate forward to find next keyframe that is used to animate CSS property.
113     for (size_t i = currentIndex; i < numKeyframes; ++i) {
114         const KeyframeValue& keyFrame = m_keyframes[i];
115         if (keyFrame.key() > fractionalTime && keyFrame.containsProperty(property)) {
116             nextIndex = i;
117             break;
118         }
119     }
120
121     // Iterate backward to find previous keyframe.
122     for (int i = currentIndex; i >= 0; --i) {
123         const KeyframeValue& keyFrame = m_keyframes[i];
124         if (keyFrame.key() <= fractionalTime && keyFrame.containsProperty(property)) {
125             prevIndex = i;
126             break;
127         }
128     }
129
130     double scale = 1;
131     double offset = 0;
132
133     if (prevIndex == -1)
134         prevIndex = 0;
135
136     if (nextIndex == -1)
137         nextIndex = numKeyframes - 1;
138
139     const KeyframeValue& prevKeyframe = m_keyframes[prevIndex];
140     const KeyframeValue& nextKeyframe = m_keyframes[nextIndex];
141
142     fromStyle = prevKeyframe.style();
143     toStyle = nextKeyframe.style();
144
145     offset = prevKeyframe.key();
146     scale = 1.0 / (nextKeyframe.key() - prevKeyframe.key());
147     // A scale of infinity is handled in AnimationBase::fractionalTime().
148     ASSERT(scale >= 0 && (!std::isinf(scale) || prevIndex == nextIndex));
149
150     prog = progress(scale, offset, KeyframeValue::timingFunction(*prevKeyframe.style()));
151 }
152
153 void KeyframeAnimation::animate(CompositeAnimation*, RenderObject*, const RenderStyle*, RenderStyle* targetStyle, RefPtr<RenderStyle>& animatedStyle)
154 {
155     // Fire the start timeout if needed
156     fireAnimationEventsIfNeeded();
157
158     // If we have not yet started, we will not have a valid start time, so just start the animation if needed.
159     if (isNew() && m_animation->playState() == AnimPlayStatePlaying)
160         updateStateMachine(AnimationStateInputStartAnimation, -1);
161
162     // If we get this far and the animation is done, it means we are cleaning up a just finished animation.
163     // If so, we need to send back the targetStyle.
164     if (postActive()) {
165         if (!animatedStyle)
166             animatedStyle = const_cast<RenderStyle*>(targetStyle);
167         return;
168     }
169
170     // If we are waiting for the start timer, we don't want to change the style yet.
171     // Special case 1 - if the delay time is 0, then we do want to set the first frame of the
172     // animation right away. This avoids a flash when the animation starts.
173     // Special case 2 - if there is a backwards fill mode, then we want to continue
174     // through to the style blend so that we get the fromStyle.
175     if (waitingToStart() && m_animation->delay() > 0 && !m_animation->fillsBackwards())
176         return;
177
178     // If we have no keyframes, don't animate.
179     if (!m_keyframes.size()) {
180         updateStateMachine(AnimationStateInputEndAnimation, -1);
181         return;
182     }
183
184     // Run a cycle of animation.
185     // We know we will need a new render style, so make one if needed.
186     if (!animatedStyle)
187         animatedStyle = RenderStyle::clone(targetStyle);
188
189     // FIXME: we need to be more efficient about determining which keyframes we are animating between.
190     // We should cache the last pair or something.
191     HashSet<CSSPropertyID>::const_iterator endProperties = m_keyframes.endProperties();
192     for (HashSet<CSSPropertyID>::const_iterator it = m_keyframes.beginProperties(); it != endProperties; ++it) {
193         // Get the from/to styles and progress between
194         const RenderStyle* fromStyle = 0;
195         const RenderStyle* toStyle = 0;
196         double progress = 0.0;
197         fetchIntervalEndpointsForProperty(*it, fromStyle, toStyle, progress);
198
199         bool needsAnim = CSSPropertyAnimation::blendProperties(this, *it, animatedStyle.get(), fromStyle, toStyle, progress);
200         if (!needsAnim)
201             // If we are running an accelerated animation, set a flag in the style
202             // to indicate it. This can be used to make sure we get an updated
203             // style for hit testing, etc.
204             animatedStyle->setIsRunningAcceleratedAnimation();
205     }
206 }
207
208 void KeyframeAnimation::getAnimatedStyle(RefPtr<RenderStyle>& animatedStyle)
209 {
210     // If we're in the delay phase and we're not backwards filling, tell the caller
211     // to use the current style.
212     if (waitingToStart() && m_animation->delay() > 0 && !m_animation->fillsBackwards())
213         return;
214
215     if (!m_keyframes.size())
216         return;
217
218     if (!animatedStyle)
219         animatedStyle = RenderStyle::clone(m_object->style());
220
221     HashSet<CSSPropertyID>::const_iterator endProperties = m_keyframes.endProperties();
222     for (HashSet<CSSPropertyID>::const_iterator it = m_keyframes.beginProperties(); it != endProperties; ++it) {
223         // Get the from/to styles and progress between
224         const RenderStyle* fromStyle = 0;
225         const RenderStyle* toStyle = 0;
226         double progress = 0.0;
227         fetchIntervalEndpointsForProperty(*it, fromStyle, toStyle, progress);
228
229         CSSPropertyAnimation::blendProperties(this, *it, animatedStyle.get(), fromStyle, toStyle, progress);
230     }
231 }
232
233 bool KeyframeAnimation::hasAnimationForProperty(CSSPropertyID property) const
234 {
235     return m_keyframes.containsProperty(property);
236 }
237
238 void KeyframeAnimation::startAnimation(double timeOffset)
239 {
240     if (m_object && m_object->compositingState() == PaintsIntoOwnBacking)
241         m_isAccelerated = toRenderBoxModelObject(m_object)->startAnimation(timeOffset, m_animation.get(), m_keyframes);
242 }
243
244 void KeyframeAnimation::pauseAnimation(double timeOffset)
245 {
246     if (!m_object)
247         return;
248
249     if (m_object && m_object->compositingState() == PaintsIntoOwnBacking && isAccelerated())
250         toRenderBoxModelObject(m_object)->animationPaused(timeOffset, m_keyframes.animationName());
251
252     // Restore the original (unanimated) style
253     if (!paused())
254         setNeedsStyleRecalc(m_object->node());
255 }
256
257 void KeyframeAnimation::endAnimation()
258 {
259     if (!m_object)
260         return;
261
262     if (m_object && m_object->compositingState() == PaintsIntoOwnBacking && isAccelerated())
263         toRenderBoxModelObject(m_object)->animationFinished(m_keyframes.animationName());
264     m_isAccelerated = false;
265
266     // Restore the original (unanimated) style
267     if (!paused())
268         setNeedsStyleRecalc(m_object->node());
269 }
270
271 bool KeyframeAnimation::shouldSendEventForListener(Document::ListenerType listenerType) const
272 {
273     return m_object->document().hasListenerType(listenerType);
274 }
275
276 void KeyframeAnimation::onAnimationStart(double elapsedTime)
277 {
278     sendAnimationEvent(EventTypeNames::animationstart, elapsedTime);
279 }
280
281 void KeyframeAnimation::onAnimationIteration(double elapsedTime)
282 {
283     sendAnimationEvent(EventTypeNames::animationiteration, elapsedTime);
284 }
285
286 void KeyframeAnimation::onAnimationEnd(double elapsedTime)
287 {
288     sendAnimationEvent(EventTypeNames::animationend, elapsedTime);
289     // End the animation if we don't fill forwards. Forward filling
290     // animations are ended properly in the class destructor.
291     if (!m_animation->fillsForwards())
292         endAnimation();
293 }
294
295 bool KeyframeAnimation::sendAnimationEvent(const AtomicString& eventType, double elapsedTime)
296 {
297     Document::ListenerType listenerType;
298     if (eventType == EventTypeNames::animationiteration)
299         listenerType = Document::ANIMATIONITERATION_LISTENER;
300     else if (eventType == EventTypeNames::animationend)
301         listenerType = Document::ANIMATIONEND_LISTENER;
302     else {
303         ASSERT(eventType == EventTypeNames::animationstart);
304         if (m_startEventDispatched)
305             return false;
306         m_startEventDispatched = true;
307         listenerType = Document::ANIMATIONSTART_LISTENER;
308     }
309
310     if (shouldSendEventForListener(listenerType)) {
311         // Dispatch the event
312         RefPtr<Element> element;
313         if (m_object->node() && m_object->node()->isElementNode())
314             element = toElement(m_object->node());
315
316         if (!element)
317             return false;
318
319         // Schedule event handling
320         m_compAnim->animationController()->addEventToDispatch(element, eventType, m_keyframes.animationName(), elapsedTime);
321
322         // Restore the original (unanimated) style
323         if (eventType == EventTypeNames::animationend && element->renderer())
324             setNeedsStyleRecalc(element.get());
325
326         return true; // Did dispatch an event
327     }
328
329     return false; // Did not dispatch an event
330 }
331
332 void KeyframeAnimation::overrideAnimations()
333 {
334     // This will override implicit animations that match the properties in the keyframe animation
335     HashSet<CSSPropertyID>::const_iterator end = m_keyframes.endProperties();
336     for (HashSet<CSSPropertyID>::const_iterator it = m_keyframes.beginProperties(); it != end; ++it)
337         compositeAnimation()->overrideImplicitAnimations(*it);
338 }
339
340 void KeyframeAnimation::resumeOverriddenAnimations()
341 {
342     // This will resume overridden implicit animations
343     HashSet<CSSPropertyID>::const_iterator end = m_keyframes.endProperties();
344     for (HashSet<CSSPropertyID>::const_iterator it = m_keyframes.beginProperties(); it != end; ++it)
345         compositeAnimation()->resumeOverriddenImplicitAnimations(*it);
346 }
347
348 bool KeyframeAnimation::affectsProperty(CSSPropertyID property) const
349 {
350     return m_keyframes.containsProperty(property);
351 }
352
353 void KeyframeAnimation::validateTransformFunctionList()
354 {
355     m_transformFunctionListValid = false;
356
357     if (m_keyframes.size() < 2 || !m_keyframes.containsProperty(CSSPropertyWebkitTransform))
358         return;
359
360     // Empty transforms match anything, so find the first non-empty entry as the reference
361     size_t numKeyframes = m_keyframes.size();
362     size_t firstNonEmptyTransformKeyframeIndex = numKeyframes;
363
364     for (size_t i = 0; i < numKeyframes; ++i) {
365         const KeyframeValue& currentKeyframe = m_keyframes[i];
366         if (currentKeyframe.style()->transform().operations().size()) {
367             firstNonEmptyTransformKeyframeIndex = i;
368             break;
369         }
370     }
371
372     if (firstNonEmptyTransformKeyframeIndex == numKeyframes)
373         return;
374
375     const TransformOperations* firstVal = &m_keyframes[firstNonEmptyTransformKeyframeIndex].style()->transform();
376
377     // See if the keyframes are valid
378     for (size_t i = firstNonEmptyTransformKeyframeIndex + 1; i < numKeyframes; ++i) {
379         const KeyframeValue& currentKeyframe = m_keyframes[i];
380         const TransformOperations* val = &currentKeyframe.style()->transform();
381
382         // An emtpy transform list matches anything.
383         if (val->operations().isEmpty())
384             continue;
385
386         if (!firstVal->operationsMatch(*val))
387             return;
388     }
389
390     // Keyframes are valid
391     m_transformFunctionListValid = true;
392 }
393
394 void KeyframeAnimation::checkForMatchingFilterFunctionLists()
395 {
396     m_filterFunctionListsMatch = false;
397
398     if (m_keyframes.size() < 2 || !m_keyframes.containsProperty(CSSPropertyWebkitFilter))
399         return;
400
401     // Empty filters match anything, so find the first non-empty entry as the reference
402     size_t numKeyframes = m_keyframes.size();
403     size_t firstNonEmptyFilterKeyframeIndex = numKeyframes;
404
405     for (size_t i = 0; i < numKeyframes; ++i) {
406         const KeyframeValue& currentKeyframe = m_keyframes[i];
407         if (currentKeyframe.style()->filter().operations().size()) {
408             firstNonEmptyFilterKeyframeIndex = i;
409             break;
410         }
411     }
412
413     if (firstNonEmptyFilterKeyframeIndex == numKeyframes)
414         return;
415
416     const FilterOperations* firstVal = &m_keyframes[firstNonEmptyFilterKeyframeIndex].style()->filter();
417
418     for (size_t i = firstNonEmptyFilterKeyframeIndex + 1; i < numKeyframes; ++i) {
419         const KeyframeValue& currentKeyframe = m_keyframes[i];
420         const FilterOperations* val = &currentKeyframe.style()->filter();
421
422         if (!firstVal->canInterpolateWith(*val))
423             return;
424     }
425
426     m_filterFunctionListsMatch = true;
427 }
428
429 double KeyframeAnimation::timeToNextService()
430 {
431     double t = AnimationBase::timeToNextService();
432     if (t != 0 || preActive())
433         return t;
434
435     // A return value of 0 means we need service. But if we only have accelerated animations we
436     // only need service at the end of the transition
437     HashSet<CSSPropertyID>::const_iterator endProperties = m_keyframes.endProperties();
438     bool acceleratedPropertiesOnly = true;
439
440     for (HashSet<CSSPropertyID>::const_iterator it = m_keyframes.beginProperties(); it != endProperties; ++it) {
441         if (!CSSPropertyAnimation::animationOfPropertyIsAccelerated(*it) || !isAccelerated()) {
442             acceleratedPropertiesOnly = false;
443             break;
444         }
445     }
446
447     if (acceleratedPropertiesOnly) {
448         bool isLooping;
449         getTimeToNextEvent(t, isLooping);
450     }
451
452     return t;
453 }
454
455 } // namespace WebCore