OLD | NEW |
| (Empty) |
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(-pivot.x(), -pivot.y()); | |
335 from_pivot.Translate(pivot.x(), 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 | |
OLD | NEW |