add helper makeShader for the common Clamp case
[platform/upstream/libSkiaSharp.git] / gm / gradients_2pt_conical.cpp
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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:
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:
301     SkString onShortName() {
302         return fName;
303     }
304
305     virtual SkISize onISize() { return SkISize::Make(840, 815); }
306
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 }