1 /*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "config.h"
18 #include "AndroidAnimation.h"
19
20 #if USE(ACCELERATED_COMPOSITING)
21
22 #include "Animation.h"
23 #include "GraphicsLayerAndroid.h"
24
25 #include "Timer.h"
26 #include "TimingFunction.h"
27 #include "TranslateTransformOperation.h"
28 #include "UnitBezier.h"
29
30 #include <wtf/CurrentTime.h>
31 #include <cutils/log.h>
32 #include <wtf/text/CString.h>
33
34 #undef XLOGC
35 #define XLOGC(...) android_printLog(ANDROID_LOG_DEBUG, "AndroidAnimation", __VA_ARGS__)
36
37 #ifdef DEBUG
38
39 #undef XLOG
40 #define XLOG(...) android_printLog(ANDROID_LOG_DEBUG, "AndroidAnimation", __VA_ARGS__)
41
42 #else
43
44 #undef XLOG
45 #define XLOG(...)
46
47 #endif // DEBUG
48
49
50 namespace WebCore {
51
52 static long gDebugAndroidAnimationInstances;
53
instancesCount()54 long AndroidAnimation::instancesCount()
55 {
56 return gDebugAndroidAnimationInstances;
57 }
58
AndroidAnimation(AnimatedPropertyID type,const Animation * animation,KeyframeValueList * operations,double beginTime)59 AndroidAnimation::AndroidAnimation(AnimatedPropertyID type,
60 const Animation* animation,
61 KeyframeValueList* operations,
62 double beginTime)
63 : m_beginTime(beginTime)
64 , m_duration(animation->duration())
65 , m_fillsBackwards(animation->fillsBackwards())
66 , m_fillsForwards(animation->fillsForwards())
67 , m_iterationCount(animation->iterationCount())
68 , m_direction(animation->direction())
69 , m_timingFunction(animation->timingFunction())
70 , m_type(type)
71 , m_operations(operations)
72 {
73 ASSERT(m_timingFunction);
74
75 if (!static_cast<int>(beginTime)) // time not set
76 m_beginTime = WTF::currentTime();
77
78 gDebugAndroidAnimationInstances++;
79 }
80
AndroidAnimation(AndroidAnimation * anim)81 AndroidAnimation::AndroidAnimation(AndroidAnimation* anim)
82 : m_beginTime(anim->m_beginTime)
83 , m_duration(anim->m_duration)
84 , m_fillsBackwards(anim->m_fillsBackwards)
85 , m_fillsForwards(anim->m_fillsForwards)
86 , m_iterationCount(anim->m_iterationCount)
87 , m_direction(anim->m_direction)
88 , m_timingFunction(anim->m_timingFunction)
89 , m_name(anim->name())
90 , m_type(anim->m_type)
91 , m_operations(anim->m_operations)
92 {
93 gDebugAndroidAnimationInstances++;
94 }
95
~AndroidAnimation()96 AndroidAnimation::~AndroidAnimation()
97 {
98 gDebugAndroidAnimationInstances--;
99 }
100
elapsedTime(double time)101 double AndroidAnimation::elapsedTime(double time)
102 {
103 if (m_beginTime <= 0.000001) // overflow or not correctly set
104 m_beginTime = time;
105
106 m_elapsedTime = time - m_beginTime;
107
108 if (m_duration <= 0)
109 m_duration = 0.000001;
110
111 if (m_elapsedTime < 0) // animation not yet started.
112 return 0;
113
114 return m_elapsedTime;
115 }
116
checkIterationsAndProgress(double time,float * finalProgress)117 bool AndroidAnimation::checkIterationsAndProgress(double time, float* finalProgress)
118 {
119 double progress = elapsedTime(time);
120 double dur = m_duration;
121 if (m_iterationCount > 0)
122 dur *= m_iterationCount;
123
124 if (m_duration <= 0)
125 return false;
126
127 // If not infinite, return false if we are done
128 if (m_iterationCount > 0 && progress > dur) {
129 *finalProgress = 1.0;
130 return false;
131 }
132
133 double fractionalTime = progress / m_duration;
134 int integralTime = static_cast<int>(fractionalTime);
135
136 fractionalTime -= integralTime;
137
138 if ((m_direction == Animation::AnimationDirectionAlternate) && (integralTime & 1))
139 fractionalTime = 1 - fractionalTime;
140
141 *finalProgress = fractionalTime;
142 return true;
143 }
144
applyTimingFunction(float from,float to,double progress,const TimingFunction * tf)145 double AndroidAnimation::applyTimingFunction(float from, float to, double progress,
146 const TimingFunction* tf)
147 {
148 double fractionalTime = progress;
149 double offset = from;
150 double scale = 1.0 / (to - from);
151
152 if (scale != 1 || offset)
153 fractionalTime = (fractionalTime - offset) * scale;
154
155 const TimingFunction* timingFunction = tf;
156
157 if (!timingFunction)
158 timingFunction = m_timingFunction.get();
159
160 if (timingFunction && timingFunction->isCubicBezierTimingFunction()) {
161 const CubicBezierTimingFunction* bezierFunction = static_cast<const CubicBezierTimingFunction*>(timingFunction);
162 UnitBezier bezier(bezierFunction->x1(),
163 bezierFunction->y1(),
164 bezierFunction->x2(),
165 bezierFunction->y2());
166 if (m_duration > 0)
167 fractionalTime = bezier.solve(fractionalTime, 1.0f / (200.0f * m_duration));
168 } else if (timingFunction && timingFunction->isStepsTimingFunction()) {
169 const StepsTimingFunction* stepFunction = static_cast<const StepsTimingFunction*>(timingFunction);
170 if (stepFunction->stepAtStart()) {
171 fractionalTime = (floor(stepFunction->numberOfSteps() * fractionalTime) + 1) / stepFunction->numberOfSteps();
172 if (fractionalTime > 1.0)
173 fractionalTime = 1.0;
174 } else {
175 fractionalTime = floor(stepFunction->numberOfSteps() * fractionalTime) / stepFunction->numberOfSteps();
176 }
177 }
178 return fractionalTime;
179 }
180
evaluate(LayerAndroid * layer,double time)181 bool AndroidAnimation::evaluate(LayerAndroid* layer, double time)
182 {
183 float progress;
184 if (!checkIterationsAndProgress(time, &progress)
185 && !(m_fillsBackwards || m_fillsForwards))
186 return false;
187
188 if (progress < 0) {
189 // The animation hasn't started yet
190 if (m_fillsBackwards) {
191 // in this case we want to apply the initial keyframe to the layer
192 applyForProgress(layer, 0);
193 }
194 // we still want to be evaluated until we get progress > 0
195 return true;
196 }
197
198 if (progress >= 1) {
199 if (!m_fillsForwards)
200 return false;
201 progress = 1;
202 }
203
204 if (!m_operations->size())
205 return false;
206
207 applyForProgress(layer, progress);
208
209 return true;
210 }
211
create(const Animation * animation,KeyframeValueList * operations,double beginTime)212 PassRefPtr<AndroidOpacityAnimation> AndroidOpacityAnimation::create(
213 const Animation* animation,
214 KeyframeValueList* operations,
215 double beginTime)
216 {
217 return adoptRef(new AndroidOpacityAnimation(animation, operations,
218 beginTime));
219 }
220
AndroidOpacityAnimation(const Animation * animation,KeyframeValueList * operations,double beginTime)221 AndroidOpacityAnimation::AndroidOpacityAnimation(const Animation* animation,
222 KeyframeValueList* operations,
223 double beginTime)
224 : AndroidAnimation(AnimatedPropertyOpacity, animation, operations, beginTime)
225 {
226 }
227
AndroidOpacityAnimation(AndroidOpacityAnimation * anim)228 AndroidOpacityAnimation::AndroidOpacityAnimation(AndroidOpacityAnimation* anim)
229 : AndroidAnimation(anim)
230 {
231 }
232
copy()233 PassRefPtr<AndroidAnimation> AndroidOpacityAnimation::copy()
234 {
235 return adoptRef(new AndroidOpacityAnimation(this));
236 }
237
pickValues(double progress,int * start,int * end)238 void AndroidAnimation::pickValues(double progress, int* start, int* end)
239 {
240 float distance = -1;
241 unsigned int foundAt = 0;
242 for (unsigned int i = 0; i < m_operations->size(); i++) {
243 const AnimationValue* value = m_operations->at(i);
244 float key = value->keyTime();
245 float d = progress - key;
246 if (distance == -1 || (d >= 0 && d < distance && i + 1 < m_operations->size())) {
247 distance = d;
248 foundAt = i;
249 }
250 }
251
252 *start = foundAt;
253
254 if (foundAt + 1 < m_operations->size())
255 *end = foundAt + 1;
256 else
257 *end = foundAt;
258 }
259
applyForProgress(LayerAndroid * layer,float progress)260 void AndroidOpacityAnimation::applyForProgress(LayerAndroid* layer, float progress)
261 {
262 // First, we need to get the from and to values
263 int from, to;
264 pickValues(progress, &from, &to);
265 FloatAnimationValue* fromValue = (FloatAnimationValue*) m_operations->at(from);
266 FloatAnimationValue* toValue = (FloatAnimationValue*) m_operations->at(to);
267
268 XLOG("[layer %d] opacity fromValue %x, key %.2f, toValue %x, key %.2f for progress %.2f",
269 layer->uniqueId(),
270 fromValue, fromValue->keyTime(),
271 toValue, toValue->keyTime(), progress);
272
273 // We now have the correct two values to work with, let's compute the
274 // progress value
275
276 const TimingFunction* timingFunction = fromValue->timingFunction();
277 progress = applyTimingFunction(fromValue->keyTime(), toValue->keyTime(),
278 progress, timingFunction);
279
280
281 float value = fromValue->value() + ((toValue->value() - fromValue->value()) * progress);
282
283 layer->setOpacity(value);
284 }
285
create(const Animation * animation,KeyframeValueList * operations,double beginTime)286 PassRefPtr<AndroidTransformAnimation> AndroidTransformAnimation::create(
287 const Animation* animation,
288 KeyframeValueList* operations,
289 double beginTime)
290 {
291 return adoptRef(new AndroidTransformAnimation(animation, operations, beginTime));
292 }
293
AndroidTransformAnimation(const Animation * animation,KeyframeValueList * operations,double beginTime)294 AndroidTransformAnimation::AndroidTransformAnimation(const Animation* animation,
295 KeyframeValueList* operations,
296 double beginTime)
297 : AndroidAnimation(AnimatedPropertyWebkitTransform, animation, operations, beginTime)
298 {
299 }
300
AndroidTransformAnimation(AndroidTransformAnimation * anim)301 AndroidTransformAnimation::AndroidTransformAnimation(AndroidTransformAnimation* anim)
302 : AndroidAnimation(anim)
303 {
304 }
305
copy()306 PassRefPtr<AndroidAnimation> AndroidTransformAnimation::copy()
307 {
308 return adoptRef(new AndroidTransformAnimation(this));
309 }
310
applyForProgress(LayerAndroid * layer,float progress)311 void AndroidTransformAnimation::applyForProgress(LayerAndroid* layer, float progress)
312 {
313 // First, we need to get the from and to values
314 int from, to;
315 pickValues(progress, &from, &to);
316
317 TransformAnimationValue* fromValue = (TransformAnimationValue*) m_operations->at(from);
318 TransformAnimationValue* toValue = (TransformAnimationValue*) m_operations->at(to);
319
320 XLOG("[layer %d] fromValue %x, key %.2f, toValue %x, key %.2f for progress %.2f",
321 layer->uniqueId(),
322 fromValue, fromValue->keyTime(),
323 toValue, toValue->keyTime(), progress);
324
325 // We now have the correct two values to work with, let's compute the
326 // progress value
327
328 const TimingFunction* timingFunction = fromValue->timingFunction();
329 float p = applyTimingFunction(fromValue->keyTime(), toValue->keyTime(),
330 progress, timingFunction);
331 XLOG("progress %.2f => %.2f from: %.2f to: %.2f", progress, p, fromValue->keyTime(),
332 toValue->keyTime());
333 progress = p;
334
335 // With both values and the progress, we also need to check out that
336 // the operations are compatible (i.e. we are animating the same number
337 // of values; if not we do a matrix blend)
338
339 TransformationMatrix transformMatrix;
340 bool valid = true;
341 unsigned int fromSize = fromValue->value()->size();
342 if (fromSize) {
343 if (toValue->value()->size() != fromSize)
344 valid = false;
345 else {
346 for (unsigned int j = 0; j < fromSize && valid; j++) {
347 if (!fromValue->value()->operations()[j]->isSameType(
348 *toValue->value()->operations()[j]))
349 valid = false;
350 }
351 }
352 }
353
354 IntSize size(layer->getSize().width(), layer->getSize().height());
355 if (valid) {
356 for (size_t i = 0; i < toValue->value()->size(); ++i)
357 toValue->value()->operations()[i]->blend(fromValue->value()->at(i),
358 progress)->apply(transformMatrix, size);
359 } else {
360 TransformationMatrix source;
361
362 fromValue->value()->apply(size, source);
363 toValue->value()->apply(size, transformMatrix);
364
365 transformMatrix.blend(source, progress);
366 }
367
368 // Set the final transform on the layer
369 layer->setTransform(transformMatrix);
370 }
371
372 } // namespace WebCore
373
374 #endif // USE(ACCELERATED_COMPOSITING)
375