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