blob: c5b1378bf6e65f069a2e0dfff65383e6601ece2c [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 Lubickbca43ec2023-10-30 10:11:22 -040018#include "tools/fonts/FontToolUtils.h"
Kevin Lubickfec1dea2016-11-22 13:57:18 -050019
20static const int kBmpSize = 24;
21static const int kMaxX = 250;
22static const int kMaxY = 250;
23static const int kPtsLen = 10;
24static const int kTxtLen = 5;
25
Kevin Lubickfec1dea2016-11-22 13:57:18 -050026static void init_string(Fuzz* fuzz, char* str, size_t bufSize) {
27 for (size_t i = 0; i < bufSize-1; ++i) {
28 fuzz->nextRange(&str[i], 0x20, 0x7E); // printable ASCII
29 }
30 str[bufSize-1] = '\0';
31}
32
33// make_paint mostly borrowed from FilterFuzz.cpp
34static void init_paint(Fuzz* fuzz, SkPaint* p) {
35 bool b;
36 fuzz->next(&b);
37 p->setAntiAlias(b);
38
39 uint8_t tmp_u8;
40 fuzz->nextRange(&tmp_u8, 0, (int)SkBlendMode::kLastMode);
41 p->setBlendMode(static_cast<SkBlendMode>(tmp_u8));
42
43 SkColor co;
44 fuzz->next(&co);
45 p->setColor(co);
46
47 fuzz->next(&b);
48 p->setDither(b);
49
Kevin Lubickfec1dea2016-11-22 13:57:18 -050050 fuzz->nextRange(&tmp_u8, 0, (int)SkPaint::kLast_Cap);
51 p->setStrokeCap(static_cast<SkPaint::Cap>(tmp_u8));
52
53 fuzz->nextRange(&tmp_u8, 0, (int)SkPaint::kLast_Join);
54 p->setStrokeJoin(static_cast<SkPaint::Join>(tmp_u8));
55
56 SkScalar sc;
57 fuzz->next(&sc);
58 p->setStrokeMiter(sc);
59
60 fuzz->next(&sc);
61 p->setStrokeWidth(sc);
62
63 fuzz->nextRange(&tmp_u8, 0, (int)SkPaint::kStrokeAndFill_Style);
64 p->setStyle(static_cast<SkPaint::Style>(tmp_u8));
65}
66
Kevin Lubickcdb4d3c2016-11-29 11:14:39 -050067static void init_bitmap(Fuzz* fuzz, SkBitmap* bmp) {
68 uint8_t colorType;
69 fuzz->nextRange(&colorType, 0, (int)kLastEnum_SkColorType);
Kevin Lubick5d5601c2017-02-21 16:06:19 -050070 // ColorType needs to match what the system configuration is.
71 if (colorType == kRGBA_8888_SkColorType || colorType == kBGRA_8888_SkColorType) {
72 colorType = kN32_SkColorType;
73 }
Kevin Lubick8c8b6182017-02-17 10:27:30 -050074 bool b;
75 fuzz->next(&b);
Kevin Lubickcdb4d3c2016-11-29 11:14:39 -050076 SkImageInfo info = SkImageInfo::Make(kBmpSize,
77 kBmpSize,
78 (SkColorType)colorType,
Kevin Lubick8c8b6182017-02-17 10:27:30 -050079 b ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
Kevin Lubickcdb4d3c2016-11-29 11:14:39 -050080 if (!bmp->tryAllocPixels(info)) {
Hal Canary2b0e6cd2018-07-09 12:43:39 -040081 SkDEBUGF("Bitmap not allocated\n");
Kevin Lubickcdb4d3c2016-11-29 11:14:39 -050082 }
Kevin Lubick8c8b6182017-02-17 10:27:30 -050083 SkColor c;
84 fuzz->next(&c);
85 bmp->eraseColor(c);
Kevin Lubickcdb4d3c2016-11-29 11:14:39 -050086
Kevin Lubickcdb4d3c2016-11-29 11:14:39 -050087 fuzz->next(&b);
88 SkPaint p;
89 if (b) {
90 init_paint(fuzz, &p);
91 }
92 else {
Kevin Lubickcdb4d3c2016-11-29 11:14:39 -050093 fuzz->next(&c);
94 p.setColor(c);
95 }
Kevin Lubickcdb4d3c2016-11-29 11:14:39 -050096}
Kevin Lubickfec1dea2016-11-22 13:57:18 -050097
98static void init_surface(Fuzz* fuzz, sk_sp<SkSurface>* s) {
99 uint8_t x, y;
100 fuzz->nextRange(&x, 1, kMaxX);
101 fuzz->nextRange(&y, 1, kMaxY);
Kevin Lubick5c93acf2023-05-09 12:11:43 -0400102 *s = SkSurfaces::Raster(SkImageInfo::MakeN32Premul(x, y));
Kevin Lubick1991f552018-02-27 10:59:10 -0500103
104 if (!*s) {
105 // Was possibly too big for the memory constrained fuzzing environments
Kevin Lubick539fb102023-05-11 13:54:20 -0400106 *s = SkSurfaces::Null(x, y);
Kevin Lubick1991f552018-02-27 10:59:10 -0500107 }
Kevin Lubickfec1dea2016-11-22 13:57:18 -0500108}
109
110
Mike Reed212e9062018-12-25 17:35:49 -0500111static void fuzz_drawText(Fuzz* fuzz, sk_sp<SkTypeface> typeface) {
John Stiles26bf5222023-10-17 10:29:41 -0400112 SkFont font(std::move(typeface));
Kevin Lubickfec1dea2016-11-22 13:57:18 -0500113 SkPaint p;
114 init_paint(fuzz, &p);
115 sk_sp<SkSurface> surface;
116 init_surface(fuzz, &surface);
117
118 char text[kTxtLen];
119 init_string(fuzz, text, kTxtLen);
120
121 SkScalar x, y;
122 fuzz->next(&x, &y);
123 // populate pts array
124 SkPoint pts[kPtsLen];
125 for (uint8_t i = 0; i < kPtsLen; ++i) {
126 pts[i].set(x, y);
Mike Reeda6d1c0a2019-01-03 23:29:38 -0500127 x += font.getSize();
Kevin Lubickfec1dea2016-11-22 13:57:18 -0500128 }
129
Kevin Lubickfec1dea2016-11-22 13:57:18 -0500130 bool b;
131 fuzz->next(&b);
Mike Reed212e9062018-12-25 17:35:49 -0500132 font.setForceAutoHinting(b);
Kevin Lubickfec1dea2016-11-22 13:57:18 -0500133 fuzz->next(&b);
Mike Reed212e9062018-12-25 17:35:49 -0500134 font.setEmbeddedBitmaps(b);
Kevin Lubickfec1dea2016-11-22 13:57:18 -0500135 fuzz->next(&b);
Mike Reed212e9062018-12-25 17:35:49 -0500136 font.setEmbolden(b);
Kevin Lubickfec1dea2016-11-22 13:57:18 -0500137 fuzz->next(&b);
Mike Reed212e9062018-12-25 17:35:49 -0500138 font.setEdging(b ? SkFont::Edging::kAntiAlias : SkFont::Edging::kSubpixelAntiAlias);
Kevin Lubickfec1dea2016-11-22 13:57:18 -0500139 fuzz->next(&b);
Mike Reed212e9062018-12-25 17:35:49 -0500140 font.setLinearMetrics(b);
Kevin Lubickfec1dea2016-11-22 13:57:18 -0500141 fuzz->next(&b);
Mike Reed212e9062018-12-25 17:35:49 -0500142 font.setSubpixel(b);
Kevin Lubickfec1dea2016-11-22 13:57:18 -0500143 fuzz->next(&x);
Mike Reed212e9062018-12-25 17:35:49 -0500144 font.setScaleX(x);
Kevin Lubickfec1dea2016-11-22 13:57:18 -0500145 fuzz->next(&x);
Mike Reed212e9062018-12-25 17:35:49 -0500146 font.setSkewX(x);
Kevin Lubickfec1dea2016-11-22 13:57:18 -0500147 fuzz->next(&x);
Mike Reed212e9062018-12-25 17:35:49 -0500148 font.setSize(x);
Kevin Lubickfec1dea2016-11-22 13:57:18 -0500149
150 SkCanvas* cnv = surface->getCanvas();
Kevin Lubickfec1dea2016-11-22 13:57:18 -0500151 fuzz->next(&x);
152 fuzz->next(&y);
Mike Reed212e9062018-12-25 17:35:49 -0500153 cnv->drawTextBlob(SkTextBlob::MakeFromPosText(text, kTxtLen-1, pts, font), x, y, p);
Kevin Lubickfec1dea2016-11-22 13:57:18 -0500154}
155
156static void fuzz_drawCircle(Fuzz* fuzz) {
157 SkPaint p;
158 init_paint(fuzz, &p);
159 sk_sp<SkSurface> surface;
160 init_surface(fuzz, &surface);
161
162 SkScalar a, b, c;
163 fuzz->next(&a, &b, &c);
164 surface->getCanvas()->drawCircle(a, b, c, p);
165}
166
167static void fuzz_drawLine(Fuzz* fuzz) {
168 SkPaint p;
169 init_paint(fuzz, &p);
170 sk_sp<SkSurface> surface;
171 init_surface(fuzz, &surface);
172
173 SkScalar a, b, c, d;
174 fuzz->next(&a, &b, &c, &d);
175 surface->getCanvas()->drawLine(a, b, c, d, p);
176}
177
178static void fuzz_drawRect(Fuzz* fuzz) {
179 SkPaint p;
180 init_paint(fuzz, &p);
181 sk_sp<SkSurface> surface;
182 init_surface(fuzz, &surface);
183
184 SkScalar a, b, c, d;
185 fuzz->next(&a, &b, &c, &d);
186 SkRect r;
187 r = SkRect::MakeXYWH(a, b, c, d);
188
189 SkCanvas* cnv = surface->getCanvas();
190 cnv->drawRect(r, p);
191
192 bool bl;
193 fuzz->next(&bl);
194 fuzz->next(&a, &b, &c, &d);
195 r = SkRect::MakeXYWH(a, b, c, d);
Michael Ludwig2f6e2f82021-08-03 13:08:50 -0400196 cnv->clipRect(r, SkClipOp::kIntersect, bl);
Kevin Lubickfec1dea2016-11-22 13:57:18 -0500197}
198
199static void fuzz_drawPath(Fuzz* fuzz) {
200 SkPaint p;
201 init_paint(fuzz, &p);
202 sk_sp<SkSurface> surface;
203 init_surface(fuzz, &surface);
204
205 // TODO(kjlubick): put the ability to fuzz a path in shared file, with
206 // other common things (e.g. rects, lines)
207 uint8_t i, j;
208 fuzz->nextRange(&i, 0, 10); // set i to number of operations to perform
209 SkPath path;
210 SkScalar a, b, c, d, e, f;
211 for (int k = 0; k < i; ++k) {
212 fuzz->nextRange(&j, 0, 5); // set j to choose operation to perform
213 switch (j) {
214 case 0:
215 fuzz->next(&a, &b);
216 path.moveTo(a, b);
217 break;
218 case 1:
219 fuzz->next(&a, &b);
220 path.lineTo(a, b);
221 break;
222 case 2:
223 fuzz->next(&a, &b, &c, &d);
224 path.quadTo(a, b, c, d);
225 break;
226 case 3:
227 fuzz->next(&a, &b, &c, &d, &e);
228 path.conicTo(a, b, c, d, e);
229 break;
230 case 4:
231 fuzz->next(&a, &b, &c, &d, &e, &f);
232 path.cubicTo(a, b, c, d, e, f);
233 break;
234 case 5:
235 fuzz->next(&a, &b, &c, &d, &e);
236 path.arcTo(a, b, c, d, e);
237 break;
238 }
239 }
240 path.close();
241
242 SkCanvas* cnv = surface->getCanvas();
243 cnv->drawPath(path, p);
244
245 bool bl;
246 fuzz->next(&bl);
Michael Ludwig2f6e2f82021-08-03 13:08:50 -0400247 cnv->clipPath(path, SkClipOp::kIntersect, bl);
Kevin Lubickfec1dea2016-11-22 13:57:18 -0500248}
249
Kevin Lubickfec1dea2016-11-22 13:57:18 -0500250static void fuzz_drawImage(Fuzz* fuzz) {
251 SkPaint p;
252 init_paint(fuzz, &p);
253 sk_sp<SkSurface> surface;
254 init_surface(fuzz, &surface);
255 SkBitmap bmp;
256 init_bitmap(fuzz, &bmp);
257
Mike Reeddc607e32020-12-23 11:50:36 -0500258 sk_sp<SkImage> image(bmp.asImage());
Kevin Lubickfec1dea2016-11-22 13:57:18 -0500259
260 bool bl;
261 fuzz->next(&bl);
262 SkScalar a, b;
263 fuzz->next(&a, &b);
264 if (bl) {
Mike Reede02d7f82021-01-21 22:25:21 -0500265 surface->getCanvas()->drawImage(image, a, b, SkSamplingOptions(), &p);
Kevin Lubickfec1dea2016-11-22 13:57:18 -0500266 }
267 else {
268 SkRect dst = SkRect::MakeWH(a, b);
269 fuzz->next(&a, &b);
270 SkRect src = SkRect::MakeWH(a, b);
271 uint8_t x;
272 fuzz->nextRange(&x, 0, 1);
273 SkCanvas::SrcRectConstraint cst = (SkCanvas::SrcRectConstraint)x;
Mike Reede02d7f82021-01-21 22:25:21 -0500274 surface->getCanvas()->drawImageRect(image.get(), src, dst, SkSamplingOptions(), &p, cst);
Kevin Lubickfec1dea2016-11-22 13:57:18 -0500275 }
276}
277
278static void fuzz_drawPaint(Fuzz* fuzz) {
279 SkPaint l, p;
280 init_paint(fuzz, &p);
281 sk_sp<SkSurface> surface;
282 init_surface(fuzz, &surface);
283
Kevin Lubickfec1dea2016-11-22 13:57:18 -0500284 surface->getCanvas()->drawPaint(p);
285}
286
287DEF_FUZZ(DrawFunctions, fuzz) {
288 uint8_t i;
289 fuzz->next(&i);
290
291 switch(i) {
292 case 0: {
Kevin Lubickbca43ec2023-10-30 10:11:22 -0400293 sk_sp<SkTypeface> f = ToolUtils::DefaultPortableTypeface();
Kevin Lubickfec1dea2016-11-22 13:57:18 -0500294 if (f == nullptr) {
295 SkDebugf("Could not initialize font.\n");
296 fuzz->signalBug();
297 }
Hal Canary2b0e6cd2018-07-09 12:43:39 -0400298 SkDEBUGF("Fuzz DrawText\n");
Kevin Lubickfec1dea2016-11-22 13:57:18 -0500299 fuzz_drawText(fuzz, f);
300 return;
301 }
302 case 1:
Hal Canary2b0e6cd2018-07-09 12:43:39 -0400303 SkDEBUGF("Fuzz DrawRect\n");
Kevin Lubickfec1dea2016-11-22 13:57:18 -0500304 fuzz_drawRect(fuzz);
305 return;
306 case 2:
Hal Canary2b0e6cd2018-07-09 12:43:39 -0400307 SkDEBUGF("Fuzz DrawCircle\n");
Kevin Lubickfec1dea2016-11-22 13:57:18 -0500308 fuzz_drawCircle(fuzz);
309 return;
310 case 3:
Hal Canary2b0e6cd2018-07-09 12:43:39 -0400311 SkDEBUGF("Fuzz DrawLine\n");
Kevin Lubickfec1dea2016-11-22 13:57:18 -0500312 fuzz_drawLine(fuzz);
313 return;
314 case 4:
Hal Canary2b0e6cd2018-07-09 12:43:39 -0400315 SkDEBUGF("Fuzz DrawPath\n");
Kevin Lubickfec1dea2016-11-22 13:57:18 -0500316 fuzz_drawPath(fuzz);
317 return;
318 case 5:
Hal Canary2b0e6cd2018-07-09 12:43:39 -0400319 SkDEBUGF("Fuzz DrawImage/DrawImageRect\n");
Kevin Lubickfec1dea2016-11-22 13:57:18 -0500320 fuzz_drawImage(fuzz);
321 return;
322 case 6:
Hal Canary2b0e6cd2018-07-09 12:43:39 -0400323 SkDEBUGF("Fuzz DrawPaint\n");
Kevin Lubickfec1dea2016-11-22 13:57:18 -0500324 fuzz_drawPaint(fuzz);
325 return;
326 }
327}