[Web Animations] Remove useless internals methods
[WebKit-https.git] / Source / WebCore / animation / AnimationTimeline.cpp
1 /*
2  * Copyright (C) Canon Inc. 2016
3  * Copyright (C) 2017 Apple Inc. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include "config.h"
28 #include "AnimationTimeline.h"
29
30 #include "Animation.h"
31 #include "AnimationEffectReadOnly.h"
32 #include "AnimationList.h"
33 #include "CSSAnimation.h"
34 #include "CSSPropertyAnimation.h"
35 #include "CSSTransition.h"
36 #include "DocumentTimeline.h"
37 #include "Element.h"
38 #include "KeyframeEffectReadOnly.h"
39 #include "RenderStyle.h"
40 #include "RenderView.h"
41 #include "StylePropertyShorthand.h"
42 #include "StyleResolver.h"
43 #include "WebAnimationUtilities.h"
44 #include <wtf/text/TextStream.h>
45 #include <wtf/text/WTFString.h>
46
47 namespace WebCore {
48
49 AnimationTimeline::AnimationTimeline(ClassType classType)
50     : m_classType(classType)
51 {
52 }
53
54 AnimationTimeline::~AnimationTimeline()
55 {
56 }
57
58 void AnimationTimeline::addAnimation(Ref<WebAnimation>&& animation)
59 {
60     m_animationsWithoutTarget.add(animation.ptr());
61     m_animations.add(WTFMove(animation));
62     timingModelDidChange();
63 }
64
65 void AnimationTimeline::removeAnimation(Ref<WebAnimation>&& animation)
66 {
67     m_animationsWithoutTarget.remove(animation.ptr());
68     m_animations.remove(WTFMove(animation));
69     timingModelDidChange();
70 }
71
72 std::optional<double> AnimationTimeline::bindingsCurrentTime()
73 {
74     auto time = currentTime();
75     if (!time)
76         return std::nullopt;
77     return secondsToWebAnimationsAPITime(*time);
78 }
79
80 HashMap<Element*, ListHashSet<RefPtr<WebAnimation>>>& AnimationTimeline::relevantMapForAnimation(WebAnimation& animation)
81 {
82     if (animation.isCSSAnimation())
83         return m_elementToCSSAnimationsMap;
84     if (animation.isCSSTransition())
85         return m_elementToCSSTransitionsMap;
86     return m_elementToAnimationsMap;
87 }
88
89 void AnimationTimeline::animationWasAddedToElement(WebAnimation& animation, Element& element)
90 {
91     m_animationsWithoutTarget.remove(&animation);
92
93     relevantMapForAnimation(animation).ensure(&element, [] {
94         return ListHashSet<RefPtr<WebAnimation>> { };
95     }).iterator->value.add(&animation);
96 }
97
98 static inline bool removeCSSTransitionFromMap(CSSTransition& transition, Element& element, HashMap<Element*, HashMap<CSSPropertyID, RefPtr<CSSTransition>>>& map)
99 {
100     auto iterator = map.find(&element);
101     if (iterator == map.end())
102         return false;
103
104     auto& cssTransitionsByProperty = iterator->value;
105     cssTransitionsByProperty.remove(transition.property());
106     if (cssTransitionsByProperty.isEmpty())
107         map.remove(&element);
108     return true;
109 }
110
111 void AnimationTimeline::animationWasRemovedFromElement(WebAnimation& animation, Element& element)
112 {
113     // This animation doesn't have a target for now.
114     m_animationsWithoutTarget.add(&animation);
115
116     // First, we clear this animation from one of the m_elementToCSSAnimationsMap, m_elementToCSSTransitionsMap,
117     // m_elementToAnimationsMap or m_elementToCompletedCSSTransitionByCSSPropertyID map, whichever is relevant to
118     // this type of animation.
119     auto& map = relevantMapForAnimation(animation);
120     auto iterator = map.find(&element);
121     if (iterator == map.end())
122         return;
123
124     auto& animations = iterator->value;
125     animations.remove(&animation);
126     if (!animations.size())
127         map.remove(iterator);
128
129     // Now, if we're dealing with a declarative animation, we remove it from either the m_elementToCSSAnimationByName
130     // or the m_elementToRunningCSSTransitionByCSSPropertyID map, whichever is relevant to this type of animation.
131     if (is<CSSAnimation>(animation)) {
132         auto iterator = m_elementToCSSAnimationByName.find(&element);
133         if (iterator != m_elementToCSSAnimationByName.end()) {
134             auto& cssAnimationsByName = iterator->value;
135             auto& name = downcast<CSSAnimation>(animation).animationName();
136             cssAnimationsByName.remove(name);
137             if (cssAnimationsByName.isEmpty())
138                 m_elementToCSSAnimationByName.remove(&element);
139         }
140     } else if (is<CSSTransition>(animation)) {
141         auto& transition = downcast<CSSTransition>(animation);
142         if (!removeCSSTransitionFromMap(transition, element, m_elementToRunningCSSTransitionByCSSPropertyID))
143             removeCSSTransitionFromMap(transition, element, m_elementToCompletedCSSTransitionByCSSPropertyID);
144     }
145 }
146
147 Vector<RefPtr<WebAnimation>> AnimationTimeline::animationsForElement(Element& element, Ordering ordering) const
148 {
149     Vector<RefPtr<WebAnimation>> animations;
150     if (m_elementToCSSTransitionsMap.contains(&element)) {
151         const auto& cssTransitions = m_elementToCSSTransitionsMap.get(&element);
152         if (ordering == Ordering::Sorted) {
153             Vector<RefPtr<WebAnimation>> sortedCSSTransitions;
154             sortedCSSTransitions.appendRange(cssTransitions.begin(), cssTransitions.end());
155             std::sort(sortedCSSTransitions.begin(), sortedCSSTransitions.end(), [](auto& lhs, auto& rhs) {
156                 // Sort transitions first by their generation time, and then by transition-property.
157                 // https://drafts.csswg.org/css-transitions-2/#animation-composite-order
158                 auto* lhsTransition = downcast<CSSTransition>(lhs.get());
159                 auto* rhsTransition = downcast<CSSTransition>(rhs.get());
160                 if (lhsTransition->generationTime() != rhsTransition->generationTime())
161                     return lhsTransition->generationTime() < rhsTransition->generationTime();
162                 return lhsTransition->transitionProperty().utf8() < rhsTransition->transitionProperty().utf8();
163             });
164             animations.appendVector(sortedCSSTransitions);
165         } else
166             animations.appendRange(cssTransitions.begin(), cssTransitions.end());
167     }
168     if (m_elementToCSSAnimationsMap.contains(&element)) {
169         const auto& cssAnimations = m_elementToCSSAnimationsMap.get(&element);
170         animations.appendRange(cssAnimations.begin(), cssAnimations.end());
171     }
172     if (m_elementToAnimationsMap.contains(&element)) {
173         const auto& webAnimations = m_elementToAnimationsMap.get(&element);
174         animations.appendRange(webAnimations.begin(), webAnimations.end());
175     }
176     return animations;
177 }
178
179 void AnimationTimeline::elementWasRemoved(Element& element)
180 {
181     for (auto& animation : animationsForElement(element)) {
182         animationWasRemovedFromElement(*animation, element);
183         removeAnimation(*animation);
184         animation->cancel(WebAnimation::Silently::Yes);
185     }
186 }
187
188 void AnimationTimeline::removeAnimationsForElement(Element& element)
189 {
190     for (auto& animation : animationsForElement(element))
191         animation->remove();
192 }
193
194 void AnimationTimeline::cancelDeclarativeAnimationsForElement(Element& element)
195 {
196     for (auto& cssTransition : m_elementToCSSTransitionsMap.get(&element))
197         cssTransition->cancel();
198     for (auto& cssAnimation : m_elementToCSSAnimationsMap.get(&element))
199         cssAnimation->cancel();
200 }
201
202 static bool shouldConsiderAnimation(Element& element, const Animation& animation)
203 {
204     if (!animation.isValidAnimation())
205         return false;
206
207     static NeverDestroyed<const String> animationNameNone(MAKE_STATIC_STRING_IMPL("none"));
208
209     auto& name = animation.name();
210     if (name == animationNameNone || name.isEmpty())
211         return false;
212
213     if (auto* styleScope = Style::Scope::forOrdinal(element, animation.nameStyleScopeOrdinal()))
214         return styleScope->resolver().isAnimationNameValid(name);
215
216     return false;
217 }
218
219 void AnimationTimeline::updateCSSAnimationsForElement(Element& element, const RenderStyle* currentStyle, const RenderStyle& afterChangeStyle)
220 {
221     // In case this element is newly getting a "display: none" we need to cancel all of its animations and disregard new ones.
222     if (currentStyle && currentStyle->hasAnimations() && currentStyle->display() != DisplayType::None && afterChangeStyle.display() == DisplayType::None) {
223         if (m_elementToCSSAnimationByName.contains(&element)) {
224             for (const auto& cssAnimationsByNameMapItem : m_elementToCSSAnimationByName.take(&element))
225                 cancelOrRemoveDeclarativeAnimation(cssAnimationsByNameMapItem.value);
226         }
227         return;
228     }
229
230     if (currentStyle && currentStyle->hasAnimations() && afterChangeStyle.hasAnimations() && *(currentStyle->animations()) == *(afterChangeStyle.animations()))
231         return;
232
233     // First, compile the list of animation names that were applied to this element up to this point.
234     HashSet<String> namesOfPreviousAnimations;
235     if (currentStyle && currentStyle->hasAnimations()) {
236         auto* previousAnimations = currentStyle->animations();
237         for (size_t i = 0; i < previousAnimations->size(); ++i) {
238             auto& previousAnimation = previousAnimations->animation(i);
239             if (shouldConsiderAnimation(element, previousAnimation))
240                 namesOfPreviousAnimations.add(previousAnimation.name());
241         }
242     }
243
244     // Create or get the CSSAnimations by animation name map for this element.
245     auto& cssAnimationsByName = m_elementToCSSAnimationByName.ensure(&element, [] {
246         return HashMap<String, RefPtr<CSSAnimation>> { };
247     }).iterator->value;
248
249     if (auto* currentAnimations = afterChangeStyle.animations()) {
250         for (size_t i = 0; i < currentAnimations->size(); ++i) {
251             auto& currentAnimation = currentAnimations->animation(i);
252             auto& name = currentAnimation.name();
253             if (namesOfPreviousAnimations.contains(name)) {
254                 // We've found the name of this animation in our list of previous animations, this means we've already
255                 // created a CSSAnimation object for it and need to ensure that this CSSAnimation is backed by the current
256                 // animation object for this animation name.
257                 cssAnimationsByName.get(name)->setBackingAnimation(currentAnimation);
258             } else if (shouldConsiderAnimation(element, currentAnimation)) {
259                 // Otherwise we are dealing with a new animation name and must create a CSSAnimation for it.
260                 cssAnimationsByName.set(name, CSSAnimation::create(element, currentAnimation, currentStyle, afterChangeStyle));
261             }
262             // Remove the name of this animation from our list since it's now known to be current.
263             namesOfPreviousAnimations.remove(name);
264         }
265     }
266
267     // The animations names left in namesOfPreviousAnimations are now known to no longer apply so we need to
268     // remove the CSSAnimation object created for them.
269     for (const auto& nameOfAnimationToRemove : namesOfPreviousAnimations) {
270         if (auto animation = cssAnimationsByName.take(nameOfAnimationToRemove))
271             cancelOrRemoveDeclarativeAnimation(animation);
272     }
273 }
274
275 RefPtr<WebAnimation> AnimationTimeline::cssAnimationForElementAndProperty(Element& element, CSSPropertyID property)
276 {
277     RefPtr<WebAnimation> matchingAnimation;
278     for (const auto& animation : m_elementToCSSAnimationsMap.get(&element)) {
279         auto* effect = animation->effect();
280         if (is<KeyframeEffectReadOnly>(effect) && downcast<KeyframeEffectReadOnly>(effect)->animatedProperties().contains(property))
281             matchingAnimation = animation;
282     }
283     return matchingAnimation;
284 }
285
286 static bool propertyInStyleMatchesValueForTransitionInMap(CSSPropertyID property, const RenderStyle& style, HashMap<CSSPropertyID, RefPtr<CSSTransition>>& transitions)
287 {
288     if (auto* transition = transitions.get(property)) {
289         if (CSSPropertyAnimation::propertiesEqual(property, &style, &transition->targetStyle()))
290             return true;
291     }
292     return false;
293 }
294
295 static double transitionCombinedDuration(const Animation* transition)
296 {
297     return std::max(0.0, transition->duration()) + transition->delay();
298 }
299
300 static bool transitionMatchesProperty(const Animation& transition, CSSPropertyID property)
301 {
302     auto mode = transition.animationMode();
303     if (mode == Animation::AnimateNone || mode == Animation::AnimateUnknownProperty)
304         return false;
305     if (mode == Animation::AnimateSingleProperty) {
306         auto transitionProperty = transition.property();
307         if (transitionProperty != property) {
308             auto shorthand = shorthandForProperty(transitionProperty);
309             for (size_t i = 0; i < shorthand.length(); ++i) {
310                 if (shorthand.properties()[i] == property)
311                     return true;
312             }
313             return false;
314         }
315     }
316     return true;
317 }
318
319 void AnimationTimeline::updateCSSTransitionsForElement(Element& element, const RenderStyle& currentStyle, const RenderStyle& afterChangeStyle)
320 {
321     // In case this element is newly getting a "display: none" we need to cancel all of its transitions and disregard new ones.
322     if (currentStyle.hasTransitions() && currentStyle.display() != DisplayType::None && afterChangeStyle.display() == DisplayType::None) {
323         if (m_elementToRunningCSSTransitionByCSSPropertyID.contains(&element)) {
324             for (const auto& cssTransitionsByCSSPropertyIDMapItem : m_elementToRunningCSSTransitionByCSSPropertyID.take(&element))
325                 cancelOrRemoveDeclarativeAnimation(cssTransitionsByCSSPropertyIDMapItem.value);
326         }
327         return;
328     }
329
330     // Section 3 "Starting of transitions" from the CSS Transitions Level 1 specification.
331     // https://drafts.csswg.org/css-transitions-1/#starting
332
333     auto& runningTransitionsByProperty = m_elementToRunningCSSTransitionByCSSPropertyID.ensure(&element, [] {
334         return HashMap<CSSPropertyID, RefPtr<CSSTransition>> { };
335     }).iterator->value;
336
337     auto& completedTransitionsByProperty = m_elementToCompletedCSSTransitionByCSSPropertyID.ensure(&element, [] {
338         return HashMap<CSSPropertyID, RefPtr<CSSTransition>> { };
339     }).iterator->value;
340
341     auto generationTime = MonotonicTime::now();
342
343     auto numberOfProperties = CSSPropertyAnimation::getNumProperties();
344     for (int propertyIndex = 0; propertyIndex < numberOfProperties; ++propertyIndex) {
345         std::optional<bool> isShorthand;
346         auto property = CSSPropertyAnimation::getPropertyAtIndex(propertyIndex, isShorthand);
347         if (isShorthand && *isShorthand)
348             continue;
349
350         const Animation* matchingBackingAnimation = nullptr;
351         if (auto* transitions = afterChangeStyle.transitions()) {
352             for (size_t i = 0; i < transitions->size(); ++i) {
353                 auto& backingAnimation = transitions->animation(i);
354                 if (transitionMatchesProperty(backingAnimation, property))
355                     matchingBackingAnimation = &backingAnimation;
356             }
357         }
358
359         // https://drafts.csswg.org/css-transitions-1/#before-change-style
360         // Define the before-change style as the computed values of all properties on the element as of the previous style change event, except with
361         // any styles derived from declarative animations such as CSS Transitions, CSS Animations, and SMIL Animations updated to the current time.
362         auto existingAnimation = cssAnimationForElementAndProperty(element, property);
363         const auto& beforeChangeStyle = existingAnimation ? downcast<CSSAnimation>(existingAnimation.get())->unanimatedStyle() : currentStyle;
364
365         if (!runningTransitionsByProperty.contains(property)
366             && !CSSPropertyAnimation::propertiesEqual(property, &beforeChangeStyle, &afterChangeStyle)
367             && CSSPropertyAnimation::canPropertyBeInterpolated(property, &beforeChangeStyle, &afterChangeStyle)
368             && !propertyInStyleMatchesValueForTransitionInMap(property, afterChangeStyle, completedTransitionsByProperty)
369             && matchingBackingAnimation && transitionCombinedDuration(matchingBackingAnimation) > 0) {
370             // 1. If all of the following are true:
371             //   - the element does not have a running transition for the property,
372             //   - the before-change style is different from and can be interpolated with the after-change style for that property,
373             //   - the element does not have a completed transition for the property or the end value of the completed transition is different from the after-change style for the property,
374             //   - there is a matching transition-property value, and
375             //   - the combined duration is greater than 0s,
376
377             // then implementations must remove the completed transition (if present) from the set of completed transitions
378             completedTransitionsByProperty.remove(property);
379
380             // and start a transition whose:
381             //   - start time is the time of the style change event plus the matching transition delay,
382             //   - end time is the start time plus the matching transition duration,
383             //   - start value is the value of the transitioning property in the before-change style,
384             //   - end value is the value of the transitioning property in the after-change style,
385             //   - reversing-adjusted start value is the same as the start value, and
386             //   - reversing shortening factor is 1.
387             auto delay = Seconds(matchingBackingAnimation->delay());
388             auto duration = Seconds(matchingBackingAnimation->duration());
389             auto& reversingAdjustedStartStyle = beforeChangeStyle;
390             auto reversingShorteningFactor = 1;
391             runningTransitionsByProperty.set(property, CSSTransition::create(element, property, generationTime, *matchingBackingAnimation, &beforeChangeStyle, afterChangeStyle, delay, duration, reversingAdjustedStartStyle, reversingShorteningFactor));
392         } else if (completedTransitionsByProperty.contains(property) && !propertyInStyleMatchesValueForTransitionInMap(property, afterChangeStyle, completedTransitionsByProperty)) {
393             // 2. Otherwise, if the element has a completed transition for the property and the end value of the completed transition is different from
394             //    the after-change style for the property, then implementations must remove the completed transition from the set of completed transitions.
395             completedTransitionsByProperty.remove(property);
396         }
397
398         bool hasRunningTransition = runningTransitionsByProperty.contains(property);
399         if ((hasRunningTransition || completedTransitionsByProperty.contains(property)) && !matchingBackingAnimation) {
400             // 3. If the element has a running transition or completed transition for the property, and there is not a matching transition-property
401             //    value, then implementations must cancel the running transition or remove the completed transition from the set of completed transitions.
402             if (hasRunningTransition)
403                 runningTransitionsByProperty.take(property)->cancel();
404             else
405                 completedTransitionsByProperty.remove(property);
406         }
407
408         if (matchingBackingAnimation && runningTransitionsByProperty.contains(property) && !propertyInStyleMatchesValueForTransitionInMap(property, afterChangeStyle, runningTransitionsByProperty)) {
409             auto previouslyRunningTransition = runningTransitionsByProperty.take(property);
410             auto& previouslyRunningTransitionCurrentStyle = previouslyRunningTransition->currentStyle();
411             // 4. If the element has a running transition for the property, there is a matching transition-property value, and the end value of the running
412             //    transition is not equal to the value of the property in the after-change style, then:
413             if (CSSPropertyAnimation::propertiesEqual(property, &previouslyRunningTransitionCurrentStyle, &afterChangeStyle) || !CSSPropertyAnimation::canPropertyBeInterpolated(property, &currentStyle, &afterChangeStyle)) {
414                 // 1. If the current value of the property in the running transition is equal to the value of the property in the after-change style,
415                 //    or if these two values cannot be interpolated, then implementations must cancel the running transition.
416                 previouslyRunningTransition->cancel();
417             } else if (transitionCombinedDuration(matchingBackingAnimation) <= 0.0 || !CSSPropertyAnimation::canPropertyBeInterpolated(property, &previouslyRunningTransitionCurrentStyle, &afterChangeStyle)) {
418                 // 2. Otherwise, if the combined duration is less than or equal to 0s, or if the current value of the property in the running transition
419                 //    cannot be interpolated with the value of the property in the after-change style, then implementations must cancel the running transition.
420                 previouslyRunningTransition->cancel();
421             } else if (CSSPropertyAnimation::propertiesEqual(property, &previouslyRunningTransition->reversingAdjustedStartStyle(), &afterChangeStyle)) {
422                 // 3. Otherwise, if the reversing-adjusted start value of the running transition is the same as the value of the property in the after-change
423                 //    style (see the section on reversing of transitions for why these case exists), implementations must cancel the running transition
424                 previouslyRunningTransition->cancel();
425
426                 // and start a new transition whose:
427                 //   - reversing-adjusted start value is the end value of the running transition,
428                 //   - reversing shortening factor is the absolute value, clamped to the range [0, 1], of the sum of:
429                 //       1. the output of the timing function of the old transition at the time of the style change event, times the reversing shortening factor of the old transition
430                 //       2. 1 minus the reversing shortening factor of the old transition.
431                 //   - start time is the time of the style change event plus:
432                 //       1. if the matching transition delay is nonnegative, the matching transition delay, or
433                 //       2. if the matching transition delay is negative, the product of the new transition’s reversing shortening factor and the matching transition delay,
434                 //   - end time is the start time plus the product of the matching transition duration and the new transition’s reversing shortening factor,
435                 //   - start value is the current value of the property in the running transition,
436                 //   - end value is the value of the property in the after-change style
437                 auto& reversingAdjustedStartStyle = previouslyRunningTransition->targetStyle();
438                 double transformedProgress = 1;
439                 if (auto* effect = previouslyRunningTransition->effect())
440                     transformedProgress = effect->iterationProgress().value_or(transformedProgress);
441                 auto reversingShorteningFactor = std::max(std::min(((transformedProgress * previouslyRunningTransition->reversingShorteningFactor()) + (1 - previouslyRunningTransition->reversingShorteningFactor())), 1.0), 0.0);
442                 auto delay = matchingBackingAnimation->delay() < 0 ? Seconds(matchingBackingAnimation->delay()) * reversingShorteningFactor : Seconds(matchingBackingAnimation->delay());
443                 auto duration = Seconds(matchingBackingAnimation->duration()) * reversingShorteningFactor;
444                 runningTransitionsByProperty.set(property, CSSTransition::create(element, property, generationTime, *matchingBackingAnimation, &previouslyRunningTransitionCurrentStyle, afterChangeStyle, delay, duration, reversingAdjustedStartStyle, reversingShorteningFactor));
445             } else {
446                 // 4. Otherwise, implementations must cancel the running transition
447                 previouslyRunningTransition->cancel();
448
449                 // and start a new transition whose:
450                 //   - start time is the time of the style change event plus the matching transition delay,
451                 //   - end time is the start time plus the matching transition duration,
452                 //   - start value is the current value of the property in the running transition,
453                 //   - end value is the value of the property in the after-change style,
454                 //   - reversing-adjusted start value is the same as the start value, and
455                 //   - reversing shortening factor is 1.
456                 auto delay = Seconds(matchingBackingAnimation->delay());
457                 auto duration = Seconds(matchingBackingAnimation->duration());
458                 auto& reversingAdjustedStartStyle = currentStyle;
459                 auto reversingShorteningFactor = 1;
460                 runningTransitionsByProperty.set(property, CSSTransition::create(element, property, generationTime, *matchingBackingAnimation, &previouslyRunningTransitionCurrentStyle, afterChangeStyle, delay, duration, reversingAdjustedStartStyle, reversingShorteningFactor));
461             }
462         }
463     }
464
465 }
466
467 void AnimationTimeline::cancelOrRemoveDeclarativeAnimation(RefPtr<DeclarativeAnimation> animation)
468 {
469     ASSERT(animation);
470     animation->cancel();
471     animationWasRemovedFromElement(*animation, animation->target());
472     removeAnimation(animation.releaseNonNull());
473 }
474
475 } // namespace WebCore