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 "UnitBezier.h"
28
29#include <wtf/CurrentTime.h>
30
31namespace WebCore {
32
33static long gDebugAndroidAnimationInstances;
34
35long AndroidAnimation::instancesCount()
36{
37    return gDebugAndroidAnimationInstances;
38}
39
40AndroidAnimation::AndroidAnimation(const Animation* animation,
41                                   double beginTime) :
42    m_beginTime(beginTime),
43    m_duration(animation->duration()),
44    m_iterationCount(animation->iterationCount()),
45    m_currentIteration(0),
46    m_direction(animation->direction()),
47    m_timingFunction(animation->timingFunction())
48{
49    if (!static_cast<int>(beginTime)) // time not set
50        m_beginTime = WTF::currentTime();
51
52    gDebugAndroidAnimationInstances++;
53}
54
55AndroidAnimation::AndroidAnimation(AndroidAnimation* anim) :
56    m_beginTime(anim->m_beginTime),
57    m_duration(anim->m_duration),
58    m_iterationCount(anim->m_iterationCount),
59    m_currentIteration(0),
60    m_direction(anim->m_direction),
61    m_timingFunction(anim->m_timingFunction)
62{
63    gDebugAndroidAnimationInstances++;
64}
65
66AndroidAnimation::~AndroidAnimation()
67{
68    gDebugAndroidAnimationInstances--;
69}
70
71float AndroidAnimation::currentProgress(double time)
72{
73    if (m_beginTime <= 0.000001) // overflow or not correctly set
74        m_beginTime = time;
75
76    m_elapsedTime = time - m_beginTime;
77
78    if (m_duration <= 0)
79      m_duration = 0.000001;
80
81    if (m_elapsedTime < 0) // animation not yet started.
82        return 0;
83
84    return m_elapsedTime / m_duration;
85}
86
87bool AndroidAnimation::checkIterationsAndProgress(double time, float* finalProgress)
88{
89    float progress = currentProgress(time);
90
91    int currentIteration = static_cast<int>(progress);
92    if (currentIteration != m_currentIteration)
93        if (m_direction == Animation::AnimationDirectionAlternate)
94            swapDirection();
95
96    m_currentIteration = currentIteration;
97    progress -= m_currentIteration;
98
99    if ((m_currentIteration >= m_iterationCount)
100          && (m_iterationCount != Animation::IterationCountInfinite))
101        return false;
102
103    if (m_timingFunction.type() != LinearTimingFunction) {
104        UnitBezier bezier(m_timingFunction.x1(),
105                          m_timingFunction.y1(),
106                          m_timingFunction.x2(),
107                          m_timingFunction.y2());
108        if (m_duration > 0)
109            progress = bezier.solve(progress, 1.0f / (200.0f * m_duration));
110    }
111
112    *finalProgress = progress;
113    return true;
114}
115
116PassRefPtr<AndroidOpacityAnimation> AndroidOpacityAnimation::create(
117                                                float fromValue,
118                                                float toValue,
119                                                const Animation* animation,
120                                                double beginTime)
121{
122    return adoptRef(new AndroidOpacityAnimation(fromValue, toValue,
123                                                animation, beginTime));
124}
125
126AndroidOpacityAnimation::AndroidOpacityAnimation(float fromValue, float toValue,
127                                                 const Animation* animation,
128                                                 double beginTime)
129    : AndroidAnimation(animation, beginTime),
130      m_fromValue(fromValue), m_toValue(toValue)
131{
132}
133
134AndroidOpacityAnimation::AndroidOpacityAnimation(AndroidOpacityAnimation* anim)
135    : AndroidAnimation(anim),
136    m_fromValue(anim->m_fromValue),
137    m_toValue(anim->m_toValue)
138{
139}
140
141PassRefPtr<AndroidAnimation> AndroidOpacityAnimation::copy()
142{
143    return adoptRef(new AndroidOpacityAnimation(this));
144}
145
146void AndroidOpacityAnimation::swapDirection()
147{
148    float v = m_toValue;
149    m_toValue = m_fromValue;
150    m_fromValue = m_toValue;
151}
152
153bool AndroidOpacityAnimation::evaluate(LayerAndroid* layer, double time)
154{
155    float progress;
156    if (!checkIterationsAndProgress(time, &progress))
157        return false;
158
159    if (progress < 0) // we still want to be evaluated until we get progress > 0
160        return true;
161
162    float value = m_fromValue + ((m_toValue - m_fromValue) * progress);
163    layer->setOpacity(value);
164    return true;
165}
166
167PassRefPtr<AndroidTransformAnimation> AndroidTransformAnimation::create(
168                                                     const Animation* animation,
169                                                     double beginTime)
170{
171    return adoptRef(new AndroidTransformAnimation(animation, beginTime));
172}
173
174AndroidTransformAnimation::AndroidTransformAnimation(const Animation* animation,
175                                                     double beginTime)
176    : AndroidAnimation(animation, beginTime),
177    m_doTranslation(false),
178    m_doScaling(false),
179    m_doRotation(false)
180{
181}
182
183AndroidTransformAnimation::AndroidTransformAnimation(AndroidTransformAnimation* anim)
184    : AndroidAnimation(anim),
185    m_doTranslation(anim->m_doTranslation),
186    m_doScaling(anim->m_doScaling),
187    m_doRotation(anim->m_doRotation),
188    m_position(anim->m_position),
189    m_fromX(anim->m_fromX), m_fromY(anim->m_fromY), m_fromZ(anim->m_fromZ),
190    m_toX(anim->m_toX), m_toY(anim->m_toY), m_toZ(anim->m_toZ),
191    m_fromAngle(anim->m_fromAngle), m_toAngle(anim->m_toAngle),
192    m_fromScaleX(anim->m_fromScaleX), m_fromScaleY(anim->m_fromScaleY), m_fromScaleZ(anim->m_fromScaleZ),
193    m_toScaleX(anim->m_toScaleX), m_toScaleY(anim->m_toScaleY), m_toScaleZ(anim->m_toScaleZ)
194{
195}
196
197PassRefPtr<AndroidAnimation> AndroidTransformAnimation::copy()
198{
199    return adoptRef(new AndroidTransformAnimation(this));
200}
201
202void AndroidTransformAnimation::setRotation(float fA, float tA)
203{
204    m_fromAngle = fA;
205    m_toAngle = tA;
206    m_doRotation = true;
207}
208
209void AndroidTransformAnimation::setTranslation(float fX, float fY, float fZ,
210    float tX, float tY, float tZ)
211{
212    m_fromX = fX;
213    m_fromY = fY;
214    m_fromZ = fZ;
215    m_toX = tX;
216    m_toY = tY;
217    m_toZ = tZ;
218    m_doTranslation = true;
219}
220
221void AndroidTransformAnimation::setScale(float fX, float fY, float fZ,
222                                         float tX, float tY, float tZ)
223{
224    m_fromScaleX = fX;
225    m_fromScaleY = fY;
226    m_fromScaleZ = fZ;
227    m_toScaleX   = tX;
228    m_toScaleY   = tY;
229    m_toScaleZ   = tZ;
230    m_doScaling = true;
231}
232
233void AndroidTransformAnimation::swapDirection()
234{
235    if (m_doTranslation) {
236        float tx = m_toX;
237        m_toX = m_fromX;
238        m_fromX = tx;
239        float ty = m_toY;
240        m_toY = m_fromY;
241        m_fromY = ty;
242        float tz = m_toZ;
243        m_toZ = m_fromZ;
244        m_fromZ = tz;
245    }
246    if (m_doScaling) {
247        float sx = m_toScaleX;
248        m_toScaleX = m_fromScaleX;
249        m_fromScaleX = sx;
250        float sy = m_toScaleY;
251        m_toScaleY = m_fromScaleY;
252        m_fromScaleY = sy;
253    }
254    if (m_doRotation) {
255        float a = m_toAngle;
256        m_toAngle = m_fromAngle;
257        m_fromAngle = a;
258    }
259}
260
261bool AndroidTransformAnimation::evaluate(LayerAndroid* layer, double time)
262{
263    float progress;
264    if (!checkIterationsAndProgress(time, &progress))
265        return false;
266
267    if (progress < 0) // we still want to be evaluated until we get progress > 0
268        return true;
269
270    float x = m_fromX + (m_toX - m_fromX) * progress;
271    float y = m_fromY + (m_toY - m_fromY) * progress;
272    float z = m_fromZ + (m_toZ - m_fromZ) * progress;
273    float sx = m_fromScaleX + (m_toScaleX - m_fromScaleX) * progress;
274    float sy = m_fromScaleY + (m_toScaleY - m_fromScaleY) * progress;
275    float sz = m_fromScaleZ + (m_toScaleZ - m_fromScaleZ) * progress;
276    float a = m_fromAngle + (m_toAngle - m_fromAngle) * progress;
277
278    if (m_doTranslation)
279        layer->setTranslation(x, y);
280
281    if (m_doScaling)
282        layer->setScale(sx, sy);
283
284    if (m_doRotation)
285        layer->setRotation(a);
286
287    return true;
288}
289
290} // namespace WebCore
291
292#endif // USE(ACCELERATED_COMPOSITING)
293