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, 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 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(bool dither)83 GradientsNoTextureGM(bool dither) : fDither(dither) {
84 this->setBGColor(sk_tool_utils::color_to_565(0xFFDDDDDD));
85 }
86
87 protected:
88
onShortName()89 SkString onShortName() override {
90 return SkString(fDither ? "gradients_no_texture" : "gradients_no_texture_nodither");
91 }
92
onISize()93 SkISize onISize() override { return SkISize::Make(640, 615); }
94
onDraw(SkCanvas * canvas)95 void onDraw(SkCanvas* canvas) override {
96 static const SkPoint kPts[2] = { { 0, 0 },
97 { SkIntToScalar(50), SkIntToScalar(50) } };
98 static const SkShader::TileMode kTM = SkShader::kClamp_TileMode;
99 SkRect kRect = { 0, 0, SkIntToScalar(50), SkIntToScalar(50) };
100 SkPaint paint;
101 paint.setAntiAlias(true);
102 paint.setDither(fDither);
103
104 canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
105 static const uint8_t kAlphas[] = { 0xff, 0x40 };
106 for (size_t a = 0; a < SK_ARRAY_COUNT(kAlphas); ++a) {
107 for (size_t i = 0; i < SK_ARRAY_COUNT(gGradData); ++i) {
108 canvas->save();
109 for (size_t j = 0; j < SK_ARRAY_COUNT(gGradMakers); ++j) {
110 SkShader* shader = gGradMakers[j](kPts, gGradData[i], kTM);
111 paint.setShader(shader)->unref();
112 paint.setAlpha(kAlphas[a]);
113 canvas->drawRect(kRect, paint);
114 canvas->translate(0, SkIntToScalar(kRect.height() + 20));
115 }
116 canvas->restore();
117 canvas->translate(SkIntToScalar(kRect.width() + 20), 0);
118 }
119 }
120 }
121
122 private:
123 bool fDither;
124
125 typedef GM INHERITED;
126 };
127
128 ///////////////////////////////////////////////////////////////////////////////
129
130 struct ColorPos {
131 SkColor* fColors;
132 SkScalar* fPos;
133 int fCount;
134
ColorPosColorPos135 ColorPos() : fColors(nullptr), fPos(nullptr), fCount(0) {}
~ColorPosColorPos136 ~ColorPos() {
137 delete[] fColors;
138 delete[] fPos;
139 }
140
constructColorPos141 void construct(const SkColor colors[], const SkScalar pos[], int count) {
142 fColors = new SkColor[count];
143 memcpy(fColors, colors, count * sizeof(SkColor));
144 if (pos) {
145 fPos = new 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
make0(ColorPos * rec)154 static void make0(ColorPos* rec) {
155 #if 0
156 From http://jsfiddle.net/3fe2a/
157
158 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%);
159 height: 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
make1(ColorPos * rec)183 static 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, nullptr, SK_ARRAY_COUNT(colors));
190 }
191
make2(ColorPos * rec)192 static 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
make3(ColorPos * rec)206 static void make3(ColorPos* rec) {
207 const SkColor colors[] = {
208 SK_ColorRED, SK_ColorBLUE, SK_ColorBLUE, SK_ColorGREEN, SK_ColorGREEN, SK_ColorBLACK,
209 };
210 const SkScalar pos[] = {
211 0, 0, 0.5f, 0.5, 1, 1,
212 };
213 rec->construct(colors, pos, SK_ARRAY_COUNT(colors));
214 }
215
216 class GradientsManyColorsGM : public GM {
217 enum {
218 W = 800,
219 };
220 SkAutoTUnref<SkShader> fShader;
221
222 typedef void (*Proc)(ColorPos*);
223 public:
GradientsManyColorsGM(bool dither)224 GradientsManyColorsGM(bool dither) : fDither(dither) {}
225
226 protected:
227
onShortName()228 SkString onShortName() override {
229 return SkString(fDither ? "gradients_many" : "gradients_many_nodither");
230 }
231
onISize()232 SkISize onISize() override { return SkISize::Make(880, 400); }
233
onDraw(SkCanvas * canvas)234 void onDraw(SkCanvas* canvas) override {
235 const Proc procs[] = {
236 make0, make1, make2, make3,
237 };
238 const SkPoint pts[] = {
239 { 0, 0 },
240 { SkIntToScalar(W), 0 },
241 };
242 const SkRect r = SkRect::MakeWH(SkIntToScalar(W), 30);
243
244 SkPaint paint;
245 paint.setDither(fDither);
246
247 canvas->translate(40, 20);
248
249 for (int i = 0; i <= 8; ++i) {
250 SkScalar x = r.width() * i / 8;
251 canvas->drawLine(x, 0, x, 10000, paint);
252 }
253
254 // expand the drawing rect so we exercise clampping in the gradients
255 const SkRect drawR = r.makeOutset(20, 0);
256 for (size_t i = 0; i < SK_ARRAY_COUNT(procs); ++i) {
257 ColorPos rec;
258 procs[i](&rec);
259 SkShader* s = SkGradientShader::CreateLinear(pts, rec.fColors, rec.fPos, rec.fCount,
260 SkShader::kClamp_TileMode);
261 paint.setShader(s)->unref();
262 canvas->drawRect(drawR, paint);
263
264 canvas->save();
265 canvas->translate(r.centerX(), r.height() + 4);
266 canvas->scale(-1, 1);
267 canvas->translate(-r.centerX(), 0);
268 canvas->drawRect(drawR, paint);
269 canvas->restore();
270
271 canvas->translate(0, r.height() + 2*r.height() + 8);
272 }
273 }
274
275 private:
276 bool fDither;
277
278 typedef GM INHERITED;
279 };
280
281 ///////////////////////////////////////////////////////////////////////////////
282
283 DEF_GM(return new GradientsNoTextureGM(true);)
284 DEF_GM(return new GradientsNoTextureGM(false);)
285 DEF_GM(return new GradientsManyColorsGM(true);)
286 DEF_GM(return new GradientsManyColorsGM(false);)
287