OSDN Git Service

Delete TextureGenerator operations outside the lock
[android-x86/external-webkit.git] / Source / WebCore / platform / graphics / android / AndroidAnimation.cpp
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 int gUniqueId;
53
54 static long gDebugAndroidAnimationInstances;
55
56 long AndroidAnimation::instancesCount()
57 {
58     return gDebugAndroidAnimationInstances;
59 }
60
61 AndroidAnimation::AndroidAnimation(AnimatedPropertyID type,
62                                    const Animation* animation,
63                                    KeyframeValueList* operations,
64                                    double beginTime)
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())
72     , m_type(type)
73     , m_operations(operations)
74     , m_uniqueId(++gUniqueId)
75     , m_hasFinished(false)
76 {
77     ASSERT(m_timingFunction);
78
79     gDebugAndroidAnimationInstances++;
80 }
81
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)
95 {
96     gDebugAndroidAnimationInstances++;
97 }
98
99 AndroidAnimation::~AndroidAnimation()
100 {
101     gDebugAndroidAnimationInstances--;
102 }
103
104 void AndroidAnimation::suggestBeginTime(double time)
105 {
106     if (m_beginTime <= 0.000001) // overflow or not yet set
107         m_beginTime = time;
108 }
109
110 double AndroidAnimation::elapsedTime(double time)
111 {
112     suggestBeginTime(time);
113     double elapsedTime = time - m_beginTime;
114
115     if (m_duration <= 0)
116       m_duration = 0.000001;
117
118     if (elapsedTime < 0) // animation not yet started.
119         return 0;
120
121     return elapsedTime;
122 }
123
124 bool AndroidAnimation::checkIterationsAndProgress(double time, float* finalProgress)
125 {
126     double progress = elapsedTime(time);
127     double dur = m_duration;
128     if (m_iterationCount > 0)
129         dur *= m_iterationCount;
130
131     if (m_duration <= 0)
132         return false;
133
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;
141             return true;
142         }
143
144         return false;
145     }
146
147     double fractionalTime = progress / m_duration;
148     int integralTime = static_cast<int>(fractionalTime);
149
150     fractionalTime -= integralTime;
151
152     if ((m_direction == Animation::AnimationDirectionAlternate) && (integralTime & 1))
153         fractionalTime = 1 - fractionalTime;
154
155     *finalProgress = fractionalTime;
156     return true;
157 }
158
159 double AndroidAnimation::applyTimingFunction(float from, float to, double progress,
160                                              const TimingFunction* tf)
161 {
162     double fractionalTime = progress;
163     double offset = from;
164     double scale = 1.0 / (to - from);
165
166     if (scale != 1 || offset)
167         fractionalTime = (fractionalTime - offset) * scale;
168
169     const TimingFunction* timingFunction = tf;
170
171     if (!timingFunction)
172         timingFunction = m_timingFunction.get();
173
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());
180         if (m_duration > 0)
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;
188         } else {
189             fractionalTime = floor(stepFunction->numberOfSteps() * fractionalTime) / stepFunction->numberOfSteps();
190         }
191     }
192     return fractionalTime;
193 }
194
195 bool AndroidAnimation::evaluate(LayerAndroid* layer, double time)
196 {
197     float progress;
198     if (!checkIterationsAndProgress(time, &progress)
199         && !(m_fillsBackwards || m_fillsForwards))
200         return false;
201
202     if (progress < 0) {
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);
207         }
208         // we still want to be evaluated until we get progress > 0
209         return true;
210     }
211
212     if (progress > 1) {
213         if (!m_fillsForwards)
214             return false;
215         progress = 1;
216     }
217
218     if (!m_operations->size())
219         return false;
220
221     applyForProgress(layer, progress);
222
223     return true;
224 }
225
226 PassRefPtr<AndroidOpacityAnimation> AndroidOpacityAnimation::create(
227                                                 const Animation* animation,
228                                                 KeyframeValueList* operations,
229                                                 double beginTime)
230 {
231     return adoptRef(new AndroidOpacityAnimation(animation, operations,
232                                                 beginTime));
233 }
234
235 AndroidOpacityAnimation::AndroidOpacityAnimation(const Animation* animation,
236                                                  KeyframeValueList* operations,
237                                                  double beginTime)
238     : AndroidAnimation(AnimatedPropertyOpacity, animation, operations, beginTime)
239 {
240 }
241
242 AndroidOpacityAnimation::AndroidOpacityAnimation(AndroidOpacityAnimation* anim)
243     : AndroidAnimation(anim)
244 {
245 }
246
247 PassRefPtr<AndroidAnimation> AndroidOpacityAnimation::copy()
248 {
249     return adoptRef(new AndroidOpacityAnimation(this));
250 }
251
252 void AndroidAnimation::pickValues(double progress, int* start, int* end)
253 {
254     float distance = -1;
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())) {
261             distance = d;
262             foundAt = i;
263         }
264     }
265
266     *start = foundAt;
267
268     if (foundAt + 1 < m_operations->size())
269         *end = foundAt + 1;
270     else
271         *end = foundAt;
272 }
273
274 void AndroidOpacityAnimation::applyForProgress(LayerAndroid* layer, float progress)
275 {
276     // First, we need to get the from and to values
277     int from, to;
278     pickValues(progress, &from, &to);
279     FloatAnimationValue* fromValue = (FloatAnimationValue*) m_operations->at(from);
280     FloatAnimationValue* toValue = (FloatAnimationValue*) m_operations->at(to);
281
282     XLOG("[layer %d] opacity fromValue %x, key %.2f, toValue %x, key %.2f for progress %.2f",
283          layer->uniqueId(),
284          fromValue, fromValue->keyTime(),
285          toValue, toValue->keyTime(), progress);
286
287     // We now have the correct two values to work with, let's compute the
288     // progress value
289
290     const TimingFunction* timingFunction = fromValue->timingFunction();
291     progress = applyTimingFunction(fromValue->keyTime(), toValue->keyTime(),
292                                    progress, timingFunction);
293
294
295     float value = fromValue->value() + ((toValue->value() - fromValue->value()) * progress);
296
297     layer->setOpacity(value);
298 }
299
300 PassRefPtr<AndroidTransformAnimation> AndroidTransformAnimation::create(
301                                                      const Animation* animation,
302                                                      KeyframeValueList* operations,
303                                                      double beginTime)
304 {
305     return adoptRef(new AndroidTransformAnimation(animation, operations, beginTime));
306 }
307
308 AndroidTransformAnimation::AndroidTransformAnimation(const Animation* animation,
309                                                      KeyframeValueList* operations,
310                                                      double beginTime)
311     : AndroidAnimation(AnimatedPropertyWebkitTransform, animation, operations, beginTime)
312 {
313 }
314
315 AndroidTransformAnimation::AndroidTransformAnimation(AndroidTransformAnimation* anim)
316     : AndroidAnimation(anim)
317 {
318 }
319
320 PassRefPtr<AndroidAnimation> AndroidTransformAnimation::copy()
321 {
322     return adoptRef(new AndroidTransformAnimation(this));
323 }
324
325 void AndroidTransformAnimation::applyForProgress(LayerAndroid* layer, float progress)
326 {
327     // First, we need to get the from and to values
328     int from, to;
329     pickValues(progress, &from, &to);
330
331     TransformAnimationValue* fromValue = (TransformAnimationValue*) m_operations->at(from);
332     TransformAnimationValue* toValue = (TransformAnimationValue*) m_operations->at(to);
333
334     XLOG("[layer %d] fromValue %x, key %.2f, toValue %x, key %.2f for progress %.2f",
335          layer->uniqueId(),
336          fromValue, fromValue->keyTime(),
337          toValue, toValue->keyTime(), progress);
338
339     // We now have the correct two values to work with, let's compute the
340     // progress value
341
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(),
346          toValue->keyTime());
347     progress = p;
348
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)
352
353     TransformationMatrix transformMatrix;
354     bool valid = true;
355     unsigned int fromSize = fromValue->value()->size();
356     if (fromSize) {
357         if (toValue->value()->size() != fromSize)
358             valid = false;
359         else {
360             for (unsigned int j = 0; j < fromSize && valid; j++) {
361                 if (!fromValue->value()->operations()[j]->isSameType(
362                     *toValue->value()->operations()[j]))
363                     valid = false;
364             }
365         }
366     }
367
368     IntSize size(layer->getSize().width(), layer->getSize().height());
369     if (valid) {
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);
373     } else {
374         TransformationMatrix source;
375
376         fromValue->value()->apply(size, source);
377         toValue->value()->apply(size, transformMatrix);
378
379         transformMatrix.blend(source, progress);
380     }
381
382     // Set the final transform on the layer
383     layer->setTransform(transformMatrix);
384 }
385
386 } // namespace WebCore
387
388 #endif // USE(ACCELERATED_COMPOSITING)