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 static const SkColor gColors[] = {
19     SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE,
20 };
21 
22 static const GradData gGradData[] = {
23     { 1, gColors, NULL },
24     { 2, gColors, NULL },
25     { 3, gColors, NULL },
26     { 4, gColors, NULL },
27 };
28 
MakeLinear(const SkPoint pts[2],const GradData & data,SkShader::TileMode tm)29 static SkShader* MakeLinear(const SkPoint pts[2], const GradData& data, SkShader::TileMode tm) {
30     return SkGradientShader::CreateLinear(pts, data.fColors, data.fPos, data.fCount, tm);
31 }
32 
MakeRadial(const SkPoint pts[2],const GradData & data,SkShader::TileMode tm)33 static 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::CreateRadial(center, center.fX, data.fColors,
38                                           data.fPos, data.fCount, tm);
39 }
40 
MakeSweep(const SkPoint pts[2],const GradData & data,SkShader::TileMode)41 static SkShader* MakeSweep(const SkPoint pts[2], const GradData& data, SkShader::TileMode) {
42     SkPoint center;
43     center.set(SkScalarAve(pts[0].fX, pts[1].fX),
44                SkScalarAve(pts[0].fY, pts[1].fY));
45     return SkGradientShader::CreateSweep(center.fX, center.fY, data.fColors, data.fPos, data.fCount);
46 }
47 
Make2Radial(const SkPoint pts[2],const GradData & data,SkShader::TileMode tm)48 static SkShader* Make2Radial(const SkPoint pts[2], const GradData& data, SkShader::TileMode tm) {
49     SkPoint center0, center1;
50     center0.set(SkScalarAve(pts[0].fX, pts[1].fX),
51                 SkScalarAve(pts[0].fY, pts[1].fY));
52     center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3)/5),
53                 SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4));
54     return SkGradientShader::CreateTwoPointConical(
55         center1, (pts[1].fX - pts[0].fX) / 7,
56         center0, (pts[1].fX - pts[0].fX) / 2,
57         data.fColors, data.fPos, data.fCount, tm);
58 }
59 
Make2Conical(const SkPoint pts[2],const GradData & data,SkShader::TileMode tm)60 static SkShader* Make2Conical(const SkPoint pts[2], const GradData& data, SkShader::TileMode tm) {
61     SkPoint center0, center1;
62     SkScalar radius0 = (pts[1].fX - pts[0].fX) / 10;
63     SkScalar radius1 = (pts[1].fX - pts[0].fX) / 3;
64     center0.set(pts[0].fX + radius0, pts[0].fY + radius0);
65     center1.set(pts[1].fX - radius1, pts[1].fY - radius1);
66     return SkGradientShader::CreateTwoPointConical(center1, radius1,
67                                                    center0, radius0,
68                                                    data.fColors, data.fPos,
69                                                    data.fCount, tm);
70 }
71 
72 
73 typedef SkShader* (*GradMaker)(const SkPoint pts[2], const GradData& data, SkShader::TileMode tm);
74 
75 static const GradMaker gGradMakers[] = {
76     MakeLinear, MakeRadial, MakeSweep, Make2Radial, Make2Conical,
77 };
78 
79 ///////////////////////////////////////////////////////////////////////////////
80 
81 class GradientsNoTextureGM : public GM {
82 public:
GradientsNoTextureGM()83     GradientsNoTextureGM() {
84         this->setBGColor(0xFFDDDDDD);
85     }
86 
87 protected:
88 
onShortName()89     SkString onShortName() override { return SkString("gradients_no_texture"); }
onISize()90     SkISize onISize() override { return SkISize::Make(640, 615); }
91 
onDraw(SkCanvas * canvas)92     void onDraw(SkCanvas* canvas) override {
93         static const SkPoint kPts[2] = { { 0, 0 },
94                                          { SkIntToScalar(50), SkIntToScalar(50) } };
95         static const SkShader::TileMode kTM = SkShader::kClamp_TileMode;
96         SkRect kRect = { 0, 0, SkIntToScalar(50), SkIntToScalar(50) };
97         SkPaint paint;
98         paint.setAntiAlias(true);
99 
100         canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
101         static const uint8_t kAlphas[] = { 0xff, 0x40 };
102         for (size_t a = 0; a < SK_ARRAY_COUNT(kAlphas); ++a) {
103             for (size_t i = 0; i < SK_ARRAY_COUNT(gGradData); ++i) {
104                 canvas->save();
105                 for (size_t j = 0; j < SK_ARRAY_COUNT(gGradMakers); ++j) {
106                     SkShader* shader = gGradMakers[j](kPts, gGradData[i], kTM);
107                     paint.setShader(shader)->unref();
108                     paint.setAlpha(kAlphas[a]);
109                     canvas->drawRect(kRect, paint);
110                     canvas->translate(0, SkIntToScalar(kRect.height() + 20));
111                 }
112                 canvas->restore();
113                 canvas->translate(SkIntToScalar(kRect.width() + 20), 0);
114             }
115         }
116     }
117 
118 private:
119     typedef GM INHERITED;
120 };
121 
122 ///////////////////////////////////////////////////////////////////////////////
123 
124 struct ColorPos {
125     SkColor*    fColors;
126     SkScalar*   fPos;
127     int         fCount;
128 
ColorPosColorPos129     ColorPos() : fColors(NULL), fPos(NULL), fCount(0) {}
~ColorPosColorPos130     ~ColorPos() {
131         SkDELETE_ARRAY(fColors);
132         SkDELETE_ARRAY(fPos);
133     }
134 
constructColorPos135     void construct(const SkColor colors[], const SkScalar pos[], int count) {
136         fColors = SkNEW_ARRAY(SkColor, count);
137         memcpy(fColors, colors, count * sizeof(SkColor));
138         if (pos) {
139             fPos = SkNEW_ARRAY(SkScalar, count);
140             memcpy(fPos, pos, count * sizeof(SkScalar));
141             fPos[0] = 0;
142             fPos[count - 1] = 1;
143         }
144         fCount = count;
145     }
146 };
147 
make0(ColorPos * rec)148 static void make0(ColorPos* rec) {
149 #if 0
150     From http://jsfiddle.net/3fe2a/
151 
152 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%);
153 height: 30px;
154 #endif
155 
156     const SkColor colors[] = {
157         0xFF22d1cd, 0xFF22d1cd, 0xFFdf4b37, 0xFFdf4b37, 0xFF22d1cd, 0xFF22d1cd, 0xFFe6de36, 0xFFe6de36,
158         0xFF3267ff, 0xFF3267ff, 0xFF9d47d1, 0xFF9d47d1, 0xFF3267ff, 0xFF3267ff, 0xFF5cdd9d, 0xFF5cdd9d,
159         0xFF3267ff, 0xFF3267ff, 0xFF9d47d1, 0xFF9d47d1, 0xFF3267ff, 0xFF3267ff, 0xFFe3d082, 0xFFe3d082
160     };
161     const double percent[] = {
162         1, 0.9510157507590116, 2.9510157507590113, 23.695886056604927,
163         25.695886056604927, 25.39321881940624, 27.39321881940624, 31.849399922570655,
164         33.849399922570655, 44.57735802921938, 46.57735802921938, 53.27185850805876,
165         55.27185850805876, 61.95718972227316, 63.95718972227316, 69.89166004442,
166         71.89166004442, 74.45795382765857, 76.45795382765857, 82.78364610713776,
167         84.78364610713776, 94.52743647737229, 96.52743647737229, 96.03934633331295,
168     };
169     const int N = SK_ARRAY_COUNT(percent);
170     SkScalar pos[N];
171     for (int i = 0; i < N; ++i) {
172         pos[i] = SkDoubleToScalar(percent[i] / 100);
173     }
174     rec->construct(colors, pos, N);
175 }
176 
make1(ColorPos * rec)177 static void make1(ColorPos* rec) {
178     const SkColor colors[] = {
179         SK_ColorBLACK, SK_ColorWHITE, SK_ColorBLACK, SK_ColorWHITE,
180         SK_ColorBLACK, SK_ColorWHITE, SK_ColorBLACK, SK_ColorWHITE,
181         SK_ColorBLACK,
182     };
183     rec->construct(colors, NULL, SK_ARRAY_COUNT(colors));
184 }
185 
make2(ColorPos * rec)186 static void make2(ColorPos* rec) {
187     const SkColor colors[] = {
188         SK_ColorBLACK, SK_ColorWHITE, SK_ColorBLACK, SK_ColorWHITE,
189         SK_ColorBLACK, SK_ColorWHITE, SK_ColorBLACK, SK_ColorWHITE,
190         SK_ColorBLACK,
191     };
192     const int N = SK_ARRAY_COUNT(colors);
193     SkScalar pos[N];
194     for (int i = 0; i < N; ++i) {
195         pos[i] = SK_Scalar1 * i / (N - 1);
196     }
197     rec->construct(colors, pos, N);
198 }
199 
200 class GradientsManyColorsGM : public GM {
201     enum {
202         W = 800,
203     };
204     SkAutoTUnref<SkShader> fShader;
205 
206     typedef void (*Proc)(ColorPos*);
207 public:
GradientsManyColorsGM()208     GradientsManyColorsGM() {}
209 
210 protected:
211 
onShortName()212     SkString onShortName() override { return SkString("gradients_many"); }
onISize()213     SkISize onISize() override { return SkISize::Make(850, 100); }
214 
onDraw(SkCanvas * canvas)215     void onDraw(SkCanvas* canvas) override {
216         const Proc procs[] = {
217             make0, make1, make2,
218         };
219         const SkPoint pts[] = {
220             { 0, 0 },
221             { SkIntToScalar(W), 0 },
222         };
223         const SkRect r = SkRect::MakeWH(SkIntToScalar(W), 30);
224 
225         SkPaint paint;
226 
227         canvas->translate(20, 20);
228 
229         for (int i = 0; i <= 8; ++i) {
230             SkScalar x = r.width() * i / 8;
231             canvas->drawLine(x, 0, x, 10000, paint);
232         }
233 
234         for (size_t i = 0; i < SK_ARRAY_COUNT(procs); ++i) {
235             ColorPos rec;
236             procs[i](&rec);
237             SkShader* s = SkGradientShader::CreateLinear(pts, rec.fColors, rec.fPos, rec.fCount,
238                                                          SkShader::kClamp_TileMode);
239             paint.setShader(s)->unref();
240             canvas->drawRect(r, paint);
241             canvas->translate(0, r.height() + 20);
242         }
243     }
244 
245 private:
246     typedef GM INHERITED;
247 };
248 
249 ///////////////////////////////////////////////////////////////////////////////
250 
251 DEF_GM( return SkNEW(GradientsNoTextureGM));
252 DEF_GM( return SkNEW(GradientsManyColorsGM));
253