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