blob: ad745df8c123912ab8e808a6eccd00377ef1dfd2 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
2/*
3 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
reed@android.com42309d42009-06-22 02:06:35 +00008#include "gm.h"
9#include "SkGradientShader.h"
10
11namespace skiagm {
12
13struct GradData {
14 int fCount;
15 const SkColor* fColors;
16 const SkScalar* fPos;
17};
18
19static const SkColor gColors[] = {
20 SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE, SK_ColorBLACK
21};
22static const SkScalar gPos0[] = { 0, SK_Scalar1 };
23static const SkScalar gPos1[] = { SK_Scalar1/4, SK_Scalar1*3/4 };
24static const SkScalar gPos2[] = {
25 0, SK_Scalar1/8, SK_Scalar1/2, SK_Scalar1*7/8, SK_Scalar1
26};
27
28static const GradData gGradData[] = {
29 { 2, gColors, NULL },
30 { 2, gColors, gPos0 },
31 { 2, gColors, gPos1 },
32 { 5, gColors, NULL },
33 { 5, gColors, gPos2 }
34};
35
36static SkShader* MakeLinear(const SkPoint pts[2], const GradData& data,
37 SkShader::TileMode tm, SkUnitMapper* mapper) {
38 return SkGradientShader::CreateLinear(pts, data.fColors, data.fPos,
39 data.fCount, tm, mapper);
40}
reed@google.comf3c1cc92010-12-23 16:45:33 +000041
reed@android.com42309d42009-06-22 02:06:35 +000042static SkShader* MakeRadial(const SkPoint pts[2], const GradData& data,
43 SkShader::TileMode tm, SkUnitMapper* mapper) {
44 SkPoint center;
45 center.set(SkScalarAve(pts[0].fX, pts[1].fX),
46 SkScalarAve(pts[0].fY, pts[1].fY));
47 return SkGradientShader::CreateRadial(center, center.fX, data.fColors,
48 data.fPos, data.fCount, tm, mapper);
49}
50
51static SkShader* MakeSweep(const SkPoint pts[2], const GradData& data,
52 SkShader::TileMode tm, SkUnitMapper* mapper) {
53 SkPoint center;
54 center.set(SkScalarAve(pts[0].fX, pts[1].fX),
55 SkScalarAve(pts[0].fY, pts[1].fY));
56 return SkGradientShader::CreateSweep(center.fX, center.fY, data.fColors,
57 data.fPos, data.fCount, mapper);
58}
59
reed@google.comf3c1cc92010-12-23 16:45:33 +000060static SkShader* Make2Radial(const SkPoint pts[2], const GradData& data,
61 SkShader::TileMode tm, SkUnitMapper* mapper) {
62 SkPoint center0, center1;
63 center0.set(SkScalarAve(pts[0].fX, pts[1].fX),
64 SkScalarAve(pts[0].fY, pts[1].fY));
65 center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3)/5),
66 SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4));
67 return SkGradientShader::CreateTwoPointRadial(
68 center1, (pts[1].fX - pts[0].fX) / 7,
69 center0, (pts[1].fX - pts[0].fX) / 2,
70 data.fColors, data.fPos, data.fCount, tm, mapper);
71}
72
reed@android.com42309d42009-06-22 02:06:35 +000073typedef SkShader* (*GradMaker)(const SkPoint pts[2], const GradData& data,
reed@google.comf3c1cc92010-12-23 16:45:33 +000074 SkShader::TileMode tm, SkUnitMapper* mapper);
reed@android.com42309d42009-06-22 02:06:35 +000075static const GradMaker gGradMakers[] = {
reed@google.comf3c1cc92010-12-23 16:45:33 +000076 MakeLinear, MakeRadial, MakeSweep, Make2Radial
reed@android.com42309d42009-06-22 02:06:35 +000077};
78
79///////////////////////////////////////////////////////////////////////////////
80
81class GradientsGM : public GM {
82public:
bsalomon@google.com48dd1a22011-10-31 14:18:20 +000083 GradientsGM() {
84 this->setBGColor(0xFFDDDDDD);
85 }
reed@android.com42309d42009-06-22 02:06:35 +000086
87protected:
88 SkString onShortName() {
89 return SkString("gradients");
90 }
91
reed@google.comac864a92011-06-27 18:11:17 +000092 virtual SkISize onISize() { return make_isize(640, 510); }
bsalomon@google.com48dd1a22011-10-31 14:18:20 +000093
reed@android.com42309d42009-06-22 02:06:35 +000094 virtual void onDraw(SkCanvas* canvas) {
reed@android.com42309d42009-06-22 02:06:35 +000095
96 SkPoint pts[2] = {
97 { 0, 0 },
98 { SkIntToScalar(100), SkIntToScalar(100) }
99 };
100 SkShader::TileMode tm = SkShader::kClamp_TileMode;
101 SkRect r = { 0, 0, SkIntToScalar(100), SkIntToScalar(100) };
102 SkPaint paint;
103 paint.setAntiAlias(true);
104
105 canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
106 for (size_t i = 0; i < SK_ARRAY_COUNT(gGradData); i++) {
107 canvas->save();
108 for (size_t j = 0; j < SK_ARRAY_COUNT(gGradMakers); j++) {
109 SkShader* shader = gGradMakers[j](pts, gGradData[i], tm, NULL);
110 paint.setShader(shader);
111 canvas->drawRect(r, paint);
112 shader->unref();
113 canvas->translate(0, SkIntToScalar(120));
114 }
115 canvas->restore();
116 canvas->translate(SkIntToScalar(120), 0);
117 }
118 }
119
120private:
121 typedef GM INHERITED;
122};
123
reed@google.comac864a92011-06-27 18:11:17 +0000124/*
125 Inspired by this <canvas> javascript, where we need to detect that we are not
126 solving a quadratic equation, but must instead solve a linear (since our X^2
127 coefficient is 0)
128
129 ctx.fillStyle = '#f00';
130 ctx.fillRect(0, 0, 100, 50);
131
132 var g = ctx.createRadialGradient(-80, 25, 70, 0, 25, 150);
133 g.addColorStop(0, '#f00');
134 g.addColorStop(0.01, '#0f0');
135 g.addColorStop(0.99, '#0f0');
136 g.addColorStop(1, '#f00');
137 ctx.fillStyle = g;
138 ctx.fillRect(0, 0, 100, 50);
139 */
140class GradientsDegenrate2PointGM : public GM {
141public:
142 GradientsDegenrate2PointGM() {}
143
144protected:
145 SkString onShortName() {
146 return SkString("gradients_degenerate_2pt");
147 }
148
149 virtual SkISize onISize() { return make_isize(320, 320); }
150
151 void drawBG(SkCanvas* canvas) {
152 canvas->drawColor(SK_ColorBLUE);
153 }
154
155 virtual void onDraw(SkCanvas* canvas) {
156 this->drawBG(canvas);
157
158 SkColor colors[] = { SK_ColorRED, SK_ColorGREEN, SK_ColorGREEN, SK_ColorRED };
159 SkScalar pos[] = { 0, SkFloatToScalar(0.01f), SkFloatToScalar(0.99f), SK_Scalar1 };
epoger@google.com59f3abf2011-07-21 15:50:33 +0000160 SkPoint c0;
161 c0.iset(-80, 25);
162 SkScalar r0 = SkIntToScalar(70);
163 SkPoint c1;
164 c1.iset(0, 25);
165 SkScalar r1 = SkIntToScalar(150);
reed@google.comac864a92011-06-27 18:11:17 +0000166 SkShader* s = SkGradientShader::CreateTwoPointRadial(c0, r0, c1, r1, colors,
167 pos, SK_ARRAY_COUNT(pos),
168 SkShader::kClamp_TileMode);
169 SkPaint paint;
170 paint.setShader(s)->unref();
171 canvas->drawPaint(paint);
172 }
173
174private:
175 typedef GM INHERITED;
176};
177
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000178/// Tests correctness of *optimized* codepaths in gradients.
179
180class ClampedGradientsGM : public GM {
181public:
182 ClampedGradientsGM() {}
183
184protected:
185 SkString onShortName() { return SkString("clamped_gradients"); }
186
187 virtual SkISize onISize() { return make_isize(640, 510); }
188
189 void drawBG(SkCanvas* canvas) {
190 canvas->drawColor(0xFFDDDDDD);
191 }
192
193 virtual void onDraw(SkCanvas* canvas) {
194 this->drawBG(canvas);
195
196 SkRect r = { 0, 0, SkIntToScalar(100), SkIntToScalar(300) };
197 SkPaint paint;
198 paint.setAntiAlias(true);
199
200 SkPoint center;
201 center.iset(0, 300);
202 canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
203 SkShader* shader = SkGradientShader::CreateRadial(
204 SkPoint(center),
bungeman@google.com01744a42011-10-06 19:37:39 +0000205 SkIntToScalar(200), gColors, NULL, 5,
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000206 SkShader::kClamp_TileMode, NULL);
207 paint.setShader(shader);
208 canvas->drawRect(r, paint);
209 shader->unref();
210 }
211
212private:
213 typedef GM INHERITED;
214};
215
tomhudson@google.comb18e58c2012-01-30 20:00:13 +0000216/// Checks quality of large radial gradients, which may display
217/// some banding.
218
219class RadialGradientGM : public GM {
220public:
221 RadialGradientGM() {}
222
223protected:
224 SkString onShortName() { return SkString("radial_gradient"); }
reed@google.combb0948f2012-01-31 14:44:13 +0000225 virtual SkISize onISize() { return make_isize(1280, 1280); }
tomhudson@google.comb18e58c2012-01-30 20:00:13 +0000226 void drawBG(SkCanvas* canvas) {
227 canvas->drawColor(0xFF000000);
228 }
229 virtual void onDraw(SkCanvas* canvas) {
reed@google.combb0948f2012-01-31 14:44:13 +0000230 const SkISize dim = this->getISize();
231
tomhudson@google.comb18e58c2012-01-30 20:00:13 +0000232 this->drawBG(canvas);
233
234 SkPaint paint;
235 paint.setDither(true);
236 SkPoint center;
reed@google.combb0948f2012-01-31 14:44:13 +0000237 center.set(SkIntToScalar(dim.width())/2, SkIntToScalar(dim.height())/2);
238 SkScalar radius = SkIntToScalar(dim.width())/2;
239 const SkColor colors[] = { 0x7f7f7f7f, 0x7f7f7f7f, 0xb2000000 };
robertphillips@google.com09042b82012-04-06 20:01:46 +0000240 const SkScalar pos[] = { SkFloatToScalar(0.0f),
241 SkFloatToScalar(0.35f),
242 SkFloatToScalar(1.0f) };
tomhudson@google.comb18e58c2012-01-30 20:00:13 +0000243 SkShader* shader =
244 SkGradientShader::CreateRadial(center, radius, colors,
reed@google.combb0948f2012-01-31 14:44:13 +0000245 pos, SK_ARRAY_COUNT(pos),
246 SkShader::kClamp_TileMode);
tomhudson@google.comb18e58c2012-01-30 20:00:13 +0000247 paint.setShader(shader)->unref();
reed@google.combb0948f2012-01-31 14:44:13 +0000248 SkRect r = {
249 0, 0, SkIntToScalar(dim.width()), SkIntToScalar(dim.height())
250 };
tomhudson@google.comb18e58c2012-01-30 20:00:13 +0000251 canvas->drawRect(r, paint);
252 }
253private:
254 typedef GM INHERITED;
255};
256
257
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000258
reed@android.com42309d42009-06-22 02:06:35 +0000259///////////////////////////////////////////////////////////////////////////////
260
261static GM* MyFactory(void*) { return new GradientsGM; }
262static GMRegistry reg(MyFactory);
263
reed@google.comac864a92011-06-27 18:11:17 +0000264static GM* MyFactory2(void*) { return new GradientsDegenrate2PointGM; }
265static GMRegistry reg2(MyFactory2);
266
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000267static GM* MyFactory3(void*) { return new ClampedGradientsGM; }
268static GMRegistry reg3(MyFactory3);
269
tomhudson@google.comb18e58c2012-01-30 20:00:13 +0000270static GM* MyFactory4(void*) { return new RadialGradientGM; }
271static GMRegistry reg4(MyFactory4);
reed@android.com42309d42009-06-22 02:06:35 +0000272}
273