/* * 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; } }