1 /*
2 * Copyright 2011 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 "include/core/SkMatrix.h"
9 #include "include/core/SkPath.h"
10 #include "include/core/SkPathTypes.h"
11 #include "include/core/SkPoint.h"
12 #include "include/core/SkRRect.h"
13 #include "include/core/SkRect.h"
14 #include "include/core/SkRegion.h"
15 #include "include/core/SkScalar.h"
16 #include "include/core/SkTypes.h"
17 #include "include/private/base/SkDebug.h"
18 #include "src/base/SkAutoMalloc.h"
19 #include "src/base/SkRandom.h"
20 #include "tests/Test.h"
21
22 #include <array>
23 #include <cstddef>
24 #include <cstdint>
25
Union(SkRegion * rgn,const SkIRect & rect)26 static void Union(SkRegion* rgn, const SkIRect& rect) {
27 rgn->op(rect, SkRegion::kUnion_Op);
28 }
29
30 #define TEST_NO_INTERSECT(rgn, rect) REPORTER_ASSERT(reporter, !rgn.intersects(rect))
31 #define TEST_INTERSECT(rgn, rect) REPORTER_ASSERT(reporter, rgn.intersects(rect))
32 #define TEST_NO_CONTAINS(rgn, rect) REPORTER_ASSERT(reporter, !rgn.contains(rect))
33
34 // inspired by http://code.google.com/p/skia/issues/detail?id=958
35 //
test_fromchrome(skiatest::Reporter * reporter)36 static void test_fromchrome(skiatest::Reporter* reporter) {
37 SkRegion r;
38 Union(&r, SkIRect::MakeXYWH(0, 0, 1, 1));
39 TEST_NO_INTERSECT(r, SkIRect::MakeXYWH(0, 0, 0, 0));
40 TEST_INTERSECT(r, SkIRect::MakeXYWH(0, 0, 2, 2));
41 TEST_INTERSECT(r, SkIRect::MakeXYWH(-1, 0, 2, 2));
42 TEST_INTERSECT(r, SkIRect::MakeXYWH(-1, -1, 2, 2));
43 TEST_INTERSECT(r, SkIRect::MakeXYWH(0, -1, 2, 2));
44 TEST_INTERSECT(r, SkIRect::MakeXYWH(-1, -1, 3, 3));
45
46 Union(&r, SkIRect::MakeXYWH(0, 0, 3, 3));
47 Union(&r, SkIRect::MakeXYWH(10, 0, 3, 3));
48 Union(&r, SkIRect::MakeXYWH(0, 10, 13, 3));
49 TEST_INTERSECT(r, SkIRect::MakeXYWH(-1, -1, 2, 2));
50 TEST_INTERSECT(r, SkIRect::MakeXYWH(2, -1, 2, 2));
51 TEST_INTERSECT(r, SkIRect::MakeXYWH(2, 2, 2, 2));
52 TEST_INTERSECT(r, SkIRect::MakeXYWH(-1, 2, 2, 2));
53
54 TEST_INTERSECT(r, SkIRect::MakeXYWH(9, -1, 2, 2));
55 TEST_INTERSECT(r, SkIRect::MakeXYWH(12, -1, 2, 2));
56 TEST_INTERSECT(r, SkIRect::MakeXYWH(12, 2, 2, 2));
57 TEST_INTERSECT(r, SkIRect::MakeXYWH(9, 2, 2, 2));
58
59 TEST_INTERSECT(r, SkIRect::MakeXYWH(0, -1, 13, 5));
60 TEST_INTERSECT(r, SkIRect::MakeXYWH(1, -1, 11, 5));
61 TEST_INTERSECT(r, SkIRect::MakeXYWH(2, -1, 9, 5));
62 TEST_INTERSECT(r, SkIRect::MakeXYWH(2, -1, 8, 5));
63 TEST_INTERSECT(r, SkIRect::MakeXYWH(3, -1, 8, 5));
64
65 TEST_INTERSECT(r, SkIRect::MakeXYWH(0, 1, 13, 1));
66 TEST_INTERSECT(r, SkIRect::MakeXYWH(1, 1, 11, 1));
67 TEST_INTERSECT(r, SkIRect::MakeXYWH(2, 1, 9, 1));
68 TEST_INTERSECT(r, SkIRect::MakeXYWH(2, 1, 8, 1));
69 TEST_INTERSECT(r, SkIRect::MakeXYWH(3, 1, 8, 1));
70
71 TEST_INTERSECT(r, SkIRect::MakeXYWH(0, 0, 13, 13));
72 TEST_INTERSECT(r, SkIRect::MakeXYWH(0, 1, 13, 11));
73 TEST_INTERSECT(r, SkIRect::MakeXYWH(0, 2, 13, 9));
74 TEST_INTERSECT(r, SkIRect::MakeXYWH(0, 2, 13, 8));
75
76
77 // These test SkRegion::contains(Rect) and SkRegion::contains(Region)
78
79 SkRegion container;
80 Union(&container, SkIRect::MakeXYWH(0, 0, 40, 20));
81 Union(&container, SkIRect::MakeXYWH(30, 20, 10, 20));
82 TEST_NO_CONTAINS(container, SkIRect::MakeXYWH(0, 0, 10, 39));
83 TEST_NO_CONTAINS(container, SkIRect::MakeXYWH(29, 0, 10, 39));
84
85 {
86 SkRegion rgn;
87 Union(&rgn, SkIRect::MakeXYWH(0, 0, 10, 10));
88 Union(&rgn, SkIRect::MakeLTRB(5, 10, 20, 20));
89 TEST_INTERSECT(rgn, SkIRect::MakeXYWH(15, 0, 5, 11));
90 }
91 }
92
test_empties(skiatest::Reporter * reporter)93 static void test_empties(skiatest::Reporter* reporter) {
94 SkRegion valid(SkIRect::MakeWH(10, 10));
95 SkRegion empty, empty2;
96
97 REPORTER_ASSERT(reporter, empty.isEmpty());
98 REPORTER_ASSERT(reporter, !valid.isEmpty());
99
100 // test intersects
101 REPORTER_ASSERT(reporter, !empty.intersects(empty2));
102 REPORTER_ASSERT(reporter, !valid.intersects(empty));
103
104 // test contains
105 REPORTER_ASSERT(reporter, !empty.contains(empty2));
106 REPORTER_ASSERT(reporter, !valid.contains(empty));
107 REPORTER_ASSERT(reporter, !empty.contains(valid));
108
109 SkPath emptyPath;
110 emptyPath.moveTo(1, 5);
111 emptyPath.close();
112 SkRegion openClip;
113 openClip.setRect({-16000, -16000, 16000, 16000});
114 empty.setPath(emptyPath, openClip); // should not assert
115 }
116
117 enum {
118 W = 256,
119 H = 256
120 };
121
randRect(SkRandom & rand)122 static SkIRect randRect(SkRandom& rand) {
123 int x = rand.nextU() % W;
124 int y = rand.nextU() % H;
125 int w = rand.nextU() % W;
126 int h = rand.nextU() % H;
127 return SkIRect::MakeXYWH(x, y, w >> 1, h >> 1);
128 }
129
randRgn(SkRandom & rand,SkRegion * rgn,int n)130 static void randRgn(SkRandom& rand, SkRegion* rgn, int n) {
131 rgn->setEmpty();
132 for (int i = 0; i < n; ++i) {
133 rgn->op(randRect(rand), SkRegion::kUnion_Op);
134 }
135 }
136
slow_contains(const SkRegion & outer,const SkRegion & inner)137 static bool slow_contains(const SkRegion& outer, const SkRegion& inner) {
138 SkRegion tmp;
139 tmp.op(outer, inner, SkRegion::kUnion_Op);
140 return outer == tmp;
141 }
142
slow_contains(const SkRegion & outer,const SkIRect & r)143 static bool slow_contains(const SkRegion& outer, const SkIRect& r) {
144 SkRegion tmp;
145 tmp.op(outer, SkRegion(r), SkRegion::kUnion_Op);
146 return outer == tmp;
147 }
148
slow_intersects(const SkRegion & outer,const SkRegion & inner)149 static bool slow_intersects(const SkRegion& outer, const SkRegion& inner) {
150 SkRegion tmp;
151 return tmp.op(outer, inner, SkRegion::kIntersect_Op);
152 }
153
test_contains_iter(skiatest::Reporter * reporter,const SkRegion & rgn)154 static void test_contains_iter(skiatest::Reporter* reporter, const SkRegion& rgn) {
155 SkRegion::Iterator iter(rgn);
156 while (!iter.done()) {
157 SkIRect r = iter.rect();
158 REPORTER_ASSERT(reporter, rgn.contains(r));
159 r.inset(-1, -1);
160 REPORTER_ASSERT(reporter, !rgn.contains(r));
161 iter.next();
162 }
163 }
164
contains_proc(skiatest::Reporter * reporter,const SkRegion & a,const SkRegion & b)165 static void contains_proc(skiatest::Reporter* reporter,
166 const SkRegion& a, const SkRegion& b) {
167 // test rgn
168 bool c0 = a.contains(b);
169 bool c1 = slow_contains(a, b);
170 REPORTER_ASSERT(reporter, c0 == c1);
171
172 // test rect
173 SkIRect r = a.getBounds();
174 r.inset(r.width()/4, r.height()/4);
175 c0 = a.contains(r);
176 c1 = slow_contains(a, r);
177 REPORTER_ASSERT(reporter, c0 == c1);
178
179 test_contains_iter(reporter, a);
180 test_contains_iter(reporter, b);
181 }
182
test_intersects_iter(skiatest::Reporter * reporter,const SkRegion & rgn)183 static void test_intersects_iter(skiatest::Reporter* reporter, const SkRegion& rgn) {
184 SkRegion::Iterator iter(rgn);
185 while (!iter.done()) {
186 SkIRect r = iter.rect();
187 REPORTER_ASSERT(reporter, rgn.intersects(r));
188 r.inset(-1, -1);
189 REPORTER_ASSERT(reporter, rgn.intersects(r));
190 iter.next();
191 }
192 }
193
intersects_proc(skiatest::Reporter * reporter,const SkRegion & a,const SkRegion & b)194 static void intersects_proc(skiatest::Reporter* reporter,
195 const SkRegion& a, const SkRegion& b) {
196 bool c0 = a.intersects(b);
197 bool c1 = slow_intersects(a, b);
198 REPORTER_ASSERT(reporter, c0 == c1);
199
200 test_intersects_iter(reporter, a);
201 test_intersects_iter(reporter, b);
202 }
203
test_proc(skiatest::Reporter * reporter,void (* proc)(skiatest::Reporter *,const SkRegion & a,const SkRegion &))204 static void test_proc(skiatest::Reporter* reporter,
205 void (*proc)(skiatest::Reporter*,
206 const SkRegion& a, const SkRegion&)) {
207 SkRandom rand;
208 for (int i = 0; i < 10000; ++i) {
209 SkRegion outer;
210 randRgn(rand, &outer, 8);
211 SkRegion inner;
212 randRgn(rand, &inner, 2);
213 proc(reporter, outer, inner);
214 }
215 }
216
rand_rect(SkIRect * rect,SkRandom & rand)217 static void rand_rect(SkIRect* rect, SkRandom& rand) {
218 int bits = 6;
219 int shift = 32 - bits;
220 rect->setLTRB(rand.nextU() >> shift, rand.nextU() >> shift,
221 rand.nextU() >> shift, rand.nextU() >> shift);
222 rect->sort();
223 }
224
test_rects(const SkIRect rect[],int count)225 static bool test_rects(const SkIRect rect[], int count) {
226 SkRegion rgn0, rgn1;
227
228 for (int i = 0; i < count; i++) {
229 rgn0.op(rect[i], SkRegion::kUnion_Op);
230 }
231 rgn1.setRects(rect, count);
232
233 if (rgn0 != rgn1) {
234 SkDebugf("\n");
235 for (int i = 0; i < count; i++) {
236 SkDebugf(" { %d, %d, %d, %d },\n",
237 rect[i].fLeft, rect[i].fTop,
238 rect[i].fRight, rect[i].fBottom);
239 }
240 SkDebugf("\n");
241 return false;
242 }
243 return true;
244 }
245
DEF_TEST(Region,reporter)246 DEF_TEST(Region, reporter) {
247 const SkIRect r2[] = {
248 { 0, 0, 1, 1 },
249 { 2, 2, 3, 3 },
250 };
251 REPORTER_ASSERT(reporter, test_rects(r2, std::size(r2)));
252
253 const SkIRect rects[] = {
254 { 0, 0, 1, 2 },
255 { 2, 1, 3, 3 },
256 { 4, 0, 5, 1 },
257 { 6, 0, 7, 4 },
258 };
259 REPORTER_ASSERT(reporter, test_rects(rects, std::size(rects)));
260
261 SkRandom rand;
262 for (int i = 0; i < 1000; i++) {
263 SkRegion rgn0, rgn1;
264
265 const int N = 8;
266 SkIRect rect[N];
267 for (int j = 0; j < N; j++) {
268 rand_rect(&rect[j], rand);
269 }
270 REPORTER_ASSERT(reporter, test_rects(rect, N));
271 }
272
273 test_proc(reporter, contains_proc);
274 test_proc(reporter, intersects_proc);
275 test_empties(reporter);
276 test_fromchrome(reporter);
277 }
278
279 // Test that writeToMemory reports the same number of bytes whether there was a
280 // buffer to write to or not.
test_write(const SkRegion & region,skiatest::Reporter * r)281 static void test_write(const SkRegion& region, skiatest::Reporter* r) {
282 const size_t bytesNeeded = region.writeToMemory(nullptr);
283 SkAutoMalloc storage(bytesNeeded);
284 const size_t bytesWritten = region.writeToMemory(storage.get());
285 REPORTER_ASSERT(r, bytesWritten == bytesNeeded);
286
287 // Also check that the bytes are meaningful.
288 SkRegion copy;
289 REPORTER_ASSERT(r, copy.readFromMemory(storage.get(), bytesNeeded));
290 REPORTER_ASSERT(r, region == copy);
291 }
292
DEF_TEST(Region_writeToMemory,r)293 DEF_TEST(Region_writeToMemory, r) {
294 // Test an empty region.
295 SkRegion region;
296 REPORTER_ASSERT(r, region.isEmpty());
297 test_write(region, r);
298
299 // Test a rectangular region
300 bool nonEmpty = region.setRect({0, 0, 50, 50});
301 REPORTER_ASSERT(r, nonEmpty);
302 REPORTER_ASSERT(r, region.isRect());
303 test_write(region, r);
304
305 // Test a complex region
306 nonEmpty = region.op({50, 50, 100, 100}, SkRegion::kUnion_Op);
307 REPORTER_ASSERT(r, nonEmpty);
308 REPORTER_ASSERT(r, region.isComplex());
309 test_write(region, r);
310
311 SkRegion complexRegion;
312 Union(&complexRegion, SkIRect::MakeXYWH(0, 0, 1, 1));
313 Union(&complexRegion, SkIRect::MakeXYWH(0, 0, 3, 3));
314 Union(&complexRegion, SkIRect::MakeXYWH(10, 0, 3, 3));
315 Union(&complexRegion, SkIRect::MakeXYWH(0, 10, 13, 3));
316 test_write(complexRegion, r);
317
318 Union(&complexRegion, SkIRect::MakeXYWH(10, 20, 3, 3));
319 Union(&complexRegion, SkIRect::MakeXYWH(0, 20, 3, 3));
320 test_write(complexRegion, r);
321 }
322
DEF_TEST(Region_readFromMemory_bad,r)323 DEF_TEST(Region_readFromMemory_bad, r) {
324 // These assume what our binary format is: conceivably we could change it
325 // and might need to remove or change some of these tests.
326 SkRegion region;
327
328 {
329 // invalid boundary rectangle
330 int32_t data[5] = {0, 4, 4, 8, 2};
331 REPORTER_ASSERT(r, 0 == region.readFromMemory(data, sizeof(data)));
332 }
333 // Region Layout, Serialized Format:
334 // COUNT LEFT TOP RIGHT BOTTOM Y_SPAN_COUNT TOTAL_INTERVAL_COUNT
335 // Top ( Bottom Span_Interval_Count ( Left Right )* Sentinel )+ Sentinel
336 {
337 // Example of valid data
338 int32_t data[] = {9, 0, 0, 10, 10, 1, 2, 0, 10, 2, 0, 4, 6, 10,
339 2147483647, 2147483647};
340 REPORTER_ASSERT(r, 0 != region.readFromMemory(data, sizeof(data)));
341 }
342 {
343 // Example of valid data with 4 intervals
344 int32_t data[] = {19, 0, 0, 30, 30, 3, 4, 0, 10, 2, 0, 10, 20, 30,
345 2147483647, 20, 0, 2147483647, 30, 2, 0, 10, 20, 30,
346 2147483647, 2147483647};
347 REPORTER_ASSERT(r, 0 != region.readFromMemory(data, sizeof(data)));
348 }
349 {
350 // Short count
351 int32_t data[] = {8, 0, 0, 10, 10, 1, 2, 0, 10, 2, 0, 4, 6, 10,
352 2147483647, 2147483647};
353 REPORTER_ASSERT(r, 0 == region.readFromMemory(data, sizeof(data)));
354 }
355 {
356 // bounds don't match
357 int32_t data[] = {9, 0, 0, 10, 11, 1, 2, 0, 10, 2, 0, 4, 6, 10,
358 2147483647, 2147483647};
359 REPORTER_ASSERT(r, 0 == region.readFromMemory(data, sizeof(data)));
360 }
361 {
362 // bad yspan count
363 int32_t data[] = {9, 0, 0, 10, 10, 2, 2, 0, 10, 2, 0, 4, 6, 10,
364 2147483647, 2147483647};
365 REPORTER_ASSERT(r, 0 == region.readFromMemory(data, sizeof(data)));
366 }
367 {
368 // bad int count
369 int32_t data[] = {9, 0, 0, 10, 10, 1, 3, 0, 10, 2, 0, 4, 6, 10,
370 2147483647, 2147483647};
371 REPORTER_ASSERT(r, 0 == region.readFromMemory(data, sizeof(data)));
372 }
373 {
374 // bad final sentinal
375 int32_t data[] = {9, 0, 0, 10, 10, 1, 2, 0, 10, 2, 0, 4, 6, 10,
376 2147483647, -1};
377 REPORTER_ASSERT(r, 0 == region.readFromMemory(data, sizeof(data)));
378 }
379 {
380 // bad row sentinal
381 int32_t data[] = {9, 0, 0, 10, 10, 1, 2, 0, 10, 2, 0, 4, 6, 10,
382 -1, 2147483647};
383 REPORTER_ASSERT(r, 0 == region.readFromMemory(data, sizeof(data)));
384 }
385 {
386 // starts with empty yspan
387 int32_t data[] = {12, 0, 0, 10, 10, 2, 2, -5, 0, 0, 2147483647, 10,
388 2, 0, 4, 6, 10, 2147483647, 2147483647};
389 REPORTER_ASSERT(r, 0 == region.readFromMemory(data, sizeof(data)));
390 }
391 {
392 // ends with empty yspan
393 int32_t data[] = {12, 0, 0, 10, 10, 2, 2, 0, 10, 2, 0, 4, 6, 10,
394 2147483647, 15, 0, 2147483647, 2147483647};
395 REPORTER_ASSERT(r, 0 == region.readFromMemory(data, sizeof(data)));
396 }
397 {
398 // y intervals out of order
399 int32_t data[] = {19, 0, -20, 30, 10, 3, 4, 0, 10, 2, 0, 10, 20, 30,
400 2147483647, -20, 0, 2147483647, -10, 2, 0, 10, 20, 30,
401 2147483647, 2147483647};
402 REPORTER_ASSERT(r, 0 == region.readFromMemory(data, sizeof(data)));
403 }
404 {
405 // x intervals out of order
406 int32_t data[] = {9, 0, 0, 10, 10, 1, 2, 0, 10, 2, 6, 10, 0, 4,
407 2147483647, 2147483647};
408 REPORTER_ASSERT(r, 0 == region.readFromMemory(data, sizeof(data)));
409 }
410 }
411
DEF_TEST(region_toobig,reporter)412 DEF_TEST(region_toobig, reporter) {
413 const int big = 1 << 30;
414 const SkIRect neg = SkIRect::MakeXYWH(-big, -big, 10, 10);
415 const SkIRect pos = SkIRect::MakeXYWH( big, big, 10, 10);
416
417 REPORTER_ASSERT(reporter, !neg.isEmpty());
418 REPORTER_ASSERT(reporter, !pos.isEmpty());
419
420 SkRegion negR(neg);
421 SkRegion posR(pos);
422
423 REPORTER_ASSERT(reporter, !negR.isEmpty());
424 REPORTER_ASSERT(reporter, !posR.isEmpty());
425
426 SkRegion rgn;
427 rgn.op(negR, posR, SkRegion::kUnion_Op);
428
429 // If we union those to rectangles, the resulting coordinates span more than int32_t, so
430 // we must mark the region as empty.
431 REPORTER_ASSERT(reporter, rgn.isEmpty());
432 }
433
DEF_TEST(region_inverse_union_skbug_7491,reporter)434 DEF_TEST(region_inverse_union_skbug_7491, reporter) {
435 SkPath path;
436 path.setFillType(SkPathFillType::kInverseWinding);
437 path.moveTo(10, 20); path.lineTo(10, 30); path.lineTo(10.1f, 10); path.close();
438
439 SkRegion clip;
440 clip.op(SkIRect::MakeLTRB(10, 10, 15, 20), SkRegion::kUnion_Op);
441 clip.op(SkIRect::MakeLTRB(20, 10, 25, 20), SkRegion::kUnion_Op);
442
443 SkRegion rgn;
444 rgn.setPath(path, clip);
445
446 REPORTER_ASSERT(reporter, clip == rgn);
447 }
448
DEF_TEST(giant_path_region,reporter)449 DEF_TEST(giant_path_region, reporter) {
450 const SkScalar big = 32767;
451 SkPath path;
452 path.moveTo(-big, 0);
453 path.quadTo(big, 0, big, big);
454 SkIRect ir = path.getBounds().round();
455 SkRegion rgn;
456 rgn.setPath(path, SkRegion(ir));
457 }
458
DEF_TEST(rrect_region_crbug_850350,reporter)459 DEF_TEST(rrect_region_crbug_850350, reporter) {
460 SkMatrix m;
461 m.reset();
462 m[1] = 0.753662348f;
463 m[3] = 1.40079998E+20f;
464
465 const SkPoint corners[] = {
466 { 2.65876e-19f, 0.0194088f },
467 { 4896, 0.00114702f },
468 { 0, 0 },
469 { 0.00114702f, 0.00495333f },
470 };
471 SkRRect rrect;
472 rrect.setRectRadii({-8.72387e-31f, 1.29996e-38f, 4896, 1.125f}, corners);
473
474 SkPath path;
475 path.addRRect(rrect);
476 path.transform(m);
477
478 SkRegion rgn;
479 rgn.setPath(path, SkRegion{SkIRect{0, 0, 24, 24}});
480 }
481
DEF_TEST(region_bug_chromium_873051,reporter)482 DEF_TEST(region_bug_chromium_873051, reporter) {
483 SkRegion region;
484 REPORTER_ASSERT(reporter, region.setRect({0, 0, 0x7FFFFFFE, 0x7FFFFFFE}));
485 REPORTER_ASSERT(reporter, !region.setRect({0, 0, 0x7FFFFFFE, 0x7FFFFFFF}));
486 REPORTER_ASSERT(reporter, !region.setRect({0, 0, 0x7FFFFFFF, 0x7FFFFFFE}));
487 REPORTER_ASSERT(reporter, !region.setRect({0, 0, 0x7FFFFFFF, 0x7FFFFFFF}));
488 }
489
DEF_TEST(region_empty_iter,reporter)490 DEF_TEST(region_empty_iter, reporter) {
491 SkRegion::Iterator emptyIter;
492 REPORTER_ASSERT(reporter, !emptyIter.rewind());
493 REPORTER_ASSERT(reporter, emptyIter.done());
494 auto eRect = emptyIter.rect();
495 REPORTER_ASSERT(reporter, eRect.isEmpty());
496 REPORTER_ASSERT(reporter, SkIRect::MakeEmpty() == eRect);
497 REPORTER_ASSERT(reporter, !emptyIter.rgn());
498
499 SkRegion region;
500 SkRegion::Iterator resetIter;
501 resetIter.reset(region);
502 REPORTER_ASSERT(reporter, resetIter.rewind());
503 REPORTER_ASSERT(reporter, resetIter.done());
504 auto rRect = resetIter.rect();
505 REPORTER_ASSERT(reporter, rRect.isEmpty());
506 REPORTER_ASSERT(reporter, SkIRect::MakeEmpty() == rRect);
507 REPORTER_ASSERT(reporter, resetIter.rgn());
508 REPORTER_ASSERT(reporter, resetIter.rgn()->isEmpty());
509
510 SkRegion::Iterator iter(region);
511 REPORTER_ASSERT(reporter, iter.done());
512 auto iRect = iter.rect();
513 REPORTER_ASSERT(reporter, iRect.isEmpty());
514 REPORTER_ASSERT(reporter, SkIRect::MakeEmpty() == iRect);
515 REPORTER_ASSERT(reporter, iter.rgn());
516 REPORTER_ASSERT(reporter, iter.rgn()->isEmpty());
517
518 SkRegion::Cliperator clipIter(region, {0, 0, 100, 100});
519 REPORTER_ASSERT(reporter, clipIter.done());
520 auto cRect = clipIter.rect();
521 REPORTER_ASSERT(reporter, cRect.isEmpty());
522 REPORTER_ASSERT(reporter, SkIRect::MakeEmpty() == cRect);
523
524 SkRegion::Spanerator spanIter(region, 0, 0, 100);
525 int left = 0, right = 0;
526 REPORTER_ASSERT(reporter, !spanIter.next(&left, &right));
527 REPORTER_ASSERT(reporter, !left);
528 REPORTER_ASSERT(reporter, !right);
529 }
530