progress_ring_pulse_animation.cc 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. // Copyright 2021 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. #include "ash/system/progress_indicator/progress_ring_pulse_animation.h"
  5. #include "base/dcheck_is_on.h"
  6. #include "base/notreached.h"
  7. #include "ui/compositor/scoped_animation_duration_scale_mode.h"
  8. #include "ui/gfx/animation/tween.h"
  9. namespace ash {
  10. namespace {
  11. // Animation -------------------------------------------------------------------
  12. constexpr float kAnimationDurationInMs = 2231.f;
  13. // Models a single key frame in the animation.
  14. struct AnimationKeyFrame {
  15. float fraction = 0.f;
  16. float opacity = 0.f;
  17. };
  18. // The collection of all key frames in the animation.
  19. constexpr AnimationKeyFrame kAnimationKeyFrames[] = {
  20. {.fraction = 0.f, .opacity = 1.f}, // Start.
  21. {.fraction = 333.f / kAnimationDurationInMs, .opacity = 0.f}, // Fade out.
  22. {.fraction = 433.f / kAnimationDurationInMs, .opacity = 0.f}, // Hold.
  23. {.fraction = 766.f / kAnimationDurationInMs, .opacity = 1.f}, // Fade in.
  24. {.fraction = 999.f / kAnimationDurationInMs, .opacity = 1.f}, // Hold.
  25. {.fraction = 1232.f / kAnimationDurationInMs, .opacity = 0.f}, // Fade out.
  26. {.fraction = 1332.f / kAnimationDurationInMs, .opacity = 0.f}, // Hold.
  27. {.fraction = 1665.f / kAnimationDurationInMs, .opacity = 1.f}, // Fade in.
  28. {.fraction = 1889.f / kAnimationDurationInMs, .opacity = 1.f}, // Hold.
  29. {.fraction = 1.f, .opacity = 0.f}}; // Fade out.
  30. } // namespace
  31. // ProgressRingPulseAnimation --------------------------------------------------
  32. ProgressRingPulseAnimation::ProgressRingPulseAnimation()
  33. : ProgressRingAnimation(Type::kPulse,
  34. base::Milliseconds(kAnimationDurationInMs),
  35. /*is_cyclic=*/false) {
  36. #if DCHECK_IS_ON()
  37. constexpr size_t kAnimationKeyFramesCount = std::size(kAnimationKeyFrames);
  38. DCHECK_GE(kAnimationKeyFramesCount, 2u);
  39. for (size_t i = 0u; i < kAnimationKeyFramesCount; ++i) {
  40. if (i == 0u) {
  41. // The first animation key frame should be at `0.f`.
  42. DCHECK_EQ(kAnimationKeyFrames[i].fraction, 0.f);
  43. } else if (i == kAnimationKeyFramesCount - 1u) {
  44. // The last animation key frame should be at `1.f`.
  45. DCHECK_EQ(kAnimationKeyFrames[i].fraction, 1.f);
  46. } else {
  47. // Animation key frames should appear in sorted order.
  48. DCHECK_GT(kAnimationKeyFrames[i].fraction, 0.f);
  49. DCHECK_LT(kAnimationKeyFrames[i].fraction, 1.f);
  50. DCHECK_GT(kAnimationKeyFrames[i].fraction,
  51. kAnimationKeyFrames[i - 1u].fraction);
  52. }
  53. }
  54. #endif // DCHECK_IS_ON()
  55. }
  56. ProgressRingPulseAnimation::~ProgressRingPulseAnimation() = default;
  57. void ProgressRingPulseAnimation::UpdateAnimatableProperties(
  58. double fraction,
  59. float* start_position,
  60. float* end_position,
  61. float* outer_ring_opacity) {
  62. *end_position = 1.f;
  63. // Loop over all animation key frames until the correct key frames for the
  64. // current animation `fraction` are found.
  65. for (size_t i = 1u; i < std::size(kAnimationKeyFrames); ++i) {
  66. if (fraction > kAnimationKeyFrames[i].fraction)
  67. continue;
  68. const AnimationKeyFrame& previous_key_frame = kAnimationKeyFrames[i - 1u];
  69. const AnimationKeyFrame& target_key_frame = kAnimationKeyFrames[i];
  70. // Update `fraction` so that it is still within the range [0, 1], but with
  71. // respect to the `previous_key_frame` and `target_key_frame`, instead of
  72. // with respect to the entire animation.
  73. fraction = (fraction - previous_key_frame.fraction) /
  74. (target_key_frame.fraction - previous_key_frame.fraction);
  75. // Interpolate `outer_ring_opacity` between the `previous_key_frame` and
  76. // `target_key_frame`.
  77. *outer_ring_opacity = gfx::Tween::FloatValueBetween(
  78. fraction, /*start_opacity=*/previous_key_frame.opacity,
  79. /*target_opacity=*/target_key_frame.opacity);
  80. return;
  81. }
  82. // This LOC should never be reached as the correct key frames for the current
  83. // animation `fraction` should have been found in the loop above.
  84. NOTREACHED();
  85. }
  86. } // namespace ash