• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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