In image filters, apply the CTM and offset to the crop rect. This is necessary to...
authorsenorblanco@chromium.org <senorblanco@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>
Tue, 27 Aug 2013 21:37:01 +0000 (21:37 +0000)
committersenorblanco@chromium.org <senorblanco@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>
Tue, 27 Aug 2013 21:37:01 +0000 (21:37 +0000)
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@10961 2bbb7eff-a529-9590-31e7-b0007b416f81

12 files changed:
gm/lighting.cpp
include/core/SkImageFilter.h
include/effects/SkMagnifierImageFilter.h
include/effects/SkMatrixConvolutionImageFilter.h
src/core/SkCanvas.cpp
src/core/SkImageFilter.cpp
src/effects/SkBlurImageFilter.cpp
src/effects/SkColorFilterImageFilter.cpp
src/effects/SkLightingImageFilter.cpp
src/effects/SkMagnifierImageFilter.cpp
src/effects/SkMatrixConvolutionImageFilter.cpp
src/gpu/SkGpuDevice.cpp

index f16e781..330e0ee 100644 (file)
@@ -44,9 +44,10 @@ protected:
 
     void drawClippedBitmap(SkCanvas* canvas, const SkPaint& paint, int x, int y) {
         canvas->save();
-        canvas->clipRect(SkRect::MakeXYWH(SkIntToScalar(x), SkIntToScalar(y),
-            SkIntToScalar(fBitmap.width()), SkIntToScalar(fBitmap.height())));
-        canvas->drawBitmap(fBitmap, SkIntToScalar(x), SkIntToScalar(y), &paint);
+        canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
+        canvas->clipRect(SkRect::MakeWH(
+          SkIntToScalar(fBitmap.width()), SkIntToScalar(fBitmap.height())));
+        canvas->drawBitmap(fBitmap, 0, 0, &paint);
         canvas->restore();
     }
 
@@ -91,18 +92,24 @@ protected:
             const SkIRect* cr = (i == 0) ? NULL : &cropRect;
             paint.setImageFilter(SkLightingImageFilter::CreatePointLitDiffuse(pointLocation, white, surfaceScale, kd, NULL, cr))->unref();
             drawClippedBitmap(canvas, paint, 0, y);
+
             paint.setImageFilter(SkLightingImageFilter::CreateDistantLitDiffuse(distantDirection, white, surfaceScale, kd, NULL, cr))->unref();
             drawClippedBitmap(canvas, paint, 110, y);
+
             paint.setImageFilter(SkLightingImageFilter::CreateSpotLitDiffuse(spotLocation, spotTarget, spotExponent, cutoffAngle, white, surfaceScale, kd, NULL, cr))->unref();
             drawClippedBitmap(canvas, paint, 220, y);
 
             y += 110;
+
             paint.setImageFilter(SkLightingImageFilter::CreatePointLitSpecular(pointLocation, white, surfaceScale, ks, shininess, NULL, cr))->unref();
             drawClippedBitmap(canvas, paint, 0, y);
+
             paint.setImageFilter(SkLightingImageFilter::CreateDistantLitSpecular(distantDirection, white, surfaceScale, ks, shininess, NULL, cr))->unref();
             drawClippedBitmap(canvas, paint, 110, y);
+
             paint.setImageFilter(SkLightingImageFilter::CreateSpotLitSpecular(spotLocation, spotTarget, spotExponent, cutoffAngle, white, surfaceScale, ks, shininess, NULL, cr))->unref();
             drawClippedBitmap(canvas, paint, 220, y);
+
             y += 110;
         }
     }
index 01b3e0b..7b9dd32 100644 (file)
@@ -77,16 +77,18 @@ public:
      *  caller to unref it.
      *
      *  The effect can assume its vertexCoords space maps 1-to-1 with texels
-     *  in the texture.  "offset" is the delta between the source and
-     *  destination rect's origins, when cropped processing is being performed.
+     *  in the texture.  "matrix" is a transformation to apply to filter
+     *  parameters before they are used in the effect. Note that this function
+     *  will be called with (NULL, NULL, SkMatrix::I()) to query for support,
+     *  so returning "true" indicates support for all possible matrices.
      */
