blob: e9e4f8e041a83ffa38662ea2ecd2de093d62bf3d [file] [log] [blame]
/*
* 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;
}
}