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