Index: Source/core/frame/animation/KeyframeAnimation.cpp |
diff --git a/Source/core/frame/animation/KeyframeAnimation.cpp b/Source/core/frame/animation/KeyframeAnimation.cpp |
deleted file mode 100644 |
index 948ca03ce42a6223c549d875860d56af61678db6..0000000000000000000000000000000000000000 |
--- a/Source/core/frame/animation/KeyframeAnimation.cpp |
+++ /dev/null |
@@ -1,455 +0,0 @@ |
-/* |
- * Copyright (C) 2007, 2012 Apple Inc. All rights reserved. |
- * |
- * Redistribution and use in source and binary forms, with or without |
- * modification, are permitted provided that the following conditions |
- * are met: |
- * |
- * 1. Redistributions of source code must retain the above copyright |
- * notice, this list of conditions and the following disclaimer. |
- * 2. Redistributions in binary form must reproduce the above copyright |
- * notice, this list of conditions and the following disclaimer in the |
- * documentation and/or other materials provided with the distribution. |
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of |
- * its contributors may be used to endorse or promote products derived |
- * from this software without specific prior written permission. |
- * |
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY |
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY |
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
- */ |
- |
-#include "config.h" |
-#include "core/frame/animation/KeyframeAnimation.h" |
- |
-#include "CSSPropertyNames.h" |
-#include "core/css/resolver/StyleResolver.h" |
-#include "core/events/ThreadLocalEventNames.h" |
-#include "core/frame/UseCounter.h" |
-#include "core/frame/animation/AnimationControllerPrivate.h" |
-#include "core/frame/animation/CSSPropertyAnimation.h" |
-#include "core/frame/animation/CompositeAnimation.h" |
-#include "core/rendering/RenderBoxModelObject.h" |
-#include "core/rendering/style/RenderStyle.h" |
-#include "public/platform/Platform.h" |
- |
-using namespace std; |
- |
-namespace WebCore { |
- |
-KeyframeAnimation::KeyframeAnimation(const CSSAnimationData* animation, RenderObject& renderer, int index, CompositeAnimation* compAnim, RenderStyle& unanimatedStyle) |
- : AnimationBase(animation, renderer, compAnim) |
- , m_keyframes(renderer, animation->name()) |
- , m_index(index) |
- , m_startEventDispatched(false) |
- , m_unanimatedStyle(unanimatedStyle) |
-{ |
- // Get the keyframe RenderStyles |
- if (m_object && m_object->node() && m_object->node()->isElementNode()) |
- m_object->document().ensureStyleResolver().keyframeStylesForAnimation(toElement(m_object->node()), unanimatedStyle, m_keyframes); |
- |
- // Update the m_transformFunctionListValid flag based on whether the function lists in the keyframes match. |
- validateTransformFunctionList(); |
- checkForMatchingFilterFunctionLists(); |
- HashSet<CSSPropertyID>::const_iterator endProperties = m_keyframes.endProperties(); |
- for (HashSet<CSSPropertyID>::const_iterator it = m_keyframes.beginProperties(); it != endProperties; ++it) |
- blink::Platform::current()->histogramSparse("WebCore.Animation.CSSProperties", UseCounter::mapCSSPropertyIdToCSSSampleIdForHistogram(*it)); |
-} |
- |
-KeyframeAnimation::~KeyframeAnimation() |
-{ |
- // Make sure to tell the renderer that we are ending. This will make sure any accelerated animations are removed. |
- if (!postActive()) |
- endAnimation(); |
-} |
- |
-void KeyframeAnimation::fetchIntervalEndpointsForProperty(CSSPropertyID property, const RenderStyle*& fromStyle, const RenderStyle*& toStyle, double& prog) const |
-{ |
- // Find the first key |
- double elapsedTime = getElapsedTime(); |
- if (m_animation->duration() && m_animation->iterationCount() != CSSAnimationData::IterationCountInfinite) |
- elapsedTime = min(elapsedTime, m_animation->duration() * m_animation->iterationCount()); |
- |
- const double fractionalTime = this->fractionalTime(1, elapsedTime, 0); |
- |
- size_t numKeyframes = m_keyframes.size(); |
- if (!numKeyframes) |
- return; |
- |
- ASSERT(!m_keyframes[0].key()); |
- ASSERT(m_keyframes[m_keyframes.size() - 1].key() == 1); |
- |
- size_t currentIndex = 0; |
- size_t firstIndex = 0; |
- size_t lastIndex = numKeyframes - 1; |
- size_t distance = numKeyframes; |
- |
- // Find keyframe that is closest to elapsed time. |
- while (distance > 1) { |
- currentIndex = (lastIndex + firstIndex) >> 1; |
- double key = m_keyframes[currentIndex].key(); |
- distance = lastIndex - currentIndex; |
- |
- if (key < fractionalTime) { |
- if (distance < 2) |
- currentIndex++; |
- firstIndex = currentIndex; |
- } else { |
- lastIndex = currentIndex; |
- } |
- } |
- |
- int prevIndex = -1; |
- int nextIndex = -1; |
- |
- // Iterate forward to find next keyframe that is used to animate CSS property. |
- for (size_t i = currentIndex; i < numKeyframes; ++i) { |
- const KeyframeValue& keyFrame = m_keyframes[i]; |
- if (keyFrame.key() > fractionalTime && keyFrame.containsProperty(property)) { |
- nextIndex = i; |
- break; |
- } |
- } |
- |
- // Iterate backward to find previous keyframe. |
- for (int i = currentIndex; i >= 0; --i) { |
- const KeyframeValue& keyFrame = m_keyframes[i]; |
- if (keyFrame.key() <= fractionalTime && keyFrame.containsProperty(property)) { |
- prevIndex = i; |
- break; |
- } |
- } |
- |
- double scale = 1; |
- double offset = 0; |
- |
- if (prevIndex == -1) |
- prevIndex = 0; |
- |
- if (nextIndex == -1) |
- nextIndex = numKeyframes - 1; |
- |
- const KeyframeValue& prevKeyframe = m_keyframes[prevIndex]; |
- const KeyframeValue& nextKeyframe = m_keyframes[nextIndex]; |
- |
- fromStyle = prevKeyframe.style(); |
- toStyle = nextKeyframe.style(); |
- |
- offset = prevKeyframe.key(); |
- scale = 1.0 / (nextKeyframe.key() - prevKeyframe.key()); |
- // A scale of infinity is handled in AnimationBase::fractionalTime(). |
- ASSERT(scale >= 0 && (!std::isinf(scale) || prevIndex == nextIndex)); |
- |
- prog = progress(scale, offset, KeyframeValue::timingFunction(*prevKeyframe.style())); |
-} |
- |
-void KeyframeAnimation::animate(CompositeAnimation*, RenderObject*, const RenderStyle*, RenderStyle* targetStyle, RefPtr<RenderStyle>& animatedStyle) |
-{ |
- // Fire the start timeout if needed |
- fireAnimationEventsIfNeeded(); |
- |
- // If we have not yet started, we will not have a valid start time, so just start the animation if needed. |
- if (isNew() && m_animation->playState() == AnimPlayStatePlaying) |
- updateStateMachine(AnimationStateInputStartAnimation, -1); |
- |
- // If we get this far and the animation is done, it means we are cleaning up a just finished animation. |
- // If so, we need to send back the targetStyle. |
- if (postActive()) { |
- if (!animatedStyle) |
- animatedStyle = const_cast<RenderStyle*>(targetStyle); |
- return; |
- } |
- |
- // If we are waiting for the start timer, we don't want to change the style yet. |
- // Special case 1 - if the delay time is 0, then we do want to set the first frame of the |
- // animation right away. This avoids a flash when the animation starts. |
- // Special case 2 - if there is a backwards fill mode, then we want to continue |
- // through to the style blend so that we get the fromStyle. |
- if (waitingToStart() && m_animation->delay() > 0 && !m_animation->fillsBackwards()) |
- return; |
- |
- // If we have no keyframes, don't animate. |
- if (!m_keyframes.size()) { |
- updateStateMachine(AnimationStateInputEndAnimation, -1); |
- return; |
- } |
- |
- // Run a cycle of animation. |
- // We know we will need a new render style, so make one if needed. |
- if (!animatedStyle) |
- animatedStyle = RenderStyle::clone(targetStyle); |
- |
- // FIXME: we need to be more efficient about determining which keyframes we are animating between. |
- // We should cache the last pair or something. |
- HashSet<CSSPropertyID>::const_iterator endProperties = m_keyframes.endProperties(); |
- for (HashSet<CSSPropertyID>::const_iterator it = m_keyframes.beginProperties(); it != endProperties; ++it) { |
- // Get the from/to styles and progress between |
- const RenderStyle* fromStyle = 0; |
- const RenderStyle* toStyle = 0; |
- double progress = 0.0; |
- fetchIntervalEndpointsForProperty(*it, fromStyle, toStyle, progress); |
- |
- bool needsAnim = CSSPropertyAnimation::blendProperties(this, *it, animatedStyle.get(), fromStyle, toStyle, progress); |
- if (!needsAnim) |
- // If we are running an accelerated animation, set a flag in the style |
- // to indicate it. This can be used to make sure we get an updated |
- // style for hit testing, etc. |
- animatedStyle->setIsRunningAcceleratedAnimation(); |
- } |
-} |
- |
-void KeyframeAnimation::getAnimatedStyle(RefPtr<RenderStyle>& animatedStyle) |
-{ |
- // If we're in the delay phase and we're not backwards filling, tell the caller |
- // to use the current style. |
- if (waitingToStart() && m_animation->delay() > 0 && !m_animation->fillsBackwards()) |
- return; |
- |
- if (!m_keyframes.size()) |
- return; |
- |
- if (!animatedStyle) |
- animatedStyle = RenderStyle::clone(m_object->style()); |
- |
- HashSet<CSSPropertyID>::const_iterator endProperties = m_keyframes.endProperties(); |
- for (HashSet<CSSPropertyID>::const_iterator it = m_keyframes.beginProperties(); it != endProperties; ++it) { |
- // Get the from/to styles and progress between |
- const RenderStyle* fromStyle = 0; |
- const RenderStyle* toStyle = 0; |
- double progress = 0.0; |
- fetchIntervalEndpointsForProperty(*it, fromStyle, toStyle, progress); |
- |
- CSSPropertyAnimation::blendProperties(this, *it, animatedStyle.get(), fromStyle, toStyle, progress); |
- } |
-} |
- |
-bool KeyframeAnimation::hasAnimationForProperty(CSSPropertyID property) const |
-{ |
- return m_keyframes.containsProperty(property); |
-} |
- |
-void KeyframeAnimation::startAnimation(double timeOffset) |
-{ |
- if (m_object && m_object->compositingState() == PaintsIntoOwnBacking) |
- m_isAccelerated = toRenderBoxModelObject(m_object)->startAnimation(timeOffset, m_animation.get(), m_keyframes); |
-} |
- |
-void KeyframeAnimation::pauseAnimation(double timeOffset) |
-{ |
- if (!m_object) |
- return; |
- |
- if (m_object && m_object->compositingState() == PaintsIntoOwnBacking && isAccelerated()) |
- toRenderBoxModelObject(m_object)->animationPaused(timeOffset, m_keyframes.animationName()); |
- |
- // Restore the original (unanimated) style |
- if (!paused()) |
- setNeedsStyleRecalc(m_object->node()); |
-} |
- |
-void KeyframeAnimation::endAnimation() |
-{ |
- if (!m_object) |
- return; |
- |
- if (m_object && m_object->compositingState() == PaintsIntoOwnBacking && isAccelerated()) |
- toRenderBoxModelObject(m_object)->animationFinished(m_keyframes.animationName()); |
- m_isAccelerated = false; |
- |
- // Restore the original (unanimated) style |
- if (!paused()) |
- setNeedsStyleRecalc(m_object->node()); |
-} |
- |
-bool KeyframeAnimation::shouldSendEventForListener(Document::ListenerType listenerType) const |
-{ |
- return m_object->document().hasListenerType(listenerType); |
-} |
- |
-void KeyframeAnimation::onAnimationStart(double elapsedTime) |
-{ |
- sendAnimationEvent(EventTypeNames::animationstart, elapsedTime); |
-} |
- |
-void KeyframeAnimation::onAnimationIteration(double elapsedTime) |
-{ |
- sendAnimationEvent(EventTypeNames::animationiteration, elapsedTime); |
-} |
- |
-void KeyframeAnimation::onAnimationEnd(double elapsedTime) |
-{ |
- sendAnimationEvent(EventTypeNames::animationend, elapsedTime); |
- // End the animation if we don't fill forwards. Forward filling |
- // animations are ended properly in the class destructor. |
- if (!m_animation->fillsForwards()) |
- endAnimation(); |
-} |
- |
-bool KeyframeAnimation::sendAnimationEvent(const AtomicString& eventType, double elapsedTime) |
-{ |
- Document::ListenerType listenerType; |
- if (eventType == EventTypeNames::animationiteration) |
- listenerType = Document::ANIMATIONITERATION_LISTENER; |
- else if (eventType == EventTypeNames::animationend) |
- listenerType = Document::ANIMATIONEND_LISTENER; |
- else { |
- ASSERT(eventType == EventTypeNames::animationstart); |
- if (m_startEventDispatched) |
- return false; |
- m_startEventDispatched = true; |
- listenerType = Document::ANIMATIONSTART_LISTENER; |
- } |
- |
- if (shouldSendEventForListener(listenerType)) { |
- // Dispatch the event |
- RefPtr<Element> element; |
- if (m_object->node() && m_object->node()->isElementNode()) |
- element = toElement(m_object->node()); |
- |
- if (!element) |
- return false; |
- |
- // Schedule event handling |
- m_compAnim->animationController()->addEventToDispatch(element, eventType, m_keyframes.animationName(), elapsedTime); |
- |
- // Restore the original (unanimated) style |
- if (eventType == EventTypeNames::animationend && element->renderer()) |
- setNeedsStyleRecalc(element.get()); |
- |
- return true; // Did dispatch an event |
- } |
- |
- return false; // Did not dispatch an event |
-} |
- |
-void KeyframeAnimation::overrideAnimations() |
-{ |
- // This will override implicit animations that match the properties in the keyframe animation |
- HashSet<CSSPropertyID>::const_iterator end = m_keyframes.endProperties(); |
- for (HashSet<CSSPropertyID>::const_iterator it = m_keyframes.beginProperties(); it != end; ++it) |
- compositeAnimation()->overrideImplicitAnimations(*it); |
-} |
- |
-void KeyframeAnimation::resumeOverriddenAnimations() |
-{ |
- // This will resume overridden implicit animations |
- HashSet<CSSPropertyID>::const_iterator end = m_keyframes.endProperties(); |
- for (HashSet<CSSPropertyID>::const_iterator it = m_keyframes.beginProperties(); it != end; ++it) |
- compositeAnimation()->resumeOverriddenImplicitAnimations(*it); |
-} |
- |
-bool KeyframeAnimation::affectsProperty(CSSPropertyID property) const |
-{ |
- return m_keyframes.containsProperty(property); |
-} |
- |
-void KeyframeAnimation::validateTransformFunctionList() |
-{ |
- m_transformFunctionListValid = false; |
- |
- if (m_keyframes.size() < 2 || !m_keyframes.containsProperty(CSSPropertyWebkitTransform)) |
- return; |
- |
- // Empty transforms match anything, so find the first non-empty entry as the reference |
- size_t numKeyframes = m_keyframes.size(); |
- size_t firstNonEmptyTransformKeyframeIndex = numKeyframes; |
- |
- for (size_t i = 0; i < numKeyframes; ++i) { |
- const KeyframeValue& currentKeyframe = m_keyframes[i]; |
- if (currentKeyframe.style()->transform().operations().size()) { |
- firstNonEmptyTransformKeyframeIndex = i; |
- break; |
- } |
- } |
- |
- if (firstNonEmptyTransformKeyframeIndex == numKeyframes) |
- return; |
- |
- const TransformOperations* firstVal = &m_keyframes[firstNonEmptyTransformKeyframeIndex].style()->transform(); |
- |
- // See if the keyframes are valid |
- for (size_t i = firstNonEmptyTransformKeyframeIndex + 1; i < numKeyframes; ++i) { |
- const KeyframeValue& currentKeyframe = m_keyframes[i]; |
- const TransformOperations* val = ¤tKeyframe.style()->transform(); |
- |
- // An emtpy transform list matches anything. |
- if (val->operations().isEmpty()) |
- continue; |
- |
- if (!firstVal->operationsMatch(*val)) |
- return; |
- } |
- |
- // Keyframes are valid |
- m_transformFunctionListValid = true; |
-} |
- |
-void KeyframeAnimation::checkForMatchingFilterFunctionLists() |
-{ |
- m_filterFunctionListsMatch = false; |
- |
- if (m_keyframes.size() < 2 || !m_keyframes.containsProperty(CSSPropertyWebkitFilter)) |
- return; |
- |
- // Empty filters match anything, so find the first non-empty entry as the reference |
- size_t numKeyframes = m_keyframes.size(); |
- size_t firstNonEmptyFilterKeyframeIndex = numKeyframes; |
- |
- for (size_t i = 0; i < numKeyframes; ++i) { |
- const KeyframeValue& currentKeyframe = m_keyframes[i]; |
- if (currentKeyframe.style()->filter().operations().size()) { |
- firstNonEmptyFilterKeyframeIndex = i; |
- break; |
- } |
- } |
- |
- if (firstNonEmptyFilterKeyframeIndex == numKeyframes) |
- return; |
- |
- const FilterOperations* firstVal = &m_keyframes[firstNonEmptyFilterKeyframeIndex].style()->filter(); |
- |
- for (size_t i = firstNonEmptyFilterKeyframeIndex + 1; i < numKeyframes; ++i) { |
- const KeyframeValue& currentKeyframe = m_keyframes[i]; |
- const FilterOperations* val = ¤tKeyframe.style()->filter(); |
- |
- if (!firstVal->canInterpolateWith(*val)) |
- return; |
- } |
- |
- m_filterFunctionListsMatch = true; |
-} |
- |
-double KeyframeAnimation::timeToNextService() |
-{ |
- double t = AnimationBase::timeToNextService(); |
- if (t != 0 || preActive()) |
- return t; |
- |
- // A return value of 0 means we need service. But if we only have accelerated animations we |
- // only need service at the end of the transition |
- HashSet<CSSPropertyID>::const_iterator endProperties = m_keyframes.endProperties(); |
- bool acceleratedPropertiesOnly = true; |
- |
- for (HashSet<CSSPropertyID>::const_iterator it = m_keyframes.beginProperties(); it != endProperties; ++it) { |
- if (!CSSPropertyAnimation::animationOfPropertyIsAccelerated(*it) || !isAccelerated()) { |
- acceleratedPropertiesOnly = false; |
- break; |
- } |
- } |
- |
- if (acceleratedPropertiesOnly) { |
- bool isLooping; |
- getTimeToNextEvent(t, isLooping); |
- } |
- |
- return t; |
-} |
- |
-} // namespace WebCore |