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/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"
17#include "src/core/SkPaintPriv.h"
18
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
25static 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
49    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
66static void init_bitmap(Fuzz* fuzz, SkBitmap* bmp) {
67    uint8_t colorType;
68    fuzz->nextRange(&colorType, 0, (int)kLastEnum_SkColorType);
69    // ColorType needs to match what the system configuration is.
70    if (colorType == kRGBA_8888_SkColorType || colorType == kBGRA_8888_SkColorType) {
71        colorType = kN32_SkColorType;
72    }
73    bool b;
74    fuzz->next(&b);
75    SkImageInfo info = SkImageInfo::Make(kBmpSize,
76                                         kBmpSize,
77                                         (SkColorType)colorType,
78                                         b ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
79    if (!bmp->tryAllocPixels(info)) {
80        SkDEBUGF("Bitmap not allocated\n");
81    }
82    SkColor c;
83    fuzz->next(&c);
84    bmp->eraseColor(c);
85
86    fuzz->next(&b);
87    SkPaint p;
88    if (b) {
89        init_paint(fuzz, &p);
90    }
91    else {
92        fuzz->next(&c);
93        p.setColor(c);
94    }
95}
96
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);
102
103    if (!*s) {
104        // Was possibly too big for the memory constrained fuzzing environments
105        *s = SkSurface::MakeNull(x, y);
106    }
107}
108
109
110static void fuzz_drawText(Fuzz* fuzz, sk_sp<SkTypeface> typeface) {
111    SkFont font(typeface);
112    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);
126        x += font.getSize();
127    }
128
129    bool b;
130    fuzz->next(&b);
131    font.setForceAutoHinting(b);
132    fuzz->next(&b);
133    font.setEmbeddedBitmaps(b);
134    fuzz->next(&b);
135    font.setEmbolden(b);
136    fuzz->next(&b);
137    font.setEdging(b ? SkFont::Edging::kAntiAlias : SkFont::Edging::kSubpixelAntiAlias);
138    fuzz->next(&b);
139    font.setLinearMetrics(b);
140    fuzz->next(&b);
141    font.setSubpixel(b);
142    fuzz->next(&x);
143    font.setScaleX(x);
144    fuzz->next(&x);
145    font.setSkewX(x);
146    fuzz->next(&x);
147    font.setSize(x);
148
149    SkCanvas* cnv = surface->getCanvas();
150    fuzz->next(&x);
151    fuzz->next(&y);
152    cnv->drawTextBlob(SkTextBlob::MakeFromPosText(text, kTxtLen-1, pts, font), x, y, p);
153}
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);
195    cnv->clipRect(r, SkClipOp::kIntersect, bl);
196}
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);
246    cnv->clipPath(path, SkClipOp::kIntersect, bl);
247}
248
249static 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
257    sk_sp<SkImage> image(bmp.asImage());
258
259    bool bl;
260    fuzz->next(&bl);
261    SkScalar a, b;
262    fuzz->next(&a, &b);
263    if (bl) {
264        surface->getCanvas()->drawImage(image, a, b, SkSamplingOptions(), &p);
265    }
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;
273        surface->getCanvas()->drawImageRect(image.get(), src, dst, SkSamplingOptions(), &p, cst);
274    }
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
283    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            }
297            SkDEBUGF("Fuzz DrawText\n");
298            fuzz_drawText(fuzz, f);
299            return;
300        }
301        case 1:
302            SkDEBUGF("Fuzz DrawRect\n");
303            fuzz_drawRect(fuzz);
304            return;
305        case 2:
306            SkDEBUGF("Fuzz DrawCircle\n");
307            fuzz_drawCircle(fuzz);
308            return;
309        case 3:
310            SkDEBUGF("Fuzz DrawLine\n");
311            fuzz_drawLine(fuzz);
312            return;
313        case 4:
314            SkDEBUGF("Fuzz DrawPath\n");
315            fuzz_drawPath(fuzz);
316            return;
317        case 5:
318            SkDEBUGF("Fuzz DrawImage/DrawImageRect\n");
319            fuzz_drawImage(fuzz);
320            return;
321        case 6:
322            SkDEBUGF("Fuzz DrawPaint\n");
323            fuzz_drawPaint(fuzz);
324            return;
325    }
326}
327