Fix zero-sized blur with crop rect.

[Cherry-pick of 6404981b0c3984ba91b3bda35e60c6c8a8a773c2 to chrome/m49.]

Neither the GPU nor CPU paths were correctly handling the crop rect
in this case.

NOTE: this change adds a new test case to the imageblurcropped GM, so
it will have to be rebaselined.

BUG=skia:4876
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1657773002
NOTREECHECKS=true
NOTRY=true
NOPRESUBMIT=true

Review URL: https://codereview.chromium.org/1663533003 .
diff --git a/gm/imagefilterscropped.cpp b/gm/imagefilterscropped.cpp
index 4c6ef62..d39e6b0 100644
--- a/gm/imagefilterscropped.cpp
+++ b/gm/imagefilterscropped.cpp
@@ -72,11 +72,11 @@
     ImageFiltersCroppedGM () {}
 
 protected:
-    virtual SkString onShortName() override {
+    SkString onShortName() override {
         return SkString("imagefilterscropped");
     }
 
-    virtual SkISize onISize() override { return SkISize::Make(400, 880); }
+    SkISize onISize() override { return SkISize::Make(400, 960); }
 
     void make_checkerboard() {
         fCheckerboard.allocN32Pixels(80, 80);
@@ -131,6 +131,7 @@
         SkImageFilter* filters[] = {
             nullptr,
             SkColorFilterImageFilter::Create(cf.get(), nullptr, &cropRect),
+            SkBlurImageFilter::Create(0.0f, 0.0f, nullptr, &cropRect),
             SkBlurImageFilter::Create(1.0f, 1.0f, nullptr, &cropRect),
             SkBlurImageFilter::Create(8.0f, 0.0f, nullptr, &cropRect),
             SkBlurImageFilter::Create(0.0f, 8.0f, nullptr, &cropRect),
diff --git a/src/effects/SkBlurImageFilter.cpp b/src/effects/SkBlurImageFilter.cpp
index 5d58369..a1d6a2f 100644
--- a/src/effects/SkBlurImageFilter.cpp
+++ b/src/effects/SkBlurImageFilter.cpp
@@ -25,7 +25,7 @@
 // raster paths.
 #define MAX_SIGMA SkIntToScalar(532)
 
-static SkVector mapSigma(const SkSize& localSigma, const SkMatrix& ctm) {
+static SkVector map_sigma(const SkSize& localSigma, const SkMatrix& ctm) {
     SkVector sigma = SkVector::Make(localSigma.width(), localSigma.height());
     ctm.mapVectors(&sigma, 1);
     sigma.fX = SkMinScalar(SkScalarAbs(sigma.fX), MAX_SIGMA);
@@ -90,19 +90,7 @@
         return false;
     }
 
-    SkAutoLockPixels alp(src);
-    if (!src.getPixels()) {
-        return false;
-    }
-
-    SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(dstBounds.width(), dstBounds.height()));
-    if (!device) {
-        return false;
-    }
-    *dst = device->accessBitmap(false);
-    SkAutoLockPixels alp_dst(*dst);
-
-    SkVector sigma = mapSigma(fSigma, ctx.ctm());
+    SkVector sigma = map_sigma(fSigma, ctx.ctm());
 
     int kernelSizeX, kernelSizeX3, lowOffsetX, highOffsetX;
     int kernelSizeY, kernelSizeY3, lowOffsetY, highOffsetY;
@@ -114,12 +102,24 @@
     }
 
     if (kernelSizeX == 0 && kernelSizeY == 0) {
-        src.copyTo(dst, dst->colorType());
-        offset->fX = dstBounds.x() + srcOffset.x();
-        offset->fY = dstBounds.y() + srcOffset.y();
+        src.extractSubset(dst, srcBounds);
+        offset->fX = srcBounds.x();
+        offset->fY = srcBounds.y();
         return true;
     }
 
+    SkAutoLockPixels alp(src);
+    if (!src.getPixels()) {
+        return false;
+    }
+
+    SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(dstBounds.width(), dstBounds.height()));
+    if (!device) {
+        return false;
+    }
+    *dst = device->accessBitmap(false);
+    SkAutoLockPixels alp_dst(*dst);
+
     SkAutoTUnref<SkBaseDevice> tempDevice(proxy->createDevice(dst->width(), dst->height()));
     if (!tempDevice) {
         return false;
@@ -191,7 +191,7 @@
 void SkBlurImageFilter::onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm,
                                            SkIRect* dst, MapDirection) const {
     *dst = src;
-    SkVector sigma = mapSigma(fSigma, ctm);
+    SkVector sigma = map_sigma(fSigma, ctm);
     dst->outset(SkScalarCeilToInt(SkScalarMul(sigma.x(), SkIntToScalar(3))),
                 SkScalarCeilToInt(SkScalarMul(sigma.y(), SkIntToScalar(3))));
 }
@@ -211,15 +211,21 @@
     if (!srcBounds.intersect(dstBounds)) {
         return false;
     }
-    GrTexture* source = input.getTexture();
-    SkVector sigma = mapSigma(fSigma, ctx.ctm());
+    SkVector sigma = map_sigma(fSigma, ctx.ctm());
+    if (sigma.x() == 0 && sigma.y() == 0) {
+        input.extractSubset(result, srcBounds);
+        offset->fX = srcBounds.x();
+        offset->fY = srcBounds.y();
+        return true;
+    }
     offset->fX = dstBounds.fLeft;
     offset->fY = dstBounds.fTop;
     srcBounds.offset(-srcOffset);
     dstBounds.offset(-srcOffset);
     SkRect srcBoundsF(SkRect::Make(srcBounds));
-    SkAutoTUnref<GrTexture> tex(SkGpuBlurUtils::GaussianBlur(source->getContext(),
-                                                             source,
+    GrTexture* inputTexture = input.getTexture();
+    SkAutoTUnref<GrTexture> tex(SkGpuBlurUtils::GaussianBlur(inputTexture->getContext(),
+                                                             inputTexture,
                                                              false,
                                                              SkRect::Make(dstBounds),
                                                              &srcBoundsF,