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