-    virtual bool asNewEffect(GrEffectRef** effect, GrTexture*, const SkIPoint& offset) const;
+    virtual bool asNewEffect(GrEffectRef** effect, GrTexture*, const SkMatrix& matrix) const;
 
     /**
      *  Returns true if the filter can be processed on the GPU.  This is most
      *  often used for multi-pass effects, where intermediate results must be
      *  rendered to textures.  For single-pass effects, use asNewEffect().
-     *  The default implementation returns asNewEffect(NULL, NULL).
+     *  The default implementation returns asNewEffect(NULL, NULL, SkMatrix::I()).
      */
     virtual bool canFilterImageGPU() const;
 
@@ -159,9 +161,10 @@ protected:
     // Default impl copies src into dst and returns true
     virtual bool onFilterBounds(const SkIRect&, const SkMatrix&, SkIRect*);
 
-    // Sets rect to the intersection of rect and the crop rect. If there
-    // is no overlap, returns false and leaves rect unchanged.
-    bool applyCropRect(SkIRect* rect) 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;
 
 private:
     typedef SkFlattenable INHERITED;
index b5cbd74..31b446f 100644 (file)
@@ -17,7 +17,7 @@ public:
     SkMagnifierImageFilter(SkRect srcRect, SkScalar inset);
 
 #if SK_SUPPORT_GPU
-    virtual bool asNewEffect(GrEffectRef** effect, GrTexture* texture, const SkIPoint& offset) const SK_OVERRIDE;
+    virtual bool asNewEffect(GrEffectRef** effect, GrTexture* texture, const SkMatrix& matrix) const SK_OVERRIDE;
 #endif
 
     SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkMagnifierImageFilter)
index 71c8938..b2602fe 100644 (file)
@@ -62,7 +62,7 @@ protected:
                                SkBitmap* result, SkIPoint* loc) SK_OVERRIDE;
 
 #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
 
 private:
