Make perlin noise do CTM-correct scaling.

When drawing perlin noise, generate noise at the resolution determined
by CTM, not by the resolution at construction time. This required moving
the generation of PaintingData to getContext() and asNewEffect() for the
raster and GPU paths, respectively.

It also required adjusting the matrices used during rendering
to be translate-only.

R=sugoi@chromium.org, bsalomon@google.com

Author: senorblanco@chromium.org

Review URL: https://codereview.chromium.org/358903002
diff --git a/expectations/gm/ignored-tests.txt b/expectations/gm/ignored-tests.txt
index c97a0b9..1adb12b 100644
--- a/expectations/gm/ignored-tests.txt
+++ b/expectations/gm/ignored-tests.txt
@@ -45,3 +45,9 @@
 blurquickreject
 blurrects
 bigblurs
+
+# senorblanco: 
+# Needs rebaselining after improved perlin noise scaling
+perlinnoise
+perlinnoise_localmatrix
+imagefiltersscaled
diff --git a/include/effects/SkPerlinNoiseShader.h b/include/effects/SkPerlinNoiseShader.h
index 96cad46..2d9dfdd 100644
--- a/include/effects/SkPerlinNoiseShader.h
+++ b/include/effects/SkPerlinNoiseShader.h
@@ -23,9 +23,9 @@
     http://www.w3.org/TR/SVG/filters.html#feTurbulenceElement
 */
 class SK_API SkPerlinNoiseShader : public SkShader {
-    struct PaintingData;
 public:
     struct StitchData;
+    struct PaintingData;
 
     /**
      *  About the noise types : the difference between the 2 is just minor tweaks to the algorithm,
@@ -77,7 +77,7 @@
     class PerlinNoiseShaderContext : public SkShader::Context {
     public:
         PerlinNoiseShaderContext(const SkPerlinNoiseShader& shader, const ContextRec&);
-        virtual ~PerlinNoiseShaderContext() {}
+        virtual ~PerlinNoiseShaderContext();
 
         virtual void shadeSpan(int x, int y, SkPMColor[], int count) SK_OVERRIDE;
         virtual void shadeSpan16(int x, int y, uint16_t[], int count) SK_OVERRIDE;
@@ -85,12 +85,13 @@
     private:
         SkPMColor shade(const SkPoint& point, StitchData& stitchData) const;
         SkScalar calculateTurbulenceValueForPoint(
-            int channel, const PaintingData& paintingData,
+            int channel,
             StitchData& stitchData, const SkPoint& point) const;
-        SkScalar noise2D(int channel, const PaintingData& paintingData,
+        SkScalar noise2D(int channel,
                          const StitchData& stitchData, const SkPoint& noiseVector) const;
 
         SkMatrix fMatrix;
+        PaintingData* fPaintingData;
 
         typedef SkShader::Context INHERITED;
     };
@@ -123,8 +124,6 @@
     /*const*/ SkISize                   fTileSize;
     /*const*/ bool                      fStitchTiles;
 
-    PaintingData* fPaintingData;
-
     typedef SkShader INHERITED;
 };
 
