Revert "Implement support for expanding crop rects in image filters"

Breaking ImageFilterTests unit test.

TBR=bsalomon@google.com
BUG=skia:

Review URL: https://codereview.chromium.org/196353021

git-svn-id: http://skia.googlecode.com/svn/trunk@13806 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gm/imagefilterscropexpand.cpp b/gm/imagefilterscropexpand.cpp
deleted file mode 100644
index 9373696..0000000
--- a/gm/imagefilterscropexpand.cpp
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * Copyright 2014 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "gm.h"
-#include "SkCanvas.h"
-#include "SkColorFilter.h"
-#include "SkColorPriv.h"
-#include "SkShader.h"
-
-#include "SkBitmapSource.h"
-#include "SkBlurImageFilter.h"
-#include "SkColorMatrixFilter.h"
-#include "SkDisplacementMapEffect.h"
-#include "SkDropShadowImageFilter.h"
-#include "SkGradientShader.h"
-#include "SkMorphologyImageFilter.h"
-#include "SkColorFilterImageFilter.h"
-#include "SkMergeImageFilter.h"
-#include "SkOffsetImageFilter.h"
-
-///////////////////////////////////////////////////////////////////////////////
-
-class ImageFiltersCropExpandGM : public skiagm::GM {
-public:
-    ImageFiltersCropExpandGM () {}
-
-protected:
-
-    virtual SkString onShortName() {
-        return SkString("imagefilterscropexpand");
-    }
-
-    virtual SkISize onISize() { return SkISize::Make(570, 650); }
-
-    void make_checkerboard(SkBitmap* bitmap) {
-        bitmap->allocN32Pixels(64, 64);
-        SkCanvas canvas(*bitmap);
-        canvas.clear(0xFFFF0000);
-        SkPaint darkPaint;
-        darkPaint.setColor(0xFF404040);
-        SkPaint lightPaint;
-        lightPaint.setColor(0xFFA0A0A0);
-        for (int y = 8; y < 48; y += 16) {
-            for (int x = 8; x < 48; x += 16) {
-                canvas.save();
-                canvas.translate(SkIntToScalar(x), SkIntToScalar(y));
-                canvas.drawRect(SkRect::MakeXYWH(0, 0, 8, 8), darkPaint);
-                canvas.drawRect(SkRect::MakeXYWH(8, 0, 8, 8), lightPaint);
-                canvas.drawRect(SkRect::MakeXYWH(0, 8, 8, 8), lightPaint);
-                canvas.drawRect(SkRect::MakeXYWH(8, 8, 8, 8), darkPaint);
-                canvas.restore();
-            }
-        }
-    }
-
-    void make_gradient_circle(int width, int height, SkBitmap* bitmap) {
-        SkScalar x = SkIntToScalar(width / 2);
-        SkScalar y = SkIntToScalar(height / 2);
-        SkScalar radius = SkMinScalar(x, y) * 0.8f;
-        bitmap->allocN32Pixels(width, height);
-        SkCanvas canvas(*bitmap);
-        canvas.clear(0x00000000);
-        SkColor colors[2];
-        colors[0] = SK_ColorWHITE;
-        colors[1] = SK_ColorBLACK;
-        SkAutoTUnref<SkShader> shader(
-            SkGradientShader::CreateRadial(SkPoint::Make(x, y), radius, colors, NULL, 2,
-                                           SkShader::kClamp_TileMode)
-        );
-        SkPaint paint;
-        paint.setShader(shader);
-        canvas.drawCircle(x, y, radius, paint);
-    }
-
-    static void draw(SkCanvas* canvas, const SkBitmap& bitmap, const SkRect& rect, SkImageFilter* filter) {
-        SkPaint paint;
-        paint.setImageFilter(filter)->unref();
-        canvas->saveLayer(&rect, &paint);
-        canvas->drawBitmap(bitmap, 0, 0);
-        canvas->restore();
-        
-        SkPaint strokePaint;
-        strokePaint.setColor(0xFFFF0000);
-        strokePaint.setStyle(SkPaint::kStroke_Style);
-        canvas->drawRect(rect, strokePaint);
-
-        canvas->translate(SkIntToScalar(80), 0);
-    }
-
-    virtual void onDraw(SkCanvas* canvas) {
-        SkAutoTUnref<SkColorFilter> cf(
-            SkColorFilter::CreateModeFilter(SK_ColorBLUE, SkXfermode::kSrcIn_Mode));
-        SkImageFilter::CropRect crop_rect(
-            SkRect::Make(SkIRect::MakeXYWH(10, 10, 44, 44)),
-            SkImageFilter::CropRect::kHasAll_CropEdge);
-
-        SkBitmap gradient_circle, checkerboard;
-        make_gradient_circle(64, 64, &gradient_circle);
-        make_checkerboard(&checkerboard);
-
-        SkAutoTUnref<SkImageFilter> gradient_circle_source(
-            SkBitmapSource::Create(gradient_circle));
-        SkAutoTUnref<SkImageFilter> noop_cropped(
-            SkOffsetImageFilter::Create(0, 0, NULL, &crop_rect));
-        SkScalar sk255 = SkIntToScalar(255);
-        SkScalar matrix[20] = { 1, 0, 0, 0, 0,
-                                0, 1, 0, 0, sk255,
-                                0, 0, 1, 0, 0,
-                                0, 0, 0, 0, sk255 };
-        SkAutoTUnref<SkColorFilter> cf_alpha_trans(SkColorMatrixFilter::Create(matrix));
-
-        SkRect r = SkRect::MakeWH(SkIntToScalar(64), SkIntToScalar(64));
-        SkScalar MARGIN = SkIntToScalar(12);
-
-        SkIRect bounds;
-        r.roundOut(&bounds);
-
-        SkPaint paint;
-        canvas->translate(MARGIN, MARGIN);
-        for (int outset = -15; outset <= 20; outset += 5) {
-            canvas->save();
-            SkRect rect = crop_rect.rect();
-            rect.outset(SkIntToScalar(outset),
-                        SkIntToScalar(outset));
-            SkImageFilter::CropRect big_rect(rect, SkImageFilter::CropRect::kHasAll_CropEdge);
-            
-            draw(canvas, checkerboard, rect, SkColorFilterImageFilter::Create(
-                cf_alpha_trans, noop_cropped.get(), &big_rect));
-
-            draw(canvas, checkerboard, rect, SkBlurImageFilter::Create(
-                8.0f, 8.0f, noop_cropped.get(), &big_rect));
-
-            draw(canvas, checkerboard, rect, SkDilateImageFilter::Create(
-                2, 2, noop_cropped.get(), &big_rect));
-
-            draw(canvas, checkerboard, rect, SkErodeImageFilter::Create(
-                2, 2, noop_cropped.get(), &big_rect));
-
-            draw(canvas, checkerboard, rect, SkDropShadowImageFilter::Create(
-                SkIntToScalar(10), SkIntToScalar(10), SkIntToScalar(3), SkIntToScalar(3),
-                SK_ColorBLUE, noop_cropped.get(), &big_rect));
-
-            draw(canvas, checkerboard, rect, SkDisplacementMapEffect::Create(
-                SkDisplacementMapEffect::kR_ChannelSelectorType,
-                SkDisplacementMapEffect::kR_ChannelSelectorType,
-                SkIntToScalar(12),
-                gradient_circle_source.get(),
-                noop_cropped.get(),
-                &big_rect));
-
-            draw(canvas, checkerboard, rect, SkOffsetImageFilter::Create(
-                SkIntToScalar(-8), SkIntToScalar(16), noop_cropped.get(), &big_rect));
-
-            canvas->restore();
-            canvas->translate(0, SkIntToScalar(80));
-        }
-    }
-
-private:
-    typedef GM INHERITED;
-};
-
-///////////////////////////////////////////////////////////////////////////////
-
-static skiagm::GM* MyFactory(void*) { return new ImageFiltersCropExpandGM; }
-static skiagm::GMRegistry reg(MyFactory);
diff --git a/gm/imagefiltersgraph.cpp b/gm/imagefiltersgraph.cpp
index 8885f0d..bc34e65 100644
--- a/gm/imagefiltersgraph.cpp
+++ b/gm/imagefiltersgraph.cpp
@@ -39,7 +39,9 @@
         }
 
         SkIRect bounds;
