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