Home | History | Annotate | Download | only in animation
      1 /*
      2  * Copyright (C) 2013 Intel Corporation. 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  * 1. Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2. Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
     17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #include "config.h"
     27 
     28 #include "core/rendering/animation/WebAnimationProvider.h"
     29 
     30 #include "core/platform/animation/AnimationTranslationUtil.h"
     31 #include "core/platform/animation/CSSAnimationData.h"
     32 #include "core/rendering/style/KeyframeList.h"
     33 #include "core/rendering/style/RenderStyle.h"
     34 #include "public/platform/WebAnimation.h"
     35 #include "wtf/text/StringBuilder.h"
     36 
     37 using blink::WebAnimation;
     38 
     39 namespace WebCore {
     40 
     41 namespace {
     42 
     43 String animationNameForTransition(AnimatedPropertyID property)
     44 {
     45     // | is not a valid identifier character in CSS, so this can never conflict with a keyframe identifier.
     46     StringBuilder id;
     47     id.appendLiteral("-|transition");
     48     id.appendNumber(static_cast<int>(property));
     49     id.append('-');
     50     return id.toString();
     51 }
     52 
     53 AnimatedPropertyID cssToGraphicsLayerProperty(CSSPropertyID cssProperty)
     54 {
     55     switch (cssProperty) {
     56     case CSSPropertyWebkitTransform:
     57         return AnimatedPropertyWebkitTransform;
     58     case CSSPropertyOpacity:
     59         return AnimatedPropertyOpacity;
     60     case CSSPropertyBackgroundColor:
     61         ASSERT_NOT_REACHED();
     62         return AnimatedPropertyInvalid; // Chromium compositor cannot accelerate background color yet.
     63     case CSSPropertyWebkitFilter:
     64         return AnimatedPropertyWebkitFilter;
     65     default:
     66         // It's fine if we see other css properties here; they are just not accelerated.
     67         break;
     68     }
     69     return AnimatedPropertyInvalid;
     70 }
     71 
     72 } // namespace
     73 
     74 WebAnimations::WebAnimations()
     75 {
     76 }
     77 
     78 WebAnimations::~WebAnimations()
     79 {
     80 }
     81 
     82 // Copy constructor is needed to use this struct as a return value. It actually moves the ownership, not copy.
     83 WebAnimations::WebAnimations(const WebAnimations& other)
     84 {
     85     ASSERT(isEmpty());
     86     m_transformAnimation.swap(const_cast<OwnPtr<WebAnimation>& >(other.m_transformAnimation));
     87     m_opacityAnimation.swap(const_cast<OwnPtr<WebAnimation>& >(other.m_opacityAnimation));
     88     m_filterAnimation.swap(const_cast<OwnPtr<WebAnimation>& >(other.m_filterAnimation));
     89     ASSERT(other.isEmpty());
     90 }
     91 
     92 bool WebAnimations::isEmpty() const
     93 {
     94     return !m_transformAnimation && !m_opacityAnimation && !m_filterAnimation;
     95 }
     96 
     97 WebAnimationProvider::WebAnimationProvider()
     98 {
     99 }
    100 
    101 WebAnimationProvider::~WebAnimationProvider()
    102 {
    103 }
    104 
    105 int WebAnimationProvider::getWebAnimationId(const String& animationName) const
    106 {
    107     if (!m_animationIdMap.contains(animationName))
    108         return 0;
    109     return m_animationIdMap.get(animationName);
    110 }
    111 
    112 int WebAnimationProvider::getWebAnimationId(CSSPropertyID property) const
    113 {
    114     AnimatedPropertyID animatedProperty = cssToGraphicsLayerProperty(property);
    115     ASSERT(animatedProperty != AnimatedPropertyInvalid);
    116     return getWebAnimationId(animationNameForTransition(animatedProperty));
    117 }
    118 
    119 WebAnimations WebAnimationProvider::startAnimation(double timeOffset, const CSSAnimationData* anim, const KeyframeList& keyframes, bool hasTransform, const IntSize& boxSize)
    120 {
    121     ASSERT(hasTransform || boxSize.isEmpty());
    122     bool hasOpacity = keyframes.containsProperty(CSSPropertyOpacity);
    123     bool hasFilter = keyframes.containsProperty(CSSPropertyWebkitFilter);
    124 
    125     if (!hasOpacity && !hasTransform && !hasFilter)
    126         return WebAnimations();
    127 
    128     KeyframeValueList transformVector(AnimatedPropertyWebkitTransform);
    129     KeyframeValueList opacityVector(AnimatedPropertyOpacity);
    130     KeyframeValueList filterVector(AnimatedPropertyWebkitFilter);
    131 
    132     size_t numKeyframes = keyframes.size();
    133     for (size_t i = 0; i < numKeyframes; ++i) {
    134         const KeyframeValue& currentKeyframe = keyframes[i];
    135         const RenderStyle* keyframeStyle = currentKeyframe.style();
    136         double key = currentKeyframe.key();
    137 
    138         if (!keyframeStyle)
    139             continue;
    140 
    141         // Get timing function.
    142         RefPtr<TimingFunction> tf = KeyframeValue::timingFunction(*keyframeStyle);
    143 
    144         bool isFirstOrLastKeyframe = !key || key == 1;
    145         if ((hasTransform && isFirstOrLastKeyframe) || currentKeyframe.containsProperty(CSSPropertyWebkitTransform))
    146             transformVector.insert(adoptPtr(new TransformAnimationValue(key, &(keyframeStyle->transform()), tf)));
    147 
    148         if ((hasOpacity && isFirstOrLastKeyframe) || currentKeyframe.containsProperty(CSSPropertyOpacity))
    149             opacityVector.insert(adoptPtr(new FloatAnimationValue(key, keyframeStyle->opacity(), tf)));
    150 
    151         if ((hasFilter && isFirstOrLastKeyframe) || currentKeyframe.containsProperty(CSSPropertyWebkitFilter))
    152             filterVector.insert(adoptPtr(new FilterAnimationValue(key, &(keyframeStyle->filter()), tf)));
    153     }
    154     WebAnimations resultAnimations;
    155     if (hasTransform)
    156         resultAnimations.m_transformAnimation = createWebAnimationAndStoreId(transformVector, boxSize, anim, keyframes.animationName(), timeOffset);
    157     if (hasOpacity)
    158         resultAnimations.m_opacityAnimation = createWebAnimationAndStoreId(opacityVector, IntSize(), anim, keyframes.animationName(), timeOffset);
    159     if (hasFilter)
    160         resultAnimations.m_filterAnimation = createWebAnimationAndStoreId(filterVector, IntSize(), anim, keyframes.animationName(), timeOffset);
    161 
    162     return resultAnimations;
    163 }
    164 
    165 WebAnimations WebAnimationProvider::startTransition(double timeOffset, CSSPropertyID property, const RenderStyle* fromStyle, const RenderStyle* toStyle, bool hasTransform, bool hasFilter, const IntSize& boxSize, float fromOpacity, float toOpacity)
    166 {
    167     ASSERT(property != CSSPropertyInvalid);
    168     ASSERT(property == CSSPropertyOpacity || (!fromOpacity && !toOpacity));
    169 
    170     WebAnimations resultAnimations;
    171     if (property == CSSPropertyOpacity) {
    172         const CSSAnimationData* opacityAnim = toStyle->transitionForProperty(CSSPropertyOpacity);
    173         if (opacityAnim && !opacityAnim->isEmptyOrZeroDuration()) {
    174             KeyframeValueList opacityVector(AnimatedPropertyOpacity);
    175             opacityVector.insert(adoptPtr(new FloatAnimationValue(0, fromOpacity)));
    176             opacityVector.insert(adoptPtr(new FloatAnimationValue(1, toOpacity)));
    177             resultAnimations.m_opacityAnimation = createWebAnimationAndStoreId(opacityVector, IntSize(), opacityAnim, animationNameForTransition(AnimatedPropertyOpacity), timeOffset);
    178         }
    179     }
    180     if (property == CSSPropertyWebkitTransform && hasTransform) {
    181         const CSSAnimationData* transformAnim = toStyle->transitionForProperty(CSSPropertyWebkitTransform);
    182         if (transformAnim && !transformAnim->isEmptyOrZeroDuration()) {
    183             KeyframeValueList transformVector(AnimatedPropertyWebkitTransform);
    184             transformVector.insert(adoptPtr(new TransformAnimationValue(0, &fromStyle->transform())));
    185             transformVector.insert(adoptPtr(new TransformAnimationValue(1, &toStyle->transform())));
    186             resultAnimations.m_transformAnimation = createWebAnimationAndStoreId(transformVector, boxSize, transformAnim, animationNameForTransition(AnimatedPropertyWebkitTransform), timeOffset);
    187         }
    188     }
    189     if (property == CSSPropertyWebkitFilter && hasFilter) {
    190         const CSSAnimationData* filterAnim = toStyle->transitionForProperty(CSSPropertyWebkitFilter);
    191         if (filterAnim && !filterAnim->isEmptyOrZeroDuration()) {
    192             KeyframeValueList filterVector(AnimatedPropertyWebkitFilter);
    193             filterVector.insert(adoptPtr(new FilterAnimationValue(0, &fromStyle->filter())));
    194             filterVector.insert(adoptPtr(new FilterAnimationValue(1, &toStyle->filter())));
    195             resultAnimations.m_filterAnimation = createWebAnimationAndStoreId(filterVector, IntSize(), filterAnim, animationNameForTransition(AnimatedPropertyWebkitFilter), timeOffset);
    196         }
    197     }
    198 
    199     return resultAnimations;
    200 }
    201 
    202 PassOwnPtr<WebAnimation> WebAnimationProvider::createWebAnimationAndStoreId(const KeyframeValueList& values, const IntSize& boxSize, const CSSAnimationData* animation, const String& animationName, double timeOffset)
    203 {
    204     int animationId = getWebAnimationId(animationName);
    205     OwnPtr<WebAnimation> webAnimation(createWebAnimation(values, animation, animationId, timeOffset, boxSize));
    206     if (!webAnimation)
    207         return PassOwnPtr<WebAnimation>();
    208 
    209     if (!animationId)
    210         m_animationIdMap.set(animationName, webAnimation->id());
    211     return webAnimation.release();
    212 }
    213 
    214 } // namespace WebCore
    215