diff options
author | Ben Murdoch <benm@google.com> | 2009-08-11 17:01:47 +0100 |
---|---|---|
committer | Ben Murdoch <benm@google.com> | 2009-08-11 18:21:02 +0100 |
commit | 0bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5 (patch) | |
tree | 2943df35f62d885c89d01063cc528dd73b480fea /WebCore/page/animation | |
parent | 7e7a70bfa49a1122b2597a1e6367d89eb4035eca (diff) | |
download | external_webkit-0bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5.zip external_webkit-0bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5.tar.gz external_webkit-0bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5.tar.bz2 |
Merge in WebKit r47029.
Diffstat (limited to 'WebCore/page/animation')
-rw-r--r-- | WebCore/page/animation/AnimationBase.cpp | 55 | ||||
-rw-r--r-- | WebCore/page/animation/AnimationBase.h | 3 | ||||
-rw-r--r-- | WebCore/page/animation/AnimationController.cpp | 18 | ||||
-rw-r--r-- | WebCore/page/animation/CompositeAnimation.cpp | 316 | ||||
-rw-r--r-- | WebCore/page/animation/CompositeAnimation.h | 2 | ||||
-rw-r--r-- | WebCore/page/animation/ImplicitAnimation.cpp | 5 | ||||
-rw-r--r-- | WebCore/page/animation/ImplicitAnimation.h | 4 | ||||
-rw-r--r-- | WebCore/page/animation/KeyframeAnimation.cpp | 12 |
8 files changed, 216 insertions, 199 deletions
diff --git a/WebCore/page/animation/AnimationBase.cpp b/WebCore/page/animation/AnimationBase.cpp index 7b8a189..7503f0a 100644 --- a/WebCore/page/animation/AnimationBase.cpp +++ b/WebCore/page/animation/AnimationBase.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007 Apple Inc. All rights reserved. + * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -45,6 +45,8 @@ #include "MatrixTransformOperation.h" #include "Matrix3DTransformOperation.h" #include "RenderBox.h" +#include "RenderLayer.h" +#include "RenderLayerBacking.h" #include "RenderStyle.h" #include "UnitBezier.h" @@ -113,11 +115,23 @@ static inline IntSize blendFunc(const AnimationBase* anim, const IntSize& from, blendFunc(anim, from.height(), to.height(), progress)); } +static inline ShadowStyle blendFunc(const AnimationBase* anim, ShadowStyle from, ShadowStyle to, double progress) +{ + if (from == to) + return to; + + double fromVal = from == Normal ? 1 : 0; + double toVal = to == Normal ? 1 : 0; + double result = blendFunc(anim, fromVal, toVal, progress); + return result > 0 ? Normal : Inset; +} + static inline ShadowData* blendFunc(const AnimationBase* anim, const ShadowData* from, const ShadowData* to, double progress) { ASSERT(from && to); return new ShadowData(blendFunc(anim, from->x, to->x, progress), blendFunc(anim, from->y, to->y, progress), - blendFunc(anim, from->blur, to->blur, progress), blendFunc(anim, from->color, to->color, progress)); + blendFunc(anim, from->blur, to->blur, progress), blendFunc(anim, from->spread, to->spread, progress), + blendFunc(anim, from->style, to->style, progress), blendFunc(anim, from->color, to->color, progress)); } static inline TransformOperations blendFunc(const AnimationBase* anim, const TransformOperations& from, const TransformOperations& to, double progress) @@ -300,7 +314,7 @@ public: { ShadowData* shadowA = (a->*m_getter)(); ShadowData* shadowB = (b->*m_getter)(); - ShadowData defaultShadowData(0, 0, 0, Color::transparent); + ShadowData defaultShadowData(0, 0, 0, 0, Normal, Color::transparent); if (!shadowA) shadowA = &defaultShadowData; @@ -404,8 +418,15 @@ static void ensurePropertyMap() gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyRight, &RenderStyle::right, &RenderStyle::setRight)); gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyTop, &RenderStyle::top, &RenderStyle::setTop)); gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyBottom, &RenderStyle::bottom, &RenderStyle::setBottom)); + gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWidth, &RenderStyle::width, &RenderStyle::setWidth)); + gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMinWidth, &RenderStyle::minWidth, &RenderStyle::setMinWidth)); + gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMaxWidth, &RenderStyle::maxWidth, &RenderStyle::setMaxWidth)); + gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyHeight, &RenderStyle::height, &RenderStyle::setHeight)); + gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMinHeight, &RenderStyle::minHeight, &RenderStyle::setMinHeight)); + gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMaxHeight, &RenderStyle::maxHeight, &RenderStyle::setMaxHeight)); + gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyBorderLeftWidth, &RenderStyle::borderLeftWidth, &RenderStyle::setBorderLeftWidth)); gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyBorderRightWidth, &RenderStyle::borderRightWidth, &RenderStyle::setBorderRightWidth)); gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyBorderTopWidth, &RenderStyle::borderTopWidth, &RenderStyle::setBorderTopWidth)); @@ -442,16 +463,18 @@ static void ensurePropertyMap() gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyOutlineWidth, &RenderStyle::outlineWidth, &RenderStyle::setOutlineWidth)); gPropertyWrappers->append(new PropertyWrapper<int>(CSSPropertyLetterSpacing, &RenderStyle::letterSpacing, &RenderStyle::setLetterSpacing)); gPropertyWrappers->append(new PropertyWrapper<int>(CSSPropertyWordSpacing, &RenderStyle::wordSpacing, &RenderStyle::setWordSpacing)); + gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyTextIndent, &RenderStyle::textIndent, &RenderStyle::setTextIndent)); + gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyWebkitPerspective, &RenderStyle::perspective, &RenderStyle::setPerspective)); gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWebkitPerspectiveOriginX, &RenderStyle::perspectiveOriginX, &RenderStyle::setPerspectiveOriginX)); gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWebkitPerspectiveOriginY, &RenderStyle::perspectiveOriginY, &RenderStyle::setPerspectiveOriginY)); gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWebkitTransformOriginX, &RenderStyle::transformOriginX, &RenderStyle::setTransformOriginX)); gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWebkitTransformOriginY, &RenderStyle::transformOriginY, &RenderStyle::setTransformOriginY)); gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyWebkitTransformOriginZ, &RenderStyle::transformOriginZ, &RenderStyle::setTransformOriginZ)); - gPropertyWrappers->append(new PropertyWrapper<const IntSize&>(CSSPropertyWebkitBorderTopLeftRadius, &RenderStyle::borderTopLeftRadius, &RenderStyle::setBorderTopLeftRadius)); - gPropertyWrappers->append(new PropertyWrapper<const IntSize&>(CSSPropertyWebkitBorderTopRightRadius, &RenderStyle::borderTopRightRadius, &RenderStyle::setBorderTopRightRadius)); - gPropertyWrappers->append(new PropertyWrapper<const IntSize&>(CSSPropertyWebkitBorderBottomLeftRadius, &RenderStyle::borderBottomLeftRadius, &RenderStyle::setBorderBottomLeftRadius)); - gPropertyWrappers->append(new PropertyWrapper<const IntSize&>(CSSPropertyWebkitBorderBottomRightRadius, &RenderStyle::borderBottomRightRadius, &RenderStyle::setBorderBottomRightRadius)); + gPropertyWrappers->append(new PropertyWrapper<const IntSize&>(CSSPropertyBorderTopLeftRadius, &RenderStyle::borderTopLeftRadius, &RenderStyle::setBorderTopLeftRadius)); + gPropertyWrappers->append(new PropertyWrapper<const IntSize&>(CSSPropertyBorderTopRightRadius, &RenderStyle::borderTopRightRadius, &RenderStyle::setBorderTopRightRadius)); + gPropertyWrappers->append(new PropertyWrapper<const IntSize&>(CSSPropertyBorderBottomLeftRadius, &RenderStyle::borderBottomLeftRadius, &RenderStyle::setBorderBottomLeftRadius)); + gPropertyWrappers->append(new PropertyWrapper<const IntSize&>(CSSPropertyBorderBottomRightRadius, &RenderStyle::borderBottomRightRadius, &RenderStyle::setBorderBottomRightRadius)); gPropertyWrappers->append(new PropertyWrapper<EVisibility>(CSSPropertyVisibility, &RenderStyle::visibility, &RenderStyle::setVisibility)); gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyZoom, &RenderStyle::zoom, &RenderStyle::setZoom)); @@ -473,7 +496,7 @@ static void ensurePropertyMap() gPropertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyOutlineColor, &RenderStyle::outlineColor, &RenderStyle::setOutlineColor)); // These are for shadows - gPropertyWrappers->append(new PropertyWrapperShadow(CSSPropertyWebkitBoxShadow, &RenderStyle::boxShadow, &RenderStyle::setBoxShadow)); + gPropertyWrappers->append(new PropertyWrapperShadow(CSSPropertyBoxShadow, &RenderStyle::boxShadow, &RenderStyle::setBoxShadow)); gPropertyWrappers->append(new PropertyWrapperShadow(CSSPropertyTextShadow, &RenderStyle::textShadow, &RenderStyle::setTextShadow)); #if ENABLE(SVG) @@ -484,8 +507,6 @@ static void ensurePropertyMap() // TODO: // - // CSSPropertyMinWidth, CSSPropertyMaxWidth, CSSPropertyMinHeight, CSSPropertyMaxHeight - // CSSPropertyTextIndent // CSSPropertyVerticalAlign // // Compound properties that have components that should be animatable: @@ -1041,7 +1062,7 @@ void AnimationBase::getTimeToNextEvent(double& time, bool& isLooping) const double nextIterationTime = m_totalDuration; if (m_totalDuration < 0 || elapsedDuration < m_totalDuration) { - durationLeft = m_animation->duration() - fmod(elapsedDuration, m_animation->duration()); + durationLeft = m_animation->duration() > 0 ? (m_animation->duration() - fmod(elapsedDuration, m_animation->duration())) : 0; nextIterationTime = elapsedDuration + durationLeft; } @@ -1065,10 +1086,18 @@ void AnimationBase::goIntoEndingOrLoopingState() m_animState = isLooping ? AnimationStateLooping : AnimationStateEnding; } -void AnimationBase::pauseAtTime(double t) +void AnimationBase::freezeAtTime(double t) { - updatePlayState(false); + ASSERT(m_startTime); // if m_startTime is zero, we haven't started yet, so we'll get a bad pause time. m_pauseTime = m_startTime + t - m_animation->delay(); + +#if USE(ACCELERATED_COMPOSITING) + if (m_object && m_object->hasLayer()) { + RenderLayer* layer = toRenderBoxModelObject(m_object)->layer(); + if (layer->isComposited()) + layer->backing()->suspendAnimations(m_pauseTime); + } +#endif } double AnimationBase::beginAnimationUpdateTime() const diff --git a/WebCore/page/animation/AnimationBase.h b/WebCore/page/animation/AnimationBase.h index 8f55a8e..3482f65 100644 --- a/WebCore/page/animation/AnimationBase.h +++ b/WebCore/page/animation/AnimationBase.h @@ -156,7 +156,8 @@ public: bool isTransformFunctionListValid() const { return m_transformFunctionListValid; } - void pauseAtTime(double t); + // Freeze the animation; used by DumpRenderTree. + void freezeAtTime(double t); double beginAnimationUpdateTime() const; diff --git a/WebCore/page/animation/AnimationController.cpp b/WebCore/page/animation/AnimationController.cpp index 58a1f5b..ed241e1 100644 --- a/WebCore/page/animation/AnimationController.cpp +++ b/WebCore/page/animation/AnimationController.cpp @@ -136,9 +136,9 @@ void AnimationControllerPrivate::updateStyleIfNeededDispatcherFired(Timer<Animat Vector<EventToDispatch>::const_iterator eventsToDispatchEnd = m_eventsToDispatch.end(); for (Vector<EventToDispatch>::const_iterator it = m_eventsToDispatch.begin(); it != eventsToDispatchEnd; ++it) { if (it->eventType == eventNames().webkitTransitionEndEvent) - it->element->dispatchWebKitTransitionEvent(it->eventType,it->name, it->elapsedTime); + it->element->dispatchWebKitTransitionEvent(it->eventType, it->name, it->elapsedTime); else - it->element->dispatchWebKitAnimationEvent(it->eventType,it->name, it->elapsedTime); + it->element->dispatchWebKitAnimationEvent(it->eventType, it->name, it->elapsedTime); } m_eventsToDispatch.clear(); @@ -152,20 +152,6 @@ void AnimationControllerPrivate::updateStyleIfNeededDispatcherFired(Timer<Animat if (m_frame) m_frame->document()->updateStyleIfNeeded(); - - // We can now safely remove any animations or transitions that are finished. - // We can't remove them any earlier because we might get a false restart of - // a transition. This can happen because we have not yet set the final property - // value until we call the rendering dispatcher. So this can make the current - // style slightly different from the desired final style (because our last - // animation step was, say 0.9999 or something). And we need to remove them - // here because if there are no more animations running we'll never get back - // into the animation code to clean them up. - RenderObjectAnimationMap::const_iterator animationsEnd = m_compositeAnimations.end(); - for (RenderObjectAnimationMap::const_iterator it = m_compositeAnimations.begin(); it != animationsEnd; ++it) { - CompositeAnimation* compAnim = it->second.get(); - compAnim->cleanupFinishedAnimations(); // will not modify m_compositeAnimations, so OK to call while iterating - } } void AnimationControllerPrivate::startUpdateStyleIfNeededDispatcher() diff --git a/WebCore/page/animation/CompositeAnimation.cpp b/WebCore/page/animation/CompositeAnimation.cpp index d60455a..8946d80 100644 --- a/WebCore/page/animation/CompositeAnimation.cpp +++ b/WebCore/page/animation/CompositeAnimation.cpp @@ -67,91 +67,117 @@ void CompositeAnimation::clearRenderer() void CompositeAnimation::updateTransitions(RenderObject* renderer, RenderStyle* currentStyle, RenderStyle* targetStyle) { - RefPtr<RenderStyle> modifiedCurrentStyle; - - // If currentStyle is null, we don't do transitions - if (!currentStyle || !targetStyle->transitions()) + // If currentStyle is null or there are no old or new transitions, just skip it + if (!currentStyle || (!targetStyle->transitions() && m_transitions.isEmpty())) return; + // Mark all existing transitions as no longer active. We will mark the still active ones + // in the next loop and then toss the ones that didn't get marked. + CSSPropertyTransitionsMap::const_iterator end = m_transitions.end(); + for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != end; ++it) + it->second->setActive(false); + + RefPtr<RenderStyle> modifiedCurrentStyle; + // Check to see if we need to update the active transitions - for (size_t i = 0; i < targetStyle->transitions()->size(); ++i) { - const Animation* anim = targetStyle->transitions()->animation(i); - bool isActiveTransition = anim->duration() || anim->delay() > 0; + if (targetStyle->transitions()) { + for (size_t i = 0; i < targetStyle->transitions()->size(); ++i) { + const Animation* anim = targetStyle->transitions()->animation(i); + bool isActiveTransition = anim->duration() || anim->delay() > 0; - int prop = anim->property(); + int prop = anim->property(); - if (prop == cAnimateNone) - continue; - - bool all = prop == cAnimateAll; + if (prop == cAnimateNone) + continue; - // Handle both the 'all' and single property cases. For the single prop case, we make only one pass - // through the loop. - for (int propertyIndex = 0; propertyIndex < AnimationBase::getNumProperties(); ++propertyIndex) { - if (all) { - // Get the next property which is not a shorthand. - bool isShorthand; - prop = AnimationBase::getPropertyAtIndex(propertyIndex, isShorthand); - if (isShorthand) - continue; - } + bool all = prop == cAnimateAll; + + // Handle both the 'all' and single property cases. For the single prop case, we make only one pass + // through the loop. + for (int propertyIndex = 0; propertyIndex < AnimationBase::getNumProperties(); ++propertyIndex) { + if (all) { + // Get the next property which is not a shorthand. + bool isShorthand; + prop = AnimationBase::getPropertyAtIndex(propertyIndex, isShorthand); + if (isShorthand) + continue; + } - // ImplicitAnimations are always hashed by actual properties, never cAnimateAll - ASSERT(prop >= firstCSSProperty && prop < (firstCSSProperty + numCSSProperties)); - - // If there is a running animation for this property, the transition is overridden - // and we have to use the unanimatedStyle from the animation. We do the test - // against the unanimated style here, but we "override" the transition later. - RefPtr<KeyframeAnimation> keyframeAnim = getAnimationForProperty(prop); - RenderStyle* fromStyle = keyframeAnim ? keyframeAnim->unanimatedStyle() : currentStyle; - - // See if there is a current transition for this prop - ImplicitAnimation* implAnim = m_transitions.get(prop).get(); - bool equal = true; - - if (implAnim) { - // This might be a transition that is just finishing. That would be the case - // if it were postActive. But we still need to check for equality because - // it could be just finishing AND changing to a new goal state. - // - // This implAnim might also not be an already running transition. It might be - // newly added to the list in a previous iteration. This would happen if - // you have both an explicit transition-property and 'all' in the same - // list. In this case, the latter one overrides the earlier one, so we - // behave as though this is a running animation being replaced. - if (!implAnim->isTargetPropertyEqual(prop, targetStyle)) { -#if USE(ACCELERATED_COMPOSITING) - // For accelerated animations we need to return a new RenderStyle with the _current_ value - // of the property, so that restarted transitions use the correct starting point. - if (AnimationBase::animationOfPropertyIsAccelerated(prop) && !implAnim->isFallbackAnimating()) { - if (!modifiedCurrentStyle) - modifiedCurrentStyle = RenderStyle::clone(currentStyle); - - implAnim->blendPropertyValueInStyle(prop, modifiedCurrentStyle.get()); + // ImplicitAnimations are always hashed by actual properties, never cAnimateAll + ASSERT(prop >= firstCSSProperty && prop < (firstCSSProperty + numCSSProperties)); + + // If there is a running animation for this property, the transition is overridden + // and we have to use the unanimatedStyle from the animation. We do the test + // against the unanimated style here, but we "override" the transition later. + RefPtr<KeyframeAnimation> keyframeAnim = getAnimationForProperty(prop); + RenderStyle* fromStyle = keyframeAnim ? keyframeAnim->unanimatedStyle() : currentStyle; + + // See if there is a current transition for this prop + ImplicitAnimation* implAnim = m_transitions.get(prop).get(); + bool equal = true; + + if (implAnim) { + // If we are post active don't bother setting the active flag. This will cause + // this animation to get removed at the end of this function. + if (!implAnim->postActive()) + implAnim->setActive(true); + + // This might be a transition that is just finishing. That would be the case + // if it were postActive. But we still need to check for equality because + // it could be just finishing AND changing to a new goal state. + // + // This implAnim might also not be an already running transition. It might be + // newly added to the list in a previous iteration. This would happen if + // you have both an explicit transition-property and 'all' in the same + // list. In this case, the latter one overrides the earlier one, so we + // behave as though this is a running animation being replaced. + if (!implAnim->isTargetPropertyEqual(prop, targetStyle)) { + #if USE(ACCELERATED_COMPOSITING) + // For accelerated animations we need to return a new RenderStyle with the _current_ value + // of the property, so that restarted transitions use the correct starting point. + if (AnimationBase::animationOfPropertyIsAccelerated(prop) && !implAnim->isFallbackAnimating()) { + if (!modifiedCurrentStyle) + modifiedCurrentStyle = RenderStyle::clone(currentStyle); + + implAnim->blendPropertyValueInStyle(prop, modifiedCurrentStyle.get()); + } + #endif + m_transitions.remove(prop); + equal = false; } -#endif - m_transitions.remove(prop); - equal = false; + } else { + // We need to start a transition if it is active and the properties don't match + equal = !isActiveTransition || AnimationBase::propertiesEqual(prop, fromStyle, targetStyle); } - } else { - // We need to start a transition if it is active and the properties don't match - equal = !isActiveTransition || AnimationBase::propertiesEqual(prop, fromStyle, targetStyle); - } - // We can be in this loop with an inactive transition (!isActiveTransition). We need - // to do that to check to see if we are canceling a transition. But we don't want to - // start one of the inactive transitions. So short circuit that here. (See - // <https://bugs.webkit.org/show_bug.cgi?id=24787> - if (!equal && isActiveTransition) { - // Add the new transition - m_transitions.set(prop, ImplicitAnimation::create(const_cast<Animation*>(anim), prop, renderer, this, modifiedCurrentStyle ? modifiedCurrentStyle.get() : fromStyle)); + // We can be in this loop with an inactive transition (!isActiveTransition). We need + // to do that to check to see if we are canceling a transition. But we don't want to + // start one of the inactive transitions. So short circuit that here. (See + // <https://bugs.webkit.org/show_bug.cgi?id=24787> + if (!equal && isActiveTransition) { + // Add the new transition + m_transitions.set(prop, ImplicitAnimation::create(const_cast<Animation*>(anim), prop, renderer, this, modifiedCurrentStyle ? modifiedCurrentStyle.get() : fromStyle)); + } + + // We only need one pass for the single prop case + if (!all) + break; } - - // We only need one pass for the single prop case - if (!all) - break; } } + + // Make a list of transitions to be removed + Vector<int> toBeRemoved; + end = m_transitions.end(); + for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != end; ++it) { + ImplicitAnimation* anim = it->second.get(); + if (!anim->active()) + toBeRemoved.append(anim->animatingProperty()); + } + + // Now remove the transitions from the list + for (size_t j = 0; j < toBeRemoved.size(); ++j) + m_transitions.remove(toBeRemoved[j]); } void CompositeAnimation::updateKeyframeAnimations(RenderObject* renderer, RenderStyle* currentStyle, RenderStyle* targetStyle) @@ -160,52 +186,62 @@ void CompositeAnimation::updateKeyframeAnimations(RenderObject* renderer, Render if (m_keyframeAnimations.isEmpty() && !targetStyle->hasAnimations()) return; - // Nothing to do if the current and target animations are the same - if (currentStyle && currentStyle->hasAnimations() && targetStyle->hasAnimations() && *(currentStyle->animations()) == *(targetStyle->animations())) - return; - - // Mark all existing animations as no longer active AnimationNameMap::const_iterator kfend = m_keyframeAnimations.end(); - for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != kfend; ++it) - it->second->setIndex(-1); - - // Toss the animation order map - m_keyframeAnimationOrderMap.clear(); - // Now mark any still active animations as active and add any new animations - if (targetStyle->animations()) { - int numAnims = targetStyle->animations()->size(); - for (int i = 0; i < numAnims; ++i) { - const Animation* anim = targetStyle->animations()->animation(i); - AtomicString animationName(anim->name()); - - if (!anim->isValidAnimation()) - continue; + if (currentStyle && currentStyle->hasAnimations() && targetStyle->hasAnimations() && *(currentStyle->animations()) == *(targetStyle->animations())) { + // The current and target animations are the same so we just need to toss any + // animation which is finished (postActive). + for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != kfend; ++it) { + if (it->second->postActive()) + it->second->setIndex(-1); + } + } else { + // Mark all existing animations as no longer active. + for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != kfend; ++it) + it->second->setIndex(-1); - // See if there is a current animation for this name - RefPtr<KeyframeAnimation> keyframeAnim = m_keyframeAnimations.get(animationName.impl()); + // Toss the animation order map. + m_keyframeAnimationOrderMap.clear(); + + // Now mark any still active animations as active and add any new animations. + if (targetStyle->animations()) { + int numAnims = targetStyle->animations()->size(); + for (int i = 0; i < numAnims; ++i) { + const Animation* anim = targetStyle->animations()->animation(i); + AtomicString animationName(anim->name()); + + if (!anim->isValidAnimation()) + continue; + + // See if there is a current animation for this name. + RefPtr<KeyframeAnimation> keyframeAnim = m_keyframeAnimations.get(animationName.impl()); - if (keyframeAnim) { - // There is one so it is still active - - // Animations match, but play states may differ. update if needed - keyframeAnim->updatePlayState(anim->playState() == AnimPlayStatePlaying); - - // Set the saved animation to this new one, just in case the play state has changed - keyframeAnim->setAnimation(anim); - keyframeAnim->setIndex(i); - } else if ((anim->duration() || anim->delay()) && anim->iterationCount()) { - keyframeAnim = KeyframeAnimation::create(const_cast<Animation*>(anim), renderer, i, this, currentStyle ? currentStyle : targetStyle); - m_keyframeAnimations.set(keyframeAnim->name().impl(), keyframeAnim); + if (keyframeAnim) { + // If this animation is postActive, skip it so it gets removed at the end of this function. + if (keyframeAnim->postActive()) + continue; + + // This one is still active. + + // Animations match, but play states may differ. Update if needed. + keyframeAnim->updatePlayState(anim->playState() == AnimPlayStatePlaying); + + // Set the saved animation to this new one, just in case the play state has changed. + keyframeAnim->setAnimation(anim); + keyframeAnim->setIndex(i); + } else if ((anim->duration() || anim->delay()) && anim->iterationCount()) { + keyframeAnim = KeyframeAnimation::create(const_cast<Animation*>(anim), renderer, i, this, currentStyle ? currentStyle : targetStyle); + m_keyframeAnimations.set(keyframeAnim->name().impl(), keyframeAnim); + } + + // Add this to the animation order map. + if (keyframeAnim) + m_keyframeAnimationOrderMap.append(keyframeAnim->name().impl()); } - - // Add this to the animation order map - if (keyframeAnim) - m_keyframeAnimationOrderMap.append(keyframeAnim->name().impl()); } } - - // Make a list of animations to be removed + + // Make a list of animations to be removed. Vector<AtomicStringImpl*> animsToBeRemoved; kfend = m_keyframeAnimations.end(); for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != kfend; ++it) { @@ -214,7 +250,7 @@ void CompositeAnimation::updateKeyframeAnimations(RenderObject* renderer, Render animsToBeRemoved.append(keyframeAnim->name().impl()); } - // Now remove the animations from the list + // Now remove the animations from the list. for (size_t j = 0; j < animsToBeRemoved.size(); ++j) m_keyframeAnimations.remove(animsToBeRemoved[j]); } @@ -223,11 +259,9 @@ PassRefPtr<RenderStyle> CompositeAnimation::animate(RenderObject* renderer, Rend { RefPtr<RenderStyle> resultStyle; - // Update animations first so we can see if any transitions are overridden - updateKeyframeAnimations(renderer, currentStyle, targetStyle); - - // We don't do any transitions if we don't have a currentStyle (on startup) + // We don't do any transitions if we don't have a currentStyle (on startup). updateTransitions(renderer, currentStyle, targetStyle); + updateKeyframeAnimations(renderer, currentStyle, targetStyle); if (currentStyle) { // Now that we have transition objects ready, let them know about the new goal state. We want them @@ -249,8 +283,6 @@ PassRefPtr<RenderStyle> CompositeAnimation::animate(RenderObject* renderer, Rend keyframeAnim->animate(this, renderer, currentStyle, targetStyle, resultStyle); } - cleanupFinishedAnimations(); - return resultStyle ? resultStyle.release() : targetStyle; } @@ -341,50 +373,6 @@ PassRefPtr<KeyframeAnimation> CompositeAnimation::getAnimationForProperty(int pr return retval; } -void CompositeAnimation::cleanupFinishedAnimations() -{ - if (isSuspended()) - return; - - // Make a list of transitions to be deleted - Vector<int> finishedTransitions; - if (!m_transitions.isEmpty()) { - CSSPropertyTransitionsMap::const_iterator transitionsEnd = m_transitions.end(); - - for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != transitionsEnd; ++it) { - ImplicitAnimation* anim = it->second.get(); - if (!anim) - continue; - if (anim->postActive()) - finishedTransitions.append(anim->animatingProperty()); - } - - // Delete them - size_t finishedTransitionCount = finishedTransitions.size(); - for (size_t i = 0; i < finishedTransitionCount; ++i) - m_transitions.remove(finishedTransitions[i]); - } - - // Make a list of animations to be deleted - Vector<AtomicStringImpl*> finishedAnimations; - if (!m_keyframeAnimations.isEmpty()) { - AnimationNameMap::const_iterator animationsEnd = m_keyframeAnimations.end(); - - for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != animationsEnd; ++it) { - KeyframeAnimation* anim = it->second.get(); - if (!anim) - continue; - if (anim->postActive()) - finishedAnimations.append(anim->name().impl()); - } - - // Delete them - size_t finishedAnimationCount = finishedAnimations.size(); - for (size_t i = 0; i < finishedAnimationCount; ++i) - m_keyframeAnimations.remove(finishedAnimations[i]); - } -} - void CompositeAnimation::suspendAnimations() { if (m_isSuspended) @@ -492,7 +480,7 @@ bool CompositeAnimation::pauseAnimationAtTime(const AtomicString& name, double t int count = keyframeAnim->m_animation->iterationCount(); if ((t >= 0.0) && (!count || (t <= count * keyframeAnim->duration()))) { - keyframeAnim->pauseAtTime(t); + keyframeAnim->freezeAtTime(t); return true; } @@ -509,7 +497,7 @@ bool CompositeAnimation::pauseTransitionAtTime(int property, double t) return false; if ((t >= 0.0) && (t <= implAnim->duration())) { - implAnim->pauseAtTime(t); + implAnim->freezeAtTime(t); return true; } diff --git a/WebCore/page/animation/CompositeAnimation.h b/WebCore/page/animation/CompositeAnimation.h index 739cfdc..b7db442 100644 --- a/WebCore/page/animation/CompositeAnimation.h +++ b/WebCore/page/animation/CompositeAnimation.h @@ -74,8 +74,6 @@ public: PassRefPtr<KeyframeAnimation> getAnimationForProperty(int property) const; - void cleanupFinishedAnimations(); - void overrideImplicitAnimations(int property); void resumeOverriddenImplicitAnimations(int property); diff --git a/WebCore/page/animation/ImplicitAnimation.cpp b/WebCore/page/animation/ImplicitAnimation.cpp index e93fee4..8e6349d 100644 --- a/WebCore/page/animation/ImplicitAnimation.cpp +++ b/WebCore/page/animation/ImplicitAnimation.cpp @@ -45,6 +45,7 @@ ImplicitAnimation::ImplicitAnimation(const Animation* transition, int animatingP , m_transitionProperty(transition->property()) , m_animatingProperty(animatingProperty) , m_overridden(false) + , m_active(true) , m_fromStyle(fromStyle) { ASSERT(animatingProperty != cAnimateAll); @@ -211,6 +212,10 @@ bool ImplicitAnimation::affectsProperty(int property) const bool ImplicitAnimation::isTargetPropertyEqual(int prop, const RenderStyle* targetStyle) { + // We can get here for a transition that has not started yet. This would make m_toStyle unset and null. + // So we check that here (see <https://bugs.webkit.org/show_bug.cgi?id=26706>) + if (!m_toStyle) + return false; return propertiesEqual(prop, m_toStyle.get(), targetStyle); } diff --git a/WebCore/page/animation/ImplicitAnimation.h b/WebCore/page/animation/ImplicitAnimation.h index 33fe4e4..7e286d2 100644 --- a/WebCore/page/animation/ImplicitAnimation.h +++ b/WebCore/page/animation/ImplicitAnimation.h @@ -66,6 +66,9 @@ public: void blendPropertyValueInStyle(int, RenderStyle* currentStyle); virtual double timeToNextService(); + + bool active() const { return m_active; } + void setActive(bool b) { m_active = b; } protected: bool shouldSendEventForListener(Document::ListenerType) const; @@ -80,6 +83,7 @@ private: int m_transitionProperty; // Transition property as specified in the RenderStyle. May be cAnimateAll int m_animatingProperty; // Specific property for this ImplicitAnimation bool m_overridden; // true when there is a keyframe animation that overrides the transitioning property + bool m_active; // used for culling the list of transitions // The two styles that we are blending. RefPtr<RenderStyle> m_fromStyle; diff --git a/WebCore/page/animation/KeyframeAnimation.cpp b/WebCore/page/animation/KeyframeAnimation.cpp index 3f84de1..39ae1e7 100644 --- a/WebCore/page/animation/KeyframeAnimation.cpp +++ b/WebCore/page/animation/KeyframeAnimation.cpp @@ -93,8 +93,10 @@ void KeyframeAnimation::getKeyframeAnimationInterval(const RenderStyle*& fromSty return; const TimingFunction* timingFunction = 0; - if (fromStyle->animations() && fromStyle->animations()->size() > 0) + if (fromStyle->animations() && fromStyle->animations()->size() > 0) { + // We get the timing function from the first animation, because we've synthesized a RenderStyle for each keyframe. timingFunction = &(fromStyle->animations()->animation(0)->timingFunction()); + } prog = progress(scale, offset, timingFunction); } @@ -209,8 +211,12 @@ void KeyframeAnimation::endAnimation(bool reset) #if USE(ACCELERATED_COMPOSITING) if (m_object->hasLayer()) { RenderLayer* layer = toRenderBoxModelObject(m_object)->layer(); - if (layer->isComposited()) - layer->backing()->animationFinished(m_keyframes.animationName(), 0, reset); + if (layer->isComposited()) { + if (reset) + layer->backing()->animationFinished(m_keyframes.animationName()); + else + layer->backing()->animationPaused(m_keyframes.animationName()); + } } #else UNUSED_PARAM(reset); |