ambient_animation_progress_tracker.cc 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. // Copyright 2022 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/ambient/ui/ambient_animation_progress_tracker.h"
  5. #include <utility>
  6. #include "base/check.h"
  7. #include "base/logging.h"
  8. #include "base/notreached.h"
  9. #include "third_party/abseil-cpp/absl/types/optional.h"
  10. namespace ash {
  11. AmbientAnimationProgressTracker::ImmutableParams::ImmutableParams() = default;
  12. AmbientAnimationProgressTracker::ImmutableParams::ImmutableParams(
  13. const ImmutableParams& other) = default;
  14. AmbientAnimationProgressTracker::ImmutableParams&
  15. AmbientAnimationProgressTracker::ImmutableParams::operator=(
  16. const ImmutableParams& other) = default;
  17. AmbientAnimationProgressTracker::ImmutableParams::~ImmutableParams() = default;
  18. AmbientAnimationProgressTracker::AmbientAnimationProgressTracker() = default;
  19. AmbientAnimationProgressTracker::~AmbientAnimationProgressTracker() = default;
  20. void AmbientAnimationProgressTracker::RegisterAnimation(
  21. lottie::Animation* animation) {
  22. DCHECK(animation);
  23. DCHECK(!animation_observations_.IsObservingSource(animation));
  24. animation_observations_.AddObservation(animation);
  25. if (animation->GetPlaybackConfig()) {
  26. // The parameters verified here all concern "time" in the animation in some
  27. // form. They must match so that the "progress" returned by
  28. // GetGlobalProgress() has the same frame of reference across all
  29. // animations. Each animation's parameters are verified one time.
  30. VerifyAnimationImmutableParams(*animation);
  31. started_animations_.insert(animation);
  32. } else {
  33. DVLOG(4) << "Animation has not been Start()ed yet. Will be verified in "
  34. "AnimationWillStartPlaying() later.";
  35. uninitialized_animations_.insert(animation);
  36. }
  37. }
  38. bool AmbientAnimationProgressTracker::HasActiveAnimations() const {
  39. // Some of the started animations may not have painted a single frame yet. If
  40. // this is the case, GetCurrentProgress() will be null, so at least one of
  41. // them must return a non-null value for GetGlobalProgress() to return a valid
  42. // value.
  43. for (const lottie::Animation* animation : started_animations_) {
  44. if (animation->GetCurrentProgress())
  45. return true;
  46. }
  47. return false;
  48. }
  49. AmbientAnimationProgressTracker::Progress
  50. AmbientAnimationProgressTracker::GetGlobalProgress() const {
  51. // Currently, the method for picking one "global" progress is trivial. It just
  52. // picks an arbitrary animation in the group because in practice, their
  53. // timestamps should not have diverged by an amount that is user-perceptible
  54. // (ex: less than 100 ms). If it's needed in the future, we can do something
  55. // more complex here like taking the median or mean progress of all
  56. // animations. But the complexity is currently not justified.
  57. for (const lottie::Animation* animation : started_animations_) {
  58. if (animation->GetCurrentProgress()) {
  59. DCHECK(animation->GetNumCompletedCycles());
  60. return {*animation->GetNumCompletedCycles(),
  61. *animation->GetCurrentProgress()};
  62. }
  63. }
  64. NOTREACHED() << "HasActiveAnimations() must be true before calling "
  65. "GetGlobalProgress()";
  66. return Progress();
  67. }
  68. AmbientAnimationProgressTracker::ImmutableParams
  69. AmbientAnimationProgressTracker::GetImmutableParams() const {
  70. DCHECK(HasActiveAnimations());
  71. // The animation picked here is arbitrary since they all should have the same
  72. // immutable params.
  73. const lottie::Animation* animation = *started_animations_.begin();
  74. auto playback_config = animation->GetPlaybackConfig();
  75. ImmutableParams params;
  76. params.total_duration = animation->GetAnimationDuration();
  77. params.scheduled_cycles = playback_config->scheduled_cycles;
  78. params.style = playback_config->style;
  79. return params;
  80. }
  81. void AmbientAnimationProgressTracker::AnimationWillStartPlaying(
  82. const lottie::Animation* animation) {
  83. DCHECK(animation_observations_.IsObservingSource(
  84. const_cast<lottie::Animation*>(animation)));
  85. VerifyAnimationImmutableParams(*animation);
  86. DCHECK(uninitialized_animations_.contains(animation));
  87. DCHECK(!started_animations_.contains(animation));
  88. uninitialized_animations_.erase(animation);
  89. started_animations_.insert(animation);
  90. }
  91. void AmbientAnimationProgressTracker::AnimationIsDeleting(
  92. const lottie::Animation* animation) {
  93. DCHECK(animation_observations_.IsObservingSource(
  94. const_cast<lottie::Animation*>(animation)));
  95. animation_observations_.RemoveObservation(
  96. const_cast<lottie::Animation*>(animation));
  97. started_animations_.erase(animation);
  98. uninitialized_animations_.erase(animation);
  99. }
  100. void AmbientAnimationProgressTracker::VerifyAnimationImmutableParams(
  101. const lottie::Animation& animation) const {
  102. DCHECK(!started_animations_.contains(&animation));
  103. if (started_animations_.empty()) {
  104. DVLOG(4) << "Incoming animation is the first started in the session. No "
  105. "need to verify against other animations";
  106. return;
  107. }
  108. // The animation picked here is arbitrary since all existing animations should
  109. // have gone through this method, verifying that all of their immutable params
  110. // match.
  111. const lottie::Animation* existing_animation = *started_animations_.begin();
  112. DCHECK_EQ(animation.GetAnimationDuration(),
  113. existing_animation->GetAnimationDuration());
  114. auto incoming_playback_config = animation.GetPlaybackConfig();
  115. auto existing_playback_config = animation.GetPlaybackConfig();
  116. DCHECK(incoming_playback_config);
  117. DCHECK(existing_playback_config);
  118. DCHECK_EQ(incoming_playback_config->scheduled_cycles.size(),
  119. existing_playback_config->scheduled_cycles.size());
  120. for (size_t i = 0; i < incoming_playback_config->scheduled_cycles.size();
  121. ++i) {
  122. DCHECK_EQ(incoming_playback_config->scheduled_cycles[i].start_offset,
  123. existing_playback_config->scheduled_cycles[i].start_offset);
  124. DCHECK_EQ(incoming_playback_config->scheduled_cycles[i].end_offset,
  125. existing_playback_config->scheduled_cycles[i].end_offset);
  126. }
  127. DCHECK_EQ(incoming_playback_config->style, existing_playback_config->style);
  128. }
  129. } // namespace ash