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