Fix for partially-specified crop rects.

When only the left or top edge of a crop rect is given, the
right and bottom should be computed based on the incoming width
and height, not based on the crop rect's width & height. This
complies more accurately with SVG semantics.

BUG=240827

Review URL: https://codereview.chromium.org/1232873002
diff --git a/src/core/SkImageFilter.cpp b/src/core/SkImageFilter.cpp
index 8a3fbb4..178d892 100644
--- a/src/core/SkImageFilter.cpp
+++ b/src/core/SkImageFilter.cpp
@@ -302,10 +302,18 @@
     ctx.ctm().mapRect(&cropRect, fCropRect.rect());
     const SkIRect cropRectI = cropRect.roundOut();
     uint32_t flags = fCropRect.flags();
-    if (flags & CropRect::kHasLeft_CropEdge) srcBounds.fLeft = cropRectI.fLeft;
-    if (flags & CropRect::kHasTop_CropEdge) srcBounds.fTop = cropRectI.fTop;
-    if (flags & CropRect::kHasRight_CropEdge) srcBounds.fRight = cropRectI.fRight;
-    if (flags & CropRect::kHasBottom_CropEdge) srcBounds.fBottom = cropRectI.fBottom;
+    if (flags & CropRect::kHasLeft_CropEdge) {
+        srcBounds.fLeft = cropRectI.fLeft;
+    }
+    if (flags & CropRect::kHasTop_CropEdge) {
+        srcBounds.fTop = cropRectI.fTop;
+    }
+    if (flags & CropRect::kHasRight_CropEdge) {
+        srcBounds.fRight = srcBounds.fLeft + cropRectI.width();
+    }
+    if (flags & CropRect::kHasBottom_CropEdge) {
+        srcBounds.fBottom = srcBounds.fTop + cropRectI.height();
+    }
     if (!srcBounds.intersect(ctx.clipBounds())) {
         return false;
     }
@@ -323,10 +331,18 @@
     const SkIRect cropRectI = cropRect.roundOut();
     uint32_t flags = fCropRect.flags();
     *bounds = srcBounds;
-    if (flags & CropRect::kHasLeft_CropEdge) bounds->fLeft = cropRectI.fLeft;
-    if (flags & CropRect::kHasTop_CropEdge) bounds->fTop = cropRectI.fTop;
-    if (flags & CropRect::kHasRight_CropEdge) bounds->fRight = cropRectI.fRight;
-    if (flags & CropRect::kHasBottom_CropEdge) bounds->fBottom = cropRectI.fBottom;
+    if (flags & CropRect::kHasLeft_CropEdge) {
+        bounds->fLeft = cropRectI.fLeft;
+    }
+    if (flags & CropRect::kHasTop_CropEdge) {
+        bounds->fTop = cropRectI.fTop;
+    }
+    if (flags & CropRect::kHasRight_CropEdge) {
+        bounds->fRight = bounds->fLeft + cropRectI.width();
+    }
+    if (flags & CropRect::kHasBottom_CropEdge) {
+        bounds->fBottom = bounds->fTop + cropRectI.height();
+    }
     if (!bounds->intersect(ctx.clipBounds())) {
         return false;
     }
diff --git a/tests/ImageFilterTest.cpp b/tests/ImageFilterTest.cpp
index 480a75f..dc35332 100644
--- a/tests/ImageFilterTest.cpp
+++ b/tests/ImageFilterTest.cpp
@@ -1139,6 +1139,27 @@
     REPORTER_ASSERT(reporter, offset.fX == 1 && offset.fY == 0);
 }
 
+DEF_TEST(PartialCropRect, reporter) {
+    SkBitmap bitmap;
+    bitmap.allocN32Pixels(100, 100);
+    bitmap.eraseARGB(0, 0, 0, 0);
+    const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
+    SkBitmapDevice device(bitmap, props);
+    SkImageFilter::Proxy proxy(&device);
+
+    SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(100, 0, 20, 30),
+        SkImageFilter::CropRect::kHasRight_CropEdge | SkImageFilter::CropRect::kHasBottom_CropEdge);
+    SkAutoTUnref<SkImageFilter> filter(make_grayscale(NULL, &cropRect));
+    SkBitmap result;
+    SkIPoint offset;
+    SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeLargest(), NULL);
+    REPORTER_ASSERT(reporter, filter->filterImage(&proxy, bitmap, ctx, &result, &offset));
+    REPORTER_ASSERT(reporter, offset.fX == 0);
+    REPORTER_ASSERT(reporter, offset.fY == 0);
+    REPORTER_ASSERT(reporter, result.width() == 20);
+    REPORTER_ASSERT(reporter, result.height() == 30);
+}
+
 #if SK_SUPPORT_GPU
 
 DEF_GPUTEST(ImageFilterCropRectGPU, reporter, factory) {