Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / animation / css / CSSAnimations.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/css/CSSAnimations.h"
33
34 #include "StylePropertyShorthand.h"
35 #include "core/animation/ActiveAnimations.h"
36 #include "core/animation/CompositorAnimations.h"
37 #include "core/animation/DocumentTimeline.h"
38 #include "core/animation/KeyframeEffectModel.h"
39 #include "core/animation/css/CSSAnimatableValueFactory.h"
40 #include "core/animation/css/CSSAnimationDataList.h"
41 #include "core/animation/css/CSSPropertyEquality.h"
42 #include "core/css/CSSKeyframeRule.h"
43 #include "core/css/resolver/StyleResolver.h"
44 #include "core/dom/Element.h"
45 #include "core/dom/PseudoElement.h"
46 #include "core/events/TransitionEvent.h"
47 #include "core/events/WebKitAnimationEvent.h"
48 #include "core/frame/UseCounter.h"
49 #include "core/rendering/RenderLayer.h"
50 #include "core/rendering/RenderObject.h"
51 #include "core/rendering/style/KeyframeList.h"
52 #include "platform/animation/TimingFunction.h"
53 #include "public/platform/Platform.h"
54 #include "wtf/BitArray.h"
55 #include "wtf/HashSet.h"
56
57 namespace WebCore {
58
59 namespace {
60
61 CSSPropertyID propertyForAnimation(CSSPropertyID property)
62 {
63     switch (property) {
64     case CSSPropertyWebkitPerspective:
65         return CSSPropertyPerspective;
66     case CSSPropertyWebkitTransform:
67         return CSSPropertyTransform;
68     case CSSPropertyWebkitPerspectiveOriginX:
69     case CSSPropertyWebkitPerspectiveOriginY:
70         if (RuntimeEnabledFeatures::cssTransformsUnprefixedEnabled())
71             return CSSPropertyPerspectiveOrigin;
72         break;
73     case CSSPropertyWebkitTransformOriginX:
74     case CSSPropertyWebkitTransformOriginY:
75     case CSSPropertyWebkitTransformOriginZ:
76         if (RuntimeEnabledFeatures::cssTransformsUnprefixedEnabled())
77             return CSSPropertyTransformOrigin;
78         break;
79     default:
80         break;
81     }
82     return property;
83 }
84
85 static void resolveKeyframes(StyleResolver* resolver, Element* element, const Element& parentElement, const RenderStyle& style, RenderStyle* parentStyle, const AtomicString& name, TimingFunction* defaultTimingFunction,
86     AnimatableValueKeyframeVector& keyframes)
87 {
88     // When the element is null, use its parent for scoping purposes.
89     const Element* elementForScoping = element ? element : &parentElement;
90     const StyleRuleKeyframes* keyframesRule = CSSAnimations::matchScopedKeyframesRule(resolver, elementForScoping, name.impl());
91     if (!keyframesRule)
92         return;
93
94     const WillBeHeapVector<RefPtrWillBeMember<StyleKeyframe> >& styleKeyframes = keyframesRule->keyframes();
95     if (styleKeyframes.isEmpty())
96         return;
97
98     // Construct and populate the style for each keyframe
99     PropertySet specifiedPropertiesForUseCounter;
100     for (size_t i = 0; i < styleKeyframes.size(); ++i) {
101         const StyleKeyframe* styleKeyframe = styleKeyframes[i].get();
102         // It's OK to pass a null element here.
103         RefPtr<RenderStyle> keyframeStyle = resolver->styleForKeyframe(element, style, parentStyle, styleKeyframe, name);
104         RefPtrWillBeRawPtr<AnimatableValueKeyframe> keyframe = AnimatableValueKeyframe::create();
105         const Vector<double>& offsets = styleKeyframe->keys();
106         ASSERT(!offsets.isEmpty());
107         keyframe->setOffset(offsets[0]);
108         keyframe->setEasing(defaultTimingFunction);
109         const StylePropertySet& properties = styleKeyframe->properties();
110         for (unsigned j = 0; j < properties.propertyCount(); j++) {
111             specifiedPropertiesForUseCounter.add(properties.propertyAt(j).id());
112             CSSPropertyID property = propertyForAnimation(properties.propertyAt(j).id());
113             if (property == CSSPropertyWebkitAnimationTimingFunction || property == CSSPropertyAnimationTimingFunction) {
114                 keyframe->setEasing(KeyframeValue::timingFunction(*keyframeStyle));
115             } else if (CSSAnimations::isAnimatableProperty(property)) {
116                 keyframe->setPropertyValue(property, CSSAnimatableValueFactory::create(property, *keyframeStyle).get());
117             }
118         }
119         keyframes.append(keyframe);
120         // The last keyframe specified at a given offset is used.
121         for (size_t j = 1; j < offsets.size(); ++j) {
122             keyframes.append(toAnimatableValueKeyframe(keyframe->cloneWithOffset(offsets[j]).get()));
123         }
124     }
125     ASSERT(!keyframes.isEmpty());
126
127     for (PropertySet::const_iterator iter = specifiedPropertiesForUseCounter.begin(); iter != specifiedPropertiesForUseCounter.end(); ++iter) {
128         const CSSPropertyID property = *iter;
129         ASSERT(property != CSSPropertyInvalid);
130         blink::Platform::current()->histogramSparse("WebCore.Animation.CSSProperties", UseCounter::mapCSSPropertyIdToCSSSampleIdForHistogram(property));
131     }
132
133     // Remove duplicate keyframes. In CSS the last keyframe at a given offset takes priority.
134     std::stable_sort(keyframes.begin(), keyframes.end(), Keyframe::compareOffsets);
135     size_t targetIndex = 0;
136     for (size_t i = 1; i < keyframes.size(); i++) {
137         if (keyframes[i]->offset() != keyframes[targetIndex]->offset())
138             targetIndex++;
139         if (targetIndex != i)
140             keyframes[targetIndex] = keyframes[i];
141     }
142     keyframes.shrink(targetIndex + 1);
143
144     // Add 0% and 100% keyframes if absent.
145     RefPtrWillBeRawPtr<AnimatableValueKeyframe> startKeyframe = keyframes[0];
146     if (startKeyframe->offset()) {
147         startKeyframe = AnimatableValueKeyframe::create();
148         startKeyframe->setOffset(0);
149         startKeyframe->setEasing(defaultTimingFunction);
150         keyframes.prepend(startKeyframe);
151     }
152     RefPtrWillBeRawPtr<AnimatableValueKeyframe> endKeyframe = keyframes[keyframes.size() - 1];
153     if (endKeyframe->offset() != 1) {
154         endKeyframe = AnimatableValueKeyframe::create();
155         endKeyframe->setOffset(1);
156         endKeyframe->setEasing(defaultTimingFunction);
157         keyframes.append(endKeyframe);
158     }
159     ASSERT(keyframes.size() >= 2);
160     ASSERT(!keyframes.first()->offset());
161     ASSERT(keyframes.last()->offset() == 1);
162
163     // Snapshot current property values for 0% and 100% if missing.
164     PropertySet allProperties;
165     size_t numKeyframes = keyframes.size();
166     for (size_t i = 0; i < numKeyframes; i++) {
167         const PropertySet& keyframeProperties = keyframes[i]->properties();
168         for (PropertySet::const_iterator iter = keyframeProperties.begin(); iter != keyframeProperties.end(); ++iter)
169             allProperties.add(*iter);
170     }
171     const PropertySet& startKeyframeProperties = startKeyframe->properties();
172     const PropertySet& endKeyframeProperties = endKeyframe->properties();
173     bool missingStartValues = startKeyframeProperties.size() < allProperties.size();
174     bool missingEndValues = endKeyframeProperties.size() < allProperties.size();
175     if (missingStartValues || missingEndValues) {
176         for (PropertySet::const_iterator iter = allProperties.begin(); iter != allProperties.end(); ++iter) {
177             const CSSPropertyID property = *iter;
178             bool startNeedsValue = missingStartValues && !startKeyframeProperties.contains(property);
179             bool endNeedsValue = missingEndValues && !endKeyframeProperties.contains(property);
180             if (!startNeedsValue && !endNeedsValue)
181                 continue;
182             RefPtrWillBeRawPtr<AnimatableValue> snapshotValue = CSSAnimatableValueFactory::create(property, style);
183             if (startNeedsValue)
184                 startKeyframe->setPropertyValue(property, snapshotValue.get());
185             if (endNeedsValue)
186                 endKeyframe->setPropertyValue(property, snapshotValue.get());
187         }
188     }
189     ASSERT(startKeyframe->properties().size() == allProperties.size());
190     ASSERT(endKeyframe->properties().size() == allProperties.size());
191 }
192
193 // Returns the default timing function.
194 const PassRefPtr<TimingFunction> timingFromAnimationData(const CSSAnimationData* animationData, Timing& timing, bool& isPaused)
195 {
196     if (animationData->isDelaySet())
197         timing.startDelay = animationData->delay();
198     if (animationData->isDurationSet())
199         timing.iterationDuration = animationData->duration();
200     if (animationData->isIterationCountSet()) {
201         if (animationData->iterationCount() == CSSAnimationData::IterationCountInfinite)
202             timing.iterationCount = std::numeric_limits<double>::infinity();
203         else
204             timing.iterationCount = animationData->iterationCount();
205     }
206     if (animationData->isFillModeSet()) {
207         switch (animationData->fillMode()) {
208         case AnimationFillModeForwards:
209             timing.fillMode = Timing::FillModeForwards;
210             break;
211         case AnimationFillModeBackwards:
212             timing.fillMode = Timing::FillModeBackwards;
213             break;
214         case AnimationFillModeBoth:
215             timing.fillMode = Timing::FillModeBoth;
216             break;
217         case AnimationFillModeNone:
218             timing.fillMode = Timing::FillModeNone;
219             break;
220         default:
221             ASSERT_NOT_REACHED();
222         }
223     } else {
224         timing.fillMode = Timing::FillModeNone;
225     }
226     if (animationData->isDirectionSet()) {
227         switch (animationData->direction()) {
228         case CSSAnimationData::AnimationDirectionNormal:
229             timing.direction = Timing::PlaybackDirectionNormal;
230             break;
231         case CSSAnimationData::AnimationDirectionAlternate:
232             timing.direction = Timing::PlaybackDirectionAlternate;
233             break;
234         case CSSAnimationData::AnimationDirectionReverse:
235             timing.direction = Timing::PlaybackDirectionReverse;
236             break;
237         case CSSAnimationData::AnimationDirectionAlternateReverse:
238             timing.direction = Timing::PlaybackDirectionAlternateReverse;
239             break;
240         default:
241             ASSERT_NOT_REACHED();
242         }
243     }
244
245     // For CSS, the constraints on the timing properties are tighter than in
246     // the general case of the Web Animations model.
247     timing.assertValid();
248     ASSERT(!timing.iterationStart);
249     ASSERT(timing.playbackRate == 1);
250     ASSERT(!std::isinf(timing.iterationDuration));
251     ASSERT(timing.timingFunction == LinearTimingFunction::shared());
252
253     isPaused = animationData->isPlayStateSet() && animationData->playState() == AnimPlayStatePaused;
254     return animationData->isTimingFunctionSet() ? animationData->timingFunction() : CSSAnimationData::initialAnimationTimingFunction();
255 }
256
257 } // namespace
258
259 const StyleRuleKeyframes* CSSAnimations::matchScopedKeyframesRule(StyleResolver* resolver, const Element* element, const StringImpl* animationName)
260 {
261     if (resolver->styleTreeHasOnlyScopedResolverForDocument())
262         return resolver->styleTreeScopedStyleResolverForDocument()->keyframeStylesForAnimation(animationName);
263
264     Vector<ScopedStyleResolver*, 8> stack;
265     resolver->styleTreeResolveScopedKeyframesRules(element, stack);
266     if (stack.isEmpty())
267         return 0;
268
269     for (size_t i = 0; i < stack.size(); ++i) {
270         if (const StyleRuleKeyframes* keyframesRule = stack.at(i)->keyframeStylesForAnimation(animationName))
271             return keyframesRule;
272     }
273     return 0;
274 }
275
276 CSSAnimations::CSSAnimations()
277 {
278 }
279
280 PassOwnPtrWillBeRawPtr<CSSAnimationUpdate> CSSAnimations::calculateUpdate(Element* element, const Element& parentElement, const RenderStyle& style, RenderStyle* parentStyle, StyleResolver* resolver)
281 {
282     OwnPtrWillBeRawPtr<CSSAnimationUpdate> update = adoptPtrWillBeNoop(new CSSAnimationUpdate());
283     calculateAnimationUpdate(update.get(), element, parentElement, style, parentStyle, resolver);
284     calculateAnimationActiveInterpolations(update.get(), element, parentElement.document().timeline().currentTimeInternal());
285     calculateTransitionUpdate(update.get(), element, style);
286     calculateTransitionActiveInterpolations(update.get(), element, parentElement.document().transitionTimeline().currentTimeInternal());
287     return update->isEmpty() ? nullptr : update.release();
288 }
289
290 void CSSAnimations::calculateAnimationUpdate(CSSAnimationUpdate* update, Element* element, const Element& parentElement, const RenderStyle& style, RenderStyle* parentStyle, StyleResolver* resolver)
291 {
292     const ActiveAnimations* activeAnimations = element ? element->activeAnimations() : 0;
293
294 #if ASSERT_DISABLED
295     // If we're in an animation style change, no animations can have started, been cancelled or changed play state.
296     // When ASSERT is enabled, we verify this optimization.
297     if (activeAnimations && activeAnimations->isAnimationStyleChange())
298         return;
299 #endif
300
301     const CSSAnimationDataList* animationDataList = style.animations();
302     const CSSAnimations* cssAnimations = activeAnimations ? &activeAnimations->cssAnimations() : 0;
303
304     HashSet<AtomicString> inactive;
305     if (cssAnimations)
306         for (AnimationMap::const_iterator iter = cssAnimations->m_animations.begin(); iter != cssAnimations->m_animations.end(); ++iter)
307             inactive.add(iter->key);
308
309     if (style.display() != NONE) {
310         for (size_t i = 0; animationDataList && i < animationDataList->size(); ++i) {
311             const CSSAnimationData* animationData = animationDataList->animation(i);
312             if (animationData->isNoneAnimation())
313                 continue;
314             ASSERT(animationData->isValidAnimation());
315             AtomicString animationName(animationData->name());
316
317             // Keyframes and animation properties are snapshotted when the
318             // animation starts, so we don't need to track changes to these,
319             // with the exception of play-state.
320             if (cssAnimations) {
321                 AnimationMap::const_iterator existing(cssAnimations->m_animations.find(animationName));
322                 if (existing != cssAnimations->m_animations.end()) {
323                     inactive.remove(animationName);
324                     AnimationPlayer* player = existing->value.get();
325                     if ((animationData->playState() == AnimPlayStatePaused) != player->paused()) {
326                         ASSERT(!activeAnimations || !activeAnimations->isAnimationStyleChange());
327                         update->toggleAnimationPaused(animationName);
328                     }
329                     continue;
330                 }
331             }
332
333             Timing timing;
334             bool isPaused;
335             RefPtr<TimingFunction> keyframeTimingFunction = timingFromAnimationData(animationData, timing, isPaused);
336             AnimatableValueKeyframeVector resolvedKeyframes;
337             resolveKeyframes(resolver, element, parentElement, style, parentStyle, animationName, keyframeTimingFunction.get(), resolvedKeyframes);
338             if (!resolvedKeyframes.isEmpty()) {
339                 ASSERT(!activeAnimations || !activeAnimations->isAnimationStyleChange());
340                 update->startAnimation(animationName, InertAnimation::create(AnimatableValueKeyframeEffectModel::create(resolvedKeyframes), timing, isPaused));
341             }
342         }
343     }
344
345     ASSERT(inactive.isEmpty() || cssAnimations);
346     for (HashSet<AtomicString>::const_iterator iter = inactive.begin(); iter != inactive.end(); ++iter) {
347         ASSERT(!activeAnimations || !activeAnimations->isAnimationStyleChange());
348         update->cancelAnimation(*iter, *cssAnimations->m_animations.get(*iter));
349     }
350 }
351
352 void CSSAnimations::maybeApplyPendingUpdate(Element* element)
353 {
354     if (!m_pendingUpdate) {
355         m_previousActiveInterpolationsForAnimations.clear();
356         return;
357     }
358
359     OwnPtrWillBeRawPtr<CSSAnimationUpdate> update = m_pendingUpdate.release();
360
361     m_previousActiveInterpolationsForAnimations.swap(update->activeInterpolationsForAnimations());
362
363     // FIXME: cancelling, pausing, unpausing animations all query compositingState, which is not necessarily up to date here
364     // since we call this from recalc style.
365     // https://code.google.com/p/chromium/issues/detail?id=339847
366     DisableCompositingQueryAsserts disabler;
367
368     for (Vector<AtomicString>::const_iterator iter = update->cancelledAnimationNames().begin(); iter != update->cancelledAnimationNames().end(); ++iter) {
369         RefPtr<AnimationPlayer> player = m_animations.take(*iter);
370         player->cancel();
371         player->update(TimingUpdateOnDemand);
372     }
373
374     for (Vector<AtomicString>::const_iterator iter = update->animationsWithPauseToggled().begin(); iter != update->animationsWithPauseToggled().end(); ++iter) {
375         AnimationPlayer* player = m_animations.get(*iter);
376         if (player->paused())
377             player->unpause();
378         else
379             player->pause();
380         if (player->outdated())
381             player->update(TimingUpdateOnDemand);
382     }
383
384     for (Vector<CSSAnimationUpdate::NewAnimation>::const_iterator iter = update->newAnimations().begin(); iter != update->newAnimations().end(); ++iter) {
385         const InertAnimation* inertAnimation = iter->animation.get();
386         OwnPtr<AnimationEventDelegate> eventDelegate = adoptPtr(new AnimationEventDelegate(element, iter->name));
387         RefPtr<Animation> animation = Animation::create(element, inertAnimation->effect(), inertAnimation->specifiedTiming(), Animation::DefaultPriority, eventDelegate.release());
388         RefPtr<AnimationPlayer> player = element->document().timeline().createAnimationPlayer(animation.get());
389         element->document().compositorPendingAnimations().add(player.get());
390         if (inertAnimation->paused())
391             player->pause();
392         player->update(TimingUpdateOnDemand);
393         m_animations.set(iter->name, player.get());
394     }
395
396     // Transitions that are run on the compositor only update main-thread state
397     // lazily. However, we need the new state to know what the from state shoud
398     // be when transitions are retargeted. Instead of triggering complete style
399     // recalculation, we find these cases by searching for new transitions that
400     // have matching cancelled animation property IDs on the compositor.
401     HashMap<CSSPropertyID, std::pair<RefPtr<Animation>, double> > retargetedCompositorTransitions;
402     for (HashSet<CSSPropertyID>::iterator iter = update->cancelledTransitions().begin(); iter != update->cancelledTransitions().end(); ++iter) {
403         CSSPropertyID id = *iter;
404         ASSERT(m_transitions.contains(id));
405
406         RefPtr<AnimationPlayer> player = m_transitions.take(id).player;
407         Animation* animation = toAnimation(player->source());
408         if (animation->hasActiveAnimationsOnCompositor(id) && update->newTransitions().find(id) != update->newTransitions().end())
409             retargetedCompositorTransitions.add(id, std::pair<RefPtr<Animation>, double>(animation, player->startTimeInternal()));
410         player->cancel();
411         player->update(TimingUpdateOnDemand);
412     }
413
414     for (CSSAnimationUpdate::NewTransitionMap::const_iterator iter = update->newTransitions().begin(); iter != update->newTransitions().end(); ++iter) {
415         const CSSAnimationUpdate::NewTransition& newTransition = iter->value;
416
417         RunningTransition runningTransition;
418         runningTransition.from = newTransition.from;
419         runningTransition.to = newTransition.to;
420
421         CSSPropertyID id = newTransition.id;
422         InertAnimation* inertAnimation = newTransition.animation.get();
423         OwnPtr<TransitionEventDelegate> eventDelegate = adoptPtr(new TransitionEventDelegate(element, newTransition.eventId));
424
425         RefPtrWillBeRawPtr<AnimationEffect> effect = inertAnimation->effect();
426
427         if (retargetedCompositorTransitions.contains(id)) {
428             const std::pair<RefPtr<Animation>, double>& oldTransition = retargetedCompositorTransitions.get(id);
429             RefPtr<Animation> oldAnimation = oldTransition.first;
430             double oldStartTime = oldTransition.second;
431             double inheritedTime = isNull(oldStartTime) ? 0 : element->document().transitionTimeline().currentTimeInternal() - oldStartTime;
432
433             AnimatableValueKeyframeEffectModel* oldEffect = toAnimatableValueKeyframeEffectModel(inertAnimation->effect());
434             const KeyframeVector& frames = oldEffect->getFrames();
435
436             AnimatableValueKeyframeVector newFrames;
437             newFrames.append(toAnimatableValueKeyframe(frames[0]->clone().get()));
438             newFrames.append(toAnimatableValueKeyframe(frames[1]->clone().get()));
439
440             newFrames[0]->clearPropertyValue(id);
441             RefPtr<InertAnimation> inertAnimationForSampling = InertAnimation::create(oldAnimation->effect(), oldAnimation->specifiedTiming(), false);
442             OwnPtrWillBeRawPtr<WillBeHeapVector<RefPtrWillBeMember<Interpolation> > > sample = inertAnimationForSampling->sample(inheritedTime);
443             ASSERT(sample->size() == 1);
444             newFrames[0]->setPropertyValue(id, toLegacyStyleInterpolation(sample->at(0).get())->currentValue());
445
446             effect = AnimatableValueKeyframeEffectModel::create(newFrames);
447         }
448
449         RefPtr<Animation> transition = Animation::create(element, effect, inertAnimation->specifiedTiming(), Animation::TransitionPriority, eventDelegate.release());
450         RefPtr<AnimationPlayer> player = element->document().transitionTimeline().createAnimationPlayer(transition.get());
451         element->document().compositorPendingAnimations().add(player.get());
452         player->update(TimingUpdateOnDemand);
453         runningTransition.player = player;
454         m_transitions.set(id, runningTransition);
455         ASSERT(id != CSSPropertyInvalid);
456         blink::Platform::current()->histogramSparse("WebCore.Animation.CSSProperties", UseCounter::mapCSSPropertyIdToCSSSampleIdForHistogram(id));
457     }
458 }
459
460 void CSSAnimations::calculateTransitionUpdateForProperty(CSSPropertyID id, const CSSAnimationData* anim, const RenderStyle& oldStyle, const RenderStyle& style, const TransitionMap* activeTransitions, CSSAnimationUpdate* update, const Element* element)
461 {
462     RefPtrWillBeRawPtr<AnimatableValue> to = nullptr;
463     if (activeTransitions) {
464         TransitionMap::const_iterator activeTransitionIter = activeTransitions->find(id);
465         if (activeTransitionIter != activeTransitions->end()) {
466             to = CSSAnimatableValueFactory::create(id, style);
467             const AnimatableValue* activeTo = activeTransitionIter->value.to;
468             if (to->equals(activeTo))
469                 return;
470             update->cancelTransition(id);
471             ASSERT(!element->activeAnimations() || !element->activeAnimations()->isAnimationStyleChange());
472         }
473     }
474
475     if (anim->duration() + anim->delay() <= 0)
476         return;
477
478     if (CSSPropertyEquality::propertiesEqual(id, oldStyle, style))
479         return;
480     if (!to)
481         to = CSSAnimatableValueFactory::create(id, style);
482
483     RefPtrWillBeRawPtr<AnimatableValue> from = CSSAnimatableValueFactory::create(id, oldStyle);
484     // If we have multiple transitions on the same property, we will use the
485     // last one since we iterate over them in order.
486     if (AnimatableValue::usesDefaultInterpolation(to.get(), from.get()))
487         return;
488
489     Timing timing;
490     bool isPaused;
491     RefPtr<TimingFunction> timingFunction = timingFromAnimationData(anim, timing, isPaused);
492     ASSERT(!isPaused);
493     // Note that the backwards part is required for delay to work.
494     timing.fillMode = Timing::FillModeBoth;
495
496     AnimatableValueKeyframeVector keyframes;
497
498     RefPtrWillBeRawPtr<AnimatableValueKeyframe> startKeyframe = AnimatableValueKeyframe::create();
499     startKeyframe->setPropertyValue(id, from.get());
500     startKeyframe->setOffset(0);
501     startKeyframe->setEasing(timingFunction);
502     keyframes.append(startKeyframe);
503
504     RefPtrWillBeRawPtr<AnimatableValueKeyframe> endKeyframe = AnimatableValueKeyframe::create();
505     endKeyframe->setPropertyValue(id, to.get());
506     endKeyframe->setOffset(1);
507     keyframes.append(endKeyframe);
508
509     RefPtrWillBeRawPtr<AnimatableValueKeyframeEffectModel> effect = AnimatableValueKeyframeEffectModel::create(keyframes);
510
511     CSSPropertyID eventId = anim->animationMode() == CSSAnimationData::AnimateAll ? id : anim->property();
512     update->startTransition(id, eventId, from.get(), to.get(), InertAnimation::create(effect, timing, isPaused));
513     ASSERT(!element->activeAnimations() || !element->activeAnimations()->isAnimationStyleChange());
514 }
515
516 void CSSAnimations::calculateTransitionUpdate(CSSAnimationUpdate* update, const Element* element, const RenderStyle& style)
517 {
518     if (!element)
519         return;
520
521     ActiveAnimations* activeAnimations = element->activeAnimations();
522     const TransitionMap* activeTransitions = activeAnimations ? &activeAnimations->cssAnimations().m_transitions : 0;
523
524 #if ASSERT_DISABLED
525     // In release builds we avoid the cost of checking for new and interrupted transitions if the style recalc is due to animation.
526     const bool animationStyleRecalc = activeAnimations && activeAnimations->isAnimationStyleChange();
527 #else
528     // In debug builds we verify that it would have been safe to avoid populating and testing listedProperties if the style recalc is due to animation.
529     const bool animationStyleRecalc = false;
530 #endif
531
532     BitArray<numCSSProperties> listedProperties;
533     bool anyTransitionHadAnimateAll = false;
534     const RenderObject* renderer = element->renderer();
535     if (!animationStyleRecalc && style.display() != NONE && renderer && renderer->style() && style.transitions()) {
536         const RenderStyle& oldStyle = *renderer->style();
537
538         for (size_t i = 0; i < style.transitions()->size(); ++i) {
539             const CSSAnimationData* anim = style.transitions()->animation(i);
540             CSSAnimationData::AnimationMode mode = anim->animationMode();
541             if (mode == CSSAnimationData::AnimateNone)
542                 continue;
543
544             bool animateAll = mode == CSSAnimationData::AnimateAll;
545             ASSERT(animateAll || mode == CSSAnimationData::AnimateSingleProperty);
546             if (animateAll)
547                 anyTransitionHadAnimateAll = true;
548             const StylePropertyShorthand& propertyList = animateAll ? CSSAnimations::animatableProperties() : shorthandForProperty(anim->property());
549             // If not a shorthand we only execute one iteration of this loop, and refer to the property directly.
550             for (unsigned j = 0; !j || j < propertyList.length(); ++j) {
551                 CSSPropertyID id = propertyList.length() ? propertyList.properties()[j] : anim->property();
552
553                 if (!animateAll) {
554                     id = propertyForAnimation(id);
555                     if (CSSAnimations::isAnimatableProperty(id))
556                         listedProperties.set(id);
557                     else
558                         continue;
559                 }
560
561                 // FIXME: We should transition if an !important property changes even when an animation is running,
562                 // but this is a bit hard to do with the current applyMatchedProperties system.
563                 if (!update->activeInterpolationsForAnimations().contains(id)
564                     && (!activeAnimations || !activeAnimations->cssAnimations().m_previousActiveInterpolationsForAnimations.contains(id))) {
565                     calculateTransitionUpdateForProperty(id, anim, oldStyle, style, activeTransitions, update, element);
566                 }
567             }
568         }
569     }
570
571     if (activeTransitions) {
572         for (TransitionMap::const_iterator iter = activeTransitions->begin(); iter != activeTransitions->end(); ++iter) {
573             const AnimationPlayer& player = *iter->value.player;
574             CSSPropertyID id = iter->key;
575             if (player.finishedInternal() || (!anyTransitionHadAnimateAll && !animationStyleRecalc && !listedProperties.get(id))) {
576                 // TODO: Figure out why this fails on Chrome OS login page. crbug.com/365507
577                 // ASSERT(player.finishedInternal() || !(activeAnimations && activeAnimations->isAnimationStyleChange()));
578                 update->cancelTransition(id);
579             }
580         }
581     }
582 }
583
584 void CSSAnimations::cancel()
585 {
586     for (AnimationMap::iterator iter = m_animations.begin(); iter != m_animations.end(); ++iter) {
587         iter->value->cancel();
588         iter->value->update(TimingUpdateOnDemand);
589     }
590
591     for (TransitionMap::iterator iter = m_transitions.begin(); iter != m_transitions.end(); ++iter) {
592         iter->value.player->cancel();
593         iter->value.player->update(TimingUpdateOnDemand);
594     }
595
596     m_animations.clear();
597     m_transitions.clear();
598     m_pendingUpdate = nullptr;
599 }
600
601 void CSSAnimations::calculateAnimationActiveInterpolations(CSSAnimationUpdate* update, const Element* element, double timelineCurrentTime)
602 {
603     ActiveAnimations* activeAnimations = element ? element->activeAnimations() : 0;
604     AnimationStack* animationStack = activeAnimations ? &activeAnimations->defaultStack() : 0;
605
606     if (update->newAnimations().isEmpty() && update->cancelledAnimationAnimationPlayers().isEmpty()) {
607         WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<Interpolation> > activeInterpolationsForAnimations(AnimationStack::activeInterpolations(animationStack, 0, 0, Animation::DefaultPriority, timelineCurrentTime));
608         update->adoptActiveInterpolationsForAnimations(activeInterpolationsForAnimations);
609         return;
610     }
611
612     Vector<InertAnimation*> newAnimations;
613     for (size_t i = 0; i < update->newAnimations().size(); ++i) {
614         newAnimations.append(update->newAnimations()[i].animation.get());
615     }
616     WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<Interpolation> > activeInterpolationsForAnimations(AnimationStack::activeInterpolations(animationStack, &newAnimations, &update->cancelledAnimationAnimationPlayers(), Animation::DefaultPriority, timelineCurrentTime));
617     update->adoptActiveInterpolationsForAnimations(activeInterpolationsForAnimations);
618 }
619
620 void CSSAnimations::calculateTransitionActiveInterpolations(CSSAnimationUpdate* update, const Element* element, double timelineCurrentTime)
621 {
622     ActiveAnimations* activeAnimations = element ? element->activeAnimations() : 0;
623     AnimationStack* animationStack = activeAnimations ? &activeAnimations->defaultStack() : 0;
624
625     WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<Interpolation> > activeInterpolationsForTransitions;
626     if (update->newTransitions().isEmpty() && update->cancelledTransitions().isEmpty()) {
627         activeInterpolationsForTransitions = AnimationStack::activeInterpolations(animationStack, 0, 0, Animation::TransitionPriority, timelineCurrentTime);
628     } else {
629         Vector<InertAnimation*> newTransitions;
630         for (CSSAnimationUpdate::NewTransitionMap::const_iterator iter = update->newTransitions().begin(); iter != update->newTransitions().end(); ++iter)
631             newTransitions.append(iter->value.animation.get());
632
633         HashSet<const AnimationPlayer*> cancelledAnimationPlayers;
634         if (!update->cancelledTransitions().isEmpty()) {
635             ASSERT(activeAnimations);
636             const TransitionMap& transitionMap = activeAnimations->cssAnimations().m_transitions;
637             for (HashSet<CSSPropertyID>::iterator iter = update->cancelledTransitions().begin(); iter != update->cancelledTransitions().end(); ++iter) {
638                 ASSERT(transitionMap.contains(*iter));
639                 cancelledAnimationPlayers.add(transitionMap.get(*iter).player.get());
640             }
641         }
642
643         activeInterpolationsForTransitions = AnimationStack::activeInterpolations(animationStack, &newTransitions, &cancelledAnimationPlayers, Animation::TransitionPriority, timelineCurrentTime);
644     }
645
646     // Properties being animated by animations don't get values from transitions applied.
647     if (!update->activeInterpolationsForAnimations().isEmpty() && !activeInterpolationsForTransitions.isEmpty()) {
648         for (WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<Interpolation> >::const_iterator iter = update->activeInterpolationsForAnimations().begin(); iter != update->activeInterpolationsForAnimations().end(); ++iter)
649             activeInterpolationsForTransitions.remove(iter->key);
650     }
651     update->adoptActiveInterpolationsForTransitions(activeInterpolationsForTransitions);
652 }
653
654 void CSSAnimations::AnimationEventDelegate::maybeDispatch(Document::ListenerType listenerType, const AtomicString& eventName, double elapsedTime)
655 {
656     if (m_target->document().hasListenerType(listenerType)) {
657         RefPtrWillBeRawPtr<WebKitAnimationEvent> event = WebKitAnimationEvent::create(eventName, m_name, elapsedTime);
658         event->setTarget(m_target);
659         m_target->document().enqueueAnimationFrameEvent(event);
660     }
661 }
662
663 void CSSAnimations::AnimationEventDelegate::onEventCondition(const TimedItem* timedItem)
664 {
665     const TimedItem::Phase currentPhase = timedItem->phase();
666     const double currentIteration = timedItem->currentIteration();
667
668     if (m_previousPhase != currentPhase
669         && (currentPhase == TimedItem::PhaseActive || currentPhase == TimedItem::PhaseAfter)
670         && (m_previousPhase == TimedItem::PhaseNone || m_previousPhase == TimedItem::PhaseBefore)) {
671         // The spec states that the elapsed time should be
672         // 'delay < 0 ? -delay : 0', but we always use 0 to match the existing
673         // implementation. See crbug.com/279611
674         maybeDispatch(Document::ANIMATIONSTART_LISTENER, EventTypeNames::animationstart, 0);
675     }
676
677     if (currentPhase == TimedItem::PhaseActive && m_previousPhase == currentPhase && m_previousIteration != currentIteration) {
678         // We fire only a single event for all iterations thast terminate
679         // between a single pair of samples. See http://crbug.com/275263. For
680         // compatibility with the existing implementation, this event uses
681         // the elapsedTime for the first iteration in question.
682         ASSERT(!std::isnan(timedItem->specifiedTiming().iterationDuration));
683         const double elapsedTime = timedItem->specifiedTiming().iterationDuration * (m_previousIteration + 1);
684         maybeDispatch(Document::ANIMATIONITERATION_LISTENER, EventTypeNames::animationiteration, elapsedTime);
685     }
686
687     if (currentPhase == TimedItem::PhaseAfter && m_previousPhase != TimedItem::PhaseAfter)
688         maybeDispatch(Document::ANIMATIONEND_LISTENER, EventTypeNames::animationend, timedItem->activeDurationInternal());
689
690     m_previousPhase = currentPhase;
691     m_previousIteration = currentIteration;
692 }
693
694 void CSSAnimations::TransitionEventDelegate::onEventCondition(const TimedItem* timedItem)
695 {
696     const TimedItem::Phase currentPhase = timedItem->phase();
697     if (currentPhase == TimedItem::PhaseAfter && currentPhase != m_previousPhase && m_target->document().hasListenerType(Document::TRANSITIONEND_LISTENER)) {
698         String propertyName = getPropertyNameString(m_property);
699         const Timing& timing = timedItem->specifiedTiming();
700         double elapsedTime = timing.iterationDuration;
701         const AtomicString& eventType = EventTypeNames::transitionend;
702         String pseudoElement = PseudoElement::pseudoElementNameForEvents(m_target->pseudoId());
703         RefPtrWillBeRawPtr<TransitionEvent> event = TransitionEvent::create(eventType, propertyName, elapsedTime, pseudoElement);
704         event->setTarget(m_target);
705         m_target->document().enqueueAnimationFrameEvent(event);
706     }
707
708     m_previousPhase = currentPhase;
709 }
710
711 bool CSSAnimations::isAnimatableProperty(CSSPropertyID property)
712 {
713     switch (property) {
714     case CSSPropertyBackgroundColor:
715     case CSSPropertyBackgroundImage:
716     case CSSPropertyBackgroundPositionX:
717     case CSSPropertyBackgroundPositionY:
718     case CSSPropertyBackgroundSize:
719     case CSSPropertyBaselineShift:
720     case CSSPropertyBorderBottomColor:
721     case CSSPropertyBorderBottomLeftRadius:
722     case CSSPropertyBorderBottomRightRadius:
723     case CSSPropertyBorderBottomWidth:
724     case CSSPropertyBorderImageOutset:
725     case CSSPropertyBorderImageSlice:
726     case CSSPropertyBorderImageSource:
727     case CSSPropertyBorderImageWidth:
728     case CSSPropertyBorderLeftColor:
729     case CSSPropertyBorderLeftWidth:
730     case CSSPropertyBorderRightColor:
731     case CSSPropertyBorderRightWidth:
732     case CSSPropertyBorderTopColor:
733     case CSSPropertyBorderTopLeftRadius:
734     case CSSPropertyBorderTopRightRadius:
735     case CSSPropertyBorderTopWidth:
736     case CSSPropertyBottom:
737     case CSSPropertyBoxShadow:
738     case CSSPropertyClip:
739     case CSSPropertyColor:
740     case CSSPropertyFill:
741     case CSSPropertyFillOpacity:
742     case CSSPropertyFlexBasis:
743     case CSSPropertyFlexGrow:
744     case CSSPropertyFlexShrink:
745     case CSSPropertyFloodColor:
746     case CSSPropertyFloodOpacity:
747     case CSSPropertyFontSize:
748     case CSSPropertyFontWeight:
749     case CSSPropertyHeight:
750     case CSSPropertyLeft:
751     case CSSPropertyLetterSpacing:
752     case CSSPropertyLightingColor:
753     case CSSPropertyLineHeight:
754     case CSSPropertyListStyleImage:
755     case CSSPropertyMarginBottom:
756     case CSSPropertyMarginLeft:
757     case CSSPropertyMarginRight:
758     case CSSPropertyMarginTop:
759     case CSSPropertyMaxHeight:
760     case CSSPropertyMaxWidth:
761     case CSSPropertyMinHeight:
762     case CSSPropertyMinWidth:
763     case CSSPropertyObjectPosition:
764     case CSSPropertyOpacity:
765     case CSSPropertyOrphans:
766     case CSSPropertyOutlineColor:
767     case CSSPropertyOutlineOffset:
768     case CSSPropertyOutlineWidth:
769     case CSSPropertyPaddingBottom:
770     case CSSPropertyPaddingLeft:
771     case CSSPropertyPaddingRight:
772     case CSSPropertyPaddingTop:
773     case CSSPropertyRight:
774     case CSSPropertyStopColor:
775     case CSSPropertyStopOpacity:
776     case CSSPropertyStroke:
777     case CSSPropertyStrokeDasharray:
778     case CSSPropertyStrokeDashoffset:
779     case CSSPropertyStrokeMiterlimit:
780     case CSSPropertyStrokeOpacity:
781     case CSSPropertyStrokeWidth:
782     case CSSPropertyTextDecorationColor:
783     case CSSPropertyTextIndent:
784     case CSSPropertyTextShadow:
785     case CSSPropertyTop:
786     case CSSPropertyVisibility:
787     case CSSPropertyWebkitBackgroundSize:
788     case CSSPropertyWebkitBorderHorizontalSpacing:
789     case CSSPropertyWebkitBorderVerticalSpacing:
790     case CSSPropertyWebkitBoxShadow:
791     case CSSPropertyWebkitClipPath:
792     case CSSPropertyWebkitColumnCount:
793     case CSSPropertyWebkitColumnGap:
794     case CSSPropertyWebkitColumnRuleColor:
795     case CSSPropertyWebkitColumnRuleWidth:
796     case CSSPropertyWebkitColumnWidth:
797     case CSSPropertyWebkitFilter:
798     case CSSPropertyWebkitMaskBoxImageOutset:
799     case CSSPropertyWebkitMaskBoxImageSlice:
800     case CSSPropertyWebkitMaskBoxImageSource:
801     case CSSPropertyWebkitMaskBoxImageWidth:
802     case CSSPropertyWebkitMaskImage:
803     case CSSPropertyWebkitMaskPositionX:
804     case CSSPropertyWebkitMaskPositionY:
805     case CSSPropertyWebkitMaskSize:
806     case CSSPropertyPerspective:
807     case CSSPropertyShapeOutside:
808     case CSSPropertyShapeMargin:
809     case CSSPropertyShapeImageThreshold:
810     case CSSPropertyWebkitTextStrokeColor:
811     case CSSPropertyTransform:
812     case CSSPropertyWidows:
813     case CSSPropertyWidth:
814     case CSSPropertyWordSpacing:
815     case CSSPropertyZIndex:
816     case CSSPropertyZoom:
817         return true;
818     case CSSPropertyPerspectiveOrigin:
819     case CSSPropertyTransformOrigin:
820         return RuntimeEnabledFeatures::cssTransformsUnprefixedEnabled();
821     case CSSPropertyWebkitPerspectiveOriginX:
822     case CSSPropertyWebkitPerspectiveOriginY:
823     case CSSPropertyWebkitTransformOriginX:
824     case CSSPropertyWebkitTransformOriginY:
825     case CSSPropertyWebkitTransformOriginZ:
826         return !RuntimeEnabledFeatures::cssTransformsUnprefixedEnabled();
827     default:
828         return false;
829     }
830 }
831
832 const StylePropertyShorthand& CSSAnimations::animatableProperties()
833 {
834     DEFINE_STATIC_LOCAL(Vector<CSSPropertyID>, properties, ());
835     DEFINE_STATIC_LOCAL(StylePropertyShorthand, propertyShorthand, ());
836     if (properties.isEmpty()) {
837         for (int i = firstCSSProperty; i < lastCSSProperty; ++i) {
838             CSSPropertyID id = convertToCSSPropertyID(i);
839             if (isAnimatableProperty(id))
840                 properties.append(id);
841         }
842         propertyShorthand = StylePropertyShorthand(CSSPropertyInvalid, properties.begin(), properties.size());
843     }
844     return propertyShorthand;
845 }
846
847 // Animation properties are not allowed to be affected by Web Animations.
848 // http://dev.w3.org/fxtf/web-animations/#not-animatable
849 bool CSSAnimations::isAllowedAnimation(CSSPropertyID property)
850 {
851     switch (property) {
852     case CSSPropertyAnimation:
853     case CSSPropertyAnimationDelay:
854     case CSSPropertyAnimationDirection:
855     case CSSPropertyAnimationDuration:
856     case CSSPropertyAnimationFillMode:
857     case CSSPropertyAnimationIterationCount:
858     case CSSPropertyAnimationName:
859     case CSSPropertyAnimationPlayState:
860     case CSSPropertyAnimationTimingFunction:
861     case CSSPropertyDisplay:
862     case CSSPropertyTransition:
863     case CSSPropertyTransitionDelay:
864     case CSSPropertyTransitionDuration:
865     case CSSPropertyTransitionProperty:
866     case CSSPropertyTransitionTimingFunction:
867     case CSSPropertyWebkitAnimation:
868     case CSSPropertyWebkitAnimationDelay:
869     case CSSPropertyWebkitAnimationDirection:
870     case CSSPropertyWebkitAnimationDuration:
871     case CSSPropertyWebkitAnimationFillMode:
872     case CSSPropertyWebkitAnimationIterationCount:
873     case CSSPropertyWebkitAnimationName:
874     case CSSPropertyWebkitAnimationPlayState:
875     case CSSPropertyWebkitAnimationTimingFunction:
876     case CSSPropertyWebkitTransition:
877     case CSSPropertyWebkitTransitionDelay:
878     case CSSPropertyWebkitTransitionDuration:
879     case CSSPropertyWebkitTransitionProperty:
880     case CSSPropertyWebkitTransitionTimingFunction:
881         return false;
882     default:
883         return true;
884     }
885 }
886
887 void CSSAnimations::trace(Visitor* visitor)
888 {
889     visitor->trace(m_transitions);
890     visitor->trace(m_pendingUpdate);
891     visitor->trace(m_previousActiveInterpolationsForAnimations);
892 }
893
894 void CSSAnimationUpdate::trace(Visitor* visitor)
895 {
896     visitor->trace(m_newTransitions);
897     visitor->trace(m_activeInterpolationsForAnimations);
898     visitor->trace(m_activeInterpolationsForTransitions);
899 }
900
901 } // namespace WebCore