blob: e7a8a891395199dcfcbd99856df67cd3e531e20c [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001/*
2 * Copyright 2011 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 */
reed3d9005c2015-04-23 10:30:27 -07007
reed@android.com42309d42009-06-22 02:06:35 +00008#include "gm.h"
Mike Klein33d20552017-03-22 13:47:51 -04009#include "sk_tool_utils.h"
reed@android.com42309d42009-06-22 02:06:35 +000010#include "SkGradientShader.h"
fmalitabc590c02016-02-22 09:12:33 -080011#include "SkLinearGradient.h"
reed@android.com42309d42009-06-22 02:06:35 +000012
13namespace skiagm {
14
15struct GradData {
brianosmane25d71c2016-09-28 11:27:28 -070016 int fCount;
17 const SkColor* fColors;
18 const SkColor4f* fColors4f;
19 const SkScalar* fPos;
reed@android.com42309d42009-06-22 02:06:35 +000020};
21
mtkleindbfd7ab2016-09-01 11:24:54 -070022constexpr SkColor gColors[] = {
reed@android.com42309d42009-06-22 02:06:35 +000023 SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE, SK_ColorBLACK
24};
brianosmane25d71c2016-09-28 11:27:28 -070025constexpr SkColor4f gColors4f[] ={
26 { 1.0f, 0.0f, 0.0f, 1.0f }, // Red
27 { 0.0f, 1.0f, 0.0f, 1.0f }, // Green
28 { 0.0f, 0.0f, 1.0f, 1.0f }, // Blue
29 { 1.0f, 1.0f, 1.0f, 1.0f }, // White
30 { 0.0f, 0.0f, 0.0f, 1.0f } // Black
31};
mtkleindbfd7ab2016-09-01 11:24:54 -070032constexpr SkScalar gPos0[] = { 0, SK_Scalar1 };
33constexpr SkScalar gPos1[] = { SK_Scalar1/4, SK_Scalar1*3/4 };
34constexpr SkScalar gPos2[] = {
reed@android.com42309d42009-06-22 02:06:35 +000035 0, SK_Scalar1/8, SK_Scalar1/2, SK_Scalar1*7/8, SK_Scalar1
36};
37
mtkleindbfd7ab2016-09-01 11:24:54 -070038constexpr SkScalar gPosClamp[] = {0.0f, 0.0f, 1.0f, 1.0f};
39constexpr SkColor gColorClamp[] = {
commit-bot@chromium.org8ba1ad32013-08-07 15:22:13 +000040 SK_ColorRED, SK_ColorGREEN, SK_ColorGREEN, SK_ColorBLUE
41};
brianosmane25d71c2016-09-28 11:27:28 -070042constexpr SkColor4f gColor4fClamp[] ={
43 { 1.0f, 0.0f, 0.0f, 1.0f }, // Red
44 { 0.0f, 1.0f, 0.0f, 1.0f }, // Green
45 { 0.0f, 1.0f, 0.0f, 1.0f }, // Green
46 { 0.0f, 0.0f, 1.0f, 1.0f } // Blue
47};
mtkleindbfd7ab2016-09-01 11:24:54 -070048constexpr GradData gGradData[] = {
brianosmane25d71c2016-09-28 11:27:28 -070049 { 2, gColors, gColors4f, nullptr },
50 { 2, gColors, gColors4f, gPos0 },
51 { 2, gColors, gColors4f, gPos1 },
52 { 5, gColors, gColors4f, nullptr },
53 { 5, gColors, gColors4f, gPos2 },
54 { 4, gColorClamp, gColor4fClamp, gPosClamp }
reed@android.com42309d42009-06-22 02:06:35 +000055};
56
reed1a9b9642016-03-13 14:13:58 -070057static sk_sp<SkShader> MakeLinear(const SkPoint pts[2], const GradData& data,
58 SkShader::TileMode tm, const SkMatrix& localMatrix) {
59 return SkGradientShader::MakeLinear(pts, data.fColors, data.fPos, data.fCount, tm, 0,
60 &localMatrix);
reed@android.com42309d42009-06-22 02:06:35 +000061}
reed@google.comf3c1cc92010-12-23 16:45:33 +000062
brianosmane25d71c2016-09-28 11:27:28 -070063static sk_sp<SkShader> MakeLinear4f(const SkPoint pts[2], const GradData& data,
64 SkShader::TileMode tm, const SkMatrix& localMatrix) {
Matt Sarett77a7a1b2017-02-07 13:56:11 -050065 auto srgb = SkColorSpace::MakeSRGBLinear();
brianosmane25d71c2016-09-28 11:27:28 -070066 return SkGradientShader::MakeLinear(pts, data.fColors4f, srgb, data.fPos, data.fCount, tm, 0,
67 &localMatrix);
68}
69
reed1a9b9642016-03-13 14:13:58 -070070static sk_sp<SkShader> MakeRadial(const SkPoint pts[2], const GradData& data,
71 SkShader::TileMode tm, const SkMatrix& localMatrix) {
reed@android.com42309d42009-06-22 02:06:35 +000072 SkPoint center;
73 center.set(SkScalarAve(pts[0].fX, pts[1].fX),
74 SkScalarAve(pts[0].fY, pts[1].fY));
reed1a9b9642016-03-13 14:13:58 -070075 return SkGradientShader::MakeRadial(center, center.fX, data.fColors, data.fPos, data.fCount,
76 tm, 0, &localMatrix);
reed@android.com42309d42009-06-22 02:06:35 +000077}
78
brianosmane25d71c2016-09-28 11:27:28 -070079static sk_sp<SkShader> MakeRadial4f(const SkPoint pts[2], const GradData& data,
80 SkShader::TileMode tm, const SkMatrix& localMatrix) {
81 SkPoint center;
82 center.set(SkScalarAve(pts[0].fX, pts[1].fX),
83 SkScalarAve(pts[0].fY, pts[1].fY));
Matt Sarett77a7a1b2017-02-07 13:56:11 -050084 auto srgb = SkColorSpace::MakeSRGBLinear();
brianosmane25d71c2016-09-28 11:27:28 -070085 return SkGradientShader::MakeRadial(center, center.fX, data.fColors4f, srgb, data.fPos,
86 data.fCount, tm, 0, &localMatrix);
87}
88
reed1a9b9642016-03-13 14:13:58 -070089static sk_sp<SkShader> MakeSweep(const SkPoint pts[2], const GradData& data,
90 SkShader::TileMode, const SkMatrix& localMatrix) {
reed@android.com42309d42009-06-22 02:06:35 +000091 SkPoint center;
92 center.set(SkScalarAve(pts[0].fX, pts[1].fX),
93 SkScalarAve(pts[0].fY, pts[1].fY));
reed1a9b9642016-03-13 14:13:58 -070094 return SkGradientShader::MakeSweep(center.fX, center.fY, data.fColors, data.fPos, data.fCount,
95 0, &localMatrix);
reed@android.com42309d42009-06-22 02:06:35 +000096}
97
brianosmane25d71c2016-09-28 11:27:28 -070098static sk_sp<SkShader> MakeSweep4f(const SkPoint pts[2], const GradData& data,
99 SkShader::TileMode, const SkMatrix& localMatrix) {
100 SkPoint center;
101 center.set(SkScalarAve(pts[0].fX, pts[1].fX),
102 SkScalarAve(pts[0].fY, pts[1].fY));
Matt Sarett77a7a1b2017-02-07 13:56:11 -0500103 auto srgb = SkColorSpace::MakeSRGBLinear();
brianosmane25d71c2016-09-28 11:27:28 -0700104 return SkGradientShader::MakeSweep(center.fX, center.fY, data.fColors4f, srgb, data.fPos,
105 data.fCount, 0, &localMatrix);
106}
107
reed1a9b9642016-03-13 14:13:58 -0700108static sk_sp<SkShader> Make2Radial(const SkPoint pts[2], const GradData& data,
109 SkShader::TileMode tm, const SkMatrix& localMatrix) {
reed@google.comf3c1cc92010-12-23 16:45:33 +0000110 SkPoint center0, center1;
111 center0.set(SkScalarAve(pts[0].fX, pts[1].fX),
112 SkScalarAve(pts[0].fY, pts[1].fY));
113 center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3)/5),
114 SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4));
reed1a9b9642016-03-13 14:13:58 -0700115 return SkGradientShader::MakeTwoPointConical(center1, (pts[1].fX - pts[0].fX) / 7,
116 center0, (pts[1].fX - pts[0].fX) / 2,
117 data.fColors, data.fPos, data.fCount, tm,
118 0, &localMatrix);
reed@google.comf3c1cc92010-12-23 16:45:33 +0000119}
120
brianosmane25d71c2016-09-28 11:27:28 -0700121static sk_sp<SkShader> Make2Radial4f(const SkPoint pts[2], const GradData& data,
122 SkShader::TileMode tm, const SkMatrix& localMatrix) {
123 SkPoint center0, center1;
124 center0.set(SkScalarAve(pts[0].fX, pts[1].fX),
125 SkScalarAve(pts[0].fY, pts[1].fY));
126 center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3) / 5),
127 SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1) / 4));
Matt Sarett77a7a1b2017-02-07 13:56:11 -0500128 auto srgb = SkColorSpace::MakeSRGBLinear();
brianosmane25d71c2016-09-28 11:27:28 -0700129 return SkGradientShader::MakeTwoPointConical(center1, (pts[1].fX - pts[0].fX) / 7,
130 center0, (pts[1].fX - pts[0].fX) / 2,
131 data.fColors4f, srgb, data.fPos, data.fCount, tm,
132 0, &localMatrix);
133}
134
reed1a9b9642016-03-13 14:13:58 -0700135static sk_sp<SkShader> Make2Conical(const SkPoint pts[2], const GradData& data,
brianosmane25d71c2016-09-28 11:27:28 -0700136 SkShader::TileMode tm, const SkMatrix& localMatrix) {
rileya@google.com5cf2c282012-07-09 14:42:16 +0000137 SkPoint center0, center1;
reed80ea19c2015-05-12 10:37:34 -0700138 SkScalar radius0 = (pts[1].fX - pts[0].fX) / 10;
139 SkScalar radius1 = (pts[1].fX - pts[0].fX) / 3;
rileya@google.com5cf2c282012-07-09 14:42:16 +0000140 center0.set(pts[0].fX + radius0, pts[0].fY + radius0);
141 center1.set(pts[1].fX - radius1, pts[1].fY - radius1);
reed1a9b9642016-03-13 14:13:58 -0700142 return SkGradientShader::MakeTwoPointConical(center1, radius1, center0, radius0,
143 data.fColors, data.fPos,
144 data.fCount, tm, 0, &localMatrix);
rileya@google.com5cf2c282012-07-09 14:42:16 +0000145}
146
brianosmane25d71c2016-09-28 11:27:28 -0700147static sk_sp<SkShader> Make2Conical4f(const SkPoint pts[2], const GradData& data,
148 SkShader::TileMode tm, const SkMatrix& localMatrix) {
149 SkPoint center0, center1;
150 SkScalar radius0 = (pts[1].fX - pts[0].fX) / 10;
151 SkScalar radius1 = (pts[1].fX - pts[0].fX) / 3;
152 center0.set(pts[0].fX + radius0, pts[0].fY + radius0);
153 center1.set(pts[1].fX - radius1, pts[1].fY - radius1);
Matt Sarett77a7a1b2017-02-07 13:56:11 -0500154 auto srgb = SkColorSpace::MakeSRGBLinear();
brianosmane25d71c2016-09-28 11:27:28 -0700155 return SkGradientShader::MakeTwoPointConical(center1, radius1, center0, radius0,
156 data.fColors4f, srgb, data.fPos,
157 data.fCount, tm, 0, &localMatrix);
158}
159
reed1a9b9642016-03-13 14:13:58 -0700160typedef sk_sp<SkShader> (*GradMaker)(const SkPoint pts[2], const GradData& data,
161 SkShader::TileMode tm, const SkMatrix& localMatrix);
mtkleindbfd7ab2016-09-01 11:24:54 -0700162constexpr GradMaker gGradMakers[] = {
rileya@google.com5cf2c282012-07-09 14:42:16 +0000163 MakeLinear, MakeRadial, MakeSweep, Make2Radial, Make2Conical
reed@android.com42309d42009-06-22 02:06:35 +0000164};
brianosmane25d71c2016-09-28 11:27:28 -0700165constexpr GradMaker gGradMakers4f[] ={
166 MakeLinear4f, MakeRadial4f, MakeSweep4f, Make2Radial4f, Make2Conical4f
167};
reed@android.com42309d42009-06-22 02:06:35 +0000168
169///////////////////////////////////////////////////////////////////////////////
170
171class GradientsGM : public GM {
172public:
fmalita063675b2015-10-12 10:41:48 -0700173 GradientsGM(bool dither) : fDither(dither) {
Matt Saretteebe87f2017-01-26 15:14:56 -0500174 this->setBGColor(sk_tool_utils::color_to_565(0xFFDDDDDD));
bsalomon@google.com48dd1a22011-10-31 14:18:20 +0000175 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000176
reed@android.com42309d42009-06-22 02:06:35 +0000177protected:
commit-bot@chromium.orga90c6802014-04-30 13:20:45 +0000178
reed@android.com42309d42009-06-22 02:06:35 +0000179 SkString onShortName() {
fmalita063675b2015-10-12 10:41:48 -0700180 return SkString(fDither ? "gradients" : "gradients_nodither");
reed@android.com42309d42009-06-22 02:06:35 +0000181 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000182
edisonn@google.com1da3a802013-09-19 17:55:49 +0000183 virtual SkISize onISize() { return SkISize::Make(840, 815); }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000184
reed@android.com42309d42009-06-22 02:06:35 +0000185 virtual void onDraw(SkCanvas* canvas) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000186
reed@android.com42309d42009-06-22 02:06:35 +0000187 SkPoint pts[2] = {
188 { 0, 0 },
Matt Saretteebe87f2017-01-26 15:14:56 -0500189 { SkIntToScalar(100), SkIntToScalar(100) }
reed@android.com42309d42009-06-22 02:06:35 +0000190 };
191 SkShader::TileMode tm = SkShader::kClamp_TileMode;
Matt Saretteebe87f2017-01-26 15:14:56 -0500192 SkRect r = { 0, 0, SkIntToScalar(100), SkIntToScalar(100) };
reed@android.com42309d42009-06-22 02:06:35 +0000193 SkPaint paint;
194 paint.setAntiAlias(true);
fmalita063675b2015-10-12 10:41:48 -0700195 paint.setDither(fDither);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000196
reed@android.com42309d42009-06-22 02:06:35 +0000197 canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
198 for (size_t i = 0; i < SK_ARRAY_COUNT(gGradData); i++) {
199 canvas->save();
200 for (size_t j = 0; j < SK_ARRAY_COUNT(gGradMakers); j++) {
commit-bot@chromium.org9c9005a2014-04-28 14:55:39 +0000201 SkMatrix scale = SkMatrix::I();
commit-bot@chromium.org8ba1ad32013-08-07 15:22:13 +0000202
203 if (i == 5) { // if the clamp case
commit-bot@chromium.org8ba1ad32013-08-07 15:22:13 +0000204 scale.setScale(0.5f, 0.5f);
205 scale.postTranslate(25.f, 25.f);
commit-bot@chromium.org8ba1ad32013-08-07 15:22:13 +0000206 }
skia.committer@gmail.comd55e3572013-08-08 07:01:20 +0000207
reed1a9b9642016-03-13 14:13:58 -0700208 paint.setShader(gGradMakers[j](pts, gGradData[i], tm, scale));
reed@android.com42309d42009-06-22 02:06:35 +0000209 canvas->drawRect(r, paint);
reed@android.com42309d42009-06-22 02:06:35 +0000210 canvas->translate(0, SkIntToScalar(120));
211 }
212 canvas->restore();
213 canvas->translate(SkIntToScalar(120), 0);
214 }
215 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000216
fmalita063675b2015-10-12 10:41:48 -0700217protected:
218 bool fDither;
219
reed@android.com42309d42009-06-22 02:06:35 +0000220private:
221 typedef GM INHERITED;
222};
fmalita063675b2015-10-12 10:41:48 -0700223DEF_GM( return new GradientsGM(true); )
224DEF_GM( return new GradientsGM(false); )
reed@android.com42309d42009-06-22 02:06:35 +0000225
brianosmane25d71c2016-09-28 11:27:28 -0700226// Like the original gradients GM, but using the SkColor4f shader factories. Should be identical.
227class Gradients4fGM : public GM {
228public:
229 Gradients4fGM(bool dither) : fDither(dither) {
230 this->setBGColor(sk_tool_utils::color_to_565(0xFFDDDDDD));
231 }
232
233protected:
234
235 SkString onShortName() {
236 return SkString(fDither ? "gradients4f" : "gradients4f_nodither");
237 }
238
239 virtual SkISize onISize() { return SkISize::Make(840, 815); }
240
241 virtual void onDraw(SkCanvas* canvas) {
242
243 SkPoint pts[2] ={
244 { 0, 0 },
245 { SkIntToScalar(100), SkIntToScalar(100) }
246 };
247 SkShader::TileMode tm = SkShader::kClamp_TileMode;
248 SkRect r ={ 0, 0, SkIntToScalar(100), SkIntToScalar(100) };
249 SkPaint paint;
250 paint.setAntiAlias(true);
251 paint.setDither(fDither);
252
253 canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
254 for (size_t i = 0; i < SK_ARRAY_COUNT(gGradData); i++) {
255 canvas->save();
256 for (size_t j = 0; j < SK_ARRAY_COUNT(gGradMakers4f); j++) {
257 SkMatrix scale = SkMatrix::I();
258
259 if (i == 5) { // if the clamp case
260 scale.setScale(0.5f, 0.5f);
261 scale.postTranslate(25.f, 25.f);
262 }
263
264 paint.setShader(gGradMakers4f[j](pts, gGradData[i], tm, scale));
265 canvas->drawRect(r, paint);
266 canvas->translate(0, SkIntToScalar(120));
267 }
268 canvas->restore();
269 canvas->translate(SkIntToScalar(120), 0);
270 }
271 }
272
273protected:
274 bool fDither;
275
276private:
277 typedef GM INHERITED;
278};
279DEF_GM(return new Gradients4fGM(true); )
280DEF_GM(return new Gradients4fGM(false); )
281
rileya@google.com5cf2c282012-07-09 14:42:16 +0000282// Based on the original gradient slide, but with perspective applied to the
283// gradient shaders' local matrices
284class GradientsLocalPerspectiveGM : public GM {
285public:
fmalita063675b2015-10-12 10:41:48 -0700286 GradientsLocalPerspectiveGM(bool dither) : fDither(dither) {
caryclark65cdba62015-06-15 06:51:08 -0700287 this->setBGColor(sk_tool_utils::color_to_565(0xFFDDDDDD));
rileya@google.com5cf2c282012-07-09 14:42:16 +0000288 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000289
rileya@google.com5cf2c282012-07-09 14:42:16 +0000290protected:
commit-bot@chromium.orga90c6802014-04-30 13:20:45 +0000291
rileya@google.com5cf2c282012-07-09 14:42:16 +0000292 SkString onShortName() {
fmalita063675b2015-10-12 10:41:48 -0700293 return SkString(fDither ? "gradients_local_perspective" :
294 "gradients_local_perspective_nodither");
rileya@google.com5cf2c282012-07-09 14:42:16 +0000295 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000296
edisonn@google.com1da3a802013-09-19 17:55:49 +0000297 virtual SkISize onISize() { return SkISize::Make(840, 815); }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000298
rileya@google.com5cf2c282012-07-09 14:42:16 +0000299 virtual void onDraw(SkCanvas* canvas) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000300
rileya@google.com5cf2c282012-07-09 14:42:16 +0000301 SkPoint pts[2] = {
302 { 0, 0 },
303 { SkIntToScalar(100), SkIntToScalar(100) }
304 };
305 SkShader::TileMode tm = SkShader::kClamp_TileMode;
306 SkRect r = { 0, 0, SkIntToScalar(100), SkIntToScalar(100) };
307 SkPaint paint;
308 paint.setAntiAlias(true);
fmalita063675b2015-10-12 10:41:48 -0700309 paint.setDither(fDither);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000310
rileya@google.com5cf2c282012-07-09 14:42:16 +0000311 canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
312 for (size_t i = 0; i < SK_ARRAY_COUNT(gGradData); i++) {
313 canvas->save();
314 for (size_t j = 0; j < SK_ARRAY_COUNT(gGradMakers); j++) {
rileya@google.com5cf2c282012-07-09 14:42:16 +0000315 // apply an increasing y perspective as we move to the right
316 SkMatrix perspective;
317 perspective.setIdentity();
reed80ea19c2015-05-12 10:37:34 -0700318 perspective.setPerspY(SkIntToScalar(i+1) / 500);
319 perspective.setSkewX(SkIntToScalar(i+1) / 10);
commit-bot@chromium.org8ba1ad32013-08-07 15:22:13 +0000320
reed1a9b9642016-03-13 14:13:58 -0700321 paint.setShader(gGradMakers[j](pts, gGradData[i], tm, perspective));
rileya@google.com5cf2c282012-07-09 14:42:16 +0000322 canvas->drawRect(r, paint);
rileya@google.com5cf2c282012-07-09 14:42:16 +0000323 canvas->translate(0, SkIntToScalar(120));
324 }
325 canvas->restore();
326 canvas->translate(SkIntToScalar(120), 0);
327 }
328 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000329
rileya@google.com5cf2c282012-07-09 14:42:16 +0000330private:
fmalita063675b2015-10-12 10:41:48 -0700331 bool fDither;
332
rileya@google.com5cf2c282012-07-09 14:42:16 +0000333 typedef GM INHERITED;
334};
fmalita063675b2015-10-12 10:41:48 -0700335DEF_GM( return new GradientsLocalPerspectiveGM(true); )
336DEF_GM( return new GradientsLocalPerspectiveGM(false); )
rileya@google.com5cf2c282012-07-09 14:42:16 +0000337
338// Based on the original gradient slide, but with perspective applied to
339// the view matrix
340class GradientsViewPerspectiveGM : public GradientsGM {
fmalita063675b2015-10-12 10:41:48 -0700341public:
342 GradientsViewPerspectiveGM(bool dither) : INHERITED(dither) { }
343
rileya@google.com5cf2c282012-07-09 14:42:16 +0000344protected:
345 SkString onShortName() {
fmalita063675b2015-10-12 10:41:48 -0700346 return SkString(fDither ? "gradients_view_perspective" :
347 "gradients_view_perspective_nodither");
rileya@google.com5cf2c282012-07-09 14:42:16 +0000348 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000349
edisonn@google.com1da3a802013-09-19 17:55:49 +0000350 virtual SkISize onISize() { return SkISize::Make(840, 500); }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000351
rileya@google.com5cf2c282012-07-09 14:42:16 +0000352 virtual void onDraw(SkCanvas* canvas) {
353 SkMatrix perspective;
354 perspective.setIdentity();
reed80ea19c2015-05-12 10:37:34 -0700355 perspective.setPerspY(0.001f);
356 perspective.setSkewX(SkIntToScalar(8) / 25);
scroggo@google.com837d31a2012-08-15 18:42:45 +0000357 canvas->concat(perspective);
rileya@google.com5cf2c282012-07-09 14:42:16 +0000358 INHERITED::onDraw(canvas);
359 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000360
rileya@google.com5cf2c282012-07-09 14:42:16 +0000361private:
362 typedef GradientsGM INHERITED;
363};
fmalita063675b2015-10-12 10:41:48 -0700364DEF_GM( return new GradientsViewPerspectiveGM(true); )
365DEF_GM( return new GradientsViewPerspectiveGM(false); )
rileya@google.com5cf2c282012-07-09 14:42:16 +0000366
reed@google.comac864a92011-06-27 18:11:17 +0000367/*
368 Inspired by this <canvas> javascript, where we need to detect that we are not
369 solving a quadratic equation, but must instead solve a linear (since our X^2
370 coefficient is 0)
371
372 ctx.fillStyle = '#f00';
373 ctx.fillRect(0, 0, 100, 50);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000374
reed@google.comac864a92011-06-27 18:11:17 +0000375 var g = ctx.createRadialGradient(-80, 25, 70, 0, 25, 150);
376 g.addColorStop(0, '#f00');
377 g.addColorStop(0.01, '#0f0');
378 g.addColorStop(0.99, '#0f0');
379 g.addColorStop(1, '#f00');
380 ctx.fillStyle = g;
381 ctx.fillRect(0, 0, 100, 50);
382 */
383class GradientsDegenrate2PointGM : public GM {
384public:
fmalita063675b2015-10-12 10:41:48 -0700385 GradientsDegenrate2PointGM(bool dither) : fDither(dither) {}
rmistry@google.comd6176b02012-08-23 18:14:13 +0000386
reed@google.comac864a92011-06-27 18:11:17 +0000387protected:
388 SkString onShortName() {
fmalita063675b2015-10-12 10:41:48 -0700389 return SkString(fDither ? "gradients_degenerate_2pt" : "gradients_degenerate_2pt_nodither");
reed@google.comac864a92011-06-27 18:11:17 +0000390 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000391
edisonn@google.com1da3a802013-09-19 17:55:49 +0000392 virtual SkISize onISize() { return SkISize::Make(320, 320); }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000393
reed@google.comac864a92011-06-27 18:11:17 +0000394 void drawBG(SkCanvas* canvas) {
395 canvas->drawColor(SK_ColorBLUE);
396 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000397
reed@google.comac864a92011-06-27 18:11:17 +0000398 virtual void onDraw(SkCanvas* canvas) {
399 this->drawBG(canvas);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000400
reed@google.comac864a92011-06-27 18:11:17 +0000401 SkColor colors[] = { SK_ColorRED, SK_ColorGREEN, SK_ColorGREEN, SK_ColorRED };
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000402 SkScalar pos[] = { 0, 0.01f, 0.99f, SK_Scalar1 };
epoger@google.com59f3abf2011-07-21 15:50:33 +0000403 SkPoint c0;
404 c0.iset(-80, 25);
405 SkScalar r0 = SkIntToScalar(70);
406 SkPoint c1;
407 c1.iset(0, 25);
408 SkScalar r1 = SkIntToScalar(150);
reed9283d202016-03-13 13:01:57 -0700409 SkPaint paint;
reed1a9b9642016-03-13 14:13:58 -0700410 paint.setShader(SkGradientShader::MakeTwoPointConical(c0, r0, c1, r1, colors,
411 pos, SK_ARRAY_COUNT(pos),
412 SkShader::kClamp_TileMode));
fmalita063675b2015-10-12 10:41:48 -0700413 paint.setDither(fDither);
reed@google.comac864a92011-06-27 18:11:17 +0000414 canvas->drawPaint(paint);
415 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000416
reed@google.comac864a92011-06-27 18:11:17 +0000417private:
fmalita063675b2015-10-12 10:41:48 -0700418 bool fDither;
419
reed@google.comac864a92011-06-27 18:11:17 +0000420 typedef GM INHERITED;
421};
fmalita063675b2015-10-12 10:41:48 -0700422DEF_GM( return new GradientsDegenrate2PointGM(true); )
423DEF_GM( return new GradientsDegenrate2PointGM(false); )
reed@google.comac864a92011-06-27 18:11:17 +0000424
caryclarkcb100712016-02-26 05:59:40 -0800425/* bug.skia.org/517
426<canvas id="canvas"></canvas>
427<script>
428var c = document.getElementById("canvas");
429var ctx = c.getContext("2d");
430ctx.fillStyle = '#ff0';
431ctx.fillRect(0, 0, 100, 50);
432
433var g = ctx.createRadialGradient(200, 25, 20, 200, 25, 10);
434g.addColorStop(0, '#0f0');
435g.addColorStop(0.003, '#f00'); // 0.004 makes this work
436g.addColorStop(1, '#ff0');
437ctx.fillStyle = g;
438ctx.fillRect(0, 0, 100, 50);
439</script>
440*/
441
442// should draw only green
443DEF_SIMPLE_GM(small_color_stop, canvas, 100, 150) {
444 SkColor colors[] = { SK_ColorGREEN, SK_ColorRED, SK_ColorYELLOW };
445 SkScalar pos[] = { 0, 0.003f, SK_Scalar1 }; // 0.004f makes this work
446 SkPoint c0 = { 200, 25 };
447 SkScalar r0 = 20;
448 SkPoint c1 = { 200, 25 };
449 SkScalar r1 = 10;
reed1a9b9642016-03-13 14:13:58 -0700450
caryclarkcb100712016-02-26 05:59:40 -0800451 SkPaint paint;
452 paint.setColor(SK_ColorYELLOW);
453 canvas->drawRect(SkRect::MakeWH(100, 150), paint);
reed1a9b9642016-03-13 14:13:58 -0700454 paint.setShader(SkGradientShader::MakeTwoPointConical(c0, r0, c1, r1, colors, pos,
455 SK_ARRAY_COUNT(pos),
456 SkShader::kClamp_TileMode));
caryclarkcb100712016-02-26 05:59:40 -0800457 canvas->drawRect(SkRect::MakeWH(100, 150), paint);
458}
459
460
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000461/// Tests correctness of *optimized* codepaths in gradients.
462
463class ClampedGradientsGM : public GM {
464public:
fmalita063675b2015-10-12 10:41:48 -0700465 ClampedGradientsGM(bool dither) : fDither(dither) {}
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000466
467protected:
fmalita063675b2015-10-12 10:41:48 -0700468 SkString onShortName() {
469 return SkString(fDither ? "clamped_gradients" : "clamped_gradients_nodither");
470 }
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000471
edisonn@google.com1da3a802013-09-19 17:55:49 +0000472 virtual SkISize onISize() { return SkISize::Make(640, 510); }
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000473
474 void drawBG(SkCanvas* canvas) {
caryclark12596012015-07-29 05:27:47 -0700475 canvas->drawColor(sk_tool_utils::color_to_565(0xFFDDDDDD));
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000476 }
477
478 virtual void onDraw(SkCanvas* canvas) {
479 this->drawBG(canvas);
480
481 SkRect r = { 0, 0, SkIntToScalar(100), SkIntToScalar(300) };
482 SkPaint paint;
fmalita063675b2015-10-12 10:41:48 -0700483 paint.setDither(fDither);
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000484 paint.setAntiAlias(true);
485
486 SkPoint center;
487 center.iset(0, 300);
488 canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
reed1a9b9642016-03-13 14:13:58 -0700489 paint.setShader(SkGradientShader::MakeRadial(
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000490 SkPoint(center),
halcanary96fcdcc2015-08-27 07:41:13 -0700491 SkIntToScalar(200), gColors, nullptr, 5,
reed1a9b9642016-03-13 14:13:58 -0700492 SkShader::kClamp_TileMode));
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000493 canvas->drawRect(r, paint);
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000494 }
495
496private:
fmalita063675b2015-10-12 10:41:48 -0700497 bool fDither;
498
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000499 typedef GM INHERITED;
500};
fmalita063675b2015-10-12 10:41:48 -0700501DEF_GM( return new ClampedGradientsGM(true); )
502DEF_GM( return new ClampedGradientsGM(false); )
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000503
tomhudson@google.comb18e58c2012-01-30 20:00:13 +0000504/// Checks quality of large radial gradients, which may display
505/// some banding.
506
507class RadialGradientGM : public GM {
508public:
509 RadialGradientGM() {}
510
511protected:
commit-bot@chromium.orga90c6802014-04-30 13:20:45 +0000512
mtklein36352bf2015-03-25 18:17:31 -0700513 SkString onShortName() override { return SkString("radial_gradient"); }
514 SkISize onISize() override { return SkISize::Make(1280, 1280); }
tomhudson@google.comb18e58c2012-01-30 20:00:13 +0000515 void drawBG(SkCanvas* canvas) {
516 canvas->drawColor(0xFF000000);
517 }
mtklein36352bf2015-03-25 18:17:31 -0700518 void onDraw(SkCanvas* canvas) override {
reed@google.combb0948f2012-01-31 14:44:13 +0000519 const SkISize dim = this->getISize();
520
tomhudson@google.comb18e58c2012-01-30 20:00:13 +0000521 this->drawBG(canvas);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000522
tomhudson@google.comb18e58c2012-01-30 20:00:13 +0000523 SkPaint paint;
524 paint.setDither(true);
525 SkPoint center;
reed@google.combb0948f2012-01-31 14:44:13 +0000526 center.set(SkIntToScalar(dim.width())/2, SkIntToScalar(dim.height())/2);
527 SkScalar radius = SkIntToScalar(dim.width())/2;
528 const SkColor colors[] = { 0x7f7f7f7f, 0x7f7f7f7f, 0xb2000000 };
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000529 const SkScalar pos[] = { 0.0f,
530 0.35f,
531 1.0f };
reed1a9b9642016-03-13 14:13:58 -0700532 paint.setShader(SkGradientShader::MakeRadial(center, radius, colors, pos,
533 SK_ARRAY_COUNT(pos),
534 SkShader::kClamp_TileMode));
reed@google.combb0948f2012-01-31 14:44:13 +0000535 SkRect r = {
536 0, 0, SkIntToScalar(dim.width()), SkIntToScalar(dim.height())
537 };
tomhudson@google.comb18e58c2012-01-30 20:00:13 +0000538 canvas->drawRect(r, paint);
539 }
540private:
541 typedef GM INHERITED;
542};
reed3d9005c2015-04-23 10:30:27 -0700543DEF_GM( return new RadialGradientGM; )
tomhudson@google.comb18e58c2012-01-30 20:00:13 +0000544
mtklein@google.com361a72f2013-08-19 18:43:34 +0000545class RadialGradient2GM : public GM {
546public:
fmalita063675b2015-10-12 10:41:48 -0700547 RadialGradient2GM(bool dither) : fDither(dither) {}
mtklein@google.com361a72f2013-08-19 18:43:34 +0000548
549protected:
commit-bot@chromium.orga90c6802014-04-30 13:20:45 +0000550
fmalita063675b2015-10-12 10:41:48 -0700551 SkString onShortName() override {
552 return SkString(fDither ? "radial_gradient2" : "radial_gradient2_nodither");
553 }
554
mtklein36352bf2015-03-25 18:17:31 -0700555 SkISize onISize() override { return SkISize::Make(800, 400); }
mtklein@google.com361a72f2013-08-19 18:43:34 +0000556 void drawBG(SkCanvas* canvas) {
557 canvas->drawColor(0xFF000000);
558 }
559
560 // Reproduces the example given in bug 7671058.
mtklein36352bf2015-03-25 18:17:31 -0700561 void onDraw(SkCanvas* canvas) override {
mtklein@google.com361a72f2013-08-19 18:43:34 +0000562 SkPaint paint1, paint2, paint3;
563 paint1.setStyle(SkPaint::kFill_Style);
564 paint2.setStyle(SkPaint::kFill_Style);
565 paint3.setStyle(SkPaint::kFill_Style);
566
567 const SkColor sweep_colors[] =
568 { 0xFFFF0000, 0xFFFFFF00, 0xFF00FF00, 0xFF00FFFF, 0xFF0000FF, 0xFFFF00FF, 0xFFFF0000 };
569 const SkColor colors1[] = { 0xFFFFFFFF, 0x00000000 };
570 const SkColor colors2[] = { 0xFF000000, 0x00000000 };
571
572 const SkScalar cx = 200, cy = 200, radius = 150;
573 SkPoint center;
574 center.set(cx, cy);
575
mtklein@google.com3ef7eea2013-09-16 13:02:52 +0000576 // We can either interpolate endpoints and premultiply each point (default, more precision),
577 // or premultiply the endpoints first, avoiding the need to premultiply each point (cheap).
578 const uint32_t flags[] = { 0, SkGradientShader::kInterpolateColorsInPremul_Flag };
mtklein@google.com361a72f2013-08-19 18:43:34 +0000579
mtklein@google.com3ef7eea2013-09-16 13:02:52 +0000580 for (size_t i = 0; i < SK_ARRAY_COUNT(flags); i++) {
reed1a9b9642016-03-13 14:13:58 -0700581 paint1.setShader(SkGradientShader::MakeSweep(cx, cy, sweep_colors,
582 nullptr, SK_ARRAY_COUNT(sweep_colors),
583 flags[i], nullptr));
584 paint2.setShader(SkGradientShader::MakeRadial(center, radius, colors1,
585 nullptr, SK_ARRAY_COUNT(colors1),
586 SkShader::kClamp_TileMode,
587 flags[i], nullptr));
588 paint3.setShader(SkGradientShader::MakeRadial(center, radius, colors2,
589 nullptr, SK_ARRAY_COUNT(colors2),
590 SkShader::kClamp_TileMode,
591 flags[i], nullptr));
fmalita063675b2015-10-12 10:41:48 -0700592 paint1.setDither(fDither);
fmalita063675b2015-10-12 10:41:48 -0700593 paint2.setDither(fDither);
fmalita063675b2015-10-12 10:41:48 -0700594 paint3.setDither(fDither);
mtklein@google.com3ef7eea2013-09-16 13:02:52 +0000595
596 canvas->drawCircle(cx, cy, radius, paint1);
597 canvas->drawCircle(cx, cy, radius, paint3);
598 canvas->drawCircle(cx, cy, radius, paint2);
599
600 canvas->translate(400, 0);
601 }
mtklein@google.com361a72f2013-08-19 18:43:34 +0000602 }
603
604private:
fmalita063675b2015-10-12 10:41:48 -0700605 bool fDither;
606
mtklein@google.com361a72f2013-08-19 18:43:34 +0000607 typedef GM INHERITED;
608};
fmalita063675b2015-10-12 10:41:48 -0700609DEF_GM( return new RadialGradient2GM(true); )
610DEF_GM( return new RadialGradient2GM(false); )
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000611
reed3d9005c2015-04-23 10:30:27 -0700612// Shallow radial (shows banding on raster)
613class RadialGradient3GM : public GM {
fmalita063675b2015-10-12 10:41:48 -0700614public:
615 RadialGradient3GM(bool dither) : fDither(dither) { }
reed@android.com42309d42009-06-22 02:06:35 +0000616
reed3d9005c2015-04-23 10:30:27 -0700617protected:
fmalita063675b2015-10-12 10:41:48 -0700618 SkString onShortName() override {
619 return SkString(fDither ? "radial_gradient3" : "radial_gradient3_nodither");
620 }
reed@android.com42309d42009-06-22 02:06:35 +0000621
reed3d9005c2015-04-23 10:30:27 -0700622 SkISize onISize() override { return SkISize::Make(500, 500); }
reed@google.comac864a92011-06-27 18:11:17 +0000623
reed3d9005c2015-04-23 10:30:27 -0700624 bool runAsBench() const override { return true; }
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000625
reed3d9005c2015-04-23 10:30:27 -0700626 void onOnceBeforeDraw() override {
627 const SkPoint center = { 0, 0 };
628 const SkScalar kRadius = 3000;
629 const SkColor gColors[] = { 0xFFFFFFFF, 0xFF000000 };
reed1a9b9642016-03-13 14:13:58 -0700630 fShader = SkGradientShader::MakeRadial(center, kRadius, gColors, nullptr, 2,
631 SkShader::kClamp_TileMode);
reed3d9005c2015-04-23 10:30:27 -0700632 }
rileya@google.com5cf2c282012-07-09 14:42:16 +0000633
reed3d9005c2015-04-23 10:30:27 -0700634 void onDraw(SkCanvas* canvas) override {
635 SkPaint paint;
636 paint.setShader(fShader);
fmalita063675b2015-10-12 10:41:48 -0700637 paint.setDither(fDither);
reed3d9005c2015-04-23 10:30:27 -0700638 canvas->drawRect(SkRect::MakeWH(500, 500), paint);
639 }
halcanary9d524f22016-03-29 09:03:52 -0700640
reed3d9005c2015-04-23 10:30:27 -0700641private:
reed1a9b9642016-03-13 14:13:58 -0700642 sk_sp<SkShader> fShader;
fmalita063675b2015-10-12 10:41:48 -0700643 bool fDither;
644
reed3d9005c2015-04-23 10:30:27 -0700645 typedef GM INHERITED;
646};
fmalita063675b2015-10-12 10:41:48 -0700647DEF_GM( return new RadialGradient3GM(true); )
648DEF_GM( return new RadialGradient3GM(false); )
rileya@google.com5cf2c282012-07-09 14:42:16 +0000649
caryclark1864bfa2015-07-30 06:41:39 -0700650class RadialGradient4GM : public GM {
fmalita063675b2015-10-12 10:41:48 -0700651public:
652 RadialGradient4GM(bool dither) : fDither(dither) { }
caryclark1864bfa2015-07-30 06:41:39 -0700653
654protected:
fmalita063675b2015-10-12 10:41:48 -0700655 SkString onShortName() override {
656 return SkString(fDither ? "radial_gradient4" : "radial_gradient4_nodither");
657 }
caryclark1864bfa2015-07-30 06:41:39 -0700658
659 SkISize onISize() override { return SkISize::Make(500, 500); }
660
661 void onOnceBeforeDraw() override {
662 const SkPoint center = { 250, 250 };
663 const SkScalar kRadius = 250;
664 const SkColor colors[] = { SK_ColorRED, SK_ColorRED, SK_ColorWHITE, SK_ColorWHITE,
665 SK_ColorRED };
666 const SkScalar pos[] = { 0, .4f, .4f, .8f, .8f, 1 };
reed1a9b9642016-03-13 14:13:58 -0700667 fShader = SkGradientShader::MakeRadial(center, kRadius, colors, pos,
668 SK_ARRAY_COUNT(gColors), SkShader::kClamp_TileMode);
caryclark1864bfa2015-07-30 06:41:39 -0700669 }
670
671 void onDraw(SkCanvas* canvas) override {
672 SkPaint paint;
673 paint.setAntiAlias(true);
fmalita063675b2015-10-12 10:41:48 -0700674 paint.setDither(fDither);
caryclark1864bfa2015-07-30 06:41:39 -0700675 paint.setShader(fShader);
676 canvas->drawRect(SkRect::MakeWH(500, 500), paint);
677 }
halcanary9d524f22016-03-29 09:03:52 -0700678
caryclark1864bfa2015-07-30 06:41:39 -0700679private:
reed1a9b9642016-03-13 14:13:58 -0700680 sk_sp<SkShader> fShader;
fmalita063675b2015-10-12 10:41:48 -0700681 bool fDither;
682
caryclark1864bfa2015-07-30 06:41:39 -0700683 typedef GM INHERITED;
684};
fmalita063675b2015-10-12 10:41:48 -0700685DEF_GM( return new RadialGradient4GM(true); )
686DEF_GM( return new RadialGradient4GM(false); )
caryclark1864bfa2015-07-30 06:41:39 -0700687
caryclark159fa572015-07-30 12:35:48 -0700688class LinearGradientGM : public GM {
fmalita063675b2015-10-12 10:41:48 -0700689public:
690 LinearGradientGM(bool dither) : fDither(dither) { }
caryclark159fa572015-07-30 12:35:48 -0700691
692protected:
fmalita063675b2015-10-12 10:41:48 -0700693 SkString onShortName() override {
694 return SkString(fDither ? "linear_gradient" : "linear_gradient_nodither");
695 }
696
caryclark159fa572015-07-30 12:35:48 -0700697 const SkScalar kWidthBump = 30.f;
698 const SkScalar kHeight = 5.f;
699 const SkScalar kMinWidth = 540.f;
700
701 SkISize onISize() override { return SkISize::Make(500, 500); }
702
703 void onOnceBeforeDraw() override {
704 SkPoint pts[2] = { {0, 0}, {0, 0} };
705 const SkColor colors[] = { SK_ColorWHITE, SK_ColorWHITE, 0xFF008200, 0xFF008200,
706 SK_ColorWHITE, SK_ColorWHITE };
707 const SkScalar unitPos[] = { 0, 50, 70, 500, 540 };
708 SkScalar pos[6];
709 pos[5] = 1;
710 for (int index = 0; index < (int) SK_ARRAY_COUNT(fShader); ++index) {
711 pts[1].fX = 500.f + index * kWidthBump;
712 for (int inner = 0; inner < (int) SK_ARRAY_COUNT(unitPos); ++inner) {
713 pos[inner] = unitPos[inner] / (kMinWidth + index * kWidthBump);
714 }
reed1a9b9642016-03-13 14:13:58 -0700715 fShader[index] = SkGradientShader::MakeLinear(pts, colors, pos,
716 SK_ARRAY_COUNT(gColors), SkShader::kClamp_TileMode);
caryclark159fa572015-07-30 12:35:48 -0700717 }
718 }
719
720 void onDraw(SkCanvas* canvas) override {
721 SkPaint paint;
722 paint.setAntiAlias(true);
fmalita063675b2015-10-12 10:41:48 -0700723 paint.setDither(fDither);
caryclark159fa572015-07-30 12:35:48 -0700724 for (int index = 0; index < (int) SK_ARRAY_COUNT(fShader); ++index) {
725 paint.setShader(fShader[index]);
726 canvas->drawRect(SkRect::MakeLTRB(0, index * kHeight, kMinWidth + index * kWidthBump,
727 (index + 1) * kHeight), paint);
728 }
729 }
halcanary9d524f22016-03-29 09:03:52 -0700730
caryclark159fa572015-07-30 12:35:48 -0700731private:
reed1a9b9642016-03-13 14:13:58 -0700732 sk_sp<SkShader> fShader[100];
fmalita063675b2015-10-12 10:41:48 -0700733 bool fDither;
734
caryclark159fa572015-07-30 12:35:48 -0700735 typedef GM INHERITED;
736};
fmalita063675b2015-10-12 10:41:48 -0700737DEF_GM( return new LinearGradientGM(true); )
738DEF_GM( return new LinearGradientGM(false); )
caryclark159fa572015-07-30 12:35:48 -0700739
fmalita8b78bd62015-11-20 13:58:24 -0800740class LinearGradientTinyGM : public GM {
fmalitabc590c02016-02-22 09:12:33 -0800741public:
742 LinearGradientTinyGM(uint32_t flags, const char* suffix = nullptr)
743 : fName("linear_gradient_tiny")
744 , fFlags(flags) {
745 fName.append(suffix);
746 }
747
fmalita8b78bd62015-11-20 13:58:24 -0800748protected:
749 SkString onShortName() override {
fmalitabc590c02016-02-22 09:12:33 -0800750 return fName;
fmalita8b78bd62015-11-20 13:58:24 -0800751 }
752
753 SkISize onISize() override {
754 return SkISize::Make(600, 500);
755 }
756
757 void onDraw(SkCanvas* canvas) override {
758 const SkScalar kRectSize = 100;
759 const unsigned kStopCount = 3;
760 const SkColor colors[kStopCount] = { SK_ColorGREEN, SK_ColorRED, SK_ColorGREEN };
761 const struct {
762 SkPoint pts[2];
763 SkScalar pos[kStopCount];
764 } configs[] = {
reedde3aac82015-11-22 13:00:04 -0800765 { { SkPoint::Make(0, 0), SkPoint::Make(10, 0) }, { 0, 0.999999f, 1 }},
766 { { SkPoint::Make(0, 0), SkPoint::Make(10, 0) }, { 0, 0.000001f, 1 }},
767 { { SkPoint::Make(0, 0), SkPoint::Make(10, 0) }, { 0, 0.999999999f, 1 }},
768 { { SkPoint::Make(0, 0), SkPoint::Make(10, 0) }, { 0, 0.000000001f, 1 }},
fmalita8b78bd62015-11-20 13:58:24 -0800769
reedde3aac82015-11-22 13:00:04 -0800770 { { SkPoint::Make(0, 0), SkPoint::Make(0, 10) }, { 0, 0.999999f, 1 }},
771 { { SkPoint::Make(0, 0), SkPoint::Make(0, 10) }, { 0, 0.000001f, 1 }},
772 { { SkPoint::Make(0, 0), SkPoint::Make(0, 10) }, { 0, 0.999999999f, 1 }},
773 { { SkPoint::Make(0, 0), SkPoint::Make(0, 10) }, { 0, 0.000000001f, 1 }},
774
775 { { SkPoint::Make(0, 0), SkPoint::Make(0.00001f, 0) }, { 0, 0.5f, 1 }},
776 { { SkPoint::Make(9.99999f, 0), SkPoint::Make(10, 0) }, { 0, 0.5f, 1 }},
777 { { SkPoint::Make(0, 0), SkPoint::Make(0, 0.00001f) }, { 0, 0.5f, 1 }},
778 { { SkPoint::Make(0, 9.99999f), SkPoint::Make(0, 10) }, { 0, 0.5f, 1 }},
fmalita8b78bd62015-11-20 13:58:24 -0800779 };
780
781 SkPaint paint;
782 for (unsigned i = 0; i < SK_ARRAY_COUNT(configs); ++i) {
783 SkAutoCanvasRestore acr(canvas, true);
reed1a9b9642016-03-13 14:13:58 -0700784 paint.setShader(SkGradientShader::MakeLinear(configs[i].pts, colors, configs[i].pos,
785 kStopCount, SkShader::kClamp_TileMode,
786 fFlags, nullptr));
fmalita8b78bd62015-11-20 13:58:24 -0800787 canvas->translate(kRectSize * ((i % 4) * 1.5f + 0.25f),
788 kRectSize * ((i / 4) * 1.5f + 0.25f));
789
fmalita8b78bd62015-11-20 13:58:24 -0800790 canvas->drawRect(SkRect::MakeWH(kRectSize, kRectSize), paint);
791 }
792 }
793
794private:
795 typedef GM INHERITED;
fmalita8b78bd62015-11-20 13:58:24 -0800796
fmalitabc590c02016-02-22 09:12:33 -0800797 SkString fName;
798 uint32_t fFlags;
799};
800DEF_GM( return new LinearGradientTinyGM(0); )
801DEF_GM( return new LinearGradientTinyGM(SkLinearGradient::kForce4fContext_PrivateFlag, "_4f"); )
reed@android.com42309d42009-06-22 02:06:35 +0000802}
reedd4eaa252016-01-22 10:35:26 -0800803
804///////////////////////////////////////////////////////////////////////////////////////////////////
805
806struct GradRun {
807 SkColor fColors[4];
808 SkScalar fPos[4];
809 int fCount;
810};
811
812#define SIZE 121
813
reed1a9b9642016-03-13 14:13:58 -0700814static sk_sp<SkShader> make_linear(const GradRun& run, SkShader::TileMode mode) {
reedd4eaa252016-01-22 10:35:26 -0800815 const SkPoint pts[] { { 30, 30 }, { SIZE - 30, SIZE - 30 } };
reed1a9b9642016-03-13 14:13:58 -0700816 return SkGradientShader::MakeLinear(pts, run.fColors, run.fPos, run.fCount, mode);
reedd4eaa252016-01-22 10:35:26 -0800817}
818
reed1a9b9642016-03-13 14:13:58 -0700819static sk_sp<SkShader> make_radial(const GradRun& run, SkShader::TileMode mode) {
reedd4eaa252016-01-22 10:35:26 -0800820 const SkScalar half = SIZE * 0.5f;
reed1a9b9642016-03-13 14:13:58 -0700821 return SkGradientShader::MakeRadial({half,half}, half - 10, run.fColors, run.fPos,
822 run.fCount, mode);
reedd4eaa252016-01-22 10:35:26 -0800823}
824
reed1a9b9642016-03-13 14:13:58 -0700825static sk_sp<SkShader> make_conical(const GradRun& run, SkShader::TileMode mode) {
reedd4eaa252016-01-22 10:35:26 -0800826 const SkScalar half = SIZE * 0.5f;
827 const SkPoint center { half, half };
reed1a9b9642016-03-13 14:13:58 -0700828 return SkGradientShader::MakeTwoPointConical(center, 20, center, half - 10,
829 run.fColors, run.fPos, run.fCount, mode);
reedd4eaa252016-01-22 10:35:26 -0800830}
831
reed1a9b9642016-03-13 14:13:58 -0700832static sk_sp<SkShader> make_sweep(const GradRun& run, SkShader::TileMode) {
reedd4eaa252016-01-22 10:35:26 -0800833 const SkScalar half = SIZE * 0.5f;
reed1a9b9642016-03-13 14:13:58 -0700834 return SkGradientShader::MakeSweep(half, half, run.fColors, run.fPos, run.fCount);
reedd4eaa252016-01-22 10:35:26 -0800835}
836
837/*
838 * Exercise duplicate color-stops, at the ends, and in the middle
839 *
840 * At the time of this writing, only Linear correctly deals with duplicates at the ends,
841 * and then only correctly on CPU backend.
842 */
843DEF_SIMPLE_GM(gradients_dup_color_stops, canvas, 704, 564) {
844 const SkColor preColor = 0xFFFF0000; // clamp color before start
845 const SkColor postColor = 0xFF0000FF; // clamp color after end
846 const SkColor color0 = 0xFF000000;
847 const SkColor color1 = 0xFF00FF00;
848 const SkColor badColor = 0xFF3388BB; // should never be seen, fills out fixed-size array
849
850 const GradRun runs[] = {
851 { { color0, color1, badColor, badColor },
852 { 0, 1, -1, -1 },
853 2,
854 },
855 { { preColor, color0, color1, badColor },
856 { 0, 0, 1, -1 },
857 3,
858 },
859 { { color0, color1, postColor, badColor },
860 { 0, 1, 1, -1 },
861 3,
862 },
863 { { preColor, color0, color1, postColor },
864 { 0, 0, 1, 1 },
865 4,
866 },
867 { { color0, color0, color1, color1 },
868 { 0, 0.5f, 0.5f, 1 },
869 4,
870 },
871 };
reed1a9b9642016-03-13 14:13:58 -0700872 sk_sp<SkShader> (*factories[])(const GradRun&, SkShader::TileMode) {
reedd4eaa252016-01-22 10:35:26 -0800873 make_linear, make_radial, make_conical, make_sweep
874 };
875
876 const SkRect rect = SkRect::MakeWH(SIZE, SIZE);
877 const SkScalar dx = SIZE + 20;
878 const SkScalar dy = SIZE + 20;
879 const SkShader::TileMode mode = SkShader::kClamp_TileMode;
880
881 SkPaint paint;
882 canvas->translate(10, 10 - dy);
883 for (auto factory : factories) {
884 canvas->translate(0, dy);
885 SkAutoCanvasRestore acr(canvas, true);
886 for (const auto& run : runs) {
reed1a9b9642016-03-13 14:13:58 -0700887 paint.setShader(factory(run, mode));
reedd4eaa252016-01-22 10:35:26 -0800888 canvas->drawRect(rect, paint);
889 canvas->translate(dx, 0);
890 }
891 }
892}
fmalitabc590c02016-02-22 09:12:33 -0800893
894static void draw_many_stops(SkCanvas* canvas, uint32_t flags) {
895 const unsigned kStopCount = 200;
896 const SkPoint pts[] = { {50, 50}, {450, 465}};
897
898 SkColor colors[kStopCount];
899 for (unsigned i = 0; i < kStopCount; i++) {
900 switch (i % 5) {
901 case 0: colors[i] = SK_ColorRED; break;
902 case 1: colors[i] = SK_ColorGREEN; break;
903 case 2: colors[i] = SK_ColorGREEN; break;
904 case 3: colors[i] = SK_ColorBLUE; break;
905 case 4: colors[i] = SK_ColorRED; break;
906 }
907 }
908
reed9283d202016-03-13 13:01:57 -0700909 SkPaint p;
reed1a9b9642016-03-13 14:13:58 -0700910 p.setShader(SkGradientShader::MakeLinear(
911 pts, colors, nullptr, SK_ARRAY_COUNT(colors), SkShader::kClamp_TileMode, flags, nullptr));
reed9283d202016-03-13 13:01:57 -0700912
fmalitabc590c02016-02-22 09:12:33 -0800913 canvas->drawRect(SkRect::MakeXYWH(0, 0, 500, 500), p);
914}
915
916DEF_SIMPLE_GM(gradient_many_stops, canvas, 500, 500) {
917 draw_many_stops(canvas, 0);
918}
919
920DEF_SIMPLE_GM(gradient_many_stops_4f, canvas, 500, 500) {
921 draw_many_stops(canvas, SkLinearGradient::kForce4fContext_PrivateFlag);
922}
fmalitaafac5812016-11-01 13:41:34 -0700923
924static void draw_subpixel_gradient(SkCanvas* canvas, uint32_t flags) {
925 const SkPoint pts[] = { {50, 50}, {50.1f, 50.1f}};
926 SkColor colors[] = { SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE };
927 SkPaint p;
928 p.setShader(SkGradientShader::MakeLinear(
929 pts, colors, nullptr, SK_ARRAY_COUNT(colors), SkShader::kRepeat_TileMode, flags, nullptr));
930 canvas->drawRect(SkRect::MakeXYWH(0, 0, 500, 500), p);
931}
932
933DEF_SIMPLE_GM(gradient_subpixel, canvas, 500, 500) {
934 draw_subpixel_gradient(canvas, 0);
935}
936
937DEF_SIMPLE_GM(gradient_subpixel_4f, canvas, 500, 500) {
938 draw_subpixel_gradient(canvas, SkLinearGradient::kForce4fContext_PrivateFlag);
939}