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