1 /*
2 * Copyright 2014 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
8 #include "gm.h"
9 #include "SkGradientShader.h"
10
11 namespace skiagm {
12
13 struct GradData {
14 int fCount;
15 const SkColor* fColors;
16 const SkScalar* fPos;
17 };
18
19 constexpr SkColor gColors[] = {
20 SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE, SK_ColorBLACK
21 };
22 constexpr SkScalar gPos0[] = { 0, SK_Scalar1 };
23 constexpr SkScalar gPos1[] = { SK_Scalar1/4, SK_Scalar1*3/4 };
24 constexpr SkScalar gPos2[] = {
25 0, SK_Scalar1/8, SK_Scalar1/2, SK_Scalar1*7/8, SK_Scalar1
26 };
27
28 constexpr SkScalar gPosClamp[] = {0.0f, 0.0f, 1.0f, 1.0f};
29 constexpr SkColor gColorClamp[] = {
30 SK_ColorRED, SK_ColorGREEN, SK_ColorGREEN, SK_ColorBLUE
31 };
32
33 constexpr GradData gGradData[] = {
34 { 2, gColors, gPos0 },
35 { 2, gColors, gPos1 },
36 { 5, gColors, gPos2 },
37 { 4, gColorClamp, gPosClamp }
38 };
39
Make2ConicalOutside(const SkPoint pts[2],const GradData & data,SkShader::TileMode tm,const SkMatrix & localMatrix)40 static sk_sp<SkShader> Make2ConicalOutside(const SkPoint pts[2], const GradData& data,
41 SkShader::TileMode tm, const SkMatrix& localMatrix) {
42 SkPoint center0, center1;
43 SkScalar radius0 = (pts[1].fX - pts[0].fX) / 10;
44 SkScalar radius1 = (pts[1].fX - pts[0].fX) / 3;
45 center0.set(pts[0].fX + radius0, pts[0].fY + radius0);
46 center1.set(pts[1].fX - radius1, pts[1].fY - radius1);
47 return SkGradientShader::MakeTwoPointConical(center0, radius0, center1, radius1, data.fColors,
48 data.fPos, data.fCount, tm, 0, &localMatrix);
49 }
50
Make2ConicalOutsideStrip(const SkPoint pts[2],const GradData & data,SkShader::TileMode tm,const SkMatrix & localMatrix)51 static sk_sp<SkShader> Make2ConicalOutsideStrip(const SkPoint pts[2], const GradData& data,
52 SkShader::TileMode tm, const SkMatrix& localMatrix) {
53 SkPoint center0, center1;
54 SkScalar radius = (pts[1].fX - pts[0].fX) / 3;
55 center0.set(pts[0].fX, pts[0].fY);
56 center1.set(pts[1].fX, pts[1].fY);
57 return SkGradientShader::MakeTwoPointConical(center0, radius, center1, radius, data.fColors,
58 data.fPos, data.fCount, tm, 0, &localMatrix);
59 }
60
Make2ConicalOutsideFlip(const SkPoint pts[2],const GradData & data,SkShader::TileMode tm,const SkMatrix & localMatrix)61 static sk_sp<SkShader> Make2ConicalOutsideFlip(const SkPoint pts[2], const GradData& data,
62 SkShader::TileMode tm, const SkMatrix& localMatrix) {
63 SkPoint center0, center1;
64 SkScalar radius0 = (pts[1].fX - pts[0].fX) / 10;
65 SkScalar radius1 = (pts[1].fX - pts[0].fX) / 3;
66 center0.set(pts[0].fX + radius0, pts[0].fY + radius0);
67 center1.set(pts[1].fX - radius1, pts[1].fY - radius1);
68 return SkGradientShader::MakeTwoPointConical(center1, radius1, center0, radius0, data.fColors,
69 data.fPos, data.fCount, tm, 0, &localMatrix);
70 }
71
Make2ConicalInside(const SkPoint pts[2],const GradData & data,SkShader::TileMode tm,const SkMatrix & localMatrix)72 static sk_sp<SkShader> Make2ConicalInside(const SkPoint pts[2], const GradData& data,
73 SkShader::TileMode tm, const SkMatrix& localMatrix) {
74 SkPoint center0, center1;
75 center0.set(SkScalarAve(pts[0].fX, pts[1].fX),
76 SkScalarAve(pts[0].fY, pts[1].fY));
77 center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3)/5),
78 SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4));
79 return SkGradientShader::MakeTwoPointConical(center1, (pts[1].fX - pts[0].fX) / 7,
80 center0, (pts[1].fX - pts[0].fX) / 2,
81 data.fColors, data.fPos, data.fCount, tm,
82 0, &localMatrix);
83 }
84
Make2ConicalInsideFlip(const SkPoint pts[2],const GradData & data,SkShader::TileMode tm,const SkMatrix & localMatrix)85 static sk_sp<SkShader> Make2ConicalInsideFlip(const SkPoint pts[2], const GradData& data,
86 SkShader::TileMode tm, const SkMatrix& localMatrix) {
87 SkPoint center0, center1;
88 center0.set(SkScalarAve(pts[0].fX, pts[1].fX),
89 SkScalarAve(pts[0].fY, pts[1].fY));
90 center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3)/5),
91 SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4));
92 return SkGradientShader::MakeTwoPointConical(center0, (pts[1].fX - pts[0].fX) / 2,
93 center1, (pts[1].fX - pts[0].fX) / 7,
94 data.fColors, data.fPos, data.fCount, tm,
95 0, &localMatrix);
96 }
97
Make2ConicalInsideCenter(const SkPoint pts[2],const GradData & data,SkShader::TileMode tm,const SkMatrix & localMatrix)98 static sk_sp<SkShader> Make2ConicalInsideCenter(const SkPoint pts[2], const GradData& data,
99 SkShader::TileMode tm, const SkMatrix& localMatrix) {
100 SkPoint center0;
101 center0.set(SkScalarAve(pts[0].fX, pts[1].fX),
102 SkScalarAve(pts[0].fY, pts[1].fY));
103 return SkGradientShader::MakeTwoPointConical(center0, (pts[1].fX - pts[0].fX) / 7,
104 center0, (pts[1].fX - pts[0].fX) / 2,
105 data.fColors, data.fPos, data.fCount, tm,
106 0, &localMatrix);
107 }
108
Make2ConicalInsideCenterReversed(const SkPoint pts[2],const GradData & data,SkShader::TileMode tm,const SkMatrix & localMatrix)109 static sk_sp<SkShader> Make2ConicalInsideCenterReversed(const SkPoint pts[2], const GradData& data,
110 SkShader::TileMode tm, const SkMatrix& localMatrix) {
111 SkPoint center0;
112 center0.set(SkScalarAve(pts[0].fX, pts[1].fX),
113 SkScalarAve(pts[0].fY, pts[1].fY));
114 return SkGradientShader::MakeTwoPointConical(center0, (pts[1].fX - pts[0].fX) / 2,
115 center0, (pts[1].fX - pts[0].fX) / 7,
116 data.fColors, data.fPos, data.fCount, tm,
117 0, &localMatrix);
118 }
119
Make2ConicalZeroRad(const SkPoint pts[2],const GradData & data,SkShader::TileMode tm,const SkMatrix & localMatrix)120 static sk_sp<SkShader> Make2ConicalZeroRad(const SkPoint pts[2], const GradData& data,
121 SkShader::TileMode tm, const SkMatrix& localMatrix) {
122 SkPoint center0, center1;
123 center0.set(SkScalarAve(pts[0].fX, pts[1].fX),
124 SkScalarAve(pts[0].fY, pts[1].fY));
125 center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3)/5),
126 SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4));
127 return SkGradientShader::MakeTwoPointConical(center1, 0.f,
128 center0, (pts[1].fX - pts[0].fX) / 2,
129 data.fColors, data.fPos, data.fCount, tm,
130 0, &localMatrix);
131 }
132
Make2ConicalZeroRadFlip(const SkPoint pts[2],const GradData & data,SkShader::TileMode tm,const SkMatrix & localMatrix)133 static sk_sp<SkShader> Make2ConicalZeroRadFlip(const SkPoint pts[2], const GradData& data,
134 SkShader::TileMode tm, const SkMatrix& localMatrix) {
135 SkPoint center0, center1;
136 center0.set(SkScalarAve(pts[0].fX, pts[1].fX),
137 SkScalarAve(pts[0].fY, pts[1].fY));
138 center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3)/5),
139 SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4));
140 return SkGradientShader::MakeTwoPointConical(center1, (pts[1].fX - pts[0].fX) / 2,
141 center0, 0.f,
142 data.fColors, data.fPos, data.fCount, tm,
143 0, &localMatrix);
144 }
145
Make2ConicalZeroRadCenter(const SkPoint pts[2],const GradData & data,SkShader::TileMode tm,const SkMatrix & localMatrix)146 static sk_sp<SkShader> Make2ConicalZeroRadCenter(const SkPoint pts[2], const GradData& data,
147 SkShader::TileMode tm, const SkMatrix& localMatrix) {
148 SkPoint center0, center1;
149 center0.set(SkScalarAve(pts[0].fX, pts[1].fX),
150 SkScalarAve(pts[0].fY, pts[1].fY));
151 center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3)/5),
152 SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4));
153 return SkGradientShader::MakeTwoPointConical(center0, 0.f, center0, (pts[1].fX - pts[0].fX) / 2,
154 data.fColors, data.fPos, data.fCount, tm,
155 0, &localMatrix);
156 }
157
Make2ConicalZeroRadOutside(const SkPoint pts[2],const GradData & data,SkShader::TileMode tm,const SkMatrix & localMatrix)158 static sk_sp<SkShader> Make2ConicalZeroRadOutside(const SkPoint pts[2], const GradData& data,
159 SkShader::TileMode tm,
160 const SkMatrix& localMatrix) {
161 SkPoint center0, center1;
162 SkScalar radius0 = 0.f;
163 SkScalar radius1 = (pts[1].fX - pts[0].fX) / 3;
164 center0.set(pts[0].fX + radius0, pts[0].fY + radius0);
165 center1.set(pts[1].fX - radius1, pts[1].fY - radius1);
166 return SkGradientShader::MakeTwoPointConical(center0, radius0, center1, radius1,
167 data.fColors, data.fPos,
168 data.fCount, tm, 0, &localMatrix);
169 }
170
Make2ConicalZeroRadFlipOutside(const SkPoint pts[2],const GradData & data,SkShader::TileMode tm,const SkMatrix & localMatrix)171 static sk_sp<SkShader> Make2ConicalZeroRadFlipOutside(const SkPoint pts[2], const GradData& data,
172 SkShader::TileMode tm,
173 const SkMatrix& localMatrix) {
174 SkPoint center0, center1;
175 SkScalar radius0 = 0.f;
176 SkScalar radius1 = (pts[1].fX - pts[0].fX) / 3;
177 center0.set(pts[0].fX + radius0, pts[0].fY + radius0);
178 center1.set(pts[1].fX - radius1, pts[1].fY - radius1);
179 return SkGradientShader::MakeTwoPointConical(center1, radius1, center0, radius0, data.fColors,
180 data.fPos, data.fCount, tm, 0, &localMatrix);
181 }
182
Make2ConicalEdgeX(const SkPoint pts[2],const GradData & data,SkShader::TileMode tm,const SkMatrix & localMatrix)183 static sk_sp<SkShader> Make2ConicalEdgeX(const SkPoint pts[2], const GradData& data,
184 SkShader::TileMode tm, const SkMatrix& localMatrix) {
185 SkPoint center0, center1;
186 SkScalar radius0 = (pts[1].fX - pts[0].fX) / 7;
187 SkScalar radius1 = (pts[1].fX - pts[0].fX) / 3;
188 center1.set(SkScalarAve(pts[0].fX, pts[1].fX),
189 SkScalarAve(pts[0].fY, pts[1].fY));
190 center0.set(center1.fX + radius1, center1.fY);
191 return SkGradientShader::MakeTwoPointConical(center0, radius0, center1, radius1, data.fColors,
192 data.fPos, data.fCount, tm, 0, &localMatrix);
193 }
194
Make2ConicalEdgeY(const SkPoint pts[2],const GradData & data,SkShader::TileMode tm,const SkMatrix & localMatrix)195 static sk_sp<SkShader> Make2ConicalEdgeY(const SkPoint pts[2], const GradData& data,
196 SkShader::TileMode tm, const SkMatrix& localMatrix) {
197 SkPoint center0, center1;
198 SkScalar radius0 = (pts[1].fX - pts[0].fX) / 7;
199 SkScalar radius1 = (pts[1].fX - pts[0].fX) / 3;
200 center1.set(SkScalarAve(pts[0].fX, pts[1].fX),
201 SkScalarAve(pts[0].fY, pts[1].fY));
202 center0.set(center1.fX, center1.fY + radius1);
203 return SkGradientShader::MakeTwoPointConical(center0, radius0, center1, radius1, data.fColors,
204 data.fPos, data.fCount, tm, 0, &localMatrix);
205 }
206
Make2ConicalZeroRadEdgeX(const SkPoint pts[2],const GradData & data,SkShader::TileMode tm,const SkMatrix & localMatrix)207 static sk_sp<SkShader> Make2ConicalZeroRadEdgeX(const SkPoint pts[2], const GradData& data,
208 SkShader::TileMode tm,
209 const SkMatrix& localMatrix) {
210 SkPoint center0, center1;
211 SkScalar radius0 = 0.f;
212 SkScalar radius1 = (pts[1].fX - pts[0].fX) / 3;
213 center1.set(SkScalarAve(pts[0].fX, pts[1].fX),
214 SkScalarAve(pts[0].fY, pts[1].fY));
215 center0.set(center1.fX + radius1, center1.fY);
216 return SkGradientShader::MakeTwoPointConical(center0, radius0, center1, radius1, data.fColors,
217 data.fPos, data.fCount, tm, 0, &localMatrix);
218 }
219
Make2ConicalZeroRadEdgeY(const SkPoint pts[2],const GradData & data,SkShader::TileMode tm,const SkMatrix & localMatrix)220 static sk_sp<SkShader> Make2ConicalZeroRadEdgeY(const SkPoint pts[2], const GradData& data,
221 SkShader::TileMode tm, const SkMatrix& localMatrix) {
222 SkPoint center0, center1;
223 SkScalar radius0 = 0.f;
224 SkScalar radius1 = (pts[1].fX - pts[0].fX) / 3;
225 center1.set(SkScalarAve(pts[0].fX, pts[1].fX),
226 SkScalarAve(pts[0].fY, pts[1].fY));
227 center0.set(center1.fX, center1.fY + radius1);
228 return SkGradientShader::MakeTwoPointConical(center0, radius0, center1, radius1, data.fColors,
229 data.fPos, data.fCount, tm, 0, &localMatrix);
230 }
231
Make2ConicalTouchX(const SkPoint pts[2],const GradData & data,SkShader::TileMode tm,const SkMatrix & localMatrix)232 static sk_sp<SkShader> Make2ConicalTouchX(const SkPoint pts[2], const GradData& data,
233 SkShader::TileMode tm, const SkMatrix& localMatrix) {
234 SkPoint center0, center1;
235 SkScalar radius0 = (pts[1].fX - pts[0].fX) / 7;
236 SkScalar radius1 = (pts[1].fX - pts[0].fX) / 3;
237 center1.set(SkScalarAve(pts[0].fX, pts[1].fX),
238 SkScalarAve(pts[0].fY, pts[1].fY));
239 center0.set(center1.fX - radius1 + radius0, center1.fY);
240 return SkGradientShader::MakeTwoPointConical(center0, radius0, center1, radius1, data.fColors,
241 data.fPos, data.fCount, tm, 0, &localMatrix);
242 }
243
Make2ConicalTouchY(const SkPoint pts[2],const GradData & data,SkShader::TileMode tm,const SkMatrix & localMatrix)244 static sk_sp<SkShader> Make2ConicalTouchY(const SkPoint pts[2], const GradData& data,
245 SkShader::TileMode tm, const SkMatrix& localMatrix) {
246 SkPoint center0, center1;
247 SkScalar radius0 = (pts[1].fX - pts[0].fX) / 7;
248 SkScalar radius1 = (pts[1].fX - pts[0].fX) / 3;
249 center1.set(SkScalarAve(pts[0].fX, pts[1].fX),
250 SkScalarAve(pts[0].fY, pts[1].fY));
251 center0.set(center1.fX, center1.fY + radius1 - radius0);
252 return SkGradientShader::MakeTwoPointConical(center0, radius0, center1, radius1, data.fColors,
253 data.fPos, data.fCount, tm, 0, &localMatrix);
254 }
255
Make2ConicalInsideSmallRad(const SkPoint pts[2],const GradData & data,SkShader::TileMode tm,const SkMatrix & localMatrix)256 static sk_sp<SkShader> Make2ConicalInsideSmallRad(const SkPoint pts[2], const GradData& data,
257 SkShader::TileMode tm, const SkMatrix& localMatrix) {
258 SkPoint center0, center1;
259 center0.set(SkScalarAve(pts[0].fX, pts[1].fX),
260 SkScalarAve(pts[0].fY, pts[1].fY));
261 center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3)/5),
262 SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4));
263 return SkGradientShader::MakeTwoPointConical(center0, 0.0000000000000000001f,
264 center0, (pts[1].fX - pts[0].fX) / 2,
265 data.fColors, data.fPos, data.fCount, tm,
266 0, &localMatrix);
267 }
268
269 typedef sk_sp<SkShader> (*GradMaker)(const SkPoint pts[2], const GradData& data,
270 SkShader::TileMode tm, const SkMatrix& localMatrix);
271
272 constexpr GradMaker gGradMakersOutside[] = {
273 Make2ConicalOutside, Make2ConicalOutsideFlip,
274 Make2ConicalZeroRadOutside, Make2ConicalZeroRadFlipOutside,
275 Make2ConicalOutsideStrip
276 };
277
278 constexpr GradMaker gGradMakersInside[] = {
279 Make2ConicalInside, Make2ConicalInsideFlip, Make2ConicalInsideCenter,
280 Make2ConicalZeroRad, Make2ConicalZeroRadFlip, Make2ConicalZeroRadCenter,
281 Make2ConicalInsideCenterReversed
282 };
283
284 constexpr GradMaker gGradMakersEdgeCases[] = {
285 Make2ConicalEdgeX, Make2ConicalEdgeY,
286 Make2ConicalZeroRadEdgeX, Make2ConicalZeroRadEdgeY,
287 Make2ConicalTouchX, Make2ConicalTouchY,
288 Make2ConicalInsideSmallRad
289 };
290
291
292 constexpr struct {
293 const GradMaker* fMaker;
294 const int fCount;
295 const char* fName;
296 } gGradCases[] = {
297 { gGradMakersOutside, SK_ARRAY_COUNT(gGradMakersOutside), "outside" },
298 { gGradMakersInside, SK_ARRAY_COUNT(gGradMakersInside), "inside" },
299 { gGradMakersEdgeCases, SK_ARRAY_COUNT(gGradMakersEdgeCases), "edge" },
300 };
301
302 enum GradCaseType { // these must match the order in gGradCases
303 kOutside_GradCaseType,
304 kInside_GradCaseType,
305 kEdge_GradCaseType,
306 };
307
308 ///////////////////////////////////////////////////////////////////////////////
309
310 class ConicalGradientsGM : public GM {
311 public:
ConicalGradientsGM(GradCaseType gradCaseType,bool dither,SkShader::TileMode mode=SkShader::kClamp_TileMode)312 ConicalGradientsGM(GradCaseType gradCaseType, bool dither,
313 SkShader::TileMode mode = SkShader::kClamp_TileMode)
314 : fGradCaseType(gradCaseType)
315 , fDither(dither)
316 , fMode(mode) {
317 this->setBGColor(0xFFDDDDDD);
318 fName.printf("gradients_2pt_conical_%s%s", gGradCases[gradCaseType].fName,
319 fDither ? "" : "_nodither");
320 switch (mode) {
321 case SkShader::kRepeat_TileMode:
322 fName.appendf("_repeat");
323 break;
324 case SkShader::kMirror_TileMode:
325 fName.appendf("_mirror");
326 break;
327 default:
328 break;
329 }
330 }
331
332 protected:
onShortName()333 SkString onShortName() {
334 return fName;
335 }
336
onISize()337 virtual SkISize onISize() { return SkISize::Make(840, 815); }
338
onDraw(SkCanvas * canvas)339 virtual void onDraw(SkCanvas* canvas) {
340
341 SkPoint pts[2] = {
342 { 0, 0 },
343 { SkIntToScalar(100), SkIntToScalar(100) }
344 };
345 SkRect r = { 0, 0, SkIntToScalar(100), SkIntToScalar(100) };
346 SkPaint paint;
347 paint.setAntiAlias(true);
348 paint.setDither(fDither);
349
350 canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
351
352 const GradMaker* gradMaker = gGradCases[fGradCaseType].fMaker;
353 const int count = gGradCases[fGradCaseType].fCount;
354
355 for (size_t i = 0; i < SK_ARRAY_COUNT(gGradData); i++) {
356 canvas->save();
357 for (int j = 0; j < count; j++) {
358 SkMatrix scale = SkMatrix::I();
359
360 if (i == 3) { // if the clamp case
361 scale.setScale(0.5f, 0.5f);
362 scale.postTranslate(25.f, 25.f);
363 }
364
365 paint.setShader(gradMaker[j](pts, gGradData[i], fMode, scale));
366 canvas->drawRect(r, paint);
367 canvas->translate(0, SkIntToScalar(120));
368 }
369 canvas->restore();
370 canvas->translate(SkIntToScalar(120), 0);
371 }
372 }
373
374 private:
375 typedef GM INHERITED;
376
377 GradCaseType fGradCaseType;
378 SkString fName;
379 bool fDither;
380 SkShader::TileMode fMode;
381 };
382 ///////////////////////////////////////////////////////////////////////////////
383
384 DEF_GM( return new ConicalGradientsGM(kInside_GradCaseType, true); )
385 DEF_GM( return new ConicalGradientsGM(kOutside_GradCaseType, true); )
386 DEF_GM( return new ConicalGradientsGM(kEdge_GradCaseType, true); )
387
388 DEF_GM( return new ConicalGradientsGM(kInside_GradCaseType, true, SkShader::kRepeat_TileMode); )
389 DEF_GM( return new ConicalGradientsGM(kOutside_GradCaseType, true, SkShader::kRepeat_TileMode); )
390 DEF_GM( return new ConicalGradientsGM(kEdge_GradCaseType, true, SkShader::kRepeat_TileMode); )
391
392 DEF_GM( return new ConicalGradientsGM(kInside_GradCaseType, true, SkShader::kMirror_TileMode); )
393 DEF_GM( return new ConicalGradientsGM(kOutside_GradCaseType, true, SkShader::kMirror_TileMode); )
394 DEF_GM( return new ConicalGradientsGM(kEdge_GradCaseType, true, SkShader::kMirror_TileMode); )
395
396 DEF_GM( return new ConicalGradientsGM(kInside_GradCaseType, false); )
397 DEF_GM( return new ConicalGradientsGM(kOutside_GradCaseType, false); )
398 DEF_GM( return new ConicalGradientsGM(kEdge_GradCaseType, false); )
399
400 }
401