index c59cd04..ff688f5 100644 (file)
@@ -999,7 +999,9 @@ void SkCanvas::internalDrawDevice(SkDevice* srcDev, int x, int y,
             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 @@ void SkCanvas::drawSprite(const SkBitmap& bitmap, int x, int y,
         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(),
index 222a029..502613b 100644 (file)
@@ -102,7 +102,7 @@ bool SkImageFilter::onFilterImage(Proxy*, const SkBitmap&, const SkMatrix&,
 }
 
 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 @@ bool SkImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, const SkMa
     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 @@ bool SkImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, const SkMa
     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 @@ bool SkImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, const SkMa
 #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 @@ bool SkImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
     return true;
 }
 
-bool SkImageFilter::asNewEffect(GrEffectRef**, GrTexture*, const SkIPoint& offset) const {
+bool SkImageFilter::asNewEffect(GrEffectRef**, GrTexture*, const SkMatrix&) const {
     return false;
 }
 
index 4b2d3b8..3f97ddd 100644 (file)
@@ -158,7 +158,7 @@ bool SkBlurImageFilter::onFilterImage(Proxy* proxy,
 
     SkIRect srcBounds, dstBounds;
     src.getBounds(&srcBounds);
-    if (!this->applyCropRect(&srcBounds)) {
+    if (!this->applyCropRect(&srcBounds, ctm)) {
         return false;
     }
 
@@ -216,7 +216,7 @@ bool SkBlurImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, const
     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(),
index 9c2c54e..16a36bb 100755 (executable)
@@ -107,7 +107,7 @@ bool SkColorFilterImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& sourc
 
     SkIRect bounds;
     src.getBounds(&bounds);
-    if (!this->applyCropRect(&bounds)) {
+    if (!this->applyCropRect(&bounds, matrix)) {
         return false;
     }
 
index ccb1dc5..e71df66 100644 (file)
@@ -265,7 +265,7 @@ public:
     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 @@ public:
     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 @@ private:
 
 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 @@ private:
     typedef GrSingleTextureEffect INHERITED;
     const SkLight* fLight;
     SkScalar fSurfaceScale;
-    SkIPoint fOffset;
+    SkMatrix fFilterMatrix;
 };
 
 class GrDiffuseLightingEffect : public GrLightingEffect {
@@ -337,12 +337,12 @@ public:
     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 @@ private:
     GrDiffuseLightingEffect(GrTexture* texture,
                             const SkLight* light,
                             SkScalar surfaceScale,
-                            const SkIPoint& offset,
+                            const SkMatrix& matrix,
                             SkScalar kd);
 
     GR_DECLARE_EFFECT_TEST;
@@ -373,13 +373,13 @@ public:
     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 @@ private:
     GrSpecularLightingEffect(GrTexture* texture,
                              const SkLight* light,
                              SkScalar surfaceScale,
-                             const SkIPoint& offset,
+                             const SkMatrix& matrix,
                              SkScalar ks,
                              SkScalar shininess);
 
@@ -434,8 +434,7 @@ public:
     // 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 @@ class GrGLDistantLight : public GrGLLight {
 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 @@ class GrGLPointLight : public GrGLLight {
 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 @@ class GrGLSpotLight : public GrGLLight {
 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 @@ public:
     }
     // 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 @@ public:
     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 @@ public:
         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 @@ protected:
     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 @@ public:
        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 @@ protected:
         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 @@ void SkDiffuseLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) con
 
 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 @@ bool SkDiffuseLightingImageFilter::onFilterImage(Proxy*,
 
     SkIRect bounds;
     src.getBounds(&bounds);
-    if (!this->applyCropRect(&bounds)) {
+    if (!this->applyCropRect(&bounds, ctm)) {
         return false;
     }
 
@@ -881,16 +915,18 @@ bool SkDiffuseLightingImageFilter::onFilterImage(Proxy*,
     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 @@ bool SkDiffuseLightingImageFilter::onFilterImage(Proxy*,
 }
 
 #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 @@ void SkSpecularLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) co
 
 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 @@ bool SkSpecularLightingImageFilter::onFilterImage(Proxy*,
 
     SkIRect bounds;
     src.getBounds(&bounds);
-    if (!this->applyCropRect(&bounds)) {
+    if (!this->applyCropRect(&bounds, ctm)) {
         return false;
     }
 
@@ -958,15 +994,16 @@ bool SkSpecularLightingImageFilter::onFilterImage(Proxy*,
     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 @@ bool SkSpecularLightingImageFilter::onFilterImage(Proxy*,
 }
 
 #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 @@ private:
 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 @@ bool GrLightingEffect::onIsEqual(const GrEffect& sBase) const {
 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 @@ GrEffectRef* GrDiffuseLightingEffect::TestCreate(SkMWCRandom* random,
     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 @@ void GrGLLightingEffect::setData(const GrGLUniformManager& uman,
     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 @@ void GrGLDiffuseLightingEffect::setData(const GrGLUniformManager& uman,
 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 @@ GrEffectRef* GrSpecularLightingEffect::TestCreate(SkMWCRandom* random,
     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::emitLightColor(GrGLShaderBuilder* builder,
 }
 
 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 GrGLDistantLight::emitSurfaceToLight(GrGLShaderBuilder* builder, const char
 ///////////////////////////////////////////////////////////////////////////////
 
 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 GrGLPointLight::emitSurfaceToLight(GrGLShaderBuilder* builder, const char*
 ///////////////////////////////////////////////////////////////////////////////
 
 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());
index a747620..aa91b1c 100644 (file)
@@ -215,7 +215,7 @@ GrEffectRef* GrMagnifierEffect::TestCreate(SkMWCRandom* random,
                                  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 @@ SkMagnifierImageFilter::SkMagnifierImageFilter(SkRect srcRect, SkScalar inset)
 }
 
 #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(),
index 1f60a49..37ca2fa 100644 (file)
@@ -561,7 +561,7 @@ GrEffectRef* GrMatrixConvolutionEffect::TestCreate(SkMWCRandom* random,
 
 bool SkMatrixConvolutionImageFilter::asNewEffect(GrEffectRef** effect,
                                                  GrTexture* texture,
-                                                 const SkIPoint&) const {
+                                                 const SkMatrix&) const {
     if (!effect) {
         return fKernelSize.width() * fKernelSize.height() <= MAX_KERNEL_SIZE;
     }
index ccb8311..f77fdf7 100644 (file)
@@ -1476,7 +1476,9 @@ void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
     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 @@ void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* device,
 
     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();