FuzzCanvas: ImageFilter
authorHal Canary <halcanary@google.com>
Thu, 9 Mar 2017 16:33:35 +0000 (11:33 -0500)
committerSkia Commit-Bot <skia-commit-bot@chromium.org>
Thu, 9 Mar 2017 22:42:18 +0000 (22:42 +0000)
Change-Id: I9446bd81fda82e398f08ed162dcd55253b597096
Reviewed-on: https://skia-review.googlesource.com/9491
Reviewed-by: Kevin Lubick <kjlubick@google.com>
Commit-Queue: Hal Canary <halcanary@google.com>

fuzz/FuzzCanvas.cpp

index 0f74e3d..e406154 100644 (file)
 // EFFECTS
 #include "Sk1DPathEffect.h"
 #include "Sk2DPathEffect.h"
+#include "SkAlphaThresholdFilter.h"
 #include "SkArcToPathEffect.h"
+#include "SkArithmeticImageFilter.h"
 #include "SkBlurMaskFilter.h"
+#include "SkColorFilterImageFilter.h"
 #include "SkColorMatrixFilter.h"
+#include "SkComposeImageFilter.h"
 #include "SkCornerPathEffect.h"
 #include "SkDashPathEffect.h"
 #include "SkDiscretePathEffect.h"
+#include "SkDisplacementMapEffect.h"
+#include "SkDropShadowImageFilter.h"
 #include "SkGaussianEdgeShader.h"
 #include "SkGradientShader.h"
 #include "SkHighContrastFilter.h"
+#include "SkImageSource.h"
+#include "SkLightingImageFilter.h"
 #include "SkLumaColorFilter.h"
+#include "SkMagnifierImageFilter.h"
+#include "SkMatrixConvolutionImageFilter.h"
+#include "SkMergeImageFilter.h"
+#include "SkMorphologyImageFilter.h"
+#include "SkOffsetImageFilter.h"
+#include "SkPaintImageFilter.h"
 #include "SkPerlinNoiseShader.h"
+#include "SkPictureImageFilter.h"
 #include "SkRRectsGaussianEdgeMaskFilter.h"
 #include "SkTableColorFilter.h"
+#include "SkTileImageFilter.h"
+#include "SkXfermodeImageFilter.h"
 
 // SRC
 #include "SkUtils.h"
@@ -49,7 +66,8 @@
 
 // TODO:
 //   SkTextBlob with Unicode
-//   SkImageFilter
+//   Cleanup function names
+//   Fuzz::nextRangeEnum()
 
 template <typename T, void (SkPaint::*S)(T)>
 inline void fuzz_input(Fuzz* fuzz, SkPaint* paint) {
@@ -134,15 +152,16 @@ static void fuzz_path(Fuzz* fuzz, SkPath* path, int maxOps) {
     }
 }
 
