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