remove localmatrix from GrGeometryProcessor base class

BUG=skia:

Review URL: https://codereview.chromium.org/1131513005
diff --git a/src/gpu/GrAAConvexPathRenderer.cpp b/src/gpu/GrAAConvexPathRenderer.cpp
index b0e0cda..0d909b1 100644
--- a/src/gpu/GrAAConvexPathRenderer.cpp
+++ b/src/gpu/GrAAConvexPathRenderer.cpp
@@ -536,6 +536,7 @@
     const Attribute* inPosition() const { return fInPosition; }
     const Attribute* inQuadEdge() const { return fInQuadEdge; }
     GrColor color() const { return fColor; }
+    const SkMatrix& localMatrix() const { return fLocalMatrix; }
 
     class GLProcessor : public GrGLGeometryProcessor {
     public:
@@ -598,8 +599,9 @@
                                   const GrGLSLCaps&,
                                   GrProcessorKeyBuilder* b) {
             const BatchTracker& local = bt.cast<BatchTracker>();
+            const QuadEdgeEffect& qee = gp.cast<QuadEdgeEffect>();
             uint32_t key = local.fInputColorType << 16;
-            key |= local.fUsesLocalCoords && gp.localMatrix().hasPerspective() ? 0x1 : 0x0;
+            key |= local.fUsesLocalCoords && qee.localMatrix().hasPerspective() ? 0x1 : 0x0;
             b->add32(key);
         }
 
@@ -615,6 +617,13 @@
             }
         }
 
+        void setTransformData(const GrPrimitiveProcessor& primProc,
+                              const GrGLProgramDataManager& pdman,
+                              int index,
+                              const SkTArray<const GrCoordTransform*, true>& transforms) override {
+            this->setTransformDataHelper<QuadEdgeEffect>(primProc, pdman, index, transforms);
+        }
+
     private:
         GrColor fColor;
         UniformHandle fColorUniform;
@@ -641,8 +650,8 @@
 
 private:
     QuadEdgeEffect(GrColor color, const SkMatrix& localMatrix)
-        : INHERITED(localMatrix)
-        , fColor(color) {
+        : fColor(color)
+        , fLocalMatrix(localMatrix) {
         this->initClassID<QuadEdgeEffect>();
         fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType));
         fInQuadEdge = &this->addVertexAttrib(Attribute("inQuadEdge", kVec4f_GrVertexAttribType));
@@ -657,6 +666,7 @@
     const Attribute* fInPosition;
     const Attribute* fInQuadEdge;
     GrColor          fColor;
+    SkMatrix         fLocalMatrix;
 
     GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
 
diff --git a/src/gpu/GrDefaultGeoProcFactory.cpp b/src/gpu/GrDefaultGeoProcFactory.cpp
index 4ceeca9..6dbf71e 100644
--- a/src/gpu/GrDefaultGeoProcFactory.cpp
+++ b/src/gpu/GrDefaultGeoProcFactory.cpp
@@ -40,6 +40,7 @@
     const Attribute* inCoverage() const { return fInCoverage; }
     GrColor color() const { return fColor; }
     const SkMatrix& viewMatrix() const { return fViewMatrix; }
+    const SkMatrix& localMatrix() const { return fLocalMatrix; }
     uint8_t coverage() const { return fCoverage; }
 
     void initBatchTracker(GrBatchTracker* bt, const GrPipelineInfo& init) const override {
@@ -121,7 +122,7 @@
             const BatchTracker& local = bt.cast<BatchTracker>();
             uint32_t key = def.fFlags;
             key |= local.fInputColorType << 8 | local.fInputCoverageType << 16;
-            key |= local.fUsesLocalCoords && gp.localMatrix().hasPerspective() ? 0x1 << 24 : 0x0;
+            key |= local.fUsesLocalCoords && def.localMatrix().hasPerspective() ? 0x1 << 24 : 0x0;
             key |= ComputePosKey(def.viewMatrix()) << 25;
             b->add32(key);
         }
@@ -145,6 +146,13 @@
             }
         }
 
+        void setTransformData(const GrPrimitiveProcessor& primProc,
+                              const GrGLProgramDataManager& pdman,
+                              int index,
+                              const SkTArray<const GrCoordTransform*, true>& transforms) override {
+            this->setTransformDataHelper<DefaultGeoProc>(primProc, pdman, index, transforms);
+        }
+
     private:
         GrColor fColor;
         uint8_t fCoverage;
@@ -171,13 +179,13 @@
                    const SkMatrix& viewMatrix,
                    const SkMatrix& localMatrix,
                    uint8_t coverage)
-        : INHERITED(localMatrix)
-        , fInPosition(NULL)
+        : fInPosition(NULL)
         , fInColor(NULL)
         , fInLocalCoords(NULL)
         , fInCoverage(NULL)
         , fColor(color)
         , fViewMatrix(viewMatrix)
