91908599ff87de44ded4e5de357b402d3babbf20
[platform/upstream/libSkiaSharp.git] / gm / xfermodeimagefilter.cpp
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 "sk_tool_utils.h"
10 #include "SkImage.h"
11 #include "SkImageSource.h"
12 #include "SkOffsetImageFilter.h"
13 #include "SkXfermodeImageFilter.h"
14
15 #define WIDTH 600
16 #define HEIGHT 700
17 #define MARGIN 12
18
19 namespace skiagm {
20
21 class XfermodeImageFilterGM : public GM {
22 public:
23     XfermodeImageFilterGM(){
24         this->setBGColor(0xFF000000);
25     }
26
27 protected:
28     SkString onShortName() override {
29         return SkString("xfermodeimagefilter");
30     }
31
32     SkISize onISize() override {
33         return SkISize::Make(WIDTH, HEIGHT);
34     }
35
36     void onOnceBeforeDraw() override {
37         fBitmap = sk_tool_utils::create_string_bitmap(80, 80, 0xD000D000, 15, 65, 96, "e");
38
39         fCheckerboard = SkImage::MakeFromBitmap(
40             sk_tool_utils::create_checkerboard_bitmap(80, 80,
41                                                       sk_tool_utils::color_to_565(0xFFA0A0A0),
42                                                       sk_tool_utils::color_to_565(0xFF404040),
43                                                       8));
44     }
45
46     void onDraw(SkCanvas* canvas) override {
47         canvas->clear(SK_ColorBLACK);
48         SkPaint paint;
49
50         const struct {
51             SkBlendMode fMode;
52             const char* fLabel;
53         } gModes[] = {
54             { SkBlendMode::kClear,    "Clear"     },
55             { SkBlendMode::kSrc,      "Src"       },
56             { SkBlendMode::kDst,      "Dst"       },
57             { SkBlendMode::kSrcOver,  "SrcOver"   },
58             { SkBlendMode::kDstOver,  "DstOver"   },
59             { SkBlendMode::kSrcIn,    "SrcIn"     },
60             { SkBlendMode::kDstIn,    "DstIn"     },
61             { SkBlendMode::kSrcOut,   "SrcOut"    },
62             { SkBlendMode::kDstOut,   "DstOut"    },
63             { SkBlendMode::kSrcATop,  "SrcATop"   },
64             { SkBlendMode::kDstATop,  "DstATop"   },
65             { SkBlendMode::kXor,      "Xor"       },
66
67             { SkBlendMode::kPlus,         "Plus"          },
68             { SkBlendMode::kModulate,     "Modulate"      },
69             { SkBlendMode::kScreen,       "Screen"        },
70             { SkBlendMode::kOverlay,      "Overlay"       },
71             { SkBlendMode::kDarken,       "Darken"        },
72             { SkBlendMode::kLighten,      "Lighten"       },
73             { SkBlendMode::kColorDodge,   "ColorDodge"    },
74             { SkBlendMode::kColorBurn,    "ColorBurn"     },
75             { SkBlendMode::kHardLight,    "HardLight"     },
76             { SkBlendMode::kSoftLight,    "SoftLight"     },
77             { SkBlendMode::kDifference,   "Difference"    },
78             { SkBlendMode::kExclusion,    "Exclusion"     },
79             { SkBlendMode::kMultiply,     "Multiply"      },
80             { SkBlendMode::kHue,          "Hue"           },
81             { SkBlendMode::kSaturation,   "Saturation"    },
82             { SkBlendMode::kColor,        "Color"         },
83             { SkBlendMode::kLuminosity,   "Luminosity"    },
84         };
85
86         int x = 0, y = 0;
87         sk_sp<SkImageFilter> background(SkImageSource::Make(fCheckerboard));
88         for (size_t i = 0; i < SK_ARRAY_COUNT(gModes); i++) {
89             paint.setImageFilter(SkXfermodeImageFilter::Make(gModes[i].fMode, background));
90             DrawClippedBitmap(canvas, fBitmap, paint, x, y);
91             x += fBitmap.width() + MARGIN;
92             if (x + fBitmap.width() > WIDTH) {
93                 x = 0;
94                 y += fBitmap.height() + MARGIN;
95             }
96         }
97         // Test arithmetic mode as image filter
98         paint.setImageFilter(SkXfermodeImageFilter::MakeArithmetic(0, 1, 1, 0, true, background));
99         DrawClippedBitmap(canvas, fBitmap, paint, x, y);
100         x += fBitmap.width() + MARGIN;
101         if (x + fBitmap.width() > WIDTH) {
102             x = 0;
103             y += fBitmap.height() + MARGIN;
104         }
105         // Test nullptr mode
106         paint.setImageFilter(SkXfermodeImageFilter::Make(SkBlendMode::kSrcOver, background));
107         DrawClippedBitmap(canvas, fBitmap, paint, x, y);
108         x += fBitmap.width() + MARGIN;
109         if (x + fBitmap.width() > WIDTH) {
110             x = 0;
111             y += fBitmap.height() + MARGIN;
112         }
113         SkRect clipRect = SkRect::MakeWH(SkIntToScalar(fBitmap.width() + 4),
114                                          SkIntToScalar(fBitmap.height() + 4));
115         // Test offsets on SrcMode (uses fixed-function blend)
116         sk_sp<SkImage> bitmapImage(SkImage::MakeFromBitmap(fBitmap));
117         sk_sp<SkImageFilter> foreground(SkImageSource::Make(std::move(bitmapImage)));
118         sk_sp<SkImageFilter> offsetForeground(SkOffsetImageFilter::Make(SkIntToScalar(4),
119                                                                         SkIntToScalar(-4),
120                                                                         foreground));
121         sk_sp<SkImageFilter> offsetBackground(SkOffsetImageFilter::Make(SkIntToScalar(4),
122                                                                         SkIntToScalar(4),
123                                                                         background));
124         paint.setImageFilter(SkXfermodeImageFilter::Make(SkBlendMode::kSrcOver,
125                                                          offsetBackground,
126                                                          offsetForeground,
127                                                          nullptr));
128         DrawClippedPaint(canvas, clipRect, paint, x, y);
129         x += fBitmap.width() + MARGIN;
130         if (x + fBitmap.width() > WIDTH) {
131             x = 0;
132             y += fBitmap.height() + MARGIN;
133         }
134         // Test offsets on Darken (uses shader blend)
135         paint.setImageFilter(SkXfermodeImageFilter::Make(SkBlendMode::kDarken,
136                                                          offsetBackground,
137                                                          offsetForeground,
138                                                          nullptr));
139         DrawClippedPaint(canvas, clipRect, paint, x, y);
140         x += fBitmap.width() + MARGIN;
141         if (x + fBitmap.width() > WIDTH) {
142             x = 0;
143             y += fBitmap.height() + MARGIN;
144         }
145         // Test cropping
146         constexpr size_t nbSamples = 3;
147         const SkBlendMode sampledModes[nbSamples] = {
148             SkBlendMode::kOverlay, SkBlendMode::kSrcOver, SkBlendMode::kPlus
149         };
150         int offsets[nbSamples][4] = {{ 10,  10, -16, -16},
151                                      { 10,  10,  10,  10},
152                                      {-10, -10,  -6,  -6}};
153         for (size_t i = 0; i < nbSamples; ++i) {
154             SkIRect cropRect = SkIRect::MakeXYWH(offsets[i][0],
155                                                  offsets[i][1],
156                                                  fBitmap.width()  + offsets[i][2],
157                                                  fBitmap.height() + offsets[i][3]);
158             SkImageFilter::CropRect rect(SkRect::Make(cropRect));
159             paint.setImageFilter(SkXfermodeImageFilter::Make(sampledModes[i],
160                                                              offsetBackground,
161                                                              offsetForeground,
162                                                              &rect));
163             DrawClippedPaint(canvas, clipRect, paint, x, y);
164             x += fBitmap.width() + MARGIN;
165             if (x + fBitmap.width() > WIDTH) {
166                 x = 0;
167                 y += fBitmap.height() + MARGIN;
168             }
169         }
170         // Test small bg, large fg with Screen (uses shader blend)
171         SkBlendMode mode = SkBlendMode::kScreen;
172         SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(10, 10, 60, 60));
173         sk_sp<SkImageFilter> cropped(SkOffsetImageFilter::Make(0, 0, foreground, &cropRect));
174         paint.setImageFilter(SkXfermodeImageFilter::Make(mode, cropped, background, nullptr));
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 small fg, large bg with Screen (uses shader blend)
182         paint.setImageFilter(SkXfermodeImageFilter::Make(mode, background, cropped, nullptr));
183         DrawClippedPaint(canvas, clipRect, paint, x, y);
184         x += fBitmap.width() + MARGIN;
185         if (x + fBitmap.width() > WIDTH) {
186             x = 0;
187             y += fBitmap.height() + MARGIN;
188         }
189         // Test small fg, large bg with SrcIn with a crop that forces it to full size.
190         // This tests that SkXfermodeImageFilter correctly applies the compositing mode to
191         // the region outside the foreground.
192         mode = SkBlendMode::kSrcIn;
193         SkImageFilter::CropRect cropRectFull(SkRect::MakeXYWH(0, 0, 80, 80));
194         paint.setImageFilter(SkXfermodeImageFilter::Make(mode, background,
195                                                          cropped, &cropRectFull));
196         DrawClippedPaint(canvas, clipRect, paint, x, y);
197         x += fBitmap.width() + MARGIN;
198         if (x + fBitmap.width() > WIDTH) {
199             x = 0;
200             y += fBitmap.height() + MARGIN;
201         }
202     }
203
204 private:
205     static void DrawClippedBitmap(SkCanvas* canvas, const SkBitmap& bitmap, const SkPaint& paint,
206                            int x, int y) {
207         canvas->save();
208         canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
209         canvas->clipRect(SkRect::MakeWH(
210             SkIntToScalar(bitmap.width()), SkIntToScalar(bitmap.height())));
211         canvas->drawBitmap(bitmap, 0, 0, &paint);
212         canvas->restore();
213     }
214
215     static void DrawClippedPaint(SkCanvas* canvas, const SkRect& rect, const SkPaint& paint,
216                           int x, int y) {
217         canvas->save();
218         canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
219         canvas->clipRect(rect);
220         canvas->drawPaint(paint);
221         canvas->restore();
222     }
223
224     SkBitmap        fBitmap;
225     sk_sp<SkImage>  fCheckerboard;
226
227     typedef GM INHERITED;
228 };
229
230 //////////////////////////////////////////////////////////////////////////////
231
232 DEF_GM( return new XfermodeImageFilterGM; );
233
234 }