blob: 8345bba09ef87b2fbe93ded3d06ec7d26cf1ceab [file] [log] [blame]
Robert Phillips60e456e2021-10-29 16:33:54 -04001/*
2 * Copyright 2021 Google LLC
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/gm.h"
Kevin Lubick677a12f2022-03-09 08:23:14 -05009#include "include/core/SkBitmap.h"
Robert Phillips60e456e2021-10-29 16:33:54 -040010#include "include/core/SkCanvas.h"
Robert Phillips8ffe4bc2022-07-13 16:49:14 -040011#include "include/core/SkColorFilter.h"
Kevin Lubick5e8f45f2022-03-31 15:07:44 -040012#include "include/core/SkColorSpace.h"
Robert Phillips78219a32022-02-03 12:31:54 -050013#include "include/core/SkImage.h"
Robert Phillips60e456e2021-10-29 16:33:54 -040014#include "include/core/SkPaint.h"
Kevin Lubick56683af2023-06-01 14:04:30 -040015#include "include/core/SkPath.h"
Michael Ludwig4007b9b2022-04-12 14:07:59 -040016#include "include/core/SkRRect.h"
Robert Phillipsdd579d32022-02-09 15:53:42 -050017#include "include/effects/SkGradientShader.h"
Robert Phillips51be21e2022-03-22 11:43:52 -040018#include "include/gpu/GrRecordingContext.h"
Robert Phillips101ea8a2022-07-21 15:43:30 -040019#include "src/core/SkColorFilterPriv.h"
Kevin Lubick8b741882023-10-06 11:41:38 -040020#include "tools/DecodeUtils.h"
Kevin Lubick9b028372023-10-05 15:04:54 -040021#include "tools/GpuToolUtils.h"
Jim Van Verth9af3a912022-02-11 09:46:00 -050022#include "tools/Resources.h"
Robert Phillips87a50d32022-04-27 10:44:48 -040023#include "tools/ToolUtils.h"
Robert Phillips60e456e2021-10-29 16:33:54 -040024
Robert Phillips78219a32022-02-03 12:31:54 -050025namespace {
26
Robert Phillips8ffe4bc2022-07-13 16:49:14 -040027sk_sp<SkShader> create_gradient_shader(SkRect r,
28 const std::array<SkColor, 3>& colors,
29 const std::array<float, 3>& offsets) {
Robert Phillipsdd579d32022-02-09 15:53:42 -050030 SkPoint pts[2] = { {r.fLeft, r.fTop}, {r.fRight, r.fTop} };
Robert Phillipsdd579d32022-02-09 15:53:42 -050031
Robert Phillips8ffe4bc2022-07-13 16:49:14 -040032 return SkGradientShader::MakeLinear(pts, colors.data(), offsets.data(), std::size(colors),
Robert Phillipsdd579d32022-02-09 15:53:42 -050033 SkTileMode::kClamp);
34}
35
Robert Phillips87a50d32022-04-27 10:44:48 -040036sk_sp<SkShader> create_image_shader(SkCanvas* destCanvas, SkTileMode tmX, SkTileMode tmY) {
Robert Phillips78219a32022-02-03 12:31:54 -050037 SkBitmap bitmap;
38
Robert Phillips87a50d32022-04-27 10:44:48 -040039 {
40 SkImageInfo ii = SkImageInfo::Make(64, 64, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
41 bitmap.allocPixels(ii);
42 bitmap.eraseColor(SK_ColorWHITE);
Robert Phillips78219a32022-02-03 12:31:54 -050043
Robert Phillips87a50d32022-04-27 10:44:48 -040044 SkCanvas tmpCanvas(bitmap);
Robert Phillips78219a32022-02-03 12:31:54 -050045
Robert Phillips87a50d32022-04-27 10:44:48 -040046 SkColor colors[3][3] = {
47 { SK_ColorRED, SK_ColorDKGRAY, SK_ColorBLUE },
48 { SK_ColorLTGRAY, SK_ColorCYAN, SK_ColorYELLOW },
49 { SK_ColorGREEN, SK_ColorWHITE, SK_ColorMAGENTA }
50 };
Robert Phillips55ec3472022-03-25 14:01:34 -040051
Robert Phillips87a50d32022-04-27 10:44:48 -040052 for (int y = 0; y < 3; ++y) {
53 for (int x = 0; x < 3; ++x) {
54 SkPaint paint;
55 paint.setColor(colors[y][x]);
56 tmpCanvas.drawRect(SkRect::MakeXYWH(x*21, y*21, 22, 22), paint);
57 }
Robert Phillips55ec3472022-03-25 14:01:34 -040058 }
Robert Phillips87a50d32022-04-27 10:44:48 -040059
60 bitmap.setAlphaType(kOpaque_SkAlphaType);
61 bitmap.setImmutable();
Robert Phillips55ec3472022-03-25 14:01:34 -040062 }
Robert Phillips78219a32022-02-03 12:31:54 -050063
Kevin Lubick77472bf2023-03-24 07:11:17 -040064 sk_sp<SkImage> img = SkImages::RasterFromBitmap(bitmap);
Robert Phillips87a50d32022-04-27 10:44:48 -040065 img = ToolUtils::MakeTextureImage(destCanvas, std::move(img));
Kevin Lubickc2ec5d02022-10-17 15:49:00 -040066 if (img) {
67 return img->makeShader(tmX, tmY, SkSamplingOptions());
68 } else {
69 return nullptr;
70 }
Robert Phillipsdd579d32022-02-09 15:53:42 -050071}
72
Robert Phillips87a50d32022-04-27 10:44:48 -040073sk_sp<SkShader> create_blend_shader(SkCanvas* destCanvas, SkBlendMode bm) {
Robert Phillipsdd579d32022-02-09 15:53:42 -050074 constexpr SkColor4f kTransYellow = {1.0f, 1.0f, 0.0f, 0.5f};
75
Robert Phillips44263c52022-03-10 17:01:46 -050076 sk_sp<SkShader> dst = SkShaders::Color(kTransYellow, nullptr);
Robert Phillipsbdf5ce72022-04-15 16:17:56 -040077 return SkShaders::Blend(bm,
78 std::move(dst),
Robert Phillips87a50d32022-04-27 10:44:48 -040079 create_image_shader(destCanvas,
80 SkTileMode::kRepeat, SkTileMode::kRepeat));
81}
82
Robert Phillips98715ef2022-11-02 13:53:48 -040083sk_sp<SkColorFilter> create_grayscale_colorfilter() {
84 float matrix[20] = {};
85 matrix[0] = matrix[5] = matrix[10] = 0.2126f;
86 matrix[1] = matrix[6] = matrix[11] = 0.7152f;
87 matrix[2] = matrix[7] = matrix[12] = 0.0722f;
88 matrix[18] = 1.0f;
89 return SkColorFilters::Matrix(matrix);
90}
91
Robert Phillips8ffe4bc2022-07-13 16:49:14 -040092void draw_image_shader_tile(SkCanvas* canvas, SkRect clipRect) {
Robert Phillips87a50d32022-04-27 10:44:48 -040093 SkPaint p;
94 p.setShader(create_image_shader(canvas, SkTileMode::kClamp, SkTileMode::kRepeat));
95
96 SkPath path;
97 path.moveTo(1, 1);
98 path.lineTo(32, 127);
99 path.lineTo(96, 127);
100 path.lineTo(127, 1);
101 path.lineTo(63, 32);
102 path.close();
103
104 canvas->save();
Robert Phillips8ffe4bc2022-07-13 16:49:14 -0400105 canvas->clipRect(clipRect);
Robert Phillips87a50d32022-04-27 10:44:48 -0400106 canvas->scale(0.5f, 0.5f);
107 canvas->drawPath(path, p);
108
109 canvas->save();
110 canvas->concat(SkMatrix::RotateDeg(90, {64, 64}));
111 canvas->translate(128, 0);
112 canvas->drawPath(path, p);
113 canvas->restore();
114 canvas->restore();
115}
116
Robert Phillips8ffe4bc2022-07-13 16:49:14 -0400117void draw_gradient_tile(SkCanvas* canvas, SkRect clipRect) {
Robert Phillips87a50d32022-04-27 10:44:48 -0400118 SkRect r{1, 1, 127, 127};
119 SkPaint p;
Robert Phillips8ffe4bc2022-07-13 16:49:14 -0400120 p.setShader(create_gradient_shader(r,
121 { SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE },
122 { 0.0f, 0.75f, 1.0f }));
Robert Phillips87a50d32022-04-27 10:44:48 -0400123
124 canvas->save();
Robert Phillips8ffe4bc2022-07-13 16:49:14 -0400125 canvas->clipRect(clipRect);
Robert Phillips87a50d32022-04-27 10:44:48 -0400126 canvas->translate(128, 0);
127 canvas->scale(0.5f, 0.5f);
128 canvas->drawRect(r, p);
129
130 canvas->save();
131 canvas->concat(SkMatrix::RotateDeg(90, {64, 64}));
132 canvas->translate(128, 0);
133 canvas->drawRect(r, p);
134 canvas->restore();
135 canvas->restore();
Robert Phillips44263c52022-03-10 17:01:46 -0500136}
137
Robert Phillips8ffe4bc2022-07-13 16:49:14 -0400138void draw_colorfilter_swatches(SkCanvas* canvas, SkRect clipRect) {
Robert Phillips101ea8a2022-07-21 15:43:30 -0400139 static constexpr int kNumTilesPerSide = 3;
140
141 SkSize tileSize = { clipRect.width() / kNumTilesPerSide, clipRect.height() / kNumTilesPerSide };
Robert Phillips8ffe4bc2022-07-13 16:49:14 -0400142
143 // Quantize to four colors
144 uint8_t table1[256];
145 for (int i = 0; i < 256; ++i) {
146 table1[i] = (i/64) * 85;
147 }
148
149 // table2 is a band-pass filter for 85-170.
150 // table3 re-expands that range to 0..255
151 uint8_t table2[256], table3[256];
152 for (int i = 0; i < 256; ++i) {
153 if (i >= 85 && i <= 170) {
154 table2[i] = i;
155 table3[i] = ((i - 85) / 85.0f) * 255.0f;
156 } else {
157 table2[i] = 0;
158 table3[i] = 0;
159 }
160 }
161
Robert Phillips101ea8a2022-07-21 15:43:30 -0400162 constexpr SkColor SK_ColorGREY = SkColorSetARGB(0xFF, 0x80, 0x80, 0x80);
163
164 sk_sp<SkColorFilter> colorFilters[kNumTilesPerSide*kNumTilesPerSide];
165 static const std::array<SkColor, 3> kGradientColors[kNumTilesPerSide*kNumTilesPerSide] = {
166 { SK_ColorBLACK, SK_ColorGREY, SK_ColorWHITE },
167 { SK_ColorBLACK, SK_ColorGREY, SK_ColorWHITE },
168 { SK_ColorBLACK, SK_ColorGREY, SK_ColorWHITE },
169 { SK_ColorBLACK, SK_ColorGREY, SK_ColorWHITE },
170 { 0x00000000, 0x80000000, 0xFF000000 }, // the Gaussian CF uses alpha only
171 { SK_ColorBLACK, SK_ColorGREY, SK_ColorWHITE },
172 { SK_ColorBLACK, SK_ColorGREY, SK_ColorWHITE },
173 { SK_ColorBLACK, SK_ColorGREY, SK_ColorWHITE },
174 { SK_ColorBLACK, SK_ColorGREY, SK_ColorWHITE },
175 };
Robert Phillips8ffe4bc2022-07-13 16:49:14 -0400176
Robert Phillips70ed99d2022-08-18 17:28:17 -0400177 colorFilters[0] = SkColorFilters::Lighting(SK_ColorLTGRAY, 0xFF440000);
178 colorFilters[1] = SkColorFilters::Table(table1);
179 colorFilters[2] = SkColorFilters::Compose(SkColorFilters::TableARGB(nullptr, table3,
180 table3, table3),
181 SkColorFilters::TableARGB(nullptr, table2,
182 table2, table2));
Robert Phillips8ffe4bc2022-07-13 16:49:14 -0400183 colorFilters[3] = SkColorFilters::Blend(SK_ColorGREEN, SkBlendMode::kMultiply);
Robert Phillips101ea8a2022-07-21 15:43:30 -0400184 colorFilters[4] = SkColorFilterPriv::MakeGaussian();
Robert Phillips8ffe4bc2022-07-13 16:49:14 -0400185
James Godfrey-Kittlef95647a2022-12-02 15:08:13 -0500186 colorFilters[5] = SkColorFilters::LinearToSRGBGamma();
187 colorFilters[6] = SkColorFilters::SRGBToLinearGamma();
188
Robert Phillips8ffe4bc2022-07-13 16:49:14 -0400189 SkPaint p;
190
191 canvas->save();
192 canvas->clipRect(clipRect);
193 canvas->translate(clipRect.fLeft, clipRect.fTop);
194
Robert Phillips101ea8a2022-07-21 15:43:30 -0400195 for (int y = 0; y < kNumTilesPerSide; ++y) {
196 for (int x = 0; x < kNumTilesPerSide; ++x) {
Robert Phillips8ffe4bc2022-07-13 16:49:14 -0400197 SkRect r = SkRect::MakeXYWH(x * tileSize.width(), y * tileSize.height(),
198 tileSize.width(), tileSize.height()).makeInset(1.0f,
199 1.0f);
Robert Phillips101ea8a2022-07-21 15:43:30 -0400200 int colorFilterIndex = x*kNumTilesPerSide+y;
Robert Phillips8ffe4bc2022-07-13 16:49:14 -0400201 p.setShader(create_gradient_shader(r,
Robert Phillips101ea8a2022-07-21 15:43:30 -0400202 kGradientColors[colorFilterIndex],
Robert Phillips8ffe4bc2022-07-13 16:49:14 -0400203 { 0.0f, 0.5f, 1.0f }));
Robert Phillips101ea8a2022-07-21 15:43:30 -0400204 p.setColorFilter(colorFilters[colorFilterIndex]);
Robert Phillips8ffe4bc2022-07-13 16:49:14 -0400205 canvas->drawRect(r, p);
206 }
207 }
208
209 canvas->restore();
210}
211
Robert Phillips44263c52022-03-10 17:01:46 -0500212void draw_blend_mode_swatches(SkCanvas* canvas, SkRect clipRect) {
213 static const int kTileHeight = 16;
214 static const int kTileWidth = 16;
215 static const SkColor4f kOpaqueWhite { 1.0f, 1.0f, 1.0f, 1.0f };
216 static const SkColor4f kTransBluish { 0.0f, 0.5f, 1.0f, 0.5f };
217 static const SkColor4f kTransWhite { 1.0f, 1.0f, 1.0f, 0.75f };
218
219 SkPaint dstPaint;
220 dstPaint.setColor(kOpaqueWhite);
221 dstPaint.setBlendMode(SkBlendMode::kSrc);
222 dstPaint.setAntiAlias(false);
223
224 SkPaint srcPaint;
225 srcPaint.setColor(kTransBluish);
226 srcPaint.setAntiAlias(false);
227
228 SkRect r = SkRect::MakeXYWH(clipRect.fLeft, clipRect.fTop, kTileWidth, kTileHeight);
229
230 // For the first pass we draw: transparent bluish on top of opaque white
231 // For the second pass we draw: transparent white on top of transparent bluish
232 for (int passes = 0; passes < 2; ++passes) {
233 for (int i = 0; i <= (int)SkBlendMode::kLastCoeffMode; ++i) {
234 if (r.fLeft+kTileWidth > clipRect.fRight) {
235 r.offsetTo(clipRect.fLeft, r.fTop+kTileHeight);
236 }
237
238 canvas->drawRect(r.makeInset(1.0f, 1.0f), dstPaint);
239 srcPaint.setBlendMode(static_cast<SkBlendMode>(i));
240 canvas->drawRect(r.makeInset(2.0f, 2.0f), srcPaint);
241
242 r.offset(kTileWidth, 0.0f);
243 }
244
245 r.offsetTo(clipRect.fLeft, r.fTop+kTileHeight);
246 srcPaint.setColor(kTransWhite);
247 dstPaint.setColor(kTransBluish);
248 }
Robert Phillips78219a32022-02-03 12:31:54 -0500249}
250
251} // anonymous namespace
252
Robert Phillips60e456e2021-10-29 16:33:54 -0400253namespace skiagm {
254
255// This is just for bootstrapping Graphite.
256class GraphiteStartGM : public GM {
257public:
258 GraphiteStartGM() {
Robert Phillips44263c52022-03-10 17:01:46 -0500259 this->setBGColor(SK_ColorBLACK);
Kevin Lubick8b741882023-10-06 11:41:38 -0400260 ToolUtils::GetResourceAsBitmap("images/color_wheel.gif", &fBitmap);
Robert Phillips60e456e2021-10-29 16:33:54 -0400261 }
262
263protected:
Robert Phillips8ffe4bc2022-07-13 16:49:14 -0400264 static constexpr int kTileWidth = 128;
265 static constexpr int kTileHeight = 128;
266 static constexpr int kWidth = 3 * kTileWidth;
267 static constexpr int kHeight = 3 * kTileHeight;
James Godfrey-Kittlef95647a2022-12-02 15:08:13 -0500268 static constexpr int kClipInset = 4;
Robert Phillips44263c52022-03-10 17:01:46 -0500269
Leandro Lovisolo24fa2112023-08-15 19:05:17 +0000270 SkString getName() const override { return SkString("graphitestart"); }
Robert Phillips60e456e2021-10-29 16:33:54 -0400271
Leandro Lovisolo8f023882023-08-15 21:13:52 +0000272 SkISize getISize() override { return SkISize::Make(kWidth, kHeight); }
Robert Phillips60e456e2021-10-29 16:33:54 -0400273
274 void onDraw(SkCanvas* canvas) override {
Robert Phillips60e456e2021-10-29 16:33:54 -0400275
Robert Phillips8ffe4bc2022-07-13 16:49:14 -0400276 const SkRect clipRect = SkRect::MakeWH(kWidth, kHeight).makeInset(kClipInset, kClipInset);
277
Michael Ludwig4007b9b2022-04-12 14:07:59 -0400278 canvas->save();
Robert Phillips8ffe4bc2022-07-13 16:49:14 -0400279 canvas->clipRRect(SkRRect::MakeRectXY(clipRect, 32.f, 32.f), true);
Michael Ludwig4007b9b2022-04-12 14:07:59 -0400280
Robert Phillips8ffe4bc2022-07-13 16:49:14 -0400281 // Upper-left corner
282 draw_image_shader_tile(canvas, SkRect::MakeXYWH(0, 0, kTileWidth, kTileHeight));
Robert Phillips60e456e2021-10-29 16:33:54 -0400283
Robert Phillips8ffe4bc2022-07-13 16:49:14 -0400284 // Upper-middle tile
285 draw_gradient_tile(canvas, SkRect::MakeXYWH(kTileWidth, 0, kTileWidth, kTileHeight));
Robert Phillipsdd579d32022-02-09 15:53:42 -0500286
Robert Phillips8ffe4bc2022-07-13 16:49:14 -0400287 // Upper-right corner
288 draw_colorfilter_swatches(canvas, SkRect::MakeXYWH(2*kTileWidth, 0,
289 kTileWidth, kTileWidth));
290
291 // Middle-left tile
Robert Phillipsdd579d32022-02-09 15:53:42 -0500292 {
293 SkPaint p;
Robert Phillips55ec3472022-03-25 14:01:34 -0400294 p.setColor(SK_ColorRED);
Robert Phillips8ffe4bc2022-07-13 16:49:14 -0400295
296 SkRect r = SkRect::MakeXYWH(0, kTileHeight, kTileWidth, kTileHeight);
297 canvas->drawRect(r.makeInset(1.0f, 1.0f), p);
Robert Phillipsdd579d32022-02-09 15:53:42 -0500298 }
299
Robert Phillips8ffe4bc2022-07-13 16:49:14 -0400300 // Middle-middle tile
Robert Phillipsdd579d32022-02-09 15:53:42 -0500301 {
302 SkPaint p;
Robert Phillips87a50d32022-04-27 10:44:48 -0400303 p.setShader(create_blend_shader(canvas, SkBlendMode::kModulate));
Robert Phillips8ffe4bc2022-07-13 16:49:14 -0400304
305 SkRect r = SkRect::MakeXYWH(kTileWidth, kTileHeight, kTileWidth, kTileHeight);
306 canvas->drawRect(r.makeInset(1.0f, 1.0f), p);
307 }
308
309 // Middle-right tile
310 {
Kevin Lubick8b741882023-10-06 11:41:38 -0400311 sk_sp<SkImage> image(ToolUtils::GetResourceAsImage("images/mandrill_128.png"));
Robert Phillips98715ef2022-11-02 13:53:48 -0400312 sk_sp<SkShader> shader;
313
314 if (image) {
315 shader = image->makeShader(SkTileMode::kRepeat, SkTileMode::kRepeat, {});
316 shader = shader->makeWithColorFilter(create_grayscale_colorfilter());
317 }
318
319 SkPaint p;
320 p.setShader(std::move(shader));
321
322 SkRect r = SkRect::MakeXYWH(2*kTileWidth, kTileHeight, kTileWidth, kTileHeight);
323 canvas->drawRect(r.makeInset(1.0f, 1.0f), p);
Robert Phillipsdd579d32022-02-09 15:53:42 -0500324 }
Robert Phillips99ba0042022-02-23 10:17:26 -0500325
Michael Ludwig4007b9b2022-04-12 14:07:59 -0400326 canvas->restore();
327
Robert Phillips8ffe4bc2022-07-13 16:49:14 -0400328 // Bottom-left corner
Kevin Lubick0f7b44e2023-02-28 09:13:11 -0500329#if defined(SK_GRAPHITE)
Jim Van Verth9af3a912022-02-11 09:46:00 -0500330 // TODO: failing serialize test on Linux, not sure what's going on
Robert Phillips8ffe4bc2022-07-13 16:49:14 -0400331 canvas->writePixels(fBitmap, 0, 2*kTileHeight);
Jim Van Verth9af3a912022-02-11 09:46:00 -0500332#endif
Robert Phillips44263c52022-03-10 17:01:46 -0500333
Robert Phillips8ffe4bc2022-07-13 16:49:14 -0400334 // Bottom-middle tile
335 draw_blend_mode_swatches(canvas, SkRect::MakeXYWH(kTileWidth, 2*kTileHeight,
336 kTileWidth, kTileHeight));
337
338 // Bottom-right corner
339 {
Robert Phillipsfcbc0842022-09-01 09:32:30 -0400340 const SkRect kTile = SkRect::MakeXYWH(2*kTileWidth, 2*kTileHeight,
341 kTileWidth, kTileHeight);
342
343 SkPaint circlePaint;
344 circlePaint.setColor(SK_ColorBLUE);
345 circlePaint.setBlendMode(SkBlendMode::kSrc);
346
347 canvas->clipRect(kTile);
Robert Phillipsce3a8ed2022-09-02 13:10:46 -0400348 canvas->drawRect(kTile.makeInset(10, 20), circlePaint);
Robert Phillipsfcbc0842022-09-01 09:32:30 -0400349
350 SkPaint restorePaint;
351 restorePaint.setBlendMode(SkBlendMode::kPlus);
352
353 canvas->saveLayer(nullptr, &restorePaint);
354 circlePaint.setColor(SK_ColorRED);
355 circlePaint.setBlendMode(SkBlendMode::kSrc);
356
Robert Phillipsce3a8ed2022-09-02 13:10:46 -0400357 canvas->drawRect(kTile.makeInset(15, 25), circlePaint);
Robert Phillipsfcbc0842022-09-01 09:32:30 -0400358 canvas->restore();
Robert Phillips8ffe4bc2022-07-13 16:49:14 -0400359 }
Robert Phillips60e456e2021-10-29 16:33:54 -0400360 }
Jim Van Verth9af3a912022-02-11 09:46:00 -0500361
Robert Phillips44263c52022-03-10 17:01:46 -0500362private:
Jim Van Verth9af3a912022-02-11 09:46:00 -0500363 SkBitmap fBitmap;
Robert Phillips60e456e2021-10-29 16:33:54 -0400364};
365
366//////////////////////////////////////////////////////////////////////////////
367
368DEF_GM(return new GraphiteStartGM;)
369
370} // namespace skiagm