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