blob: 171dbbba607927119916766990b5a8f8ce15ec05 [file] [log] [blame]
robertphillips@google.com5985e7c2012-11-29 13:24:55 +00001/*
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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "include/core/SkMatrix.h"
9#include "include/core/SkRRect.h"
10#include "src/core/SkPointPriv.h"
11#include "tests/Test.h"
robertphillips@google.com5985e7c2012-11-29 13:24:55 +000012
robertphillips2a679ae2015-03-13 09:53:01 -070013static void test_tricky_radii(skiatest::Reporter* reporter) {
14 {
15 // crbug.com/458522
16 SkRRect rr;
17 const SkRect bounds = { 3709, 3709, 3709 + 7402, 3709 + 29825 };
18 const SkScalar rad = 12814;
19 const SkVector vec[] = { { rad, rad }, { 0, rad }, { rad, rad }, { 0, rad } };
20 rr.setRectRadii(bounds, vec);
21 }
22
23 {
24 // crbug.com//463920
25 SkRect r = SkRect::MakeLTRB(0, 0, 1009, 33554432.0);
26 SkVector radii[4] = {
27 { 13.0f, 8.0f }, { 170.0f, 2.0 }, { 256.0f, 33554432.0 }, { 110.0f, 5.0f }
28 };
29 SkRRect rr;
30 rr.setRectRadii(r, radii);
31
32 REPORTER_ASSERT(reporter, (double) rr.radii(SkRRect::kUpperRight_Corner).fY +
33 (double) rr.radii(SkRRect::kLowerRight_Corner).fY <=
34 rr.height());
35 }
reed694b0d12015-02-13 14:33:02 -080036}
37
38static void test_empty_crbug_458524(skiatest::Reporter* reporter) {
39 SkRRect rr;
40 const SkRect bounds = { 3709, 3709, 3709 + 7402, 3709 + 29825 };
41 const SkScalar rad = 40;
42 rr.setRectXY(bounds, rad, rad);
43
44 SkRRect other;
45 SkMatrix matrix;
46 matrix.setScale(0, 1);
47 rr.transform(matrix, &other);
48 REPORTER_ASSERT(reporter, SkRRect::kEmpty_Type == other.getType());
49}
50
robertphillips05302f82015-09-29 11:24:07 -070051// Test that all the SkRRect entry points correctly handle un-sorted and
52// zero-sized input rects
53static void test_empty(skiatest::Reporter* reporter) {
54 static const SkRect oooRects[] = { // out of order
55 { 100, 0, 0, 100 }, // ooo horizontal
56 { 0, 100, 100, 0 }, // ooo vertical
57 { 100, 100, 0, 0 }, // ooo both
58 };
59
60 static const SkRect emptyRects[] = {
61 { 100, 100, 100, 200 }, // empty horizontal
62 { 100, 100, 200, 100 }, // empty vertical
63 { 100, 100, 100, 100 }, // empty both
64 { 0, 0, 0, 0 } // setEmpty-empty
65 };
66
67 static const SkVector radii[4] = { { 0, 1 }, { 2, 3 }, { 4, 5 }, { 6, 7 } };
68
69 SkRRect r;
70
71 for (size_t i = 0; i < SK_ARRAY_COUNT(oooRects); ++i) {
72 r.setRect(oooRects[i]);
73 REPORTER_ASSERT(reporter, !r.isEmpty());
Brian Salomon0a241ce2017-12-15 11:31:05 -050074 REPORTER_ASSERT(reporter, r.rect() == oooRects[i].makeSorted());
robertphillips05302f82015-09-29 11:24:07 -070075
76 r.setOval(oooRects[i]);
77 REPORTER_ASSERT(reporter, !r.isEmpty());
Brian Salomon0a241ce2017-12-15 11:31:05 -050078 REPORTER_ASSERT(reporter, r.rect() == oooRects[i].makeSorted());
robertphillips05302f82015-09-29 11:24:07 -070079
80 r.setRectXY(oooRects[i], 1, 2);
81 REPORTER_ASSERT(reporter, !r.isEmpty());
Brian Salomon0a241ce2017-12-15 11:31:05 -050082 REPORTER_ASSERT(reporter, r.rect() == oooRects[i].makeSorted());
robertphillips05302f82015-09-29 11:24:07 -070083
84 r.setNinePatch(oooRects[i], 0, 1, 2, 3);
85 REPORTER_ASSERT(reporter, !r.isEmpty());
Brian Salomon0a241ce2017-12-15 11:31:05 -050086 REPORTER_ASSERT(reporter, r.rect() == oooRects[i].makeSorted());
robertphillips05302f82015-09-29 11:24:07 -070087
88 r.setRectRadii(oooRects[i], radii);
89 REPORTER_ASSERT(reporter, !r.isEmpty());
Brian Salomon0a241ce2017-12-15 11:31:05 -050090 REPORTER_ASSERT(reporter, r.rect() == oooRects[i].makeSorted());
robertphillips05302f82015-09-29 11:24:07 -070091 }
92
93 for (size_t i = 0; i < SK_ARRAY_COUNT(emptyRects); ++i) {
94 r.setRect(emptyRects[i]);
95 REPORTER_ASSERT(reporter, r.isEmpty());
Brian Salomon0a241ce2017-12-15 11:31:05 -050096 REPORTER_ASSERT(reporter, r.rect() == emptyRects[i]);
robertphillips05302f82015-09-29 11:24:07 -070097
98 r.setOval(emptyRects[i]);
99 REPORTER_ASSERT(reporter, r.isEmpty());
Brian Salomon0a241ce2017-12-15 11:31:05 -0500100 REPORTER_ASSERT(reporter, r.rect() == emptyRects[i]);
robertphillips05302f82015-09-29 11:24:07 -0700101
102 r.setRectXY(emptyRects[i], 1, 2);
103 REPORTER_ASSERT(reporter, r.isEmpty());
Brian Salomon0a241ce2017-12-15 11:31:05 -0500104 REPORTER_ASSERT(reporter, r.rect() == emptyRects[i]);
robertphillips05302f82015-09-29 11:24:07 -0700105
106 r.setNinePatch(emptyRects[i], 0, 1, 2, 3);
107 REPORTER_ASSERT(reporter, r.isEmpty());
Brian Salomon0a241ce2017-12-15 11:31:05 -0500108 REPORTER_ASSERT(reporter, r.rect() == emptyRects[i]);
robertphillips05302f82015-09-29 11:24:07 -0700109
110 r.setRectRadii(emptyRects[i], radii);
111 REPORTER_ASSERT(reporter, r.isEmpty());
Brian Salomon0a241ce2017-12-15 11:31:05 -0500112 REPORTER_ASSERT(reporter, r.rect() == emptyRects[i]);
robertphillips05302f82015-09-29 11:24:07 -0700113 }
Brian Salomon0a241ce2017-12-15 11:31:05 -0500114
115 r.setRect({SK_ScalarNaN, 10, 10, 20});
116 REPORTER_ASSERT(reporter, r == SkRRect::MakeEmpty());
117 r.setRect({0, 10, 10, SK_ScalarInfinity});
118 REPORTER_ASSERT(reporter, r == SkRRect::MakeEmpty());
robertphillips05302f82015-09-29 11:24:07 -0700119}
120
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000121static const SkScalar kWidth = 100.0f;
122static const SkScalar kHeight = 100.0f;
robertphillips@google.com5985e7c2012-11-29 13:24:55 +0000123
mike@reedtribe.orgbcbef572012-12-23 23:11:21 +0000124static void test_inset(skiatest::Reporter* reporter) {
125 SkRRect rr, rr2;
126 SkRect r = { 0, 0, 100, 100 };
127
128 rr.setRect(r);
129 rr.inset(-20, -20, &rr2);
130 REPORTER_ASSERT(reporter, rr2.isRect());
131
132 rr.inset(20, 20, &rr2);
133 REPORTER_ASSERT(reporter, rr2.isRect());
skia.committer@gmail.com1a60dab2012-12-24 02:01:25 +0000134
mike@reedtribe.orgbcbef572012-12-23 23:11:21 +0000135 rr.inset(r.width()/2, r.height()/2, &rr2);
136 REPORTER_ASSERT(reporter, rr2.isEmpty());
137
138 rr.setRectXY(r, 20, 20);
139 rr.inset(19, 19, &rr2);
140 REPORTER_ASSERT(reporter, rr2.isSimple());
141 rr.inset(20, 20, &rr2);
142 REPORTER_ASSERT(reporter, rr2.isRect());
143}
144
robertphillipsfe1b1802015-02-24 11:18:48 -0800145
146static void test_9patch_rrect(skiatest::Reporter* reporter,
147 const SkRect& rect,
148 SkScalar l, SkScalar t, SkScalar r, SkScalar b,
149 bool checkRadii) {
150 SkRRect rr;
151 rr.setNinePatch(rect, l, t, r, b);
152
153 REPORTER_ASSERT(reporter, SkRRect::kNinePatch_Type == rr.type());
154 REPORTER_ASSERT(reporter, rr.rect() == rect);
155
156 if (checkRadii) {
157 // This test doesn't hold if the radii will be rescaled by SkRRect
158 SkRect ninePatchRadii = { l, t, r, b };
159 SkPoint rquad[4];
160 ninePatchRadii.toQuad(rquad);
161 for (int i = 0; i < 4; ++i) {
162 REPORTER_ASSERT(reporter, rquad[i] == rr.radii((SkRRect::Corner) i));
163 }
164 }
165 SkRRect rr2; // construct the same RR using the most general set function
166 SkVector radii[4] = { { l, t }, { r, t }, { r, b }, { l, b } };
167 rr2.setRectRadii(rect, radii);
168 REPORTER_ASSERT(reporter, rr2 == rr && rr2.getType() == rr.getType());
169}
170
robertphillips@google.com5985e7c2012-11-29 13:24:55 +0000171// Test out the basic API entry points
172static void test_round_rect_basic(skiatest::Reporter* reporter) {
173 // Test out initialization methods
reed@google.com2b57dc62013-01-08 13:23:32 +0000174 SkPoint zeroPt = { 0, 0 };
robertphillips@google.com5985e7c2012-11-29 13:24:55 +0000175 SkRRect empty;
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +0000176
robertphillips@google.com5985e7c2012-11-29 13:24:55 +0000177 empty.setEmpty();
178
179 REPORTER_ASSERT(reporter, SkRRect::kEmpty_Type == empty.type());
180 REPORTER_ASSERT(reporter, empty.rect().isEmpty());
181
182 for (int i = 0; i < 4; ++i) {
183 REPORTER_ASSERT(reporter, zeroPt == empty.radii((SkRRect::Corner) i));
184 }
185
186 //----
187 SkRect rect = SkRect::MakeLTRB(0, 0, kWidth, kHeight);
188
189 SkRRect rr1;
190 rr1.setRect(rect);
191
192 REPORTER_ASSERT(reporter, SkRRect::kRect_Type == rr1.type());
193 REPORTER_ASSERT(reporter, rr1.rect() == rect);
194
195 for (int i = 0; i < 4; ++i) {
196 REPORTER_ASSERT(reporter, zeroPt == rr1.radii((SkRRect::Corner) i));
197 }
commit-bot@chromium.orgf338d7c2014-03-17 21:17:30 +0000198 SkRRect rr1_2; // construct the same RR using the most general set function
199 SkVector rr1_2_radii[4] = { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } };
200 rr1_2.setRectRadii(rect, rr1_2_radii);
201 REPORTER_ASSERT(reporter, rr1_2 == rr1 && rr1_2.getType() == rr1.getType());
202 SkRRect rr1_3; // construct the same RR using the nine patch set function
203 rr1_3.setNinePatch(rect, 0, 0, 0, 0);
204 REPORTER_ASSERT(reporter, rr1_3 == rr1 && rr1_3.getType() == rr1.getType());
robertphillips@google.com5985e7c2012-11-29 13:24:55 +0000205
206 //----
207 SkPoint halfPoint = { SkScalarHalf(kWidth), SkScalarHalf(kHeight) };
208 SkRRect rr2;
209 rr2.setOval(rect);
210
211 REPORTER_ASSERT(reporter, SkRRect::kOval_Type == rr2.type());
212 REPORTER_ASSERT(reporter, rr2.rect() == rect);
213
214 for (int i = 0; i < 4; ++i) {
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +0000215 REPORTER_ASSERT(reporter,
Cary Clarkdf429f32017-11-08 11:44:31 -0500216 SkPointPriv::EqualsWithinTolerance(rr2.radii((SkRRect::Corner) i),
217 halfPoint));
robertphillips@google.com5985e7c2012-11-29 13:24:55 +0000218 }
commit-bot@chromium.orgf338d7c2014-03-17 21:17:30 +0000219 SkRRect rr2_2; // construct the same RR using the most general set function
220 SkVector rr2_2_radii[4] = { { halfPoint.fX, halfPoint.fY }, { halfPoint.fX, halfPoint.fY },
221 { halfPoint.fX, halfPoint.fY }, { halfPoint.fX, halfPoint.fY } };
222 rr2_2.setRectRadii(rect, rr2_2_radii);
223 REPORTER_ASSERT(reporter, rr2_2 == rr2 && rr2_2.getType() == rr2.getType());
224 SkRRect rr2_3; // construct the same RR using the nine patch set function
225 rr2_3.setNinePatch(rect, halfPoint.fX, halfPoint.fY, halfPoint.fX, halfPoint.fY);
226 REPORTER_ASSERT(reporter, rr2_3 == rr2 && rr2_3.getType() == rr2.getType());
robertphillips@google.com5985e7c2012-11-29 13:24:55 +0000227
228 //----
229 SkPoint p = { 5, 5 };
230 SkRRect rr3;
231 rr3.setRectXY(rect, p.fX, p.fY);
232
233 REPORTER_ASSERT(reporter, SkRRect::kSimple_Type == rr3.type());
234 REPORTER_ASSERT(reporter, rr3.rect() == rect);
235
236 for (int i = 0; i < 4; ++i) {
237 REPORTER_ASSERT(reporter, p == rr3.radii((SkRRect::Corner) i));
238 }
commit-bot@chromium.orgf338d7c2014-03-17 21:17:30 +0000239 SkRRect rr3_2; // construct the same RR using the most general set function
240 SkVector rr3_2_radii[4] = { { 5, 5 }, { 5, 5 }, { 5, 5 }, { 5, 5 } };
241 rr3_2.setRectRadii(rect, rr3_2_radii);
242 REPORTER_ASSERT(reporter, rr3_2 == rr3 && rr3_2.getType() == rr3.getType());
243 SkRRect rr3_3; // construct the same RR using the nine patch set function
244 rr3_3.setNinePatch(rect, 5, 5, 5, 5);
245 REPORTER_ASSERT(reporter, rr3_3 == rr3 && rr3_3.getType() == rr3.getType());
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +0000246
robertphillips@google.com5985e7c2012-11-29 13:24:55 +0000247 //----
robertphillipsfe1b1802015-02-24 11:18:48 -0800248 test_9patch_rrect(reporter, rect, 10, 9, 8, 7, true);
robertphillips@google.com5985e7c2012-11-29 13:24:55 +0000249
robertphillipsfe1b1802015-02-24 11:18:48 -0800250 {
251 // Test out the rrect from skia:3466
252 SkRect rect2 = SkRect::MakeLTRB(0.358211994f, 0.755430222f, 0.872866154f, 0.806214333f);
robertphillips@google.com5985e7c2012-11-29 13:24:55 +0000253
robertphillipsfe1b1802015-02-24 11:18:48 -0800254 test_9patch_rrect(reporter,
255 rect2,
256 0.926942348f, 0.642850280f, 0.529063463f, 0.587844372f,
257 false);
robertphillips@google.com5985e7c2012-11-29 13:24:55 +0000258 }
259
260 //----
261 SkPoint radii2[4] = { { 0, 0 }, { 0, 0 }, { 50, 50 }, { 20, 50 } };
262
263 SkRRect rr5;
264 rr5.setRectRadii(rect, radii2);
265
266 REPORTER_ASSERT(reporter, SkRRect::kComplex_Type == rr5.type());
267 REPORTER_ASSERT(reporter, rr5.rect() == rect);
268
269 for (int i = 0; i < 4; ++i) {
270 REPORTER_ASSERT(reporter, radii2[i] == rr5.radii((SkRRect::Corner) i));
271 }
272
273 // Test out == & !=
274 REPORTER_ASSERT(reporter, empty != rr3);
robertphillipsfe1b1802015-02-24 11:18:48 -0800275 REPORTER_ASSERT(reporter, rr3 != rr5);
robertphillips@google.com5985e7c2012-11-29 13:24:55 +0000276}
277
278// Test out the cases when the RR degenerates to a rect
279static void test_round_rect_rects(skiatest::Reporter* reporter) {
280 SkRect r;
robertphillips@google.com5985e7c2012-11-29 13:24:55 +0000281
282 //----
283 SkRRect empty;
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +0000284
robertphillips@google.com5985e7c2012-11-29 13:24:55 +0000285 empty.setEmpty();
286
287 REPORTER_ASSERT(reporter, SkRRect::kEmpty_Type == empty.type());
288 r = empty.rect();
289 REPORTER_ASSERT(reporter, 0 == r.fLeft && 0 == r.fTop && 0 == r.fRight && 0 == r.fBottom);
290
291 //----
292 SkRect rect = SkRect::MakeLTRB(0, 0, kWidth, kHeight);
293 SkRRect rr1;
294 rr1.setRectXY(rect, 0, 0);
295
296 REPORTER_ASSERT(reporter, SkRRect::kRect_Type == rr1.type());
297 r = rr1.rect();
298 REPORTER_ASSERT(reporter, rect == r);
robertphillips@google.com5985e7c2012-11-29 13:24:55 +0000299
300 //----
301 SkPoint radii[4] = { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } };
302
303 SkRRect rr2;
304 rr2.setRectRadii(rect, radii);
305
306 REPORTER_ASSERT(reporter, SkRRect::kRect_Type == rr2.type());
307 r = rr2.rect();
308 REPORTER_ASSERT(reporter, rect == r);
robertphillips@google.com5985e7c2012-11-29 13:24:55 +0000309
310 //----
311 SkPoint radii2[4] = { { 0, 0 }, { 20, 20 }, { 50, 50 }, { 20, 50 } };
312
313 SkRRect rr3;
314 rr3.setRectRadii(rect, radii2);
315 REPORTER_ASSERT(reporter, SkRRect::kComplex_Type == rr3.type());
316}
317
318// Test out the cases when the RR degenerates to an oval
319static void test_round_rect_ovals(skiatest::Reporter* reporter) {
robertphillips@google.com5985e7c2012-11-29 13:24:55 +0000320 //----
321 SkRect oval;
322 SkRect rect = SkRect::MakeLTRB(0, 0, kWidth, kHeight);
323 SkRRect rr1;
324 rr1.setRectXY(rect, SkScalarHalf(kWidth), SkScalarHalf(kHeight));
325
326 REPORTER_ASSERT(reporter, SkRRect::kOval_Type == rr1.type());
327 oval = rr1.rect();
328 REPORTER_ASSERT(reporter, oval == rect);
robertphillips@google.com5985e7c2012-11-29 13:24:55 +0000329}
330
331// Test out the non-degenerate RR cases
332static void test_round_rect_general(skiatest::Reporter* reporter) {
robertphillips@google.com5985e7c2012-11-29 13:24:55 +0000333 //----
334 SkRect rect = SkRect::MakeLTRB(0, 0, kWidth, kHeight);
335 SkRRect rr1;
336 rr1.setRectXY(rect, 20, 20);
337
338 REPORTER_ASSERT(reporter, SkRRect::kSimple_Type == rr1.type());
robertphillips@google.com5985e7c2012-11-29 13:24:55 +0000339
340 //----
robertphillips@google.com5985e7c2012-11-29 13:24:55 +0000341 SkPoint radii[4] = { { 0, 0 }, { 20, 20 }, { 50, 50 }, { 20, 50 } };
342
343 SkRRect rr2;
344 rr2.setRectRadii(rect, radii);
345
346 REPORTER_ASSERT(reporter, SkRRect::kComplex_Type == rr2.type());
robertphillips@google.com5985e7c2012-11-29 13:24:55 +0000347}
348
349// Test out questionable-parameter handling
350static void test_round_rect_iffy_parameters(skiatest::Reporter* reporter) {
351
352 // When the radii exceed the base rect they are proportionally scaled down
353 // to fit
354 SkRect rect = SkRect::MakeLTRB(0, 0, kWidth, kHeight);
355 SkPoint radii[4] = { { 50, 100 }, { 100, 50 }, { 50, 100 }, { 100, 50 } };
356
357 SkRRect rr1;
358 rr1.setRectRadii(rect, radii);
359
360 REPORTER_ASSERT(reporter, SkRRect::kComplex_Type == rr1.type());
361
362 const SkPoint& p = rr1.radii(SkRRect::kUpperLeft_Corner);
363
364 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(p.fX, 33.33333f));
365 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(p.fY, 66.66666f));
366
367 // Negative radii should be capped at zero
368 SkRRect rr2;
369 rr2.setRectXY(rect, -10, -20);
370
371 REPORTER_ASSERT(reporter, SkRRect::kRect_Type == rr2.type());
372
373 const SkPoint& p2 = rr2.radii(SkRRect::kUpperLeft_Corner);
374
375 REPORTER_ASSERT(reporter, 0.0f == p2.fX);
376 REPORTER_ASSERT(reporter, 0.0f == p2.fY);
377}
378
robertphillips@google.com32c1b662013-04-25 12:23:00 +0000379// Move a small box from the start position by (stepX, stepY) 'numSteps' times
380// testing for containment in 'rr' at each step.
381static void test_direction(skiatest::Reporter* reporter, const SkRRect &rr,
skia.committer@gmail.com2cf444f2013-04-26 07:00:58 +0000382 SkScalar initX, int stepX, SkScalar initY, int stepY,
robertphillips@google.com32c1b662013-04-25 12:23:00 +0000383 int numSteps, const bool* contains) {
384 SkScalar x = initX, y = initY;
385 for (int i = 0; i < numSteps; ++i) {
skia.committer@gmail.com2cf444f2013-04-26 07:00:58 +0000386 SkRect test = SkRect::MakeXYWH(x, y,
387 stepX ? SkIntToScalar(stepX) : SK_Scalar1,
robertphillips@google.com32c1b662013-04-25 12:23:00 +0000388 stepY ? SkIntToScalar(stepY) : SK_Scalar1);
389 test.sort();
390
391 REPORTER_ASSERT(reporter, contains[i] == rr.contains(test));
392
393 x += stepX;
394 y += stepY;
395 }
396}
397
398// Exercise the RR's contains rect method
399static void test_round_rect_contains_rect(skiatest::Reporter* reporter) {
400
401 static const int kNumRRects = 4;
402 static const SkVector gRadii[kNumRRects][4] = {
403 { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, // rect
404 { { 20, 20 }, { 20, 20 }, { 20, 20 }, { 20, 20 } }, // circle
405 { { 10, 10 }, { 10, 10 }, { 10, 10 }, { 10, 10 } }, // simple
406 { { 0, 0 }, { 20, 20 }, { 10, 10 }, { 30, 30 } } // complex
407 };
408
409 SkRRect rrects[kNumRRects];
410 for (int i = 0; i < kNumRRects; ++i) {
411 rrects[i].setRectRadii(SkRect::MakeWH(40, 40), gRadii[i]);
412 }
413
414 // First test easy outs - boxes that are obviously out on
415 // each corner and edge
416 static const SkRect easyOuts[] = {
417 { -5, -5, 5, 5 }, // NW
418 { 15, -5, 20, 5 }, // N
419 { 35, -5, 45, 5 }, // NE
420 { 35, 15, 45, 20 }, // E
421 { 35, 45, 35, 45 }, // SE
422 { 15, 35, 20, 45 }, // S
423 { -5, 35, 5, 45 }, // SW
424 { -5, 15, 5, 20 } // W
425 };
skia.committer@gmail.com2cf444f2013-04-26 07:00:58 +0000426
robertphillips@google.com32c1b662013-04-25 12:23:00 +0000427 for (int i = 0; i < kNumRRects; ++i) {
428 for (size_t j = 0; j < SK_ARRAY_COUNT(easyOuts); ++j) {
429 REPORTER_ASSERT(reporter, !rrects[i].contains(easyOuts[j]));
430 }
431 }
432
skia.committer@gmail.com2cf444f2013-04-26 07:00:58 +0000433 // Now test non-trivial containment. For each compass
434 // point walk a 1x1 rect in from the edge of the bounding
robertphillips@google.com32c1b662013-04-25 12:23:00 +0000435 // rect
436 static const int kNumSteps = 15;
437 bool answers[kNumRRects][8][kNumSteps] = {
438 // all the test rects are inside the degenerate rrect
439 {
440 // rect
441 { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
442 { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
443 { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
444 { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
445 { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
446 { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
447 { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
448 { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
449 },
450 // for the circle we expect 6 blocks to be out on the
skia.committer@gmail.com2cf444f2013-04-26 07:00:58 +0000451 // corners (then the rest in) and only the first block
452 // out on the vertical and horizontal axes (then
robertphillips@google.com32c1b662013-04-25 12:23:00 +0000453 // the rest in)
454 {
455 // circle
456 { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
457 { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
458 { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
459 { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
460 { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
461 { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
462 { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
463 { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
464 },
465 // for the simple round rect we expect 3 out on
466 // the corners (then the rest in) and no blocks out
467 // on the vertical and horizontal axes
468 {
469 // simple RR
470 { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
471 { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
472 { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
473 { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
474 { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
475 { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
476 { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
477 { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
478 },
479 // for the complex case the answer is different for each direction
480 {
481 // complex RR
482 // all in for NW (rect) corner (same as rect case)
483 { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
484 // only first block out for N (same as circle case)
485 { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
486 // first 6 blocks out for NE (same as circle case)
487 { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
488 // only first block out for E (same as circle case)
489 { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
490 // first 3 blocks out for SE (same as simple case)
491 { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
492 // first two blocks out for S
493 { 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
494 // first 9 blocks out for SW
495 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1 },
496 // first two blocks out for W (same as S)
497 { 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
498 }
499 };
500
501 for (int i = 0; i < kNumRRects; ++i) {
502 test_direction(reporter, rrects[i], 0, 1, 0, 1, kNumSteps, answers[i][0]); // NW
503 test_direction(reporter, rrects[i], 19.5f, 0, 0, 1, kNumSteps, answers[i][1]); // N
504 test_direction(reporter, rrects[i], 40, -1, 0, 1, kNumSteps, answers[i][2]); // NE
505 test_direction(reporter, rrects[i], 40, -1, 19.5f, 0, kNumSteps, answers[i][3]); // E
506 test_direction(reporter, rrects[i], 40, -1, 40, -1, kNumSteps, answers[i][4]); // SE
507 test_direction(reporter, rrects[i], 19.5f, 0, 40, -1, kNumSteps, answers[i][5]); // S
508 test_direction(reporter, rrects[i], 0, 1, 40, -1, kNumSteps, answers[i][6]); // SW
509 test_direction(reporter, rrects[i], 0, 1, 19.5f, 0, kNumSteps, answers[i][7]); // W
510 }
511}
512
scroggo@google.com20e3cd22013-11-05 15:54:42 +0000513// Called for a matrix that should cause SkRRect::transform to fail.
514static void assert_transform_failure(skiatest::Reporter* reporter, const SkRRect& orig,
515 const SkMatrix& matrix) {
516 // The test depends on the fact that the original is not empty.
517 SkASSERT(!orig.isEmpty());
518 SkRRect dst;
519 dst.setEmpty();
520
521 const SkRRect copyOfDst = dst;
522 const SkRRect copyOfOrig = orig;
523 bool success = orig.transform(matrix, &dst);
524 // This transform should fail.
525 REPORTER_ASSERT(reporter, !success);
526 // Since the transform failed, dst should be unchanged.
527 REPORTER_ASSERT(reporter, copyOfDst == dst);
528 // original should not be modified.
529 REPORTER_ASSERT(reporter, copyOfOrig == orig);
530 REPORTER_ASSERT(reporter, orig != dst);
531}
532
533#define GET_RADII \
534 const SkVector& origUL = orig.radii(SkRRect::kUpperLeft_Corner); \
535 const SkVector& origUR = orig.radii(SkRRect::kUpperRight_Corner); \
536 const SkVector& origLR = orig.radii(SkRRect::kLowerRight_Corner); \
537 const SkVector& origLL = orig.radii(SkRRect::kLowerLeft_Corner); \
538 const SkVector& dstUL = dst.radii(SkRRect::kUpperLeft_Corner); \
539 const SkVector& dstUR = dst.radii(SkRRect::kUpperRight_Corner); \
540 const SkVector& dstLR = dst.radii(SkRRect::kLowerRight_Corner); \
541 const SkVector& dstLL = dst.radii(SkRRect::kLowerLeft_Corner)
542
543// Called to test various transforms on a single SkRRect.
544static void test_transform_helper(skiatest::Reporter* reporter, const SkRRect& orig) {
545 SkRRect dst;
546 dst.setEmpty();
547
548 // The identity matrix will duplicate the rrect.
549 bool success = orig.transform(SkMatrix::I(), &dst);
550 REPORTER_ASSERT(reporter, success);
551 REPORTER_ASSERT(reporter, orig == dst);
552
553 // Skew and Perspective make transform fail.
554 SkMatrix matrix;
555 matrix.reset();
556 matrix.setSkewX(SkIntToScalar(2));
557 assert_transform_failure(reporter, orig, matrix);
558
559 matrix.reset();
560 matrix.setSkewY(SkIntToScalar(3));
561 assert_transform_failure(reporter, orig, matrix);
562
563 matrix.reset();
reed3f43f8a2015-01-20 19:58:36 -0800564 matrix.setPerspX(4);
scroggo@google.com20e3cd22013-11-05 15:54:42 +0000565 assert_transform_failure(reporter, orig, matrix);
566
567 matrix.reset();
reed3f43f8a2015-01-20 19:58:36 -0800568 matrix.setPerspY(5);
scroggo@google.com20e3cd22013-11-05 15:54:42 +0000569 assert_transform_failure(reporter, orig, matrix);
570
571 // Rotation fails.
572 matrix.reset();
scroggo@google.com20e3cd22013-11-05 15:54:42 +0000573 matrix.setRotate(SkIntToScalar(37));
574 assert_transform_failure(reporter, orig, matrix);
575
576 // Translate will keep the rect moved, but otherwise the same.
577 matrix.reset();
578 SkScalar translateX = SkIntToScalar(32);
579 SkScalar translateY = SkIntToScalar(15);
580 matrix.setTranslateX(translateX);
581 matrix.setTranslateY(translateY);
582 dst.setEmpty();
583 success = orig.transform(matrix, &dst);
584 REPORTER_ASSERT(reporter, success);
585 for (int i = 0; i < 4; ++i) {
586 REPORTER_ASSERT(reporter,
587 orig.radii((SkRRect::Corner) i) == dst.radii((SkRRect::Corner) i));
588 }
589 REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().width());
590 REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().height());
591 REPORTER_ASSERT(reporter, dst.rect().left() == orig.rect().left() + translateX);
592 REPORTER_ASSERT(reporter, dst.rect().top() == orig.rect().top() + translateY);
593
594 // Keeping the translation, but adding skew will make transform fail.
595 matrix.setSkewY(SkIntToScalar(7));
596 assert_transform_failure(reporter, orig, matrix);
597
598 // Scaling in -x will flip the round rect horizontally.
599 matrix.reset();
600 matrix.setScaleX(SkIntToScalar(-1));
601 dst.setEmpty();
602 success = orig.transform(matrix, &dst);
603 REPORTER_ASSERT(reporter, success);
604 {
605 GET_RADII;
606 // Radii have swapped in x.
607 REPORTER_ASSERT(reporter, origUL == dstUR);
608 REPORTER_ASSERT(reporter, origUR == dstUL);
609 REPORTER_ASSERT(reporter, origLR == dstLL);
610 REPORTER_ASSERT(reporter, origLL == dstLR);
611 }
612 // Width and height remain the same.
613 REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().width());
614 REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().height());
615 // Right and left have swapped (sort of)
616 REPORTER_ASSERT(reporter, orig.rect().right() == -dst.rect().left());
617 // Top has stayed the same.
618 REPORTER_ASSERT(reporter, orig.rect().top() == dst.rect().top());
619
620 // Keeping the scale, but adding a persp will make transform fail.
reed3f43f8a2015-01-20 19:58:36 -0800621 matrix.setPerspX(7);
scroggo@google.com20e3cd22013-11-05 15:54:42 +0000622 assert_transform_failure(reporter, orig, matrix);
623
624 // Scaling in -y will flip the round rect vertically.
625 matrix.reset();
626 matrix.setScaleY(SkIntToScalar(-1));
627 dst.setEmpty();
628 success = orig.transform(matrix, &dst);
629 REPORTER_ASSERT(reporter, success);
630 {
631 GET_RADII;
632 // Radii have swapped in y.
633 REPORTER_ASSERT(reporter, origUL == dstLL);
634 REPORTER_ASSERT(reporter, origUR == dstLR);
635 REPORTER_ASSERT(reporter, origLR == dstUR);
636 REPORTER_ASSERT(reporter, origLL == dstUL);
637 }
638 // Width and height remain the same.
639 REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().width());
640 REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().height());
641 // Top and bottom have swapped (sort of)
642 REPORTER_ASSERT(reporter, orig.rect().top() == -dst.rect().bottom());
643 // Left has stayed the same.
644 REPORTER_ASSERT(reporter, orig.rect().left() == dst.rect().left());
645
646 // Scaling in -x and -y will swap in both directions.
647 matrix.reset();
648 matrix.setScaleY(SkIntToScalar(-1));
649 matrix.setScaleX(SkIntToScalar(-1));
650 dst.setEmpty();
651 success = orig.transform(matrix, &dst);
652 REPORTER_ASSERT(reporter, success);
653 {
654 GET_RADII;
655 REPORTER_ASSERT(reporter, origUL == dstLR);
656 REPORTER_ASSERT(reporter, origUR == dstLL);
657 REPORTER_ASSERT(reporter, origLR == dstUL);
658 REPORTER_ASSERT(reporter, origLL == dstUR);
659 }
660 // Width and height remain the same.
661 REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().width());
662 REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().height());
663 REPORTER_ASSERT(reporter, orig.rect().top() == -dst.rect().bottom());
664 REPORTER_ASSERT(reporter, orig.rect().right() == -dst.rect().left());
665
666 // Scale in both directions.
667 SkScalar xScale = SkIntToScalar(3);
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000668 SkScalar yScale = 3.2f;
scroggo@google.com20e3cd22013-11-05 15:54:42 +0000669 matrix.reset();
670 matrix.setScaleX(xScale);
671 matrix.setScaleY(yScale);
672 dst.setEmpty();
673 success = orig.transform(matrix, &dst);
674 REPORTER_ASSERT(reporter, success);
675 // Radii are scaled.
676 for (int i = 0; i < 4; ++i) {
677 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.radii((SkRRect::Corner) i).fX,
Mike Reeddf85c382017-02-14 10:59:19 -0500678 orig.radii((SkRRect::Corner) i).fX * xScale));
scroggo@google.com20e3cd22013-11-05 15:54:42 +0000679 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.radii((SkRRect::Corner) i).fY,
Mike Reeddf85c382017-02-14 10:59:19 -0500680 orig.radii((SkRRect::Corner) i).fY * yScale));
scroggo@google.com20e3cd22013-11-05 15:54:42 +0000681 }
682 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.rect().width(),
Mike Reeddf85c382017-02-14 10:59:19 -0500683 orig.rect().width() * xScale));
scroggo@google.com20e3cd22013-11-05 15:54:42 +0000684 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.rect().height(),
Mike Reeddf85c382017-02-14 10:59:19 -0500685 orig.rect().height() * yScale));
scroggo@google.com20e3cd22013-11-05 15:54:42 +0000686 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.rect().left(),
Mike Reeddf85c382017-02-14 10:59:19 -0500687 orig.rect().left() * xScale));
scroggo@google.com20e3cd22013-11-05 15:54:42 +0000688 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.rect().top(),
Mike Reeddf85c382017-02-14 10:59:19 -0500689 orig.rect().top() * yScale));
Malay Keshave4628b12019-04-03 13:28:05 -0700690
691
692 // a-----b d-----a
693 // | | -> | |
694 // | | Rotate 90 | |
695 // d-----c c-----b
696 matrix.reset();
697 matrix.setRotate(SkIntToScalar(90));
698 dst.setEmpty();
699 success = orig.transform(matrix, &dst);
700 REPORTER_ASSERT(reporter, success);
701 {
702 GET_RADII;
703 // Radii have cycled clockwise and swapped their x and y axis.
704 REPORTER_ASSERT(reporter, dstUL.x() == origLL.y());
705 REPORTER_ASSERT(reporter, dstUL.y() == origLL.x());
706 REPORTER_ASSERT(reporter, dstUR.x() == origUL.y());
707 REPORTER_ASSERT(reporter, dstUR.y() == origUL.x());
708 REPORTER_ASSERT(reporter, dstLR.x() == origUR.y());
709 REPORTER_ASSERT(reporter, dstLR.y() == origUR.x());
710 REPORTER_ASSERT(reporter, dstLL.x() == origLR.y());
711 REPORTER_ASSERT(reporter, dstLL.y() == origLR.x());
712 }
713 // Width and height would get swapped.
714 REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().height());
715 REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().width());
716
717 // a-----b b-----a c-----b
718 // | | -> | | -> | |
719 // | | Flip X | | Rotate 90 | |
720 // d-----c c-----d d-----a
721 matrix.reset();
722 matrix.setRotate(SkIntToScalar(90));
723 matrix.postScale(SkIntToScalar(-1), SkIntToScalar(1));
724 dst.setEmpty();
725 success = orig.transform(matrix, &dst);
726 REPORTER_ASSERT(reporter, success);
727 {
728 GET_RADII;
729 REPORTER_ASSERT(reporter, dstUL.x() == origLR.y());
730 REPORTER_ASSERT(reporter, dstUL.y() == origLR.x());
731 REPORTER_ASSERT(reporter, dstUR.x() == origUR.y());
732 REPORTER_ASSERT(reporter, dstUR.y() == origUR.x());
733 REPORTER_ASSERT(reporter, dstLR.x() == origUL.y());
734 REPORTER_ASSERT(reporter, dstLR.y() == origUL.x());
735 REPORTER_ASSERT(reporter, dstLL.x() == origLL.y());
736 REPORTER_ASSERT(reporter, dstLL.y() == origLL.x());
737 }
738 // Width and height would get swapped.
739 REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().height());
740 REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().width());
741
742 // a-----b d-----a c-----b
743 // | | -> | | -> | |
744 // | | Rotate 90 | | Flip Y | |
745 // d-----c c-----b d-----a
746 //
747 // This is the same as Flip X and Rotate 90.
748 matrix.reset();
749 matrix.setScale(SkIntToScalar(1), SkIntToScalar(-1));
750 matrix.postRotate(SkIntToScalar(90));
751 SkRRect dst2;
752 dst2.setEmpty();
753 success = orig.transform(matrix, &dst2);
754 REPORTER_ASSERT(reporter, success);
755 REPORTER_ASSERT(reporter, dst == dst2);
756
757 // a-----b b-----c c-----b
758 // | | -> | | -> | |
759 // | | Rotate 270 | | Flip X | |
760 // d-----c a-----d d-----a
761 matrix.reset();
762 matrix.setScale(SkIntToScalar(-1), SkIntToScalar(1));
763 matrix.postRotate(SkIntToScalar(270));
764 dst2.setEmpty();
765 success = orig.transform(matrix, &dst2);
766 REPORTER_ASSERT(reporter, success);
767 REPORTER_ASSERT(reporter, dst == dst2);
768
769 // a-----b d-----c c-----b
770 // | | -> | | -> | |
771 // | | Flip Y | | Rotate 270 | |
772 // d-----c a-----b d-----a
773 matrix.reset();
774 matrix.setRotate(SkIntToScalar(270));
775 matrix.postScale(SkIntToScalar(1), SkIntToScalar(-1));
776 dst2.setEmpty();
777 success = orig.transform(matrix, &dst2);
778 REPORTER_ASSERT(reporter, success);
779 REPORTER_ASSERT(reporter, dst == dst2);
780
781 // a-----b d-----a a-----d
782 // | | -> | | -> | |
783 // | | Rotate 90 | | Flip X | |
784 // d-----c c-----b b-----c
785 matrix.reset();
786 matrix.setScale(SkIntToScalar(-1), SkIntToScalar(1));
787 matrix.postRotate(SkIntToScalar(90));
788 dst.setEmpty();
789 success = orig.transform(matrix, &dst);
790 REPORTER_ASSERT(reporter, success);
791 {
792 GET_RADII;
793 REPORTER_ASSERT(reporter, dstUL.x() == origUL.y());
794 REPORTER_ASSERT(reporter, dstUL.y() == origUL.x());
795 REPORTER_ASSERT(reporter, dstUR.x() == origLL.y());
796 REPORTER_ASSERT(reporter, dstUR.y() == origLL.x());
797 REPORTER_ASSERT(reporter, dstLR.x() == origLR.y());
798 REPORTER_ASSERT(reporter, dstLR.y() == origLR.x());
799 REPORTER_ASSERT(reporter, dstLL.x() == origUR.y());
800 REPORTER_ASSERT(reporter, dstLL.y() == origUR.x());
801 }
802 // Width and height would get swapped.
803 REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().height());
804 REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().width());
805
806 // a-----b d-----c a-----d
807 // | | -> | | -> | |
808 // | | Flip Y | | Rotate 90 | |
809 // d-----c a-----b b-----c
810 // This is the same as rotate 90 and flip x.
811 matrix.reset();
812 matrix.setRotate(SkIntToScalar(90));
813 matrix.postScale(SkIntToScalar(1), SkIntToScalar(-1));
814 dst2.setEmpty();
815 success = orig.transform(matrix, &dst2);
816 REPORTER_ASSERT(reporter, success);
817 REPORTER_ASSERT(reporter, dst == dst2);
818
819 // a-----b b-----a a-----d
820 // | | -> | | -> | |
821 // | | Flip X | | Rotate 270 | |
822 // d-----c c-----d b-----c
823 matrix.reset();
824 matrix.setRotate(SkIntToScalar(270));
825 matrix.postScale(SkIntToScalar(-1), SkIntToScalar(1));
826 dst2.setEmpty();
827 success = orig.transform(matrix, &dst2);
828 REPORTER_ASSERT(reporter, success);
829 REPORTER_ASSERT(reporter, dst == dst2);
830
831 // a-----b b-----c a-----d
832 // | | -> | | -> | |
833 // | | Rotate 270 | | Flip Y | |
834 // d-----c a-----d b-----c
835 matrix.reset();
836 matrix.setScale(SkIntToScalar(1), SkIntToScalar(-1));
837 matrix.postRotate(SkIntToScalar(270));
838 dst2.setEmpty();
839 success = orig.transform(matrix, &dst2);
840 REPORTER_ASSERT(reporter, success);
841 REPORTER_ASSERT(reporter, dst == dst2);
842
843
844 // a-----b b-----a c-----d b-----c
845 // | | -> | | -> | | -> | |
846 // | | Flip X | | Flip Y | | Rotate 90 | |
847 // d-----c c-----d b-----a a-----d
848 //
849 // This is the same as rotation by 270.
850 matrix.reset();
851 matrix.setRotate(SkIntToScalar(90));
852 matrix.postScale(SkIntToScalar(-1), SkIntToScalar(-1));
853 dst.setEmpty();
854 success = orig.transform(matrix, &dst);
855 REPORTER_ASSERT(reporter, success);
856 {
857 GET_RADII;
858 // Radii have cycled clockwise and swapped their x and y axis.
859 REPORTER_ASSERT(reporter, dstUL.x() == origUR.y());
860 REPORTER_ASSERT(reporter, dstUL.y() == origUR.x());
861 REPORTER_ASSERT(reporter, dstUR.x() == origLR.y());
862 REPORTER_ASSERT(reporter, dstUR.y() == origLR.x());
863 REPORTER_ASSERT(reporter, dstLR.x() == origLL.y());
864 REPORTER_ASSERT(reporter, dstLR.y() == origLL.x());
865 REPORTER_ASSERT(reporter, dstLL.x() == origUL.y());
866 REPORTER_ASSERT(reporter, dstLL.y() == origUL.x());
867 }
868 // Width and height would get swapped.
869 REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().height());
870 REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().width());
871
872 // a-----b b-----c
873 // | | -> | |
874 // | | Rotate 270 | |
875 // d-----c a-----d
876 //
877 dst2.setEmpty();
878 matrix.reset();
879 matrix.setRotate(SkIntToScalar(270));
880 success = orig.transform(matrix, &dst2);
881 REPORTER_ASSERT(reporter, success);
882 REPORTER_ASSERT(reporter, dst == dst2);
883
884 // a-----b b-----a c-----d d-----a
885 // | | -> | | -> | | -> | |
886 // | | Flip X | | Flip Y | | Rotate 270 | |
887 // d-----c c-----d b-----a c-----b
888 //
889 // This is the same as rotation by 90 degrees.
890 matrix.reset();
891 matrix.setRotate(SkIntToScalar(270));
892 matrix.postScale(SkIntToScalar(-1), SkIntToScalar(-1));
893 dst.setEmpty();
894 success = orig.transform(matrix, &dst);
895 REPORTER_ASSERT(reporter, success);
896
897 matrix.reset();
898 matrix.setRotate(SkIntToScalar(90));
899 dst2.setEmpty();
900 success = orig.transform(matrix, &dst2);
901 REPORTER_ASSERT(reporter, dst == dst2);
902
scroggo@google.com20e3cd22013-11-05 15:54:42 +0000903}
904
905static void test_round_rect_transform(skiatest::Reporter* reporter) {
906 SkRRect rrect;
907 {
908 SkRect r = { 0, 0, kWidth, kHeight };
909 rrect.setRectXY(r, SkIntToScalar(4), SkIntToScalar(7));
910 test_transform_helper(reporter, rrect);
911 }
912 {
913 SkRect r = { SkIntToScalar(5), SkIntToScalar(15),
914 SkIntToScalar(27), SkIntToScalar(34) };
915 SkVector radii[4] = { { 0, SkIntToScalar(1) },
916 { SkIntToScalar(2), SkIntToScalar(3) },
917 { SkIntToScalar(4), SkIntToScalar(5) },
918 { SkIntToScalar(6), SkIntToScalar(7) } };
919 rrect.setRectRadii(r, radii);
920 test_transform_helper(reporter, rrect);
921 }
922}
923
halcanary9d524f22016-03-29 09:03:52 -0700924// Test out the case where an oval already off in space is translated/scaled
robertphillipse5c1e3c2014-06-27 08:59:26 -0700925// further off into space - yielding numerical issues when the rect & radii
926// are transformed separatly
927// BUG=skia:2696
928static void test_issue_2696(skiatest::Reporter* reporter) {
929 SkRRect rrect;
930 SkRect r = { 28443.8594f, 53.1428604f, 28446.7148f, 56.0000038f };
931 rrect.setOval(r);
932
933 SkMatrix xform;
934 xform.setAll(2.44f, 0.0f, 485411.7f,
935 0.0f, 2.44f, -438.7f,
936 0.0f, 0.0f, 1.0f);
937 SkRRect dst;
938
939 bool success = rrect.transform(xform, &dst);
940 REPORTER_ASSERT(reporter, success);
941
942 SkScalar halfWidth = SkScalarHalf(dst.width());
943 SkScalar halfHeight = SkScalarHalf(dst.height());
944
945 for (int i = 0; i < 4; ++i) {
halcanary9d524f22016-03-29 09:03:52 -0700946 REPORTER_ASSERT(reporter,
robertphillipse5c1e3c2014-06-27 08:59:26 -0700947 SkScalarNearlyEqual(dst.radii((SkRRect::Corner)i).fX, halfWidth));
halcanary9d524f22016-03-29 09:03:52 -0700948 REPORTER_ASSERT(reporter,
robertphillipse5c1e3c2014-06-27 08:59:26 -0700949 SkScalarNearlyEqual(dst.radii((SkRRect::Corner)i).fY, halfHeight));
950 }
951}
952
Mike Reede5826002018-01-19 12:28:52 -0500953void test_read_rrect(skiatest::Reporter* reporter, const SkRRect& rrect, bool shouldEqualSrc) {
Brian Salomonfb6a7892017-09-20 11:05:49 -0400954 // It would be cleaner to call rrect.writeToMemory into a buffer. However, writeToMemory asserts
955 // that the rrect is valid and our caller may have fiddled with the internals of rrect to make
956 // it invalid.
957 const void* buffer = reinterpret_cast<const void*>(&rrect);
958 SkRRect deserialized;
959 size_t size = deserialized.readFromMemory(buffer, sizeof(SkRRect));
Mike Reede5826002018-01-19 12:28:52 -0500960 REPORTER_ASSERT(reporter, size == SkRRect::kSizeInMemory);
961 REPORTER_ASSERT(reporter, deserialized.isValid());
962 if (shouldEqualSrc) {
963 REPORTER_ASSERT(reporter, rrect == deserialized);
Brian Salomonfb6a7892017-09-20 11:05:49 -0400964 }
965}
966
967static void test_read(skiatest::Reporter* reporter) {
968 static const SkRect kRect = {10.f, 10.f, 20.f, 20.f};
969 static const SkRect kNaNRect = {10.f, 10.f, 20.f, SK_ScalarNaN};
970 static const SkRect kInfRect = {10.f, 10.f, SK_ScalarInfinity, 20.f};
971 SkRRect rrect;
972
973 test_read_rrect(reporter, SkRRect::MakeEmpty(), true);
974 test_read_rrect(reporter, SkRRect::MakeRect(kRect), true);
975 // These get coerced to empty.
976 test_read_rrect(reporter, SkRRect::MakeRect(kInfRect), true);
977 test_read_rrect(reporter, SkRRect::MakeRect(kNaNRect), true);
978
979 rrect.setRect(kRect);
980 SkRect* innerRect = reinterpret_cast<SkRect*>(&rrect);
981 SkASSERT(*innerRect == kRect);
982 *innerRect = kInfRect;
983 test_read_rrect(reporter, rrect, false);
984 *innerRect = kNaNRect;
985 test_read_rrect(reporter, rrect, false);
986
987 test_read_rrect(reporter, SkRRect::MakeOval(kRect), true);
988 test_read_rrect(reporter, SkRRect::MakeOval(kInfRect), true);
989 test_read_rrect(reporter, SkRRect::MakeOval(kNaNRect), true);
990 rrect.setOval(kRect);
991 *innerRect = kInfRect;
992 test_read_rrect(reporter, rrect, false);
993 *innerRect = kNaNRect;
994 test_read_rrect(reporter, rrect, false);
995
996 test_read_rrect(reporter, SkRRect::MakeRectXY(kRect, 5.f, 5.f), true);
997 // rrect should scale down the radii to make this legal
998 test_read_rrect(reporter, SkRRect::MakeRectXY(kRect, 5.f, 400.f), true);
999
1000 static const SkVector kRadii[4] = {{0.5f, 1.f}, {1.5f, 2.f}, {2.5f, 3.f}, {3.5f, 4.f}};
1001 rrect.setRectRadii(kRect, kRadii);
1002 test_read_rrect(reporter, rrect, true);
1003 SkScalar* innerRadius = reinterpret_cast<SkScalar*>(&rrect) + 6;
1004 SkASSERT(*innerRadius == 1.5f);
1005 *innerRadius = 400.f;
1006 test_read_rrect(reporter, rrect, false);
1007 *innerRadius = SK_ScalarInfinity;
1008 test_read_rrect(reporter, rrect, false);
1009 *innerRadius = SK_ScalarNaN;
1010 test_read_rrect(reporter, rrect, false);
Brian Salomon4b0e3642017-11-20 21:56:29 -05001011 *innerRadius = -10.f;
1012 test_read_rrect(reporter, rrect, false);
Brian Salomonfb6a7892017-09-20 11:05:49 -04001013}
1014
tfarina@chromium.orge4fafb12013-12-12 21:11:12 +00001015DEF_TEST(RoundRect, reporter) {
robertphillips@google.com5985e7c2012-11-29 13:24:55 +00001016 test_round_rect_basic(reporter);
1017 test_round_rect_rects(reporter);
1018 test_round_rect_ovals(reporter);
1019 test_round_rect_general(reporter);
1020 test_round_rect_iffy_parameters(reporter);
mike@reedtribe.orgbcbef572012-12-23 23:11:21 +00001021 test_inset(reporter);
robertphillips@google.com32c1b662013-04-25 12:23:00 +00001022 test_round_rect_contains_rect(reporter);
scroggo@google.com20e3cd22013-11-05 15:54:42 +00001023 test_round_rect_transform(reporter);
robertphillipse5c1e3c2014-06-27 08:59:26 -07001024 test_issue_2696(reporter);
robertphillips2a679ae2015-03-13 09:53:01 -07001025 test_tricky_radii(reporter);
reed694b0d12015-02-13 14:33:02 -08001026 test_empty_crbug_458524(reporter);
robertphillips05302f82015-09-29 11:24:07 -07001027 test_empty(reporter);
Brian Salomonfb6a7892017-09-20 11:05:49 -04001028 test_read(reporter);
robertphillips@google.com5985e7c2012-11-29 13:24:55 +00001029}