|  | /* | 
|  | * 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/Fuzz.h" | 
|  | #include "include/core/SkBitmap.h" | 
|  | #include "include/core/SkCanvas.h" | 
|  | #include "include/core/SkFont.h" | 
|  | #include "include/core/SkImage.h" | 
|  | #include "include/core/SkPath.h" | 
|  | #include "include/core/SkSurface.h" | 
|  | #include "include/core/SkTextBlob.h" | 
|  | #include "include/core/SkTypeface.h" | 
|  | #include "src/core/SkPaintPriv.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)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 = SkSurfaces::Raster(SkImageInfo::MakeN32Premul(x, y)); | 
|  |  | 
|  | if (!*s) { | 
|  | // Was possibly too big for the memory constrained fuzzing environments | 
|  | *s = SkSurfaces::Null(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, SkClipOp::kIntersect, 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, SkClipOp::kIntersect, bl); | 
|  | } | 
|  |  | 
|  | 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(bmp.asImage()); | 
|  |  | 
|  | bool bl; | 
|  | fuzz->next(&bl); | 
|  | SkScalar a, b; | 
|  | fuzz->next(&a, &b); | 
|  | if (bl) { | 
|  | surface->getCanvas()->drawImage(image, a, b, SkSamplingOptions(), &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.get(), src, dst, SkSamplingOptions(), &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 DrawPaint\n"); | 
|  | fuzz_drawPaint(fuzz); | 
|  | return; | 
|  | } | 
|  | } |