Home | History | Annotate | Download | only in android
      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)
    351