blob: 6ed4b7cb7a795c76ea06af73f1ded06c3a5dc47f [file] [log] [blame]
kjlubick1eda1eb2016-08-12 06:26:03 -07001/*
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 "SkGradientShader.h"
11#include "SkSurface.h"
12#include "SkTLazy.h"
13
14#include <algorithm>
15
16const int MAX_COUNT = 400;
17
18bool makeMatrix(Fuzz* fuzz, SkMatrix* m) {
19 SkScalar scaleX, skewX, transX, skewY, scaleY, transY, persp0, persp1, persp2;
kjlubick85d30172016-10-24 11:53:35 -070020 if (!fuzz->next(&scaleX) ||
21 !fuzz->next(&skewX) ||
22 !fuzz->next(&transX) ||
23 !fuzz->next(&skewY) ||
24 !fuzz->next(&scaleY) ||
25 !fuzz->next(&transY) ||
26 !fuzz->next(&persp0) ||
27 !fuzz->next(&persp1) ||
28 !fuzz->next(&persp2)) {
kjlubick1eda1eb2016-08-12 06:26:03 -070029 return false;
30 }
31 m->setAll(scaleX, skewX, transX, skewY, scaleY, transY, persp0, persp1, persp2);
32 return true;
33}
34
kjlubick840f12a2016-10-25 06:11:05 -070035bool initGradientParams(Fuzz* fuzz, std::vector<SkColor>* colors,
36 std::vector<SkScalar>* pos, SkShader::TileMode* mode) {
kjlubick1eda1eb2016-08-12 06:26:03 -070037 if (fuzz->remaining() < sizeof(uint32_t)) {
38 return false;
39 }
kjlubick840f12a2016-10-25 06:11:05 -070040 uint32_t count = fuzz->nextRangeU(0, MAX_COUNT);
kjlubick1eda1eb2016-08-12 06:26:03 -070041
kjlubick840f12a2016-10-25 06:11:05 -070042 if (fuzz->remaining() < sizeof(uint32_t)) {
kjlubick1eda1eb2016-08-12 06:26:03 -070043 return false;
44 }
kjlubick1eda1eb2016-08-12 06:26:03 -070045 *mode = static_cast<SkShader::TileMode>(fuzz->nextRangeU(0, 3));
kjlubick840f12a2016-10-25 06:11:05 -070046
47 colors->clear();
48 pos ->clear();
49 for (uint32_t i = 0; i < count; i++) {
50 SkColor c;
51 SkScalar s;
52 if (!fuzz->next(&c) || !fuzz->next(&s)) {
53 return false;
54 }
55 colors->push_back(c);
56 pos ->push_back(s);
57 }
58 if (count) {
59 std::sort(pos->begin(), pos->end());
60 // The order matters. If count == 1, we want pos == 0.
61 (*pos)[count - 1] = 1;
62 (*pos)[0] = 0;
63 }
kjlubick1eda1eb2016-08-12 06:26:03 -070064 return true;
65}
66
67void fuzzLinearGradient(Fuzz* fuzz) {
68 SkScalar a, b, c, d;
69 bool useLocalMatrix, useGlobalMatrix;
kjlubick85d30172016-10-24 11:53:35 -070070 if (!fuzz->next(&a) ||
71 !fuzz->next(&b) ||
72 !fuzz->next(&c) ||
73 !fuzz->next(&d) ||
74 !fuzz->next(&useLocalMatrix) ||
75 !fuzz->next(&useGlobalMatrix)) {
kjlubick1eda1eb2016-08-12 06:26:03 -070076 return;
77 }
78 SkPoint pts[2] = {SkPoint::Make(a,b), SkPoint::Make(c, d)};
79
kjlubick840f12a2016-10-25 06:11:05 -070080 std::vector<SkColor> colors;
81 std::vector<SkScalar> pos;
kjlubick1eda1eb2016-08-12 06:26:03 -070082 SkShader::TileMode mode;
kjlubick840f12a2016-10-25 06:11:05 -070083 if (!initGradientParams(fuzz, &colors, &pos, &mode)) {
kjlubick1eda1eb2016-08-12 06:26:03 -070084 return;
85 }
86
87 SkPaint p;
88 uint32_t flags;
89 if (!fuzz->next(&flags)) {
90 return;
91 }
92
93 SkTLazy<SkMatrix> localMatrix;
94 if (useLocalMatrix && !makeMatrix(fuzz, localMatrix.init())) {
95 return;
96 }
kjlubick840f12a2016-10-25 06:11:05 -070097 p.setShader(SkGradientShader::MakeLinear(pts, colors.data(), pos.data(),
98 colors.size(), mode, flags, localMatrix.getMaybeNull()));
kjlubick1eda1eb2016-08-12 06:26:03 -070099
100 sk_sp<SkSurface> surface(SkSurface::MakeRasterN32Premul(50, 50));
101 if (useGlobalMatrix) {
102 SkMatrix gm;
103 if (!makeMatrix(fuzz, &gm)) {
104 return;
105 }
106 SkCanvas* c = surface->getCanvas();
107 c->setMatrix(gm);
108 c->drawPaint(p);
109 } else {
110 surface->getCanvas()->drawPaint(p);
111 }
112}
113
114void fuzzRadialGradient(Fuzz* fuzz) {
115 SkScalar a, b, radius;
116 bool useLocalMatrix, useGlobalMatrix;
kjlubick85d30172016-10-24 11:53:35 -0700117 if (!fuzz->next(&a) ||
118 !fuzz->next(&b) ||
119 !fuzz->next(&radius) ||
120 !fuzz->next(&useLocalMatrix) ||
121 !fuzz->next(&useGlobalMatrix)) {
kjlubick1eda1eb2016-08-12 06:26:03 -0700122 return;
123 }
124 SkPoint center = SkPoint::Make(a,b);
125
kjlubick840f12a2016-10-25 06:11:05 -0700126 std::vector<SkColor> colors;
127 std::vector<SkScalar> pos;
kjlubick1eda1eb2016-08-12 06:26:03 -0700128 SkShader::TileMode mode;
kjlubick840f12a2016-10-25 06:11:05 -0700129 if (!initGradientParams(fuzz, &colors, &pos, &mode)) {
kjlubick1eda1eb2016-08-12 06:26:03 -0700130 return;
131 }
132
133 SkPaint p;
134 uint32_t flags;
135 if (!fuzz->next(&flags)) {
136 return;
137 }
138
139 SkTLazy<SkMatrix> localMatrix;
140 if (useLocalMatrix && !makeMatrix(fuzz, localMatrix.init())) {
141 return;
142 }
kjlubick840f12a2016-10-25 06:11:05 -0700143 p.setShader(SkGradientShader::MakeRadial(center, radius, colors.data(),
144 pos.data(), colors.size(), mode, flags, localMatrix.getMaybeNull()));
kjlubick1eda1eb2016-08-12 06:26:03 -0700145
146
147 sk_sp<SkSurface> surface(SkSurface::MakeRasterN32Premul(50, 50));
148 if (useGlobalMatrix) {
149 SkMatrix gm;
150 if (!makeMatrix(fuzz, &gm)) {
151 return;
152 }
153 SkCanvas* c = surface->getCanvas();
154 c->setMatrix(gm);
155 c->drawPaint(p);
156 } else {
157 surface->getCanvas()->drawPaint(p);
158 }
159}
160
161void fuzzTwoPointConicalGradient(Fuzz* fuzz) {
162 SkScalar a, b, startRadius, c, d, endRadius;
163 bool useLocalMatrix, useGlobalMatrix;
kjlubick85d30172016-10-24 11:53:35 -0700164 if (!fuzz->next(&a) ||
165 !fuzz->next(&b) ||
166 !fuzz->next(&startRadius) ||
167 !fuzz->next(&c) ||
168 !fuzz->next(&d) ||
169 !fuzz->next(&endRadius) ||
170 !fuzz->next(&useLocalMatrix) ||
171 !fuzz->next(&useGlobalMatrix)) {
kjlubick1eda1eb2016-08-12 06:26:03 -0700172 return;
173 }
174 SkPoint start = SkPoint::Make(a, b);
175 SkPoint end = SkPoint::Make(c, d);
176
kjlubick840f12a2016-10-25 06:11:05 -0700177 std::vector<SkColor> colors;
178 std::vector<SkScalar> pos;
kjlubick1eda1eb2016-08-12 06:26:03 -0700179 SkShader::TileMode mode;
kjlubick840f12a2016-10-25 06:11:05 -0700180 if (!initGradientParams(fuzz, &colors, &pos, &mode)) {
kjlubick1eda1eb2016-08-12 06:26:03 -0700181 return;
182 }
183
184 SkPaint p;
185 uint32_t flags;
186 if (!fuzz->next(&flags)) {
187 return;
188 }
189
190 SkTLazy<SkMatrix> localMatrix;
191 if (useLocalMatrix && !makeMatrix(fuzz, localMatrix.init())) {
192 return;
193 }
kjlubick840f12a2016-10-25 06:11:05 -0700194 p.setShader(SkGradientShader::MakeTwoPointConical(start, startRadius,
195 end, endRadius, colors.data(), pos.data(), colors.size(), mode,
196 flags, localMatrix.getMaybeNull()));
kjlubick1eda1eb2016-08-12 06:26:03 -0700197
198 sk_sp<SkSurface> surface(SkSurface::MakeRasterN32Premul(50, 50));
199 if (useGlobalMatrix) {
200 SkMatrix gm;
201 if (!makeMatrix(fuzz, &gm)) {
202 return;
203 }
204 SkCanvas* c = surface->getCanvas();
205 c->setMatrix(gm);
206 c->drawPaint(p);
207 } else {
208 surface->getCanvas()->drawPaint(p);
209 }
210}
211
212void fuzzSweepGradient(Fuzz* fuzz) {
213 SkScalar cx, cy;
214 bool useLocalMatrix, useGlobalMatrix;
kjlubick85d30172016-10-24 11:53:35 -0700215 if (!fuzz->next(&cx) ||
216 !fuzz->next(&cy) ||
217 !fuzz->next(&useLocalMatrix) ||
218 !fuzz->next(&useGlobalMatrix)) {
kjlubick1eda1eb2016-08-12 06:26:03 -0700219 return;
220 }
221
kjlubick840f12a2016-10-25 06:11:05 -0700222 std::vector<SkColor> colors;
223 std::vector<SkScalar> pos;
kjlubick1eda1eb2016-08-12 06:26:03 -0700224 SkShader::TileMode mode;
kjlubick840f12a2016-10-25 06:11:05 -0700225 if (!initGradientParams(fuzz, &colors, &pos, &mode)) {
kjlubick1eda1eb2016-08-12 06:26:03 -0700226 return;
227 }
228
229 SkPaint p;
230 if (useLocalMatrix) {
231 SkMatrix m;
232 if (!makeMatrix(fuzz, &m)) {
233 return;
234 }
235 uint32_t flags;
236 if (!fuzz->next(&flags)) {
237 return;
238 }
kjlubick840f12a2016-10-25 06:11:05 -0700239 p.setShader(SkGradientShader::MakeSweep(cx, cy, colors.data(),
240 pos.data(), colors.size(), flags, &m));
kjlubick1eda1eb2016-08-12 06:26:03 -0700241 } else {
kjlubick840f12a2016-10-25 06:11:05 -0700242 p.setShader(SkGradientShader::MakeSweep(cx, cy, colors.data(),
243 pos.data(), colors.size()));
kjlubick1eda1eb2016-08-12 06:26:03 -0700244 }
245
246
247 sk_sp<SkSurface> surface(SkSurface::MakeRasterN32Premul(50, 50));
248 if (useGlobalMatrix) {
249 SkMatrix gm;
250 if (!makeMatrix(fuzz, &gm)) {
251 return;
252 }
253 SkCanvas* c = surface->getCanvas();
254 c->setMatrix(gm);
255 c->drawPaint(p);
256 } else {
257 surface->getCanvas()->drawPaint(p);
258 }
259}
260
261DEF_FUZZ(Gradients, fuzz) {
262 uint8_t i;
kjlubick85d30172016-10-24 11:53:35 -0700263 if (!fuzz->next(&i)) {
kjlubick1eda1eb2016-08-12 06:26:03 -0700264 return;
265 }
266
267 switch(i) {
268 case 0:
269 SkDebugf("LinearGradient\n");
270 fuzzLinearGradient(fuzz);
271 return;
272 case 1:
273 SkDebugf("RadialGradient\n");
274 fuzzRadialGradient(fuzz);
275 return;
276 case 2:
277 SkDebugf("TwoPointConicalGradient\n");
278 fuzzTwoPointConicalGradient(fuzz);
279 return;
280 }
281 SkDebugf("SweepGradient\n");
282 fuzzSweepGradient(fuzz);
283 return;
284}