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 3 // found in the LICENSE file. 4 5 #include <limits> 6 7 #include "base/basictypes.h" 8 #include "base/memory/scoped_vector.h" 9 #include "cc/animation/transform_operations.h" 10 #include "cc/test/geometry_test_utils.h" 11 #include "testing/gtest/include/gtest/gtest.h" 12 #include "ui/gfx/animation/tween.h" 13 #include "ui/gfx/box_f.h" 14 #include "ui/gfx/rect_conversions.h" 15 #include "ui/gfx/vector3d_f.h" 16 17 namespace cc { 18 namespace { 19 20 TEST(TransformOperationTest, TransformTypesAreUnique) { 21 ScopedVector<TransformOperations> transforms; 22 23 TransformOperations* to_add = new TransformOperations(); 24 to_add->AppendTranslate(1, 0, 0); 25 transforms.push_back(to_add); 26 27 to_add = new TransformOperations(); 28 to_add->AppendRotate(0, 0, 1, 2); 29 transforms.push_back(to_add); 30 31 to_add = new TransformOperations(); 32 to_add->AppendScale(2, 2, 2); 33 transforms.push_back(to_add); 34 35 to_add = new TransformOperations(); 36 to_add->AppendSkew(1, 0); 37 transforms.push_back(to_add); 38 39 to_add = new TransformOperations(); 40 to_add->AppendPerspective(800); 41 transforms.push_back(to_add); 42 43 for (size_t i = 0; i < transforms.size(); ++i) { 44 for (size_t j = 0; j < transforms.size(); ++j) { 45 bool matches_type = transforms[i]->MatchesTypes(*transforms[j]); 46 EXPECT_TRUE((i == j && matches_type) || !matches_type); 47 } 48 } 49 } 50 51 TEST(TransformOperationTest, MatchTypesSameLength) { 52 TransformOperations translates; 53 translates.AppendTranslate(1, 0, 0); 54 translates.AppendTranslate(1, 0, 0); 55 translates.AppendTranslate(1, 0, 0); 56 57 TransformOperations skews; 58 skews.AppendSkew(0, 2); 59 skews.AppendSkew(0, 2); 60 skews.AppendSkew(0, 2); 61 62 TransformOperations translates2; 63 translates2.AppendTranslate(0, 2, 0); 64 translates2.AppendTranslate(0, 2, 0); 65 translates2.AppendTranslate(0, 2, 0); 66 67 TransformOperations translates3 = translates2; 68 69 EXPECT_FALSE(translates.MatchesTypes(skews)); 70 EXPECT_TRUE(translates.MatchesTypes(translates2)); 71 EXPECT_TRUE(translates.MatchesTypes(translates3)); 72 } 73 74 TEST(TransformOperationTest, MatchTypesDifferentLength) { 75 TransformOperations translates; 76 translates.AppendTranslate(1, 0, 0); 77 translates.AppendTranslate(1, 0, 0); 78 translates.AppendTranslate(1, 0, 0); 79 80 TransformOperations skews; 81 skews.AppendSkew(2, 0); 82 skews.AppendSkew(2, 0); 83 84 TransformOperations translates2; 85 translates2.AppendTranslate(0, 2, 0); 86 translates2.AppendTranslate(0, 2, 0); 87 88 EXPECT_FALSE(translates.MatchesTypes(skews)); 89 EXPECT_FALSE(translates.MatchesTypes(translates2)); 90 } 91 92 void GetIdentityOperations(ScopedVector<TransformOperations>* operations) { 93 TransformOperations* to_add = new TransformOperations(); 94 operations->push_back(to_add); 95 96 to_add = new TransformOperations(); 97 to_add->AppendTranslate(0, 0, 0); 98 operations->push_back(to_add); 99 100 to_add = new TransformOperations(); 101 to_add->AppendTranslate(0, 0, 0); 102 to_add->AppendTranslate(0, 0, 0); 103 operations->push_back(to_add); 104 105 to_add = new TransformOperations(); 106 to_add->AppendScale(1, 1, 1); 107 operations->push_back(to_add); 108 109 to_add = new TransformOperations(); 110 to_add->AppendScale(1, 1, 1); 111 to_add->AppendScale(1, 1, 1); 112 operations->push_back(to_add); 113 114 to_add = new TransformOperations(); 115 to_add->AppendSkew(0, 0); 116 operations->push_back(to_add); 117 118 to_add = new TransformOperations(); 119 to_add->AppendSkew(0, 0); 120 to_add->AppendSkew(0, 0); 121 operations->push_back(to_add); 122 123 to_add = new TransformOperations(); 124 to_add->AppendRotate(0, 0, 1, 0); 125 operations->push_back(to_add); 126 127 to_add = new TransformOperations(); 128 to_add->AppendRotate(0, 0, 1, 0); 129 to_add->AppendRotate(0, 0, 1, 0); 130 operations->push_back(to_add); 131 132 to_add = new TransformOperations(); 133 to_add->AppendMatrix(gfx::Transform()); 134 operations->push_back(to_add); 135 136 to_add = new TransformOperations(); 137 to_add->AppendMatrix(gfx::Transform()); 138 to_add->AppendMatrix(gfx::Transform()); 139 operations->push_back(to_add); 140 } 141 142 TEST(TransformOperationTest, IdentityAlwaysMatches) { 143 ScopedVector<TransformOperations> operations; 144 GetIdentityOperations(&operations); 145 146 for (size_t i = 0; i < operations.size(); ++i) { 147 for (size_t j = 0; j < operations.size(); ++j) 148 EXPECT_TRUE(operations[i]->MatchesTypes(*operations[j])); 149 } 150 } 151 152 TEST(TransformOperationTest, ApplyTranslate) { 153 SkMScalar x = 1; 154 SkMScalar y = 2; 155 SkMScalar z = 3; 156 TransformOperations operations; 157 operations.AppendTranslate(x, y, z); 158 gfx::Transform expected; 159 expected.Translate3d(x, y, z); 160 EXPECT_TRANSFORMATION_MATRIX_EQ(expected, operations.Apply()); 161 } 162 163 TEST(TransformOperationTest, ApplyRotate) { 164 SkMScalar x = 1; 165 SkMScalar y = 2; 166 SkMScalar z = 3; 167 SkMScalar degrees = 80; 168 TransformOperations operations; 169 operations.AppendRotate(x, y, z, degrees); 170 gfx::Transform expected; 171 expected.RotateAbout(gfx::Vector3dF(x, y, z), degrees); 172 EXPECT_TRANSFORMATION_MATRIX_EQ(expected, operations.Apply()); 173 } 174 175 TEST(TransformOperationTest, ApplyScale) { 176 SkMScalar x = 1; 177 SkMScalar y = 2; 178 SkMScalar z = 3; 179 TransformOperations operations; 180 operations.AppendScale(x, y, z); 181 gfx::Transform expected; 182 expected.Scale3d(x, y, z); 183 EXPECT_TRANSFORMATION_MATRIX_EQ(expected, operations.Apply()); 184 } 185 186 TEST(TransformOperationTest, ApplySkew) { 187 SkMScalar x = 1; 188 SkMScalar y = 2; 189 TransformOperations operations; 190 operations.AppendSkew(x, y); 191 gfx::Transform expected; 192 expected.SkewX(x); 193 expected.SkewY(y); 194 EXPECT_TRANSFORMATION_MATRIX_EQ(expected, operations.Apply()); 195 } 196 197 TEST(TransformOperationTest, ApplyPerspective) { 198 SkMScalar depth = 800; 199 TransformOperations operations; 200 operations.AppendPerspective(depth); 201 gfx::Transform expected; 202 expected.ApplyPerspectiveDepth(depth); 203 EXPECT_TRANSFORMATION_MATRIX_EQ(expected, operations.Apply()); 204 } 205 206 TEST(TransformOperationTest, ApplyMatrix) { 207 SkMScalar dx = 1; 208 SkMScalar dy = 2; 209 SkMScalar dz = 3; 210 gfx::Transform expected_matrix; 211 expected_matrix.Translate3d(dx, dy, dz); 212 TransformOperations matrix_transform; 213 matrix_transform.AppendMatrix(expected_matrix); 214 EXPECT_TRANSFORMATION_MATRIX_EQ(expected_matrix, matrix_transform.Apply()); 215 } 216 217 TEST(TransformOperationTest, ApplyOrder) { 218 SkMScalar sx = 2; 219 SkMScalar sy = 4; 220 SkMScalar sz = 8; 221 222 SkMScalar dx = 1; 223 SkMScalar dy = 2; 224 SkMScalar dz = 3; 225 226 TransformOperations operations; 227 operations.AppendScale(sx, sy, sz); 228 operations.AppendTranslate(dx, dy, dz); 229 230 gfx::Transform expected_scale_matrix; 231 expected_scale_matrix.Scale3d(sx, sy, sz); 232 233 gfx::Transform expected_translate_matrix; 234 expected_translate_matrix.Translate3d(dx, dy, dz); 235 236 gfx::Transform expected_combined_matrix = expected_scale_matrix; 237 expected_combined_matrix.PreconcatTransform(expected_translate_matrix); 238 239 EXPECT_TRANSFORMATION_MATRIX_EQ(expected_combined_matrix, operations.Apply()); 240 } 241 242 TEST(TransformOperationTest, BlendOrder) { 243 SkMScalar sx1 = 2; 244 SkMScalar sy1 = 4; 245 SkMScalar sz1 = 8; 246 247 SkMScalar dx1 = 1; 248 SkMScalar dy1 = 2; 249 SkMScalar dz1 = 3; 250 251 SkMScalar sx2 = 4; 252 SkMScalar sy2 = 8; 253 SkMScalar sz2 = 16; 254 255 SkMScalar dx2 = 10; 256 SkMScalar dy2 = 20; 257 SkMScalar dz2 = 30; 258 259 TransformOperations operations_from; 260 operations_from.AppendScale(sx1, sy1, sz1); 261 operations_from.AppendTranslate(dx1, dy1, dz1); 262 263 TransformOperations operations_to; 264 operations_to.AppendScale(sx2, sy2, sz2); 265 operations_to.AppendTranslate(dx2, dy2, dz2); 266 267 gfx::Transform scale_from; 268 scale_from.Scale3d(sx1, sy1, sz1); 269 gfx::Transform translate_from; 270 translate_from.Translate3d(dx1, dy1, dz1); 271 272 gfx::Transform scale_to; 273 scale_to.Scale3d(sx2, sy2, sz2); 274 gfx::Transform translate_to; 275 translate_to.Translate3d(dx2, dy2, dz2); 276 277 SkMScalar progress = 0.25f; 278 279 gfx::Transform blended_scale = scale_to; 280 blended_scale.Blend(scale_from, progress); 281 282 gfx::Transform blended_translate = translate_to; 283 blended_translate.Blend(translate_from, progress); 284 285 gfx::Transform expected = blended_scale; 286 expected.PreconcatTransform(blended_translate); 287 288 EXPECT_TRANSFORMATION_MATRIX_EQ( 289 expected, operations_to.Blend(operations_from, progress)); 290 } 291 292 static void CheckProgress(SkMScalar progress, 293 const gfx::Transform& from_matrix, 294 const gfx::Transform& to_matrix, 295 const TransformOperations& from_transform, 296 const TransformOperations& to_transform) { 297 gfx::Transform expected_matrix = to_matrix; 298 expected_matrix.Blend(from_matrix, progress); 299 EXPECT_TRANSFORMATION_MATRIX_EQ( 300 expected_matrix, to_transform.Blend(from_transform, progress)); 301 } 302 303 TEST(TransformOperationTest, BlendProgress) { 304 SkMScalar sx = 2; 305 SkMScalar sy = 4; 306 SkMScalar sz = 8; 307 TransformOperations operations_from; 308 operations_from.AppendScale(sx, sy, sz); 309 310 gfx::Transform matrix_from; 311 matrix_from.Scale3d(sx, sy, sz); 312 313 sx = 4; 314 sy = 8; 315 sz = 16; 316 TransformOperations operations_to; 317 operations_to.AppendScale(sx, sy, sz); 318 319 gfx::Transform matrix_to; 320 matrix_to.Scale3d(sx, sy, sz); 321 322 CheckProgress(-1, matrix_from, matrix_to, operations_from, operations_to); 323 CheckProgress(0, matrix_from, matrix_to, operations_from, operations_to); 324 CheckProgress(0.25f, matrix_from, matrix_to, operations_from, operations_to); 325 CheckProgress(0.5f, matrix_from, matrix_to, operations_from, operations_to); 326 CheckProgress(1, matrix_from, matrix_to, operations_from, operations_to); 327 CheckProgress(2, matrix_from, matrix_to, operations_from, operations_to); 328 } 329 330 TEST(TransformOperationTest, BlendWhenTypesDoNotMatch) { 331 SkMScalar sx1 = 2; 332 SkMScalar sy1 = 4; 333 SkMScalar sz1 = 8; 334 335 SkMScalar dx1 = 1; 336 SkMScalar dy1 = 2; 337 SkMScalar dz1 = 3; 338 339 SkMScalar sx2 = 4; 340 SkMScalar sy2 = 8; 341 SkMScalar sz2 = 16; 342 343 SkMScalar dx2 = 10; 344 SkMScalar dy2 = 20; 345 SkMScalar dz2 = 30; 346 347 TransformOperations operations_from; 348 operations_from.AppendScale(sx1, sy1, sz1); 349 operations_from.AppendTranslate(dx1, dy1, dz1); 350 351 TransformOperations operations_to; 352 operations_to.AppendTranslate(dx2, dy2, dz2); 353 operations_to.AppendScale(sx2, sy2, sz2); 354 355 gfx::Transform from; 356 from.Scale3d(sx1, sy1, sz1); 357 from.Translate3d(dx1, dy1, dz1); 358 359 gfx::Transform to; 360 to.Translate3d(dx2, dy2, dz2); 361 to.Scale3d(sx2, sy2, sz2); 362 363 SkMScalar progress = 0.25f; 364 365 gfx::Transform expected = to; 366 expected.Blend(from, progress); 367 368 EXPECT_TRANSFORMATION_MATRIX_EQ( 369 expected, operations_to.Blend(operations_from, progress)); 370 } 371 372 TEST(TransformOperationTest, LargeRotationsWithSameAxis) { 373 TransformOperations operations_from; 374 operations_from.AppendRotate(0, 0, 1, 0); 375 376 TransformOperations operations_to; 377 operations_to.AppendRotate(0, 0, 2, 360); 378 379 SkMScalar progress = 0.5f; 380 381 gfx::Transform expected; 382 expected.RotateAbout(gfx::Vector3dF(0, 0, 1), 180); 383 384 EXPECT_TRANSFORMATION_MATRIX_EQ( 385 expected, operations_to.Blend(operations_from, progress)); 386 } 387 388 TEST(TransformOperationTest, LargeRotationsWithSameAxisInDifferentDirection) { 389 TransformOperations operations_from; 390 operations_from.AppendRotate(0, 0, 1, 180); 391 392 TransformOperations operations_to; 393 operations_to.AppendRotate(0, 0, -1, 180); 394 395 SkMScalar progress = 0.5f; 396 397 gfx::Transform expected; 398 399 EXPECT_TRANSFORMATION_MATRIX_EQ( 400 expected, operations_to.Blend(operations_from, progress)); 401 } 402 403 TEST(TransformOperationTest, LargeRotationsWithDifferentAxes) { 404 TransformOperations operations_from; 405 operations_from.AppendRotate(0, 0, 1, 175); 406 407 TransformOperations operations_to; 408 operations_to.AppendRotate(0, 1, 0, 175); 409 410 SkMScalar progress = 0.5f; 411 gfx::Transform matrix_from; 412 matrix_from.RotateAbout(gfx::Vector3dF(0, 0, 1), 175); 413 414 gfx::Transform matrix_to; 415 matrix_to.RotateAbout(gfx::Vector3dF(0, 1, 0), 175); 416 417 gfx::Transform expected = matrix_to; 418 expected.Blend(matrix_from, progress); 419 420 EXPECT_TRANSFORMATION_MATRIX_EQ( 421 expected, operations_to.Blend(operations_from, progress)); 422 } 423 424 TEST(TransformOperationTest, BlendRotationFromIdentity) { 425 ScopedVector<TransformOperations> identity_operations; 426 GetIdentityOperations(&identity_operations); 427 428 for (size_t i = 0; i < identity_operations.size(); ++i) { 429 TransformOperations operations; 430 operations.AppendRotate(0, 0, 1, 360); 431 432 SkMScalar progress = 0.5f; 433 434 gfx::Transform expected; 435 expected.RotateAbout(gfx::Vector3dF(0, 0, 1), 180); 436 437 EXPECT_TRANSFORMATION_MATRIX_EQ( 438 expected, operations.Blend(*identity_operations[i], progress)); 439 440 progress = -0.5f; 441 442 expected.MakeIdentity(); 443 expected.RotateAbout(gfx::Vector3dF(0, 0, 1), -180); 444 445 EXPECT_TRANSFORMATION_MATRIX_EQ( 446 expected, operations.Blend(*identity_operations[i], progress)); 447 448 progress = 1.5f; 449 450 expected.MakeIdentity(); 451 expected.RotateAbout(gfx::Vector3dF(0, 0, 1), 540); 452 453 EXPECT_TRANSFORMATION_MATRIX_EQ( 454 expected, operations.Blend(*identity_operations[i], progress)); 455 } 456 } 457 458 TEST(TransformOperationTest, BlendTranslationFromIdentity) { 459 ScopedVector<TransformOperations> identity_operations; 460 GetIdentityOperations(&identity_operations); 461 462 for (size_t i = 0; i < identity_operations.size(); ++i) { 463 TransformOperations operations; 464 operations.AppendTranslate(2, 2, 2); 465 466 SkMScalar progress = 0.5f; 467 468 gfx::Transform expected; 469 expected.Translate3d(1, 1, 1); 470 471 EXPECT_TRANSFORMATION_MATRIX_EQ( 472 expected, operations.Blend(*identity_operations[i], progress)); 473 474 progress = -0.5f; 475 476 expected.MakeIdentity(); 477 expected.Translate3d(-1, -1, -1); 478 479 EXPECT_TRANSFORMATION_MATRIX_EQ( 480 expected, operations.Blend(*identity_operations[i], progress)); 481 482 progress = 1.5f; 483 484 expected.MakeIdentity(); 485 expected.Translate3d(3, 3, 3); 486 487 EXPECT_TRANSFORMATION_MATRIX_EQ( 488 expected, operations.Blend(*identity_operations[i], progress)); 489 } 490 } 491 492 TEST(TransformOperationTest, BlendScaleFromIdentity) { 493 ScopedVector<TransformOperations> identity_operations; 494 GetIdentityOperations(&identity_operations); 495 496 for (size_t i = 0; i < identity_operations.size(); ++i) { 497 TransformOperations operations; 498 operations.AppendScale(3, 3, 3); 499 500 SkMScalar progress = 0.5f; 501 502 gfx::Transform expected; 503 expected.Scale3d(2, 2, 2); 504 505 EXPECT_TRANSFORMATION_MATRIX_EQ( 506 expected, operations.Blend(*identity_operations[i], progress)); 507 508 progress = -0.5f; 509 510 expected.MakeIdentity(); 511 expected.Scale3d(0, 0, 0); 512 513 EXPECT_TRANSFORMATION_MATRIX_EQ( 514 expected, operations.Blend(*identity_operations[i], progress)); 515 516 progress = 1.5f; 517 518 expected.MakeIdentity(); 519 expected.Scale3d(4, 4, 4); 520 521 EXPECT_TRANSFORMATION_MATRIX_EQ( 522 expected, operations.Blend(*identity_operations[i], progress)); 523 } 524 } 525 526 TEST(TransformOperationTest, BlendSkewFromIdentity) { 527 ScopedVector<TransformOperations> identity_operations; 528 GetIdentityOperations(&identity_operations); 529 530 for (size_t i = 0; i < identity_operations.size(); ++i) { 531 TransformOperations operations; 532 operations.AppendSkew(2, 2); 533 534 SkMScalar progress = 0.5f; 535 536 gfx::Transform expected; 537 expected.SkewX(1); 538 expected.SkewY(1); 539 540 EXPECT_TRANSFORMATION_MATRIX_EQ( 541 expected, operations.Blend(*identity_operations[i], progress)); 542 543 progress = -0.5f; 544 545 expected.MakeIdentity(); 546 expected.SkewX(-1); 547 expected.SkewY(-1); 548 549 EXPECT_TRANSFORMATION_MATRIX_EQ( 550 expected, operations.Blend(*identity_operations[i], progress)); 551 552 progress = 1.5f; 553 554 expected.MakeIdentity(); 555 expected.SkewX(3); 556 expected.SkewY(3); 557 558 EXPECT_TRANSFORMATION_MATRIX_EQ( 559 expected, operations.Blend(*identity_operations[i], progress)); 560 } 561 } 562 563 TEST(TransformOperationTest, BlendPerspectiveFromIdentity) { 564 ScopedVector<TransformOperations> identity_operations; 565 GetIdentityOperations(&identity_operations); 566 567 for (size_t i = 0; i < identity_operations.size(); ++i) { 568 TransformOperations operations; 569 operations.AppendPerspective(1000); 570 571 SkMScalar progress = 0.5f; 572 573 gfx::Transform expected; 574 expected.ApplyPerspectiveDepth(2000); 575 576 EXPECT_TRANSFORMATION_MATRIX_EQ( 577 expected, operations.Blend(*identity_operations[i], progress)); 578 } 579 } 580 581 TEST(TransformOperationTest, BlendRotationToIdentity) { 582 ScopedVector<TransformOperations> identity_operations; 583 GetIdentityOperations(&identity_operations); 584 585 for (size_t i = 0; i < identity_operations.size(); ++i) { 586 TransformOperations operations; 587 operations.AppendRotate(0, 0, 1, 360); 588 589 SkMScalar progress = 0.5f; 590 591 gfx::Transform expected; 592 expected.RotateAbout(gfx::Vector3dF(0, 0, 1), 180); 593 594 EXPECT_TRANSFORMATION_MATRIX_EQ( 595 expected, identity_operations[i]->Blend(operations, progress)); 596 } 597 } 598 599 TEST(TransformOperationTest, BlendTranslationToIdentity) { 600 ScopedVector<TransformOperations> identity_operations; 601 GetIdentityOperations(&identity_operations); 602 603 for (size_t i = 0; i < identity_operations.size(); ++i) { 604 TransformOperations operations; 605 operations.AppendTranslate(2, 2, 2); 606 607 SkMScalar progress = 0.5f; 608 609 gfx::Transform expected; 610 expected.Translate3d(1, 1, 1); 611 612 EXPECT_TRANSFORMATION_MATRIX_EQ( 613 expected, identity_operations[i]->Blend(operations, progress)); 614 } 615 } 616 617 TEST(TransformOperationTest, BlendScaleToIdentity) { 618 ScopedVector<TransformOperations> identity_operations; 619 GetIdentityOperations(&identity_operations); 620 621 for (size_t i = 0; i < identity_operations.size(); ++i) { 622 TransformOperations operations; 623 operations.AppendScale(3, 3, 3); 624 625 SkMScalar progress = 0.5f; 626 627 gfx::Transform expected; 628 expected.Scale3d(2, 2, 2); 629 630 EXPECT_TRANSFORMATION_MATRIX_EQ( 631 expected, identity_operations[i]->Blend(operations, progress)); 632 } 633 } 634 635 TEST(TransformOperationTest, BlendSkewToIdentity) { 636 ScopedVector<TransformOperations> identity_operations; 637 GetIdentityOperations(&identity_operations); 638 639 for (size_t i = 0; i < identity_operations.size(); ++i) { 640 TransformOperations operations; 641 operations.AppendSkew(2, 2); 642 643 SkMScalar progress = 0.5f; 644 645 gfx::Transform expected; 646 expected.SkewX(1); 647 expected.SkewY(1); 648 649 EXPECT_TRANSFORMATION_MATRIX_EQ( 650 expected, identity_operations[i]->Blend(operations, progress)); 651 } 652 } 653 654 TEST(TransformOperationTest, BlendPerspectiveToIdentity) { 655 ScopedVector<TransformOperations> identity_operations; 656 GetIdentityOperations(&identity_operations); 657 658 for (size_t i = 0; i < identity_operations.size(); ++i) { 659 TransformOperations operations; 660 operations.AppendPerspective(1000); 661 662 SkMScalar progress = 0.5f; 663 664 gfx::Transform expected; 665 expected.ApplyPerspectiveDepth(2000); 666 667 EXPECT_TRANSFORMATION_MATRIX_EQ( 668 expected, identity_operations[i]->Blend(operations, progress)); 669 } 670 } 671 672 TEST(TransformOperationTest, ExtrapolatePerspectiveBlending) { 673 TransformOperations operations1; 674 operations1.AppendPerspective(1000); 675 676 TransformOperations operations2; 677 operations2.AppendPerspective(500); 678 679 gfx::Transform expected; 680 expected.ApplyPerspectiveDepth(400); 681 682 EXPECT_TRANSFORMATION_MATRIX_EQ( 683 expected, operations1.Blend(operations2, -0.5)); 684 685 expected.MakeIdentity(); 686 expected.ApplyPerspectiveDepth(2000); 687 688 EXPECT_TRANSFORMATION_MATRIX_EQ( 689 expected, operations1.Blend(operations2, 1.5)); 690 } 691 692 TEST(TransformOperationTest, ExtrapolateMatrixBlending) { 693 gfx::Transform transform1; 694 transform1.Translate3d(1, 1, 1); 695 TransformOperations operations1; 696 operations1.AppendMatrix(transform1); 697 698 gfx::Transform transform2; 699 transform2.Translate3d(3, 3, 3); 700 TransformOperations operations2; 701 operations2.AppendMatrix(transform2); 702 703 gfx::Transform expected; 704 EXPECT_TRANSFORMATION_MATRIX_EQ( 705 expected, operations1.Blend(operations2, 1.5)); 706 707 expected.Translate3d(4, 4, 4); 708 EXPECT_TRANSFORMATION_MATRIX_EQ( 709 expected, operations1.Blend(operations2, -0.5)); 710 } 711 712 TEST(TransformOperationTest, BlendedBoundsWhenTypesDoNotMatch) { 713 TransformOperations operations_from; 714 operations_from.AppendScale(2.0, 4.0, 8.0); 715 operations_from.AppendTranslate(1.0, 2.0, 3.0); 716 717 TransformOperations operations_to; 718 operations_to.AppendTranslate(10.0, 20.0, 30.0); 719 operations_to.AppendScale(4.0, 8.0, 16.0); 720 721 gfx::BoxF box(1.f, 1.f, 1.f); 722 gfx::BoxF bounds; 723 724 SkMScalar min_progress = 0.f; 725 SkMScalar max_progress = 1.f; 726 727 EXPECT_FALSE(operations_to.BlendedBoundsForBox( 728 box, operations_from, min_progress, max_progress, &bounds)); 729 } 730 731 TEST(TransformOperationTest, BlendedBoundsForIdentity) { 732 TransformOperations operations_from; 733 operations_from.AppendIdentity(); 734 TransformOperations operations_to; 735 operations_to.AppendIdentity(); 736 737 gfx::BoxF box(1.f, 2.f, 3.f); 738 gfx::BoxF bounds; 739 740 SkMScalar min_progress = 0.f; 741 SkMScalar max_progress = 1.f; 742 743 EXPECT_TRUE(operations_to.BlendedBoundsForBox( 744 box, operations_from, min_progress, max_progress, &bounds)); 745 EXPECT_EQ(box.ToString(), bounds.ToString()); 746 } 747 748 TEST(TransformOperationTest, BlendedBoundsForTranslate) { 749 TransformOperations operations_from; 750 operations_from.AppendTranslate(3.0, -4.0, 2.0); 751 TransformOperations operations_to; 752 operations_to.AppendTranslate(7.0, 4.0, -2.0); 753 754 gfx::BoxF box(1.f, 2.f, 3.f, 4.f, 4.f, 4.f); 755 gfx::BoxF bounds; 756 757 SkMScalar min_progress = -0.5f; 758 SkMScalar max_progress = 1.5f; 759 EXPECT_TRUE(operations_to.BlendedBoundsForBox( 760 box, operations_from, min_progress, max_progress, &bounds)); 761 EXPECT_EQ(gfx::BoxF(2.f, -6.f, -1.f, 12.f, 20.f, 12.f).ToString(), 762 bounds.ToString()); 763 764 min_progress = 0.f; 765 max_progress = 1.f; 766 EXPECT_TRUE(operations_to.BlendedBoundsForBox( 767 box, operations_from, min_progress, max_progress, &bounds)); 768 EXPECT_EQ(gfx::BoxF(4.f, -2.f, 1.f, 8.f, 12.f, 8.f).ToString(), 769 bounds.ToString()); 770 771 TransformOperations identity; 772 EXPECT_TRUE(operations_to.BlendedBoundsForBox( 773 box, identity, min_progress, max_progress, &bounds)); 774 EXPECT_EQ(gfx::BoxF(1.f, 2.f, 1.f, 11.f, 8.f, 6.f).ToString(), 775 bounds.ToString()); 776 777 EXPECT_TRUE(identity.BlendedBoundsForBox( 778 box, operations_from, min_progress, max_progress, &bounds)); 779 EXPECT_EQ(gfx::BoxF(1.f, -2.f, 3.f, 7.f, 8.f, 6.f).ToString(), 780 bounds.ToString()); 781 } 782 783 TEST(TransformOperationTest, BlendedBoundsForScale) { 784 TransformOperations operations_from; 785 operations_from.AppendScale(3.0, 0.5, 2.0); 786 TransformOperations operations_to; 787 operations_to.AppendScale(7.0, 4.0, -2.0); 788 789 gfx::BoxF box(1.f, 2.f, 3.f, 4.f, 4.f, 4.f); 790 gfx::BoxF bounds; 791 792 SkMScalar min_progress = -0.5f; 793 SkMScalar max_progress = 1.5f; 794 EXPECT_TRUE(operations_to.BlendedBoundsForBox( 795 box, operations_from, min_progress, max_progress, &bounds)); 796 EXPECT_EQ(gfx::BoxF(1.f, -7.5f, -28.f, 44.f, 42.f, 56.f).ToString(), 797 bounds.ToString()); 798 799 min_progress = 0.f; 800 max_progress = 1.f; 801 EXPECT_TRUE(operations_to.BlendedBoundsForBox( 802 box, operations_from, min_progress, max_progress, &bounds)); 803 EXPECT_EQ(gfx::BoxF(3.f, 1.f, -14.f, 32.f, 23.f, 28.f).ToString(), 804 bounds.ToString()); 805 806 TransformOperations identity; 807 EXPECT_TRUE(operations_to.BlendedBoundsForBox( 808 box, identity, min_progress, max_progress, &bounds)); 809 EXPECT_EQ(gfx::BoxF(1.f, 2.f, -14.f, 34.f, 22.f, 21.f).ToString(), 810 bounds.ToString()); 811 812 EXPECT_TRUE(identity.BlendedBoundsForBox( 813 box, operations_from, min_progress, max_progress, &bounds)); 814 EXPECT_EQ(gfx::BoxF(1.f, 1.f, 3.f, 14.f, 5.f, 11.f).ToString(), 815 bounds.ToString()); 816 } 817 818 TEST(TransformOperationTest, BlendedBoundsWithZeroScale) { 819 TransformOperations zero_scale; 820 zero_scale.AppendScale(0.0, 0.0, 0.0); 821 TransformOperations non_zero_scale; 822 non_zero_scale.AppendScale(2.0, -4.0, 5.0); 823 824 gfx::BoxF box(1.f, 2.f, 3.f, 4.f, 4.f, 4.f); 825 gfx::BoxF bounds; 826 827 SkMScalar min_progress = 0.f; 828 SkMScalar max_progress = 1.f; 829 EXPECT_TRUE(zero_scale.BlendedBoundsForBox( 830 box, non_zero_scale, min_progress, max_progress, &bounds)); 831 EXPECT_EQ(gfx::BoxF(0.f, -24.f, 0.f, 10.f, 24.f, 35.f).ToString(), 832 bounds.ToString()); 833 834 EXPECT_TRUE(non_zero_scale.BlendedBoundsForBox( 835 box, zero_scale, min_progress, max_progress, &bounds)); 836 EXPECT_EQ(gfx::BoxF(0.f, -24.f, 0.f, 10.f, 24.f, 35.f).ToString(), 837 bounds.ToString()); 838 839 EXPECT_TRUE(zero_scale.BlendedBoundsForBox( 840 box, zero_scale, min_progress, max_progress, &bounds)); 841 EXPECT_EQ(gfx::BoxF().ToString(), bounds.ToString()); 842 } 843 844 TEST(TransformOperationTest, BlendedBoundsForRotationTrivial) { 845 TransformOperations operations_from; 846 operations_from.AppendRotate(0.f, 0.f, 1.f, 0.f); 847 TransformOperations operations_to; 848 operations_to.AppendRotate(0.f, 0.f, 1.f, 360.f); 849 850 float sqrt_2 = sqrt(2.f); 851 gfx::BoxF box( 852 -sqrt_2, -sqrt_2, 0.f, sqrt_2, sqrt_2, 0.f); 853 gfx::BoxF bounds; 854 855 // Since we're rotating 360 degrees, any box with dimensions between 0 and 856 // 2 * sqrt(2) should give the same result. 857 float sizes[] = { 0.f, 0.1f, sqrt_2, 2.f * sqrt_2 }; 858 for (size_t i = 0; i < arraysize(sizes); ++i) { 859 box.set_size(sizes[i], sizes[i], 0.f); 860 SkMScalar min_progress = 0.f; 861 SkMScalar max_progress = 1.f; 862 EXPECT_TRUE(operations_to.BlendedBoundsForBox( 863 box, operations_from, min_progress, max_progress, &bounds)); 864 EXPECT_EQ(gfx::BoxF(-2.f, -2.f, 0.f, 4.f, 4.f, 0.f).ToString(), 865 bounds.ToString()); 866 } 867 } 868 869 TEST(TransformOperationTest, BlendedBoundsForRotationAllExtrema) { 870 // If the normal is out of the plane, we can have up to 6 extrema (a min/max 871 // in each dimension) between the endpoints of the arc. This test ensures that 872 // we consider all 6. 873 TransformOperations operations_from; 874 operations_from.AppendRotate(1.f, 1.f, 1.f, 30.f); 875 TransformOperations operations_to; 876 operations_to.AppendRotate(1.f, 1.f, 1.f, 390.f); 877 878 gfx::BoxF box(1.f, 0.f, 0.f, 0.f, 0.f, 0.f); 879 gfx::BoxF bounds; 880 881 float min = -1.f / 3.f; 882 float max = 1.f; 883 float size = max - min; 884 EXPECT_TRUE(operations_to.BlendedBoundsForBox( 885 box, operations_from, 0.f, 1.f, &bounds)); 886 EXPECT_EQ(gfx::BoxF(min, min, min, size, size, size).ToString(), 887 bounds.ToString()); 888 } 889 890 TEST(TransformOperationTest, BlendedBoundsForRotationDifferentAxes) { 891 // We can handle rotations about a single axis. If the axes are different, 892 // we revert to matrix interpolation for which inflated bounds cannot be 893 // computed. 894 TransformOperations operations_from; 895 operations_from.AppendRotate(1.f, 1.f, 1.f, 30.f); 896 TransformOperations operations_to_same; 897 operations_to_same.AppendRotate(1.f, 1.f, 1.f, 390.f); 898 TransformOperations operations_to_opposite; 899 operations_to_opposite.AppendRotate(-1.f, -1.f, -1.f, 390.f); 900 TransformOperations operations_to_different; 901 operations_to_different.AppendRotate(1.f, 3.f, 1.f, 390.f); 902 903 gfx::BoxF box(1.f, 0.f, 0.f, 0.f, 0.f, 0.f); 904 gfx::BoxF bounds; 905 906 EXPECT_TRUE(operations_to_same.BlendedBoundsForBox( 907 box, operations_from, 0.f, 1.f, &bounds)); 908 EXPECT_TRUE(operations_to_opposite.BlendedBoundsForBox( 909 box, operations_from, 0.f, 1.f, &bounds)); 910 EXPECT_FALSE(operations_to_different.BlendedBoundsForBox( 911 box, operations_from, 0.f, 1.f, &bounds)); 912 } 913 914 TEST(TransformOperationTest, BlendedBoundsForRotationPointOnAxis) { 915 // Checks that if the point to rotate is sitting on the axis of rotation, that 916 // it does not get affected. 917 TransformOperations operations_from; 918 operations_from.AppendRotate(1.f, 1.f, 1.f, 30.f); 919 TransformOperations operations_to; 920 operations_to.AppendRotate(1.f, 1.f, 1.f, 390.f); 921 922 gfx::BoxF box(1.f, 1.f, 1.f, 0.f, 0.f, 0.f); 923 gfx::BoxF bounds; 924 925 EXPECT_TRUE(operations_to.BlendedBoundsForBox( 926 box, operations_from, 0.f, 1.f, &bounds)); 927 EXPECT_EQ(box.ToString(), bounds.ToString()); 928 } 929 930 // This would have been best as anonymous structs, but |arraysize| does not get 931 // along with anonymous structs (and using ARRAYSIZE_UNSAFE seemed like a worse 932 // option). 933 struct ProblematicAxisTest { 934 float x; 935 float y; 936 float z; 937 gfx::BoxF expected; 938 }; 939 940 TEST(TransformOperationTest, BlendedBoundsForRotationProblematicAxes) { 941 // Zeros in the components of the axis of rotation turned out to be tricky to 942 // deal with in practice. This function tests some potentially problematic 943 // axes to ensure sane behavior. 944 945 // Some common values used in the expected boxes. 946 float dim1 = 0.292893f; 947 float dim2 = sqrt(2.f); 948 float dim3 = 2.f * dim2; 949 950 ProblematicAxisTest tests[] = { 951 { 0.f, 0.f, 0.f, gfx::BoxF(1.f, 1.f, 1.f, 0.f, 0.f, 0.f) }, 952 { 1.f, 0.f, 0.f, gfx::BoxF(1.f, -dim2, -dim2, 0.f, dim3, dim3) }, 953 { 0.f, 1.f, 0.f, gfx::BoxF(-dim2, 1.f, -dim2, dim3, 0.f, dim3) }, 954 { 0.f, 0.f, 1.f, gfx::BoxF(-dim2, -dim2, 1.f, dim3, dim3, 0.f) }, 955 { 1.f, 1.f, 0.f, gfx::BoxF(dim1, dim1, -1.f, dim2, dim2, 2.f) }, 956 { 0.f, 1.f, 1.f, gfx::BoxF(-1.f, dim1, dim1, 2.f, dim2, dim2) }, 957 { 1.f, 0.f, 1.f, gfx::BoxF(dim1, -1.f, dim1, dim2, 2.f, dim2) } 958 }; 959 960 for (size_t i = 0; i < arraysize(tests); ++i) { 961 float x = tests[i].x; 962 float y = tests[i].y; 963 float z = tests[i].z; 964 TransformOperations operations_from; 965 operations_from.AppendRotate(x, y, z, 0.f); 966 TransformOperations operations_to; 967 operations_to.AppendRotate(x, y, z, 360.f); 968 gfx::BoxF box(1.f, 1.f, 1.f, 0.f, 0.f, 0.f); 969 gfx::BoxF bounds; 970 971 EXPECT_TRUE(operations_to.BlendedBoundsForBox( 972 box, operations_from, 0.f, 1.f, &bounds)); 973 EXPECT_EQ(tests[i].expected.ToString(), bounds.ToString()); 974 } 975 } 976 977 // These would have been best as anonymous structs, but |arraysize| does not get 978 // along with anonymous structs (and using ARRAYSIZE_UNSAFE seemed like a worse 979 // option). 980 struct TestAxis { 981 float x; 982 float y; 983 float z; 984 }; 985 986 struct TestAngles { 987 float theta_from; 988 float theta_to; 989 }; 990 991 struct TestProgress { 992 float min_progress; 993 float max_progress; 994 }; 995 996 static void ExpectBoxesApproximatelyEqual(const gfx::BoxF& lhs, 997 const gfx::BoxF& rhs, 998 float tolerance) { 999 EXPECT_NEAR(lhs.x(), rhs.x(), tolerance); 1000 EXPECT_NEAR(lhs.y(), rhs.y(), tolerance); 1001 EXPECT_NEAR(lhs.z(), rhs.z(), tolerance); 1002 EXPECT_NEAR(lhs.width(), rhs.width(), tolerance); 1003 EXPECT_NEAR(lhs.height(), rhs.height(), tolerance); 1004 EXPECT_NEAR(lhs.depth(), rhs.depth(), tolerance); 1005 } 1006 1007 static void EmpiricallyTestBounds(const TransformOperations& from, 1008 const TransformOperations& to, 1009 SkMScalar min_progress, 1010 SkMScalar max_progress, 1011 bool test_containment_only) { 1012 gfx::BoxF box(200.f, 500.f, 100.f, 100.f, 300.f, 200.f); 1013 gfx::BoxF bounds; 1014 EXPECT_TRUE( 1015 to.BlendedBoundsForBox(box, from, min_progress, max_progress, &bounds)); 1016 1017 bool first_time = true; 1018 gfx::BoxF empirical_bounds; 1019 static const size_t kNumSteps = 10; 1020 for (size_t step = 0; step < kNumSteps; ++step) { 1021 float t = step / (kNumSteps - 1.f); 1022 t = gfx::Tween::FloatValueBetween(t, min_progress, max_progress); 1023 gfx::Transform partial_transform = to.Blend(from, t); 1024 gfx::BoxF transformed = box; 1025 partial_transform.TransformBox(&transformed); 1026 1027 if (first_time) { 1028 empirical_bounds = transformed; 1029 first_time = false; 1030 } else { 1031 empirical_bounds.Union(transformed); 1032 } 1033 } 1034 1035 if (test_containment_only) { 1036 gfx::BoxF unified_bounds = bounds; 1037 unified_bounds.Union(empirical_bounds); 1038 // Convert to the screen space rects these boxes represent. 1039 gfx::Rect bounds_rect = ToEnclosingRect( 1040 gfx::RectF(bounds.x(), bounds.y(), bounds.width(), bounds.height())); 1041 gfx::Rect unified_bounds_rect = 1042 ToEnclosingRect(gfx::RectF(unified_bounds.x(), 1043 unified_bounds.y(), 1044 unified_bounds.width(), 1045 unified_bounds.height())); 1046 EXPECT_EQ(bounds_rect.ToString(), unified_bounds_rect.ToString()); 1047 } else { 1048 // Our empirical estimate will be a little rough since we're only doing 1049 // 100 samples. 1050 static const float kTolerance = 1e-2f; 1051 ExpectBoxesApproximatelyEqual(empirical_bounds, bounds, kTolerance); 1052 } 1053 } 1054 1055 static void EmpiricallyTestBoundsEquality(const TransformOperations& from, 1056 const TransformOperations& to, 1057 SkMScalar min_progress, 1058 SkMScalar max_progress) { 1059 EmpiricallyTestBounds(from, to, min_progress, max_progress, false); 1060 } 1061 1062 static void EmpiricallyTestBoundsContainment(const TransformOperations& from, 1063 const TransformOperations& to, 1064 SkMScalar min_progress, 1065 SkMScalar max_progress) { 1066 EmpiricallyTestBounds(from, to, min_progress, max_progress, true); 1067 } 1068 1069 TEST(TransformOperationTest, BlendedBoundsForRotationEmpiricalTests) { 1070 // Sets up various axis angle combinations, computes the bounding box and 1071 // empirically tests that the transformed bounds are indeed contained by the 1072 // computed bounding box. 1073 1074 TestAxis axes[] = { 1075 { 1.f, 1.f, 1.f }, 1076 { -1.f, -1.f, -1.f }, 1077 { -1.f, 2.f, 3.f }, 1078 { 1.f, -2.f, 3.f }, 1079 { 1.f, 2.f, -3.f }, 1080 { 0.f, 0.f, 0.f }, 1081 { 1.f, 0.f, 0.f }, 1082 { 0.f, 1.f, 0.f }, 1083 { 0.f, 0.f, 1.f }, 1084 { 1.f, 1.f, 0.f }, 1085 { 0.f, 1.f, 1.f }, 1086 { 1.f, 0.f, 1.f }, 1087 { -1.f, 0.f, 0.f }, 1088 { 0.f, -1.f, 0.f }, 1089 { 0.f, 0.f, -1.f }, 1090 { -1.f, -1.f, 0.f }, 1091 { 0.f, -1.f, -1.f }, 1092 { -1.f, 0.f, -1.f } 1093 }; 1094 1095 TestAngles angles[] = { 1096 { 5.f, 10.f }, 1097 { 10.f, 5.f }, 1098 { 0.f, 360.f }, 1099 { 20.f, 180.f }, 1100 { -20.f, -180.f }, 1101 { 180.f, -220.f }, 1102 { 220.f, 320.f } 1103 }; 1104 1105 // We can go beyond the range [0, 1] (the bezier might slide out of this range 1106 // at either end), but since the first and last knots are at (0, 0) and (1, 1) 1107 // we will never go within it, so these tests are sufficient. 1108 TestProgress progress[] = { 1109 { 0.f, 1.f }, 1110 { -.25f, 1.25f }, 1111 }; 1112 1113 for (size_t i = 0; i < arraysize(axes); ++i) { 1114 for (size_t j = 0; j < arraysize(angles); ++j) { 1115 for (size_t k = 0; k < arraysize(progress); ++k) { 1116 float x = axes[i].x; 1117 float y = axes[i].y; 1118 float z = axes[i].z; 1119 TransformOperations operations_from; 1120 operations_from.AppendRotate(x, y, z, angles[j].theta_from); 1121 TransformOperations operations_to; 1122 operations_to.AppendRotate(x, y, z, angles[j].theta_to); 1123 EmpiricallyTestBoundsContainment(operations_from, 1124 operations_to, 1125 progress[k].min_progress, 1126 progress[k].max_progress); 1127 } 1128 } 1129 } 1130 } 1131 1132 TEST(TransformOperationTest, PerspectiveMatrixAndTransformBlendingEquivalency) { 1133 TransformOperations from_operations; 1134 from_operations.AppendPerspective(200); 1135 1136 TransformOperations to_operations; 1137 to_operations.AppendPerspective(1000); 1138 1139 gfx::Transform from_transform; 1140 from_transform.ApplyPerspectiveDepth(200); 1141 1142 gfx::Transform to_transform; 1143 to_transform.ApplyPerspectiveDepth(1000); 1144 1145 static const int steps = 20; 1146 for (int i = 0; i < steps; ++i) { 1147 double progress = static_cast<double>(i) / (steps - 1); 1148 1149 gfx::Transform blended_matrix = to_transform; 1150 EXPECT_TRUE(blended_matrix.Blend(from_transform, progress)); 1151 1152 gfx::Transform blended_transform = 1153 to_operations.Blend(from_operations, progress); 1154 1155 EXPECT_TRANSFORMATION_MATRIX_EQ(blended_matrix, blended_transform); 1156 } 1157 } 1158 1159 struct TestPerspectiveDepths { 1160 float from_depth; 1161 float to_depth; 1162 }; 1163 1164 TEST(TransformOperationTest, BlendedBoundsForPerspective) { 1165 TestPerspectiveDepths perspective_depths[] = { 1166 { 600.f, 400.f }, 1167 { 800.f, 1000.f }, 1168 { 800.f, std::numeric_limits<float>::infinity() }, 1169 }; 1170 1171 TestProgress progress[] = { 1172 { 0.f, 1.f }, 1173 { -0.1f, 1.1f }, 1174 }; 1175 1176 for (size_t i = 0; i < arraysize(perspective_depths); ++i) { 1177 for (size_t j = 0; j < arraysize(progress); ++j) { 1178 TransformOperations operations_from; 1179 operations_from.AppendPerspective(perspective_depths[i].from_depth); 1180 TransformOperations operations_to; 1181 operations_to.AppendPerspective(perspective_depths[i].to_depth); 1182 EmpiricallyTestBoundsEquality(operations_from, 1183 operations_to, 1184 progress[j].min_progress, 1185 progress[j].max_progress); 1186 } 1187 } 1188 } 1189 1190 struct TestSkews { 1191 float from_x; 1192 float from_y; 1193 float to_x; 1194 float to_y; 1195 }; 1196 1197 TEST(TransformOperationTest, BlendedBoundsForSkew) { 1198 TestSkews skews[] = { 1199 { 1.f, 0.5f, 0.5f, 1.f }, 1200 { 2.f, 1.f, 0.5f, 0.5f }, 1201 }; 1202 1203 TestProgress progress[] = { 1204 { 0.f, 1.f }, 1205 { -0.1f, 1.1f }, 1206 }; 1207 1208 for (size_t i = 0; i < arraysize(skews); ++i) { 1209 for (size_t j = 0; j < arraysize(progress); ++j) { 1210 TransformOperations operations_from; 1211 operations_from.AppendSkew(skews[i].from_x, skews[i].from_y); 1212 TransformOperations operations_to; 1213 operations_to.AppendSkew(skews[i].to_x, skews[i].to_y); 1214 EmpiricallyTestBoundsEquality(operations_from, 1215 operations_to, 1216 progress[j].min_progress, 1217 progress[j].max_progress); 1218 } 1219 } 1220 } 1221 1222 TEST(TransformOperationTest, BlendedBoundsForSequence) { 1223 TransformOperations operations_from; 1224 operations_from.AppendTranslate(2.0, 4.0, -1.0); 1225 operations_from.AppendScale(-1.0, 2.0, 3.0); 1226 operations_from.AppendTranslate(1.0, -5.0, 1.0); 1227 TransformOperations operations_to; 1228 operations_to.AppendTranslate(6.0, -2.0, 3.0); 1229 operations_to.AppendScale(-3.0, -2.0, 5.0); 1230 operations_to.AppendTranslate(13.0, -1.0, 5.0); 1231 1232 gfx::BoxF box(1.f, 2.f, 3.f, 4.f, 4.f, 4.f); 1233 gfx::BoxF bounds; 1234 1235 SkMScalar min_progress = -0.5f; 1236 SkMScalar max_progress = 1.5f; 1237 EXPECT_TRUE(operations_to.BlendedBoundsForBox( 1238 box, operations_from, min_progress, max_progress, &bounds)); 1239 EXPECT_EQ(gfx::BoxF(-57.f, -59.f, -1.f, 76.f, 112.f, 80.f).ToString(), 1240 bounds.ToString()); 1241 1242 min_progress = 0.f; 1243 max_progress = 1.f; 1244 EXPECT_TRUE(operations_to.BlendedBoundsForBox( 1245 box, operations_from, min_progress, max_progress, &bounds)); 1246 EXPECT_EQ(gfx::BoxF(-32.f, -25.f, 7.f, 42.f, 44.f, 48.f).ToString(), 1247 bounds.ToString()); 1248 1249 TransformOperations identity; 1250 EXPECT_TRUE(operations_to.BlendedBoundsForBox( 1251 box, identity, min_progress, max_progress, &bounds)); 1252 EXPECT_EQ(gfx::BoxF(-33.f, -13.f, 3.f, 57.f, 19.f, 52.f).ToString(), 1253 bounds.ToString()); 1254 1255 EXPECT_TRUE(identity.BlendedBoundsForBox( 1256 box, operations_from, min_progress, max_progress, &bounds)); 1257 EXPECT_EQ(gfx::BoxF(-7.f, -3.f, 2.f, 15.f, 23.f, 20.f).ToString(), 1258 bounds.ToString()); 1259 } 1260 1261 } // namespace 1262 } // namespace cc 1263