• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
CalculateValue(Tween::Type type,double state)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 {
FloatToColorByte(float f)73 uint8 FloatToColorByte(float f) {
74   return std::min(std::max(ToRoundedInt(f * 255.f), 0), 255);
75 }
76 
BlendColorComponents(uint8 start,uint8 target,float start_alpha,float target_alpha,float blended_alpha,double progress)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
ColorValueBetween(double value,SkColor start,SkColor target)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
DoubleValueBetween(double value,double start,double target)125 double Tween::DoubleValueBetween(double value, double start, double target) {
126   return start + (target - start) * value;
127 }
128 
129 // static
FloatValueBetween(double value,float start,float target)130 float Tween::FloatValueBetween(double value, float start, float target) {
131   return static_cast<float>(start + (target - start) * value);
132 }
133 
134 // static
IntValueBetween(double value,int start,int target)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
LinearIntValueBetween(double value,int start,int target)151 int Tween::LinearIntValueBetween(double value, int start, int target) {
152   return std::floor(0.5 + DoubleValueBetween(value, start, target));
153 }
154 
155 // static
RectValueBetween(double value,const gfx::Rect & start_bounds,const gfx::Rect & target_bounds)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
TransformValueBetween(double value,const gfx::Transform & start_transform,const gfx::Transform & end_transform)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