|  | /* | 
|  | * Copyright 2013 Google Inc. | 
|  | * | 
|  | * Use of this source code is governed by a BSD-style license that can be | 
|  | * found in the LICENSE file. | 
|  | */ | 
|  |  | 
|  | #include "SkDeviceLooper.h" | 
|  | #include "SkRasterClip.h" | 
|  | #include "Test.h" | 
|  |  | 
|  | static void make_pm(SkAutoPixmapStorage* pixmap, int w, int h) { | 
|  | pixmap->alloc(SkImageInfo::Make(w, h, kAlpha_8_SkColorType, kPremul_SkAlphaType)); | 
|  | } | 
|  |  | 
|  | static bool equal(const SkRasterClip& a, const SkRasterClip& b) { | 
|  | if (a.isBW()) { | 
|  | return b.isBW() && a.bwRgn() == b.bwRgn(); | 
|  | } else { | 
|  | return a.isAA() && a.aaRgn() == b.aaRgn(); | 
|  | } | 
|  | } | 
|  |  | 
|  | static const struct { | 
|  | SkISize fDevSize; | 
|  | SkIRect fRCBounds; | 
|  | SkIRect fRect; | 
|  | } gRec[] = { | 
|  | { { 4000, 10 }, { 0, 0, 4000, 10 }, { 0, 0, 4000, 4000 } }, | 
|  | { { 10, 4000 }, { 0, 0, 10, 4000 }, { 0, 0, 4000, 4000 } }, | 
|  | // very large devce, small rect | 
|  | { { 32000, 10 }, { 0, 0, 32000, 10 }, { 0, 0, 4000, 4000 } }, | 
|  | { { 10, 32000 }, { 0, 0, 10, 32000 }, { 0, 0, 4000, 4000 } }, | 
|  | // very large device, small clip | 
|  | { { 32000, 10 }, { 0, 0, 4000, 10 }, { 0, 0, 32000, 32000 } }, | 
|  | { { 10, 32000 }, { 0, 0, 10, 4000 }, { 0, 0, 32000, 32000 } }, | 
|  | }; | 
|  |  | 
|  | static void test_simple(skiatest::Reporter* reporter) { | 
|  |  | 
|  | for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) { | 
|  | SkAutoPixmapStorage pmap; | 
|  | make_pm(&pmap, gRec[i].fDevSize.width(), gRec[i].fDevSize.height()); | 
|  |  | 
|  | SkRasterClip rc(gRec[i].fRCBounds); | 
|  |  | 
|  | for (int aa = 0; aa <= 1; ++aa) { | 
|  | SkDeviceLooper looper(pmap, rc, gRec[i].fRect, SkToBool(aa)); | 
|  |  | 
|  | bool valid = looper.next(); | 
|  | REPORTER_ASSERT(reporter, valid); | 
|  | if (valid) { | 
|  | REPORTER_ASSERT(reporter, looper.getPixmap().width() == pmap.width()); | 
|  | REPORTER_ASSERT(reporter, looper.getPixmap().height() == pmap.height()); | 
|  | REPORTER_ASSERT(reporter, equal(looper.getRC(), rc)); | 
|  |  | 
|  | REPORTER_ASSERT(reporter, !looper.next()); | 
|  | } | 
|  | } | 
|  | // test that a rect that doesn't intersect returns no loops | 
|  | { | 
|  | SkIRect r = rc.getBounds(); | 
|  | r.offset(r.width(), 0); | 
|  | SkDeviceLooper looper(pmap, rc, r, false); | 
|  | REPORTER_ASSERT(reporter, !looper.next()); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // mask-bits are interpreted as the areas where the clip is visible | 
|  | //  [ 0x01  0x02 ] | 
|  | //  [ 0x04  0x08 ] | 
|  | // | 
|  | static void make_rgn(SkRegion* rgn, int w, int h, unsigned mask) { | 
|  | SkASSERT(SkAlign2(w)); | 
|  | SkASSERT(SkAlign2(h)); | 
|  | w >>= 1; | 
|  | h >>= 1; | 
|  | const SkIRect baseR = SkIRect::MakeWH(w, h); | 
|  |  | 
|  | int bit = 1; | 
|  | for (int y = 0; y <= 1; ++y) { | 
|  | for (int x = 0; x <= 1; ++x) { | 
|  | if (mask & bit) { | 
|  | SkIRect r = baseR; | 
|  | r.offset(x * w, y * h); | 
|  | rgn->op(r, SkRegion::kUnion_Op); | 
|  | } | 
|  | bit <<= 1; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | static void test_complex(skiatest::Reporter* reporter) { | 
|  | // choose size values that will result in 4 quadrants, given fAA setting | 
|  | const int BW_SIZE = 17 * 1000; | 
|  | const int AA_SIZE = 7 * 1000; | 
|  |  | 
|  | struct { | 
|  | SkISize fSize; | 
|  | bool    fAA; | 
|  | } const gRec[] = { | 
|  | { { BW_SIZE, BW_SIZE }, false }, | 
|  | { {  AA_SIZE, AA_SIZE }, true }, | 
|  | }; | 
|  |  | 
|  | for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) { | 
|  | const int w = gRec[i].fSize.width(); | 
|  | const int h = gRec[i].fSize.height(); | 
|  |  | 
|  | SkAutoPixmapStorage pmap; | 
|  | make_pm(&pmap, w, h); | 
|  |  | 
|  | const SkIRect rect = SkIRect::MakeWH(w, h); | 
|  |  | 
|  | // mask-bits are interpreted as the areas where the clip is visible | 
|  | //  [ 0x01  0x02 ] | 
|  | //  [ 0x04  0x08 ] | 
|  | // | 
|  | for (int mask = 0; mask <= 15; ++mask) { | 
|  | SkRegion rgn; | 
|  | make_rgn(&rgn, w, h, mask); | 
|  |  | 
|  | SkRasterClip rc; | 
|  | rc.op(rgn, SkRegion::kReplace_Op); | 
|  |  | 
|  | SkDeviceLooper looper(pmap, rc, rect, gRec[i].fAA); | 
|  | while (looper.next()) { | 
|  | REPORTER_ASSERT(reporter, !looper.getRC().isEmpty()); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | DEF_TEST(DeviceLooper, reporter) { | 
|  | test_simple(reporter); | 
|  | test_complex(reporter); | 
|  | } |