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 19namespace gfx { 20 21// static 22double 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 62namespace { 63uint8 FloatToColorByte(float f) { 64 return std::min(std::max(ToRoundedInt(f * 255.f), 0), 255); 65} 66 67uint8 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 83SkColor 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 115double Tween::DoubleValueBetween(double value, double start, double target) { 116 return start + (target - start) * value; 117} 118 119// static 120float Tween::FloatValueBetween(double value, float start, float target) { 121 return static_cast<float>(start + (target - start) * value); 122} 123 124// static 125int 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 141int Tween::LinearIntValueBetween(double value, int start, int target) { 142 return std::floor(0.5 + DoubleValueBetween(value, start, target)); 143} 144 145// static 146gfx::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 158gfx::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