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