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

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 164 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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
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
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