xref: /aosp_15_r20/external/skia/gm/gradients_no_texture.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
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 
8 #include "gm/gm.h"
9 #include "include/core/SkCanvas.h"
10 #include "include/core/SkColor.h"
11 #include "include/core/SkPaint.h"
12 #include "include/core/SkPoint.h"
13 #include "include/core/SkRect.h"
14 #include "include/core/SkRefCnt.h"
15 #include "include/core/SkScalar.h"
16 #include "include/core/SkShader.h"
17 #include "include/core/SkSize.h"
18 #include "include/core/SkString.h"
19 #include "include/core/SkTileMode.h"
20 #include "include/core/SkTypes.h"
21 #include "include/effects/SkGradientShader.h"
22 
23 #include <string.h>
24 
25 using namespace skiagm;
26 
27 struct GradData {
28     int             fCount;
29     const SkColor*  fColors;
30     const SkScalar* fPos;
31 };
32 
33 constexpr SkColor gColors[] = {
34     SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE,
35 };
36 
37 constexpr GradData gGradData[] = {
38     { 1, gColors, nullptr },
39     { 2, gColors, nullptr },
40     { 3, gColors, nullptr },
41     { 4, gColors, nullptr },
42 };
43 
MakeLinear(const SkPoint pts[2],const GradData & data,SkTileMode tm)44 static sk_sp<SkShader> MakeLinear(const SkPoint pts[2], const GradData& data, SkTileMode tm) {
45     return SkGradientShader::MakeLinear(pts, data.fColors, data.fPos, data.fCount, tm);
46 }
47 
MakeRadial(const SkPoint pts[2],const GradData & data,SkTileMode tm)48 static sk_sp<SkShader> MakeRadial(const SkPoint pts[2], const GradData& data, SkTileMode tm) {
49     SkPoint center;
50     center.set(SkScalarAve(pts[0].fX, pts[1].fX),
51                SkScalarAve(pts[0].fY, pts[1].fY));
52     return SkGradientShader::MakeRadial(center, center.fX, data.fColors, data.fPos, data.fCount, tm);
53 }
54 
MakeSweep(const SkPoint pts[2],const GradData & data,SkTileMode)55 static sk_sp<SkShader> MakeSweep(const SkPoint pts[2], const GradData& data, SkTileMode) {
56     SkPoint center;
57     center.set(SkScalarAve(pts[0].fX, pts[1].fX),
58                SkScalarAve(pts[0].fY, pts[1].fY));
59     return SkGradientShader::MakeSweep(center.fX, center.fY, data.fColors, data.fPos, data.fCount);
60 }
61 
Make2Radial(const SkPoint pts[2],const GradData & data,SkTileMode tm)62 static sk_sp<SkShader> Make2Radial(const SkPoint pts[2], const GradData& data, SkTileMode tm) {
63     SkPoint center0, center1;
64     center0.set(SkScalarAve(pts[0].fX, pts[1].fX),
65                 SkScalarAve(pts[0].fY, pts[1].fY));
66     center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3)/5),
67                 SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4));
68     return SkGradientShader::MakeTwoPointConical(
69         center1, (pts[1].fX - pts[0].fX) / 7,
70         center0, (pts[1].fX - pts[0].fX) / 2,
71         data.fColors, data.fPos, data.fCount, tm);
72 }
73 
Make2Conical(const SkPoint pts[2],const GradData & data,SkTileMode tm)74 static sk_sp<SkShader> Make2Conical(const SkPoint pts[2], const GradData& data, SkTileMode tm) {
75     SkPoint center0, center1;
76     SkScalar radius0 = (pts[1].fX - pts[0].fX) / 10;
77     SkScalar radius1 = (pts[1].fX - pts[0].fX) / 3;
78     center0.set(pts[0].fX + radius0, pts[0].fY + radius0);
79     center1.set(pts[1].fX - radius1, pts[1].fY - radius1);
80     return SkGradientShader::MakeTwoPointConical(center1, radius1,
81                                                    center0, radius0,
82                                                    data.fColors, data.fPos,
83                                                    data.fCount, tm);
84 }
85 
86 
87 typedef sk_sp<SkShader> (*GradMaker)(const SkPoint pts[2], const GradData& data, SkTileMode tm);
88 
89 constexpr GradMaker gGradMakers[] = {
90     MakeLinear, MakeRadial, MakeSweep, Make2Radial, Make2Conical,
91 };
92 
93 ///////////////////////////////////////////////////////////////////////////////
94 
95 class GradientsNoTextureGM : public GM {
96 public:
GradientsNoTextureGM(bool dither)97     GradientsNoTextureGM(bool dither) : fDither(dither) {
98         this->setBGColor(0xFFDDDDDD);
99     }
100 
101 protected:
getName() const102     SkString getName() const override {
103         return SkString(fDither ? "gradients_no_texture" : "gradients_no_texture_nodither");
104     }
105 
getISize()106     SkISize getISize() override { return SkISize::Make(640, 615); }
107 
onDraw(SkCanvas * canvas)108     void onDraw(SkCanvas* canvas) override {
109         constexpr SkPoint kPts[2] = { { 0, 0 },
110                                          { SkIntToScalar(50), SkIntToScalar(50) } };
111         constexpr SkTileMode kTM = SkTileMode::kClamp;
112         SkRect kRect = { 0, 0, SkIntToScalar(50), SkIntToScalar(50) };
113         SkPaint paint;
114         paint.setAntiAlias(true);
115         paint.setDither(fDither);
116 
117         canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
118         constexpr uint8_t kAlphas[] = { 0xff, 0x40 };
119         for (size_t a = 0; a < std::size(kAlphas); ++a) {
120             for (size_t i = 0; i < std::size(gGradData); ++i) {
121                 canvas->save();
122                 for (size_t j = 0; j < std::size(gGradMakers); ++j) {
123                     paint.setShader(gGradMakers[j](kPts, gGradData[i], kTM));
124                     paint.setAlpha(kAlphas[a]);
125                     canvas->drawRect(kRect, paint);
126                     canvas->translate(0, SkIntToScalar(kRect.height() + 20));
127                 }
128                 canvas->restore();
129                 canvas->translate(SkIntToScalar(kRect.width() + 20), 0);
130             }
131         }
132     }
133 
134 private:
135     bool fDither;
136 
137     using INHERITED = GM;
138 };
139 
140 ///////////////////////////////////////////////////////////////////////////////
141 
142 struct ColorPos {
143     SkColor*    fColors;
144     SkScalar*   fPos;
145     int         fCount;
146 
ColorPosColorPos147     ColorPos() : fColors(nullptr), fPos(nullptr), fCount(0) {}
~ColorPosColorPos148     ~ColorPos() {
149         delete[] fColors;
150         delete[] fPos;
151     }
152 
constructColorPos153     void construct(const SkColor colors[], const SkScalar pos[], int count) {
154         fColors = new SkColor[count];
155         memcpy(fColors, colors, count * sizeof(SkColor));
156         if (pos) {
157             fPos = new SkScalar[count];
158             memcpy(fPos, pos, count * sizeof(SkScalar));
159             fPos[0] = 0;
160             fPos[count - 1] = 1;
161         }
162         fCount = count;
163     }
164 };
165 
make0(ColorPos * rec)166 static void make0(ColorPos* rec) {
167 #if 0
168     From http://jsfiddle.net/3fe2a/
169 
170 background-image: -webkit-linear-gradient(left, #22d1cd 1%, #22d1cd 0.9510157507590116%, #df4b37 2.9510157507590113%, #df4b37 23.695886056604927%, #22d1cd 25.695886056604927%, #22d1cd 25.39321881940624%, #e6de36 27.39321881940624%, #e6de36 31.849399922570655%, #3267ff 33.849399922570655%, #3267ff 44.57735802921938%, #9d47d1 46.57735802921938%, #9d47d1 53.27185850805876%, #3267ff 55.27185850805876%, #3267ff 61.95718972227316%, #5cdd9d 63.95718972227316%, #5cdd9d 69.89166004442%, #3267ff 71.89166004442%, #3267ff 74.45795382765857%, #9d47d1 76.45795382765857%, #9d47d1 82.78364610713776%, #3267ff 84.78364610713776%, #3267ff 94.52743647737229%, #e3d082 96.52743647737229%, #e3d082 96.03934633331295%);
171 height: 30px;
172 #endif
173 
174     const SkColor colors[] = {
175         0xFF22d1cd, 0xFF22d1cd, 0xFFdf4b37, 0xFFdf4b37, 0xFF22d1cd, 0xFF22d1cd, 0xFFe6de36, 0xFFe6de36,
176         0xFF3267ff, 0xFF3267ff, 0xFF9d47d1, 0xFF9d47d1, 0xFF3267ff, 0xFF3267ff, 0xFF5cdd9d, 0xFF5cdd9d,
177         0xFF3267ff, 0xFF3267ff, 0xFF9d47d1, 0xFF9d47d1, 0xFF3267ff, 0xFF3267ff, 0xFFe3d082, 0xFFe3d082
178     };
179     const double percent[] = {
180         1, 0.9510157507590116, 2.9510157507590113, 23.695886056604927,
181         25.695886056604927, 25.39321881940624, 27.39321881940624, 31.849399922570655,
182         33.849399922570655, 44.57735802921938, 46.57735802921938, 53.27185850805876,
183         55.27185850805876, 61.95718972227316, 63.95718972227316, 69.89166004442,
184         71.89166004442, 74.45795382765857, 76.45795382765857, 82.78364610713776,
185         84.78364610713776, 94.52743647737229, 96.52743647737229, 96.03934633331295,
186     };
187     const int N = std::size(percent);
188     SkScalar pos[N];
189     for (int i = 0; i < N; ++i) {
190         pos[i] = SkDoubleToScalar(percent[i] / 100);
191     }
192     rec->construct(colors, pos, N);
193 }
194 
make1(ColorPos * rec)195 static void make1(ColorPos* rec) {
196     const SkColor colors[] = {
197         SK_ColorBLACK, SK_ColorWHITE, SK_ColorBLACK, SK_ColorWHITE,
198         SK_ColorBLACK, SK_ColorWHITE, SK_ColorBLACK, SK_ColorWHITE,
199         SK_ColorBLACK,
200     };
201     rec->construct(colors, nullptr, std::size(colors));
202 }
203 
make2(ColorPos * rec)204 static void make2(ColorPos* rec) {
205     const SkColor colors[] = {
206         SK_ColorBLACK, SK_ColorWHITE, SK_ColorBLACK, SK_ColorWHITE,
207         SK_ColorBLACK, SK_ColorWHITE, SK_ColorBLACK, SK_ColorWHITE,
208         SK_ColorBLACK,
209     };
210     const int N = std::size(colors);
211     SkScalar pos[N];
212     for (int i = 0; i < N; ++i) {
213         pos[i] = SK_Scalar1 * i / (N - 1);
214     }
215     rec->construct(colors, pos, N);
216 }
217 
make3(ColorPos * rec)218 static void make3(ColorPos* rec) {
219     const SkColor colors[] = {
220         SK_ColorRED, SK_ColorBLUE, SK_ColorBLUE, SK_ColorGREEN, SK_ColorGREEN, SK_ColorBLACK,
221     };
222     const SkScalar pos[] = {
223         0, 0, 0.5f, 0.5, 1, 1,
224     };
225     rec->construct(colors, pos, std::size(colors));
226 }
227 
228 class GradientsManyColorsGM : public GM {
229     enum {
230         W = 800,
231     };
232     sk_sp<SkShader> fShader;
233 
234     typedef void (*Proc)(ColorPos*);
235 public:
GradientsManyColorsGM(bool dither)236     GradientsManyColorsGM(bool dither) : fDither(dither) {}
237 
238 protected:
getName() const239     SkString getName() const override {
240         return SkString(fDither ? "gradients_many" : "gradients_many_nodither");
241     }
242 
getISize()243     SkISize getISize() override { return SkISize::Make(880, 400); }
244 
onDraw(SkCanvas * canvas)245     void onDraw(SkCanvas* canvas) override {
246         const Proc procs[] = {
247             make0, make1, make2, make3,
248         };
249         const SkPoint pts[] = {
250             { 0, 0 },
251             { SkIntToScalar(W), 0 },
252         };
253         const SkRect r = SkRect::MakeWH(SkIntToScalar(W), 30);
254 
255         SkPaint paint;
256         paint.setDither(fDither);
257 
258         canvas->translate(40, 20);
259 
260         for (int i = 0; i <= 8; ++i) {
261             SkScalar x = r.width() * i / 8;
262             canvas->drawLine(x, 0, x, 10000, paint);
263         }
264 
265         // expand the drawing rect so we exercise clampping in the gradients
266         const SkRect drawR = r.makeOutset(20, 0);
267         for (size_t i = 0; i < std::size(procs); ++i) {
268             ColorPos rec;
269             procs[i](&rec);
270             paint.setShader(SkGradientShader::MakeLinear(pts, rec.fColors, rec.fPos, rec.fCount,
271                                                          SkTileMode::kClamp));
272             canvas->drawRect(drawR, paint);
273 
274             canvas->save();
275             canvas->translate(r.centerX(), r.height() + 4);
276             canvas->scale(-1, 1);
277             canvas->translate(-r.centerX(), 0);
278             canvas->drawRect(drawR, paint);
279             canvas->restore();
280 
281             canvas->translate(0, r.height() + 2*r.height() + 8);
282         }
283     }
284 
285 private:
286     bool fDither;
287 
288     using INHERITED = GM;
289 };
290 
291 ///////////////////////////////////////////////////////////////////////////////
292 
293 DEF_GM(return new GradientsNoTextureGM(true);)
294 DEF_GM(return new GradientsNoTextureGM(false);)
295 DEF_GM(return new GradientsManyColorsGM(true);)
296 DEF_GM(return new GradientsManyColorsGM(false);)
297