2 * Copyright 2014 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
9 #include "sk_tool_utils.h"
10 #include "SkGradientShader.h"
16 const SkColor* fColors;
20 constexpr SkColor gColors[] = {
21 SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE, SK_ColorBLACK
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
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
34 constexpr GradData gGradData[] = {
35 { 2, gColors, gPos0 },
36 { 2, gColors, gPos1 },
37 { 5, gColors, gPos2 },
38 { 4, gColorClamp, gPosClamp }
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);
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);
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,
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,
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,
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,
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,
124 data.fColors, data.fPos, data.fCount, tm,
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,
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);
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);
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);
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);
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);
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);
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);
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);
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,
251 typedef sk_sp<SkShader> (*GradMaker)(const SkPoint pts[2], const GradData& data,
252 SkShader::TileMode tm, const SkMatrix& localMatrix);
254 constexpr GradMaker gGradMakersOutside[] = {
255 Make2ConicalOutside, Make2ConicalOutsideFlip,
256 Make2ConicalZeroRadOutside, Make2ConicalZeroRadFlipOutside
259 constexpr GradMaker gGradMakersInside[] = {
260 Make2ConicalInside, Make2ConicalInsideFlip, Make2ConicalInsideCenter,
261 Make2ConicalZeroRad, Make2ConicalZeroRadFlip, Make2ConicalZeroRadCenter,
264 constexpr GradMaker gGradMakersEdgeCases[] = {
265 Make2ConicalEdgeX, Make2ConicalEdgeY,
266 Make2ConicalZeroRadEdgeX, Make2ConicalZeroRadEdgeY,
267 Make2ConicalTouchX, Make2ConicalTouchY,
268 Make2ConicalInsideSmallRad
273 const GradMaker* fMaker;
277 { gGradMakersOutside, SK_ARRAY_COUNT(gGradMakersOutside), "outside" },
278 { gGradMakersInside, SK_ARRAY_COUNT(gGradMakersInside), "inside" },
279 { gGradMakersEdgeCases, SK_ARRAY_COUNT(gGradMakersEdgeCases), "edge" },
282 enum GradCaseType { // these must match the order in gGradCases
283 kOutside_GradCaseType,
284 kInside_GradCaseType,
288 ///////////////////////////////////////////////////////////////////////////////
290 class ConicalGradientsGM : public GM {
292 ConicalGradientsGM(GradCaseType gradCaseType, bool dither)
293 : fGradCaseType(gradCaseType)
295 this->setBGColor(sk_tool_utils::color_to_565(0xFFDDDDDD));
296 fName.printf("gradients_2pt_conical_%s%s", gGradCases[gradCaseType].fName,
297 fDither ? "" : "_nodither");
301 SkString onShortName() {
305 virtual SkISize onISize() { return SkISize::Make(840, 815); }
307 virtual void onDraw(SkCanvas* canvas) {
311 { SkIntToScalar(100), SkIntToScalar(100) }
313 SkShader::TileMode tm = SkShader::kClamp_TileMode;
314 SkRect r = { 0, 0, SkIntToScalar(100), SkIntToScalar(100) };
316 paint.setAntiAlias(true);
317 paint.setDither(fDither);
319 canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
321 const GradMaker* gradMaker = gGradCases[fGradCaseType].fMaker;
322 const int count = gGradCases[fGradCaseType].fCount;
324 for (size_t i = 0; i < SK_ARRAY_COUNT(gGradData); i++) {
326 for (int j = 0; j < count; j++) {
327 SkMatrix scale = SkMatrix::I();
329 if (i == 3) { // if the clamp case
330 scale.setScale(0.5f, 0.5f);
331 scale.postTranslate(25.f, 25.f);
334 paint.setShader(gradMaker[j](pts, gGradData[i], tm, scale));
335 canvas->drawRect(r, paint);
336 canvas->translate(0, SkIntToScalar(120));
339 canvas->translate(SkIntToScalar(120), 0);
344 typedef GM INHERITED;
346 GradCaseType fGradCaseType;
350 ///////////////////////////////////////////////////////////////////////////////
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); )
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); )