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