Remove coordchanges from drawstate

BUG=skia:

Review URL: https://codereview.chromium.org/818233002
diff --git a/expectations/gm/ignored-tests.txt b/expectations/gm/ignored-tests.txt
index 8e60172..9b35ba4 100644
--- a/expectations/gm/ignored-tests.txt
+++ b/expectations/gm/ignored-tests.txt
@@ -33,6 +33,9 @@
 ## epoger will rebaseline by 25 Dec 2013
 #gradtext
 
+# joshualitt
+dashing3
+
 # robertphillips - skia:2995
 blurrects
 
@@ -44,4 +47,4 @@
 dashcubics
 
 #reed - gm updated, so just need to rebaseline
-c_gms
\ No newline at end of file
+c_gms
diff --git a/gm/beziereffects.cpp b/gm/beziereffects.cpp
index e7e63ea..b486404 100644
--- a/gm/beziereffects.cpp
+++ b/gm/beziereffects.cpp
@@ -250,7 +250,8 @@
                         continue;
                     }
                     GrPrimitiveEdgeType et = (GrPrimitiveEdgeType)edgeType;
-                    gp.reset(GrConicEffect::Create(0xff000000, et, *tt.target()->caps()));
+                    gp.reset(GrConicEffect::Create(0xff000000, et, *tt.target()->caps(),
+                                                   SkMatrix::I()));
                     if (!gp) {
                         continue;
                     }
@@ -439,7 +440,8 @@
                         continue;
                     }
                     GrPrimitiveEdgeType et = (GrPrimitiveEdgeType)edgeType;
-                    gp.reset(GrQuadEffect::Create(0xff000000, et, *tt.target()->caps()));
+                    gp.reset(GrQuadEffect::Create(0xff000000, et, *tt.target()->caps(),
+                                                  SkMatrix::I()));
                     if (!gp) {
                         continue;
                     }
diff --git a/src/gpu/GrAAConvexPathRenderer.cpp b/src/gpu/GrAAConvexPathRenderer.cpp
index 6d69823..3a344ce 100644
--- a/src/gpu/GrAAConvexPathRenderer.cpp
+++ b/src/gpu/GrAAConvexPathRenderer.cpp
@@ -505,8 +505,8 @@
 class QuadEdgeEffect : public GrGeometryProcessor {
 public:
 
-    static GrGeometryProcessor* Create(GrColor color) {
-        return SkNEW_ARGS(QuadEdgeEffect, (color));
+    static GrGeometryProcessor* Create(GrColor color, const SkMatrix& localMatrix) {
+        return SkNEW_ARGS(QuadEdgeEffect, (color, localMatrix));
     }
 
     virtual ~QuadEdgeEffect() {}
@@ -626,7 +626,8 @@
     }
 
 private:
-    QuadEdgeEffect(GrColor color) : INHERITED(color) {
+    QuadEdgeEffect(GrColor color, const SkMatrix& localMatrix)
+        : INHERITED(color, false, localMatrix) {
         this->initClassID<QuadEdgeEffect>();
         fInPosition = &this->addVertexAttrib(GrAttribute("inPosition", kVec2f_GrVertexAttribType));
         fInQuadEdge = &this->addVertexAttrib(GrAttribute("inQuadEdge", kVec4f_GrVertexAttribType));
@@ -661,7 +662,9 @@
                                                 const GrDrawTargetCaps& caps,
                                                 GrTexture*[]) {
     // Doesn't work without derivative instructions.
-    return caps.shaderDerivativeSupport() ? QuadEdgeEffect::Create(GrRandomColor(random)) : NULL;
+    return caps.shaderDerivativeSupport() ?
+           QuadEdgeEffect::Create(GrRandomColor(random),
+                                  GrProcessorUnitTest::TestMatrix(random)) : NULL;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -688,11 +691,13 @@
     }
 
     SkMatrix viewMatrix = drawState->getViewMatrix();
-    GrDrawState::AutoViewMatrixRestore avmr;
-    if (!avmr.setIdentity(drawState)) {
+    SkMatrix invert;
+    if (!viewMatrix.invert(&invert)) {
         return false;
     }
 
+    GrDrawState::AutoViewMatrixRestore avmr(drawState);
+
     // We use the fact that SkPath::transform path does subdivision based on
     // perspective. Otherwise, we apply the view matrix when copying to the
     // segment representation.
@@ -725,7 +730,7 @@
     // Our computed verts should all be within one pixel of the segment control points.
     devBounds.outset(SK_Scalar1, SK_Scalar1);
 
-    SkAutoTUnref<GrGeometryProcessor> quadProcessor(QuadEdgeEffect::Create(color));
+    SkAutoTUnref<GrGeometryProcessor> quadProcessor(QuadEdgeEffect::Create(color, invert));
 
     GrDrawTarget::AutoReleaseGeometry arg(target, vCount, quadProcessor->getVertexStride(), iCount);
     SkASSERT(quadProcessor->getVertexStride() == sizeof(QuadVertex));
diff --git a/src/gpu/GrAAHairLinePathRenderer.cpp b/src/gpu/GrAAHairLinePathRenderer.cpp
index 98e6965..319228e 100644
--- a/src/gpu/GrAAHairLinePathRenderer.cpp
+++ b/src/gpu/GrAAHairLinePathRenderer.cpp
@@ -832,18 +832,30 @@
     lineCnt = lines.count() / 2;
     conicCnt = conics.count() / 3;
 
+    // createGeom transforms the geometry to device space when the matrix does not have
+    // perspective.
+    GrDrawState::AutoViewMatrixRestore avmr;
+    SkMatrix invert = SkMatrix::I();
+    if (!drawState->getViewMatrix().hasPerspective()) {
+        avmr.setIdentity(drawState);
+        if (!drawState->getViewMatrix().invert(&invert)) {
+            return false;
+        }
+    }
+
     // do lines first
     if (lineCnt) {
         GrDrawTarget::AutoReleaseGeometry arg;
         SkRect devBounds;
 
+        GrDrawState::AutoRestoreEffects are(drawState);
         uint32_t gpFlags = GrDefaultGeoProcFactory::kPosition_GPType |
                            GrDefaultGeoProcFactory::kCoverage_GPType;
-        GrDrawState::AutoRestoreEffects are(drawState);
         SkAutoTUnref<const GrGeometryProcessor> gp(GrDefaultGeoProcFactory::Create(color,
                                                                                    gpFlags,
                                                                                    false,
-                                                                                   newCoverage));
+                                                                                   newCoverage,
+                                                                                   invert));
 
         if (!this->createLineGeom(target,
                                   drawState,
@@ -857,13 +869,6 @@
             return false;
         }
 
-        // createLineGeom transforms the geometry to device space when the matrix does not have
-        // perspective.
-        GrDrawState::AutoViewMatrixRestore avmr;
-        if (!drawState->getViewMatrix().hasPerspective() && !avmr.setIdentity(drawState)) {
-            return false;
-        }
-
         // Check devBounds
         SkASSERT(check_bounds<LineVertex>(drawState, devBounds, arg.vertices(),
                                           kLineSegNumVertices * lineCnt));
@@ -906,14 +911,6 @@
             return false;
         }
 
-        // createGeom transforms the geometry to device space when the matrix does not have
-        // perspective.
-        GrDrawState::AutoViewMatrixRestore avmr;
-        if (!drawState->getViewMatrix().hasPerspective() && !avmr.setIdentity(drawState)) {
-            return false;
-        }
-
-
         // Check devBounds
         SkASSERT(check_bounds<BezierVertex>(drawState, devBounds, arg.vertices(),
                                             kQuadNumVertices * quadCnt + kQuadNumVertices * conicCnt));
@@ -923,6 +920,7 @@
                     GrQuadEffect::Create(color,
                                          kHairlineAA_GrProcessorEdgeType,
                                          *target->caps(),
+                                         invert,
                                          newCoverage));
             SkASSERT(hairQuadProcessor);
             GrDrawState::AutoRestoreEffects are(drawState);
@@ -946,7 +944,7 @@
         if (conicCnt > 0) {
             SkAutoTUnref<GrGeometryProcessor> hairConicProcessor(
                     GrConicEffect::Create(color, kHairlineAA_GrProcessorEdgeType, *target->caps(),
-                                          newCoverage));
+                                          invert, newCoverage));
             SkASSERT(hairConicProcessor);
             GrDrawState::AutoRestoreEffects are(drawState);
             target->setIndexSourceToBuffer(fQuadsIndexBuffer);
