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