widget_animation_smoothness_inspector.cc 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. // Copyright (c) 2020 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/shelf/test/widget_animation_smoothness_inspector.h"
  5. #include "base/strings/stringprintf.h"
  6. #include "ui/compositor/layer.h"
  7. #include "ui/compositor/layer_animation_sequence.h"
  8. #include "ui/compositor/layer_animator.h"
  9. #include "ui/views/widget/widget.h"
  10. namespace ash {
  11. const char kErrorFormat[] =
  12. "Animation changes the widget's %s but stutters at value %d between steps "
  13. "%lu and %lu (on a total of %lu steps)";
  14. WidgetAnimationSmoothnessInspector::WidgetAnimationSmoothnessInspector(
  15. views::Widget* widget)
  16. : widget_(widget) {
  17. widget->GetLayer()->GetAnimator()->AddObserver(this);
  18. }
  19. WidgetAnimationSmoothnessInspector::~WidgetAnimationSmoothnessInspector() {
  20. widget_->GetLayer()->GetAnimator()->RemoveObserver(this);
  21. }
  22. bool WidgetAnimationSmoothnessInspector::CheckAnimation(
  23. unsigned int min_steps) const {
  24. DCHECK(min_steps > 2) << "An animation with 2 steps or less isn't "
  25. << "really an animation";
  26. if (bound_history_.size() < min_steps)
  27. return false;
  28. const unsigned long total_step_count = bound_history_.size();
  29. const unsigned long interval_between_steps_to_check =
  30. total_step_count / (min_steps - 1);
  31. const gfx::Rect initial_bounds = bound_history_.front();
  32. const gfx::Rect final_bounds = bound_history_.back();
  33. const bool x_changed = initial_bounds.x() != final_bounds.x();
  34. const bool y_changed = initial_bounds.y() != final_bounds.y();
  35. const bool w_changed = initial_bounds.width() != final_bounds.width();
  36. const bool h_changed = initial_bounds.height() != final_bounds.height();
  37. // An animation that changes nothing can't be considered smooth.
  38. if (!x_changed && !y_changed && !w_changed && !h_changed)
  39. return false;
  40. int last_x = initial_bounds.x();
  41. int last_y = initial_bounds.y();
  42. int last_w = initial_bounds.width();
  43. int last_h = initial_bounds.height();
  44. auto print_error = [=](const char* dimension, int value,
  45. unsigned long step) -> void {
  46. // Step numbers are 1-based in user-visible messages.
  47. DLOG(ERROR) << base::StringPrintf(
  48. kErrorFormat, dimension, value,
  49. 1 + step - interval_between_steps_to_check, 1 + step, total_step_count);
  50. };
  51. for (unsigned long i = interval_between_steps_to_check; i < total_step_count;
  52. i += interval_between_steps_to_check) {
  53. // Check the actual last step on the last loop iteration.
  54. if ((total_step_count - i) < interval_between_steps_to_check)
  55. i = total_step_count - 1;
  56. const gfx::Rect bounds = bound_history_[i];
  57. if (x_changed && bounds.x() == last_x) {
  58. print_error("x", last_x, i);
  59. return false;
  60. }
  61. if (y_changed && bounds.y() == last_y) {
  62. print_error("y", last_y, i);
  63. return false;
  64. }
  65. if (w_changed && bounds.width() == last_y) {
  66. print_error("width", last_w, i);
  67. return false;
  68. }
  69. if (h_changed && bounds.height() == last_h) {
  70. print_error("height", last_h, i);
  71. return false;
  72. }
  73. last_x = bounds.x();
  74. last_y = bounds.y();
  75. last_w = bounds.width();
  76. last_h = bounds.height();
  77. }
  78. return true;
  79. }
  80. void WidgetAnimationSmoothnessInspector::OnLayerAnimationEnded(
  81. ui::LayerAnimationSequence* sequence) {
  82. bound_history_.push_back(widget_->GetClientAreaBoundsInScreen());
  83. }
  84. void WidgetAnimationSmoothnessInspector::OnLayerAnimationAborted(
  85. ui::LayerAnimationSequence* sequence) {}
  86. void WidgetAnimationSmoothnessInspector::OnLayerAnimationScheduled(
  87. ui::LayerAnimationSequence* sequence) {
  88. bound_history_.push_back(widget_->GetClientAreaBoundsInScreen());
  89. }
  90. void WidgetAnimationSmoothnessInspector::OnLayerAnimationProgressed(
  91. const ui::LayerAnimationSequence* sequence) {
  92. bound_history_.push_back(widget_->GetClientAreaBoundsInScreen());
  93. }
  94. } // namespace ash