insets_outsets_base.h 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  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. #ifndef UI_GFX_GEOMETRY_INSETS_OUTSETS_BASE_H_
  5. #define UI_GFX_GEOMETRY_INSETS_OUTSETS_BASE_H_
  6. #include <string>
  7. #include "base/numerics/clamped_math.h"
  8. #include "base/strings/stringprintf.h"
  9. #include "ui/gfx/geometry/size.h"
  10. namespace gfx {
  11. // The common base template class for Insets and Outsets.
  12. // Represents the widths of the four borders or margins of an unspecified
  13. // rectangle. It stores the thickness of the top, left, bottom and right
  14. // edges, without storing the actual size and position of the rectangle itself.
  15. template <typename T>
  16. class InsetsOutsetsBase {
  17. public:
  18. constexpr InsetsOutsetsBase() = default;
  19. constexpr explicit InsetsOutsetsBase(int all)
  20. : top_(all),
  21. left_(all),
  22. bottom_(ClampBottomOrRight(all, all)),
  23. right_(ClampBottomOrRight(all, all)) {}
  24. constexpr int top() const { return top_; }
  25. constexpr int left() const { return left_; }
  26. constexpr int bottom() const { return bottom_; }
  27. constexpr int right() const { return right_; }
  28. // Returns the total width taken up by the insets/outsets, which is the sum
  29. // of the left and right insets/outsets.
  30. constexpr int width() const { return left_ + right_; }
  31. // Returns the total height taken up by the insets/outsets, which is the sum
  32. // of the top and bottom insets/outsets.
  33. constexpr int height() const { return top_ + bottom_; }
  34. // Returns the sum of the left and right insets/outsets as the width,
  35. // the sum of the top and bottom insets/outsets as the height.
  36. constexpr Size size() const { return Size(width(), height()); }
  37. // Returns true if the insets/outsets are empty.
  38. bool IsEmpty() const { return width() == 0 && height() == 0; }
  39. // These setters can be used together with the default constructor and the
  40. // single-parameter constructor to construct Insets instances, for example:
  41. // // T, L, B, R
  42. // Insets a = Insets().set_top(2); // 2, 0, 0, 0
  43. // Insets b = Insets().set_left(2).set_bottom(3); // 0, 2, 3, 0
  44. // Insets c = Insets().set_left_right(1, 2).set_top_bottom(3, 4);
  45. // // 3, 1, 4, 2
  46. // Insets d = Insets(1).set_top(5); // 5, 1, 1, 1
  47. constexpr T& set_top(int top) {
  48. top_ = top;
  49. bottom_ = ClampBottomOrRight(top_, bottom_);
  50. return *static_cast<T*>(this);
  51. }
  52. constexpr T& set_left(int left) {
  53. left_ = left;
  54. right_ = ClampBottomOrRight(left_, right_);
  55. return *static_cast<T*>(this);
  56. }
  57. constexpr T& set_bottom(int bottom) {
  58. bottom_ = ClampBottomOrRight(top_, bottom);
  59. return *static_cast<T*>(this);
  60. }
  61. constexpr T& set_right(int right) {
  62. right_ = ClampBottomOrRight(left_, right);
  63. return *static_cast<T*>(this);
  64. }
  65. // These are preferred to the above setters when setting a pair of edges
  66. // because these have less clamping and better performance.
  67. constexpr T& set_left_right(int left, int right) {
  68. left_ = left;
  69. right_ = ClampBottomOrRight(left_, right);
  70. return *static_cast<T*>(this);
  71. }
  72. constexpr T& set_top_bottom(int top, int bottom) {
  73. top_ = top;
  74. bottom_ = ClampBottomOrRight(top_, bottom);
  75. return *static_cast<T*>(this);
  76. }
  77. // In addition to the above, we can also use the following methods to
  78. // construct Insets/Outsets.
  79. // TLBR() is for Chomium UI code. We should not use it in blink code because
  80. // the order of parameters is different from the normal orders used in blink.
  81. // Blink code can use the above setters and VH().
  82. static constexpr T TLBR(int top, int left, int bottom, int right) {
  83. return T().set_top_bottom(top, bottom).set_left_right(left, right);
  84. }
  85. static constexpr T VH(int vertical, int horizontal) {
  86. return TLBR(vertical, horizontal, vertical, horizontal);
  87. }
  88. // Sets each side to the maximum of the side and the corresponding side of
  89. // |other|.
  90. void SetToMax(const T& other) {
  91. top_ = std::max(top_, other.top_);
  92. left_ = std::max(left_, other.left_);
  93. bottom_ = std::max(bottom_, other.bottom_);
  94. right_ = std::max(right_, other.right_);
  95. }
  96. bool operator==(const InsetsOutsetsBase<T>& other) const {
  97. return top_ == other.top_ && left_ == other.left_ &&
  98. bottom_ == other.bottom_ && right_ == other.right_;
  99. }
  100. bool operator!=(const InsetsOutsetsBase<T>& other) const {
  101. return !(*this == other);
  102. }
  103. void operator+=(const T& other) {
  104. top_ = base::ClampAdd(top_, other.top_);
  105. left_ = base::ClampAdd(left_, other.left_);
  106. bottom_ = ClampBottomOrRight(top_, base::ClampAdd(bottom_, other.bottom_));
  107. right_ = ClampBottomOrRight(left_, base::ClampAdd(right_, other.right_));
  108. }
  109. void operator-=(const T& other) {
  110. top_ = base::ClampSub(top_, other.top_);
  111. left_ = base::ClampSub(left_, other.left_);
  112. bottom_ = ClampBottomOrRight(top_, base::ClampSub(bottom_, other.bottom_));
  113. right_ = ClampBottomOrRight(left_, base::ClampSub(right_, other.right_));
  114. }
  115. T operator-() const {
  116. return T()
  117. .set_left_right(-base::MakeClampedNum(left_),
  118. -base::MakeClampedNum(right_))
  119. .set_top_bottom(-base::MakeClampedNum(top_),
  120. -base::MakeClampedNum(bottom_));
  121. }
  122. // Returns a string representation of the insets/outsets.
  123. std::string ToString() const {
  124. return base::StringPrintf("x:%d,%d y:%d,%d", left_, right_, top_, bottom_);
  125. }
  126. private:
  127. // Clamp the bottom/right to avoid integer over/underflow in width() and
  128. // height(). This returns the clamped bottom/right given a |top_or_left| and
  129. // a |bottom_or_right|.
  130. static constexpr int ClampBottomOrRight(int top_or_left,
  131. int bottom_or_right) {
  132. return base::ClampAdd(top_or_left, bottom_or_right) - top_or_left;
  133. }
  134. int top_ = 0;
  135. int left_ = 0;
  136. int bottom_ = 0;
  137. int right_ = 0;
  138. };
  139. } // namespace gfx
  140. #endif // UI_GFX_GEOMETRY_INSETS_OUTSETS_BASE_H_