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