| 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 |