1 // Copyright (c) 2012 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 "ui/gfx/interpolated_transform.h" 6 7 #include "base/basictypes.h" 8 #include "testing/gtest/include/gtest/gtest.h" 9 #include "ui/gfx/rect.h" 10 11 namespace { 12 13 void CheckApproximatelyEqual(const gfx::Transform& lhs, 14 const gfx::Transform& rhs) { 15 for (int i = 0; i < 4; ++i) { 16 for (int j = 0; j < 4; ++j) { 17 EXPECT_FLOAT_EQ(lhs.matrix().get(i, j), rhs.matrix().get(i, j)); 18 } 19 } 20 } 21 22 } // namespace 23 24 TEST(InterpolatedTransformTest, InterpolatedRotation) { 25 ui::InterpolatedRotation interpolated_rotation(0, 100); 26 ui::InterpolatedRotation interpolated_rotation_diff_start_end( 27 0, 100, 100, 200); 28 29 for (int i = 0; i <= 100; ++i) { 30 gfx::Transform rotation; 31 rotation.Rotate(i); 32 gfx::Transform interpolated = interpolated_rotation.Interpolate(i / 100.0f); 33 CheckApproximatelyEqual(rotation, interpolated); 34 interpolated = interpolated_rotation_diff_start_end.Interpolate(i + 100); 35 CheckApproximatelyEqual(rotation, interpolated); 36 } 37 } 38 39 TEST(InterpolatedTransformTest, InterpolatedScale) { 40 ui::InterpolatedScale interpolated_scale(gfx::Point3F(0, 0, 0), 41 gfx::Point3F(100, 100, 100)); 42 ui::InterpolatedScale interpolated_scale_diff_start_end( 43 gfx::Point3F(0, 0, 0), gfx::Point3F(100, 100, 100), 100, 200); 44 45 for (int i = 0; i <= 100; ++i) { 46 gfx::Transform scale; 47 scale.Scale(i, i); 48 gfx::Transform interpolated = interpolated_scale.Interpolate(i / 100.0f); 49 CheckApproximatelyEqual(scale, interpolated); 50 interpolated = interpolated_scale_diff_start_end.Interpolate(i + 100); 51 CheckApproximatelyEqual(scale, interpolated); 52 } 53 } 54 55 TEST(InterpolatedTransformTest, InterpolatedTranslate) { 56 ui::InterpolatedTranslation interpolated_xform(gfx::Point(0, 0), 57 gfx::Point(100, 100)); 58 59 ui::InterpolatedTranslation interpolated_xform_diff_start_end( 60 gfx::Point(0, 0), gfx::Point(100, 100), 100, 200); 61 62 for (int i = 0; i <= 100; ++i) { 63 gfx::Transform xform; 64 xform.Translate(i, i); 65 gfx::Transform interpolated = interpolated_xform.Interpolate(i / 100.0f); 66 CheckApproximatelyEqual(xform, interpolated); 67 interpolated = interpolated_xform_diff_start_end.Interpolate(i + 100); 68 CheckApproximatelyEqual(xform, interpolated); 69 } 70 } 71 72 TEST(InterpolatedTransformTest, InterpolatedRotationAboutPivot) { 73 gfx::Point pivot(100, 100); 74 gfx::Point above_pivot(100, 200); 75 ui::InterpolatedRotation rot(0, 90); 76 ui::InterpolatedTransformAboutPivot interpolated_xform( 77 pivot, 78 new ui::InterpolatedRotation(0, 90)); 79 gfx::Transform result = interpolated_xform.Interpolate(0.0f); 80 CheckApproximatelyEqual(gfx::Transform(), result); 81 result = interpolated_xform.Interpolate(1.0f); 82 gfx::Point expected_result = pivot; 83 result.TransformPoint(&pivot); 84 EXPECT_EQ(expected_result, pivot); 85 expected_result = gfx::Point(0, 100); 86 result.TransformPoint(&above_pivot); 87 EXPECT_EQ(expected_result, above_pivot); 88 } 89 90 TEST(InterpolatedTransformTest, InterpolatedScaleAboutPivot) { 91 gfx::Point pivot(100, 100); 92 gfx::Point above_pivot(100, 200); 93 ui::InterpolatedTransformAboutPivot interpolated_xform( 94 pivot, 95 new ui::InterpolatedScale(gfx::Point3F(1, 1, 1), gfx::Point3F(2, 2, 2))); 96 gfx::Transform result = interpolated_xform.Interpolate(0.0f); 97 CheckApproximatelyEqual(gfx::Transform(), result); 98 result = interpolated_xform.Interpolate(1.0f); 99 gfx::Point expected_result = pivot; 100 result.TransformPoint(&pivot); 101 EXPECT_EQ(expected_result, pivot); 102 expected_result = gfx::Point(100, 300); 103 result.TransformPoint(&above_pivot); 104 EXPECT_EQ(expected_result, above_pivot); 105 } 106 107 ui::InterpolatedTransform* GetScreenRotation(int degrees, bool reversed) { 108 gfx::Point old_pivot; 109 gfx::Point new_pivot; 110 111 int width = 1920; 112 int height = 180; 113 114 switch (degrees) { 115 case 90: 116 new_pivot = gfx::Point(width, 0); 117 break; 118 case -90: 119 new_pivot = gfx::Point(0, height); 120 break; 121 case 180: 122 case 360: 123 new_pivot = old_pivot = gfx::Point(width / 2, height / 2); 124 break; 125 } 126 127 scoped_ptr<ui::InterpolatedTransform> rotation( 128 new ui::InterpolatedTransformAboutPivot( 129 old_pivot, 130 new ui::InterpolatedRotation(reversed ? degrees : 0, 131 reversed ? 0 : degrees))); 132 133 scoped_ptr<ui::InterpolatedTransform> translation( 134 new ui::InterpolatedTranslation( 135 gfx::Point(0, 0), 136 gfx::Point(new_pivot.x() - old_pivot.x(), 137 new_pivot.y() - old_pivot.y()))); 138 139 float scale_factor = 0.9f; 140 scoped_ptr<ui::InterpolatedTransform> scale_down( 141 new ui::InterpolatedScale(1.0f, scale_factor, 0.0f, 0.5f)); 142 143 scoped_ptr<ui::InterpolatedTransform> scale_up( 144 new ui::InterpolatedScale(1.0f, 1.0f / scale_factor, 0.5f, 1.0f)); 145 146 scoped_ptr<ui::InterpolatedTransform> to_return( 147 new ui::InterpolatedConstantTransform(gfx::Transform())); 148 149 scale_up->SetChild(scale_down.release()); 150 translation->SetChild(scale_up.release()); 151 rotation->SetChild(translation.release()); 152 to_return->SetChild(rotation.release()); 153 to_return->SetReversed(reversed); 154 155 return to_return.release(); 156 } 157 158 TEST(InterpolatedTransformTest, ScreenRotationEndsCleanly) { 159 for (int i = 0; i < 2; ++i) { 160 for (int degrees = -360; degrees <= 360; degrees += 90) { 161 const bool reversed = i == 1; 162 scoped_ptr<ui::InterpolatedTransform> screen_rotation( 163 GetScreenRotation(degrees, reversed)); 164 gfx::Transform interpolated = screen_rotation->Interpolate(1.0f); 165 SkMatrix44& m = interpolated.matrix(); 166 // Upper-left 3x3 matrix should all be 0, 1 or -1. 167 for (int row = 0; row < 3; ++row) { 168 for (int col = 0; col < 3; ++col) { 169 float entry = m.get(row, col); 170 EXPECT_TRUE(entry == 0 || entry == 1 || entry == -1); 171 } 172 } 173 } 174 } 175 } 176 177 ui::InterpolatedTransform* GetMaximize() { 178 gfx::Rect target_bounds(0, 0, 1920, 1080); 179 gfx::Rect initial_bounds(30, 1000, 192, 108); 180 181 float scale_x = static_cast<float>( 182 target_bounds.height()) / initial_bounds.width(); 183 float scale_y = static_cast<float>( 184 target_bounds.width()) / initial_bounds.height(); 185 186 scoped_ptr<ui::InterpolatedTransform> scale( 187 new ui::InterpolatedScale(gfx::Point3F(1, 1, 1), 188 gfx::Point3F(scale_x, scale_y, 1))); 189 190 scoped_ptr<ui::InterpolatedTransform> translation( 191 new ui::InterpolatedTranslation( 192 gfx::Point(), 193 gfx::Point(target_bounds.x() - initial_bounds.x(), 194 target_bounds.y() - initial_bounds.y()))); 195 196 scoped_ptr<ui::InterpolatedTransform> rotation( 197 new ui::InterpolatedRotation(0, 4.0f)); 198 199 scoped_ptr<ui::InterpolatedTransform> rotation_about_pivot( 200 new ui::InterpolatedTransformAboutPivot( 201 gfx::Point(initial_bounds.width() * 0.5, 202 initial_bounds.height() * 0.5), 203 rotation.release())); 204 205 scale->SetChild(translation.release()); 206 rotation_about_pivot->SetChild(scale.release()); 207 208 rotation_about_pivot->SetReversed(true); 209 210 return rotation_about_pivot.release(); 211 } 212 213 TEST(InterpolatedTransformTest, MaximizeEndsCleanly) { 214 scoped_ptr<ui::InterpolatedTransform> maximize(GetMaximize()); 215 gfx::Transform interpolated = maximize->Interpolate(1.0f); 216 SkMatrix44& m = interpolated.matrix(); 217 // Upper-left 3x3 matrix should all be 0, 1 or -1. 218 for (int row = 0; row < 3; ++row) { 219 for (int col = 0; col < 3; ++col) { 220 float entry = m.get(row, col); 221 EXPECT_TRUE(entry == 0 || entry == 1 || entry == -1); 222 } 223 } 224 } 225