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 "SkAutoMalloc.h"
      9 #include "SkPath.h"
     10 #include "SkRandom.h"
     11 #include "SkRegion.h"
     12 #include "Test.h"
     13 
     14 static void Union(SkRegion* rgn, const SkIRect& rect) {
     15     rgn->op(rect, SkRegion::kUnion_Op);
     16 }
     17 
     18 #define TEST_NO_INTERSECT(rgn, rect)    REPORTER_ASSERT(reporter, !rgn.intersects(rect))
     19 #define TEST_INTERSECT(rgn, rect)       REPORTER_ASSERT(reporter, rgn.intersects(rect))
     20 #define TEST_NO_CONTAINS(rgn, rect)     REPORTER_ASSERT(reporter, !rgn.contains(rect))
     21 
     22 // inspired by http://code.google.com/p/skia/issues/detail?id=958
     23 //
     24 static void test_fromchrome(skiatest::Reporter* reporter) {
     25     SkRegion r;
     26     Union(&r, SkIRect::MakeXYWH(0, 0, 1, 1));
     27     TEST_NO_INTERSECT(r, SkIRect::MakeXYWH(0, 0, 0, 0));
     28     TEST_INTERSECT(r, SkIRect::MakeXYWH(0, 0, 2, 2));
     29     TEST_INTERSECT(r, SkIRect::MakeXYWH(-1, 0, 2, 2));
     30     TEST_INTERSECT(r, SkIRect::MakeXYWH(-1, -1, 2, 2));
     31     TEST_INTERSECT(r, SkIRect::MakeXYWH(0, -1, 2, 2));
     32     TEST_INTERSECT(r, SkIRect::MakeXYWH(-1, -1, 3, 3));
     33 
     34     Union(&r, SkIRect::MakeXYWH(0, 0, 3, 3));
     35     Union(&r, SkIRect::MakeXYWH(10, 0, 3, 3));
     36     Union(&r, SkIRect::MakeXYWH(0, 10, 13, 3));
     37     TEST_INTERSECT(r, SkIRect::MakeXYWH(-1, -1, 2, 2));
     38     TEST_INTERSECT(r, SkIRect::MakeXYWH(2, -1, 2, 2));
     39     TEST_INTERSECT(r, SkIRect::MakeXYWH(2, 2, 2, 2));
     40     TEST_INTERSECT(r, SkIRect::MakeXYWH(-1, 2, 2, 2));
     41 
     42     TEST_INTERSECT(r, SkIRect::MakeXYWH(9, -1, 2, 2));
     43     TEST_INTERSECT(r, SkIRect::MakeXYWH(12, -1, 2, 2));
     44     TEST_INTERSECT(r, SkIRect::MakeXYWH(12, 2, 2, 2));
     45     TEST_INTERSECT(r, SkIRect::MakeXYWH(9, 2, 2, 2));
     46 
     47     TEST_INTERSECT(r, SkIRect::MakeXYWH(0, -1, 13, 5));
     48     TEST_INTERSECT(r, SkIRect::MakeXYWH(1, -1, 11, 5));
     49     TEST_INTERSECT(r, SkIRect::MakeXYWH(2, -1, 9, 5));
     50     TEST_INTERSECT(r, SkIRect::MakeXYWH(2, -1, 8, 5));
     51     TEST_INTERSECT(r, SkIRect::MakeXYWH(3, -1, 8, 5));
     52 
     53     TEST_INTERSECT(r, SkIRect::MakeXYWH(0, 1, 13, 1));
     54     TEST_INTERSECT(r, SkIRect::MakeXYWH(1, 1, 11, 1));
     55     TEST_INTERSECT(r, SkIRect::MakeXYWH(2, 1, 9, 1));
     56     TEST_INTERSECT(r, SkIRect::MakeXYWH(2, 1, 8, 1));
     57     TEST_INTERSECT(r, SkIRect::MakeXYWH(3, 1, 8, 1));
     58 
     59     TEST_INTERSECT(r, SkIRect::MakeXYWH(0, 0, 13, 13));
     60     TEST_INTERSECT(r, SkIRect::MakeXYWH(0, 1, 13, 11));
     61     TEST_INTERSECT(r, SkIRect::MakeXYWH(0, 2, 13, 9));
     62     TEST_INTERSECT(r, SkIRect::MakeXYWH(0, 2, 13, 8));
     63 
     64 
     65     // These test SkRegion::contains(Rect) and SkRegion::contains(Region)
     66 
     67     SkRegion container;
     68     Union(&container, SkIRect::MakeXYWH(0, 0, 40, 20));
     69     Union(&container, SkIRect::MakeXYWH(30, 20, 10, 20));
     70     TEST_NO_CONTAINS(container, SkIRect::MakeXYWH(0, 0, 10, 39));
     71     TEST_NO_CONTAINS(container, SkIRect::MakeXYWH(29, 0, 10, 39));
     72 
     73     {
     74         SkRegion rgn;
     75         Union(&rgn, SkIRect::MakeXYWH(0, 0, 10, 10));
     76         Union(&rgn, SkIRect::MakeLTRB(5, 10, 20, 20));
     77         TEST_INTERSECT(rgn, SkIRect::MakeXYWH(15, 0, 5, 11));
     78     }
     79 }
     80 
     81 static void test_empties(skiatest::Reporter* reporter) {
     82     SkRegion valid(SkIRect::MakeWH(10, 10));
     83     SkRegion empty, empty2;
     84 
     85     REPORTER_ASSERT(reporter, empty.isEmpty());
     86     REPORTER_ASSERT(reporter, !valid.isEmpty());
     87 
     88     // test intersects
     89     REPORTER_ASSERT(reporter, !empty.intersects(empty2));
     90     REPORTER_ASSERT(reporter, !valid.intersects(empty));
     91 
     92     // test contains
     93     REPORTER_ASSERT(reporter, !empty.contains(empty2));
     94     REPORTER_ASSERT(reporter, !valid.contains(empty));
     95     REPORTER_ASSERT(reporter, !empty.contains(valid));
     96 
     97     SkPath emptyPath;
     98     emptyPath.moveTo(1, 5);
     99     emptyPath.close();
    100     SkRegion openClip;
    101     openClip.setRect(-16000, -16000, 16000, 16000);
    102     empty.setPath(emptyPath, openClip);  // should not assert
    103 }
    104 
    105 enum {
    106     W = 256,
    107     H = 256
    108 };
    109 
    110 static SkIRect randRect(SkRandom& rand) {
    111     int x = rand.nextU() % W;
    112     int y = rand.nextU() % H;
    113     int w = rand.nextU() % W;
    114     int h = rand.nextU() % H;
    115     return SkIRect::MakeXYWH(x, y, w >> 1, h >> 1);
    116 }
    117 
    118 static void randRgn(SkRandom& rand, SkRegion* rgn, int n) {
    119     rgn->setEmpty();
    120     for (int i = 0; i < n; ++i) {
    121         rgn->op(randRect(rand), SkRegion::kUnion_Op);
    122     }
    123 }
    124 
    125 static bool slow_contains(const SkRegion& outer, const SkRegion& inner) {
    126     SkRegion tmp;
    127     tmp.op(outer, inner, SkRegion::kUnion_Op);
    128     return outer == tmp;
    129 }
    130 
    131 static bool slow_contains(const SkRegion& outer, const SkIRect& r) {
    132     SkRegion tmp;
    133     tmp.op(outer, SkRegion(r), SkRegion::kUnion_Op);
    134     return outer == tmp;
    135 }
    136 
    137 static bool slow_intersects(const SkRegion& outer, const SkRegion& inner) {
    138     SkRegion tmp;
    139     return tmp.op(outer, inner, SkRegion::kIntersect_Op);
    140 }
    141 
    142 static void test_contains_iter(skiatest::Reporter* reporter, const SkRegion& rgn) {
    143     SkRegion::Iterator iter(rgn);
    144     while (!iter.done()) {
    145         SkIRect r = iter.rect();
    146         REPORTER_ASSERT(reporter, rgn.contains(r));
    147         r.inset(-1, -1);
    148         REPORTER_ASSERT(reporter, !rgn.contains(r));
    149         iter.next();
    150     }
    151 }
    152 
    153 static void contains_proc(skiatest::Reporter* reporter,
    154                           const SkRegion& a, const SkRegion& b) {
    155     // test rgn
    156     bool c0 = a.contains(b);
    157     bool c1 = slow_contains(a, b);
    158     REPORTER_ASSERT(reporter, c0 == c1);
    159 
    160     // test rect
    161     SkIRect r = a.getBounds();
    162     r.inset(r.width()/4, r.height()/4);
    163     c0 = a.contains(r);
    164     c1 = slow_contains(a, r);
    165     REPORTER_ASSERT(reporter, c0 == c1);
    166 
    167     test_contains_iter(reporter, a);
    168     test_contains_iter(reporter, b);
    169 }
    170 
    171 static void test_intersects_iter(skiatest::Reporter* reporter, const SkRegion& rgn) {
    172     SkRegion::Iterator iter(rgn);
    173     while (!iter.done()) {
    174         SkIRect r = iter.rect();
    175         REPORTER_ASSERT(reporter, rgn.intersects(r));
    176         r.inset(-1, -1);
    177         REPORTER_ASSERT(reporter, rgn.intersects(r));
    178         iter.next();
    179     }
    180 }
    181 
    182 static void intersects_proc(skiatest::Reporter* reporter,
    183                           const SkRegion& a, const SkRegion& b) {
    184     bool c0 = a.intersects(b);
    185     bool c1 = slow_intersects(a, b);
    186     REPORTER_ASSERT(reporter, c0 == c1);
    187 
    188     test_intersects_iter(reporter, a);
    189     test_intersects_iter(reporter, b);
    190 }
    191 
    192 static void test_proc(skiatest::Reporter* reporter,
    193                       void (*proc)(skiatest::Reporter*,
    194                                    const SkRegion& a, const SkRegion&)) {
    195     SkRandom rand;
    196     for (int i = 0; i < 10000; ++i) {
    197         SkRegion outer;
    198         randRgn(rand, &outer, 8);
    199         SkRegion inner;
    200         randRgn(rand, &inner, 2);
    201         proc(reporter, outer, inner);
    202     }
    203 }
    204 
    205 static void rand_rect(SkIRect* rect, SkRandom& rand) {
    206     int bits = 6;
    207     int shift = 32 - bits;
    208     rect->set(rand.nextU() >> shift, rand.nextU() >> shift,
    209               rand.nextU() >> shift, rand.nextU() >> shift);
    210     rect->sort();
    211 }
    212 
    213 static bool test_rects(const SkIRect rect[], int count) {
    214     SkRegion rgn0, rgn1;
    215 
    216     for (int i = 0; i < count; i++) {
    217         rgn0.op(rect[i], SkRegion::kUnion_Op);
    218     }
    219     rgn1.setRects(rect, count);
    220 
    221     if (rgn0 != rgn1) {
    222         SkDebugf("\n");
    223         for (int i = 0; i < count; i++) {
    224             SkDebugf(" { %d, %d, %d, %d },\n",
    225                      rect[i].fLeft, rect[i].fTop,
    226                      rect[i].fRight, rect[i].fBottom);
    227         }
    228         SkDebugf("\n");
    229         return false;
    230     }
    231     return true;
    232 }
    233 
    234 DEF_TEST(Region, reporter) {
    235     const SkIRect r2[] = {
    236         { 0, 0, 1, 1 },
    237         { 2, 2, 3, 3 },
    238     };
    239     REPORTER_ASSERT(reporter, test_rects(r2, SK_ARRAY_COUNT(r2)));
    240 
    241     const SkIRect rects[] = {
    242         { 0, 0, 1, 2 },
    243         { 2, 1, 3, 3 },
    244         { 4, 0, 5, 1 },
    245         { 6, 0, 7, 4 },
    246     };
    247     REPORTER_ASSERT(reporter, test_rects(rects, SK_ARRAY_COUNT(rects)));
    248 
    249     SkRandom rand;
    250     for (int i = 0; i < 1000; i++) {
    251         SkRegion rgn0, rgn1;
    252 
    253         const int N = 8;
    254         SkIRect rect[N];
    255         for (int j = 0; j < N; j++) {
    256             rand_rect(&rect[j], rand);
    257         }
    258         REPORTER_ASSERT(reporter, test_rects(rect, N));
    259     }
    260 
    261     test_proc(reporter, contains_proc);
    262     test_proc(reporter, intersects_proc);
    263     test_empties(reporter);
    264     test_fromchrome(reporter);
    265 }
    266 
    267 // Test that writeToMemory reports the same number of bytes whether there was a
    268 // buffer to write to or not.
    269 static void test_write(const SkRegion& region, skiatest::Reporter* r) {
    270     const size_t bytesNeeded = region.writeToMemory(nullptr);
    271     SkAutoMalloc storage(bytesNeeded);
    272     const size_t bytesWritten = region.writeToMemory(storage.get());
    273     REPORTER_ASSERT(r, bytesWritten == bytesNeeded);
    274 
    275     // Also check that the bytes are meaningful.
    276     SkRegion copy;
    277     REPORTER_ASSERT(r, copy.readFromMemory(storage.get(), bytesNeeded));
    278     REPORTER_ASSERT(r, region == copy);
    279 }
    280 
    281 DEF_TEST(Region_writeToMemory, r) {
    282     // Test an empty region.
    283     SkRegion region;
    284     REPORTER_ASSERT(r, region.isEmpty());
    285     test_write(region, r);
    286 
    287     // Test a rectangular region
    288     bool nonEmpty = region.setRect(0, 0, 50, 50);
    289     REPORTER_ASSERT(r, nonEmpty);
    290     REPORTER_ASSERT(r, region.isRect());
    291     test_write(region, r);
    292 
    293     // Test a complex region
    294     nonEmpty = region.op(50, 50, 100, 100, SkRegion::kUnion_Op);
    295     REPORTER_ASSERT(r, nonEmpty);
    296     REPORTER_ASSERT(r, region.isComplex());
    297     test_write(region, r);
    298 
    299     SkRegion complexRegion;
    300     Union(&complexRegion, SkIRect::MakeXYWH(0, 0, 1, 1));
    301     Union(&complexRegion, SkIRect::MakeXYWH(0, 0, 3, 3));
    302     Union(&complexRegion, SkIRect::MakeXYWH(10, 0, 3, 3));
    303     Union(&complexRegion, SkIRect::MakeXYWH(0, 10, 13, 3));
    304     test_write(complexRegion, r);
    305 
    306     Union(&complexRegion, SkIRect::MakeXYWH(10, 20, 3, 3));
    307     Union(&complexRegion, SkIRect::MakeXYWH(0,  20, 3, 3));
    308     test_write(complexRegion, r);
    309 }
    310 
    311 DEF_TEST(Region_readFromMemory_bad, r) {
    312     // These assume what our binary format is: conceivably we could change it
    313     // and might need to remove or change some of these tests.
    314     SkRegion region;
    315 
    316     {
    317         // invalid boundary rectangle
    318         int32_t data[5] = {0, 4, 4, 8, 2};
    319         REPORTER_ASSERT(r, 0 == region.readFromMemory(data, sizeof(data)));
    320     }
    321     // Region Layout, Serialized Format:
    322     //    COUNT LEFT TOP RIGHT BOTTOM Y_SPAN_COUNT TOTAL_INTERVAL_COUNT
    323     //    Top ( Bottom Span_Interval_Count ( Left Right )* Sentinel )+ Sentinel
    324     {
    325         // Example of valid data
    326         int32_t data[] = {9, 0, 0, 10, 10, 1, 2, 0, 10, 2, 0, 4, 6, 10,
    327                           2147483647, 2147483647};
    328         REPORTER_ASSERT(r, 0 != region.readFromMemory(data, sizeof(data)));
    329     }
    330     {
    331         // Short count
    332         int32_t data[] = {8, 0, 0, 10, 10, 1, 2, 0, 10, 2, 0, 4, 6, 10,
    333                           2147483647, 2147483647};
    334         REPORTER_ASSERT(r, 0 == region.readFromMemory(data, sizeof(data)));
    335     }
    336     {
    337         // bounds don't match
    338         int32_t data[] = {9, 0, 0, 10, 11, 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         //  bad yspan count
    344         int32_t data[] = {9, 0, 0, 10, 10, 2, 2, 0, 10, 2, 0, 4, 6, 10,
    345                           2147483647, 2147483647};
    346         REPORTER_ASSERT(r, 0 == region.readFromMemory(data, sizeof(data)));
    347     }
    348     {
    349         // bad int count
    350         int32_t data[] = {9, 0, 0, 10, 10, 1, 3, 0, 10, 2, 0, 4, 6, 10,
    351                           2147483647, 2147483647};
    352         REPORTER_ASSERT(r, 0 == region.readFromMemory(data, sizeof(data)));
    353     }
    354     {
    355         // bad final sentinal
    356         int32_t data[] = {9, 0, 0, 10, 10, 1, 2, 0, 10, 2, 0, 4, 6, 10,
    357                           2147483647, -1};
    358         REPORTER_ASSERT(r, 0 == region.readFromMemory(data, sizeof(data)));
    359     }
    360     {
    361         // bad row sentinal
    362         int32_t data[] = {9, 0, 0, 10, 10, 1, 2, 0, 10, 2, 0, 4, 6, 10,
    363                           -1, 2147483647};
    364         REPORTER_ASSERT(r, 0 == region.readFromMemory(data, sizeof(data)));
    365     }
    366 }
    367