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