rrect_f.cc 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. // Copyright 2018 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/rrect_f.h"
  5. #include <iomanip>
  6. #include <iostream>
  7. #include <sstream>
  8. #include "base/values.h"
  9. #include "third_party/skia/include/core/SkMatrix.h"
  10. namespace gfx {
  11. // Sets all x radii to x_rad, and all y radii to y_rad. If one of x_rad or
  12. // y_rad are zero, sets ALL radii to zero.
  13. RRectF::RRectF(float x,
  14. float y,
  15. float width,
  16. float height,
  17. float x_rad,
  18. float y_rad)
  19. : skrrect_(SkRRect::MakeRectXY(SkRect::MakeXYWH(x, y, width, height),
  20. x_rad,
  21. y_rad)) {
  22. if (IsEmpty()) {
  23. // Make sure that empty rects are created fully empty, not with some
  24. // non-zero dimensions.
  25. skrrect_ = SkRRect::MakeEmpty();
  26. }
  27. }
  28. // Directly sets all four corners.
  29. RRectF::RRectF(float x,
  30. float y,
  31. float width,
  32. float height,
  33. float upper_left_x,
  34. float upper_left_y,
  35. float upper_right_x,
  36. float upper_right_y,
  37. float lower_right_x,
  38. float lower_right_y,
  39. float lower_left_x,
  40. float lower_left_y) {
  41. SkVector radii[4] = {
  42. {upper_left_x, upper_left_y},
  43. {upper_right_x, upper_right_y},
  44. {lower_right_x, lower_right_y},
  45. {lower_left_x, lower_left_y},
  46. };
  47. skrrect_.setRectRadii(SkRect::MakeXYWH(x, y, width, height), radii);
  48. if (IsEmpty()) {
  49. // Make sure that empty rects are created fully empty, not with some
  50. // non-zero dimensions.
  51. skrrect_ = SkRRect::MakeEmpty();
  52. }
  53. }
  54. gfx::Vector2dF RRectF::GetSimpleRadii() const {
  55. DCHECK(GetType() <= Type::kOval);
  56. SkPoint result = skrrect_.getSimpleRadii();
  57. return gfx::Vector2dF(result.x(), result.y());
  58. }
  59. float RRectF::GetSimpleRadius() const {
  60. DCHECK(GetType() <= Type::kOval);
  61. SkPoint result = skrrect_.getSimpleRadii();
  62. DCHECK_EQ(result.x(), result.y());
  63. return result.x();
  64. }
  65. RRectF::Type RRectF::GetType() const {
  66. SkPoint rad;
  67. switch (skrrect_.getType()) {
  68. case SkRRect::kEmpty_Type:
  69. return Type::kEmpty;
  70. case SkRRect::kRect_Type:
  71. return Type::kRect;
  72. case SkRRect::kSimple_Type:
  73. rad = skrrect_.getSimpleRadii();
  74. if (rad.x() == rad.y()) {
  75. return Type::kSingle;
  76. }
  77. return Type::kSimple;
  78. case SkRRect::kOval_Type:
  79. rad = skrrect_.getSimpleRadii();
  80. if (rad.x() == rad.y()) {
  81. return Type::kSingle;
  82. }
  83. return Type::kOval;
  84. case SkRRect::kNinePatch_Type:
  85. case SkRRect::kComplex_Type:
  86. default:
  87. return Type::kComplex;
  88. }
  89. }
  90. gfx::Vector2dF RRectF::GetCornerRadii(Corner corner) const {
  91. SkPoint result = skrrect_.radii(SkRRect::Corner(corner));
  92. return gfx::Vector2dF(result.x(), result.y());
  93. }
  94. void RRectF::GetAllRadii(SkVector radii[4]) const {
  95. // Unfortunately, the only way to get all radii is one at a time.
  96. radii[SkRRect::kUpperLeft_Corner] =
  97. skrrect_.radii(SkRRect::kUpperLeft_Corner);
  98. radii[SkRRect::kUpperRight_Corner] =
  99. skrrect_.radii(SkRRect::kUpperRight_Corner);
  100. radii[SkRRect::kLowerRight_Corner] =
  101. skrrect_.radii(SkRRect::kLowerRight_Corner);
  102. radii[SkRRect::kLowerLeft_Corner] =
  103. skrrect_.radii(SkRRect::kLowerLeft_Corner);
  104. }
  105. void RRectF::SetCornerRadii(Corner corner, float x_rad, float y_rad) {
  106. // Unfortunately, the only way to set this is to create a new SkRRect.
  107. SkVector radii[4];
  108. GetAllRadii(radii);
  109. radii[SkRRect::Corner(corner)] = SkPoint::Make(x_rad, y_rad);
  110. skrrect_.setRectRadii(skrrect_.rect(), radii);
  111. }
  112. void RRectF::Scale(float x_scale, float y_scale) {
  113. if (IsEmpty()) {
  114. // SkRRect doesn't support scaling of empty rects.
  115. return;
  116. }
  117. if (!x_scale || !y_scale) {
  118. // SkRRect doesn't support scaling TO an empty rect.
  119. skrrect_ = SkRRect::MakeEmpty();
  120. return;
  121. }
  122. SkMatrix scale = SkMatrix::Scale(x_scale, y_scale);
  123. SkRRect result;
  124. bool success = skrrect_.transform(scale, &result);
  125. DCHECK(success);
  126. skrrect_ = result;
  127. }
  128. void RRectF::Offset(float horizontal, float vertical) {
  129. skrrect_.offset(horizontal, vertical);
  130. }
  131. const RRectF& RRectF::operator+=(const gfx::Vector2dF& offset) {
  132. Offset(offset.x(), offset.y());
  133. return *this;
  134. }
  135. const RRectF& RRectF::operator-=(const gfx::Vector2dF& offset) {
  136. Offset(-offset.x(), -offset.y());
  137. return *this;
  138. }
  139. std::string RRectF::ToString() const {
  140. std::stringstream ss;
  141. ss << std::fixed << std::setprecision(3);
  142. ss << rect().origin().x() << "," << rect().origin().y() << " "
  143. << rect().size().width() << "x" << rect().size().height();
  144. Type type = this->GetType();
  145. if (type <= Type::kRect) {
  146. ss << ", rectangular";
  147. } else if (type <= Type::kSingle) {
  148. ss << ", radius " << GetSimpleRadius();
  149. } else if (type <= Type::kSimple) {
  150. gfx::Vector2dF radii = GetSimpleRadii();
  151. ss << ", x_rad " << radii.x() << ", y_rad " << radii.y();
  152. } else {
  153. ss << ",";
  154. const Corner corners[] = {Corner::kUpperLeft, Corner::kUpperRight,
  155. Corner::kLowerRight, Corner::kLowerLeft};
  156. for (const auto& c : corners) {
  157. auto this_corner = GetCornerRadii(c);
  158. ss << " [" << this_corner.x() << " " << this_corner.y() << "]";
  159. }
  160. }
  161. return ss.str();
  162. }
  163. namespace {
  164. inline bool AboveTol(float val1, float val2, float tolerance) {
  165. return (std::abs(val1 - val2) > tolerance);
  166. }
  167. } // namespace
  168. bool RRectF::ApproximatelyEqual(const RRectF& rect, float tolerance) const {
  169. if (AboveTol(skrrect_.rect().x(), rect.skrrect_.rect().x(), tolerance) ||
  170. AboveTol(skrrect_.rect().y(), rect.skrrect_.rect().y(), tolerance) ||
  171. AboveTol(skrrect_.width(), rect.skrrect_.width(), tolerance) ||
  172. AboveTol(skrrect_.height(), rect.skrrect_.height(), tolerance))
  173. return false;
  174. for (int i = 0; i < 4; i++) {
  175. SkVector r1 = skrrect_.radii(SkRRect::Corner(i));
  176. SkVector r2 = rect.skrrect_.radii(SkRRect::Corner(i));
  177. if (std::abs(r1.x() - r2.x()) > tolerance ||
  178. std::abs(r1.y() - r2.y()) > tolerance) {
  179. return false;
  180. }
  181. }
  182. return true;
  183. }
  184. } // namespace gfx