resize_utils.cc 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. // Copyright 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 "ui/gfx/geometry/resize_utils.h"
  5. #include <ostream>
  6. #include "base/check_op.h"
  7. #include "base/cxx17_backports.h"
  8. #include "base/numerics/safe_conversions.h"
  9. #include "ui/gfx/geometry/rect.h"
  10. #include "ui/gfx/geometry/size.h"
  11. namespace gfx {
  12. namespace {
  13. // This function decides whether SizeRectToAspectRatio() will adjust the height
  14. // to match the specified width (resizing horizontally) or vice versa (resizing
  15. // vertically).
  16. bool IsResizingHorizontally(ResizeEdge resize_edge) {
  17. switch (resize_edge) {
  18. case ResizeEdge::kLeft:
  19. case ResizeEdge::kRight:
  20. case ResizeEdge::kTopLeft:
  21. case ResizeEdge::kBottomLeft:
  22. return true;
  23. default:
  24. return false;
  25. }
  26. }
  27. } // namespace
  28. void SizeRectToAspectRatio(ResizeEdge resize_edge,
  29. float aspect_ratio,
  30. const Size& min_window_size,
  31. absl::optional<Size> max_window_size,
  32. Rect* rect) {
  33. DCHECK_GT(aspect_ratio, 0.0f);
  34. if (max_window_size.has_value()) {
  35. DCHECK_GE(max_window_size->width(), min_window_size.width());
  36. DCHECK_GE(max_window_size->height(), min_window_size.height());
  37. DCHECK(Rect(rect->origin(), *max_window_size).Contains(*rect))
  38. << rect->ToString() << " is larger than the maximum size "
  39. << max_window_size->ToString();
  40. }
  41. DCHECK(rect->Contains(Rect(rect->origin(), min_window_size)))
  42. << rect->ToString() << " is smaller than the minimum size "
  43. << min_window_size.ToString();
  44. Size new_size = rect->size();
  45. if (IsResizingHorizontally(resize_edge)) {
  46. new_size.set_height(base::ClampRound(new_size.width() / aspect_ratio));
  47. if (min_window_size.height() > new_size.height() ||
  48. (max_window_size.has_value() &&
  49. new_size.height() > max_window_size->height())) {
  50. if (max_window_size.has_value()) {
  51. new_size.set_height(base::clamp(new_size.height(),
  52. min_window_size.height(),
  53. max_window_size->height()));
  54. } else {
  55. new_size.set_height(min_window_size.height());
  56. }
  57. new_size.set_width(base::ClampRound(new_size.height() * aspect_ratio));
  58. }
  59. } else {
  60. new_size.set_width(base::ClampRound(new_size.height() * aspect_ratio));
  61. if (min_window_size.width() > new_size.width() ||
  62. (max_window_size.has_value() &&
  63. new_size.width() > max_window_size->width())) {
  64. if (max_window_size.has_value()) {
  65. new_size.set_width(base::clamp(new_size.width(),
  66. min_window_size.width(),
  67. max_window_size->width()));
  68. } else {
  69. new_size.set_width(min_window_size.width());
  70. }
  71. new_size.set_height(base::ClampRound(new_size.width() / aspect_ratio));
  72. }
  73. }
  74. // The dimensions might still be outside of the allowed ranges at this point.
  75. // This happens when the aspect ratio makes it impossible to fit |rect|
  76. // within the size limits without letter-/pillarboxing.
  77. if (max_window_size.has_value())
  78. new_size.SetToMin(*max_window_size);
  79. new_size.SetToMax(min_window_size);
  80. // |rect| bounds before sizing to aspect ratio.
  81. int left = rect->x();
  82. int top = rect->y();
  83. int right = rect->right();
  84. int bottom = rect->bottom();
  85. switch (resize_edge) {
  86. case ResizeEdge::kRight:
  87. case ResizeEdge::kBottom:
  88. right = new_size.width() + left;
  89. bottom = top + new_size.height();
  90. break;
  91. case ResizeEdge::kTop:
  92. right = new_size.width() + left;
  93. top = bottom - new_size.height();
  94. break;
  95. case ResizeEdge::kLeft:
  96. case ResizeEdge::kTopLeft:
  97. left = right - new_size.width();
  98. top = bottom - new_size.height();
  99. break;
  100. case ResizeEdge::kTopRight:
  101. right = left + new_size.width();
  102. top = bottom - new_size.height();
  103. break;
  104. case ResizeEdge::kBottomLeft:
  105. left = right - new_size.width();
  106. bottom = top + new_size.height();
  107. break;
  108. case ResizeEdge::kBottomRight:
  109. right = left + new_size.width();
  110. bottom = top + new_size.height();
  111. break;
  112. }
  113. rect->SetByBounds(left, top, right, bottom);
  114. }
  115. } // namespace gfx