Changeset 39211 in webkit


Ignore:
Timestamp:
Dec 11, 2008, 8:24:32 AM (17 years ago)
Author:
cmarrin@apple.com
Message:

Reviewed by Dave Hyatt.

Fixed https://bugs.webkit.org/show_bug.cgi?id=22738

This gets rid of the per-animation timers which were used when an animation
started, ended and looped. Their job is now done by the main AnimationController's
timer. It is now set to fire as needed. For instance, if there is a delay, it will
fire after the delay time and then every 30ms to run the animation. The start, loop
and end events are generated as needed during the firing of this timer.

I had to add one more bit of code. When animation timers used to fire the animation events.
This would always happen from the RunLoop, so any style changes that happened in the
event handler would get picked up on the next updateRendering() call. But now the start
event is generated during the styleIsAvailable() call, which is in the middle of the
updateRendering() cycle. And calling an event handler in the middle of updateRendering()
is not allowed and causes style changes to get missed. We already have a mechanism in
AnimationController to defer updateRendering() calls. So I added logic to defer all
event handling to there. Now, I put any request for event handling into a list and ask
for a deferred updateRendering() call. When that deferred timer fires, I go through that
list, send all the events and then call updateRendering().

Location:
trunk/WebCore
Files:
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/WebCore/ChangeLog

    r39209 r39211  
     12008-12-10  Chris Marrin  <cmarrin@apple.com>
     2
     3        Reviewed by Dave Hyatt.
     4
     5        Fixed https://bugs.webkit.org/show_bug.cgi?id=22738
     6
     7        This gets rid of the per-animation timers which were used when an animation
     8        started, ended and looped. Their job is now done by the main AnimationController's
     9        timer. It is now set to fire as needed. For instance, if there is a delay, it will
     10        fire after the delay time and then every 30ms to run the animation. The start, loop
     11        and end events are generated as needed during the firing of this timer.
     12
     13        I had to add one more bit of code. When animation timers used to fire the animation events.
     14        This would always happen from the RunLoop, so any style changes that happened in the
     15        event handler would get picked up on the next updateRendering() call. But now the start
     16        event is generated during the styleIsAvailable() call, which is in the middle of the
     17        updateRendering() cycle. And calling an event handler in the middle of updateRendering()
     18        is not allowed and causes style changes to get missed. We already have a mechanism in
     19        AnimationController to defer updateRendering() calls. So I added logic to defer all
     20        event handling to there. Now, I put any request for event handling into a list and ask
     21        for a deferred updateRendering() call. When that deferred timer fires, I go through that
     22        list, send all the events and then call updateRendering().
     23
     24        * page/animation/AnimationBase.cpp:
     25        (WebCore::AnimationBase::AnimationBase):
     26        (WebCore::AnimationBase::updateStateMachine):
     27        (WebCore::AnimationBase::fireAnimationEventsIfNeeded):
     28        (WebCore::AnimationBase::willNeedService):
     29        (WebCore::AnimationBase::goIntoEndingOrLoopingState):
     30        * page/animation/AnimationBase.h:
     31        * page/animation/AnimationController.cpp:
     32        (WebCore::AnimationControllerPrivate::updateAnimationTimer):
     33        (WebCore::AnimationControllerPrivate::updateRenderingDispatcherFired):
     34        (WebCore::AnimationControllerPrivate::addEventToDispatch):
     35        (WebCore::AnimationControllerPrivate::animationTimerFired):
     36        (WebCore::AnimationController::addEventToDispatch):
     37        * page/animation/AnimationController.h:
     38        * page/animation/CompositeAnimation.cpp:
     39        (WebCore::CompositeAnimationPrivate::updateTransitions):
     40        (WebCore::CompositeAnimationPrivate::willNeedService):
     41        (WebCore::CompositeAnimationPrivate::getAnimationForProperty):
     42        (WebCore::CompositeAnimation::willNeedService):
     43        (WebCore::CompositeAnimation::getAnimationForProperty):
     44        * page/animation/CompositeAnimation.h:
     45        * page/animation/ImplicitAnimation.cpp:
     46        (WebCore::ImplicitAnimation::animate):
     47        (WebCore::ImplicitAnimation::onAnimationEnd):
     48        (WebCore::ImplicitAnimation::sendTransitionEvent):
     49        * page/animation/ImplicitAnimation.h:
     50        * page/animation/KeyframeAnimation.cpp:
     51        (WebCore::KeyframeAnimation::animate):
     52        (WebCore::KeyframeAnimation::sendAnimationEvent):
     53        * page/animation/KeyframeAnimation.h:
     54        (WebCore::KeyframeAnimation::setUnanimatedStyle):
     55
    1562008-12-11  Simon Hausmann  <simon.hausmann@nokia.com>
    257
  • trunk/WebCore/page/animation/AnimationBase.cpp

    r39092 r39211  
    6262    UnitBezier bezier(p1x, p1y, p2x, p2y);
    6363    return bezier.solve(t, solveEpsilon(duration));
    64 }
    65 
    66 void AnimationTimerCallback::timerFired(Timer<AnimationTimerBase>*)
    67 {
    68     m_anim->animationTimerCallbackFired(m_eventType, m_elapsedTime);
    6964}
    7065
     
    385380    , m_startTime(0)
    386381    , m_pauseTime(-1)
     382    , m_requestedStartTime(0)
    387383    , m_object(renderer)
    388     , m_animationTimerCallback(const_cast<AnimationBase*>(this))
    389384    , m_animation(const_cast<Animation*>(transition))
    390385    , m_compAnim(compAnim)
    391386    , m_transformFunctionListValid(false)
    392 {
     387    , m_nextIterationDuration(-1)
     388{
     389    // Compute the total duration
     390    m_totalDuration = -1;
     391    if (m_animation->iterationCount() > 0)
     392        m_totalDuration = m_animation->duration() * m_animation->iterationCount();
    393393}
    394394
     
    499499        m_startTime = 0;
    500500        m_pauseTime = -1;
     501        m_requestedStartTime = 0;
     502        m_nextIterationDuration = -1;
    501503        m_waitedForResponse = false;
    502504        endAnimation(false);
     
    505507
    506508    if (input == AnimationStateInputRestartAnimation) {
    507         cancelTimers();
    508509        if (m_animState == AnimationStateStartWaitStyleAvailable)
    509510            m_compAnim->setWaitingForStyleAvailable(false);
     
    511512        m_startTime = 0;
    512513        m_pauseTime = -1;
     514        m_requestedStartTime = 0;
     515        m_nextIterationDuration = -1;
    513516        endAnimation(false);
    514517
     
    519522
    520523    if (input == AnimationStateInputEndAnimation) {
    521         cancelTimers();
    522524        if (m_animState == AnimationStateStartWaitStyleAvailable)
    523525            m_compAnim->setWaitingForStyleAvailable(false);
     
    550552            ASSERT(input == AnimationStateInputStartAnimation || input == AnimationStateInputPlayStateRunnning || input == AnimationStateInputPlayStatePaused);
    551553            if (input == AnimationStateInputStartAnimation || input == AnimationStateInputPlayStateRunnning) {
    552                 // Set the start timer to the initial delay (0 if no delay)
    553554                m_waitedForResponse = false;
     555                m_requestedStartTime = currentTime();
    554556                m_animState = AnimationStateStartWaitTimer;
    555                 m_animationTimerCallback.startTimer(m_animation->delay(), eventNames().webkitAnimationStartEvent, m_animation->delay());
    556557            }
    557558            break;
     
    572573                // We're waiting for the start timer to fire and we got a pause. Cancel the timer, pause and wait
    573574                m_pauseTime = currentTime();
    574                 cancelTimers();
    575575                m_animState = AnimationStatePausedWaitTimer;
    576576            }
     
    606606                    m_startTime = param;
    607607
    608                 // Decide when the end or loop event needs to fire
    609                 primeEventTimers();
     608                // Decide whether to go into looping or ending state
     609                goIntoEndingOrLoopingState();
    610610
    611611                // Trigger a render so we can start the animation
     
    629629                // Loop timer fired, loop again or end.
    630630                onAnimationIteration(param);
    631                 primeEventTimers();
     631
     632                // Decide whether to go into looping or ending state
     633                goIntoEndingOrLoopingState();
    632634            } else {
    633635                // We are pausing while running. Cancel the animation and wait
    634636                m_pauseTime = currentTime();
    635                 cancelTimers();
    636637                endAnimation(false);
    637638                m_animState = AnimationStatePausedRun;
     
    658659                // We are pausing while running. Cancel the animation and wait
    659660                m_pauseTime = currentTime();
    660                 cancelTimers();
    661661                endAnimation(false);
    662662                m_animState = AnimationStatePausedRun;
     
    706706}
    707707   
    708 void AnimationBase::animationTimerCallbackFired(const AtomicString& eventType, double elapsedTime)
    709 {
     708void AnimationBase::fireAnimationEventsIfNeeded()
     709{
     710    // If we are waiting for the delay time to expire and it has, go to the next state
     711    if (m_animState != AnimationStateStartWaitTimer && m_animState != AnimationStateLooping && m_animState != AnimationStateEnding)
     712        return;
     713
    710714    // We have to make sure to keep a ref to the this pointer, because it could get destroyed
    711715    // during an animation callback that might get called. Since the owner is a CompositeAnimation
     
    715719    RefPtr<CompositeAnimation> compProtector(m_compAnim);
    716720   
    717     ASSERT(m_object->document() && !m_object->document()->inPageCache());
    718 
    719     // FIXME: use an enum
    720     if (eventType == eventNames().webkitAnimationStartEvent)
    721         updateStateMachine(AnimationStateInputStartTimerFired, elapsedTime);
    722     else if (eventType == eventNames().webkitAnimationIterationEvent)
    723         updateStateMachine(AnimationStateInputLoopTimerFired, elapsedTime);
    724     else if (eventType == eventNames().webkitAnimationEndEvent) {
    725         updateStateMachine(AnimationStateInputEndTimerFired, elapsedTime);
     721    // Check for start timeout
     722    if (m_animState == AnimationStateStartWaitTimer) {
     723        if (currentTime() - m_requestedStartTime >= m_animation->delay())
     724            updateStateMachine(AnimationStateInputStartTimerFired, 0);
     725        return;
     726    }
     727   
     728    double elapsedDuration = currentTime() - m_startTime;
     729    ASSERT(elapsedDuration >= 0);
     730   
     731    // Check for end timeout
     732    if (m_totalDuration > 0 && elapsedDuration >= m_totalDuration) {
     733        // Fire an end event
     734        updateStateMachine(AnimationStateInputEndTimerFired, m_totalDuration);
     735    }
     736    else {
     737        // Check for iteration timeout
     738        if (m_nextIterationDuration < 0) {
     739            // Hasn't been set yet, set it
     740            double durationLeft = m_animation->duration() - fmod(elapsedDuration, m_animation->duration());
     741            m_nextIterationDuration = elapsedDuration + durationLeft;
     742        }
     743       
     744        if (elapsedDuration >= m_nextIterationDuration) {
     745            // Set to the next iteration
     746            double previous = m_nextIterationDuration;
     747            double durationLeft = m_animation->duration() - fmod(elapsedDuration, m_animation->duration());
     748            m_nextIterationDuration = elapsedDuration + durationLeft;
     749           
     750            // Send the event
     751            updateStateMachine(AnimationStateInputLoopTimerFired, previous);
     752        }
    726753    }
    727754}
     
    731758    if (paused() == run || isNew())
    732759        updateStateMachine(run ? AnimationStateInputPlayStateRunnning : AnimationStateInputPlayStatePaused, -1);
     760}
     761
     762double AnimationBase::willNeedService() const
     763{
     764    // Returns the time at which next service is required. -1 means no service is required. 0 means
     765    // service is required now, and > 0 means service is required that many seconds in the future.
     766    if (paused() || isNew())
     767        return -1;
     768       
     769    if (m_animState == AnimationStateStartWaitTimer) {
     770        double timeFromNow = m_animation->delay() - (currentTime() - m_requestedStartTime);
     771        return (float) ((timeFromNow > 0) ? timeFromNow : 0);
     772    }
     773   
     774    // In all other cases, we need service right away.
     775    return 0;
    733776}
    734777
     
    777820}
    778821
    779 void AnimationBase::primeEventTimers()
     822void AnimationBase::goIntoEndingOrLoopingState()
    780823{
    781824    // Decide when the end or loop event needs to fire
    782     double ct = currentTime();
    783     const double elapsedDuration = ct - m_startTime;
    784     ASSERT(elapsedDuration >= 0);
    785 
    786825    double totalDuration = -1;
    787826    if (m_animation->iterationCount() > 0)
    788827        totalDuration = m_animation->duration() * m_animation->iterationCount();
    789828
     829    const double elapsedDuration = currentTime() - m_startTime;
     830    ASSERT(elapsedDuration >= 0);
    790831    double durationLeft = 0;
    791832    double nextIterationTime = totalDuration;
     833
    792834    if (totalDuration < 0 || elapsedDuration < totalDuration) {
    793835        durationLeft = m_animation->duration() - fmod(elapsedDuration, m_animation->duration());
     
    795837    }
    796838
    797     // At this point, we may have 0 durationLeft, if we've gotten the event late and we are already
    798     // past totalDuration. In this case we still fire an end timer before processing the end.
    799     // This defers the call to sendAnimationEvents to avoid re-entrant calls that destroy
    800     // the RenderObject, and therefore |this| before we're done with it.
    801839    if (totalDuration < 0 || nextIterationTime < totalDuration) {
    802         // We are not at the end yet, send a loop event
     840        // We are not at the end yet
    803841        ASSERT(nextIterationTime > 0);
    804842        m_animState = AnimationStateLooping;
    805         m_animationTimerCallback.startTimer(durationLeft, eventNames().webkitAnimationIterationEvent, nextIterationTime);
    806843    } else {
    807         // We are at the end, send an end event
     844        // We are at the end
    808845        m_animState = AnimationStateEnding;
    809         m_animationTimerCallback.startTimer(durationLeft, eventNames().webkitAnimationEndEvent, nextIterationTime);
    810846    }
    811847}
  • trunk/WebCore/page/animation/AnimationBase.h

    r38768 r39211  
    3131
    3232#include "AtomicString.h"
    33 #include "Timer.h"
    3433#include <wtf/HashMap.h>
    3534
     
    4645class TimingFunction;
    4746
    48 class AnimationTimerBase {
    49 public:
    50     AnimationTimerBase(AnimationBase* anim)
    51         : m_timer(this, &AnimationTimerBase::timerFired)
    52         , m_anim(anim)
    53     {
    54         m_timer.startOneShot(0);
    55     }
    56 
    57     virtual ~AnimationTimerBase() { }
    58 
    59     void startTimer(double timeout = 0)
    60     {
    61         m_timer.startOneShot(timeout);
    62     }
    63 
    64     void cancelTimer()
    65     {
    66         m_timer.stop();
    67     }
    68 
    69     virtual void timerFired(Timer<AnimationTimerBase>*) = 0;
    70 
    71 private:
    72     Timer<AnimationTimerBase> m_timer;
    73 
    74 protected:
    75     AnimationBase* m_anim;
    76 };
    77 
    78 class AnimationTimerCallback : public AnimationTimerBase {
    79 public:
    80     AnimationTimerCallback(AnimationBase* anim)
    81         : AnimationTimerBase(anim)
    82         , m_elapsedTime(0)
    83     {
    84     }
    85 
    86     virtual ~AnimationTimerCallback() { }
    87 
    88     virtual void timerFired(Timer<AnimationTimerBase>*);
    89 
    90     void startTimer(double timeout, const AtomicString& eventType, double elapsedTime)
    91     {
    92         m_eventType = eventType;
    93         m_elapsedTime = elapsedTime;
    94         AnimationTimerBase::startTimer(timeout);
    95     }
    96 
    97 private:
    98     AtomicString m_eventType;
    99     double m_elapsedTime;
    100 };
    101 
    10247class AnimationBase : public RefCounted<AnimationBase> {
    10348    friend class CompositeAnimationPrivate;
     
    11257    double startTime() const { return m_startTime; }
    11358    double duration() const;
    114 
    115     void cancelTimers()
    116     {
    117         m_animationTimerCallback.cancelTimer();
    118     }
    11959
    12060    // Animations and Transitions go through the states below. When entering the STARTED state
     
    179119    // (e.g. a software animation)
    180120    void setAnimating(bool inAnimating = true) { m_isAnimating = inAnimating; }
    181     bool isAnimating() const { return m_isAnimating; }
     121    double willNeedService() const;
    182122
    183123    double progress(double scale, double offset, const TimingFunction*) const;
     
    188128    virtual bool shouldFireEvents() const { return false; }
    189129
    190     void animationTimerCallbackFired(const AtomicString& eventType, double elapsedTime);
     130    void fireAnimationEventsIfNeeded();
    191131
    192132    bool animationsMatch(const Animation*) const;
     
    227167    virtual void endAnimation(bool reset) { }
    228168
    229     void primeEventTimers();
     169    void goIntoEndingOrLoopingState();
    230170
    231171    static bool propertiesEqual(int prop, const RenderStyle* a, const RenderStyle* b);
     
    245185    double m_startTime;
    246186    double m_pauseTime;
     187    double m_requestedStartTime;
    247188    RenderObject* m_object;
    248189
    249     AnimationTimerCallback m_animationTimerCallback;
    250190    RefPtr<Animation> m_animation;
    251191    CompositeAnimation* m_compAnim;
    252192    bool m_transformFunctionListValid;
     193    double m_totalDuration, m_nextIterationDuration;
    253194};
    254195
  • trunk/WebCore/page/animation/AnimationController.cpp

    r39059 r39211  
    3131#include "CompositeAnimation.h"
    3232#include "CSSParser.h"
     33#include "EventNames.h"
    3334#include "Frame.h"
    3435#include "Timer.h"
     
    4748
    4849    void animationTimerFired(Timer<AnimationControllerPrivate>*);
    49     void updateAnimationTimer();
     50    void updateAnimationTimer(bool callSetChanged = false);
    5051
    5152    void updateRenderingDispatcherFired(Timer<AnimationControllerPrivate>*);
    5253    void startUpdateRenderingDispatcher();
     54    void addEventToDispatch(PassRefPtr<Element> element, const AtomicString& eventType, const String& name, double elapsedTime);
    5355
    5456    bool hasAnimations() const { return !m_compositeAnimations.isEmpty(); }
     
    7173    Timer<AnimationControllerPrivate> m_updateRenderingDispatcher;
    7274    Frame* m_frame;
     75   
     76    class EventToDispatch {
     77    public:
     78        RefPtr<Element> element;
     79        AtomicString eventType;
     80        String name;
     81        double elapsedTime;
     82    };
     83   
     84    Vector<EventToDispatch> m_eventsToDispatch;
    7385};
    7486
     
    122134}
    123135
    124 void AnimationControllerPrivate::updateAnimationTimer()
    125 {
    126     bool isAnimating = false;
     136void AnimationControllerPrivate::updateAnimationTimer(bool callSetChanged/* = false*/)
     137{
     138    double needsService = -1;
     139    bool calledSetChanged = false;
    127140
    128141    RenderObjectAnimationMap::const_iterator animationsEnd = m_compositeAnimations.end();
    129142    for (RenderObjectAnimationMap::const_iterator it = m_compositeAnimations.begin(); it != animationsEnd; ++it) {
    130143        RefPtr<CompositeAnimation> compAnim = it->second;
    131         if (!compAnim->isSuspended() && compAnim->isAnimating()) {
    132             isAnimating = true;
    133             break;
     144        if (!compAnim->isSuspended()) {
     145            double t = compAnim->willNeedService();
     146            if (t != -1 && (t < needsService || needsService == -1))
     147                needsService = t;
     148            if (needsService == 0) {
     149                if (callSetChanged) {
     150                    Node* node = it->first->element();
     151                    ASSERT(!node || (node->document() && !node->document()->inPageCache()));
     152                    node->setChanged(AnimationStyleChange);
     153                    calledSetChanged = true;
     154                }
     155                else
     156                    break;
     157            }
    134158        }
    135159    }
    136160   
    137     if (isAnimating) {
    138         if (!m_animationTimer.isActive())
     161    if (calledSetChanged)
     162        m_frame->document()->updateRendering();
     163   
     164    // If we want service immediately, we start a repeating timer to reduce the overhead of starting
     165    if (needsService == 0) {
     166        if (!m_animationTimer.isActive() || m_animationTimer.repeatInterval() == 0)
    139167            m_animationTimer.startRepeating(cAnimationTimerDelay);
    140     } else if (m_animationTimer.isActive())
     168        return;
     169    }
     170   
     171    // If we don't need service, we want to make sure the timer is no longer running
     172    if (needsService < 0) {
     173        if (m_animationTimer.isActive())
     174            m_animationTimer.stop();
     175        return;
     176    }
     177   
     178    // Otherwise, we want to start a one-shot timer so we get here again
     179    if (m_animationTimer.isActive())
    141180        m_animationTimer.stop();
     181    m_animationTimer.startOneShot(needsService);
    142182}
    143183
    144184void AnimationControllerPrivate::updateRenderingDispatcherFired(Timer<AnimationControllerPrivate>*)
    145185{
     186    // fire all the events
     187    Vector<EventToDispatch>::const_iterator end = m_eventsToDispatch.end();
     188    for (Vector<EventToDispatch>::const_iterator it = m_eventsToDispatch.begin(); it != end; ++it) {
     189        if (it->eventType == eventNames().webkitTransitionEndEvent)
     190            it->element->dispatchWebKitTransitionEvent(it->eventType,it->name, it->elapsedTime);
     191        else
     192            it->element->dispatchWebKitAnimationEvent(it->eventType,it->name, it->elapsedTime);
     193    }
     194   
     195    m_eventsToDispatch.clear();
     196   
    146197    if (m_frame && m_frame->document())
    147198        m_frame->document()->updateRendering();
     
    154205}
    155206
     207void AnimationControllerPrivate::addEventToDispatch(PassRefPtr<Element> element, const AtomicString& eventType, const String& name, double elapsedTime)
     208{
     209    m_eventsToDispatch.grow(m_eventsToDispatch.size()+1);
     210    EventToDispatch& event = m_eventsToDispatch[m_eventsToDispatch.size()-1];
     211    event.element = element;
     212    event.eventType = eventType;
     213    event.name = name;
     214    event.elapsedTime = elapsedTime;
     215   
     216    startUpdateRenderingDispatcher();
     217}
     218
    156219void AnimationControllerPrivate::animationTimerFired(Timer<AnimationControllerPrivate>* timer)
    157220{
    158221    // When the timer fires, all we do is call setChanged on all DOM nodes with running animations and then do an immediate
    159222    // updateRendering.  It will then call back to us with new information.
    160     bool isAnimating = false;
    161     RenderObjectAnimationMap::const_iterator animationsEnd = m_compositeAnimations.end();
    162     for (RenderObjectAnimationMap::const_iterator it = m_compositeAnimations.begin(); it != animationsEnd; ++it) {
    163         RefPtr<CompositeAnimation> compAnim = it->second;
    164         if (!compAnim->isSuspended() && compAnim->isAnimating()) {
    165             isAnimating = true;
    166             compAnim->setAnimating(false);
    167 
    168             Node* node = it->first->element();
    169             ASSERT(!node || (node->document() && !node->document()->inPageCache()));
    170             node->setChanged(AnimationStyleChange);
    171         }
    172     }
    173 
    174     m_frame->document()->updateRendering();
    175 
    176     updateAnimationTimer();
     223    updateAnimationTimer(true);
    177224}
    178225
     
    343390}
    344391
     392void AnimationController::addEventToDispatch(PassRefPtr<Element> element, const AtomicString& eventType, const String& name, double elapsedTime)
     393{
     394    m_data->addEventToDispatch(element, eventType, name, elapsedTime);
     395}
     396
    345397void AnimationController::styleAvailable()
    346398{
  • trunk/WebCore/page/animation/AnimationController.h

    r38526 r39211  
    3535
    3636class AnimationControllerPrivate;
     37class AtomicString;
    3738class Document;
     39class Element;
    3840class Frame;
    3941class Node;
     
    6062    void suspendAnimations(Document*);
    6163    void resumeAnimations(Document*);
    62     void updateAnimationTimer();
    6364
    6465    void startUpdateRenderingDispatcher();
     66    void addEventToDispatch(PassRefPtr<Element>, const AtomicString& eventType, const String& name, double elapsedTime);
    6567
    6668    void styleAvailable();
  • trunk/WebCore/page/animation/CompositeAnimation.cpp

    r39059 r39211  
    5858
    5959    void setAnimating(bool);
    60     bool isAnimating() const;
    61    
    62     const KeyframeAnimation* getAnimationForProperty(int property) const;
     60    double willNeedService() const;
     61   
     62    PassRefPtr<KeyframeAnimation> getAnimationForProperty(int property);
    6363
    6464    void cleanupFinishedAnimations(RenderObject*);
     
    158158            // and we have to use the unanimatedStyle from the animation. We do the test
    159159            // against the unanimated style here, but we "override" the transition later.
    160             const KeyframeAnimation* keyframeAnim = getAnimationForProperty(prop);
     160            RefPtr<KeyframeAnimation> keyframeAnim = getAnimationForProperty(prop);
    161161            RenderStyle* fromStyle = keyframeAnim ? keyframeAnim->unanimatedStyle() : currentStyle;
    162162
     
    308308}
    309309
    310 bool CompositeAnimationPrivate::isAnimating() const
    311 {
     310double CompositeAnimationPrivate::willNeedService() const
     311{
     312    // Returns the time at which next service is required. -1 means no service is required. 0 means
     313    // service is required now, and > 0 means service is required that many seconds in the future.
     314    double minT = -1;
     315   
    312316    CSSPropertyTransitionsMap::const_iterator transitionsEnd = m_transitions.end();
    313317    for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != transitionsEnd; ++it) {
    314318        ImplicitAnimation* transition = it->second.get();
    315         if (transition && !transition->paused() && transition->isAnimating() && transition->active())
    316             return true;
    317     }
    318 
    319     AnimationNameMap::const_iterator animationsEnd = m_keyframeAnimations.end();
    320     for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != animationsEnd; ++it) {
    321         KeyframeAnimation* anim = it->second.get();
    322         if (anim && !anim->paused() && anim->isAnimating() && anim->active())
    323             return true;
    324     }
    325 
    326     return false;
    327 }
    328 
    329 const KeyframeAnimation* CompositeAnimationPrivate::getAnimationForProperty(int property) const
    330 {
    331     const KeyframeAnimation* retval = 0;
     319        double t = transition ? transition->willNeedService() : -1;
     320        if (t < minT || minT == -1)
     321            minT = t;
     322        if (minT == 0)
     323            return 0;
     324    }
     325
     326    AnimationNameMap::const_iterator animationsEnd = m_keyframeAnimations.end();
     327    for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != animationsEnd; ++it) {
     328        KeyframeAnimation* animation = it->second.get();
     329        double t = animation ? animation->willNeedService() : -1;
     330        if (t < minT || minT == -1)
     331            minT = t;
     332        if (minT == 0)
     333            return 0;
     334    }
     335
     336    return minT;
     337}
     338
     339PassRefPtr<KeyframeAnimation> CompositeAnimationPrivate::getAnimationForProperty(int property)
     340{
     341    RefPtr<KeyframeAnimation> retval;
    332342   
    333343    // We want to send back the last animation with the property if there are multiples.
     
    335345    AnimationNameMap::const_iterator animationsEnd = m_keyframeAnimations.end();
    336346    for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != animationsEnd; ++it) {
    337         const KeyframeAnimation* anim = it->second.get();
     347        RefPtr<KeyframeAnimation> anim = it->second;
    338348        if (anim->hasAnimationForProperty(property))
    339349            retval = anim;
     
    572582}
    573583
     584AnimationController* CompositeAnimation::animationController()
     585{
     586    return m_data->animationController();
     587}
     588
    574589void CompositeAnimation::clearRenderer()
    575590{
     
    582597}
    583598
    584 AnimationController* CompositeAnimation::animationController()
    585 {
    586     return m_data->animationController();
    587 }
    588 
    589 bool CompositeAnimation::isAnimating() const
    590 {
    591     return m_data->isAnimating();
     599double CompositeAnimation::willNeedService() const
     600{
     601    return m_data->willNeedService();
    592602}
    593603
     
    632642}
    633643
     644PassRefPtr<KeyframeAnimation> CompositeAnimation::getAnimationForProperty(int property)
     645{
     646    return m_data->getAnimationForProperty(property);
     647}
     648
    634649void CompositeAnimation::setAnimationStartTime(double t)
    635650{
  • trunk/WebCore/page/animation/CompositeAnimation.h

    r39059 r39211  
    3939class CompositeAnimationPrivate;
    4040class AnimationController;
     41class KeyframeAnimation;
    4142class RenderObject;
    4243class RenderStyle;
     
    5657
    5758    PassRefPtr<RenderStyle> animate(RenderObject*, RenderStyle* currentStyle, RenderStyle* targetStyle);
    58     bool isAnimating() const;
     59    double willNeedService() const;
    5960   
    6061    AnimationController* animationController();
     
    7071    void setAnimating(bool);
    7172    bool isAnimatingProperty(int property, bool isRunningNow) const;
     73   
     74    PassRefPtr<KeyframeAnimation> getAnimationForProperty(int property);
     75
    7276
    7377    void setAnimationStartTime(double t);
  • trunk/WebCore/page/animation/ImplicitAnimation.cpp

    r38876 r39211  
    2828
    2929#include "config.h"
     30
     31#include "AnimationController.h"
     32#include "CompositeAnimation.h"
    3033#include "CSSPropertyNames.h"
    3134#include "EventNames.h"
    3235#include "ImplicitAnimation.h"
     36#include "KeyframeAnimation.h"
    3337#include "RenderObject.h"
    3438
     
    7680    if (blendProperties(this, m_animatingProperty, animatedStyle.get(), m_fromStyle.get(), m_toStyle.get(), progress(1, 0, 0)))
    7781        setAnimating();
     82
     83    // Fire the start timeout if needed
     84    fireAnimationEventsIfNeeded();
    7885}
    7986
    8087void ImplicitAnimation::onAnimationEnd(double elapsedTime)
    8188{
     89    // If we have a keyframe animation on this property, this transition is being overridden. The keyframe
     90    // animation keeps an unanimated style in case a transition starts while the keyframe animation is
     91    // running. But now that the transition has completed, we need to update this style with its new
     92    // destination. If we didn't, the next time through we would think a transition had started
     93    // (comparing the old unanimated style with the new final style of the transition).
     94    RefPtr<KeyframeAnimation> keyframeAnim = m_compAnim->getAnimationForProperty(m_animatingProperty);
     95    if (keyframeAnim)
     96        keyframeAnim->setUnanimatedStyle(m_toStyle);
     97   
    8298    if (!sendTransitionEvent(eventNames().webkitTransitionEndEvent, elapsedTime)) {
    8399        // We didn't dispatch an event, which would call endAnimation(), so we'll just call it here.
     
    105121                return false;
    106122
    107             // Call the event handler
    108             element->dispatchWebKitTransitionEvent(eventType, propertyName, elapsedTime);
     123            // Schedule event handling
     124            m_object->animation()->addEventToDispatch(element, eventType, propertyName, elapsedTime);
    109125
    110126            // Restore the original (unanimated) style
    111             if (eventType == eventNames().webkitAnimationEndEvent && element->renderer())
     127            if (eventType == eventNames().webkitTransitionEndEvent && element->renderer())
    112128                setChanged(element.get());
    113129
  • trunk/WebCore/page/animation/ImplicitAnimation.h

    r37637 r39211  
    5555    virtual bool overridden() const { return m_overridden; }
    5656
    57     virtual bool shouldFireEvents() const { return true; }
    58 
    5957    virtual bool affectsProperty(int) const;
    6058
  • trunk/WebCore/page/animation/KeyframeAnimation.cpp

    r39176 r39211  
    3030#include "KeyframeAnimation.h"
    3131
     32#include "AnimationController.h"
    3233#include "CSSPropertyNames.h"
    3334#include "CSSStyleSelector.h"
     
    6364                                    const RenderStyle* targetStyle, RefPtr<RenderStyle>& animatedStyle)
    6465{
     66    // Fire the start timeout if needed
     67    fireAnimationEventsIfNeeded();
     68   
    6569    // If we have not yet started, we will not have a valid start time, so just start the animation if needed.
    6670    if (isNew() && m_animation->playState() == AnimPlayStatePlaying)
     
    201205            return false;
    202206
    203         // Call the event handler
    204         element->dispatchWebKitAnimationEvent(eventType, m_keyframes.animationName(), elapsedTime);
     207        // Schedule event handling
     208        m_object->animation()->addEventToDispatch(element, eventType, m_keyframes.animationName(), elapsedTime);
    205209
    206210        // Restore the original (unanimated) style
  • trunk/WebCore/page/animation/KeyframeAnimation.h

    r37637 r39211  
    5252    void setIndex(int i) { m_index = i; }
    5353
    54     virtual bool shouldFireEvents() const { return true; }
    55    
    5654    bool hasAnimationForProperty(int property) const;
    5755   
     56    void setUnanimatedStyle(PassRefPtr<RenderStyle> style) { m_unanimatedStyle = style; }
    5857    RenderStyle* unanimatedStyle() const { return m_unanimatedStyle.get(); }
    5958
Note: See TracChangeset for help on using the changeset viewer.