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