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);
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" },
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" },
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) {
94 y += fBitmap.height() + MARGIN;
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) {
103 y += fBitmap.height() + MARGIN;
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) {
111 y += fBitmap.height() + MARGIN;
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),
121 sk_sp<SkImageFilter> offsetBackground(SkOffsetImageFilter::Make(SkIntToScalar(4),
124 paint.setImageFilter(SkXfermodeImageFilter::Make(SkBlendMode::kSrcOver,
128 DrawClippedPaint(canvas, clipRect, paint, x, y);
129 x += fBitmap.width() + MARGIN;
130 if (x + fBitmap.width() > WIDTH) {
132 y += fBitmap.height() + MARGIN;
134 // Test offsets on Darken (uses shader blend)
135 paint.setImageFilter(SkXfermodeImageFilter::Make(SkBlendMode::kDarken,
139 DrawClippedPaint(canvas, clipRect, paint, x, y);
140 x += fBitmap.width() + MARGIN;
141 if (x + fBitmap.width() > WIDTH) {
143 y += fBitmap.height() + MARGIN;
146 constexpr size_t nbSamples = 3;
147 const SkBlendMode sampledModes[nbSamples] = {
148 SkBlendMode::kOverlay, SkBlendMode::kSrcOver, SkBlendMode::kPlus
150 int offsets[nbSamples][4] = {{ 10, 10, -16, -16},
153 for (size_t i = 0; i < nbSamples; ++i) {
154 SkIRect cropRect = SkIRect::MakeXYWH(offsets[i][0],
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],
163 DrawClippedPaint(canvas, clipRect, paint, x, y);
164 x += fBitmap.width() + MARGIN;
165 if (x + fBitmap.width() > WIDTH) {
167 y += fBitmap.height() + MARGIN;
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) {
179 y += fBitmap.height() + MARGIN;
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) {
187 y += fBitmap.height() + MARGIN;
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) {
200 y += fBitmap.height() + MARGIN;
205 static void DrawClippedBitmap(SkCanvas* canvas, const SkBitmap& bitmap, const SkPaint& paint,
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);
215 static void DrawClippedPaint(SkCanvas* canvas, const SkRect& rect, const SkPaint& paint,
218 canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
219 canvas->clipRect(rect);
220 canvas->drawPaint(paint);
225 sk_sp<SkImage> fCheckerboard;
227 typedef GM INHERITED;
230 //////////////////////////////////////////////////////////////////////////////
232 DEF_GM( return new XfermodeImageFilterGM; );