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 #define LOG_TAG "AndroidAnimation"
18 #define LOG_NDEBUG 1
19
20 #include "config.h"
21 #include "AndroidAnimation.h"
22
23 #if USE(ACCELERATED_COMPOSITING)
24
25 #include "AndroidLog.h"
26 #include "Animation.h"
27 #include "GraphicsLayerAndroid.h"
28 #include "Timer.h"
29 #include "TimingFunction.h"
30 #include "TranslateTransformOperation.h"
31 #include "UnitBezier.h"
32
33 namespace WebCore {
34
35 static int gUniqueId;
36
37 static long gDebugAndroidAnimationInstances;
38
instancesCount()39 long AndroidAnimation::instancesCount()
40 {
41 return gDebugAndroidAnimationInstances;
42 }
43
AndroidAnimation(AnimatedPropertyID type,const Animation * animation,KeyframeValueList * operations,double beginTime)44 AndroidAnimation::AndroidAnimation(AnimatedPropertyID type,
45 const Animation* animation,
46 KeyframeValueList* operations,
47 double beginTime)
48 : m_beginTime(beginTime)
49 , m_duration(animation->duration())
50 , m_fillsBackwards(animation->fillsBackwards())
51 , m_fillsForwards(animation->fillsForwards())
52 , m_iterationCount(animation->iterationCount())
53 , m_direction(animation->direction())
54 , m_timingFunction(animation->timingFunction())
55 , m_type(type)
56 , m_operations(operations)
57 , m_uniqueId(++gUniqueId)
58 , m_hasFinished(false)
59 {
60 ASSERT(m_timingFunction);
61
62 gDebugAndroidAnimationInstances++;
63 }
64
~AndroidAnimation()65 AndroidAnimation::~AndroidAnimation()
66 {
67 gDebugAndroidAnimationInstances--;
68 }
69
suggestBeginTime(double time)70 void AndroidAnimation::suggestBeginTime(double time)
71 {
72 if (m_beginTime <= 0.000001) // overflow or not yet set
73 m_beginTime = time;
74 }
75
elapsedTime(double time)76 double AndroidAnimation::elapsedTime(double time)
77 {
78 double elapsedTime = (m_beginTime < 0.000001) ? 0 : time - m_beginTime;
79
80 if (m_duration <= 0)
81 m_duration = 0.000001;
82
83 if (elapsedTime < 0) // animation not yet started.
84 return 0;
85
86 return elapsedTime;
87 }
88
checkIterationsAndProgress(double time,float * finalProgress)89 bool AndroidAnimation::checkIterationsAndProgress(double time, float* finalProgress)
90 {
91 double progress = elapsedTime(time);
92 double dur = m_duration;
93 if (m_iterationCount > 0)
94 dur *= m_iterationCount;
95
96 if (m_duration <= 0)
97 return false;
98
99 // If not infinite, return false if we are done
100 if (m_iterationCount > 0 && progress > dur) {
101 *finalProgress = 1.0;
102 if (!m_hasFinished) {
103 // first time past duration, continue with progress 1.0 so the
104 // element's final position lines up with it's last keyframe
105 m_hasFinished = true;
106 return true;
107 }
108
109 return false;
110 }
111
112 double fractionalTime = progress / m_duration;
113 int integralTime = static_cast<int>(fractionalTime);
114
115 fractionalTime -= integralTime;
116
117 if ((m_direction == Animation::AnimationDirectionAlternate) && (integralTime & 1))
118 fractionalTime = 1 - fractionalTime;
119
120 *finalProgress = fractionalTime;
121 return true;
122 }
123
applyTimingFunction(float from,float to,double progress,const TimingFunction * tf)124 double AndroidAnimation::applyTimingFunction(float from, float to, double progress,
125 const TimingFunction* tf)
126 {
127 double fractionalTime = progress;
128 double offset = from;
129 double scale = 1.0 / (to - from);
130
131 if (scale != 1 || offset)
132 fractionalTime = (fractionalTime - offset) * scale;
133
134 const TimingFunction* timingFunction = tf;
135
136 if (!timingFunction)
137 timingFunction = m_timingFunction.get();
138
139 if (timingFunction && timingFunction->isCubicBezierTimingFunction()) {
140 const CubicBezierTimingFunction* bezierFunction = static_cast<const CubicBezierTimingFunction*>(timingFunction);
141 UnitBezier bezier(bezierFunction->x1(),
142 bezierFunction->y1(),
143 bezierFunction->x2(),
144 bezierFunction->y2());
145 if (m_duration > 0)
146 fractionalTime = bezier.solve(fractionalTime, 1.0f / (200.0f * m_duration));
147 } else if (timingFunction && timingFunction->isStepsTimingFunction()) {
148 const StepsTimingFunction* stepFunction = static_cast<const StepsTimingFunction*>(timingFunction);
149 if (stepFunction->stepAtStart()) {
150 fractionalTime = (floor(stepFunction->numberOfSteps() * fractionalTime) + 1) / stepFunction->numberOfSteps();
151 if (fractionalTime > 1.0)
152 fractionalTime = 1.0;
153 } else {
154 fractionalTime = floor(stepFunction->numberOfSteps() * fractionalTime) / stepFunction->numberOfSteps();
155 }
156 }
157 return fractionalTime;
158 }
159
evaluate(LayerAndroid * layer,double time)160 bool AndroidAnimation::evaluate(LayerAndroid* layer, double time)
161 {
162 float progress;
163 if (!checkIterationsAndProgress(time, &progress)
164 && !(m_fillsBackwards || m_fillsForwards))
165 return false;
166
167 if (progress < 0) {
168 // The animation hasn't started yet
169 if (m_fillsBackwards || m_beginTime <= 0.000001) {
170 // in this case we want to apply the initial keyframe to the layer
171 applyForProgress(layer, 0);
172 }
173 // we still want to be evaluated until we get progress > 0
174 return true;
175 }
176
177 if (progress > 1) {
178 if (!m_fillsForwards)
179 return false;
180 progress = 1;
181 }
182
183 if (!m_operations->size())
184 return false;
185
186 applyForProgress(layer, progress);
187
188 return true;
189 }
190
create(const Animation * animation,KeyframeValueList * operations,double beginTime)191 PassRefPtr<AndroidOpacityAnimation> AndroidOpacityAnimation::create(
192 const Animation* animation,
193 KeyframeValueList* operations,
194 double beginTime)
195 {
196 return adoptRef(new AndroidOpacityAnimation(animation, operations,
197 beginTime));
198 }
199
AndroidOpacityAnimation(const Animation * animation,KeyframeValueList * operations,double beginTime)200 AndroidOpacityAnimation::AndroidOpacityAnimation(const Animation* animation,
201 KeyframeValueList* operations,
202 double beginTime)
203 : AndroidAnimation(AnimatedPropertyOpacity, animation, operations, beginTime)
204 {
205 }
206
pickValues(double progress,int * start,int * end)207 void AndroidAnimation::pickValues(double progress, int* start, int* end)
208 {
209 float distance = -1;
210 unsigned int foundAt = 0;
211 for (unsigned int i = 0; i < m_operations->size(); i++) {
212 const AnimationValue* value = m_operations->at(i);
213 float key = value->keyTime();
214 float d = progress - key;
215 if (distance == -1 || (d >= 0 && d < distance && i + 1 < m_operations->size())) {
216 distance = d;
217 foundAt = i;
218 }
219 }
220
221 *start = foundAt;
222
223 if (foundAt + 1 < m_operations->size())
224 *end = foundAt + 1;
225 else
226 *end = foundAt;
227 }
228
applyForProgress(LayerAndroid * layer,float progress)229 void AndroidOpacityAnimation::applyForProgress(LayerAndroid* layer, float progress)
230 {
231 // First, we need to get the from and to values
232 int from, to;
233 pickValues(progress, &from, &to);
234 FloatAnimationValue* fromValue = (FloatAnimationValue*) m_operations->at(from);
235 FloatAnimationValue* toValue = (FloatAnimationValue*) m_operations->at(to);
236
237 ALOGV("[layer %d] opacity fromValue %x, key %.2f, toValue %x, key %.2f for progress %.2f",
238 layer->uniqueId(),
239 fromValue, fromValue->keyTime(),
240 toValue, toValue->keyTime(), progress);
241
242 // We now have the correct two values to work with, let's compute the
243 // progress value
244
245 const TimingFunction* timingFunction = fromValue->timingFunction();
246 progress = applyTimingFunction(fromValue->keyTime(), toValue->keyTime(),
247 progress, timingFunction);
248
249
250 float value = fromValue->value() + ((toValue->value() - fromValue->value()) * progress);
251
252 layer->setOpacity(value);
253 }
254
create(const Animation * animation,KeyframeValueList * operations,double beginTime)255 PassRefPtr<AndroidTransformAnimation> AndroidTransformAnimation::create(
256 const Animation* animation,
257 KeyframeValueList* operations,
258 double beginTime)
259 {
260 return adoptRef(new AndroidTransformAnimation(animation, operations, beginTime));
261 }
262
AndroidTransformAnimation(const Animation * animation,KeyframeValueList * operations,double beginTime)263 AndroidTransformAnimation::AndroidTransformAnimation(const Animation* animation,
264 KeyframeValueList* operations,
265 double beginTime)
266 : AndroidAnimation(AnimatedPropertyWebkitTransform, animation, operations, beginTime)
267 {
268 }
269
applyForProgress(LayerAndroid * layer,float progress)270 void AndroidTransformAnimation::applyForProgress(LayerAndroid* layer, float progress)
271 {
272 // First, we need to get the from and to values
273 int from, to;
274 pickValues(progress, &from, &to);
275
276 TransformAnimationValue* fromValue = (TransformAnimationValue*) m_operations->at(from);
277 TransformAnimationValue* toValue = (TransformAnimationValue*) m_operations->at(to);
278
279 ALOGV("[layer %d] fromValue %x, key %.2f, toValue %x, key %.2f for progress %.2f",
280 layer->uniqueId(),
281 fromValue, fromValue->keyTime(),
282 toValue, toValue->keyTime(), progress);
283
284 // We now have the correct two values to work with, let's compute the
285 // progress value
286
287 const TimingFunction* timingFunction = fromValue->timingFunction();
288 float p = applyTimingFunction(fromValue->keyTime(), toValue->keyTime(),
289 progress, timingFunction);
290 ALOGV("progress %.2f => %.2f from: %.2f to: %.2f", progress, p, fromValue->keyTime(),
291 toValue->keyTime());
292 progress = p;
293
294 // With both values and the progress, we also need to check out that
295 // the operations are compatible (i.e. we are animating the same number
296 // of values; if not we do a matrix blend)
297
298 TransformationMatrix transformMatrix;
299 bool valid = true;
300 unsigned int fromSize = fromValue->value()->size();
301 if (fromSize) {
302 if (toValue->value()->size() != fromSize)
303 valid = false;
304 else {
305 for (unsigned int j = 0; j < fromSize && valid; j++) {
306 if (!fromValue->value()->operations()[j]->isSameType(
307 *toValue->value()->operations()[j]))
308 valid = false;
309 }
310 }
311 }
312
313 IntSize size(layer->getSize().width(), layer->getSize().height());
314 if (valid) {
315 for (size_t i = 0; i < toValue->value()->size(); ++i)
316 toValue->value()->operations()[i]->blend(fromValue->value()->at(i),
317 progress)->apply(transformMatrix, size);
318 } else {
319 TransformationMatrix source;
320
321 fromValue->value()->apply(size, source);
322 toValue->value()->apply(size, transformMatrix);
323
324 transformMatrix.blend(source, progress);
325 }
326
327 // Set the final transform on the layer
328 layer->setTransform(transformMatrix);
329 }
330
331 } // namespace WebCore
332
333 #endif // USE(ACCELERATED_COMPOSITING)
334