+        , fLocalMatrix(localMatrix)
         , fCoverage(coverage)
         , fFlags(gpTypeFlags) {
         this->initClassID<DefaultGeoProc>();
@@ -213,6 +221,7 @@
     const Attribute* fInCoverage;
     GrColor fColor;
     SkMatrix fViewMatrix;
+    SkMatrix fLocalMatrix;
     uint8_t fCoverage;
     uint32_t fFlags;
 
diff --git a/src/gpu/GrGeometryProcessor.h b/src/gpu/GrGeometryProcessor.h
index 4458a32..eee286b 100644
--- a/src/gpu/GrGeometryProcessor.h
+++ b/src/gpu/GrGeometryProcessor.h
@@ -19,8 +19,8 @@
  */
 class GrGeometryProcessor : public GrPrimitiveProcessor {
 public:
-    GrGeometryProcessor(const SkMatrix& localMatrix = SkMatrix::I())
-        : INHERITED(localMatrix, false)
+    GrGeometryProcessor()
+        : INHERITED(false)
         , fWillUseGeoShader(false)
         , fHasLocalCoords(false) {}
 
diff --git a/src/gpu/GrOvalRenderer.cpp b/src/gpu/GrOvalRenderer.cpp
index 909db5d..0a7b3f8 100644
--- a/src/gpu/GrOvalRenderer.cpp
+++ b/src/gpu/GrOvalRenderer.cpp
@@ -78,6 +78,7 @@
     const Attribute* inPosition() const { return fInPosition; }
     const Attribute* inCircleEdge() const { return fInCircleEdge; }
     GrColor color() const { return fColor; }
+    const SkMatrix& localMatrix() const { return fLocalMatrix; }
     virtual ~CircleEdgeEffect() {}
 
     const char* name() const override { return "CircleEdge"; }
@@ -131,9 +132,9 @@
                            const GrGLSLCaps&,
                            GrProcessorKeyBuilder* b) {
             const BatchTracker& local = bt.cast<BatchTracker>();
-            const CircleEdgeEffect& circleEffect = gp.cast<CircleEdgeEffect>();
-            uint16_t key = circleEffect.isStroked() ? 0x1 : 0x0;
-            key |= local.fUsesLocalCoords && gp.localMatrix().hasPerspective() ? 0x2 : 0x0;
+            const CircleEdgeEffect& ce = gp.cast<CircleEdgeEffect>();
+            uint16_t key = ce.isStroked() ? 0x1 : 0x0;
+            key |= local.fUsesLocalCoords && ce.localMatrix().hasPerspective() ? 0x2 : 0x0;
             b->add32(key << 16 | local.fInputColorType);
         }
 
@@ -149,6 +150,13 @@
             }
         }
 
+        void setTransformData(const GrPrimitiveProcessor& primProc,
+                              const GrGLProgramDataManager& pdman,
+                              int index,
+                              const SkTArray<const GrCoordTransform*, true>& transforms) override {
+            this->setTransformDataHelper<CircleEdgeEffect>(primProc, pdman, index, transforms);
+        }
+
     private:
         GrColor fColor;
         UniformHandle fColorUniform;
@@ -174,8 +182,8 @@
 
 private:
     CircleEdgeEffect(GrColor color, bool stroke, const SkMatrix& localMatrix)
-        : INHERITED(localMatrix)
-        , fColor(color) {
+        : fColor(color)
+        , fLocalMatrix(localMatrix) {
         this->initClassID<CircleEdgeEffect>();
         fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType));
         fInCircleEdge = &this->addVertexAttrib(Attribute("inCircleEdge",
@@ -190,6 +198,7 @@
     };
 
     GrColor fColor;
+    SkMatrix fLocalMatrix;
     const Attribute* fInPosition;
     const Attribute* fInCircleEdge;
     bool fStroke;
@@ -234,6 +243,7 @@
     const Attribute* inEllipseOffset() const { return fInEllipseOffset; }
     const Attribute* inEllipseRadii() const { return fInEllipseRadii; }
     GrColor color() const { return fColor; }
+    const SkMatrix& localMatrix() const { return fLocalMatrix; }
 
     inline bool isStroked() const { return fStroke; }
 
@@ -305,9 +315,9 @@
                            const GrGLSLCaps&,
                            GrProcessorKeyBuilder* b) {
             const BatchTracker& local = bt.cast<BatchTracker>();
-            const EllipseEdgeEffect& ellipseEffect = gp.cast<EllipseEdgeEffect>();
-            uint16_t key = ellipseEffect.isStroked() ? 0x1 : 0x0;
-            key |= local.fUsesLocalCoords && gp.localMatrix().hasPerspective() ? 0x2 : 0x0;
+            const EllipseEdgeEffect& ee = gp.cast<EllipseEdgeEffect>();
+            uint16_t key = ee.isStroked() ? 0x1 : 0x0;
+            key |= local.fUsesLocalCoords && ee.localMatrix().hasPerspective() ? 0x2 : 0x0;
             b->add32(key << 16 | local.fInputColorType);
         }
 
@@ -324,6 +334,13 @@
             }
         }
 
+        void setTransformData(const GrPrimitiveProcessor& primProc,
+                              const GrGLProgramDataManager& pdman,
+                              int index,
+                              const SkTArray<const GrCoordTransform*, true>& transforms) override {
+            this->setTransformDataHelper<EllipseEdgeEffect>(primProc, pdman, index, transforms);
+        }
+
     private:
         GrColor fColor;
         UniformHandle fColorUniform;
@@ -350,8 +367,8 @@
 
 private:
     EllipseEdgeEffect(GrColor color, bool stroke, const SkMatrix& localMatrix)
