| /* | 
 |  * 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 "SkImage.h" | 
 | #include "SkLayerRasterizer.h" | 
 | #include "SkPath.h" | 
 | #include "SkSurface.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::kFull_Hinting); | 
 |     p->setHinting(static_cast<SkPaint::Hinting>(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); | 
 | } | 
 |  | 
 |  | 
 | static void fuzz_drawText(Fuzz* fuzz, sk_sp<SkTypeface> font) { | 
 |     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 += p.getTextSize(); | 
 |     } | 
 |  | 
 |     p.setTypeface(font); | 
 |     // set text related attributes | 
 |     bool b; | 
 |     fuzz->next(&b); | 
 |     p.setAutohinted(b); | 
 |     fuzz->next(&b); | 
 |     p.setDevKernText(b); | 
 |     fuzz->next(&b); | 
 |     p.setEmbeddedBitmapText(b); | 
 |     fuzz->next(&b); | 
 |     p.setFakeBoldText(b); | 
 |     fuzz->next(&b); | 
 |     p.setLCDRenderText(b); | 
 |     fuzz->next(&b); | 
 |     p.setLinearText(b); | 
 |     fuzz->next(&b); | 
 |     p.setSubpixelText(b); | 
 |     fuzz->next(&x); | 
 |     p.setTextScaleX(x); | 
 |     fuzz->next(&x); | 
 |     p.setTextSkewX(x); | 
 |     fuzz->next(&x); | 
 |     p.setTextSize(x); | 
 |     fuzz->next(&b); | 
 |     p.setVerticalText(b); | 
 |  | 
 |     SkCanvas* cnv = surface->getCanvas(); | 
 |     cnv->drawPosText(text, (kTxtLen-1), pts, p); | 
 |  | 
 |     fuzz->next(&x); | 
 |     fuzz->next(&y); | 
 |     cnv->drawText(text, (kTxtLen-1), 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); | 
 |  | 
 |     // add layers | 
 |     uint8_t x; | 
 |     fuzz->nextRange(&x, 1, 3); // max 3 layers | 
 |     SkLayerRasterizer::Builder builder; | 
 |     for (int i = 0; i < x; i++) { | 
 |         init_paint(fuzz, &l); | 
 |         builder.addLayer(l); | 
 |     } | 
 |  | 
 |     sk_sp<SkLayerRasterizer> raster(builder.detach()); | 
 |     p.setRasterizer(raster); | 
 |  | 
 |     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; | 
 |     } | 
 | } |