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 #include <limits> | 5 #include <limits> |
6 | 6 |
7 #include "base/basictypes.h" | 7 #include "base/basictypes.h" |
8 #include "base/memory/scoped_vector.h" | 8 #include "base/memory/scoped_vector.h" |
9 #include "cc/animation/transform_operations.h" | 9 #include "cc/animation/transform_operations.h" |
10 #include "cc/test/geometry_test_utils.h" | 10 #include "cc/test/geometry_test_utils.h" |
11 #include "testing/gtest/include/gtest/gtest.h" | 11 #include "testing/gtest/include/gtest/gtest.h" |
12 #include "ui/gfx/animation/tween.h" | 12 #include "ui/gfx/animation/tween.h" |
13 #include "ui/gfx/box_f.h" | 13 #include "ui/gfx/box_f.h" |
| 14 #include "ui/gfx/rect_conversions.h" |
14 #include "ui/gfx/vector3d_f.h" | 15 #include "ui/gfx/vector3d_f.h" |
15 | 16 |
16 namespace cc { | 17 namespace cc { |
17 namespace { | 18 namespace { |
18 | 19 |
19 TEST(TransformOperationTest, TransformTypesAreUnique) { | 20 TEST(TransformOperationTest, TransformTypesAreUnique) { |
20 ScopedVector<TransformOperations> transforms; | 21 ScopedVector<TransformOperations> transforms; |
21 | 22 |
22 TransformOperations* to_add = new TransformOperations(); | 23 TransformOperations* to_add = new TransformOperations(); |
23 to_add->AppendTranslate(1, 0, 0); | 24 to_add->AppendTranslate(1, 0, 0); |
(...skipping 855 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
879 | 880 |
880 float min = -1.f / 3.f; | 881 float min = -1.f / 3.f; |
881 float max = 1.f; | 882 float max = 1.f; |
882 float size = max - min; | 883 float size = max - min; |
883 EXPECT_TRUE(operations_to.BlendedBoundsForBox( | 884 EXPECT_TRUE(operations_to.BlendedBoundsForBox( |
884 box, operations_from, 0.f, 1.f, &bounds)); | 885 box, operations_from, 0.f, 1.f, &bounds)); |
885 EXPECT_EQ(gfx::BoxF(min, min, min, size, size, size).ToString(), | 886 EXPECT_EQ(gfx::BoxF(min, min, min, size, size, size).ToString(), |
886 bounds.ToString()); | 887 bounds.ToString()); |
887 } | 888 } |
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 |
889 TEST(TransformOperationTest, BlendedBoundsForRotationPointOnAxis) { | 914 TEST(TransformOperationTest, BlendedBoundsForRotationPointOnAxis) { |
890 // Checks that if the point to rotate is sitting on the axis of rotation, that | 915 // Checks that if the point to rotate is sitting on the axis of rotation, that |
891 // it does not get affected. | 916 // it does not get affected. |
892 TransformOperations operations_from; | 917 TransformOperations operations_from; |
893 operations_from.AppendRotate(1.f, 1.f, 1.f, 30.f); | 918 operations_from.AppendRotate(1.f, 1.f, 1.f, 30.f); |
894 TransformOperations operations_to; | 919 TransformOperations operations_to; |
895 operations_to.AppendRotate(1.f, 1.f, 1.f, 390.f); | 920 operations_to.AppendRotate(1.f, 1.f, 1.f, 390.f); |
896 | 921 |
897 gfx::BoxF box(1.f, 1.f, 1.f, 0.f, 0.f, 0.f); | 922 gfx::BoxF box(1.f, 1.f, 1.f, 0.f, 0.f, 0.f); |
898 gfx::BoxF bounds; | 923 gfx::BoxF bounds; |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
961 struct TestAngles { | 986 struct TestAngles { |
962 float theta_from; | 987 float theta_from; |
963 float theta_to; | 988 float theta_to; |
964 }; | 989 }; |
965 | 990 |
966 struct TestProgress { | 991 struct TestProgress { |
967 float min_progress; | 992 float min_progress; |
968 float max_progress; | 993 float max_progress; |
969 }; | 994 }; |
970 | 995 |
971 TEST(TransformOperationsTest, BlendedBoundsForRotationEmpiricalTests) { | 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) { |
972 // Sets up various axis angle combinations, computes the bounding box and | 1070 // Sets up various axis angle combinations, computes the bounding box and |
973 // empirically tests that the transformed bounds are indeed contained by the | 1071 // empirically tests that the transformed bounds are indeed contained by the |
974 // computed bounding box. | 1072 // computed bounding box. |
975 | 1073 |
976 TestAxis axes[] = { | 1074 TestAxis axes[] = { |
977 { 1.f, 1.f, 1.f }, | 1075 { 1.f, 1.f, 1.f }, |
978 { -1.f, -1.f, -1.f }, | 1076 { -1.f, -1.f, -1.f }, |
979 { -1.f, 2.f, 3.f }, | 1077 { -1.f, 2.f, 3.f }, |
980 { 1.f, -2.f, 3.f }, | 1078 { 1.f, -2.f, 3.f }, |
981 { 1.f, 2.f, -3.f }, | 1079 { 1.f, 2.f, -3.f }, |
(...skipping 23 matching lines...) Expand all Loading... |
1005 }; | 1103 }; |
1006 | 1104 |
1007 // We can go beyond the range [0, 1] (the bezier might slide out of this range | 1105 // We can go beyond the range [0, 1] (the bezier might slide out of this range |
1008 // at either end), but since the first and last knots are at (0, 0) and (1, 1) | 1106 // at either end), but since the first and last knots are at (0, 0) and (1, 1) |
1009 // we will never go within it, so these tests are sufficient. | 1107 // we will never go within it, so these tests are sufficient. |
1010 TestProgress progress[] = { | 1108 TestProgress progress[] = { |
1011 { 0.f, 1.f }, | 1109 { 0.f, 1.f }, |
1012 { -.25f, 1.25f }, | 1110 { -.25f, 1.25f }, |
1013 }; | 1111 }; |
1014 | 1112 |
1015 size_t num_steps = 150; | |
1016 for (size_t i = 0; i < arraysize(axes); ++i) { | 1113 for (size_t i = 0; i < arraysize(axes); ++i) { |
1017 for (size_t j = 0; j < arraysize(angles); ++j) { | 1114 for (size_t j = 0; j < arraysize(angles); ++j) { |
1018 for (size_t k = 0; k < arraysize(progress); ++k) { | 1115 for (size_t k = 0; k < arraysize(progress); ++k) { |
1019 float x = axes[i].x; | 1116 float x = axes[i].x; |
1020 float y = axes[i].y; | 1117 float y = axes[i].y; |
1021 float z = axes[i].z; | 1118 float z = axes[i].z; |
1022 TransformOperations operations_from; | 1119 TransformOperations operations_from; |
1023 operations_from.AppendRotate(x, y, z, angles[j].theta_from); | 1120 operations_from.AppendRotate(x, y, z, angles[j].theta_from); |
1024 TransformOperations operations_to; | 1121 TransformOperations operations_to; |
1025 operations_to.AppendRotate(x, y, z, angles[j].theta_to); | 1122 operations_to.AppendRotate(x, y, z, angles[j].theta_to); |
1026 | 1123 EmpiricallyTestBoundsContainment(operations_from, |
1027 gfx::BoxF box(2.f, 5.f, 6.f, 1.f, 3.f, 2.f); | 1124 operations_to, |
1028 gfx::BoxF bounds; | 1125 progress[k].min_progress, |
1029 | 1126 progress[k].max_progress); |
1030 EXPECT_TRUE(operations_to.BlendedBoundsForBox(box, | |
1031 operations_from, | |
1032 progress[k].min_progress, | |
1033 progress[k].max_progress, | |
1034 &bounds)); | |
1035 bool first_point = true; | |
1036 gfx::BoxF empirical_bounds; | |
1037 for (size_t step = 0; step < num_steps; ++step) { | |
1038 float t = step / (num_steps - 1.f); | |
1039 t = gfx::Tween::FloatValueBetween( | |
1040 t, progress[k].min_progress, progress[k].max_progress); | |
1041 gfx::Transform partial_rotation = | |
1042 operations_to.Blend(operations_from, t); | |
1043 | |
1044 for (int corner = 0; corner < 8; ++corner) { | |
1045 gfx::Point3F point = box.origin(); | |
1046 point += gfx::Vector3dF(corner & 1 ? box.width() : 0.f, | |
1047 corner & 2 ? box.height() : 0.f, | |
1048 corner & 4 ? box.depth() : 0.f); | |
1049 partial_rotation.TransformPoint(&point); | |
1050 if (first_point) { | |
1051 empirical_bounds.set_origin(point); | |
1052 first_point = false; | |
1053 } else { | |
1054 empirical_bounds.ExpandTo(point); | |
1055 } | |
1056 } | |
1057 } | |
1058 | |
1059 // Our empirical estimate will be a little rough since we're only doing | |
1060 // 100 samples. | |
1061 static const float kTolerance = 1e-2f; | |
1062 EXPECT_NEAR(empirical_bounds.x(), bounds.x(), kTolerance); | |
1063 EXPECT_NEAR(empirical_bounds.y(), bounds.y(), kTolerance); | |
1064 EXPECT_NEAR(empirical_bounds.z(), bounds.z(), kTolerance); | |
1065 EXPECT_NEAR(empirical_bounds.width(), bounds.width(), kTolerance); | |
1066 EXPECT_NEAR(empirical_bounds.height(), bounds.height(), kTolerance); | |
1067 EXPECT_NEAR(empirical_bounds.depth(), bounds.depth(), kTolerance); | |
1068 } | 1127 } |
1069 } | 1128 } |
1070 } | 1129 } |
1071 } | 1130 } |
1072 | 1131 |
1073 TEST(TransformOperationTest, PerspectiveMatrixAndTransformBlendingEquivalency) { | 1132 TEST(TransformOperationTest, PerspectiveMatrixAndTransformBlendingEquivalency) { |
1074 TransformOperations from_operations; | 1133 TransformOperations from_operations; |
1075 from_operations.AppendPerspective(200); | 1134 from_operations.AppendPerspective(200); |
1076 | 1135 |
1077 TransformOperations to_operations; | 1136 TransformOperations to_operations; |
(...skipping 12 matching lines...) Expand all Loading... |
1090 gfx::Transform blended_matrix = to_transform; | 1149 gfx::Transform blended_matrix = to_transform; |
1091 EXPECT_TRUE(blended_matrix.Blend(from_transform, progress)); | 1150 EXPECT_TRUE(blended_matrix.Blend(from_transform, progress)); |
1092 | 1151 |
1093 gfx::Transform blended_transform = | 1152 gfx::Transform blended_transform = |
1094 to_operations.Blend(from_operations, progress); | 1153 to_operations.Blend(from_operations, progress); |
1095 | 1154 |
1096 EXPECT_TRANSFORMATION_MATRIX_EQ(blended_matrix, blended_transform); | 1155 EXPECT_TRANSFORMATION_MATRIX_EQ(blended_matrix, blended_transform); |
1097 } | 1156 } |
1098 } | 1157 } |
1099 | 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 |
1100 TEST(TransformOperationTest, BlendedBoundsForSequence) { | 1222 TEST(TransformOperationTest, BlendedBoundsForSequence) { |
1101 TransformOperations operations_from; | 1223 TransformOperations operations_from; |
1102 operations_from.AppendTranslate(2.0, 4.0, -1.0); | 1224 operations_from.AppendTranslate(2.0, 4.0, -1.0); |
1103 operations_from.AppendScale(-1.0, 2.0, 3.0); | 1225 operations_from.AppendScale(-1.0, 2.0, 3.0); |
1104 operations_from.AppendTranslate(1.0, -5.0, 1.0); | 1226 operations_from.AppendTranslate(1.0, -5.0, 1.0); |
1105 TransformOperations operations_to; | 1227 TransformOperations operations_to; |
1106 operations_to.AppendTranslate(6.0, -2.0, 3.0); | 1228 operations_to.AppendTranslate(6.0, -2.0, 3.0); |
1107 operations_to.AppendScale(-3.0, -2.0, 5.0); | 1229 operations_to.AppendScale(-3.0, -2.0, 5.0); |
1108 operations_to.AppendTranslate(13.0, -1.0, 5.0); | 1230 operations_to.AppendTranslate(13.0, -1.0, 5.0); |
1109 | 1231 |
(...skipping 21 matching lines...) Expand all Loading... |
1131 bounds.ToString()); | 1253 bounds.ToString()); |
1132 | 1254 |
1133 EXPECT_TRUE(identity.BlendedBoundsForBox( | 1255 EXPECT_TRUE(identity.BlendedBoundsForBox( |
1134 box, operations_from, min_progress, max_progress, &bounds)); | 1256 box, operations_from, min_progress, max_progress, &bounds)); |
1135 EXPECT_EQ(gfx::BoxF(-7.f, -3.f, 2.f, 15.f, 23.f, 20.f).ToString(), | 1257 EXPECT_EQ(gfx::BoxF(-7.f, -3.f, 2.f, 15.f, 23.f, 20.f).ToString(), |
1136 bounds.ToString()); | 1258 bounds.ToString()); |
1137 } | 1259 } |
1138 | 1260 |
1139 } // namespace | 1261 } // namespace |
1140 } // namespace cc | 1262 } // namespace cc |
OLD | NEW |