1
2/*
3 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8#include "SampleCode.h"
9#include "SkView.h"
10#include "SkCanvas.h"
11#include "SkColorFilter.h"
12#include "SkDevice.h"
13#include "SkPaint.h"
14#include "SkShader.h"
15
16static int inflate5To8(int x) {
17    return (x << 3) | (x >> 2);
18}
19
20static int trunc5(int x) {
21    return x >> 3;
22}
23
24#define SK_R16_BITS 5
25
26#ifdef SK_DEBUG
27static int round5_slow(int x) {
28    int orig = x & 7;
29    int fake = x >> 5;
30    int trunc = x >> 3;
31
32    int diff = fake - orig;
33
34    int bias = 0;
35    if (diff > 4) {
36        bias = -1;
37    } else if (diff < -4) {
38        bias = 1;
39    }
40    return trunc + bias;
41}
42#endif
43
44static int round5_fast(int x) {
45    int result = x + 3 - (x >> 5) + (x >> 7);
46    result >>= 3;
47#ifdef SK_DEBUG
48    {
49        int r2 = round5_slow(x);
50        SkASSERT(r2 == result);
51    }
52#endif
53    return result;
54}
55
56static void test_5bits() {
57    int e0 = 0;
58    int e1 = 0;
59    int e2 = 0;
60    int ae0 = 0;
61    int ae1 = 0;
62    int ae2 = 0;
63    for (int i = 0; i < 256; i++) {
64        int t0 = trunc5(i);
65        int t1 = round5_fast(i);
66        int t2 = trunc5(i);
67        int v0 = inflate5To8(t0);
68        int v1 = inflate5To8(t1);
69        int v2 = inflate5To8(t2);
70        int err0 = i - v0;
71        int err1 = i - v1;
72        int err2 = i - v2;
73        SkDebugf("--- %3d : trunc=%3d (%2d) round:%3d (%2d) \n"/*new:%d (%2d)\n"*/, i,
74                 v0, err0, v1, err1, v2, err2);
75
76
77        e0 += err0;
78        e1 += err1;
79        e2 += err2;
80        ae0 += SkAbs32(err0);
81        ae1 += SkAbs32(err1);
82        ae2 += SkAbs32(err2);
83    }
84    SkDebugf("--- trunc: %d %d  round: %d %d new: %d %d\n", e0, ae0, e1, ae1, e2, ae2);
85}
86
87// No longer marked static, since it is externed in SampleUnpremul.
88SkShader* createChecker();
89SkShader* createChecker() {
90    SkBitmap bm;
91    bm.allocN32Pixels(2, 2);
92    bm.lockPixels();
93    *bm.getAddr32(0, 0) = *bm.getAddr32(1, 1) = SkPreMultiplyColor(0xFFFFFFFF);
94    *bm.getAddr32(0, 1) = *bm.getAddr32(1, 0) = SkPreMultiplyColor(0xFFCCCCCC);
95    SkMatrix m;
96    m.setScale(12, 12);
97    return SkShader::CreateBitmapShader(bm, SkShader::kRepeat_TileMode,
98                                        SkShader::kRepeat_TileMode, &m);
99}
100
101static SkBitmap createBitmap(int n) {
102    SkBitmap bitmap;
103    bitmap.allocN32Pixels(n, n);
104    bitmap.eraseColor(SK_ColorTRANSPARENT);
105
106    SkCanvas canvas(bitmap);
107    SkRect r;
108    r.set(0, 0, SkIntToScalar(n), SkIntToScalar(n));
109    r.inset(SK_Scalar1, SK_Scalar1);
110
111    SkPaint paint;
112    paint.setAntiAlias(true);
113
114    paint.setColor(SK_ColorRED);
115    canvas.drawOval(r, paint);
116
117    r.inset(SK_Scalar1*n/4, SK_Scalar1*n/4);
118    paint.setXfermodeMode(SkXfermode::kSrc_Mode);
119    paint.setColor(0x800000FF);
120    canvas.drawOval(r, paint);
121
122    return bitmap;
123}
124
125class ColorFilterView : public SampleView {
126    SkBitmap fBitmap;
127    SkShader* fShader;
128    enum {
129        N = 64
130    };
131public:
132    ColorFilterView() {
133        fBitmap = createBitmap(N);
134        fShader = createChecker();
135
136        if (false) { // avoid bit rot, suppress warning
137            test_5bits();
138        }
139    }
140
141    virtual ~ColorFilterView() {
142        fShader->unref();
143    }
144
145protected:
146    // overrides from SkEventSink
147    virtual bool onQuery(SkEvent* evt) {
148        if (SampleCode::TitleQ(*evt)) {
149            SampleCode::TitleR(evt, "ColorFilter");
150            return true;
151        }
152        return this->INHERITED::onQuery(evt);
153    }
154
155    virtual void onDrawBackground(SkCanvas* canvas) {
156        SkPaint paint;
157        paint.setShader(fShader);
158        canvas->drawPaint(paint);
159    }
160
161    virtual void onDrawContent(SkCanvas* canvas) {
162        if (false) {
163            SkPaint p;
164            p.setAntiAlias(true);
165            SkRect r = { 20.4f, 10, 20.6f, 20 };
166            canvas->drawRect(r, p);
167            r.set(30.9f, 10, 31.1f, 20);
168            canvas->drawRect(r, p);
169            return;
170        }
171
172        static const SkXfermode::Mode gModes[] = {
173            SkXfermode::kClear_Mode,
174            SkXfermode::kSrc_Mode,
175            SkXfermode::kDst_Mode,
176            SkXfermode::kSrcOver_Mode,
177            SkXfermode::kDstOver_Mode,
178            SkXfermode::kSrcIn_Mode,
179            SkXfermode::kDstIn_Mode,
180            SkXfermode::kSrcOut_Mode,
181            SkXfermode::kDstOut_Mode,
182            SkXfermode::kSrcATop_Mode,
183            SkXfermode::kDstATop_Mode,
184            SkXfermode::kXor_Mode,
185            SkXfermode::kPlus_Mode,
186            SkXfermode::kModulate_Mode,
187        };
188
189        static const SkColor gColors[] = {
190            0xFF000000,
191            0x80000000,
192            0xFF00FF00,
193            0x8000FF00,
194            0x00000000,
195        };
196
197        float scale = 1.5f;
198        SkPaint paint;
199        canvas->translate(N / 8, N / 8);
200
201        for (size_t y = 0; y < SK_ARRAY_COUNT(gColors); y++) {
202            for (size_t x = 0; x < SK_ARRAY_COUNT(gModes); x++) {
203                SkColorFilter* cf = SkColorFilter::CreateModeFilter(gColors[y], gModes[x]);
204                SkSafeUnref(paint.setColorFilter(cf));
205                canvas->drawBitmap(fBitmap, x * N * 1.25f, y * N * scale, &paint);
206            }
207        }
208
209    }
210
211private:
212    typedef SampleView INHERITED;
213};
214
215//////////////////////////////////////////////////////////////////////////////
216
217static SkView* MyFactory() { return new ColorFilterView; }
218static SkViewRegister reg(MyFactory);
219