blob: ec94c3396859789214d50f769d71edd661e7c6aa [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
8#include "Test.h"
9#include "SkRRect.h"
10
11static const SkScalar kWidth = 100.0f;
12static const SkScalar kHeight = 100.0f;
13
mike@reedtribe.orgbcbef572012-12-23 23:11:21 +000014static void test_inset(skiatest::Reporter* reporter) {
15 SkRRect rr, rr2;
16 SkRect r = { 0, 0, 100, 100 };
17
18 rr.setRect(r);
19 rr.inset(-20, -20, &rr2);
20 REPORTER_ASSERT(reporter, rr2.isRect());
21
22 rr.inset(20, 20, &rr2);
23 REPORTER_ASSERT(reporter, rr2.isRect());
skia.committer@gmail.com1a60dab2012-12-24 02:01:25 +000024
mike@reedtribe.orgbcbef572012-12-23 23:11:21 +000025 rr.inset(r.width()/2, r.height()/2, &rr2);
26 REPORTER_ASSERT(reporter, rr2.isEmpty());
27
28 rr.setRectXY(r, 20, 20);
29 rr.inset(19, 19, &rr2);
30 REPORTER_ASSERT(reporter, rr2.isSimple());
31 rr.inset(20, 20, &rr2);
32 REPORTER_ASSERT(reporter, rr2.isRect());
33}
34
robertphillips@google.com5985e7c2012-11-29 13:24:55 +000035// Test out the basic API entry points
36static void test_round_rect_basic(skiatest::Reporter* reporter) {
37 // Test out initialization methods
reed@google.com2b57dc62013-01-08 13:23:32 +000038 SkPoint zeroPt = { 0, 0 };
robertphillips@google.com5985e7c2012-11-29 13:24:55 +000039 SkRRect empty;
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +000040
robertphillips@google.com5985e7c2012-11-29 13:24:55 +000041 empty.setEmpty();
42
43 REPORTER_ASSERT(reporter, SkRRect::kEmpty_Type == empty.type());
44 REPORTER_ASSERT(reporter, empty.rect().isEmpty());
45
46 for (int i = 0; i < 4; ++i) {
47 REPORTER_ASSERT(reporter, zeroPt == empty.radii((SkRRect::Corner) i));
48 }
49
50 //----
51 SkRect rect = SkRect::MakeLTRB(0, 0, kWidth, kHeight);
52
53 SkRRect rr1;
54 rr1.setRect(rect);
55
56 REPORTER_ASSERT(reporter, SkRRect::kRect_Type == rr1.type());
57 REPORTER_ASSERT(reporter, rr1.rect() == rect);
58
59 for (int i = 0; i < 4; ++i) {
60 REPORTER_ASSERT(reporter, zeroPt == rr1.radii((SkRRect::Corner) i));
61 }
62
63 //----
64 SkPoint halfPoint = { SkScalarHalf(kWidth), SkScalarHalf(kHeight) };
65 SkRRect rr2;
66 rr2.setOval(rect);
67
68 REPORTER_ASSERT(reporter, SkRRect::kOval_Type == rr2.type());
69 REPORTER_ASSERT(reporter, rr2.rect() == rect);
70
71 for (int i = 0; i < 4; ++i) {
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +000072 REPORTER_ASSERT(reporter,
robertphillips@google.com5985e7c2012-11-29 13:24:55 +000073 rr2.radii((SkRRect::Corner) i).equalsWithinTolerance(halfPoint));
74 }
75
76 //----
77 SkPoint p = { 5, 5 };
78 SkRRect rr3;
79 rr3.setRectXY(rect, p.fX, p.fY);
80
81 REPORTER_ASSERT(reporter, SkRRect::kSimple_Type == rr3.type());
82 REPORTER_ASSERT(reporter, rr3.rect() == rect);
83
84 for (int i = 0; i < 4; ++i) {
85 REPORTER_ASSERT(reporter, p == rr3.radii((SkRRect::Corner) i));
86 }
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +000087
robertphillips@google.com5985e7c2012-11-29 13:24:55 +000088 //----
89 SkPoint radii[4] = { { 5, 5 }, { 5, 5 }, { 5, 5 }, { 5, 5 } };
90
91 SkRRect rr4;
92 rr4.setRectRadii(rect, radii);
93
94 REPORTER_ASSERT(reporter, SkRRect::kSimple_Type == rr4.type());
95 REPORTER_ASSERT(reporter, rr4.rect() == rect);
96
97 for (int i = 0; i < 4; ++i) {
98 REPORTER_ASSERT(reporter, radii[i] == rr4.radii((SkRRect::Corner) i));
99 }
100
101 //----
102 SkPoint radii2[4] = { { 0, 0 }, { 0, 0 }, { 50, 50 }, { 20, 50 } };
103
104 SkRRect rr5;
105 rr5.setRectRadii(rect, radii2);
106
107 REPORTER_ASSERT(reporter, SkRRect::kComplex_Type == rr5.type());
108 REPORTER_ASSERT(reporter, rr5.rect() == rect);
109
110 for (int i = 0; i < 4; ++i) {
111 REPORTER_ASSERT(reporter, radii2[i] == rr5.radii((SkRRect::Corner) i));
112 }
113
114 // Test out == & !=
115 REPORTER_ASSERT(reporter, empty != rr3);
116 REPORTER_ASSERT(reporter, rr3 == rr4);
117 REPORTER_ASSERT(reporter, rr4 != rr5);
118}
119
120// Test out the cases when the RR degenerates to a rect
121static void test_round_rect_rects(skiatest::Reporter* reporter) {
122 SkRect r;
robertphillips@google.com5985e7c2012-11-29 13:24:55 +0000123
124 //----
125 SkRRect empty;
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +0000126
robertphillips@google.com5985e7c2012-11-29 13:24:55 +0000127 empty.setEmpty();
128
129 REPORTER_ASSERT(reporter, SkRRect::kEmpty_Type == empty.type());
130 r = empty.rect();
131 REPORTER_ASSERT(reporter, 0 == r.fLeft && 0 == r.fTop && 0 == r.fRight && 0 == r.fBottom);
132
133 //----
134 SkRect rect = SkRect::MakeLTRB(0, 0, kWidth, kHeight);
135 SkRRect rr1;
136 rr1.setRectXY(rect, 0, 0);
137
138 REPORTER_ASSERT(reporter, SkRRect::kRect_Type == rr1.type());
139 r = rr1.rect();
140 REPORTER_ASSERT(reporter, rect == r);
robertphillips@google.com5985e7c2012-11-29 13:24:55 +0000141
142 //----
143 SkPoint radii[4] = { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } };
144
145 SkRRect rr2;
146 rr2.setRectRadii(rect, radii);
147
148 REPORTER_ASSERT(reporter, SkRRect::kRect_Type == rr2.type());
149 r = rr2.rect();
150 REPORTER_ASSERT(reporter, rect == r);
robertphillips@google.com5985e7c2012-11-29 13:24:55 +0000151
152 //----
153 SkPoint radii2[4] = { { 0, 0 }, { 20, 20 }, { 50, 50 }, { 20, 50 } };
154
155 SkRRect rr3;
156 rr3.setRectRadii(rect, radii2);
157 REPORTER_ASSERT(reporter, SkRRect::kComplex_Type == rr3.type());
158}
159
160// Test out the cases when the RR degenerates to an oval
161static void test_round_rect_ovals(skiatest::Reporter* reporter) {
robertphillips@google.com5985e7c2012-11-29 13:24:55 +0000162 //----
163 SkRect oval;
164 SkRect rect = SkRect::MakeLTRB(0, 0, kWidth, kHeight);
165 SkRRect rr1;
166 rr1.setRectXY(rect, SkScalarHalf(kWidth), SkScalarHalf(kHeight));
167
168 REPORTER_ASSERT(reporter, SkRRect::kOval_Type == rr1.type());
169 oval = rr1.rect();
170 REPORTER_ASSERT(reporter, oval == rect);
robertphillips@google.com5985e7c2012-11-29 13:24:55 +0000171}
172
173// Test out the non-degenerate RR cases
174static void test_round_rect_general(skiatest::Reporter* reporter) {
robertphillips@google.com5985e7c2012-11-29 13:24:55 +0000175 //----
176 SkRect rect = SkRect::MakeLTRB(0, 0, kWidth, kHeight);
177 SkRRect rr1;
178 rr1.setRectXY(rect, 20, 20);
179
180 REPORTER_ASSERT(reporter, SkRRect::kSimple_Type == rr1.type());
robertphillips@google.com5985e7c2012-11-29 13:24:55 +0000181
182 //----
robertphillips@google.com5985e7c2012-11-29 13:24:55 +0000183 SkPoint radii[4] = { { 0, 0 }, { 20, 20 }, { 50, 50 }, { 20, 50 } };
184
185 SkRRect rr2;
186 rr2.setRectRadii(rect, radii);
187
188 REPORTER_ASSERT(reporter, SkRRect::kComplex_Type == rr2.type());
robertphillips@google.com5985e7c2012-11-29 13:24:55 +0000189}
190
191// Test out questionable-parameter handling
192static void test_round_rect_iffy_parameters(skiatest::Reporter* reporter) {
193
194 // When the radii exceed the base rect they are proportionally scaled down
195 // to fit
196 SkRect rect = SkRect::MakeLTRB(0, 0, kWidth, kHeight);
197 SkPoint radii[4] = { { 50, 100 }, { 100, 50 }, { 50, 100 }, { 100, 50 } };
198
199 SkRRect rr1;
200 rr1.setRectRadii(rect, radii);
201
202 REPORTER_ASSERT(reporter, SkRRect::kComplex_Type == rr1.type());
203
204 const SkPoint& p = rr1.radii(SkRRect::kUpperLeft_Corner);
205
206 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(p.fX, 33.33333f));
207 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(p.fY, 66.66666f));
208
209 // Negative radii should be capped at zero
210 SkRRect rr2;
211 rr2.setRectXY(rect, -10, -20);
212
213 REPORTER_ASSERT(reporter, SkRRect::kRect_Type == rr2.type());
214
215 const SkPoint& p2 = rr2.radii(SkRRect::kUpperLeft_Corner);
216
217 REPORTER_ASSERT(reporter, 0.0f == p2.fX);
218 REPORTER_ASSERT(reporter, 0.0f == p2.fY);
219}
220
robertphillips@google.com32c1b662013-04-25 12:23:00 +0000221// Move a small box from the start position by (stepX, stepY) 'numSteps' times
222// testing for containment in 'rr' at each step.
223static void test_direction(skiatest::Reporter* reporter, const SkRRect &rr,
skia.committer@gmail.com2cf444f2013-04-26 07:00:58 +0000224 SkScalar initX, int stepX, SkScalar initY, int stepY,
robertphillips@google.com32c1b662013-04-25 12:23:00 +0000225 int numSteps, const bool* contains) {
226 SkScalar x = initX, y = initY;
227 for (int i = 0; i < numSteps; ++i) {
skia.committer@gmail.com2cf444f2013-04-26 07:00:58 +0000228 SkRect test = SkRect::MakeXYWH(x, y,
229 stepX ? SkIntToScalar(stepX) : SK_Scalar1,
robertphillips@google.com32c1b662013-04-25 12:23:00 +0000230 stepY ? SkIntToScalar(stepY) : SK_Scalar1);
231 test.sort();
232
233 REPORTER_ASSERT(reporter, contains[i] == rr.contains(test));
234
235 x += stepX;
236 y += stepY;
237 }
238}
239
240// Exercise the RR's contains rect method
241static void test_round_rect_contains_rect(skiatest::Reporter* reporter) {
242
243 static const int kNumRRects = 4;
244 static const SkVector gRadii[kNumRRects][4] = {
245 { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, // rect
246 { { 20, 20 }, { 20, 20 }, { 20, 20 }, { 20, 20 } }, // circle
247 { { 10, 10 }, { 10, 10 }, { 10, 10 }, { 10, 10 } }, // simple
248 { { 0, 0 }, { 20, 20 }, { 10, 10 }, { 30, 30 } } // complex
249 };
250
251 SkRRect rrects[kNumRRects];
252 for (int i = 0; i < kNumRRects; ++i) {
253 rrects[i].setRectRadii(SkRect::MakeWH(40, 40), gRadii[i]);
254 }
255
256 // First test easy outs - boxes that are obviously out on
257 // each corner and edge
258 static const SkRect easyOuts[] = {
259 { -5, -5, 5, 5 }, // NW
260 { 15, -5, 20, 5 }, // N
261 { 35, -5, 45, 5 }, // NE
262 { 35, 15, 45, 20 }, // E
263 { 35, 45, 35, 45 }, // SE
264 { 15, 35, 20, 45 }, // S
265 { -5, 35, 5, 45 }, // SW
266 { -5, 15, 5, 20 } // W
267 };
skia.committer@gmail.com2cf444f2013-04-26 07:00:58 +0000268
robertphillips@google.com32c1b662013-04-25 12:23:00 +0000269 for (int i = 0; i < kNumRRects; ++i) {
270 for (size_t j = 0; j < SK_ARRAY_COUNT(easyOuts); ++j) {
271 REPORTER_ASSERT(reporter, !rrects[i].contains(easyOuts[j]));
272 }
273 }
274
skia.committer@gmail.com2cf444f2013-04-26 07:00:58 +0000275 // Now test non-trivial containment. For each compass
276 // point walk a 1x1 rect in from the edge of the bounding
robertphillips@google.com32c1b662013-04-25 12:23:00 +0000277 // rect
278 static const int kNumSteps = 15;
279 bool answers[kNumRRects][8][kNumSteps] = {
280 // all the test rects are inside the degenerate rrect
281 {
282 // rect
283 { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
284 { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
285 { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
286 { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
287 { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
288 { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
289 { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
290 { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
291 },
292 // for the circle we expect 6 blocks to be out on the
skia.committer@gmail.com2cf444f2013-04-26 07:00:58 +0000293 // corners (then the rest in) and only the first block
294 // out on the vertical and horizontal axes (then
robertphillips@google.com32c1b662013-04-25 12:23:00 +0000295 // the rest in)
296 {
297 // circle
298 { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
299 { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
300 { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
301 { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
302 { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
303 { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
304 { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
305 { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
306 },
307 // for the simple round rect we expect 3 out on
308 // the corners (then the rest in) and no blocks out
309 // on the vertical and horizontal axes
310 {
311 // simple RR
312 { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
313 { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
314 { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
315 { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
316 { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
317 { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
318 { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
319 { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
320 },
321 // for the complex case the answer is different for each direction
322 {
323 // complex RR
324 // all in for NW (rect) corner (same as rect case)
325 { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
326 // only first block out for N (same as circle case)
327 { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
328 // first 6 blocks out for NE (same as circle case)
329 { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
330 // only first block out for E (same as circle case)
331 { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
332 // first 3 blocks out for SE (same as simple case)
333 { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
334 // first two blocks out for S
335 { 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
336 // first 9 blocks out for SW
337 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1 },
338 // first two blocks out for W (same as S)
339 { 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
340 }
341 };
342
343 for (int i = 0; i < kNumRRects; ++i) {
344 test_direction(reporter, rrects[i], 0, 1, 0, 1, kNumSteps, answers[i][0]); // NW
345 test_direction(reporter, rrects[i], 19.5f, 0, 0, 1, kNumSteps, answers[i][1]); // N
346 test_direction(reporter, rrects[i], 40, -1, 0, 1, kNumSteps, answers[i][2]); // NE
347 test_direction(reporter, rrects[i], 40, -1, 19.5f, 0, kNumSteps, answers[i][3]); // E
348 test_direction(reporter, rrects[i], 40, -1, 40, -1, kNumSteps, answers[i][4]); // SE
349 test_direction(reporter, rrects[i], 19.5f, 0, 40, -1, kNumSteps, answers[i][5]); // S
350 test_direction(reporter, rrects[i], 0, 1, 40, -1, kNumSteps, answers[i][6]); // SW
351 test_direction(reporter, rrects[i], 0, 1, 19.5f, 0, kNumSteps, answers[i][7]); // W
352 }
353}
354
robertphillips@google.com5985e7c2012-11-29 13:24:55 +0000355static void TestRoundRect(skiatest::Reporter* reporter) {
356 test_round_rect_basic(reporter);
357 test_round_rect_rects(reporter);
358 test_round_rect_ovals(reporter);
359 test_round_rect_general(reporter);
360 test_round_rect_iffy_parameters(reporter);
mike@reedtribe.orgbcbef572012-12-23 23:11:21 +0000361 test_inset(reporter);
robertphillips@google.com32c1b662013-04-25 12:23:00 +0000362 test_round_rect_contains_rect(reporter);
robertphillips@google.com5985e7c2012-11-29 13:24:55 +0000363}
364
365#include "TestClassDef.h"
366DEFINE_TESTCLASS("RoundRect", TestRoundRectClass, TestRoundRect)