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