summaryrefslogtreecommitdiffstats
path: root/ui/base/animation/tween.cc
blob: b8f4385b36030707eb2679ffa517eae0e4f22dad (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/base/animation/tween.h"

#include <math.h>

#if defined(OS_WIN)
#include <float.h>
#endif

#include "base/logging.h"
#include "ui/gfx/interpolated_transform.h"

namespace ui {

// static
double Tween::CalculateValue(Tween::Type type, double state) {
  DCHECK_GE(state, 0);
  DCHECK_LE(state, 1);

  switch (type) {
    case EASE_IN:
      return pow(state, 2);

    case EASE_IN_OUT:
      if (state < 0.5)
        return pow(state * 2, 2) / 2.0;
      return 1.0 - (pow((state - 1.0) * 2, 2) / 2.0);

    case FAST_IN_OUT:
      return (pow(state - 0.5, 3) + 0.125) / 0.25;

    case LINEAR:
      return state;

    case EASE_OUT_SNAP:
      state = 0.95 * (1.0 - pow(1.0 - state, 2));
      break;

    case EASE_OUT:
      return 1.0 - pow(1.0 - state, 2);

    case ZERO:
      return 0;
  }

  NOTREACHED();
  return state;
}

// static
double Tween::ValueBetween(double value, double start, double target) {
  return start + (target - start) * value;
}

// static
int Tween::ValueBetween(double value, int start, int target) {
  if (start == target)
    return start;
  double delta = static_cast<double>(target - start);
  if (delta < 0)
    delta--;
  else
    delta++;
#if defined(OS_WIN)
  return start + static_cast<int>(value * _nextafter(delta, 0));
#else
  return start + static_cast<int>(value * nextafter(delta, 0));
#endif
}

// static
gfx::Rect Tween::ValueBetween(double value,
                              const gfx::Rect& start_bounds,
                              const gfx::Rect& target_bounds) {
  return gfx::Rect(ValueBetween(value, start_bounds.x(), target_bounds.x()),
                   ValueBetween(value, start_bounds.y(), target_bounds.y()),
                   ValueBetween(value, start_bounds.width(),
                                target_bounds.width()),
                   ValueBetween(value, start_bounds.height(),
                                target_bounds.height()));
}

// static
Transform Tween::ValueBetween(double value,
                              const Transform& start_transform,
                              const Transform& end_transform) {
  if (value >= 1.0)
    return end_transform;
  if (value <= 0.0)
    return start_transform;

  Transform to_return;
  gfx::Point start_translation, end_translation;
  float start_rotation, end_rotation;
  gfx::Point3f start_scale, end_scale;
  if (InterpolatedTransform::FactorTRS(start_transform,
                                       &start_translation,
                                       &start_rotation,
                                       &start_scale) &&
      InterpolatedTransform::FactorTRS(end_transform,
                                       &end_translation,
                                       &end_rotation,
                                       &end_scale)) {
    to_return.SetScale(ValueBetween(value, start_scale.x(), end_scale.x()),
                       ValueBetween(value, start_scale.y(), end_scale.y()));
    to_return.ConcatRotate(ValueBetween(value, start_rotation, end_rotation));
    to_return.ConcatTranslate(
        ValueBetween(value, start_translation.x(), end_translation.x()),
        ValueBetween(value, start_translation.y(), end_translation.y()));
  } else {
    for (int row = 0; row < 4; ++row) {
      for (int col = 0; col < 4; ++col) {
        to_return.matrix().set(row, col,
            ValueBetween(value,
                         start_transform.matrix().get(row, col),
                         end_transform.matrix().get(row, col)));
      }
    }
  }

  return to_return;
}

}  // namespace ui