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