Home | History | Annotate | Download | only in fuzz
      1 /*
      2  * Copyright 2016 Mozilla Foundation
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "Fuzz.h"
      9 #include "SkBitmap.h"
     10 #include "SkCanvas.h"
     11 #include "SkFont.h"
     12 #include "SkImage.h"
     13 #include "SkPath.h"
     14 #include "SkSurface.h"
     15 #include "SkTextBlob.h"
     16 #include "SkTypeface.h"
     17 #include "SkClipOpPriv.h"
     18 
     19 static const int kBmpSize = 24;
     20 static const int kMaxX = 250;
     21 static const int kMaxY = 250;
     22 static const int kPtsLen = 10;
     23 static const int kTxtLen = 5;
     24 
     25 static void init_string(Fuzz* fuzz, char* str, size_t bufSize) {
     26     for (size_t i = 0; i < bufSize-1; ++i) {
     27         fuzz->nextRange(&str[i], 0x20, 0x7E); // printable ASCII
     28     }
     29     str[bufSize-1] = '\0';
     30 }
     31 
     32 // make_paint mostly borrowed from FilterFuzz.cpp
     33 static void init_paint(Fuzz* fuzz, SkPaint* p) {
     34     bool b;
     35     fuzz->next(&b);
     36     p->setAntiAlias(b);
     37 
     38     uint8_t tmp_u8;
     39     fuzz->nextRange(&tmp_u8, 0, (int)SkBlendMode::kLastMode);
     40     p->setBlendMode(static_cast<SkBlendMode>(tmp_u8));
     41 
     42     SkColor co;
     43     fuzz->next(&co);
     44     p->setColor(co);
     45 
     46     fuzz->next(&b);
     47     p->setDither(b);
     48 
     49     fuzz->nextRange(&tmp_u8, 0, (int)kHigh_SkFilterQuality);
     50     p->setFilterQuality(static_cast<SkFilterQuality>(tmp_u8));
     51 
     52     fuzz->nextRange(&tmp_u8, 0, (int)SkPaint::kLast_Cap);
     53     p->setStrokeCap(static_cast<SkPaint::Cap>(tmp_u8));
     54 
     55     fuzz->nextRange(&tmp_u8, 0, (int)SkPaint::kLast_Join);
     56     p->setStrokeJoin(static_cast<SkPaint::Join>(tmp_u8));
     57 
     58     SkScalar sc;
     59     fuzz->next(&sc);
     60     p->setStrokeMiter(sc);
     61 
     62     fuzz->next(&sc);
     63     p->setStrokeWidth(sc);
     64 
     65     fuzz->nextRange(&tmp_u8, 0, (int)SkPaint::kStrokeAndFill_Style);
     66     p->setStyle(static_cast<SkPaint::Style>(tmp_u8));
     67 }
     68 
     69 static void init_bitmap(Fuzz* fuzz, SkBitmap* bmp) {
     70     uint8_t colorType;
     71     fuzz->nextRange(&colorType, 0, (int)kLastEnum_SkColorType);
     72     // ColorType needs to match what the system configuration is.
     73     if (colorType == kRGBA_8888_SkColorType || colorType == kBGRA_8888_SkColorType) {
     74         colorType = kN32_SkColorType;
     75     }
     76     bool b;
     77     fuzz->next(&b);
     78     SkImageInfo info = SkImageInfo::Make(kBmpSize,
     79                                          kBmpSize,
     80                                          (SkColorType)colorType,
     81                                          b ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
     82     if (!bmp->tryAllocPixels(info)) {
     83         SkDEBUGF("Bitmap not allocated\n");
     84     }
     85     SkColor c;
     86     fuzz->next(&c);
     87     bmp->eraseColor(c);
     88 
     89     fuzz->next(&b);
     90     SkPaint p;
     91     if (b) {
     92         init_paint(fuzz, &p);
     93     }
     94     else {
     95         fuzz->next(&c);
     96         p.setColor(c);
     97     }
     98 }
     99 
    100 static void init_surface(Fuzz* fuzz, sk_sp<SkSurface>* s) {
    101     uint8_t x, y;
    102     fuzz->nextRange(&x, 1, kMaxX);
    103     fuzz->nextRange(&y, 1, kMaxY);
    104     *s = SkSurface::MakeRasterN32Premul(x, y);
    105 
    106     if (!*s) {
    107         // Was possibly too big for the memory constrained fuzzing environments
    108         *s = SkSurface::MakeNull(x, y);
    109     }
    110 }
    111 
    112 
    113 static void fuzz_drawText(Fuzz* fuzz, sk_sp<SkTypeface> typeface) {
    114     SkFont font(typeface);
    115     SkPaint p;
    116     init_paint(fuzz, &p);
    117     sk_sp<SkSurface> surface;
    118     init_surface(fuzz, &surface);
    119 
    120     char text[kTxtLen];
    121     init_string(fuzz, text, kTxtLen);
    122 
    123     SkScalar x, y;
    124     fuzz->next(&x, &y);
    125     // populate pts array
    126     SkPoint pts[kPtsLen];
    127     for (uint8_t i = 0; i < kPtsLen; ++i) {
    128         pts[i].set(x, y);
    129         x += font.getSize();
    130     }
    131 
    132     bool b;
    133     fuzz->next(&b);
    134     font.setForceAutoHinting(b);
    135     fuzz->next(&b);
    136     font.setEmbeddedBitmaps(b);
    137     fuzz->next(&b);
    138     font.setEmbolden(b);
    139     fuzz->next(&b);
    140     font.setEdging(b ? SkFont::Edging::kAntiAlias : SkFont::Edging::kSubpixelAntiAlias);
    141     fuzz->next(&b);
    142     font.setLinearMetrics(b);
    143     fuzz->next(&b);
    144     font.setSubpixel(b);
    145     fuzz->next(&x);
    146     font.setScaleX(x);
    147     fuzz->next(&x);
    148     font.setSkewX(x);
    149     fuzz->next(&x);
    150     font.setSize(x);
    151 
    152     SkCanvas* cnv = surface->getCanvas();
    153     fuzz->next(&x);
    154     fuzz->next(&y);
    155     cnv->drawTextBlob(SkTextBlob::MakeFromPosText(text, kTxtLen-1, pts, font), x, y, p);
    156 }
    157 
    158 static void fuzz_drawCircle(Fuzz* fuzz) {
    159     SkPaint p;
    160     init_paint(fuzz, &p);
    161     sk_sp<SkSurface> surface;
    162     init_surface(fuzz, &surface);
    163 
    164     SkScalar a, b, c;
    165     fuzz->next(&a, &b, &c);
    166     surface->getCanvas()->drawCircle(a, b, c, p);
    167 }
    168 
    169 static void fuzz_drawLine(Fuzz* fuzz) {
    170     SkPaint p;
    171     init_paint(fuzz, &p);
    172     sk_sp<SkSurface> surface;
    173     init_surface(fuzz, &surface);
    174 
    175     SkScalar a, b, c, d;
    176     fuzz->next(&a, &b, &c, &d);
    177     surface->getCanvas()->drawLine(a, b, c, d, p);
    178 }
    179 
    180 static void fuzz_drawRect(Fuzz* fuzz) {
    181     SkPaint p;
    182     init_paint(fuzz, &p);
    183     sk_sp<SkSurface> surface;
    184     init_surface(fuzz, &surface);
    185 
    186     SkScalar a, b, c, d;
    187     fuzz->next(&a, &b, &c, &d);
    188     SkRect r;
    189     r = SkRect::MakeXYWH(a, b, c, d);
    190 
    191     SkCanvas* cnv = surface->getCanvas();
    192     cnv->drawRect(r, p);
    193 
    194     bool bl;
    195     fuzz->next(&bl);
    196     fuzz->next(&a, &b, &c, &d);
    197     r = SkRect::MakeXYWH(a, b, c, d);
    198     cnv->clipRect(r, kIntersect_SkClipOp, bl);
    199 }
    200 
    201 static void fuzz_drawPath(Fuzz* fuzz) {
    202     SkPaint p;
    203     init_paint(fuzz, &p);
    204     sk_sp<SkSurface> surface;
    205     init_surface(fuzz, &surface);
    206 
    207     // TODO(kjlubick): put the ability to fuzz a path in shared file, with
    208     // other common things (e.g. rects, lines)
    209     uint8_t i, j;
    210     fuzz->nextRange(&i, 0, 10); // set i to number of operations to perform
    211     SkPath path;
    212     SkScalar a, b, c, d, e, f;
    213     for (int k = 0; k < i; ++k) {
    214         fuzz->nextRange(&j, 0, 5); // set j to choose operation to perform
    215         switch (j) {
    216             case 0:
    217                 fuzz->next(&a, &b);
    218                 path.moveTo(a, b);
    219                 break;
    220             case 1:
    221                 fuzz->next(&a, &b);
    222                 path.lineTo(a, b);
    223                 break;
    224             case 2:
    225                 fuzz->next(&a, &b, &c, &d);
    226                 path.quadTo(a, b, c, d);
    227                 break;
    228             case 3:
    229                 fuzz->next(&a, &b, &c, &d, &e);
    230                 path.conicTo(a, b, c, d, e);
    231                 break;
    232             case 4:
    233                 fuzz->next(&a, &b, &c, &d, &e, &f);
    234                 path.cubicTo(a, b, c, d, e, f);
    235                 break;
    236             case 5:
    237                 fuzz->next(&a, &b, &c, &d, &e);
    238                 path.arcTo(a, b, c, d, e);
    239                 break;
    240         }
    241     }
    242     path.close();
    243 
    244     SkCanvas* cnv = surface->getCanvas();
    245     cnv->drawPath(path, p);
    246 
    247     bool bl;
    248     fuzz->next(&bl);
    249     cnv->clipPath(path, kIntersect_SkClipOp, bl);
    250 }
    251 
    252 static void fuzz_drawBitmap(Fuzz* fuzz) {
    253     SkPaint p;
    254     init_paint(fuzz, &p);
    255     sk_sp<SkSurface> surface;
    256     init_surface(fuzz, &surface);
    257     SkBitmap bmp;
    258     init_bitmap(fuzz, &bmp);
    259 
    260     SkScalar a, b;
    261     fuzz->next(&a, &b);
    262     surface->getCanvas()->drawBitmap(bmp, a, b, &p);
    263 }
    264 
    265 static void fuzz_drawImage(Fuzz* fuzz) {
    266     SkPaint p;
    267     init_paint(fuzz, &p);
    268     sk_sp<SkSurface> surface;
    269     init_surface(fuzz, &surface);
    270     SkBitmap bmp;
    271     init_bitmap(fuzz, &bmp);
    272 
    273     sk_sp<SkImage> image(SkImage::MakeFromBitmap(bmp));
    274 
    275     bool bl;
    276     fuzz->next(&bl);
    277     SkScalar a, b;
    278     fuzz->next(&a, &b);
    279     if (bl) {
    280         surface->getCanvas()->drawImage(image, a, b, &p);
    281     }
    282     else {
    283         SkRect dst = SkRect::MakeWH(a, b);
    284         fuzz->next(&a, &b);
    285         SkRect src = SkRect::MakeWH(a, b);
    286         uint8_t x;
    287         fuzz->nextRange(&x, 0, 1);
    288         SkCanvas::SrcRectConstraint cst = (SkCanvas::SrcRectConstraint)x;
    289         surface->getCanvas()->drawImageRect(image, src, dst, &p, cst);
    290     }
    291 }
    292 
    293 static void fuzz_drawPaint(Fuzz* fuzz) {
    294     SkPaint l, p;
    295     init_paint(fuzz, &p);
    296     sk_sp<SkSurface> surface;
    297     init_surface(fuzz, &surface);
    298 
    299     surface->getCanvas()->drawPaint(p);
    300 }
    301 
    302 DEF_FUZZ(DrawFunctions, fuzz) {
    303     uint8_t i;
    304     fuzz->next(&i);
    305 
    306     switch(i) {
    307         case 0: {
    308             sk_sp<SkTypeface> f = SkTypeface::MakeDefault();
    309             if (f == nullptr) {
    310               SkDebugf("Could not initialize font.\n");
    311               fuzz->signalBug();
    312             }
    313             SkDEBUGF("Fuzz DrawText\n");
    314             fuzz_drawText(fuzz, f);
    315             return;
    316         }
    317         case 1:
    318             SkDEBUGF("Fuzz DrawRect\n");
    319             fuzz_drawRect(fuzz);
    320             return;
    321         case 2:
    322             SkDEBUGF("Fuzz DrawCircle\n");
    323             fuzz_drawCircle(fuzz);
    324             return;
    325         case 3:
    326             SkDEBUGF("Fuzz DrawLine\n");
    327             fuzz_drawLine(fuzz);
    328             return;
    329         case 4:
    330             SkDEBUGF("Fuzz DrawPath\n");
    331             fuzz_drawPath(fuzz);
    332             return;
    333         case 5:
    334             SkDEBUGF("Fuzz DrawImage/DrawImageRect\n");
    335             fuzz_drawImage(fuzz);
    336             return;
    337         case 6:
    338             SkDEBUGF("Fuzz DrawBitmap\n");
    339             fuzz_drawBitmap(fuzz);
    340             return;
    341         case 7:
    342             SkDEBUGF("Fuzz DrawPaint\n");
    343             fuzz_drawPaint(fuzz);
    344             return;
    345     }
    346 }
    347