rrect_f_unittest.cc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  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 "base/cxx17_backports.h"
  6. #include "testing/gtest/include/gtest/gtest.h"
  7. #include "ui/gfx/geometry/rrect_f_builder.h"
  8. namespace gfx {
  9. TEST(RRectFTest, IsEmpty) {
  10. EXPECT_TRUE(RRectF().IsEmpty());
  11. EXPECT_TRUE(RRectF(0, 0, 0, 0, 0).IsEmpty());
  12. EXPECT_TRUE(RRectF(0, 0, 10, 0, 0).IsEmpty());
  13. EXPECT_TRUE(RRectF(0, 0, 0, 10, 0).IsEmpty());
  14. EXPECT_TRUE(RRectF(0, 0, 0, 10, 10).IsEmpty());
  15. EXPECT_FALSE(RRectF(0, 0, 10, 10, 0).IsEmpty());
  16. }
  17. TEST(RRectFTest, Equals) {
  18. EXPECT_EQ(RRectF(0, 0, 0, 0, 0, 0), RRectF(0, 0, 0, 0, 0, 0));
  19. EXPECT_EQ(RRectF(1, 2, 3, 4, 5, 6), RRectF(1, 2, 3, 4, 5, 6));
  20. EXPECT_EQ(RRectF(1, 2, 3, 4, 5, 5), RRectF(1, 2, 3, 4, 5));
  21. EXPECT_EQ(RRectF(0, 0, 2, 3, 0, 0), RRectF(0, 0, 2, 3, 0, 1));
  22. EXPECT_EQ(RRectF(0, 0, 2, 3, 0, 0), RRectF(0, 0, 2, 3, 1, 0));
  23. EXPECT_EQ(RRectF(1, 2, 3, 0, 5, 6), RRectF(0, 0, 0, 0, 0, 0));
  24. EXPECT_EQ(RRectF(0, 0, 0, 0, 5, 6), RRectF(0, 0, 0, 0, 0, 0));
  25. EXPECT_NE(RRectF(10, 20, 30, 40, 7, 8), RRectF(1, 20, 30, 40, 7, 8));
  26. EXPECT_NE(RRectF(10, 20, 30, 40, 7, 8), RRectF(10, 2, 30, 40, 7, 8));
  27. EXPECT_NE(RRectF(10, 20, 30, 40, 7, 8), RRectF(10, 20, 3, 40, 7, 8));
  28. EXPECT_NE(RRectF(10, 20, 30, 40, 7, 8), RRectF(10, 20, 30, 4, 7, 8));
  29. EXPECT_NE(RRectF(10, 20, 30, 40, 7, 8), RRectF(10, 20, 30, 40, 5, 8));
  30. EXPECT_NE(RRectF(10, 20, 30, 40, 7, 8), RRectF(10, 20, 30, 40, 7, 6));
  31. }
  32. TEST(RRectFTest, PlusMinusOffset) {
  33. const RRectF a(40, 50, 60, 70, 5);
  34. gfx::Vector2d offset(23, 34);
  35. RRectF correct(63, 84, 60, 70, 5);
  36. RRectF b = a + offset;
  37. ASSERT_EQ(b, correct);
  38. b = a;
  39. b.Offset(offset);
  40. ASSERT_EQ(b, correct);
  41. correct = RRectF(17, 16, 60, 70, 5);
  42. b = a - offset;
  43. ASSERT_EQ(b, correct);
  44. b = a;
  45. b.Offset(-offset);
  46. ASSERT_EQ(b, correct);
  47. }
  48. TEST(RRectFTest, RRectTypes) {
  49. RRectF a(40, 50, 0, 70, 0);
  50. EXPECT_EQ(a.GetType(), RRectF::Type::kEmpty);
  51. EXPECT_TRUE(a.IsEmpty());
  52. a = RRectF(40, 50, 60, 70, 0);
  53. EXPECT_EQ(a.GetType(), RRectF::Type::kRect);
  54. a = RRectF(40, 50, 60, 70, 5);
  55. EXPECT_EQ(a.GetType(), RRectF::Type::kSingle);
  56. a = RRectF(40, 50, 60, 70, 5, 5);
  57. EXPECT_EQ(a.GetType(), RRectF::Type::kSingle);
  58. a = RRectF(40, 50, 60, 60, 30, 30);
  59. EXPECT_EQ(a.GetType(), RRectF::Type::kSingle);
  60. a = RRectF(40, 50, 60, 70, 6, 3);
  61. EXPECT_EQ(a.GetType(), RRectF::Type::kSimple);
  62. a = RRectF(40, 50, 60, 70, 30, 3);
  63. EXPECT_EQ(a.GetType(), RRectF::Type::kSimple);
  64. a = RRectF(40, 50, 60, 70, 30, 35);
  65. EXPECT_EQ(a.GetType(), RRectF::Type::kOval);
  66. a.SetCornerRadii(RRectF::Corner::kLowerRight, gfx::Vector2dF(7, 8));
  67. EXPECT_EQ(a.GetType(), RRectF::Type::kComplex);
  68. // When one radius is larger than half its dimension, both radii are scaled
  69. // down proportionately.
  70. a = RRectF(40, 50, 60, 70, 30, 70);
  71. EXPECT_EQ(a.GetType(), RRectF::Type::kSimple);
  72. EXPECT_EQ(a, RRectF(40, 50, 60, 70, 15, 35));
  73. // If they stay equal to half the radius, it stays oval.
  74. a = RRectF(40, 50, 60, 70, 120, 140);
  75. EXPECT_EQ(a.GetType(), RRectF::Type::kOval);
  76. }
  77. void CheckRadii(RRectF val,
  78. float ulx,
  79. float uly,
  80. float urx,
  81. float ury,
  82. float lrx,
  83. float lry,
  84. float llx,
  85. float lly) {
  86. EXPECT_EQ(val.GetCornerRadii(RRectF::Corner::kUpperLeft),
  87. gfx::Vector2dF(ulx, uly));
  88. EXPECT_EQ(val.GetCornerRadii(RRectF::Corner::kUpperRight),
  89. gfx::Vector2dF(urx, ury));
  90. EXPECT_EQ(val.GetCornerRadii(RRectF::Corner::kLowerRight),
  91. gfx::Vector2dF(lrx, lry));
  92. EXPECT_EQ(val.GetCornerRadii(RRectF::Corner::kLowerLeft),
  93. gfx::Vector2dF(llx, lly));
  94. }
  95. TEST(RRectFTest, RRectRadii) {
  96. RRectF a(40, 50, 60, 70, 0);
  97. CheckRadii(a, 0, 0, 0, 0, 0, 0, 0, 0);
  98. a.SetCornerRadii(RRectF::Corner::kUpperLeft, 1, 2);
  99. CheckRadii(a, 1, 2, 0, 0, 0, 0, 0, 0);
  100. a.SetCornerRadii(RRectF::Corner::kUpperRight, 3, 4);
  101. CheckRadii(a, 1, 2, 3, 4, 0, 0, 0, 0);
  102. a.SetCornerRadii(RRectF::Corner::kLowerRight, 5, 6);
  103. CheckRadii(a, 1, 2, 3, 4, 5, 6, 0, 0);
  104. a.SetCornerRadii(RRectF::Corner::kLowerLeft, 7, 8);
  105. CheckRadii(a, 1, 2, 3, 4, 5, 6, 7, 8);
  106. RRectF b(40, 50, 60, 70, 1, 2, 3, 4, 5, 6, 7, 8);
  107. EXPECT_EQ(a, b);
  108. }
  109. TEST(RRectFTest, FromRectF) {
  110. // Check that explicit conversion from float rect works.
  111. RectF a(40, 50, 60, 70);
  112. RRectF b(40, 50, 60, 70, 0);
  113. RRectF c = RRectF(a);
  114. EXPECT_EQ(b, c);
  115. }
  116. TEST(RRectFTest, FromSkRRect) {
  117. // Check that explicit conversion from SkRRect works.
  118. SkRRect a = SkRRect::MakeRectXY(SkRect::MakeXYWH(40, 50, 60, 70), 15, 25);
  119. RRectF b(40, 50, 60, 70, 15, 25);
  120. RRectF c = RRectF(a);
  121. EXPECT_EQ(b, c);
  122. // Try with single radius constructor.
  123. a = SkRRect::MakeRectXY(SkRect::MakeXYWH(40, 50, 60, 70), 15, 15);
  124. b = RRectF(40, 50, 60, 70, 15);
  125. c = RRectF(a);
  126. EXPECT_EQ(b, c);
  127. }
  128. TEST(RRectFTest, FromRoundedCornersF) {
  129. constexpr RectF kRect(50.0f, 40.0f);
  130. constexpr RoundedCornersF kCorners(1.5f, 2.5f, 3.5f, 4.5f);
  131. const RRectF rrect_f(kRect, kCorners);
  132. const auto upper_left = rrect_f.GetCornerRadii(RRectF::Corner::kUpperLeft);
  133. EXPECT_EQ(kCorners.upper_left(), upper_left.x());
  134. EXPECT_EQ(kCorners.upper_left(), upper_left.y());
  135. const auto upper_right = rrect_f.GetCornerRadii(RRectF::Corner::kUpperRight);
  136. EXPECT_EQ(kCorners.upper_right(), upper_right.x());
  137. EXPECT_EQ(kCorners.upper_right(), upper_right.y());
  138. const auto lower_right = rrect_f.GetCornerRadii(RRectF::Corner::kLowerRight);
  139. EXPECT_EQ(kCorners.lower_right(), lower_right.x());
  140. EXPECT_EQ(kCorners.lower_right(), lower_right.y());
  141. const auto lower_left = rrect_f.GetCornerRadii(RRectF::Corner::kLowerLeft);
  142. EXPECT_EQ(kCorners.lower_left(), lower_left.x());
  143. EXPECT_EQ(kCorners.lower_left(), lower_left.y());
  144. }
  145. TEST(RRectFTest, ToString) {
  146. RRectF a(40, 50, 60, 70, 0);
  147. EXPECT_EQ(a.ToString(), "40.000,50.000 60.000x70.000, rectangular");
  148. a = RRectF(40, 50, 60, 70, 15);
  149. EXPECT_EQ(a.ToString(), "40.000,50.000 60.000x70.000, radius 15.000");
  150. a = RRectF(40, 50, 60, 70, 15, 25);
  151. EXPECT_EQ(a.ToString(),
  152. "40.000,50.000 60.000x70.000, x_rad 15.000, y_rad 25.000");
  153. a.SetCornerRadii(RRectF::Corner::kLowerRight, gfx::Vector2dF(7, 8));
  154. EXPECT_EQ(a.ToString(),
  155. "40.000,50.000 60.000x70.000, [15.000 25.000] "
  156. "[15.000 25.000] [7.000 8.000] [15.000 25.000]");
  157. }
  158. TEST(RRectFTest, Sizes) {
  159. RRectF a(40, 50, 60, 70, 5, 6);
  160. EXPECT_EQ(a.rect().x(), 40);
  161. EXPECT_EQ(a.rect().y(), 50);
  162. EXPECT_EQ(a.rect().width(), 60);
  163. EXPECT_EQ(a.rect().height(), 70);
  164. EXPECT_EQ(a.GetSimpleRadii().x(), 5);
  165. EXPECT_EQ(a.GetSimpleRadii().y(), 6);
  166. a = RRectF(40, 50, 60, 70, 5, 5);
  167. EXPECT_EQ(a.GetSimpleRadius(), 5);
  168. a.Clear();
  169. EXPECT_TRUE(a.IsEmpty());
  170. // Make sure ovals can still get simple radii
  171. a = RRectF(40, 50, 60, 70, 30, 35);
  172. EXPECT_EQ(a.GetType(), RRectF::Type::kOval);
  173. EXPECT_EQ(a.GetSimpleRadii().x(), 30);
  174. EXPECT_EQ(a.GetSimpleRadii().y(), 35);
  175. }
  176. TEST(RRectFTest, Contains) {
  177. RRectF a(40, 50, 60, 70, 5, 6);
  178. RectF b(50, 60, 5, 6);
  179. EXPECT_TRUE(a.Contains(b));
  180. b = RectF(40, 50, 5, 6); // Right on the border
  181. EXPECT_FALSE(a.Contains(b));
  182. b = RectF(95, 114, 5, 6); // Right on the border
  183. EXPECT_FALSE(a.Contains(b));
  184. b = RectF(40, 50, 60, 70);
  185. EXPECT_FALSE(a.Contains(b));
  186. }
  187. TEST(RRectFTest, Scale) {
  188. // Note that SKRRect (the backing for RRectF) does not support scaling by NaN,
  189. // or scaling out of numerical bounds. So this test doesn't exercise those.
  190. static const struct Test {
  191. float x1; // source
  192. float y1;
  193. float w1;
  194. float h1;
  195. float x_rad1;
  196. float y_rad1;
  197. float x_scale;
  198. float y_scale;
  199. float x2; // target
  200. float y2;
  201. float w2;
  202. float h2;
  203. float x_rad2;
  204. float y_rad2;
  205. } tests[] = {
  206. {3.0f, 4.0f, 5.0f, 6.0f, 0.0f, 0.0f, 1.5f, 1.5f, 4.5f, 6.0f, 7.5f, 9.0f,
  207. 0.0f, 0.0f},
  208. {3.0f, 4.0f, 5.0f, 6.0f, 1.0f, 1.0f, 1.5f, 1.5f, 4.5f, 6.0f, 7.5f, 9.0f,
  209. 1.5f, 1.5f},
  210. {3.0f, 4.0f, 5.0f, 6.0f, 0.0f, 0.0f, 1.5f, 3.0f, 4.5f, 12.0f, 7.5f, 18.0f,
  211. 0.0f, 0.0f},
  212. {3.0f, 4.0f, 5.0f, 6.0f, 1.0f, 1.0f, 1.5f, 3.0f, 4.5f, 12.0f, 7.5f, 18.0f,
  213. 1.5f, 3.0f},
  214. {3.0f, 4.0f, 0.0f, 6.0f, 1.0f, 1.0f, 1.5f, 1.5f, 0.0f, 0.0f, 0.0f, 0.0f,
  215. 0.0f, 0.0f},
  216. {3.0f, 4.0f, 5.0f, 6.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
  217. 0.0f, 0.0f},
  218. {3.0f, 4.0f, 5.0f, 6.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
  219. 0.0f, 0.0f},
  220. {3.0f, 4.0f, 5.0f, 6.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
  221. 0.0f, 0.0f},
  222. };
  223. for (auto& test : tests) {
  224. RRectF r1(test.x1, test.y1, test.w1, test.h1, test.x_rad1, test.y_rad1);
  225. RRectF r2(test.x2, test.y2, test.w2, test.h2, test.x_rad2, test.y_rad2);
  226. r1.Scale(test.x_scale, test.y_scale);
  227. ASSERT_TRUE(r1.GetType() <= RRectF::Type::kSimple);
  228. EXPECT_EQ(r1.rect().x(), r2.rect().x());
  229. EXPECT_EQ(r1.rect().y(), r2.rect().y());
  230. EXPECT_EQ(r1.rect().width(), r2.rect().width());
  231. EXPECT_EQ(r1.rect().height(), r2.rect().height());
  232. EXPECT_EQ(r1.GetSimpleRadii(), r2.GetSimpleRadii());
  233. }
  234. }
  235. TEST(RRectFTest, InsetOutset) {
  236. RRectF a(40, 50, 60, 70, 5);
  237. RRectF b = a;
  238. b.Inset(3);
  239. ASSERT_EQ(b, RRectF(43, 53, 54, 64, 2));
  240. b = a;
  241. b.Outset(3);
  242. ASSERT_EQ(b, RRectF(37, 47, 66, 76, 8));
  243. }
  244. // The following tests(started with "Build*") are for RRectFBuilder. All
  245. // different tests are to make sure that existing RRectF definitions can be
  246. // implemented with RRectFBuilder.
  247. TEST(RRectFTest, BuildFromRectF) {
  248. RectF a = RectF();
  249. RRectF b(a);
  250. RRectF c = RRectFBuilder().set_rect(a).Build();
  251. EXPECT_EQ(b, c);
  252. a = RectF(60, 70);
  253. b = RRectF(a);
  254. c = RRectFBuilder().set_rect(a).Build();
  255. EXPECT_EQ(b, c);
  256. a = RectF(40, 50, 60, 70);
  257. b = RRectF(a);
  258. c = RRectFBuilder().set_rect(a).Build();
  259. EXPECT_EQ(b, c);
  260. }
  261. TEST(RRectFTest, BuildFromRadius) {
  262. RRectF a(40, 50, 60, 70, 15);
  263. RRectF b = RRectFBuilder()
  264. .set_origin(40, 50)
  265. .set_size(60, 70)
  266. .set_radius(15)
  267. .Build();
  268. EXPECT_EQ(a, b);
  269. a = RRectF(40, 50, 60, 70, 15, 25);
  270. b = RRectFBuilder()
  271. .set_origin(40, 50)
  272. .set_size(60, 70)
  273. .set_radius(15, 25)
  274. .Build();
  275. EXPECT_EQ(a, b);
  276. const PointF p(40, 50);
  277. const SizeF s(60, 70);
  278. b = RRectFBuilder().set_origin(p).set_size(s).set_radius(15, 25).Build();
  279. EXPECT_EQ(a, b);
  280. }
  281. TEST(RRectFTest, BuildFromRectFWithRadius) {
  282. RectF a(40, 50, 60, 70);
  283. RRectF b(a, 15);
  284. RRectF c = RRectFBuilder().set_rect(a).set_radius(15).Build();
  285. EXPECT_EQ(b, c);
  286. b = RRectF(a, 15, 25);
  287. c = RRectFBuilder().set_rect(a).set_radius(15, 25).Build();
  288. EXPECT_EQ(b, c);
  289. }
  290. TEST(RRectFTest, BuildFromCorners) {
  291. RRectF a(40, 50, 60, 70, 1, 2, 3, 4, 5, 6, 7, 8);
  292. RRectF b = RRectFBuilder()
  293. .set_origin(40, 50)
  294. .set_size(60, 70)
  295. .set_upper_left(1, 2)
  296. .set_upper_right(3, 4)
  297. .set_lower_right(5, 6)
  298. .set_lower_left(7, 8)
  299. .Build();
  300. EXPECT_EQ(a, b);
  301. }
  302. TEST(RRectFTest, BuildFromRectFWithCorners) {
  303. RectF a(40, 50, 60, 70);
  304. RRectF b(a, 1, 2, 3, 4, 5, 6, 7, 8);
  305. RRectF c = RRectFBuilder()
  306. .set_rect(a)
  307. .set_upper_left(1, 2)
  308. .set_upper_right(3, 4)
  309. .set_lower_right(5, 6)
  310. .set_lower_left(7, 8)
  311. .Build();
  312. EXPECT_EQ(b, c);
  313. }
  314. TEST(RRectFTest, BuildFromRoundedCornersF) {
  315. RectF a(40, 50, 60, 70);
  316. RoundedCornersF corners(1.5f, 2.5f, 3.5f, 4.5f);
  317. RRectF b(a, corners);
  318. RRectF c = RRectFBuilder().set_rect(a).set_corners(corners).Build();
  319. EXPECT_EQ(b, c);
  320. }
  321. // In the following tests(*CornersHigherThanSize), we test whether the corner
  322. // radii gets truncated in case of being greater than the width/height.
  323. TEST(RRectFTest, BuildFromCornersHigherThanSize) {
  324. RRectF a(0, 0, 20, 10, 12, 2, 8, 4, 14, 6, 6, 8);
  325. RRectF b = RRectFBuilder()
  326. .set_origin(0, 0)
  327. .set_size(20, 10)
  328. .set_upper_left(48, 8)
  329. .set_upper_right(32, 16)
  330. .set_lower_right(56, 24)
  331. .set_lower_left(24, 32)
  332. .Build();
  333. EXPECT_EQ(a, b);
  334. }
  335. TEST(RRectFTest, BuildFromRectFWithCornersHigherThanSize) {
  336. RectF a(0, 0, 20, 10);
  337. RRectF b(a, 12, 2, 8, 4, 14, 6, 6, 8);
  338. RRectF c = RRectFBuilder()
  339. .set_rect(a)
  340. .set_upper_left(48, 8)
  341. .set_upper_right(32, 16)
  342. .set_lower_right(56, 24)
  343. .set_lower_left(24, 32)
  344. .Build();
  345. EXPECT_EQ(b, c);
  346. }
  347. // In this test, we set the radius first but then change the value of the
  348. // corners.
  349. TEST(RRectFTest, BuildFromRadiusAndCorners) {
  350. RRectF a(40, 50, 60, 70, 1, 2, 3, 4, 15, 25, 15, 25);
  351. RRectF b = RRectFBuilder()
  352. .set_origin(40, 50)
  353. .set_size(60, 70)
  354. .set_radius(15, 25)
  355. .set_upper_left(1, 2)
  356. .set_upper_right(3, 4)
  357. .Build();
  358. EXPECT_EQ(a, b);
  359. }
  360. } // namespace gfx