1 /*
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 
8 #include "Fuzz.h"
9 #include "SkBitmap.h"
10 #include "SkCanvas.h"
11 #include "SkImage.h"
12 #include "SkLayerRasterizer.h"
13 #include "SkPath.h"
14 #include "SkSurface.h"
15 #include "SkTypeface.h"
16 #include "SkClipOpPriv.h"
17 
18 static const int kBmpSize = 24;
19 static const int kMaxX = 250;
20 static const int kMaxY = 250;
21 static const int kPtsLen = 10;
22 static const int kTxtLen = 5;
23 
init_string(Fuzz * fuzz,char * str,size_t bufSize)24 static void init_string(Fuzz* fuzz, char* str, size_t bufSize) {
25     for (size_t i = 0; i < bufSize-1; ++i) {
26         fuzz->nextRange(&str[i], 0x20, 0x7E); // printable ASCII
27     }
28     str[bufSize-1] = '\0';
29 }
30 
31 // make_paint mostly borrowed from FilterFuzz.cpp
init_paint(Fuzz * fuzz,SkPaint * p)32 static void init_paint(Fuzz* fuzz, SkPaint* p) {
33     bool b;
34     fuzz->next(&b);
35     p->setAntiAlias(b);
36 
37     uint8_t tmp_u8;
38     fuzz->nextRange(&tmp_u8, 0, (int)SkBlendMode::kLastMode);
39     p->setBlendMode(static_cast<SkBlendMode>(tmp_u8));
40 
41     SkColor co;
42     fuzz->next(&co);
43     p->setColor(co);
44 
45     fuzz->next(&b);
46     p->setDither(b);
47 
48     fuzz->nextRange(&tmp_u8, 0, (int)kHigh_SkFilterQuality);
49     p->setFilterQuality(static_cast<SkFilterQuality>(tmp_u8));
50 
51     fuzz->nextRange(&tmp_u8, 0, (int)SkPaint::kFull_Hinting);
52     p->setHinting(static_cast<SkPaint::Hinting>(tmp_u8));
53 
54     fuzz->nextRange(&tmp_u8, 0, (int)SkPaint::kLast_Cap);
55     p->setStrokeCap(static_cast<SkPaint::Cap>(tmp_u8));
56 
57     fuzz->nextRange(&tmp_u8, 0, (int)SkPaint::kLast_Join);
58     p->setStrokeJoin(static_cast<SkPaint::Join>(tmp_u8));
59 
60     SkScalar sc;
61     fuzz->next(&sc);
62     p->setStrokeMiter(sc);
63 
64     fuzz->next(&sc);
65     p->setStrokeWidth(sc);
66 
67     fuzz->nextRange(&tmp_u8, 0, (int)SkPaint::kStrokeAndFill_Style);
68     p->setStyle(static_cast<SkPaint::Style>(tmp_u8));
69 }
70 
init_bitmap(Fuzz * fuzz,SkBitmap * bmp)71 static void init_bitmap(Fuzz* fuzz, SkBitmap* bmp) {
72     uint8_t colorType;
73     fuzz->nextRange(&colorType, 0, (int)kLastEnum_SkColorType);
74     // ColorType needs to match what the system configuration is.
75     if (colorType == kRGBA_8888_SkColorType || colorType == kBGRA_8888_SkColorType) {
76         colorType = kN32_SkColorType;
77     }
78     bool b;
79     fuzz->next(&b);
80     SkImageInfo info = SkImageInfo::Make(kBmpSize,
81                                          kBmpSize,
82                                          (SkColorType)colorType,
83                                          b ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
84     if (!bmp->tryAllocPixels(info)) {
85         SkDebugf("Bitmap not allocated\n");
86     }
87     SkColor c;
88     fuzz->next(&c);
89     bmp->eraseColor(c);
90 
91     fuzz->next(&b);
92     SkPaint p;
93     if (b) {
94         init_paint(fuzz, &p);
95     }
96     else {
97         fuzz->next(&c);
98         p.setColor(c);
99     }
100 }
101 
init_surface(Fuzz * fuzz,sk_sp<SkSurface> * s)102 static void init_surface(Fuzz* fuzz, sk_sp<SkSurface>* s) {
103     uint8_t x, y;
104     fuzz->nextRange(&x, 1, kMaxX);
105     fuzz->nextRange(&y, 1, kMaxY);
106     *s = SkSurface::MakeRasterN32Premul(x, y);
107 }
108 
109 
fuzz_drawText(Fuzz * fuzz,sk_sp<SkTypeface> font)110 static void fuzz_drawText(Fuzz* fuzz, sk_sp<SkTypeface> font) {
111     SkPaint p;
112     init_paint(fuzz, &p);
113     sk_sp<SkSurface> surface;
114     init_surface(fuzz, &surface);
115 
116     char text[kTxtLen];
117     init_string(fuzz, text, kTxtLen);
118 
119     SkScalar x, y;
120     fuzz->next(&x, &y);
121     // populate pts array
122     SkPoint pts[kPtsLen];
123     for (uint8_t i = 0; i < kPtsLen; ++i) {
124         pts[i].set(x, y);
125         x += p.getTextSize();
126     }
127 
128     p.setTypeface(font);
129     // set text related attributes
130     bool b;
131     fuzz->next(&b);
132     p.setAutohinted(b);
133     fuzz->next(&b);
134     p.setDevKernText(b);
135     fuzz->next(&b);
136     p.setEmbeddedBitmapText(b);
137     fuzz->next(&b);
138     p.setFakeBoldText(b);
139     fuzz->next(&b);
140     p.setLCDRenderText(b);
141     fuzz->next(&b);
142     p.setLinearText(b);
143     fuzz->next(&b);
144     p.setSubpixelText(b);
145     fuzz->next(&x);
146     p.setTextScaleX(x);
147     fuzz->next(&x);
148     p.setTextSkewX(x);
149     fuzz->next(&x);
150     p.setTextSize(x);
151     fuzz->next(&b);
152     p.setVerticalText(b);
153 
154     SkCanvas* cnv = surface->getCanvas();
155     cnv->drawPosText(text, (kTxtLen-1), pts, p);
156 
157     fuzz->next(&x);
158     fuzz->next(&y);
159     cnv->drawText(text, (kTxtLen-1), x, y, p);
160 }
161 
fuzz_drawCircle(Fuzz * fuzz)162 static void fuzz_drawCircle(Fuzz* fuzz) {
163     SkPaint p;
164     init_paint(fuzz, &p);
165     sk_sp<SkSurface> surface;
166     init_surface(fuzz, &surface);
167 
168     SkScalar a, b, c;
169     fuzz->next(&a, &b, &c);
170     surface->getCanvas()->drawCircle(a, b, c, p);
171 }
172 
fuzz_drawLine(Fuzz * fuzz)173 static void fuzz_drawLine(Fuzz* fuzz) {
174     SkPaint p;
175     init_paint(fuzz, &p);
176     sk_sp<SkSurface> surface;
177     init_surface(fuzz, &surface);
178 
179     SkScalar a, b, c, d;
180     fuzz->next(&a, &b, &c, &d);
181     surface->getCanvas()->drawLine(a, b, c, d, p);
182 }
183 
fuzz_drawRect(Fuzz * fuzz)184 static void fuzz_drawRect(Fuzz* fuzz) {
185     SkPaint p;
186     init_paint(fuzz, &p);
187     sk_sp<SkSurface> surface;
188     init_surface(fuzz, &surface);
189 
190     SkScalar a, b, c, d;
191     fuzz->next(&a, &b, &c, &d);
192     SkRect r;
193     r = SkRect::MakeXYWH(a, b, c, d);
194 
195     SkCanvas* cnv = surface->getCanvas();
196     cnv->drawRect(r, p);
197 
198     bool bl;
199     fuzz->next(&bl);
200     fuzz->next(&a, &b, &c, &d);
201     r = SkRect::MakeXYWH(a, b, c, d);
202     cnv->clipRect(r, kIntersect_SkClipOp, bl);
203 }
204 
fuzz_drawPath(Fuzz * fuzz)205 static void fuzz_drawPath(Fuzz* fuzz) {
206     SkPaint p;
207     init_paint(fuzz, &p);
208     sk_sp<SkSurface> surface;
209     init_surface(fuzz, &surface);
210 
211     // TODO(kjlubick): put the ability to fuzz a path in shared file, with
212     // other common things (e.g. rects, lines)
213     uint8_t i, j;
214     fuzz->nextRange(&i, 0, 10); // set i to number of operations to perform
215     SkPath path;
216     SkScalar a, b, c, d, e, f;
217     for (int k = 0; k < i; ++k) {
218         fuzz->nextRange(&j, 0, 5); // set j to choose operation to perform
219         switch (j) {
220             case 0:
221                 fuzz->next(&a, &b);
222                 path.moveTo(a, b);
223                 break;
224             case 1:
225                 fuzz->next(&a, &b);
226                 path.lineTo(a, b);
227                 break;
228             case 2:
229                 fuzz->next(&a, &b, &c, &d);
230                 path.quadTo(a, b, c, d);
231                 break;
232             case 3:
233                 fuzz->next(&a, &b, &c, &d, &e);
234                 path.conicTo(a, b, c, d, e);
235                 break;
236             case 4:
237                 fuzz->next(&a, &b, &c, &d, &e, &f);
238                 path.cubicTo(a, b, c, d, e, f);
239                 break;
240             case 5:
241                 fuzz->next(&a, &b, &c, &d, &e);
242                 path.arcTo(a, b, c, d, e);
243                 break;
244         }
245     }
246     path.close();
247 
248     SkCanvas* cnv = surface->getCanvas();
249     cnv->drawPath(path, p);
250 
251     bool bl;
252     fuzz->next(&bl);
253     cnv->clipPath(path, kIntersect_SkClipOp, bl);
254 }
255 
fuzz_drawBitmap(Fuzz * fuzz)256 static void fuzz_drawBitmap(Fuzz* fuzz) {
257     SkPaint p;
258     init_paint(fuzz, &p);
259     sk_sp<SkSurface> surface;
260     init_surface(fuzz, &surface);
261     SkBitmap bmp;
262     init_bitmap(fuzz, &bmp);
263 
264     SkScalar a, b;
265     fuzz->next(&a, &b);
266     surface->getCanvas()->drawBitmap(bmp, a, b, &p);
267 }
268 
fuzz_drawImage(Fuzz * fuzz)269 static void fuzz_drawImage(Fuzz* fuzz) {
270     SkPaint p;
271     init_paint(fuzz, &p);
272     sk_sp<SkSurface> surface;
273     init_surface(fuzz, &surface);
274     SkBitmap bmp;
275     init_bitmap(fuzz, &bmp);
276 
277     sk_sp<SkImage> image(SkImage::MakeFromBitmap(bmp));
278 
279     bool bl;
280     fuzz->next(&bl);
281     SkScalar a, b;
282     fuzz->next(&a, &b);
283     if (bl) {
284         surface->getCanvas()->drawImage(image, a, b, &p);
285     }
286     else {
287         SkRect dst = SkRect::MakeWH(a, b);
288         fuzz->next(&a, &b);
289         SkRect src = SkRect::MakeWH(a, b);
290         uint8_t x;
291         fuzz->nextRange(&x, 0, 1);
292         SkCanvas::SrcRectConstraint cst = (SkCanvas::SrcRectConstraint)x;
293         surface->getCanvas()->drawImageRect(image, src, dst, &p, cst);
294     }
295 }
296 
fuzz_drawPaint(Fuzz * fuzz)297 static void fuzz_drawPaint(Fuzz* fuzz) {
298     SkPaint l, p;
299     init_paint(fuzz, &p);
300     sk_sp<SkSurface> surface;
301     init_surface(fuzz, &surface);
302 
303     // add layers
304     uint8_t x;
305     fuzz->nextRange(&x, 1, 3); // max 3 layers
306     SkLayerRasterizer::Builder builder;
307     for (int i = 0; i < x; i++) {
308         init_paint(fuzz, &l);
309         builder.addLayer(l);
310     }
311 
312     sk_sp<SkLayerRasterizer> raster(builder.detach());
313     p.setRasterizer(raster);
314 
315     surface->getCanvas()->drawPaint(p);
316 }
317 
DEF_FUZZ(DrawFunctions,fuzz)318 DEF_FUZZ(DrawFunctions, fuzz) {
319     uint8_t i;
320     fuzz->next(&i);
321 
322     switch(i) {
323         case 0: {
324             sk_sp<SkTypeface> f = SkTypeface::MakeDefault();
325             if (f == nullptr) {
326               SkDebugf("Could not initialize font.\n");
327               fuzz->signalBug();
328             }
329             SkDebugf("Fuzz DrawText\n");
330             fuzz_drawText(fuzz, f);
331             return;
332         }
333         case 1:
334             SkDebugf("Fuzz DrawRect\n");
335             fuzz_drawRect(fuzz);
336             return;
337         case 2:
338             SkDebugf("Fuzz DrawCircle\n");
339             fuzz_drawCircle(fuzz);
340             return;
341         case 3:
342             SkDebugf("Fuzz DrawLine\n");
343             fuzz_drawLine(fuzz);
344             return;
345         case 4:
346             SkDebugf("Fuzz DrawPath\n");
347             fuzz_drawPath(fuzz);
348             return;
349         case 5:
350             SkDebugf("Fuzz DrawImage/DrawImageRect\n");
351             fuzz_drawImage(fuzz);
352             return;
353         case 6:
354             SkDebugf("Fuzz DrawBitmap\n");
355             fuzz_drawBitmap(fuzz);
356             return;
357         case 7:
358             SkDebugf("Fuzz DrawPaint\n");
359             fuzz_drawPaint(fuzz);
360             return;
361     }
362 }
363