FuzzCanvas.cpp revision 3a97d2742fa3df70357e4a758e9b7142792b3518
1/* 2 * Copyright 2017 Google Inc. 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 10// CORE 11#include "SkCanvas.h" 12#include "SkColorFilter.h" 13#include "SkDebugCanvas.h" 14#include "SkDocument.h" 15#include "SkFontMgr.h" 16#include "SkImageFilter.h" 17#include "SkMaskFilter.h" 18#include "SkNullCanvas.h" 19#include "SkPathEffect.h" 20#include "SkPictureRecorder.h" 21#include "SkRegion.h" 22#include "SkSurface.h" 23#include "SkTypeface.h" 24 25// EFFECTS 26#include "SkGaussianEdgeShader.h" 27#include "SkGradientShader.h" 28#include "SkPerlinNoiseShader.h" 29 30// SRC 31#include "SkUtils.h" 32 33// MISC 34 35#include <iostream> 36 37// TODO: 38// SkCanvas::drawTextBlob 39// SkCanvas::drawTextRSXform 40// SkColorFilter 41// SkImageFilter 42// SkMaskFilter 43// SkPathEffect 44 45template <typename T, void (SkPaint::*S)(T)> 46inline void fuzz_input(Fuzz* fuzz, SkPaint* paint) { 47 T value; 48 fuzz->next(&value); 49 (paint->*S)(value); 50} 51 52template <typename T, void (SkPaint::*S)(T)> 53inline void fuzz_enum_input(Fuzz* fuzz, SkPaint* paint, T rmin, T rmax) { 54 using U = skstd::underlying_type_t<T>; 55 U value; 56 fuzz->nextRange(&value, (U)rmin, (U)rmax); 57 (paint->*S)((T)value); 58} 59 60// be careful: `foo(make_bool(f), make_bool(f))` is undefined. 61static bool make_bool(Fuzz* fuzz) { 62 bool b; 63 fuzz->next(&b); 64 return b; 65} 66 67// We don't always want to test NaNs. 68static void fuzz_nice_float(Fuzz* fuzz, float* f) { 69 fuzz->next(f); 70 if (*f != *f || ::fabs(*f) > 1.0e35f) { 71 *f = 0.0f; 72 } 73} 74 75template <typename... Args> 76void fuzz_nice_float(Fuzz* fuzz, float* f, Args... rest) { 77 fuzz_nice_float(fuzz, f); 78 fuzz_nice_float(fuzz, rest...); 79} 80 81static void fuzz_path(Fuzz* fuzz, SkPath* path, int maxOps) { 82 if (maxOps < 2) { 83 maxOps = 2; 84 } 85 uint8_t fillType; 86 fuzz->nextRange(&fillType, 0, (uint8_t)SkPath::kInverseEvenOdd_FillType); 87 path->setFillType((SkPath::FillType)fillType); 88 uint8_t numOps; 89 fuzz->nextRange(&numOps, 2, maxOps); 90 for (uint8_t i = 0; i < numOps; ++i) { 91 uint8_t op; 92 fuzz->nextRange(&op, 0, 6); 93 SkScalar a, b, c, d, e, f; 94 switch (op) { 95 case 0: 96 fuzz_nice_float(fuzz, &a, &b); 97 path->moveTo(a, b); 98 break; 99 case 1: 100 fuzz_nice_float(fuzz, &a, &b); 101 path->lineTo(a, b); 102 break; 103 case 2: 104 fuzz_nice_float(fuzz, &a, &b, &c, &d); 105 path->quadTo(a, b, c, d); 106 break; 107 case 3: 108 fuzz_nice_float(fuzz, &a, &b, &c, &d, &e); 109 path->conicTo(a, b, c, d, e); 110 break; 111 case 4: 112 fuzz_nice_float(fuzz, &a, &b, &c, &d, &e, &f); 113 path->cubicTo(a, b, c, d, e, f); 114 break; 115 case 5: 116 fuzz_nice_float(fuzz, &a, &b, &c, &d, &e); 117 path->arcTo(a, b, c, d, e); 118 break; 119 case 6: 120 path->close(); 121 break; 122 default: 123 break; 124 } 125 } 126} 127 128static void fuzz_region(Fuzz* fuzz, SkRegion* region) { 129 uint8_t N; 130 fuzz->nextRange(&N, 0, 10); 131 for (uint8_t i = 0; i < N; ++i) { 132 SkIRect r; 133 uint8_t op; 134 fuzz->next(&r); 135 r.sort(); 136 fuzz->nextRange(&op, 0, (uint8_t)SkRegion::kLastOp); 137 if (!region->op(r, (SkRegion::Op)op)) { 138 return; 139 } 140 } 141} 142 143template <> inline void Fuzz::next(SkShader::TileMode* m) { 144 using U = skstd::underlying_type_t<SkShader::TileMode>; 145 this->nextRange((U*)m, (U)0, (U)(SkShader::kTileModeCount - 1)); 146} 147 148 149template <> inline void Fuzz::next(SkMatrix* m) { 150 constexpr int kArrayLength = 9; 151 SkScalar buffer[kArrayLength]; 152 int matrixType; 153 this->nextRange(&matrixType, 0, 4); 154 switch (matrixType) { 155 case 0: // identity 156 *m = SkMatrix::I(); 157 return; 158 case 1: // translate 159 this->nextRange(&buffer[0], -4000.0f, 4000.0f); 160 this->nextRange(&buffer[1], -4000.0f, 4000.0f); 161 *m = SkMatrix::MakeTrans(buffer[0], buffer[1]); 162 return; 163 case 2: // translate + scale 164 this->nextRange(&buffer[0], -400.0f, 400.0f); 165 this->nextRange(&buffer[1], -400.0f, 400.0f); 166 this->nextRange(&buffer[2], -4000.0f, 4000.0f); 167 this->nextRange(&buffer[3], -4000.0f, 4000.0f); 168 *m = SkMatrix::MakeScale(buffer[0], buffer[1]); 169 m->postTranslate(buffer[2], buffer[3]); 170 return; 171 case 3: // affine 172 this->nextN(buffer, 6); 173 m->setAffine(buffer); 174 return; 175 case 4: // perspective 176 this->nextN(buffer, kArrayLength); 177 m->set9(buffer); 178 return; 179 default: 180 return; 181 } 182} 183 184template <> inline void Fuzz::next(SkRRect* rr) { 185 SkRect r; 186 SkVector radii[4]; 187 this->next(&r); 188 this->nextN(radii, 4); 189 rr->setRectRadii(r, radii); 190 SkASSERT(rr->isValid()); 191} 192 193template <> inline void Fuzz::next(SkBlendMode* mode) { 194 using U = skstd::underlying_type_t<SkBlendMode>; 195 this->nextRange((U*)mode, (U)0, (U)SkBlendMode::kLastMode); 196} 197 198sk_sp<SkImage> MakeFuzzImage(Fuzz*); 199 200SkBitmap MakeFuzzBitmap(Fuzz*); 201 202static sk_sp<SkPicture> make_picture(Fuzz*, int depth); 203 204sk_sp<SkColorFilter> MakeColorFilter(Fuzz* fuzz) { return nullptr; /*TODO*/ } 205 206void make_pos(Fuzz* fuzz, SkScalar* pos, int colorCount) { 207 SkScalar totalPos = 0; 208 for (int i = 0; i < colorCount; ++i) { 209 fuzz->nextRange(&pos[i], 1.0f, 1024.0f); 210 totalPos += pos[i]; 211 } 212 totalPos = 1.0f / totalPos; 213 for (int i = 0; i < colorCount; ++i) { 214 pos[i] *= totalPos; 215 } 216 //SkASSERT(fabs(pos[colorCount - 1] - 1.0f) < 0.00001f); 217 pos[colorCount - 1] = 1.0f; 218} 219 220sk_sp<SkShader> MakeFuzzShader(Fuzz* fuzz, int depth) { 221 sk_sp<SkShader> shader1(nullptr), shader2(nullptr); 222 sk_sp<SkColorFilter> colorFilter(nullptr); 223 SkBitmap bitmap; 224 sk_sp<SkImage> img; 225 SkShader::TileMode tmX, tmY; 226 bool useMatrix; 227 SkColor color; 228 SkMatrix matrix; 229 SkBlendMode blendMode; 230 int shaderType; 231 if (depth <= 0) { 232 return nullptr; 233 } 234 fuzz->nextRange(&shaderType, 0, 14); 235 switch (shaderType) { 236 case 0: 237 return nullptr; 238 case 1: 239 return SkShader::MakeEmptyShader(); 240 case 2: 241 fuzz->next(&color); 242 return SkShader::MakeColorShader(color); 243 case 3: 244 img = MakeFuzzImage(fuzz); 245 fuzz->next(&tmX, &tmY, &useMatrix); 246 if (useMatrix) { 247 fuzz->next(&matrix); 248 } 249 return img->makeShader(tmX, tmY, useMatrix ? &matrix : nullptr); 250 case 4: 251 bitmap = MakeFuzzBitmap(fuzz); 252 fuzz->next(&tmX, &tmY, &useMatrix); 253 if (useMatrix) { 254 fuzz->next(&matrix); 255 } 256 return SkShader::MakeBitmapShader(bitmap, tmX, tmY, useMatrix ? &matrix : nullptr); 257 case 5: 258 shader1 = MakeFuzzShader(fuzz, depth - 1); // limit recursion. 259 fuzz->next(&matrix); 260 return shader1 ? shader1->makeWithLocalMatrix(matrix) : nullptr; 261 case 6: 262 shader1 = MakeFuzzShader(fuzz, depth - 1); // limit recursion. 263 colorFilter = MakeColorFilter(fuzz); 264 return shader1 ? shader1->makeWithColorFilter(std::move(colorFilter)) : nullptr; 265 case 7: 266 shader1 = MakeFuzzShader(fuzz, depth - 1); // limit recursion. 267 shader2 = MakeFuzzShader(fuzz, depth - 1); 268 fuzz->next(&blendMode); 269 return SkShader::MakeComposeShader(std::move(shader1), std::move(shader2), blendMode); 270 case 8: 271 { 272 auto pic = make_picture(fuzz, depth); 273 bool useTile; 274 SkRect tile; 275 fuzz->next(&tmX, &tmY, &useMatrix, &useTile); 276 if (useMatrix) { 277 fuzz->next(&matrix); 278 } 279 if (useTile) { 280 fuzz->next(&tile); 281 } 282 return SkShader::MakePictureShader(std::move(pic), tmX, tmY, 283 useMatrix ? &matrix : nullptr, 284 useTile ? &tile : nullptr); 285 } 286 // EFFECTS: 287 case 9: 288 return SkGaussianEdgeShader::Make(); 289 case 10: 290 { 291 constexpr int kMaxColors = 12; 292 SkPoint pts[2]; 293 SkColor colors[kMaxColors]; 294 SkScalar pos[kMaxColors]; 295 int colorCount; 296 bool usePos; 297 fuzz->nextN(pts, 2); 298 fuzz->nextRange(&colorCount, 2, kMaxColors); 299 fuzz->nextN(colors, colorCount); 300 fuzz->next(&tmX, &useMatrix, &usePos); 301 if (useMatrix) { 302 fuzz->next(&matrix); 303 } 304 if (usePos) { 305 make_pos(fuzz, pos, colorCount); 306 } 307 return SkGradientShader::MakeLinear(pts, 308 colors, 309 usePos ? pos : nullptr, 310 colorCount, 311 tmX, 0, 312 useMatrix ? &matrix : nullptr); 313 } 314 case 11: 315 { 316 constexpr int kMaxColors = 12; 317 SkPoint center; 318 SkScalar radius; 319 int colorCount; 320 bool usePos; 321 SkColor colors[kMaxColors]; 322 SkScalar pos[kMaxColors]; 323 fuzz->next(&tmX, &useMatrix, &usePos, ¢er, &radius); 324 fuzz->nextRange(&colorCount, 2, kMaxColors); 325 fuzz->nextN(colors, colorCount); 326 if (useMatrix) { 327 fuzz->next(&matrix); 328 } 329 if (usePos) { 330 make_pos(fuzz, pos, colorCount); 331 } 332 return SkGradientShader::MakeRadial(center, radius, colors, 333 usePos ? pos : nullptr, 334 colorCount, tmX, 0, 335 useMatrix ? &matrix : nullptr); 336 } 337 case 12: 338 { 339 constexpr int kMaxColors = 12; 340 SkPoint start, end; 341 SkScalar startRadius, endRadius; 342 int colorCount; 343 bool usePos; 344 SkColor colors[kMaxColors]; 345 SkScalar pos[kMaxColors]; 346 fuzz->next(&tmX, &useMatrix, &usePos, &startRadius, &endRadius, &start, &end); 347 fuzz->nextRange(&colorCount, 2, kMaxColors); 348 fuzz->nextN(colors, colorCount); 349 if (useMatrix) { 350 fuzz->next(&matrix); 351 } 352 if (usePos) { 353 make_pos(fuzz, pos, colorCount); 354 } 355 return SkGradientShader::MakeTwoPointConical(start, startRadius, end, endRadius, 356 colors, usePos ? pos : nullptr, 357 colorCount, tmX, 0, 358 useMatrix ? &matrix : nullptr); 359 } 360 case 13: 361 { 362 constexpr int kMaxColors = 12; 363 SkScalar cx, cy; 364 int colorCount; 365 bool usePos; 366 SkColor colors[kMaxColors]; 367 SkScalar pos[kMaxColors]; 368 fuzz->next(&cx, &cy, &useMatrix, &usePos); 369 fuzz->nextRange(&colorCount, 2, kMaxColors); 370 fuzz->nextN(colors, colorCount); 371 if (useMatrix) { 372 fuzz->next(&matrix); 373 } 374 if (usePos) { 375 make_pos(fuzz, pos, colorCount); 376 } 377 return SkGradientShader::MakeSweep(cx, cy, colors, usePos ? pos : nullptr, 378 colorCount, 0, useMatrix ? &matrix : nullptr); 379 } 380 case 14: 381 { 382 SkScalar baseFrequencyX, baseFrequencyY, seed; 383 int numOctaves; 384 SkISize tileSize; 385 bool useTileSize, turbulence; 386 fuzz->next(&baseFrequencyX, &baseFrequencyY, &seed, &useTileSize, &turbulence); 387 if (useTileSize) { 388 fuzz->next(&tileSize); 389 } 390 fuzz->nextRange(&numOctaves, 2, 7); 391 if (turbulence) { 392 return SkPerlinNoiseShader::MakeTurbulence(baseFrequencyX, baseFrequencyY, 393 numOctaves, seed, 394 useTileSize ? &tileSize : nullptr); 395 } else { 396 return SkPerlinNoiseShader::MakeFractalNoise(baseFrequencyX, baseFrequencyY, 397 numOctaves, seed, 398 useTileSize ? &tileSize : nullptr); 399 } 400 } 401 default: 402 break; 403 } 404 return nullptr; 405} 406 407 408sk_sp<SkPathEffect> MakeFuzzPathEffect(Fuzz* fuzz) { return nullptr; /*TODO*/ } 409 410sk_sp<SkMaskFilter> MakeFuzzMaskFilter(Fuzz* fuzz) { return nullptr; /*TODO*/ } 411 412sk_sp<SkTypeface> MakeFuzzTypeface(Fuzz* fuzz) { 413 if (make_bool(fuzz)) { 414 return nullptr; 415 } 416 auto fontMugger = SkFontMgr::RefDefault(); 417 SkASSERT(fontMugger); 418 int familyCount = fontMugger->countFamilies(); 419 int i, j; 420 fuzz->nextRange(&i, 0, familyCount - 1); 421 sk_sp<SkFontStyleSet> family(fontMugger->createStyleSet(i)); 422 int styleCount = family->count(); 423 fuzz->nextRange(&j, 0, styleCount - 1); 424 return sk_sp<SkTypeface>(family->createTypeface(j)); 425} 426 427sk_sp<SkImageFilter> MakeFuzzImageFilter(Fuzz* fuzz) { return nullptr; /*TODO*/ } 428 429sk_sp<SkImage> MakeFuzzImage(Fuzz* fuzz) { 430 int w, h; 431 fuzz->nextRange(&w, 1, 1024); 432 fuzz->nextRange(&h, 1, 1024); 433 SkAutoTMalloc<SkPMColor> data(w * h); 434 SkPixmap pixmap(SkImageInfo::MakeN32Premul(w, h), data.get(), w * sizeof(SkPMColor)); 435 int n = w * h; 436 for (int i = 0; i < n; ++i) { 437 SkColor c; 438 fuzz->next(&c); 439 data[i] = SkPreMultiplyColor(c); 440 } 441 (void)data.release(); 442 return SkImage::MakeFromRaster( 443 pixmap, [](const void* p, void*) { sk_free((void*)p); }, nullptr); 444} 445 446SkBitmap MakeFuzzBitmap(Fuzz* fuzz) { 447 SkBitmap bitmap; 448 int w, h; 449 fuzz->nextRange(&w, 1, 1024); 450 fuzz->nextRange(&h, 1, 1024); 451 bitmap.allocN32Pixels(w, h); 452 SkAutoLockPixels autoLockPixels(bitmap); 453 for (int y = 0; y < h; ++y) { 454 for (int x = 0; x < w; ++x) { 455 SkColor c; 456 fuzz->next(&c); 457 *bitmap.getAddr32(x, y) = SkPreMultiplyColor(c); 458 } 459 } 460 return bitmap; 461} 462 463void FuzzPaint(Fuzz* fuzz, SkPaint* paint, int depth) { 464 if (!fuzz || !paint || depth <= 0) { 465 return; 466 } 467 468 fuzz_input<bool, &SkPaint::setAntiAlias>(fuzz, paint); 469 fuzz_input<bool, &SkPaint::setDither>(fuzz, paint); 470 fuzz_input<SkColor, &SkPaint::setColor>(fuzz, paint); 471 fuzz_enum_input<SkBlendMode, &SkPaint::setBlendMode>(fuzz, paint, (SkBlendMode)0, 472 SkBlendMode::kLastMode); 473 fuzz_enum_input<SkPaint::Hinting, &SkPaint::setHinting>(fuzz, paint, SkPaint::kNo_Hinting, 474 SkPaint::kFull_Hinting); 475 fuzz_enum_input<SkFilterQuality, &SkPaint::setFilterQuality>( 476 fuzz, paint, SkFilterQuality::kNone_SkFilterQuality, 477 SkFilterQuality::kLast_SkFilterQuality); 478 fuzz_enum_input<SkPaint::Style, &SkPaint::setStyle>(fuzz, paint, SkPaint::kFill_Style, 479 SkPaint::kStrokeAndFill_Style); 480 paint->setShader(MakeFuzzShader(fuzz, depth)); 481 paint->setPathEffect(MakeFuzzPathEffect(fuzz)); 482 paint->setMaskFilter(MakeFuzzMaskFilter(fuzz)); 483 paint->setImageFilter(MakeFuzzImageFilter(fuzz)); 484 paint->setColorFilter(MakeColorFilter(fuzz)); 485 486 if (paint->getStyle() != SkPaint::kFill_Style) { 487 fuzz_input<SkScalar, &SkPaint::setStrokeWidth>(fuzz, paint); 488 fuzz_input<SkScalar, &SkPaint::setStrokeMiter>(fuzz, paint); 489 fuzz_enum_input<SkPaint::Cap, &SkPaint::setStrokeCap>(fuzz, paint, SkPaint::kButt_Cap, 490 SkPaint::kLast_Cap); 491 fuzz_enum_input<SkPaint::Join, &SkPaint::setStrokeJoin>(fuzz, paint, SkPaint::kMiter_Join, 492 SkPaint::kLast_Join); 493 } 494} 495 496void FuzzPaintText(Fuzz* fuzz, SkPaint* paint) { 497 paint->setTypeface(MakeFuzzTypeface(fuzz)); 498 fuzz_input<SkScalar, &SkPaint::setTextSize>(fuzz, paint); 499 fuzz_input<SkScalar, &SkPaint::setTextScaleX>(fuzz, paint); 500 fuzz_input<SkScalar, &SkPaint::setTextSkewX>(fuzz, paint); 501 fuzz_input<bool, &SkPaint::setLinearText>(fuzz, paint); 502 fuzz_input<bool, &SkPaint::setSubpixelText>(fuzz, paint); 503 fuzz_input<bool, &SkPaint::setLCDRenderText>(fuzz, paint); 504 fuzz_input<bool, &SkPaint::setEmbeddedBitmapText>(fuzz, paint); 505 fuzz_input<bool, &SkPaint::setAutohinted>(fuzz, paint); 506 fuzz_input<bool, &SkPaint::setVerticalText>(fuzz, paint); 507 fuzz_input<bool, &SkPaint::setFakeBoldText>(fuzz, paint); 508 fuzz_input<bool, &SkPaint::setDevKernText>(fuzz, paint); 509 fuzz_enum_input<SkPaint::Align, &SkPaint::setTextAlign>(fuzz, paint, SkPaint::kLeft_Align, 510 SkPaint::kRight_Align); 511 fuzz_enum_input<SkPaint::TextEncoding, &SkPaint::setTextEncoding>( 512 fuzz, paint, SkPaint::kUTF8_TextEncoding, SkPaint::kGlyphID_TextEncoding); 513} 514 515SkTDArray<uint8_t> fuzz_text(Fuzz* fuzz, const SkPaint& paint) { 516 SkTDArray<uint8_t> array; 517 if (SkPaint::kGlyphID_TextEncoding == paint.getTextEncoding()) { 518 int glyphRange = paint.getTypeface() 519 ? paint.getTypeface()->countGlyphs() 520 : SkTypeface::MakeDefault()->countGlyphs(); 521 constexpr int kMaxGlyphCount = 20; 522 int glyphCount; 523 fuzz->nextRange(&glyphCount, 0, kMaxGlyphCount); 524 SkGlyphID* glyphs = (SkGlyphID*)array.append(glyphCount * sizeof(SkGlyphID)); 525 for (int i = 0; i < glyphCount; ++i) { 526 fuzz->nextRange(&glyphs[i], 0, glyphRange - 1); 527 } 528 return array; 529 } 530 static const SkUnichar ranges[][2] = { 531 {0x0020, 0x007F}, 532 {0x00A1, 0x0250}, 533 {0x0400, 0x0500}, 534 }; 535 int32_t count = 0; 536 for (size_t i = 0; i < SK_ARRAY_COUNT(ranges); ++i){ 537 count += (ranges[i][1] - ranges[i][0]); 538 } 539 constexpr int kMaxLength = 30; 540 SkUnichar buffer[kMaxLength]; 541 int length; 542 fuzz->nextRange(&length, 1, kMaxLength); 543 for (int j = 0; j < length; ++j) { 544 int32_t value; 545 fuzz->nextRange(&value, 0, count - 1); 546 for (size_t i = 0; i < SK_ARRAY_COUNT(ranges); ++i){ 547 if (value + ranges[i][0] < ranges[i][1]) { 548 buffer[j] = value + ranges[i][0]; 549 break; 550 } else { 551 value -= (ranges[i][1] - ranges[i][0]); 552 } 553 } 554 } 555 switch (paint.getTextEncoding()) { 556 case SkPaint::kUTF8_TextEncoding: 557 { 558 size_t utf8len = 0; 559 for (int j = 0; j < length; ++j) { 560 utf8len += SkUTF8_FromUnichar(buffer[j], nullptr); 561 } 562 char* ptr = (char*)array.append(utf8len); 563 for (int j = 0; j < length; ++j) { 564 ptr += SkUTF8_FromUnichar(buffer[j], ptr); 565 } 566 } 567 break; 568 case SkPaint::kUTF16_TextEncoding: 569 { 570 size_t utf16len = 0; 571 for (int j = 0; j < length; ++j) { 572 utf16len += SkUTF16_FromUnichar(buffer[j]); 573 } 574 uint16_t* ptr = (uint16_t*)array.append(utf16len * sizeof(uint16_t)); 575 for (int j = 0; j < length; ++j) { 576 ptr += SkUTF16_FromUnichar(buffer[j], ptr); 577 } 578 } 579 break; 580 case SkPaint::kUTF32_TextEncoding: 581 memcpy(array.append(length * sizeof(SkUnichar)), buffer, length * sizeof(SkUnichar)); 582 break; 583 default: 584 SkASSERT(false); 585 } 586 return array; 587} 588 589 590void fuzz_canvas(Fuzz* fuzz, SkCanvas* canvas, int depth = 4) { 591 if (!fuzz || !canvas || depth <= 0) { 592 return; 593 } 594 SkAutoCanvasRestore autoCanvasRestore(canvas, false); 595 unsigned N; 596 fuzz->nextRange(&N, 0, 2000); 597 for (unsigned i = 0; i < N; ++i) { 598 if (fuzz->exhausted()) { 599 return; 600 } 601 SkPaint paint; 602 SkMatrix matrix; 603 unsigned drawCommand; 604 fuzz->nextRange(&drawCommand, 0, 54); 605 switch (drawCommand) { 606 case 0: 607 canvas->flush(); 608 break; 609 case 1: 610 canvas->save(); 611 break; 612 case 2: { 613 SkRect bounds; 614 fuzz->next(&bounds); 615 FuzzPaint(fuzz, &paint, depth); 616 canvas->saveLayer(&bounds, &paint); 617 break; 618 } 619 case 3: { 620 SkRect bounds; 621 fuzz->next(&bounds); 622 canvas->saveLayer(&bounds, nullptr); 623 break; 624 } 625 case 4: 626 FuzzPaint(fuzz, &paint, depth); 627 canvas->saveLayer(nullptr, &paint); 628 break; 629 case 5: 630 canvas->saveLayer(nullptr, nullptr); 631 break; 632 case 6: { 633 uint8_t alpha; 634 fuzz->next(&alpha); 635 canvas->saveLayerAlpha(nullptr, (U8CPU)alpha); 636 break; 637 } 638 case 7: { 639 SkRect bounds; 640 uint8_t alpha; 641 fuzz->next(&bounds, &alpha); 642 canvas->saveLayerAlpha(&bounds, (U8CPU)alpha); 643 break; 644 } 645 case 8: { 646 SkCanvas::SaveLayerRec saveLayerRec; 647 SkRect bounds; 648 if (make_bool(fuzz)) { 649 fuzz->next(&bounds); 650 saveLayerRec.fBounds = &bounds; 651 } 652 if (make_bool(fuzz)) { 653 FuzzPaint(fuzz, &paint, depth); 654 saveLayerRec.fPaint = &paint; 655 } 656 sk_sp<SkImageFilter> imageFilter; 657 if (make_bool(fuzz)) { 658 imageFilter = MakeFuzzImageFilter(fuzz); 659 saveLayerRec.fBackdrop = imageFilter.get(); 660 } 661 if (make_bool(fuzz)) { 662 saveLayerRec.fSaveLayerFlags |= SkCanvas::kIsOpaque_SaveLayerFlag; 663 } 664 if (make_bool(fuzz)) { 665 saveLayerRec.fSaveLayerFlags |= SkCanvas::kPreserveLCDText_SaveLayerFlag; 666 } 667 canvas->saveLayer(saveLayerRec); 668 break; 669 } 670 case 9: 671 canvas->restore(); 672 break; 673 case 10: { 674 int saveCount; 675 fuzz->next(&saveCount); 676 canvas->restoreToCount(saveCount); 677 break; 678 } 679 case 11: { 680 SkScalar x, y; 681 fuzz->next(&x, &y); 682 canvas->translate(x, y); 683 break; 684 } 685 case 12: { 686 SkScalar x, y; 687 fuzz->next(&x, &y); 688 canvas->scale(x, y); 689 break; 690 } 691 case 13: { 692 SkScalar v; 693 fuzz->next(&v); 694 canvas->rotate(v); 695 break; 696 } 697 case 14: { 698 SkScalar x, y, v; 699 fuzz->next(&x, &y, &v); 700 canvas->rotate(v, x, y); 701 break; 702 } 703 case 15: { 704 SkScalar x, y; 705 fuzz->next(&x, &y); 706 canvas->skew(x, y); 707 break; 708 } 709 case 16: { 710 SkMatrix mat; 711 fuzz->next(&mat); 712 canvas->concat(mat); 713 break; 714 } 715 case 17: { 716 SkMatrix mat; 717 fuzz->next(&mat); 718 canvas->setMatrix(mat); 719 break; 720 } 721 case 18: 722 canvas->resetMatrix(); 723 break; 724 case 19: { 725 SkRect r; 726 int op; 727 bool doAntiAlias; 728 fuzz->next(&r, &doAntiAlias); 729 fuzz->nextRange(&op, 0, 1); 730 r.sort(); 731 canvas->clipRect(r, (SkClipOp)op, doAntiAlias); 732 break; 733 } 734 case 20: { 735 SkRRect rr; 736 int op; 737 bool doAntiAlias; 738 fuzz->next(&rr); 739 fuzz->next(&doAntiAlias); 740 fuzz->nextRange(&op, 0, 1); 741 canvas->clipRRect(rr, (SkClipOp)op, doAntiAlias); 742 break; 743 } 744 case 21: { 745 SkPath path; 746 fuzz_path(fuzz, &path, 30); 747 int op; 748 bool doAntiAlias; 749 fuzz->next(&doAntiAlias); 750 fuzz->nextRange(&op, 0, 1); 751 canvas->clipPath(path, (SkClipOp)op, doAntiAlias); 752 break; 753 } 754 case 22: { 755 SkRegion region; 756 fuzz_region(fuzz, ®ion); 757 int op; 758 fuzz->nextRange(&op, 0, 1); 759 canvas->clipRegion(region, (SkClipOp)op); 760 break; 761 } 762 case 23: 763 FuzzPaint(fuzz, &paint, depth); 764 canvas->drawPaint(paint); 765 break; 766 case 24: { 767 FuzzPaint(fuzz, &paint, depth); 768 uint8_t pointMode; 769 fuzz->nextRange(&pointMode, 0, 3); 770 size_t count; 771 constexpr int kMaxCount = 30; 772 fuzz->nextRange(&count, 0, kMaxCount); 773 SkPoint pts[kMaxCount]; 774 fuzz->nextN(pts, count); 775 canvas->drawPoints((SkCanvas::PointMode)pointMode, count, pts, paint); 776 break; 777 } 778 case 25: { 779 FuzzPaint(fuzz, &paint, depth); 780 SkRect r; 781 fuzz->next(&r); 782 canvas->drawRect(r, paint); 783 break; 784 } 785 case 26: { 786 FuzzPaint(fuzz, &paint, depth); 787 SkRegion region; 788 fuzz_region(fuzz, ®ion); 789 canvas->drawRegion(region, paint); 790 break; 791 } 792 case 27: { 793 FuzzPaint(fuzz, &paint, depth); 794 SkRect r; 795 fuzz->next(&r); 796 canvas->drawOval(r, paint); 797 break; 798 } 799 case 29: { 800 FuzzPaint(fuzz, &paint, depth); 801 SkRRect rr; 802 fuzz->next(&rr); 803 canvas->drawRRect(rr, paint); 804 break; 805 } 806 case 30: { 807 FuzzPaint(fuzz, &paint, depth); 808 SkRRect orr, irr; 809 fuzz->next(&orr); 810 fuzz->next(&irr); 811 canvas->drawDRRect(orr, irr, paint); 812 break; 813 } 814 case 31: { 815 FuzzPaint(fuzz, &paint, depth); 816 SkRect r; 817 SkScalar start, sweep; 818 bool useCenter; 819 fuzz->next(&r, &start, &sweep, &useCenter); 820 canvas->drawArc(r, start, sweep, useCenter, paint); 821 break; 822 } 823 case 32: { 824 SkPath path; 825 fuzz_path(fuzz, &path, 60); 826 canvas->drawPath(path, paint); 827 break; 828 } 829 case 33: { 830 sk_sp<SkImage> img = MakeFuzzImage(fuzz); 831 SkScalar left, top; 832 bool usePaint; 833 fuzz->next(&left, &top, &usePaint); 834 if (usePaint) { 835 FuzzPaint(fuzz, &paint, depth); 836 } 837 canvas->drawImage(img.get(), left, top, usePaint ? &paint : nullptr); 838 break; 839 } 840 case 34: { 841 auto img = MakeFuzzImage(fuzz); 842 SkRect src, dst; 843 bool usePaint; 844 fuzz->next(&src, &dst, &usePaint); 845 if (usePaint) { 846 FuzzPaint(fuzz, &paint, depth); 847 } 848 SkCanvas::SrcRectConstraint constraint = make_bool(fuzz) 849 ? SkCanvas::kStrict_SrcRectConstraint 850 : SkCanvas::kFast_SrcRectConstraint; 851 canvas->drawImageRect(img, src, dst, usePaint ? &paint : nullptr, constraint); 852 break; 853 } 854 case 35: { 855 auto img = MakeFuzzImage(fuzz); 856 SkIRect src; 857 SkRect dst; 858 bool usePaint; 859 fuzz->next(&src, &dst, &usePaint); 860 if (usePaint) { 861 FuzzPaint(fuzz, &paint, depth); 862 } 863 SkCanvas::SrcRectConstraint constraint = make_bool(fuzz) 864 ? SkCanvas::kStrict_SrcRectConstraint 865 : SkCanvas::kFast_SrcRectConstraint; 866 canvas->drawImageRect(img, src, dst, usePaint ? &paint : nullptr, constraint); 867 break; 868 } 869 case 36: { 870 bool usePaint; 871 auto img = MakeFuzzImage(fuzz); 872 SkRect dst; 873 fuzz->next(&dst, &usePaint); 874 if (usePaint) { 875 FuzzPaint(fuzz, &paint, depth); 876 } 877 SkCanvas::SrcRectConstraint constraint = make_bool(fuzz) 878 ? SkCanvas::kStrict_SrcRectConstraint 879 : SkCanvas::kFast_SrcRectConstraint; 880 canvas->drawImageRect(img, dst, usePaint ? &paint : nullptr, constraint); 881 break; 882 } 883 case 37: { 884 auto img = MakeFuzzImage(fuzz); 885 SkIRect center; 886 SkRect dst; 887 bool usePaint; 888 fuzz->next(¢er, &dst, &usePaint); 889 if (usePaint) { 890 FuzzPaint(fuzz, &paint, depth); 891 } 892 canvas->drawImageNine(img, center, dst, usePaint ? &paint : nullptr); 893 break; 894 } 895 case 38: { 896 SkBitmap bitmap = MakeFuzzBitmap(fuzz); 897 SkScalar left, top; 898 bool usePaint; 899 fuzz->next(&left, &top, &usePaint); 900 if (usePaint) { 901 FuzzPaint(fuzz, &paint, depth); 902 } 903 canvas->drawBitmap(bitmap, left, top, usePaint ? &paint : nullptr); 904 break; 905 } 906 case 39: { 907 SkBitmap bitmap = MakeFuzzBitmap(fuzz); 908 SkRect src, dst; 909 bool usePaint; 910 fuzz->next(&src, &dst, &usePaint); 911 if (usePaint) { 912 FuzzPaint(fuzz, &paint, depth); 913 } 914 SkCanvas::SrcRectConstraint constraint = make_bool(fuzz) 915 ? SkCanvas::kStrict_SrcRectConstraint 916 : SkCanvas::kFast_SrcRectConstraint; 917 canvas->drawBitmapRect(bitmap, src, dst, usePaint ? &paint : nullptr, constraint); 918 break; 919 } 920 case 40: { 921 SkBitmap img = MakeFuzzBitmap(fuzz); 922 SkIRect src; 923 SkRect dst; 924 bool usePaint; 925 fuzz->next(&src, &dst, &usePaint); 926 if (usePaint) { 927 FuzzPaint(fuzz, &paint, depth); 928 } 929 SkCanvas::SrcRectConstraint constraint = make_bool(fuzz) 930 ? SkCanvas::kStrict_SrcRectConstraint 931 : SkCanvas::kFast_SrcRectConstraint; 932 canvas->drawBitmapRect(img, src, dst, usePaint ? &paint : nullptr, constraint); 933 break; 934 } 935 case 41: { 936 SkBitmap img = MakeFuzzBitmap(fuzz); 937 SkRect dst; 938 bool usePaint; 939 fuzz->next(&dst, &usePaint); 940 if (usePaint) { 941 FuzzPaint(fuzz, &paint, depth); 942 } 943 SkCanvas::SrcRectConstraint constraint = make_bool(fuzz) 944 ? SkCanvas::kStrict_SrcRectConstraint 945 : SkCanvas::kFast_SrcRectConstraint; 946 canvas->drawBitmapRect(img, dst, usePaint ? &paint : nullptr, constraint); 947 break; 948 } 949 case 42: { 950 SkBitmap img = MakeFuzzBitmap(fuzz); 951 SkIRect center; 952 SkRect dst; 953 bool usePaint; 954 fuzz->next(¢er, &dst, &usePaint); 955 if (usePaint) { 956 FuzzPaint(fuzz, &paint, depth); 957 } 958 canvas->drawBitmapNine(img, center, dst, usePaint ? &paint : nullptr); 959 break; 960 } 961 case 43: { 962 SkBitmap img = MakeFuzzBitmap(fuzz); 963 bool usePaint; 964 SkRect dst; 965 fuzz->next(&usePaint, &dst); 966 if (usePaint) { 967 FuzzPaint(fuzz, &paint, depth); 968 } 969 constexpr int kMax = 6; 970 int xDivs[kMax], yDivs[kMax]; 971 SkCanvas::Lattice lattice{xDivs, yDivs, nullptr, 0, 0, nullptr}; 972 fuzz->nextRange(&lattice.fXCount, 2, kMax); 973 fuzz->nextRange(&lattice.fYCount, 2, kMax); 974 fuzz->nextN(xDivs, lattice.fXCount); 975 fuzz->nextN(yDivs, lattice.fYCount); 976 canvas->drawBitmapLattice(img, lattice, dst, usePaint ? &paint : nullptr); 977 break; 978 } 979 case 44: { 980 auto img = MakeFuzzImage(fuzz); 981 bool usePaint; 982 SkRect dst; 983 fuzz->next(&usePaint, &dst); 984 if (usePaint) { 985 FuzzPaint(fuzz, &paint, depth); 986 } 987 constexpr int kMax = 6; 988 int xDivs[kMax], yDivs[kMax]; 989 SkCanvas::Lattice lattice{xDivs, yDivs, nullptr, 0, 0, nullptr}; 990 fuzz->nextRange(&lattice.fXCount, 2, kMax); 991 fuzz->nextRange(&lattice.fYCount, 2, kMax); 992 fuzz->nextN(xDivs, lattice.fXCount); 993 fuzz->nextN(yDivs, lattice.fYCount); 994 canvas->drawImageLattice(img.get(), lattice, dst, usePaint ? &paint : nullptr); 995 break; 996 } 997 case 45: { 998 FuzzPaint(fuzz, &paint, depth); 999 FuzzPaintText(fuzz, &paint); 1000 SkScalar x, y; 1001 fuzz->next(&x, &y); 1002 SkTDArray<uint8_t> text = fuzz_text(fuzz, paint); 1003 canvas->drawText(text.begin(), SkToSizeT(text.count()), x, y, paint); 1004 break; 1005 } 1006 case 46: { 1007 FuzzPaint(fuzz, &paint, depth); 1008 FuzzPaintText(fuzz, &paint); 1009 SkTDArray<uint8_t> text = fuzz_text(fuzz, paint); 1010 int glyphCount = paint.countText(text.begin(), SkToSizeT(text.count())); 1011 if (glyphCount < 1) { 1012 break; 1013 } 1014 SkAutoTMalloc<SkPoint> pos(glyphCount); 1015 SkAutoTMalloc<SkScalar> widths(glyphCount); 1016 paint.getTextWidths(text.begin(), SkToSizeT(text.count()), widths.get()); 1017 pos[0] = {0, 0}; 1018 for (int i = 1; i < glyphCount; ++i) { 1019 float y; 1020 fuzz->nextRange(&y, -0.5f * paint.getTextSize(), 1021 0.5f * paint.getTextSize()); 1022 pos[i] = {pos[i - 1].x() + widths[i - 1], y}; 1023 } 1024 canvas->drawPosText(text.begin(), SkToSizeT(text.count()), pos.get(), paint); 1025 break; 1026 } 1027 case 47: { 1028 FuzzPaint(fuzz, &paint, depth); 1029 FuzzPaintText(fuzz, &paint); 1030 SkTDArray<uint8_t> text = fuzz_text(fuzz, paint); 1031 int glyphCount = paint.countText(text.begin(), SkToSizeT(text.count())); 1032 SkAutoTMalloc<SkScalar> widths(glyphCount); 1033 if (glyphCount < 1) { 1034 break; 1035 } 1036 paint.getTextWidths(text.begin(), SkToSizeT(text.count()), widths.get()); 1037 SkScalar x = widths[0]; 1038 for (int i = 0; i < glyphCount; ++i) { 1039 SkTSwap(x, widths[i]); 1040 x += widths[i]; 1041 SkScalar offset; 1042 fuzz->nextRange(&offset, -0.125f * paint.getTextSize(), 1043 0.125f * paint.getTextSize()); 1044 widths[i] += offset; 1045 } 1046 SkScalar y; 1047 fuzz->next(&y); 1048 canvas->drawPosTextH(text.begin(), SkToSizeT(text.count()), 1049 widths.get(), y, paint); 1050 break; 1051 } 1052 case 48: { 1053 FuzzPaint(fuzz, &paint, depth); 1054 FuzzPaintText(fuzz, &paint); 1055 SkTDArray<uint8_t> text = fuzz_text(fuzz, paint); 1056 SkPath path; 1057 fuzz_path(fuzz, &path, 20); 1058 SkScalar hOffset, vOffset; 1059 fuzz->next(&hOffset, &vOffset); 1060 canvas->drawTextOnPathHV(text.begin(), SkToSizeT(text.count()), 1061 path, hOffset, vOffset, paint); 1062 break; 1063 } 1064 case 49: { 1065 SkMatrix matrix; 1066 bool useMatrix = make_bool(fuzz); 1067 if (useMatrix) { 1068 fuzz->next(&matrix); 1069 } 1070 FuzzPaint(fuzz, &paint, depth); 1071 FuzzPaintText(fuzz, &paint); 1072 SkTDArray<uint8_t> text = fuzz_text(fuzz, paint); 1073 SkPath path; 1074 fuzz_path(fuzz, &path, 20); 1075 canvas->drawTextOnPath(text.begin(), SkToSizeT(text.count()), path, 1076 useMatrix ? &matrix : nullptr, paint); 1077 break; 1078 } 1079 case 50: { 1080 // canvas->drawTextRSXform(...); // TODO 1081 break; 1082 } 1083 case 51: { 1084 // canvas->drawTextBlob(...); // TODO 1085 break; 1086 } 1087 case 52: { 1088 bool usePaint, useMatrix; 1089 fuzz->next(&usePaint, &useMatrix); 1090 if (usePaint) { 1091 FuzzPaint(fuzz, &paint, depth); 1092 } 1093 if (useMatrix) { 1094 fuzz->next(&matrix); 1095 } 1096 auto pic = make_picture(fuzz, depth); 1097 canvas->drawPicture(pic, useMatrix ? &matrix : nullptr, 1098 usePaint ? &paint : nullptr); 1099 break; 1100 } 1101 case 53: { 1102 FuzzPaint(fuzz, &paint, depth); 1103 SkCanvas::VertexMode vertexMode; 1104 SkBlendMode mode; 1105 uint8_t vm, bm; 1106 fuzz->nextRange(&vm, 0, (uint8_t)SkCanvas::kTriangleFan_VertexMode); 1107 fuzz->nextRange(&bm, 0, (uint8_t)SkBlendMode::kLastMode); 1108 vertexMode = (SkCanvas::VertexMode)vm; 1109 mode = (SkBlendMode)bm; 1110 constexpr int kMaxCount = 100; 1111 int vertexCount; 1112 SkPoint vertices[kMaxCount]; 1113 SkPoint texs[kMaxCount]; 1114 SkColor colors[kMaxCount]; 1115 fuzz->nextRange(&vertexCount, 3, kMaxCount); 1116 fuzz->nextN(vertices, vertexCount); 1117 bool useTexs, useColors; 1118 fuzz->next(&useTexs, &useColors); 1119 if (useTexs) { 1120 fuzz->nextN(texs, vertexCount); 1121 } 1122 if (useColors) { 1123 fuzz->nextN(colors, vertexCount); 1124 } 1125 int indexCount = 0; 1126 uint16_t indices[kMaxCount * 2]; 1127 if (make_bool(fuzz)) { 1128 fuzz->nextRange(&indexCount, vertexCount, vertexCount + kMaxCount); 1129 for (int i = 0; i < indexCount; ++i) { 1130 fuzz->nextRange(&indices[i], 0, vertexCount - 1); 1131 } 1132 } 1133 canvas->drawVertices(vertexMode, vertexCount, vertices, 1134 useTexs ? texs : nullptr, 1135 useColors ? colors : nullptr, 1136 mode, 1137 indexCount > 0 ? indices : nullptr, 1138 indexCount, 1139 paint); 1140 break; 1141 } 1142 case 54: { 1143 // canvas->drawVertices(...); 1144 // TODO 1145 break; 1146 } 1147 default: 1148 break; 1149 } 1150 } 1151} 1152 1153static sk_sp<SkPicture> make_picture(Fuzz* fuzz, int depth) { 1154 SkScalar w, h; 1155 fuzz->next(&w, &h); 1156 SkPictureRecorder pictureRecorder; 1157 fuzz_canvas(fuzz, pictureRecorder.beginRecording(w, h), depth - 1); 1158 return pictureRecorder.finishRecordingAsPicture(); 1159} 1160 1161DEF_FUZZ(NullCanvas, fuzz) { 1162 fuzz_canvas(fuzz, SkMakeNullCanvas().get()); 1163} 1164 1165DEF_FUZZ(RasterN32Canvas, fuzz) { 1166 fuzz_canvas(fuzz, SkMakeNullCanvas().get()); 1167 auto surface = SkSurface::MakeRasterN32Premul(612, 792); 1168 SkASSERT(surface && surface->getCanvas()); 1169 fuzz_canvas(fuzz, surface->getCanvas()); 1170} 1171 1172DEF_FUZZ(PDFCanvas, fuzz) { 1173 struct final : public SkWStream { 1174 bool write(const void*, size_t n) override { fN += n; return true; } 1175 size_t bytesWritten() const override { return fN; } 1176 size_t fN = 0; 1177 } stream; 1178 auto doc = SkDocument::MakePDF(&stream); 1179 fuzz_canvas(fuzz, doc->beginPage(612.0f, 792.0f)); 1180} 1181 1182// not a "real" thing to fuzz, used to debug errors found while fuzzing. 1183DEF_FUZZ(_DumpCanvas, fuzz) { 1184 SkDebugCanvas debugCanvas(612, 792); 1185 fuzz_canvas(fuzz, &debugCanvas); 1186 std::unique_ptr<SkCanvas> nullCanvas = SkMakeNullCanvas(); 1187 UrlDataManager dataManager(SkString("data")); 1188 Json::Value json = debugCanvas.toJSON(dataManager, debugCanvas.getSize(), nullCanvas.get()); 1189 Json::StyledStreamWriter(" ").write(std::cout, json); 1190} 1191