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