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