OSDN Git Service

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