blob: c96020aba75465d28528919a793fcbd96595dfdb [file] [log] [blame]
Kevin Lubickfec1dea2016-11-22 13:57:18 -05001/*
2 * Copyright 2016 Mozilla Foundation
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/SkBitmap.h"
10#include "include/core/SkCanvas.h"
11#include "include/core/SkFont.h"
12#include "include/core/SkImage.h"
13#include "include/core/SkPath.h"
14#include "include/core/SkSurface.h"
15#include "include/core/SkTextBlob.h"
16#include "include/core/SkTypeface.h"
Mike Reede78f8ce2020-12-19 15:14:06 -050017#include "src/core/SkPaintPriv.h"
Kevin Lubickfec1dea2016-11-22 13:57:18 -050018
19static const int kBmpSize = 24;
20static const int kMaxX = 250;
21static const int kMaxY = 250;
22static const int kPtsLen = 10;
23static const int kTxtLen = 5;
24
Kevin Lubickfec1dea2016-11-22 13:57:18 -050025static void init_string(Fuzz* fuzz, char* str, size_t bufSize) {
26 for (size_t i = 0; i < bufSize-1; ++i) {
27 fuzz->nextRange(&str[i], 0x20, 0x7E); // printable ASCII
28 }
29 str[bufSize-1] = '\0';
30}
31
32// make_paint mostly borrowed from FilterFuzz.cpp
33static void init_paint(Fuzz* fuzz, SkPaint* p) {
34 bool b;
35 fuzz->next(&b);
36 p->setAntiAlias(b);
37
38 uint8_t tmp_u8;
39 fuzz->nextRange(&tmp_u8, 0, (int)SkBlendMode::kLastMode);
40 p->setBlendMode(static_cast<SkBlendMode>(tmp_u8));
41
42 SkColor co;
43 fuzz->next(&co);
44 p->setColor(co);
45
46 fuzz->next(&b);
47 p->setDither(b);
48
Kevin Lubickfec1dea2016-11-22 13:57:18 -050049 fuzz->nextRange(&tmp_u8, 0, (int)SkPaint::kLast_Cap);
50 p->setStrokeCap(static_cast<SkPaint::Cap>(tmp_u8));
51
52 fuzz->nextRange(&tmp_u8, 0, (int)SkPaint::kLast_Join);
53 p->setStrokeJoin(static_cast<SkPaint::Join>(tmp_u8));
54
55 SkScalar sc;
56 fuzz->next(&sc);
57 p->setStrokeMiter(sc);
58
59 fuzz->next(&sc);
60 p->setStrokeWidth(sc);
61
62 fuzz->nextRange(&tmp_u8, 0, (int)SkPaint::kStrokeAndFill_Style);
63 p->setStyle(static_cast<SkPaint::Style>(tmp_u8));
64}
65
Kevin Lubickcdb4d3c2016-11-29 11:14:39 -050066static void init_bitmap(Fuzz* fuzz, SkBitmap* bmp) {
67 uint8_t colorType;
68 fuzz->nextRange(&colorType, 0, (int)kLastEnum_SkColorType);
Kevin Lubick5d5601c2017-02-21 16:06:19 -050069 // ColorType needs to match what the system configuration is.
70 if (colorType == kRGBA_8888_SkColorType || colorType == kBGRA_8888_SkColorType) {
71 colorType = kN32_SkColorType;
72 }
Kevin Lubick8c8b6182017-02-17 10:27:30 -050073 bool b;
74 fuzz->next(&b);
Kevin Lubickcdb4d3c2016-11-29 11:14:39 -050075 SkImageInfo info = SkImageInfo::Make(kBmpSize,
76 kBmpSize,
77 (SkColorType)colorType,
Kevin Lubick8c8b6182017-02-17 10:27:30 -050078 b ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
Kevin Lubickcdb4d3c2016-11-29 11:14:39 -050079 if (!bmp->tryAllocPixels(info)) {
Hal Canary2b0e6cd2018-07-09 12:43:39 -040080 SkDEBUGF("Bitmap not allocated\n");
Kevin Lubickcdb4d3c2016-11-29 11:14:39 -050081 }
Kevin Lubick8c8b6182017-02-17 10:27:30 -050082 SkColor c;
83 fuzz->next(&c);
84 bmp->eraseColor(c);
Kevin Lubickcdb4d3c2016-11-29 11:14:39 -050085
Kevin Lubickcdb4d3c2016-11-29 11:14:39 -050086 fuzz->next(&b);
87 SkPaint p;
88 if (b) {
89 init_paint(fuzz, &p);
90 }
91 else {
Kevin Lubickcdb4d3c2016-11-29 11:14:39 -050092 fuzz->next(&c);
93 p.setColor(c);
94 }
Kevin Lubickcdb4d3c2016-11-29 11:14:39 -050095}
Kevin Lubickfec1dea2016-11-22 13:57:18 -050096
97static void init_surface(Fuzz* fuzz, sk_sp<SkSurface>* s) {
98 uint8_t x, y;
99 fuzz->nextRange(&x, 1, kMaxX);
100 fuzz->nextRange(&y, 1, kMaxY);
101 *s = SkSurface::MakeRasterN32Premul(x, y);
Kevin Lubick1991f552018-02-27 10:59:10 -0500102
103 if (!*s) {
104 // Was possibly too big for the memory constrained fuzzing environments
105 *s = SkSurface::MakeNull(x, y);
106 }
Kevin Lubickfec1dea2016-11-22 13:57:18 -0500107}
108
109
Mike Reed212e9062018-12-25 17:35:49 -0500110static void fuzz_drawText(Fuzz* fuzz, sk_sp<SkTypeface> typeface) {
Mike Reeda6d1c0a2019-01-03 23:29:38 -0500111 SkFont font(typeface);
Kevin Lubickfec1dea2016-11-22 13:57:18 -0500112 SkPaint p;
113 init_paint(fuzz, &p);
114 sk_sp<SkSurface> surface;
115 init_surface(fuzz, &surface);
116
117 char text[kTxtLen];
118 init_string(fuzz, text, kTxtLen);
119
120 SkScalar x, y;
121 fuzz->next(&x, &y);
122 // populate pts array
123 SkPoint pts[kPtsLen];
124 for (uint8_t i = 0; i < kPtsLen; ++i) {
125 pts[i].set(x, y);
Mike Reeda6d1c0a2019-01-03 23:29:38 -0500126 x += font.getSize();
Kevin Lubickfec1dea2016-11-22 13:57:18 -0500127 }
128
Kevin Lubickfec1dea2016-11-22 13:57:18 -0500129 bool b;
130 fuzz->next(&b);
Mike Reed212e9062018-12-25 17:35:49 -0500131 font.setForceAutoHinting(b);
Kevin Lubickfec1dea2016-11-22 13:57:18 -0500132 fuzz->next(&b);
Mike Reed212e9062018-12-25 17:35:49 -0500133 font.setEmbeddedBitmaps(b);
Kevin Lubickfec1dea2016-11-22 13:57:18 -0500134 fuzz->next(&b);
Mike Reed212e9062018-12-25 17:35:49 -0500135 font.setEmbolden(b);
Kevin Lubickfec1dea2016-11-22 13:57:18 -0500136 fuzz->next(&b);
Mike Reed212e9062018-12-25 17:35:49 -0500137 font.setEdging(b ? SkFont::Edging::kAntiAlias : SkFont::Edging::kSubpixelAntiAlias);
Kevin Lubickfec1dea2016-11-22 13:57:18 -0500138 fuzz->next(&b);
Mike Reed212e9062018-12-25 17:35:49 -0500139 font.setLinearMetrics(b);
Kevin Lubickfec1dea2016-11-22 13:57:18 -0500140 fuzz->next(&b);
Mike Reed212e9062018-12-25 17:35:49 -0500141 font.setSubpixel(b);
Kevin Lubickfec1dea2016-11-22 13:57:18 -0500142 fuzz->next(&x);
Mike Reed212e9062018-12-25 17:35:49 -0500143 font.setScaleX(x);
Kevin Lubickfec1dea2016-11-22 13:57:18 -0500144 fuzz->next(&x);
Mike Reed212e9062018-12-25 17:35:49 -0500145 font.setSkewX(x);
Kevin Lubickfec1dea2016-11-22 13:57:18 -0500146 fuzz->next(&x);
Mike Reed212e9062018-12-25 17:35:49 -0500147 font.setSize(x);
Kevin Lubickfec1dea2016-11-22 13:57:18 -0500148
149 SkCanvas* cnv = surface->getCanvas();
Kevin Lubickfec1dea2016-11-22 13:57:18 -0500150 fuzz->next(&x);
151 fuzz->next(&y);
Mike Reed212e9062018-12-25 17:35:49 -0500152 cnv->drawTextBlob(SkTextBlob::MakeFromPosText(text, kTxtLen-1, pts, font), x, y, p);
Kevin Lubickfec1dea2016-11-22 13:57:18 -0500153}
154
155static void fuzz_drawCircle(Fuzz* fuzz) {
156 SkPaint p;
157 init_paint(fuzz, &p);
158 sk_sp<SkSurface> surface;
159 init_surface(fuzz, &surface);
160
161 SkScalar a, b, c;
162 fuzz->next(&a, &b, &c);
163 surface->getCanvas()->drawCircle(a, b, c, p);
164}
165
166static void fuzz_drawLine(Fuzz* fuzz) {
167 SkPaint p;
168 init_paint(fuzz, &p);
169 sk_sp<SkSurface> surface;
170 init_surface(fuzz, &surface);
171
172 SkScalar a, b, c, d;
173 fuzz->next(&a, &b, &c, &d);
174 surface->getCanvas()->drawLine(a, b, c, d, p);
175}
176
177static void fuzz_drawRect(Fuzz* fuzz) {
178 SkPaint p;
179 init_paint(fuzz, &p);
180 sk_sp<SkSurface> surface;
181 init_surface(fuzz, &surface);
182
183 SkScalar a, b, c, d;
184 fuzz->next(&a, &b, &c, &d);
185 SkRect r;
186 r = SkRect::MakeXYWH(a, b, c, d);
187
188 SkCanvas* cnv = surface->getCanvas();
189 cnv->drawRect(r, p);
190
191 bool bl;
192 fuzz->next(&bl);
193 fuzz->next(&a, &b, &c, &d);
194 r = SkRect::MakeXYWH(a, b, c, d);
Michael Ludwig2f6e2f82021-08-03 13:08:50 -0400195 cnv->clipRect(r, SkClipOp::kIntersect, bl);
Kevin Lubickfec1dea2016-11-22 13:57:18 -0500196}
197
198static void fuzz_drawPath(Fuzz* fuzz) {
199 SkPaint p;
200 init_paint(fuzz, &p);
201 sk_sp<SkSurface> surface;
202 init_surface(fuzz, &surface);
203
204 // TODO(kjlubick): put the ability to fuzz a path in shared file, with
205 // other common things (e.g. rects, lines)
206 uint8_t i, j;
207 fuzz->nextRange(&i, 0, 10); // set i to number of operations to perform
208 SkPath path;
209 SkScalar a, b, c, d, e, f;
210 for (int k = 0; k < i; ++k) {
211 fuzz->nextRange(&j, 0, 5); // set j to choose operation to perform
212 switch (j) {
213 case 0:
214 fuzz->next(&a, &b);
215 path.moveTo(a, b);
216 break;
217 case 1:
218 fuzz->next(&a, &b);
219 path.lineTo(a, b);
220 break;
221 case 2:
222 fuzz->next(&a, &b, &c, &d);
223 path.quadTo(a, b, c, d);
224 break;
225 case 3:
226 fuzz->next(&a, &b, &c, &d, &e);
227 path.conicTo(a, b, c, d, e);
228 break;
229 case 4:
230 fuzz->next(&a, &b, &c, &d, &e, &f);
231 path.cubicTo(a, b, c, d, e, f);
232 break;
233 case 5:
234 fuzz->next(&a, &b, &c, &d, &e);
235 path.arcTo(a, b, c, d, e);
236 break;
237 }
238 }
239 path.close();
240
241 SkCanvas* cnv = surface->getCanvas();
242 cnv->drawPath(path, p);
243
244 bool bl;
245 fuzz->next(&bl);
Michael Ludwig2f6e2f82021-08-03 13:08:50 -0400246 cnv->clipPath(path, SkClipOp::kIntersect, bl);
Kevin Lubickfec1dea2016-11-22 13:57:18 -0500247}
248
Kevin Lubickfec1dea2016-11-22 13:57:18 -0500249static void fuzz_drawImage(Fuzz* fuzz) {
250 SkPaint p;
251 init_paint(fuzz, &p);
252 sk_sp<SkSurface> surface;
253 init_surface(fuzz, &surface);
254 SkBitmap bmp;
255 init_bitmap(fuzz, &bmp);
256
Mike Reeddc607e32020-12-23 11:50:36 -0500257 sk_sp<SkImage> image(bmp.asImage());
Kevin Lubickfec1dea2016-11-22 13:57:18 -0500258
259 bool bl;
260 fuzz->next(&bl);
261 SkScalar a, b;
262 fuzz->next(&a, &b);
263 if (bl) {
Mike Reede02d7f82021-01-21 22:25:21 -0500264 surface->getCanvas()->drawImage(image, a, b, SkSamplingOptions(), &p);
Kevin Lubickfec1dea2016-11-22 13:57:18 -0500265 }
266 else {
267 SkRect dst = SkRect::MakeWH(a, b);
268 fuzz->next(&a, &b);
269 SkRect src = SkRect::MakeWH(a, b);
270 uint8_t x;
271 fuzz->nextRange(&x, 0, 1);
272 SkCanvas::SrcRectConstraint cst = (SkCanvas::SrcRectConstraint)x;
Mike Reede02d7f82021-01-21 22:25:21 -0500273 surface->getCanvas()->drawImageRect(image.get(), src, dst, SkSamplingOptions(), &p, cst);
Kevin Lubickfec1dea2016-11-22 13:57:18 -0500274 }
275}
276
277static void fuzz_drawPaint(Fuzz* fuzz) {
278 SkPaint l, p;
279 init_paint(fuzz, &p);
280 sk_sp<SkSurface> surface;
281 init_surface(fuzz, &surface);
282
Kevin Lubickfec1dea2016-11-22 13:57:18 -0500283 surface->getCanvas()->drawPaint(p);
284}
285
286DEF_FUZZ(DrawFunctions, fuzz) {
287 uint8_t i;
288 fuzz->next(&i);
289
290 switch(i) {
291 case 0: {
292 sk_sp<SkTypeface> f = SkTypeface::MakeDefault();
293 if (f == nullptr) {
294 SkDebugf("Could not initialize font.\n");
295 fuzz->signalBug();
296 }
Hal Canary2b0e6cd2018-07-09 12:43:39 -0400297 SkDEBUGF("Fuzz DrawText\n");
Kevin Lubickfec1dea2016-11-22 13:57:18 -0500298 fuzz_drawText(fuzz, f);
299 return;
300 }
301 case 1:
Hal Canary2b0e6cd2018-07-09 12:43:39 -0400302 SkDEBUGF("Fuzz DrawRect\n");
Kevin Lubickfec1dea2016-11-22 13:57:18 -0500303 fuzz_drawRect(fuzz);
304 return;
305 case 2:
Hal Canary2b0e6cd2018-07-09 12:43:39 -0400306 SkDEBUGF("Fuzz DrawCircle\n");
Kevin Lubickfec1dea2016-11-22 13:57:18 -0500307 fuzz_drawCircle(fuzz);
308 return;
309 case 3:
Hal Canary2b0e6cd2018-07-09 12:43:39 -0400310 SkDEBUGF("Fuzz DrawLine\n");
Kevin Lubickfec1dea2016-11-22 13:57:18 -0500311 fuzz_drawLine(fuzz);
312 return;
313 case 4:
Hal Canary2b0e6cd2018-07-09 12:43:39 -0400314 SkDEBUGF("Fuzz DrawPath\n");
Kevin Lubickfec1dea2016-11-22 13:57:18 -0500315 fuzz_drawPath(fuzz);
316 return;
317 case 5:
Hal Canary2b0e6cd2018-07-09 12:43:39 -0400318 SkDEBUGF("Fuzz DrawImage/DrawImageRect\n");
Kevin Lubickfec1dea2016-11-22 13:57:18 -0500319 fuzz_drawImage(fuzz);
320 return;
321 case 6:
Hal Canary2b0e6cd2018-07-09 12:43:39 -0400322 SkDEBUGF("Fuzz DrawPaint\n");
Kevin Lubickfec1dea2016-11-22 13:57:18 -0500323 fuzz_drawPaint(fuzz);
324 return;
325 }
326}