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 #include "FuzzCommon.h" 10 11 // CORE 12 #include "SkCanvas.h" 13 #include "SkColorFilter.h" 14 #include "SkDebugCanvas.h" 15 #include "SkFontMgr.h" 16 #include "SkImageFilter.h" 17 #include "SkMaskFilter.h" 18 #include "SkNullCanvas.h" 19 #include "SkOSFile.h" 20 #include "SkPDFDocument.h" 21 #include "SkPathEffect.h" 22 #include "SkPicturePriv.h" 23 #include "SkPictureRecorder.h" 24 #include "SkPoint3.h" 25 #include "SkRSXform.h" 26 #include "SkRegion.h" 27 #include "SkSurface.h" 28 #include "SkTo.h" 29 #include "SkTypeface.h" 30 31 // EFFECTS 32 #include "Sk1DPathEffect.h" 33 #include "Sk2DPathEffect.h" 34 #include "SkAlphaThresholdFilter.h" 35 #include "SkArithmeticImageFilter.h" 36 #include "SkBlurImageFilter.h" 37 #include "SkBlurMaskFilter.h" 38 #include "SkColorFilterImageFilter.h" 39 #include "SkColorMatrixFilter.h" 40 #include "SkComposeImageFilter.h" 41 #include "SkCornerPathEffect.h" 42 #include "SkDashPathEffect.h" 43 #include "SkDiscretePathEffect.h" 44 #include "SkDisplacementMapEffect.h" 45 #include "SkDropShadowImageFilter.h" 46 #include "SkGradientShader.h" 47 #include "SkHighContrastFilter.h" 48 #include "SkImageSource.h" 49 #include "SkLightingImageFilter.h" 50 #include "SkLumaColorFilter.h" 51 #include "SkMagnifierImageFilter.h" 52 #include "SkMatrixConvolutionImageFilter.h" 53 #include "SkMergeImageFilter.h" 54 #include "SkMorphologyImageFilter.h" 55 #include "SkOffsetImageFilter.h" 56 #include "SkPaintImageFilter.h" 57 #include "SkPerlinNoiseShader.h" 58 #include "SkPictureImageFilter.h" 59 #include "SkReadBuffer.h" 60 #include "SkTableColorFilter.h" 61 #include "SkTextBlob.h" 62 #include "SkTileImageFilter.h" 63 #include "SkXfermodeImageFilter.h" 64 65 // SRC 66 #include "SkCommandLineFlags.h" 67 #include "SkUTF.h" 68 69 #if SK_SUPPORT_GPU 70 #include "GrContextFactory.h" 71 #include "GrContextPriv.h" 72 #include "gl/GrGLFunctions.h" 73 #include "gl/GrGLGpu.h" 74 #include "gl/GrGLUtil.h" 75 #endif 76 77 // MISC 78 79 #include <iostream> 80 #include <utility> 81 82 DEFINE_bool2(gpuInfo, g, false, "Display GPU information on relevant targets."); 83 84 // TODO: 85 // SkTextBlob with Unicode 86 // SkImage: more types 87 88 // be careful: `foo(make_fuzz_t<T>(f), make_fuzz_t<U>(f))` is undefined. 89 // In fact, all make_fuzz_foo() functions have this potential problem. 90 // Use sequence points! 91 template <typename T> 92 inline T make_fuzz_t(Fuzz* fuzz) { 93 T t; 94 fuzz->next(&t); 95 return t; 96 } 97 98 static sk_sp<SkImage> make_fuzz_image(Fuzz*); 99 100 static SkBitmap make_fuzz_bitmap(Fuzz*); 101 102 static sk_sp<SkPicture> make_fuzz_picture(Fuzz*, int depth); 103 104 static sk_sp<SkColorFilter> make_fuzz_colorfilter(Fuzz* fuzz, int depth) { 105 if (depth <= 0) { 106 return nullptr; 107 } 108 int colorFilterType; 109 fuzz->nextRange(&colorFilterType, 0, 8); 110 switch (colorFilterType) { 111 case 0: 112 return nullptr; 113 case 1: { 114 SkColor color; 115 SkBlendMode mode; 116 fuzz->next(&color); 117 fuzz->nextRange(&mode, 0, SkBlendMode::kLastMode); 118 return SkColorFilter::MakeModeFilter(color, mode); 119 } 120 case 2: { 121 sk_sp<SkColorFilter> outer = make_fuzz_colorfilter(fuzz, depth - 1); 122 if (!outer) { 123 return nullptr; 124 } 125 sk_sp<SkColorFilter> inner = make_fuzz_colorfilter(fuzz, depth - 1); 126 // makeComposed should be able to handle nullptr. 127 return outer->makeComposed(std::move(inner)); 128 } 129 case 3: { 130 SkScalar array[20]; 131 fuzz->nextN(array, SK_ARRAY_COUNT(array)); 132 return SkColorFilter::MakeMatrixFilterRowMajor255(array); 133 } 134 case 4: { 135 SkColor mul, add; 136 fuzz->next(&mul, &add); 137 return SkColorMatrixFilter::MakeLightingFilter(mul, add); 138 } 139 case 5: { 140 bool grayscale; 141 int invertStyle; 142 float contrast; 143 fuzz->next(&grayscale); 144 fuzz->nextRange(&invertStyle, 0, 2); 145 fuzz->nextRange(&contrast, -1.0f, 1.0f); 146 return SkHighContrastFilter::Make(SkHighContrastConfig( 147 grayscale, SkHighContrastConfig::InvertStyle(invertStyle), contrast)); 148 } 149 case 6: 150 return SkLumaColorFilter::Make(); 151 case 7: { 152 uint8_t table[256]; 153 fuzz->nextN(table, SK_ARRAY_COUNT(table)); 154 return SkTableColorFilter::Make(table); 155 } 156 case 8: { 157 uint8_t tableA[256]; 158 uint8_t tableR[256]; 159 uint8_t tableG[256]; 160 uint8_t tableB[256]; 161 fuzz->nextN(tableA, SK_ARRAY_COUNT(tableA)); 162 fuzz->nextN(tableR, SK_ARRAY_COUNT(tableR)); 163 fuzz->nextN(tableG, SK_ARRAY_COUNT(tableG)); 164 fuzz->nextN(tableB, SK_ARRAY_COUNT(tableB)); 165 return SkTableColorFilter::MakeARGB(tableA, tableR, tableG, tableB); 166 } 167 default: 168 SkASSERT(false); 169 break; 170 } 171 return nullptr; 172 } 173 174 static void fuzz_gradient_stops(Fuzz* fuzz, SkScalar* pos, int colorCount) { 175 SkScalar totalPos = 0; 176 for (int i = 0; i < colorCount; ++i) { 177 fuzz->nextRange(&pos[i], 1.0f, 1024.0f); 178 totalPos += pos[i]; 179 } 180 totalPos = 1.0f / totalPos; 181 for (int i = 0; i < colorCount; ++i) { 182 pos[i] *= totalPos; 183 } 184 // SkASSERT(fabs(pos[colorCount - 1] - 1.0f) < 0.00001f); 185 pos[colorCount - 1] = 1.0f; 186 } 187 188 static sk_sp<SkShader> make_fuzz_shader(Fuzz* fuzz, int depth) { 189 sk_sp<SkShader> shader1(nullptr), shader2(nullptr); 190 sk_sp<SkColorFilter> colorFilter(nullptr); 191 SkBitmap bitmap; 192 sk_sp<SkImage> img; 193 SkShader::TileMode tmX, tmY; 194 bool useMatrix; 195 SkColor color; 196 SkMatrix matrix; 197 SkBlendMode blendMode; 198 int shaderType; 199 if (depth <= 0) { 200 return nullptr; 201 } 202 fuzz->nextRange(&shaderType, 0, 14); 203 switch (shaderType) { 204 case 0: 205 return nullptr; 206 case 1: 207 return SkShader::MakeEmptyShader(); 208 case 2: 209 fuzz->next(&color); 210 return SkShader::MakeColorShader(color); 211 case 3: 212 img = make_fuzz_image(fuzz); 213 fuzz->nextRange(&tmX, 0, SkShader::TileMode::kLast_TileMode); 214 fuzz->nextRange(&tmY, 0, SkShader::TileMode::kLast_TileMode); 215 fuzz->next(&useMatrix); 216 if (useMatrix) { 217 FuzzNiceMatrix(fuzz, &matrix); 218 } 219 return img->makeShader(tmX, tmY, useMatrix ? &matrix : nullptr); 220 case 4: 221 bitmap = make_fuzz_bitmap(fuzz); 222 fuzz->nextRange(&tmX, 0, SkShader::TileMode::kLast_TileMode); 223 fuzz->nextRange(&tmY, 0, SkShader::TileMode::kLast_TileMode); 224 fuzz->next(&useMatrix); 225 if (useMatrix) { 226 FuzzNiceMatrix(fuzz, &matrix); 227 } 228 return SkShader::MakeBitmapShader(bitmap, tmX, tmY, useMatrix ? &matrix : nullptr); 229 case 5: 230 shader1 = make_fuzz_shader(fuzz, depth - 1); // limit recursion. 231 FuzzNiceMatrix(fuzz, &matrix); 232 return shader1 ? shader1->makeWithLocalMatrix(matrix) : nullptr; 233 case 6: 234 shader1 = make_fuzz_shader(fuzz, depth - 1); // limit recursion. 235 colorFilter = make_fuzz_colorfilter(fuzz, depth - 1); 236 return shader1 ? shader1->makeWithColorFilter(std::move(colorFilter)) : nullptr; 237 case 7: 238 shader1 = make_fuzz_shader(fuzz, depth - 1); // limit recursion. 239 shader2 = make_fuzz_shader(fuzz, depth - 1); 240 fuzz->nextRange(&blendMode, 0, SkBlendMode::kLastMode); 241 return SkShader::MakeComposeShader(std::move(shader1), std::move(shader2), blendMode); 242 case 8: { 243 auto pic = make_fuzz_picture(fuzz, depth - 1); 244 bool useTile; 245 SkRect tile; 246 fuzz->nextRange(&tmX, 0, SkShader::TileMode::kLast_TileMode); 247 fuzz->nextRange(&tmY, 0, SkShader::TileMode::kLast_TileMode); 248 fuzz->next(&useMatrix, &useTile); 249 if (useMatrix) { 250 FuzzNiceMatrix(fuzz, &matrix); 251 } 252 if (useTile) { 253 fuzz->next(&tile); 254 } 255 return SkShader::MakePictureShader(std::move(pic), tmX, tmY, 256 useMatrix ? &matrix : nullptr, 257 useTile ? &tile : nullptr); 258 } 259 // EFFECTS: 260 case 9: 261 // Deprecated SkGaussianEdgeShader 262 return nullptr; 263 case 10: { 264 constexpr int kMaxColors = 12; 265 SkPoint pts[2]; 266 SkColor colors[kMaxColors]; 267 SkScalar pos[kMaxColors]; 268 int colorCount; 269 bool usePos; 270 fuzz->nextN(pts, 2); 271 fuzz->nextRange(&colorCount, 2, kMaxColors); 272 fuzz->nextN(colors, colorCount); 273 fuzz->nextRange(&tmX, 0, SkShader::TileMode::kLast_TileMode); 274 fuzz->next(&useMatrix, &usePos); 275 if (useMatrix) { 276 FuzzNiceMatrix(fuzz, &matrix); 277 } 278 if (usePos) { 279 fuzz_gradient_stops(fuzz, pos, colorCount); 280 } 281 return SkGradientShader::MakeLinear(pts, colors, usePos ? pos : nullptr, colorCount, 282 tmX, 0, useMatrix ? &matrix : nullptr); 283 } 284 case 11: { 285 constexpr int kMaxColors = 12; 286 SkPoint center; 287 SkScalar radius; 288 int colorCount; 289 bool usePos; 290 SkColor colors[kMaxColors]; 291 SkScalar pos[kMaxColors]; 292 fuzz->nextRange(&tmX, 0, SkShader::TileMode::kLast_TileMode); 293 fuzz->next(&useMatrix, &usePos, ¢er, &radius); 294 fuzz->nextRange(&colorCount, 2, kMaxColors); 295 fuzz->nextN(colors, colorCount); 296 if (useMatrix) { 297 FuzzNiceMatrix(fuzz, &matrix); 298 } 299 if (usePos) { 300 fuzz_gradient_stops(fuzz, pos, colorCount); 301 } 302 return SkGradientShader::MakeRadial(center, radius, colors, usePos ? pos : nullptr, 303 colorCount, tmX, 0, useMatrix ? &matrix : nullptr); 304 } 305 case 12: { 306 constexpr int kMaxColors = 12; 307 SkPoint start, end; 308 SkScalar startRadius, endRadius; 309 int colorCount; 310 bool usePos; 311 SkColor colors[kMaxColors]; 312 SkScalar pos[kMaxColors]; 313 fuzz->nextRange(&tmX, 0, SkShader::TileMode::kLast_TileMode); 314 fuzz->next(&useMatrix, &usePos, &startRadius, &endRadius, &start, &end); 315 fuzz->nextRange(&colorCount, 2, kMaxColors); 316 fuzz->nextN(colors, colorCount); 317 if (useMatrix) { 318 FuzzNiceMatrix(fuzz, &matrix); 319 } 320 if (usePos) { 321 fuzz_gradient_stops(fuzz, pos, colorCount); 322 } 323 return SkGradientShader::MakeTwoPointConical(start, startRadius, end, endRadius, colors, 324 usePos ? pos : nullptr, colorCount, tmX, 0, 325 useMatrix ? &matrix : nullptr); 326 } 327 case 13: { 328 constexpr int kMaxColors = 12; 329 SkScalar cx, cy; 330 int colorCount; 331 bool usePos; 332 SkColor colors[kMaxColors]; 333 SkScalar pos[kMaxColors]; 334 fuzz->next(&cx, &cy, &useMatrix, &usePos); 335 fuzz->nextRange(&colorCount, 2, kMaxColors); 336 fuzz->nextN(colors, colorCount); 337 if (useMatrix) { 338 FuzzNiceMatrix(fuzz, &matrix); 339 } 340 if (usePos) { 341 fuzz_gradient_stops(fuzz, pos, colorCount); 342 } 343 return SkGradientShader::MakeSweep(cx, cy, colors, usePos ? pos : nullptr, colorCount, 344 0, useMatrix ? &matrix : nullptr); 345 } 346 case 14: { 347 SkScalar baseFrequencyX, baseFrequencyY, seed; 348 int numOctaves; 349 SkISize tileSize; 350 bool useTileSize, turbulence; 351 fuzz->next(&baseFrequencyX, &baseFrequencyY, &seed, &useTileSize, &turbulence); 352 if (useTileSize) { 353 fuzz->next(&tileSize); 354 } 355 fuzz->nextRange(&numOctaves, 2, 7); 356 if (turbulence) { 357 return SkPerlinNoiseShader::MakeTurbulence(baseFrequencyX, baseFrequencyY, 358 numOctaves, seed, 359 useTileSize ? &tileSize : nullptr); 360 } else { 361 return SkPerlinNoiseShader::MakeFractalNoise(baseFrequencyX, baseFrequencyY, 362 numOctaves, seed, 363 useTileSize ? &tileSize : nullptr); 364 } 365 } 366 default: 367 SkASSERT(false); 368 break; 369 } 370 return nullptr; 371 } 372 373 static sk_sp<SkPathEffect> make_fuzz_patheffect(Fuzz* fuzz, int depth) { 374 if (depth <= 0) { 375 return nullptr; 376 } 377 uint8_t pathEffectType; 378 fuzz->nextRange(&pathEffectType, 0, 8); 379 switch (pathEffectType) { 380 case 0: { 381 return nullptr; 382 } 383 case 1: { 384 sk_sp<SkPathEffect> first = make_fuzz_patheffect(fuzz, depth - 1); 385 sk_sp<SkPathEffect> second = make_fuzz_patheffect(fuzz, depth - 1); 386 return SkPathEffect::MakeSum(std::move(first), std::move(second)); 387 } 388 case 2: { 389 sk_sp<SkPathEffect> first = make_fuzz_patheffect(fuzz, depth - 1); 390 sk_sp<SkPathEffect> second = make_fuzz_patheffect(fuzz, depth - 1); 391 return SkPathEffect::MakeCompose(std::move(first), std::move(second)); 392 } 393 case 3: { 394 SkPath path; 395 FuzzNicePath(fuzz, &path, 20); 396 SkScalar advance, phase; 397 fuzz->next(&advance, &phase); 398 SkPath1DPathEffect::Style style; 399 fuzz->nextRange(&style, 0, SkPath1DPathEffect::kLastEnum_Style); 400 return SkPath1DPathEffect::Make(path, advance, phase, style); 401 } 402 case 4: { 403 SkScalar width; 404 SkMatrix matrix; 405 fuzz->next(&width); 406 FuzzNiceMatrix(fuzz, &matrix); 407 return SkLine2DPathEffect::Make(width, matrix); 408 } 409 case 5: { 410 SkPath path; 411 FuzzNicePath(fuzz, &path, 20); 412 SkMatrix matrix; 413 FuzzNiceMatrix(fuzz, &matrix); 414 return SkPath2DPathEffect::Make(matrix, path); 415 } 416 case 6: { 417 SkScalar radius; 418 fuzz->next(&radius); 419 return SkCornerPathEffect::Make(radius); 420 } 421 case 7: { 422 SkScalar phase; 423 fuzz->next(&phase); 424 SkScalar intervals[20]; 425 int count; 426 fuzz->nextRange(&count, 0, (int)SK_ARRAY_COUNT(intervals)); 427 fuzz->nextN(intervals, count); 428 return SkDashPathEffect::Make(intervals, count, phase); 429 } 430 case 8: { 431 SkScalar segLength, dev; 432 uint32_t seed; 433 fuzz->next(&segLength, &dev, &seed); 434 return SkDiscretePathEffect::Make(segLength, dev, seed); 435 } 436 default: 437 SkASSERT(false); 438 return nullptr; 439 } 440 } 441 442 static sk_sp<SkMaskFilter> make_fuzz_maskfilter(Fuzz* fuzz) { 443 int maskfilterType; 444 fuzz->nextRange(&maskfilterType, 0, 1); 445 switch (maskfilterType) { 446 case 0: 447 return nullptr; 448 case 1: { 449 SkBlurStyle blurStyle; 450 fuzz->nextRange(&blurStyle, 0, kLastEnum_SkBlurStyle); 451 SkScalar sigma; 452 fuzz->next(&sigma); 453 bool respectCTM; 454 fuzz->next(&respectCTM); 455 return SkMaskFilter::MakeBlur(blurStyle, sigma, respectCTM); 456 } 457 default: 458 SkASSERT(false); 459 return nullptr; 460 } 461 } 462 463 static sk_sp<SkTypeface> make_fuzz_typeface(Fuzz* fuzz) { 464 if (make_fuzz_t<bool>(fuzz)) { 465 return nullptr; 466 } 467 auto fontMugger = SkFontMgr::RefDefault(); 468 SkASSERT(fontMugger); 469 int familyCount = fontMugger->countFamilies(); 470 int i, j; 471 fuzz->nextRange(&i, 0, familyCount - 1); 472 sk_sp<SkFontStyleSet> family(fontMugger->createStyleSet(i)); 473 int styleCount = family->count(); 474 fuzz->nextRange(&j, 0, styleCount - 1); 475 return sk_sp<SkTypeface>(family->createTypeface(j)); 476 } 477 478 static sk_sp<SkImageFilter> make_fuzz_imageFilter(Fuzz* fuzz, int depth); 479 480 static sk_sp<SkImageFilter> make_fuzz_lighting_imagefilter(Fuzz* fuzz, int depth) { 481 if (depth <= 0) { 482 return nullptr; 483 } 484 uint8_t imageFilterType; 485 fuzz->nextRange(&imageFilterType, 1, 6); 486 SkPoint3 p, q; 487 SkColor lightColor; 488 SkScalar surfaceScale, k, specularExponent, cutoffAngle, shininess; 489 sk_sp<SkImageFilter> input; 490 SkImageFilter::CropRect cropRect; 491 bool useCropRect; 492 fuzz->next(&useCropRect); 493 if (useCropRect) { 494 fuzz->next(&cropRect); 495 } 496 switch (imageFilterType) { 497 case 1: 498 fuzz->next(&p, &lightColor, &surfaceScale, &k); 499 input = make_fuzz_imageFilter(fuzz, depth - 1); 500 return SkLightingImageFilter::MakeDistantLitDiffuse(p, lightColor, surfaceScale, k, 501 std::move(input), 502 useCropRect ? &cropRect : nullptr); 503 case 2: 504 fuzz->next(&p, &lightColor, &surfaceScale, &k); 505 input = make_fuzz_imageFilter(fuzz, depth - 1); 506 return SkLightingImageFilter::MakePointLitDiffuse(p, lightColor, surfaceScale, k, 507 std::move(input), 508 useCropRect ? &cropRect : nullptr); 509 case 3: 510 fuzz->next(&p, &q, &specularExponent, &cutoffAngle, &lightColor, &surfaceScale, &k); 511 input = make_fuzz_imageFilter(fuzz, depth - 1); 512 return SkLightingImageFilter::MakeSpotLitDiffuse( 513 p, q, specularExponent, cutoffAngle, lightColor, surfaceScale, k, 514 std::move(input), useCropRect ? &cropRect : nullptr); 515 case 4: 516 fuzz->next(&p, &lightColor, &surfaceScale, &k, &shininess); 517 input = make_fuzz_imageFilter(fuzz, depth - 1); 518 return SkLightingImageFilter::MakeDistantLitSpecular(p, lightColor, surfaceScale, k, 519 shininess, std::move(input), 520 useCropRect ? &cropRect : nullptr); 521 case 5: 522 fuzz->next(&p, &lightColor, &surfaceScale, &k, &shininess); 523 input = make_fuzz_imageFilter(fuzz, depth - 1); 524 return SkLightingImageFilter::MakePointLitSpecular(p, lightColor, surfaceScale, k, 525 shininess, std::move(input), 526 useCropRect ? &cropRect : nullptr); 527 case 6: 528 fuzz->next(&p, &q, &specularExponent, &cutoffAngle, &lightColor, &surfaceScale, &k, 529 &shininess); 530 input = make_fuzz_imageFilter(fuzz, depth - 1); 531 return SkLightingImageFilter::MakeSpotLitSpecular( 532 p, q, specularExponent, cutoffAngle, lightColor, surfaceScale, k, shininess, 533 std::move(input), useCropRect ? &cropRect : nullptr); 534 default: 535 SkASSERT(false); 536 return nullptr; 537 } 538 } 539 540 static void fuzz_paint(Fuzz* fuzz, SkPaint* paint, int depth); 541 542 static sk_sp<SkImageFilter> make_fuzz_imageFilter(Fuzz* fuzz, int depth) { 543 if (depth <= 0) { 544 return nullptr; 545 } 546 uint8_t imageFilterType; 547 fuzz->nextRange(&imageFilterType, 0, 23); 548 switch (imageFilterType) { 549 case 0: 550 return nullptr; 551 case 1: { 552 SkScalar sigmaX, sigmaY; 553 sk_sp<SkImageFilter> input = make_fuzz_imageFilter(fuzz, depth - 1); 554 bool useCropRect; 555 fuzz->next(&sigmaX, &sigmaY, &useCropRect); 556 SkImageFilter::CropRect cropRect; 557 if (useCropRect) { 558 fuzz->next(&cropRect); 559 } 560 return SkBlurImageFilter::Make(sigmaX, sigmaY, std::move(input), 561 useCropRect ? &cropRect : nullptr); 562 } 563 case 2: { 564 SkMatrix matrix; 565 FuzzNiceMatrix(fuzz, &matrix); 566 SkFilterQuality quality; 567 fuzz->nextRange(&quality, 0, SkFilterQuality::kLast_SkFilterQuality); 568 sk_sp<SkImageFilter> input = make_fuzz_imageFilter(fuzz, depth - 1); 569 return SkImageFilter::MakeMatrixFilter(matrix, quality, std::move(input)); 570 } 571 case 3: { 572 SkRegion region; 573 SkScalar innerMin, outerMax; 574 sk_sp<SkImageFilter> input = make_fuzz_imageFilter(fuzz, depth - 1); 575 bool useCropRect; 576 fuzz->next(®ion, &innerMin, &outerMax, &useCropRect); 577 SkImageFilter::CropRect cropRect; 578 if (useCropRect) { 579 fuzz->next(&cropRect); 580 } 581 return SkAlphaThresholdFilter::Make(region, innerMin, outerMax, std::move(input), 582 useCropRect ? &cropRect : nullptr); 583 } 584 case 4: { 585 float k1, k2, k3, k4; 586 bool enforcePMColor; 587 bool useCropRect; 588 fuzz->next(&k1, &k2, &k3, &k4, &enforcePMColor, &useCropRect); 589 sk_sp<SkImageFilter> background = make_fuzz_imageFilter(fuzz, depth - 1); 590 sk_sp<SkImageFilter> foreground = make_fuzz_imageFilter(fuzz, depth - 1); 591 SkImageFilter::CropRect cropRect; 592 if (useCropRect) { 593 fuzz->next(&cropRect); 594 } 595 return SkArithmeticImageFilter::Make(k1, k2, k3, k4, enforcePMColor, 596 std::move(background), std::move(foreground), 597 useCropRect ? &cropRect : nullptr); 598 } 599 case 5: { 600 sk_sp<SkColorFilter> cf = make_fuzz_colorfilter(fuzz, depth - 1); 601 sk_sp<SkImageFilter> input = make_fuzz_imageFilter(fuzz, depth - 1); 602 bool useCropRect; 603 SkImageFilter::CropRect cropRect; 604 fuzz->next(&useCropRect); 605 if (useCropRect) { 606 fuzz->next(&cropRect); 607 } 608 return SkColorFilterImageFilter::Make(std::move(cf), std::move(input), 609 useCropRect ? &cropRect : nullptr); 610 } 611 case 6: { 612 sk_sp<SkImageFilter> ifo = make_fuzz_imageFilter(fuzz, depth - 1); 613 sk_sp<SkImageFilter> ifi = make_fuzz_imageFilter(fuzz, depth - 1); 614 return SkComposeImageFilter::Make(std::move(ifo), std::move(ifi)); 615 } 616 case 7: { 617 SkDisplacementMapEffect::ChannelSelectorType xChannelSelector, yChannelSelector; 618 fuzz->nextRange(&xChannelSelector, 1, 4); 619 fuzz->nextRange(&yChannelSelector, 1, 4); 620 SkScalar scale; 621 bool useCropRect; 622 fuzz->next(&scale, &useCropRect); 623 SkImageFilter::CropRect cropRect; 624 if (useCropRect) { 625 fuzz->next(&cropRect); 626 } 627 sk_sp<SkImageFilter> displacement = make_fuzz_imageFilter(fuzz, depth - 1); 628 sk_sp<SkImageFilter> color = make_fuzz_imageFilter(fuzz, depth - 1); 629 return SkDisplacementMapEffect::Make(xChannelSelector, yChannelSelector, scale, 630 std::move(displacement), std::move(color), 631 useCropRect ? &cropRect : nullptr); 632 } 633 case 8: { 634 SkScalar dx, dy, sigmaX, sigmaY; 635 SkColor color; 636 SkDropShadowImageFilter::ShadowMode shadowMode; 637 fuzz->nextRange(&shadowMode, 0, 1); 638 bool useCropRect; 639 fuzz->next(&dx, &dy, &sigmaX, &sigmaY, &color, &useCropRect); 640 SkImageFilter::CropRect cropRect; 641 if (useCropRect) { 642 fuzz->next(&cropRect); 643 } 644 sk_sp<SkImageFilter> input = make_fuzz_imageFilter(fuzz, depth - 1); 645 return SkDropShadowImageFilter::Make(dx, dy, sigmaX, sigmaY, color, shadowMode, 646 std::move(input), 647 useCropRect ? &cropRect : nullptr); 648 } 649 case 9: 650 return SkImageSource::Make(make_fuzz_image(fuzz)); 651 case 10: { 652 sk_sp<SkImage> image = make_fuzz_image(fuzz); 653 SkRect srcRect, dstRect; 654 SkFilterQuality filterQuality; 655 fuzz->next(&srcRect, &dstRect); 656 fuzz->nextRange(&filterQuality, 0, SkFilterQuality::kLast_SkFilterQuality); 657 return SkImageSource::Make(std::move(image), srcRect, dstRect, filterQuality); 658 } 659 case 11: 660 return make_fuzz_lighting_imagefilter(fuzz, depth - 1); 661 case 12: { 662 SkRect srcRect; 663 SkScalar inset; 664 bool useCropRect; 665 SkImageFilter::CropRect cropRect; 666 fuzz->next(&srcRect, &inset, &useCropRect); 667 if (useCropRect) { 668 fuzz->next(&cropRect); 669 } 670 sk_sp<SkImageFilter> input = make_fuzz_imageFilter(fuzz, depth - 1); 671 return SkMagnifierImageFilter::Make(srcRect, inset, std::move(input), 672 useCropRect ? &cropRect : nullptr); 673 } 674 case 13: { 675 constexpr int kMaxKernelSize = 5; 676 int32_t n, m; 677 fuzz->nextRange(&n, 1, kMaxKernelSize); 678 fuzz->nextRange(&m, 1, kMaxKernelSize); 679 SkScalar kernel[kMaxKernelSize * kMaxKernelSize]; 680 fuzz->nextN(kernel, n * m); 681 int32_t offsetX, offsetY; 682 fuzz->nextRange(&offsetX, 0, n - 1); 683 fuzz->nextRange(&offsetY, 0, m - 1); 684 SkScalar gain, bias; 685 bool convolveAlpha, useCropRect; 686 fuzz->next(&gain, &bias, &convolveAlpha, &useCropRect); 687 SkMatrixConvolutionImageFilter::TileMode tileMode; 688 fuzz->nextRange(&tileMode, 0, SkMatrixConvolutionImageFilter::TileMode::kLast_TileMode); 689 SkImageFilter::CropRect cropRect; 690 if (useCropRect) { 691 fuzz->next(&cropRect); 692 } 693 sk_sp<SkImageFilter> input = make_fuzz_imageFilter(fuzz, depth - 1); 694 return SkMatrixConvolutionImageFilter::Make( 695 SkISize{n, m}, kernel, gain, bias, SkIPoint{offsetX, offsetY}, tileMode, 696 convolveAlpha, std::move(input), useCropRect ? &cropRect : nullptr); 697 } 698 case 14: { 699 sk_sp<SkImageFilter> first = make_fuzz_imageFilter(fuzz, depth - 1); 700 sk_sp<SkImageFilter> second = make_fuzz_imageFilter(fuzz, depth - 1); 701 bool useCropRect; 702 fuzz->next(&useCropRect); 703 SkImageFilter::CropRect cropRect; 704 if (useCropRect) { 705 fuzz->next(&cropRect); 706 } 707 return SkMergeImageFilter::Make(std::move(first), std::move(second), 708 useCropRect ? &cropRect : nullptr); 709 } 710 case 15: { 711 constexpr int kMaxCount = 4; 712 sk_sp<SkImageFilter> ifs[kMaxCount]; 713 int count; 714 fuzz->nextRange(&count, 1, kMaxCount); 715 for (int i = 0; i < count; ++i) { 716 ifs[i] = make_fuzz_imageFilter(fuzz, depth - 1); 717 } 718 bool useCropRect; 719 fuzz->next(&useCropRect); 720 SkImageFilter::CropRect cropRect; 721 if (useCropRect) { 722 fuzz->next(&cropRect); 723 } 724 return SkMergeImageFilter::Make(ifs, count, useCropRect ? &cropRect : nullptr); 725 } 726 case 16: { 727 int rx, ry; 728 fuzz->next(&rx, &ry); 729 bool useCropRect; 730 fuzz->next(&useCropRect); 731 SkImageFilter::CropRect cropRect; 732 if (useCropRect) { 733 fuzz->next(&cropRect); 734 } 735 sk_sp<SkImageFilter> input = make_fuzz_imageFilter(fuzz, depth - 1); 736 return SkDilateImageFilter::Make(rx, ry, std::move(input), 737 useCropRect ? &cropRect : nullptr); 738 } 739 case 17: { 740 int rx, ry; 741 fuzz->next(&rx, &ry); 742 bool useCropRect; 743 fuzz->next(&useCropRect); 744 SkImageFilter::CropRect cropRect; 745 if (useCropRect) { 746 fuzz->next(&cropRect); 747 } 748 sk_sp<SkImageFilter> input = make_fuzz_imageFilter(fuzz, depth - 1); 749 return SkErodeImageFilter::Make(rx, ry, std::move(input), 750 useCropRect ? &cropRect : nullptr); 751 } 752 case 18: { 753 SkScalar dx, dy; 754 fuzz->next(&dx, &dy); 755 bool useCropRect; 756 fuzz->next(&useCropRect); 757 SkImageFilter::CropRect cropRect; 758 if (useCropRect) { 759 fuzz->next(&cropRect); 760 } 761 sk_sp<SkImageFilter> input = make_fuzz_imageFilter(fuzz, depth - 1); 762 return SkOffsetImageFilter::Make(dx, dy, std::move(input), 763 useCropRect ? &cropRect : nullptr); 764 } 765 case 19: { 766 SkPaint paint; 767 fuzz_paint(fuzz, &paint, depth - 1); 768 bool useCropRect; 769 fuzz->next(&useCropRect); 770 SkImageFilter::CropRect cropRect; 771 if (useCropRect) { 772 fuzz->next(&cropRect); 773 } 774 return SkPaintImageFilter::Make(paint, useCropRect ? &cropRect : nullptr); 775 } 776 case 20: { 777 sk_sp<SkPicture> picture = make_fuzz_picture(fuzz, depth - 1); 778 return SkPictureImageFilter::Make(std::move(picture)); 779 } 780 case 21: { 781 SkRect cropRect; 782 fuzz->next(&cropRect); 783 sk_sp<SkPicture> picture = make_fuzz_picture(fuzz, depth - 1); 784 return SkPictureImageFilter::Make(std::move(picture), cropRect); 785 } 786 case 22: { 787 SkRect src, dst; 788 fuzz->next(&src, &dst); 789 sk_sp<SkImageFilter> input = make_fuzz_imageFilter(fuzz, depth - 1); 790 return SkTileImageFilter::Make(src, dst, std::move(input)); 791 } 792 case 23: { 793 SkBlendMode blendMode; 794 bool useCropRect; 795 fuzz->next(&useCropRect); 796 fuzz->nextRange(&blendMode, 0, SkBlendMode::kLastMode); 797 SkImageFilter::CropRect cropRect; 798 if (useCropRect) { 799 fuzz->next(&cropRect); 800 } 801 sk_sp<SkImageFilter> bg = make_fuzz_imageFilter(fuzz, depth - 1); 802 sk_sp<SkImageFilter> fg = make_fuzz_imageFilter(fuzz, depth - 1); 803 return SkXfermodeImageFilter::Make(blendMode, std::move(bg), std::move(fg), 804 useCropRect ? &cropRect : nullptr); 805 } 806 default: 807 SkASSERT(false); 808 return nullptr; 809 } 810 } 811 812 static sk_sp<SkImage> make_fuzz_image(Fuzz* fuzz) { 813 int w, h; 814 fuzz->nextRange(&w, 1, 1024); 815 fuzz->nextRange(&h, 1, 1024); 816 SkAutoTMalloc<SkPMColor> data(w * h); 817 SkPixmap pixmap(SkImageInfo::MakeN32Premul(w, h), data.get(), w * sizeof(SkPMColor)); 818 int n = w * h; 819 for (int i = 0; i < n; ++i) { 820 SkColor c; 821 fuzz->next(&c); 822 data[i] = SkPreMultiplyColor(c); 823 } 824 (void)data.release(); 825 return SkImage::MakeFromRaster(pixmap, [](const void* p, void*) { sk_free((void*)p); }, 826 nullptr); 827 } 828 829 static SkBitmap make_fuzz_bitmap(Fuzz* fuzz) { 830 SkBitmap bitmap; 831 int w, h; 832 fuzz->nextRange(&w, 1, 1024); 833 fuzz->nextRange(&h, 1, 1024); 834 if (!bitmap.tryAllocN32Pixels(w, h)) { 835 SkDEBUGF("Could not allocate pixels %d x %d", w, h); 836 return bitmap; 837 } 838 for (int y = 0; y < h; ++y) { 839 for (int x = 0; x < w; ++x) { 840 SkColor c; 841 fuzz->next(&c); 842 *bitmap.getAddr32(x, y) = SkPreMultiplyColor(c); 843 } 844 } 845 return bitmap; 846 } 847 848 template <typename T, typename Min, typename Max> 849 inline T make_fuzz_t_range(Fuzz* fuzz, Min minv, Max maxv) { 850 T value; 851 fuzz->nextRange(&value, minv, maxv); 852 return value; 853 } 854 855 static void fuzz_paint(Fuzz* fuzz, SkPaint* paint, int depth) { 856 if (!fuzz || !paint || depth <= 0) { 857 return; 858 } 859 860 paint->setAntiAlias( make_fuzz_t<bool>(fuzz)); 861 paint->setDither( make_fuzz_t<bool>(fuzz)); 862 paint->setColor( make_fuzz_t<SkColor>(fuzz)); 863 paint->setBlendMode( make_fuzz_t_range<SkBlendMode>(fuzz, 0, SkBlendMode::kLastMode)); 864 paint->setFilterQuality(make_fuzz_t_range<SkFilterQuality>(fuzz, 0, kLast_SkFilterQuality)); 865 paint->setStyle( make_fuzz_t_range<SkPaint::Style>(fuzz, 0, 2)); 866 paint->setShader( make_fuzz_shader(fuzz, depth - 1)); 867 paint->setPathEffect( make_fuzz_patheffect(fuzz, depth - 1)); 868 paint->setMaskFilter( make_fuzz_maskfilter(fuzz)); 869 paint->setImageFilter( make_fuzz_imageFilter(fuzz, depth - 1)); 870 paint->setColorFilter( make_fuzz_colorfilter(fuzz, depth - 1)); 871 872 if (paint->getStyle() != SkPaint::kFill_Style) { 873 paint->setStrokeWidth(make_fuzz_t<SkScalar>(fuzz)); 874 paint->setStrokeMiter(make_fuzz_t<SkScalar>(fuzz)); 875 paint->setStrokeCap( make_fuzz_t_range<SkPaint::Cap>(fuzz, 0, SkPaint::kLast_Cap)); 876 paint->setStrokeJoin( make_fuzz_t_range<SkPaint::Join>(fuzz, 0, SkPaint::kLast_Join)); 877 } 878 } 879 880 static SkFont fuzz_font(Fuzz* fuzz) { 881 SkFont font; 882 font.setTypeface( make_fuzz_typeface(fuzz)); 883 font.setSize( make_fuzz_t<SkScalar>(fuzz)); 884 font.setScaleX( make_fuzz_t<SkScalar>(fuzz)); 885 font.setSkewX( make_fuzz_t<SkScalar>(fuzz)); 886 font.setLinearMetrics( make_fuzz_t<bool>(fuzz)); 887 font.setSubpixel( make_fuzz_t<bool>(fuzz)); 888 font.setEmbeddedBitmaps( make_fuzz_t<bool>(fuzz)); 889 font.setForceAutoHinting( make_fuzz_t<bool>(fuzz)); 890 font.setEmbolden( make_fuzz_t<bool>(fuzz)); 891 font.setHinting( make_fuzz_t_range<SkFontHinting>(fuzz, 0, kFull_SkFontHinting)); 892 font.setEdging( make_fuzz_t_range<SkFont::Edging>(fuzz, 0, 893 (int)SkFont::Edging::kSubpixelAntiAlias)); 894 return font; 895 } 896 897 static SkTextEncoding fuzz_paint_text_encoding(Fuzz* fuzz) { 898 return make_fuzz_t_range<SkTextEncoding>(fuzz, 0, 3); 899 } 900 901 constexpr int kMaxGlyphCount = 30; 902 903 static SkTDArray<uint8_t> make_fuzz_text(Fuzz* fuzz, const SkFont& font, SkTextEncoding encoding) { 904 SkTDArray<uint8_t> array; 905 if (kGlyphID_SkTextEncoding == encoding) { 906 int glyphRange = font.getTypefaceOrDefault()->countGlyphs(); 907 if (glyphRange == 0) { 908 // Some fuzzing environments have no fonts, so empty array is the best 909 // we can do. 910 return array; 911 } 912 int glyphCount; 913 fuzz->nextRange(&glyphCount, 1, kMaxGlyphCount); 914 SkGlyphID* glyphs = (SkGlyphID*)array.append(glyphCount * sizeof(SkGlyphID)); 915 for (int i = 0; i < glyphCount; ++i) { 916 fuzz->nextRange(&glyphs[i], 0, glyphRange - 1); 917 } 918 return array; 919 } 920 static const SkUnichar ranges[][2] = { 921 {0x0020, 0x007F}, 922 {0x00A1, 0x0250}, 923 {0x0400, 0x0500}, 924 }; 925 int32_t count = 0; 926 for (size_t i = 0; i < SK_ARRAY_COUNT(ranges); ++i) { 927 count += (ranges[i][1] - ranges[i][0]); 928 } 929 constexpr int kMaxLength = kMaxGlyphCount; 930 SkUnichar buffer[kMaxLength]; 931 int length; 932 fuzz->nextRange(&length, 1, kMaxLength); 933 for (int j = 0; j < length; ++j) { 934 int32_t value; 935 fuzz->nextRange(&value, 0, count - 1); 936 for (size_t i = 0; i < SK_ARRAY_COUNT(ranges); ++i) { 937 if (value + ranges[i][0] < ranges[i][1]) { 938 buffer[j] = value + ranges[i][0]; 939 break; 940 } else { 941 value -= (ranges[i][1] - ranges[i][0]); 942 } 943 } 944 } 945 switch (encoding) { 946 case kUTF8_SkTextEncoding: { 947 size_t utf8len = 0; 948 for (int j = 0; j < length; ++j) { 949 utf8len += SkUTF::ToUTF8(buffer[j], nullptr); 950 } 951 char* ptr = (char*)array.append(utf8len); 952 for (int j = 0; j < length; ++j) { 953 ptr += SkUTF::ToUTF8(buffer[j], ptr); 954 } 955 } break; 956 case kUTF16_SkTextEncoding: { 957 size_t utf16len = 0; 958 for (int j = 0; j < length; ++j) { 959 utf16len += SkUTF::ToUTF16(buffer[j]); 960 } 961 uint16_t* ptr = (uint16_t*)array.append(utf16len * sizeof(uint16_t)); 962 for (int j = 0; j < length; ++j) { 963 ptr += SkUTF::ToUTF16(buffer[j], ptr); 964 } 965 } break; 966 case kUTF32_SkTextEncoding: 967 memcpy(array.append(length * sizeof(SkUnichar)), buffer, length * sizeof(SkUnichar)); 968 break; 969 default: 970 SkASSERT(false); 971 break; 972 } 973 return array; 974 } 975 976 static sk_sp<SkTextBlob> make_fuzz_textblob(Fuzz* fuzz) { 977 SkTextBlobBuilder textBlobBuilder; 978 int8_t runCount; 979 fuzz->nextRange(&runCount, (int8_t)1, (int8_t)8); 980 while (runCount-- > 0) { 981 SkFont font; 982 SkTextEncoding encoding = fuzz_paint_text_encoding(fuzz); 983 font.setEdging(make_fuzz_t<bool>(fuzz) ? SkFont::Edging::kAlias : SkFont::Edging::kAntiAlias); 984 SkTDArray<uint8_t> text = make_fuzz_text(fuzz, font, encoding); 985 int glyphCount = font.countText(text.begin(), SkToSizeT(text.count()), encoding); 986 SkASSERT(glyphCount <= kMaxGlyphCount); 987 SkScalar x, y; 988 const SkTextBlobBuilder::RunBuffer* buffer; 989 uint8_t runType; 990 fuzz->nextRange(&runType, (uint8_t)0, (uint8_t)2); 991 const void* textPtr = text.begin(); 992 size_t textLen = SkToSizeT(text.count()); 993 switch (runType) { 994 case 0: 995 fuzz->next(&x, &y); 996 // TODO: Test other variations of this. 997 buffer = &textBlobBuilder.allocRun(font, glyphCount, x, y); 998 (void)font.textToGlyphs(textPtr, textLen, encoding, buffer->glyphs, glyphCount); 999 break; 1000 case 1: 1001 fuzz->next(&y); 1002 // TODO: Test other variations of this. 1003 buffer = &textBlobBuilder.allocRunPosH(font, glyphCount, y); 1004 (void)font.textToGlyphs(textPtr, textLen, encoding, buffer->glyphs, glyphCount); 1005 fuzz->nextN(buffer->pos, glyphCount); 1006 break; 1007 case 2: 1008 // TODO: Test other variations of this. 1009 buffer = &textBlobBuilder.allocRunPos(font, glyphCount); 1010 (void)font.textToGlyphs(textPtr, textLen, encoding, buffer->glyphs, glyphCount); 1011 fuzz->nextN(buffer->pos, glyphCount * 2); 1012 break; 1013 default: 1014 SkASSERT(false); 1015 break; 1016 } 1017 } 1018 return textBlobBuilder.make(); 1019 } 1020 1021 extern std::atomic<bool> gSkUseDeltaAA; 1022 extern std::atomic<bool> gSkForceDeltaAA; 1023 1024 static void fuzz_canvas(Fuzz* fuzz, SkCanvas* canvas, int depth = 9) { 1025 if (!fuzz || !canvas || depth <= 0) { 1026 return; 1027 } 1028 SkAutoCanvasRestore autoCanvasRestore(canvas, false); 1029 bool useDAA; 1030 fuzz->next(&useDAA); 1031 if (useDAA) { 1032 gSkForceDeltaAA = true; 1033 gSkUseDeltaAA = true; 1034 } 1035 unsigned N; 1036 fuzz->nextRange(&N, 0, 2000); 1037 for (unsigned i = 0; i < N; ++i) { 1038 if (fuzz->exhausted()) { 1039 return; 1040 } 1041 SkPaint paint; 1042 SkFont font; 1043 unsigned drawCommand; 1044 fuzz->nextRange(&drawCommand, 0, 53); 1045 switch (drawCommand) { 1046 case 0: 1047 canvas->flush(); 1048 break; 1049 case 1: 1050 canvas->save(); 1051 break; 1052 case 2: { 1053 SkRect bounds; 1054 fuzz->next(&bounds); 1055 fuzz_paint(fuzz, &paint, depth - 1); 1056 canvas->saveLayer(&bounds, &paint); 1057 break; 1058 } 1059 case 3: { 1060 SkRect bounds; 1061 fuzz->next(&bounds); 1062 canvas->saveLayer(&bounds, nullptr); 1063 break; 1064 } 1065 case 4: 1066 fuzz_paint(fuzz, &paint, depth - 1); 1067 canvas->saveLayer(nullptr, &paint); 1068 break; 1069 case 5: 1070 canvas->saveLayer(nullptr, nullptr); 1071 break; 1072 case 6: { 1073 uint8_t alpha; 1074 fuzz->next(&alpha); 1075 canvas->saveLayerAlpha(nullptr, (U8CPU)alpha); 1076 break; 1077 } 1078 case 7: { 1079 SkRect bounds; 1080 uint8_t alpha; 1081 fuzz->next(&bounds, &alpha); 1082 canvas->saveLayerAlpha(&bounds, (U8CPU)alpha); 1083 break; 1084 } 1085 case 8: { 1086 SkCanvas::SaveLayerRec saveLayerRec; 1087 SkRect bounds; 1088 if (make_fuzz_t<bool>(fuzz)) { 1089 fuzz->next(&bounds); 1090 saveLayerRec.fBounds = &bounds; 1091 } 1092 if (make_fuzz_t<bool>(fuzz)) { 1093 fuzz_paint(fuzz, &paint, depth - 1); 1094 saveLayerRec.fPaint = &paint; 1095 } 1096 sk_sp<SkImageFilter> imageFilter; 1097 if (make_fuzz_t<bool>(fuzz)) { 1098 imageFilter = make_fuzz_imageFilter(fuzz, depth - 1); 1099 saveLayerRec.fBackdrop = imageFilter.get(); 1100 } 1101 // _DumpCanvas can't handle this. 1102 // if (make_fuzz_t<bool>(fuzz)) { 1103 // saveLayerRec.fSaveLayerFlags |= SkCanvas::kPreserveLCDText_SaveLayerFlag; 1104 // } 1105 1106 canvas->saveLayer(saveLayerRec); 1107 break; 1108 } 1109 case 9: 1110 canvas->restore(); 1111 break; 1112 case 10: { 1113 int saveCount; 1114 fuzz->next(&saveCount); 1115 canvas->restoreToCount(saveCount); 1116 break; 1117 } 1118 case 11: { 1119 SkScalar x, y; 1120 fuzz->next(&x, &y); 1121 canvas->translate(x, y); 1122 break; 1123 } 1124 case 12: { 1125 SkScalar x, y; 1126 fuzz->next(&x, &y); 1127 canvas->scale(x, y); 1128 break; 1129 } 1130 case 13: { 1131 SkScalar v; 1132 fuzz->next(&v); 1133 canvas->rotate(v); 1134 break; 1135 } 1136 case 14: { 1137 SkScalar x, y, v; 1138 fuzz->next(&x, &y, &v); 1139 canvas->rotate(v, x, y); 1140 break; 1141 } 1142 case 15: { 1143 SkScalar x, y; 1144 fuzz->next(&x, &y); 1145 canvas->skew(x, y); 1146 break; 1147 } 1148 case 16: { 1149 SkMatrix mat; 1150 FuzzNiceMatrix(fuzz, &mat); 1151 canvas->concat(mat); 1152 break; 1153 } 1154 case 17: { 1155 SkMatrix mat; 1156 FuzzNiceMatrix(fuzz, &mat); 1157 canvas->setMatrix(mat); 1158 break; 1159 } 1160 case 18: 1161 canvas->resetMatrix(); 1162 break; 1163 case 19: { 1164 SkRect r; 1165 int op; 1166 bool doAntiAlias; 1167 fuzz->next(&r, &doAntiAlias); 1168 fuzz->nextRange(&op, 0, 1); 1169 r.sort(); 1170 canvas->clipRect(r, (SkClipOp)op, doAntiAlias); 1171 break; 1172 } 1173 case 20: { 1174 SkRRect rr; 1175 int op; 1176 bool doAntiAlias; 1177 FuzzNiceRRect(fuzz, &rr); 1178 fuzz->next(&doAntiAlias); 1179 fuzz->nextRange(&op, 0, 1); 1180 canvas->clipRRect(rr, (SkClipOp)op, doAntiAlias); 1181 break; 1182 } 1183 case 21: { 1184 SkPath path; 1185 FuzzNicePath(fuzz, &path, 30); 1186 int op; 1187 bool doAntiAlias; 1188 fuzz->next(&doAntiAlias); 1189 fuzz->nextRange(&op, 0, 1); 1190 canvas->clipPath(path, (SkClipOp)op, doAntiAlias); 1191 break; 1192 } 1193 case 22: { 1194 SkRegion region; 1195 int op; 1196 fuzz->next(®ion); 1197 fuzz->nextRange(&op, 0, 1); 1198 canvas->clipRegion(region, (SkClipOp)op); 1199 break; 1200 } 1201 case 23: 1202 fuzz_paint(fuzz, &paint, depth - 1); 1203 canvas->drawPaint(paint); 1204 break; 1205 case 24: { 1206 fuzz_paint(fuzz, &paint, depth - 1); 1207 SkCanvas::PointMode pointMode; 1208 fuzz->nextRange(&pointMode, 1209 SkCanvas::kPoints_PointMode, SkCanvas::kPolygon_PointMode); 1210 size_t count; 1211 constexpr int kMaxCount = 30; 1212 fuzz->nextRange(&count, 0, kMaxCount); 1213 SkPoint pts[kMaxCount]; 1214 fuzz->nextN(pts, count); 1215 canvas->drawPoints(pointMode, count, pts, paint); 1216 break; 1217 } 1218 case 25: { 1219 fuzz_paint(fuzz, &paint, depth - 1); 1220 SkRect r; 1221 fuzz->next(&r); 1222 if (!r.isFinite()) { 1223 break; 1224 } 1225 canvas->drawRect(r, paint); 1226 break; 1227 } 1228 case 26: { 1229 fuzz_paint(fuzz, &paint, depth - 1); 1230 SkRegion region; 1231 fuzz->next(®ion); 1232 canvas->drawRegion(region, paint); 1233 break; 1234 } 1235 case 27: { 1236 fuzz_paint(fuzz, &paint, depth - 1); 1237 SkRect r; 1238 fuzz->next(&r); 1239 if (!r.isFinite()) { 1240 break; 1241 } 1242 canvas->drawOval(r, paint); 1243 break; 1244 } 1245 case 28: break; // must have deleted this some time earlier 1246 case 29: { 1247 fuzz_paint(fuzz, &paint, depth - 1); 1248 SkRRect rr; 1249 FuzzNiceRRect(fuzz, &rr); 1250 canvas->drawRRect(rr, paint); 1251 break; 1252 } 1253 case 30: { 1254 fuzz_paint(fuzz, &paint, depth - 1); 1255 SkRRect orr, irr; 1256 FuzzNiceRRect(fuzz, &orr); 1257 FuzzNiceRRect(fuzz, &irr); 1258 if (orr.getBounds().contains(irr.getBounds())) { 1259 canvas->drawDRRect(orr, irr, paint); 1260 } 1261 break; 1262 } 1263 case 31: { 1264 fuzz_paint(fuzz, &paint, depth - 1); 1265 SkRect r; 1266 SkScalar start, sweep; 1267 bool useCenter; 1268 fuzz->next(&r, &start, &sweep, &useCenter); 1269 canvas->drawArc(r, start, sweep, useCenter, paint); 1270 break; 1271 } 1272 case 32: { 1273 fuzz_paint(fuzz, &paint, depth - 1); 1274 SkPath path; 1275 FuzzNicePath(fuzz, &path, 60); 1276 canvas->drawPath(path, paint); 1277 break; 1278 } 1279 case 33: { 1280 sk_sp<SkImage> img = make_fuzz_image(fuzz); 1281 SkScalar left, top; 1282 bool usePaint; 1283 fuzz->next(&left, &top, &usePaint); 1284 if (usePaint) { 1285 fuzz_paint(fuzz, &paint, depth - 1); 1286 } 1287 canvas->drawImage(img.get(), left, top, usePaint ? &paint : nullptr); 1288 break; 1289 } 1290 case 34: { 1291 auto img = make_fuzz_image(fuzz); 1292 SkRect src, dst; 1293 bool usePaint; 1294 fuzz->next(&src, &dst, &usePaint); 1295 if (usePaint) { 1296 fuzz_paint(fuzz, &paint, depth - 1); 1297 } 1298 canvas->drawImageRect(img, src, dst, usePaint ? &paint : nullptr); 1299 break; 1300 } 1301 case 35: { 1302 auto img = make_fuzz_image(fuzz); 1303 SkIRect src; 1304 SkRect dst; 1305 bool usePaint; 1306 fuzz->next(&src, &dst, &usePaint); 1307 if (usePaint) { 1308 fuzz_paint(fuzz, &paint, depth - 1); 1309 } 1310 SkCanvas::SrcRectConstraint constraint = 1311 make_fuzz_t<bool>(fuzz) ? SkCanvas::kStrict_SrcRectConstraint 1312 : SkCanvas::kFast_SrcRectConstraint; 1313 canvas->drawImageRect(img, src, dst, usePaint ? &paint : nullptr, constraint); 1314 break; 1315 } 1316 case 36: { 1317 bool usePaint; 1318 auto img = make_fuzz_image(fuzz); 1319 SkRect dst; 1320 fuzz->next(&dst, &usePaint); 1321 if (usePaint) { 1322 fuzz_paint(fuzz, &paint, depth - 1); 1323 } 1324 canvas->drawImageRect(img, dst, usePaint ? &paint : nullptr); 1325 break; 1326 } 1327 case 37: { 1328 auto img = make_fuzz_image(fuzz); 1329 SkIRect center; 1330 SkRect dst; 1331 bool usePaint; 1332 fuzz->next(&usePaint); 1333 if (usePaint) { 1334 fuzz_paint(fuzz, &paint, depth - 1); 1335 } 1336 if (make_fuzz_t<bool>(fuzz)) { 1337 fuzz->next(¢er); 1338 } else { // Make valid center, see SkLatticeIter::Valid(). 1339 fuzz->nextRange(¢er.fLeft, 0, img->width() - 1); 1340 fuzz->nextRange(¢er.fTop, 0, img->height() - 1); 1341 fuzz->nextRange(¢er.fRight, center.fLeft + 1, img->width()); 1342 fuzz->nextRange(¢er.fBottom, center.fTop + 1, img->height()); 1343 } 1344 fuzz->next(&dst); 1345 canvas->drawImageNine(img, center, dst, usePaint ? &paint : nullptr); 1346 break; 1347 } 1348 case 38: { 1349 SkBitmap bitmap = make_fuzz_bitmap(fuzz); 1350 SkScalar left, top; 1351 bool usePaint; 1352 fuzz->next(&left, &top, &usePaint); 1353 if (usePaint) { 1354 fuzz_paint(fuzz, &paint, depth - 1); 1355 } 1356 canvas->drawBitmap(bitmap, left, top, usePaint ? &paint : nullptr); 1357 break; 1358 } 1359 case 39: { 1360 SkBitmap bitmap = make_fuzz_bitmap(fuzz); 1361 SkRect src, dst; 1362 bool usePaint; 1363 fuzz->next(&src, &dst, &usePaint); 1364 if (usePaint) { 1365 fuzz_paint(fuzz, &paint, depth - 1); 1366 } 1367 SkCanvas::SrcRectConstraint constraint = 1368 make_fuzz_t<bool>(fuzz) ? SkCanvas::kStrict_SrcRectConstraint 1369 : SkCanvas::kFast_SrcRectConstraint; 1370 canvas->drawBitmapRect(bitmap, src, dst, usePaint ? &paint : nullptr, constraint); 1371 break; 1372 } 1373 case 40: { 1374 SkBitmap img = make_fuzz_bitmap(fuzz); 1375 SkIRect src; 1376 SkRect dst; 1377 bool usePaint; 1378 fuzz->next(&src, &dst, &usePaint); 1379 if (usePaint) { 1380 fuzz_paint(fuzz, &paint, depth - 1); 1381 } 1382 SkCanvas::SrcRectConstraint constraint = 1383 make_fuzz_t<bool>(fuzz) ? SkCanvas::kStrict_SrcRectConstraint 1384 : SkCanvas::kFast_SrcRectConstraint; 1385 canvas->drawBitmapRect(img, src, dst, usePaint ? &paint : nullptr, constraint); 1386 break; 1387 } 1388 case 41: { 1389 SkBitmap img = make_fuzz_bitmap(fuzz); 1390 SkRect dst; 1391 bool usePaint; 1392 fuzz->next(&dst, &usePaint); 1393 if (usePaint) { 1394 fuzz_paint(fuzz, &paint, depth - 1); 1395 } 1396 SkCanvas::SrcRectConstraint constraint = 1397 make_fuzz_t<bool>(fuzz) ? SkCanvas::kStrict_SrcRectConstraint 1398 : SkCanvas::kFast_SrcRectConstraint; 1399 canvas->drawBitmapRect(img, dst, usePaint ? &paint : nullptr, constraint); 1400 break; 1401 } 1402 case 42: { 1403 SkBitmap img = make_fuzz_bitmap(fuzz); 1404 SkIRect center; 1405 SkRect dst; 1406 bool usePaint; 1407 fuzz->next(&usePaint); 1408 if (usePaint) { 1409 fuzz_paint(fuzz, &paint, depth - 1); 1410 } 1411 if (make_fuzz_t<bool>(fuzz)) { 1412 fuzz->next(¢er); 1413 } else { // Make valid center, see SkLatticeIter::Valid(). 1414 if (img.width() == 0 || img.height() == 0) { 1415 // bitmap may not have had its pixels initialized. 1416 break; 1417 } 1418 fuzz->nextRange(¢er.fLeft, 0, img.width() - 1); 1419 fuzz->nextRange(¢er.fTop, 0, img.height() - 1); 1420 fuzz->nextRange(¢er.fRight, center.fLeft + 1, img.width()); 1421 fuzz->nextRange(¢er.fBottom, center.fTop + 1, img.height()); 1422 } 1423 fuzz->next(&dst); 1424 canvas->drawBitmapNine(img, center, dst, usePaint ? &paint : nullptr); 1425 break; 1426 } 1427 case 43: { 1428 SkBitmap img = make_fuzz_bitmap(fuzz); 1429 bool usePaint; 1430 SkRect dst; 1431 fuzz->next(&usePaint, &dst); 1432 if (usePaint) { 1433 fuzz_paint(fuzz, &paint, depth - 1); 1434 } 1435 constexpr int kMax = 6; 1436 int xDivs[kMax], yDivs[kMax]; 1437 SkCanvas::Lattice lattice{xDivs, yDivs, nullptr, 0, 0, nullptr, nullptr}; 1438 fuzz->nextRange(&lattice.fXCount, 2, kMax); 1439 fuzz->nextRange(&lattice.fYCount, 2, kMax); 1440 fuzz->nextN(xDivs, lattice.fXCount); 1441 fuzz->nextN(yDivs, lattice.fYCount); 1442 canvas->drawBitmapLattice(img, lattice, dst, usePaint ? &paint : nullptr); 1443 break; 1444 } 1445 case 44: { 1446 auto img = make_fuzz_image(fuzz); 1447 bool usePaint; 1448 SkRect dst; 1449 fuzz->next(&usePaint, &dst); 1450 if (usePaint) { 1451 fuzz_paint(fuzz, &paint, depth - 1); 1452 } 1453 constexpr int kMax = 6; 1454 int xDivs[kMax], yDivs[kMax]; 1455 SkCanvas::Lattice lattice{xDivs, yDivs, nullptr, 0, 0, nullptr, nullptr}; 1456 fuzz->nextRange(&lattice.fXCount, 2, kMax); 1457 fuzz->nextRange(&lattice.fYCount, 2, kMax); 1458 fuzz->nextN(xDivs, lattice.fXCount); 1459 fuzz->nextN(yDivs, lattice.fYCount); 1460 canvas->drawImageLattice(img.get(), lattice, dst, usePaint ? &paint : nullptr); 1461 break; 1462 } 1463 case 45: { 1464 fuzz_paint(fuzz, &paint, depth - 1); 1465 font = fuzz_font(fuzz); 1466 SkTextEncoding encoding = fuzz_paint_text_encoding(fuzz); 1467 SkScalar x, y; 1468 fuzz->next(&x, &y); 1469 SkTDArray<uint8_t> text = make_fuzz_text(fuzz, font, encoding); 1470 canvas->drawSimpleText(text.begin(), SkToSizeT(text.count()), encoding, x, y, 1471 font, paint); 1472 break; 1473 } 1474 case 46: { 1475 // was drawPosText 1476 break; 1477 } 1478 case 47: { 1479 // was drawPosTextH 1480 break; 1481 } 1482 case 48: { 1483 // was drawtextonpath 1484 break; 1485 } 1486 case 49: { 1487 // was drawtextonpath 1488 break; 1489 } 1490 case 50: { 1491 // was drawTextRSXform 1492 break; 1493 } 1494 case 51: { 1495 sk_sp<SkTextBlob> blob = make_fuzz_textblob(fuzz); 1496 fuzz_paint(fuzz, &paint, depth - 1); 1497 SkScalar x, y; 1498 fuzz->next(&x, &y); 1499 canvas->drawTextBlob(blob, x, y, paint); 1500 break; 1501 } 1502 case 52: { 1503 SkMatrix matrix; 1504 bool usePaint, useMatrix; 1505 fuzz->next(&usePaint, &useMatrix); 1506 if (usePaint) { 1507 fuzz_paint(fuzz, &paint, depth - 1); 1508 } 1509 if (useMatrix) { 1510 FuzzNiceMatrix(fuzz, &matrix); 1511 } 1512 auto pic = make_fuzz_picture(fuzz, depth - 1); 1513 canvas->drawPicture(pic, useMatrix ? &matrix : nullptr, 1514 usePaint ? &paint : nullptr); 1515 break; 1516 } 1517 case 53: { 1518 fuzz_paint(fuzz, &paint, depth - 1); 1519 SkVertices::VertexMode vertexMode; 1520 SkBlendMode blendMode; 1521 fuzz->nextRange(&vertexMode, 0, SkVertices::kTriangleFan_VertexMode); 1522 fuzz->nextRange(&blendMode, 0, SkBlendMode::kLastMode); 1523 constexpr int kMaxCount = 100; 1524 int vertexCount; 1525 SkPoint vertices[kMaxCount]; 1526 SkPoint texs[kMaxCount]; 1527 SkColor colors[kMaxCount]; 1528 fuzz->nextRange(&vertexCount, 3, kMaxCount); 1529 fuzz->nextN(vertices, vertexCount); 1530 bool useTexs, useColors; 1531 fuzz->next(&useTexs, &useColors); 1532 if (useTexs) { 1533 fuzz->nextN(texs, vertexCount); 1534 } 1535 if (useColors) { 1536 fuzz->nextN(colors, vertexCount); 1537 } 1538 int indexCount = 0; 1539 uint16_t indices[kMaxCount * 2]; 1540 if (make_fuzz_t<bool>(fuzz)) { 1541 fuzz->nextRange(&indexCount, vertexCount, vertexCount + kMaxCount); 1542 for (int i = 0; i < indexCount; ++i) { 1543 fuzz->nextRange(&indices[i], 0, vertexCount - 1); 1544 } 1545 } 1546 canvas->drawVertices(SkVertices::MakeCopy(vertexMode, vertexCount, vertices, 1547 useTexs ? texs : nullptr, 1548 useColors ? colors : nullptr, 1549 indexCount, indices), 1550 blendMode, paint); 1551 break; 1552 } 1553 default: 1554 SkASSERT(false); 1555 break; 1556 } 1557 } 1558 } 1559 1560 static sk_sp<SkPicture> make_fuzz_picture(Fuzz* fuzz, int depth) { 1561 SkScalar w, h; 1562 fuzz->next(&w, &h); 1563 SkPictureRecorder pictureRecorder; 1564 fuzz_canvas(fuzz, pictureRecorder.beginRecording(w, h), depth - 1); 1565 return pictureRecorder.finishRecordingAsPicture(); 1566 } 1567 1568 DEF_FUZZ(NullCanvas, fuzz) { 1569 fuzz_canvas(fuzz, SkMakeNullCanvas().get()); 1570 } 1571 1572 constexpr SkISize kCanvasSize = {128, 160}; 1573 1574 DEF_FUZZ(RasterN32Canvas, fuzz) { 1575 auto surface = SkSurface::MakeRasterN32Premul(kCanvasSize.width(), kCanvasSize.height()); 1576 if (!surface || !surface->getCanvas()) { fuzz->signalBug(); } 1577 fuzz_canvas(fuzz, surface->getCanvas()); 1578 } 1579 1580 DEF_FUZZ(RasterN32CanvasViaSerialization, fuzz) { 1581 SkPictureRecorder recorder; 1582 fuzz_canvas(fuzz, recorder.beginRecording(SkIntToScalar(kCanvasSize.width()), 1583 SkIntToScalar(kCanvasSize.height()))); 1584 sk_sp<SkPicture> pic(recorder.finishRecordingAsPicture()); 1585 if (!pic) { fuzz->signalBug(); } 1586 sk_sp<SkData> data = pic->serialize(); 1587 if (!data) { fuzz->signalBug(); } 1588 SkReadBuffer rb(data->data(), data->size()); 1589 auto deserialized = SkPicturePriv::MakeFromBuffer(rb); 1590 if (!deserialized) { fuzz->signalBug(); } 1591 auto surface = SkSurface::MakeRasterN32Premul(kCanvasSize.width(), kCanvasSize.height()); 1592 SkASSERT(surface && surface->getCanvas()); 1593 surface->getCanvas()->drawPicture(deserialized); 1594 } 1595 1596 DEF_FUZZ(ImageFilter, fuzz) { 1597 auto fil = make_fuzz_imageFilter(fuzz, 20); 1598 1599 SkPaint paint; 1600 paint.setImageFilter(fil); 1601 SkBitmap bitmap; 1602 SkCanvas canvas(bitmap); 1603 canvas.saveLayer(SkRect::MakeWH(500, 500), &paint); 1604 } 1605 1606 1607 //SkRandom _rand; 1608 #define SK_ADD_RANDOM_BIT_FLIPS 1609 1610 DEF_FUZZ(SerializedImageFilter, fuzz) { 1611 auto filter = make_fuzz_imageFilter(fuzz, 20); 1612 if (!filter) { 1613 return; 1614 } 1615 auto data = filter->serialize(); 1616 const unsigned char* ptr = static_cast<const unsigned char*>(data->data()); 1617 size_t len = data->size(); 1618 #ifdef SK_ADD_RANDOM_BIT_FLIPS 1619 unsigned char* p = const_cast<unsigned char*>(ptr); 1620 for (size_t i = 0; i < len; ++i, ++p) { 1621 uint8_t j; 1622 fuzz->nextRange(&j, 1, 250); 1623 if (j == 1) { // 0.4% of the time, flip a bit or byte 1624 uint8_t k; 1625 fuzz->nextRange(&k, 1, 10); 1626 if (k == 1) { // Then 10% of the time, change a whole byte 1627 uint8_t s; 1628 fuzz->nextRange(&s, 0, 2); 1629 switch(s) { 1630 case 0: 1631 *p ^= 0xFF; // Flip entire byte 1632 break; 1633 case 1: 1634 *p = 0xFF; // Set all bits to 1 1635 break; 1636 case 2: 1637 *p = 0x00; // Set all bits to 0 1638 break; 1639 } 1640 } else { 1641 uint8_t s; 1642 fuzz->nextRange(&s, 0, 7); 1643 *p ^= (1 << 7); 1644 } 1645 } 1646 } 1647 #endif // SK_ADD_RANDOM_BIT_FLIPS 1648 auto deserializedFil = SkImageFilter::Deserialize(ptr, len); 1649 1650 // uncomment below to write out a serialized image filter (to make corpus 1651 // for -t filter_fuzz) 1652 // SkString s("./serialized_filters/sf"); 1653 // s.appendU32(_rand.nextU()); 1654 // auto file = sk_fopen(s.c_str(), SkFILE_Flags::kWrite_SkFILE_Flag); 1655 // sk_fwrite(data->bytes(), data->size(), file); 1656 // sk_fclose(file); 1657 1658 SkPaint paint; 1659 paint.setImageFilter(deserializedFil); 1660 SkBitmap bitmap; 1661 SkCanvas canvas(bitmap); 1662 canvas.saveLayer(SkRect::MakeWH(500, 500), &paint); 1663 } 1664 1665 #if SK_SUPPORT_GPU 1666 1667 static void dump_GPU_info(GrContext* context) { 1668 const GrGLInterface* gl = static_cast<GrGLGpu*>(context->priv().getGpu()) 1669 ->glInterface(); 1670 const GrGLubyte* output; 1671 GR_GL_CALL_RET(gl, output, GetString(GR_GL_RENDERER)); 1672 SkDebugf("GL_RENDERER %s\n", (const char*) output); 1673 1674 GR_GL_CALL_RET(gl, output, GetString(GR_GL_VENDOR)); 1675 SkDebugf("GL_VENDOR %s\n", (const char*) output); 1676 1677 GR_GL_CALL_RET(gl, output, GetString(GR_GL_VERSION)); 1678 SkDebugf("GL_VERSION %s\n", (const char*) output); 1679 } 1680 1681 static void fuzz_ganesh(Fuzz* fuzz, GrContext* context) { 1682 SkASSERT(context); 1683 auto surface = SkSurface::MakeRenderTarget( 1684 context, 1685 SkBudgeted::kNo, 1686 SkImageInfo::Make(kCanvasSize.width(), kCanvasSize.height(), kRGBA_8888_SkColorType, kPremul_SkAlphaType)); 1687 SkASSERT(surface && surface->getCanvas()); 1688 fuzz_canvas(fuzz, surface->getCanvas()); 1689 } 1690 1691 DEF_FUZZ(NativeGLCanvas, fuzz) { 1692 sk_gpu_test::GrContextFactory f; 1693 GrContext* context = f.get(sk_gpu_test::GrContextFactory::kGL_ContextType); 1694 if (!context) { 1695 context = f.get(sk_gpu_test::GrContextFactory::kGLES_ContextType); 1696 } 1697 if (FLAGS_gpuInfo) { 1698 dump_GPU_info(context); 1699 } 1700 fuzz_ganesh(fuzz, context); 1701 } 1702 1703 // This target is deprecated, NullGLContext is not well maintained. 1704 // Please use MockGPUCanvas instead. 1705 DEF_FUZZ(NullGLCanvas, fuzz) { 1706 sk_gpu_test::GrContextFactory f; 1707 fuzz_ganesh(fuzz, f.get(sk_gpu_test::GrContextFactory::kNullGL_ContextType)); 1708 } 1709 1710 DEF_FUZZ(MockGPUCanvas, fuzz) { 1711 sk_gpu_test::GrContextFactory f; 1712 fuzz_ganesh(fuzz, f.get(sk_gpu_test::GrContextFactory::kMock_ContextType)); 1713 } 1714 #endif 1715 1716 DEF_FUZZ(PDFCanvas, fuzz) { 1717 SkNullWStream stream; 1718 auto doc = SkPDF::MakeDocument(&stream); 1719 fuzz_canvas(fuzz, doc->beginPage(SkIntToScalar(kCanvasSize.width()), 1720 SkIntToScalar(kCanvasSize.height()))); 1721 } 1722 1723 // not a "real" thing to fuzz, used to debug errors found while fuzzing. 1724 DEF_FUZZ(_DumpCanvas, fuzz) { 1725 SkDebugCanvas debugCanvas(kCanvasSize.width(), kCanvasSize.height()); 1726 fuzz_canvas(fuzz, &debugCanvas); 1727 std::unique_ptr<SkCanvas> nullCanvas = SkMakeNullCanvas(); 1728 UrlDataManager dataManager(SkString("data")); 1729 SkDynamicMemoryWStream stream; 1730 SkJSONWriter writer(&stream, SkJSONWriter::Mode::kPretty); 1731 writer.beginObject(); // root 1732 debugCanvas.toJSON(writer, dataManager, debugCanvas.getSize(), nullCanvas.get()); 1733 writer.endObject(); // root 1734 writer.flush(); 1735 sk_sp<SkData> json = stream.detachAsData(); 1736 fwrite(json->data(), json->size(), 1, stdout); 1737 } 1738