diff --git a/src/effects/SkPerlinNoiseShader.cpp b/src/effects/SkPerlinNoiseShader.cpp
index 84026b6..7f0127e 100644
--- a/src/effects/SkPerlinNoiseShader.cpp
+++ b/src/effects/SkPerlinNoiseShader.cpp
@@ -79,10 +79,19 @@
 
 struct SkPerlinNoiseShader::PaintingData {
     PaintingData(const SkISize& tileSize, SkScalar seed,
-                 SkScalar baseFrequencyX, SkScalar baseFrequencyY)
-      : fTileSize(tileSize)
-      , fBaseFrequency(SkPoint::Make(baseFrequencyX, baseFrequencyY))
+                 SkScalar baseFrequencyX, SkScalar baseFrequencyY,
+                 const SkMatrix& matrix)
     {
+        SkVector wavelength = SkVector::Make(SkScalarInvert(baseFrequencyX),
+                                             SkScalarInvert(baseFrequencyY));
+        matrix.mapVectors(&wavelength, 1);
+        fBaseFrequency.fX = SkScalarInvert(wavelength.fX);
+        fBaseFrequency.fY = SkScalarInvert(wavelength.fY);
+        SkVector sizeVec = SkVector::Make(SkIntToScalar(tileSize.fWidth),
+                                          SkIntToScalar(tileSize.fHeight));
+        matrix.mapVectors(&sizeVec, 1);
+        fTileSize.fWidth = SkScalarRoundToInt(sizeVec.fX);
+        fTileSize.fHeight = SkScalarRoundToInt(sizeVec.fY);
         this->init(seed);
         if (!fTileSize.isEmpty()) {
             this->stitch();
@@ -275,7 +284,6 @@
   , fStitchTiles(!fTileSize.isEmpty())
 {
     SkASSERT(numOctaves >= 0 && numOctaves < 256);
-    fPaintingData = SkNEW_ARGS(PaintingData, (fTileSize, fSeed, fBaseFrequencyX, fBaseFrequencyY));
 }
 
 SkPerlinNoiseShader::SkPerlinNoiseShader(SkReadBuffer& buffer)
@@ -289,15 +297,12 @@
     fStitchTiles    = buffer.readBool();
     fTileSize.fWidth  = buffer.readInt();
     fTileSize.fHeight = buffer.readInt();
-    fPaintingData = SkNEW_ARGS(PaintingData, (fTileSize, fSeed, fBaseFrequencyX, fBaseFrequencyY));
     buffer.validate(perlin_noise_type_is_valid(fType) &&
                     (fNumOctaves >= 0) && (fNumOctaves <= 255) &&
                     (fStitchTiles != fTileSize.isEmpty()));
 }
 
 SkPerlinNoiseShader::~SkPerlinNoiseShader() {
-    // Safety, should have been done in endContext()
-    SkDELETE(fPaintingData);
 }
 
 void SkPerlinNoiseShader::flatten(SkWriteBuffer& buffer) const {
@@ -313,8 +318,7 @@
 }
 
 SkScalar SkPerlinNoiseShader::PerlinNoiseShaderContext::noise2D(
-        int channel, const PaintingData& paintingData,
-        const StitchData& stitchData, const SkPoint& noiseVector) const {
+        int channel, const StitchData& stitchData, const SkPoint& noiseVector) const {
     struct Noise {
         int noisePositionIntegerValue;
         int nextNoisePositionIntegerValue;
@@ -347,9 +351,9 @@
     noiseX.nextNoisePositionIntegerValue &= kBlockMask;
     noiseY.nextNoisePositionIntegerValue &= kBlockMask;
     int i =
-        paintingData.fLatticeSelector[noiseX.noisePositionIntegerValue];
+        fPaintingData->fLatticeSelector[noiseX.noisePositionIntegerValue];
     int j =
-        paintingData.fLatticeSelector[noiseX.nextNoisePositionIntegerValue];
+        fPaintingData->fLatticeSelector[noiseX.nextNoisePositionIntegerValue];
     int b00 = (i + noiseY.noisePositionIntegerValue) & kBlockMask;
     int b10 = (j + noiseY.noisePositionIntegerValue) & kBlockMask;
     int b01 = (i + noiseY.nextNoisePositionIntegerValue) & kBlockMask;
@@ -359,32 +363,31 @@
     // This is taken 1:1 from SVG spec: http://www.w3.org/TR/SVG11/filters.html#feTurbulenceElement
     SkPoint fractionValue = SkPoint::Make(noiseX.noisePositionFractionValue,
                                           noiseY.noisePositionFractionValue); // Offset (0,0)
-    u = paintingData.fGradient[channel][b00].dot(fractionValue);
+    u = fPaintingData->fGradient[channel][b00].dot(fractionValue);
     fractionValue.fX -= SK_Scalar1; // Offset (-1,0)
-    v = paintingData.fGradient[channel][b10].dot(fractionValue);
+    v = fPaintingData->fGradient[channel][b10].dot(fractionValue);
     SkScalar a = SkScalarInterp(u, v, sx);
     fractionValue.fY -= SK_Scalar1; // Offset (-1,-1)
-    v = paintingData.fGradient[channel][b11].dot(fractionValue);
+    v = fPaintingData->fGradient[channel][b11].dot(fractionValue);
     fractionValue.fX = noiseX.noisePositionFractionValue; // Offset (0,-1)
-    u = paintingData.fGradient[channel][b01].dot(fractionValue);
+    u = fPaintingData->fGradient[channel][b01].dot(fractionValue);
     SkScalar b = SkScalarInterp(u, v, sx);
     return SkScalarInterp(a, b, sy);
 }
 
 SkScalar SkPerlinNoiseShader::PerlinNoiseShaderContext::calculateTurbulenceValueForPoint(
-        int channel, const PaintingData& paintingData,
-        StitchData& stitchData, const SkPoint& point) const {
+        int channel, StitchData& stitchData, const SkPoint& point) const {
     const SkPerlinNoiseShader& perlinNoiseShader = static_cast<const SkPerlinNoiseShader&>(fShader);
     if (perlinNoiseShader.fStitchTiles) {
         // Set up TurbulenceInitial stitch values.
-        stitchData = paintingData.fStitchDataInit;
+        stitchData = fPaintingData->fStitchDataInit;
     }
     SkScalar turbulenceFunctionResult = 0;
-    SkPoint noiseVector(SkPoint::Make(SkScalarMul(point.x(), paintingData.fBaseFrequency.fX),
-                                      SkScalarMul(point.y(), paintingData.fBaseFrequency.fY)));
+    SkPoint noiseVector(SkPoint::Make(SkScalarMul(point.x(), fPaintingData->fBaseFrequency.fX),
+                                      SkScalarMul(point.y(), fPaintingData->fBaseFrequency.fY)));
     SkScalar ratio = SK_Scalar1;
     for (int octave = 0; octave < perlinNoiseShader.fNumOctaves; ++octave) {
-        SkScalar noise = noise2D(channel, paintingData, stitchData, noiseVector);
+        SkScalar noise = noise2D(channel, stitchData, noiseVector);
         turbulenceFunctionResult += SkScalarDiv(
             (perlinNoiseShader.fType == kFractalNoise_Type) ? noise : SkScalarAbs(noise), ratio);
         noiseVector.fX *= 2;
@@ -417,7 +420,6 @@
 
 SkPMColor SkPerlinNoiseShader::PerlinNoiseShaderContext::shade(
         const SkPoint& point, StitchData& stitchData) const {
-    const SkPerlinNoiseShader& perlinNoiseShader = static_cast<const SkPerlinNoiseShader&>(fShader);
     SkPoint newPoint;
     fMatrix.mapPoints(&newPoint, &point, 1);
     newPoint.fX = SkScalarRoundToScalar(newPoint.fX);
@@ -426,8 +428,7 @@
     U8CPU rgba[4];
     for (int channel = 3; channel >= 0; --channel) {
         rgba[channel] = SkScalarFloorToInt(255 *
-            calculateTurbulenceValueForPoint(channel, *perlinNoiseShader.fPaintingData,
-                                             stitchData, newPoint));
+            calculateTurbulenceValueForPoint(channel, stitchData, newPoint));
     }
     return SkPreMultiplyARGB(rgba[3], rgba[0], rgba[1], rgba[2]);
 }
@@ -450,16 +451,14 @@
     if (rec.fLocalMatrix) {
         newMatrix.preConcat(*rec.fLocalMatrix);
     }
-    SkMatrix invMatrix;
-    if (!newMatrix.invert(&invMatrix)) {
-        invMatrix.reset();
-    }
     // This (1,1) translation is due to WebKit's 1 based coordinates for the noise
     // (as opposed to 0 based, usually). The same adjustment is in the setData() function.
-    newMatrix.postTranslate(SK_Scalar1, SK_Scalar1);
-    newMatrix.postConcat(invMatrix);
-    newMatrix.postConcat(invMatrix);
-    fMatrix = newMatrix;
+    fMatrix.setTranslate(-newMatrix.getTranslateX() + SK_Scalar1, -newMatrix.getTranslateY() + SK_Scalar1);
+    fPaintingData = SkNEW_ARGS(PaintingData, (shader.fTileSize, shader.fSeed, shader.fBaseFrequencyX, shader.fBaseFrequencyY, newMatrix));
+}
+
+SkPerlinNoiseShader::PerlinNoiseShaderContext::~PerlinNoiseShaderContext() {
+    SkDELETE(fPaintingData);
 }
 
 void SkPerlinNoiseShader::PerlinNoiseShaderContext::shadeSpan(
@@ -517,7 +516,6 @@
     int                                 fNumOctaves;
     GrGLUniformManager::UniformHandle   fBaseFrequencyUni;
     GrGLUniformManager::UniformHandle   fAlphaUni;
-    GrGLUniformManager::UniformHandle   fInvMatrixUni;
 
 private:
     typedef GrGLEffect INHERITED;
@@ -527,27 +525,29 @@
 
 class GrPerlinNoiseEffect : public GrEffect {
 public:
-    static GrEffectRef* Create(SkPerlinNoiseShader::Type type, const SkVector& baseFrequency,
+    static GrEffectRef* Create(SkPerlinNoiseShader::Type type,
                                int numOctaves, bool stitchTiles,
-                               const SkPerlinNoiseShader::StitchData& stitchData,
+                               SkPerlinNoiseShader::PaintingData* paintingData,
                                GrTexture* permutationsTexture, GrTexture* noiseTexture,
                                const SkMatrix& matrix, uint8_t alpha) {
-        AutoEffectUnref effect(SkNEW_ARGS(GrPerlinNoiseEffect, (type, baseFrequency, numOctaves,
-            stitchTiles, stitchData, permutationsTexture, noiseTexture, matrix, alpha)));
+        AutoEffectUnref effect(SkNEW_ARGS(GrPerlinNoiseEffect, (type, numOctaves,
+            stitchTiles, paintingData, permutationsTexture, noiseTexture, matrix, alpha)));
         return CreateEffectRef(effect);
     }
 
-    virtual ~GrPerlinNoiseEffect() { }
+    virtual ~GrPerlinNoiseEffect() {
+        SkDELETE(fPaintingData);
+    }
 
     static const char* Name() { return "PerlinNoise"; }
     virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
         return GrTBackendEffectFactory<GrPerlinNoiseEffect>::getInstance();
     }
-    const SkPerlinNoiseShader::StitchData& stitchData() const { return fStitchData; }
+    const SkPerlinNoiseShader::StitchData& stitchData() const { return fPaintingData->fStitchDataInit; }
 
     SkPerlinNoiseShader::Type type() const { return fType; }
     bool stitchTiles() const { return fStitchTiles; }
-    const SkVector& baseFrequency() const { return fBaseFrequency; }
+    const SkVector& baseFrequency() const { return fPaintingData->fBaseFrequency; }
     int numOctaves() const { return fNumOctaves; }
     const SkMatrix& matrix() const { return fCoordTransform.getMatrix(); }
     uint8_t alpha() const { return fAlpha; }
@@ -558,34 +558,31 @@
     virtual bool onIsEqual(const GrEffect& sBase) const SK_OVERRIDE {
         const GrPerlinNoiseEffect& s = CastEffect<GrPerlinNoiseEffect>(sBase);
         return fType == s.fType &&
-               fBaseFrequency == s.fBaseFrequency &&
+               fPaintingData->fBaseFrequency == s.fPaintingData->fBaseFrequency &&
                fNumOctaves == s.fNumOctaves &&
                fStitchTiles == s.fStitchTiles &&
                fCoordTransform.getMatrix() == s.fCoordTransform.getMatrix() &&
                fAlpha == s.fAlpha &&
                fPermutationsAccess.getTexture() == s.fPermutationsAccess.getTexture() &&
                fNoiseAccess.getTexture() == s.fNoiseAccess.getTexture() &&
-               fStitchData == s.fStitchData;
+               fPaintingData->fStitchDataInit == s.fPaintingData->fStitchDataInit;
     }
 
-    GrPerlinNoiseEffect(SkPerlinNoiseShader::Type type, const SkVector& baseFrequency,
+    GrPerlinNoiseEffect(SkPerlinNoiseShader::Type type,
                         int numOctaves, bool stitchTiles,
-                        const SkPerlinNoiseShader::StitchData& stitchData,
+                        SkPerlinNoiseShader::PaintingData* paintingData,
                         GrTexture* permutationsTexture, GrTexture* noiseTexture,
                         const SkMatrix& matrix, uint8_t alpha)
       : fType(type)
-      , fBaseFrequency(baseFrequency)
       , fNumOctaves(numOctaves)
       , fStitchTiles(stitchTiles)
       , fAlpha(alpha)
       , fPermutationsAccess(permutationsTexture)
       , fNoiseAccess(noiseTexture)
-      , fStitchData(stitchData) {
+      , fPaintingData(paintingData) {
         this->addTextureAccess(&fPermutationsAccess);
         this->addTextureAccess(&fNoiseAccess);
-        SkMatrix m = matrix;
-        m.postTranslate(SK_Scalar1, SK_Scalar1);
-        fCoordTransform.reset(kLocal_GrCoordSet, m);
+        fCoordTransform.reset(kLocal_GrCoordSet, matrix);
         this->addCoordTransform(&fCoordTransform);
         this->setWillNotUseInputColor();
     }
@@ -594,13 +591,12 @@
 
     SkPerlinNoiseShader::Type       fType;
     GrCoordTransform                fCoordTransform;
-    SkVector                        fBaseFrequency;
     int                             fNumOctaves;
     bool                            fStitchTiles;
     uint8_t                         fAlpha;
     GrTextureAccess                 fPermutationsAccess;
     GrTextureAccess                 fNoiseAccess;
-    SkPerlinNoiseShader::StitchData fStitchData;
+    SkPerlinNoiseShader::PaintingData *fPaintingData;
 
     void getConstantColorComponents(GrColor*, uint32_t* validFlags) const SK_OVERRIDE {
         *validFlags = 0; // This is noise. Nothing is constant.
@@ -660,9 +656,6 @@
 
     SkString vCoords = builder->ensureFSCoords2D(coords, 0);
 
-    fInvMatrixUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
-                                        kMat33f_GrSLType, "invMatrix");
-    const char* invMatrixUni = builder->getUniformCStr(fInvMatrixUni);
     fBaseFrequencyUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
                                             kVec2f_GrSLType, "baseFrequency");
     const char* baseFrequencyUni = builder->getUniformCStr(fBaseFrequencyUni);
@@ -841,8 +834,8 @@
     }
 
     // There are rounding errors if the floor operation is not performed here
-    builder->fsCodeAppendf("\n\t\tvec2 %s = floor((%s * vec3(%s, 1.0)).xy) * %s;",
-                           noiseVec, invMatrixUni, vCoords.c_str(), baseFrequencyUni);
+    builder->fsCodeAppendf("\n\t\tvec2 %s = floor(%s.xy) * %s;",
+                           noiseVec, vCoords.c_str(), baseFrequencyUni);
 
     // Clear the color accumulator
     builder->fsCodeAppendf("\n\t\t%s = vec4(0.0);", outputColor);
@@ -942,16 +935,6 @@
     uman.set2f(fBaseFrequencyUni, baseFrequency.fX, baseFrequency.fY);
     uman.set1f(fAlphaUni, SkScalarDiv(SkIntToScalar(turbulence.alpha()), SkIntToScalar(255)));
 
-    SkMatrix m = turbulence.matrix();
-    m.postTranslate(-SK_Scalar1, -SK_Scalar1);
-    SkMatrix invM;
-    if (!m.invert(&invM)) {
-        invM.reset();
-    } else {
-        invM.postConcat(invM); // Square the matrix
-    }
-    uman.setSkMatrix(fInvMatrixUni, invM);
-
     if (turbulence.stitchTiles()) {
         const SkPerlinNoiseShader::StitchData& stitchData = turbulence.stitchData();
         uman.set2f(fStitchDataUni, SkIntToScalar(stitchData.fWidth),
@@ -967,12 +950,15 @@
     SkASSERT(NULL != context);
     
     *grColor = SkColor2GrColorJustAlpha(paint.getColor());
-    
+
     SkMatrix localMatrix = this->getLocalMatrix();
     if (externalLocalMatrix) {
         localMatrix.preConcat(*externalLocalMatrix);
     }
 
+    SkMatrix matrix = context->getMatrix();
+    matrix.preConcat(localMatrix);
+
     if (0 == fNumOctaves) {
         SkColor clearColor = 0;
         if (kFractalNoise_Type == fType) {
@@ -987,18 +973,26 @@
     // Either we don't stitch tiles, either we have a valid tile size
     SkASSERT(!fStitchTiles || !fTileSize.isEmpty());
 
+    SkPerlinNoiseShader::PaintingData* paintingData = SkNEW_ARGS(PaintingData, (fTileSize, fSeed, fBaseFrequencyX, fBaseFrequencyY, matrix));
     GrTexture* permutationsTexture = GrLockAndRefCachedBitmapTexture(
-        context, fPaintingData->getPermutationsBitmap(), NULL);
+        context, paintingData->getPermutationsBitmap(), NULL);
     GrTexture* noiseTexture = GrLockAndRefCachedBitmapTexture(
-        context, fPaintingData->getNoiseBitmap(), NULL);
+        context, paintingData->getNoiseBitmap(), NULL);
 
-    *grEffect = (NULL != permutationsTexture) && (NULL != noiseTexture) ?
-        GrPerlinNoiseEffect::Create(fType, fPaintingData->fBaseFrequency,
-                                    fNumOctaves, fStitchTiles,
-                                    fPaintingData->fStitchDataInit,
-                                    permutationsTexture, noiseTexture,
-                                    localMatrix, paint.getAlpha()) :
-        NULL;
+    SkMatrix m = context->getMatrix();
+    m.setTranslateX(-localMatrix.getTranslateX() + SK_Scalar1);
+    m.setTranslateY(-localMatrix.getTranslateY() + SK_Scalar1);
+    if ((NULL != permutationsTexture) && (NULL != noiseTexture)) {
+        *grEffect = GrPerlinNoiseEffect::Create(fType,
+                                                fNumOctaves,
+                                                fStitchTiles,
+                                                paintingData,
+                                                permutationsTexture, noiseTexture,
+                                                m, paint.getAlpha());
+    } else {
+        SkDELETE(paintingData);
+        *grEffect = NULL;
+    }
 
     // Unlock immediately, this is not great, but we don't have a way of
     // knowing when else to unlock it currently. TODO: Remove this when