REGRESSION (r193610): Drop down menu doesn’t expand at allofbach.com
[WebKit-https.git] / Source / WebCore / page / animation / KeyframeAnimation.cpp
1 /*
2  * Copyright (C) 2007, 2012 Apple 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
6  * are met:
7  *
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  * 3.  Neither the name of Apple Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission. 
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include "config.h"
30 #include "KeyframeAnimation.h"
31
32 #include "AnimationControllerPrivate.h"
33 #include "CSSPropertyAnimation.h"
34 #include "CSSPropertyNames.h"
35 #include "CompositeAnimation.h"
36 #include "EventNames.h"
37 #include "GeometryUtilities.h"
38 #include "RenderBox.h"
39 #include "RenderStyle.h"
40 #include "StyleResolver.h"
41
42 namespace WebCore {
43
44 KeyframeAnimation::KeyframeAnimation(const Animation& animation, RenderElement* renderer, CompositeAnimation* compositeAnimation, const RenderStyle* unanimatedStyle)
45     : AnimationBase(animation, renderer, compositeAnimation)
46     , m_keyframes(animation.name())
47     , m_unanimatedStyle(RenderStyle::clonePtr(*unanimatedStyle))
48 {
49     // Get the keyframe RenderStyles
50     if (m_object && m_object->element())
51         m_object->element()->styleResolver().keyframeStylesForAnimation(*m_object->element(), unanimatedStyle, m_keyframes);
52
53     // Update the m_transformFunctionListValid flag based on whether the function lists in the keyframes match.
54     validateTransformFunctionList();
55     checkForMatchingFilterFunctionLists();
56 #if ENABLE(FILTERS_LEVEL_2)
57     checkForMatchingBackdropFilterFunctionLists();
58 #endif
59 }
60
61 KeyframeAnimation::~KeyframeAnimation()
62 {
63     // Make sure to tell the renderer that we are ending. This will make sure any accelerated animations are removed.
64     if (!postActive())
65         endAnimation();
66 }
67
68 void KeyframeAnimation::fetchIntervalEndpointsForProperty(CSSPropertyID property, const RenderStyle*& fromStyle, const RenderStyle*& toStyle, double& prog) const
69 {
70     size_t numKeyframes = m_keyframes.size();
71     if (!numKeyframes)
72         return;
73
74     // Find the first key
75     double elapsedTime = getElapsedTime();
76     if (m_animation->duration() && m_animation->iterationCount() != Animation::IterationCountInfinite)
77         elapsedTime = std::min(elapsedTime, m_animation->duration() * m_animation->iterationCount());
78
79     const double fractionalTime = this->fractionalTime(1, elapsedTime, 0);
80     ASSERT(!m_keyframes[0].key());
81     ASSERT(m_keyframes[m_keyframes.size() - 1].key() == 1);
82
83     int prevIndex = -1;
84     int nextIndex = -1;
85     // FIXME: with a lot of keys, this linear search will be slow. We could binary search.
86     for (size_t i = 0; i < numKeyframes; ++i) {
87         const KeyframeValue& currKeyFrame = m_keyframes[i];
88
89         if (!currKeyFrame.containsProperty(property))
90             continue;
91
92         if (fractionalTime < currKeyFrame.key()) {
93             nextIndex = i;
94             break;
95         }
96         prevIndex = i;
97     }
98
99     if (prevIndex == -1)
100         prevIndex = 0;
101     if (nextIndex == -1)
102         nextIndex = m_keyframes.size() - 1;
103
104     const KeyframeValue& prevKeyframe = m_keyframes[prevIndex];
105     const KeyframeValue& nextKeyframe = m_keyframes[nextIndex];
106
107     fromStyle = prevKeyframe.style();
108     toStyle = nextKeyframe.style();
109
110     double offset = prevKeyframe.key();
111     double scale = 1.0 / (nextIndex == prevIndex ?  1 : (nextKeyframe.key() - prevKeyframe.key()));
112
113     prog = progress(scale, offset, prevKeyframe.timingFunction(name()));
114 }
115
116 bool KeyframeAnimation::animate(CompositeAnimation* compositeAnimation, RenderElement*, const RenderStyle*, const RenderStyle* targetStyle, std::unique_ptr<RenderStyle>& animatedStyle)
117 {
118     // Fire the start timeout if needed
119     fireAnimationEventsIfNeeded();
120     
121     // If we have not yet started, we will not have a valid start time, so just start the animation if needed.
122     if (isNew()) {
123         if (m_animation->playState() == AnimPlayStatePlaying && !compositeAnimation->isSuspended())
124             updateStateMachine(AnimationStateInput::StartAnimation, -1);
125         else if (m_animation->playState() == AnimPlayStatePaused)
126             updateStateMachine(AnimationStateInput::PlayStatePaused, -1);
127     }
128
129     // If we get this far and the animation is done, it means we are cleaning up a just finished animation.
130     // If so, we need to send back the targetStyle.
131     if (postActive()) {
132         if (!animatedStyle)
133             animatedStyle = RenderStyle::clonePtr(*targetStyle);
134         return false;
135     }
136
137     // If we are waiting for the start timer, we don't want to change the style yet.
138     // Special case 1 - if the delay time is 0, then we do want to set the first frame of the
139     // animation right away. This avoids a flash when the animation starts.
140     // Special case 2 - if there is a backwards fill mode, then we want to continue
141     // through to the style blend so that we get the fromStyle.
142     if (waitingToStart() && m_animation->delay() > 0 && !m_animation->fillsBackwards())
143         return false;
144     
145     // If we have no keyframes, don't animate.
146     if (!m_keyframes.size()) {
147         updateStateMachine(AnimationStateInput::EndAnimation, -1);
148         return false;
149     }
150
151     AnimationState oldState = state();
152
153     // Run a cycle of animation.
154     // We know we will need a new render style, so make one if needed.
155     if (!animatedStyle)
156         animatedStyle = RenderStyle::clonePtr(*targetStyle);
157
158     // FIXME: we need to be more efficient about determining which keyframes we are animating between.
159     // We should cache the last pair or something.
160     for (auto propertyID : m_keyframes.properties()) {
161         // Get the from/to styles and progress between
162         const RenderStyle* fromStyle = nullptr;
163         const RenderStyle* toStyle = nullptr;
164         double progress = 0;
165         fetchIntervalEndpointsForProperty(propertyID, fromStyle, toStyle, progress);
166
167         bool needsAnim = CSSPropertyAnimation::blendProperties(this, propertyID, animatedStyle.get(), fromStyle, toStyle, progress);
168         if (!needsAnim)
169             // If we are running an accelerated animation, set a flag in the style
170             // to indicate it. This can be used to make sure we get an updated
171             // style for hit testing, etc.
172             // FIXME: still need this?
173             animatedStyle->setIsRunningAcceleratedAnimation();
174     }
175     
176     return state() != oldState;
177 }
178
179 void KeyframeAnimation::getAnimatedStyle(std::unique_ptr<RenderStyle>& animatedStyle)
180 {
181     // If we're done, or in the delay phase and we're not backwards filling, tell the caller to use the current style.
182     if (postActive() || (waitingToStart() && m_animation->delay() > 0 && !m_animation->fillsBackwards()))
183         return;
184
185     if (!m_keyframes.size())
186         return;
187
188     if (!animatedStyle)
189         animatedStyle = RenderStyle::clonePtr(m_object->style());
190
191     for (auto propertyID : m_keyframes.properties()) {
192         // Get the from/to styles and progress between
193         const RenderStyle* fromStyle = nullptr;
194         const RenderStyle* toStyle = nullptr;
195         double progress = 0;
196         fetchIntervalEndpointsForProperty(propertyID, fromStyle, toStyle, progress);
197
198         CSSPropertyAnimation::blendProperties(this, propertyID, animatedStyle.get(), fromStyle, toStyle, progress);
199     }
200 }
201
202 bool KeyframeAnimation::computeExtentOfTransformAnimation(LayoutRect& bounds) const
203 {
204     ASSERT(m_keyframes.containsProperty(CSSPropertyTransform));
205
206     if (!is<RenderBox>(m_object))
207         return true; // Non-boxes don't get transformed;
208
209     RenderBox& box = downcast<RenderBox>(*m_object);
210     FloatRect rendererBox = snapRectToDevicePixels(box.borderBoxRect(), box.document().deviceScaleFactor());
211
212     FloatRect cumulativeBounds = bounds;
213
214     for (auto& keyframe : m_keyframes.keyframes()) {
215         if (!keyframe.containsProperty(CSSPropertyTransform))
216             continue;
217
218         LayoutRect keyframeBounds = bounds;
219         
220         bool canCompute;
221         if (transformFunctionListsMatch())
222             canCompute = computeTransformedExtentViaTransformList(rendererBox, *keyframe.style(), keyframeBounds);
223         else
224             canCompute = computeTransformedExtentViaMatrix(rendererBox, *keyframe.style(), keyframeBounds);
225         
226         if (!canCompute)
227             return false;
228         
229         cumulativeBounds.unite(keyframeBounds);
230     }
231
232     bounds = LayoutRect(cumulativeBounds);
233     return true;
234 }
235
236 bool KeyframeAnimation::hasAnimationForProperty(CSSPropertyID property) const
237 {
238     return m_keyframes.containsProperty(property);
239 }
240
241 bool KeyframeAnimation::startAnimation(double timeOffset)
242 {
243     if (m_object && m_object->isComposited())
244         return downcast<RenderBoxModelObject>(*m_object).startAnimation(timeOffset, m_animation.ptr(), m_keyframes);
245     return false;
246 }
247
248 void KeyframeAnimation::pauseAnimation(double timeOffset)
249 {
250     if (!m_object)
251         return;
252
253     if (m_object->isComposited())
254         downcast<RenderBoxModelObject>(*m_object).animationPaused(timeOffset, m_keyframes.animationName());
255
256     // Restore the original (unanimated) style
257     if (!paused())
258         setNeedsStyleRecalc(m_object->element());
259 }
260
261 void KeyframeAnimation::endAnimation()
262 {
263     if (!m_object)
264         return;
265
266     if (m_object->isComposited())
267         downcast<RenderBoxModelObject>(*m_object).animationFinished(m_keyframes.animationName());
268
269     // Restore the original (unanimated) style
270     if (!paused())
271         setNeedsStyleRecalc(m_object->element());
272 }
273
274 bool KeyframeAnimation::shouldSendEventForListener(Document::ListenerType listenerType) const
275 {
276     return m_object->document().hasListenerType(listenerType);
277 }
278
279 void KeyframeAnimation::onAnimationStart(double elapsedTime)
280 {
281     sendAnimationEvent(eventNames().animationstartEvent, elapsedTime);
282 }
283
284 void KeyframeAnimation::onAnimationIteration(double elapsedTime)
285 {
286     sendAnimationEvent(eventNames().animationiterationEvent, elapsedTime);
287 }
288
289 void KeyframeAnimation::onAnimationEnd(double elapsedTime)
290 {
291     sendAnimationEvent(eventNames().animationendEvent, elapsedTime);
292     // End the animation if we don't fill forwards. Forward filling
293     // animations are ended properly in the class destructor.
294     if (!m_animation->fillsForwards())
295         endAnimation();
296 }
297
298 bool KeyframeAnimation::sendAnimationEvent(const AtomicString& eventType, double elapsedTime)
299 {
300     Document::ListenerType listenerType;
301     if (eventType == eventNames().webkitAnimationIterationEvent || eventType == eventNames().animationiterationEvent)
302         listenerType = Document::ANIMATIONITERATION_LISTENER;
303     else if (eventType == eventNames().webkitAnimationEndEvent || eventType == eventNames().animationendEvent)
304         listenerType = Document::ANIMATIONEND_LISTENER;
305     else {
306         ASSERT(eventType == eventNames().webkitAnimationStartEvent || eventType == eventNames().animationstartEvent);
307         if (m_startEventDispatched)
308             return false;
309         m_startEventDispatched = true;
310         listenerType = Document::ANIMATIONSTART_LISTENER;
311     }
312
313     if (shouldSendEventForListener(listenerType)) {
314         // Dispatch the event
315         RefPtr<Element> element = m_object->element();
316
317         ASSERT(!element || !element->document().inPageCache());
318         if (!element)
319             return false;
320
321         // Schedule event handling
322         m_compositeAnimation->animationController().addEventToDispatch(element, eventType, m_keyframes.animationName(), elapsedTime);
323
324         // Restore the original (unanimated) style
325         if ((eventType == eventNames().webkitAnimationEndEvent || eventType == eventNames().animationendEvent) && element->renderer())
326             setNeedsStyleRecalc(element.get());
327
328         return true; // Did dispatch an event
329     }
330
331     return false; // Did not dispatch an event
332 }
333
334 void KeyframeAnimation::overrideAnimations()
335 {
336     // This will override implicit animations that match the properties in the keyframe animation
337     for (auto propertyID : m_keyframes.properties())
338         compositeAnimation()->overrideImplicitAnimations(propertyID);
339 }
340
341 void KeyframeAnimation::resumeOverriddenAnimations()
342 {
343     // This will resume overridden implicit animations
344     for (auto propertyID : m_keyframes.properties())
345         compositeAnimation()->resumeOverriddenImplicitAnimations(propertyID);
346 }
347
348 bool KeyframeAnimation::affectsProperty(CSSPropertyID property) const
349 {
350     return m_keyframes.containsProperty(property);
351 }
352
353 void KeyframeAnimation::validateTransformFunctionList()
354 {
355     m_transformFunctionListsMatch = false;
356     
357     if (m_keyframes.size() < 2 || !m_keyframes.containsProperty(CSSPropertyTransform))
358         return;
359
360     // Empty transforms match anything, so find the first non-empty entry as the reference
361     size_t numKeyframes = m_keyframes.size();
362     size_t firstNonEmptyTransformKeyframeIndex = numKeyframes;
363
364     for (size_t i = 0; i < numKeyframes; ++i) {
365         const KeyframeValue& currentKeyframe = m_keyframes[i];
366         if (currentKeyframe.style()->transform().operations().size()) {
367             firstNonEmptyTransformKeyframeIndex = i;
368             break;
369         }
370     }
371     
372     if (firstNonEmptyTransformKeyframeIndex == numKeyframes)
373         return;
374         
375     const TransformOperations* firstVal = &m_keyframes[firstNonEmptyTransformKeyframeIndex].style()->transform();
376     
377     // See if the keyframes are valid
378     for (size_t i = firstNonEmptyTransformKeyframeIndex + 1; i < numKeyframes; ++i) {
379         const KeyframeValue& currentKeyframe = m_keyframes[i];
380         const TransformOperations* val = &currentKeyframe.style()->transform();
381         
382         // An emtpy transform list matches anything.
383         if (val->operations().isEmpty())
384             continue;
385         
386         if (!firstVal->operationsMatch(*val))
387             return;
388     }
389
390     m_transformFunctionListsMatch = true;
391 }
392
393 void KeyframeAnimation::checkForMatchingFilterFunctionLists()
394 {
395     m_filterFunctionListsMatch = false;
396
397     if (m_keyframes.size() < 2 || !m_keyframes.containsProperty(CSSPropertyFilter))
398         return;
399
400     // Empty filters match anything, so find the first non-empty entry as the reference
401     size_t numKeyframes = m_keyframes.size();
402     size_t firstNonEmptyFilterKeyframeIndex = numKeyframes;
403
404     for (size_t i = 0; i < numKeyframes; ++i) {
405         if (m_keyframes[i].style()->filter().operations().size()) {
406             firstNonEmptyFilterKeyframeIndex = i;
407             break;
408         }
409     }
410     
411     if (firstNonEmptyFilterKeyframeIndex == numKeyframes)
412         return;
413
414     auto& firstVal = m_keyframes[firstNonEmptyFilterKeyframeIndex].style()->filter();
415     
416     for (size_t i = firstNonEmptyFilterKeyframeIndex + 1; i < numKeyframes; ++i) {
417         auto& value = m_keyframes[i].style()->filter();
418
419         // An emtpy filter list matches anything.
420         if (value.operations().isEmpty())
421             continue;
422
423         if (!firstVal.operationsMatch(value))
424             return;
425     }
426
427     m_filterFunctionListsMatch = true;
428 }
429
430 #if ENABLE(FILTERS_LEVEL_2)
431 void KeyframeAnimation::checkForMatchingBackdropFilterFunctionLists()
432 {
433     m_backdropFilterFunctionListsMatch = false;
434
435     if (m_keyframes.size() < 2 || !m_keyframes.containsProperty(CSSPropertyWebkitBackdropFilter))
436         return;
437
438     // Empty filters match anything, so find the first non-empty entry as the reference
439     size_t numKeyframes = m_keyframes.size();
440     size_t firstNonEmptyFilterKeyframeIndex = numKeyframes;
441
442     for (size_t i = 0; i < numKeyframes; ++i) {
443         if (m_keyframes[i].style()->backdropFilter().operations().size()) {
444             firstNonEmptyFilterKeyframeIndex = i;
445             break;
446         }
447     }
448
449     if (firstNonEmptyFilterKeyframeIndex == numKeyframes)
450         return;
451
452     auto& firstVal = m_keyframes[firstNonEmptyFilterKeyframeIndex].style()->backdropFilter();
453
454     for (size_t i = firstNonEmptyFilterKeyframeIndex + 1; i < numKeyframes; ++i) {
455         auto& value = m_keyframes[i].style()->backdropFilter();
456
457         // An emtpy filter list matches anything.
458         if (value.operations().isEmpty())
459             continue;
460
461         if (!firstVal.operationsMatch(value))
462             return;
463     }
464
465     m_backdropFilterFunctionListsMatch = true;
466 }
467 #endif
468
469 double KeyframeAnimation::timeToNextService()
470 {
471     double t = AnimationBase::timeToNextService();
472     if (t != 0 || preActive())
473         return t;
474         
475     // A return value of 0 means we need service. But if we only have accelerated animations we 
476     // only need service at the end of the transition
477     bool acceleratedPropertiesOnly = true;
478     
479     for (auto propertyID : m_keyframes.properties()) {
480         if (!CSSPropertyAnimation::animationOfPropertyIsAccelerated(propertyID) || !isAccelerated()) {
481             acceleratedPropertiesOnly = false;
482             break;
483         }
484     }
485
486     if (acceleratedPropertiesOnly) {
487         bool isLooping;
488         getTimeToNextEvent(t, isLooping);
489     }
490
491     return t;
492 }
493
494 } // namespace WebCore