Home | History | Annotate | Download | only in tests
      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 "SkPath.h"
      9 #include "SkRandom.h"
     10 #include "SkRegion.h"
     11 #include "Test.h"
     12 
     13 static void Union(SkRegion* rgn, const SkIRect& rect) {
     14     rgn->op(rect, SkRegion::kUnion_Op);
     15 }
     16 
     17 #define TEST_NO_INTERSECT(rgn, rect)    REPORTER_ASSERT(reporter, !rgn.intersects(rect))
     18 #define TEST_INTERSECT(rgn, rect)       REPORTER_ASSERT(reporter, rgn.intersects(rect))
     19 #define TEST_NO_CONTAINS(rgn, rect)     REPORTER_ASSERT(reporter, !rgn.contains(rect))
     20 
     21 // inspired by http://code.google.com/p/skia/issues/detail?id=958
     22 //
     23 static void test_fromchrome(skiatest::Reporter* reporter) {
     24     SkRegion r;
     25     Union(&r, SkIRect::MakeXYWH(0, 0, 1, 1));
     26     TEST_NO_INTERSECT(r, SkIRect::MakeXYWH(0, 0, 0, 0));
     27     TEST_INTERSECT(r, SkIRect::MakeXYWH(0, 0, 2, 2));
     28     TEST_INTERSECT(r, SkIRect::MakeXYWH(-1, 0, 2, 2));
     29     TEST_INTERSECT(r, SkIRect::MakeXYWH(-1, -1, 2, 2));
     30     TEST_INTERSECT(r, SkIRect::MakeXYWH(0, -1, 2, 2));
     31     TEST_INTERSECT(r, SkIRect::MakeXYWH(-1, -1, 3, 3));
     32 
     33     Union(&r, SkIRect::MakeXYWH(0, 0, 3, 3));
     34     Union(&r, SkIRect::MakeXYWH(10, 0, 3, 3));
     35     Union(&r, SkIRect::MakeXYWH(0, 10, 13, 3));
     36     TEST_INTERSECT(r, SkIRect::MakeXYWH(-1, -1, 2, 2));
     37     TEST_INTERSECT(r, SkIRect::MakeXYWH(2, -1, 2, 2));
     38     TEST_INTERSECT(r, SkIRect::MakeXYWH(2, 2, 2, 2));
     39     TEST_INTERSECT(r, SkIRect::MakeXYWH(-1, 2, 2, 2));
     40 
     41     TEST_INTERSECT(r, SkIRect::MakeXYWH(9, -1, 2, 2));
     42     TEST_INTERSECT(r, SkIRect::MakeXYWH(12, -1, 2, 2));
     43     TEST_INTERSECT(r, SkIRect::MakeXYWH(12, 2, 2, 2));
     44     TEST_INTERSECT(r, SkIRect::MakeXYWH(9, 2, 2, 2));
     45 
     46     TEST_INTERSECT(r, SkIRect::MakeXYWH(0, -1, 13, 5));
     47     TEST_INTERSECT(r, SkIRect::MakeXYWH(1, -1, 11, 5));
     48     TEST_INTERSECT(r, SkIRect::MakeXYWH(2, -1, 9, 5));
     49     TEST_INTERSECT(r, SkIRect::MakeXYWH(2, -1, 8, 5));
     50     TEST_INTERSECT(r, SkIRect::MakeXYWH(3, -1, 8, 5));
     51 
     52     TEST_INTERSECT(r, SkIRect::MakeXYWH(0, 1, 13, 1));
     53     TEST_INTERSECT(r, SkIRect::MakeXYWH(1, 1, 11, 1));
     54     TEST_INTERSECT(r, SkIRect::MakeXYWH(2, 1, 9, 1));
     55     TEST_INTERSECT(r, SkIRect::MakeXYWH(2, 1, 8, 1));
     56     TEST_INTERSECT(r, SkIRect::MakeXYWH(3, 1, 8, 1));
     57 
     58     TEST_INTERSECT(r, SkIRect::MakeXYWH(0, 0, 13, 13));
     59     TEST_INTERSECT(r, SkIRect::MakeXYWH(0, 1, 13, 11));
     60     TEST_INTERSECT(r, SkIRect::MakeXYWH(0, 2, 13, 9));
     61     TEST_INTERSECT(r, SkIRect::MakeXYWH(0, 2, 13, 8));
     62 
     63 
     64     // These test SkRegion::contains(Rect) and SkRegion::contains(Region)
     65 
     66     SkRegion container;
     67     Union(&container, SkIRect::MakeXYWH(0, 0, 40, 20));
     68     Union(&container, SkIRect::MakeXYWH(30, 20, 10, 20));
     69     TEST_NO_CONTAINS(container, SkIRect::MakeXYWH(0, 0, 10, 39));
     70     TEST_NO_CONTAINS(container, SkIRect::MakeXYWH(29, 0, 10, 39));
     71 
     72     {
     73         SkRegion rgn;
     74         Union(&rgn, SkIRect::MakeXYWH(0, 0, 10, 10));
     75         Union(&rgn, SkIRect::MakeLTRB(5, 10, 20, 20));
     76         TEST_INTERSECT(rgn, SkIRect::MakeXYWH(15, 0, 5, 11));
     77     }
     78 }
     79 
     80 static void test_empties(skiatest::Reporter* reporter) {
     81     SkRegion valid(SkIRect::MakeWH(10, 10));
     82     SkRegion empty, empty2;
     83 
     84     REPORTER_ASSERT(reporter, empty.isEmpty());
     85     REPORTER_ASSERT(reporter, !valid.isEmpty());
     86 
     87     // test intersects
     88     REPORTER_ASSERT(reporter, !empty.intersects(empty2));
     89     REPORTER_ASSERT(reporter, !valid.intersects(empty));
     90 
     91     // test contains
     92     REPORTER_ASSERT(reporter, !empty.contains(empty2));
     93     REPORTER_ASSERT(reporter, !valid.contains(empty));
     94     REPORTER_ASSERT(reporter, !empty.contains(valid));
     95 
     96     SkPath emptyPath;
     97     emptyPath.moveTo(1, 5);
     98     emptyPath.close();
     99     SkRegion openClip;
    100     openClip.setRect(-16000, -16000, 16000, 16000);
    101     empty.setPath(emptyPath, openClip);  // should not assert
    102 }
    103 
    104 enum {
    105     W = 256,
    106     H = 256
    107 };
    108 
    109 static SkIRect randRect(SkRandom& rand) {
    110     int x = rand.nextU() % W;
    111     int y = rand.nextU() % H;
    112     int w = rand.nextU() % W;
    113     int h = rand.nextU() % H;
    114     return SkIRect::MakeXYWH(x, y, w >> 1, h >> 1);
    115 }
    116 
    117 static void randRgn(SkRandom& rand, SkRegion* rgn, int n) {
    118     rgn->setEmpty();
    119     for (int i = 0; i < n; ++i) {
    120         rgn->op(randRect(rand), SkRegion::kUnion_Op);
    121     }
    122 }
    123 
    124 static bool slow_contains(const SkRegion& outer, const SkRegion& inner) {
    125     SkRegion tmp;
    126     tmp.op(outer, inner, SkRegion::kUnion_Op);
    127     return outer == tmp;
    128 }
    129 
    130 static bool slow_contains(const SkRegion& outer, const SkIRect& r) {
    131     SkRegion tmp;
    132     tmp.op(outer, SkRegion(r), SkRegion::kUnion_Op);
    133     return outer == tmp;
    134 }
    135 
    136 static bool slow_intersects(const SkRegion& outer, const SkRegion& inner) {
    137     SkRegion tmp;
    138     return tmp.op(outer, inner, SkRegion::kIntersect_Op);
    139 }
    140 
    141 static void test_contains_iter(skiatest::Reporter* reporter, const SkRegion& rgn) {
    142     SkRegion::Iterator iter(rgn);
    143     while (!iter.done()) {
    144         SkIRect r = iter.rect();
    145         REPORTER_ASSERT(reporter, rgn.contains(r));
    146         r.inset(-1, -1);
    147         REPORTER_ASSERT(reporter, !rgn.contains(r));
    148         iter.next();
    149     }
    150 }
    151 
    152 static void contains_proc(skiatest::Reporter* reporter,
    153                           const SkRegion& a, const SkRegion& b) {
    154     // test rgn
    155     bool c0 = a.contains(b);
    156     bool c1 = slow_contains(a, b);
    157     REPORTER_ASSERT(reporter, c0 == c1);
    158 
    159     // test rect
    160     SkIRect r = a.getBounds();
    161     r.inset(r.width()/4, r.height()/4);
    162     c0 = a.contains(r);
    163     c1 = slow_contains(a, r);
    164     REPORTER_ASSERT(reporter, c0 == c1);
    165 
    166     test_contains_iter(reporter, a);
    167     test_contains_iter(reporter, b);
    168 }
    169 
    170 static void test_intersects_iter(skiatest::Reporter* reporter, const SkRegion& rgn) {
    171     SkRegion::Iterator iter(rgn);
    172     while (!iter.done()) {
    173         SkIRect r = iter.rect();
    174         REPORTER_ASSERT(reporter, rgn.intersects(r));
    175         r.inset(-1, -1);
    176         REPORTER_ASSERT(reporter, rgn.intersects(r));
    177         iter.next();
    178     }
    179 }
    180 
    181 static void intersects_proc(skiatest::Reporter* reporter,
    182                           const SkRegion& a, const SkRegion& b) {
    183     bool c0 = a.intersects(b);
    184     bool c1 = slow_intersects(a, b);
    185     REPORTER_ASSERT(reporter, c0 == c1);
    186 
    187     test_intersects_iter(reporter, a);
    188     test_intersects_iter(reporter, b);
    189 }
    190 
    191 static void test_proc(skiatest::Reporter* reporter,
    192                       void (*proc)(skiatest::Reporter*,
    193                                    const SkRegion& a, const SkRegion&)) {
    194     SkRandom rand;
    195     for (int i = 0; i < 10000; ++i) {
    196         SkRegion outer;
    197         randRgn(rand, &outer, 8);
    198         SkRegion inner;
    199         randRgn(rand, &inner, 2);
    200         proc(reporter, outer, inner);
    201     }
    202 }
    203 
    204 static void rand_rect(SkIRect* rect, SkRandom& rand) {
    205     int bits = 6;
    206     int shift = 32 - bits;
    207     rect->set(rand.nextU() >> shift, rand.nextU() >> shift,
    208               rand.nextU() >> shift, rand.nextU() >> shift);
    209     rect->sort();
    210 }
    211 
    212 static bool test_rects(const SkIRect rect[], int count) {
    213     SkRegion rgn0, rgn1;
    214 
    215     for (int i = 0; i < count; i++) {
    216         rgn0.op(rect[i], SkRegion::kUnion_Op);
    217     }
    218     rgn1.setRects(rect, count);
    219 
    220     if (rgn0 != rgn1) {
    221         SkDebugf("\n");
    222         for (int i = 0; i < count; i++) {
    223             SkDebugf(" { %d, %d, %d, %d },\n",
    224                      rect[i].fLeft, rect[i].fTop,
    225                      rect[i].fRight, rect[i].fBottom);
    226         }
    227         SkDebugf("\n");
    228         return false;
    229     }
    230     return true;
    231 }
    232 
    233 DEF_TEST(Region, reporter) {
    234     const SkIRect r2[] = {
    235         { 0, 0, 1, 1 },
    236         { 2, 2, 3, 3 },
    237     };
    238     REPORTER_ASSERT(reporter, test_rects(r2, SK_ARRAY_COUNT(r2)));
    239 
    240     const SkIRect rects[] = {
    241         { 0, 0, 1, 2 },
    242         { 2, 1, 3, 3 },
    243         { 4, 0, 5, 1 },
    244         { 6, 0, 7, 4 },
    245     };
    246     REPORTER_ASSERT(reporter, test_rects(rects, SK_ARRAY_COUNT(rects)));
    247 
    248     SkRandom rand;
    249     for (int i = 0; i < 1000; i++) {
    250         SkRegion rgn0, rgn1;
    251 
    252         const int N = 8;
    253         SkIRect rect[N];
    254         for (int j = 0; j < N; j++) {
    255             rand_rect(&rect[j], rand);
    256         }
    257         REPORTER_ASSERT(reporter, test_rects(rect, N));
    258     }
    259 
    260     test_proc(reporter, contains_proc);
    261     test_proc(reporter, intersects_proc);
    262     test_empties(reporter);
    263     test_fromchrome(reporter);
    264 }
    265 
    266 // Test that writeToMemory reports the same number of bytes whether there was a
    267 // buffer to write to or not.
    268 static void test_write(const SkRegion& region, skiatest::Reporter* r) {
    269     const size_t bytesNeeded = region.writeToMemory(nullptr);
    270     SkAutoMalloc storage(bytesNeeded);
    271     const size_t bytesWritten = region.writeToMemory(storage.get());
    272     REPORTER_ASSERT(r, bytesWritten == bytesNeeded);
    273 }
    274 
    275 DEF_TEST(Region_writeToMemory, r) {
    276     // Test an empty region.
    277     SkRegion region;
    278     REPORTER_ASSERT(r, region.isEmpty());
    279     test_write(region, r);
    280 
    281     // Test a rectangular region
    282     bool nonEmpty = region.setRect(0, 0, 50, 50);
    283     REPORTER_ASSERT(r, nonEmpty);
    284     REPORTER_ASSERT(r, region.isRect());
    285     test_write(region, r);
    286 
    287     // Test a complex region
    288     nonEmpty = region.op(50, 50, 100, 100, SkRegion::kUnion_Op);
    289     REPORTER_ASSERT(r, nonEmpty);
    290     REPORTER_ASSERT(r, region.isComplex());
    291     test_write(region, r);
    292 }
    293