FuzzDrawFunctions from twsmith

BUG=skia:

GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=4979

Change-Id: Ib5cc6ea036538b611d6959c679a276050e145f57
Reviewed-on: https://skia-review.googlesource.com/4979
Reviewed-by: Mike Klein <mtklein@chromium.org>
diff --git a/BUILD.gn b/BUILD.gn
index 501c568..a5b4d37 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -1233,6 +1233,7 @@
   executable("fuzz") {
     sources = [
       "fuzz/FilterFuzz.cpp",
+      "fuzz/FuzzDrawFunctions.cpp",
       "fuzz/FuzzGradients.cpp",
       "fuzz/FuzzParsePath.cpp",
       "fuzz/FuzzPathop.cpp",
diff --git a/fuzz/FuzzDrawFunctions.cpp b/fuzz/FuzzDrawFunctions.cpp
new file mode 100644
index 0000000..b73bbf9
--- /dev/null
+++ b/fuzz/FuzzDrawFunctions.cpp
@@ -0,0 +1,358 @@
+/*
+ * 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"
+
+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_bitmap(Fuzz* fuzz, SkBitmap* bmp) {
+    uint8_t colorType;
+    fuzz->nextRange(&colorType, 0, (int)kLastEnum_SkColorType);
+    SkImageInfo info = SkImageInfo::Make(kBmpSize,
+                                         kBmpSize,
+                                         (SkColorType)colorType,
+                                         kPremul_SkAlphaType);
+    if (!bmp->tryAllocPixels(info)) {
+        SkDebugf("Bitmap not allocated\n");
+    }
+    bool b;
+    fuzz->next(&b);
+    if (b) { // initialize
+        SkCanvas canvas(*bmp);
+        canvas.clear(0);
+        SkColor c;
+        fuzz->next(&c);
+        SkPaint p; // TODO: maybe init_paint?
+        p.setColor(c);
+        canvas.drawRect(SkRect::MakeXYWH(0, 0, kBmpSize, kBmpSize), p);
+    }
+}
+
+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_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.setStrikeThruText(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.setUnderlineText(b);
+    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, SkCanvas::kIntersect_Op, 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, SkCanvas::kIntersect_Op, 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;
+    }
+}