-        : INHERITED(localMatrix)
-        , fColor(color) {
+        : fColor(color)
+        , fLocalMatrix(localMatrix) {
         this->initClassID<EllipseEdgeEffect>();
         fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType));
         fInEllipseOffset = &this->addVertexAttrib(Attribute("inEllipseOffset",
@@ -371,6 +388,7 @@
     const Attribute* fInEllipseOffset;
     const Attribute* fInEllipseRadii;
     GrColor fColor;
+    SkMatrix fLocalMatrix;
     bool fStroke;
 
     GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
@@ -454,7 +472,7 @@
 
             // emit transforms
             this->emitTransforms(args.fPB, gpArgs->fPositionVar, ee.inPosition()->fName,
-                                 ee.localMatrix(), args.fTransformsIn, args.fTransformsOut);
+                                 args.fTransformsIn, args.fTransformsOut);
 
             GrGLFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
             SkAssertResult(fsBuilder->enableFeature(
@@ -504,7 +522,6 @@
             const BatchTracker& local = bt.cast<BatchTracker>();
             const DIEllipseEdgeEffect& ellipseEffect = gp.cast<DIEllipseEdgeEffect>();
             uint16_t key = ellipseEffect.getMode();
-            key |= local.fUsesLocalCoords && gp.localMatrix().hasPerspective() ? 0x1 << 8 : 0x0;
             key |= ComputePosKey(ellipseEffect.viewMatrix()) << 9;
             b->add32(key << 16 | local.fInputColorType);
         }
diff --git a/src/gpu/GrPathProcessor.cpp b/src/gpu/GrPathProcessor.cpp
index a6d1e27..5c07a8b 100644
--- a/src/gpu/GrPathProcessor.cpp
+++ b/src/gpu/GrPathProcessor.cpp
@@ -13,9 +13,10 @@
 GrPathProcessor::GrPathProcessor(GrColor color,
                                  const SkMatrix& viewMatrix,
                                  const SkMatrix& localMatrix)
-    : INHERITED(localMatrix, true)
+    : INHERITED(true)
+    , fColor(color)
     , fViewMatrix(viewMatrix)
-    , fColor(color) {
+    , fLocalMatrix(localMatrix) {
     this->initClassID<GrPathProcessor>();
 }
 
diff --git a/src/gpu/GrPathProcessor.h b/src/gpu/GrPathProcessor.h
index 39b0b7a..e34d0ce 100644
--- a/src/gpu/GrPathProcessor.h
+++ b/src/gpu/GrPathProcessor.h
@@ -37,8 +37,10 @@
 
     const char* name() const override { return "PathProcessor"; }
 
-    const SkMatrix& viewMatrix() const { return fViewMatrix; }
     GrColor color() const { return fColor; }
+    const SkMatrix& viewMatrix() const { return fViewMatrix; }
+    const SkMatrix& localMatrix() const { return fLocalMatrix; }
+
 
     void getInvariantOutputColor(GrInitInvariantOutput* out) const override;
     void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override;
@@ -54,10 +56,44 @@
 
 private:
     GrPathProcessor(GrColor color, const SkMatrix& viewMatrix, const SkMatrix& localMatrix);
+
+    /*
+     * CanCombineOutput will return true if two draws are 'batchable' from a color perspective.
+     * TODO is this really necessary?
+     */
+    static bool CanCombineOutput(GrGPInput left, GrColor lColor, GrGPInput right, GrColor rColor) {
+        if (left != right) {
+            return false;
+        }
+
+        if (kUniform_GrGPInput == left && lColor != rColor) {
+            return false;
+        }
+
+        return true;
+    }
+
+    static bool CanCombineLocalMatrices(const GrPrimitiveProcessor& l,
+                                        bool leftUsesLocalCoords,
+                                        const GrPrimitiveProcessor& r,
+                                        bool rightUsesLocalCoords) {
+        if (leftUsesLocalCoords != rightUsesLocalCoords) {
+            return false;
+        }
+
+        const GrPathProcessor& left = l.cast<GrPathProcessor>();
+        const GrPathProcessor& right = r.cast<GrPathProcessor>();
+        if (leftUsesLocalCoords && !left.localMatrix().cheapEqualTo(right.localMatrix())) {
+            return false;
+        }
+        return true;
+    }
+
     bool hasExplicitLocalCoords() const override { return false; }
 
-    const SkMatrix fViewMatrix;
     GrColor fColor;
+    const SkMatrix fViewMatrix;
+    const SkMatrix fLocalMatrix;
 
     typedef GrPrimitiveProcessor INHERITED;
 };
diff --git a/src/gpu/GrPrimitiveProcessor.h b/src/gpu/GrPrimitiveProcessor.h
index 8d94525..2e25bdb 100644
--- a/src/gpu/GrPrimitiveProcessor.h
+++ b/src/gpu/GrPrimitiveProcessor.h
@@ -102,10 +102,6 @@
  */
 class GrPrimitiveProcessor : public GrProcessor {
 public:
-    // TODO let the PrimProc itself set this in its setData call, this should really live on the
-    // bundle of primitive data
-    const SkMatrix& localMatrix() const { return fLocalMatrix; }
-
     virtual void initBatchTracker(GrBatchTracker*, const GrPipelineInfo&) const = 0;
 
     virtual bool canMakeEqual(const GrBatchTracker& mine,
@@ -173,42 +169,11 @@
     bool isPathRendering() const { return fIsPathRendering; }
 
 protected:
-    GrPrimitiveProcessor(const SkMatrix& localMatrix, bool isPathRendering)
+    GrPrimitiveProcessor(bool isPathRendering)
         : fNumAttribs(0)
         , fVertexStride(0)
-        , fLocalMatrix(localMatrix)
         , fIsPathRendering(isPathRendering) {}
 
-    /*
-     * CanCombineOutput will return true if two draws are 'batchable' from a color perspective.
-     * TODO remove this when GPs can upgrade to attribute color
-     */
-    static bool CanCombineOutput(GrGPInput left, GrColor lColor, GrGPInput right, GrColor rColor) {
-        if (left != right) {
-            return false;
-        }
-
-        if (kUniform_GrGPInput == left && lColor != rColor) {
-            return false;
-        }
-
-        return true;
-    }
-
-    static bool CanCombineLocalMatrices(const GrPrimitiveProcessor& left,
-                                        bool leftUsesLocalCoords,
-                                        const GrPrimitiveProcessor& right,
-                                        bool rightUsesLocalCoords) {
-        if (leftUsesLocalCoords != rightUsesLocalCoords) {
-            return false;
-        }
-
-        if (leftUsesLocalCoords && !left.localMatrix().cheapEqualTo(right.localMatrix())) {
-            return false;
-        }
-        return true;
-    }
-
     Attribute fAttribs[kMaxVertexAttribs];
     int fNumAttribs;
     size_t fVertexStride;
@@ -216,7 +181,6 @@
 private:
     virtual bool hasExplicitLocalCoords() const = 0;
 
-    SkMatrix fLocalMatrix;
     bool fIsPathRendering;
 
     typedef GrProcessor INHERITED;
diff --git a/src/gpu/effects/GrBezierEffect.cpp b/src/gpu/effects/GrBezierEffect.cpp
index 7948e94..a09d6ce 100644
--- a/src/gpu/effects/GrBezierEffect.cpp
+++ b/src/gpu/effects/GrBezierEffect.cpp
@@ -50,6 +50,13 @@
         }
     }
 
+    void setTransformData(const GrPrimitiveProcessor& primProc,
+                          const GrGLProgramDataManager& pdman,
+                          int index,
+                          const SkTArray<const GrCoordTransform*, true>& transforms) override {
+        this->setTransformDataHelper<GrConicEffect>(primProc, pdman, index, transforms);
+    }
+
 private:
     GrColor fColor;
     uint8_t fCoverageScale;
@@ -170,7 +177,7 @@
     uint32_t key = ce.isAntiAliased() ? (ce.isFilled() ? 0x0 : 0x1) : 0x2;
     key |= kUniform_GrGPInput == local.fInputColorType ? 0x4 : 0x0;
     key |= 0xff != local.fCoverageScale ? 0x8 : 0x0;
-    key |= local.fUsesLocalCoords && gp.localMatrix().hasPerspective() ? 0x10 : 0x0;
+    key |= local.fUsesLocalCoords && ce.localMatrix().hasPerspective() ? 0x10 : 0x0;
     key |= ComputePosKey(ce.viewMatrix()) << 5;
     b->add32(key);
 }
@@ -192,9 +199,9 @@
 
 GrConicEffect::GrConicEffect(GrColor color, const SkMatrix& viewMatrix, uint8_t coverage,
                              GrPrimitiveEdgeType edgeType, const SkMatrix& localMatrix)
-    : INHERITED(localMatrix)
-    , fColor(color)
+    : fColor(color)
     , fViewMatrix(viewMatrix)
+    , fLocalMatrix(viewMatrix)
     , fCoverageScale(coverage)
     , fEdgeType(edgeType) {
     this->initClassID<GrConicEffect>();
@@ -271,6 +278,13 @@
         }
     }
 
