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