RoundRectTest.cpp 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029
  1. /*
  2. * Copyright 2012 Google Inc.
  3. *
  4. * Use of this source code is governed by a BSD-style license that can be
  5. * found in the LICENSE file.
  6. */
  7. #include "include/core/SkMatrix.h"
  8. #include "include/core/SkRRect.h"
  9. #include "src/core/SkPointPriv.h"
  10. #include "tests/Test.h"
  11. static void test_tricky_radii(skiatest::Reporter* reporter) {
  12. {
  13. // crbug.com/458522
  14. SkRRect rr;
  15. const SkRect bounds = { 3709, 3709, 3709 + 7402, 3709 + 29825 };
  16. const SkScalar rad = 12814;
  17. const SkVector vec[] = { { rad, rad }, { 0, rad }, { rad, rad }, { 0, rad } };
  18. rr.setRectRadii(bounds, vec);
  19. }
  20. {
  21. // crbug.com//463920
  22. SkRect r = SkRect::MakeLTRB(0, 0, 1009, 33554432.0);
  23. SkVector radii[4] = {
  24. { 13.0f, 8.0f }, { 170.0f, 2.0 }, { 256.0f, 33554432.0 }, { 110.0f, 5.0f }
  25. };
  26. SkRRect rr;
  27. rr.setRectRadii(r, radii);
  28. REPORTER_ASSERT(reporter, (double) rr.radii(SkRRect::kUpperRight_Corner).fY +
  29. (double) rr.radii(SkRRect::kLowerRight_Corner).fY <=
  30. rr.height());
  31. }
  32. }
  33. static void test_empty_crbug_458524(skiatest::Reporter* reporter) {
  34. SkRRect rr;
  35. const SkRect bounds = { 3709, 3709, 3709 + 7402, 3709 + 29825 };
  36. const SkScalar rad = 40;
  37. rr.setRectXY(bounds, rad, rad);
  38. SkRRect other;
  39. SkMatrix matrix;
  40. matrix.setScale(0, 1);
  41. rr.transform(matrix, &other);
  42. REPORTER_ASSERT(reporter, SkRRect::kEmpty_Type == other.getType());
  43. }
  44. // Test that all the SkRRect entry points correctly handle un-sorted and
  45. // zero-sized input rects
  46. static void test_empty(skiatest::Reporter* reporter) {
  47. static const SkRect oooRects[] = { // out of order
  48. { 100, 0, 0, 100 }, // ooo horizontal
  49. { 0, 100, 100, 0 }, // ooo vertical
  50. { 100, 100, 0, 0 }, // ooo both
  51. };
  52. static const SkRect emptyRects[] = {
  53. { 100, 100, 100, 200 }, // empty horizontal
  54. { 100, 100, 200, 100 }, // empty vertical
  55. { 100, 100, 100, 100 }, // empty both
  56. { 0, 0, 0, 0 } // setEmpty-empty
  57. };
  58. static const SkVector radii[4] = { { 0, 1 }, { 2, 3 }, { 4, 5 }, { 6, 7 } };
  59. SkRRect r;
  60. for (size_t i = 0; i < SK_ARRAY_COUNT(oooRects); ++i) {
  61. r.setRect(oooRects[i]);
  62. REPORTER_ASSERT(reporter, !r.isEmpty());
  63. REPORTER_ASSERT(reporter, r.rect() == oooRects[i].makeSorted());
  64. r.setOval(oooRects[i]);
  65. REPORTER_ASSERT(reporter, !r.isEmpty());
  66. REPORTER_ASSERT(reporter, r.rect() == oooRects[i].makeSorted());
  67. r.setRectXY(oooRects[i], 1, 2);
  68. REPORTER_ASSERT(reporter, !r.isEmpty());
  69. REPORTER_ASSERT(reporter, r.rect() == oooRects[i].makeSorted());
  70. r.setNinePatch(oooRects[i], 0, 1, 2, 3);
  71. REPORTER_ASSERT(reporter, !r.isEmpty());
  72. REPORTER_ASSERT(reporter, r.rect() == oooRects[i].makeSorted());
  73. r.setRectRadii(oooRects[i], radii);
  74. REPORTER_ASSERT(reporter, !r.isEmpty());
  75. REPORTER_ASSERT(reporter, r.rect() == oooRects[i].makeSorted());
  76. }
  77. for (size_t i = 0; i < SK_ARRAY_COUNT(emptyRects); ++i) {
  78. r.setRect(emptyRects[i]);
  79. REPORTER_ASSERT(reporter, r.isEmpty());
  80. REPORTER_ASSERT(reporter, r.rect() == emptyRects[i]);
  81. r.setOval(emptyRects[i]);
  82. REPORTER_ASSERT(reporter, r.isEmpty());
  83. REPORTER_ASSERT(reporter, r.rect() == emptyRects[i]);
  84. r.setRectXY(emptyRects[i], 1, 2);
  85. REPORTER_ASSERT(reporter, r.isEmpty());
  86. REPORTER_ASSERT(reporter, r.rect() == emptyRects[i]);
  87. r.setNinePatch(emptyRects[i], 0, 1, 2, 3);
  88. REPORTER_ASSERT(reporter, r.isEmpty());
  89. REPORTER_ASSERT(reporter, r.rect() == emptyRects[i]);
  90. r.setRectRadii(emptyRects[i], radii);
  91. REPORTER_ASSERT(reporter, r.isEmpty());
  92. REPORTER_ASSERT(reporter, r.rect() == emptyRects[i]);
  93. }
  94. r.setRect({SK_ScalarNaN, 10, 10, 20});
  95. REPORTER_ASSERT(reporter, r == SkRRect::MakeEmpty());
  96. r.setRect({0, 10, 10, SK_ScalarInfinity});
  97. REPORTER_ASSERT(reporter, r == SkRRect::MakeEmpty());
  98. }
  99. static const SkScalar kWidth = 100.0f;
  100. static const SkScalar kHeight = 100.0f;
  101. static void test_inset(skiatest::Reporter* reporter) {
  102. SkRRect rr, rr2;
  103. SkRect r = { 0, 0, 100, 100 };
  104. rr.setRect(r);
  105. rr.inset(-20, -20, &rr2);
  106. REPORTER_ASSERT(reporter, rr2.isRect());
  107. rr.inset(20, 20, &rr2);
  108. REPORTER_ASSERT(reporter, rr2.isRect());
  109. rr.inset(r.width()/2, r.height()/2, &rr2);
  110. REPORTER_ASSERT(reporter, rr2.isEmpty());
  111. rr.setRectXY(r, 20, 20);
  112. rr.inset(19, 19, &rr2);
  113. REPORTER_ASSERT(reporter, rr2.isSimple());
  114. rr.inset(20, 20, &rr2);
  115. REPORTER_ASSERT(reporter, rr2.isRect());
  116. }
  117. static void test_9patch_rrect(skiatest::Reporter* reporter,
  118. const SkRect& rect,
  119. SkScalar l, SkScalar t, SkScalar r, SkScalar b,
  120. bool checkRadii) {
  121. SkRRect rr;
  122. rr.setNinePatch(rect, l, t, r, b);
  123. REPORTER_ASSERT(reporter, SkRRect::kNinePatch_Type == rr.type());
  124. REPORTER_ASSERT(reporter, rr.rect() == rect);
  125. if (checkRadii) {
  126. // This test doesn't hold if the radii will be rescaled by SkRRect
  127. SkRect ninePatchRadii = { l, t, r, b };
  128. SkPoint rquad[4];
  129. ninePatchRadii.toQuad(rquad);
  130. for (int i = 0; i < 4; ++i) {
  131. REPORTER_ASSERT(reporter, rquad[i] == rr.radii((SkRRect::Corner) i));
  132. }
  133. }
  134. SkRRect rr2; // construct the same RR using the most general set function
  135. SkVector radii[4] = { { l, t }, { r, t }, { r, b }, { l, b } };
  136. rr2.setRectRadii(rect, radii);
  137. REPORTER_ASSERT(reporter, rr2 == rr && rr2.getType() == rr.getType());
  138. }
  139. // Test out the basic API entry points
  140. static void test_round_rect_basic(skiatest::Reporter* reporter) {
  141. // Test out initialization methods
  142. SkPoint zeroPt = { 0, 0 };
  143. SkRRect empty;
  144. empty.setEmpty();
  145. REPORTER_ASSERT(reporter, SkRRect::kEmpty_Type == empty.type());
  146. REPORTER_ASSERT(reporter, empty.rect().isEmpty());
  147. for (int i = 0; i < 4; ++i) {
  148. REPORTER_ASSERT(reporter, zeroPt == empty.radii((SkRRect::Corner) i));
  149. }
  150. //----
  151. SkRect rect = SkRect::MakeLTRB(0, 0, kWidth, kHeight);
  152. SkRRect rr1;
  153. rr1.setRect(rect);
  154. REPORTER_ASSERT(reporter, SkRRect::kRect_Type == rr1.type());
  155. REPORTER_ASSERT(reporter, rr1.rect() == rect);
  156. for (int i = 0; i < 4; ++i) {
  157. REPORTER_ASSERT(reporter, zeroPt == rr1.radii((SkRRect::Corner) i));
  158. }
  159. SkRRect rr1_2; // construct the same RR using the most general set function
  160. SkVector rr1_2_radii[4] = { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } };
  161. rr1_2.setRectRadii(rect, rr1_2_radii);
  162. REPORTER_ASSERT(reporter, rr1_2 == rr1 && rr1_2.getType() == rr1.getType());
  163. SkRRect rr1_3; // construct the same RR using the nine patch set function
  164. rr1_3.setNinePatch(rect, 0, 0, 0, 0);
  165. REPORTER_ASSERT(reporter, rr1_3 == rr1 && rr1_3.getType() == rr1.getType());
  166. //----
  167. SkPoint halfPoint = { SkScalarHalf(kWidth), SkScalarHalf(kHeight) };
  168. SkRRect rr2;
  169. rr2.setOval(rect);
  170. REPORTER_ASSERT(reporter, SkRRect::kOval_Type == rr2.type());
  171. REPORTER_ASSERT(reporter, rr2.rect() == rect);
  172. for (int i = 0; i < 4; ++i) {
  173. REPORTER_ASSERT(reporter,
  174. SkPointPriv::EqualsWithinTolerance(rr2.radii((SkRRect::Corner) i),
  175. halfPoint));
  176. }
  177. SkRRect rr2_2; // construct the same RR using the most general set function
  178. SkVector rr2_2_radii[4] = { { halfPoint.fX, halfPoint.fY }, { halfPoint.fX, halfPoint.fY },
  179. { halfPoint.fX, halfPoint.fY }, { halfPoint.fX, halfPoint.fY } };
  180. rr2_2.setRectRadii(rect, rr2_2_radii);
  181. REPORTER_ASSERT(reporter, rr2_2 == rr2 && rr2_2.getType() == rr2.getType());
  182. SkRRect rr2_3; // construct the same RR using the nine patch set function
  183. rr2_3.setNinePatch(rect, halfPoint.fX, halfPoint.fY, halfPoint.fX, halfPoint.fY);
  184. REPORTER_ASSERT(reporter, rr2_3 == rr2 && rr2_3.getType() == rr2.getType());
  185. //----
  186. SkPoint p = { 5, 5 };
  187. SkRRect rr3;
  188. rr3.setRectXY(rect, p.fX, p.fY);
  189. REPORTER_ASSERT(reporter, SkRRect::kSimple_Type == rr3.type());
  190. REPORTER_ASSERT(reporter, rr3.rect() == rect);
  191. for (int i = 0; i < 4; ++i) {
  192. REPORTER_ASSERT(reporter, p == rr3.radii((SkRRect::Corner) i));
  193. }
  194. SkRRect rr3_2; // construct the same RR using the most general set function
  195. SkVector rr3_2_radii[4] = { { 5, 5 }, { 5, 5 }, { 5, 5 }, { 5, 5 } };
  196. rr3_2.setRectRadii(rect, rr3_2_radii);
  197. REPORTER_ASSERT(reporter, rr3_2 == rr3 && rr3_2.getType() == rr3.getType());
  198. SkRRect rr3_3; // construct the same RR using the nine patch set function
  199. rr3_3.setNinePatch(rect, 5, 5, 5, 5);
  200. REPORTER_ASSERT(reporter, rr3_3 == rr3 && rr3_3.getType() == rr3.getType());
  201. //----
  202. test_9patch_rrect(reporter, rect, 10, 9, 8, 7, true);
  203. {
  204. // Test out the rrect from skia:3466
  205. SkRect rect2 = SkRect::MakeLTRB(0.358211994f, 0.755430222f, 0.872866154f, 0.806214333f);
  206. test_9patch_rrect(reporter,
  207. rect2,
  208. 0.926942348f, 0.642850280f, 0.529063463f, 0.587844372f,
  209. false);
  210. }
  211. //----
  212. SkPoint radii2[4] = { { 0, 0 }, { 0, 0 }, { 50, 50 }, { 20, 50 } };
  213. SkRRect rr5;
  214. rr5.setRectRadii(rect, radii2);
  215. REPORTER_ASSERT(reporter, SkRRect::kComplex_Type == rr5.type());
  216. REPORTER_ASSERT(reporter, rr5.rect() == rect);
  217. for (int i = 0; i < 4; ++i) {
  218. REPORTER_ASSERT(reporter, radii2[i] == rr5.radii((SkRRect::Corner) i));
  219. }
  220. // Test out == & !=
  221. REPORTER_ASSERT(reporter, empty != rr3);
  222. REPORTER_ASSERT(reporter, rr3 != rr5);
  223. }
  224. // Test out the cases when the RR degenerates to a rect
  225. static void test_round_rect_rects(skiatest::Reporter* reporter) {
  226. SkRect r;
  227. //----
  228. SkRRect empty;
  229. empty.setEmpty();
  230. REPORTER_ASSERT(reporter, SkRRect::kEmpty_Type == empty.type());
  231. r = empty.rect();
  232. REPORTER_ASSERT(reporter, 0 == r.fLeft && 0 == r.fTop && 0 == r.fRight && 0 == r.fBottom);
  233. //----
  234. SkRect rect = SkRect::MakeLTRB(0, 0, kWidth, kHeight);
  235. SkRRect rr1;
  236. rr1.setRectXY(rect, 0, 0);
  237. REPORTER_ASSERT(reporter, SkRRect::kRect_Type == rr1.type());
  238. r = rr1.rect();
  239. REPORTER_ASSERT(reporter, rect == r);
  240. //----
  241. SkPoint radii[4] = { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } };
  242. SkRRect rr2;
  243. rr2.setRectRadii(rect, radii);
  244. REPORTER_ASSERT(reporter, SkRRect::kRect_Type == rr2.type());
  245. r = rr2.rect();
  246. REPORTER_ASSERT(reporter, rect == r);
  247. //----
  248. SkPoint radii2[4] = { { 0, 0 }, { 20, 20 }, { 50, 50 }, { 20, 50 } };
  249. SkRRect rr3;
  250. rr3.setRectRadii(rect, radii2);
  251. REPORTER_ASSERT(reporter, SkRRect::kComplex_Type == rr3.type());
  252. }
  253. // Test out the cases when the RR degenerates to an oval
  254. static void test_round_rect_ovals(skiatest::Reporter* reporter) {
  255. //----
  256. SkRect oval;
  257. SkRect rect = SkRect::MakeLTRB(0, 0, kWidth, kHeight);
  258. SkRRect rr1;
  259. rr1.setRectXY(rect, SkScalarHalf(kWidth), SkScalarHalf(kHeight));
  260. REPORTER_ASSERT(reporter, SkRRect::kOval_Type == rr1.type());
  261. oval = rr1.rect();
  262. REPORTER_ASSERT(reporter, oval == rect);
  263. }
  264. // Test out the non-degenerate RR cases
  265. static void test_round_rect_general(skiatest::Reporter* reporter) {
  266. //----
  267. SkRect rect = SkRect::MakeLTRB(0, 0, kWidth, kHeight);
  268. SkRRect rr1;
  269. rr1.setRectXY(rect, 20, 20);
  270. REPORTER_ASSERT(reporter, SkRRect::kSimple_Type == rr1.type());
  271. //----
  272. SkPoint radii[4] = { { 0, 0 }, { 20, 20 }, { 50, 50 }, { 20, 50 } };
  273. SkRRect rr2;
  274. rr2.setRectRadii(rect, radii);
  275. REPORTER_ASSERT(reporter, SkRRect::kComplex_Type == rr2.type());
  276. }
  277. // Test out questionable-parameter handling
  278. static void test_round_rect_iffy_parameters(skiatest::Reporter* reporter) {
  279. // When the radii exceed the base rect they are proportionally scaled down
  280. // to fit
  281. SkRect rect = SkRect::MakeLTRB(0, 0, kWidth, kHeight);
  282. SkPoint radii[4] = { { 50, 100 }, { 100, 50 }, { 50, 100 }, { 100, 50 } };
  283. SkRRect rr1;
  284. rr1.setRectRadii(rect, radii);
  285. REPORTER_ASSERT(reporter, SkRRect::kComplex_Type == rr1.type());
  286. const SkPoint& p = rr1.radii(SkRRect::kUpperLeft_Corner);
  287. REPORTER_ASSERT(reporter, SkScalarNearlyEqual(p.fX, 33.33333f));
  288. REPORTER_ASSERT(reporter, SkScalarNearlyEqual(p.fY, 66.66666f));
  289. // Negative radii should be capped at zero
  290. SkRRect rr2;
  291. rr2.setRectXY(rect, -10, -20);
  292. REPORTER_ASSERT(reporter, SkRRect::kRect_Type == rr2.type());
  293. const SkPoint& p2 = rr2.radii(SkRRect::kUpperLeft_Corner);
  294. REPORTER_ASSERT(reporter, 0.0f == p2.fX);
  295. REPORTER_ASSERT(reporter, 0.0f == p2.fY);
  296. }
  297. // Move a small box from the start position by (stepX, stepY) 'numSteps' times
  298. // testing for containment in 'rr' at each step.
  299. static void test_direction(skiatest::Reporter* reporter, const SkRRect &rr,
  300. SkScalar initX, int stepX, SkScalar initY, int stepY,
  301. int numSteps, const bool* contains) {
  302. SkScalar x = initX, y = initY;
  303. for (int i = 0; i < numSteps; ++i) {
  304. SkRect test = SkRect::MakeXYWH(x, y,
  305. stepX ? SkIntToScalar(stepX) : SK_Scalar1,
  306. stepY ? SkIntToScalar(stepY) : SK_Scalar1);
  307. test.sort();
  308. REPORTER_ASSERT(reporter, contains[i] == rr.contains(test));
  309. x += stepX;
  310. y += stepY;
  311. }
  312. }
  313. // Exercise the RR's contains rect method
  314. static void test_round_rect_contains_rect(skiatest::Reporter* reporter) {
  315. static const int kNumRRects = 4;
  316. static const SkVector gRadii[kNumRRects][4] = {
  317. { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, // rect
  318. { { 20, 20 }, { 20, 20 }, { 20, 20 }, { 20, 20 } }, // circle
  319. { { 10, 10 }, { 10, 10 }, { 10, 10 }, { 10, 10 } }, // simple
  320. { { 0, 0 }, { 20, 20 }, { 10, 10 }, { 30, 30 } } // complex
  321. };
  322. SkRRect rrects[kNumRRects];
  323. for (int i = 0; i < kNumRRects; ++i) {
  324. rrects[i].setRectRadii(SkRect::MakeWH(40, 40), gRadii[i]);
  325. }
  326. // First test easy outs - boxes that are obviously out on
  327. // each corner and edge
  328. static const SkRect easyOuts[] = {
  329. { -5, -5, 5, 5 }, // NW
  330. { 15, -5, 20, 5 }, // N
  331. { 35, -5, 45, 5 }, // NE
  332. { 35, 15, 45, 20 }, // E
  333. { 35, 45, 35, 45 }, // SE
  334. { 15, 35, 20, 45 }, // S
  335. { -5, 35, 5, 45 }, // SW
  336. { -5, 15, 5, 20 } // W
  337. };
  338. for (int i = 0; i < kNumRRects; ++i) {
  339. for (size_t j = 0; j < SK_ARRAY_COUNT(easyOuts); ++j) {
  340. REPORTER_ASSERT(reporter, !rrects[i].contains(easyOuts[j]));
  341. }
  342. }
  343. // Now test non-trivial containment. For each compass
  344. // point walk a 1x1 rect in from the edge of the bounding
  345. // rect
  346. static const int kNumSteps = 15;
  347. bool answers[kNumRRects][8][kNumSteps] = {
  348. // all the test rects are inside the degenerate rrect
  349. {
  350. // rect
  351. { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
  352. { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
  353. { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
  354. { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
  355. { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
  356. { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
  357. { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
  358. { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
  359. },
  360. // for the circle we expect 6 blocks to be out on the
  361. // corners (then the rest in) and only the first block
  362. // out on the vertical and horizontal axes (then
  363. // the rest in)
  364. {
  365. // circle
  366. { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
  367. { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
  368. { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
  369. { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
  370. { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
  371. { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
  372. { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
  373. { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
  374. },
  375. // for the simple round rect we expect 3 out on
  376. // the corners (then the rest in) and no blocks out
  377. // on the vertical and horizontal axes
  378. {
  379. // simple RR
  380. { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
  381. { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
  382. { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
  383. { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
  384. { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
  385. { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
  386. { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
  387. { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
  388. },
  389. // for the complex case the answer is different for each direction
  390. {
  391. // complex RR
  392. // all in for NW (rect) corner (same as rect case)
  393. { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
  394. // only first block out for N (same as circle case)
  395. { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
  396. // first 6 blocks out for NE (same as circle case)
  397. { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
  398. // only first block out for E (same as circle case)
  399. { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
  400. // first 3 blocks out for SE (same as simple case)
  401. { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
  402. // first two blocks out for S
  403. { 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
  404. // first 9 blocks out for SW
  405. { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1 },
  406. // first two blocks out for W (same as S)
  407. { 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
  408. }
  409. };
  410. for (int i = 0; i < kNumRRects; ++i) {
  411. test_direction(reporter, rrects[i], 0, 1, 0, 1, kNumSteps, answers[i][0]); // NW
  412. test_direction(reporter, rrects[i], 19.5f, 0, 0, 1, kNumSteps, answers[i][1]); // N
  413. test_direction(reporter, rrects[i], 40, -1, 0, 1, kNumSteps, answers[i][2]); // NE
  414. test_direction(reporter, rrects[i], 40, -1, 19.5f, 0, kNumSteps, answers[i][3]); // E
  415. test_direction(reporter, rrects[i], 40, -1, 40, -1, kNumSteps, answers[i][4]); // SE
  416. test_direction(reporter, rrects[i], 19.5f, 0, 40, -1, kNumSteps, answers[i][5]); // S
  417. test_direction(reporter, rrects[i], 0, 1, 40, -1, kNumSteps, answers[i][6]); // SW
  418. test_direction(reporter, rrects[i], 0, 1, 19.5f, 0, kNumSteps, answers[i][7]); // W
  419. }
  420. }
  421. // Called for a matrix that should cause SkRRect::transform to fail.
  422. static void assert_transform_failure(skiatest::Reporter* reporter, const SkRRect& orig,
  423. const SkMatrix& matrix) {
  424. // The test depends on the fact that the original is not empty.
  425. SkASSERT(!orig.isEmpty());
  426. SkRRect dst;
  427. dst.setEmpty();
  428. const SkRRect copyOfDst = dst;
  429. const SkRRect copyOfOrig = orig;
  430. bool success = orig.transform(matrix, &dst);
  431. // This transform should fail.
  432. REPORTER_ASSERT(reporter, !success);
  433. // Since the transform failed, dst should be unchanged.
  434. REPORTER_ASSERT(reporter, copyOfDst == dst);
  435. // original should not be modified.
  436. REPORTER_ASSERT(reporter, copyOfOrig == orig);
  437. REPORTER_ASSERT(reporter, orig != dst);
  438. }
  439. #define GET_RADII \
  440. const SkVector& origUL = orig.radii(SkRRect::kUpperLeft_Corner); \
  441. const SkVector& origUR = orig.radii(SkRRect::kUpperRight_Corner); \
  442. const SkVector& origLR = orig.radii(SkRRect::kLowerRight_Corner); \
  443. const SkVector& origLL = orig.radii(SkRRect::kLowerLeft_Corner); \
  444. const SkVector& dstUL = dst.radii(SkRRect::kUpperLeft_Corner); \
  445. const SkVector& dstUR = dst.radii(SkRRect::kUpperRight_Corner); \
  446. const SkVector& dstLR = dst.radii(SkRRect::kLowerRight_Corner); \
  447. const SkVector& dstLL = dst.radii(SkRRect::kLowerLeft_Corner)
  448. // Called to test various transforms on a single SkRRect.
  449. static void test_transform_helper(skiatest::Reporter* reporter, const SkRRect& orig) {
  450. SkRRect dst;
  451. dst.setEmpty();
  452. // The identity matrix will duplicate the rrect.
  453. bool success = orig.transform(SkMatrix::I(), &dst);
  454. REPORTER_ASSERT(reporter, success);
  455. REPORTER_ASSERT(reporter, orig == dst);
  456. // Skew and Perspective make transform fail.
  457. SkMatrix matrix;
  458. matrix.reset();
  459. matrix.setSkewX(SkIntToScalar(2));
  460. assert_transform_failure(reporter, orig, matrix);
  461. matrix.reset();
  462. matrix.setSkewY(SkIntToScalar(3));
  463. assert_transform_failure(reporter, orig, matrix);
  464. matrix.reset();
  465. matrix.setPerspX(4);
  466. assert_transform_failure(reporter, orig, matrix);
  467. matrix.reset();
  468. matrix.setPerspY(5);
  469. assert_transform_failure(reporter, orig, matrix);
  470. // Rotation fails.
  471. matrix.reset();
  472. matrix.setRotate(SkIntToScalar(37));
  473. assert_transform_failure(reporter, orig, matrix);
  474. // Translate will keep the rect moved, but otherwise the same.
  475. matrix.reset();
  476. SkScalar translateX = SkIntToScalar(32);
  477. SkScalar translateY = SkIntToScalar(15);
  478. matrix.setTranslateX(translateX);
  479. matrix.setTranslateY(translateY);
  480. dst.setEmpty();
  481. success = orig.transform(matrix, &dst);
  482. REPORTER_ASSERT(reporter, success);
  483. for (int i = 0; i < 4; ++i) {
  484. REPORTER_ASSERT(reporter,
  485. orig.radii((SkRRect::Corner) i) == dst.radii((SkRRect::Corner) i));
  486. }
  487. REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().width());
  488. REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().height());
  489. REPORTER_ASSERT(reporter, dst.rect().left() == orig.rect().left() + translateX);
  490. REPORTER_ASSERT(reporter, dst.rect().top() == orig.rect().top() + translateY);
  491. // Keeping the translation, but adding skew will make transform fail.
  492. matrix.setSkewY(SkIntToScalar(7));
  493. assert_transform_failure(reporter, orig, matrix);
  494. // Scaling in -x will flip the round rect horizontally.
  495. matrix.reset();
  496. matrix.setScaleX(SkIntToScalar(-1));
  497. dst.setEmpty();
  498. success = orig.transform(matrix, &dst);
  499. REPORTER_ASSERT(reporter, success);
  500. {
  501. GET_RADII;
  502. // Radii have swapped in x.
  503. REPORTER_ASSERT(reporter, origUL == dstUR);
  504. REPORTER_ASSERT(reporter, origUR == dstUL);
  505. REPORTER_ASSERT(reporter, origLR == dstLL);
  506. REPORTER_ASSERT(reporter, origLL == dstLR);
  507. }
  508. // Width and height remain the same.
  509. REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().width());
  510. REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().height());
  511. // Right and left have swapped (sort of)
  512. REPORTER_ASSERT(reporter, orig.rect().right() == -dst.rect().left());
  513. // Top has stayed the same.
  514. REPORTER_ASSERT(reporter, orig.rect().top() == dst.rect().top());
  515. // Keeping the scale, but adding a persp will make transform fail.
  516. matrix.setPerspX(7);
  517. assert_transform_failure(reporter, orig, matrix);
  518. // Scaling in -y will flip the round rect vertically.
  519. matrix.reset();
  520. matrix.setScaleY(SkIntToScalar(-1));
  521. dst.setEmpty();
  522. success = orig.transform(matrix, &dst);
  523. REPORTER_ASSERT(reporter, success);
  524. {
  525. GET_RADII;
  526. // Radii have swapped in y.
  527. REPORTER_ASSERT(reporter, origUL == dstLL);
  528. REPORTER_ASSERT(reporter, origUR == dstLR);
  529. REPORTER_ASSERT(reporter, origLR == dstUR);
  530. REPORTER_ASSERT(reporter, origLL == dstUL);
  531. }
  532. // Width and height remain the same.
  533. REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().width());
  534. REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().height());
  535. // Top and bottom have swapped (sort of)
  536. REPORTER_ASSERT(reporter, orig.rect().top() == -dst.rect().bottom());
  537. // Left has stayed the same.
  538. REPORTER_ASSERT(reporter, orig.rect().left() == dst.rect().left());
  539. // Scaling in -x and -y will swap in both directions.
  540. matrix.reset();
  541. matrix.setScaleY(SkIntToScalar(-1));
  542. matrix.setScaleX(SkIntToScalar(-1));
  543. dst.setEmpty();
  544. success = orig.transform(matrix, &dst);
  545. REPORTER_ASSERT(reporter, success);
  546. {
  547. GET_RADII;
  548. REPORTER_ASSERT(reporter, origUL == dstLR);
  549. REPORTER_ASSERT(reporter, origUR == dstLL);
  550. REPORTER_ASSERT(reporter, origLR == dstUL);
  551. REPORTER_ASSERT(reporter, origLL == dstUR);
  552. }
  553. // Width and height remain the same.
  554. REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().width());
  555. REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().height());
  556. REPORTER_ASSERT(reporter, orig.rect().top() == -dst.rect().bottom());
  557. REPORTER_ASSERT(reporter, orig.rect().right() == -dst.rect().left());
  558. // Scale in both directions.
  559. SkScalar xScale = SkIntToScalar(3);
  560. SkScalar yScale = 3.2f;
  561. matrix.reset();
  562. matrix.setScaleX(xScale);
  563. matrix.setScaleY(yScale);
  564. dst.setEmpty();
  565. success = orig.transform(matrix, &dst);
  566. REPORTER_ASSERT(reporter, success);
  567. // Radii are scaled.
  568. for (int i = 0; i < 4; ++i) {
  569. REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.radii((SkRRect::Corner) i).fX,
  570. orig.radii((SkRRect::Corner) i).fX * xScale));
  571. REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.radii((SkRRect::Corner) i).fY,
  572. orig.radii((SkRRect::Corner) i).fY * yScale));
  573. }
  574. REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.rect().width(),
  575. orig.rect().width() * xScale));
  576. REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.rect().height(),
  577. orig.rect().height() * yScale));
  578. REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.rect().left(),
  579. orig.rect().left() * xScale));
  580. REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.rect().top(),
  581. orig.rect().top() * yScale));
  582. // a-----b d-----a
  583. // | | -> | |
  584. // | | Rotate 90 | |
  585. // d-----c c-----b
  586. matrix.reset();
  587. matrix.setRotate(SkIntToScalar(90));
  588. dst.setEmpty();
  589. success = orig.transform(matrix, &dst);
  590. REPORTER_ASSERT(reporter, success);
  591. {
  592. GET_RADII;
  593. // Radii have cycled clockwise and swapped their x and y axis.
  594. REPORTER_ASSERT(reporter, dstUL.x() == origLL.y());
  595. REPORTER_ASSERT(reporter, dstUL.y() == origLL.x());
  596. REPORTER_ASSERT(reporter, dstUR.x() == origUL.y());
  597. REPORTER_ASSERT(reporter, dstUR.y() == origUL.x());
  598. REPORTER_ASSERT(reporter, dstLR.x() == origUR.y());
  599. REPORTER_ASSERT(reporter, dstLR.y() == origUR.x());
  600. REPORTER_ASSERT(reporter, dstLL.x() == origLR.y());
  601. REPORTER_ASSERT(reporter, dstLL.y() == origLR.x());
  602. }
  603. // Width and height would get swapped.
  604. REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().height());
  605. REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().width());
  606. // a-----b b-----a c-----b
  607. // | | -> | | -> | |
  608. // | | Flip X | | Rotate 90 | |
  609. // d-----c c-----d d-----a
  610. matrix.reset();
  611. matrix.setRotate(SkIntToScalar(90));
  612. matrix.postScale(SkIntToScalar(-1), SkIntToScalar(1));
  613. dst.setEmpty();
  614. success = orig.transform(matrix, &dst);
  615. REPORTER_ASSERT(reporter, success);
  616. {
  617. GET_RADII;
  618. REPORTER_ASSERT(reporter, dstUL.x() == origLR.y());
  619. REPORTER_ASSERT(reporter, dstUL.y() == origLR.x());
  620. REPORTER_ASSERT(reporter, dstUR.x() == origUR.y());
  621. REPORTER_ASSERT(reporter, dstUR.y() == origUR.x());
  622. REPORTER_ASSERT(reporter, dstLR.x() == origUL.y());
  623. REPORTER_ASSERT(reporter, dstLR.y() == origUL.x());
  624. REPORTER_ASSERT(reporter, dstLL.x() == origLL.y());
  625. REPORTER_ASSERT(reporter, dstLL.y() == origLL.x());
  626. }
  627. // Width and height would get swapped.
  628. REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().height());
  629. REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().width());
  630. // a-----b d-----a c-----b
  631. // | | -> | | -> | |
  632. // | | Rotate 90 | | Flip Y | |
  633. // d-----c c-----b d-----a
  634. //
  635. // This is the same as Flip X and Rotate 90.
  636. matrix.reset();
  637. matrix.setScale(SkIntToScalar(1), SkIntToScalar(-1));
  638. matrix.postRotate(SkIntToScalar(90));
  639. SkRRect dst2;
  640. dst2.setEmpty();
  641. success = orig.transform(matrix, &dst2);
  642. REPORTER_ASSERT(reporter, success);
  643. REPORTER_ASSERT(reporter, dst == dst2);
  644. // a-----b b-----c c-----b
  645. // | | -> | | -> | |
  646. // | | Rotate 270 | | Flip X | |
  647. // d-----c a-----d d-----a
  648. matrix.reset();
  649. matrix.setScale(SkIntToScalar(-1), SkIntToScalar(1));
  650. matrix.postRotate(SkIntToScalar(270));
  651. dst2.setEmpty();
  652. success = orig.transform(matrix, &dst2);
  653. REPORTER_ASSERT(reporter, success);
  654. REPORTER_ASSERT(reporter, dst == dst2);
  655. // a-----b d-----c c-----b
  656. // | | -> | | -> | |
  657. // | | Flip Y | | Rotate 270 | |
  658. // d-----c a-----b d-----a
  659. matrix.reset();
  660. matrix.setRotate(SkIntToScalar(270));
  661. matrix.postScale(SkIntToScalar(1), SkIntToScalar(-1));
  662. dst2.setEmpty();
  663. success = orig.transform(matrix, &dst2);
  664. REPORTER_ASSERT(reporter, success);
  665. REPORTER_ASSERT(reporter, dst == dst2);
  666. // a-----b d-----a a-----d
  667. // | | -> | | -> | |
  668. // | | Rotate 90 | | Flip X | |
  669. // d-----c c-----b b-----c
  670. matrix.reset();
  671. matrix.setScale(SkIntToScalar(-1), SkIntToScalar(1));
  672. matrix.postRotate(SkIntToScalar(90));
  673. dst.setEmpty();
  674. success = orig.transform(matrix, &dst);
  675. REPORTER_ASSERT(reporter, success);
  676. {
  677. GET_RADII;
  678. REPORTER_ASSERT(reporter, dstUL.x() == origUL.y());
  679. REPORTER_ASSERT(reporter, dstUL.y() == origUL.x());
  680. REPORTER_ASSERT(reporter, dstUR.x() == origLL.y());
  681. REPORTER_ASSERT(reporter, dstUR.y() == origLL.x());
  682. REPORTER_ASSERT(reporter, dstLR.x() == origLR.y());
  683. REPORTER_ASSERT(reporter, dstLR.y() == origLR.x());
  684. REPORTER_ASSERT(reporter, dstLL.x() == origUR.y());
  685. REPORTER_ASSERT(reporter, dstLL.y() == origUR.x());
  686. }
  687. // Width and height would get swapped.
  688. REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().height());
  689. REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().width());
  690. // a-----b d-----c a-----d
  691. // | | -> | | -> | |
  692. // | | Flip Y | | Rotate 90 | |
  693. // d-----c a-----b b-----c
  694. // This is the same as rotate 90 and flip x.
  695. matrix.reset();
  696. matrix.setRotate(SkIntToScalar(90));
  697. matrix.postScale(SkIntToScalar(1), SkIntToScalar(-1));
  698. dst2.setEmpty();
  699. success = orig.transform(matrix, &dst2);
  700. REPORTER_ASSERT(reporter, success);
  701. REPORTER_ASSERT(reporter, dst == dst2);
  702. // a-----b b-----a a-----d
  703. // | | -> | | -> | |
  704. // | | Flip X | | Rotate 270 | |
  705. // d-----c c-----d b-----c
  706. matrix.reset();
  707. matrix.setRotate(SkIntToScalar(270));
  708. matrix.postScale(SkIntToScalar(-1), SkIntToScalar(1));
  709. dst2.setEmpty();
  710. success = orig.transform(matrix, &dst2);
  711. REPORTER_ASSERT(reporter, success);
  712. REPORTER_ASSERT(reporter, dst == dst2);
  713. // a-----b b-----c a-----d
  714. // | | -> | | -> | |
  715. // | | Rotate 270 | | Flip Y | |
  716. // d-----c a-----d b-----c
  717. matrix.reset();
  718. matrix.setScale(SkIntToScalar(1), SkIntToScalar(-1));
  719. matrix.postRotate(SkIntToScalar(270));
  720. dst2.setEmpty();
  721. success = orig.transform(matrix, &dst2);
  722. REPORTER_ASSERT(reporter, success);
  723. REPORTER_ASSERT(reporter, dst == dst2);
  724. // a-----b b-----a c-----d b-----c
  725. // | | -> | | -> | | -> | |
  726. // | | Flip X | | Flip Y | | Rotate 90 | |
  727. // d-----c c-----d b-----a a-----d
  728. //
  729. // This is the same as rotation by 270.
  730. matrix.reset();
  731. matrix.setRotate(SkIntToScalar(90));
  732. matrix.postScale(SkIntToScalar(-1), SkIntToScalar(-1));
  733. dst.setEmpty();
  734. success = orig.transform(matrix, &dst);
  735. REPORTER_ASSERT(reporter, success);
  736. {
  737. GET_RADII;
  738. // Radii have cycled clockwise and swapped their x and y axis.
  739. REPORTER_ASSERT(reporter, dstUL.x() == origUR.y());
  740. REPORTER_ASSERT(reporter, dstUL.y() == origUR.x());
  741. REPORTER_ASSERT(reporter, dstUR.x() == origLR.y());
  742. REPORTER_ASSERT(reporter, dstUR.y() == origLR.x());
  743. REPORTER_ASSERT(reporter, dstLR.x() == origLL.y());
  744. REPORTER_ASSERT(reporter, dstLR.y() == origLL.x());
  745. REPORTER_ASSERT(reporter, dstLL.x() == origUL.y());
  746. REPORTER_ASSERT(reporter, dstLL.y() == origUL.x());
  747. }
  748. // Width and height would get swapped.
  749. REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().height());
  750. REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().width());
  751. // a-----b b-----c
  752. // | | -> | |
  753. // | | Rotate 270 | |
  754. // d-----c a-----d
  755. //
  756. dst2.setEmpty();
  757. matrix.reset();
  758. matrix.setRotate(SkIntToScalar(270));
  759. success = orig.transform(matrix, &dst2);
  760. REPORTER_ASSERT(reporter, success);
  761. REPORTER_ASSERT(reporter, dst == dst2);
  762. // a-----b b-----a c-----d d-----a
  763. // | | -> | | -> | | -> | |
  764. // | | Flip X | | Flip Y | | Rotate 270 | |
  765. // d-----c c-----d b-----a c-----b
  766. //
  767. // This is the same as rotation by 90 degrees.
  768. matrix.reset();
  769. matrix.setRotate(SkIntToScalar(270));
  770. matrix.postScale(SkIntToScalar(-1), SkIntToScalar(-1));
  771. dst.setEmpty();
  772. success = orig.transform(matrix, &dst);
  773. REPORTER_ASSERT(reporter, success);
  774. matrix.reset();
  775. matrix.setRotate(SkIntToScalar(90));
  776. dst2.setEmpty();
  777. success = orig.transform(matrix, &dst2);
  778. REPORTER_ASSERT(reporter, dst == dst2);
  779. }
  780. static void test_round_rect_transform(skiatest::Reporter* reporter) {
  781. SkRRect rrect;
  782. {
  783. SkRect r = { 0, 0, kWidth, kHeight };
  784. rrect.setRectXY(r, SkIntToScalar(4), SkIntToScalar(7));
  785. test_transform_helper(reporter, rrect);
  786. }
  787. {
  788. SkRect r = { SkIntToScalar(5), SkIntToScalar(15),
  789. SkIntToScalar(27), SkIntToScalar(34) };
  790. SkVector radii[4] = { { 0, SkIntToScalar(1) },
  791. { SkIntToScalar(2), SkIntToScalar(3) },
  792. { SkIntToScalar(4), SkIntToScalar(5) },
  793. { SkIntToScalar(6), SkIntToScalar(7) } };
  794. rrect.setRectRadii(r, radii);
  795. test_transform_helper(reporter, rrect);
  796. }
  797. }
  798. // Test out the case where an oval already off in space is translated/scaled
  799. // further off into space - yielding numerical issues when the rect & radii
  800. // are transformed separatly
  801. // BUG=skia:2696
  802. static void test_issue_2696(skiatest::Reporter* reporter) {
  803. SkRRect rrect;
  804. SkRect r = { 28443.8594f, 53.1428604f, 28446.7148f, 56.0000038f };
  805. rrect.setOval(r);
  806. SkMatrix xform;
  807. xform.setAll(2.44f, 0.0f, 485411.7f,
  808. 0.0f, 2.44f, -438.7f,
  809. 0.0f, 0.0f, 1.0f);
  810. SkRRect dst;
  811. bool success = rrect.transform(xform, &dst);
  812. REPORTER_ASSERT(reporter, success);
  813. SkScalar halfWidth = SkScalarHalf(dst.width());
  814. SkScalar halfHeight = SkScalarHalf(dst.height());
  815. for (int i = 0; i < 4; ++i) {
  816. REPORTER_ASSERT(reporter,
  817. SkScalarNearlyEqual(dst.radii((SkRRect::Corner)i).fX, halfWidth));
  818. REPORTER_ASSERT(reporter,
  819. SkScalarNearlyEqual(dst.radii((SkRRect::Corner)i).fY, halfHeight));
  820. }
  821. }
  822. void test_read_rrect(skiatest::Reporter* reporter, const SkRRect& rrect, bool shouldEqualSrc) {
  823. // It would be cleaner to call rrect.writeToMemory into a buffer. However, writeToMemory asserts
  824. // that the rrect is valid and our caller may have fiddled with the internals of rrect to make
  825. // it invalid.
  826. const void* buffer = reinterpret_cast<const void*>(&rrect);
  827. SkRRect deserialized;
  828. size_t size = deserialized.readFromMemory(buffer, sizeof(SkRRect));
  829. REPORTER_ASSERT(reporter, size == SkRRect::kSizeInMemory);
  830. REPORTER_ASSERT(reporter, deserialized.isValid());
  831. if (shouldEqualSrc) {
  832. REPORTER_ASSERT(reporter, rrect == deserialized);
  833. }
  834. }
  835. static void test_read(skiatest::Reporter* reporter) {
  836. static const SkRect kRect = {10.f, 10.f, 20.f, 20.f};
  837. static const SkRect kNaNRect = {10.f, 10.f, 20.f, SK_ScalarNaN};
  838. static const SkRect kInfRect = {10.f, 10.f, SK_ScalarInfinity, 20.f};
  839. SkRRect rrect;
  840. test_read_rrect(reporter, SkRRect::MakeEmpty(), true);
  841. test_read_rrect(reporter, SkRRect::MakeRect(kRect), true);
  842. // These get coerced to empty.
  843. test_read_rrect(reporter, SkRRect::MakeRect(kInfRect), true);
  844. test_read_rrect(reporter, SkRRect::MakeRect(kNaNRect), true);
  845. rrect.setRect(kRect);
  846. SkRect* innerRect = reinterpret_cast<SkRect*>(&rrect);
  847. SkASSERT(*innerRect == kRect);
  848. *innerRect = kInfRect;
  849. test_read_rrect(reporter, rrect, false);
  850. *innerRect = kNaNRect;
  851. test_read_rrect(reporter, rrect, false);
  852. test_read_rrect(reporter, SkRRect::MakeOval(kRect), true);
  853. test_read_rrect(reporter, SkRRect::MakeOval(kInfRect), true);
  854. test_read_rrect(reporter, SkRRect::MakeOval(kNaNRect), true);
  855. rrect.setOval(kRect);
  856. *innerRect = kInfRect;
  857. test_read_rrect(reporter, rrect, false);
  858. *innerRect = kNaNRect;
  859. test_read_rrect(reporter, rrect, false);
  860. test_read_rrect(reporter, SkRRect::MakeRectXY(kRect, 5.f, 5.f), true);
  861. // rrect should scale down the radii to make this legal
  862. test_read_rrect(reporter, SkRRect::MakeRectXY(kRect, 5.f, 400.f), true);
  863. static const SkVector kRadii[4] = {{0.5f, 1.f}, {1.5f, 2.f}, {2.5f, 3.f}, {3.5f, 4.f}};
  864. rrect.setRectRadii(kRect, kRadii);
  865. test_read_rrect(reporter, rrect, true);
  866. SkScalar* innerRadius = reinterpret_cast<SkScalar*>(&rrect) + 6;
  867. SkASSERT(*innerRadius == 1.5f);
  868. *innerRadius = 400.f;
  869. test_read_rrect(reporter, rrect, false);
  870. *innerRadius = SK_ScalarInfinity;
  871. test_read_rrect(reporter, rrect, false);
  872. *innerRadius = SK_ScalarNaN;
  873. test_read_rrect(reporter, rrect, false);
  874. *innerRadius = -10.f;
  875. test_read_rrect(reporter, rrect, false);
  876. }
  877. DEF_TEST(RoundRect, reporter) {
  878. test_round_rect_basic(reporter);
  879. test_round_rect_rects(reporter);
  880. test_round_rect_ovals(reporter);
  881. test_round_rect_general(reporter);
  882. test_round_rect_iffy_parameters(reporter);
  883. test_inset(reporter);
  884. test_round_rect_contains_rect(reporter);
  885. test_round_rect_transform(reporter);
  886. test_issue_2696(reporter);
  887. test_tricky_radii(reporter);
  888. test_empty_crbug_458524(reporter);
  889. test_empty(reporter);
  890. test_read(reporter);
  891. }