+    void setTransformData(const GrPrimitiveProcessor& primProc,
+                          const GrGLProgramDataManager& pdman,
+                          int index,
+                          const SkTArray<const GrCoordTransform*, true>& transforms) override {
+        this->setTransformDataHelper<GrQuadEffect>(primProc, pdman, index, transforms);
+    }
+
 private:
     GrColor fColor;
     uint8_t fCoverageScale;
@@ -377,7 +391,7 @@
     uint32_t key = ce.isAntiAliased() ? (ce.isFilled() ? 0x0 : 0x1) : 0x2;
     key |= kUniform_GrGPInput == local.fInputColorType ? 0x4 : 0x0;
     key |= 0xff != local.fCoverageScale ? 0x8 : 0x0;
-    key |= local.fUsesLocalCoords && gp.localMatrix().hasPerspective() ? 0x10 : 0x0;
+    key |= local.fUsesLocalCoords && ce.localMatrix().hasPerspective() ? 0x10 : 0x0;
     key |= ComputePosKey(ce.viewMatrix()) << 5;
     b->add32(key);
 }
@@ -399,9 +413,9 @@
 
 GrQuadEffect::GrQuadEffect(GrColor color, const SkMatrix& viewMatrix, uint8_t coverage,
                            GrPrimitiveEdgeType edgeType, const SkMatrix& localMatrix)
-    : INHERITED(localMatrix)
-    , fColor(color)
+    : fColor(color)
     , fViewMatrix(viewMatrix)