-static void fuzz_region(Fuzz* fuzz, SkRegion* region) {
+template <>
+inline void Fuzz::next(SkRegion* region) {
     uint8_t N;
-    fuzz->nextRange(&N, 0, 10);
+    this->nextRange(&N, 0, 10);
     for (uint8_t i = 0; i < N; ++i) {
         SkIRect r;
         uint8_t op;
-        fuzz->next(&r);
+        this->next(&r);
         r.sort();
-        fuzz->nextRange(&op, 0, (uint8_t)SkRegion::kLastOp);
+        this->nextRange(&op, 0, (uint8_t)SkRegion::kLastOp);
         if (!region->op(r, (SkRegion::Op)op)) {
             return;
         }
@@ -156,6 +175,14 @@ inline void Fuzz::next(SkShader::TileMode* m) {
 }
 
 template <>
+inline void Fuzz::next(SkFilterQuality* q) {
+    using U = skstd::underlying_type_t<SkFilterQuality>;
+    this->nextRange((U*)q,
+                    (U)SkFilterQuality::kNone_SkFilterQuality,
+                    (U)SkFilterQuality::kLast_SkFilterQuality);
+}
+
+template <>
 inline void Fuzz::next(SkMatrix* m) {
     constexpr int kArrayLength = 9;
     SkScalar buffer[kArrayLength];
@@ -218,7 +245,7 @@ SkBitmap MakeFuzzBitmap(Fuzz*);
 
 static sk_sp<SkPicture> make_picture(Fuzz*, int depth);
 
-sk_sp<SkColorFilter> MakeColorFilter(Fuzz* fuzz, int depth = 3) {
+sk_sp<SkColorFilter> MakeColorFilter(Fuzz* fuzz, int depth) {
     if (depth <= 0) {
         return nullptr;
     }
@@ -337,7 +364,7 @@ sk_sp<SkShader> MakeFuzzShader(Fuzz* fuzz, int depth) {
             return shader1 ? shader1->makeWithLocalMatrix(matrix) : nullptr;
         case 6:
             shader1 = MakeFuzzShader(fuzz, depth - 1);  // limit recursion.
-            colorFilter = MakeColorFilter(fuzz);
+            colorFilter = MakeColorFilter(fuzz, depth - 1);
             return shader1 ? shader1->makeWithColorFilter(std::move(colorFilter)) : nullptr;
         case 7:
             shader1 = MakeFuzzShader(fuzz, depth - 1);  // limit recursion.
@@ -345,7 +372,7 @@ sk_sp<SkShader> MakeFuzzShader(Fuzz* fuzz, int depth) {
             fuzz->next(&blendMode);
             return SkShader::MakeComposeShader(std::move(shader1), std::move(shader2), blendMode);
         case 8: {
-            auto pic = make_picture(fuzz, depth);
+            auto pic = make_picture(fuzz, depth - 1);
             bool useTile;
             SkRect tile;
             fuzz->next(&tmX, &tmY, &useMatrix, &useTile);
@@ -468,7 +495,7 @@ sk_sp<SkShader> MakeFuzzShader(Fuzz* fuzz, int depth) {
     return nullptr;
 }
 
-sk_sp<SkPathEffect> MakeFuzzPathEffect(Fuzz* fuzz, int depth = 3) {
+sk_sp<SkPathEffect> MakeFuzzPathEffect(Fuzz* fuzz, int depth) {
     if (depth <= 0) {
         return nullptr;
     }
@@ -589,7 +616,360 @@ sk_sp<SkTypeface> MakeFuzzTypeface(Fuzz* fuzz) {
     return sk_sp<SkTypeface>(family->createTypeface(j));
 }
 
-sk_sp<SkImageFilter> MakeFuzzImageFilter(Fuzz* fuzz) { return nullptr; /*TODO*/ }
+template <>
+inline void Fuzz::next(SkImageFilter::CropRect* cropRect) {
+    SkRect rect;
+    uint8_t flags;
+    this->next(&rect);
+    this->nextRange(&flags, 0, 0xF);
+    *cropRect = SkImageFilter::CropRect(rect, flags);
+}
+
+static sk_sp<SkImageFilter> MakeFuzzImageFilter(Fuzz* fuzz, int depth);
+
+static sk_sp<SkImageFilter> make_fuzz_lighting_imagefilter(Fuzz* fuzz, int depth) {
+    if (depth <= 0) {
+        return nullptr;
+    }
+    uint8_t imageFilterType;
+    fuzz->nextRange(&imageFilterType, 1, 6);
+    SkPoint3 p, q;
+    SkColor lightColor;
+    SkScalar surfaceScale, k, specularExponent, cutoffAngle, shininess;
+    sk_sp<SkImageFilter> input;
+    SkImageFilter::CropRect cropRect;
+    bool useCropRect;
+    fuzz->next(&useCropRect);
+    if (useCropRect) {
+        fuzz->next(&cropRect);
+    }
+    switch (imageFilterType) {
+        case 1:
+            fuzz->next(&p, &lightColor, &surfaceScale, &k);
+            input = MakeFuzzImageFilter(fuzz, depth - 1);
+            return SkLightingImageFilter::MakeDistantLitDiffuse(p, lightColor, surfaceScale, k,
+                                                                std::move(input),
+                                                                useCropRect ? &cropRect : nullptr);
+        case 2:
+            fuzz->next(&p, &lightColor, &surfaceScale, &k);
+            input = MakeFuzzImageFilter(fuzz, depth - 1);
+            return SkLightingImageFilter::MakePointLitDiffuse(p, lightColor, surfaceScale, k,
+                                                              std::move(input),
+                                                              useCropRect ? &cropRect : nullptr);
+        case 3:
+            fuzz->next(&p, &q, &specularExponent, &cutoffAngle, &lightColor, &surfaceScale, &k);
+            input = MakeFuzzImageFilter(fuzz, depth - 1);
+            return SkLightingImageFilter::MakeSpotLitDiffuse(
+                    p, q, specularExponent, cutoffAngle, lightColor, surfaceScale, k,
+                    std::move(input), useCropRect ? &cropRect : nullptr);
+        case 4:
+            fuzz->next(&p, &lightColor, &surfaceScale, &k, &shininess);
+            input = MakeFuzzImageFilter(fuzz, depth - 1);
+            return SkLightingImageFilter::MakeDistantLitSpecular(p, lightColor, surfaceScale, k,
+                                                                 shininess, std::move(input),
+                                                                 useCropRect ? &cropRect : nullptr);
+        case 5:
+            fuzz->next(&p, &lightColor, &surfaceScale, &k, &shininess);
+            input = MakeFuzzImageFilter(fuzz, depth - 1);
+            return SkLightingImageFilter::MakePointLitSpecular(p, lightColor, surfaceScale, k,
+                                                               shininess, std::move(input),
+                                                               useCropRect ? &cropRect : nullptr);
+        case 6:
+            fuzz->next(&p, &q, &specularExponent, &cutoffAngle, &lightColor, &surfaceScale, &k,
+                       &shininess);
+            input = MakeFuzzImageFilter(fuzz, depth - 1);
+            return SkLightingImageFilter::MakeSpotLitSpecular(
+                    p, q, specularExponent, cutoffAngle, lightColor, surfaceScale, k, shininess,
+                    std::move(input), useCropRect ? &cropRect : nullptr);
+        default:
+            SkASSERT(false);
+            return nullptr;
+    }
+}
+
+static void FuzzPaint(Fuzz* fuzz, SkPaint* paint, int depth);
+
+static sk_sp<SkImageFilter> MakeFuzzImageFilter(Fuzz* fuzz, int depth) {
+    if (depth <= 0) {
+        return nullptr;
+    }
+    uint8_t imageFilterType;
+    fuzz->nextRange(&imageFilterType, 0, 24);
+    switch (imageFilterType) {
+        case 0:
+            return nullptr;
+        case 1: {
+            SkScalar sigmaX, sigmaY;
+            sk_sp<SkImageFilter> input = MakeFuzzImageFilter(fuzz, depth - 1);
+            SkImageFilter::CropRect cropRect;
+            bool useCropRect;
+            fuzz->next(&sigmaX, &sigmaY, &useCropRect);
+            if (useCropRect) {
+                fuzz->next(&useCropRect);
+            }
+            return SkImageFilter::MakeBlur(sigmaX, sigmaY, std::move(input),
+                                           useCropRect ? &cropRect : nullptr);
+        }
+        case 2: {
+            SkMatrix matrix;
+            SkFilterQuality quality;
+            fuzz->next(&matrix, &quality);
+            sk_sp<SkImageFilter> input = MakeFuzzImageFilter(fuzz, depth - 1);
+            return SkImageFilter::MakeMatrixFilter(matrix, quality, std::move(input));
+        }
+        case 3: {
+            SkRegion region;
+            SkScalar innerMin, outerMax;
+            sk_sp<SkImageFilter> input = MakeFuzzImageFilter(fuzz, depth - 1);
+            SkImageFilter::CropRect cropRect;
+            bool useCropRect;
+            fuzz->next(&region, &innerMin, &outerMax, &useCropRect);
+            if (useCropRect) {
+                fuzz->next(&useCropRect);
+            }
+            return SkAlphaThresholdFilter::Make(region, innerMin, outerMax, std::move(input),
+                                                useCropRect ? &cropRect : nullptr);
+        }
+        case 4: {
+            float k1, k2, k3, k4;
+            bool enforcePMColor;
+            bool useCropRect;
+            fuzz->next(&k1, &k2, &k3, &k4, &enforcePMColor, &useCropRect);
+            sk_sp<SkImageFilter> background = MakeFuzzImageFilter(fuzz, depth - 1);
+            sk_sp<SkImageFilter> foreground = MakeFuzzImageFilter(fuzz, depth - 1);
+            SkImageFilter::CropRect cropRect;
+            if (useCropRect) {
+                fuzz->next(&useCropRect);
+            }
+            return SkArithmeticImageFilter::Make(k1, k2, k3, k4, enforcePMColor,
+                                                 std::move(background), std::move(foreground),
+                                                 useCropRect ? &cropRect : nullptr);
+        }
+        case 5: {
+            sk_sp<SkColorFilter> cf = MakeColorFilter(fuzz, depth - 1);
+            sk_sp<SkImageFilter> input = MakeFuzzImageFilter(fuzz, depth - 1);
+            bool useCropRect;
+            SkImageFilter::CropRect cropRect;
+            fuzz->next(&useCropRect);
+            if (useCropRect) {
+                fuzz->next(&useCropRect);
+            }
+            return SkColorFilterImageFilter::Make(std::move(cf), std::move(input),
+                                                  useCropRect ? &cropRect : nullptr);
+        }
+        case 6: {
+            sk_sp<SkImageFilter> ifo = MakeFuzzImageFilter(fuzz, depth - 1);
+            sk_sp<SkImageFilter> ifi = MakeFuzzImageFilter(fuzz, depth - 1);
+            return SkComposeImageFilter::Make(std::move(ifo), std::move(ifi));
+        }
+        case 7: {
+            SkDisplacementMapEffect::ChannelSelectorType xChannelSelector, yChannelSelector;
+            using U = skstd::underlying_type_t<SkDisplacementMapEffect::ChannelSelectorType>;
+            fuzz->nextRange((U*)(&xChannelSelector), 0, 4);
+            fuzz->nextRange((U*)(&yChannelSelector), 0, 4);
+            SkScalar scale;
+            bool useCropRect;
+            fuzz->next(&scale, &useCropRect);
+            SkImageFilter::CropRect cropRect;
+            if (useCropRect) {
+                fuzz->next(&useCropRect);
+            }
+            sk_sp<SkImageFilter> displacement = MakeFuzzImageFilter(fuzz, depth - 1);
+            sk_sp<SkImageFilter> color = MakeFuzzImageFilter(fuzz, depth - 1);
+            return SkDisplacementMapEffect::Make(xChannelSelector, yChannelSelector, scale,
+                                                 std::move(displacement), std::move(color),
+                                                 useCropRect ? &cropRect : nullptr);
+        }
+        case 8: {
+            SkScalar dx, dy, sigmaX, sigmaY;
+            SkColor color;
+            SkDropShadowImageFilter::ShadowMode shadowMode;
+            using U = skstd::underlying_type_t<SkDropShadowImageFilter::ShadowMode>;
+            fuzz->nextRange((U*)(&shadowMode), (U)0, (U)1);
+            bool useCropRect;
+            fuzz->next(&dx, &dy, &sigmaX, &sigmaY, &color, &useCropRect);
+            SkImageFilter::CropRect cropRect;
+            if (useCropRect) {
+                fuzz->next(&useCropRect);
+            }
+            sk_sp<SkImageFilter> input = MakeFuzzImageFilter(fuzz, depth - 1);
+            return SkDropShadowImageFilter::Make(dx, dy, sigmaX, sigmaY, color, shadowMode,
+                                                 std::move(input),
+                                                 useCropRect ? &cropRect : nullptr);
+        }
+        case 9:
+            return SkImageSource::Make(MakeFuzzImage(fuzz));
+        case 10: {
+            sk_sp<SkImage> image = MakeFuzzImage(fuzz);
+            SkRect srcRect, dstRect;
+            SkFilterQuality filterQuality;
+            fuzz->next(&srcRect, &dstRect, &filterQuality);
+            return SkImageSource::Make(std::move(image), srcRect, dstRect, filterQuality);
+        }
+        case 11:
+            return make_fuzz_lighting_imagefilter(fuzz, depth - 1);
+        case 12: {
+            SkRect srcRect;
+            SkScalar inset;
+            bool useCropRect;
+            SkImageFilter::CropRect cropRect;
+            fuzz->next(&srcRect, &inset, &useCropRect);
+            if (useCropRect) {
+                fuzz->next(&useCropRect);
+            }
+            sk_sp<SkImageFilter> input = MakeFuzzImageFilter(fuzz, depth - 1);
+            return SkMagnifierImageFilter::Make(srcRect, inset, std::move(input),
+                                                useCropRect ? &cropRect : nullptr);
+        }
+        case 13: {
+            constexpr int kMaxKernelSize = 5;
+            int32_t n, m;
+            fuzz->nextRange(&n, 1, kMaxKernelSize);
+            fuzz->nextRange(&m, 1, kMaxKernelSize);
+            SkScalar kernel[kMaxKernelSize * kMaxKernelSize];
+            fuzz->nextN(kernel, n * m);
+            int32_t offsetX, offsetY;
+            fuzz->nextRange(&offsetX, 0, n - 1);
+            fuzz->nextRange(&offsetY, 0, m - 1);
+            SkScalar gain, bias;
+            bool convolveAlpha, useCropRect;
+            fuzz->next(&gain, &bias, &convolveAlpha, &useCropRect);
+            SkMatrixConvolutionImageFilter::TileMode tileMode;
+            using U = skstd::underlying_type_t<SkMatrixConvolutionImageFilter::TileMode>;
+            fuzz->nextRange((U*)(&tileMode), (U)0, (U)2);
+            SkImageFilter::CropRect cropRect;
+            if (useCropRect) {
+                fuzz->next(&useCropRect);
+            }
+            sk_sp<SkImageFilter> input = MakeFuzzImageFilter(fuzz, depth - 1);
+            return SkMatrixConvolutionImageFilter::Make(
+                    SkISize{n, m}, kernel, gain, bias, SkIPoint{offsetX, offsetY}, tileMode,
+                    convolveAlpha, std::move(input), useCropRect ? &cropRect : nullptr);
+        }
+        case 14: {
+            sk_sp<SkImageFilter> first = MakeFuzzImageFilter(fuzz, depth - 1);
+            sk_sp<SkImageFilter> second = MakeFuzzImageFilter(fuzz, depth - 1);
+            SkBlendMode blendMode;
+            bool useCropRect;
+            fuzz->next(&useCropRect, &blendMode);
+            SkImageFilter::CropRect cropRect;
+            if (useCropRect) {
+                fuzz->next(&useCropRect);
+            }
+            return SkMergeImageFilter::Make(std::move(first), std::move(second), blendMode,
+                                            useCropRect ? &cropRect : nullptr);
+        }
+        case 15: {
+            constexpr int kMaxCount = 4;
+            sk_sp<SkImageFilter> ifs[kMaxCount];
+            SkBlendMode blendModes[kMaxCount];
+            int count;
+            fuzz->nextRange(&count, 1, kMaxCount);
+            for (int i = 0; i < count; ++i) {
+                ifs[i] = MakeFuzzImageFilter(fuzz, depth - 1);
+            }
+            fuzz->nextN(blendModes, count);
+            bool useCropRect;
+            fuzz->next(&useCropRect);
+            SkImageFilter::CropRect cropRect;
+            if (useCropRect) {
+                fuzz->next(&useCropRect);
+            }
+            return SkMergeImageFilter::MakeN(ifs, count, blendModes,
+                                             useCropRect ? &cropRect : nullptr);
+        }
+        case 16: {
+            int rx, ry;
+            fuzz->next(&rx, &ry);
+            bool useCropRect;
+            fuzz->next(&useCropRect);
+            SkImageFilter::CropRect cropRect;
+            if (useCropRect) {
+                fuzz->next(&useCropRect);
+            }
+            sk_sp<SkImageFilter> input = MakeFuzzImageFilter(fuzz, depth - 1);
+            return SkDilateImageFilter::Make(rx, ry, std::move(input),
+                                             useCropRect ? &cropRect : nullptr);
+        }
+        case 17: {
+            int rx, ry;
+            fuzz->next(&rx, &ry);
+            bool useCropRect;
+            fuzz->next(&useCropRect);
+            SkImageFilter::CropRect cropRect;
+            if (useCropRect) {
+                fuzz->next(&useCropRect);
+            }
+            sk_sp<SkImageFilter> input = MakeFuzzImageFilter(fuzz, depth - 1);
+            return SkErodeImageFilter::Make(rx, ry, std::move(input),
+                                            useCropRect ? &cropRect : nullptr);
+        }
+        case 18: {
+            SkScalar dx, dy;
+            fuzz->next(&dx, &dy);
+            bool useCropRect;
+            fuzz->next(&useCropRect);
+            SkImageFilter::CropRect cropRect;
+            if (useCropRect) {
+                fuzz->next(&useCropRect);
+            }
+            sk_sp<SkImageFilter> input = MakeFuzzImageFilter(fuzz, depth - 1);
+            return SkOffsetImageFilter::Make(dx, dy, std::move(input),
+                                             useCropRect ? &cropRect : nullptr);
+        }
+        case 19: {
+            SkPaint paint;
+            FuzzPaint(fuzz, &paint, depth - 1);
+            bool useCropRect;
+            fuzz->next(&useCropRect);
+            SkImageFilter::CropRect cropRect;
+            if (useCropRect) {
+                fuzz->next(&useCropRect);
+            }
+            return SkPaintImageFilter::Make(paint, useCropRect ? &cropRect : nullptr);
+        }
+        case 20: {
+            sk_sp<SkPicture> picture = make_picture(fuzz, depth - 1);
+            return SkPictureImageFilter::Make(std::move(picture));
+        }
+        case 21: {
+            SkRect cropRect;
+            fuzz->next(&cropRect);
+            sk_sp<SkPicture> picture = make_picture(fuzz, depth - 1);
+            return SkPictureImageFilter::Make(std::move(picture), cropRect);
+        }
+        case 22: {
+            SkRect cropRect;
+            SkFilterQuality filterQuality;
+            fuzz->next(&cropRect, &filterQuality);
+            sk_sp<SkPicture> picture = make_picture(fuzz, depth - 1);
+            return SkPictureImageFilter::MakeForLocalSpace(std::move(picture), cropRect,
+                                                           filterQuality);
+        }
+        case 23: {
+            SkRect src, dst;
+            fuzz->next(&src, &dst);
+            sk_sp<SkImageFilter> input = MakeFuzzImageFilter(fuzz, depth - 1);
+            return SkTileImageFilter::Make(src, dst, std::move(input));
+        }
+        case 24: {
+            SkBlendMode blendMode;
+            bool useCropRect;
+            fuzz->next(&useCropRect, &blendMode);
+            SkImageFilter::CropRect cropRect;
+            if (useCropRect) {
+                fuzz->next(&useCropRect);
+            }
+            sk_sp<SkImageFilter> bg = MakeFuzzImageFilter(fuzz, depth - 1);
+            sk_sp<SkImageFilter> fg = MakeFuzzImageFilter(fuzz, depth - 1);
+            return SkXfermodeImageFilter::Make(blendMode, std::move(bg), std::move(fg),
+                                               useCropRect ? &cropRect : nullptr);
+        }
+        default:
+            SkASSERT(false);
+            return nullptr;
+    }
+}
 
 sk_sp<SkImage> MakeFuzzImage(Fuzz* fuzz) {
     int w, h;
@@ -640,11 +1020,11 @@ void FuzzPaint(Fuzz* fuzz, SkPaint* paint, int depth) {
             SkFilterQuality::kLast_SkFilterQuality);
     fuzz_enum_input<SkPaint::Style, &SkPaint::setStyle>(fuzz, paint, SkPaint::kFill_Style,
                                                         SkPaint::kStrokeAndFill_Style);
-    paint->setShader(MakeFuzzShader(fuzz, depth));
-    paint->setPathEffect(MakeFuzzPathEffect(fuzz));
+    paint->setShader(MakeFuzzShader(fuzz, depth - 1));
+    paint->setPathEffect(MakeFuzzPathEffect(fuzz, depth - 1));
     paint->setMaskFilter(MakeFuzzMaskFilter(fuzz));
-    paint->setImageFilter(MakeFuzzImageFilter(fuzz));
-    paint->setColorFilter(MakeColorFilter(fuzz));
+    paint->setImageFilter(MakeFuzzImageFilter(fuzz, depth - 1));
+    paint->setColorFilter(MakeColorFilter(fuzz, depth - 1));
 
     if (paint->getStyle() != SkPaint::kFill_Style) {
         fuzz_input<SkScalar, &SkPaint::setStrokeWidth>(fuzz, paint);
@@ -793,7 +1173,7 @@ static sk_sp<SkTextBlob> make_fuzz_textblob(Fuzz* fuzz) {
     return textBlobBuilder.make();
 }
 
-void fuzz_canvas(Fuzz* fuzz, SkCanvas* canvas, int depth = 4) {
+void fuzz_canvas(Fuzz* fuzz, SkCanvas* canvas, int depth = 9) {
     if (!fuzz || !canvas || depth <= 0) {
         return;
     }
@@ -818,7 +1198,7 @@ void fuzz_canvas(Fuzz* fuzz, SkCanvas* canvas, int depth = 4) {
             case 2: {
                 SkRect bounds;
                 fuzz->next(&bounds);
-                FuzzPaint(fuzz, &paint, depth);
+                FuzzPaint(fuzz, &paint, depth - 1);
                 canvas->saveLayer(&bounds, &paint);
                 break;
             }
@@ -829,7 +1209,7 @@ void fuzz_canvas(Fuzz* fuzz, SkCanvas* canvas, int depth = 4) {
                 break;
             }
             case 4:
-                FuzzPaint(fuzz, &paint, depth);
+                FuzzPaint(fuzz, &paint, depth - 1);
                 canvas->saveLayer(nullptr, &paint);
                 break;
             case 5:
@@ -856,12 +1236,12 @@ void fuzz_canvas(Fuzz* fuzz, SkCanvas* canvas, int depth = 4) {
                     saveLayerRec.fBounds = &bounds;
                 }
                 if (make_bool(fuzz)) {
-                    FuzzPaint(fuzz, &paint, depth);
+                    FuzzPaint(fuzz, &paint, depth - 1);
                     saveLayerRec.fPaint = &paint;
                 }
                 sk_sp<SkImageFilter> imageFilter;
                 if (make_bool(fuzz)) {
-                    imageFilter = MakeFuzzImageFilter(fuzz);
+                    imageFilter = MakeFuzzImageFilter(fuzz, depth - 1);
                     saveLayerRec.fBackdrop = imageFilter.get();
                 }
                 // _DumpCanvas can't handle this.
@@ -961,18 +1341,18 @@ void fuzz_canvas(Fuzz* fuzz, SkCanvas* canvas, int depth = 4) {
             }
             case 22: {
                 SkRegion region;
-                fuzz_region(fuzz, &region);
                 int op;
+                fuzz->next(&region);
                 fuzz->nextRange(&op, 0, 1);
                 canvas->clipRegion(region, (SkClipOp)op);
                 break;
             }
             case 23:
-                FuzzPaint(fuzz, &paint, depth);
+                FuzzPaint(fuzz, &paint, depth - 1);
                 canvas->drawPaint(paint);
                 break;
             case 24: {
-                FuzzPaint(fuzz, &paint, depth);
+                FuzzPaint(fuzz, &paint, depth - 1);
                 uint8_t pointMode;
                 fuzz->nextRange(&pointMode, 0, 3);
                 size_t count;
@@ -984,35 +1364,35 @@ void fuzz_canvas(Fuzz* fuzz, SkCanvas* canvas, int depth = 4) {
                 break;
             }
             case 25: {
-                FuzzPaint(fuzz, &paint, depth);
+                FuzzPaint(fuzz, &paint, depth - 1);
                 SkRect r;
                 fuzz->next(&r);
                 canvas->drawRect(r, paint);
                 break;
             }
             case 26: {
-                FuzzPaint(fuzz, &paint, depth);
+                FuzzPaint(fuzz, &paint, depth - 1);
                 SkRegion region;
-                fuzz_region(fuzz, &region);
+                fuzz->next(&region);
                 canvas->drawRegion(region, paint);
                 break;
             }
             case 27: {
-                FuzzPaint(fuzz, &paint, depth);
+                FuzzPaint(fuzz, &paint, depth - 1);
                 SkRect r;
                 fuzz->next(&r);
                 canvas->drawOval(r, paint);
                 break;
             }
             case 29: {
-                FuzzPaint(fuzz, &paint, depth);
+                FuzzPaint(fuzz, &paint, depth - 1);
                 SkRRect rr;
                 fuzz->next(&rr);
                 canvas->drawRRect(rr, paint);
                 break;
             }
             case 30: {
-                FuzzPaint(fuzz, &paint, depth);
+                FuzzPaint(fuzz, &paint, depth - 1);
                 SkRRect orr, irr;
                 fuzz->next(&orr);
                 fuzz->next(&irr);
@@ -1022,7 +1402,7 @@ void fuzz_canvas(Fuzz* fuzz, SkCanvas* canvas, int depth = 4) {
                 break;
             }
             case 31: {
-                FuzzPaint(fuzz, &paint, depth);
+                FuzzPaint(fuzz, &paint, depth - 1);
                 SkRect r;
                 SkScalar start, sweep;
                 bool useCenter;
@@ -1042,7 +1422,7 @@ void fuzz_canvas(Fuzz* fuzz, SkCanvas* canvas, int depth = 4) {
                 bool usePaint;
                 fuzz->next(&left, &top, &usePaint);
                 if (usePaint) {
-                    FuzzPaint(fuzz, &paint, depth);
+                    FuzzPaint(fuzz, &paint, depth - 1);
                 }
                 canvas->drawImage(img.get(), left, top, usePaint ? &paint : nullptr);
                 break;
@@ -1053,7 +1433,7 @@ void fuzz_canvas(Fuzz* fuzz, SkCanvas* canvas, int depth = 4) {
                 bool usePaint;
                 fuzz->next(&src, &dst, &usePaint);
                 if (usePaint) {
-                    FuzzPaint(fuzz, &paint, depth);
+                    FuzzPaint(fuzz, &paint, depth - 1);
                 }
                 SkCanvas::SrcRectConstraint constraint =
                         make_bool(fuzz) ? SkCanvas::kStrict_SrcRectConstraint
@@ -1068,7 +1448,7 @@ void fuzz_canvas(Fuzz* fuzz, SkCanvas* canvas, int depth = 4) {
                 bool usePaint;
                 fuzz->next(&src, &dst, &usePaint);
                 if (usePaint) {
-                    FuzzPaint(fuzz, &paint, depth);
+                    FuzzPaint(fuzz, &paint, depth - 1);
                 }
                 SkCanvas::SrcRectConstraint constraint =
                         make_bool(fuzz) ? SkCanvas::kStrict_SrcRectConstraint
@@ -1082,7 +1462,7 @@ void fuzz_canvas(Fuzz* fuzz, SkCanvas* canvas, int depth = 4) {
                 SkRect dst;
                 fuzz->next(&dst, &usePaint);
                 if (usePaint) {
-                    FuzzPaint(fuzz, &paint, depth);
+                    FuzzPaint(fuzz, &paint, depth - 1);
                 }
                 SkCanvas::SrcRectConstraint constraint =
                         make_bool(fuzz) ? SkCanvas::kStrict_SrcRectConstraint
@@ -1097,7 +1477,7 @@ void fuzz_canvas(Fuzz* fuzz, SkCanvas* canvas, int depth = 4) {
                 bool usePaint;
                 fuzz->next(&center, &dst, &usePaint);
                 if (usePaint) {
-                    FuzzPaint(fuzz, &paint, depth);
+                    FuzzPaint(fuzz, &paint, depth - 1);
                 }
                 canvas->drawImageNine(img, center, dst, usePaint ? &paint : nullptr);
                 break;
@@ -1108,7 +1488,7 @@ void fuzz_canvas(Fuzz* fuzz, SkCanvas* canvas, int depth = 4) {
                 bool usePaint;
                 fuzz->next(&left, &top, &usePaint);
                 if (usePaint) {
-                    FuzzPaint(fuzz, &paint, depth);
+                    FuzzPaint(fuzz, &paint, depth - 1);
                 }
                 canvas->drawBitmap(bitmap, left, top, usePaint ? &paint : nullptr);
                 break;
@@ -1119,7 +1499,7 @@ void fuzz_canvas(Fuzz* fuzz, SkCanvas* canvas, int depth = 4) {
                 bool usePaint;
                 fuzz->next(&src, &dst, &usePaint);
                 if (usePaint) {
-                    FuzzPaint(fuzz, &paint, depth);
+                    FuzzPaint(fuzz, &paint, depth - 1);
                 }
                 SkCanvas::SrcRectConstraint constraint =
                         make_bool(fuzz) ? SkCanvas::kStrict_SrcRectConstraint
@@ -1134,7 +1514,7 @@ void fuzz_canvas(Fuzz* fuzz, SkCanvas* canvas, int depth = 4) {
                 bool usePaint;
                 fuzz->next(&src, &dst, &usePaint);
                 if (usePaint) {
-                    FuzzPaint(fuzz, &paint, depth);
+                    FuzzPaint(fuzz, &paint, depth - 1);
                 }
                 SkCanvas::SrcRectConstraint constraint =
                         make_bool(fuzz) ? SkCanvas::kStrict_SrcRectConstraint
@@ -1148,7 +1528,7 @@ void fuzz_canvas(Fuzz* fuzz, SkCanvas* canvas, int depth = 4) {
                 bool usePaint;
                 fuzz->next(&dst, &usePaint);
                 if (usePaint) {
-                    FuzzPaint(fuzz, &paint, depth);
+                    FuzzPaint(fuzz, &paint, depth - 1);
                 }
                 SkCanvas::SrcRectConstraint constraint =
                         make_bool(fuzz) ? SkCanvas::kStrict_SrcRectConstraint
@@ -1163,7 +1543,7 @@ void fuzz_canvas(Fuzz* fuzz, SkCanvas* canvas, int depth = 4) {
                 bool usePaint;
                 fuzz->next(&center, &dst, &usePaint);
                 if (usePaint) {
-                    FuzzPaint(fuzz, &paint, depth);
+                    FuzzPaint(fuzz, &paint, depth - 1);
                 }
                 canvas->drawBitmapNine(img, center, dst, usePaint ? &paint : nullptr);
                 break;
@@ -1174,7 +1554,7 @@ void fuzz_canvas(Fuzz* fuzz, SkCanvas* canvas, int depth = 4) {
                 SkRect dst;
                 fuzz->next(&usePaint, &dst);
                 if (usePaint) {
-                    FuzzPaint(fuzz, &paint, depth);
+                    FuzzPaint(fuzz, &paint, depth - 1);
                 }
                 constexpr int kMax = 6;
                 int xDivs[kMax], yDivs[kMax];
@@ -1192,7 +1572,7 @@ void fuzz_canvas(Fuzz* fuzz, SkCanvas* canvas, int depth = 4) {
                 SkRect dst;
                 fuzz->next(&usePaint, &dst);
                 if (usePaint) {
-                    FuzzPaint(fuzz, &paint, depth);
+                    FuzzPaint(fuzz, &paint, depth - 1);
                 }
                 constexpr int kMax = 6;
                 int xDivs[kMax], yDivs[kMax];
@@ -1205,7 +1585,7 @@ void fuzz_canvas(Fuzz* fuzz, SkCanvas* canvas, int depth = 4) {
                 break;
             }
             case 45: {
-                FuzzPaint(fuzz, &paint, depth);
+                FuzzPaint(fuzz, &paint, depth - 1);
                 FuzzPaintText(fuzz, &paint);
                 fuzz_paint_text_encoding(fuzz, &paint);
                 SkScalar x, y;
@@ -1215,7 +1595,7 @@ void fuzz_canvas(Fuzz* fuzz, SkCanvas* canvas, int depth = 4) {
                 break;
             }
             case 46: {
-                FuzzPaint(fuzz, &paint, depth);
+                FuzzPaint(fuzz, &paint, depth - 1);
                 FuzzPaintText(fuzz, &paint);
                 fuzz_paint_text_encoding(fuzz, &paint);
                 SkTDArray<uint8_t> text = make_fuzz_text(fuzz, paint);
@@ -1236,7 +1616,7 @@ void fuzz_canvas(Fuzz* fuzz, SkCanvas* canvas, int depth = 4) {
                 break;
             }
             case 47: {
-                FuzzPaint(fuzz, &paint, depth);
+                FuzzPaint(fuzz, &paint, depth - 1);
                 FuzzPaintText(fuzz, &paint);
                 fuzz_paint_text_encoding(fuzz, &paint);
                 SkTDArray<uint8_t> text = make_fuzz_text(fuzz, paint);
@@ -1261,7 +1641,7 @@ void fuzz_canvas(Fuzz* fuzz, SkCanvas* canvas, int depth = 4) {
                 break;
             }
             case 48: {
-                FuzzPaint(fuzz, &paint, depth);
+                FuzzPaint(fuzz, &paint, depth - 1);
                 FuzzPaintText(fuzz, &paint);
                 fuzz_paint_text_encoding(fuzz, &paint);
                 SkTDArray<uint8_t> text = make_fuzz_text(fuzz, paint);
@@ -1279,7 +1659,7 @@ void fuzz_canvas(Fuzz* fuzz, SkCanvas* canvas, int depth = 4) {
                 if (useMatrix) {
                     fuzz->next(&matrix);
                 }
-                FuzzPaint(fuzz, &paint, depth);
+                FuzzPaint(fuzz, &paint, depth - 1);
                 FuzzPaintText(fuzz, &paint);
                 fuzz_paint_text_encoding(fuzz, &paint);
                 SkTDArray<uint8_t> text = make_fuzz_text(fuzz, paint);
@@ -1290,7 +1670,7 @@ void fuzz_canvas(Fuzz* fuzz, SkCanvas* canvas, int depth = 4) {
                 break;
             }
             case 50: {
-                FuzzPaint(fuzz, &paint, depth);
+                FuzzPaint(fuzz, &paint, depth - 1);
                 FuzzPaintText(fuzz, &paint);
                 fuzz_paint_text_encoding(fuzz, &paint);
                 SkTDArray<uint8_t> text = make_fuzz_text(fuzz, paint);
@@ -1310,7 +1690,7 @@ void fuzz_canvas(Fuzz* fuzz, SkCanvas* canvas, int depth = 4) {
             }
             case 51: {
                 sk_sp<SkTextBlob> blob = make_fuzz_textblob(fuzz);
-                FuzzPaint(fuzz, &paint, depth);
+                FuzzPaint(fuzz, &paint, depth - 1);
                 SkScalar x, y;
                 fuzz->next(&x, &y);
                 canvas->drawTextBlob(blob, x, y, paint);
@@ -1320,18 +1700,18 @@ void fuzz_canvas(Fuzz* fuzz, SkCanvas* canvas, int depth = 4) {
                 bool usePaint, useMatrix;
                 fuzz->next(&usePaint, &useMatrix);
                 if (usePaint) {
-                    FuzzPaint(fuzz, &paint, depth);
+                    FuzzPaint(fuzz, &paint, depth - 1);
                 }
                 if (useMatrix) {
                     fuzz->next(&matrix);
                 }
-                auto pic = make_picture(fuzz, depth);
+                auto pic = make_picture(fuzz, depth - 1);
                 canvas->drawPicture(pic, useMatrix ? &matrix : nullptr,
                                     usePaint ? &paint : nullptr);
                 break;
             }
             case 53: {
-                FuzzPaint(fuzz, &paint, depth);
+                FuzzPaint(fuzz, &paint, depth - 1);
                 SkCanvas::VertexMode vertexMode;
                 SkBlendMode mode;
                 uint8_t vm, bm;