blob: 2dfab4efd00ec485824952d423cce98591f6c987 [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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#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/SkTLazy.h"
13#include "tools/flags/CommandLineFlags.h"
kjlubick1eda1eb2016-08-12 06:26:03 -070014
15#include <algorithm>
Kevin Lubick2f535ce2016-11-01 15:01:12 -040016#include <vector>
kjlubick1eda1eb2016-08-12 06:26:03 -070017
Mike Kleinc6142d82019-03-25 10:54:59 -050018static DEFINE_bool2(verbose, v, false, "log verbose linear gradient description");
19
kjlubick1eda1eb2016-08-12 06:26:03 -070020const int MAX_COUNT = 400;
21
Kevin Lubick2f535ce2016-11-01 15:01:12 -040022void makeMatrix(Fuzz* fuzz, SkMatrix* m) {
Kevin Lubick416b2482016-11-10 16:17:49 -050023 SkScalar mat[9];
24 fuzz->nextN(mat, 9);
25 m->set9(mat);
kjlubick1eda1eb2016-08-12 06:26:03 -070026}
27
Kevin Lubick2f535ce2016-11-01 15:01:12 -040028void initGradientParams(Fuzz* fuzz, std::vector<SkColor>* colors,
Mike Reedfae8fce2019-04-03 10:27:45 -040029 std::vector<SkScalar>* pos, SkTileMode* mode) {
Kevin Lubick416b2482016-11-10 16:17:49 -050030 int count;
31 fuzz->nextRange(&count, 0, MAX_COUNT);
kjlubick1eda1eb2016-08-12 06:26:03 -070032
Kevin Lubick416b2482016-11-10 16:17:49 -050033 // Use a uint8_t to conserve bytes. This makes our "fuzzed bytes footprint"
34 // smaller, which leads to more efficient fuzzing.
35 uint8_t m;
36 fuzz->nextRange(&m, 0, 2);
Mike Reedfae8fce2019-04-03 10:27:45 -040037 *mode = static_cast<SkTileMode>(m);
kjlubick840f12a2016-10-25 06:11:05 -070038
39 colors->clear();
40 pos ->clear();
Kevin Lubick2f535ce2016-11-01 15:01:12 -040041 for (int i = 0; i < count; i++) {
Kevin Lubick416b2482016-11-10 16:17:49 -050042 SkColor c;
43 SkScalar s;
44 fuzz->next(&c, &s);
45 colors->push_back(c);
46 pos ->push_back(s);
kjlubick840f12a2016-10-25 06:11:05 -070047 }
48 if (count) {
49 std::sort(pos->begin(), pos->end());
50 // The order matters. If count == 1, we want pos == 0.
51 (*pos)[count - 1] = 1;
52 (*pos)[0] = 0;
53 }
kjlubick1eda1eb2016-08-12 06:26:03 -070054}
55
Florin Malita75435bf2017-02-09 11:31:32 -050056static void logOptionalMatrix(const char* label, const SkMatrix* m) {
57 if (!m) {
58 return;
59 }
60
Hal Canary2b0e6cd2018-07-09 12:43:39 -040061 SkDEBUGF(" %s: [ ", label);
Florin Malita75435bf2017-02-09 11:31:32 -050062 for (int i = 0; i < 9; ++i) {
Hal Canary2b0e6cd2018-07-09 12:43:39 -040063 SkDEBUGF("%.9g ", m->get(i));
Florin Malita75435bf2017-02-09 11:31:32 -050064 }
Hal Canary2b0e6cd2018-07-09 12:43:39 -040065 SkDEBUGF("]\n");
Florin Malita75435bf2017-02-09 11:31:32 -050066}
67
68static void logLinearGradient(const SkPoint pts[2],
69 const std::vector<SkColor>& colors,
70 const std::vector<SkScalar> pos,
Mike Reedfae8fce2019-04-03 10:27:45 -040071 SkTileMode mode,
Florin Malita75435bf2017-02-09 11:31:32 -050072 uint32_t flags,
73 const SkMatrix* localMatrix,
74 const SkMatrix* globalMatrix) {
75 if (!FLAGS_verbose) {
76 return;
77 }
78
79 SkDebugf("--- fuzzLinearGradient ---\n");
Florin Malita3d1a6bc2017-02-09 15:05:15 -050080 SkDebugf(" pts:\t\t[ (%.9g %.9g) (%.9g %.9g) ]\n",
Florin Malita75435bf2017-02-09 11:31:32 -050081 pts[0].x(), pts[0].y(), pts[1].x(), pts[1].y());
82 SkDebugf(" colors:\t[ ");
83 for (auto color : colors) {
84 SkDebugf("0x%x ", color);
85 }
86
87 SkDebugf("]\n pos:\t\t");
88 if (pos.empty()) {
89 SkDebugf("nullptr");
90 } else {
91 SkDebugf("[ ");
92 for (auto p : pos) {
93 SkDebugf("%f ", p);
94 }
95 }
96 SkDebugf("]\n");
97
98 static const char* gModeName[] = {
Mike Reedfae8fce2019-04-03 10:27:45 -040099 "kClamp_TileMode", "kRepeat_TileMode", "kMirror_TileMode", "kDecal_TileMode"
Florin Malita75435bf2017-02-09 11:31:32 -0500100 };
Mike Reedfae8fce2019-04-03 10:27:45 -0400101 SkASSERT((unsigned)mode < SK_ARRAY_COUNT(gModeName));
102 SkDebugf(" mode:\t\t%s\n", gModeName[(unsigned)mode]);
Florin Malita75435bf2017-02-09 11:31:32 -0500103 SkDebugf(" flags:\t0x%x\n", flags);
104 logOptionalMatrix("local matrix", localMatrix);
105 logOptionalMatrix("global matrix", globalMatrix);
106}
107
kjlubick1eda1eb2016-08-12 06:26:03 -0700108void fuzzLinearGradient(Fuzz* fuzz) {
Kevin Lubick416b2482016-11-10 16:17:49 -0500109 SkPoint pts[2];
110 fuzz->next(&pts[0].fX, &pts[0].fY, &pts[1].fX, &pts[1].fY);
111 bool useLocalMatrix, useGlobalMatrix;
112 fuzz->next(&useLocalMatrix, &useGlobalMatrix);
kjlubick1eda1eb2016-08-12 06:26:03 -0700113
Kevin Lubick2f535ce2016-11-01 15:01:12 -0400114 std::vector<SkColor> colors;
115 std::vector<SkScalar> pos;
Mike Reedfae8fce2019-04-03 10:27:45 -0400116 SkTileMode mode;
Kevin Lubick2f535ce2016-11-01 15:01:12 -0400117 initGradientParams(fuzz, &colors, &pos, &mode);
kjlubick1eda1eb2016-08-12 06:26:03 -0700118
Kevin Lubick2f535ce2016-11-01 15:01:12 -0400119 SkPaint p;
Kevin Lubick416b2482016-11-10 16:17:49 -0500120 uint32_t flags;
121 fuzz->next(&flags);
kjlubick1eda1eb2016-08-12 06:26:03 -0700122
Kevin Lubick2f535ce2016-11-01 15:01:12 -0400123 SkTLazy<SkMatrix> localMatrix;
124 if (useLocalMatrix) {
125 makeMatrix(fuzz, localMatrix.init());
126 }
127 p.setShader(SkGradientShader::MakeLinear(pts, colors.data(), pos.data(),
128 colors.size(), mode, flags, localMatrix.getMaybeNull()));
kjlubick1eda1eb2016-08-12 06:26:03 -0700129
Kevin Lubick2f535ce2016-11-01 15:01:12 -0400130 sk_sp<SkSurface> surface(SkSurface::MakeRasterN32Premul(50, 50));
131 if (useGlobalMatrix) {
132 SkMatrix gm;
133 makeMatrix(fuzz, &gm);
Florin Malita75435bf2017-02-09 11:31:32 -0500134 logLinearGradient(pts, colors, pos, mode, flags, localMatrix.getMaybeNull(), &gm);
Kevin Lubick2f535ce2016-11-01 15:01:12 -0400135 SkCanvas* c = surface->getCanvas();
136 c->setMatrix(gm);
137 c->drawPaint(p);
138 } else {
Florin Malita75435bf2017-02-09 11:31:32 -0500139 logLinearGradient(pts, colors, pos, mode, flags, localMatrix.getMaybeNull(), nullptr);
Kevin Lubick2f535ce2016-11-01 15:01:12 -0400140 surface->getCanvas()->drawPaint(p);
141 }
kjlubick1eda1eb2016-08-12 06:26:03 -0700142}
143
144void fuzzRadialGradient(Fuzz* fuzz) {
Kevin Lubick416b2482016-11-10 16:17:49 -0500145 SkPoint center;
146 fuzz->next(&center.fX, &center.fY);
147 SkScalar radius;
148 bool useLocalMatrix, useGlobalMatrix;
149 fuzz->next(&radius, &useLocalMatrix, &useGlobalMatrix);
kjlubick1eda1eb2016-08-12 06:26:03 -0700150
151
Kevin Lubick2f535ce2016-11-01 15:01:12 -0400152 std::vector<SkColor> colors;
153 std::vector<SkScalar> pos;
Mike Reedfae8fce2019-04-03 10:27:45 -0400154 SkTileMode mode;
Kevin Lubick2f535ce2016-11-01 15:01:12 -0400155 initGradientParams(fuzz, &colors, &pos, &mode);
156
157 SkPaint p;
Kevin Lubick416b2482016-11-10 16:17:49 -0500158 uint32_t flags;
159 fuzz->next(&flags);
Kevin Lubick2f535ce2016-11-01 15:01:12 -0400160
161 SkTLazy<SkMatrix> localMatrix;
162 if (useLocalMatrix) {
163 makeMatrix(fuzz, localMatrix.init());
164 }
165 p.setShader(SkGradientShader::MakeRadial(center, radius, colors.data(),
166 pos.data(), colors.size(), mode, flags, localMatrix.getMaybeNull()));
167
168
169 sk_sp<SkSurface> surface(SkSurface::MakeRasterN32Premul(50, 50));
170 if (useGlobalMatrix) {
171 SkMatrix gm;
172 makeMatrix(fuzz, &gm);
173 SkCanvas* c = surface->getCanvas();
174 c->setMatrix(gm);
175 c->drawPaint(p);
176 } else {
177 surface->getCanvas()->drawPaint(p);
178 }
kjlubick1eda1eb2016-08-12 06:26:03 -0700179}
180
181void fuzzTwoPointConicalGradient(Fuzz* fuzz) {
Kevin Lubick416b2482016-11-10 16:17:49 -0500182 SkPoint start;
183 fuzz->next(&start.fX, &start.fY);
184 SkPoint end;
185 fuzz->next(&end.fX, &end.fY);
186 SkScalar startRadius, endRadius;
187 bool useLocalMatrix, useGlobalMatrix;
188 fuzz->next(&startRadius, &endRadius, &useLocalMatrix, &useGlobalMatrix);
kjlubick1eda1eb2016-08-12 06:26:03 -0700189
Kevin Lubick2f535ce2016-11-01 15:01:12 -0400190 std::vector<SkColor> colors;
191 std::vector<SkScalar> pos;
Mike Reedfae8fce2019-04-03 10:27:45 -0400192 SkTileMode mode;
Kevin Lubick2f535ce2016-11-01 15:01:12 -0400193 initGradientParams(fuzz, &colors, &pos, &mode);
kjlubick1eda1eb2016-08-12 06:26:03 -0700194
Kevin Lubick2f535ce2016-11-01 15:01:12 -0400195 SkPaint p;
Kevin Lubick416b2482016-11-10 16:17:49 -0500196 uint32_t flags;
197 fuzz->next(&flags);
kjlubick1eda1eb2016-08-12 06:26:03 -0700198
Kevin Lubick2f535ce2016-11-01 15:01:12 -0400199 SkTLazy<SkMatrix> localMatrix;
200 if (useLocalMatrix) {
201 makeMatrix(fuzz, localMatrix.init());
202 }
203 p.setShader(SkGradientShader::MakeTwoPointConical(start, startRadius,
204 end, endRadius, colors.data(), pos.data(), colors.size(), mode,
205 flags, localMatrix.getMaybeNull()));
kjlubick1eda1eb2016-08-12 06:26:03 -0700206
Kevin Lubick2f535ce2016-11-01 15:01:12 -0400207 sk_sp<SkSurface> surface(SkSurface::MakeRasterN32Premul(50, 50));
208 if (useGlobalMatrix) {
209 SkMatrix gm;
210 makeMatrix(fuzz, &gm);
211 SkCanvas* c = surface->getCanvas();
212 c->setMatrix(gm);
213 c->drawPaint(p);
214 } else {
215 surface->getCanvas()->drawPaint(p);
216 }
kjlubick1eda1eb2016-08-12 06:26:03 -0700217}
218
219void fuzzSweepGradient(Fuzz* fuzz) {
Kevin Lubick416b2482016-11-10 16:17:49 -0500220 SkScalar cx, cy;
221 bool useLocalMatrix, useGlobalMatrix;
222 fuzz->next(&cx, &cy, &useLocalMatrix, &useGlobalMatrix);
kjlubick1eda1eb2016-08-12 06:26:03 -0700223
Kevin Lubick2f535ce2016-11-01 15:01:12 -0400224 std::vector<SkColor> colors;
225 std::vector<SkScalar> pos;
Mike Reedfae8fce2019-04-03 10:27:45 -0400226 SkTileMode mode;
Kevin Lubick2f535ce2016-11-01 15:01:12 -0400227 initGradientParams(fuzz, &colors, &pos, &mode);
kjlubick1eda1eb2016-08-12 06:26:03 -0700228
Kevin Lubick2f535ce2016-11-01 15:01:12 -0400229 SkPaint p;
230 if (useLocalMatrix) {
231 SkMatrix m;
232 makeMatrix(fuzz, &m);
Kevin Lubick416b2482016-11-10 16:17:49 -0500233 uint32_t flags;
234 fuzz->next(&flags);
kjlubick1eda1eb2016-08-12 06:26:03 -0700235
Kevin Lubick2f535ce2016-11-01 15:01:12 -0400236 p.setShader(SkGradientShader::MakeSweep(cx, cy, colors.data(),
237 pos.data(), colors.size(), flags, &m));
238 } else {
239 p.setShader(SkGradientShader::MakeSweep(cx, cy, colors.data(),
240 pos.data(), colors.size()));
241 }
kjlubick1eda1eb2016-08-12 06:26:03 -0700242
Kevin Lubick2f535ce2016-11-01 15:01:12 -0400243 sk_sp<SkSurface> surface(SkSurface::MakeRasterN32Premul(50, 50));
244 if (useGlobalMatrix) {
245 SkMatrix gm;
246 makeMatrix(fuzz, &gm);
247 SkCanvas* c = surface->getCanvas();
248 c->setMatrix(gm);
249 c->drawPaint(p);
250 } else {
251 surface->getCanvas()->drawPaint(p);
252 }
kjlubick1eda1eb2016-08-12 06:26:03 -0700253}
254
255DEF_FUZZ(Gradients, fuzz) {
Kevin Lubick416b2482016-11-10 16:17:49 -0500256 uint8_t i;
257 fuzz->next(&i);
kjlubick1eda1eb2016-08-12 06:26:03 -0700258
259 switch(i) {
260 case 0:
Hal Canary2b0e6cd2018-07-09 12:43:39 -0400261 SkDEBUGF("LinearGradient\n");
kjlubick1eda1eb2016-08-12 06:26:03 -0700262 fuzzLinearGradient(fuzz);
263 return;
264 case 1:
Hal Canary2b0e6cd2018-07-09 12:43:39 -0400265 SkDEBUGF("RadialGradient\n");
kjlubick1eda1eb2016-08-12 06:26:03 -0700266 fuzzRadialGradient(fuzz);
267 return;
268 case 2:
Hal Canary2b0e6cd2018-07-09 12:43:39 -0400269 SkDEBUGF("TwoPointConicalGradient\n");
kjlubick1eda1eb2016-08-12 06:26:03 -0700270 fuzzTwoPointConicalGradient(fuzz);
271 return;
272 }
Hal Canary2b0e6cd2018-07-09 12:43:39 -0400273 SkDEBUGF("SweepGradient\n");
kjlubick1eda1eb2016-08-12 06:26:03 -0700274 fuzzSweepGradient(fuzz);
275 return;
276}