blob: 9acd633f29dd0d618dac899ac1035b086465d16a [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"
Mike Klein33d20552017-03-22 13:47:51 -04008#include "sk_tool_utils.h"
bsalomon@google.com82d12232013-09-09 15:36:26 +00009#include "SkGradientShader.h"
10
11using namespace skiagm;
12
13struct GradData {
14 int fCount;
15 const SkColor* fColors;
16 const SkScalar* fPos;
17};
18
mtkleindbfd7ab2016-09-01 11:24:54 -070019constexpr SkColor gColors[] = {
bsalomon@google.com82d12232013-09-09 15:36:26 +000020 SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE,
21};
22
mtkleindbfd7ab2016-09-01 11:24:54 -070023constexpr GradData gGradData[] = {
halcanary96fcdcc2015-08-27 07:41:13 -070024 { 1, gColors, nullptr },
25 { 2, gColors, nullptr },
26 { 3, gColors, nullptr },
27 { 4, gColors, nullptr },
bsalomon@google.com82d12232013-09-09 15:36:26 +000028};
29
reed1a9b9642016-03-13 14:13:58 -070030static sk_sp<SkShader> MakeLinear(const SkPoint pts[2], const GradData& data, SkShader::TileMode tm) {
31 return SkGradientShader::MakeLinear(pts, data.fColors, data.fPos, data.fCount, tm);
bsalomon@google.com82d12232013-09-09 15:36:26 +000032}
33
reed1a9b9642016-03-13 14:13:58 -070034static sk_sp<SkShader> MakeRadial(const SkPoint pts[2], const GradData& data, SkShader::TileMode tm) {
bsalomon@google.com82d12232013-09-09 15:36:26 +000035 SkPoint center;
36 center.set(SkScalarAve(pts[0].fX, pts[1].fX),
37 SkScalarAve(pts[0].fY, pts[1].fY));
reed1a9b9642016-03-13 14:13:58 -070038 return SkGradientShader::MakeRadial(center, center.fX, data.fColors, data.fPos, data.fCount, tm);
bsalomon@google.com82d12232013-09-09 15:36:26 +000039}
40
reed1a9b9642016-03-13 14:13:58 -070041static sk_sp<SkShader> MakeSweep(const SkPoint pts[2], const GradData& data, SkShader::TileMode) {
bsalomon@google.com82d12232013-09-09 15:36:26 +000042 SkPoint center;
43 center.set(SkScalarAve(pts[0].fX, pts[1].fX),
44 SkScalarAve(pts[0].fY, pts[1].fY));
reed1a9b9642016-03-13 14:13:58 -070045 return SkGradientShader::MakeSweep(center.fX, center.fY, data.fColors, data.fPos, data.fCount);
bsalomon@google.com82d12232013-09-09 15:36:26 +000046}
47
reed1a9b9642016-03-13 14:13:58 -070048static sk_sp<SkShader> Make2Radial(const SkPoint pts[2], const GradData& data, SkShader::TileMode tm) {
bsalomon@google.com82d12232013-09-09 15:36:26 +000049 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));
reed1a9b9642016-03-13 14:13:58 -070054 return SkGradientShader::MakeTwoPointConical(
bsalomon@google.com82d12232013-09-09 15:36:26 +000055 center1, (pts[1].fX - pts[0].fX) / 7,
56 center0, (pts[1].fX - pts[0].fX) / 2,
commit-bot@chromium.org83f23d82014-05-22 12:27:41 +000057 data.fColors, data.fPos, data.fCount, tm);
bsalomon@google.com82d12232013-09-09 15:36:26 +000058}
59
reed1a9b9642016-03-13 14:13:58 -070060static sk_sp<SkShader> Make2Conical(const SkPoint pts[2], const GradData& data, SkShader::TileMode tm) {
bsalomon@google.com82d12232013-09-09 15:36:26 +000061 SkPoint center0, center1;
reed80ea19c2015-05-12 10:37:34 -070062 SkScalar radius0 = (pts[1].fX - pts[0].fX) / 10;
63 SkScalar radius1 = (pts[1].fX - pts[0].fX) / 3;
bsalomon@google.com82d12232013-09-09 15:36:26 +000064 center0.set(pts[0].fX + radius0, pts[0].fY + radius0);
65 center1.set(pts[1].fX - radius1, pts[1].fY - radius1);
reed1a9b9642016-03-13 14:13:58 -070066 return SkGradientShader::MakeTwoPointConical(center1, radius1,
bsalomon@google.com82d12232013-09-09 15:36:26 +000067 center0, radius0,
68 data.fColors, data.fPos,
commit-bot@chromium.org83f23d82014-05-22 12:27:41 +000069 data.fCount, tm);
bsalomon@google.com82d12232013-09-09 15:36:26 +000070}
71
72
reed1a9b9642016-03-13 14:13:58 -070073typedef sk_sp<SkShader> (*GradMaker)(const SkPoint pts[2], const GradData& data, SkShader::TileMode tm);
commit-bot@chromium.org83f23d82014-05-22 12:27:41 +000074
mtkleindbfd7ab2016-09-01 11:24:54 -070075constexpr GradMaker gGradMakers[] = {
bsalomon@google.com82d12232013-09-09 15:36:26 +000076 MakeLinear, MakeRadial, MakeSweep, Make2Radial, Make2Conical,
77};
78
79///////////////////////////////////////////////////////////////////////////////
80
81class GradientsNoTextureGM : public GM {
82public:
fmalita063675b2015-10-12 10:41:48 -070083 GradientsNoTextureGM(bool dither) : fDither(dither) {
caryclark65cdba62015-06-15 06:51:08 -070084 this->setBGColor(sk_tool_utils::color_to_565(0xFFDDDDDD));
bsalomon@google.com82d12232013-09-09 15:36:26 +000085 }
86
87protected:
commit-bot@chromium.orga90c6802014-04-30 13:20:45 +000088
fmalita063675b2015-10-12 10:41:48 -070089 SkString onShortName() override {
90 return SkString(fDither ? "gradients_no_texture" : "gradients_no_texture_nodither");
91 }
92
mtklein36352bf2015-03-25 18:17:31 -070093 SkISize onISize() override { return SkISize::Make(640, 615); }
bsalomon@google.com82d12232013-09-09 15:36:26 +000094
mtklein36352bf2015-03-25 18:17:31 -070095 void onDraw(SkCanvas* canvas) override {
mtkleindbfd7ab2016-09-01 11:24:54 -070096 constexpr SkPoint kPts[2] = { { 0, 0 },
bsalomon@google.com82d12232013-09-09 15:36:26 +000097 { SkIntToScalar(50), SkIntToScalar(50) } };
mtkleindbfd7ab2016-09-01 11:24:54 -070098 constexpr SkShader::TileMode kTM = SkShader::kClamp_TileMode;
bsalomon@google.com82d12232013-09-09 15:36:26 +000099 SkRect kRect = { 0, 0, SkIntToScalar(50), SkIntToScalar(50) };
100 SkPaint paint;
101 paint.setAntiAlias(true);
fmalita063675b2015-10-12 10:41:48 -0700102 paint.setDither(fDither);
bsalomon@google.com82d12232013-09-09 15:36:26 +0000103
104 canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
mtkleindbfd7ab2016-09-01 11:24:54 -0700105 constexpr uint8_t kAlphas[] = { 0xff, 0x40 };
bsalomon@google.com82d12232013-09-09 15:36:26 +0000106 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) {
reed1a9b9642016-03-13 14:13:58 -0700110 paint.setShader(gGradMakers[j](kPts, gGradData[i], kTM));
bsalomon@google.com82d12232013-09-09 15:36:26 +0000111 paint.setAlpha(kAlphas[a]);
112 canvas->drawRect(kRect, paint);
113 canvas->translate(0, SkIntToScalar(kRect.height() + 20));
114 }
115 canvas->restore();
116 canvas->translate(SkIntToScalar(kRect.width() + 20), 0);
117 }
118 }
119 }
120
121private:
fmalita063675b2015-10-12 10:41:48 -0700122 bool fDither;
123
bsalomon@google.com82d12232013-09-09 15:36:26 +0000124 typedef GM INHERITED;
125};
126
127///////////////////////////////////////////////////////////////////////////////
128
reed@google.com7b8999b2014-04-18 17:55:37 +0000129struct ColorPos {
130 SkColor* fColors;
131 SkScalar* fPos;
132 int fCount;
133
halcanary96fcdcc2015-08-27 07:41:13 -0700134 ColorPos() : fColors(nullptr), fPos(nullptr), fCount(0) {}
reed@google.com7b8999b2014-04-18 17:55:37 +0000135 ~ColorPos() {
halcanary385fe4d2015-08-26 13:07:48 -0700136 delete[] fColors;
137 delete[] fPos;
reed@google.com7b8999b2014-04-18 17:55:37 +0000138 }
139
140 void construct(const SkColor colors[], const SkScalar pos[], int count) {
halcanary385fe4d2015-08-26 13:07:48 -0700141 fColors = new SkColor[count];
reed@google.com7b8999b2014-04-18 17:55:37 +0000142 memcpy(fColors, colors, count * sizeof(SkColor));
143 if (pos) {
halcanary385fe4d2015-08-26 13:07:48 -0700144 fPos = new SkScalar[count];
reed@google.com7b8999b2014-04-18 17:55:37 +0000145 memcpy(fPos, pos, count * sizeof(SkScalar));
146 fPos[0] = 0;
147 fPos[count - 1] = 1;
148 }
149 fCount = count;
150 }
151};
152
153static void make0(ColorPos* rec) {
154#if 0
155 From http://jsfiddle.net/3fe2a/
156
157background-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%);
158height: 30px;
159#endif
160
161 const SkColor colors[] = {
162 0xFF22d1cd, 0xFF22d1cd, 0xFFdf4b37, 0xFFdf4b37, 0xFF22d1cd, 0xFF22d1cd, 0xFFe6de36, 0xFFe6de36,
163 0xFF3267ff, 0xFF3267ff, 0xFF9d47d1, 0xFF9d47d1, 0xFF3267ff, 0xFF3267ff, 0xFF5cdd9d, 0xFF5cdd9d,
164 0xFF3267ff, 0xFF3267ff, 0xFF9d47d1, 0xFF9d47d1, 0xFF3267ff, 0xFF3267ff, 0xFFe3d082, 0xFFe3d082
165 };
166 const double percent[] = {
167 1, 0.9510157507590116, 2.9510157507590113, 23.695886056604927,
168 25.695886056604927, 25.39321881940624, 27.39321881940624, 31.849399922570655,
169 33.849399922570655, 44.57735802921938, 46.57735802921938, 53.27185850805876,
170 55.27185850805876, 61.95718972227316, 63.95718972227316, 69.89166004442,
171 71.89166004442, 74.45795382765857, 76.45795382765857, 82.78364610713776,
172 84.78364610713776, 94.52743647737229, 96.52743647737229, 96.03934633331295,
173 };
174 const int N = SK_ARRAY_COUNT(percent);
175 SkScalar pos[N];
176 for (int i = 0; i < N; ++i) {
177 pos[i] = SkDoubleToScalar(percent[i] / 100);
178 }
179 rec->construct(colors, pos, N);
180}
181
182static void make1(ColorPos* rec) {
183 const SkColor colors[] = {
184 SK_ColorBLACK, SK_ColorWHITE, SK_ColorBLACK, SK_ColorWHITE,
185 SK_ColorBLACK, SK_ColorWHITE, SK_ColorBLACK, SK_ColorWHITE,
186 SK_ColorBLACK,
187 };
halcanary96fcdcc2015-08-27 07:41:13 -0700188 rec->construct(colors, nullptr, SK_ARRAY_COUNT(colors));
reed@google.com7b8999b2014-04-18 17:55:37 +0000189}
190
191static void make2(ColorPos* rec) {
192 const SkColor colors[] = {
193 SK_ColorBLACK, SK_ColorWHITE, SK_ColorBLACK, SK_ColorWHITE,
194 SK_ColorBLACK, SK_ColorWHITE, SK_ColorBLACK, SK_ColorWHITE,
195 SK_ColorBLACK,
196 };
197 const int N = SK_ARRAY_COUNT(colors);
198 SkScalar pos[N];
199 for (int i = 0; i < N; ++i) {
200 pos[i] = SK_Scalar1 * i / (N - 1);
201 }
202 rec->construct(colors, pos, N);
203}
204
reed6b90df62015-11-13 06:23:54 -0800205static void make3(ColorPos* rec) {
206 const SkColor colors[] = {
207 SK_ColorRED, SK_ColorBLUE, SK_ColorBLUE, SK_ColorGREEN, SK_ColorGREEN, SK_ColorBLACK,
208 };
209 const SkScalar pos[] = {
210 0, 0, 0.5f, 0.5, 1, 1,
211 };
212 rec->construct(colors, pos, SK_ARRAY_COUNT(colors));
213}
214
reed@google.com7b8999b2014-04-18 17:55:37 +0000215class GradientsManyColorsGM : public GM {
216 enum {
217 W = 800,
218 };
Hal Canarycefc4312016-11-04 16:26:16 -0400219 sk_sp<SkShader> fShader;
reed@google.com7b8999b2014-04-18 17:55:37 +0000220
221 typedef void (*Proc)(ColorPos*);
222public:
fmalita063675b2015-10-12 10:41:48 -0700223 GradientsManyColorsGM(bool dither) : fDither(dither) {}
skia.committer@gmail.com8a777a52014-04-19 03:04:56 +0000224
reed@google.com7b8999b2014-04-18 17:55:37 +0000225protected:
commit-bot@chromium.orga90c6802014-04-30 13:20:45 +0000226
fmalita063675b2015-10-12 10:41:48 -0700227 SkString onShortName() override {
228 return SkString(fDither ? "gradients_many" : "gradients_many_nodither");
229 }
230
reed6b90df62015-11-13 06:23:54 -0800231 SkISize onISize() override { return SkISize::Make(880, 400); }
skia.committer@gmail.com8a777a52014-04-19 03:04:56 +0000232
mtklein36352bf2015-03-25 18:17:31 -0700233 void onDraw(SkCanvas* canvas) override {
reed@google.com7b8999b2014-04-18 17:55:37 +0000234 const Proc procs[] = {
reed6b90df62015-11-13 06:23:54 -0800235 make0, make1, make2, make3,
reed@google.com7b8999b2014-04-18 17:55:37 +0000236 };
237 const SkPoint pts[] = {
238 { 0, 0 },
239 { SkIntToScalar(W), 0 },
240 };
241 const SkRect r = SkRect::MakeWH(SkIntToScalar(W), 30);
242
243 SkPaint paint;
fmalita063675b2015-10-12 10:41:48 -0700244 paint.setDither(fDither);
skia.committer@gmail.com8a777a52014-04-19 03:04:56 +0000245
reed6b90df62015-11-13 06:23:54 -0800246 canvas->translate(40, 20);
skia.committer@gmail.com8a777a52014-04-19 03:04:56 +0000247
reed@google.com7b8999b2014-04-18 17:55:37 +0000248 for (int i = 0; i <= 8; ++i) {
249 SkScalar x = r.width() * i / 8;
250 canvas->drawLine(x, 0, x, 10000, paint);
251 }
252
reed6b90df62015-11-13 06:23:54 -0800253 // expand the drawing rect so we exercise clampping in the gradients
254 const SkRect drawR = r.makeOutset(20, 0);
reed@google.com7b8999b2014-04-18 17:55:37 +0000255 for (size_t i = 0; i < SK_ARRAY_COUNT(procs); ++i) {
256 ColorPos rec;
257 procs[i](&rec);
reed1a9b9642016-03-13 14:13:58 -0700258 paint.setShader(SkGradientShader::MakeLinear(pts, rec.fColors, rec.fPos, rec.fCount,
259 SkShader::kClamp_TileMode));
reed6b90df62015-11-13 06:23:54 -0800260 canvas->drawRect(drawR, paint);
261
262 canvas->save();
263 canvas->translate(r.centerX(), r.height() + 4);
264 canvas->scale(-1, 1);
265 canvas->translate(-r.centerX(), 0);
266 canvas->drawRect(drawR, paint);
267 canvas->restore();
268
269 canvas->translate(0, r.height() + 2*r.height() + 8);
reed@google.com7b8999b2014-04-18 17:55:37 +0000270 }
271 }
skia.committer@gmail.com8a777a52014-04-19 03:04:56 +0000272
reed@google.com7b8999b2014-04-18 17:55:37 +0000273private:
fmalita063675b2015-10-12 10:41:48 -0700274 bool fDither;
275
reed@google.com7b8999b2014-04-18 17:55:37 +0000276 typedef GM INHERITED;
277};
278
279///////////////////////////////////////////////////////////////////////////////
280
fmalita063675b2015-10-12 10:41:48 -0700281DEF_GM(return new GradientsNoTextureGM(true);)
282DEF_GM(return new GradientsNoTextureGM(false);)
283DEF_GM(return new GradientsManyColorsGM(true);)
284DEF_GM(return new GradientsManyColorsGM(false);)