James Robinson | 646469d | 2014-10-03 15:33:28 -0700 | [diff] [blame] | 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/compositor/layer_animation_element.h" |
| 6 | |
| 7 | #include "base/basictypes.h" |
| 8 | #include "base/compiler_specific.h" |
| 9 | #include "base/memory/scoped_ptr.h" |
| 10 | #include "base/time/time.h" |
| 11 | #include "testing/gtest/include/gtest/gtest.h" |
| 12 | #include "ui/compositor/layer_animation_delegate.h" |
| 13 | #include "ui/compositor/scoped_animation_duration_scale_mode.h" |
| 14 | #include "ui/compositor/test/test_layer_animation_delegate.h" |
| 15 | #include "ui/compositor/test/test_utils.h" |
| 16 | #include "ui/gfx/rect.h" |
| 17 | #include "ui/gfx/transform.h" |
| 18 | |
| 19 | namespace ui { |
| 20 | |
| 21 | namespace { |
| 22 | |
| 23 | // Check that the transformation element progresses the delegate as expected and |
| 24 | // that the element can be reused after it completes. |
| 25 | TEST(LayerAnimationElementTest, TransformElement) { |
| 26 | TestLayerAnimationDelegate delegate; |
| 27 | gfx::Transform start_transform, target_transform; |
| 28 | start_transform.Rotate(-30.0); |
| 29 | target_transform.Rotate(30.0); |
| 30 | base::TimeTicks start_time; |
| 31 | base::TimeTicks effective_start_time; |
| 32 | base::TimeDelta delta = base::TimeDelta::FromSeconds(1); |
| 33 | |
| 34 | scoped_ptr<LayerAnimationElement> element( |
| 35 | LayerAnimationElement::CreateTransformElement(target_transform, delta)); |
| 36 | element->set_animation_group_id(1); |
| 37 | |
| 38 | for (int i = 0; i < 2; ++i) { |
| 39 | start_time = effective_start_time + delta; |
| 40 | element->set_requested_start_time(start_time); |
| 41 | delegate.SetTransformFromAnimation(start_transform); |
| 42 | element->Start(&delegate, 1); |
| 43 | element->Progress(start_time, &delegate); |
| 44 | CheckApproximatelyEqual(start_transform, |
| 45 | delegate.GetTransformForAnimation()); |
| 46 | effective_start_time = start_time + delta; |
| 47 | element->set_effective_start_time(effective_start_time); |
| 48 | element->Progress(effective_start_time, &delegate); |
| 49 | EXPECT_FLOAT_EQ(0.0, element->last_progressed_fraction()); |
| 50 | element->Progress(effective_start_time + delta/2, &delegate); |
| 51 | EXPECT_FLOAT_EQ(0.5, element->last_progressed_fraction()); |
| 52 | |
| 53 | base::TimeDelta element_duration; |
| 54 | EXPECT_TRUE(element->IsFinished(effective_start_time + delta, |
| 55 | &element_duration)); |
| 56 | EXPECT_EQ(2 * delta, element_duration); |
| 57 | |
| 58 | element->Progress(effective_start_time + delta, &delegate); |
| 59 | EXPECT_FLOAT_EQ(1.0, element->last_progressed_fraction()); |
| 60 | CheckApproximatelyEqual(target_transform, |
| 61 | delegate.GetTransformForAnimation()); |
| 62 | } |
| 63 | |
| 64 | LayerAnimationElement::TargetValue target_value(&delegate); |
| 65 | element->GetTargetValue(&target_value); |
| 66 | CheckApproximatelyEqual(target_transform, target_value.transform); |
| 67 | } |
| 68 | |
| 69 | // Ensures that duration is copied correctly. |
| 70 | TEST(LayerAnimationElementTest, InverseElementDurationNoScale) { |
| 71 | gfx::Transform transform; |
| 72 | base::TimeDelta delta; |
| 73 | |
| 74 | scoped_ptr<LayerAnimationElement> base_element( |
| 75 | LayerAnimationElement::CreateTransformElement(transform, delta)); |
| 76 | |
| 77 | scoped_ptr<LayerAnimationElement> inverse_element( |
| 78 | LayerAnimationElement::CreateInverseTransformElement(transform, |
| 79 | base_element.get())); |
| 80 | EXPECT_EQ(base_element->duration(), inverse_element->duration()); |
| 81 | } |
| 82 | |
| 83 | // Ensures that duration is copied correctly and not double scaled. |
| 84 | TEST(LayerAnimationElementTest, InverseElementDurationScaled) { |
| 85 | gfx::Transform transform; |
| 86 | base::TimeDelta delta; |
| 87 | |
| 88 | ScopedAnimationDurationScaleMode faster_duration( |
| 89 | ScopedAnimationDurationScaleMode::FAST_DURATION); |
| 90 | scoped_ptr<LayerAnimationElement> base_element( |
| 91 | LayerAnimationElement::CreateTransformElement(transform, delta)); |
| 92 | |
| 93 | scoped_ptr<LayerAnimationElement> inverse_element( |
| 94 | LayerAnimationElement::CreateInverseTransformElement(transform, |
| 95 | base_element.get())); |
| 96 | EXPECT_EQ(base_element->duration(), inverse_element->duration()); |
| 97 | } |
| 98 | |
| 99 | // Ensures that the GetTargetTransform() method works as intended. |
| 100 | TEST(LayerAnimationElementTest, InverseElementTargetCalculation) { |
| 101 | base::TimeTicks start_time; |
| 102 | base::TimeDelta delta = base::TimeDelta::FromSeconds(1); |
| 103 | start_time += delta; |
| 104 | |
| 105 | gfx::Transform identity, transform; |
| 106 | |
| 107 | transform.Scale3d(2.0, 2.0, 2.0); |
| 108 | |
| 109 | scoped_ptr<LayerAnimationElement> base_element( |
| 110 | LayerAnimationElement::CreateTransformElement(transform, delta)); |
| 111 | scoped_ptr<LayerAnimationElement> inverse_element( |
| 112 | LayerAnimationElement::CreateInverseTransformElement(identity, |
| 113 | base_element.get())); |
| 114 | |
| 115 | base_element->set_requested_start_time(start_time); |
| 116 | inverse_element->set_requested_start_time(start_time); |
| 117 | |
| 118 | TestLayerAnimationDelegate delegate; |
| 119 | delegate.SetTransformFromAnimation(transform); |
| 120 | |
| 121 | base_element->Start(&delegate, 1); |
| 122 | inverse_element->Start(&delegate, 1); |
| 123 | LayerAnimationElement::TargetValue target; |
| 124 | inverse_element->GetTargetValue(&target); |
| 125 | |
| 126 | EXPECT_TRUE(target.transform.IsIdentity()) |
| 127 | << "Target should be identity such that the initial 2x scale from the start" |
| 128 | << " carries over at end when parent is doubled."; |
| 129 | } |
| 130 | |
| 131 | // Check that the bounds element progresses the delegate as expected and |
| 132 | // that the element can be reused after it completes. |
| 133 | TEST(LayerAnimationElementTest, BoundsElement) { |
| 134 | TestLayerAnimationDelegate delegate; |
| 135 | gfx::Rect start, target, middle; |
| 136 | start = target = middle = gfx::Rect(0, 0, 50, 50); |
| 137 | start.set_x(-90); |
| 138 | target.set_x(90); |
| 139 | base::TimeTicks start_time; |
| 140 | base::TimeDelta delta = base::TimeDelta::FromSeconds(1); |
| 141 | |
| 142 | scoped_ptr<LayerAnimationElement> element( |
| 143 | LayerAnimationElement::CreateBoundsElement(target, delta)); |
| 144 | |
| 145 | for (int i = 0; i < 2; ++i) { |
| 146 | start_time += delta; |
| 147 | element->set_requested_start_time(start_time); |
| 148 | delegate.SetBoundsFromAnimation(start); |
| 149 | element->Start(&delegate, 1); |
| 150 | element->Progress(start_time, &delegate); |
| 151 | CheckApproximatelyEqual(start, delegate.GetBoundsForAnimation()); |
| 152 | element->Progress(start_time + delta/2, &delegate); |
| 153 | CheckApproximatelyEqual(middle, delegate.GetBoundsForAnimation()); |
| 154 | |
| 155 | base::TimeDelta element_duration; |
| 156 | EXPECT_TRUE(element->IsFinished(start_time + delta, &element_duration)); |
| 157 | EXPECT_EQ(delta, element_duration); |
| 158 | |
| 159 | element->Progress(start_time + delta, &delegate); |
| 160 | CheckApproximatelyEqual(target, delegate.GetBoundsForAnimation()); |
| 161 | } |
| 162 | |
| 163 | LayerAnimationElement::TargetValue target_value(&delegate); |
| 164 | element->GetTargetValue(&target_value); |
| 165 | CheckApproximatelyEqual(target, target_value.bounds); |
| 166 | } |
| 167 | |
| 168 | // Check that the opacity element progresses the delegate as expected and |
| 169 | // that the element can be reused after it completes. |
| 170 | TEST(LayerAnimationElementTest, OpacityElement) { |
| 171 | TestLayerAnimationDelegate delegate; |
| 172 | float start = 0.0; |
| 173 | float middle = 0.5; |
| 174 | float target = 1.0; |
| 175 | base::TimeTicks start_time; |
| 176 | base::TimeTicks effective_start_time; |
| 177 | base::TimeDelta delta = base::TimeDelta::FromSeconds(1); |
| 178 | scoped_ptr<LayerAnimationElement> element( |
| 179 | LayerAnimationElement::CreateOpacityElement(target, delta)); |
| 180 | |
| 181 | for (int i = 0; i < 2; ++i) { |
| 182 | start_time = effective_start_time + delta; |
| 183 | element->set_requested_start_time(start_time); |
| 184 | delegate.SetOpacityFromAnimation(start); |
| 185 | element->Start(&delegate, 1); |
| 186 | element->Progress(start_time, &delegate); |
| 187 | EXPECT_FLOAT_EQ(start, element->last_progressed_fraction()); |
| 188 | effective_start_time = start_time + delta; |
| 189 | element->set_effective_start_time(effective_start_time); |
| 190 | element->Progress(effective_start_time, &delegate); |
| 191 | EXPECT_FLOAT_EQ(start, element->last_progressed_fraction()); |
| 192 | element->Progress(effective_start_time + delta/2, &delegate); |
| 193 | EXPECT_FLOAT_EQ(middle, element->last_progressed_fraction()); |
| 194 | |
| 195 | base::TimeDelta element_duration; |
| 196 | EXPECT_TRUE(element->IsFinished(effective_start_time + delta, |
| 197 | &element_duration)); |
| 198 | EXPECT_EQ(2 * delta, element_duration); |
| 199 | |
| 200 | element->Progress(effective_start_time + delta, &delegate); |
| 201 | EXPECT_FLOAT_EQ(target, element->last_progressed_fraction()); |
| 202 | EXPECT_FLOAT_EQ(target, delegate.GetOpacityForAnimation()); |
| 203 | } |
| 204 | |
| 205 | LayerAnimationElement::TargetValue target_value(&delegate); |
| 206 | element->GetTargetValue(&target_value); |
| 207 | EXPECT_FLOAT_EQ(target, target_value.opacity); |
| 208 | } |
| 209 | |
| 210 | // Check that the visibility element progresses the delegate as expected and |
| 211 | // that the element can be reused after it completes. |
| 212 | TEST(LayerAnimationElementTest, VisibilityElement) { |
| 213 | TestLayerAnimationDelegate delegate; |
| 214 | bool start = true; |
| 215 | bool target = false; |
| 216 | base::TimeTicks start_time; |
| 217 | base::TimeDelta delta = base::TimeDelta::FromSeconds(1); |
| 218 | scoped_ptr<LayerAnimationElement> element( |
| 219 | LayerAnimationElement::CreateVisibilityElement(target, delta)); |
| 220 | |
| 221 | for (int i = 0; i < 2; ++i) { |
| 222 | start_time += delta; |
| 223 | element->set_requested_start_time(start_time); |
| 224 | delegate.SetVisibilityFromAnimation(start); |
| 225 | element->Start(&delegate, 1); |
| 226 | element->Progress(start_time, &delegate); |
| 227 | EXPECT_TRUE(delegate.GetVisibilityForAnimation()); |
| 228 | element->Progress(start_time + delta/2, &delegate); |
| 229 | EXPECT_TRUE(delegate.GetVisibilityForAnimation()); |
| 230 | |
| 231 | base::TimeDelta element_duration; |
| 232 | EXPECT_TRUE(element->IsFinished(start_time + delta, &element_duration)); |
| 233 | EXPECT_EQ(delta, element_duration); |
| 234 | |
| 235 | element->Progress(start_time + delta, &delegate); |
| 236 | EXPECT_FALSE(delegate.GetVisibilityForAnimation()); |
| 237 | } |
| 238 | |
| 239 | LayerAnimationElement::TargetValue target_value(&delegate); |
| 240 | element->GetTargetValue(&target_value); |
| 241 | EXPECT_FALSE(target_value.visibility); |
| 242 | } |
| 243 | |
| 244 | // Check that the Brightness element progresses the delegate as expected and |
| 245 | // that the element can be reused after it completes. |
| 246 | TEST(LayerAnimationElementTest, BrightnessElement) { |
| 247 | TestLayerAnimationDelegate delegate; |
| 248 | float start = 0.0; |
| 249 | float middle = 0.5; |
| 250 | float target = 1.0; |
| 251 | base::TimeTicks start_time; |
| 252 | base::TimeDelta delta = base::TimeDelta::FromSeconds(1); |
| 253 | scoped_ptr<LayerAnimationElement> element( |
| 254 | LayerAnimationElement::CreateBrightnessElement(target, delta)); |
| 255 | |
| 256 | for (int i = 0; i < 2; ++i) { |
| 257 | start_time += delta; |
| 258 | element->set_requested_start_time(start_time); |
| 259 | delegate.SetBrightnessFromAnimation(start); |
| 260 | element->Start(&delegate, 1); |
| 261 | element->Progress(start_time, &delegate); |
| 262 | EXPECT_FLOAT_EQ(start, delegate.GetBrightnessForAnimation()); |
| 263 | element->Progress(start_time + delta/2, &delegate); |
| 264 | EXPECT_FLOAT_EQ(middle, delegate.GetBrightnessForAnimation()); |
| 265 | |
| 266 | base::TimeDelta element_duration; |
| 267 | EXPECT_TRUE(element->IsFinished(start_time + delta, &element_duration)); |
| 268 | EXPECT_EQ(delta, element_duration); |
| 269 | |
| 270 | element->Progress(start_time + delta, &delegate); |
| 271 | EXPECT_FLOAT_EQ(target, delegate.GetBrightnessForAnimation()); |
| 272 | } |
| 273 | |
| 274 | LayerAnimationElement::TargetValue target_value(&delegate); |
| 275 | element->GetTargetValue(&target_value); |
| 276 | EXPECT_FLOAT_EQ(target, target_value.brightness); |
| 277 | } |
| 278 | |
| 279 | // Check that the Grayscale element progresses the delegate as expected and |
| 280 | // that the element can be reused after it completes. |
| 281 | TEST(LayerAnimationElementTest, GrayscaleElement) { |
| 282 | TestLayerAnimationDelegate delegate; |
| 283 | float start = 0.0; |
| 284 | float middle = 0.5; |
| 285 | float target = 1.0; |
| 286 | base::TimeTicks start_time; |
| 287 | base::TimeDelta delta = base::TimeDelta::FromSeconds(1); |
| 288 | scoped_ptr<LayerAnimationElement> element( |
| 289 | LayerAnimationElement::CreateGrayscaleElement(target, delta)); |
| 290 | |
| 291 | for (int i = 0; i < 2; ++i) { |
| 292 | start_time += delta; |
| 293 | element->set_requested_start_time(start_time); |
| 294 | delegate.SetGrayscaleFromAnimation(start); |
| 295 | element->Start(&delegate, 1); |
| 296 | element->Progress(start_time, &delegate); |
| 297 | EXPECT_FLOAT_EQ(start, delegate.GetGrayscaleForAnimation()); |
| 298 | element->Progress(start_time + delta/2, &delegate); |
| 299 | EXPECT_FLOAT_EQ(middle, delegate.GetGrayscaleForAnimation()); |
| 300 | |
| 301 | base::TimeDelta element_duration; |
| 302 | EXPECT_TRUE(element->IsFinished(start_time + delta, &element_duration)); |
| 303 | EXPECT_EQ(delta, element_duration); |
| 304 | |
| 305 | element->Progress(start_time + delta, &delegate); |
| 306 | EXPECT_FLOAT_EQ(target, delegate.GetGrayscaleForAnimation()); |
| 307 | } |
| 308 | |
| 309 | LayerAnimationElement::TargetValue target_value(&delegate); |
| 310 | element->GetTargetValue(&target_value); |
| 311 | EXPECT_FLOAT_EQ(target, target_value.grayscale); |
| 312 | } |
| 313 | |
| 314 | // Check that the pause element progresses the delegate as expected and |
| 315 | // that the element can be reused after it completes. |
| 316 | TEST(LayerAnimationElementTest, PauseElement) { |
| 317 | LayerAnimationElement::AnimatableProperties properties = |
| 318 | LayerAnimationElement::TRANSFORM | LayerAnimationElement::BOUNDS | |
| 319 | LayerAnimationElement::OPACITY | LayerAnimationElement::BRIGHTNESS | |
| 320 | LayerAnimationElement::GRAYSCALE; |
| 321 | |
| 322 | base::TimeTicks start_time; |
| 323 | base::TimeDelta delta = base::TimeDelta::FromSeconds(1); |
| 324 | |
| 325 | scoped_ptr<LayerAnimationElement> element( |
| 326 | LayerAnimationElement::CreatePauseElement(properties, delta)); |
| 327 | |
| 328 | TestLayerAnimationDelegate delegate; |
| 329 | TestLayerAnimationDelegate copy = delegate; |
| 330 | |
| 331 | start_time += delta; |
| 332 | element->set_requested_start_time(start_time); |
| 333 | element->Start(&delegate, 1); |
| 334 | |
| 335 | // Pause should last for |delta|. |
| 336 | base::TimeDelta element_duration; |
| 337 | EXPECT_TRUE(element->IsFinished(start_time + delta, &element_duration)); |
| 338 | EXPECT_EQ(delta, element_duration); |
| 339 | |
| 340 | element->Progress(start_time + delta, &delegate); |
| 341 | |
| 342 | // Nothing should have changed. |
| 343 | CheckApproximatelyEqual(delegate.GetBoundsForAnimation(), |
| 344 | copy.GetBoundsForAnimation()); |
| 345 | CheckApproximatelyEqual(delegate.GetTransformForAnimation(), |
| 346 | copy.GetTransformForAnimation()); |
| 347 | EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), |
| 348 | copy.GetOpacityForAnimation()); |
| 349 | EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), |
| 350 | copy.GetBrightnessForAnimation()); |
| 351 | EXPECT_FLOAT_EQ(delegate.GetGrayscaleForAnimation(), |
| 352 | copy.GetGrayscaleForAnimation()); |
| 353 | } |
| 354 | |
| 355 | // Check that a threaded opacity element updates the delegate as expected when |
| 356 | // aborted. |
| 357 | TEST(LayerAnimationElementTest, AbortOpacityElement) { |
| 358 | TestLayerAnimationDelegate delegate; |
| 359 | float start = 0.0; |
| 360 | float target = 1.0; |
| 361 | base::TimeTicks start_time; |
| 362 | base::TimeTicks effective_start_time; |
| 363 | base::TimeDelta delta = base::TimeDelta::FromSeconds(1); |
| 364 | scoped_ptr<LayerAnimationElement> element( |
| 365 | LayerAnimationElement::CreateOpacityElement(target, delta)); |
| 366 | |
| 367 | // Choose a non-linear Tween type. |
| 368 | gfx::Tween::Type tween_type = gfx::Tween::EASE_IN; |
| 369 | element->set_tween_type(tween_type); |
| 370 | |
| 371 | delegate.SetOpacityFromAnimation(start); |
| 372 | |
| 373 | // Aborting the element before it has started should not update the delegate. |
| 374 | element->Abort(&delegate); |
| 375 | EXPECT_FLOAT_EQ(start, delegate.GetOpacityForAnimation()); |
| 376 | |
| 377 | start_time += delta; |
| 378 | element->set_requested_start_time(start_time); |
| 379 | element->Start(&delegate, 1); |
| 380 | element->Progress(start_time, &delegate); |
| 381 | effective_start_time = start_time + delta; |
| 382 | element->set_effective_start_time(effective_start_time); |
| 383 | element->Progress(effective_start_time, &delegate); |
| 384 | element->Progress(effective_start_time + delta/2, &delegate); |
| 385 | |
| 386 | // Since the element has started, it should update the delegate when |
| 387 | // aborted. |
| 388 | element->Abort(&delegate); |
| 389 | EXPECT_FLOAT_EQ(gfx::Tween::CalculateValue(tween_type, 0.5), |
| 390 | delegate.GetOpacityForAnimation()); |
| 391 | } |
| 392 | |
| 393 | // Check that a threaded transform element updates the delegate as expected when |
| 394 | // aborted. |
| 395 | TEST(LayerAnimationElementTest, AbortTransformElement) { |
| 396 | TestLayerAnimationDelegate delegate; |
| 397 | gfx::Transform start_transform, target_transform; |
| 398 | start_transform.Rotate(-30.0); |
| 399 | target_transform.Rotate(30.0); |
| 400 | base::TimeTicks start_time; |
| 401 | base::TimeTicks effective_start_time; |
| 402 | base::TimeDelta delta = base::TimeDelta::FromSeconds(1); |
| 403 | scoped_ptr<LayerAnimationElement> element( |
| 404 | LayerAnimationElement::CreateTransformElement(target_transform, delta)); |
| 405 | |
| 406 | // Choose a non-linear Tween type. |
| 407 | gfx::Tween::Type tween_type = gfx::Tween::EASE_IN; |
| 408 | element->set_tween_type(tween_type); |
| 409 | |
| 410 | delegate.SetTransformFromAnimation(start_transform); |
| 411 | |
| 412 | // Aborting the element before it has started should not update the delegate. |
| 413 | element->Abort(&delegate); |
| 414 | CheckApproximatelyEqual(start_transform, delegate.GetTransformForAnimation()); |
| 415 | |
| 416 | start_time += delta; |
| 417 | element->set_requested_start_time(start_time); |
| 418 | element->Start(&delegate, 1); |
| 419 | element->Progress(start_time, &delegate); |
| 420 | effective_start_time = start_time + delta; |
| 421 | element->set_effective_start_time(effective_start_time); |
| 422 | element->Progress(effective_start_time, &delegate); |
| 423 | element->Progress(effective_start_time + delta/2, &delegate); |
| 424 | |
| 425 | // Since the element has started, it should update the delegate when |
| 426 | // aborted. |
| 427 | element->Abort(&delegate); |
| 428 | target_transform.Blend(start_transform, |
| 429 | gfx::Tween::CalculateValue(tween_type, 0.5)); |
| 430 | CheckApproximatelyEqual(target_transform, |
| 431 | delegate.GetTransformForAnimation()); |
| 432 | } |
| 433 | |
| 434 | } // namespace |
| 435 | |
| 436 | } // namespace ui |