2 * Copyright 2013 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
8 #include "sk_tool_utils.h"
9 #include "SkGradientShader.h"
11 using namespace skiagm;
15 const SkColor* fColors;
19 constexpr SkColor gColors[] = {
20 SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE,
23 constexpr GradData gGradData[] = {
24 { 1, gColors, nullptr },
25 { 2, gColors, nullptr },
26 { 3, gColors, nullptr },
27 { 4, gColors, nullptr },
30 static sk_sp<SkShader> MakeLinear(const SkPoint pts[2], const GradData& data, SkShader::TileMode tm) {
31 return SkGradientShader::MakeLinear(pts, data.fColors, data.fPos, data.fCount, tm);
34 static sk_sp<SkShader> MakeRadial(const SkPoint pts[2], const GradData& data, SkShader::TileMode tm) {
36 center.set(SkScalarAve(pts[0].fX, pts[1].fX),
37 SkScalarAve(pts[0].fY, pts[1].fY));
38 return SkGradientShader::MakeRadial(center, center.fX, data.fColors, data.fPos, data.fCount, tm);
41 static sk_sp<SkShader> MakeSweep(const SkPoint pts[2], const GradData& data, SkShader::TileMode) {
43 center.set(SkScalarAve(pts[0].fX, pts[1].fX),
44 SkScalarAve(pts[0].fY, pts[1].fY));
45 return SkGradientShader::MakeSweep(center.fX, center.fY, data.fColors, data.fPos, data.fCount);
48 static sk_sp<SkShader> Make2Radial(const SkPoint pts[2], const GradData& data, SkShader::TileMode tm) {
49 SkPoint center0, center1;
50 center0.set(SkScalarAve(pts[0].fX, pts[1].fX),
51 SkScalarAve(pts[0].fY, pts[1].fY));
52 center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3)/5),
53 SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4));
54 return SkGradientShader::MakeTwoPointConical(
55 center1, (pts[1].fX - pts[0].fX) / 7,
56 center0, (pts[1].fX - pts[0].fX) / 2,
57 data.fColors, data.fPos, data.fCount, tm);
60 static sk_sp<SkShader> Make2Conical(const SkPoint pts[2], const GradData& data, SkShader::TileMode tm) {
61 SkPoint center0, center1;
62 SkScalar radius0 = (pts[1].fX - pts[0].fX) / 10;
63 SkScalar radius1 = (pts[1].fX - pts[0].fX) / 3;
64 center0.set(pts[0].fX + radius0, pts[0].fY + radius0);
65 center1.set(pts[1].fX - radius1, pts[1].fY - radius1);
66 return SkGradientShader::MakeTwoPointConical(center1, radius1,
68 data.fColors, data.fPos,
73 typedef sk_sp<SkShader> (*GradMaker)(const SkPoint pts[2], const GradData& data, SkShader::TileMode tm);
75 constexpr GradMaker gGradMakers[] = {
76 MakeLinear, MakeRadial, MakeSweep, Make2Radial, Make2Conical,
79 ///////////////////////////////////////////////////////////////////////////////
81 class GradientsNoTextureGM : public GM {
83 GradientsNoTextureGM(bool dither) : fDither(dither) {
84 this->setBGColor(sk_tool_utils::color_to_565(0xFFDDDDDD));
89 SkString onShortName() override {
90 return SkString(fDither ? "gradients_no_texture" : "gradients_no_texture_nodither");
93 SkISize onISize() override { return SkISize::Make(640, 615); }
95 void onDraw(SkCanvas* canvas) override {
96 constexpr SkPoint kPts[2] = { { 0, 0 },
97 { SkIntToScalar(50), SkIntToScalar(50) } };
98 constexpr SkShader::TileMode kTM = SkShader::kClamp_TileMode;
99 SkRect kRect = { 0, 0, SkIntToScalar(50), SkIntToScalar(50) };
101 paint.setAntiAlias(true);
102 paint.setDither(fDither);
104 canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
105 constexpr uint8_t kAlphas[] = { 0xff, 0x40 };
106 for (size_t a = 0; a < SK_ARRAY_COUNT(kAlphas); ++a) {
107 for (size_t i = 0; i < SK_ARRAY_COUNT(gGradData); ++i) {
109 for (size_t j = 0; j < SK_ARRAY_COUNT(gGradMakers); ++j) {
110 paint.setShader(gGradMakers[j](kPts, gGradData[i], kTM));
111 paint.setAlpha(kAlphas[a]);
112 canvas->drawRect(kRect, paint);
113 canvas->translate(0, SkIntToScalar(kRect.height() + 20));
116 canvas->translate(SkIntToScalar(kRect.width() + 20), 0);
124 typedef GM INHERITED;
127 ///////////////////////////////////////////////////////////////////////////////
134 ColorPos() : fColors(nullptr), fPos(nullptr), fCount(0) {}
140 void construct(const SkColor colors[], const SkScalar pos[], int count) {
141 fColors = new SkColor[count];
142 memcpy(fColors, colors, count * sizeof(SkColor));
144 fPos = new SkScalar[count];
145 memcpy(fPos, pos, count * sizeof(SkScalar));
153 static void make0(ColorPos* rec) {
155 From http://jsfiddle.net/3fe2a/
157 background-image: -webkit-linear-gradient(left, #22d1cd 1%, #22d1cd 0.9510157507590116%, #df4b37 2.9510157507590113%, #df4b37 23.695886056604927%, #22d1cd 25.695886056604927%, #22d1cd 25.39321881940624%, #e6de36 27.39321881940624%, #e6de36 31.849399922570655%, #3267ff 33.849399922570655%, #3267ff 44.57735802921938%, #9d47d1 46.57735802921938%, #9d47d1 53.27185850805876%, #3267ff 55.27185850805876%, #3267ff 61.95718972227316%, #5cdd9d 63.95718972227316%, #5cdd9d 69.89166004442%, #3267ff 71.89166004442%, #3267ff 74.45795382765857%, #9d47d1 76.45795382765857%, #9d47d1 82.78364610713776%, #3267ff 84.78364610713776%, #3267ff 94.52743647737229%, #e3d082 96.52743647737229%, #e3d082 96.03934633331295%);
161 const SkColor colors[] = {
162 0xFF22d1cd, 0xFF22d1cd, 0xFFdf4b37, 0xFFdf4b37, 0xFF22d1cd, 0xFF22d1cd, 0xFFe6de36, 0xFFe6de36,
163 0xFF3267ff, 0xFF3267ff, 0xFF9d47d1, 0xFF9d47d1, 0xFF3267ff, 0xFF3267ff, 0xFF5cdd9d, 0xFF5cdd9d,
164 0xFF3267ff, 0xFF3267ff, 0xFF9d47d1, 0xFF9d47d1, 0xFF3267ff, 0xFF3267ff, 0xFFe3d082, 0xFFe3d082
166 const double percent[] = {
167 1, 0.9510157507590116, 2.9510157507590113, 23.695886056604927,
168 25.695886056604927, 25.39321881940624, 27.39321881940624, 31.849399922570655,
169 33.849399922570655, 44.57735802921938, 46.57735802921938, 53.27185850805876,
170 55.27185850805876, 61.95718972227316, 63.95718972227316, 69.89166004442,
171 71.89166004442, 74.45795382765857, 76.45795382765857, 82.78364610713776,
172 84.78364610713776, 94.52743647737229, 96.52743647737229, 96.03934633331295,
174 const int N = SK_ARRAY_COUNT(percent);
176 for (int i = 0; i < N; ++i) {
177 pos[i] = SkDoubleToScalar(percent[i] / 100);
179 rec->construct(colors, pos, N);
182 static void make1(ColorPos* rec) {
183 const SkColor colors[] = {
184 SK_ColorBLACK, SK_ColorWHITE, SK_ColorBLACK, SK_ColorWHITE,
185 SK_ColorBLACK, SK_ColorWHITE, SK_ColorBLACK, SK_ColorWHITE,
188 rec->construct(colors, nullptr, SK_ARRAY_COUNT(colors));
191 static void make2(ColorPos* rec) {
192 const SkColor colors[] = {
193 SK_ColorBLACK, SK_ColorWHITE, SK_ColorBLACK, SK_ColorWHITE,
194 SK_ColorBLACK, SK_ColorWHITE, SK_ColorBLACK, SK_ColorWHITE,
197 const int N = SK_ARRAY_COUNT(colors);
199 for (int i = 0; i < N; ++i) {
200 pos[i] = SK_Scalar1 * i / (N - 1);
202 rec->construct(colors, pos, N);
205 static void make3(ColorPos* rec) {
206 const SkColor colors[] = {
207 SK_ColorRED, SK_ColorBLUE, SK_ColorBLUE, SK_ColorGREEN, SK_ColorGREEN, SK_ColorBLACK,
209 const SkScalar pos[] = {
210 0, 0, 0.5f, 0.5, 1, 1,
212 rec->construct(colors, pos, SK_ARRAY_COUNT(colors));
215 class GradientsManyColorsGM : public GM {
219 sk_sp<SkShader> fShader;
221 typedef void (*Proc)(ColorPos*);
223 GradientsManyColorsGM(bool dither) : fDither(dither) {}
227 SkString onShortName() override {
228 return SkString(fDither ? "gradients_many" : "gradients_many_nodither");
231 SkISize onISize() override { return SkISize::Make(880, 400); }
233 void onDraw(SkCanvas* canvas) override {
234 const Proc procs[] = {
235 make0, make1, make2, make3,
237 const SkPoint pts[] = {
239 { SkIntToScalar(W), 0 },
241 const SkRect r = SkRect::MakeWH(SkIntToScalar(W), 30);
244 paint.setDither(fDither);
246 canvas->translate(40, 20);
248 for (int i = 0; i <= 8; ++i) {
249 SkScalar x = r.width() * i / 8;
250 canvas->drawLine(x, 0, x, 10000, paint);
253 // expand the drawing rect so we exercise clampping in the gradients
254 const SkRect drawR = r.makeOutset(20, 0);
255 for (size_t i = 0; i < SK_ARRAY_COUNT(procs); ++i) {
258 paint.setShader(SkGradientShader::MakeLinear(pts, rec.fColors, rec.fPos, rec.fCount,
259 SkShader::kClamp_TileMode));
260 canvas->drawRect(drawR, paint);
263 canvas->translate(r.centerX(), r.height() + 4);
264 canvas->scale(-1, 1);
265 canvas->translate(-r.centerX(), 0);
266 canvas->drawRect(drawR, paint);
269 canvas->translate(0, r.height() + 2*r.height() + 8);
276 typedef GM INHERITED;
279 ///////////////////////////////////////////////////////////////////////////////
281 DEF_GM(return new GradientsNoTextureGM(true);)
282 DEF_GM(return new GradientsNoTextureGM(false);)
283 DEF_GM(return new GradientsManyColorsGM(true);)
284 DEF_GM(return new GradientsManyColorsGM(false);)