• 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 
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:
102 
onShortName()103     SkString onShortName() override {
104         return SkString(fDither ? "gradients_no_texture" : "gradients_no_texture_nodither");
105     }
106 
onISize()107     SkISize onISize() override { return SkISize::Make(640, 615); }
108 
onDraw(SkCanvas * canvas)109     void onDraw(SkCanvas* canvas) override {
110         constexpr SkPoint kPts[2] = { { 0, 0 },
111                                          { SkIntToScalar(50), SkIntToScalar(50) } };
112         constexpr SkTileMode kTM = SkTileMode::kClamp;
113         SkRect kRect = { 0, 0, SkIntToScalar(50), SkIntToScalar(50) };
114         SkPaint paint;
115         paint.setAntiAlias(true);
116         paint.setDither(fDither);
117 
118         canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
119         constexpr uint8_t kAlphas[] = { 0xff, 0x40 };
120         for (size_t a = 0; a < SK_ARRAY_COUNT(kAlphas); ++a) {
121             for (size_t i = 0; i < SK_ARRAY_COUNT(gGradData); ++i) {
122                 canvas->save();
123                 for (size_t j = 0; j < SK_ARRAY_COUNT(gGradMakers); ++j) {
124                     paint.setShader(gGradMakers[j](kPts, gGradData[i], kTM));
125                     paint.setAlpha(kAlphas[a]);
126                     canvas->drawRect(kRect, paint);
127                     canvas->translate(0, SkIntToScalar(kRect.height() + 20));
128                 }
129                 canvas->restore();
130                 canvas->translate(SkIntToScalar(kRect.width() + 20), 0);
131             }
132         }
133     }
134 
135 private:
136     bool fDither;
137 
138     typedef GM INHERITED;
139 };
140 
141 ///////////////////////////////////////////////////////////////////////////////
142 
143 struct ColorPos {
144     SkColor*    fColors;
145     SkScalar*   fPos;
146     int         fCount;
147 
ColorPosColorPos148     ColorPos() : fColors(nullptr), fPos(nullptr), fCount(0) {}
~ColorPosColorPos149     ~ColorPos() {
150         delete[] fColors;
151         delete[] fPos;
152     }
153 
constructColorPos154     void construct(const SkColor colors[], const SkScalar pos[], int count) {
155         fColors = new SkColor[count];
156         memcpy(fColors, colors, count * sizeof(SkColor));
157         if (pos) {
158             fPos = new SkScalar[count];
159             memcpy(fPos, pos, count * sizeof(SkScalar));
160             fPos[0] = 0;
161             fPos[count - 1] = 1;
162         }
163         fCount = count;
164     }
165 };
166 
make0(ColorPos * rec)167 static void make0(ColorPos* rec) {
168 #if 0
169     From http://jsfiddle.net/3fe2a/
170 
171 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%);
172 height: 30px;
173 #endif
174 
175     const SkColor colors[] = {
176         0xFF22d1cd, 0xFF22d1cd, 0xFFdf4b37, 0xFFdf4b37, 0xFF22d1cd, 0xFF22d1cd, 0xFFe6de36, 0xFFe6de36,
177         0xFF3267ff, 0xFF3267ff, 0xFF9d47d1, 0xFF9d47d1, 0xFF3267ff, 0xFF3267ff, 0xFF5cdd9d, 0xFF5cdd9d,
178         0xFF3267ff, 0xFF3267ff, 0xFF9d47d1, 0xFF9d47d1, 0xFF3267ff, 0xFF3267ff, 0xFFe3d082, 0xFFe3d082
179     };
180     const double percent[] = {
181         1, 0.9510157507590116, 2.9510157507590113, 23.695886056604927,
182         25.695886056604927, 25.39321881940624, 27.39321881940624, 31.849399922570655,
183         33.849399922570655, 44.57735802921938, 46.57735802921938, 53.27185850805876,
184         55.27185850805876, 61.95718972227316, 63.95718972227316, 69.89166004442,
185         71.89166004442, 74.45795382765857, 76.45795382765857, 82.78364610713776,
186         84.78364610713776, 94.52743647737229, 96.52743647737229, 96.03934633331295,
187     };
188     const int N = SK_ARRAY_COUNT(percent);
189     SkScalar pos[N];
190     for (int i = 0; i < N; ++i) {
191         pos[i] = SkDoubleToScalar(percent[i] / 100);
192     }
193     rec->construct(colors, pos, N);
194 }
195 
make1(ColorPos * rec)196 static void make1(ColorPos* rec) {
197     const SkColor colors[] = {
198         SK_ColorBLACK, SK_ColorWHITE, SK_ColorBLACK, SK_ColorWHITE,
199         SK_ColorBLACK, SK_ColorWHITE, SK_ColorBLACK, SK_ColorWHITE,
200         SK_ColorBLACK,
201     };
202     rec->construct(colors, nullptr, SK_ARRAY_COUNT(colors));
203 }
204 
make2(ColorPos * rec)205 static void make2(ColorPos* rec) {
206     const SkColor colors[] = {
207         SK_ColorBLACK, SK_ColorWHITE, SK_ColorBLACK, SK_ColorWHITE,
208         SK_ColorBLACK, SK_ColorWHITE, SK_ColorBLACK, SK_ColorWHITE,
209         SK_ColorBLACK,
210     };
211     const int N = SK_ARRAY_COUNT(colors);
212     SkScalar pos[N];
213     for (int i = 0; i < N; ++i) {
214         pos[i] = SK_Scalar1 * i / (N - 1);
215     }
216     rec->construct(colors, pos, N);
217 }
218 
make3(ColorPos * rec)219 static void make3(ColorPos* rec) {
220     const SkColor colors[] = {
221         SK_ColorRED, SK_ColorBLUE, SK_ColorBLUE, SK_ColorGREEN, SK_ColorGREEN, SK_ColorBLACK,
222     };
223     const SkScalar pos[] = {
224         0, 0, 0.5f, 0.5, 1, 1,
225     };
226     rec->construct(colors, pos, SK_ARRAY_COUNT(colors));
227 }
228 
229 class GradientsManyColorsGM : public GM {
230     enum {
231         W = 800,
232     };
233     sk_sp<SkShader> fShader;
234 
235     typedef void (*Proc)(ColorPos*);
236 public:
GradientsManyColorsGM(bool dither)237     GradientsManyColorsGM(bool dither) : fDither(dither) {}
238 
239 protected:
240 
onShortName()241     SkString onShortName() override {
242         return SkString(fDither ? "gradients_many" : "gradients_many_nodither");
243     }
244 
onISize()245     SkISize onISize() override { return SkISize::Make(880, 400); }
246 
onDraw(SkCanvas * canvas)247     void onDraw(SkCanvas* canvas) override {
248         const Proc procs[] = {
249             make0, make1, make2, make3,
250         };
251         const SkPoint pts[] = {
252             { 0, 0 },
253             { SkIntToScalar(W), 0 },
254         };
255         const SkRect r = SkRect::MakeWH(SkIntToScalar(W), 30);
256 
257         SkPaint paint;
258         paint.setDither(fDither);
259 
260         canvas->translate(40, 20);
261 
262         for (int i = 0; i <= 8; ++i) {
263             SkScalar x = r.width() * i / 8;
264             canvas->drawLine(x, 0, x, 10000, paint);
265         }
266 
267         // expand the drawing rect so we exercise clampping in the gradients
268         const SkRect drawR = r.makeOutset(20, 0);
269         for (size_t i = 0; i < SK_ARRAY_COUNT(procs); ++i) {
270             ColorPos rec;
271             procs[i](&rec);
272             paint.setShader(SkGradientShader::MakeLinear(pts, rec.fColors, rec.fPos, rec.fCount,
273                                                          SkTileMode::kClamp));
274             canvas->drawRect(drawR, paint);
275 
276             canvas->save();
277             canvas->translate(r.centerX(), r.height() + 4);
278             canvas->scale(-1, 1);
279             canvas->translate(-r.centerX(), 0);
280             canvas->drawRect(drawR, paint);
281             canvas->restore();
282 
283             canvas->translate(0, r.height() + 2*r.height() + 8);
284         }
285     }
286 
287 private:
288     bool fDither;
289 
290     typedef GM INHERITED;
291 };
292 
293 ///////////////////////////////////////////////////////////////////////////////
294 
295 DEF_GM(return new GradientsNoTextureGM(true);)
296 DEF_GM(return new GradientsNoTextureGM(false);)
297 DEF_GM(return new GradientsManyColorsGM(true);)
298 DEF_GM(return new GradientsManyColorsGM(false);)
299