Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / animation / Animation.cpp
1 /*
2  * Copyright (C) 2013 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 are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #include "config.h"
32 #include "core/animation/Animation.h"
33
34 #include "bindings/v8/Dictionary.h"
35 #include "core/animation/ActiveAnimations.h"
36 #include "core/animation/AnimationHelpers.h"
37 #include "core/animation/CompositorAnimations.h"
38 #include "core/animation/DocumentTimeline.h"
39 #include "core/animation/KeyframeEffectModel.h"
40 #include "core/animation/Player.h"
41 #include "core/css/parser/BisonCSSParser.h"
42 #include "core/css/resolver/StyleResolver.h"
43 #include "core/dom/Element.h"
44 #include "core/rendering/RenderLayer.h"
45 #include "wtf/text/StringBuilder.h"
46
47 namespace WebCore {
48
49 PassRefPtr<Animation> Animation::create(PassRefPtr<Element> target, PassRefPtr<AnimationEffect> effect, const Timing& timing, Priority priority, PassOwnPtr<EventDelegate> eventDelegate)
50 {
51     return adoptRef(new Animation(target, effect, timing, priority, eventDelegate));
52 }
53
54 static bool checkDocumentAndRenderer(Element* element)
55 {
56     if (!element->inActiveDocument())
57         return false;
58     element->document().updateStyleIfNeeded();
59     if (!element->renderer())
60         return false;
61     return true;
62 }
63
64 PassRefPtr<Animation> Animation::create(Element* element, Vector<Dictionary> keyframeDictionaryVector, Dictionary timingInput)
65 {
66     ASSERT(RuntimeEnabledFeatures::webAnimationsAPIEnabled());
67
68     // FIXME: This test will not be neccessary once resolution of keyframe values occurs at
69     // animation application time.
70     if (!checkDocumentAndRenderer(element))
71         return 0;
72
73     return createUnsafe(element, keyframeDictionaryVector, timingInput);
74 }
75
76 PassRefPtr<Animation> Animation::create(Element* element, Vector<Dictionary> keyframeDictionaryVector, double timingInput)
77 {
78     ASSERT(RuntimeEnabledFeatures::webAnimationsAPIEnabled());
79
80     // FIXME: This test will not be neccessary once resolution of keyframe values occurs at
81     // animation application time.
82     if (!checkDocumentAndRenderer(element))
83         return 0;
84
85     return createUnsafe(element, keyframeDictionaryVector, timingInput);
86 }
87
88 PassRefPtr<Animation> Animation::create(Element* element, Vector<Dictionary> keyframeDictionaryVector)
89 {
90     ASSERT(RuntimeEnabledFeatures::webAnimationsAPIEnabled());
91
92     // FIXME: This test will not be neccessary once resolution of keyframe values occurs at
93     // animation application time.
94     if (!checkDocumentAndRenderer(element))
95         return 0;
96
97     return createUnsafe(element, keyframeDictionaryVector);
98 }
99
100 void Animation::setStartDelay(Timing& timing, double startDelay)
101 {
102     if (std::isfinite(startDelay))
103         timing.startDelay = startDelay;
104     else
105         timing.startDelay = 0;
106 }
107
108 void Animation::setEndDelay(Timing& timing, double endDelay)
109 {
110     if (std::isfinite(endDelay))
111         timing.endDelay = endDelay;
112     else
113         timing.endDelay = 0;
114 }
115
116 void Animation::setFillMode(Timing& timing, String fillMode)
117 {
118     if (fillMode == "none") {
119         timing.fillMode = Timing::FillModeNone;
120     } else if (fillMode == "backwards") {
121         timing.fillMode = Timing::FillModeBackwards;
122     } else if (fillMode == "both") {
123         timing.fillMode = Timing::FillModeBoth;
124     } else if (fillMode == "forwards") {
125         timing.fillMode = Timing::FillModeForwards;
126     } else {
127         timing.fillMode = Timing::FillModeAuto;
128     }
129 }
130
131 void Animation::setIterationStart(Timing& timing, double iterationStart)
132 {
133     if (!std::isnan(iterationStart) && !std::isinf(iterationStart))
134         timing.iterationStart = std::max<double>(iterationStart, 0);
135     else
136         timing.iterationStart = 0;
137 }
138
139 void Animation::setIterationCount(Timing& timing, double iterationCount)
140 {
141     if (!std::isnan(iterationCount))
142         timing.iterationCount = std::max<double>(iterationCount, 0);
143     else
144         timing.iterationCount = 1;
145 }
146
147 void Animation::setIterationDuration(Timing& timing, double iterationDuration)
148 {
149     if (!std::isnan(iterationDuration) && iterationDuration >= 0)
150         timing.iterationDuration = iterationDuration;
151     else
152         timing.iterationDuration = std::numeric_limits<double>::quiet_NaN();
153 }
154
155 void Animation::setPlaybackRate(Timing& timing, double playbackRate)
156 {
157     if (!std::isnan(playbackRate) && !std::isinf(playbackRate))
158         timing.playbackRate = playbackRate;
159     else
160         timing.playbackRate = 1;
161 }
162
163 void Animation::setPlaybackDirection(Timing& timing, String direction)
164 {
165     if (direction == "reverse") {
166         timing.direction = Timing::PlaybackDirectionReverse;
167     } else if (direction == "alternate") {
168         timing.direction = Timing::PlaybackDirectionAlternate;
169     } else if (direction == "alternate-reverse") {
170         timing.direction = Timing::PlaybackDirectionAlternateReverse;
171     } else {
172         timing.direction = Timing::PlaybackDirectionNormal;
173     }
174 }
175
176 void Animation::setTimingFunction(Timing& timing, String timingFunctionString)
177 {
178     RefPtr<CSSValue> timingFunctionValue = BisonCSSParser::parseAnimationTimingFunctionValue(timingFunctionString);
179     if (timingFunctionValue) {
180         RefPtr<TimingFunction> timingFunction = CSSToStyleMap::animationTimingFunction(timingFunctionValue.get(), false);
181         if (timingFunction) {
182             timing.timingFunction = timingFunction;
183             return;
184         }
185     }
186     timing.timingFunction = LinearTimingFunction::create();
187 }
188
189 void Animation::populateTiming(Timing& timing, Dictionary timingInputDictionary)
190 {
191     // FIXME: This method needs to be refactored to handle invalid
192     // null, NaN, Infinity values better.
193     // See: http://www.w3.org/TR/WebIDL/#es-double
194     double startDelay = 0;
195     timingInputDictionary.get("delay", startDelay);
196     setStartDelay(timing, startDelay);
197
198     double endDelay = 0;
199     timingInputDictionary.get("endDelay", endDelay);
200     setEndDelay(timing, endDelay);
201
202     String fillMode;
203     timingInputDictionary.get("fill", fillMode);
204     setFillMode(timing, fillMode);
205
206     double iterationStart = 0;
207     timingInputDictionary.get("iterationStart", iterationStart);
208     setIterationStart(timing, iterationStart);
209
210     double iterationCount = 1;
211     timingInputDictionary.get("iterations", iterationCount);
212     setIterationCount(timing, iterationCount);
213
214     v8::Local<v8::Value> iterationDurationValue;
215     if (timingInputDictionary.get("duration", iterationDurationValue)) {
216         double iterationDuration = iterationDurationValue->NumberValue();
217         setIterationDuration(timing, iterationDuration);
218     }
219
220     double playbackRate = 1;
221     timingInputDictionary.get("playbackRate", playbackRate);
222     setPlaybackRate(timing, playbackRate);
223
224     String direction;
225     timingInputDictionary.get("direction", direction);
226     setPlaybackDirection(timing, direction);
227
228     String timingFunctionString;
229     timingInputDictionary.get("easing", timingFunctionString);
230     setTimingFunction(timing, timingFunctionString);
231
232     timing.assertValid();
233 }
234
235 static PassRefPtr<KeyframeEffectModel> createKeyframeEffectModel(Element* element, Vector<Dictionary> keyframeDictionaryVector)
236 {
237     KeyframeEffectModel::KeyframeVector keyframes;
238     Vector<RefPtr<MutableStylePropertySet> > propertySetVector;
239
240     for (size_t i = 0; i < keyframeDictionaryVector.size(); ++i) {
241         RefPtr<MutableStylePropertySet> propertySet = MutableStylePropertySet::create();
242         propertySetVector.append(propertySet);
243
244         RefPtr<Keyframe> keyframe = Keyframe::create();
245         keyframes.append(keyframe);
246
247         double offset;
248         if (keyframeDictionaryVector[i].get("offset", offset)) {
249             keyframe->setOffset(offset);
250         }
251
252         String compositeString;
253         keyframeDictionaryVector[i].get("composite", compositeString);
254         if (compositeString == "add")
255             keyframe->setComposite(AnimationEffect::CompositeAdd);
256
257         String timingFunctionString;
258         if (keyframeDictionaryVector[i].get("easing", timingFunctionString)) {
259             RefPtr<CSSValue> timingFunctionValue = BisonCSSParser::parseAnimationTimingFunctionValue(timingFunctionString);
260             if (timingFunctionValue) {
261                 keyframe->setEasing(CSSToStyleMap::animationTimingFunction(timingFunctionValue.get(), false));
262             }
263         }
264
265         Vector<String> keyframeProperties;
266         keyframeDictionaryVector[i].getOwnPropertyNames(keyframeProperties);
267
268         for (size_t j = 0; j < keyframeProperties.size(); ++j) {
269             String property = keyframeProperties[j];
270             CSSPropertyID id = camelCaseCSSPropertyNameToID(property);
271
272             // FIXME: There is no way to store invalid properties or invalid values
273             // in a Keyframe object, so for now I just skip over them. Eventually we
274             // will need to support getFrames(), which should return exactly the
275             // keyframes that were input through the API. We will add a layer to wrap
276             // KeyframeEffectModel, store input keyframes and implement getFrames.
277             if (id == CSSPropertyInvalid || !CSSAnimations::isAnimatableProperty(id))
278                 continue;
279
280             String value;
281             keyframeDictionaryVector[i].get(property, value);
282             propertySet->setProperty(id, value);
283         }
284     }
285
286     // FIXME: Replace this with code that just parses, when that code is available.
287     RefPtr<KeyframeEffectModel> effect = StyleResolver::createKeyframeEffectModel(*element, propertySetVector, keyframes);
288     return effect;
289 }
290
291 PassRefPtr<Animation> Animation::createUnsafe(Element* element, Vector<Dictionary> keyframeDictionaryVector, Dictionary timingInput)
292 {
293     RefPtr<KeyframeEffectModel> effect = createKeyframeEffectModel(element, keyframeDictionaryVector);
294
295     Timing timing;
296     populateTiming(timing, timingInput);
297
298     return create(element, effect, timing);
299 }
300
301 PassRefPtr<Animation> Animation::createUnsafe(Element* element, Vector<Dictionary> keyframeDictionaryVector, double timingInput)
302 {
303     RefPtr<KeyframeEffectModel> effect = createKeyframeEffectModel(element, keyframeDictionaryVector);
304
305     Timing timing;
306     if (!std::isnan(timingInput))
307         timing.iterationDuration = std::max<double>(timingInput, 0);
308
309     return create(element, effect, timing);
310 }
311
312 PassRefPtr<Animation> Animation::createUnsafe(Element* element, Vector<Dictionary> keyframeDictionaryVector)
313 {
314     RefPtr<KeyframeEffectModel> effect = createKeyframeEffectModel(element, keyframeDictionaryVector);
315     Timing timing;
316
317     return create(element, effect, timing);
318 }
319
320 Animation::Animation(PassRefPtr<Element> target, PassRefPtr<AnimationEffect> effect, const Timing& timing, Priority priority, PassOwnPtr<EventDelegate> eventDelegate)
321     : TimedItem(timing, eventDelegate)
322     , m_target(target)
323     , m_effect(effect)
324     , m_activeInAnimationStack(false)
325     , m_priority(priority)
326 {
327 }
328
329 void Animation::didAttach()
330 {
331     if (m_target)
332         m_target->ensureActiveAnimations()->players().add(player());
333 }
334
335 void Animation::willDetach()
336 {
337     if (m_target)
338         m_target->activeAnimations()->players().remove(player());
339     if (m_activeInAnimationStack)
340         clearEffects();
341 }
342
343 static AnimationStack& ensureAnimationStack(Element* element)
344 {
345     return element->ensureActiveAnimations()->defaultStack();
346 }
347
348 bool Animation::applyEffects(bool previouslyInEffect)
349 {
350     ASSERT(isInEffect());
351     if (!m_target || !m_effect)
352         return false;
353
354     if (player() && !previouslyInEffect) {
355         ensureAnimationStack(m_target.get()).add(this);
356         m_activeInAnimationStack = true;
357     }
358
359     double iteration = currentIteration();
360     ASSERT(iteration >= 0);
361     // FIXME: Handle iteration values which overflow int.
362     m_compositableValues = m_effect->sample(static_cast<int>(iteration), timeFraction());
363     if (player()) {
364         m_target->setNeedsAnimationStyleRecalc();
365         return true;
366     }
367     return false;
368 }
369
370 void Animation::clearEffects()
371 {
372     ASSERT(player());
373     ASSERT(m_activeInAnimationStack);
374     ensureAnimationStack(m_target.get()).remove(this);
375
376     {
377         // FIXME: clearEffects is called from withins style recalc.
378         // This queries compositingState, which is not necessarily up to date.
379         // https://code.google.com/p/chromium/issues/detail?id=339847
380         DisableCompositingQueryAsserts disabler;
381         cancelAnimationOnCompositor();
382     }
383
384     m_activeInAnimationStack = false;
385     m_compositableValues.clear();
386     m_target->setNeedsAnimationStyleRecalc();
387     invalidate();
388 }
389
390 bool Animation::updateChildrenAndEffects() const
391 {
392     if (!m_effect)
393         return false;
394
395     if (isInEffect())
396         return const_cast<Animation*>(this)->applyEffects(m_activeInAnimationStack);
397
398     if (m_activeInAnimationStack) {
399         const_cast<Animation*>(this)->clearEffects();
400         return true;
401     }
402     return false;
403 }
404
405 double Animation::calculateTimeToEffectChange(bool forwards, double localTime, double timeToNextIteration) const
406 {
407     const double start = startTime() + specifiedTiming().startDelay;
408     const double end = start + activeDuration();
409
410     switch (phase()) {
411     case PhaseBefore:
412         ASSERT(start >= localTime);
413         return forwards
414             ? start - localTime
415             : std::numeric_limits<double>::infinity();
416     case PhaseActive:
417         if (forwards && hasActiveAnimationsOnCompositor()) {
418             ASSERT(specifiedTiming().playbackRate == 1);
419             // Need service to apply fill / fire events.
420             return std::min(end - localTime, timeToNextIteration);
421         }
422         return 0;
423     case PhaseAfter:
424         ASSERT(localTime >= end);
425         // If this Animation is still in effect then it will need to update
426         // when its parent goes out of effect. We have no way of knowing when
427         // that will be, however, so the parent will need to supply it.
428         return forwards
429             ? std::numeric_limits<double>::infinity()
430             : localTime - end;
431     case PhaseNone:
432         ASSERT(player() && player()->timeline() && !player()->timeline()->hasStarted());
433         return std::numeric_limits<double>::infinity();
434     default:
435         ASSERT_NOT_REACHED();
436         return std::numeric_limits<double>::infinity();
437     }
438 }
439
440 bool Animation::isCandidateForAnimationOnCompositor() const
441 {
442     if (!effect() || !m_target)
443         return false;
444     return CompositorAnimations::instance()->isCandidateForAnimationOnCompositor(specifiedTiming(), *effect());
445 }
446
447 bool Animation::maybeStartAnimationOnCompositor()
448 {
449     ASSERT(!hasActiveAnimationsOnCompositor());
450     if (!isCandidateForAnimationOnCompositor())
451         return false;
452     if (!CompositorAnimations::instance()->canStartAnimationOnCompositor(*m_target.get()))
453         return false;
454     if (!CompositorAnimations::instance()->startAnimationOnCompositor(*m_target.get(), specifiedTiming(), *effect(), m_compositorAnimationIds))
455         return false;
456     ASSERT(!m_compositorAnimationIds.isEmpty());
457     return true;
458 }
459
460 bool Animation::hasActiveAnimationsOnCompositor() const
461 {
462     return !m_compositorAnimationIds.isEmpty();
463 }
464
465 bool Animation::hasActiveAnimationsOnCompositor(CSSPropertyID property) const
466 {
467     return hasActiveAnimationsOnCompositor() && affects(property);
468 }
469
470 bool Animation::affects(CSSPropertyID property) const
471 {
472     return m_effect && m_effect->affects(property);
473 }
474
475 void Animation::cancelAnimationOnCompositor()
476 {
477     if (!hasActiveAnimationsOnCompositor())
478         return;
479     if (!m_target || !m_target->renderer())
480         return;
481     for (size_t i = 0; i < m_compositorAnimationIds.size(); ++i)
482         CompositorAnimations::instance()->cancelAnimationOnCompositor(*m_target.get(), m_compositorAnimationIds[i]);
483     m_compositorAnimationIds.clear();
484 }
485
486 void Animation::pauseAnimationForTestingOnCompositor(double pauseTime)
487 {
488     ASSERT(hasActiveAnimationsOnCompositor());
489     if (!m_target || !m_target->renderer())
490         return;
491     for (size_t i = 0; i < m_compositorAnimationIds.size(); ++i)
492         CompositorAnimations::instance()->pauseAnimationForTestingOnCompositor(*m_target.get(), m_compositorAnimationIds[i], pauseTime);
493 }
494
495 } // namespace WebCore