blob: 61f8cc421d4815d613b1905ed06834fa6d748d15 [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
Mike Reedac9f0c92020-12-23 10:11:33 -050051 fCheckerboard = ToolUtils::create_checkerboard_image(80, 80, 0xFFA0A0A0, 0xFF404040, 8);
senorblanco@chromium.orge93e1db2013-12-09 18:31:42 +000052 }
53
mtklein36352bf2015-03-25 18:17:31 -070054 void onDraw(SkCanvas* canvas) override {
senorblanco16b254a2015-04-09 11:13:24 -070055 canvas->clear(SK_ColorBLACK);
senorblanco@chromium.org86fc2662013-05-31 17:49:12 +000056 SkPaint paint;
57
Brian Osmand1e67e72017-03-15 12:19:37 -040058 const SkBlendMode gModes[] = {
59 SkBlendMode::kClear,
60 SkBlendMode::kSrc,
61 SkBlendMode::kDst,
62 SkBlendMode::kSrcOver,
63 SkBlendMode::kDstOver,
64 SkBlendMode::kSrcIn,
65 SkBlendMode::kDstIn,
66 SkBlendMode::kSrcOut,
67 SkBlendMode::kDstOut,
68 SkBlendMode::kSrcATop,
69 SkBlendMode::kDstATop,
70 SkBlendMode::kXor,
senorblanco@chromium.org86fc2662013-05-31 17:49:12 +000071
Brian Osmand1e67e72017-03-15 12:19:37 -040072 SkBlendMode::kPlus,
73 SkBlendMode::kModulate,
74 SkBlendMode::kScreen,
75 SkBlendMode::kOverlay,
76 SkBlendMode::kDarken,
77 SkBlendMode::kLighten,
78 SkBlendMode::kColorDodge,
79 SkBlendMode::kColorBurn,
80 SkBlendMode::kHardLight,
81 SkBlendMode::kSoftLight,
82 SkBlendMode::kDifference,
83 SkBlendMode::kExclusion,
84 SkBlendMode::kMultiply,
85 SkBlendMode::kHue,
86 SkBlendMode::kSaturation,
87 SkBlendMode::kColor,
88 SkBlendMode::kLuminosity,
senorblanco@chromium.org86fc2662013-05-31 17:49:12 +000089 };
90
91 int x = 0, y = 0;
Michael Ludwig898bbfa2019-08-02 15:21:23 -040092 sk_sp<SkImageFilter> background(SkImageFilters::Image(fCheckerboard));
senorblanco@chromium.org86fc2662013-05-31 17:49:12 +000093 for (size_t i = 0; i < SK_ARRAY_COUNT(gModes); i++) {
Michael Ludwig01b93ea2020-10-09 10:45:07 -040094 paint.setImageFilter(SkImageFilters::Blend(gModes[i], background));
fmalita5598b632015-09-15 11:26:13 -070095 DrawClippedBitmap(canvas, fBitmap, paint, x, y);
senorblanco@chromium.org86fc2662013-05-31 17:49:12 +000096 x += fBitmap.width() + MARGIN;
97 if (x + fBitmap.width() > WIDTH) {
98 x = 0;
99 y += fBitmap.height() + MARGIN;
100 }
101 }
102 // Test arithmetic mode as image filter
Michael Ludwig898bbfa2019-08-02 15:21:23 -0400103 paint.setImageFilter(SkImageFilters::Arithmetic(0, 1, 1, 0, true, background, nullptr));
fmalita5598b632015-09-15 11:26:13 -0700104 DrawClippedBitmap(canvas, fBitmap, paint, x, y);
senorblanco@chromium.org86fc2662013-05-31 17:49:12 +0000105 x += fBitmap.width() + MARGIN;
106 if (x + fBitmap.width() > WIDTH) {
107 x = 0;
108 y += fBitmap.height() + MARGIN;
109 }
halcanary96fcdcc2015-08-27 07:41:13 -0700110 // Test nullptr mode
Michael Ludwig01b93ea2020-10-09 10:45:07 -0400111 paint.setImageFilter(SkImageFilters::Blend(SkBlendMode::kSrcOver, background));
fmalita5598b632015-09-15 11:26:13 -0700112 DrawClippedBitmap(canvas, fBitmap, paint, x, y);
commit-bot@chromium.org7b320702013-07-10 21:22:18 +0000113 x += fBitmap.width() + MARGIN;
114 if (x + fBitmap.width() > WIDTH) {
115 x = 0;
116 y += fBitmap.height() + MARGIN;
117 }
senorblanco@chromium.orge93e1db2013-12-09 18:31:42 +0000118 SkRect clipRect = SkRect::MakeWH(SkIntToScalar(fBitmap.width() + 4),
119 SkIntToScalar(fBitmap.height() + 4));
commit-bot@chromium.org7b320702013-07-10 21:22:18 +0000120 // Test offsets on SrcMode (uses fixed-function blend)
Mike Reedac9f0c92020-12-23 10:11:33 -0500121 sk_sp<SkImage> bitmapImage(fBitmap.asImage());
Michael Ludwig898bbfa2019-08-02 15:21:23 -0400122 sk_sp<SkImageFilter> foreground(SkImageFilters::Image(std::move(bitmapImage)));
123 sk_sp<SkImageFilter> offsetForeground(SkImageFilters::Offset(4, -4, foreground));
124 sk_sp<SkImageFilter> offsetBackground(SkImageFilters::Offset(4, 4, background));
Michael Ludwig01b93ea2020-10-09 10:45:07 -0400125 paint.setImageFilter(SkImageFilters::Blend(
Michael Ludwig898bbfa2019-08-02 15:21:23 -0400126 SkBlendMode::kSrcOver, offsetBackground, offsetForeground));
fmalita5598b632015-09-15 11:26:13 -0700127 DrawClippedPaint(canvas, clipRect, paint, x, y);
commit-bot@chromium.org7b320702013-07-10 21:22:18 +0000128 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)
Michael Ludwig01b93ea2020-10-09 10:45:07 -0400134 paint.setImageFilter(SkImageFilters::Blend(
Michael Ludwig898bbfa2019-08-02 15:21:23 -0400135 SkBlendMode::kDarken, offsetBackground, offsetForeground));
fmalita5598b632015-09-15 11:26:13 -0700136 DrawClippedPaint(canvas, clipRect, paint, x, y);
commit-bot@chromium.org1a4fb702013-09-26 16:09:28 +0000137 x += fBitmap.width() + MARGIN;
138 if (x + fBitmap.width() > WIDTH) {
139 x = 0;
140 y += fBitmap.height() + MARGIN;
141 }
142 // Test cropping
mtkleindbfd7ab2016-09-01 11:24:54 -0700143 constexpr size_t nbSamples = 3;
reed374772b2016-10-05 17:33:02 -0700144 const SkBlendMode sampledModes[nbSamples] = {
145 SkBlendMode::kOverlay, SkBlendMode::kSrcOver, SkBlendMode::kPlus
146 };
commit-bot@chromium.org1a4fb702013-09-26 16:09:28 +0000147 int offsets[nbSamples][4] = {{ 10, 10, -16, -16},
148 { 10, 10, 10, 10},
149 {-10, -10, -6, -6}};
150 for (size_t i = 0; i < nbSamples; ++i) {
senorblanco@chromium.orge93e1db2013-12-09 18:31:42 +0000151 SkIRect cropRect = SkIRect::MakeXYWH(offsets[i][0],
152 offsets[i][1],
commit-bot@chromium.org1a4fb702013-09-26 16:09:28 +0000153 fBitmap.width() + offsets[i][2],
154 fBitmap.height() + offsets[i][3]);
Michael Ludwig01b93ea2020-10-09 10:45:07 -0400155 paint.setImageFilter(SkImageFilters::Blend(sampledModes[i], offsetBackground,
156 offsetForeground, &cropRect));
fmalita5598b632015-09-15 11:26:13 -0700157 DrawClippedPaint(canvas, clipRect, paint, x, y);
commit-bot@chromium.org1a4fb702013-09-26 16:09:28 +0000158 x += fBitmap.width() + MARGIN;
159 if (x + fBitmap.width() > WIDTH) {
160 x = 0;
161 y += fBitmap.height() + MARGIN;
162 }
163 }
senorblanco06d54ad2016-01-13 13:48:54 -0800164 // Test small bg, large fg with Screen (uses shader blend)
Michael Ludwig898bbfa2019-08-02 15:21:23 -0400165 SkIRect cropRect = SkIRect::MakeXYWH(10, 10, 60, 60);
166 sk_sp<SkImageFilter> cropped(SkImageFilters::Offset(0, 0, foreground, &cropRect));
Michael Ludwig01b93ea2020-10-09 10:45:07 -0400167 paint.setImageFilter(SkImageFilters::Blend(SkBlendMode::kScreen, cropped, background));
senorblanco06d54ad2016-01-13 13:48:54 -0800168 DrawClippedPaint(canvas, clipRect, paint, x, y);
169 x += fBitmap.width() + MARGIN;
170 if (x + fBitmap.width() > WIDTH) {
171 x = 0;
172 y += fBitmap.height() + MARGIN;
173 }
174 // Test small fg, large bg with Screen (uses shader blend)
Michael Ludwig01b93ea2020-10-09 10:45:07 -0400175 paint.setImageFilter(SkImageFilters::Blend(SkBlendMode::kScreen, background, cropped));
senorblanco06d54ad2016-01-13 13:48:54 -0800176 DrawClippedPaint(canvas, clipRect, paint, x, y);
177 x += fBitmap.width() + MARGIN;
178 if (x + fBitmap.width() > WIDTH) {
179 x = 0;
180 y += fBitmap.height() + MARGIN;
181 }
senorblanco9db04272016-03-31 08:24:29 -0700182 // Test small fg, large bg with SrcIn with a crop that forces it to full size.
183 // This tests that SkXfermodeImageFilter correctly applies the compositing mode to
184 // the region outside the foreground.
Michael Ludwig898bbfa2019-08-02 15:21:23 -0400185 SkIRect cropRectFull = SkIRect::MakeXYWH(0, 0, 80, 80);
Michael Ludwig01b93ea2020-10-09 10:45:07 -0400186 paint.setImageFilter(SkImageFilters::Blend(SkBlendMode::kSrcIn, background, cropped,
187 &cropRectFull));
senorblanco9db04272016-03-31 08:24:29 -0700188 DrawClippedPaint(canvas, clipRect, paint, x, y);
189 x += fBitmap.width() + MARGIN;
190 if (x + fBitmap.width() > WIDTH) {
191 x = 0;
192 y += fBitmap.height() + MARGIN;
193 }
senorblanco@chromium.org86fc2662013-05-31 17:49:12 +0000194 }
fmalita5598b632015-09-15 11:26:13 -0700195
senorblanco@chromium.org86fc2662013-05-31 17:49:12 +0000196private:
fmalita5598b632015-09-15 11:26:13 -0700197 static void DrawClippedBitmap(SkCanvas* canvas, const SkBitmap& bitmap, const SkPaint& paint,
Robert Phillips1119dc32017-04-11 12:54:57 -0400198 int x, int y) {
fmalita5598b632015-09-15 11:26:13 -0700199 canvas->save();
200 canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
Mike Reed568f0ae2021-01-24 08:57:23 -0500201 canvas->clipIRect(bitmap.bounds());
Mike Reed607a3822021-01-24 19:49:21 -0500202 canvas->drawImage(bitmap.asImage(), 0, 0, SkSamplingOptions(), &paint);
fmalita5598b632015-09-15 11:26:13 -0700203 canvas->restore();
204 }
205
206 static void DrawClippedPaint(SkCanvas* canvas, const SkRect& rect, const SkPaint& paint,
Robert Phillips1119dc32017-04-11 12:54:57 -0400207 int x, int y) {
fmalita5598b632015-09-15 11:26:13 -0700208 canvas->save();
209 canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
210 canvas->clipRect(rect);
211 canvas->drawPaint(paint);
212 canvas->restore();
213 }
214
reed9ce9d672016-03-17 10:51:11 -0700215 SkBitmap fBitmap;
216 sk_sp<SkImage> fCheckerboard;
fmalita5598b632015-09-15 11:26:13 -0700217
John Stiles7571f9e2020-09-02 22:42:33 -0400218 using INHERITED = GM;
senorblanco@chromium.org86fc2662013-05-31 17:49:12 +0000219};
220
221//////////////////////////////////////////////////////////////////////////////
222
senorblanco@chromium.orge93e1db2013-12-09 18:31:42 +0000223DEF_GM( return new XfermodeImageFilterGM; );
senorblanco@chromium.org86fc2662013-05-31 17:49:12 +0000224
John Stilesa6841be2020-08-06 14:11:56 -0400225} // namespace skiagm