diff --git a/src/gpu/GrAARectRenderer.cpp b/src/gpu/GrAARectRenderer.cpp
index 07e81ec..3f0e1b0 100644
--- a/src/gpu/GrAARectRenderer.cpp
+++ b/src/gpu/GrAARectRenderer.cpp
@@ -26,16 +26,18 @@
 }
 
 static const GrGeometryProcessor* create_rect_gp(const GrDrawState& drawState, GrColor color,
-                                                 CoverageAttribType* type) {
+                                                 CoverageAttribType* type,
+                                                 const SkMatrix& localMatrix) {
     uint32_t flags = GrDefaultGeoProcFactory::kColor_GPType;
     const GrGeometryProcessor* gp;
     if (drawState.canTweakAlphaForCoverage()) {
-        gp = GrDefaultGeoProcFactory::Create(color, flags);
+        gp = GrDefaultGeoProcFactory::Create(color, flags, localMatrix);
         SkASSERT(gp->getVertexStride() == sizeof(GrDefaultGeoProcFactory::PositionColorAttr));
         *type = kUseColor_CoverageAttribType;
     } else {
         flags |= GrDefaultGeoProcFactory::kCoverage_GPType;
-        gp = GrDefaultGeoProcFactory::Create(color, flags, GrColorIsOpaque(color));
+        gp = GrDefaultGeoProcFactory::Create(color, flags, GrColorIsOpaque(color), 0xff,
+                                             localMatrix);
         SkASSERT(gp->getVertexStride()==sizeof(GrDefaultGeoProcFactory::PositionColorCoverageAttr));
         *type = kUseCoverage_CoverageAttribType;
     }
@@ -178,13 +180,15 @@
 void GrAARectRenderer::geometryFillAARect(GrDrawTarget* target,
                                           GrDrawState* drawState,
                                           GrColor color,
+                                          const SkMatrix& localMatrix,
                                           const SkRect& rect,
                                           const SkMatrix& combinedMatrix,
                                           const SkRect& devRect) {
     GrDrawState::AutoRestoreEffects are(drawState);
 
     CoverageAttribType type;
-    SkAutoTUnref<const GrGeometryProcessor> gp(create_rect_gp(*drawState, color, &type));
+    SkAutoTUnref<const GrGeometryProcessor> gp(create_rect_gp(*drawState, color, &type,
+                                                              localMatrix));
 
     size_t vertexStride = gp->getVertexStride();
     GrDrawTarget::AutoReleaseGeometry geo(target, 8, vertexStride, 0);
@@ -308,6 +312,7 @@
 void GrAARectRenderer::strokeAARect(GrDrawTarget* target,
                                     GrDrawState* drawState,
                                     GrColor color,
+                                    const SkMatrix& localMatrix,
                                     const SkRect& rect,
                                     const SkMatrix& combinedMatrix,
                                     const SkRect& devRect,
@@ -354,7 +359,8 @@
     }
 
     if (spare <= 0 && miterStroke) {
-        this->fillAARect(target, drawState, color, devOutside, SkMatrix::I(), devOutside);
+        this->fillAARect(target, drawState, color, localMatrix, devOutside, SkMatrix::I(),
+                         devOutside);
         return;
     }
 
@@ -371,13 +377,14 @@
         devOutsideAssist.outset(0, ry);
     }
 
-    this->geometryStrokeAARect(target, drawState, color, devOutside, devOutsideAssist, devInside,
-                               miterStroke);
+    this->geometryStrokeAARect(target, drawState, color, localMatrix, devOutside, devOutsideAssist,
+                               devInside, miterStroke);
 }
 
 void GrAARectRenderer::geometryStrokeAARect(GrDrawTarget* target,
                                             GrDrawState* drawState,
                                             GrColor color,
+                                            const SkMatrix& localMatrix,
                                             const SkRect& devOutside,
                                             const SkRect& devOutsideAssist,
                                             const SkRect& devInside,
@@ -385,7 +392,8 @@
     GrDrawState::AutoRestoreEffects are(drawState);
 
     CoverageAttribType type;
-    SkAutoTUnref<const GrGeometryProcessor> gp(create_rect_gp(*drawState, color, &type));
+    SkAutoTUnref<const GrGeometryProcessor> gp(create_rect_gp(*drawState, color, &type,
+                                                              localMatrix));
 
     int innerVertexNum = 4;
     int outerVertexNum = miterStroke ? 4 : 8;
@@ -510,6 +518,7 @@
 void GrAARectRenderer::fillAANestedRects(GrDrawTarget* target,
                                          GrDrawState* drawState,
                                          GrColor color,
+                                         const SkMatrix& localMatrix,
                                          const SkRect rects[2],
                                          const SkMatrix& combinedMatrix) {
     SkASSERT(combinedMatrix.rectStaysRect());
@@ -521,10 +530,11 @@
     combinedMatrix.mapPoints((SkPoint*)&devInside, (const SkPoint*)&rects[1], 2);
 
     if (devInside.isEmpty()) {
-        this->fillAARect(target, drawState, color, devOutside, SkMatrix::I(), devOutside);
+        this->fillAARect(target, drawState, color, localMatrix, devOutside, SkMatrix::I(),
+                         devOutside);
         return;
     }
 
-    this->geometryStrokeAARect(target, drawState, color, devOutside, devOutsideAssist, devInside,
-                               true);
+    this->geometryStrokeAARect(target, drawState, color, localMatrix, devOutside, devOutsideAssist,
+                               devInside, true);
 }
diff --git a/src/gpu/GrAARectRenderer.h b/src/gpu/GrAARectRenderer.h
index b1780ad..d97a111 100644
--- a/src/gpu/GrAARectRenderer.h
+++ b/src/gpu/GrAARectRenderer.h
@@ -45,15 +45,17 @@
     void fillAARect(GrDrawTarget* target,
                     GrDrawState* ds,
                     GrColor color,
+                    const SkMatrix& localMatrix,
                     const SkRect& rect,
                     const SkMatrix& combinedMatrix,
                     const SkRect& devRect) {
-        this->geometryFillAARect(target, ds, color, rect, combinedMatrix, devRect);
+        this->geometryFillAARect(target, ds, color, localMatrix, rect, combinedMatrix, devRect);
     }
 
     void strokeAARect(GrDrawTarget*,
                       GrDrawState*,
                       GrColor,
+                      const SkMatrix& localMatrix,
                       const SkRect& rect,
                       const SkMatrix& combinedMatrix,
                       const SkRect& devRect,
@@ -63,6 +65,7 @@
     void fillAANestedRects(GrDrawTarget*,
                            GrDrawState*,
                            GrColor,
+                           const SkMatrix& localMatrix,
                            const SkRect rects[2],
                            const SkMatrix& combinedMatrix);
 
@@ -72,6 +75,7 @@
     void geometryFillAARect(GrDrawTarget*,
                             GrDrawState*,
                             GrColor,
+                            const SkMatrix& localMatrix,
                             const SkRect& rect,
                             const SkMatrix& combinedMatrix,
                             const SkRect& devRect);
@@ -79,6 +83,7 @@
     void geometryStrokeAARect(GrDrawTarget*,
                               GrDrawState*,
                               GrColor,
+                              const SkMatrix& localMatrix,
                               const SkRect& devOutside,
                               const SkRect& devOutsideAssist,
                               const SkRect& devInside,
diff --git a/src/gpu/GrClipMaskManager.cpp b/src/gpu/GrClipMaskManager.cpp
index e56f4dd..4b57868 100644
--- a/src/gpu/GrClipMaskManager.cpp
+++ b/src/gpu/GrClipMaskManager.cpp
@@ -360,6 +360,7 @@
                 this->getContext()->getAARectRenderer()->fillAARect(fClipTarget,
                                                                     drawState,
                                                                     color,
+                                                                    SkMatrix::I(),
                                                                     element->getRect(),
                                                                     SkMatrix::I(),
                                                                     element->getRect());
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index 2818aa9..13de4fe 100755
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -743,23 +743,26 @@
                                            color);
 
     if (doAA) {
-        GrDrawState::AutoViewMatrixRestore avmr;
-        if (!avmr.setIdentity(&drawState)) {
+        SkMatrix invert;
+        if (!drawState.getViewMatrix().invert(&invert)) {
             return;
         }
+        GrDrawState::AutoViewMatrixRestore avmr(&drawState);
 
         if (width >= 0) {
             const SkStrokeRec& strokeRec = strokeInfo->getStrokeRec();
             fAARectRenderer->strokeAARect(target,
                                           &drawState,
                                           color,
+                                          invert,
                                           rect,
                                           matrix,
                                           devBoundRect,
                                           strokeRec);
         } else {
             // filled AA rect
-            fAARectRenderer->fillAARect(target, &drawState, color, rect, matrix, devBoundRect);
+            fAARectRenderer->fillAARect(target, &drawState, color, invert, rect, matrix,
+                                        devBoundRect);
         }
         return;
     }
@@ -1088,15 +1091,11 @@
             GrDrawTarget* target = this->prepareToDraw(&drawState, &paint, &viewMatrix, &acf);
             if (NULL == target) {
                 return;
-            };
+            }
 
-            SkMatrix origViewMatrix = drawState.getViewMatrix();
-            GrDrawState::AutoViewMatrixRestore avmr;
-            if (avmr.setIdentity(&drawState)) {
-                if (GrDashingEffect::DrawDashLine(fGpu, target, &drawState, color, pts, paint,
-                                                  strokeInfo, origViewMatrix)) {
-                    return;
-                }
+            if (GrDashingEffect::DrawDashLine(fGpu, target, &drawState, color, pts, paint,
+                                              strokeInfo)) {
+                return;
             }
         }
 
@@ -1138,12 +1137,15 @@
 
         if (is_nested_rects(target, &drawState, color, path, strokeRec, rects)) {
             SkMatrix origViewMatrix = drawState.getViewMatrix();
-            GrDrawState::AutoViewMatrixRestore avmr;
-            if (!avmr.setIdentity(&drawState)) {
+
+            SkMatrix invert;
+            if (!drawState.getViewMatrix().invert(&invert)) {
                 return;
             }
+            GrDrawState::AutoViewMatrixRestore avmr(&drawState);
 
-            fAARectRenderer->fillAANestedRects(target, &drawState, color, rects, origViewMatrix);
+            fAARectRenderer->fillAANestedRects(target, &drawState, color, invert, rects,
+                                               origViewMatrix);
             return;
         }
     }
diff --git a/src/gpu/GrDefaultPathRenderer.cpp b/src/gpu/GrDefaultPathRenderer.cpp
index 7222e62..e7c678d 100644
--- a/src/gpu/GrDefaultPathRenderer.cpp
+++ b/src/gpu/GrDefaultPathRenderer.cpp
@@ -475,6 +475,8 @@
             drawState->setXPFactory(backupXPFactory);
             SkRect bounds;
             GrDrawState::AutoViewMatrixRestore avmr;
+            const SkMatrix& viewMatrix = drawState->getViewMatrix();
+            SkMatrix localMatrix = SkMatrix::I();
             if (reverse) {
                 SkASSERT(drawState->getRenderTarget());
                 // draw over the dev bounds (which will be the whole dst surface for inv fill).
@@ -485,13 +487,16 @@
                     drawState->getViewInverse(&vmi)) {
                     vmi.mapRect(&bounds);
                 } else {
+                    if (!viewMatrix.invert(&localMatrix)) {
+                        return false;
+                    }
                     avmr.setIdentity(drawState);
                 }
             } else {
                 bounds = path.getBounds();
             }
             GrDrawTarget::AutoGeometryPush agp(target);
-            target->drawSimpleRect(drawState, color, bounds);
+            target->drawRect(drawState, color, bounds, NULL, &localMatrix);
         } else {
             if (passCount > 1) {
                 drawState->setDisableColorXPFactory();
diff --git a/src/gpu/GrDrawState.cpp b/src/gpu/GrDrawState.cpp
index 643253e..67a356a 100644
--- a/src/gpu/GrDrawState.cpp
+++ b/src/gpu/GrDrawState.cpp
@@ -211,93 +211,6 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-void GrDrawState::AutoViewMatrixRestore::restore() {
-    if (fDrawState) {
-        SkDEBUGCODE(--fDrawState->fBlockEffectRemovalCnt;)
-        fDrawState->fViewMatrix = fViewMatrix;
-        SkASSERT(fDrawState->numColorStages() >= fNumColorStages);
-        int numCoverageStages = fSavedCoordChanges.count() - fNumColorStages;
-        SkASSERT(fDrawState->numCoverageStages() >= numCoverageStages);
-
-        int i = 0;
-        for (int s = 0; s < fNumColorStages; ++s, ++i) {
-            fDrawState->fColorStages[s].restoreCoordChange(fSavedCoordChanges[i]);
-        }
-        for (int s = 0; s < numCoverageStages; ++s, ++i) {
-            fDrawState->fCoverageStages[s].restoreCoordChange(fSavedCoordChanges[i]);
-        }
-        fDrawState = NULL;
-    }
-}
-
-void GrDrawState::AutoViewMatrixRestore::set(GrDrawState* drawState,
-                                             const SkMatrix& preconcatMatrix) {
-    this->restore();
-
-    SkASSERT(NULL == fDrawState);
-    if (NULL == drawState || preconcatMatrix.isIdentity()) {
-        return;
-    }
-    fDrawState = drawState;
-
-    fViewMatrix = drawState->getViewMatrix();
-    drawState->fViewMatrix.preConcat(preconcatMatrix);
-
-    this->doEffectCoordChanges(preconcatMatrix);
-    SkDEBUGCODE(++fDrawState->fBlockEffectRemovalCnt;)
-}
-
-bool GrDrawState::AutoViewMatrixRestore::setIdentity(GrDrawState* drawState) {
-    this->restore();
-
-    if (NULL == drawState) {
-        return false;
-    }
-
-    if (drawState->getViewMatrix().isIdentity()) {
-        return true;
-    }
-
-    fViewMatrix = drawState->getViewMatrix();
-    if (0 == drawState->numFragmentStages()) {
-        drawState->fViewMatrix.reset();
-        fDrawState = drawState;
-        fNumColorStages = 0;
-        fSavedCoordChanges.reset(0);
-        SkDEBUGCODE(++fDrawState->fBlockEffectRemovalCnt;)
-        return true;
-    } else {
-        SkMatrix inv;
-        if (!fViewMatrix.invert(&inv)) {
-            return false;
-        }
-        drawState->fViewMatrix.reset();
-        fDrawState = drawState;
-        this->doEffectCoordChanges(inv);
-        SkDEBUGCODE(++fDrawState->fBlockEffectRemovalCnt;)
-        return true;
-    }
-}
-
-void GrDrawState::AutoViewMatrixRestore::doEffectCoordChanges(const SkMatrix& coordChangeMatrix) {
-    fSavedCoordChanges.reset(fDrawState->numFragmentStages());
-    int i = 0;
-
-    fNumColorStages = fDrawState->numColorStages();
-    for (int s = 0; s < fNumColorStages; ++s, ++i) {
-        fDrawState->getColorStage(s).saveCoordChange(&fSavedCoordChanges[i]);
-        fDrawState->fColorStages[s].localCoordChange(coordChangeMatrix);
-    }
-
-    int numCoverageStages = fDrawState->numCoverageStages();
-    for (int s = 0; s < numCoverageStages; ++s, ++i) {
-        fDrawState->getCoverageStage(s).saveCoordChange(&fSavedCoordChanges[i]);
-        fDrawState->fCoverageStages[s].localCoordChange(coordChangeMatrix);
-    }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
 GrDrawState::~GrDrawState() {
     SkASSERT(0 == fBlockEffectRemovalCnt);
 }
diff --git a/src/gpu/GrDrawState.h b/src/gpu/GrDrawState.h
index 36e2b3a..1f469d5 100644
--- a/src/gpu/GrDrawState.h
+++ b/src/gpu/GrDrawState.h
@@ -306,40 +306,41 @@
     ////////////////////////////////////////////////////////////////////////////
 
     /**
-     * Preconcats the current view matrix and restores the previous view matrix in the destructor.
-     * Effect matrices are automatically adjusted to compensate and adjusted back in the destructor.
+     * Sets the viewmatrix to identity and restores it in the destructor.
+     * TODO remove vm off of drawstate
      */
     class AutoViewMatrixRestore : public ::SkNoncopyable {
     public:
-        AutoViewMatrixRestore() : fDrawState(NULL) {}
-
-        AutoViewMatrixRestore(GrDrawState* ds, const SkMatrix& preconcatMatrix) {
+        AutoViewMatrixRestore() {
             fDrawState = NULL;
-            this->set(ds, preconcatMatrix);
         }
 
-        ~AutoViewMatrixRestore() { this->restore(); }
+        AutoViewMatrixRestore(GrDrawState* ds) {
+            SkASSERT(ds);
+            fDrawState = ds;
+            fViewMatrix = fDrawState->fViewMatrix;
+            fDrawState->fViewMatrix = SkMatrix::I();
+        }
 
-        /**
-         * Can be called prior to destructor to restore the original matrix.
-         */
-        void restore();
+        void setIdentity(GrDrawState* ds) {
+            SkASSERT(ds);
+            fDrawState = ds;
+            fViewMatrix = fDrawState->fViewMatrix;
+            fDrawState->fViewMatrix = SkMatrix::I();
+        }
 
-        void set(GrDrawState* drawState, const SkMatrix& preconcatMatrix);
-
-        /** Sets the draw state's matrix to identity. This can fail because the current view matrix
-            is not invertible. */
-        bool setIdentity(GrDrawState* drawState);
+        ~AutoViewMatrixRestore() {
+            if (fDrawState) {
+                fDrawState->fViewMatrix = fViewMatrix;
+            }
+        }
 
     private:
-        void doEffectCoordChanges(const SkMatrix& coordChangeMatrix);
-
         GrDrawState*                                           fDrawState;
         SkMatrix                                               fViewMatrix;
-        int                                                    fNumColorStages;
-        SkAutoSTArray<8, GrFragmentStage::SavedCoordChange>    fSavedCoordChanges;
     };
 
+
     /// @}
 
     ///////////////////////////////////////////////////////////////////////////
diff --git a/src/gpu/GrInOrderDrawBuffer.cpp b/src/gpu/GrInOrderDrawBuffer.cpp
index 6e5c1fe..1f49035 100644
--- a/src/gpu/GrInOrderDrawBuffer.cpp
+++ b/src/gpu/GrInOrderDrawBuffer.cpp
@@ -120,11 +120,27 @@
                                      const SkMatrix* localMatrix) {
     GrDrawState::AutoRestoreEffects are(ds);
 
+    // Go to device coords to allow batching across matrix changes
+    SkMatrix matrix = ds->getViewMatrix();
+    SkMatrix invert = SkMatrix::I();
+
+    // if we have a local rect, then we apply the localMatrix directly to the localRect to generate
+    // vertex local coords
     bool hasExplicitLocalCoords = SkToBool(localRect);
-    SkAutoTUnref<const GrGeometryProcessor> gp(
-            create_rect_gp(hasExplicitLocalCoords,
-                           color,
-                           hasExplicitLocalCoords ? NULL : localMatrix));
+    if (!hasExplicitLocalCoords) {
+        if (!matrix.isIdentity() && !matrix.invert(&invert)) {
+            SkDebugf("Could not invert\n");
+            return;
+        }
+
+        if (localMatrix) {
+            invert.preConcat(*localMatrix);
+        }
+    }
+
+    SkAutoTUnref<const GrGeometryProcessor> gp(create_rect_gp(hasExplicitLocalCoords,
+                                                              color,
+                                                              &invert));
 
     size_t vstride = gp->getVertexStride();
     SkASSERT(vstride == sizeof(SkPoint) + sizeof(GrColor) + (SkToBool(localRect) ? sizeof(SkPoint) :
@@ -135,16 +151,10 @@
         return;
     }
 
-    // Go to device coords to allow batching across matrix changes
-    SkMatrix matrix = ds->getViewMatrix();
-
     // When the caller has provided an explicit source rect for a stage then we don't want to
     // modify that stage's matrix. Otherwise if the effect is generating its source rect from
     // the vertex positions then we have to account for the view matrix change.
-    GrDrawState::AutoViewMatrixRestore avmr;
-    if (!avmr.setIdentity(ds)) {
-        return;
-    }
+    GrDrawState::AutoViewMatrixRestore avmr(ds);
 
     geo.positions()->setRectFan(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, vstride);
     matrix.mapPointsWithStride(geo.positions(), vstride, 4);
diff --git a/src/gpu/GrOvalRenderer.cpp b/src/gpu/GrOvalRenderer.cpp
index 05838cf..ac088b9 100644
--- a/src/gpu/GrOvalRenderer.cpp
+++ b/src/gpu/GrOvalRenderer.cpp
@@ -65,8 +65,8 @@
 
 class CircleEdgeEffect : public GrGeometryProcessor {
 public:
-    static GrGeometryProcessor* Create(GrColor color, bool stroke) {
-        return SkNEW_ARGS(CircleEdgeEffect, (color, stroke));
+    static GrGeometryProcessor* Create(GrColor color, bool stroke, const SkMatrix& localMatrix) {
+        return SkNEW_ARGS(CircleEdgeEffect, (color, stroke, localMatrix));
     }
 
     const GrAttribute* inPosition() const { return fInPosition; }
@@ -174,7 +174,8 @@
     }
 
 private:
-    CircleEdgeEffect(GrColor color, bool stroke) : INHERITED(color) {
+    CircleEdgeEffect(GrColor color, bool stroke, const SkMatrix& localMatrix)
+        : INHERITED(color, false, localMatrix) {
         this->initClassID<CircleEdgeEffect>();
         fInPosition = &this->addVertexAttrib(GrAttribute("inPosition", kVec2f_GrVertexAttribType));
         fInCircleEdge = &this->addVertexAttrib(GrAttribute("inCircleEdge",
@@ -212,7 +213,8 @@
                                                   GrContext* context,
                                                   const GrDrawTargetCaps&,
                                                   GrTexture* textures[]) {
-    return CircleEdgeEffect::Create(GrRandomColor(random), random->nextBool());
+    return CircleEdgeEffect::Create(GrRandomColor(random), random->nextBool(),
+                                    GrProcessorUnitTest::TestMatrix(random));
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -227,8 +229,8 @@
 
 class EllipseEdgeEffect : public GrGeometryProcessor {
 public:
-    static GrGeometryProcessor* Create(GrColor color, bool stroke) {
-        return SkNEW_ARGS(EllipseEdgeEffect, (color, stroke));
+    static GrGeometryProcessor* Create(GrColor color, bool stroke, const SkMatrix& localMatrix) {
+        return SkNEW_ARGS(EllipseEdgeEffect, (color, stroke, localMatrix));
     }
 
     virtual ~EllipseEdgeEffect() {}
@@ -360,7 +362,8 @@
     }
 
 private:
-    EllipseEdgeEffect(GrColor color, bool stroke) : INHERITED(color) {
+    EllipseEdgeEffect(GrColor color, bool stroke, const SkMatrix& localMatrix)
+        : INHERITED(color, false, localMatrix) {
         this->initClassID<EllipseEdgeEffect>();
         fInPosition = &this->addVertexAttrib(GrAttribute("inPosition", kVec2f_GrVertexAttribType));
         fInEllipseOffset = &this->addVertexAttrib(GrAttribute("inEllipseOffset",
@@ -401,7 +404,8 @@
                                                    GrContext* context,
                                                    const GrDrawTargetCaps&,
                                                    GrTexture* textures[]) {
-    return EllipseEdgeEffect::Create(GrRandomColor(random), random->nextBool());
+    return EllipseEdgeEffect::Create(GrRandomColor(random), random->nextBool(),
+                                     GrProcessorUnitTest::TestMatrix(random));
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -667,11 +671,13 @@
     SkScalar radius = vm.mapRadius(SkScalarHalf(circle.width()));
     SkScalar strokeWidth = vm.mapRadius(stroke.getWidth());
 
-    GrDrawState::AutoViewMatrixRestore avmr;
-    if (!avmr.setIdentity(drawState)) {
+    SkMatrix invert;
+    if (!vm.invert(&invert)) {
         return;
     }
 
+    GrDrawState::AutoViewMatrixRestore avmr(drawState);
+
     SkStrokeRec::Style style = stroke.getStyle();
     bool isStrokeOnly = SkStrokeRec::kStroke_Style == style ||
                         SkStrokeRec::kHairline_Style == style;
@@ -694,7 +700,7 @@
     }
 
     SkAutoTUnref<GrGeometryProcessor> gp(
-            CircleEdgeEffect::Create(color, isStrokeOnly && innerRadius > 0));
+            CircleEdgeEffect::Create(color, isStrokeOnly && innerRadius > 0, invert));
 
     GrDrawTarget::AutoReleaseGeometry geo(target, 4, gp->getVertexStride(),  0);
     SkASSERT(gp->getVertexStride() == sizeof(CircleVertex));
@@ -816,13 +822,16 @@
         yRadius += scaledStroke.fY;
     }
 
-    GrDrawState::AutoViewMatrixRestore avmr;
-    if (!avmr.setIdentity(drawState)) {
+    SkMatrix invert;
+    if (!vm.invert(&invert)) {
         return false;
     }
 
+    GrDrawState::AutoViewMatrixRestore avmr(drawState);
+
     SkAutoTUnref<GrGeometryProcessor> gp(
-            EllipseEdgeEffect::Create(color, isStrokeOnly && innerXRadius > 0 && innerYRadius > 0));
+            EllipseEdgeEffect::Create(color, isStrokeOnly && innerXRadius > 0 && innerYRadius > 0,
+                                      invert));
 
     GrDrawTarget::AutoReleaseGeometry geo(target, 4, gp->getVertexStride(),  0);
     SkASSERT(gp->getVertexStride() == sizeof(EllipseVertex));
@@ -1084,16 +1093,19 @@
     if (!are.isSet()) {
         are.set(drawState);
     }
-    GrDrawState::AutoViewMatrixRestore avmr;
-    if (!avmr.setIdentity(drawState)) {
+
+    SkMatrix invert;
+    if (!drawState->getViewMatrix().invert(&invert)) {
         return false;
     }
+
+    GrDrawState::AutoViewMatrixRestore avmr(drawState);
     drawState->addCoverageProcessor(effect)->unref();
     SkRect bounds = outer->getBounds();
     if (applyAA) {
         bounds.outset(SK_ScalarHalf, SK_ScalarHalf);
     }
-    target->drawSimpleRect(drawState, color, bounds);
+    target->drawRect(drawState, color, bounds, NULL, &invert);
     return true;
 }
 
@@ -1169,11 +1181,14 @@
     }
 
     // reset to device coordinates
-    GrDrawState::AutoViewMatrixRestore avmr;
-    if (!avmr.setIdentity(drawState)) {
+    SkMatrix invert;
+    if (!vm.invert(&invert)) {
+        SkDebugf("Failed to invert\n");
         return false;
     }
 
+    GrDrawState::AutoViewMatrixRestore avmr(drawState);
+
     GrIndexBuffer* indexBuffer = this->rRectIndexBuffer(isStrokeOnly);
     if (NULL == indexBuffer) {
         SkDebugf("Failed to create index buffer!\n");
@@ -1201,7 +1216,8 @@
 
         isStrokeOnly = (isStrokeOnly && innerRadius >= 0);
 
-        SkAutoTUnref<GrGeometryProcessor> effect(CircleEdgeEffect::Create(color, isStrokeOnly));
+        SkAutoTUnref<GrGeometryProcessor> effect(CircleEdgeEffect::Create(color, isStrokeOnly,
+                                                                          invert));
 
         GrDrawTarget::AutoReleaseGeometry geo(target, 16, effect->getVertexStride(),  0);
         SkASSERT(effect->getVertexStride() == sizeof(CircleVertex));
@@ -1300,7 +1316,8 @@
 
         isStrokeOnly = (isStrokeOnly && innerXRadius >= 0 && innerYRadius >= 0);
 
-        SkAutoTUnref<GrGeometryProcessor> effect(EllipseEdgeEffect::Create(color, isStrokeOnly));
+        SkAutoTUnref<GrGeometryProcessor> effect(EllipseEdgeEffect::Create(color, isStrokeOnly,
+                                                                           invert));
 
         GrDrawTarget::AutoReleaseGeometry geo(target, 16, effect->getVertexStride(),  0);
         SkASSERT(effect->getVertexStride() == sizeof(EllipseVertex));
diff --git a/src/gpu/GrSWMaskHelper.cpp b/src/gpu/GrSWMaskHelper.cpp
index 61e7f1f..b64d37b 100644
--- a/src/gpu/GrSWMaskHelper.cpp
+++ b/src/gpu/GrSWMaskHelper.cpp
@@ -350,10 +350,11 @@
                                               GrDrawState* drawState,
                                               GrColor color,
                                               const SkIRect& rect) {
-    GrDrawState::AutoViewMatrixRestore avmr;
-    if (!avmr.setIdentity(drawState)) {
+    SkMatrix invert;
+    if (!drawState->getViewMatrix().invert(&invert)) {
         return;
     }
+    GrDrawState::AutoViewMatrixRestore avmr(drawState);
     GrDrawState::AutoRestoreEffects are(drawState);
 
     SkRect dstRect = SkRect::MakeLTRB(SK_Scalar1 * rect.fLeft,
@@ -374,5 +375,5 @@
                                                        GrTextureParams::kNone_FilterMode,
                                                        kDevice_GrCoordSet))->unref();
 
-    target->drawSimpleRect(drawState, color, dstRect);
+    target->drawRect(drawState, color, dstRect, NULL, &invert);
 }
diff --git a/src/gpu/GrSoftwarePathRenderer.cpp b/src/gpu/GrSoftwarePathRenderer.cpp
index 157e81d..8eb66d8 100644
--- a/src/gpu/GrSoftwarePathRenderer.cpp
+++ b/src/gpu/GrSoftwarePathRenderer.cpp
@@ -81,30 +81,34 @@
                           GrColor color,
                           const SkIRect& devClipBounds,
                           const SkIRect& devPathBounds) {
-    GrDrawState::AutoViewMatrixRestore avmr;
-    if (!avmr.setIdentity(drawState)) {
+    const SkMatrix& matrix = drawState->getViewMatrix();
+    SkMatrix invert;
+    if (!matrix.invert(&invert)) {
         return;
     }
+
+    GrDrawState::AutoViewMatrixRestore avmr(drawState);
+
     SkRect rect;
     if (devClipBounds.fTop < devPathBounds.fTop) {
         rect.iset(devClipBounds.fLeft, devClipBounds.fTop,
                   devClipBounds.fRight, devPathBounds.fTop);
-        target->drawSimpleRect(drawState, color, rect);
+        target->drawRect(drawState, color, rect, NULL, &invert);
     }
     if (devClipBounds.fLeft < devPathBounds.fLeft) {
         rect.iset(devClipBounds.fLeft, devPathBounds.fTop,
                   devPathBounds.fLeft, devPathBounds.fBottom);
-        target->drawSimpleRect(drawState, color, rect);
+        target->drawRect(drawState, color, rect, NULL, &invert);
     }
     if (devClipBounds.fRight > devPathBounds.fRight) {
         rect.iset(devPathBounds.fRight, devPathBounds.fTop,
                   devClipBounds.fRight, devPathBounds.fBottom);
-        target->drawSimpleRect(drawState, color, rect);
+        target->drawRect(drawState, color, rect, NULL, &invert);
     }
     if (devClipBounds.fBottom > devPathBounds.fBottom) {
         rect.iset(devClipBounds.fLeft, devPathBounds.fBottom,
                   devClipBounds.fRight, devClipBounds.fBottom);
-        target->drawSimpleRect(drawState, color, rect);
+        target->drawRect(drawState, color, rect, NULL, &invert);
     }
 }
 
diff --git a/src/gpu/GrStencilAndCoverPathRenderer.cpp b/src/gpu/GrStencilAndCoverPathRenderer.cpp
index d8470f3..2feea01 100644
--- a/src/gpu/GrStencilAndCoverPathRenderer.cpp
+++ b/src/gpu/GrStencilAndCoverPathRenderer.cpp
@@ -121,6 +121,7 @@
         SkAutoTUnref<GrPathProcessor> pp(GrPathProcessor::Create(GrColor_WHITE));
         target->stencilPath(drawState, pp, p, convert_skpath_filltype(path.getFillType()));
 
+        SkMatrix invert = SkMatrix::I();
         GrDrawState::AutoViewMatrixRestore avmr;
         SkRect bounds = SkRect::MakeLTRB(0, 0,
                                          SkIntToScalar(drawState->getRenderTarget()->width()),
@@ -134,9 +135,12 @@
             SkScalar bloat = drawState->getViewMatrix().getMaxScale() * SK_ScalarHalf;
             bounds.outset(bloat, bloat);
         } else {
+            if (!drawState->getViewMatrix().invert(&invert)) {
+                return false;
+            }
             avmr.setIdentity(drawState);
         }
-        target->drawSimpleRect(drawState, color, bounds);
+        target->drawRect(drawState, color, bounds, NULL, &invert);
     } else {
         GR_STATIC_CONST_SAME_STENCIL(kStencilPass,
             kZero_StencilOp,
diff --git a/src/gpu/effects/GrBezierEffect.cpp b/src/gpu/effects/GrBezierEffect.cpp
index 0ba7bee..c90067d 100644
--- a/src/gpu/effects/GrBezierEffect.cpp
+++ b/src/gpu/effects/GrBezierEffect.cpp
@@ -183,8 +183,9 @@
     return SkNEW_ARGS(GrGLConicEffect, (*this, bt));
 }
 
-GrConicEffect::GrConicEffect(GrColor color, uint8_t coverage, GrPrimitiveEdgeType edgeType)
-    : INHERITED(color, false), fCoverageScale(coverage), fEdgeType(edgeType) {
+GrConicEffect::GrConicEffect(GrColor color, uint8_t coverage, GrPrimitiveEdgeType edgeType,
+                             const SkMatrix& localMatrix)
+    : INHERITED(color, false, localMatrix), fCoverageScale(coverage), fEdgeType(edgeType) {
     this->initClassID<GrConicEffect>();
     fInPosition = &this->addVertexAttrib(GrAttribute("inPosition", kVec2f_GrVertexAttribType));
     fInConicCoeffs = &this->addVertexAttrib(GrAttribute("inConicCoeffs",
@@ -227,7 +228,8 @@
     do {
         GrPrimitiveEdgeType edgeType = static_cast<GrPrimitiveEdgeType>(
                                                     random->nextULessThan(kGrProcessorEdgeTypeCnt));
-        gp = GrConicEffect::Create(GrRandomColor(random), edgeType, caps);
+        gp = GrConicEffect::Create(GrRandomColor(random), edgeType, caps,
+                                   GrProcessorUnitTest::TestMatrix(random));
     } while (NULL == gp);
     return gp;
 }
@@ -393,8 +395,9 @@
     return SkNEW_ARGS(GrGLQuadEffect, (*this, bt));
 }
 
-GrQuadEffect::GrQuadEffect(GrColor color, uint8_t coverage, GrPrimitiveEdgeType edgeType)
-    : INHERITED(color, false), fCoverageScale(coverage), fEdgeType(edgeType) {
+GrQuadEffect::GrQuadEffect(GrColor color, uint8_t coverage, GrPrimitiveEdgeType edgeType,
+                           const SkMatrix& localMatrix)
+    : INHERITED(color, false, localMatrix), fCoverageScale(coverage), fEdgeType(edgeType) {
     this->initClassID<GrQuadEffect>();
     fInPosition = &this->addVertexAttrib(GrAttribute("inPosition", kVec2f_GrVertexAttribType));
     fInHairQuadEdge = &this->addVertexAttrib(GrAttribute("inHairQuadEdge",
@@ -437,7 +440,8 @@
     do {
         GrPrimitiveEdgeType edgeType = static_cast<GrPrimitiveEdgeType>(
                 random->nextULessThan(kGrProcessorEdgeTypeCnt));
-        gp = GrQuadEffect::Create(GrRandomColor(random), edgeType, caps);
+        gp = GrQuadEffect::Create(GrRandomColor(random), edgeType, caps,
+                                  GrProcessorUnitTest::TestMatrix(random));
     } while (NULL == gp);
     return gp;
 }
diff --git a/src/gpu/effects/GrBezierEffect.h b/src/gpu/effects/GrBezierEffect.h
index 5954ee3..b985fec 100644
--- a/src/gpu/effects/GrBezierEffect.h
+++ b/src/gpu/effects/GrBezierEffect.h
@@ -61,21 +61,25 @@
     static GrGeometryProcessor* Create(GrColor color,
                                        const GrPrimitiveEdgeType edgeType,
                                        const GrDrawTargetCaps& caps,
+                                       const SkMatrix& localMatrix,
                                        uint8_t coverage = 0xff) {
         switch (edgeType) {
             case kFillAA_GrProcessorEdgeType:
                 if (!caps.shaderDerivativeSupport()) {
                     return NULL;
                 }
-                return SkNEW_ARGS(GrConicEffect, (color, coverage, kFillAA_GrProcessorEdgeType));
+                return SkNEW_ARGS(GrConicEffect, (color, coverage, kFillAA_GrProcessorEdgeType,
+                                                  localMatrix));
             case kHairlineAA_GrProcessorEdgeType:
                 if (!caps.shaderDerivativeSupport()) {
                     return NULL;
                 }
                 return SkNEW_ARGS(GrConicEffect, (color, coverage,
-                                                  kHairlineAA_GrProcessorEdgeType));
+                                                  kHairlineAA_GrProcessorEdgeType,
+                                                  localMatrix));
             case kFillBW_GrProcessorEdgeType:
-                return SkNEW_ARGS(GrConicEffect, (color, coverage, kFillBW_GrProcessorEdgeType));;
+                return SkNEW_ARGS(GrConicEffect, (color, coverage, kFillBW_GrProcessorEdgeType,
+                                                  localMatrix));
             default:
                 return NULL;
         }
@@ -103,7 +107,7 @@
                         const GrBatchTracker&) const SK_OVERRIDE;
 
 private:
-    GrConicEffect(GrColor, uint8_t coverage, GrPrimitiveEdgeType);
+    GrConicEffect(GrColor, uint8_t coverage, GrPrimitiveEdgeType, const SkMatrix& localMatrix);
 
     virtual bool onIsEqual(const GrGeometryProcessor& other) const SK_OVERRIDE;
 
@@ -137,20 +141,24 @@
     static GrGeometryProcessor* Create(GrColor color,
                                        const GrPrimitiveEdgeType edgeType,
                                        const GrDrawTargetCaps& caps,
+                                       const SkMatrix& localMatrix,
                                        uint8_t coverage = 0xff) {
         switch (edgeType) {
             case kFillAA_GrProcessorEdgeType:
                 if (!caps.shaderDerivativeSupport()) {
                     return NULL;
                 }
-                return SkNEW_ARGS(GrQuadEffect, (color, coverage, kFillAA_GrProcessorEdgeType));
+                return SkNEW_ARGS(GrQuadEffect, (color, coverage, kFillAA_GrProcessorEdgeType,
+                                                 localMatrix));
             case kHairlineAA_GrProcessorEdgeType:
                 if (!caps.shaderDerivativeSupport()) {
                     return NULL;
                 }
-                return SkNEW_ARGS(GrQuadEffect, (color, coverage, kHairlineAA_GrProcessorEdgeType));
+                return SkNEW_ARGS(GrQuadEffect, (color, coverage, kHairlineAA_GrProcessorEdgeType,
+                                                 localMatrix));
             case kFillBW_GrProcessorEdgeType:
-                return SkNEW_ARGS(GrQuadEffect, (color, coverage, kFillBW_GrProcessorEdgeType));
+                return SkNEW_ARGS(GrQuadEffect, (color, coverage, kFillBW_GrProcessorEdgeType,
+                                                 localMatrix));
             default:
                 return NULL;
         }
@@ -178,7 +186,7 @@
                         const GrBatchTracker&) const SK_OVERRIDE;
 
 private:
-    GrQuadEffect(GrColor, uint8_t coverage, GrPrimitiveEdgeType);
+    GrQuadEffect(GrColor, uint8_t coverage, GrPrimitiveEdgeType, const SkMatrix& localMatrix);
 
     virtual bool onIsEqual(const GrGeometryProcessor& other) const SK_OVERRIDE;
 
diff --git a/src/gpu/effects/GrDashingEffect.cpp b/src/gpu/effects/GrDashingEffect.cpp
index d5b0b48..339e44a 100644
--- a/src/gpu/effects/GrDashingEffect.cpp
+++ b/src/gpu/effects/GrDashingEffect.cpp
@@ -166,7 +166,8 @@
 
 bool GrDashingEffect::DrawDashLine(GrGpu* gpu, GrDrawTarget* target, GrDrawState* drawState,
                                    GrColor color, const SkPoint pts[2], const GrPaint& paint,
-                                   const GrStrokeInfo& strokeInfo, const SkMatrix& vm) {
+                                   const GrStrokeInfo& strokeInfo) {
+    const SkMatrix& vm = drawState->getViewMatrix();
 
     if (!can_fast_path_dash(pts, strokeInfo, *target, *drawState, vm)) {
         return false;
@@ -335,6 +336,15 @@
         devIntervals[0] = lineLength;
     }
 
+    // reset to device coordinates
+    SkMatrix invert;
+    if (!vm.invert(&invert)) {
+        SkDebugf("Failed to invert\n");
+        return false;
+    }
+
+    GrDrawState::AutoViewMatrixRestore avmr(drawState);
+
     SkAutoTUnref<const GrGeometryProcessor> gp;
     bool fullDash = devIntervals[1] > 0.f || useAA;
     if (fullDash) {
@@ -347,10 +357,11 @@
         bool isRoundCap = SkPaint::kRound_Cap == cap;
         GrDashingEffect::DashCap capType = isRoundCap ? GrDashingEffect::kRound_DashCap :
                                                         GrDashingEffect::kNonRound_DashCap;
-        gp.reset(GrDashingEffect::Create(color, edgeType, devInfo, strokeWidth, capType));
+        gp.reset(GrDashingEffect::Create(color, edgeType, devInfo, strokeWidth, capType, invert));
     } else {
         // Set up the vertex data for the line and start/end dashes
-        gp.reset(GrDefaultGeoProcFactory::Create(color, GrDefaultGeoProcFactory::kPosition_GPType));
+        gp.reset(GrDefaultGeoProcFactory::Create(color, GrDefaultGeoProcFactory::kPosition_GPType,
+                                                 invert));
     }
 
     int totalRectCnt = 0;
@@ -464,7 +475,8 @@
     static GrGeometryProcessor* Create(GrColor,
                                        GrPrimitiveEdgeType edgeType,
                                        const DashInfo& info,
-                                       SkScalar radius);
+                                       SkScalar radius,
+                                       const SkMatrix& localMatrix);
 
     virtual ~DashingCircleEffect();
 
@@ -496,7 +508,7 @@
 
 private:
     DashingCircleEffect(GrColor, GrPrimitiveEdgeType edgeType, const DashInfo& info,
-                        SkScalar radius);
+                        SkScalar radius, const SkMatrix& localMatrix);
 
     virtual bool onIsEqual(const GrGeometryProcessor& other) const SK_OVERRIDE;
 
@@ -633,12 +645,13 @@
 GrGeometryProcessor* DashingCircleEffect::Create(GrColor color,
                                                  GrPrimitiveEdgeType edgeType,
                                                  const DashInfo& info,
-                                                 SkScalar radius) {
+                                                 SkScalar radius,
+                                                 const SkMatrix& localMatrix) {
     if (info.fCount != 2 || info.fIntervals[0] != 0) {
         return NULL;
     }
 
-    return SkNEW_ARGS(DashingCircleEffect, (color, edgeType, info, radius));
+    return SkNEW_ARGS(DashingCircleEffect, (color, edgeType, info, radius, localMatrix));
 }
 
 DashingCircleEffect::~DashingCircleEffect() {}
@@ -660,8 +673,9 @@
 DashingCircleEffect::DashingCircleEffect(GrColor color,
                                          GrPrimitiveEdgeType edgeType,
                                          const DashInfo& info,
-                                         SkScalar radius)
-    : INHERITED(color), fEdgeType(edgeType) {
+                                         SkScalar radius,
+                                         const SkMatrix& localMatrix)
+    : INHERITED(color, false, localMatrix), fEdgeType(edgeType) {
     this->initClassID<DashingCircleEffect>();
     fInPosition = &this->addVertexAttrib(GrAttribute("inPosition", kVec2f_GrVertexAttribType));
     fInCoord = &this->addVertexAttrib(GrAttribute("inCoord", kVec2f_GrVertexAttribType));
@@ -714,7 +728,8 @@
     info.fIntervals[1] = random->nextRangeScalar(0, 10.f);
     info.fPhase = random->nextRangeScalar(0, info.fIntervals[1]);
 
-    return DashingCircleEffect::Create(GrRandomColor(random), edgeType, info, strokeWidth);
+    return DashingCircleEffect::Create(GrRandomColor(random), edgeType, info, strokeWidth,
+                                       GrProcessorUnitTest::TestMatrix(random));
 }
 
 //////////////////////////////////////////////////////////////////////////////
@@ -743,7 +758,8 @@
     static GrGeometryProcessor* Create(GrColor,
                                        GrPrimitiveEdgeType edgeType,
                                        const DashInfo& info,
-                                       SkScalar strokeWidth);
+                                       SkScalar strokeWidth,
+                                       const SkMatrix& localMatrix);
 
     virtual ~DashingLineEffect();
 
@@ -773,7 +789,7 @@
 
 private:
     DashingLineEffect(GrColor, GrPrimitiveEdgeType edgeType, const DashInfo& info,
-                      SkScalar strokeWidth);
+                      SkScalar strokeWidth, const SkMatrix& localMatrix);
 
     virtual bool onIsEqual(const GrGeometryProcessor& other) const SK_OVERRIDE;
 
@@ -923,12 +939,13 @@
 GrGeometryProcessor* DashingLineEffect::Create(GrColor color,
                                                GrPrimitiveEdgeType edgeType,
                                                const DashInfo& info,
-                                               SkScalar strokeWidth) {
+                                               SkScalar strokeWidth,
+                                               const SkMatrix& localMatrix) {
     if (info.fCount != 2) {
         return NULL;
     }
 
-    return SkNEW_ARGS(DashingLineEffect, (color, edgeType, info, strokeWidth));
+    return SkNEW_ARGS(DashingLineEffect, (color, edgeType, info, strokeWidth, localMatrix));
 }
 
 DashingLineEffect::~DashingLineEffect() {}
@@ -950,8 +967,9 @@
 DashingLineEffect::DashingLineEffect(GrColor color,
                                      GrPrimitiveEdgeType edgeType,
                                      const DashInfo& info,
-                                     SkScalar strokeWidth)
-    : INHERITED(color), fEdgeType(edgeType) {
+                                     SkScalar strokeWidth,
+                                     const SkMatrix& localMatrix)
+    : INHERITED(color, false, localMatrix), fEdgeType(edgeType) {
     this->initClassID<DashingLineEffect>();
     fInPosition = &this->addVertexAttrib(GrAttribute("inPosition", kVec2f_GrVertexAttribType));
     fInCoord = &this->addVertexAttrib(GrAttribute("inCoord", kVec2f_GrVertexAttribType));
@@ -1004,7 +1022,8 @@
     info.fIntervals[1] = random->nextRangeScalar(0, 10.f);
     info.fPhase = random->nextRangeScalar(0, info.fIntervals[0] + info.fIntervals[1]);
 
-    return DashingLineEffect::Create(GrRandomColor(random), edgeType, info, strokeWidth);
+    return DashingLineEffect::Create(GrRandomColor(random), edgeType, info, strokeWidth,
+                                     GrProcessorUnitTest::TestMatrix(random));
 }
 
 //////////////////////////////////////////////////////////////////////////////
@@ -1013,12 +1032,14 @@
                                              GrPrimitiveEdgeType edgeType,
                                              const SkPathEffect::DashInfo& info,
                                              SkScalar strokeWidth,
-                                             GrDashingEffect::DashCap cap) {
+                                             GrDashingEffect::DashCap cap,
+                                             const SkMatrix& localMatrix) {
     switch (cap) {
         case GrDashingEffect::kRound_DashCap:
-            return DashingCircleEffect::Create(color, edgeType, info, SkScalarHalf(strokeWidth));
+            return DashingCircleEffect::Create(color, edgeType, info, SkScalarHalf(strokeWidth),
+                                               localMatrix);
         case GrDashingEffect::kNonRound_DashCap:
-            return DashingLineEffect::Create(color, edgeType, info, strokeWidth);
+            return DashingLineEffect::Create(color, edgeType, info, strokeWidth, localMatrix);
         default:
             SkFAIL("Unexpected dashed cap.");
     }
diff --git a/src/gpu/effects/GrDashingEffect.h b/src/gpu/effects/GrDashingEffect.h
index 492c690..61cba7e 100644
--- a/src/gpu/effects/GrDashingEffect.h
+++ b/src/gpu/effects/GrDashingEffect.h
@@ -25,8 +25,7 @@
 
 namespace GrDashingEffect {
     bool DrawDashLine(GrGpu*, GrDrawTarget*, GrDrawState*, GrColor, const SkPoint pts[2],
-                      const GrPaint& paint, const GrStrokeInfo& strokeInfo,
-                      const SkMatrix& vm);
+                      const GrPaint& paint, const GrStrokeInfo& strokeInfo);
 
     enum DashCap {
         kRound_DashCap,
@@ -43,7 +42,8 @@
                                 GrPrimitiveEdgeType edgeType,
                                 const SkPathEffect::DashInfo& info,
                                 SkScalar strokeWidth,
-                                DashCap cap);
+                                DashCap cap,
+                                const SkMatrix& localMatrix);
 }
 
 #endif