2 * Copyright 2013 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
9 #include "sk_tool_utils.h"
11 #include "SkImageSource.h"
12 #include "SkOffsetImageFilter.h"
13 #include "SkXfermodeImageFilter.h"
21 class XfermodeImageFilterGM : public GM {
23 XfermodeImageFilterGM(){
24 this->setBGColor(0xFF000000);
28 SkString onShortName() override {
29 return SkString("xfermodeimagefilter");
32 SkISize onISize() override {
33 return SkISize::Make(WIDTH, HEIGHT);
36 void onOnceBeforeDraw() override {
37 fBitmap = sk_tool_utils::create_string_bitmap(80, 80, 0xD000D000, 15, 65, 96, "e");
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),
46 void onDraw(SkCanvas* canvas) override {
47 canvas->clear(SK_ColorBLACK);
51 SkXfermode::Mode fMode;
54 { SkXfermode::kClear_Mode, "Clear" },
55 { SkXfermode::kSrc_Mode, "Src" },
56 { SkXfermode::kDst_Mode, "Dst" },
57 { SkXfermode::kSrcOver_Mode, "SrcOver" },
58 { SkXfermode::kDstOver_Mode, "DstOver" },
59 { SkXfermode::kSrcIn_Mode, "SrcIn" },
60 { SkXfermode::kDstIn_Mode, "DstIn" },
61 { SkXfermode::kSrcOut_Mode, "SrcOut" },
62 { SkXfermode::kDstOut_Mode, "DstOut" },
63 { SkXfermode::kSrcATop_Mode, "SrcATop" },
64 { SkXfermode::kDstATop_Mode, "DstATop" },
65 { SkXfermode::kXor_Mode, "Xor" },
67 { SkXfermode::kPlus_Mode, "Plus" },
68 { SkXfermode::kModulate_Mode, "Modulate" },
69 { SkXfermode::kScreen_Mode, "Screen" },
70 { SkXfermode::kOverlay_Mode, "Overlay" },
71 { SkXfermode::kDarken_Mode, "Darken" },
72 { SkXfermode::kLighten_Mode, "Lighten" },
73 { SkXfermode::kColorDodge_Mode, "ColorDodge" },
74 { SkXfermode::kColorBurn_Mode, "ColorBurn" },
75 { SkXfermode::kHardLight_Mode, "HardLight" },
76 { SkXfermode::kSoftLight_Mode, "SoftLight" },
77 { SkXfermode::kDifference_Mode, "Difference" },
78 { SkXfermode::kExclusion_Mode, "Exclusion" },
79 { SkXfermode::kMultiply_Mode, "Multiply" },
80 { SkXfermode::kHue_Mode, "Hue" },
81 { SkXfermode::kSaturation_Mode, "Saturation" },
82 { SkXfermode::kColor_Mode, "Color" },
83 { SkXfermode::kLuminosity_Mode, "Luminosity" },
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(SkXfermode::Make(gModes[i].fMode),
91 DrawClippedBitmap(canvas, fBitmap, paint, x, y);
92 x += fBitmap.width() + MARGIN;
93 if (x + fBitmap.width() > WIDTH) {
95 y += fBitmap.height() + MARGIN;
98 // Test arithmetic mode as image filter
99 paint.setImageFilter(SkXfermodeImageFilter::MakeArithmetic(0, 1, 1, 0, true, background));
100 DrawClippedBitmap(canvas, fBitmap, paint, x, y);
101 x += fBitmap.width() + MARGIN;
102 if (x + fBitmap.width() > WIDTH) {
104 y += fBitmap.height() + MARGIN;
107 paint.setImageFilter(SkXfermodeImageFilter::Make(nullptr, background));
108 DrawClippedBitmap(canvas, fBitmap, paint, x, y);
109 x += fBitmap.width() + MARGIN;
110 if (x + fBitmap.width() > WIDTH) {
112 y += fBitmap.height() + MARGIN;
114 SkRect clipRect = SkRect::MakeWH(SkIntToScalar(fBitmap.width() + 4),
115 SkIntToScalar(fBitmap.height() + 4));
116 // Test offsets on SrcMode (uses fixed-function blend)
117 sk_sp<SkImage> bitmapImage(SkImage::MakeFromBitmap(fBitmap));
118 sk_sp<SkImageFilter> foreground(SkImageSource::Make(std::move(bitmapImage)));
119 sk_sp<SkImageFilter> offsetForeground(SkOffsetImageFilter::Make(SkIntToScalar(4),
122 sk_sp<SkImageFilter> offsetBackground(SkOffsetImageFilter::Make(SkIntToScalar(4),
125 paint.setImageFilter(SkXfermodeImageFilter::Make(
126 SkXfermode::Make(SkXfermode::kSrcOver_Mode),
130 DrawClippedPaint(canvas, clipRect, paint, x, y);
131 x += fBitmap.width() + MARGIN;
132 if (x + fBitmap.width() > WIDTH) {
134 y += fBitmap.height() + MARGIN;
136 // Test offsets on Darken (uses shader blend)
137 paint.setImageFilter(SkXfermodeImageFilter::Make(SkXfermode::Make(SkXfermode::kDarken_Mode),
141 DrawClippedPaint(canvas, clipRect, paint, x, y);
142 x += fBitmap.width() + MARGIN;
143 if (x + fBitmap.width() > WIDTH) {
145 y += fBitmap.height() + MARGIN;
148 constexpr size_t nbSamples = 3;
149 SkXfermode::Mode sampledModes[nbSamples] = {SkXfermode::kOverlay_Mode,
150 SkXfermode::kSrcOver_Mode,
151 SkXfermode::kPlus_Mode};
152 int offsets[nbSamples][4] = {{ 10, 10, -16, -16},
155 for (size_t i = 0; i < nbSamples; ++i) {
156 SkIRect cropRect = SkIRect::MakeXYWH(offsets[i][0],
158 fBitmap.width() + offsets[i][2],
159 fBitmap.height() + offsets[i][3]);
160 SkImageFilter::CropRect rect(SkRect::Make(cropRect));
161 paint.setImageFilter(SkXfermodeImageFilter::Make(SkXfermode::Make(sampledModes[i]),
165 DrawClippedPaint(canvas, clipRect, paint, x, y);
166 x += fBitmap.width() + MARGIN;
167 if (x + fBitmap.width() > WIDTH) {
169 y += fBitmap.height() + MARGIN;
172 // Test small bg, large fg with Screen (uses shader blend)
173 auto mode = SkXfermode::Make(SkXfermode::kScreen_Mode);
174 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(10, 10, 60, 60));
175 sk_sp<SkImageFilter> cropped(SkOffsetImageFilter::Make(0, 0, foreground, &cropRect));
176 paint.setImageFilter(SkXfermodeImageFilter::Make(mode, cropped, background, nullptr));
177 DrawClippedPaint(canvas, clipRect, paint, x, y);
178 x += fBitmap.width() + MARGIN;
179 if (x + fBitmap.width() > WIDTH) {
181 y += fBitmap.height() + MARGIN;
183 // Test small fg, large bg with Screen (uses shader blend)
184 paint.setImageFilter(SkXfermodeImageFilter::Make(mode, background, cropped, nullptr));
185 DrawClippedPaint(canvas, clipRect, paint, x, y);
186 x += fBitmap.width() + MARGIN;
187 if (x + fBitmap.width() > WIDTH) {
189 y += fBitmap.height() + MARGIN;
191 // Test small fg, large bg with SrcIn with a crop that forces it to full size.
192 // This tests that SkXfermodeImageFilter correctly applies the compositing mode to
193 // the region outside the foreground.
194 mode = SkXfermode::Make(SkXfermode::kSrcIn_Mode);
195 SkImageFilter::CropRect cropRectFull(SkRect::MakeXYWH(0, 0, 80, 80));
196 paint.setImageFilter(SkXfermodeImageFilter::Make(mode, background,
197 cropped, &cropRectFull));
198 DrawClippedPaint(canvas, clipRect, paint, x, y);
199 x += fBitmap.width() + MARGIN;
200 if (x + fBitmap.width() > WIDTH) {
202 y += fBitmap.height() + MARGIN;
207 static void DrawClippedBitmap(SkCanvas* canvas, const SkBitmap& bitmap, const SkPaint& paint,
210 canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
211 canvas->clipRect(SkRect::MakeWH(
212 SkIntToScalar(bitmap.width()), SkIntToScalar(bitmap.height())));
213 canvas->drawBitmap(bitmap, 0, 0, &paint);
217 static void DrawClippedPaint(SkCanvas* canvas, const SkRect& rect, const SkPaint& paint,
220 canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
221 canvas->clipRect(rect);
222 canvas->drawPaint(paint);
227 sk_sp<SkImage> fCheckerboard;
229 typedef GM INHERITED;
232 //////////////////////////////////////////////////////////////////////////////
234 DEF_GM( return new XfermodeImageFilterGM; );