Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / ui / gfx / interpolated_transform.cc
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/interpolated_transform.h"
6
7 #include <cmath>
8
9 #ifndef M_PI
10 #define M_PI 3.14159265358979323846
11 #endif
12
13 #include "base/logging.h"
14 #include "ui/gfx/animation/tween.h"
15
16 namespace {
17
18 static const double EPSILON = 1e-6;
19
20 bool IsMultipleOfNinetyDegrees(double degrees) {
21   double remainder = fabs(fmod(degrees, 90.0));
22   return remainder < EPSILON || 90.0 - remainder < EPSILON;
23 }
24
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
29 // either 0, 1 or -1.
30 bool MassageRotationIfMultipleOfNinetyDegrees(gfx::Transform* rotation,
31                                               float degrees) {
32   if (!IsMultipleOfNinetyDegrees(degrees) || !rotation)
33     return false;
34
35   gfx::Transform transform;
36   SkMatrix44& m = transform.matrix();
37   float degrees_by_ninety = degrees / 90.0f;
38
39   int n = static_cast<int>(degrees_by_ninety > 0
40       ? floor(degrees_by_ninety + 0.5f)
41       : ceil(degrees_by_ninety - 0.5f));
42
43   n %= 4;
44   if (n < 0)
45     n += 4;
46
47   // n should now be in the range [0, 3]
48   if (n == 1) {
49     m.set3x3( 0,  1,  0,
50              -1,  0,  0,
51               0,  0,  1);
52   } else if (n == 2) {
53     m.set3x3(-1,  0,  0,
54               0, -1,  0,
55               0,  0,  1);
56   } else if (n == 3) {
57     m.set3x3( 0, -1,  0,
58               1,  0,  0,
59               0,  0,  1);
60   }
61
62   *rotation = transform;
63   return true;
64 }
65
66 } // namespace
67
68 namespace ui {
69
70 ///////////////////////////////////////////////////////////////////////////////
71 // InterpolatedTransform
72 //
73
74 InterpolatedTransform::InterpolatedTransform()
75     : start_time_(0.0f),
76       end_time_(1.0f),
77       reversed_(false) {
78 }
79
80 InterpolatedTransform::InterpolatedTransform(float start_time,
81                                              float end_time)
82     : start_time_(start_time),
83       end_time_(end_time),
84       reversed_(false) {
85 }
86
87 InterpolatedTransform::~InterpolatedTransform() {}
88
89 gfx::Transform InterpolatedTransform::Interpolate(float t) const {
90   if (reversed_)
91     t = 1.0f - t;
92   gfx::Transform result = InterpolateButDoNotCompose(t);
93   if (child_.get()) {
94     result.ConcatTransform(child_->Interpolate(t));
95   }
96   return result;
97 }
98
99 void InterpolatedTransform::SetChild(InterpolatedTransform* child) {
100   child_.reset(child);
101 }
102
103 inline float InterpolatedTransform::ValueBetween(float time,
104                                                  float start_value,
105                                                  float end_value) const {
106   // can't handle NaN
107   DCHECK(time == time && start_time_ == start_time_ && end_time_ == end_time_);
108   if (time != time || start_time_ != start_time_ || end_time_ != end_time_)
109     return start_value;
110
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_);
116
117   if (time < start_time_)
118     return start_value;
119
120   if (time >= end_time_)
121     return end_value;
122
123   float t = (time - start_time_) / (end_time_ - start_time_);
124   return static_cast<float>(
125       gfx::Tween::DoubleValueBetween(t, start_value, end_value));
126 }
127
128 ///////////////////////////////////////////////////////////////////////////////
129 // InterpolatedRotation
130 //
131
132 InterpolatedRotation::InterpolatedRotation(float start_degrees,
133                                            float end_degrees)
134     : InterpolatedTransform(),
135       start_degrees_(start_degrees),
136       end_degrees_(end_degrees) {
137 }
138
139 InterpolatedRotation::InterpolatedRotation(float start_degrees,
140                                            float end_degrees,
141                                            float start_time,
142                                            float end_time)
143     : InterpolatedTransform(start_time, end_time),
144       start_degrees_(start_degrees),
145       end_degrees_(end_degrees) {
146 }
147
148 InterpolatedRotation::~InterpolatedRotation() {}
149
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);
156   return result;
157 }
158
159 ///////////////////////////////////////////////////////////////////////////////
160 // InterpolatedAxisAngleRotation
161 //
162
163 InterpolatedAxisAngleRotation::InterpolatedAxisAngleRotation(
164     const gfx::Vector3dF& axis,
165     float start_degrees,
166     float end_degrees)
167     : InterpolatedTransform(),
168       axis_(axis),
169       start_degrees_(start_degrees),
170       end_degrees_(end_degrees) {
171 }
172
173 InterpolatedAxisAngleRotation::InterpolatedAxisAngleRotation(
174     const gfx::Vector3dF& axis,
175     float start_degrees,
176     float end_degrees,
177     float start_time,
178     float end_time)
179     : InterpolatedTransform(start_time, end_time),
180       axis_(axis),
181       start_degrees_(start_degrees),
182       end_degrees_(end_degrees) {
183 }
184
185 InterpolatedAxisAngleRotation::~InterpolatedAxisAngleRotation() {}
186
187 gfx::Transform
188 InterpolatedAxisAngleRotation::InterpolateButDoNotCompose(float t) const {
189   gfx::Transform result;
190   result.RotateAbout(axis_, ValueBetween(t, start_degrees_, end_degrees_));
191   return result;
192 }
193
194 ///////////////////////////////////////////////////////////////////////////////
195 // InterpolatedScale
196 //
197
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)) {
202 }
203
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)) {
209 }
210
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) {
216 }
217
218 InterpolatedScale::InterpolatedScale(const gfx::Point3F& start_scale,
219                                      const gfx::Point3F& end_scale,
220                                      float start_time,
221                                      float end_time)
222     : InterpolatedTransform(start_time, end_time),
223       start_scale_(start_scale),
224       end_scale_(end_scale) {
225 }
226
227 InterpolatedScale::~InterpolatedScale() {}
228
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);
235   return result;
236 }
237
238 ///////////////////////////////////////////////////////////////////////////////
239 // InterpolatedTranslation
240 //
241
242 InterpolatedTranslation::InterpolatedTranslation(const gfx::Point& start_pos,
243                                                  const gfx::Point& end_pos)
244     : InterpolatedTransform(),
245       start_pos_(start_pos),
246       end_pos_(end_pos) {
247 }
248
249 InterpolatedTranslation::InterpolatedTranslation(const gfx::Point& start_pos,
250                                                  const gfx::Point& end_pos,
251                                                  float start_time,
252                                                  float end_time)
253     : InterpolatedTransform(start_time, end_time),
254       start_pos_(start_pos),
255       end_pos_(end_pos) {
256 }
257
258 InterpolatedTranslation::InterpolatedTranslation(const gfx::Point3F& start_pos,
259                                                  const gfx::Point3F& end_pos)
260     : InterpolatedTransform(), start_pos_(start_pos), end_pos_(end_pos) {
261 }
262
263 InterpolatedTranslation::InterpolatedTranslation(const gfx::Point3F& start_pos,
264                                                  const gfx::Point3F& end_pos,
265                                                  float start_time,
266                                                  float end_time)
267     : InterpolatedTransform(start_time, end_time),
268       start_pos_(start_pos),
269       end_pos_(end_pos) {
270 }
271
272 InterpolatedTranslation::~InterpolatedTranslation() {}
273
274 gfx::Transform
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()));
280   return result;
281 }
282
283 ///////////////////////////////////////////////////////////////////////////////
284 // InterpolatedConstantTransform
285 //
286
287 InterpolatedConstantTransform::InterpolatedConstantTransform(
288   const gfx::Transform& transform)
289     : InterpolatedTransform(),
290   transform_(transform) {
291 }
292
293 gfx::Transform
294 InterpolatedConstantTransform::InterpolateButDoNotCompose(float t) const {
295   return transform_;
296 }
297
298 InterpolatedConstantTransform::~InterpolatedConstantTransform() {}
299
300 ///////////////////////////////////////////////////////////////////////////////
301 // InterpolatedTransformAboutPivot
302 //
303
304 InterpolatedTransformAboutPivot::InterpolatedTransformAboutPivot(
305   const gfx::Point& pivot,
306   InterpolatedTransform* transform)
307     : InterpolatedTransform() {
308   Init(pivot, transform);
309 }
310
311 InterpolatedTransformAboutPivot::InterpolatedTransformAboutPivot(
312   const gfx::Point& pivot,
313   InterpolatedTransform* transform,
314   float start_time,
315   float end_time)
316     : InterpolatedTransform() {
317   Init(pivot, transform);
318 }
319
320 InterpolatedTransformAboutPivot::~InterpolatedTransformAboutPivot() {}
321
322 gfx::Transform
323 InterpolatedTransformAboutPivot::InterpolateButDoNotCompose(float t) const {
324   if (transform_.get()) {
325     return transform_->Interpolate(t);
326   }
327   return gfx::Transform();
328 }
329
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()));
336
337   scoped_ptr<InterpolatedTransform> pre_transform(
338     new InterpolatedConstantTransform(to_pivot));
339   scoped_ptr<InterpolatedTransform> post_transform(
340     new InterpolatedConstantTransform(from_pivot));
341
342   pre_transform->SetChild(xform);
343   xform->SetChild(post_transform.release());
344   transform_.reset(pre_transform.release());
345 }
346
347 InterpolatedMatrixTransform::InterpolatedMatrixTransform(
348     const gfx::Transform& start_transform,
349     const gfx::Transform& end_transform)
350     : InterpolatedTransform() {
351   Init(start_transform, end_transform);
352 }
353
354 InterpolatedMatrixTransform::InterpolatedMatrixTransform(
355     const gfx::Transform& start_transform,
356     const gfx::Transform& end_transform,
357     float start_time,
358     float end_time)
359     : InterpolatedTransform() {
360   Init(start_transform, end_transform);
361 }
362
363 InterpolatedMatrixTransform::~InterpolatedMatrixTransform() {}
364
365 gfx::Transform
366 InterpolatedMatrixTransform::InterpolateButDoNotCompose(float t) const {
367   gfx::DecomposedTransform blended;
368   bool success = gfx::BlendDecomposedTransforms(&blended,
369                                                 end_decomp_,
370                                                 start_decomp_,
371                                                 t);
372   DCHECK(success);
373   return gfx::ComposeTransform(blended);
374 }
375
376 void InterpolatedMatrixTransform::Init(const gfx::Transform& start_transform,
377                                        const gfx::Transform& end_transform) {
378   bool success = gfx::DecomposeTransform(&start_decomp_, start_transform);
379   DCHECK(success);
380   success = gfx::DecomposeTransform(&end_decomp_, end_transform);
381   DCHECK(success);
382 }
383
384 } // namespace ui