+    , fLocalMatrix(localMatrix)
     , fCoverageScale(coverage)
     , fEdgeType(edgeType) {
     this->initClassID<GrQuadEffect>();
@@ -509,8 +523,8 @@
     this->setupPosition(args.fPB, gpArgs, gp.inPosition()->fName, gp.viewMatrix());
 
     // emit transforms with position
-    this->emitTransforms(args.fPB, gpArgs->fPositionVar, gp.inPosition()->fName, gp.localMatrix(),
-                         args.fTransformsIn, args.fTransformsOut);
+    this->emitTransforms(args.fPB, gpArgs->fPositionVar, gp.inPosition()->fName, args.fTransformsIn,
+                         args.fTransformsOut);
 
     GrGLFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
 
@@ -607,7 +621,6 @@
     const CubicBatchTracker& local = bt.cast<CubicBatchTracker>();
     uint32_t key = ce.isAntiAliased() ? (ce.isFilled() ? 0x0 : 0x1) : 0x2;
     key |= kUniform_GrGPInput == local.fInputColorType ? 0x4 : 0x8;
-    key |= local.fUsesLocalCoords && gp.localMatrix().hasPerspective() ? 0x10 : 0x0;
     key |= ComputePosKey(ce.viewMatrix()) << 5;
     b->add32(key);
 }
diff --git a/src/gpu/effects/GrBezierEffect.h b/src/gpu/effects/GrBezierEffect.h
index 0ceefb1..f1b22fa 100644
--- a/src/gpu/effects/GrBezierEffect.h
+++ b/src/gpu/effects/GrBezierEffect.h
@@ -99,6 +99,7 @@
     inline GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; }
     GrColor color() const { return fColor; }
     const SkMatrix& viewMatrix() const { return fViewMatrix; }
+    const SkMatrix& localMatrix() const { return fLocalMatrix; }
 
     virtual void getGLProcessorKey(const GrBatchTracker& bt,
                                    const GrGLSLCaps& caps,
@@ -115,6 +116,7 @@
 
     GrColor             fColor;
     SkMatrix            fViewMatrix;
+    SkMatrix            fLocalMatrix;
     uint8_t             fCoverageScale;
     GrPrimitiveEdgeType fEdgeType;
     const Attribute*    fInPosition;
@@ -179,6 +181,7 @@
     inline GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; }
     GrColor color() const { return fColor; }
     const SkMatrix& viewMatrix() const { return fViewMatrix; }
+    const SkMatrix& localMatrix() const { return fLocalMatrix; }
 
     virtual void getGLProcessorKey(const GrBatchTracker& bt,
                                    const GrGLSLCaps& caps,
@@ -195,6 +198,7 @@
 
     GrColor             fColor;
     SkMatrix            fViewMatrix;
+    SkMatrix            fLocalMatrix;
     uint8_t             fCoverageScale;
     GrPrimitiveEdgeType fEdgeType;
     const Attribute*    fInPosition;
diff --git a/src/gpu/effects/GrBitmapTextGeoProc.cpp b/src/gpu/effects/GrBitmapTextGeoProc.cpp
index edee861..a7261c0 100644
--- a/src/gpu/effects/GrBitmapTextGeoProc.cpp
+++ b/src/gpu/effects/GrBitmapTextGeoProc.cpp
@@ -88,6 +88,13 @@
         }
     }
 
+    void setTransformData(const GrPrimitiveProcessor& primProc,
+                          const GrGLProgramDataManager& pdman,
+                          int index,
+                          const SkTArray<const GrCoordTransform*, true>& transforms) override {
+        this->setTransformDataHelper<GrBitmapTextGeoProc>(primProc, pdman, index, transforms);
+    }
+
     static inline void GenKey(const GrGeometryProcessor& proc,
                               const GrBatchTracker& bt,
                               const GrGLSLCaps&,
@@ -99,7 +106,7 @@
         const GrBitmapTextGeoProc& gp = proc.cast<GrBitmapTextGeoProc>();
         uint32_t key = 0;
         key |= SkToBool(gp.inColor()) ? 0x1 : 0x0;
-        key |= local.fUsesLocalCoords && proc.localMatrix().hasPerspective() ? 0x2 : 0x0;
+        key |= local.fUsesLocalCoords && gp.localMatrix().hasPerspective() ? 0x2 : 0x0;
         key |= gp.maskFormat() == kARGB_GrMaskFormat ? 0x4 : 0x0;
         b->add32(local.fInputColorType << 16 | key);
     }
@@ -116,8 +123,8 @@
 GrBitmapTextGeoProc::GrBitmapTextGeoProc(GrColor color, GrTexture* texture,
                                          const GrTextureParams& params, GrMaskFormat format,
                                          const SkMatrix& localMatrix)
