• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(&center.fX, &center.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