| /* |
| * Copyright 2016 Mozilla Foundation |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include "Fuzz.h" |
| #include "SkBitmap.h" |
| #include "SkCanvas.h" |
| #include "SkFont.h" |
| #include "SkImage.h" |
| #include "SkPath.h" |
| #include "SkSurface.h" |
| #include "SkTextBlob.h" |
| #include "SkTypeface.h" |
| #include "SkClipOpPriv.h" |
| |
| static const int kBmpSize = 24; |
| static const int kMaxX = 250; |
| static const int kMaxY = 250; |
| static const int kPtsLen = 10; |
| static const int kTxtLen = 5; |
| |
| static void init_string(Fuzz* fuzz, char* str, size_t bufSize) { |
| for (size_t i = 0; i < bufSize-1; ++i) { |
| fuzz->nextRange(&str[i], 0x20, 0x7E); // printable ASCII |
| } |
| str[bufSize-1] = '\0'; |
| } |
| |
| // make_paint mostly borrowed from FilterFuzz.cpp |
| static void init_paint(Fuzz* fuzz, SkPaint* p) { |
| bool b; |
| fuzz->next(&b); |
| p->setAntiAlias(b); |
| |
| uint8_t tmp_u8; |
| fuzz->nextRange(&tmp_u8, 0, (int)SkBlendMode::kLastMode); |
| p->setBlendMode(static_cast<SkBlendMode>(tmp_u8)); |
| |
| SkColor co; |
| fuzz->next(&co); |
| p->setColor(co); |
| |
| fuzz->next(&b); |
| p->setDither(b); |
| |
| fuzz->nextRange(&tmp_u8, 0, (int)kHigh_SkFilterQuality); |
| p->setFilterQuality(static_cast<SkFilterQuality>(tmp_u8)); |
| |
| fuzz->nextRange(&tmp_u8, 0, (int)SkPaint::kLast_Cap); |
| p->setStrokeCap(static_cast<SkPaint::Cap>(tmp_u8)); |
| |
| fuzz->nextRange(&tmp_u8, 0, (int)SkPaint::kLast_Join); |
| p->setStrokeJoin(static_cast<SkPaint::Join>(tmp_u8)); |
| |
| SkScalar sc; |
| fuzz->next(&sc); |
| p->setStrokeMiter(sc); |
| |
| fuzz->next(&sc); |
| p->setStrokeWidth(sc); |
| |
| fuzz->nextRange(&tmp_u8, 0, (int)SkPaint::kStrokeAndFill_Style); |
| p->setStyle(static_cast<SkPaint::Style>(tmp_u8)); |
| } |
| |
| static void init_bitmap(Fuzz* fuzz, SkBitmap* bmp) { |
| uint8_t colorType; |
| fuzz->nextRange(&colorType, 0, (int)kLastEnum_SkColorType); |
| // ColorType needs to match what the system configuration is. |
| if (colorType == kRGBA_8888_SkColorType || colorType == kBGRA_8888_SkColorType) { |
| colorType = kN32_SkColorType; |
| } |
| bool b; |
| fuzz->next(&b); |
| SkImageInfo info = SkImageInfo::Make(kBmpSize, |
| kBmpSize, |
| (SkColorType)colorType, |
| b ? kOpaque_SkAlphaType : kPremul_SkAlphaType); |
| if (!bmp->tryAllocPixels(info)) { |
| SkDEBUGF("Bitmap not allocated\n"); |
| } |
| SkColor c; |
| fuzz->next(&c); |
| bmp->eraseColor(c); |
| |
| fuzz->next(&b); |
| SkPaint p; |
| if (b) { |
| init_paint(fuzz, &p); |
| } |
| else { |
| fuzz->next(&c); |
| p.setColor(c); |
| } |
| } |
| |
| static void init_surface(Fuzz* fuzz, sk_sp<SkSurface>* s) { |
| uint8_t x, y; |
| fuzz->nextRange(&x, 1, kMaxX); |
| fuzz->nextRange(&y, 1, kMaxY); |
| *s = SkSurface::MakeRasterN32Premul(x, y); |
| |
| if (!*s) { |
| // Was possibly too big for the memory constrained fuzzing environments |
| *s = SkSurface::MakeNull(x, y); |
| } |
| } |
| |
| |
| static void fuzz_drawText(Fuzz* fuzz, sk_sp<SkTypeface> typeface) { |
| SkFont font(typeface); |
| SkPaint p; |
| init_paint(fuzz, &p); |
| sk_sp<SkSurface> surface; |
| init_surface(fuzz, &surface); |
| |
| char text[kTxtLen]; |
| init_string(fuzz, text, kTxtLen); |
| |
| SkScalar x, y; |
| fuzz->next(&x, &y); |
| // populate pts array |
| SkPoint pts[kPtsLen]; |
| for (uint8_t i = 0; i < kPtsLen; ++i) { |
| pts[i].set(x, y); |
| x += font.getSize(); |
| } |
| |
| bool b; |
| fuzz->next(&b); |
| font.setForceAutoHinting(b); |
| fuzz->next(&b); |
| font.setEmbeddedBitmaps(b); |
| fuzz->next(&b); |
| font.setEmbolden(b); |
| fuzz->next(&b); |
| font.setEdging(b ? SkFont::Edging::kAntiAlias : SkFont::Edging::kSubpixelAntiAlias); |
| fuzz->next(&b); |
| font.setLinearMetrics(b); |
| fuzz->next(&b); |
| font.setSubpixel(b); |
| fuzz->next(&x); |
| font.setScaleX(x); |
| fuzz->next(&x); |
| font.setSkewX(x); |
| fuzz->next(&x); |
| font.setSize(x); |
| |
| SkCanvas* cnv = surface->getCanvas(); |
| fuzz->next(&x); |
| fuzz->next(&y); |
| cnv->drawTextBlob(SkTextBlob::MakeFromPosText(text, kTxtLen-1, pts, font), x, y, p); |
| } |
| |
| static void fuzz_drawCircle(Fuzz* fuzz) { |
| SkPaint p; |
| init_paint(fuzz, &p); |
| sk_sp<SkSurface> surface; |
| init_surface(fuzz, &surface); |
| |
| SkScalar a, b, c; |
| fuzz->next(&a, &b, &c); |
| surface->getCanvas()->drawCircle(a, b, c, p); |
| } |
| |
| static void fuzz_drawLine(Fuzz* fuzz) { |
| SkPaint p; |
| init_paint(fuzz, &p); |
| sk_sp<SkSurface> surface; |
| init_surface(fuzz, &surface); |
| |
| SkScalar a, b, c, d; |
| fuzz->next(&a, &b, &c, &d); |
| surface->getCanvas()->drawLine(a, b, c, d, p); |
| } |
| |
| static void fuzz_drawRect(Fuzz* fuzz) { |
| SkPaint p; |
| init_paint(fuzz, &p); |
| sk_sp<SkSurface> surface; |
| init_surface(fuzz, &surface); |
| |
| SkScalar a, b, c, d; |
| fuzz->next(&a, &b, &c, &d); |
| SkRect r; |
| r = SkRect::MakeXYWH(a, b, c, d); |
| |
| SkCanvas* cnv = surface->getCanvas(); |
| cnv->drawRect(r, p); |
| |
| bool bl; |
| fuzz->next(&bl); |
| fuzz->next(&a, &b, &c, &d); |
| r = SkRect::MakeXYWH(a, b, c, d); |
| cnv->clipRect(r, kIntersect_SkClipOp, bl); |
| } |
| |
| static void fuzz_drawPath(Fuzz* fuzz) { |
| SkPaint p; |
| init_paint(fuzz, &p); |
| sk_sp<SkSurface> surface; |
| init_surface(fuzz, &surface); |
| |
| // TODO(kjlubick): put the ability to fuzz a path in shared file, with |
| // other common things (e.g. rects, lines) |
| uint8_t i, j; |
| fuzz->nextRange(&i, 0, 10); // set i to number of operations to perform |
| SkPath path; |
| SkScalar a, b, c, d, e, f; |
| for (int k = 0; k < i; ++k) { |
| fuzz->nextRange(&j, 0, 5); // set j to choose operation to perform |
| switch (j) { |
| case 0: |
| fuzz->next(&a, &b); |
| path.moveTo(a, b); |
| break; |
| case 1: |
| fuzz->next(&a, &b); |
| path.lineTo(a, b); |
| break; |
| case 2: |
| fuzz->next(&a, &b, &c, &d); |
| path.quadTo(a, b, c, d); |
| break; |
| case 3: |
| fuzz->next(&a, &b, &c, &d, &e); |
| path.conicTo(a, b, c, d, e); |
| break; |
| case 4: |
| fuzz->next(&a, &b, &c, &d, &e, &f); |
| path.cubicTo(a, b, c, d, e, f); |
| break; |
| case 5: |
| fuzz->next(&a, &b, &c, &d, &e); |
| path.arcTo(a, b, c, d, e); |
| break; |
| } |
| } |
| path.close(); |
| |
| SkCanvas* cnv = surface->getCanvas(); |
| cnv->drawPath(path, p); |
| |
| bool bl; |
| fuzz->next(&bl); |
| cnv->clipPath(path, kIntersect_SkClipOp, bl); |
| } |
| |
| static void fuzz_drawBitmap(Fuzz* fuzz) { |
| SkPaint p; |
| init_paint(fuzz, &p); |
| sk_sp<SkSurface> surface; |
| init_surface(fuzz, &surface); |
| SkBitmap bmp; |
| init_bitmap(fuzz, &bmp); |
| |
| SkScalar a, b; |
| fuzz->next(&a, &b); |
| surface->getCanvas()->drawBitmap(bmp, a, b, &p); |
| } |
| |
| static void fuzz_drawImage(Fuzz* fuzz) { |
| SkPaint p; |
| init_paint(fuzz, &p); |
| sk_sp<SkSurface> surface; |
| init_surface(fuzz, &surface); |
| SkBitmap bmp; |
| init_bitmap(fuzz, &bmp); |
| |
| sk_sp<SkImage> image(SkImage::MakeFromBitmap(bmp)); |
| |
| bool bl; |
| fuzz->next(&bl); |
| SkScalar a, b; |
| fuzz->next(&a, &b); |
| if (bl) { |
| surface->getCanvas()->drawImage(image, a, b, &p); |
| } |
| else { |
| SkRect dst = SkRect::MakeWH(a, b); |
| fuzz->next(&a, &b); |
| SkRect src = SkRect::MakeWH(a, b); |
| uint8_t x; |
| fuzz->nextRange(&x, 0, 1); |
| SkCanvas::SrcRectConstraint cst = (SkCanvas::SrcRectConstraint)x; |
| surface->getCanvas()->drawImageRect(image, src, dst, &p, cst); |
| } |
| } |
| |
| static void fuzz_drawPaint(Fuzz* fuzz) { |
| SkPaint l, p; |
| init_paint(fuzz, &p); |
| sk_sp<SkSurface> surface; |
| init_surface(fuzz, &surface); |
| |
| surface->getCanvas()->drawPaint(p); |
| } |
| |
| DEF_FUZZ(DrawFunctions, fuzz) { |
| uint8_t i; |
| fuzz->next(&i); |
| |
| switch(i) { |
| case 0: { |
| sk_sp<SkTypeface> f = SkTypeface::MakeDefault(); |
| if (f == nullptr) { |
| SkDebugf("Could not initialize font.\n"); |
| fuzz->signalBug(); |
| } |
| SkDEBUGF("Fuzz DrawText\n"); |
| fuzz_drawText(fuzz, f); |
| return; |
| } |
| case 1: |
| SkDEBUGF("Fuzz DrawRect\n"); |
| fuzz_drawRect(fuzz); |
| return; |
| case 2: |
| SkDEBUGF("Fuzz DrawCircle\n"); |
| fuzz_drawCircle(fuzz); |
| return; |
| case 3: |
| SkDEBUGF("Fuzz DrawLine\n"); |
| fuzz_drawLine(fuzz); |
| return; |
| case 4: |
| SkDEBUGF("Fuzz DrawPath\n"); |
| fuzz_drawPath(fuzz); |
| return; |
| case 5: |
| SkDEBUGF("Fuzz DrawImage/DrawImageRect\n"); |
| fuzz_drawImage(fuzz); |
| return; |
| case 6: |
| SkDEBUGF("Fuzz DrawBitmap\n"); |
| fuzz_drawBitmap(fuzz); |
| return; |
| case 7: |
| SkDEBUGF("Fuzz DrawPaint\n"); |
| fuzz_drawPaint(fuzz); |
| return; |
| } |
| } |