-    : INHERITED(localMatrix)
-    , fColor(color)
+    : fColor(color)
+    , fLocalMatrix(localMatrix)
     , fTextureAccess(texture, params)
     , fInColor(NULL)
     , fMaskFormat(format) {
diff --git a/src/gpu/effects/GrBitmapTextGeoProc.h b/src/gpu/effects/GrBitmapTextGeoProc.h
index dc4e1a8..837dcb6 100644
--- a/src/gpu/effects/GrBitmapTextGeoProc.h
+++ b/src/gpu/effects/GrBitmapTextGeoProc.h
@@ -36,6 +36,7 @@
     const Attribute* inTextureCoords() const { return fInTextureCoords; }
     GrMaskFormat maskFormat() const { return fMaskFormat; }
     GrColor color() const { return fColor; }
+    const SkMatrix& localMatrix() const { return fLocalMatrix; }
 
     virtual void getGLProcessorKey(const GrBatchTracker& bt,
                                    const GrGLSLCaps& caps,
@@ -51,6 +52,7 @@
                         GrMaskFormat format, const SkMatrix& localMatrix);
 
     GrColor          fColor;
+    SkMatrix         fLocalMatrix;
     GrTextureAccess  fTextureAccess;
     const Attribute* fInPosition;
     const Attribute* fInColor;
diff --git a/src/gpu/effects/GrDashingEffect.cpp b/src/gpu/effects/GrDashingEffect.cpp
index 8604755..05aa277 100644
--- a/src/gpu/effects/GrDashingEffect.cpp
+++ b/src/gpu/effects/GrDashingEffect.cpp
@@ -785,6 +785,8 @@
 
     GrColor color() const { return fColor; }
 
+    const SkMatrix& localMatrix() const { return fLocalMatrix; }
+
     virtual void getGLProcessorKey(const GrBatchTracker&,
                                    const GrGLSLCaps&,
                                    GrProcessorKeyBuilder* b) const override;
@@ -798,6 +800,7 @@
     DashingCircleEffect(GrColor, DashAAMode aaMode, const SkMatrix& localMatrix);
 
     GrColor             fColor;
+    SkMatrix            fLocalMatrix;
     DashAAMode          fAAMode;
     const Attribute*    fInPosition;
     const Attribute*    fInDashParams;
@@ -825,6 +828,13 @@
                          const GrPrimitiveProcessor&,
                          const GrBatchTracker&) override;
 
+    void setTransformData(const GrPrimitiveProcessor& primProc,
+                          const GrGLProgramDataManager& pdman,
+                          int index,
+                          const SkTArray<const GrCoordTransform*, true>& transforms) override {
+        this->setTransformDataHelper<DashingCircleEffect>(primProc, pdman, index, transforms);
+    }
+
 private:
     UniformHandle fParamUniform;
     UniformHandle fColorUniform;
@@ -910,7 +920,7 @@
     const DashingCircleBatchTracker& local = bt.cast<DashingCircleBatchTracker>();
     const DashingCircleEffect& dce = gp.cast<DashingCircleEffect>();
     uint32_t key = 0;
-    key |= local.fUsesLocalCoords && gp.localMatrix().hasPerspective() ? 0x1 : 0x0;
+    key |= local.fUsesLocalCoords && dce.localMatrix().hasPerspective() ? 0x1 : 0x0;
     key |= dce.aaMode() << 8;
     b->add32(key << 16 | local.fInputColorType);
 }
@@ -937,8 +947,8 @@
 DashingCircleEffect::DashingCircleEffect(GrColor color,
                                          DashAAMode aaMode,
                                          const SkMatrix& localMatrix)
-    : INHERITED(localMatrix)
-    , fColor(color)
+    : fColor(color)
+    , fLocalMatrix(localMatrix)
     , fAAMode(aaMode) {
     this->initClassID<DashingCircleEffect>();
     fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType));
@@ -1003,6 +1013,8 @@
 
     GrColor color() const { return fColor; }
 
+    const SkMatrix& localMatrix() const { return fLocalMatrix; }
+
     virtual void getGLProcessorKey(const GrBatchTracker& bt,
                                    const GrGLSLCaps& caps,
                                    GrProcessorKeyBuilder* b) const override;
@@ -1016,6 +1028,7 @@
     DashingLineEffect(GrColor, DashAAMode aaMode, const SkMatrix& localMatrix);
 
     GrColor             fColor;
+    SkMatrix            fLocalMatrix;
     DashAAMode          fAAMode;
     const Attribute*    fInPosition;
     const Attribute*    fInDashParams;
@@ -1043,6 +1056,13 @@
                          const GrPrimitiveProcessor&,
                          const GrBatchTracker&) override;
 
+    void setTransformData(const GrPrimitiveProcessor& primProc,
+                          const GrGLProgramDataManager& pdman,
+                          int index,
+                          const SkTArray<const GrCoordTransform*, true>& transforms) override {
+        this->setTransformDataHelper<DashingLineEffect>(primProc, pdman, index, transforms);
+    }
+
 private:
     GrColor       fColor;
     UniformHandle fColorUniform;
@@ -1140,7 +1160,7 @@
     const DashingLineBatchTracker& local = bt.cast<DashingLineBatchTracker>();
     const DashingLineEffect& de = gp.cast<DashingLineEffect>();
     uint32_t key = 0;
-    key |= local.fUsesLocalCoords && gp.localMatrix().hasPerspective() ? 0x1 : 0x0;
+    key |= local.fUsesLocalCoords && de.localMatrix().hasPerspective() ? 0x1 : 0x0;
     key |= de.aaMode() << 8;
     b->add32(key << 16 | local.fInputColorType);
 }
@@ -1167,8 +1187,8 @@
 DashingLineEffect::DashingLineEffect(GrColor color,
                                      DashAAMode aaMode,
                                      const SkMatrix& localMatrix)
-    : INHERITED(localMatrix)
-    , fColor(color)
+    : fColor(color)
+    , fLocalMatrix(localMatrix)
     , fAAMode(aaMode) {
     this->initClassID<DashingLineEffect>();
     fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType));
