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