xref: /aosp_15_r20/external/skia/gm/graphitestart.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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/SkPath.h"
16 #include "include/core/SkRRect.h"
17 #include "include/effects/SkGradientShader.h"
18 #include "include/gpu/ganesh/GrRecordingContext.h"
19 #include "src/core/SkColorFilterPriv.h"
20 #include "tools/DecodeUtils.h"
21 #include "tools/GpuToolUtils.h"
22 #include "tools/Resources.h"
23 #include "tools/ToolUtils.h"
24 
25 namespace {
26 
create_gradient_shader(SkRect r,const std::array<SkColor,3> & colors,const std::array<float,3> & offsets)27 sk_sp<SkShader> create_gradient_shader(SkRect r,
28                                        const std::array<SkColor, 3>& colors,
29                                        const std::array<float, 3>& offsets) {
30     SkPoint pts[2] = { {r.fLeft, r.fTop}, {r.fRight, r.fTop} };
31 
32     return SkGradientShader::MakeLinear(pts, colors.data(), offsets.data(), std::size(colors),
33                                         SkTileMode::kClamp);
34 }
35 
create_image_shader(SkCanvas * destCanvas,SkTileMode tmX,SkTileMode tmY)36 sk_sp<SkShader> create_image_shader(SkCanvas* destCanvas, SkTileMode tmX, SkTileMode tmY) {
37     SkBitmap bitmap;
38 
39     {
40         SkImageInfo ii = SkImageInfo::Make(64, 64, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
41         bitmap.allocPixels(ii);
42         bitmap.eraseColor(SK_ColorWHITE);
43 
44         SkCanvas tmpCanvas(bitmap);
45 
46         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         };
51 
52         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             }
58         }
59 
60         bitmap.setAlphaType(kOpaque_SkAlphaType);
61         bitmap.setImmutable();
62     }
63 
64     sk_sp<SkImage> img = SkImages::RasterFromBitmap(bitmap);
65     img = ToolUtils::MakeTextureImage(destCanvas, std::move(img));
66     if (img) {
67         return img->makeShader(tmX, tmY, SkSamplingOptions());
68     } else {
69         return nullptr;
70     }
71 }
72 
create_blend_shader(SkCanvas * destCanvas,SkBlendMode bm)73 sk_sp<SkShader> create_blend_shader(SkCanvas* destCanvas, SkBlendMode bm) {
74     constexpr SkColor4f kTransYellow = {1.0f, 1.0f, 0.0f, 0.5f};
75 
76     sk_sp<SkShader> dst = SkShaders::Color(kTransYellow, nullptr);
77     return SkShaders::Blend(bm,
78                             std::move(dst),
79                             create_image_shader(destCanvas,
80                                                 SkTileMode::kRepeat, SkTileMode::kRepeat));
81 }
82 
create_grayscale_colorfilter()83 sk_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 
draw_image_shader_tile(SkCanvas * canvas,SkRect clipRect)92 void draw_image_shader_tile(SkCanvas* canvas, SkRect clipRect) {
93     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();
105         canvas->clipRect(clipRect);
106         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 
draw_gradient_tile(SkCanvas * canvas,SkRect clipRect)117 void draw_gradient_tile(SkCanvas* canvas, SkRect clipRect) {
118     SkRect r{1, 1, 127, 127};
119     SkPaint p;
120     p.setShader(create_gradient_shader(r,
121                                        { SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE },
122                                        { 0.0f, 0.75f, 1.0f }));
123 
124     canvas->save();
125         canvas->clipRect(clipRect);
126         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();
136 }
137 
draw_colorfilter_swatches(SkCanvas * canvas,SkRect clipRect)138 void draw_colorfilter_swatches(SkCanvas* canvas, SkRect clipRect) {
139     static constexpr int kNumTilesPerSide = 3;
140 
141     SkSize tileSize = { clipRect.width() / kNumTilesPerSide, clipRect.height() / kNumTilesPerSide };
142 
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 
162     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     };
176 
177     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));
183     colorFilters[3] = SkColorFilters::Blend(SK_ColorGREEN, SkBlendMode::kMultiply);
184     colorFilters[4] = SkColorFilterPriv::MakeGaussian();
185 
186     colorFilters[5] = SkColorFilters::LinearToSRGBGamma();
187     colorFilters[6] = SkColorFilters::SRGBToLinearGamma();
188 
189     SkPaint p;
190 
191     canvas->save();
192         canvas->clipRect(clipRect);
193         canvas->translate(clipRect.fLeft, clipRect.fTop);
194 
195         for (int y = 0; y < kNumTilesPerSide; ++y) {
196             for (int x = 0; x < kNumTilesPerSide; ++x) {
197                 SkRect r = SkRect::MakeXYWH(x * tileSize.width(), y * tileSize.height(),
198                                             tileSize.width(), tileSize.height()).makeInset(1.0f,
199                                                                                            1.0f);
200                 int colorFilterIndex = x*kNumTilesPerSide+y;
201                 p.setShader(create_gradient_shader(r,
202                                                    kGradientColors[colorFilterIndex],
203                                                    { 0.0f, 0.5f, 1.0f }));
204                 p.setColorFilter(colorFilters[colorFilterIndex]);
205                 canvas->drawRect(r, p);
206             }
207         }
208 
209     canvas->restore();
210 }
211 
draw_blend_mode_swatches(SkCanvas * canvas,SkRect clipRect)212 void 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     }
249 }
250 
251 } // anonymous namespace
252 
253 namespace skiagm {
254 
255 // This is just for bootstrapping Graphite.
256 class GraphiteStartGM : public GM {
257 public:
258     GraphiteStartGM() = default;
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 
onOnceBeforeDraw()267     void onOnceBeforeDraw() override {
268         this->setBGColor(SK_ColorBLACK);
269         ToolUtils::GetResourceAsBitmap("images/color_wheel.gif", &fBitmap);
270     }
271 
getName() const272     SkString getName() const override { return SkString("graphitestart"); }
273 
getISize()274     SkISize getISize() override { return SkISize::Make(kWidth, kHeight); }
275 
onDraw(SkCanvas * canvas)276     void onDraw(SkCanvas* canvas) override {
277 
278         const SkRect clipRect = SkRect::MakeWH(kWidth, kHeight).makeInset(kClipInset, kClipInset);
279 
280         canvas->save();
281         canvas->clipRRect(SkRRect::MakeRectXY(clipRect, 32.f, 32.f), true);
282 
283         // Upper-left corner
284         draw_image_shader_tile(canvas, SkRect::MakeXYWH(0, 0, kTileWidth, kTileHeight));
285 
286         // Upper-middle tile
287         draw_gradient_tile(canvas, SkRect::MakeXYWH(kTileWidth, 0, kTileWidth, kTileHeight));
288 
289         // Upper-right corner
290         draw_colorfilter_swatches(canvas, SkRect::MakeXYWH(2*kTileWidth, 0,
291                                                            kTileWidth, kTileWidth));
292 
293         // Middle-left tile
294         {
295             SkPaint p;
296             p.setColor(SK_ColorRED);
297 
298             SkRect r = SkRect::MakeXYWH(0, kTileHeight, kTileWidth, kTileHeight);
299             canvas->drawRect(r.makeInset(1.0f, 1.0f), p);
300         }
301 
302         // Middle-middle tile
303         {
304             SkPaint p;
305             p.setShader(create_blend_shader(canvas, SkBlendMode::kModulate));
306 
307             SkRect r = SkRect::MakeXYWH(kTileWidth, kTileHeight, kTileWidth, kTileHeight);
308             canvas->drawRect(r.makeInset(1.0f, 1.0f), p);
309         }
310 
311         // Middle-right tile
312         {
313             sk_sp<SkImage> image(ToolUtils::GetResourceAsImage("images/mandrill_128.png"));
314             sk_sp<SkShader> shader;
315 
316             if (image) {
317                 shader = image->makeShader(SkTileMode::kRepeat, SkTileMode::kRepeat, {});
318                 shader = shader->makeWithColorFilter(create_grayscale_colorfilter());
319             }
320 
321             SkPaint p;
322             p.setShader(std::move(shader));
323 
324             SkRect r = SkRect::MakeXYWH(2*kTileWidth, kTileHeight, kTileWidth, kTileHeight);
325             canvas->drawRect(r.makeInset(1.0f, 1.0f), p);
326         }
327 
328         canvas->restore();
329 
330         // Bottom-left corner
331 #if defined(SK_GRAPHITE)
332         // TODO: failing serialize test on Linux, not sure what's going on
333         canvas->writePixels(fBitmap, 0, 2*kTileHeight);
334 #endif
335 
336         // Bottom-middle tile
337         draw_blend_mode_swatches(canvas, SkRect::MakeXYWH(kTileWidth, 2*kTileHeight,
338                                                           kTileWidth, kTileHeight));
339 
340         // Bottom-right corner
341         {
342             const SkRect kTile = SkRect::MakeXYWH(2*kTileWidth, 2*kTileHeight,
343                                                   kTileWidth, kTileHeight);
344 
345             SkPaint circlePaint;
346             circlePaint.setColor(SK_ColorBLUE);
347             circlePaint.setBlendMode(SkBlendMode::kSrc);
348 
349             canvas->clipRect(kTile);
350             canvas->drawRect(kTile.makeInset(10, 20), circlePaint);
351 
352             SkPaint restorePaint;
353             restorePaint.setBlendMode(SkBlendMode::kPlus);
354 
355             canvas->saveLayer(nullptr, &restorePaint);
356                 circlePaint.setColor(SK_ColorRED);
357                 circlePaint.setBlendMode(SkBlendMode::kSrc);
358 
359                 canvas->drawRect(kTile.makeInset(15, 25), circlePaint);
360             canvas->restore();
361         }
362     }
363 
364 private:
365     SkBitmap fBitmap;
366 };
367 
368 //////////////////////////////////////////////////////////////////////////////
369 
370 DEF_GM(return new GraphiteStartGM;)
371 
372 }  // namespace skiagm
373