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 namespace WebCore {
     43 
     44 KeyframeAnimation::KeyframeAnimation(const Animation* animation, RenderObject* renderer, int index, CompositeAnimation* compAnim, RenderStyle* unanimatedStyle)
     45     : AnimationBase(animation, renderer, compAnim)
     46     , m_keyframes(renderer, animation->name())
     47     , m_index(index)
     48     , m_unanimatedStyle(unanimatedStyle)
     49 {
     50     // Get the keyframe RenderStyles
     51     if (m_object && m_object->node() && m_object->node()->isElementNode())
     52         m_object->document()->styleSelector()->keyframeStylesForAnimation(static_cast<Element*>(m_object->node()), unanimatedStyle, m_keyframes);
     53 
     54     // Update the m_transformFunctionListValid flag based on whether the function lists in the keyframes match.
     55     validateTransformFunctionList();
     56 }
     57 
     58 KeyframeAnimation::~KeyframeAnimation()
     59 {
     60     // Make sure to tell the renderer that we are ending. This will make sure any accelerated animations are removed.
     61     if (!postActive())
     62         endAnimation();
     63 }
     64 
     65 void KeyframeAnimation::getKeyframeAnimationInterval(const RenderStyle*& fromStyle, const RenderStyle*& toStyle, double& prog) const
     66 {
     67     // Find the first key
     68     double elapsedTime = getElapsedTime();
     69 
     70     double t = m_animation->duration() ? (elapsedTime / m_animation->duration()) : 1;
     71     int i = static_cast<int>(t);
     72     t -= i;
     73     if (m_animation->direction() && (i & 1))
     74         t = 1 - t;
     75 
     76     double scale = 1;
     77     double offset = 0;
     78     Vector<KeyframeValue>::const_iterator endKeyframes = m_keyframes.endKeyframes();
     79     for (Vector<KeyframeValue>::const_iterator it = m_keyframes.beginKeyframes(); it != endKeyframes; ++it) {
     80         if (t < it->key()) {
     81             // The first key should always be 0, so we should never succeed on the first key
     82             if (!fromStyle)
     83                 break;
     84             scale = 1.0 / (it->key() - offset);
     85             toStyle = it->style();
     86             break;
     87         }
     88 
     89         offset = it->key();
     90         fromStyle = it->style();
     91     }
     92 
     93     if (!fromStyle || !toStyle)
     94         return;
     95 
     96     const TimingFunction* timingFunction = 0;
     97     if (fromStyle->animations() && fromStyle->animations()->size() > 0) {
     98         // We get the timing function from the first animation, because we've synthesized a RenderStyle for each keyframe.
     99         timingFunction = &(fromStyle->animations()->animation(0)->timingFunction());
    100     }
    101 
    102     prog = progress(scale, offset, timingFunction);
    103 }
    104 
    105 void KeyframeAnimation::animate(CompositeAnimation*, RenderObject*, const RenderStyle*, RenderStyle* targetStyle, RefPtr<RenderStyle>& animatedStyle)
    106 {
    107     // Fire the start timeout if needed
    108     fireAnimationEventsIfNeeded();
    109 
    110     // If we have not yet started, we will not have a valid start time, so just start the animation if needed.
    111     if (isNew() && m_animation->playState() == AnimPlayStatePlaying)
    112         updateStateMachine(AnimationStateInputStartAnimation, -1);
    113 
    114     // If we get this far and the animation is done, it means we are cleaning up a just finished animation.
    115     // If so, we need to send back the targetStyle.
    116     if (postActive()) {
    117         if (!animatedStyle)
    118             animatedStyle = const_cast<RenderStyle*>(targetStyle);
    119         return;
    120     }
    121 
    122     // If we are waiting for the start timer, we don't want to change the style yet.
    123     // Special case - if the delay time is 0, then we do want to set the first frame of the
    124     // animation right away. This avoids a flash when the animation starts.
    125     if (waitingToStart() && m_animation->delay() > 0)
    126         return;
    127 
    128     // FIXME: we need to be more efficient about determining which keyframes we are animating between.
    129     // We should cache the last pair or something.
    130 
    131     // Get the from/to styles and progress between
    132     const RenderStyle* fromStyle = 0;
    133     const RenderStyle* toStyle = 0;
    134     double progress;
    135     getKeyframeAnimationInterval(fromStyle, toStyle, progress);
    136 
    137     // If either style is 0 we have an invalid case, just stop the animation.
    138     if (!fromStyle || !toStyle) {
    139         updateStateMachine(AnimationStateInputEndAnimation, -1);
    140         return;
    141     }
    142 
    143     // Run a cycle of animation.
    144     // We know we will need a new render style, so make one if needed.
    145     if (!animatedStyle)
    146         animatedStyle = RenderStyle::clone(targetStyle);
    147 
    148     HashSet<int>::const_iterator endProperties = m_keyframes.endProperties();
    149     for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != endProperties; ++it) {
    150         bool needsAnim = blendProperties(this, *it, animatedStyle.get(), fromStyle, toStyle, progress);
    151         if (needsAnim)
    152             setAnimating();
    153         else {
    154 #if USE(ACCELERATED_COMPOSITING)
    155             // If we are running an accelerated animation, set a flag in the style
    156             // to indicate it. This can be used to make sure we get an updated
    157             // style for hit testing, etc.
    158             animatedStyle->setIsRunningAcceleratedAnimation();
    159 #endif
    160         }
    161     }
    162 }
    163 
    164 void KeyframeAnimation::getAnimatedStyle(RefPtr<RenderStyle>& animatedStyle)
    165 {
    166     // Get the from/to styles and progress between
    167     const RenderStyle* fromStyle = 0;
    168     const RenderStyle* toStyle = 0;
    169     double progress;
    170     getKeyframeAnimationInterval(fromStyle, toStyle, progress);
    171 
    172     // If either style is 0 we have an invalid case
    173     if (!fromStyle || !toStyle)
    174         return;
    175 
    176     if (!animatedStyle)
    177         animatedStyle = RenderStyle::clone(m_object->style());
    178 
    179     HashSet<int>::const_iterator endProperties = m_keyframes.endProperties();
    180     for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != endProperties; ++it)
    181         blendProperties(this, *it, animatedStyle.get(), fromStyle, toStyle, progress);
    182 }
    183 
    184 bool KeyframeAnimation::hasAnimationForProperty(int property) const
    185 {
    186     HashSet<int>::const_iterator end = m_keyframes.endProperties();
    187     for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != end; ++it) {
    188         if (*it == property)
    189             return true;
    190     }
    191 
    192     return false;
    193 }
    194 
    195 bool KeyframeAnimation::startAnimation(double timeOffset)
    196 {
    197 #if USE(ACCELERATED_COMPOSITING)
    198     if (m_object && m_object->hasLayer()) {
    199         RenderLayer* layer = toRenderBoxModelObject(m_object)->layer();
    200         if (layer->isComposited())
    201             return layer->backing()->startAnimation(timeOffset, m_animation.get(), m_keyframes);
    202     }
    203 #else
    204     UNUSED_PARAM(timeOffset);
    205 #endif
    206     return false;
    207 }
    208 
    209 void KeyframeAnimation::pauseAnimation(double timeOffset)
    210 {
    211     if (!m_object)
    212         return;
    213 
    214 #if USE(ACCELERATED_COMPOSITING)
    215     if (m_object->hasLayer()) {
    216         RenderLayer* layer = toRenderBoxModelObject(m_object)->layer();
    217         if (layer->isComposited())
    218             layer->backing()->animationPaused(timeOffset, m_keyframes.animationName());
    219     }
    220 #else
    221     UNUSED_PARAM(timeOffset);
    222 #endif
    223     // Restore the original (unanimated) style
    224     if (!paused())
    225         setNeedsStyleRecalc(m_object->node());
    226 }
    227 
    228 void KeyframeAnimation::endAnimation()
    229 {
    230     if (!m_object)
    231         return;
    232 
    233 #if USE(ACCELERATED_COMPOSITING)
    234     if (m_object->hasLayer()) {
    235         RenderLayer* layer = toRenderBoxModelObject(m_object)->layer();
    236         if (layer->isComposited())
    237             layer->backing()->animationFinished(m_keyframes.animationName());
    238     }
    239 #endif
    240     // Restore the original (unanimated) style
    241     if (!paused())
    242         setNeedsStyleRecalc(m_object->node());
    243 }
    244 
    245 bool KeyframeAnimation::shouldSendEventForListener(Document::ListenerType listenerType) const
    246 {
    247     return m_object->document()->hasListenerType(listenerType);
    248 }
    249 
    250 void KeyframeAnimation::onAnimationStart(double elapsedTime)
    251 {
    252     sendAnimationEvent(eventNames().webkitAnimationStartEvent, elapsedTime);
    253 }
    254 
    255 void KeyframeAnimation::onAnimationIteration(double elapsedTime)
    256 {
    257     sendAnimationEvent(eventNames().webkitAnimationIterationEvent, elapsedTime);
    258 }
    259 
    260 void KeyframeAnimation::onAnimationEnd(double elapsedTime)
    261 {
    262     sendAnimationEvent(eventNames().webkitAnimationEndEvent, elapsedTime);
    263     endAnimation();
    264 }
    265 
    266 bool KeyframeAnimation::sendAnimationEvent(const AtomicString& eventType, double elapsedTime)
    267 {
    268     Document::ListenerType listenerType;
    269     if (eventType == eventNames().webkitAnimationIterationEvent)
    270         listenerType = Document::ANIMATIONITERATION_LISTENER;
    271     else if (eventType == eventNames().webkitAnimationEndEvent)
    272         listenerType = Document::ANIMATIONEND_LISTENER;
    273     else {
    274         ASSERT(eventType == eventNames().webkitAnimationStartEvent);
    275         listenerType = Document::ANIMATIONSTART_LISTENER;
    276     }
    277 
    278     if (shouldSendEventForListener(listenerType)) {
    279         // Dispatch the event
    280         RefPtr<Element> element;
    281         if (m_object->node() && m_object->node()->isElementNode())
    282             element = static_cast<Element*>(m_object->node());
    283 
    284         ASSERT(!element || (element->document() && !element->document()->inPageCache()));
    285         if (!element)
    286             return false;
    287 
    288         // Schedule event handling
    289         m_compAnim->animationController()->addEventToDispatch(element, eventType, m_keyframes.animationName(), elapsedTime);
    290 
    291         // Restore the original (unanimated) style
    292         if (eventType == eventNames().webkitAnimationEndEvent && element->renderer())
    293             setNeedsStyleRecalc(element.get());
    294 
    295         return true; // Did dispatch an event
    296     }
    297 
    298     return false; // Did not dispatch an event
    299 }
    300 
    301 void KeyframeAnimation::overrideAnimations()
    302 {
    303     // This will override implicit animations that match the properties in the keyframe animation
    304     HashSet<int>::const_iterator end = m_keyframes.endProperties();
    305     for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != end; ++it)
    306         compositeAnimation()->overrideImplicitAnimations(*it);
    307 }
    308 
    309 void KeyframeAnimation::resumeOverriddenAnimations()
    310 {
    311     // This will resume overridden implicit animations
    312     HashSet<int>::const_iterator end = m_keyframes.endProperties();
    313     for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != end; ++it)
    314         compositeAnimation()->resumeOverriddenImplicitAnimations(*it);
    315 }
    316 
    317 bool KeyframeAnimation::affectsProperty(int property) const
    318 {
    319     HashSet<int>::const_iterator end = m_keyframes.endProperties();
    320     for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != end; ++it) {
    321         if (*it == property)
    322             return true;
    323     }
    324     return false;
    325 }
    326 
    327 void KeyframeAnimation::validateTransformFunctionList()
    328 {
    329     m_transformFunctionListValid = false;
    330 
    331     if (m_keyframes.size() < 2 || !m_keyframes.containsProperty(CSSPropertyWebkitTransform))
    332         return;
    333 
    334     Vector<KeyframeValue>::const_iterator end = m_keyframes.endKeyframes();
    335 
    336     // Empty transforms match anything, so find the first non-empty entry as the reference
    337     size_t firstIndex = 0;
    338     Vector<KeyframeValue>::const_iterator firstIt = end;
    339 
    340     for (Vector<KeyframeValue>::const_iterator it = m_keyframes.beginKeyframes(); it != end; ++it, ++firstIndex) {
    341         if (it->style()->transform().operations().size() > 0) {
    342             firstIt = it;
    343             break;
    344         }
    345     }
    346 
    347     if (firstIt == end)
    348         return;
    349 
    350     const TransformOperations* firstVal = &firstIt->style()->transform();
    351 
    352     // See if the keyframes are valid
    353     for (Vector<KeyframeValue>::const_iterator it = firstIt+1; it != end; ++it) {
    354         const TransformOperations* val = &it->style()->transform();
    355 
    356         // A null transform matches anything
    357         if (val->operations().isEmpty())
    358             continue;
    359 
    360         // If the sizes of the function lists don't match, the lists don't match
    361         if (firstVal->operations().size() != val->operations().size())
    362             return;
    363 
    364         // If the types of each function are not the same, the lists don't match
    365         for (size_t j = 0; j < firstVal->operations().size(); ++j) {
    366             if (!firstVal->operations()[j]->isSameType(*val->operations()[j]))
    367                 return;
    368         }
    369     }
    370 
    371     // Keyframes are valid
    372     m_transformFunctionListValid = true;
    373 }
    374 
    375 double KeyframeAnimation::timeToNextService()
    376 {
    377     double t = AnimationBase::timeToNextService();
    378 #if USE(ACCELERATED_COMPOSITING)
    379     if (t != 0 || preActive())
    380         return t;
    381 
    382     // A return value of 0 means we need service. But if we only have accelerated animations we
    383     // only need service at the end of the transition
    384     HashSet<int>::const_iterator endProperties = m_keyframes.endProperties();
    385     bool acceleratedPropertiesOnly = true;
    386 
    387     for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != endProperties; ++it) {
    388         if (!animationOfPropertyIsAccelerated(*it) || isFallbackAnimating()) {
    389             acceleratedPropertiesOnly = false;
    390             break;
    391         }
    392     }
    393 
    394     if (acceleratedPropertiesOnly) {
    395         bool isLooping;
    396         getTimeToNextEvent(t, isLooping);
    397     }
    398 #endif
    399     return t;
    400 }
    401 
    402 } // namespace WebCore
    403