Home | History | Annotate | Download | only in layers
      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 
     39 long AndroidAnimation::instancesCount()
     40 {
     41     return gDebugAndroidAnimationInstances;
     42 }
     43 
     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 
     65 AndroidAnimation::~AndroidAnimation()
     66 {
     67     gDebugAndroidAnimationInstances--;
     68 }
     69 
     70 void AndroidAnimation::suggestBeginTime(double time)
     71 {
     72     if (m_beginTime <= 0.000001) // overflow or not yet set
     73         m_beginTime = time;
     74 }
     75 
     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 
     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 
    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 
    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 
    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 
    200 AndroidOpacityAnimation::AndroidOpacityAnimation(const Animation* animation,
    201                                                  KeyframeValueList* operations,
    202                                                  double beginTime)
    203     : AndroidAnimation(AnimatedPropertyOpacity, animation, operations, beginTime)
    204 {
    205 }
    206 
    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 
    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 
    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 
    263 AndroidTransformAnimation::AndroidTransformAnimation(const Animation* animation,
    264                                                      KeyframeValueList* operations,
    265                                                      double beginTime)
    266     : AndroidAnimation(AnimatedPropertyWebkitTransform, animation, operations, beginTime)
    267 {
    268 }
    269 
    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