• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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"
9 #include "include/core/SkBitmap.h"
10 #include "include/core/SkCanvas.h"
11 #include "include/core/SkColorFilter.h"
12 #include "include/core/SkColorSpace.h"
13 #include "include/core/SkImage.h"
14 #include "include/core/SkPaint.h"
15 #include "include/core/SkRRect.h"
16 #include "include/effects/SkGradientShader.h"
17 #include "include/gpu/GrRecordingContext.h"
18 #include "src/core/SkColorFilterPriv.h"
19 #include "tools/Resources.h"
20 #include "tools/ToolUtils.h"
21 
22 namespace {
23 
create_gradient_shader(SkRect r,const std::array<SkColor,3> & colors,const std::array<float,3> & offsets)24 sk_sp<SkShader> create_gradient_shader(SkRect r,
25                                        const std::array<SkColor, 3>& colors,
26                                        const std::array<float, 3>& offsets) {
27     SkPoint pts[2] = { {r.fLeft, r.fTop}, {r.fRight, r.fTop} };
28 
29     return SkGradientShader::MakeLinear(pts, colors.data(), offsets.data(), std::size(colors),
30                                         SkTileMode::kClamp);
31 }
32 
create_image_shader(SkCanvas * destCanvas,SkTileMode tmX,SkTileMode tmY)33 sk_sp<SkShader> create_image_shader(SkCanvas* destCanvas, SkTileMode tmX, SkTileMode tmY) {
34     SkBitmap bitmap;
35 
36     {
37         SkImageInfo ii = SkImageInfo::Make(64, 64, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
38         bitmap.allocPixels(ii);
39         bitmap.eraseColor(SK_ColorWHITE);
40 
41         SkCanvas tmpCanvas(bitmap);
42 
43         SkColor colors[3][3] = {
44                 { SK_ColorRED,    SK_ColorDKGRAY, SK_ColorBLUE },
45                 { SK_ColorLTGRAY, SK_ColorCYAN,   SK_ColorYELLOW },
46                 { SK_ColorGREEN,  SK_ColorWHITE,  SK_ColorMAGENTA }
47         };
48 
49         for (int y = 0; y < 3; ++y) {
50             for (int x = 0; x < 3; ++x) {
51                 SkPaint paint;
52                 paint.setColor(colors[y][x]);
53                 tmpCanvas.drawRect(SkRect::MakeXYWH(x*21, y*21, 22, 22), paint);
54             }
55         }
56 
57         bitmap.setAlphaType(kOpaque_SkAlphaType);
58         bitmap.setImmutable();
59     }
60 
61     sk_sp<SkImage> img = SkImage::MakeFromBitmap(bitmap);
62     img = ToolUtils::MakeTextureImage(destCanvas, std::move(img));
63     if (img) {
64         return img->makeShader(tmX, tmY, SkSamplingOptions());
65     } else {
66         return nullptr;
67     }
68 }
69 
create_blend_shader(SkCanvas * destCanvas,SkBlendMode bm)70 sk_sp<SkShader> create_blend_shader(SkCanvas* destCanvas, SkBlendMode bm) {
71     constexpr SkColor4f kTransYellow = {1.0f, 1.0f, 0.0f, 0.5f};
72 
73     sk_sp<SkShader> dst = SkShaders::Color(kTransYellow, nullptr);
74     return SkShaders::Blend(bm,
75                             std::move(dst),
76                             create_image_shader(destCanvas,
77                                                 SkTileMode::kRepeat, SkTileMode::kRepeat));
78 }
79 
create_grayscale_colorfilter()80 sk_sp<SkColorFilter> create_grayscale_colorfilter() {
81     float matrix[20] = {};
82     matrix[0] = matrix[5] = matrix[10] = 0.2126f;
83     matrix[1] = matrix[6] = matrix[11] = 0.7152f;
84     matrix[2] = matrix[7] = matrix[12] = 0.0722f;
85     matrix[18] = 1.0f;
86     return SkColorFilters::Matrix(matrix);
87 }
88 
draw_image_shader_tile(SkCanvas * canvas,SkRect clipRect)89 void draw_image_shader_tile(SkCanvas* canvas, SkRect clipRect) {
90     SkPaint p;
91     p.setShader(create_image_shader(canvas, SkTileMode::kClamp, SkTileMode::kRepeat));
92 
93     SkPath path;
94     path.moveTo(1,   1);
95     path.lineTo(32,  127);
96     path.lineTo(96,  127);
97     path.lineTo(127, 1);
98     path.lineTo(63,  32);
99     path.close();
100 
101     canvas->save();
102         canvas->clipRect(clipRect);
103         canvas->scale(0.5f, 0.5f);
104         canvas->drawPath(path, p);
105 
106         canvas->save();
107             canvas->concat(SkMatrix::RotateDeg(90, {64, 64}));
108             canvas->translate(128, 0);
109             canvas->drawPath(path, p);
110         canvas->restore();
111     canvas->restore();
112 }
113 
draw_gradient_tile(SkCanvas * canvas,SkRect clipRect)114 void draw_gradient_tile(SkCanvas* canvas, SkRect clipRect) {
115     SkRect r{1, 1, 127, 127};
116     SkPaint p;
117     p.setShader(create_gradient_shader(r,
118                                        { SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE },
119                                        { 0.0f, 0.75f, 1.0f }));
120 
121     canvas->save();
122         canvas->clipRect(clipRect);
123         canvas->translate(128, 0);
124         canvas->scale(0.5f, 0.5f);
125         canvas->drawRect(r, p);
126 
127         canvas->save();
128             canvas->concat(SkMatrix::RotateDeg(90, {64, 64}));
129             canvas->translate(128, 0);
130             canvas->drawRect(r, p);
131         canvas->restore();
132     canvas->restore();
133 }
134 
draw_colorfilter_swatches(SkCanvas * canvas,SkRect clipRect)135 void draw_colorfilter_swatches(SkCanvas* canvas, SkRect clipRect) {
136     static constexpr int kNumTilesPerSide = 3;
137 
138     SkSize tileSize = { clipRect.width() / kNumTilesPerSide, clipRect.height() / kNumTilesPerSide };
139 
140     // Quantize to four colors
141     uint8_t table1[256];
142     for (int i = 0; i < 256; ++i) {
143         table1[i] = (i/64) * 85;
144     }
145 
146     // table2 is a band-pass filter for 85-170.
147     // table3 re-expands that range to 0..255
148     uint8_t table2[256], table3[256];
149     for (int i = 0; i < 256; ++i) {
150         if (i >= 85 && i <= 170) {
151             table2[i] = i;
152             table3[i] = ((i - 85) / 85.0f) * 255.0f;
153         } else {
154             table2[i] = 0;
155             table3[i] = 0;
156         }
157     }
158 
159     constexpr SkColor SK_ColorGREY = SkColorSetARGB(0xFF, 0x80, 0x80, 0x80);
160 
161     sk_sp<SkColorFilter> colorFilters[kNumTilesPerSide*kNumTilesPerSide];
162     static const std::array<SkColor, 3> kGradientColors[kNumTilesPerSide*kNumTilesPerSide] = {
163             { SK_ColorBLACK, SK_ColorGREY, SK_ColorWHITE },
164             { SK_ColorBLACK, SK_ColorGREY, SK_ColorWHITE },
165             { SK_ColorBLACK, SK_ColorGREY, SK_ColorWHITE },
166             { SK_ColorBLACK, SK_ColorGREY, SK_ColorWHITE },
167             { 0x00000000,    0x80000000,   0xFF000000    },  // the Gaussian CF uses alpha only
168             { SK_ColorBLACK, SK_ColorGREY, SK_ColorWHITE },
169             { SK_ColorBLACK, SK_ColorGREY, SK_ColorWHITE },
170             { SK_ColorBLACK, SK_ColorGREY, SK_ColorWHITE },
171             { SK_ColorBLACK, SK_ColorGREY, SK_ColorWHITE },
172     };
173 
174     colorFilters[0] = SkColorFilters::Lighting(SK_ColorLTGRAY, 0xFF440000);
175     colorFilters[1] = SkColorFilters::Table(table1);
176     colorFilters[2] = SkColorFilters::Compose(SkColorFilters::TableARGB(nullptr, table3,
177                                                                         table3, table3),
178                                               SkColorFilters::TableARGB(nullptr, table2,
179                                                                         table2, table2));
180     colorFilters[3] = SkColorFilters::Blend(SK_ColorGREEN, SkBlendMode::kMultiply);
181     colorFilters[4] = SkColorFilterPriv::MakeGaussian();
182 
183     colorFilters[5] = SkColorFilters::LinearToSRGBGamma();
184     colorFilters[6] = SkColorFilters::SRGBToLinearGamma();
185 
186     SkPaint p;
187 
188     canvas->save();
189         canvas->clipRect(clipRect);
190         canvas->translate(clipRect.fLeft, clipRect.fTop);
191 
192         for (int y = 0; y < kNumTilesPerSide; ++y) {
193             for (int x = 0; x < kNumTilesPerSide; ++x) {
194                 SkRect r = SkRect::MakeXYWH(x * tileSize.width(), y * tileSize.height(),
195                                             tileSize.width(), tileSize.height()).makeInset(1.0f,
196                                                                                            1.0f);
197                 int colorFilterIndex = x*kNumTilesPerSide+y;
198                 p.setShader(create_gradient_shader(r,
199                                                    kGradientColors[colorFilterIndex],
200                                                    { 0.0f, 0.5f, 1.0f }));
201                 p.setColorFilter(colorFilters[colorFilterIndex]);
202                 canvas->drawRect(r, p);
203             }
204         }
205 
206     canvas->restore();
207 }
208 
draw_blend_mode_swatches(SkCanvas * canvas,SkRect clipRect)209 void draw_blend_mode_swatches(SkCanvas* canvas, SkRect clipRect) {
210     static const int kTileHeight = 16;
211     static const int kTileWidth = 16;
212     static const SkColor4f kOpaqueWhite { 1.0f, 1.0f, 1.0f, 1.0f };
213     static const SkColor4f kTransBluish { 0.0f, 0.5f, 1.0f, 0.5f };
214     static const SkColor4f kTransWhite { 1.0f, 1.0f, 1.0f, 0.75f };
215 
216     SkPaint dstPaint;
217     dstPaint.setColor(kOpaqueWhite);
218     dstPaint.setBlendMode(SkBlendMode::kSrc);
219     dstPaint.setAntiAlias(false);
220 
221     SkPaint srcPaint;
222     srcPaint.setColor(kTransBluish);
223     srcPaint.setAntiAlias(false);
224 
225     SkRect r = SkRect::MakeXYWH(clipRect.fLeft, clipRect.fTop, kTileWidth, kTileHeight);
226 
227     // For the first pass we draw: transparent bluish on top of opaque white
228     // For the second pass we draw: transparent white on top of transparent bluish
229     for (int passes = 0; passes < 2; ++passes) {
230         for (int i = 0; i <= (int)SkBlendMode::kLastCoeffMode; ++i) {
231             if (r.fLeft+kTileWidth > clipRect.fRight) {
232                 r.offsetTo(clipRect.fLeft, r.fTop+kTileHeight);
233             }
234 
235             canvas->drawRect(r.makeInset(1.0f, 1.0f), dstPaint);
236             srcPaint.setBlendMode(static_cast<SkBlendMode>(i));
237             canvas->drawRect(r.makeInset(2.0f, 2.0f), srcPaint);
238 
239             r.offset(kTileWidth, 0.0f);
240         }
241 
242         r.offsetTo(clipRect.fLeft, r.fTop+kTileHeight);
243         srcPaint.setColor(kTransWhite);
244         dstPaint.setColor(kTransBluish);
245     }
246 }
247 
248 } // anonymous namespace
249 
250 namespace skiagm {
251 
252 // This is just for bootstrapping Graphite.
253 class GraphiteStartGM : public GM {
254 public:
GraphiteStartGM()255     GraphiteStartGM() {
256         this->setBGColor(SK_ColorBLACK);
257         GetResourceAsBitmap("images/color_wheel.gif", &fBitmap);
258     }
259 
260 protected:
261     static constexpr int kTileWidth = 128;
262     static constexpr int kTileHeight = 128;
263     static constexpr int kWidth = 3 * kTileWidth;
264     static constexpr int kHeight = 3 * kTileHeight;
265     static constexpr int kClipInset = 4;
266 
onShortName()267     SkString onShortName() override {
268         return SkString("graphitestart");
269     }
270 
onISize()271     SkISize onISize() override {
272         return SkISize::Make(kWidth, kHeight);
273     }
274 
onDraw(SkCanvas * canvas)275     void onDraw(SkCanvas* canvas) override {
276 
277         const SkRect clipRect = SkRect::MakeWH(kWidth, kHeight).makeInset(kClipInset, kClipInset);
278 
279         canvas->save();
280         canvas->clipRRect(SkRRect::MakeRectXY(clipRect, 32.f, 32.f), true);
281 
282         // Upper-left corner
283         draw_image_shader_tile(canvas, SkRect::MakeXYWH(0, 0, kTileWidth, kTileHeight));
284 
285         // Upper-middle tile
286         draw_gradient_tile(canvas, SkRect::MakeXYWH(kTileWidth, 0, kTileWidth, kTileHeight));
287 
288         // Upper-right corner
289         draw_colorfilter_swatches(canvas, SkRect::MakeXYWH(2*kTileWidth, 0,
290                                                            kTileWidth, kTileWidth));
291 
292         // Middle-left tile
293         {
294             SkPaint p;
295             p.setColor(SK_ColorRED);
296 
297             SkRect r = SkRect::MakeXYWH(0, kTileHeight, kTileWidth, kTileHeight);
298             canvas->drawRect(r.makeInset(1.0f, 1.0f), p);
299         }
300 
301         // Middle-middle tile
302         {
303             SkPaint p;
304             p.setShader(create_blend_shader(canvas, SkBlendMode::kModulate));
305 
306             SkRect r = SkRect::MakeXYWH(kTileWidth, kTileHeight, kTileWidth, kTileHeight);
307             canvas->drawRect(r.makeInset(1.0f, 1.0f), p);
308         }
309 
310         // Middle-right tile
311         {
312             sk_sp<SkImage> image(GetResourceAsImage("images/mandrill_128.png"));
313             sk_sp<SkShader> shader;
314 
315             if (image) {
316                 shader = image->makeShader(SkTileMode::kRepeat, SkTileMode::kRepeat, {});
317                 shader = shader->makeWithColorFilter(create_grayscale_colorfilter());
318             }
319 
320             SkPaint p;
321             p.setShader(std::move(shader));
322 
323             SkRect r = SkRect::MakeXYWH(2*kTileWidth, kTileHeight, kTileWidth, kTileHeight);
324             canvas->drawRect(r.makeInset(1.0f, 1.0f), p);
325         }
326 
327         canvas->restore();
328 
329         // Bottom-left corner
330 #if defined(SK_GRAPHITE)
331         // TODO: failing serialize test on Linux, not sure what's going on
332         canvas->writePixels(fBitmap, 0, 2*kTileHeight);
333 #endif
334 
335         // Bottom-middle tile
336         draw_blend_mode_swatches(canvas, SkRect::MakeXYWH(kTileWidth, 2*kTileHeight,
337                                                           kTileWidth, kTileHeight));
338 
339         // Bottom-right corner
340         {
341             const SkRect kTile = SkRect::MakeXYWH(2*kTileWidth, 2*kTileHeight,
342                                                   kTileWidth, kTileHeight);
343 
344             SkPaint circlePaint;
345             circlePaint.setColor(SK_ColorBLUE);
346             circlePaint.setBlendMode(SkBlendMode::kSrc);
347 
348             canvas->clipRect(kTile);
349             canvas->drawRect(kTile.makeInset(10, 20), circlePaint);
350 
351             SkPaint restorePaint;
352             restorePaint.setBlendMode(SkBlendMode::kPlus);
353 
354             canvas->saveLayer(nullptr, &restorePaint);
355                 circlePaint.setColor(SK_ColorRED);
356                 circlePaint.setBlendMode(SkBlendMode::kSrc);
357 
358                 canvas->drawRect(kTile.makeInset(15, 25), circlePaint);
359             canvas->restore();
360         }
361     }
362 
363 private:
364     SkBitmap fBitmap;
365 };
366 
367 //////////////////////////////////////////////////////////////////////////////
368 
369 DEF_GM(return new GraphiteStartGM;)
370 
371 }  // namespace skiagm
372