2 * Copyright (C) 2009 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #include "AndroidAnimation.h"
20 #if USE(ACCELERATED_COMPOSITING)
22 #include "Animation.h"
23 #include "GraphicsLayerAndroid.h"
26 #include "TimingFunction.h"
27 #include "TranslateTransformOperation.h"
28 #include "UnitBezier.h"
30 #include <wtf/CurrentTime.h>
31 #include <cutils/log.h>
32 #include <wtf/text/CString.h>
35 #define XLOGC(...) android_printLog(ANDROID_LOG_DEBUG, "AndroidAnimation", __VA_ARGS__)
40 #define XLOG(...) android_printLog(ANDROID_LOG_DEBUG, "AndroidAnimation", __VA_ARGS__)
54 static long gDebugAndroidAnimationInstances;
56 long AndroidAnimation::instancesCount()
58 return gDebugAndroidAnimationInstances;
61 AndroidAnimation::AndroidAnimation(AnimatedPropertyID type,
62 const Animation* animation,
63 KeyframeValueList* operations,
65 : m_beginTime(beginTime)
66 , m_duration(animation->duration())
67 , m_fillsBackwards(animation->fillsBackwards())
68 , m_fillsForwards(animation->fillsForwards())
69 , m_iterationCount(animation->iterationCount())
70 , m_direction(animation->direction())
71 , m_timingFunction(animation->timingFunction())
73 , m_operations(operations)
74 , m_uniqueId(++gUniqueId)
75 , m_hasFinished(false)
77 ASSERT(m_timingFunction);
79 gDebugAndroidAnimationInstances++;
82 AndroidAnimation::AndroidAnimation(AndroidAnimation* anim)
83 : m_beginTime(anim->m_beginTime)
84 , m_duration(anim->m_duration)
85 , m_fillsBackwards(anim->m_fillsBackwards)
86 , m_fillsForwards(anim->m_fillsForwards)
87 , m_iterationCount(anim->m_iterationCount)
88 , m_direction(anim->m_direction)
89 , m_timingFunction(anim->m_timingFunction)
90 , m_name(anim->name())
91 , m_type(anim->m_type)
92 , m_operations(anim->m_operations)
93 , m_uniqueId(anim->m_uniqueId)
94 , m_hasFinished(anim->m_hasFinished)
96 gDebugAndroidAnimationInstances++;
99 AndroidAnimation::~AndroidAnimation()
101 gDebugAndroidAnimationInstances--;
104 void AndroidAnimation::suggestBeginTime(double time)
106 if (m_beginTime <= 0.000001) // overflow or not yet set
110 double AndroidAnimation::elapsedTime(double time)
112 suggestBeginTime(time);
113 double elapsedTime = time - m_beginTime;
116 m_duration = 0.000001;
118 if (elapsedTime < 0) // animation not yet started.
124 bool AndroidAnimation::checkIterationsAndProgress(double time, float* finalProgress)
126 double progress = elapsedTime(time);
127 double dur = m_duration;
128 if (m_iterationCount > 0)
129 dur *= m_iterationCount;
134 // If not infinite, return false if we are done
135 if (m_iterationCount > 0 && progress > dur) {
136 *finalProgress = 1.0;
137 if (!m_hasFinished) {
138 // first time past duration, continue with progress 1.0 so the
139 // element's final position lines up with it's last keyframe
140 m_hasFinished = true;
147 double fractionalTime = progress / m_duration;
148 int integralTime = static_cast<int>(fractionalTime);
150 fractionalTime -= integralTime;
152 if ((m_direction == Animation::AnimationDirectionAlternate) && (integralTime & 1))
153 fractionalTime = 1 - fractionalTime;
155 *finalProgress = fractionalTime;
159 double AndroidAnimation::applyTimingFunction(float from, float to, double progress,
160 const TimingFunction* tf)
162 double fractionalTime = progress;
163 double offset = from;
164 double scale = 1.0 / (to - from);
166 if (scale != 1 || offset)
167 fractionalTime = (fractionalTime - offset) * scale;
169 const TimingFunction* timingFunction = tf;
172 timingFunction = m_timingFunction.get();
174 if (timingFunction && timingFunction->isCubicBezierTimingFunction()) {
175 const CubicBezierTimingFunction* bezierFunction = static_cast<const CubicBezierTimingFunction*>(timingFunction);
176 UnitBezier bezier(bezierFunction->x1(),
177 bezierFunction->y1(),
178 bezierFunction->x2(),
179 bezierFunction->y2());
181 fractionalTime = bezier.solve(fractionalTime, 1.0f / (200.0f * m_duration));
182 } else if (timingFunction && timingFunction->isStepsTimingFunction()) {
183 const StepsTimingFunction* stepFunction = static_cast<const StepsTimingFunction*>(timingFunction);
184 if (stepFunction->stepAtStart()) {
185 fractionalTime = (floor(stepFunction->numberOfSteps() * fractionalTime) + 1) / stepFunction->numberOfSteps();
186 if (fractionalTime > 1.0)
187 fractionalTime = 1.0;
189 fractionalTime = floor(stepFunction->numberOfSteps() * fractionalTime) / stepFunction->numberOfSteps();
192 return fractionalTime;
195 bool AndroidAnimation::evaluate(LayerAndroid* layer, double time)
198 if (!checkIterationsAndProgress(time, &progress)
199 && !(m_fillsBackwards || m_fillsForwards))
203 // The animation hasn't started yet
204 if (m_fillsBackwards) {
205 // in this case we want to apply the initial keyframe to the layer
206 applyForProgress(layer, 0);
208 // we still want to be evaluated until we get progress > 0
213 if (!m_fillsForwards)
218 if (!m_operations->size())
221 applyForProgress(layer, progress);
226 PassRefPtr<AndroidOpacityAnimation> AndroidOpacityAnimation::create(
227 const Animation* animation,
228 KeyframeValueList* operations,
231 return adoptRef(new AndroidOpacityAnimation(animation, operations,
235 AndroidOpacityAnimation::AndroidOpacityAnimation(const Animation* animation,
236 KeyframeValueList* operations,
238 : AndroidAnimation(AnimatedPropertyOpacity, animation, operations, beginTime)
242 AndroidOpacityAnimation::AndroidOpacityAnimation(AndroidOpacityAnimation* anim)
243 : AndroidAnimation(anim)
247 PassRefPtr<AndroidAnimation> AndroidOpacityAnimation::copy()
249 return adoptRef(new AndroidOpacityAnimation(this));
252 void AndroidAnimation::pickValues(double progress, int* start, int* end)
255 unsigned int foundAt = 0;
256 for (unsigned int i = 0; i < m_operations->size(); i++) {
257 const AnimationValue* value = m_operations->at(i);
258 float key = value->keyTime();
259 float d = progress - key;
260 if (distance == -1 || (d >= 0 && d < distance && i + 1 < m_operations->size())) {
268 if (foundAt + 1 < m_operations->size())
274 void AndroidOpacityAnimation::applyForProgress(LayerAndroid* layer, float progress)
276 // First, we need to get the from and to values
278 pickValues(progress, &from, &to);
279 FloatAnimationValue* fromValue = (FloatAnimationValue*) m_operations->at(from);
280 FloatAnimationValue* toValue = (FloatAnimationValue*) m_operations->at(to);
282 XLOG("[layer %d] opacity fromValue %x, key %.2f, toValue %x, key %.2f for progress %.2f",
284 fromValue, fromValue->keyTime(),
285 toValue, toValue->keyTime(), progress);
287 // We now have the correct two values to work with, let's compute the
290 const TimingFunction* timingFunction = fromValue->timingFunction();
291 progress = applyTimingFunction(fromValue->keyTime(), toValue->keyTime(),
292 progress, timingFunction);
295 float value = fromValue->value() + ((toValue->value() - fromValue->value()) * progress);
297 layer->setOpacity(value);
300 PassRefPtr<AndroidTransformAnimation> AndroidTransformAnimation::create(
301 const Animation* animation,
302 KeyframeValueList* operations,
305 return adoptRef(new AndroidTransformAnimation(animation, operations, beginTime));
308 AndroidTransformAnimation::AndroidTransformAnimation(const Animation* animation,
309 KeyframeValueList* operations,
311 : AndroidAnimation(AnimatedPropertyWebkitTransform, animation, operations, beginTime)
315 AndroidTransformAnimation::AndroidTransformAnimation(AndroidTransformAnimation* anim)
316 : AndroidAnimation(anim)
320 PassRefPtr<AndroidAnimation> AndroidTransformAnimation::copy()
322 return adoptRef(new AndroidTransformAnimation(this));
325 void AndroidTransformAnimation::applyForProgress(LayerAndroid* layer, float progress)
327 // First, we need to get the from and to values
329 pickValues(progress, &from, &to);
331 TransformAnimationValue* fromValue = (TransformAnimationValue*) m_operations->at(from);
332 TransformAnimationValue* toValue = (TransformAnimationValue*) m_operations->at(to);
334 XLOG("[layer %d] fromValue %x, key %.2f, toValue %x, key %.2f for progress %.2f",
336 fromValue, fromValue->keyTime(),
337 toValue, toValue->keyTime(), progress);
339 // We now have the correct two values to work with, let's compute the
342 const TimingFunction* timingFunction = fromValue->timingFunction();
343 float p = applyTimingFunction(fromValue->keyTime(), toValue->keyTime(),
344 progress, timingFunction);
345 XLOG("progress %.2f => %.2f from: %.2f to: %.2f", progress, p, fromValue->keyTime(),
349 // With both values and the progress, we also need to check out that
350 // the operations are compatible (i.e. we are animating the same number
351 // of values; if not we do a matrix blend)
353 TransformationMatrix transformMatrix;
355 unsigned int fromSize = fromValue->value()->size();
357 if (toValue->value()->size() != fromSize)
360 for (unsigned int j = 0; j < fromSize && valid; j++) {
361 if (!fromValue->value()->operations()[j]->isSameType(
362 *toValue->value()->operations()[j]))
368 IntSize size(layer->getSize().width(), layer->getSize().height());
370 for (size_t i = 0; i < toValue->value()->size(); ++i)
371 toValue->value()->operations()[i]->blend(fromValue->value()->at(i),
372 progress)->apply(transformMatrix, size);
374 TransformationMatrix source;
376 fromValue->value()->apply(size, source);
377 toValue->value()->apply(size, transformMatrix);
379 transformMatrix.blend(source, progress);
382 // Set the final transform on the layer
383 layer->setTransform(transformMatrix);
386 } // namespace WebCore
388 #endif // USE(ACCELERATED_COMPOSITING)