• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
animationNameForTransition(AnimatedPropertyID property)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 
cssToGraphicsLayerProperty(CSSPropertyID cssProperty)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 
WebAnimations()74 WebAnimations::WebAnimations()
75 {
76 }
77 
~WebAnimations()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.
WebAnimations(const WebAnimations & other)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 
isEmpty() const92 bool WebAnimations::isEmpty() const
93 {
94     return !m_transformAnimation && !m_opacityAnimation && !m_filterAnimation;
95 }
96 
WebAnimationProvider()97 WebAnimationProvider::WebAnimationProvider()
98 {
99 }
100 
~WebAnimationProvider()101 WebAnimationProvider::~WebAnimationProvider()
102 {
103 }
104 
getWebAnimationId(const String & animationName) const105 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 
getWebAnimationId(CSSPropertyID property) const112 int WebAnimationProvider::getWebAnimationId(CSSPropertyID property) const
113 {
114     AnimatedPropertyID animatedProperty = cssToGraphicsLayerProperty(property);
115     ASSERT(animatedProperty != AnimatedPropertyInvalid);
116     return getWebAnimationId(animationNameForTransition(animatedProperty));
117 }
118 
startAnimation(double timeOffset,const CSSAnimationData * anim,const KeyframeList & keyframes,bool hasTransform,const IntSize & boxSize)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 
startTransition(double timeOffset,CSSPropertyID property,const RenderStyle * fromStyle,const RenderStyle * toStyle,bool hasTransform,bool hasFilter,const IntSize & boxSize,float fromOpacity,float toOpacity)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 
createWebAnimationAndStoreId(const KeyframeValueList & values,const IntSize & boxSize,const CSSAnimationData * animation,const String & animationName,double timeOffset)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