Home | History | Annotate | Download | only in animation
      1 /*
      2  * Copyright (C) 2007 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 Computer, 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 "CSSPropertyNames.h"
     34 #include "CSSStyleSelector.h"
     35 #include "CompositeAnimation.h"
     36 #include "EventNames.h"
     37 #include "RenderLayer.h"
     38 #include "RenderLayerBacking.h"
     39 #include "RenderStyle.h"
     40 #include <wtf/UnusedParam.h>
     41 
     42 using namespace std;
     43 
     44 namespace WebCore {
     45 
     46 KeyframeAnimation::KeyframeAnimation(const Animation* animation, RenderObject* renderer, int index, CompositeAnimation* compAnim, RenderStyle* unanimatedStyle)
     47     : AnimationBase(animation, renderer, compAnim)
     48     , m_keyframes(renderer, animation->name())
     49     , m_index(index)
     50     , m_startEventDispatched(false)
     51     , m_unanimatedStyle(unanimatedStyle)
     52 {
     53     // Get the keyframe RenderStyles
     54     if (m_object && m_object->node() && m_object->node()->isElementNode())
     55         m_object->document()->styleSelector()->keyframeStylesForAnimation(static_cast<Element*>(m_object->node()), unanimatedStyle, m_keyframes);
     56 
     57     // Update the m_transformFunctionListValid flag based on whether the function lists in the keyframes match.
     58     validateTransformFunctionList();
     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(int property, const RenderStyle*& fromStyle, const RenderStyle*& toStyle, double& prog) const
     69 {
     70     // Find the first key
     71     double elapsedTime = getElapsedTime();
     72     if (m_animation->duration() && m_animation->iterationCount() != Animation::IterationCountInfinite)
     73         elapsedTime = min(elapsedTime, m_animation->duration() * m_animation->iterationCount());
     74 
     75     double fractionalTime = m_animation->duration() ? (elapsedTime / m_animation->duration()) : 1;
     76 
     77     // FIXME: startTime can be before the current animation "frame" time. This is to sync with the frame time
     78     // concept in AnimationTimeController. So we need to somehow sync the two. Until then, the possible
     79     // error is small and will probably not be noticeable. Until we fix this, remove the assert.
     80     // https://bugs.webkit.org/show_bug.cgi?id=52037
     81     // ASSERT(fractionalTime >= 0);
     82     if (fractionalTime < 0)
     83         fractionalTime = 0;
     84 
     85     // FIXME: share this code with AnimationBase::progress().
     86     int iteration = static_cast<int>(fractionalTime);
     87     if (m_animation->iterationCount() != Animation::IterationCountInfinite)
     88         iteration = min(iteration, m_animation->iterationCount() - 1);
     89     fractionalTime -= iteration;
     90 
     91     bool reversing = (m_animation->direction() == Animation::AnimationDirectionAlternate) && (iteration & 1);
     92     if (reversing)
     93         fractionalTime = 1 - fractionalTime;
     94 
     95     size_t numKeyframes = m_keyframes.size();
     96     if (!numKeyframes)
     97         return;
     98 
     99     ASSERT(!m_keyframes[0].key());
    100     ASSERT(m_keyframes[m_keyframes.size() - 1].key() == 1);
    101 
    102     int prevIndex = -1;
    103     int nextIndex = -1;
    104 
    105     // FIXME: with a lot of keys, this linear search will be slow. We could binary search.
    106     for (size_t i = 0; i < numKeyframes; ++i) {
    107         const KeyframeValue& currKeyFrame = m_keyframes[i];
    108 
    109         if (!currKeyFrame.containsProperty(property))
    110             continue;
    111 
    112         if (fractionalTime < currKeyFrame.key()) {
    113             nextIndex = i;
    114             break;
    115         }
    116 
    117         prevIndex = i;
    118     }
    119 
    120     double scale = 1;
    121     double offset = 0;
    122 
    123     if (prevIndex == -1)
    124         prevIndex = 0;
    125 
    126     if (nextIndex == -1)
    127         nextIndex = m_keyframes.size() - 1;
    128 
    129     const KeyframeValue& prevKeyframe = m_keyframes[prevIndex];
    130     const KeyframeValue& nextKeyframe = m_keyframes[nextIndex];
    131 
    132     fromStyle = prevKeyframe.style();
    133     toStyle = nextKeyframe.style();
    134 
    135     offset = prevKeyframe.key();
    136     scale = 1.0 / (nextKeyframe.key() - prevKeyframe.key());
    137 
    138     const TimingFunction* timingFunction = 0;
    139     if (fromStyle->animations() && fromStyle->animations()->size() > 0) {
    140         // We get the timing function from the first animation, because we've synthesized a RenderStyle for each keyframe.
    141         timingFunction = fromStyle->animations()->animation(0)->timingFunction().get();
    142     }
    143 
    144     prog = progress(scale, offset, timingFunction);
    145 }
    146 
    147 void KeyframeAnimation::animate(CompositeAnimation*, RenderObject*, const RenderStyle*, RenderStyle* targetStyle, RefPtr<RenderStyle>& animatedStyle)
    148 {
    149     // Fire the start timeout if needed
    150     fireAnimationEventsIfNeeded();
    151 
    152     // If we have not yet started, we will not have a valid start time, so just start the animation if needed.
    153     if (isNew() && m_animation->playState() == AnimPlayStatePlaying)
    154         updateStateMachine(AnimationStateInputStartAnimation, -1);
    155 
    156     // If we get this far and the animation is done, it means we are cleaning up a just finished animation.
    157     // If so, we need to send back the targetStyle.
    158     if (postActive()) {
    159         if (!animatedStyle)
    160             animatedStyle = const_cast<RenderStyle*>(targetStyle);
    161         return;
    162     }
    163 
    164     // If we are waiting for the start timer, we don't want to change the style yet.
    165     // Special case 1 - if the delay time is 0, then we do want to set the first frame of the
    166     // animation right away. This avoids a flash when the animation starts.
    167     // Special case 2 - if there is a backwards fill mode, then we want to continue
    168     // through to the style blend so that we get the fromStyle.
    169     if (waitingToStart() && m_animation->delay() > 0 && !m_animation->fillsBackwards())
    170         return;
    171 
    172     // If we have no keyframes, don't animate.
    173     if (!m_keyframes.size()) {
    174         updateStateMachine(AnimationStateInputEndAnimation, -1);
    175         return;
    176     }
    177 
    178     // Run a cycle of animation.
    179     // We know we will need a new render style, so make one if needed.
    180     if (!animatedStyle)
    181         animatedStyle = RenderStyle::clone(targetStyle);
    182 
    183     // FIXME: we need to be more efficient about determining which keyframes we are animating between.
    184     // We should cache the last pair or something.
    185     HashSet<int>::const_iterator endProperties = m_keyframes.endProperties();
    186     for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != endProperties; ++it) {
    187         int property = *it;
    188 
    189         // Get the from/to styles and progress between
    190         const RenderStyle* fromStyle = 0;
    191         const RenderStyle* toStyle = 0;
    192         double progress = 0.0;
    193         fetchIntervalEndpointsForProperty(property, fromStyle, toStyle, progress);
    194 
    195         bool needsAnim = blendProperties(this, property, animatedStyle.get(), fromStyle, toStyle, progress);
    196         if (needsAnim)
    197             setAnimating();
    198         else {
    199 #if USE(ACCELERATED_COMPOSITING)
    200             // If we are running an accelerated animation, set a flag in the style
    201             // to indicate it. This can be used to make sure we get an updated
    202             // style for hit testing, etc.
    203             animatedStyle->setIsRunningAcceleratedAnimation();
    204 #endif
    205         }
    206     }
    207 }
    208 
    209 void KeyframeAnimation::getAnimatedStyle(RefPtr<RenderStyle>& animatedStyle)
    210 {
    211     // If we're in the delay phase and we're not backwards filling, tell the caller
    212     // to use the current style.
    213     if (waitingToStart() && m_animation->delay() > 0 && !m_animation->fillsBackwards())
    214         return;
    215 
    216     if (!m_keyframes.size())
    217         return;
    218 
    219     if (!animatedStyle)
    220         animatedStyle = RenderStyle::clone(m_object->style());
    221 
    222     HashSet<int>::const_iterator endProperties = m_keyframes.endProperties();
    223     for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != endProperties; ++it) {
    224         int property = *it;
    225 
    226         // Get the from/to styles and progress between
    227         const RenderStyle* fromStyle = 0;
    228         const RenderStyle* toStyle = 0;
    229         double progress = 0.0;
    230         fetchIntervalEndpointsForProperty(property, fromStyle, toStyle, progress);
    231 
    232         blendProperties(this, property, animatedStyle.get(), fromStyle, toStyle, progress);
    233     }
    234 }
    235 
    236 bool KeyframeAnimation::hasAnimationForProperty(int property) const
    237 {
    238     // FIXME: why not just m_keyframes.containsProperty()?
    239     HashSet<int>::const_iterator end = m_keyframes.endProperties();
    240     for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != end; ++it) {
    241         if (*it == property)
    242             return true;
    243     }
    244 
    245     return false;
    246 }
    247 
    248 bool KeyframeAnimation::startAnimation(double timeOffset)
    249 {
    250 #if USE(ACCELERATED_COMPOSITING)
    251     if (m_object && m_object->hasLayer()) {
    252         RenderLayer* layer = toRenderBoxModelObject(m_object)->layer();
    253         if (layer->isComposited())
    254             return layer->backing()->startAnimation(timeOffset, m_animation.get(), m_keyframes);
    255     }
    256 #else
    257     UNUSED_PARAM(timeOffset);
    258 #endif
    259     return false;
    260 }
    261 
    262 void KeyframeAnimation::pauseAnimation(double timeOffset)
    263 {
    264     if (!m_object)
    265         return;
    266 
    267 #if USE(ACCELERATED_COMPOSITING)
    268     if (m_object->hasLayer()) {
    269         RenderLayer* layer = toRenderBoxModelObject(m_object)->layer();
    270         if (layer->isComposited())
    271             layer->backing()->animationPaused(timeOffset, m_keyframes.animationName());
    272     }
    273 #else
    274     UNUSED_PARAM(timeOffset);
    275 #endif
    276     // Restore the original (unanimated) style
    277     if (!paused())
    278         setNeedsStyleRecalc(m_object->node());
    279 }
    280 
    281 void KeyframeAnimation::endAnimation()
    282 {
    283     if (!m_object)
    284         return;
    285 
    286 #if USE(ACCELERATED_COMPOSITING)
    287     if (m_object->hasLayer()) {
    288         RenderLayer* layer = toRenderBoxModelObject(m_object)->layer();
    289         if (layer->isComposited())
    290             layer->backing()->animationFinished(m_keyframes.animationName());
    291     }
    292 #endif
    293     // Restore the original (unanimated) style
    294     if (!paused())
    295         setNeedsStyleRecalc(m_object->node());
    296 }
    297 
    298 bool KeyframeAnimation::shouldSendEventForListener(Document::ListenerType listenerType) const
    299 {
    300     return m_object->document()->hasListenerType(listenerType);
    301 }
    302 
    303 void KeyframeAnimation::onAnimationStart(double elapsedTime)
    304 {
    305     sendAnimationEvent(eventNames().webkitAnimationStartEvent, elapsedTime);
    306 }
    307 
    308 void KeyframeAnimation::onAnimationIteration(double elapsedTime)
    309 {
    310     sendAnimationEvent(eventNames().webkitAnimationIterationEvent, elapsedTime);
    311 }
    312 
    313 void KeyframeAnimation::onAnimationEnd(double elapsedTime)
    314 {
    315     sendAnimationEvent(eventNames().webkitAnimationEndEvent, elapsedTime);
    316     // End the animation if we don't fill forwards. Forward filling
    317     // animations are ended properly in the class destructor.
    318     if (!m_animation->fillsForwards())
    319         endAnimation();
    320 }
    321 
    322 bool KeyframeAnimation::sendAnimationEvent(const AtomicString& eventType, double elapsedTime)
    323 {
    324     Document::ListenerType listenerType;
    325     if (eventType == eventNames().webkitAnimationIterationEvent)
    326         listenerType = Document::ANIMATIONITERATION_LISTENER;
    327     else if (eventType == eventNames().webkitAnimationEndEvent)
    328         listenerType = Document::ANIMATIONEND_LISTENER;
    329     else {
    330         ASSERT(eventType == eventNames().webkitAnimationStartEvent);
    331         if (m_startEventDispatched)
    332             return false;
    333         m_startEventDispatched = true;
    334         listenerType = Document::ANIMATIONSTART_LISTENER;
    335     }
    336 
    337     if (shouldSendEventForListener(listenerType)) {
    338         // Dispatch the event
    339         RefPtr<Element> element;
    340         if (m_object->node() && m_object->node()->isElementNode())
    341             element = static_cast<Element*>(m_object->node());
    342 
    343         ASSERT(!element || (element->document() && !element->document()->inPageCache()));
    344         if (!element)
    345             return false;
    346 
    347         // Schedule event handling
    348         m_compAnim->animationController()->addEventToDispatch(element, eventType, m_keyframes.animationName(), elapsedTime);
    349 
    350         // Restore the original (unanimated) style
    351         if (eventType == eventNames().webkitAnimationEndEvent && element->renderer())
    352             setNeedsStyleRecalc(element.get());
    353 
    354         return true; // Did dispatch an event
    355     }
    356 
    357     return false; // Did not dispatch an event
    358 }
    359 
    360 void KeyframeAnimation::overrideAnimations()
    361 {
    362     // This will override implicit animations that match the properties in the keyframe animation
    363     HashSet<int>::const_iterator end = m_keyframes.endProperties();
    364     for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != end; ++it)
    365         compositeAnimation()->overrideImplicitAnimations(*it);
    366 }
    367 
    368 void KeyframeAnimation::resumeOverriddenAnimations()
    369 {
    370     // This will resume overridden implicit animations
    371     HashSet<int>::const_iterator end = m_keyframes.endProperties();
    372     for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != end; ++it)
    373         compositeAnimation()->resumeOverriddenImplicitAnimations(*it);
    374 }
    375 
    376 bool KeyframeAnimation::affectsProperty(int property) const
    377 {
    378     HashSet<int>::const_iterator end = m_keyframes.endProperties();
    379     for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != end; ++it) {
    380         if (*it == property)
    381             return true;
    382     }
    383     return false;
    384 }
    385 
    386 void KeyframeAnimation::validateTransformFunctionList()
    387 {
    388     m_transformFunctionListValid = false;
    389 
    390     if (m_keyframes.size() < 2 || !m_keyframes.containsProperty(CSSPropertyWebkitTransform))
    391         return;
    392 
    393     // Empty transforms match anything, so find the first non-empty entry as the reference
    394     size_t numKeyframes = m_keyframes.size();
    395     size_t firstNonEmptyTransformKeyframeIndex = numKeyframes;
    396 
    397     for (size_t i = 0; i < numKeyframes; ++i) {
    398         const KeyframeValue& currentKeyframe = m_keyframes[i];
    399         if (currentKeyframe.style()->transform().operations().size()) {
    400             firstNonEmptyTransformKeyframeIndex = i;
    401             break;
    402         }
    403     }
    404 
    405     if (firstNonEmptyTransformKeyframeIndex == numKeyframes)
    406         return;
    407 
    408     const TransformOperations* firstVal = &m_keyframes[firstNonEmptyTransformKeyframeIndex].style()->transform();
    409 
    410     // See if the keyframes are valid
    411     for (size_t i = firstNonEmptyTransformKeyframeIndex + 1; i < numKeyframes; ++i) {
    412         const KeyframeValue& currentKeyframe = m_keyframes[i];
    413         const TransformOperations* val = &currentKeyframe.style()->transform();
    414 
    415         // A null transform matches anything
    416         if (val->operations().isEmpty())
    417             continue;
    418 
    419         // If the sizes of the function lists don't match, the lists don't match
    420         if (firstVal->operations().size() != val->operations().size())
    421             return;
    422 
    423         // If the types of each function are not the same, the lists don't match
    424         for (size_t j = 0; j < firstVal->operations().size(); ++j) {
    425             if (!firstVal->operations()[j]->isSameType(*val->operations()[j]))
    426                 return;
    427         }
    428     }
    429 
    430     // Keyframes are valid
    431     m_transformFunctionListValid = true;
    432 }
    433 
    434 double KeyframeAnimation::timeToNextService()
    435 {
    436     double t = AnimationBase::timeToNextService();
    437 #if USE(ACCELERATED_COMPOSITING)
    438     if (t != 0 || preActive())
    439         return t;
    440 
    441     // A return value of 0 means we need service. But if we only have accelerated animations we
    442     // only need service at the end of the transition
    443     HashSet<int>::const_iterator endProperties = m_keyframes.endProperties();
    444     bool acceleratedPropertiesOnly = true;
    445 
    446     for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != endProperties; ++it) {
    447         if (!animationOfPropertyIsAccelerated(*it) || !isAccelerated()) {
    448             acceleratedPropertiesOnly = false;
    449             break;
    450         }
    451     }
    452 
    453     if (acceleratedPropertiesOnly) {
    454         bool isLooping;
    455         getTimeToNextEvent(t, isLooping);
    456     }
    457 #endif
    458     return t;
    459 }
    460 
    461 } // namespace WebCore
    462