diff --git a/src/gpu/effects/GrDistanceFieldGeoProc.cpp b/src/gpu/effects/GrDistanceFieldGeoProc.cpp
index 35b0599..ba42bb4 100755
--- a/src/gpu/effects/GrDistanceFieldGeoProc.cpp
+++ b/src/gpu/effects/GrDistanceFieldGeoProc.cpp
@@ -68,9 +68,8 @@
         this->setupPosition(pb, gpArgs, dfTexEffect.inPosition()->fName, dfTexEffect.viewMatrix());
 
         // emit transforms
-        const SkMatrix& localMatrix = dfTexEffect.localMatrix();
         this->emitTransforms(args.fPB, gpArgs->fPositionVar, dfTexEffect.inPosition()->fName,
-                             localMatrix, args.fTransformsIn, args.fTransformsOut);
+                             args.fTransformsIn, args.fTransformsOut);
 
         // add varyings
         GrGLVertToFrag recipScale(kFloat_GrSLType);
@@ -172,7 +171,6 @@
         const DistanceFieldBatchTracker& local = bt.cast<DistanceFieldBatchTracker>();
         uint32_t key = dfTexEffect.getFlags();
         key |= local.fInputColorType << 16;
-        key |= local.fUsesLocalCoords && gp.localMatrix().hasPerspective() ? 0x1 << 24: 0x0;
         key |= ComputePosKey(dfTexEffect.viewMatrix()) << 25;
         b->add32(key);
     }
@@ -198,8 +196,7 @@
                                                            float distanceAdjust,
 #endif
                                                            uint32_t flags)
-    : INHERITED(SkMatrix::I())
-    , fColor(color)
+    : fColor(color)
     , fViewMatrix(viewMatrix)
     , fTextureAccess(texture, params)
 #ifdef SK_GAMMA_APPLY_TO_A8
@@ -312,7 +309,7 @@
 
         // emit transforms
         this->emitTransforms(args.fPB, gpArgs->fPositionVar, dfTexEffect.inPosition()->fName,
-                             dfTexEffect.localMatrix(), args.fTransformsIn, args.fTransformsOut);
+                             args.fTransformsIn, args.fTransformsOut);
 
         const char* textureSizeUniName = NULL;
         fTextureSizeUni = args.fPB->addUniform(GrGLProgramBuilder::kFragment_Visibility,
@@ -405,7 +402,6 @@
         const DistanceFieldPathBatchTracker& local = bt.cast<DistanceFieldPathBatchTracker>();
         uint32_t key = dfTexEffect.getFlags();
         key |= local.fInputColorType << 16;
-        key |= local.fUsesLocalCoords && gp.localMatrix().hasPerspective() ? 0x1 << 24: 0x0;
         key |= ComputePosKey(dfTexEffect.viewMatrix()) << 25;
         b->add32(key);
     }
@@ -427,8 +423,7 @@
         GrTexture* texture,
         const GrTextureParams& params,
         uint32_t flags)
-    : INHERITED(SkMatrix::I())
-    , fColor(color)
+    : fColor(color)
     , fViewMatrix(viewMatrix)
     , fTextureAccess(texture, params)
     , fFlags(flags & kNonLCD_DistanceFieldEffectMask)
@@ -526,9 +521,8 @@
         this->setupPosition(pb, gpArgs, dfTexEffect.inPosition()->fName, dfTexEffect.viewMatrix());
 
         // emit transforms
-        const SkMatrix& localMatrix = dfTexEffect.localMatrix();
         this->emitTransforms(args.fPB, gpArgs->fPositionVar, dfTexEffect.inPosition()->fName,
-                             localMatrix, args.fTransformsIn, args.fTransformsOut);
+                             args.fTransformsIn, args.fTransformsOut);
 
         // set up varyings
         bool isUniformScale = SkToBool(dfTexEffect.getFlags() & kUniformScale_DistanceFieldEffectMask);
@@ -676,7 +670,6 @@
         const DistanceFieldLCDBatchTracker& local = bt.cast<DistanceFieldLCDBatchTracker>();
         uint32_t key = dfTexEffect.getFlags();
         key |= local.fInputColorType << 16;
-        key |= local.fUsesLocalCoords && gp.localMatrix().hasPerspective() ? 0x1 << 24: 0x0;
         key |= ComputePosKey(dfTexEffect.viewMatrix()) << 25;
         b->add32(key);
     }
@@ -697,8 +690,7 @@
                                                   GrTexture* texture, const GrTextureParams& params,
                                                   DistanceAdjust distanceAdjust,
                                                   uint32_t flags)
-    : INHERITED(SkMatrix::I())
-    , fColor(color)
+    : fColor(color)
     , fViewMatrix(viewMatrix)
     , fTextureAccess(texture, params)
     , fDistanceAdjust(distanceAdjust)
diff --git a/src/gpu/gl/GrGLGeometryProcessor.cpp b/src/gpu/gl/GrGLGeometryProcessor.cpp
index 79bcb4c..60c0043 100644
--- a/src/gpu/gl/GrGLGeometryProcessor.cpp
+++ b/src/gpu/gl/GrGLGeometryProcessor.cpp
@@ -89,23 +89,6 @@
     }
 }
 
