1/*
2 * Copyright 2013 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 "SkDeviceLooper.h"
9#include "SkRasterClip.h"
10#include "Test.h"
11
12static void make_bm(SkBitmap* bm, int w, int h) {
13    bm->allocPixels(SkImageInfo::Make(w, h, kAlpha_8_SkColorType,
14                                      kPremul_SkAlphaType));
15}
16
17static bool equal(const SkRasterClip& a, const SkRasterClip& b) {
18    if (a.isBW()) {
19        return b.isBW() && a.bwRgn() == b.bwRgn();
20    } else {
21        return a.isAA() && a.aaRgn() == b.aaRgn();
22    }
23}
24
25static const struct {
26    SkISize fDevSize;
27    SkIRect fRCBounds;
28    SkIRect fRect;
29} gRec[] = {
30    { { 4000, 10 }, { 0, 0, 4000, 10 }, { 0, 0, 4000, 4000 } },
31    { { 10, 4000 }, { 0, 0, 10, 4000 }, { 0, 0, 4000, 4000 } },
32    // very large devce, small rect
33    { { 32000, 10 }, { 0, 0, 32000, 10 }, { 0, 0, 4000, 4000 } },
34    { { 10, 32000 }, { 0, 0, 10, 32000 }, { 0, 0, 4000, 4000 } },
35    // very large device, small clip
36    { { 32000, 10 }, { 0, 0, 4000, 10 }, { 0, 0, 32000, 32000 } },
37    { { 10, 32000 }, { 0, 0, 10, 4000 }, { 0, 0, 32000, 32000 } },
38};
39
40static void test_simple(skiatest::Reporter* reporter) {
41
42    for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) {
43        SkBitmap bitmap;
44        make_bm(&bitmap, gRec[i].fDevSize.width(), gRec[i].fDevSize.height());
45
46        SkRasterClip rc(gRec[i].fRCBounds);
47
48        for (int aa = 0; aa <= 1; ++aa) {
49            SkDeviceLooper looper(bitmap, rc, gRec[i].fRect, SkToBool(aa));
50
51            bool valid = looper.next();
52            REPORTER_ASSERT(reporter, valid);
53            if (valid) {
54                REPORTER_ASSERT(reporter, looper.getBitmap().width() == bitmap.width());
55                REPORTER_ASSERT(reporter, looper.getBitmap().height() == bitmap.height());
56                REPORTER_ASSERT(reporter, equal(looper.getRC(), rc));
57
58                REPORTER_ASSERT(reporter, !looper.next());
59            }
60        }
61        // test that a rect that doesn't intersect returns no loops
62        {
63            SkIRect r = rc.getBounds();
64            r.offset(r.width(), 0);
65            SkDeviceLooper looper(bitmap, rc, r, false);
66            REPORTER_ASSERT(reporter, !looper.next());
67        }
68    }
69}
70
71// mask-bits are interpreted as the areas where the clip is visible
72//  [ 0x01  0x02 ]
73//  [ 0x04  0x08 ]
74//
75static void make_rgn(SkRegion* rgn, int w, int h, unsigned mask) {
76    SkASSERT(SkAlign2(w));
77    SkASSERT(SkAlign2(h));
78    w >>= 1;
79    h >>= 1;
80    const SkIRect baseR = SkIRect::MakeWH(w, h);
81
82    int bit = 1;
83    for (int y = 0; y <= 1; ++y) {
84        for (int x = 0; x <= 1; ++x) {
85            if (mask & bit) {
86                SkIRect r = baseR;
87                r.offset(x * w, y * h);
88                rgn->op(r, SkRegion::kUnion_Op);
89            }
90            bit <<= 1;
91        }
92    }
93}
94
95static void test_complex(skiatest::Reporter* reporter) {
96    // choose size values that will result in 4 quadrants, given fAA setting
97    const int BW_SIZE = 17 * 1000;
98    const int AA_SIZE = 7 * 1000;
99
100    struct {
101        SkISize fSize;
102        bool    fAA;
103    } const gRec[] = {
104        { { BW_SIZE, BW_SIZE }, false },
105        { {  AA_SIZE, AA_SIZE }, true },
106    };
107
108    for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) {
109        const int w = gRec[i].fSize.width();
110        const int h = gRec[i].fSize.height();
111
112        SkBitmap bitmap;
113        make_bm(&bitmap, w, h);
114
115        const SkIRect rect = SkIRect::MakeWH(w, h);
116
117        // mask-bits are interpreted as the areas where the clip is visible
118        //  [ 0x01  0x02 ]
119        //  [ 0x04  0x08 ]
120        //
121        for (int mask = 0; mask <= 15; ++mask) {
122            SkRegion rgn;
123            make_rgn(&rgn, w, h, mask);
124
125            SkRasterClip rc;
126            rc.op(rgn, SkRegion::kReplace_Op);
127
128            SkDeviceLooper looper(bitmap, rc, rect, gRec[i].fAA);
129            while (looper.next()) {
130                REPORTER_ASSERT(reporter, !looper.getRC().isEmpty());
131            }
132        }
133    }
134}
135
136DEF_TEST(DeviceLooper, reporter) {
137    test_simple(reporter);
138    test_complex(reporter);
139}
140