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