In image filters, apply the CTM and offset to the crop rect. This is necessary to compensate for both clipping applied by the compositor (communicated via the CTM) and for cropping applied in upstream image filters (communicated via the offset). This requires a few ugly conversions, since the crop rect is an SkIRect, and the ctm is an SkMatrix.

I also had to offset the matrix passed to filter evaluation by drawSprite() and internalDrawBitmap() by the primitive position. This is the same offset that is applied when drawing the primitive, to compensate for the internal saveLayer().

Also apply the total matrix to the filter params in asNewEffect(), so that (for example) lighting params are offset by both the compositor clipping and upstream crop rects.

R=reed@google.com

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

git-svn-id: http://skia.googlecode.com/svn/trunk/src@10961 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/core/SkCanvas.cpp b/core/SkCanvas.cpp
index c59cd04..ff688f5 100644
--- a/core/SkCanvas.cpp
+++ b/core/SkCanvas.cpp
@@ -999,7 +999,9 @@
             SkDeviceImageFilterProxy proxy(dstDev);
             SkBitmap dst;
             const SkBitmap& src = srcDev->accessBitmap(false);
-            if (filter->filterImage(&proxy, src, *iter.fMatrix, &dst, &pos)) {
+            SkMatrix matrix = *iter.fMatrix;
+            matrix.postTranslate(SkIntToScalar(-x), SkIntToScalar(-y));
+            if (filter->filterImage(&proxy, src, matrix, &dst, &pos)) {
                 SkPaint tmpUnfiltered(*paint);
                 tmpUnfiltered.setImageFilter(NULL);
                 dstDev->drawSprite(iter, dst, pos.x(), pos.y(), tmpUnfiltered);
@@ -1034,8 +1036,9 @@
         if (filter && !iter.fDevice->canHandleImageFilter(filter)) {
             SkDeviceImageFilterProxy proxy(iter.fDevice);
             SkBitmap dst;
-            if (filter->filterImage(&proxy, bitmap, *iter.fMatrix,
-                                    &dst, &pos)) {
+            SkMatrix matrix = *iter.fMatrix;
+            matrix.postTranslate(SkIntToScalar(-x), SkIntToScalar(-y));
+            if (filter->filterImage(&proxy, bitmap, matrix, &dst, &pos)) {
                 SkPaint tmpUnfiltered(*paint);
                 tmpUnfiltered.setImageFilter(NULL);
                 iter.fDevice->drawSprite(iter, dst, pos.x(), pos.y(),
diff --git a/core/SkImageFilter.cpp b/core/SkImageFilter.cpp
index 222a029..502613b 100644
--- a/core/SkImageFilter.cpp
+++ b/core/SkImageFilter.cpp
@@ -102,7 +102,7 @@
 }
 
 bool SkImageFilter::canFilterImageGPU() const {
-    return this->asNewEffect(NULL, NULL, SkIPoint::Make(0, 0));
+    return this->asNewEffect(NULL, NULL, SkMatrix::I());
 }
 
 bool SkImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, const SkMatrix& ctm,
@@ -116,7 +116,7 @@
     GrTexture* srcTexture = input.getTexture();
     SkIRect bounds;
     src.getBounds(&bounds);
-    if (!this->applyCropRect(&bounds)) {
+    if (!this->applyCropRect(&bounds, ctm)) {
         return false;
     }
     SkRect srcRect = SkRect::Make(bounds);
@@ -135,7 +135,9 @@
     GrContext::AutoRenderTarget art(context, dst.texture()->asRenderTarget());
     GrContext::AutoClip acs(context, dstRect);
     GrEffectRef* effect;
-    this->asNewEffect(&effect, srcTexture, SkIPoint::Make(bounds.left(), bounds.top()));
+    SkMatrix matrix(ctm);
+    matrix.postTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top()));
+    this->asNewEffect(&effect, srcTexture, matrix);
     SkASSERT(effect);
     SkAutoUnref effectRef(effect);
     GrPaint paint;
@@ -152,8 +154,17 @@
 #endif
 }
 
-bool SkImageFilter::applyCropRect(SkIRect* rect) const {
-    return rect->intersect(fCropRect);
+bool SkImageFilter::applyCropRect(SkIRect* rect, const SkMatrix& matrix) const {
+    SkRect cropRect;
+    matrix.mapRect(&cropRect, SkRect::Make(fCropRect));
+    SkIRect cropRectI;
+    cropRect.roundOut(&cropRectI);
+    // If the original crop rect edges were unset, max out the new crop edges
+    if (fCropRect.fLeft == SK_MinS32) cropRectI.fLeft = SK_MinS32;
+    if (fCropRect.fTop == SK_MinS32) cropRectI.fTop = SK_MinS32;
+    if (fCropRect.fRight == SK_MaxS32) cropRectI.fRight = SK_MaxS32;
+    if (fCropRect.fBottom == SK_MaxS32) cropRectI.fBottom = SK_MaxS32;
+    return rect->intersect(cropRectI);
 }
 
 bool SkImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
@@ -162,7 +173,7 @@
     return true;
 }
 
-bool SkImageFilter::asNewEffect(GrEffectRef**, GrTexture*, const SkIPoint& offset) const {
+bool SkImageFilter::asNewEffect(GrEffectRef**, GrTexture*, const SkMatrix&) const {
     return false;
 }
 
diff --git a/effects/SkBlurImageFilter.cpp b/effects/SkBlurImageFilter.cpp
index 4b2d3b8..3f97ddd 100644
--- a/effects/SkBlurImageFilter.cpp
+++ b/effects/SkBlurImageFilter.cpp
@@ -158,7 +158,7 @@
 
     SkIRect srcBounds, dstBounds;
     src.getBounds(&srcBounds);
-    if (!this->applyCropRect(&srcBounds)) {
+    if (!this->applyCropRect(&srcBounds, ctm)) {
         return false;
     }
 
@@ -216,7 +216,7 @@
     GrTexture* source = input.getTexture();
     SkIRect rect;
     src.getBounds(&rect);
-    if (!this->applyCropRect(&rect)) {
+    if (!this->applyCropRect(&rect, ctm)) {
         return false;
     }
     SkAutoTUnref<GrTexture> tex(SkGpuBlurUtils::GaussianBlur(source->getContext(),
diff --git a/effects/SkColorFilterImageFilter.cpp b/effects/SkColorFilterImageFilter.cpp
index 9c2c54e..16a36bb 100755
--- a/effects/SkColorFilterImageFilter.cpp
+++ b/effects/SkColorFilterImageFilter.cpp
@@ -107,7 +107,7 @@
 
     SkIRect bounds;
     src.getBounds(&bounds);
-    if (!this->applyCropRect(&bounds)) {
+    if (!this->applyCropRect(&bounds, matrix)) {
         return false;
     }
 
diff --git a/effects/SkLightingImageFilter.cpp b/effects/SkLightingImageFilter.cpp
index ccb1dc5..e71df66 100644
--- a/effects/SkLightingImageFilter.cpp
+++ b/effects/SkLightingImageFilter.cpp
@@ -265,7 +265,7 @@
     SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDiffuseLightingImageFilter)
 
 #if SK_SUPPORT_GPU
-    virtual bool asNewEffect(GrEffectRef** effect, GrTexture*, const SkIPoint& offset) const SK_OVERRIDE;
+    virtual bool asNewEffect(GrEffectRef** effect, GrTexture*, const SkMatrix& matrix) const SK_OVERRIDE;
 #endif
     SkScalar kd() const { return fKD; }
 
@@ -287,7 +287,7 @@
     SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpecularLightingImageFilter)
 
 #if SK_SUPPORT_GPU
-    virtual bool asNewEffect(GrEffectRef** effect, GrTexture*, const SkIPoint& offset) const SK_OVERRIDE;
+    virtual bool asNewEffect(GrEffectRef** effect, GrTexture*, const SkMatrix& matrix) const SK_OVERRIDE;
 #endif
 
     SkScalar ks() const { return fKS; }
@@ -309,12 +309,12 @@
 
 class GrLightingEffect : public GrSingleTextureEffect {
 public:
-    GrLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale, const SkIPoint& offset);
+    GrLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale, const SkMatrix& matrix);
     virtual ~GrLightingEffect();
 
     const SkLight* light() const { return fLight; }
     SkScalar surfaceScale() const { return fSurfaceScale; }
-    const SkIPoint& offset() const { return fOffset; }
+    const SkMatrix& filterMatrix() const { return fFilterMatrix; }
 
     virtual void getConstantColorComponents(GrColor* color,
                                             uint32_t* validFlags) const SK_OVERRIDE {
@@ -329,7 +329,7 @@
     typedef GrSingleTextureEffect INHERITED;
     const SkLight* fLight;
     SkScalar fSurfaceScale;
-    SkIPoint fOffset;
+    SkMatrix fFilterMatrix;
 };
 
 class GrDiffuseLightingEffect : public GrLightingEffect {
@@ -337,12 +337,12 @@
     static GrEffectRef* Create(GrTexture* texture,
                                const SkLight* light,
                                SkScalar surfaceScale,
-                               const SkIPoint& offset,
+                               const SkMatrix& matrix,
                                SkScalar kd) {
         AutoEffectUnref effect(SkNEW_ARGS(GrDiffuseLightingEffect, (texture,
                                                                     light,
                                                                     surfaceScale,
-                                                                    offset,
+                                                                    matrix,
                                                                     kd)));
         return CreateEffectRef(effect);
     }
@@ -360,7 +360,7 @@
     GrDiffuseLightingEffect(GrTexture* texture,
                             const SkLight* light,
                             SkScalar surfaceScale,
-                            const SkIPoint& offset,
+                            const SkMatrix& matrix,
                             SkScalar kd);
 
     GR_DECLARE_EFFECT_TEST;
@@ -373,13 +373,13 @@
     static GrEffectRef* Create(GrTexture* texture,
                                const SkLight* light,
                                SkScalar surfaceScale,
-                               const SkIPoint& offset,
+                               const SkMatrix& matrix,
                                SkScalar ks,
                                SkScalar shininess) {
         AutoEffectUnref effect(SkNEW_ARGS(GrSpecularLightingEffect, (texture,
                                                                      light,
                                                                      surfaceScale,
-                                                                     offset,
+                                                                     matrix,
                                                                      ks,
                                                                      shininess)));
         return CreateEffectRef(effect);
@@ -398,7 +398,7 @@
     GrSpecularLightingEffect(GrTexture* texture,
                              const SkLight* light,
                              SkScalar surfaceScale,
-                             const SkIPoint& offset,
+                             const SkMatrix& matrix,
                              SkScalar ks,
                              SkScalar shininess);
 
@@ -434,8 +434,7 @@
     // This is called from GrGLLightingEffect's setData(). Subclasses of GrGLLight must call
     // INHERITED::setData().
     virtual void setData(const GrGLUniformManager&,
-                         const SkLight* light,
-                         const SkIPoint& offset) const;
+                         const SkLight* light) const;
 
 protected:
     /**
@@ -456,8 +455,7 @@
 public:
     virtual ~GrGLDistantLight() {}
     virtual void setData(const GrGLUniformManager&,
-                         const SkLight* light,
-                         const SkIPoint& offset) const SK_OVERRIDE;
+                         const SkLight* light) const SK_OVERRIDE;
     virtual void emitSurfaceToLight(GrGLShaderBuilder*, const char* z) SK_OVERRIDE;
 
 private:
@@ -471,8 +469,7 @@
 public:
     virtual ~GrGLPointLight() {}
     virtual void setData(const GrGLUniformManager&,
-                         const SkLight* light,
-                         const SkIPoint& offset) const SK_OVERRIDE;
+                         const SkLight* light) const SK_OVERRIDE;
     virtual void emitSurfaceToLight(GrGLShaderBuilder*, const char* z) SK_OVERRIDE;
 
 private:
@@ -486,8 +483,7 @@
 public:
     virtual ~GrGLSpotLight() {}
     virtual void setData(const GrGLUniformManager&,
-                         const SkLight* light,
-                         const SkIPoint& offset) const SK_OVERRIDE;
+                         const SkLight* light) const SK_OVERRIDE;
     virtual void emitSurfaceToLight(GrGLShaderBuilder*, const char* z) SK_OVERRIDE;
     virtual void emitLightColor(GrGLShaderBuilder*, const char *surfaceToLight) SK_OVERRIDE;
 
@@ -529,12 +525,15 @@
     }
     // Called to know whether the generated GrGLLight will require access to the fragment position.
     virtual bool requiresFragmentPosition() const = 0;
+    virtual SkLight* transform(const SkMatrix& matrix) const = 0;
 
 protected:
     SkLight(SkColor color)
       : fColor(SkIntToScalar(SkColorGetR(color)),
                SkIntToScalar(SkColorGetG(color)),
                SkIntToScalar(SkColorGetB(color))) {}
+    SkLight(const SkPoint3& color)
+      : fColor(color) {}
     SkLight(SkFlattenableReadBuffer& buffer)
       : INHERITED(buffer) {
         fColor = readPoint3(buffer);
@@ -588,9 +587,15 @@
     SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDistantLight)
 
 protected:
+    SkDistantLight(const SkPoint3& direction, const SkPoint3& color)
+      : INHERITED(color), fDirection(direction) {
+    }
     SkDistantLight(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
         fDirection = readPoint3(buffer);
     }
+    virtual SkLight* transform(const SkMatrix& matrix) const {
+        return new SkDistantLight(direction(), color());
+    }
     virtual void flatten(SkFlattenableWriteBuffer& buffer) const {
         INHERITED::flatten(buffer);
         writePoint3(fDirection, buffer);
@@ -635,6 +640,12 @@
         return INHERITED::isEqual(other) &&
                fLocation == o.fLocation;
     }
+    virtual SkLight* transform(const SkMatrix& matrix) const {
+        SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
+        matrix.mapPoints(&location2, 1);
+        SkPoint3 location(location2.fX, location2.fY, fLocation.fZ);
+        return new SkPointLight(location, color());
+    }
 
     SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkPointLight)
 
@@ -642,6 +653,8 @@
     SkPointLight(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
         fLocation = readPoint3(buffer);
     }
+    SkPointLight(const SkPoint3& location, const SkPoint3& color)
+     : INHERITED(color), fLocation(location) {}
     virtual void flatten(SkFlattenableWriteBuffer& buffer) const {
         INHERITED::flatten(buffer);
         writePoint3(fLocation, buffer);
@@ -670,6 +683,16 @@
        fConeScale = SkScalarInvert(antiAliasThreshold);
     }
 
+    virtual SkLight* transform(const SkMatrix& matrix) const {
+        SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
+        matrix.mapPoints(&location2, 1);
+        SkPoint3 location(location2.fX, location2.fY, fLocation.fZ);
+        SkPoint target2 = SkPoint::Make(fTarget.fX, fTarget.fY);
+        matrix.mapPoints(&target2, 1);
+        SkPoint3 target(target2.fX, target2.fY, fTarget.fZ);
+        return new SkSpotLight(location, target, fSpecularExponent, fCosOuterConeAngle, fCosInnerConeAngle, fConeScale, fS, color());
+    }
+
     SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
         SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
                            fLocation.fY - SkIntToScalar(y),
@@ -719,6 +742,17 @@
         fConeScale = buffer.readScalar();
         fS = readPoint3(buffer);
     }
+    SkSpotLight(const SkPoint3& location, const SkPoint3& target, SkScalar specularExponent, SkScalar cosOuterConeAngle, SkScalar cosInnerConeAngle, SkScalar coneScale, const SkPoint3& s, const SkPoint3& color)
+     : INHERITED(color),
+       fLocation(location),
+       fTarget(target),
+       fSpecularExponent(specularExponent),
+       fCosOuterConeAngle(cosOuterConeAngle),
+       fCosInnerConeAngle(cosInnerConeAngle),
+       fConeScale(coneScale),
+       fS(s)
+    {
+    }
     virtual void flatten(SkFlattenableWriteBuffer& buffer) const {
         INHERITED::flatten(buffer);
         writePoint3(fLocation, buffer);
@@ -857,7 +891,7 @@
 
 bool SkDiffuseLightingImageFilter::onFilterImage(Proxy*,
                                                  const SkBitmap& src,
-                                                 const SkMatrix&,
+                                                 const SkMatrix& ctm,
                                                  SkBitmap* dst,
                                                  SkIPoint* offset) {
     if (src.config() != SkBitmap::kARGB_8888_Config) {
@@ -870,7 +904,7 @@
 
     SkIRect bounds;
     src.getBounds(&bounds);
-    if (!this->applyCropRect(&bounds)) {
+    if (!this->applyCropRect(&bounds, ctm)) {
         return false;
     }
 
@@ -881,16 +915,18 @@
     dst->setConfig(src.config(), bounds.width(), bounds.height());
     dst->allocPixels();
 
+    SkAutoTUnref<SkLight> transformedLight(light()->transform(ctm));
+
     DiffuseLightingType lightingType(fKD);
-    switch (light()->type()) {
+    switch (transformedLight->type()) {
         case SkLight::kDistant_LightType:
-            lightBitmap<DiffuseLightingType, SkDistantLight>(lightingType, light(), src, dst, surfaceScale(), bounds);
+            lightBitmap<DiffuseLightingType, SkDistantLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
             break;
         case SkLight::kPoint_LightType:
-            lightBitmap<DiffuseLightingType, SkPointLight>(lightingType, light(), src, dst, surfaceScale(), bounds);
+            lightBitmap<DiffuseLightingType, SkPointLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
             break;
         case SkLight::kSpot_LightType:
-            lightBitmap<DiffuseLightingType, SkSpotLight>(lightingType, light(), src, dst, surfaceScale(), bounds);
+            lightBitmap<DiffuseLightingType, SkSpotLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
             break;
     }
 
@@ -900,10 +936,10 @@
 }
 
 #if SK_SUPPORT_GPU
-bool SkDiffuseLightingImageFilter::asNewEffect(GrEffectRef** effect, GrTexture* texture, const SkIPoint& offset) const {
+bool SkDiffuseLightingImageFilter::asNewEffect(GrEffectRef** effect, GrTexture* texture, const SkMatrix& matrix) const {
     if (effect) {
         SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
-        *effect = GrDiffuseLightingEffect::Create(texture, light(), scale, offset, kd());
+        *effect = GrDiffuseLightingEffect::Create(texture, light(), scale, matrix, kd());
     }
     return true;
 }
@@ -933,7 +969,7 @@
 
 bool SkSpecularLightingImageFilter::onFilterImage(Proxy*,
                                                   const SkBitmap& src,
-                                                  const SkMatrix&,
+                                                  const SkMatrix& ctm,
                                                   SkBitmap* dst,
                                                   SkIPoint* offset) {
     if (src.config() != SkBitmap::kARGB_8888_Config) {
@@ -946,7 +982,7 @@
 
     SkIRect bounds;
     src.getBounds(&bounds);
-    if (!this->applyCropRect(&bounds)) {
+    if (!this->applyCropRect(&bounds, ctm)) {
         return false;
     }
 
@@ -958,15 +994,16 @@
     dst->allocPixels();
 
     SpecularLightingType lightingType(fKS, fShininess);
-    switch (light()->type()) {
+    SkAutoTUnref<SkLight> transformedLight(light()->transform(ctm));
+    switch (transformedLight->type()) {
         case SkLight::kDistant_LightType:
-            lightBitmap<SpecularLightingType, SkDistantLight>(lightingType, light(), src, dst, surfaceScale(), bounds);
+            lightBitmap<SpecularLightingType, SkDistantLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
             break;
         case SkLight::kPoint_LightType:
-            lightBitmap<SpecularLightingType, SkPointLight>(lightingType, light(), src, dst, surfaceScale(), bounds);
+            lightBitmap<SpecularLightingType, SkPointLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
             break;
         case SkLight::kSpot_LightType:
-            lightBitmap<SpecularLightingType, SkSpotLight>(lightingType, light(), src, dst, surfaceScale(), bounds);
+            lightBitmap<SpecularLightingType, SkSpotLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
             break;
     }
     offset->fX += bounds.left();
@@ -975,10 +1012,10 @@
 }
 
 #if SK_SUPPORT_GPU
-bool SkSpecularLightingImageFilter::asNewEffect(GrEffectRef** effect, GrTexture* texture, const SkIPoint& offset) const {
+bool SkSpecularLightingImageFilter::asNewEffect(GrEffectRef** effect, GrTexture* texture, const SkMatrix& matrix) const {
     if (effect) {
         SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
-        *effect = GrSpecularLightingEffect::Create(texture, light(), scale, offset, ks(), shininess());
+        *effect = GrSpecularLightingEffect::Create(texture, light(), scale, matrix, ks(), shininess());
     }
     return true;
 }
@@ -1087,11 +1124,11 @@
 GrLightingEffect::GrLightingEffect(GrTexture* texture,
                                    const SkLight* light,
                                    SkScalar surfaceScale,
-                                   const SkIPoint& offset)
+                                   const SkMatrix& matrix)
     : INHERITED(texture, MakeDivByTextureWHMatrix(texture))
     , fLight(light)
     , fSurfaceScale(surfaceScale)
-    , fOffset(offset) {
+    , fFilterMatrix(matrix) {
     fLight->ref();
     if (light->requiresFragmentPosition()) {
         this->setWillReadFragmentPosition();
@@ -1114,9 +1151,9 @@
 GrDiffuseLightingEffect::GrDiffuseLightingEffect(GrTexture* texture,
                                                  const SkLight* light,
                                                  SkScalar surfaceScale,
-                                                 const SkIPoint& offset,
+                                                 const SkMatrix& matrix,
                                                  SkScalar kd)
-    : INHERITED(texture, light, surfaceScale, offset), fKD(kd) {
+    : INHERITED(texture, light, surfaceScale, matrix), fKD(kd) {
 }
 
 const GrBackendEffectFactory& GrDiffuseLightingEffect::getFactory() const {
@@ -1138,9 +1175,12 @@
     SkScalar surfaceScale = random->nextSScalar1();
     SkScalar kd = random->nextUScalar1();
     SkAutoTUnref<SkLight> light(create_random_light(random));
-    SkIPoint offset = SkIPoint::Make(random->nextS(), random->nextS());
+    SkMatrix matrix;
+    for (int i = 0; i < 9; i++) {
+        matrix[i] = random->nextUScalar1();
+    }
     return GrDiffuseLightingEffect::Create(textures[GrEffectUnitTest::kAlphaTextureIdx],
-                                           light, surfaceScale, offset, kd);
+                                           light, surfaceScale, matrix, kd);
 }
 
 
@@ -1278,7 +1318,8 @@
     float ySign = texture->origin() == kTopLeft_GrSurfaceOrigin ? -1.0f : 1.0f;
     uman.set2f(fImageIncrementUni, 1.0f / texture->width(), ySign / texture->height());
     uman.set1f(fSurfaceScaleUni, lighting.surfaceScale());
-    fLight->setData(uman, lighting.light(), lighting.offset());
+    SkAutoTUnref<SkLight> transformedLight(lighting.light()->transform(lighting.filterMatrix()));
+    fLight->setData(uman, transformedLight);
     fEffectMatrix.setData(uman,
                           lighting.getMatrix(),
                           drawEffect,
@@ -1330,10 +1371,10 @@
 GrSpecularLightingEffect::GrSpecularLightingEffect(GrTexture* texture,
                                                    const SkLight* light,
                                                    SkScalar surfaceScale,
-                                                   const SkIPoint& offset,
+                                                   const SkMatrix& matrix,
                                                    SkScalar ks,
                                                    SkScalar shininess)
-    : INHERITED(texture, light, surfaceScale, offset),
+    : INHERITED(texture, light, surfaceScale, matrix),
       fKS(ks),
       fShininess(shininess) {
 }
@@ -1359,9 +1400,12 @@
     SkScalar ks = random->nextUScalar1();
     SkScalar shininess = random->nextUScalar1();
     SkAutoTUnref<SkLight> light(create_random_light(random));
-    SkIPoint offset = SkIPoint::Make(random->nextS(), random->nextS());
+    SkMatrix matrix;
+    for (int i = 0; i < 9; i++) {
+        matrix[i] = random->nextUScalar1();
+    }
     return GrSpecularLightingEffect::Create(textures[GrEffectUnitTest::kAlphaTextureIdx],
-                                            light, surfaceScale, offset, ks, shininess);
+                                            light, surfaceScale, matrix, ks, shininess);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -1419,17 +1463,15 @@
 }
 
 void GrGLLight::setData(const GrGLUniformManager& uman,
-                        const SkLight* light,
-                        const SkIPoint&) const {
+                        const SkLight* light) const {
     setUniformPoint3(uman, fColorUni, light->color() * SkScalarInvert(SkIntToScalar(255)));
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 
 void GrGLDistantLight::setData(const GrGLUniformManager& uman,
-                               const SkLight* light,
-                               const SkIPoint& offset) const {
-    INHERITED::setData(uman, light, offset);
+                               const SkLight* light) const {
+    INHERITED::setData(uman, light);
     SkASSERT(light->type() == SkLight::kDistant_LightType);
     const SkDistantLight* distantLight = static_cast<const SkDistantLight*>(light);
     setUniformNormal3(uman, fDirectionUni, distantLight->direction());
@@ -1445,15 +1487,11 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 void GrGLPointLight::setData(const GrGLUniformManager& uman,
-                             const SkLight* light,
-                             const SkIPoint& offset) const {
-    INHERITED::setData(uman, light, offset);
+                             const SkLight* light) const {
+    INHERITED::setData(uman, light);
     SkASSERT(light->type() == SkLight::kPoint_LightType);
     const SkPointLight* pointLight = static_cast<const SkPointLight*>(light);
-    SkPoint3 location = pointLight->location();
-    location.fX -= offset.fX;
-    location.fY -= offset.fY;
-    setUniformPoint3(uman, fLocationUni, location);
+    setUniformPoint3(uman, fLocationUni, pointLight->location());
 }
 
 void GrGLPointLight::emitSurfaceToLight(GrGLShaderBuilder* builder, const char* z) {
@@ -1466,15 +1504,11 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 void GrGLSpotLight::setData(const GrGLUniformManager& uman,
-                            const SkLight* light,
-                            const SkIPoint& offset) const {
-    INHERITED::setData(uman, light, offset);
+                            const SkLight* light) const {
+    INHERITED::setData(uman, light);
     SkASSERT(light->type() == SkLight::kSpot_LightType);
     const SkSpotLight* spotLight = static_cast<const SkSpotLight *>(light);
-    SkPoint3 location = spotLight->location();
-    location.fX -= offset.fX;
-    location.fY -= offset.fY;
-    setUniformPoint3(uman, fLocationUni, location);
+    setUniformPoint3(uman, fLocationUni, spotLight->location());
     uman.set1f(fExponentUni, spotLight->specularExponent());
     uman.set1f(fCosInnerConeAngleUni, spotLight->cosInnerConeAngle());
     uman.set1f(fCosOuterConeAngleUni, spotLight->cosOuterConeAngle());
diff --git a/effects/SkMagnifierImageFilter.cpp b/effects/SkMagnifierImageFilter.cpp
index a747620..aa91b1c 100644
--- a/effects/SkMagnifierImageFilter.cpp
+++ b/effects/SkMagnifierImageFilter.cpp
@@ -215,7 +215,7 @@
                                  SkIntToScalar(width), SkIntToScalar(height)),
                 inset));
     GrEffectRef* effect;
-    filter->asNewEffect(&effect, textures[0], SkIPoint::Make(0, 0));
+    filter->asNewEffect(&effect, textures[0], SkMatrix::I());
     SkASSERT(NULL != effect);
     return effect;
 }
@@ -261,7 +261,7 @@
 }
 
 #if SK_SUPPORT_GPU
-bool SkMagnifierImageFilter::asNewEffect(GrEffectRef** effect, GrTexture* texture, const SkIPoint&) const {
+bool SkMagnifierImageFilter::asNewEffect(GrEffectRef** effect, GrTexture* texture, const SkMatrix&) const {
     if (effect) {
         *effect = GrMagnifierEffect::Create(texture,
                                             fSrcRect.x() / texture->width(),
diff --git a/effects/SkMatrixConvolutionImageFilter.cpp b/effects/SkMatrixConvolutionImageFilter.cpp
index 1f60a49..37ca2fa 100644
--- a/effects/SkMatrixConvolutionImageFilter.cpp
+++ b/effects/SkMatrixConvolutionImageFilter.cpp
@@ -561,7 +561,7 @@
 
 bool SkMatrixConvolutionImageFilter::asNewEffect(GrEffectRef** effect,
                                                  GrTexture* texture,
-                                                 const SkIPoint&) const {
+                                                 const SkMatrix&) const {
     if (!effect) {
         return fKernelSize.width() * fKernelSize.height() <= MAX_KERNEL_SIZE;
     }
diff --git a/gpu/SkGpuDevice.cpp b/gpu/SkGpuDevice.cpp
index ccb8311..f77fdf7 100644
--- a/gpu/SkGpuDevice.cpp
+++ b/gpu/SkGpuDevice.cpp
@@ -1476,7 +1476,9 @@
     SkBitmap filteredBitmap;
 
     if (NULL != filter) {
-        if (filter_texture(this, fContext, texture, filter, w, h, SkMatrix::I(), &filteredBitmap,
+        SkMatrix matrix(*draw.fMatrix);
+        matrix.postTranslate(SkIntToScalar(-left), SkIntToScalar(-top));
+        if (filter_texture(this, fContext, texture, filter, w, h, matrix, &filteredBitmap,
                            &offset)) {
             texture = (GrTexture*) filteredBitmap.getTexture();
             w = filteredBitmap.width();
@@ -1563,7 +1565,9 @@
 
     if (NULL != filter) {
         SkIPoint offset = SkIPoint::Make(0, 0);
-        if (filter_texture(this, fContext, devTex, filter, w, h, SkMatrix::I(), &filteredBitmap,
+        SkMatrix matrix(*draw.fMatrix);
+        matrix.postTranslate(SkIntToScalar(-x), SkIntToScalar(-y));
+        if (filter_texture(this, fContext, devTex, filter, w, h, matrix, &filteredBitmap,
                            &offset)) {
             devTex = filteredBitmap.getTexture();
             w = filteredBitmap.width();