1 /*
2 * Copyright 2016 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 "Fuzz.h"
9 #include "SkCanvas.h"
10 #include "SkCommonFlags.h"
11 #include "SkGradientShader.h"
12 #include "SkSurface.h"
13 #include "SkTLazy.h"
14
15 #include <algorithm>
16 #include <vector>
17
18 const int MAX_COUNT = 400;
19
makeMatrix(Fuzz * fuzz,SkMatrix * m)20 void makeMatrix(Fuzz* fuzz, SkMatrix* m) {
21 SkScalar mat[9];
22 fuzz->nextN(mat, 9);
23 m->set9(mat);
24 }
25
initGradientParams(Fuzz * fuzz,std::vector<SkColor> * colors,std::vector<SkScalar> * pos,SkShader::TileMode * mode)26 void initGradientParams(Fuzz* fuzz, std::vector<SkColor>* colors,
27 std::vector<SkScalar>* pos, SkShader::TileMode* mode) {
28 int count;
29 fuzz->nextRange(&count, 0, MAX_COUNT);
30
31 // Use a uint8_t to conserve bytes. This makes our "fuzzed bytes footprint"
32 // smaller, which leads to more efficient fuzzing.
33 uint8_t m;
34 fuzz->nextRange(&m, 0, 2);
35 *mode = static_cast<SkShader::TileMode>(m);
36
37 colors->clear();
38 pos ->clear();
39 for (int i = 0; i < count; i++) {
40 SkColor c;
41 SkScalar s;
42 fuzz->next(&c, &s);
43 colors->push_back(c);
44 pos ->push_back(s);
45 }
46 if (count) {
47 std::sort(pos->begin(), pos->end());
48 // The order matters. If count == 1, we want pos == 0.
49 (*pos)[count - 1] = 1;
50 (*pos)[0] = 0;
51 }
52 }
53
logOptionalMatrix(const char * label,const SkMatrix * m)54 static void logOptionalMatrix(const char* label, const SkMatrix* m) {
55 if (!m) {
56 return;
57 }
58
59 SkDEBUGF(" %s: [ ", label);
60 for (int i = 0; i < 9; ++i) {
61 SkDEBUGF("%.9g ", m->get(i));
62 }
63 SkDEBUGF("]\n");
64 }
65
logLinearGradient(const SkPoint pts[2],const std::vector<SkColor> & colors,const std::vector<SkScalar> pos,SkShader::TileMode mode,uint32_t flags,const SkMatrix * localMatrix,const SkMatrix * globalMatrix)66 static void logLinearGradient(const SkPoint pts[2],
67 const std::vector<SkColor>& colors,
68 const std::vector<SkScalar> pos,
69 SkShader::TileMode mode,
70 uint32_t flags,
71 const SkMatrix* localMatrix,
72 const SkMatrix* globalMatrix) {
73 if (!FLAGS_verbose) {
74 return;
75 }
76
77 SkDebugf("--- fuzzLinearGradient ---\n");
78 SkDebugf(" pts:\t\t[ (%.9g %.9g) (%.9g %.9g) ]\n",
79 pts[0].x(), pts[0].y(), pts[1].x(), pts[1].y());
80 SkDebugf(" colors:\t[ ");
81 for (auto color : colors) {
82 SkDebugf("0x%x ", color);
83 }
84
85 SkDebugf("]\n pos:\t\t");
86 if (pos.empty()) {
87 SkDebugf("nullptr");
88 } else {
89 SkDebugf("[ ");
90 for (auto p : pos) {
91 SkDebugf("%f ", p);
92 }
93 }
94 SkDebugf("]\n");
95
96 static const char* gModeName[] = {
97 "kClamp_TileMode", "kRepeat_TileMode", "kMirror_TileMode"
98 };
99 SkASSERT(mode < SK_ARRAY_COUNT(gModeName));
100 SkDebugf(" mode:\t\t%s\n", gModeName[mode]);
101 SkDebugf(" flags:\t0x%x\n", flags);
102 logOptionalMatrix("local matrix", localMatrix);
103 logOptionalMatrix("global matrix", globalMatrix);
104 }
105
fuzzLinearGradient(Fuzz * fuzz)106 void fuzzLinearGradient(Fuzz* fuzz) {
107 SkPoint pts[2];
108 fuzz->next(&pts[0].fX, &pts[0].fY, &pts[1].fX, &pts[1].fY);
109 bool useLocalMatrix, useGlobalMatrix;
110 fuzz->next(&useLocalMatrix, &useGlobalMatrix);
111
112 std::vector<SkColor> colors;
113 std::vector<SkScalar> pos;
114 SkShader::TileMode mode;
115 initGradientParams(fuzz, &colors, &pos, &mode);
116
117 SkPaint p;
118 uint32_t flags;
119 fuzz->next(&flags);
120
121 SkTLazy<SkMatrix> localMatrix;
122 if (useLocalMatrix) {
123 makeMatrix(fuzz, localMatrix.init());
124 }
125 p.setShader(SkGradientShader::MakeLinear(pts, colors.data(), pos.data(),
126 colors.size(), mode, flags, localMatrix.getMaybeNull()));
127
128 sk_sp<SkSurface> surface(SkSurface::MakeRasterN32Premul(50, 50));
129 if (useGlobalMatrix) {
130 SkMatrix gm;
131 makeMatrix(fuzz, &gm);
132 logLinearGradient(pts, colors, pos, mode, flags, localMatrix.getMaybeNull(), &gm);
133 SkCanvas* c = surface->getCanvas();
134 c->setMatrix(gm);
135 c->drawPaint(p);
136 } else {
137 logLinearGradient(pts, colors, pos, mode, flags, localMatrix.getMaybeNull(), nullptr);
138 surface->getCanvas()->drawPaint(p);
139 }
140 }
141
fuzzRadialGradient(Fuzz * fuzz)142 void fuzzRadialGradient(Fuzz* fuzz) {
143 SkPoint center;
144 fuzz->next(¢er.fX, ¢er.fY);
145 SkScalar radius;
146 bool useLocalMatrix, useGlobalMatrix;
147 fuzz->next(&radius, &useLocalMatrix, &useGlobalMatrix);
148
149
150 std::vector<SkColor> colors;
151 std::vector<SkScalar> pos;
152 SkShader::TileMode mode;
153 initGradientParams(fuzz, &colors, &pos, &mode);
154
155 SkPaint p;
156 uint32_t flags;
157 fuzz->next(&flags);
158
159 SkTLazy<SkMatrix> localMatrix;
160 if (useLocalMatrix) {
161 makeMatrix(fuzz, localMatrix.init());
162 }
163 p.setShader(SkGradientShader::MakeRadial(center, radius, colors.data(),
164 pos.data(), colors.size(), mode, flags, localMatrix.getMaybeNull()));
165
166
167 sk_sp<SkSurface> surface(SkSurface::MakeRasterN32Premul(50, 50));
168 if (useGlobalMatrix) {
169 SkMatrix gm;
170 makeMatrix(fuzz, &gm);
171 SkCanvas* c = surface->getCanvas();
172 c->setMatrix(gm);
173 c->drawPaint(p);
174 } else {
175 surface->getCanvas()->drawPaint(p);
176 }
177 }
178
fuzzTwoPointConicalGradient(Fuzz * fuzz)179 void fuzzTwoPointConicalGradient(Fuzz* fuzz) {
180 SkPoint start;
181 fuzz->next(&start.fX, &start.fY);
182 SkPoint end;
183 fuzz->next(&end.fX, &end.fY);
184 SkScalar startRadius, endRadius;
185 bool useLocalMatrix, useGlobalMatrix;
186 fuzz->next(&startRadius, &endRadius, &useLocalMatrix, &useGlobalMatrix);
187
188 std::vector<SkColor> colors;
189 std::vector<SkScalar> pos;
190 SkShader::TileMode mode;
191 initGradientParams(fuzz, &colors, &pos, &mode);
192
193 SkPaint p;
194 uint32_t flags;
195 fuzz->next(&flags);
196
197 SkTLazy<SkMatrix> localMatrix;
198 if (useLocalMatrix) {
199 makeMatrix(fuzz, localMatrix.init());
200 }
201 p.setShader(SkGradientShader::MakeTwoPointConical(start, startRadius,
202 end, endRadius, colors.data(), pos.data(), colors.size(), mode,
203 flags, localMatrix.getMaybeNull()));
204
205 sk_sp<SkSurface> surface(SkSurface::MakeRasterN32Premul(50, 50));
206 if (useGlobalMatrix) {
207 SkMatrix gm;
208 makeMatrix(fuzz, &gm);
209 SkCanvas* c = surface->getCanvas();
210 c->setMatrix(gm);
211 c->drawPaint(p);
212 } else {
213 surface->getCanvas()->drawPaint(p);
214 }
215 }
216
fuzzSweepGradient(Fuzz * fuzz)217 void fuzzSweepGradient(Fuzz* fuzz) {
218 SkScalar cx, cy;
219 bool useLocalMatrix, useGlobalMatrix;
220 fuzz->next(&cx, &cy, &useLocalMatrix, &useGlobalMatrix);
221
222 std::vector<SkColor> colors;
223 std::vector<SkScalar> pos;
224 SkShader::TileMode mode;
225 initGradientParams(fuzz, &colors, &pos, &mode);
226
227 SkPaint p;
228 if (useLocalMatrix) {
229 SkMatrix m;
230 makeMatrix(fuzz, &m);
231 uint32_t flags;
232 fuzz->next(&flags);
233
234 p.setShader(SkGradientShader::MakeSweep(cx, cy, colors.data(),
235 pos.data(), colors.size(), flags, &m));
236 } else {
237 p.setShader(SkGradientShader::MakeSweep(cx, cy, colors.data(),
238 pos.data(), colors.size()));
239 }
240
241 sk_sp<SkSurface> surface(SkSurface::MakeRasterN32Premul(50, 50));
242 if (useGlobalMatrix) {
243 SkMatrix gm;
244 makeMatrix(fuzz, &gm);
245 SkCanvas* c = surface->getCanvas();
246 c->setMatrix(gm);
247 c->drawPaint(p);
248 } else {
249 surface->getCanvas()->drawPaint(p);
250 }
251 }
252
DEF_FUZZ(Gradients,fuzz)253 DEF_FUZZ(Gradients, fuzz) {
254 uint8_t i;
255 fuzz->next(&i);
256
257 switch(i) {
258 case 0:
259 SkDEBUGF("LinearGradient\n");
260 fuzzLinearGradient(fuzz);
261 return;
262 case 1:
263 SkDEBUGF("RadialGradient\n");
264 fuzzRadialGradient(fuzz);
265 return;
266 case 2:
267 SkDEBUGF("TwoPointConicalGradient\n");
268 fuzzTwoPointConicalGradient(fuzz);
269 return;
270 }
271 SkDEBUGF("SweepGradient\n");
272 fuzzSweepGradient(fuzz);
273 return;
274 }
275