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