-        if (!this->applyCropRect(ctx, proxy, source, &srcOffset, &bounds, &source)) {
+        source.getBounds(&bounds);
+
+        if (!this->applyCropRect(&bounds, ctx.ctm())) {
             return false;
         }
 
diff --git a/gyp/gmslides.gypi b/gyp/gmslides.gypi
index 85258fc..27ecc3c 100644
--- a/gyp/gmslides.gypi
+++ b/gyp/gmslides.gypi
@@ -101,7 +101,6 @@
     '../gm/imagefiltersbase.cpp',
     '../gm/imagefiltersclipped.cpp',
     '../gm/imagefilterscropped.cpp',
-    '../gm/imagefilterscropexpand.cpp',
     '../gm/imagefiltersgraph.cpp',
     '../gm/imagefiltersscaled.cpp',
     '../gm/internal_links.cpp',
diff --git a/include/core/SkImageFilter.h b/include/core/SkImageFilter.h
index 0f52b69..4f33f54 100644
--- a/include/core/SkImageFilter.h
+++ b/include/core/SkImageFilter.h
@@ -223,25 +223,10 @@
     // no inputs.
     virtual bool onFilterBounds(const SkIRect&, const SkMatrix&, SkIRect*) const;
 
-    /** Computes source bounds as the src bitmap bounds offset by srcOffset.
-     *  Apply the transformed crop rect to the bounds if any of the
-     *  corresponding edge flags are set. Intersects the result against the
-     *  context's clipBounds, and returns the result in "bounds". If there is
-     *  no intersection, returns false and leaves "bounds" unchanged.
-     */
-    bool applyCropRect(const Context&, const SkBitmap& src, const SkIPoint& srcOffset,
-                       SkIRect* bounds) const;
-
-    /** Same as the above call, except that if the resulting crop rect is not
-     *  entirely contained by the source bitmap's bounds, it creates a new
-     *  bitmap in "result" and pads the edges with transparent black. In that
-     *  case, the srcOffset is modified to be the same as the bounds, since no
-     *  further adjustment is needed by the caller. This version should only
-     *  be used by filters which are not capable of processing a smaller
-     *  source bitmap into a larger destination.
-     */
-    bool applyCropRect(const Context&, Proxy* proxy, const SkBitmap& src, SkIPoint* srcOffset,
-                       SkIRect* bounds, SkBitmap* result) const;
+    // Applies "matrix" to the crop rect, and sets "rect" to the intersection of
+    // "rect" and the transformed crop rect. If there is no overlap, returns
+    // false and leaves "rect" unchanged.
+    bool applyCropRect(SkIRect* rect, const SkMatrix& matrix) const;
 
     /**
      *  Returns true if the filter can be expressed a single-pass
diff --git a/src/core/SkImageFilter.cpp b/src/core/SkImageFilter.cpp
index 2be66e7..6613f09 100644
--- a/src/core/SkImageFilter.cpp
+++ b/src/core/SkImageFilter.cpp
@@ -8,7 +8,6 @@
 #include "SkImageFilter.h"
 
 #include "SkBitmap.h"
-#include "SkDevice.h"
 #include "SkReadBuffer.h"
 #include "SkWriteBuffer.h"
 #include "SkRect.h"
@@ -156,7 +155,9 @@
     }
     GrTexture* srcTexture = input.getTexture();
     SkIRect bounds;
-    if (!this->applyCropRect(ctx, proxy, input, &srcOffset, &bounds, &input)) {
+    src.getBounds(&bounds);
+    bounds.offset(srcOffset);
+    if (!this->applyCropRect(&bounds, ctx.ctm())) {
         return false;
     }
     SkRect srcRect = SkRect::Make(bounds);
@@ -195,60 +196,18 @@
 #endif
 }
 
-bool SkImageFilter::applyCropRect(const Context& ctx, const SkBitmap& src,
-                                  const SkIPoint& srcOffset, SkIRect* bounds) const {
-    SkIRect srcBounds;
-    src.getBounds(&srcBounds);
-    srcBounds.offset(srcOffset);
+bool SkImageFilter::applyCropRect(SkIRect* rect, const SkMatrix& matrix) const {
     SkRect cropRect;
-    ctx.ctm().mapRect(&cropRect, fCropRect.rect());
+    matrix.mapRect(&cropRect, fCropRect.rect());
     SkIRect cropRectI;
     cropRect.roundOut(&cropRectI);
     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 (!srcBounds.intersect(ctx.clipBounds())) {
-        return false;
-    }
-    *bounds = srcBounds;
-    return true;
-}
-
-bool SkImageFilter::applyCropRect(const Context& ctx, Proxy* proxy, const SkBitmap& src,
-                                  SkIPoint* srcOffset, SkIRect* bounds, SkBitmap* dst) const {
-    SkIRect srcBounds;
-    src.getBounds(&srcBounds);
-    srcBounds.offset(*srcOffset);
-    SkRect cropRect;
-    ctx.ctm().mapRect(&cropRect, fCropRect.rect());
-    SkIRect cropRectI;
-    cropRect.roundOut(&cropRectI);
-    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 (!bounds->intersect(ctx.clipBounds())) {
-        return false;
-    }
-    if (srcBounds.contains(*bounds)) {
-        *dst = src;
-        return true;
-    } else {
-        SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds->width(), bounds->height()));
-        if (!device) {
-            return false;
-        }
-        SkCanvas canvas(device);
-        canvas.clear(0x00000000);
-        canvas.drawBitmap(src, srcOffset->x() - bounds->x(), srcOffset->y() - bounds->y());
-        *srcOffset = SkIPoint::Make(bounds->x(), bounds->y());
-        *dst = device->accessBitmap(false);
-        return true;
-    }
+    // If the original crop rect edges were unset, max out the new crop edges
+    if (!(flags & CropRect::kHasLeft_CropEdge)) cropRectI.fLeft = SK_MinS32;
+    if (!(flags & CropRect::kHasTop_CropEdge)) cropRectI.fTop = SK_MinS32;
+    if (!(flags & CropRect::kHasRight_CropEdge)) cropRectI.fRight = SK_MaxS32;
+    if (!(flags & CropRect::kHasBottom_CropEdge)) cropRectI.fBottom = SK_MaxS32;
+    return rect->intersect(cropRectI);
 }
 
 bool SkImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
diff --git a/src/effects/SkBlurImageFilter.cpp b/src/effects/SkBlurImageFilter.cpp
index ffebe54..adcb28f 100644
--- a/src/effects/SkBlurImageFilter.cpp
+++ b/src/effects/SkBlurImageFilter.cpp
@@ -146,13 +146,15 @@
         return false;
     }
 
-    SkIRect srcBounds, dstBounds;
-    if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &srcBounds, &src)) {
+    SkAutoLockPixels alp(src);
+    if (!src.getPixels()) {
         return false;
     }
 
-    SkAutoLockPixels alp(src);
-    if (!src.getPixels()) {
+    SkIRect srcBounds, dstBounds;
+    src.getBounds(&srcBounds);
+    srcBounds.offset(srcOffset);
+    if (!this->applyCropRect(&srcBounds, ctx.ctm())) {
         return false;
     }
 
@@ -256,11 +258,13 @@
     if (getInput(0) && !getInput(0)->getInputResultGPU(proxy, src, ctx, &input, &srcOffset)) {
         return false;
     }
+    GrTexture* source = input.getTexture();
     SkIRect rect;
-    if (!this->applyCropRect(ctx, proxy, input, &srcOffset, &rect, &input)) {
+    src.getBounds(&rect);
+    rect.offset(srcOffset);
+    if (!this->applyCropRect(&rect, ctx.ctm())) {
         return false;
     }
-    GrTexture* source = input.getTexture();
     SkVector sigma, localSigma = SkVector::Make(fSigma.width(), fSigma.height());
     ctx.ctm().mapVectors(&sigma, &localSigma, 1);
     offset->fX = rect.fLeft;
diff --git a/src/effects/SkColorFilterImageFilter.cpp b/src/effects/SkColorFilterImageFilter.cpp
index 8cdd546..0de7330 100755
--- a/src/effects/SkColorFilterImageFilter.cpp
+++ b/src/effects/SkColorFilterImageFilter.cpp
@@ -109,7 +109,9 @@
     }
 
     SkIRect bounds;
-    if (!this->applyCropRect(ctx, src, srcOffset, &bounds)) {
+    src.getBounds(&bounds);
+    bounds.offset(srcOffset);
+    if (!this->applyCropRect(&bounds, ctx.ctm())) {
         return false;
     }
 
diff --git a/src/effects/SkDisplacementMapEffect.cpp b/src/effects/SkDisplacementMapEffect.cpp
index 4b26a5f..a1c18c6 100644
--- a/src/effects/SkDisplacementMapEffect.cpp
+++ b/src/effects/SkDisplacementMapEffect.cpp
@@ -209,23 +209,26 @@
         (color.colorType() != kPMColor_SkColorType)) {
         return false;
     }
+
+    SkAutoLockPixels alp_displacement(displ), alp_color(color);
+    if (!displ.getPixels() || !color.getPixels()) {
+        return false;
+    }
     SkIRect bounds;
-    // Since computeDisplacement does bounds checking on color pixel access, we don't need to pad
-    // the color bitmap to bounds here.
-    if (!this->applyCropRect(ctx, color, colorOffset, &bounds)) {
+    color.getBounds(&bounds);
+    bounds.offset(colorOffset);
+    if (!this->applyCropRect(&bounds, ctx.ctm())) {
         return false;
     }
     SkIRect displBounds;
-    if (!this->applyCropRect(ctx, proxy, displ, &displOffset, &displBounds, &displ)) {
+    displ.getBounds(&displBounds);
+    displBounds.offset(displOffset);
+    if (!this->applyCropRect(&displBounds, ctx.ctm())) {
         return false;
     }
     if (!bounds.intersect(displBounds)) {
         return false;
     }
-    SkAutoLockPixels alp_displacement(displ), alp_color(color);
-    if (!displ.getPixels() || !color.getPixels()) {
-        return false;
-    }
 
     dst->setConfig(color.config(), bounds.width(), bounds.height());
     if (!dst->allocPixels()) {
@@ -251,18 +254,14 @@
     } else {
         *dst = src;
     }
-    dst->outset(fScale * SK_ScalarHalf, fScale * SK_ScalarHalf);
 }
 
 bool SkDisplacementMapEffect::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
                                    SkIRect* dst) const {
-    SkIRect bounds = src;
-    if (getColorInput() && !getColorInput()->filterBounds(src, ctm, &bounds)) {
-        return false;
+    if (getColorInput()) {
+        return getColorInput()->filterBounds(src, ctm, dst);
     }
-    bounds.outset(SkScalarCeilToInt(fScale * SK_ScalarHalf),
-                  SkScalarCeilToInt(fScale * SK_ScalarHalf));
-    *dst = bounds;
+    *dst = src;
     return true;
 }
 
@@ -357,6 +356,7 @@
                                                                &colorOffset)) {
         return false;
     }
+    GrTexture* color = colorBM.getTexture();
     SkBitmap displacementBM = src;
     SkIPoint displacementOffset = SkIPoint::Make(0, 0);
     if (getDisplacementInput() &&
@@ -364,21 +364,6 @@
                                                    &displacementOffset)) {
         return false;
     }
-    SkIRect bounds;
-    // Since GrDisplacementMapEffect does bounds checking on color pixel access, we don't need to
-    // pad the color bitmap to bounds here.
-    if (!this->applyCropRect(ctx, colorBM, colorOffset, &bounds)) {
-        return false;
-    }
-    SkIRect displBounds;
-    if (!this->applyCropRect(ctx, proxy, displacementBM,
-                             &displacementOffset, &displBounds, &displacementBM)) {
-        return false;
-    }
-    if (!bounds.intersect(displBounds)) {
-        return false;
-    }
-    GrTexture* color = colorBM.getTexture();
     GrTexture* displacement = displacementBM.getTexture();
     GrContext* context = color->getContext();
 
@@ -395,6 +380,21 @@
 
     SkVector scale = SkVector::Make(fScale, fScale);
     ctx.ctm().mapVectors(&scale, 1);
+    SkIRect bounds;
+    colorBM.getBounds(&bounds);
+    bounds.offset(colorOffset);
+    if (!this->applyCropRect(&bounds, ctx.ctm())) {
+        return false;
+    }
+    SkIRect displBounds;
+    displacementBM.getBounds(&displBounds);
+    displBounds.offset(displacementOffset);
+    if (!this->applyCropRect(&displBounds, ctx.ctm())) {
+        return false;
+    }
+    if (!bounds.intersect(displBounds)) {
+        return false;
+    }
 
     GrPaint paint;
     SkMatrix offsetMatrix = GrEffect::MakeDivByTextureWHMatrix(displacement);
diff --git a/src/effects/SkDropShadowImageFilter.cpp b/src/effects/SkDropShadowImageFilter.cpp
index 40ab8cf..94055ce 100644
--- a/src/effects/SkDropShadowImageFilter.cpp
+++ b/src/effects/SkDropShadowImageFilter.cpp
@@ -66,7 +66,9 @@
         return false;
 
     SkIRect bounds;
-    if (!this->applyCropRect(ctx, src, srcOffset, &bounds)) {
+    src.getBounds(&bounds);
+    bounds.offset(srcOffset);
+    if (!this->applyCropRect(&bounds, ctx.ctm())) {
         return false;
     }
 
@@ -88,8 +90,7 @@
     paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
     SkVector offsetVec, localOffsetVec = SkVector::Make(fDx, fDy);
     ctx.ctm().mapVectors(&offsetVec, &localOffsetVec, 1);
-    canvas.translate(SkIntToScalar(srcOffset.fX - bounds.fLeft),
-                     SkIntToScalar(srcOffset.fY - bounds.fTop));
+    canvas.translate(-SkIntToScalar(bounds.fLeft), -SkIntToScalar(bounds.fTop));
     canvas.drawBitmap(src, offsetVec.fX, offsetVec.fY, &paint);
     canvas.drawBitmap(src, 0, 0);
     *result = device->accessBitmap(false);
diff --git a/src/effects/SkLightingImageFilter.cpp b/src/effects/SkLightingImageFilter.cpp
index 54bb1c8..206be1b 100644
--- a/src/effects/SkLightingImageFilter.cpp
+++ b/src/effects/SkLightingImageFilter.cpp
@@ -946,8 +946,15 @@
     if (src.colorType() != kPMColor_SkColorType) {
         return false;
     }
+    SkAutoLockPixels alp(src);
+    if (!src.getPixels()) {
+        return false;
+    }
+
     SkIRect bounds;
-    if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) {
+    src.getBounds(&bounds);
+    bounds.offset(srcOffset);
+    if (!this->applyCropRect(&bounds, ctx.ctm())) {
         return false;
     }
 
@@ -955,11 +962,6 @@
         return false;
     }
 
-    SkAutoLockPixels alp(src);
-    if (!src.getPixels()) {
-        return false;
-    }
-
     dst->setConfig(src.config(), bounds.width(), bounds.height());
     if (!dst->allocPixels()) {
         return false;
@@ -1037,9 +1039,15 @@
     if (src.colorType() != kPMColor_SkColorType) {
         return false;
     }
+    SkAutoLockPixels alp(src);
+    if (!src.getPixels()) {
+        return false;
+    }
 
     SkIRect bounds;
-    if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) {
+    src.getBounds(&bounds);
+    bounds.offset(srcOffset);
+    if (!this->applyCropRect(&bounds, ctx.ctm())) {
         return false;
     }
 
@@ -1047,11 +1055,6 @@
         return false;
     }
 
-    SkAutoLockPixels alp(src);
-    if (!src.getPixels()) {
-        return false;
-    }
-
     dst->setConfig(src.config(), bounds.width(), bounds.height());
     dst->allocPixels();
     if (!dst->getPixels()) {
diff --git a/src/effects/SkMatrixConvolutionImageFilter.cpp b/src/effects/SkMatrixConvolutionImageFilter.cpp
index 7b9812d..1df1ff9 100644
--- a/src/effects/SkMatrixConvolutionImageFilter.cpp
+++ b/src/effects/SkMatrixConvolutionImageFilter.cpp
@@ -265,7 +265,9 @@
     }
 
     SkIRect bounds;
-    if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) {
+    src.getBounds(&bounds);
+    bounds.offset(srcOffset);
+    if (!this->applyCropRect(&bounds, ctx.ctm())) {
         return false;
     }
 
diff --git a/src/effects/SkMergeImageFilter.cpp b/src/effects/SkMergeImageFilter.cpp
index adf9afe..ff36e5b 100755
--- a/src/effects/SkMergeImageFilter.cpp
+++ b/src/effects/SkMergeImageFilter.cpp
@@ -73,7 +73,8 @@
     }
 
     SkIRect bounds;
-    if (!this->applyCropRect(ctx, src, SkIPoint::Make(0, 0), &bounds)) {
+    src.getBounds(&bounds);
+    if (!this->applyCropRect(&bounds, ctx.ctm())) {
         return false;
     }
 
diff --git a/src/effects/SkMorphologyImageFilter.cpp b/src/effects/SkMorphologyImageFilter.cpp
index fb69758..90940b9 100644
--- a/src/effects/SkMorphologyImageFilter.cpp
+++ b/src/effects/SkMorphologyImageFilter.cpp
@@ -154,7 +154,9 @@
     }
 
     SkIRect bounds;
-    if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) {
+    src.getBounds(&bounds);
+    bounds.offset(srcOffset);
+    if (!this->applyCropRect(&bounds, ctx.ctm())) {
         return false;
     }
 
@@ -545,7 +547,9 @@
         return false;
     }
     SkIRect bounds;
-    if (!this->applyCropRect(ctx, proxy, input, &srcOffset, &bounds, &input)) {
+    input.getBounds(&bounds);
+    bounds.offset(srcOffset);
+    if (!this->applyCropRect(&bounds, ctx.ctm())) {
         return false;
     }
     SkVector radius = SkVector::Make(SkIntToScalar(this->radius().width()),
diff --git a/src/effects/SkOffsetImageFilter.cpp b/src/effects/SkOffsetImageFilter.cpp
index ae35a4c..98eb05b 100644
--- a/src/effects/SkOffsetImageFilter.cpp
+++ b/src/effects/SkOffsetImageFilter.cpp
@@ -42,7 +42,10 @@
         }
 
         SkIRect bounds;
-        if (!this->applyCropRect(ctx, src, srcOffset, &bounds)) {
+        src.getBounds(&bounds);
+        bounds.offset(srcOffset);
+
+        if (!applyCropRect(&bounds, ctx.ctm())) {
             return false;
         }
 
diff --git a/src/effects/SkRectShaderImageFilter.cpp b/src/effects/SkRectShaderImageFilter.cpp
index 13e59c2..dad0e02 100644
--- a/src/effects/SkRectShaderImageFilter.cpp
+++ b/src/effects/SkRectShaderImageFilter.cpp
@@ -56,7 +56,8 @@
                                             SkBitmap* result,
                                             SkIPoint* offset) const {
     SkIRect bounds;
-    if (!this->applyCropRect(ctx, source, SkIPoint::Make(0, 0), &bounds)) {
+    source.getBounds(&bounds);
+    if (!this->applyCropRect(&bounds, ctx.ctm())) {
         return false;
     }
 
diff --git a/src/effects/SkXfermodeImageFilter.cpp b/src/effects/SkXfermodeImageFilter.cpp
index 901353f..ebfd16c 100644
--- a/src/effects/SkXfermodeImageFilter.cpp
+++ b/src/effects/SkXfermodeImageFilter.cpp
@@ -62,13 +62,14 @@
     }
 
     SkIRect bounds, foregroundBounds;
-    if (!applyCropRect(ctx, foreground, foregroundOffset, &foregroundBounds)) {
-        return false;
-    }
-    if (!applyCropRect(ctx, background, backgroundOffset, &bounds)) {
-        return false;
-    }
+    background.getBounds(&bounds);
+    bounds.offset(backgroundOffset);
+    foreground.getBounds(&foregroundBounds);
+    foregroundBounds.offset(foregroundOffset);
     bounds.join(foregroundBounds);
+    if (!applyCropRect(&bounds, ctx.ctm())) {
+        return false;
+    }
 
     SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds.width(), bounds.height()));
     if (NULL == device.get()) {