blob: c1847d446243b18558c7b25e0684eddfe492b0d8 [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"
9#include "SkGradientShader.h"
10
11namespace skiagm {
12
13struct GradData {
14 int fCount;
15 const SkColor* fColors;
16 const SkScalar* fPos;
17};
18
19static const SkColor gColors[] = {
20 SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE, SK_ColorBLACK
21};
22static const SkScalar gPos0[] = { 0, SK_Scalar1 };
23static const SkScalar gPos1[] = { SK_Scalar1/4, SK_Scalar1*3/4 };
24static const SkScalar gPos2[] = {
25 0, SK_Scalar1/8, SK_Scalar1/2, SK_Scalar1*7/8, SK_Scalar1
26};
27
commit-bot@chromium.org8ba1ad32013-08-07 15:22:13 +000028static const SkScalar gPosClamp[] = {0.0f, 0.0f, 1.0f, 1.0f};
29static const SkColor gColorClamp[] = {
30 SK_ColorRED, SK_ColorGREEN, SK_ColorGREEN, SK_ColorBLUE
31};
32
reed@android.com42309d42009-06-22 02:06:35 +000033static const GradData gGradData[] = {
halcanary96fcdcc2015-08-27 07:41:13 -070034 { 2, gColors, nullptr },
reed@android.com42309d42009-06-22 02:06:35 +000035 { 2, gColors, gPos0 },
36 { 2, gColors, gPos1 },
halcanary96fcdcc2015-08-27 07:41:13 -070037 { 5, gColors, nullptr },
commit-bot@chromium.org8ba1ad32013-08-07 15:22:13 +000038 { 5, gColors, gPos2 },
39 { 4, gColorClamp, gPosClamp }
reed@android.com42309d42009-06-22 02:06:35 +000040};
41
42static SkShader* MakeLinear(const SkPoint pts[2], const GradData& data,
commit-bot@chromium.org83f23d82014-05-22 12:27:41 +000043 SkShader::TileMode tm, const SkMatrix& localMatrix) {
reed@android.com42309d42009-06-22 02:06:35 +000044 return SkGradientShader::CreateLinear(pts, data.fColors, data.fPos,
commit-bot@chromium.org83f23d82014-05-22 12:27:41 +000045 data.fCount, tm, 0, &localMatrix);
reed@android.com42309d42009-06-22 02:06:35 +000046}
reed@google.comf3c1cc92010-12-23 16:45:33 +000047
reed@android.com42309d42009-06-22 02:06:35 +000048static SkShader* MakeRadial(const SkPoint pts[2], const GradData& data,
commit-bot@chromium.org83f23d82014-05-22 12:27:41 +000049 SkShader::TileMode tm, const SkMatrix& localMatrix) {
reed@android.com42309d42009-06-22 02:06:35 +000050 SkPoint center;
51 center.set(SkScalarAve(pts[0].fX, pts[1].fX),
52 SkScalarAve(pts[0].fY, pts[1].fY));
53 return SkGradientShader::CreateRadial(center, center.fX, data.fColors,
commit-bot@chromium.org83f23d82014-05-22 12:27:41 +000054 data.fPos, data.fCount, tm, 0, &localMatrix);
reed@android.com42309d42009-06-22 02:06:35 +000055}
56
57static SkShader* MakeSweep(const SkPoint pts[2], const GradData& data,
commit-bot@chromium.org83f23d82014-05-22 12:27:41 +000058 SkShader::TileMode, const SkMatrix& localMatrix) {
reed@android.com42309d42009-06-22 02:06:35 +000059 SkPoint center;
60 center.set(SkScalarAve(pts[0].fX, pts[1].fX),
61 SkScalarAve(pts[0].fY, pts[1].fY));
62 return SkGradientShader::CreateSweep(center.fX, center.fY, data.fColors,
commit-bot@chromium.org83f23d82014-05-22 12:27:41 +000063 data.fPos, data.fCount, 0, &localMatrix);
reed@android.com42309d42009-06-22 02:06:35 +000064}
65
reed@google.comf3c1cc92010-12-23 16:45:33 +000066static SkShader* Make2Radial(const SkPoint pts[2], const GradData& data,
commit-bot@chromium.org83f23d82014-05-22 12:27:41 +000067 SkShader::TileMode tm, const SkMatrix& localMatrix) {
reed@google.comf3c1cc92010-12-23 16:45:33 +000068 SkPoint center0, center1;
69 center0.set(SkScalarAve(pts[0].fX, pts[1].fX),
70 SkScalarAve(pts[0].fY, pts[1].fY));
71 center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3)/5),
72 SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4));
reed71a6cbf2015-05-04 08:32:51 -070073 return SkGradientShader::CreateTwoPointConical(
74 center1, (pts[1].fX - pts[0].fX) / 7,
75 center0, (pts[1].fX - pts[0].fX) / 2,
76 data.fColors, data.fPos, data.fCount, tm,
77 0, &localMatrix);
reed@google.comf3c1cc92010-12-23 16:45:33 +000078}
79
rileya@google.com5cf2c282012-07-09 14:42:16 +000080static SkShader* Make2Conical(const SkPoint pts[2], const GradData& data,
commit-bot@chromium.org83f23d82014-05-22 12:27:41 +000081 SkShader::TileMode tm, const SkMatrix& localMatrix) {
rileya@google.com5cf2c282012-07-09 14:42:16 +000082 SkPoint center0, center1;
reed80ea19c2015-05-12 10:37:34 -070083 SkScalar radius0 = (pts[1].fX - pts[0].fX) / 10;
84 SkScalar radius1 = (pts[1].fX - pts[0].fX) / 3;
rileya@google.com5cf2c282012-07-09 14:42:16 +000085 center0.set(pts[0].fX + radius0, pts[0].fY + radius0);
86 center1.set(pts[1].fX - radius1, pts[1].fY - radius1);
rmistry@google.comd6176b02012-08-23 18:14:13 +000087 return SkGradientShader::CreateTwoPointConical(center1, radius1,
88 center0, radius0,
89 data.fColors, data.fPos,
commit-bot@chromium.org83f23d82014-05-22 12:27:41 +000090 data.fCount, tm, 0, &localMatrix);
rileya@google.com5cf2c282012-07-09 14:42:16 +000091}
92
reed@android.com42309d42009-06-22 02:06:35 +000093typedef SkShader* (*GradMaker)(const SkPoint pts[2], const GradData& data,
commit-bot@chromium.org83f23d82014-05-22 12:27:41 +000094 SkShader::TileMode tm, const SkMatrix& localMatrix);
reed@android.com42309d42009-06-22 02:06:35 +000095static const GradMaker gGradMakers[] = {
rileya@google.com5cf2c282012-07-09 14:42:16 +000096 MakeLinear, MakeRadial, MakeSweep, Make2Radial, Make2Conical
reed@android.com42309d42009-06-22 02:06:35 +000097};
98
99///////////////////////////////////////////////////////////////////////////////
100
101class GradientsGM : public GM {
102public:
fmalita063675b2015-10-12 10:41:48 -0700103 GradientsGM(bool dither) : fDither(dither) {
caryclark65cdba62015-06-15 06:51:08 -0700104 this->setBGColor(sk_tool_utils::color_to_565(0xFFDDDDDD));
bsalomon@google.com48dd1a22011-10-31 14:18:20 +0000105 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000106
reed@android.com42309d42009-06-22 02:06:35 +0000107protected:
commit-bot@chromium.orga90c6802014-04-30 13:20:45 +0000108
reed@android.com42309d42009-06-22 02:06:35 +0000109 SkString onShortName() {
fmalita063675b2015-10-12 10:41:48 -0700110 return SkString(fDither ? "gradients" : "gradients_nodither");
reed@android.com42309d42009-06-22 02:06:35 +0000111 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000112
edisonn@google.com1da3a802013-09-19 17:55:49 +0000113 virtual SkISize onISize() { return SkISize::Make(840, 815); }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000114
reed@android.com42309d42009-06-22 02:06:35 +0000115 virtual void onDraw(SkCanvas* canvas) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000116
reed@android.com42309d42009-06-22 02:06:35 +0000117 SkPoint pts[2] = {
118 { 0, 0 },
119 { SkIntToScalar(100), SkIntToScalar(100) }
120 };
121 SkShader::TileMode tm = SkShader::kClamp_TileMode;
122 SkRect r = { 0, 0, SkIntToScalar(100), SkIntToScalar(100) };
123 SkPaint paint;
124 paint.setAntiAlias(true);
fmalita063675b2015-10-12 10:41:48 -0700125 paint.setDither(fDither);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000126
reed@android.com42309d42009-06-22 02:06:35 +0000127 canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
128 for (size_t i = 0; i < SK_ARRAY_COUNT(gGradData); i++) {
129 canvas->save();
130 for (size_t j = 0; j < SK_ARRAY_COUNT(gGradMakers); j++) {
commit-bot@chromium.org9c9005a2014-04-28 14:55:39 +0000131 SkMatrix scale = SkMatrix::I();
commit-bot@chromium.org8ba1ad32013-08-07 15:22:13 +0000132
133 if (i == 5) { // if the clamp case
commit-bot@chromium.org8ba1ad32013-08-07 15:22:13 +0000134 scale.setScale(0.5f, 0.5f);
135 scale.postTranslate(25.f, 25.f);
commit-bot@chromium.org8ba1ad32013-08-07 15:22:13 +0000136 }
skia.committer@gmail.comd55e3572013-08-08 07:01:20 +0000137
commit-bot@chromium.org83f23d82014-05-22 12:27:41 +0000138 SkShader* shader = gGradMakers[j](pts, gGradData[i], tm, scale);
commit-bot@chromium.org9c9005a2014-04-28 14:55:39 +0000139
reed@android.com42309d42009-06-22 02:06:35 +0000140 paint.setShader(shader);
141 canvas->drawRect(r, paint);
142 shader->unref();
143 canvas->translate(0, SkIntToScalar(120));
144 }
145 canvas->restore();
146 canvas->translate(SkIntToScalar(120), 0);
147 }
148 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000149
fmalita063675b2015-10-12 10:41:48 -0700150protected:
151 bool fDither;
152
reed@android.com42309d42009-06-22 02:06:35 +0000153private:
154 typedef GM INHERITED;
155};
fmalita063675b2015-10-12 10:41:48 -0700156DEF_GM( return new GradientsGM(true); )
157DEF_GM( return new GradientsGM(false); )
reed@android.com42309d42009-06-22 02:06:35 +0000158
rileya@google.com5cf2c282012-07-09 14:42:16 +0000159// Based on the original gradient slide, but with perspective applied to the
160// gradient shaders' local matrices
161class GradientsLocalPerspectiveGM : public GM {
162public:
fmalita063675b2015-10-12 10:41:48 -0700163 GradientsLocalPerspectiveGM(bool dither) : fDither(dither) {
caryclark65cdba62015-06-15 06:51:08 -0700164 this->setBGColor(sk_tool_utils::color_to_565(0xFFDDDDDD));
rileya@google.com5cf2c282012-07-09 14:42:16 +0000165 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000166
rileya@google.com5cf2c282012-07-09 14:42:16 +0000167protected:
commit-bot@chromium.orga90c6802014-04-30 13:20:45 +0000168
rileya@google.com5cf2c282012-07-09 14:42:16 +0000169 SkString onShortName() {
fmalita063675b2015-10-12 10:41:48 -0700170 return SkString(fDither ? "gradients_local_perspective" :
171 "gradients_local_perspective_nodither");
rileya@google.com5cf2c282012-07-09 14:42:16 +0000172 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000173
edisonn@google.com1da3a802013-09-19 17:55:49 +0000174 virtual SkISize onISize() { return SkISize::Make(840, 815); }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000175
rileya@google.com5cf2c282012-07-09 14:42:16 +0000176 virtual void onDraw(SkCanvas* canvas) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000177
rileya@google.com5cf2c282012-07-09 14:42:16 +0000178 SkPoint pts[2] = {
179 { 0, 0 },
180 { SkIntToScalar(100), SkIntToScalar(100) }
181 };
182 SkShader::TileMode tm = SkShader::kClamp_TileMode;
183 SkRect r = { 0, 0, SkIntToScalar(100), SkIntToScalar(100) };
184 SkPaint paint;
185 paint.setAntiAlias(true);
fmalita063675b2015-10-12 10:41:48 -0700186 paint.setDither(fDither);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000187
rileya@google.com5cf2c282012-07-09 14:42:16 +0000188 canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
189 for (size_t i = 0; i < SK_ARRAY_COUNT(gGradData); i++) {
190 canvas->save();
191 for (size_t j = 0; j < SK_ARRAY_COUNT(gGradMakers); j++) {
rileya@google.com5cf2c282012-07-09 14:42:16 +0000192 // apply an increasing y perspective as we move to the right
193 SkMatrix perspective;
194 perspective.setIdentity();
reed80ea19c2015-05-12 10:37:34 -0700195 perspective.setPerspY(SkIntToScalar(i+1) / 500);
196 perspective.setSkewX(SkIntToScalar(i+1) / 10);
commit-bot@chromium.org8ba1ad32013-08-07 15:22:13 +0000197
commit-bot@chromium.org83f23d82014-05-22 12:27:41 +0000198 SkShader* shader = gGradMakers[j](pts, gGradData[i], tm, perspective);
rileya@google.com5cf2c282012-07-09 14:42:16 +0000199
200 paint.setShader(shader);
201 canvas->drawRect(r, paint);
202 shader->unref();
203 canvas->translate(0, SkIntToScalar(120));
204 }
205 canvas->restore();
206 canvas->translate(SkIntToScalar(120), 0);
207 }
208 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000209
rileya@google.com5cf2c282012-07-09 14:42:16 +0000210private:
fmalita063675b2015-10-12 10:41:48 -0700211 bool fDither;
212
rileya@google.com5cf2c282012-07-09 14:42:16 +0000213 typedef GM INHERITED;
214};
fmalita063675b2015-10-12 10:41:48 -0700215DEF_GM( return new GradientsLocalPerspectiveGM(true); )
216DEF_GM( return new GradientsLocalPerspectiveGM(false); )
rileya@google.com5cf2c282012-07-09 14:42:16 +0000217
218// Based on the original gradient slide, but with perspective applied to
219// the view matrix
220class GradientsViewPerspectiveGM : public GradientsGM {
fmalita063675b2015-10-12 10:41:48 -0700221public:
222 GradientsViewPerspectiveGM(bool dither) : INHERITED(dither) { }
223
rileya@google.com5cf2c282012-07-09 14:42:16 +0000224protected:
225 SkString onShortName() {
fmalita063675b2015-10-12 10:41:48 -0700226 return SkString(fDither ? "gradients_view_perspective" :
227 "gradients_view_perspective_nodither");
rileya@google.com5cf2c282012-07-09 14:42:16 +0000228 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000229
edisonn@google.com1da3a802013-09-19 17:55:49 +0000230 virtual SkISize onISize() { return SkISize::Make(840, 500); }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000231
rileya@google.com5cf2c282012-07-09 14:42:16 +0000232 virtual void onDraw(SkCanvas* canvas) {
233 SkMatrix perspective;
234 perspective.setIdentity();
reed80ea19c2015-05-12 10:37:34 -0700235 perspective.setPerspY(0.001f);
236 perspective.setSkewX(SkIntToScalar(8) / 25);
scroggo@google.com837d31a2012-08-15 18:42:45 +0000237 canvas->concat(perspective);
rileya@google.com5cf2c282012-07-09 14:42:16 +0000238 INHERITED::onDraw(canvas);
239 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000240
rileya@google.com5cf2c282012-07-09 14:42:16 +0000241private:
242 typedef GradientsGM INHERITED;
243};
fmalita063675b2015-10-12 10:41:48 -0700244DEF_GM( return new GradientsViewPerspectiveGM(true); )
245DEF_GM( return new GradientsViewPerspectiveGM(false); )
rileya@google.com5cf2c282012-07-09 14:42:16 +0000246
reed@google.comac864a92011-06-27 18:11:17 +0000247/*
248 Inspired by this <canvas> javascript, where we need to detect that we are not
249 solving a quadratic equation, but must instead solve a linear (since our X^2
250 coefficient is 0)
251
252 ctx.fillStyle = '#f00';
253 ctx.fillRect(0, 0, 100, 50);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000254
reed@google.comac864a92011-06-27 18:11:17 +0000255 var g = ctx.createRadialGradient(-80, 25, 70, 0, 25, 150);
256 g.addColorStop(0, '#f00');
257 g.addColorStop(0.01, '#0f0');
258 g.addColorStop(0.99, '#0f0');
259 g.addColorStop(1, '#f00');
260 ctx.fillStyle = g;
261 ctx.fillRect(0, 0, 100, 50);
262 */
263class GradientsDegenrate2PointGM : public GM {
264public:
fmalita063675b2015-10-12 10:41:48 -0700265 GradientsDegenrate2PointGM(bool dither) : fDither(dither) {}
rmistry@google.comd6176b02012-08-23 18:14:13 +0000266
reed@google.comac864a92011-06-27 18:11:17 +0000267protected:
268 SkString onShortName() {
fmalita063675b2015-10-12 10:41:48 -0700269 return SkString(fDither ? "gradients_degenerate_2pt" : "gradients_degenerate_2pt_nodither");
reed@google.comac864a92011-06-27 18:11:17 +0000270 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000271
edisonn@google.com1da3a802013-09-19 17:55:49 +0000272 virtual SkISize onISize() { return SkISize::Make(320, 320); }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000273
reed@google.comac864a92011-06-27 18:11:17 +0000274 void drawBG(SkCanvas* canvas) {
275 canvas->drawColor(SK_ColorBLUE);
276 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000277
reed@google.comac864a92011-06-27 18:11:17 +0000278 virtual void onDraw(SkCanvas* canvas) {
279 this->drawBG(canvas);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000280
reed@google.comac864a92011-06-27 18:11:17 +0000281 SkColor colors[] = { SK_ColorRED, SK_ColorGREEN, SK_ColorGREEN, SK_ColorRED };
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000282 SkScalar pos[] = { 0, 0.01f, 0.99f, SK_Scalar1 };
epoger@google.com59f3abf2011-07-21 15:50:33 +0000283 SkPoint c0;
284 c0.iset(-80, 25);
285 SkScalar r0 = SkIntToScalar(70);
286 SkPoint c1;
287 c1.iset(0, 25);
288 SkScalar r1 = SkIntToScalar(150);
reed71a6cbf2015-05-04 08:32:51 -0700289 SkShader* s = SkGradientShader::CreateTwoPointConical(c0, r0, c1, r1, colors,
290 pos, SK_ARRAY_COUNT(pos),
291 SkShader::kClamp_TileMode);
reed@google.comac864a92011-06-27 18:11:17 +0000292 SkPaint paint;
fmalita063675b2015-10-12 10:41:48 -0700293 paint.setDither(fDither);
reed@google.comac864a92011-06-27 18:11:17 +0000294 paint.setShader(s)->unref();
295 canvas->drawPaint(paint);
296 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000297
reed@google.comac864a92011-06-27 18:11:17 +0000298private:
fmalita063675b2015-10-12 10:41:48 -0700299 bool fDither;
300
reed@google.comac864a92011-06-27 18:11:17 +0000301 typedef GM INHERITED;
302};
fmalita063675b2015-10-12 10:41:48 -0700303DEF_GM( return new GradientsDegenrate2PointGM(true); )
304DEF_GM( return new GradientsDegenrate2PointGM(false); )
reed@google.comac864a92011-06-27 18:11:17 +0000305
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000306/// Tests correctness of *optimized* codepaths in gradients.
307
308class ClampedGradientsGM : public GM {
309public:
fmalita063675b2015-10-12 10:41:48 -0700310 ClampedGradientsGM(bool dither) : fDither(dither) {}
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000311
312protected:
fmalita063675b2015-10-12 10:41:48 -0700313 SkString onShortName() {
314 return SkString(fDither ? "clamped_gradients" : "clamped_gradients_nodither");
315 }
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000316
edisonn@google.com1da3a802013-09-19 17:55:49 +0000317 virtual SkISize onISize() { return SkISize::Make(640, 510); }
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000318
319 void drawBG(SkCanvas* canvas) {
caryclark12596012015-07-29 05:27:47 -0700320 canvas->drawColor(sk_tool_utils::color_to_565(0xFFDDDDDD));
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000321 }
322
323 virtual void onDraw(SkCanvas* canvas) {
324 this->drawBG(canvas);
325
326 SkRect r = { 0, 0, SkIntToScalar(100), SkIntToScalar(300) };
327 SkPaint paint;
fmalita063675b2015-10-12 10:41:48 -0700328 paint.setDither(fDither);
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000329 paint.setAntiAlias(true);
330
331 SkPoint center;
332 center.iset(0, 300);
333 canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
334 SkShader* shader = SkGradientShader::CreateRadial(
335 SkPoint(center),
halcanary96fcdcc2015-08-27 07:41:13 -0700336 SkIntToScalar(200), gColors, nullptr, 5,
commit-bot@chromium.org83f23d82014-05-22 12:27:41 +0000337 SkShader::kClamp_TileMode);
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000338 paint.setShader(shader);
339 canvas->drawRect(r, paint);
340 shader->unref();
341 }
342
343private:
fmalita063675b2015-10-12 10:41:48 -0700344 bool fDither;
345
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000346 typedef GM INHERITED;
347};
fmalita063675b2015-10-12 10:41:48 -0700348DEF_GM( return new ClampedGradientsGM(true); )
349DEF_GM( return new ClampedGradientsGM(false); )
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000350
tomhudson@google.comb18e58c2012-01-30 20:00:13 +0000351/// Checks quality of large radial gradients, which may display
352/// some banding.
353
354class RadialGradientGM : public GM {
355public:
356 RadialGradientGM() {}
357
358protected:
commit-bot@chromium.orga90c6802014-04-30 13:20:45 +0000359
mtklein36352bf2015-03-25 18:17:31 -0700360 SkString onShortName() override { return SkString("radial_gradient"); }
361 SkISize onISize() override { return SkISize::Make(1280, 1280); }
tomhudson@google.comb18e58c2012-01-30 20:00:13 +0000362 void drawBG(SkCanvas* canvas) {
363 canvas->drawColor(0xFF000000);
364 }
mtklein36352bf2015-03-25 18:17:31 -0700365 void onDraw(SkCanvas* canvas) override {
reed@google.combb0948f2012-01-31 14:44:13 +0000366 const SkISize dim = this->getISize();
367
tomhudson@google.comb18e58c2012-01-30 20:00:13 +0000368 this->drawBG(canvas);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000369
tomhudson@google.comb18e58c2012-01-30 20:00:13 +0000370 SkPaint paint;
371 paint.setDither(true);
372 SkPoint center;
reed@google.combb0948f2012-01-31 14:44:13 +0000373 center.set(SkIntToScalar(dim.width())/2, SkIntToScalar(dim.height())/2);
374 SkScalar radius = SkIntToScalar(dim.width())/2;
375 const SkColor colors[] = { 0x7f7f7f7f, 0x7f7f7f7f, 0xb2000000 };
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000376 const SkScalar pos[] = { 0.0f,
377 0.35f,
378 1.0f };
tomhudson@google.comb18e58c2012-01-30 20:00:13 +0000379 SkShader* shader =
380 SkGradientShader::CreateRadial(center, radius, colors,
reed@google.combb0948f2012-01-31 14:44:13 +0000381 pos, SK_ARRAY_COUNT(pos),
382 SkShader::kClamp_TileMode);
tomhudson@google.comb18e58c2012-01-30 20:00:13 +0000383 paint.setShader(shader)->unref();
reed@google.combb0948f2012-01-31 14:44:13 +0000384 SkRect r = {
385 0, 0, SkIntToScalar(dim.width()), SkIntToScalar(dim.height())
386 };
tomhudson@google.comb18e58c2012-01-30 20:00:13 +0000387 canvas->drawRect(r, paint);
388 }
389private:
390 typedef GM INHERITED;
391};
reed3d9005c2015-04-23 10:30:27 -0700392DEF_GM( return new RadialGradientGM; )
tomhudson@google.comb18e58c2012-01-30 20:00:13 +0000393
mtklein@google.com361a72f2013-08-19 18:43:34 +0000394class RadialGradient2GM : public GM {
395public:
fmalita063675b2015-10-12 10:41:48 -0700396 RadialGradient2GM(bool dither) : fDither(dither) {}
mtklein@google.com361a72f2013-08-19 18:43:34 +0000397
398protected:
commit-bot@chromium.orga90c6802014-04-30 13:20:45 +0000399
fmalita063675b2015-10-12 10:41:48 -0700400 SkString onShortName() override {
401 return SkString(fDither ? "radial_gradient2" : "radial_gradient2_nodither");
402 }
403
mtklein36352bf2015-03-25 18:17:31 -0700404 SkISize onISize() override { return SkISize::Make(800, 400); }
mtklein@google.com361a72f2013-08-19 18:43:34 +0000405 void drawBG(SkCanvas* canvas) {
406 canvas->drawColor(0xFF000000);
407 }
408
409 // Reproduces the example given in bug 7671058.
mtklein36352bf2015-03-25 18:17:31 -0700410 void onDraw(SkCanvas* canvas) override {
mtklein@google.com361a72f2013-08-19 18:43:34 +0000411 SkPaint paint1, paint2, paint3;
412 paint1.setStyle(SkPaint::kFill_Style);
413 paint2.setStyle(SkPaint::kFill_Style);
414 paint3.setStyle(SkPaint::kFill_Style);
415
416 const SkColor sweep_colors[] =
417 { 0xFFFF0000, 0xFFFFFF00, 0xFF00FF00, 0xFF00FFFF, 0xFF0000FF, 0xFFFF00FF, 0xFFFF0000 };
418 const SkColor colors1[] = { 0xFFFFFFFF, 0x00000000 };
419 const SkColor colors2[] = { 0xFF000000, 0x00000000 };
420
421 const SkScalar cx = 200, cy = 200, radius = 150;
422 SkPoint center;
423 center.set(cx, cy);
424
mtklein@google.com3ef7eea2013-09-16 13:02:52 +0000425 // We can either interpolate endpoints and premultiply each point (default, more precision),
426 // or premultiply the endpoints first, avoiding the need to premultiply each point (cheap).
427 const uint32_t flags[] = { 0, SkGradientShader::kInterpolateColorsInPremul_Flag };
mtklein@google.com361a72f2013-08-19 18:43:34 +0000428
mtklein@google.com3ef7eea2013-09-16 13:02:52 +0000429 for (size_t i = 0; i < SK_ARRAY_COUNT(flags); i++) {
430 SkAutoTUnref<SkShader> sweep(
431 SkGradientShader::CreateSweep(cx, cy, sweep_colors,
halcanary96fcdcc2015-08-27 07:41:13 -0700432 nullptr, SK_ARRAY_COUNT(sweep_colors),
433 flags[i], nullptr));
mtklein@google.com3ef7eea2013-09-16 13:02:52 +0000434 SkAutoTUnref<SkShader> radial1(
435 SkGradientShader::CreateRadial(center, radius, colors1,
halcanary96fcdcc2015-08-27 07:41:13 -0700436 nullptr, SK_ARRAY_COUNT(colors1),
mtklein@google.com3ef7eea2013-09-16 13:02:52 +0000437 SkShader::kClamp_TileMode,
halcanary96fcdcc2015-08-27 07:41:13 -0700438 flags[i], nullptr));
mtklein@google.com3ef7eea2013-09-16 13:02:52 +0000439 SkAutoTUnref<SkShader> radial2(
440 SkGradientShader::CreateRadial(center, radius, colors2,
halcanary96fcdcc2015-08-27 07:41:13 -0700441 nullptr, SK_ARRAY_COUNT(colors2),
mtklein@google.com3ef7eea2013-09-16 13:02:52 +0000442 SkShader::kClamp_TileMode,
halcanary96fcdcc2015-08-27 07:41:13 -0700443 flags[i], nullptr));
mtklein@google.com3ef7eea2013-09-16 13:02:52 +0000444 paint1.setShader(sweep);
fmalita063675b2015-10-12 10:41:48 -0700445 paint1.setDither(fDither);
mtklein@google.com3ef7eea2013-09-16 13:02:52 +0000446 paint2.setShader(radial1);
fmalita063675b2015-10-12 10:41:48 -0700447 paint2.setDither(fDither);
mtklein@google.com3ef7eea2013-09-16 13:02:52 +0000448 paint3.setShader(radial2);
fmalita063675b2015-10-12 10:41:48 -0700449 paint3.setDither(fDither);
mtklein@google.com3ef7eea2013-09-16 13:02:52 +0000450
451 canvas->drawCircle(cx, cy, radius, paint1);
452 canvas->drawCircle(cx, cy, radius, paint3);
453 canvas->drawCircle(cx, cy, radius, paint2);
454
455 canvas->translate(400, 0);
456 }
mtklein@google.com361a72f2013-08-19 18:43:34 +0000457 }
458
459private:
fmalita063675b2015-10-12 10:41:48 -0700460 bool fDither;
461
mtklein@google.com361a72f2013-08-19 18:43:34 +0000462 typedef GM INHERITED;
463};
fmalita063675b2015-10-12 10:41:48 -0700464DEF_GM( return new RadialGradient2GM(true); )
465DEF_GM( return new RadialGradient2GM(false); )
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000466
reed3d9005c2015-04-23 10:30:27 -0700467// Shallow radial (shows banding on raster)
468class RadialGradient3GM : public GM {
fmalita063675b2015-10-12 10:41:48 -0700469public:
470 RadialGradient3GM(bool dither) : fDither(dither) { }
reed@android.com42309d42009-06-22 02:06:35 +0000471
reed3d9005c2015-04-23 10:30:27 -0700472protected:
fmalita063675b2015-10-12 10:41:48 -0700473 SkString onShortName() override {
474 return SkString(fDither ? "radial_gradient3" : "radial_gradient3_nodither");
475 }
reed@android.com42309d42009-06-22 02:06:35 +0000476
reed3d9005c2015-04-23 10:30:27 -0700477 SkISize onISize() override { return SkISize::Make(500, 500); }
reed@google.comac864a92011-06-27 18:11:17 +0000478
reed3d9005c2015-04-23 10:30:27 -0700479 bool runAsBench() const override { return true; }
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000480
reed3d9005c2015-04-23 10:30:27 -0700481 void onOnceBeforeDraw() override {
482 const SkPoint center = { 0, 0 };
483 const SkScalar kRadius = 3000;
484 const SkColor gColors[] = { 0xFFFFFFFF, 0xFF000000 };
halcanary96fcdcc2015-08-27 07:41:13 -0700485 fShader.reset(SkGradientShader::CreateRadial(center, kRadius, gColors, nullptr, 2,
mtklein1113da72015-04-27 12:08:01 -0700486 SkShader::kClamp_TileMode));
reed3d9005c2015-04-23 10:30:27 -0700487 }
rileya@google.com5cf2c282012-07-09 14:42:16 +0000488
reed3d9005c2015-04-23 10:30:27 -0700489 void onDraw(SkCanvas* canvas) override {
490 SkPaint paint;
491 paint.setShader(fShader);
fmalita063675b2015-10-12 10:41:48 -0700492 paint.setDither(fDither);
reed3d9005c2015-04-23 10:30:27 -0700493 canvas->drawRect(SkRect::MakeWH(500, 500), paint);
494 }
495
496private:
fmalita063675b2015-10-12 10:41:48 -0700497 SkAutoTUnref<SkShader> fShader;
498 bool fDither;
499
reed3d9005c2015-04-23 10:30:27 -0700500 typedef GM INHERITED;
501};
fmalita063675b2015-10-12 10:41:48 -0700502DEF_GM( return new RadialGradient3GM(true); )
503DEF_GM( return new RadialGradient3GM(false); )
rileya@google.com5cf2c282012-07-09 14:42:16 +0000504
caryclark1864bfa2015-07-30 06:41:39 -0700505class RadialGradient4GM : public GM {
fmalita063675b2015-10-12 10:41:48 -0700506public:
507 RadialGradient4GM(bool dither) : fDither(dither) { }
caryclark1864bfa2015-07-30 06:41:39 -0700508
509protected:
fmalita063675b2015-10-12 10:41:48 -0700510 SkString onShortName() override {
511 return SkString(fDither ? "radial_gradient4" : "radial_gradient4_nodither");
512 }
caryclark1864bfa2015-07-30 06:41:39 -0700513
514 SkISize onISize() override { return SkISize::Make(500, 500); }
515
516 void onOnceBeforeDraw() override {
517 const SkPoint center = { 250, 250 };
518 const SkScalar kRadius = 250;
519 const SkColor colors[] = { SK_ColorRED, SK_ColorRED, SK_ColorWHITE, SK_ColorWHITE,
520 SK_ColorRED };
521 const SkScalar pos[] = { 0, .4f, .4f, .8f, .8f, 1 };
522 fShader.reset(SkGradientShader::CreateRadial(center, kRadius, colors, pos,
523 SK_ARRAY_COUNT(gColors), SkShader::kClamp_TileMode));
524 }
525
526 void onDraw(SkCanvas* canvas) override {
527 SkPaint paint;
528 paint.setAntiAlias(true);
fmalita063675b2015-10-12 10:41:48 -0700529 paint.setDither(fDither);
caryclark1864bfa2015-07-30 06:41:39 -0700530 paint.setShader(fShader);
531 canvas->drawRect(SkRect::MakeWH(500, 500), paint);
532 }
533
534private:
fmalita063675b2015-10-12 10:41:48 -0700535 SkAutoTUnref<SkShader> fShader;
536 bool fDither;
537
caryclark1864bfa2015-07-30 06:41:39 -0700538 typedef GM INHERITED;
539};
fmalita063675b2015-10-12 10:41:48 -0700540DEF_GM( return new RadialGradient4GM(true); )
541DEF_GM( return new RadialGradient4GM(false); )
caryclark1864bfa2015-07-30 06:41:39 -0700542
caryclark159fa572015-07-30 12:35:48 -0700543class LinearGradientGM : public GM {
fmalita063675b2015-10-12 10:41:48 -0700544public:
545 LinearGradientGM(bool dither) : fDither(dither) { }
caryclark159fa572015-07-30 12:35:48 -0700546
547protected:
fmalita063675b2015-10-12 10:41:48 -0700548 SkString onShortName() override {
549 return SkString(fDither ? "linear_gradient" : "linear_gradient_nodither");
550 }
551
caryclark159fa572015-07-30 12:35:48 -0700552 const SkScalar kWidthBump = 30.f;
553 const SkScalar kHeight = 5.f;
554 const SkScalar kMinWidth = 540.f;
555
556 SkISize onISize() override { return SkISize::Make(500, 500); }
557
558 void onOnceBeforeDraw() override {
559 SkPoint pts[2] = { {0, 0}, {0, 0} };
560 const SkColor colors[] = { SK_ColorWHITE, SK_ColorWHITE, 0xFF008200, 0xFF008200,
561 SK_ColorWHITE, SK_ColorWHITE };
562 const SkScalar unitPos[] = { 0, 50, 70, 500, 540 };
563 SkScalar pos[6];
564 pos[5] = 1;
565 for (int index = 0; index < (int) SK_ARRAY_COUNT(fShader); ++index) {
566 pts[1].fX = 500.f + index * kWidthBump;
567 for (int inner = 0; inner < (int) SK_ARRAY_COUNT(unitPos); ++inner) {
568 pos[inner] = unitPos[inner] / (kMinWidth + index * kWidthBump);
569 }
570 fShader[index].reset(SkGradientShader::CreateLinear(pts, colors, pos,
571 SK_ARRAY_COUNT(gColors), SkShader::kClamp_TileMode));
572 }
573 }
574
575 void onDraw(SkCanvas* canvas) override {
576 SkPaint paint;
577 paint.setAntiAlias(true);
fmalita063675b2015-10-12 10:41:48 -0700578 paint.setDither(fDither);
caryclark159fa572015-07-30 12:35:48 -0700579 for (int index = 0; index < (int) SK_ARRAY_COUNT(fShader); ++index) {
580 paint.setShader(fShader[index]);
581 canvas->drawRect(SkRect::MakeLTRB(0, index * kHeight, kMinWidth + index * kWidthBump,
582 (index + 1) * kHeight), paint);
583 }
584 }
585
586private:
fmalita063675b2015-10-12 10:41:48 -0700587 SkAutoTUnref<SkShader> fShader[100];
588 bool fDither;
589
caryclark159fa572015-07-30 12:35:48 -0700590 typedef GM INHERITED;
591};
fmalita063675b2015-10-12 10:41:48 -0700592DEF_GM( return new LinearGradientGM(true); )
593DEF_GM( return new LinearGradientGM(false); )
caryclark159fa572015-07-30 12:35:48 -0700594
fmalita8b78bd62015-11-20 13:58:24 -0800595class LinearGradientTinyGM : public GM {
596protected:
597 SkString onShortName() override {
598 return SkString("linear_gradient_tiny");
599 }
600
601 SkISize onISize() override {
602 return SkISize::Make(600, 500);
603 }
604
605 void onDraw(SkCanvas* canvas) override {
606 const SkScalar kRectSize = 100;
607 const unsigned kStopCount = 3;
608 const SkColor colors[kStopCount] = { SK_ColorGREEN, SK_ColorRED, SK_ColorGREEN };
609 const struct {
610 SkPoint pts[2];
611 SkScalar pos[kStopCount];
612 } configs[] = {
reedde3aac82015-11-22 13:00:04 -0800613 { { SkPoint::Make(0, 0), SkPoint::Make(10, 0) }, { 0, 0.999999f, 1 }},
614 { { SkPoint::Make(0, 0), SkPoint::Make(10, 0) }, { 0, 0.000001f, 1 }},
615 { { SkPoint::Make(0, 0), SkPoint::Make(10, 0) }, { 0, 0.999999999f, 1 }},
616 { { SkPoint::Make(0, 0), SkPoint::Make(10, 0) }, { 0, 0.000000001f, 1 }},
fmalita8b78bd62015-11-20 13:58:24 -0800617
reedde3aac82015-11-22 13:00:04 -0800618 { { SkPoint::Make(0, 0), SkPoint::Make(0, 10) }, { 0, 0.999999f, 1 }},
619 { { SkPoint::Make(0, 0), SkPoint::Make(0, 10) }, { 0, 0.000001f, 1 }},
620 { { SkPoint::Make(0, 0), SkPoint::Make(0, 10) }, { 0, 0.999999999f, 1 }},
621 { { SkPoint::Make(0, 0), SkPoint::Make(0, 10) }, { 0, 0.000000001f, 1 }},
622
623 { { SkPoint::Make(0, 0), SkPoint::Make(0.00001f, 0) }, { 0, 0.5f, 1 }},
624 { { SkPoint::Make(9.99999f, 0), SkPoint::Make(10, 0) }, { 0, 0.5f, 1 }},
625 { { SkPoint::Make(0, 0), SkPoint::Make(0, 0.00001f) }, { 0, 0.5f, 1 }},
626 { { SkPoint::Make(0, 9.99999f), SkPoint::Make(0, 10) }, { 0, 0.5f, 1 }},
fmalita8b78bd62015-11-20 13:58:24 -0800627 };
628
629 SkPaint paint;
630 for (unsigned i = 0; i < SK_ARRAY_COUNT(configs); ++i) {
631 SkAutoCanvasRestore acr(canvas, true);
632 SkAutoTUnref<SkShader> gradient(
633 SkGradientShader::CreateLinear(configs[i].pts, colors, configs[i].pos, kStopCount,
634 SkShader::kClamp_TileMode));
635 canvas->translate(kRectSize * ((i % 4) * 1.5f + 0.25f),
636 kRectSize * ((i / 4) * 1.5f + 0.25f));
637
638 paint.setShader(gradient);
639 canvas->drawRect(SkRect::MakeWH(kRectSize, kRectSize), paint);
640 }
641 }
642
643private:
644 typedef GM INHERITED;
645};
646DEF_GM( return new LinearGradientTinyGM(); )
647
reed@android.com42309d42009-06-22 02:06:35 +0000648}
reedd4eaa252016-01-22 10:35:26 -0800649
650///////////////////////////////////////////////////////////////////////////////////////////////////
651
652struct GradRun {
653 SkColor fColors[4];
654 SkScalar fPos[4];
655 int fCount;
656};
657
658#define SIZE 121
659
660static SkShader* make_linear(const GradRun& run, SkShader::TileMode mode) {
661 const SkPoint pts[] { { 30, 30 }, { SIZE - 30, SIZE - 30 } };
662 return SkGradientShader::CreateLinear(pts, run.fColors, run.fPos, run.fCount, mode);
663}
664
665static SkShader* make_radial(const GradRun& run, SkShader::TileMode mode) {
666 const SkScalar half = SIZE * 0.5f;
667 return SkGradientShader::CreateRadial({half,half}, half - 10,
668 run.fColors, run.fPos, run.fCount, mode);
669}
670
671static SkShader* make_conical(const GradRun& run, SkShader::TileMode mode) {
672 const SkScalar half = SIZE * 0.5f;
673 const SkPoint center { half, half };
674 return SkGradientShader::CreateTwoPointConical(center, 20, center, half - 10,
675 run.fColors, run.fPos, run.fCount, mode);
676}
677
678static SkShader* make_sweep(const GradRun& run, SkShader::TileMode) {
679 const SkScalar half = SIZE * 0.5f;
680 return SkGradientShader::CreateSweep(half, half, run.fColors, run.fPos, run.fCount);
681}
682
683/*
684 * Exercise duplicate color-stops, at the ends, and in the middle
685 *
686 * At the time of this writing, only Linear correctly deals with duplicates at the ends,
687 * and then only correctly on CPU backend.
688 */
689DEF_SIMPLE_GM(gradients_dup_color_stops, canvas, 704, 564) {
690 const SkColor preColor = 0xFFFF0000; // clamp color before start
691 const SkColor postColor = 0xFF0000FF; // clamp color after end
692 const SkColor color0 = 0xFF000000;
693 const SkColor color1 = 0xFF00FF00;
694 const SkColor badColor = 0xFF3388BB; // should never be seen, fills out fixed-size array
695
696 const GradRun runs[] = {
697 { { color0, color1, badColor, badColor },
698 { 0, 1, -1, -1 },
699 2,
700 },
701 { { preColor, color0, color1, badColor },
702 { 0, 0, 1, -1 },
703 3,
704 },
705 { { color0, color1, postColor, badColor },
706 { 0, 1, 1, -1 },
707 3,
708 },
709 { { preColor, color0, color1, postColor },
710 { 0, 0, 1, 1 },
711 4,
712 },
713 { { color0, color0, color1, color1 },
714 { 0, 0.5f, 0.5f, 1 },
715 4,
716 },
717 };
718 SkShader* (*factories[])(const GradRun&, SkShader::TileMode) {
719 make_linear, make_radial, make_conical, make_sweep
720 };
721
722 const SkRect rect = SkRect::MakeWH(SIZE, SIZE);
723 const SkScalar dx = SIZE + 20;
724 const SkScalar dy = SIZE + 20;
725 const SkShader::TileMode mode = SkShader::kClamp_TileMode;
726
727 SkPaint paint;
728 canvas->translate(10, 10 - dy);
729 for (auto factory : factories) {
730 canvas->translate(0, dy);
731 SkAutoCanvasRestore acr(canvas, true);
732 for (const auto& run : runs) {
733 paint.setShader(factory(run, mode))->unref();
734 canvas->drawRect(rect, paint);
735 canvas->translate(dx, 0);
736 }
737 }
738}