Disable ExtensionIconSourceTest.IconLoaded* on Mac and Win
[chromium-blink-merge.git] / ui / gfx / interpolated_transform.cc
blob583c27f05b9988a7d011ddd7d67496fd1e5df126
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.
5 #include "ui/gfx/interpolated_transform.h"
7 #include <cmath>
9 #ifndef M_PI
10 #define M_PI 3.14159265358979323846
11 #endif
13 #include "base/logging.h"
14 #include "ui/base/animation/tween.h"
16 namespace {
18 static const double EPSILON = 1e-6;
20 bool IsMultipleOfNinetyDegrees(double degrees) {
21 double remainder = fabs(fmod(degrees, 90.0));
22 return remainder < EPSILON || 90.0 - remainder < EPSILON;
25 bool IsApproximatelyZero(double value) {
26 return fabs(value) < EPSILON;
29 // Returns false if |degrees| is not a multiple of ninety degrees or if
30 // |rotation| is NULL. It does not affect |rotation| in this case. Otherwise
31 // *rotation is set to be the appropriate sanitized rotation matrix. That is,
32 // the rotation matrix corresponding to |degrees| which has entries that are all
33 // either 0, 1 or -1.
34 bool MassageRotationIfMultipleOfNinetyDegrees(gfx::Transform* rotation,
35 float degrees) {
36 if (!IsMultipleOfNinetyDegrees(degrees) || !rotation)
37 return false;
39 gfx::Transform transform;
40 SkMatrix44& m = transform.matrix();
41 float degrees_by_ninety = degrees / 90.0f;
43 int n = static_cast<int>(degrees_by_ninety > 0
44 ? floor(degrees_by_ninety + 0.5f)
45 : ceil(degrees_by_ninety - 0.5f));
47 n %= 4;
48 if (n < 0)
49 n += 4;
51 // n should now be in the range [0, 3]
52 if (n == 1) {
53 m.set3x3( 0, 1, 0,
54 -1, 0, 0,
55 0, 0, 1);
56 } else if (n == 2) {
57 m.set3x3(-1, 0, 0,
58 0, -1, 0,
59 0, 0, 1);
60 } else if (n == 3) {
61 m.set3x3( 0, -1, 0,
62 1, 0, 0,
63 0, 0, 1);
66 *rotation = transform;
67 return true;
70 } // namespace
72 namespace ui {
74 ///////////////////////////////////////////////////////////////////////////////
75 // InterpolatedTransform
78 InterpolatedTransform::InterpolatedTransform()
79 : start_time_(0.0f),
80 end_time_(1.0f),
81 reversed_(false) {
84 InterpolatedTransform::InterpolatedTransform(float start_time,
85 float end_time)
86 : start_time_(start_time),
87 end_time_(end_time),
88 reversed_(false) {
91 InterpolatedTransform::~InterpolatedTransform() {}
93 gfx::Transform InterpolatedTransform::Interpolate(float t) const {
94 if (reversed_)
95 t = 1.0f - t;
96 gfx::Transform result = InterpolateButDoNotCompose(t);
97 if (child_.get()) {
98 result.ConcatTransform(child_->Interpolate(t));
100 return result;
103 void InterpolatedTransform::SetChild(InterpolatedTransform* child) {
104 child_.reset(child);
107 inline float InterpolatedTransform::ValueBetween(float time,
108 float start_value,
109 float end_value) const {
110 // can't handle NaN
111 DCHECK(time == time && start_time_ == start_time_ && end_time_ == end_time_);
112 if (time != time || start_time_ != start_time_ || end_time_ != end_time_)
113 return start_value;
115 // Ok if equal -- we'll get a step function. Note: if end_time_ ==
116 // start_time_ == x, then if none of the numbers are NaN, then it
117 // must be true that time < x or time >= x, so we will return early
118 // due to one of the following if statements.
119 DCHECK(end_time_ >= start_time_);
121 if (time < start_time_)
122 return start_value;
124 if (time >= end_time_)
125 return end_value;
127 float t = (time - start_time_) / (end_time_ - start_time_);
128 return static_cast<float>(Tween::ValueBetween(t, start_value, end_value));
131 ///////////////////////////////////////////////////////////////////////////////
132 // InterpolatedRotation
135 InterpolatedRotation::InterpolatedRotation(float start_degrees,
136 float end_degrees)
137 : InterpolatedTransform(),
138 start_degrees_(start_degrees),
139 end_degrees_(end_degrees) {
142 InterpolatedRotation::InterpolatedRotation(float start_degrees,
143 float end_degrees,
144 float start_time,
145 float end_time)
146 : InterpolatedTransform(start_time, end_time),
147 start_degrees_(start_degrees),
148 end_degrees_(end_degrees) {
151 InterpolatedRotation::~InterpolatedRotation() {}
153 gfx::Transform InterpolatedRotation::InterpolateButDoNotCompose(float t) const {
154 gfx::Transform result;
155 float interpolated_degrees = ValueBetween(t, start_degrees_, end_degrees_);
156 result.Rotate(interpolated_degrees);
157 if (t == 0.0f || t == 1.0f)
158 MassageRotationIfMultipleOfNinetyDegrees(&result, interpolated_degrees);
159 return result;
162 ///////////////////////////////////////////////////////////////////////////////
163 // InterpolatedAxisAngleRotation
166 InterpolatedAxisAngleRotation::InterpolatedAxisAngleRotation(
167 const gfx::Vector3dF& axis,
168 float start_degrees,
169 float end_degrees)
170 : InterpolatedTransform(),
171 axis_(axis),
172 start_degrees_(start_degrees),
173 end_degrees_(end_degrees) {
176 InterpolatedAxisAngleRotation::InterpolatedAxisAngleRotation(
177 const gfx::Vector3dF& axis,
178 float start_degrees,
179 float end_degrees,
180 float start_time,
181 float end_time)
182 : InterpolatedTransform(start_time, end_time),
183 axis_(axis),
184 start_degrees_(start_degrees),
185 end_degrees_(end_degrees) {
188 InterpolatedAxisAngleRotation::~InterpolatedAxisAngleRotation() {}
190 gfx::Transform
191 InterpolatedAxisAngleRotation::InterpolateButDoNotCompose(float t) const {
192 gfx::Transform result;
193 result.RotateAbout(axis_, ValueBetween(t, start_degrees_, end_degrees_));
194 return result;
197 ///////////////////////////////////////////////////////////////////////////////
198 // InterpolatedScale
201 InterpolatedScale::InterpolatedScale(float start_scale, float end_scale)
202 : InterpolatedTransform(),
203 start_scale_(gfx::Point3F(start_scale, start_scale, start_scale)),
204 end_scale_(gfx::Point3F(end_scale, end_scale, end_scale)) {
207 InterpolatedScale::InterpolatedScale(float start_scale, float end_scale,
208 float start_time, float end_time)
209 : InterpolatedTransform(start_time, end_time),
210 start_scale_(gfx::Point3F(start_scale, start_scale, start_scale)),
211 end_scale_(gfx::Point3F(end_scale, end_scale, end_scale)) {
214 InterpolatedScale::InterpolatedScale(const gfx::Point3F& start_scale,
215 const gfx::Point3F& end_scale)
216 : InterpolatedTransform(),
217 start_scale_(start_scale),
218 end_scale_(end_scale) {
221 InterpolatedScale::InterpolatedScale(const gfx::Point3F& start_scale,
222 const gfx::Point3F& end_scale,
223 float start_time,
224 float end_time)
225 : InterpolatedTransform(start_time, end_time),
226 start_scale_(start_scale),
227 end_scale_(end_scale) {
230 InterpolatedScale::~InterpolatedScale() {}
232 gfx::Transform InterpolatedScale::InterpolateButDoNotCompose(float t) const {
233 gfx::Transform result;
234 float scale_x = ValueBetween(t, start_scale_.x(), end_scale_.x());
235 float scale_y = ValueBetween(t, start_scale_.y(), end_scale_.y());
236 // TODO(vollick) 3d xforms.
237 result.Scale(scale_x, scale_y);
238 return result;
241 ///////////////////////////////////////////////////////////////////////////////
242 // InterpolatedTranslation
245 InterpolatedTranslation::InterpolatedTranslation(const gfx::Point& start_pos,
246 const gfx::Point& end_pos)
247 : InterpolatedTransform(),
248 start_pos_(start_pos),
249 end_pos_(end_pos) {
252 InterpolatedTranslation::InterpolatedTranslation(const gfx::Point& start_pos,
253 const gfx::Point& end_pos,
254 float start_time,
255 float end_time)
256 : InterpolatedTransform(start_time, end_time),
257 start_pos_(start_pos),
258 end_pos_(end_pos) {
261 InterpolatedTranslation::~InterpolatedTranslation() {}
263 gfx::Transform
264 InterpolatedTranslation::InterpolateButDoNotCompose(float t) const {
265 gfx::Transform result;
266 // TODO(vollick) 3d xforms.
267 result.Translate(ValueBetween(t, start_pos_.x(), end_pos_.x()),
268 ValueBetween(t, start_pos_.y(), end_pos_.y()));
269 return result;
272 ///////////////////////////////////////////////////////////////////////////////
273 // InterpolatedConstantTransform
276 InterpolatedConstantTransform::InterpolatedConstantTransform(
277 const gfx::Transform& transform)
278 : InterpolatedTransform(),
279 transform_(transform) {
282 gfx::Transform
283 InterpolatedConstantTransform::InterpolateButDoNotCompose(float t) const {
284 return transform_;
287 InterpolatedConstantTransform::~InterpolatedConstantTransform() {}
289 ///////////////////////////////////////////////////////////////////////////////
290 // InterpolatedTransformAboutPivot
293 InterpolatedTransformAboutPivot::InterpolatedTransformAboutPivot(
294 const gfx::Point& pivot,
295 InterpolatedTransform* transform)
296 : InterpolatedTransform() {
297 Init(pivot, transform);
300 InterpolatedTransformAboutPivot::InterpolatedTransformAboutPivot(
301 const gfx::Point& pivot,
302 InterpolatedTransform* transform,
303 float start_time,
304 float end_time)
305 : InterpolatedTransform() {
306 Init(pivot, transform);
309 InterpolatedTransformAboutPivot::~InterpolatedTransformAboutPivot() {}
311 gfx::Transform
312 InterpolatedTransformAboutPivot::InterpolateButDoNotCompose(float t) const {
313 if (transform_.get()) {
314 return transform_->Interpolate(t);
316 return gfx::Transform();
319 void InterpolatedTransformAboutPivot::Init(const gfx::Point& pivot,
320 InterpolatedTransform* xform) {
321 gfx::Transform to_pivot;
322 gfx::Transform from_pivot;
323 to_pivot.Translate(-pivot.x(), -pivot.y());
324 from_pivot.Translate(pivot.x(), pivot.y());
326 scoped_ptr<InterpolatedTransform> pre_transform(
327 new InterpolatedConstantTransform(to_pivot));
328 scoped_ptr<InterpolatedTransform> post_transform(
329 new InterpolatedConstantTransform(from_pivot));
331 pre_transform->SetChild(xform);
332 xform->SetChild(post_transform.release());
333 transform_.reset(pre_transform.release());
336 InterpolatedMatrixTransform::InterpolatedMatrixTransform(
337 const gfx::Transform& start_transform,
338 const gfx::Transform& end_transform)
339 : InterpolatedTransform() {
340 Init(start_transform, end_transform);
343 InterpolatedMatrixTransform::InterpolatedMatrixTransform(
344 const gfx::Transform& start_transform,
345 const gfx::Transform& end_transform,
346 float start_time,
347 float end_time)
348 : InterpolatedTransform() {
349 Init(start_transform, end_transform);
352 InterpolatedMatrixTransform::~InterpolatedMatrixTransform() {}
354 gfx::Transform
355 InterpolatedMatrixTransform::InterpolateButDoNotCompose(float t) const {
356 gfx::DecomposedTransform blended;
357 bool success = gfx::BlendDecomposedTransforms(&blended,
358 end_decomp_,
359 start_decomp_,
361 DCHECK(success);
362 return gfx::ComposeTransform(blended);
365 void InterpolatedMatrixTransform::Init(const gfx::Transform& start_transform,
366 const gfx::Transform& end_transform) {
367 bool success = gfx::DecomposeTransform(&start_decomp_, start_transform);
368 DCHECK(success);
369 success = gfx::DecomposeTransform(&end_decomp_, end_transform);
370 DCHECK(success);
373 } // namespace ui