blob: 155d6a643c33671fb4aa4c0035ec669e45760889 [file] [log] [blame]
senorblanco@chromium.org86fc2662013-05-31 17:49:12 +00001/*
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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "gm/gm.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -04009#include "include/core/SkBitmap.h"
10#include "include/core/SkBlendMode.h"
11#include "include/core/SkCanvas.h"
12#include "include/core/SkColor.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050013#include "include/core/SkImage.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040014#include "include/core/SkImageFilter.h"
15#include "include/core/SkPaint.h"
16#include "include/core/SkRect.h"
17#include "include/core/SkRefCnt.h"
18#include "include/core/SkScalar.h"
19#include "include/core/SkSize.h"
20#include "include/core/SkString.h"
21#include "include/core/SkTypes.h"
Michael Ludwig898bbfa2019-08-02 15:21:23 -040022#include "include/effects/SkImageFilters.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050023#include "tools/ToolUtils.h"
senorblanco@chromium.org86fc2662013-05-31 17:49:12 +000024
Ben Wagner7fde8e12019-05-01 17:28:53 -040025#include <utility>
26
senorblanco@chromium.org86fc2662013-05-31 17:49:12 +000027#define WIDTH 600
senorblanco06d54ad2016-01-13 13:48:54 -080028#define HEIGHT 700
senorblanco@chromium.org86fc2662013-05-31 17:49:12 +000029#define MARGIN 12
30
31namespace skiagm {
32
33class XfermodeImageFilterGM : public GM {
34public:
senorblanco@chromium.orge93e1db2013-12-09 18:31:42 +000035 XfermodeImageFilterGM(){
senorblanco@chromium.org86fc2662013-05-31 17:49:12 +000036 this->setBGColor(0xFF000000);
37 }
38
39protected:
mtklein36352bf2015-03-25 18:17:31 -070040 SkString onShortName() override {
senorblanco@chromium.org86fc2662013-05-31 17:49:12 +000041 return SkString("xfermodeimagefilter");
42 }
43
mtklein36352bf2015-03-25 18:17:31 -070044 SkISize onISize() override {
tfarinaf5393182014-06-09 23:59:03 -070045 return SkISize::Make(WIDTH, HEIGHT);
senorblanco@chromium.org86fc2662013-05-31 17:49:12 +000046 }
47
mtklein36352bf2015-03-25 18:17:31 -070048 void onOnceBeforeDraw() override {
Mike Kleinea3f0142019-03-20 11:12:10 -050049 fBitmap = ToolUtils::create_string_bitmap(80, 80, 0xD000D000, 15, 65, 96, "e");
halcanary878fa022015-01-26 11:24:32 -080050
reed9ce9d672016-03-17 10:51:11 -070051 fCheckerboard = SkImage::MakeFromBitmap(
Mike Kleinea3f0142019-03-20 11:12:10 -050052 ToolUtils::create_checkerboard_bitmap(80, 80, 0xFFA0A0A0, 0xFF404040, 8));
senorblanco@chromium.orge93e1db2013-12-09 18:31:42 +000053 }
54
mtklein36352bf2015-03-25 18:17:31 -070055 void onDraw(SkCanvas* canvas) override {
senorblanco16b254a2015-04-09 11:13:24 -070056 canvas->clear(SK_ColorBLACK);
senorblanco@chromium.org86fc2662013-05-31 17:49:12 +000057 SkPaint paint;
58
Brian Osmand1e67e72017-03-15 12:19:37 -040059 const SkBlendMode gModes[] = {
60 SkBlendMode::kClear,
61 SkBlendMode::kSrc,
62 SkBlendMode::kDst,
63 SkBlendMode::kSrcOver,
64 SkBlendMode::kDstOver,
65 SkBlendMode::kSrcIn,
66 SkBlendMode::kDstIn,
67 SkBlendMode::kSrcOut,
68 SkBlendMode::kDstOut,
69 SkBlendMode::kSrcATop,
70 SkBlendMode::kDstATop,
71 SkBlendMode::kXor,
senorblanco@chromium.org86fc2662013-05-31 17:49:12 +000072
Brian Osmand1e67e72017-03-15 12:19:37 -040073 SkBlendMode::kPlus,
74 SkBlendMode::kModulate,
75 SkBlendMode::kScreen,
76 SkBlendMode::kOverlay,
77 SkBlendMode::kDarken,
78 SkBlendMode::kLighten,
79 SkBlendMode::kColorDodge,
80 SkBlendMode::kColorBurn,
81 SkBlendMode::kHardLight,
82 SkBlendMode::kSoftLight,
83 SkBlendMode::kDifference,
84 SkBlendMode::kExclusion,
85 SkBlendMode::kMultiply,
86 SkBlendMode::kHue,
87 SkBlendMode::kSaturation,
88 SkBlendMode::kColor,
89 SkBlendMode::kLuminosity,
senorblanco@chromium.org86fc2662013-05-31 17:49:12 +000090 };
91
92 int x = 0, y = 0;
Michael Ludwig898bbfa2019-08-02 15:21:23 -040093 sk_sp<SkImageFilter> background(SkImageFilters::Image(fCheckerboard));
senorblanco@chromium.org86fc2662013-05-31 17:49:12 +000094 for (size_t i = 0; i < SK_ARRAY_COUNT(gModes); i++) {
Michael Ludwig898bbfa2019-08-02 15:21:23 -040095 paint.setImageFilter(SkImageFilters::Xfermode(gModes[i], background));
fmalita5598b632015-09-15 11:26:13 -070096 DrawClippedBitmap(canvas, fBitmap, paint, x, y);
senorblanco@chromium.org86fc2662013-05-31 17:49:12 +000097 x += fBitmap.width() + MARGIN;
98 if (x + fBitmap.width() > WIDTH) {
99 x = 0;
100 y += fBitmap.height() + MARGIN;
101 }
102 }
103 // Test arithmetic mode as image filter
Michael Ludwig898bbfa2019-08-02 15:21:23 -0400104 paint.setImageFilter(SkImageFilters::Arithmetic(0, 1, 1, 0, true, background, nullptr));
fmalita5598b632015-09-15 11:26:13 -0700105 DrawClippedBitmap(canvas, fBitmap, paint, x, y);
senorblanco@chromium.org86fc2662013-05-31 17:49:12 +0000106 x += fBitmap.width() + MARGIN;
107 if (x + fBitmap.width() > WIDTH) {
108 x = 0;
109 y += fBitmap.height() + MARGIN;
110 }
halcanary96fcdcc2015-08-27 07:41:13 -0700111 // Test nullptr mode
Michael Ludwig898bbfa2019-08-02 15:21:23 -0400112 paint.setImageFilter(SkImageFilters::Xfermode(SkBlendMode::kSrcOver, background));
fmalita5598b632015-09-15 11:26:13 -0700113 DrawClippedBitmap(canvas, fBitmap, paint, x, y);
commit-bot@chromium.org7b320702013-07-10 21:22:18 +0000114 x += fBitmap.width() + MARGIN;
115 if (x + fBitmap.width() > WIDTH) {
116 x = 0;
117 y += fBitmap.height() + MARGIN;
118 }
senorblanco@chromium.orge93e1db2013-12-09 18:31:42 +0000119 SkRect clipRect = SkRect::MakeWH(SkIntToScalar(fBitmap.width() + 4),
120 SkIntToScalar(fBitmap.height() + 4));
commit-bot@chromium.org7b320702013-07-10 21:22:18 +0000121 // Test offsets on SrcMode (uses fixed-function blend)
reed9ce9d672016-03-17 10:51:11 -0700122 sk_sp<SkImage> bitmapImage(SkImage::MakeFromBitmap(fBitmap));
Michael Ludwig898bbfa2019-08-02 15:21:23 -0400123 sk_sp<SkImageFilter> foreground(SkImageFilters::Image(std::move(bitmapImage)));
124 sk_sp<SkImageFilter> offsetForeground(SkImageFilters::Offset(4, -4, foreground));
125 sk_sp<SkImageFilter> offsetBackground(SkImageFilters::Offset(4, 4, background));
126 paint.setImageFilter(SkImageFilters::Xfermode(
127 SkBlendMode::kSrcOver, offsetBackground, offsetForeground));
fmalita5598b632015-09-15 11:26:13 -0700128 DrawClippedPaint(canvas, clipRect, paint, x, y);
commit-bot@chromium.org7b320702013-07-10 21:22:18 +0000129 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)
Michael Ludwig898bbfa2019-08-02 15:21:23 -0400135 paint.setImageFilter(SkImageFilters::Xfermode(
136 SkBlendMode::kDarken, offsetBackground, offsetForeground));
fmalita5598b632015-09-15 11:26:13 -0700137 DrawClippedPaint(canvas, clipRect, paint, x, y);
commit-bot@chromium.org1a4fb702013-09-26 16:09:28 +0000138 x += fBitmap.width() + MARGIN;
139 if (x + fBitmap.width() > WIDTH) {
140 x = 0;
141 y += fBitmap.height() + MARGIN;
142 }
143 // Test cropping
mtkleindbfd7ab2016-09-01 11:24:54 -0700144 constexpr size_t nbSamples = 3;
reed374772b2016-10-05 17:33:02 -0700145 const SkBlendMode sampledModes[nbSamples] = {
146 SkBlendMode::kOverlay, SkBlendMode::kSrcOver, SkBlendMode::kPlus
147 };
commit-bot@chromium.org1a4fb702013-09-26 16:09:28 +0000148 int offsets[nbSamples][4] = {{ 10, 10, -16, -16},
149 { 10, 10, 10, 10},
150 {-10, -10, -6, -6}};
151 for (size_t i = 0; i < nbSamples; ++i) {
senorblanco@chromium.orge93e1db2013-12-09 18:31:42 +0000152 SkIRect cropRect = SkIRect::MakeXYWH(offsets[i][0],
153 offsets[i][1],
commit-bot@chromium.org1a4fb702013-09-26 16:09:28 +0000154 fBitmap.width() + offsets[i][2],
155 fBitmap.height() + offsets[i][3]);
Michael Ludwig898bbfa2019-08-02 15:21:23 -0400156 paint.setImageFilter(SkImageFilters::Xfermode(sampledModes[i], offsetBackground,
157 offsetForeground, &cropRect));
fmalita5598b632015-09-15 11:26:13 -0700158 DrawClippedPaint(canvas, clipRect, paint, x, y);
commit-bot@chromium.org1a4fb702013-09-26 16:09:28 +0000159 x += fBitmap.width() + MARGIN;
160 if (x + fBitmap.width() > WIDTH) {
161 x = 0;
162 y += fBitmap.height() + MARGIN;
163 }
164 }
senorblanco06d54ad2016-01-13 13:48:54 -0800165 // Test small bg, large fg with Screen (uses shader blend)
Michael Ludwig898bbfa2019-08-02 15:21:23 -0400166 SkIRect cropRect = SkIRect::MakeXYWH(10, 10, 60, 60);
167 sk_sp<SkImageFilter> cropped(SkImageFilters::Offset(0, 0, foreground, &cropRect));
168 paint.setImageFilter(SkImageFilters::Xfermode(SkBlendMode::kScreen, cropped, background,
169 nullptr));
senorblanco06d54ad2016-01-13 13:48:54 -0800170 DrawClippedPaint(canvas, clipRect, paint, x, y);
171 x += fBitmap.width() + MARGIN;
172 if (x + fBitmap.width() > WIDTH) {
173 x = 0;
174 y += fBitmap.height() + MARGIN;
175 }
176 // Test small fg, large bg with Screen (uses shader blend)
Michael Ludwig898bbfa2019-08-02 15:21:23 -0400177 paint.setImageFilter(SkImageFilters::Xfermode(SkBlendMode::kScreen, background, cropped,
178 nullptr));
senorblanco06d54ad2016-01-13 13:48:54 -0800179 DrawClippedPaint(canvas, clipRect, paint, x, y);
180 x += fBitmap.width() + MARGIN;
181 if (x + fBitmap.width() > WIDTH) {
182 x = 0;
183 y += fBitmap.height() + MARGIN;
184 }
senorblanco9db04272016-03-31 08:24:29 -0700185 // Test small fg, large bg with SrcIn with a crop that forces it to full size.
186 // This tests that SkXfermodeImageFilter correctly applies the compositing mode to
187 // the region outside the foreground.
Michael Ludwig898bbfa2019-08-02 15:21:23 -0400188 SkIRect cropRectFull = SkIRect::MakeXYWH(0, 0, 80, 80);
189 paint.setImageFilter(SkImageFilters::Xfermode(SkBlendMode::kSrcIn, background, cropped,
190 &cropRectFull));
senorblanco9db04272016-03-31 08:24:29 -0700191 DrawClippedPaint(canvas, clipRect, paint, x, y);
192 x += fBitmap.width() + MARGIN;
193 if (x + fBitmap.width() > WIDTH) {
194 x = 0;
195 y += fBitmap.height() + MARGIN;
196 }
senorblanco@chromium.org86fc2662013-05-31 17:49:12 +0000197 }
fmalita5598b632015-09-15 11:26:13 -0700198
senorblanco@chromium.org86fc2662013-05-31 17:49:12 +0000199private:
fmalita5598b632015-09-15 11:26:13 -0700200 static void DrawClippedBitmap(SkCanvas* canvas, const SkBitmap& bitmap, const SkPaint& paint,
Robert Phillips1119dc32017-04-11 12:54:57 -0400201 int x, int y) {
fmalita5598b632015-09-15 11:26:13 -0700202 canvas->save();
203 canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
Robert Phillips1119dc32017-04-11 12:54:57 -0400204 canvas->clipRect(SkRect::MakeIWH(bitmap.width(), bitmap.height()));
fmalita5598b632015-09-15 11:26:13 -0700205 canvas->drawBitmap(bitmap, 0, 0, &paint);
206 canvas->restore();
207 }
208
209 static void DrawClippedPaint(SkCanvas* canvas, const SkRect& rect, const SkPaint& paint,
Robert Phillips1119dc32017-04-11 12:54:57 -0400210 int x, int y) {
fmalita5598b632015-09-15 11:26:13 -0700211 canvas->save();
212 canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
213 canvas->clipRect(rect);
214 canvas->drawPaint(paint);
215 canvas->restore();
216 }
217
reed9ce9d672016-03-17 10:51:11 -0700218 SkBitmap fBitmap;
219 sk_sp<SkImage> fCheckerboard;
fmalita5598b632015-09-15 11:26:13 -0700220
senorblanco@chromium.orge93e1db2013-12-09 18:31:42 +0000221 typedef GM INHERITED;
senorblanco@chromium.org86fc2662013-05-31 17:49:12 +0000222};
223
224//////////////////////////////////////////////////////////////////////////////
225
senorblanco@chromium.orge93e1db2013-12-09 18:31:42 +0000226DEF_GM( return new XfermodeImageFilterGM; );
senorblanco@chromium.org86fc2662013-05-31 17:49:12 +0000227
228}