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