| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 // Needed on Windows to get |M_PI| from <cmath> | 5 // Needed on Windows to get |M_PI| from <cmath> |
| 6 #ifdef _WIN32 | 6 #ifdef _WIN32 |
| 7 #define _USE_MATH_DEFINES | 7 #define _USE_MATH_DEFINES |
| 8 #endif | 8 #endif |
| 9 | 9 |
| 10 #include <algorithm> | 10 #include <algorithm> |
| 11 #include <cmath> | 11 #include <cmath> |
| 12 #include <limits> | 12 #include <limits> |
| 13 | 13 |
| 14 #include "base/logging.h" | 14 #include "base/logging.h" |
| 15 #include "cc/animation/transform_operation.h" | 15 #include "cc/animation/transform_operation.h" |
| 16 #include "cc/animation/transform_operations.h" |
| 16 #include "ui/gfx/box_f.h" | 17 #include "ui/gfx/box_f.h" |
| 18 #include "ui/gfx/transform_util.h" |
| 17 #include "ui/gfx/vector3d_f.h" | 19 #include "ui/gfx/vector3d_f.h" |
| 18 | 20 |
| 19 namespace { | 21 namespace { |
| 20 const SkMScalar kAngleEpsilon = 1e-4f; | 22 const SkMScalar kAngleEpsilon = 1e-4f; |
| 21 } | 23 } |
| 22 | 24 |
| 23 namespace cc { | 25 namespace cc { |
| 24 | 26 |
| 25 bool TransformOperation::IsIdentity() const { | 27 bool TransformOperation::IsIdentity() const { |
| 26 return matrix.IsIdentity(); | 28 return matrix.IsIdentity(); |
| (...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 191 break; | 193 break; |
| 192 } | 194 } |
| 193 case TransformOperation::TransformOperationIdentity: | 195 case TransformOperation::TransformOperationIdentity: |
| 194 // Do nothing. | 196 // Do nothing. |
| 195 break; | 197 break; |
| 196 } | 198 } |
| 197 | 199 |
| 198 return true; | 200 return true; |
| 199 } | 201 } |
| 200 | 202 |
| 201 static void ApplyScaleToBox(float x_scale, | |
| 202 float y_scale, | |
| 203 float z_scale, | |
| 204 gfx::BoxF* box) { | |
| 205 if (x_scale < 0) | |
| 206 box->set_x(-box->right()); | |
| 207 if (y_scale < 0) | |
| 208 box->set_y(-box->bottom()); | |
| 209 if (z_scale < 0) | |
| 210 box->set_z(-box->front()); | |
| 211 box->Scale(std::abs(x_scale), std::abs(y_scale), std::abs(z_scale)); | |
| 212 } | |
| 213 | |
| 214 static void UnionBoxWithZeroScale(gfx::BoxF* box) { | |
| 215 float min_x = std::min(box->x(), 0.f); | |
| 216 float min_y = std::min(box->y(), 0.f); | |
| 217 float min_z = std::min(box->z(), 0.f); | |
| 218 float max_x = std::max(box->right(), 0.f); | |
| 219 float max_y = std::max(box->bottom(), 0.f); | |
| 220 float max_z = std::max(box->front(), 0.f); | |
| 221 *box = gfx::BoxF( | |
| 222 min_x, min_y, min_z, max_x - min_x, max_y - min_y, max_z - min_z); | |
| 223 } | |
| 224 | |
| 225 // If p = (px, py) is a point in the plane being rotated about (0, 0, nz), this | 203 // If p = (px, py) is a point in the plane being rotated about (0, 0, nz), this |
| 226 // function computes the angles we would have to rotate from p to get to | 204 // function computes the angles we would have to rotate from p to get to |
| 227 // (length(p), 0), (-length(p), 0), (0, length(p)), (0, -length(p)). If nz is | 205 // (length(p), 0), (-length(p), 0), (0, length(p)), (0, -length(p)). If nz is |
| 228 // negative, these angles will need to be reversed. | 206 // negative, these angles will need to be reversed. |
| 229 static void FindCandidatesInPlane(float px, | 207 static void FindCandidatesInPlane(float px, |
| 230 float py, | 208 float py, |
| 231 float nz, | 209 float nz, |
| 232 double* candidates, | 210 double* candidates, |
| 233 int* num_candidates) { | 211 int* num_candidates) { |
| 234 double phi = atan2(px, py); | 212 double phi = atan2(px, py); |
| 235 *num_candidates = 4; | 213 *num_candidates = 4; |
| 236 candidates[0] = phi; | 214 candidates[0] = phi; |
| 237 for (int i = 1; i < *num_candidates; ++i) | 215 for (int i = 1; i < *num_candidates; ++i) |
| 238 candidates[i] = candidates[i - 1] + M_PI_2; | 216 candidates[i] = candidates[i - 1] + M_PI_2; |
| 239 if (nz < 0.f) { | 217 if (nz < 0.f) { |
| 240 for (int i = 0; i < *num_candidates; ++i) | 218 for (int i = 0; i < *num_candidates; ++i) |
| 241 candidates[i] *= -1.f; | 219 candidates[i] *= -1.f; |
| 242 } | 220 } |
| 243 } | 221 } |
| 244 | 222 |
| 245 static float RadiansToDegrees(float radians) { | 223 static float RadiansToDegrees(float radians) { |
| 246 return (180.f * radians) / M_PI; | 224 return (180.f * radians) / M_PI; |
| 247 } | 225 } |
| 248 | 226 |
| 249 static float DegreesToRadians(float degrees) { | 227 static float DegreesToRadians(float degrees) { |
| 250 return (M_PI * degrees) / 180.f; | 228 return (M_PI * degrees) / 180.f; |
| 251 } | 229 } |
| 252 | 230 |
| 253 // Div by zero doesn't always result in Inf as you might hope, so we'll do this | |
| 254 // explicitly here. | |
| 255 static float SafeDivide(float numerator, float denominator) { | |
| 256 if (numerator == 0.f) | |
| 257 return 0.f; | |
| 258 | |
| 259 if (denominator == 0.f) { | |
| 260 return numerator > 0.f ? std::numeric_limits<float>::infinity() | |
| 261 : -std::numeric_limits<float>::infinity(); | |
| 262 } | |
| 263 | |
| 264 return numerator / denominator; | |
| 265 } | |
| 266 | |
| 267 static void BoundingBoxForArc(const gfx::Point3F& point, | 231 static void BoundingBoxForArc(const gfx::Point3F& point, |
| 268 const TransformOperation* from, | 232 const TransformOperation* from, |
| 269 const TransformOperation* to, | 233 const TransformOperation* to, |
| 270 SkMScalar min_progress, | 234 SkMScalar min_progress, |
| 271 SkMScalar max_progress, | 235 SkMScalar max_progress, |
| 272 gfx::BoxF* box) { | 236 gfx::BoxF* box) { |
| 273 const TransformOperation* exemplar = from ? from : to; | 237 const TransformOperation* exemplar = from ? from : to; |
| 274 gfx::Vector3dF axis(exemplar->rotate.axis.x, | 238 gfx::Vector3dF axis(exemplar->rotate.axis.x, |
| 275 exemplar->rotate.axis.y, | 239 exemplar->rotate.axis.y, |
| 276 exemplar->rotate.axis.z); | 240 exemplar->rotate.axis.z); |
| 277 | 241 |
| 278 const bool x_is_zero = axis.x() == 0.f; | 242 const bool x_is_zero = axis.x() == 0.f; |
| 279 const bool y_is_zero = axis.y() == 0.f; | 243 const bool y_is_zero = axis.y() == 0.f; |
| 280 const bool z_is_zero = axis.z() == 0.f; | 244 const bool z_is_zero = axis.z() == 0.f; |
| 281 | 245 |
| 282 // We will have at most 6 angles to test (excluding from->angle and | 246 // We will have at most 6 angles to test (excluding from->angle and |
| 283 // to->angle). | 247 // to->angle). |
| 284 static const int kMaxNumCandidates = 6; | 248 static const int kMaxNumCandidates = 6; |
| 285 double candidates[kMaxNumCandidates]; | 249 double candidates[kMaxNumCandidates]; |
| 286 int num_candidates = kMaxNumCandidates; | 250 int num_candidates = kMaxNumCandidates; |
| 287 | 251 |
| 288 if (x_is_zero && y_is_zero && z_is_zero) | 252 if (x_is_zero && y_is_zero && z_is_zero) |
| 289 return; | 253 return; |
| 290 | 254 |
| 291 SkMScalar from_angle = from ? from->rotate.angle : 0.f; | 255 SkMScalar from_angle = from ? from->rotate.angle : 0.f; |
| 292 SkMScalar to_angle = to ? to->rotate.angle : 0.f; | 256 SkMScalar to_angle = to ? to->rotate.angle : 0.f; |
| 293 | 257 |
| 258 // If the axes of rotation are pointing in opposite directions, we need to |
| 259 // flip one of the angles. Note, if both |from| and |to| exist, then axis will |
| 260 // correspond to |from|. |
| 261 if (from && to) { |
| 262 gfx::Vector3dF other_axis( |
| 263 to->rotate.axis.x, to->rotate.axis.y, to->rotate.axis.z); |
| 264 if (gfx::DotProduct(axis, other_axis) < 0.f) |
| 265 to_angle *= -1.f; |
| 266 } |
| 267 |
| 294 float min_degrees = | 268 float min_degrees = |
| 295 SkMScalarToFloat(BlendSkMScalars(from_angle, to_angle, min_progress)); | 269 SkMScalarToFloat(BlendSkMScalars(from_angle, to_angle, min_progress)); |
| 296 float max_degrees = | 270 float max_degrees = |
| 297 SkMScalarToFloat(BlendSkMScalars(from_angle, to_angle, max_progress)); | 271 SkMScalarToFloat(BlendSkMScalars(from_angle, to_angle, max_progress)); |
| 298 if (max_degrees < min_degrees) | 272 if (max_degrees < min_degrees) |
| 299 std::swap(min_degrees, max_degrees); | 273 std::swap(min_degrees, max_degrees); |
| 300 | 274 |
| 301 gfx::Transform from_transform; | 275 gfx::Transform from_transform; |
| 302 from_transform.RotateAbout(axis, min_degrees); | 276 from_transform.RotateAbout(axis, min_degrees); |
| 303 gfx::Transform to_transform; | 277 gfx::Transform to_transform; |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 353 | 327 |
| 354 gfx::Point3F pz(0.f, 0.f, 1.f); | 328 gfx::Point3F pz(0.f, 0.f, 1.f); |
| 355 gfx::Vector3dF to_pz = pz - center; | 329 gfx::Vector3dF to_pz = pz - center; |
| 356 gfx::Point3F pz_projected = | 330 gfx::Point3F pz_projected = |
| 357 pz - ScaleVector3d(normal, gfx::DotProduct(to_pz, normal)); | 331 pz - ScaleVector3d(normal, gfx::DotProduct(to_pz, normal)); |
| 358 gfx::Vector3dF vz = pz_projected - origin; | 332 gfx::Vector3dF vz = pz_projected - origin; |
| 359 | 333 |
| 360 double phi_x = atan2(gfx::DotProduct(v2, vx), gfx::DotProduct(v1, vx)); | 334 double phi_x = atan2(gfx::DotProduct(v2, vx), gfx::DotProduct(v1, vx)); |
| 361 double phi_z = atan2(gfx::DotProduct(v2, vz), gfx::DotProduct(v1, vz)); | 335 double phi_z = atan2(gfx::DotProduct(v2, vz), gfx::DotProduct(v1, vz)); |
| 362 | 336 |
| 363 // NB: it is fine if the denominators here are zero and these values go to | 337 candidates[0] = atan2(normal.y(), normal.x() * normal.z()) + phi_x; |
| 364 // infinity; atan can handle it. | |
| 365 double tan_theta1 = SafeDivide(normal.y(), (normal.x() * normal.z())); | |
| 366 double tan_theta2 = SafeDivide(-normal.z(), (normal.x() * normal.y())); | |
| 367 | |
| 368 candidates[0] = atan(tan_theta1) + phi_x; | |
| 369 candidates[1] = candidates[0] + M_PI; | 338 candidates[1] = candidates[0] + M_PI; |
| 370 candidates[2] = atan(tan_theta2) + phi_x; | 339 candidates[2] = atan2(-normal.z(), normal.x() * normal.y()) + phi_x; |
| 371 candidates[3] = candidates[2] + M_PI; | 340 candidates[3] = candidates[2] + M_PI; |
| 372 candidates[4] = atan(-tan_theta1) + phi_z; | 341 candidates[4] = atan2(normal.y(), -normal.x() * normal.z()) + phi_z; |
| 373 candidates[5] = candidates[4] + M_PI; | 342 candidates[5] = candidates[4] + M_PI; |
| 374 } | 343 } |
| 375 | 344 |
| 376 double min_radians = DegreesToRadians(min_degrees); | 345 double min_radians = DegreesToRadians(min_degrees); |
| 377 double max_radians = DegreesToRadians(max_degrees); | 346 double max_radians = DegreesToRadians(max_degrees); |
| 378 | 347 |
| 379 for (int i = 0; i < num_candidates; ++i) { | 348 for (int i = 0; i < num_candidates; ++i) { |
| 380 double radians = candidates[i]; | 349 double radians = candidates[i]; |
| 381 while (radians < min_radians) | 350 while (radians < min_radians) |
| 382 radians += 2.0 * M_PI; | 351 radians += 2.0 * M_PI; |
| (...skipping 25 matching lines...) Expand all Loading... |
| 408 } | 377 } |
| 409 | 378 |
| 410 TransformOperation::Type interpolation_type = | 379 TransformOperation::Type interpolation_type = |
| 411 TransformOperation::TransformOperationIdentity; | 380 TransformOperation::TransformOperationIdentity; |
| 412 if (is_identity_to) | 381 if (is_identity_to) |
| 413 interpolation_type = from->type; | 382 interpolation_type = from->type; |
| 414 else | 383 else |
| 415 interpolation_type = to->type; | 384 interpolation_type = to->type; |
| 416 | 385 |
| 417 switch (interpolation_type) { | 386 switch (interpolation_type) { |
| 418 case TransformOperation::TransformOperationTranslate: { | 387 case TransformOperation::TransformOperationIdentity: |
| 419 SkMScalar from_x, from_y, from_z; | |
| 420 if (is_identity_from) { | |
| 421 from_x = from_y = from_z = 0.0; | |
| 422 } else { | |
| 423 from_x = from->translate.x; | |
| 424 from_y = from->translate.y; | |
| 425 from_z = from->translate.z; | |
| 426 } | |
| 427 SkMScalar to_x, to_y, to_z; | |
| 428 if (is_identity_to) { | |
| 429 to_x = to_y = to_z = 0.0; | |
| 430 } else { | |
| 431 to_x = to->translate.x; | |
| 432 to_y = to->translate.y; | |
| 433 to_z = to->translate.z; | |
| 434 } | |
| 435 *bounds = box; | 388 *bounds = box; |
| 436 *bounds += gfx::Vector3dF(BlendSkMScalars(from_x, to_x, min_progress), | |
| 437 BlendSkMScalars(from_y, to_y, min_progress), | |
| 438 BlendSkMScalars(from_z, to_z, min_progress)); | |
| 439 gfx::BoxF bounds_max = box; | |
| 440 bounds_max += gfx::Vector3dF(BlendSkMScalars(from_x, to_x, max_progress), | |
| 441 BlendSkMScalars(from_y, to_y, max_progress), | |
| 442 BlendSkMScalars(from_z, to_z, max_progress)); | |
| 443 bounds->Union(bounds_max); | |
| 444 return true; | 389 return true; |
| 445 } | 390 case TransformOperation::TransformOperationTranslate: |
| 391 case TransformOperation::TransformOperationSkew: |
| 392 case TransformOperation::TransformOperationPerspective: |
| 446 case TransformOperation::TransformOperationScale: { | 393 case TransformOperation::TransformOperationScale: { |
| 447 SkMScalar from_x, from_y, from_z; | 394 gfx::Transform from_transform; |
| 448 if (is_identity_from) { | 395 gfx::Transform to_transform; |
| 449 from_x = from_y = from_z = 1.0; | 396 if (!BlendTransformOperations(from, to, min_progress, &from_transform) || |
| 450 } else { | 397 !BlendTransformOperations(from, to, max_progress, &to_transform)) |
| 451 from_x = from->scale.x; | 398 return false; |
| 452 from_y = from->scale.y; | 399 |
| 453 from_z = from->scale.z; | |
| 454 } | |
| 455 SkMScalar to_x, to_y, to_z; | |
| 456 if (is_identity_to) { | |
| 457 to_x = to_y = to_z = 1.0; | |
| 458 } else { | |
| 459 to_x = to->scale.x; | |
| 460 to_y = to->scale.y; | |
| 461 to_z = to->scale.z; | |
| 462 } | |
| 463 *bounds = box; | 400 *bounds = box; |
| 464 ApplyScaleToBox( | 401 from_transform.TransformBox(bounds); |
| 465 SkMScalarToFloat(BlendSkMScalars(from_x, to_x, min_progress)), | 402 |
| 466 SkMScalarToFloat(BlendSkMScalars(from_y, to_y, min_progress)), | 403 gfx::BoxF to_box = box; |
| 467 SkMScalarToFloat(BlendSkMScalars(from_z, to_z, min_progress)), | 404 to_transform.TransformBox(&to_box); |
| 468 bounds); | 405 bounds->ExpandTo(to_box); |
| 469 gfx::BoxF bounds_max = box; | |
| 470 ApplyScaleToBox( | |
| 471 SkMScalarToFloat(BlendSkMScalars(from_x, to_x, max_progress)), | |
| 472 SkMScalarToFloat(BlendSkMScalars(from_y, to_y, max_progress)), | |
| 473 SkMScalarToFloat(BlendSkMScalars(from_z, to_z, max_progress)), | |
| 474 &bounds_max); | |
| 475 if (!bounds->IsEmpty() && !bounds_max.IsEmpty()) { | |
| 476 bounds->Union(bounds_max); | |
| 477 } else if (!bounds->IsEmpty()) { | |
| 478 UnionBoxWithZeroScale(bounds); | |
| 479 } else if (!bounds_max.IsEmpty()) { | |
| 480 UnionBoxWithZeroScale(&bounds_max); | |
| 481 *bounds = bounds_max; | |
| 482 } | |
| 483 | 406 |
| 484 return true; | 407 return true; |
| 485 } | 408 } |
| 486 case TransformOperation::TransformOperationIdentity: | |
| 487 *bounds = box; | |
| 488 return true; | |
| 489 case TransformOperation::TransformOperationRotate: { | 409 case TransformOperation::TransformOperationRotate: { |
| 410 SkMScalar axis_x = 0; |
| 411 SkMScalar axis_y = 0; |
| 412 SkMScalar axis_z = 1; |
| 413 SkMScalar from_angle = 0; |
| 414 if (!ShareSameAxis(from, to, &axis_x, &axis_y, &axis_z, &from_angle)) |
| 415 return false; |
| 416 |
| 490 bool first_point = true; | 417 bool first_point = true; |
| 491 for (int i = 0; i < 8; ++i) { | 418 for (int i = 0; i < 8; ++i) { |
| 492 gfx::Point3F corner = box.origin(); | 419 gfx::Point3F corner = box.origin(); |
| 493 corner += gfx::Vector3dF(i & 1 ? box.width() : 0.f, | 420 corner += gfx::Vector3dF(i & 1 ? box.width() : 0.f, |
| 494 i & 2 ? box.height() : 0.f, | 421 i & 2 ? box.height() : 0.f, |
| 495 i & 4 ? box.depth() : 0.f); | 422 i & 4 ? box.depth() : 0.f); |
| 496 gfx::BoxF box_for_arc; | 423 gfx::BoxF box_for_arc; |
| 497 BoundingBoxForArc( | 424 BoundingBoxForArc( |
| 498 corner, from, to, min_progress, max_progress, &box_for_arc); | 425 corner, from, to, min_progress, max_progress, &box_for_arc); |
| 499 if (first_point) | 426 if (first_point) |
| 500 *bounds = box_for_arc; | 427 *bounds = box_for_arc; |
| 501 else | 428 else |
| 502 bounds->Union(box_for_arc); | 429 bounds->Union(box_for_arc); |
| 503 first_point = false; | 430 first_point = false; |
| 504 } | 431 } |
| 505 return true; | 432 return true; |
| 506 } | 433 } |
| 507 case TransformOperation::TransformOperationSkew: | |
| 508 case TransformOperation::TransformOperationPerspective: | |
| 509 case TransformOperation::TransformOperationMatrix: | 434 case TransformOperation::TransformOperationMatrix: |
| 510 return false; | 435 return false; |
| 511 } | 436 } |
| 512 NOTREACHED(); | 437 NOTREACHED(); |
| 513 return false; | 438 return false; |
| 514 } | 439 } |
| 515 | 440 |
| 516 } // namespace cc | 441 } // namespace cc |
| OLD | NEW |