Home | History | Annotate | Download | only in animation
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "ui/gfx/animation/tween.h"
      6 
      7 #include <math.h>
      8 
      9 #if defined(OS_WIN)
     10 #include <float.h>
     11 #endif
     12 
     13 #include <algorithm>
     14 
     15 #include "base/basictypes.h"
     16 #include "base/logging.h"
     17 #include "ui/gfx/safe_integer_conversions.h"
     18 
     19 namespace gfx {
     20 
     21 // static
     22 double Tween::CalculateValue(Tween::Type type, double state) {
     23   DCHECK_GE(state, 0);
     24   DCHECK_LE(state, 1);
     25 
     26   switch (type) {
     27     case EASE_IN:
     28       return pow(state, 2);
     29 
     30     case EASE_IN_2:
     31       return pow(state, 4);
     32 
     33     case EASE_IN_OUT:
     34       if (state < 0.5)
     35         return pow(state * 2, 2) / 2.0;
     36       return 1.0 - (pow((state - 1.0) * 2, 2) / 2.0);
     37 
     38     case FAST_IN_OUT:
     39       return (pow(state - 0.5, 3) + 0.125) / 0.25;
     40 
     41     case LINEAR:
     42       return state;
     43 
     44     case EASE_OUT_SNAP:
     45       state = 0.95 * (1.0 - pow(1.0 - state, 2));
     46       return state;
     47 
     48     case EASE_OUT:
     49       return 1.0 - pow(1.0 - state, 2);
     50 
     51     case SMOOTH_IN_OUT:
     52       return sin(state);
     53 
     54     case ZERO:
     55       return 0;
     56   }
     57 
     58   NOTREACHED();
     59   return state;
     60 }
     61 
     62 namespace {
     63 uint8 FloatToColorByte(float f) {
     64   return std::min(std::max(ToRoundedInt(f * 255.f), 0), 255);
     65 }
     66 
     67 uint8 BlendColorComponents(uint8 start,
     68                            uint8 target,
     69                            float start_alpha,
     70                            float target_alpha,
     71                            float blended_alpha,
     72                            double progress) {
     73   // Since progress can be outside [0, 1], blending can produce a value outside
     74   // [0, 255].
     75   float blended_premultiplied = Tween::FloatValueBetween(
     76       progress, start / 255.f * start_alpha, target / 255.f * target_alpha);
     77   return FloatToColorByte(blended_premultiplied / blended_alpha);
     78 }
     79 
     80 }  // namespace
     81 
     82 // static
     83 SkColor Tween::ColorValueBetween(double value, SkColor start, SkColor target) {
     84   float start_a = SkColorGetA(start) / 255.f;
     85   float target_a = SkColorGetA(target) / 255.f;
     86   float blended_a = FloatValueBetween(value, start_a, target_a);
     87   if (blended_a <= 0.f)
     88     return SkColorSetARGB(0, 0, 0, 0);
     89   blended_a = std::min(blended_a, 1.f);
     90 
     91   uint8 blended_r = BlendColorComponents(SkColorGetR(start),
     92                                          SkColorGetR(target),
     93                                          start_a,
     94                                          target_a,
     95                                          blended_a,
     96                                          value);
     97   uint8 blended_g = BlendColorComponents(SkColorGetG(start),
     98                                          SkColorGetG(target),
     99                                          start_a,
    100                                          target_a,
    101                                          blended_a,
    102                                          value);
    103   uint8 blended_b = BlendColorComponents(SkColorGetB(start),
    104                                          SkColorGetB(target),
    105                                          start_a,
    106                                          target_a,
    107                                          blended_a,
    108                                          value);
    109 
    110   return SkColorSetARGB(
    111       FloatToColorByte(blended_a), blended_r, blended_g, blended_b);
    112 }
    113 
    114 // static
    115 double Tween::DoubleValueBetween(double value, double start, double target) {
    116   return start + (target - start) * value;
    117 }
    118 
    119 // static
    120 float Tween::FloatValueBetween(double value, float start, float target) {
    121   return static_cast<float>(start + (target - start) * value);
    122 }
    123 
    124 // static
    125 int Tween::IntValueBetween(double value, int start, int target) {
    126   if (start == target)
    127     return start;
    128   double delta = static_cast<double>(target - start);
    129   if (delta < 0)
    130     delta--;
    131   else
    132     delta++;
    133 #if defined(OS_WIN)
    134   return start + static_cast<int>(value * _nextafter(delta, 0));
    135 #else
    136   return start + static_cast<int>(value * nextafter(delta, 0));
    137 #endif
    138 }
    139 
    140 //static
    141 int Tween::LinearIntValueBetween(double value, int start, int target) {
    142   return std::floor(0.5 + DoubleValueBetween(value, start, target));
    143 }
    144 
    145 // static
    146 gfx::Rect Tween::RectValueBetween(double value,
    147                                   const gfx::Rect& start_bounds,
    148                                   const gfx::Rect& target_bounds) {
    149   return gfx::Rect(
    150       LinearIntValueBetween(value, start_bounds.x(), target_bounds.x()),
    151       LinearIntValueBetween(value, start_bounds.y(), target_bounds.y()),
    152       LinearIntValueBetween(value, start_bounds.width(), target_bounds.width()),
    153       LinearIntValueBetween(
    154           value, start_bounds.height(), target_bounds.height()));
    155 }
    156 
    157 // static
    158 gfx::Transform Tween::TransformValueBetween(
    159     double value,
    160     const gfx::Transform& start_transform,
    161     const gfx::Transform& end_transform) {
    162   if (value >= 1.0)
    163     return end_transform;
    164   if (value <= 0.0)
    165     return start_transform;
    166 
    167   gfx::Transform to_return = end_transform;
    168   to_return.Blend(start_transform, value);
    169 
    170   return to_return;
    171 }
    172 
    173 }  // namespace gfx
    174