2 * Copyright 2011 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
8 #include "include/core/SkPath.h"
9 #include "include/core/SkRRect.h"
10 #include "include/core/SkRegion.h"
11 #include "include/utils/SkRandom.h"
12 #include "src/core/SkAutoMalloc.h"
13 #include "tests/Test.h"
15 static void Union(SkRegion* rgn, const SkIRect& rect) {
16 rgn->op(rect, SkRegion::kUnion_Op);
19 #define TEST_NO_INTERSECT(rgn, rect) REPORTER_ASSERT(reporter, !rgn.intersects(rect))
20 #define TEST_INTERSECT(rgn, rect) REPORTER_ASSERT(reporter, rgn.intersects(rect))
21 #define TEST_NO_CONTAINS(rgn, rect) REPORTER_ASSERT(reporter, !rgn.contains(rect))
23 // inspired by http://code.google.com/p/skia/issues/detail?id=958
25 static void test_fromchrome(skiatest::Reporter* reporter) {
27 Union(&r, SkIRect::MakeXYWH(0, 0, 1, 1));
28 TEST_NO_INTERSECT(r, SkIRect::MakeXYWH(0, 0, 0, 0));
29 TEST_INTERSECT(r, SkIRect::MakeXYWH(0, 0, 2, 2));
30 TEST_INTERSECT(r, SkIRect::MakeXYWH(-1, 0, 2, 2));
31 TEST_INTERSECT(r, SkIRect::MakeXYWH(-1, -1, 2, 2));
32 TEST_INTERSECT(r, SkIRect::MakeXYWH(0, -1, 2, 2));
33 TEST_INTERSECT(r, SkIRect::MakeXYWH(-1, -1, 3, 3));
35 Union(&r, SkIRect::MakeXYWH(0, 0, 3, 3));
36 Union(&r, SkIRect::MakeXYWH(10, 0, 3, 3));
37 Union(&r, SkIRect::MakeXYWH(0, 10, 13, 3));
38 TEST_INTERSECT(r, SkIRect::MakeXYWH(-1, -1, 2, 2));
39 TEST_INTERSECT(r, SkIRect::MakeXYWH(2, -1, 2, 2));
40 TEST_INTERSECT(r, SkIRect::MakeXYWH(2, 2, 2, 2));
41 TEST_INTERSECT(r, SkIRect::MakeXYWH(-1, 2, 2, 2));
43 TEST_INTERSECT(r, SkIRect::MakeXYWH(9, -1, 2, 2));
44 TEST_INTERSECT(r, SkIRect::MakeXYWH(12, -1, 2, 2));
45 TEST_INTERSECT(r, SkIRect::MakeXYWH(12, 2, 2, 2));
46 TEST_INTERSECT(r, SkIRect::MakeXYWH(9, 2, 2, 2));
48 TEST_INTERSECT(r, SkIRect::MakeXYWH(0, -1, 13, 5));
49 TEST_INTERSECT(r, SkIRect::MakeXYWH(1, -1, 11, 5));
50 TEST_INTERSECT(r, SkIRect::MakeXYWH(2, -1, 9, 5));
51 TEST_INTERSECT(r, SkIRect::MakeXYWH(2, -1, 8, 5));
52 TEST_INTERSECT(r, SkIRect::MakeXYWH(3, -1, 8, 5));
54 TEST_INTERSECT(r, SkIRect::MakeXYWH(0, 1, 13, 1));
55 TEST_INTERSECT(r, SkIRect::MakeXYWH(1, 1, 11, 1));
56 TEST_INTERSECT(r, SkIRect::MakeXYWH(2, 1, 9, 1));
57 TEST_INTERSECT(r, SkIRect::MakeXYWH(2, 1, 8, 1));
58 TEST_INTERSECT(r, SkIRect::MakeXYWH(3, 1, 8, 1));
60 TEST_INTERSECT(r, SkIRect::MakeXYWH(0, 0, 13, 13));
61 TEST_INTERSECT(r, SkIRect::MakeXYWH(0, 1, 13, 11));
62 TEST_INTERSECT(r, SkIRect::MakeXYWH(0, 2, 13, 9));
63 TEST_INTERSECT(r, SkIRect::MakeXYWH(0, 2, 13, 8));
66 // These test SkRegion::contains(Rect) and SkRegion::contains(Region)
69 Union(&container, SkIRect::MakeXYWH(0, 0, 40, 20));
70 Union(&container, SkIRect::MakeXYWH(30, 20, 10, 20));
71 TEST_NO_CONTAINS(container, SkIRect::MakeXYWH(0, 0, 10, 39));
72 TEST_NO_CONTAINS(container, SkIRect::MakeXYWH(29, 0, 10, 39));
76 Union(&rgn, SkIRect::MakeXYWH(0, 0, 10, 10));
77 Union(&rgn, SkIRect::MakeLTRB(5, 10, 20, 20));
78 TEST_INTERSECT(rgn, SkIRect::MakeXYWH(15, 0, 5, 11));
82 static void test_empties(skiatest::Reporter* reporter) {
83 SkRegion valid(SkIRect::MakeWH(10, 10));
84 SkRegion empty, empty2;
86 REPORTER_ASSERT(reporter, empty.isEmpty());
87 REPORTER_ASSERT(reporter, !valid.isEmpty());
90 REPORTER_ASSERT(reporter, !empty.intersects(empty2));
91 REPORTER_ASSERT(reporter, !valid.intersects(empty));
94 REPORTER_ASSERT(reporter, !empty.contains(empty2));
95 REPORTER_ASSERT(reporter, !valid.contains(empty));
96 REPORTER_ASSERT(reporter, !empty.contains(valid));
99 emptyPath.moveTo(1, 5);
102 openClip.setRect({-16000, -16000, 16000, 16000});
103 empty.setPath(emptyPath, openClip); // should not assert
111 static SkIRect randRect(SkRandom& rand) {
112 int x = rand.nextU() % W;
113 int y = rand.nextU() % H;
114 int w = rand.nextU() % W;
115 int h = rand.nextU() % H;
116 return SkIRect::MakeXYWH(x, y, w >> 1, h >> 1);
119 static void randRgn(SkRandom& rand, SkRegion* rgn, int n) {
121 for (int i = 0; i < n; ++i) {
122 rgn->op(randRect(rand), SkRegion::kUnion_Op);
126 static bool slow_contains(const SkRegion& outer, const SkRegion& inner) {
128 tmp.op(outer, inner, SkRegion::kUnion_Op);
132 static bool slow_contains(const SkRegion& outer, const SkIRect& r) {
134 tmp.op(outer, SkRegion(r), SkRegion::kUnion_Op);
138 static bool slow_intersects(const SkRegion& outer, const SkRegion& inner) {
140 return tmp.op(outer, inner, SkRegion::kIntersect_Op);
143 static void test_contains_iter(skiatest::Reporter* reporter, const SkRegion& rgn) {
144 SkRegion::Iterator iter(rgn);
145 while (!iter.done()) {
146 SkIRect r = iter.rect();
147 REPORTER_ASSERT(reporter, rgn.contains(r));
149 REPORTER_ASSERT(reporter, !rgn.contains(r));
154 static void contains_proc(skiatest::Reporter* reporter,
155 const SkRegion& a, const SkRegion& b) {
157 bool c0 = a.contains(b);
158 bool c1 = slow_contains(a, b);
159 REPORTER_ASSERT(reporter, c0 == c1);
162 SkIRect r = a.getBounds();
163 r.inset(r.width()/4, r.height()/4);
165 c1 = slow_contains(a, r);
166 REPORTER_ASSERT(reporter, c0 == c1);
168 test_contains_iter(reporter, a);
169 test_contains_iter(reporter, b);
172 static void test_intersects_iter(skiatest::Reporter* reporter, const SkRegion& rgn) {
173 SkRegion::Iterator iter(rgn);
174 while (!iter.done()) {
175 SkIRect r = iter.rect();
176 REPORTER_ASSERT(reporter, rgn.intersects(r));
178 REPORTER_ASSERT(reporter, rgn.intersects(r));
183 static void intersects_proc(skiatest::Reporter* reporter,
184 const SkRegion& a, const SkRegion& b) {
185 bool c0 = a.intersects(b);
186 bool c1 = slow_intersects(a, b);
187 REPORTER_ASSERT(reporter, c0 == c1);
189 test_intersects_iter(reporter, a);
190 test_intersects_iter(reporter, b);
193 static void test_proc(skiatest::Reporter* reporter,
194 void (*proc)(skiatest::Reporter*,
195 const SkRegion& a, const SkRegion&)) {
197 for (int i = 0; i < 10000; ++i) {
199 randRgn(rand, &outer, 8);
201 randRgn(rand, &inner, 2);
202 proc(reporter, outer, inner);
206 static void rand_rect(SkIRect* rect, SkRandom& rand) {
208 int shift = 32 - bits;
209 rect->setLTRB(rand.nextU() >> shift, rand.nextU() >> shift,
210 rand.nextU() >> shift, rand.nextU() >> shift);
214 static bool test_rects(const SkIRect rect[], int count) {
217 for (int i = 0; i < count; i++) {
218 rgn0.op(rect[i], SkRegion::kUnion_Op);
220 rgn1.setRects(rect, count);
224 for (int i = 0; i < count; i++) {
225 SkDebugf(" { %d, %d, %d, %d },\n",
226 rect[i].fLeft, rect[i].fTop,
227 rect[i].fRight, rect[i].fBottom);
235 DEF_TEST(Region, reporter) {
236 const SkIRect r2[] = {
240 REPORTER_ASSERT(reporter, test_rects(r2, SK_ARRAY_COUNT(r2)));
242 const SkIRect rects[] = {
248 REPORTER_ASSERT(reporter, test_rects(rects, SK_ARRAY_COUNT(rects)));
251 for (int i = 0; i < 1000; i++) {
256 for (int j = 0; j < N; j++) {
257 rand_rect(&rect[j], rand);
259 REPORTER_ASSERT(reporter, test_rects(rect, N));
262 test_proc(reporter, contains_proc);
263 test_proc(reporter, intersects_proc);
264 test_empties(reporter);
265 test_fromchrome(reporter);
268 // Test that writeToMemory reports the same number of bytes whether there was a
269 // buffer to write to or not.
270 static void test_write(const SkRegion& region, skiatest::Reporter* r) {
271 const size_t bytesNeeded = region.writeToMemory(nullptr);
272 SkAutoMalloc storage(bytesNeeded);
273 const size_t bytesWritten = region.writeToMemory(storage.get());
274 REPORTER_ASSERT(r, bytesWritten == bytesNeeded);
276 // Also check that the bytes are meaningful.
278 REPORTER_ASSERT(r, copy.readFromMemory(storage.get(), bytesNeeded));
279 REPORTER_ASSERT(r, region == copy);
282 DEF_TEST(Region_writeToMemory, r) {
283 // Test an empty region.
285 REPORTER_ASSERT(r, region.isEmpty());
286 test_write(region, r);
288 // Test a rectangular region
289 bool nonEmpty = region.setRect({0, 0, 50, 50});
290 REPORTER_ASSERT(r, nonEmpty);
291 REPORTER_ASSERT(r, region.isRect());
292 test_write(region, r);
294 // Test a complex region
295 nonEmpty = region.op({50, 50, 100, 100}, SkRegion::kUnion_Op);
296 REPORTER_ASSERT(r, nonEmpty);
297 REPORTER_ASSERT(r, region.isComplex());
298 test_write(region, r);
300 SkRegion complexRegion;
301 Union(&complexRegion, SkIRect::MakeXYWH(0, 0, 1, 1));
302 Union(&complexRegion, SkIRect::MakeXYWH(0, 0, 3, 3));
303 Union(&complexRegion, SkIRect::MakeXYWH(10, 0, 3, 3));
304 Union(&complexRegion, SkIRect::MakeXYWH(0, 10, 13, 3));
305 test_write(complexRegion, r);
307 Union(&complexRegion, SkIRect::MakeXYWH(10, 20, 3, 3));
308 Union(&complexRegion, SkIRect::MakeXYWH(0, 20, 3, 3));
309 test_write(complexRegion, r);
312 DEF_TEST(Region_readFromMemory_bad, r) {
313 // These assume what our binary format is: conceivably we could change it
314 // and might need to remove or change some of these tests.
318 // invalid boundary rectangle
319 int32_t data[5] = {0, 4, 4, 8, 2};
320 REPORTER_ASSERT(r, 0 == region.readFromMemory(data, sizeof(data)));
322 // Region Layout, Serialized Format:
323 // COUNT LEFT TOP RIGHT BOTTOM Y_SPAN_COUNT TOTAL_INTERVAL_COUNT
324 // Top ( Bottom Span_Interval_Count ( Left Right )* Sentinel )+ Sentinel
326 // Example of valid data
327 int32_t data[] = {9, 0, 0, 10, 10, 1, 2, 0, 10, 2, 0, 4, 6, 10,
328 2147483647, 2147483647};
329 REPORTER_ASSERT(r, 0 != region.readFromMemory(data, sizeof(data)));
332 // Example of valid data with 4 intervals
333 int32_t data[] = {19, 0, 0, 30, 30, 3, 4, 0, 10, 2, 0, 10, 20, 30,
334 2147483647, 20, 0, 2147483647, 30, 2, 0, 10, 20, 30,
335 2147483647, 2147483647};
336 REPORTER_ASSERT(r, 0 != region.readFromMemory(data, sizeof(data)));
340 int32_t data[] = {8, 0, 0, 10, 10, 1, 2, 0, 10, 2, 0, 4, 6, 10,
341 2147483647, 2147483647};
342 REPORTER_ASSERT(r, 0 == region.readFromMemory(data, sizeof(data)));
345 // bounds don't match
346 int32_t data[] = {9, 0, 0, 10, 11, 1, 2, 0, 10, 2, 0, 4, 6, 10,
347 2147483647, 2147483647};
348 REPORTER_ASSERT(r, 0 == region.readFromMemory(data, sizeof(data)));
352 int32_t data[] = {9, 0, 0, 10, 10, 2, 2, 0, 10, 2, 0, 4, 6, 10,
353 2147483647, 2147483647};
354 REPORTER_ASSERT(r, 0 == region.readFromMemory(data, sizeof(data)));
358 int32_t data[] = {9, 0, 0, 10, 10, 1, 3, 0, 10, 2, 0, 4, 6, 10,
359 2147483647, 2147483647};
360 REPORTER_ASSERT(r, 0 == region.readFromMemory(data, sizeof(data)));
363 // bad final sentinal
364 int32_t data[] = {9, 0, 0, 10, 10, 1, 2, 0, 10, 2, 0, 4, 6, 10,
366 REPORTER_ASSERT(r, 0 == region.readFromMemory(data, sizeof(data)));
370 int32_t data[] = {9, 0, 0, 10, 10, 1, 2, 0, 10, 2, 0, 4, 6, 10,
372 REPORTER_ASSERT(r, 0 == region.readFromMemory(data, sizeof(data)));
375 // starts with empty yspan
376 int32_t data[] = {12, 0, 0, 10, 10, 2, 2, -5, 0, 0, 2147483647, 10,
377 2, 0, 4, 6, 10, 2147483647, 2147483647};
378 REPORTER_ASSERT(r, 0 == region.readFromMemory(data, sizeof(data)));
381 // ends with empty yspan
382 int32_t data[] = {12, 0, 0, 10, 10, 2, 2, 0, 10, 2, 0, 4, 6, 10,
383 2147483647, 15, 0, 2147483647, 2147483647};
384 REPORTER_ASSERT(r, 0 == region.readFromMemory(data, sizeof(data)));
387 // y intervals out of order
388 int32_t data[] = {19, 0, -20, 30, 10, 3, 4, 0, 10, 2, 0, 10, 20, 30,
389 2147483647, -20, 0, 2147483647, -10, 2, 0, 10, 20, 30,
390 2147483647, 2147483647};
391 REPORTER_ASSERT(r, 0 == region.readFromMemory(data, sizeof(data)));
394 // x intervals out of order
395 int32_t data[] = {9, 0, 0, 10, 10, 1, 2, 0, 10, 2, 6, 10, 0, 4,
396 2147483647, 2147483647};
397 REPORTER_ASSERT(r, 0 == region.readFromMemory(data, sizeof(data)));
401 DEF_TEST(region_toobig, reporter) {
402 const int big = 1 << 30;
403 const SkIRect neg = SkIRect::MakeXYWH(-big, -big, 10, 10);
404 const SkIRect pos = SkIRect::MakeXYWH( big, big, 10, 10);
406 REPORTER_ASSERT(reporter, !neg.isEmpty());
407 REPORTER_ASSERT(reporter, !pos.isEmpty());
412 REPORTER_ASSERT(reporter, !negR.isEmpty());
413 REPORTER_ASSERT(reporter, !posR.isEmpty());
416 rgn.op(negR, posR, SkRegion::kUnion_Op);
418 // If we union those to rectangles, the resulting coordinates span more than int32_t, so
419 // we must mark the region as empty.
420 REPORTER_ASSERT(reporter, rgn.isEmpty());
423 DEF_TEST(region_inverse_union_skbug_7491, reporter) {
425 path.setFillType(SkPathFillType::kInverseWinding);
426 path.moveTo(10, 20); path.lineTo(10, 30); path.lineTo(10.1f, 10); path.close();
429 clip.op(SkIRect::MakeLTRB(10, 10, 15, 20), SkRegion::kUnion_Op);
430 clip.op(SkIRect::MakeLTRB(20, 10, 25, 20), SkRegion::kUnion_Op);
433 rgn.setPath(path, clip);
435 REPORTER_ASSERT(reporter, clip == rgn);
438 DEF_TEST(giant_path_region, reporter) {
439 const SkScalar big = 32767;
441 path.moveTo(-big, 0);
442 path.quadTo(big, 0, big, big);
443 SkIRect ir = path.getBounds().round();
445 rgn.setPath(path, SkRegion(ir));
448 DEF_TEST(rrect_region_crbug_850350, reporter) {
452 m[3] = 1.40079998E+20f;
454 const SkPoint corners[] = {
455 { 2.65876e-19f, 0.0194088f },
456 { 4896, 0.00114702f },
458 { 0.00114702f, 0.00495333f },
461 rrect.setRectRadii({-8.72387e-31f, 1.29996e-38f, 4896, 1.125f}, corners);
464 path.addRRect(rrect);
468 rgn.setPath(path, SkRegion{SkIRect{0, 0, 24, 24}});
471 DEF_TEST(region_bug_chromium_873051, reporter) {
473 REPORTER_ASSERT(reporter, region.setRect({0, 0, 0x7FFFFFFE, 0x7FFFFFFE}));
474 REPORTER_ASSERT(reporter, !region.setRect({0, 0, 0x7FFFFFFE, 0x7FFFFFFF}));
475 REPORTER_ASSERT(reporter, !region.setRect({0, 0, 0x7FFFFFFF, 0x7FFFFFFE}));
476 REPORTER_ASSERT(reporter, !region.setRect({0, 0, 0x7FFFFFFF, 0x7FFFFFFF}));
479 DEF_TEST(region_empty_iter, reporter) {
480 SkRegion::Iterator emptyIter;
481 REPORTER_ASSERT(reporter, !emptyIter.rewind());
482 REPORTER_ASSERT(reporter, emptyIter.done());
483 auto eRect = emptyIter.rect();
484 REPORTER_ASSERT(reporter, eRect.isEmpty());
485 REPORTER_ASSERT(reporter, SkIRect::MakeEmpty() == eRect);
486 REPORTER_ASSERT(reporter, !emptyIter.rgn());
489 SkRegion::Iterator resetIter;
490 resetIter.reset(region);
491 REPORTER_ASSERT(reporter, resetIter.rewind());
492 REPORTER_ASSERT(reporter, resetIter.done());
493 auto rRect = resetIter.rect();
494 REPORTER_ASSERT(reporter, rRect.isEmpty());
495 REPORTER_ASSERT(reporter, SkIRect::MakeEmpty() == rRect);
496 REPORTER_ASSERT(reporter, resetIter.rgn());
497 REPORTER_ASSERT(reporter, resetIter.rgn()->isEmpty());
499 SkRegion::Iterator iter(region);
500 REPORTER_ASSERT(reporter, iter.done());
501 auto iRect = iter.rect();
502 REPORTER_ASSERT(reporter, iRect.isEmpty());
503 REPORTER_ASSERT(reporter, SkIRect::MakeEmpty() == iRect);
504 REPORTER_ASSERT(reporter, iter.rgn());
505 REPORTER_ASSERT(reporter, iter.rgn()->isEmpty());
507 SkRegion::Cliperator clipIter(region, {0, 0, 100, 100});
508 REPORTER_ASSERT(reporter, clipIter.done());
509 auto cRect = clipIter.rect();
510 REPORTER_ASSERT(reporter, cRect.isEmpty());
511 REPORTER_ASSERT(reporter, SkIRect::MakeEmpty() == cRect);
513 SkRegion::Spanerator spanIter(region, 0, 0, 100);
514 int left = 0, right = 0;
515 REPORTER_ASSERT(reporter, !spanIter.next(&left, &right));
516 REPORTER_ASSERT(reporter, !left);
517 REPORTER_ASSERT(reporter, !right);