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 "gm.h"
9#include "SkArithmeticMode.h"
10#include "SkOffsetImageFilter.h"
11#include "SkXfermodeImageFilter.h"
12#include "SkBitmapSource.h"
13
14#define WIDTH 600
15#define HEIGHT 600
16#define MARGIN 12
17
18namespace skiagm {
19
20class XfermodeImageFilterGM : public GM {
21public:
22    XfermodeImageFilterGM(){
23        this->setBGColor(0xFF000000);
24    }
25
26protected:
27    virtual SkString onShortName() SK_OVERRIDE {
28        return SkString("xfermodeimagefilter");
29    }
30
31    void make_bitmap() {
32        fBitmap.allocN32Pixels(80, 80);
33        SkCanvas canvas(fBitmap);
34        canvas.clear(0x00000000);
35        SkPaint paint;
36        paint.setAntiAlias(true);
37        paint.setColor(0xD000D000);
38        paint.setTextSize(SkIntToScalar(96));
39        const char* str = "e";
40        canvas.drawText(str, strlen(str), SkIntToScalar(15), SkIntToScalar(65), paint);
41    }
42
43    void make_checkerboard() {
44        fCheckerboard.allocN32Pixels(80, 80);
45        SkCanvas canvas(fCheckerboard);
46        canvas.clear(0x00000000);
47        SkPaint darkPaint;
48        darkPaint.setColor(0xFF404040);
49        SkPaint lightPaint;
50        lightPaint.setColor(0xFFA0A0A0);
51        for (int y = 0; y < 80; y += 16) {
52          for (int x = 0; x < 80; x += 16) {
53            canvas.save();
54            canvas.translate(SkIntToScalar(x), SkIntToScalar(y));
55            canvas.drawRect(SkRect::MakeXYWH(0, 0, 8, 8), darkPaint);
56            canvas.drawRect(SkRect::MakeXYWH(8, 0, 8, 8), lightPaint);
57            canvas.drawRect(SkRect::MakeXYWH(0, 8, 8, 8), lightPaint);
58            canvas.drawRect(SkRect::MakeXYWH(8, 8, 8, 8), darkPaint);
59            canvas.restore();
60          }
61        }
62    }
63
64    virtual SkISize onISize() SK_OVERRIDE {
65        return SkISize::Make(WIDTH, HEIGHT);
66    }
67
68    static void drawClippedBitmap(SkCanvas* canvas, const SkBitmap& bitmap, const SkPaint& paint,
69                           int x, int y) {
70        canvas->save();
71        canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
72        canvas->clipRect(SkRect::MakeWH(
73            SkIntToScalar(bitmap.width()), SkIntToScalar(bitmap.height())));
74        canvas->drawBitmap(bitmap, 0, 0, &paint);
75        canvas->restore();
76    }
77
78    static void drawClippedPaint(SkCanvas* canvas, const SkRect& rect, const SkPaint& paint,
79                          int x, int y) {
80        canvas->save();
81        canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
82        canvas->clipRect(rect);
83        canvas->drawPaint(paint);
84        canvas->restore();
85    }
86
87    virtual void onOnceBeforeDraw() SK_OVERRIDE {
88        make_bitmap();
89        make_checkerboard();
90    }
91
92    virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
93        canvas->clear(0x00000000);
94        SkPaint paint;
95
96        const struct {
97            SkXfermode::Mode  fMode;
98            const char*         fLabel;
99        } gModes[] = {
100            { SkXfermode::kClear_Mode,    "Clear"     },
101            { SkXfermode::kSrc_Mode,      "Src"       },
102            { SkXfermode::kDst_Mode,      "Dst"       },
103            { SkXfermode::kSrcOver_Mode,  "SrcOver"   },
104            { SkXfermode::kDstOver_Mode,  "DstOver"   },
105            { SkXfermode::kSrcIn_Mode,    "SrcIn"     },
106            { SkXfermode::kDstIn_Mode,    "DstIn"     },
107            { SkXfermode::kSrcOut_Mode,   "SrcOut"    },
108            { SkXfermode::kDstOut_Mode,   "DstOut"    },
109            { SkXfermode::kSrcATop_Mode,  "SrcATop"   },
110            { SkXfermode::kDstATop_Mode,  "DstATop"   },
111            { SkXfermode::kXor_Mode,      "Xor"       },
112
113            { SkXfermode::kPlus_Mode,         "Plus"          },
114            { SkXfermode::kModulate_Mode,     "Modulate"      },
115            { SkXfermode::kScreen_Mode,       "Screen"        },
116            { SkXfermode::kOverlay_Mode,      "Overlay"       },
117            { SkXfermode::kDarken_Mode,       "Darken"        },
118            { SkXfermode::kLighten_Mode,      "Lighten"       },
119            { SkXfermode::kColorDodge_Mode,   "ColorDodge"    },
120            { SkXfermode::kColorBurn_Mode,    "ColorBurn"     },
121            { SkXfermode::kHardLight_Mode,    "HardLight"     },
122            { SkXfermode::kSoftLight_Mode,    "SoftLight"     },
123            { SkXfermode::kDifference_Mode,   "Difference"    },
124            { SkXfermode::kExclusion_Mode,    "Exclusion"     },
125            { SkXfermode::kMultiply_Mode,     "Multiply"      },
126            { SkXfermode::kHue_Mode,          "Hue"           },
127            { SkXfermode::kSaturation_Mode,   "Saturation"    },
128            { SkXfermode::kColor_Mode,        "Color"         },
129            { SkXfermode::kLuminosity_Mode,   "Luminosity"    },
130        };
131
132        int x = 0, y = 0;
133        SkAutoTUnref<SkImageFilter> background(SkBitmapSource::Create(fCheckerboard));
134        for (size_t i = 0; i < SK_ARRAY_COUNT(gModes); i++) {
135            SkAutoTUnref<SkXfermode> mode(SkXfermode::Create(gModes[i].fMode));
136            SkAutoTUnref<SkImageFilter> filter(SkXfermodeImageFilter::Create(mode, background));
137            paint.setImageFilter(filter);
138            drawClippedBitmap(canvas, fBitmap, paint, x, y);
139            x += fBitmap.width() + MARGIN;
140            if (x + fBitmap.width() > WIDTH) {
141                x = 0;
142                y += fBitmap.height() + MARGIN;
143            }
144        }
145        // Test arithmetic mode as image filter
146        SkAutoTUnref<SkXfermode> mode(SkArithmeticMode::Create(0, SK_Scalar1, SK_Scalar1, 0));
147        SkAutoTUnref<SkImageFilter> filter(SkXfermodeImageFilter::Create(mode, background));
148        paint.setImageFilter(filter);
149        drawClippedBitmap(canvas, fBitmap, paint, x, y);
150        x += fBitmap.width() + MARGIN;
151        if (x + fBitmap.width() > WIDTH) {
152            x = 0;
153            y += fBitmap.height() + MARGIN;
154        }
155        // Test NULL mode
156        filter.reset(SkXfermodeImageFilter::Create(NULL, background));
157        paint.setImageFilter(filter);
158        drawClippedBitmap(canvas, fBitmap, paint, x, y);
159        x += fBitmap.width() + MARGIN;
160        if (x + fBitmap.width() > WIDTH) {
161            x = 0;
162            y += fBitmap.height() + MARGIN;
163        }
164        SkRect clipRect = SkRect::MakeWH(SkIntToScalar(fBitmap.width() + 4),
165                                         SkIntToScalar(fBitmap.height() + 4));
166        // Test offsets on SrcMode (uses fixed-function blend)
167        SkAutoTUnref<SkImageFilter> foreground(SkBitmapSource::Create(fBitmap));
168        SkAutoTUnref<SkImageFilter> offsetForeground(SkOffsetImageFilter::Create(
169            SkIntToScalar(4), SkIntToScalar(-4), foreground));
170        SkAutoTUnref<SkImageFilter> offsetBackground(SkOffsetImageFilter::Create(
171            SkIntToScalar(4), SkIntToScalar(4), background));
172        mode.reset(SkXfermode::Create(SkXfermode::kSrcOver_Mode));
173        filter.reset(SkXfermodeImageFilter::Create(mode, offsetBackground, offsetForeground));
174        paint.setImageFilter(filter);
175        drawClippedPaint(canvas, clipRect, paint, x, y);
176        x += fBitmap.width() + MARGIN;
177        if (x + fBitmap.width() > WIDTH) {
178            x = 0;
179            y += fBitmap.height() + MARGIN;
180        }
181        // Test offsets on Darken (uses shader blend)
182        mode.reset(SkXfermode::Create(SkXfermode::kDarken_Mode));
183        filter.reset(SkXfermodeImageFilter::Create(mode, offsetBackground, offsetForeground));
184        paint.setImageFilter(filter);
185        drawClippedPaint(canvas, clipRect, paint, x, y);
186        x += fBitmap.width() + MARGIN;
187        if (x + fBitmap.width() > WIDTH) {
188            x = 0;
189            y += fBitmap.height() + MARGIN;
190        }
191        // Test cropping
192        static const size_t nbSamples = 3;
193        SkXfermode::Mode sampledModes[nbSamples] = {SkXfermode::kOverlay_Mode,
194                                                    SkXfermode::kSrcOver_Mode,
195                                                    SkXfermode::kPlus_Mode};
196        int offsets[nbSamples][4] = {{ 10,  10, -16, -16},
197                                     { 10,  10,  10,  10},
198                                     {-10, -10,  -6,  -6}};
199        for (size_t i = 0; i < nbSamples; ++i) {
200            SkIRect cropRect = SkIRect::MakeXYWH(offsets[i][0],
201                                                 offsets[i][1],
202                                                 fBitmap.width()  + offsets[i][2],
203                                                 fBitmap.height() + offsets[i][3]);
204            SkImageFilter::CropRect rect(SkRect::Make(cropRect));
205            mode.reset(SkXfermode::Create(sampledModes[i]));
206            filter.reset(SkXfermodeImageFilter::Create(
207                                    mode, offsetBackground, offsetForeground, &rect));
208            paint.setImageFilter(filter);
209            drawClippedPaint(canvas, clipRect, paint, x, y);
210            x += fBitmap.width() + MARGIN;
211            if (x + fBitmap.width() > WIDTH) {
212                x = 0;
213                y += fBitmap.height() + MARGIN;
214            }
215        }
216    }
217private:
218    SkBitmap fBitmap, fCheckerboard;
219    typedef GM INHERITED;
220};
221
222//////////////////////////////////////////////////////////////////////////////
223
224DEF_GM( return new XfermodeImageFilterGM; );
225
226}
227