Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(364)

Side by Side Diff: cc/animation/transform_operation.cc

Issue 55763004: Allow the computation of inflated bounds for non matrix transform operations. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 216 matching lines...) Expand 10 before | Expand all | Expand 10 after
243 } 245 }
244 246
245 static float RadiansToDegrees(float radians) { 247 static float RadiansToDegrees(float radians) {
246 return (180.f * radians) / M_PI; 248 return (180.f * radians) / M_PI;
247 } 249 }
248 250
249 static float DegreesToRadians(float degrees) { 251 static float DegreesToRadians(float degrees) {
250 return (M_PI * degrees) / 180.f; 252 return (M_PI * degrees) / 180.f;
251 } 253 }
252 254
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, 255 static void BoundingBoxForArc(const gfx::Point3F& point,
268 const TransformOperation* from, 256 const TransformOperation* from,
269 const TransformOperation* to, 257 const TransformOperation* to,
270 SkMScalar min_progress, 258 SkMScalar min_progress,
271 SkMScalar max_progress, 259 SkMScalar max_progress,
272 gfx::BoxF* box) { 260 gfx::BoxF* box) {
273 const TransformOperation* exemplar = from ? from : to; 261 const TransformOperation* exemplar = from ? from : to;
274 gfx::Vector3dF axis(exemplar->rotate.axis.x, 262 gfx::Vector3dF axis(exemplar->rotate.axis.x,
275 exemplar->rotate.axis.y, 263 exemplar->rotate.axis.y,
276 exemplar->rotate.axis.z); 264 exemplar->rotate.axis.z);
277 265
278 const bool x_is_zero = axis.x() == 0.f; 266 const bool x_is_zero = axis.x() == 0.f;
279 const bool y_is_zero = axis.y() == 0.f; 267 const bool y_is_zero = axis.y() == 0.f;
280 const bool z_is_zero = axis.z() == 0.f; 268 const bool z_is_zero = axis.z() == 0.f;
281 269
282 // We will have at most 6 angles to test (excluding from->angle and 270 // We will have at most 6 angles to test (excluding from->angle and
283 // to->angle). 271 // to->angle).
284 static const int kMaxNumCandidates = 6; 272 static const int kMaxNumCandidates = 6;
285 double candidates[kMaxNumCandidates]; 273 double candidates[kMaxNumCandidates];
286 int num_candidates = kMaxNumCandidates; 274 int num_candidates = kMaxNumCandidates;
287 275
288 if (x_is_zero && y_is_zero && z_is_zero) 276 if (x_is_zero && y_is_zero && z_is_zero)
289 return; 277 return;
290 278
291 SkMScalar from_angle = from ? from->rotate.angle : 0.f; 279 SkMScalar from_angle = from ? from->rotate.angle : 0.f;
292 SkMScalar to_angle = to ? to->rotate.angle : 0.f; 280 SkMScalar to_angle = to ? to->rotate.angle : 0.f;
293 281
282 // If the axes of rotation are pointing in opposite directions, we need to
283 // flip one of the angles. Note, if both |from| and |to| exist, then axis will
284 // correspond to |from|.
285 if (from && to) {
286 gfx::Vector3dF other_axis(
287 to->rotate.axis.x, to->rotate.axis.y, to->rotate.axis.z);
288 if (gfx::DotProduct(axis, other_axis) < 0.f)
289 to_angle *= -1.f;
290 }
ajuma 2013/11/01 21:02:08 One thing I find confusing is that we don't need t
Ian Vollick 2013/11/03 19:05:19 Whoops, nothing! I thought that we'd enforced that
291
294 float min_degrees = 292 float min_degrees =
295 SkMScalarToFloat(BlendSkMScalars(from_angle, to_angle, min_progress)); 293 SkMScalarToFloat(BlendSkMScalars(from_angle, to_angle, min_progress));
296 float max_degrees = 294 float max_degrees =
297 SkMScalarToFloat(BlendSkMScalars(from_angle, to_angle, max_progress)); 295 SkMScalarToFloat(BlendSkMScalars(from_angle, to_angle, max_progress));
298 if (max_degrees < min_degrees) 296 if (max_degrees < min_degrees)
299 std::swap(min_degrees, max_degrees); 297 std::swap(min_degrees, max_degrees);
300 298
301 gfx::Transform from_transform; 299 gfx::Transform from_transform;
302 from_transform.RotateAbout(axis, min_degrees); 300 from_transform.RotateAbout(axis, min_degrees);
303 gfx::Transform to_transform; 301 gfx::Transform to_transform;
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
353 351
354 gfx::Point3F pz(0.f, 0.f, 1.f); 352 gfx::Point3F pz(0.f, 0.f, 1.f);
355 gfx::Vector3dF to_pz = pz - center; 353 gfx::Vector3dF to_pz = pz - center;
356 gfx::Point3F pz_projected = 354 gfx::Point3F pz_projected =
357 pz - ScaleVector3d(normal, gfx::DotProduct(to_pz, normal)); 355 pz - ScaleVector3d(normal, gfx::DotProduct(to_pz, normal));
358 gfx::Vector3dF vz = pz_projected - origin; 356 gfx::Vector3dF vz = pz_projected - origin;
359 357
360 double phi_x = atan2(gfx::DotProduct(v2, vx), gfx::DotProduct(v1, vx)); 358 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)); 359 double phi_z = atan2(gfx::DotProduct(v2, vz), gfx::DotProduct(v1, vz));
362 360
363 // NB: it is fine if the denominators here are zero and these values go to 361 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; 362 candidates[1] = candidates[0] + M_PI;
370 candidates[2] = atan(tan_theta2) + phi_x; 363 candidates[2] = atan2(-normal.z(), normal.x() * normal.y()) + phi_x;
371 candidates[3] = candidates[2] + M_PI; 364 candidates[3] = candidates[2] + M_PI;
372 candidates[4] = atan(-tan_theta1) + phi_z; 365 candidates[4] = atan2(normal.y(), -normal.x() * normal.z()) + phi_z;
373 candidates[5] = candidates[4] + M_PI; 366 candidates[5] = candidates[4] + M_PI;
374 } 367 }
375 368
376 double min_radians = DegreesToRadians(min_degrees); 369 double min_radians = DegreesToRadians(min_degrees);
377 double max_radians = DegreesToRadians(max_degrees); 370 double max_radians = DegreesToRadians(max_degrees);
378 371
379 for (int i = 0; i < num_candidates; ++i) { 372 for (int i = 0; i < num_candidates; ++i) {
380 double radians = candidates[i]; 373 double radians = candidates[i];
381 while (radians < min_radians) 374 while (radians < min_radians)
382 radians += 2.0 * M_PI; 375 radians += 2.0 * M_PI;
(...skipping 25 matching lines...) Expand all
408 } 401 }
409 402
410 TransformOperation::Type interpolation_type = 403 TransformOperation::Type interpolation_type =
411 TransformOperation::TransformOperationIdentity; 404 TransformOperation::TransformOperationIdentity;
412 if (is_identity_to) 405 if (is_identity_to)
413 interpolation_type = from->type; 406 interpolation_type = from->type;
414 else 407 else
415 interpolation_type = to->type; 408 interpolation_type = to->type;
416 409
417 switch (interpolation_type) { 410 switch (interpolation_type) {
418 case TransformOperation::TransformOperationTranslate: { 411 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; 412 *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; 413 return true;
445 } 414 case TransformOperation::TransformOperationTranslate:
415 case TransformOperation::TransformOperationSkew:
416 case TransformOperation::TransformOperationPerspective:
446 case TransformOperation::TransformOperationScale: { 417 case TransformOperation::TransformOperationScale: {
447 SkMScalar from_x, from_y, from_z; 418 gfx::Transform from_transform;
448 if (is_identity_from) { 419 gfx::Transform to_transform;
449 from_x = from_y = from_z = 1.0; 420 if (!BlendTransformOperations(from, to, min_progress, &from_transform) ||
450 } else { 421 !BlendTransformOperations(from, to, max_progress, &to_transform))
451 from_x = from->scale.x; 422 return false;
452 from_y = from->scale.y; 423
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; 424 *bounds = box;
464 ApplyScaleToBox( 425 from_transform.TransformBox(bounds);
465 SkMScalarToFloat(BlendSkMScalars(from_x, to_x, min_progress)), 426
466 SkMScalarToFloat(BlendSkMScalars(from_y, to_y, min_progress)), 427 gfx::BoxF to_box = box;
467 SkMScalarToFloat(BlendSkMScalars(from_z, to_z, min_progress)), 428 to_transform.TransformBox(&to_box);
468 bounds); 429 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 430
484 return true; 431 return true;
485 } 432 }
486 case TransformOperation::TransformOperationIdentity:
487 *bounds = box;
488 return true;
489 case TransformOperation::TransformOperationRotate: { 433 case TransformOperation::TransformOperationRotate: {
490 bool first_point = true; 434 bool first_point = true;
491 for (int i = 0; i < 8; ++i) { 435 for (int i = 0; i < 8; ++i) {
492 gfx::Point3F corner = box.origin(); 436 gfx::Point3F corner = box.origin();
493 corner += gfx::Vector3dF(i & 1 ? box.width() : 0.f, 437 corner += gfx::Vector3dF(i & 1 ? box.width() : 0.f,
494 i & 2 ? box.height() : 0.f, 438 i & 2 ? box.height() : 0.f,
495 i & 4 ? box.depth() : 0.f); 439 i & 4 ? box.depth() : 0.f);
496 gfx::BoxF box_for_arc; 440 gfx::BoxF box_for_arc;
497 BoundingBoxForArc( 441 BoundingBoxForArc(
498 corner, from, to, min_progress, max_progress, &box_for_arc); 442 corner, from, to, min_progress, max_progress, &box_for_arc);
499 if (first_point) 443 if (first_point)
500 *bounds = box_for_arc; 444 *bounds = box_for_arc;
501 else 445 else
502 bounds->Union(box_for_arc); 446 bounds->Union(box_for_arc);
503 first_point = false; 447 first_point = false;
504 } 448 }
505 return true; 449 return true;
506 } 450 }
507 case TransformOperation::TransformOperationSkew:
508 case TransformOperation::TransformOperationPerspective:
509 case TransformOperation::TransformOperationMatrix: 451 case TransformOperation::TransformOperationMatrix:
510 return false; 452 return false;
511 } 453 }
512 NOTREACHED(); 454 NOTREACHED();
513 return false; 455 return false;
514 } 456 }
515 457
516 } // namespace cc 458 } // namespace cc
OLDNEW
« no previous file with comments | « cc/animation/layer_animation_controller_unittest.cc ('k') | cc/animation/transform_operations_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698