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