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#include "sk_tool_utils.h"
8#include "SampleCode.h"
9#include "SkView.h"
10#include "SkCanvas.h"
11#include "SkColorFilter.h"
12#include "SkPaint.h"
13#include "SkShader.h"
14
15static int inflate5To8(int x) {
16    return (x << 3) | (x >> 2);
17}
18
19static int trunc5(int x) {
20    return x >> 3;
21}
22
23#define SK_R16_BITS 5
24
25#ifdef SK_DEBUG
26static int round5_slow(int x) {
27    int orig = x & 7;
28    int fake = x >> 5;
29    int trunc = x >> 3;
30
31    int diff = fake - orig;
32
33    int bias = 0;
34    if (diff > 4) {
35        bias = -1;
36    } else if (diff < -4) {
37        bias = 1;
38    }
39    return trunc + bias;
40}
41#endif
42
43static int round5_fast(int x) {
44    int result = x + 3 - (x >> 5) + (x >> 7);
45    result >>= 3;
46#ifdef SK_DEBUG
47    {
48        int r2 = round5_slow(x);
49        SkASSERT(r2 == result);
50    }
51#endif
52    return result;
53}
54
55static void test_5bits() {
56    int e0 = 0;
57    int e1 = 0;
58    int e2 = 0;
59    int ae0 = 0;
60    int ae1 = 0;
61    int ae2 = 0;
62    for (int i = 0; i < 256; i++) {
63        int t0 = trunc5(i);
64        int t1 = round5_fast(i);
65        int t2 = trunc5(i);
66        int v0 = inflate5To8(t0);
67        int v1 = inflate5To8(t1);
68        int v2 = inflate5To8(t2);
69        int err0 = i - v0;
70        int err1 = i - v1;
71        int err2 = i - v2;
72        SkDebugf("--- %3d : trunc=%3d (%2d) round:%3d (%2d) \n"/*new:%d (%2d)\n"*/, i,
73                 v0, err0, v1, err1, v2, err2);
74
75
76        e0 += err0;
77        e1 += err1;
78        e2 += err2;
79        ae0 += SkAbs32(err0);
80        ae1 += SkAbs32(err1);
81        ae2 += SkAbs32(err2);
82    }
83    SkDebugf("--- trunc: %d %d  round: %d %d new: %d %d\n", e0, ae0, e1, ae1, e2, ae2);
84}
85
86static SkBitmap createBitmap(int n) {
87    SkBitmap bitmap;
88    bitmap.allocN32Pixels(n, n);
89    bitmap.eraseColor(SK_ColorTRANSPARENT);
90
91    SkCanvas canvas(bitmap);
92    SkRect r;
93    r.set(0, 0, SkIntToScalar(n), SkIntToScalar(n));
94    r.inset(SK_Scalar1, SK_Scalar1);
95
96    SkPaint paint;
97    paint.setAntiAlias(true);
98
99    paint.setColor(SK_ColorRED);
100    canvas.drawOval(r, paint);
101
102    r.inset(SK_Scalar1*n/4, SK_Scalar1*n/4);
103    paint.setBlendMode(SkBlendMode::kSrc);
104    paint.setColor(0x800000FF);
105    canvas.drawOval(r, paint);
106
107    return bitmap;
108}
109
110class ColorFilterView : public SampleView {
111    SkBitmap fBitmap;
112    sk_sp<SkShader> fShader;
113    enum {
114        N = 64
115    };
116public:
117    ColorFilterView() {
118        fBitmap = createBitmap(N);
119        fShader = sk_tool_utils::create_checkerboard_shader(
120                0xFFCCCCCC, 0xFFFFFFFF, 12);
121
122        if (false) { // avoid bit rot, suppress warning
123            test_5bits();
124        }
125    }
126
127protected:
128    // overrides from SkEventSink
129    virtual bool onQuery(SkEvent* evt) {
130        if (SampleCode::TitleQ(*evt)) {
131            SampleCode::TitleR(evt, "ColorFilter");
132            return true;
133        }
134        return this->INHERITED::onQuery(evt);
135    }
136
137    virtual void onDrawBackground(SkCanvas* canvas) {
138        SkPaint paint;
139        paint.setShader(fShader);
140        canvas->drawPaint(paint);
141    }
142
143    virtual void onDrawContent(SkCanvas* canvas) {
144        if (false) {
145            SkPaint p;
146            p.setAntiAlias(true);
147            SkRect r = { 20.4f, 10, 20.6f, 20 };
148            canvas->drawRect(r, p);
149            r.set(30.9f, 10, 31.1f, 20);
150            canvas->drawRect(r, p);
151            return;
152        }
153
154        static const SkBlendMode gModes[] = {
155            SkBlendMode::kClear,
156            SkBlendMode::kSrc,
157            SkBlendMode::kDst,
158            SkBlendMode::kSrcOver,
159            SkBlendMode::kDstOver,
160            SkBlendMode::kSrcIn,
161            SkBlendMode::kDstIn,
162            SkBlendMode::kSrcOut,
163            SkBlendMode::kDstOut,
164            SkBlendMode::kSrcATop,
165            SkBlendMode::kDstATop,
166            SkBlendMode::kXor,
167            SkBlendMode::kPlus,
168            SkBlendMode::kModulate,
169        };
170
171        static const SkColor gColors[] = {
172            0xFF000000,
173            0x80000000,
174            0xFF00FF00,
175            0x8000FF00,
176            0x00000000,
177        };
178
179        float scale = 1.5f;
180        SkPaint paint;
181        canvas->translate(N / 8, N / 8);
182
183        for (size_t y = 0; y < SK_ARRAY_COUNT(gColors); y++) {
184            for (size_t x = 0; x < SK_ARRAY_COUNT(gModes); x++) {
185                paint.setColorFilter(SkColorFilter::MakeModeFilter(gColors[y], gModes[x]));
186                canvas->drawBitmap(fBitmap, x * N * 1.25f, y * N * scale, &paint);
187            }
188        }
189
190    }
191
192private:
193    typedef SampleView INHERITED;
194};
195
196//////////////////////////////////////////////////////////////////////////////
197
198static SkView* MyFactory() { return new ColorFilterView; }
199static SkViewRegister reg(MyFactory);
200