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"
10 #define M_PI 3.14159265358979323846
13 #include "base/logging.h"
14 #include "ui/gfx/animation/tween.h"
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 // Returns false if |degrees| is not a multiple of ninety degrees or if
26 // |rotation| is NULL. It does not affect |rotation| in this case. Otherwise
27 // *rotation is set to be the appropriate sanitized rotation matrix. That is,
28 // the rotation matrix corresponding to |degrees| which has entries that are all
30 bool MassageRotationIfMultipleOfNinetyDegrees(gfx::Transform* rotation,
32 if (!IsMultipleOfNinetyDegrees(degrees) || !rotation)
35 gfx::Transform transform;
36 SkMatrix44& m = transform.matrix();
37 float degrees_by_ninety = degrees / 90.0f;
39 int n = static_cast<int>(degrees_by_ninety > 0
40 ? floor(degrees_by_ninety + 0.5f)
41 : ceil(degrees_by_ninety - 0.5f));
47 // n should now be in the range [0, 3]
62 *rotation = transform;
70 ///////////////////////////////////////////////////////////////////////////////
71 // InterpolatedTransform
74 InterpolatedTransform::InterpolatedTransform()
80 InterpolatedTransform::InterpolatedTransform(float start_time,
82 : start_time_(start_time),
87 InterpolatedTransform::~InterpolatedTransform() {}
89 gfx::Transform InterpolatedTransform::Interpolate(float t) const {
92 gfx::Transform result = InterpolateButDoNotCompose(t);
94 result.ConcatTransform(child_->Interpolate(t));
99 void InterpolatedTransform::SetChild(InterpolatedTransform* child) {
103 inline float InterpolatedTransform::ValueBetween(float time,
105 float end_value) const {
107 DCHECK(time == time && start_time_ == start_time_ && end_time_ == end_time_);
108 if (time != time || start_time_ != start_time_ || end_time_ != end_time_)
111 // Ok if equal -- we'll get a step function. Note: if end_time_ ==
112 // start_time_ == x, then if none of the numbers are NaN, then it
113 // must be true that time < x or time >= x, so we will return early
114 // due to one of the following if statements.
115 DCHECK(end_time_ >= start_time_);
117 if (time < start_time_)
120 if (time >= end_time_)
123 float t = (time - start_time_) / (end_time_ - start_time_);
124 return static_cast<float>(
125 gfx::Tween::DoubleValueBetween(t, start_value, end_value));
128 ///////////////////////////////////////////////////////////////////////////////
129 // InterpolatedRotation
132 InterpolatedRotation::InterpolatedRotation(float start_degrees,
134 : InterpolatedTransform(),
135 start_degrees_(start_degrees),
136 end_degrees_(end_degrees) {
139 InterpolatedRotation::InterpolatedRotation(float start_degrees,
143 : InterpolatedTransform(start_time, end_time),
144 start_degrees_(start_degrees),
145 end_degrees_(end_degrees) {
148 InterpolatedRotation::~InterpolatedRotation() {}
150 gfx::Transform InterpolatedRotation::InterpolateButDoNotCompose(float t) const {
151 gfx::Transform result;
152 float interpolated_degrees = ValueBetween(t, start_degrees_, end_degrees_);
153 result.Rotate(interpolated_degrees);
154 if (t == 0.0f || t == 1.0f)
155 MassageRotationIfMultipleOfNinetyDegrees(&result, interpolated_degrees);
159 ///////////////////////////////////////////////////////////////////////////////
160 // InterpolatedAxisAngleRotation
163 InterpolatedAxisAngleRotation::InterpolatedAxisAngleRotation(
164 const gfx::Vector3dF& axis,
167 : InterpolatedTransform(),
169 start_degrees_(start_degrees),
170 end_degrees_(end_degrees) {
173 InterpolatedAxisAngleRotation::InterpolatedAxisAngleRotation(
174 const gfx::Vector3dF& axis,
179 : InterpolatedTransform(start_time, end_time),
181 start_degrees_(start_degrees),
182 end_degrees_(end_degrees) {
185 InterpolatedAxisAngleRotation::~InterpolatedAxisAngleRotation() {}
188 InterpolatedAxisAngleRotation::InterpolateButDoNotCompose(float t) const {
189 gfx::Transform result;
190 result.RotateAbout(axis_, ValueBetween(t, start_degrees_, end_degrees_));
194 ///////////////////////////////////////////////////////////////////////////////
198 InterpolatedScale::InterpolatedScale(float start_scale, float end_scale)
199 : InterpolatedTransform(),
200 start_scale_(gfx::Point3F(start_scale, start_scale, start_scale)),
201 end_scale_(gfx::Point3F(end_scale, end_scale, end_scale)) {
204 InterpolatedScale::InterpolatedScale(float start_scale, float end_scale,
205 float start_time, float end_time)
206 : InterpolatedTransform(start_time, end_time),
207 start_scale_(gfx::Point3F(start_scale, start_scale, start_scale)),
208 end_scale_(gfx::Point3F(end_scale, end_scale, end_scale)) {
211 InterpolatedScale::InterpolatedScale(const gfx::Point3F& start_scale,
212 const gfx::Point3F& end_scale)
213 : InterpolatedTransform(),
214 start_scale_(start_scale),
215 end_scale_(end_scale) {
218 InterpolatedScale::InterpolatedScale(const gfx::Point3F& start_scale,
219 const gfx::Point3F& end_scale,
222 : InterpolatedTransform(start_time, end_time),
223 start_scale_(start_scale),
224 end_scale_(end_scale) {
227 InterpolatedScale::~InterpolatedScale() {}
229 gfx::Transform InterpolatedScale::InterpolateButDoNotCompose(float t) const {
230 gfx::Transform result;
231 float scale_x = ValueBetween(t, start_scale_.x(), end_scale_.x());
232 float scale_y = ValueBetween(t, start_scale_.y(), end_scale_.y());
233 float scale_z = ValueBetween(t, start_scale_.z(), end_scale_.z());
234 result.Scale3d(scale_x, scale_y, scale_z);
238 ///////////////////////////////////////////////////////////////////////////////
239 // InterpolatedTranslation
242 InterpolatedTranslation::InterpolatedTranslation(const gfx::Point& start_pos,
243 const gfx::Point& end_pos)
244 : InterpolatedTransform(),
245 start_pos_(start_pos),
249 InterpolatedTranslation::InterpolatedTranslation(const gfx::Point& start_pos,
250 const gfx::Point& end_pos,
253 : InterpolatedTransform(start_time, end_time),
254 start_pos_(start_pos),
258 InterpolatedTranslation::InterpolatedTranslation(const gfx::Point3F& start_pos,
259 const gfx::Point3F& end_pos)
260 : InterpolatedTransform(), start_pos_(start_pos), end_pos_(end_pos) {
263 InterpolatedTranslation::InterpolatedTranslation(const gfx::Point3F& start_pos,
264 const gfx::Point3F& end_pos,
267 : InterpolatedTransform(start_time, end_time),
268 start_pos_(start_pos),
272 InterpolatedTranslation::~InterpolatedTranslation() {}
275 InterpolatedTranslation::InterpolateButDoNotCompose(float t) const {
276 gfx::Transform result;
277 result.Translate3d(ValueBetween(t, start_pos_.x(), end_pos_.x()),
278 ValueBetween(t, start_pos_.y(), end_pos_.y()),
279 ValueBetween(t, start_pos_.z(), end_pos_.z()));
283 ///////////////////////////////////////////////////////////////////////////////
284 // InterpolatedConstantTransform
287 InterpolatedConstantTransform::InterpolatedConstantTransform(
288 const gfx::Transform& transform)
289 : InterpolatedTransform(),
290 transform_(transform) {
294 InterpolatedConstantTransform::InterpolateButDoNotCompose(float t) const {
298 InterpolatedConstantTransform::~InterpolatedConstantTransform() {}
300 ///////////////////////////////////////////////////////////////////////////////
301 // InterpolatedTransformAboutPivot
304 InterpolatedTransformAboutPivot::InterpolatedTransformAboutPivot(
305 const gfx::Point& pivot,
306 InterpolatedTransform* transform)
307 : InterpolatedTransform() {
308 Init(pivot, transform);
311 InterpolatedTransformAboutPivot::InterpolatedTransformAboutPivot(
312 const gfx::Point& pivot,
313 InterpolatedTransform* transform,
316 : InterpolatedTransform() {
317 Init(pivot, transform);
320 InterpolatedTransformAboutPivot::~InterpolatedTransformAboutPivot() {}
323 InterpolatedTransformAboutPivot::InterpolateButDoNotCompose(float t) const {
324 if (transform_.get()) {
325 return transform_->Interpolate(t);
327 return gfx::Transform();
330 void InterpolatedTransformAboutPivot::Init(const gfx::Point& pivot,
331 InterpolatedTransform* xform) {
332 gfx::Transform to_pivot;
333 gfx::Transform from_pivot;
334 to_pivot.Translate(SkIntToMScalar(-pivot.x()), SkIntToMScalar(-pivot.y()));
335 from_pivot.Translate(SkIntToMScalar(pivot.x()), SkIntToMScalar(pivot.y()));
337 scoped_ptr<InterpolatedTransform> pre_transform(
338 new InterpolatedConstantTransform(to_pivot));
339 scoped_ptr<InterpolatedTransform> post_transform(
340 new InterpolatedConstantTransform(from_pivot));
342 pre_transform->SetChild(xform);
343 xform->SetChild(post_transform.release());
344 transform_.reset(pre_transform.release());
347 InterpolatedMatrixTransform::InterpolatedMatrixTransform(
348 const gfx::Transform& start_transform,
349 const gfx::Transform& end_transform)
350 : InterpolatedTransform() {
351 Init(start_transform, end_transform);
354 InterpolatedMatrixTransform::InterpolatedMatrixTransform(
355 const gfx::Transform& start_transform,
356 const gfx::Transform& end_transform,
359 : InterpolatedTransform() {
360 Init(start_transform, end_transform);
363 InterpolatedMatrixTransform::~InterpolatedMatrixTransform() {}
366 InterpolatedMatrixTransform::InterpolateButDoNotCompose(float t) const {
367 gfx::DecomposedTransform blended;
368 bool success = gfx::BlendDecomposedTransforms(&blended,
373 return gfx::ComposeTransform(blended);
376 void InterpolatedMatrixTransform::Init(const gfx::Transform& start_transform,
377 const gfx::Transform& end_transform) {
378 bool success = gfx::DecomposeTransform(&start_decomp_, start_transform);
380 success = gfx::DecomposeTransform(&end_decomp_, end_transform);