-void
-GrGLGeometryProcessor::setTransformData(const GrPrimitiveProcessor& primProc,
-                                        const GrGLProgramDataManager& pdman,
-                                        int index,
-                                        const SkTArray<const GrCoordTransform*, true>& transforms) {
-    SkSTArray<2, Transform, true>& procTransforms = fInstalledTransforms[index];
-    int numTransforms = transforms.count();
-    for (int t = 0; t < numTransforms; ++t) {
-        SkASSERT(procTransforms[t].fHandle.isValid());
-        const SkMatrix& transform = GetTransformMatrix(primProc.localMatrix(), *transforms[t]);
-        if (!procTransforms[t].fCurrentValue.cheapEqualTo(transform)) {
-            pdman.setSkMatrix(procTransforms[t].fHandle.convertToUniformHandle(), transform);
-            procTransforms[t].fCurrentValue = transform;
-        }
-    }
-}
-
 void GrGLGeometryProcessor::setupPosition(GrGLGPBuilder* pb,
                                           GrGPArgs* gpArgs,
                                           const char* posName,
diff --git a/src/gpu/gl/GrGLGeometryProcessor.h b/src/gpu/gl/GrGLGeometryProcessor.h
index 49ccb8b..dfb2b90 100644
--- a/src/gpu/gl/GrGLGeometryProcessor.h
+++ b/src/gpu/gl/GrGLGeometryProcessor.h
@@ -22,19 +22,32 @@
     /* Any general emit code goes in the base class emitCode.  Subclasses override onEmitCode */
     void emitCode(EmitArgs&) override;
 
-    void setTransformData(const GrPrimitiveProcessor&,
-                          const GrGLProgramDataManager&,
-                          int index,
-                          const SkTArray<const GrCoordTransform*, true>& transforms);
+    // By default we use the identity matrix
+    virtual void setTransformData(const GrPrimitiveProcessor&,
+                                  const GrGLProgramDataManager& pdman,
+                                  int index,
+                                  const SkTArray<const GrCoordTransform*, true>& transforms) {
+        this->setTransformDataMatrix(SkMatrix::I(), pdman, index, transforms);
+    }
+
+    // A helper which subclasses can use if needed
+    template <class GeometryProcessor>
+    void setTransformDataHelper(const GrPrimitiveProcessor& primProc,
+                                const GrGLProgramDataManager& pdman,
+                                int index,
+                                const SkTArray<const GrCoordTransform*, true>& transforms) {
+        const GeometryProcessor& gp = primProc.cast<GeometryProcessor>();
+        this->setTransformDataMatrix(gp.localMatrix(), pdman, index, transforms);
+    }
 
 protected:
-    // Many GrGeometryProcessors do not need explicit local coords
+    // A helper for subclasses which don't have an explicit local matrix
     void emitTransforms(GrGLGPBuilder* gp,
                         const GrShaderVar& posVar,
-                        const SkMatrix& localMatrix,
+                        const char* localCoords,
                         const TransformsIn& tin,
                         TransformsOut* tout) {
-        this->emitTransforms(gp, posVar, posVar.c_str(), localMatrix, tin, tout);
+        this->emitTransforms(gp, posVar, localCoords, SkMatrix::I(), tin, tout);
     }
 
     void emitTransforms(GrGLGPBuilder*,
@@ -67,6 +80,22 @@
     }
 
 private:
+    void setTransformDataMatrix(const SkMatrix& localMatrix,
+                                const GrGLProgramDataManager& pdman,
+                                int index,
+                                const SkTArray<const GrCoordTransform*, true>& transforms) {
+        SkSTArray<2, Transform, true>& procTransforms = fInstalledTransforms[index];
+        int numTransforms = transforms.count();
+        for (int t = 0; t < numTransforms; ++t) {
+            SkASSERT(procTransforms[t].fHandle.isValid());
+            const SkMatrix& transform = GetTransformMatrix(localMatrix, *transforms[t]);
+            if (!procTransforms[t].fCurrentValue.cheapEqualTo(transform)) {
+                pdman.setSkMatrix(procTransforms[t].fHandle.convertToUniformHandle(), transform);
+                procTransforms[t].fCurrentValue = transform;
+            }
+        }
+    }
+
     virtual void onEmitCode(EmitArgs&, GrGPArgs*) = 0;
 
     typedef GrGLPrimitiveProcessor INHERITED;
diff --git a/src/gpu/gl/GrGLPathProcessor.cpp b/src/gpu/gl/GrGLPathProcessor.cpp
index 9ce6682..e8c10a3 100644
--- a/src/gpu/gl/GrGLPathProcessor.cpp
+++ b/src/gpu/gl/GrGLPathProcessor.cpp
@@ -108,11 +108,12 @@
         const SkTArray<const GrCoordTransform*, true>& coordTransforms,
         GrGLPathRendering* glpr,
         GrGLuint programID) {
+    const GrPathProcessor& pathProc = primProc.cast<GrPathProcessor>();
     SkSTArray<2, Transform, true>& transforms = fInstalledTransforms[index];
     int numTransforms = transforms.count();
     for (int t = 0; t < numTransforms; ++t) {
         SkASSERT(transforms[t].fHandle.isValid());
-        const SkMatrix& transform = GetTransformMatrix(primProc.localMatrix(),
+        const SkMatrix& transform = GetTransformMatrix(pathProc.localMatrix(),
                                                        *coordTransforms[t]);
         if (transforms[t].fCurrentValue.cheapEqualTo(transform)) {
             continue;