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