blob: 5d0d4c920207ecfd13951f1eb5e2f9903d7db247 [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
mtkleindbfd7ab2016-09-01 11:24:54 -070018constexpr SkColor gColors[] = {
bsalomon@google.com82d12232013-09-09 15:36:26 +000019 SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE,
20};
21
mtkleindbfd7ab2016-09-01 11:24:54 -070022constexpr GradData gGradData[] = {
halcanary96fcdcc2015-08-27 07:41:13 -070023 { 1, gColors, nullptr },
24 { 2, gColors, nullptr },
25 { 3, gColors, nullptr },
26 { 4, gColors, nullptr },
bsalomon@google.com82d12232013-09-09 15:36:26 +000027};
28
reed1a9b9642016-03-13 14:13:58 -070029static sk_sp<SkShader> MakeLinear(const SkPoint pts[2], const GradData& data, SkShader::TileMode tm) {
30 return SkGradientShader::MakeLinear(pts, data.fColors, data.fPos, data.fCount, tm);
bsalomon@google.com82d12232013-09-09 15:36:26 +000031}
32
reed1a9b9642016-03-13 14:13:58 -070033static sk_sp<SkShader> MakeRadial(const SkPoint pts[2], const GradData& data, SkShader::TileMode tm) {
bsalomon@google.com82d12232013-09-09 15:36:26 +000034 SkPoint center;
35 center.set(SkScalarAve(pts[0].fX, pts[1].fX),
36 SkScalarAve(pts[0].fY, pts[1].fY));
reed1a9b9642016-03-13 14:13:58 -070037 return SkGradientShader::MakeRadial(center, center.fX, data.fColors, data.fPos, data.fCount, tm);
bsalomon@google.com82d12232013-09-09 15:36:26 +000038}
39
reed1a9b9642016-03-13 14:13:58 -070040static sk_sp<SkShader> MakeSweep(const SkPoint pts[2], const GradData& data, SkShader::TileMode) {
bsalomon@google.com82d12232013-09-09 15:36:26 +000041 SkPoint center;
42 center.set(SkScalarAve(pts[0].fX, pts[1].fX),
43 SkScalarAve(pts[0].fY, pts[1].fY));
reed1a9b9642016-03-13 14:13:58 -070044 return SkGradientShader::MakeSweep(center.fX, center.fY, data.fColors, data.fPos, data.fCount);
bsalomon@google.com82d12232013-09-09 15:36:26 +000045}
46
reed1a9b9642016-03-13 14:13:58 -070047static sk_sp<SkShader> Make2Radial(const SkPoint pts[2], const GradData& data, SkShader::TileMode tm) {
bsalomon@google.com82d12232013-09-09 15:36:26 +000048 SkPoint center0, center1;
49 center0.set(SkScalarAve(pts[0].fX, pts[1].fX),
50 SkScalarAve(pts[0].fY, pts[1].fY));
51 center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3)/5),
52 SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4));
reed1a9b9642016-03-13 14:13:58 -070053 return SkGradientShader::MakeTwoPointConical(
bsalomon@google.com82d12232013-09-09 15:36:26 +000054 center1, (pts[1].fX - pts[0].fX) / 7,
55 center0, (pts[1].fX - pts[0].fX) / 2,
commit-bot@chromium.org83f23d82014-05-22 12:27:41 +000056 data.fColors, data.fPos, data.fCount, tm);
bsalomon@google.com82d12232013-09-09 15:36:26 +000057}
58
reed1a9b9642016-03-13 14:13:58 -070059static sk_sp<SkShader> Make2Conical(const SkPoint pts[2], const GradData& data, SkShader::TileMode tm) {
bsalomon@google.com82d12232013-09-09 15:36:26 +000060 SkPoint center0, center1;
reed80ea19c2015-05-12 10:37:34 -070061 SkScalar radius0 = (pts[1].fX - pts[0].fX) / 10;
62 SkScalar radius1 = (pts[1].fX - pts[0].fX) / 3;
bsalomon@google.com82d12232013-09-09 15:36:26 +000063 center0.set(pts[0].fX + radius0, pts[0].fY + radius0);
64 center1.set(pts[1].fX - radius1, pts[1].fY - radius1);
reed1a9b9642016-03-13 14:13:58 -070065 return SkGradientShader::MakeTwoPointConical(center1, radius1,
bsalomon@google.com82d12232013-09-09 15:36:26 +000066 center0, radius0,
67 data.fColors, data.fPos,
commit-bot@chromium.org83f23d82014-05-22 12:27:41 +000068 data.fCount, tm);
bsalomon@google.com82d12232013-09-09 15:36:26 +000069}
70
71
reed1a9b9642016-03-13 14:13:58 -070072typedef sk_sp<SkShader> (*GradMaker)(const SkPoint pts[2], const GradData& data, SkShader::TileMode tm);
commit-bot@chromium.org83f23d82014-05-22 12:27:41 +000073
mtkleindbfd7ab2016-09-01 11:24:54 -070074constexpr GradMaker gGradMakers[] = {
bsalomon@google.com82d12232013-09-09 15:36:26 +000075 MakeLinear, MakeRadial, MakeSweep, Make2Radial, Make2Conical,
76};
77
78///////////////////////////////////////////////////////////////////////////////
79
80class GradientsNoTextureGM : public GM {
81public:
fmalita063675b2015-10-12 10:41:48 -070082 GradientsNoTextureGM(bool dither) : fDither(dither) {
caryclark65cdba62015-06-15 06:51:08 -070083 this->setBGColor(sk_tool_utils::color_to_565(0xFFDDDDDD));
bsalomon@google.com82d12232013-09-09 15:36:26 +000084 }
85
86protected:
commit-bot@chromium.orga90c6802014-04-30 13:20:45 +000087
fmalita063675b2015-10-12 10:41:48 -070088 SkString onShortName() override {
89 return SkString(fDither ? "gradients_no_texture" : "gradients_no_texture_nodither");
90 }
91
mtklein36352bf2015-03-25 18:17:31 -070092 SkISize onISize() override { return SkISize::Make(640, 615); }
bsalomon@google.com82d12232013-09-09 15:36:26 +000093
mtklein36352bf2015-03-25 18:17:31 -070094 void onDraw(SkCanvas* canvas) override {
mtkleindbfd7ab2016-09-01 11:24:54 -070095 constexpr SkPoint kPts[2] = { { 0, 0 },
bsalomon@google.com82d12232013-09-09 15:36:26 +000096 { SkIntToScalar(50), SkIntToScalar(50) } };
mtkleindbfd7ab2016-09-01 11:24:54 -070097 constexpr SkShader::TileMode kTM = SkShader::kClamp_TileMode;
bsalomon@google.com82d12232013-09-09 15:36:26 +000098 SkRect kRect = { 0, 0, SkIntToScalar(50), SkIntToScalar(50) };
99 SkPaint paint;
100 paint.setAntiAlias(true);
fmalita063675b2015-10-12 10:41:48 -0700101 paint.setDither(fDither);
bsalomon@google.com82d12232013-09-09 15:36:26 +0000102
103 canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
mtkleindbfd7ab2016-09-01 11:24:54 -0700104 constexpr uint8_t kAlphas[] = { 0xff, 0x40 };
bsalomon@google.com82d12232013-09-09 15:36:26 +0000105 for (size_t a = 0; a < SK_ARRAY_COUNT(kAlphas); ++a) {
106 for (size_t i = 0; i < SK_ARRAY_COUNT(gGradData); ++i) {
107 canvas->save();
108 for (size_t j = 0; j < SK_ARRAY_COUNT(gGradMakers); ++j) {
reed1a9b9642016-03-13 14:13:58 -0700109 paint.setShader(gGradMakers[j](kPts, gGradData[i], kTM));
bsalomon@google.com82d12232013-09-09 15:36:26 +0000110 paint.setAlpha(kAlphas[a]);
111 canvas->drawRect(kRect, paint);
112 canvas->translate(0, SkIntToScalar(kRect.height() + 20));
113 }
114 canvas->restore();
115 canvas->translate(SkIntToScalar(kRect.width() + 20), 0);
116 }
117 }
118 }
119
120private:
fmalita063675b2015-10-12 10:41:48 -0700121 bool fDither;
122
bsalomon@google.com82d12232013-09-09 15:36:26 +0000123 typedef GM INHERITED;
124};
125
126///////////////////////////////////////////////////////////////////////////////
127
reed@google.com7b8999b2014-04-18 17:55:37 +0000128struct ColorPos {
129 SkColor* fColors;
130 SkScalar* fPos;
131 int fCount;
132
halcanary96fcdcc2015-08-27 07:41:13 -0700133 ColorPos() : fColors(nullptr), fPos(nullptr), fCount(0) {}
reed@google.com7b8999b2014-04-18 17:55:37 +0000134 ~ColorPos() {
halcanary385fe4d2015-08-26 13:07:48 -0700135 delete[] fColors;
136 delete[] fPos;
reed@google.com7b8999b2014-04-18 17:55:37 +0000137 }
138
139 void construct(const SkColor colors[], const SkScalar pos[], int count) {
halcanary385fe4d2015-08-26 13:07:48 -0700140 fColors = new SkColor[count];
reed@google.com7b8999b2014-04-18 17:55:37 +0000141 memcpy(fColors, colors, count * sizeof(SkColor));
142 if (pos) {
halcanary385fe4d2015-08-26 13:07:48 -0700143 fPos = new SkScalar[count];
reed@google.com7b8999b2014-04-18 17:55:37 +0000144 memcpy(fPos, pos, count * sizeof(SkScalar));
145 fPos[0] = 0;
146 fPos[count - 1] = 1;
147 }
148 fCount = count;
149 }
150};
151
152static void make0(ColorPos* rec) {
153#if 0
154 From http://jsfiddle.net/3fe2a/
155
156background-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%);
157height: 30px;
158#endif
159
160 const SkColor colors[] = {
161 0xFF22d1cd, 0xFF22d1cd, 0xFFdf4b37, 0xFFdf4b37, 0xFF22d1cd, 0xFF22d1cd, 0xFFe6de36, 0xFFe6de36,
162 0xFF3267ff, 0xFF3267ff, 0xFF9d47d1, 0xFF9d47d1, 0xFF3267ff, 0xFF3267ff, 0xFF5cdd9d, 0xFF5cdd9d,
163 0xFF3267ff, 0xFF3267ff, 0xFF9d47d1, 0xFF9d47d1, 0xFF3267ff, 0xFF3267ff, 0xFFe3d082, 0xFFe3d082
164 };
165 const double percent[] = {
166 1, 0.9510157507590116, 2.9510157507590113, 23.695886056604927,
167 25.695886056604927, 25.39321881940624, 27.39321881940624, 31.849399922570655,
168 33.849399922570655, 44.57735802921938, 46.57735802921938, 53.27185850805876,
169 55.27185850805876, 61.95718972227316, 63.95718972227316, 69.89166004442,
170 71.89166004442, 74.45795382765857, 76.45795382765857, 82.78364610713776,
171 84.78364610713776, 94.52743647737229, 96.52743647737229, 96.03934633331295,
172 };
173 const int N = SK_ARRAY_COUNT(percent);
174 SkScalar pos[N];
175 for (int i = 0; i < N; ++i) {
176 pos[i] = SkDoubleToScalar(percent[i] / 100);
177 }
178 rec->construct(colors, pos, N);
179}
180
181static void make1(ColorPos* rec) {
182 const SkColor colors[] = {
183 SK_ColorBLACK, SK_ColorWHITE, SK_ColorBLACK, SK_ColorWHITE,
184 SK_ColorBLACK, SK_ColorWHITE, SK_ColorBLACK, SK_ColorWHITE,
185 SK_ColorBLACK,
186 };
halcanary96fcdcc2015-08-27 07:41:13 -0700187 rec->construct(colors, nullptr, SK_ARRAY_COUNT(colors));
reed@google.com7b8999b2014-04-18 17:55:37 +0000188}
189
190static void make2(ColorPos* rec) {
191 const SkColor colors[] = {
192 SK_ColorBLACK, SK_ColorWHITE, SK_ColorBLACK, SK_ColorWHITE,
193 SK_ColorBLACK, SK_ColorWHITE, SK_ColorBLACK, SK_ColorWHITE,
194 SK_ColorBLACK,
195 };
196 const int N = SK_ARRAY_COUNT(colors);
197 SkScalar pos[N];
198 for (int i = 0; i < N; ++i) {
199 pos[i] = SK_Scalar1 * i / (N - 1);
200 }
201 rec->construct(colors, pos, N);
202}
203
reed6b90df62015-11-13 06:23:54 -0800204static void make3(ColorPos* rec) {
205 const SkColor colors[] = {
206 SK_ColorRED, SK_ColorBLUE, SK_ColorBLUE, SK_ColorGREEN, SK_ColorGREEN, SK_ColorBLACK,
207 };
208 const SkScalar pos[] = {
209 0, 0, 0.5f, 0.5, 1, 1,
210 };
211 rec->construct(colors, pos, SK_ARRAY_COUNT(colors));
212}
213
reed@google.com7b8999b2014-04-18 17:55:37 +0000214class GradientsManyColorsGM : public GM {
215 enum {
216 W = 800,
217 };
218 SkAutoTUnref<SkShader> fShader;
219
220 typedef void (*Proc)(ColorPos*);
221public:
fmalita063675b2015-10-12 10:41:48 -0700222 GradientsManyColorsGM(bool dither) : fDither(dither) {}
skia.committer@gmail.com8a777a52014-04-19 03:04:56 +0000223
reed@google.com7b8999b2014-04-18 17:55:37 +0000224protected:
commit-bot@chromium.orga90c6802014-04-30 13:20:45 +0000225
fmalita063675b2015-10-12 10:41:48 -0700226 SkString onShortName() override {
227 return SkString(fDither ? "gradients_many" : "gradients_many_nodither");
228 }
229
reed6b90df62015-11-13 06:23:54 -0800230 SkISize onISize() override { return SkISize::Make(880, 400); }
skia.committer@gmail.com8a777a52014-04-19 03:04:56 +0000231
mtklein36352bf2015-03-25 18:17:31 -0700232 void onDraw(SkCanvas* canvas) override {
reed@google.com7b8999b2014-04-18 17:55:37 +0000233 const Proc procs[] = {
reed6b90df62015-11-13 06:23:54 -0800234 make0, make1, make2, make3,
reed@google.com7b8999b2014-04-18 17:55:37 +0000235 };
236 const SkPoint pts[] = {
237 { 0, 0 },
238 { SkIntToScalar(W), 0 },
239 };
240 const SkRect r = SkRect::MakeWH(SkIntToScalar(W), 30);
241
242 SkPaint paint;
fmalita063675b2015-10-12 10:41:48 -0700243 paint.setDither(fDither);
skia.committer@gmail.com8a777a52014-04-19 03:04:56 +0000244
reed6b90df62015-11-13 06:23:54 -0800245 canvas->translate(40, 20);
skia.committer@gmail.com8a777a52014-04-19 03:04:56 +0000246
reed@google.com7b8999b2014-04-18 17:55:37 +0000247 for (int i = 0; i <= 8; ++i) {
248 SkScalar x = r.width() * i / 8;
249 canvas->drawLine(x, 0, x, 10000, paint);
250 }
251
reed6b90df62015-11-13 06:23:54 -0800252 // expand the drawing rect so we exercise clampping in the gradients
253 const SkRect drawR = r.makeOutset(20, 0);
reed@google.com7b8999b2014-04-18 17:55:37 +0000254 for (size_t i = 0; i < SK_ARRAY_COUNT(procs); ++i) {
255 ColorPos rec;
256 procs[i](&rec);
reed1a9b9642016-03-13 14:13:58 -0700257 paint.setShader(SkGradientShader::MakeLinear(pts, rec.fColors, rec.fPos, rec.fCount,
258 SkShader::kClamp_TileMode));
reed6b90df62015-11-13 06:23:54 -0800259 canvas->drawRect(drawR, paint);
260
261 canvas->save();
262 canvas->translate(r.centerX(), r.height() + 4);
263 canvas->scale(-1, 1);
264 canvas->translate(-r.centerX(), 0);
265 canvas->drawRect(drawR, paint);
266 canvas->restore();
267
268 canvas->translate(0, r.height() + 2*r.height() + 8);
reed@google.com7b8999b2014-04-18 17:55:37 +0000269 }
270 }
skia.committer@gmail.com8a777a52014-04-19 03:04:56 +0000271
reed@google.com7b8999b2014-04-18 17:55:37 +0000272private:
fmalita063675b2015-10-12 10:41:48 -0700273 bool fDither;
274
reed@google.com7b8999b2014-04-18 17:55:37 +0000275 typedef GM INHERITED;
276};
277
278///////////////////////////////////////////////////////////////////////////////
279
fmalita063675b2015-10-12 10:41:48 -0700280DEF_GM(return new GradientsNoTextureGM(true);)
281DEF_GM(return new GradientsNoTextureGM(false);)
282DEF_GM(return new GradientsManyColorsGM(true);)
283DEF_GM(return new GradientsManyColorsGM(false);)