Replace GrDrawState::AutoDeviceCoordDraw with GrDrawState::AutoViewMatrixRestore::setIdentity(). s

R=robertphillips@google.com

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

git-svn-id: http://skia.googlecode.com/svn/trunk@9331 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/gpu/GrAAConvexPathRenderer.cpp b/src/gpu/GrAAConvexPathRenderer.cpp
index e76f0c8..77980e4 100644
--- a/src/gpu/GrAAConvexPathRenderer.cpp
+++ b/src/gpu/GrAAConvexPathRenderer.cpp
@@ -602,23 +602,21 @@
         return true;
     }
 
-    GrDrawTarget::AutoStateRestore asr(target, GrDrawTarget::kPreserve_ASRInit);
-    GrDrawState* drawState = target->drawState();
-
-    GrDrawState::AutoDeviceCoordDraw adcd(drawState);
-    if (!adcd.succeeded()) {
+    SkMatrix viewMatrix = target->getDrawState().getViewMatrix();
+    GrDrawTarget::AutoStateRestore asr;
+    if (!asr.setIdentity(target, GrDrawTarget::kPreserve_ASRInit)) {
         return false;
     }
-    const SkMatrix* vm = &adcd.getOriginalMatrix();
+    GrDrawState* drawState = target->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.
     SkPath tmpPath;
-    if (vm->hasPerspective()) {
-        origPath.transform(*vm, &tmpPath);
+    if (viewMatrix.hasPerspective()) {
+        origPath.transform(viewMatrix, &tmpPath);
         path = &tmpPath;
-        vm = &SkMatrix::I();
+        viewMatrix = SkMatrix::I();
     }
 
     QuadVertex *verts;
@@ -633,7 +631,7 @@
     SkSTArray<kPreallocSegmentCnt, Segment, true> segments;
     SkPoint fanPt;
 
-    if (!get_segments(*path, *vm, &segments, &fanPt, &vCount, &iCount)) {
+    if (!get_segments(*path, viewMatrix, &segments, &fanPt, &vCount, &iCount)) {
         return false;
     }
 
@@ -662,8 +660,8 @@
 
     // This is valid because all the computed verts are within 1 pixel of the path control points.
     SkRect devBounds;
-    devBounds = origPath.getBounds();
-    adcd.getOriginalMatrix().mapRect(&devBounds);
+    devBounds = path->getBounds();
+    viewMatrix.mapRect(&devBounds);
     devBounds.outset(SK_Scalar1, SK_Scalar1);
 
     // Check devBounds
diff --git a/src/gpu/GrAAHairLinePathRenderer.cpp b/src/gpu/GrAAHairLinePathRenderer.cpp
index 51d5a79..1a15521 100644
--- a/src/gpu/GrAAHairLinePathRenderer.cpp
+++ b/src/gpu/GrAAHairLinePathRenderer.cpp
@@ -816,18 +816,16 @@
         return false;
     }
 
-    GrDrawTarget::AutoStateRestore asr(target, GrDrawTarget::kPreserve_ASRInit);
-    GrDrawState* drawState = target->drawState();
+    GrDrawTarget::AutoStateRestore asr;
 
-    GrDrawState::AutoDeviceCoordDraw adcd;
     // createGeom transforms the geometry to device space when the matrix does not have
     // perspective.
-    if (!drawState->getViewMatrix().hasPerspective()) {
-        adcd.set(drawState);
-        if (!adcd.succeeded()) {
-            return false;
-        }
+    if (target->getDrawState().getViewMatrix().hasPerspective()) {
+        asr.set(target, GrDrawTarget::kPreserve_ASRInit);
+    } else if (!asr.setIdentity(target, GrDrawTarget::kPreserve_ASRInit)) {
+        return false;
     }
+    GrDrawState* drawState = target->drawState();
 
     // TODO: See whether rendering lines as degenerate quads improves perf
     // when we have a mix
diff --git a/src/gpu/GrClipMaskManager.cpp b/src/gpu/GrClipMaskManager.cpp
index c022b34d..1362179 100644
--- a/src/gpu/GrClipMaskManager.cpp
+++ b/src/gpu/GrClipMaskManager.cpp
@@ -347,9 +347,9 @@
                                   SkRegion::Op op,
                                   const GrIRect& dstBound,
                                   const GrIRect& srcBound) {
+    GrDrawState::AutoViewMatrixRestore avmr;
     GrDrawState* drawState = fGpu->drawState();
-    SkMatrix oldMatrix = drawState->getViewMatrix();
-    drawState->viewMatrix()->reset();
+    SkAssertResult(avmr.setIdentity(drawState));
 
     drawState->setRenderTarget(dstMask->asRenderTarget());
 
@@ -366,7 +366,6 @@
     fGpu->drawSimpleRect(SkRect::MakeFromIRect(dstBound), NULL);
 
     drawState->disableStage(0);
-    drawState->setViewMatrix(oldMatrix);
 }
 
 // get a texture to act as a temporary buffer for AA clip boolean operations
@@ -437,9 +436,6 @@
         return NULL;
     }
 
-    GrDrawTarget::AutoGeometryAndStatePush agasp(fGpu, GrDrawTarget::kReset_ASRInit);
-    GrDrawState* drawState = fGpu->drawState();
-
     // The top-left of the mask corresponds to the top-left corner of the bounds.
     SkVector clipToMaskOffset = {
         SkIntToScalar(-clipSpaceIBounds.fLeft),
@@ -449,12 +445,16 @@
     // we populate with a rasterization of the clip.
     SkIRect maskSpaceIBounds = SkIRect::MakeWH(clipSpaceIBounds.width(), clipSpaceIBounds.height());
 
+    // Set the matrix so that rendered clip elements are transformed to mask space from clip space.
+    SkMatrix translate;
+    translate.setTranslate(clipToMaskOffset);
+    GrDrawTarget::AutoGeometryAndStatePush agasp(fGpu, GrDrawTarget::kReset_ASRInit, &translate);
+
+    GrDrawState* drawState = fGpu->drawState();
+
     // We're drawing a coverage mask and want coverage to be run through the blend function.
     drawState->enableState(GrDrawState::kCoverageDrawing_StateBit);
 
-    // Set the matrix so that rendered clip elements are transformed to mask space from clip space.
-    drawState->viewMatrix()->setTranslate(clipToMaskOffset);
-
     // The scratch texture that we are drawing into can be substantially larger than the mask. Only
     // clear the part that we care about.
     fGpu->clear(&maskSpaceIBounds,
@@ -589,8 +589,16 @@
 
         stencilBuffer->setLastClip(genID, clipSpaceIBounds, clipSpaceToStencilOffset);
 
-        GrDrawTarget::AutoGeometryAndStatePush agasp(fGpu, GrDrawTarget::kReset_ASRInit);
+        // Set the matrix so that rendered clip elements are transformed from clip to stencil space.
+        SkVector translate = {
+            SkIntToScalar(clipSpaceToStencilOffset.fX),
+            SkIntToScalar(clipSpaceToStencilOffset.fY)
+        };
+        SkMatrix matrix;
+        matrix.setTranslate(translate);
+        GrDrawTarget::AutoGeometryAndStatePush agasp(fGpu, GrDrawTarget::kReset_ASRInit, &matrix);
         drawState = fGpu->drawState();
+
         drawState->setRenderTarget(rt);
 
         // We set the current clip to the bounds so that our recursive draws are scissored to them.
@@ -599,13 +607,6 @@
         GrDrawTarget::AutoClipRestore acr(fGpu, stencilSpaceIBounds);
         drawState->enableState(GrDrawState::kClip_StateBit);
 
-        // Set the matrix so that rendered clip elements are transformed from clip to stencil space.
-        SkVector translate = {
-            SkIntToScalar(clipSpaceToStencilOffset.fX),
-            SkIntToScalar(clipSpaceToStencilOffset.fY)
-        };
-        drawState->viewMatrix()->setTranslate(translate);
-
 #if !VISUALIZE_COMPLEX_CLIP
         drawState->enableState(GrDrawState::kNoColorWrites_StateBit);
 #endif
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index 5f255a6..acae5b2 100644
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -777,8 +777,8 @@
                                            &combinedMatrix, &devRect,
                                            &useVertexCoverage);
     if (doAA) {
-        GrDrawState::AutoDeviceCoordDraw adcd(target->drawState());
-        if (!adcd.succeeded()) {
+        GrDrawState::AutoViewMatrixRestore avmr;
+        if (!avmr.setIdentity(target->drawState())) {
             return;
         }
         if (width >= 0) {
@@ -846,7 +846,6 @@
                                const SkMatrix* dstMatrix,
                                const SkMatrix* localMatrix) {
     SK_TRACE_EVENT0("GrContext::drawRectToRect");
-
     GrDrawTarget* target = this->prepareToDraw(&paint, BUFFERED_DRAW);
     GrDrawState::AutoStageDisable atr(fDrawState);
 
@@ -1049,21 +1048,22 @@
     GrDrawTarget* target = this->prepareToDraw(&paint, BUFFERED_DRAW);
     GrDrawState::AutoStageDisable atr(fDrawState);
 
-    bool useAA = paint.isAntiAlias() && !this->getRenderTarget()->isMultisampled();
+    bool useAA = paint.isAntiAlias() && !target->getDrawState().getRenderTarget()->isMultisampled();
     if (useAA && stroke.getWidth() < 0 && !path.isConvex()) {
         // Concave AA paths are expensive - try to avoid them for special cases
         bool useVertexCoverage;
         SkRect rects[2];
 
         if (is_nested_rects(target, path, stroke, rects, &useVertexCoverage)) {
-            GrDrawState::AutoDeviceCoordDraw adcd(target->drawState());
-            if (!adcd.succeeded()) {
+            SkMatrix origViewMatrix = target->getDrawState().getViewMatrix();
+            GrDrawState::AutoViewMatrixRestore avmr;
+            if (!avmr.setIdentity(target->drawState())) {
                 return;
             }
 
             fAARectRenderer->fillAANestedRects(this->getGpu(), target,
                                                rects,
-                                               adcd.getOriginalMatrix(),
+                                               origViewMatrix,
                                                useVertexCoverage);
             return;
         }
@@ -1534,14 +1534,13 @@
     // writeRenderTargetPixels can be called in the midst of drawing another
     // object (e.g., when uploading a SW path rendering to the gpu while
     // drawing a rect) so preserve the current geometry.
-    GrDrawTarget::AutoGeometryAndStatePush agasp(fGpu, GrDrawTarget::kReset_ASRInit);
+    SkMatrix matrix;
+    matrix.setTranslate(SkIntToScalar(left), SkIntToScalar(top));
+    GrDrawTarget::AutoGeometryAndStatePush agasp(fGpu, GrDrawTarget::kReset_ASRInit, &matrix);
     GrDrawState* drawState = fGpu->drawState();
     GrAssert(effect);
     drawState->setEffect(0, effect);
 
-    SkMatrix matrix;
-    matrix.setTranslate(SkIntToScalar(left), SkIntToScalar(top));
-    drawState->setViewMatrix(matrix);
     drawState->setRenderTarget(target);
 
     fGpu->drawSimpleRect(GrRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height)), NULL);
@@ -1565,8 +1564,7 @@
         }
 #endif
     } else {
-        fDrawState->reset();
-        *fDrawState->viewMatrix() = fViewMatrix;
+        fDrawState->reset(fViewMatrix);
         fDrawState->setRenderTarget(fRenderTarget.get());
     }
     GrDrawTarget* target;
diff --git a/src/gpu/GrDefaultPathRenderer.cpp b/src/gpu/GrDefaultPathRenderer.cpp
index 87deb9c..13bfe92 100644
--- a/src/gpu/GrDefaultPathRenderer.cpp
+++ b/src/gpu/GrDefaultPathRenderer.cpp
@@ -459,7 +459,7 @@
                 drawState->disableState(GrDrawState::kNoColorWrites_StateBit);
             }
             GrRect bounds;
-            GrDrawState::AutoDeviceCoordDraw adcd;
+            GrDrawState::AutoViewMatrixRestore avmr;
             if (reverse) {
                 GrAssert(NULL != drawState->getRenderTarget());
                 // draw over the dev bounds (which will be the whole dst surface for inv fill).
@@ -470,7 +470,7 @@
                     drawState->getViewInverse(&vmi)) {
                     vmi.mapRect(&bounds);
                 } else {
-                    adcd.set(drawState);
+                    avmr.setIdentity(drawState);
                 }
             } else {
                 bounds = path.getBounds();
diff --git a/src/gpu/GrDrawState.cpp b/src/gpu/GrDrawState.cpp
index 2cc50f7..f114ccc 100644
--- a/src/gpu/GrDrawState.cpp
+++ b/src/gpu/GrDrawState.cpp
@@ -8,6 +8,25 @@
 #include "GrDrawState.h"
 #include "GrPaint.h"
 
+bool GrDrawState::setIdentityViewMatrix()  {
+    SkMatrix invVM;
+    bool inverted = false;
+    for (int s = 0; s < GrDrawState::kNumStages; ++s) {
+        if (this->isStageEnabled(s)) {
+            if (!inverted) {
+                if (!fCommon.fViewMatrix.invert(&invVM)) {
+                    // sad trombone sound
+                    return false;
+                }
+                inverted = true;
+            }
+            fStages[s].localCoordChange(invVM);
+        }
+    }
+    fCommon.fViewMatrix.reset();
+    return true;
+}
+
 void GrDrawState::setFromPaint(const GrPaint& paint, const SkMatrix& vm, GrRenderTarget* rt) {
     for (int i = 0; i < GrPaint::kMaxColorStages; ++i) {
         int s = i + GrPaint::kFirstColorStage;
@@ -395,81 +414,59 @@
 
 void GrDrawState::AutoViewMatrixRestore::restore() {
     if (NULL != fDrawState) {
-        fDrawState->setViewMatrix(fViewMatrix);
+        fDrawState->fCommon.fViewMatrix = fViewMatrix;
         for (int s = 0; s < GrDrawState::kNumStages; ++s) {
             if (fRestoreMask & (1 << s)) {
                 fDrawState->fStages[s].restoreCoordChange(fSavedCoordChanges[s]);
             }
         }
+        fDrawState = NULL;
     }
-    fDrawState = NULL;
 }
 
 void GrDrawState::AutoViewMatrixRestore::set(GrDrawState* drawState,
                                              const SkMatrix& preconcatMatrix) {
     this->restore();
 
-    fDrawState = drawState;
-    if (NULL == drawState) {
+    if (NULL == drawState || preconcatMatrix.isIdentity()) {
         return;
     }
+    fDrawState = drawState;
 
     fRestoreMask = 0;
     fViewMatrix = drawState->getViewMatrix();
-    drawState->preConcatViewMatrix(preconcatMatrix);
+    drawState->fCommon.fViewMatrix.preConcat(preconcatMatrix);
     for (int s = 0; s < GrDrawState::kNumStages; ++s) {
         if (drawState->isStageEnabled(s)) {
             fRestoreMask |= (1 << s);
-            fDrawState->fStages[s].saveCoordChange(&fSavedCoordChanges[s]);
+            drawState->fStages[s].saveCoordChange(&fSavedCoordChanges[s]);
             drawState->fStages[s].localCoordChange(preconcatMatrix);
         }
     }
 }
 
-////////////////////////////////////////////////////////////////////////////////
-
-void GrDrawState::AutoDeviceCoordDraw::restore() {
-    if (NULL != fDrawState) {
-        fDrawState->setViewMatrix(fViewMatrix);
-        for (int s = 0; s < GrDrawState::kNumStages; ++s) {
-            if (fRestoreMask & (1 << s)) {
-                fDrawState->fStages[s].restoreCoordChange(fSavedCoordChanges[s]);
-            }
-        }
-    }
-    fDrawState = NULL;
-}
-
-bool GrDrawState::AutoDeviceCoordDraw::set(GrDrawState* drawState) {
-    GrAssert(NULL != drawState);
-
+bool GrDrawState::AutoViewMatrixRestore::setIdentity(GrDrawState* drawState) {
     this->restore();
 
-    fDrawState = drawState;
-    if (NULL == fDrawState) {
+    if (NULL == drawState) {
         return false;
     }
 
+    if (drawState->getViewMatrix().isIdentity()) {
+        return true;
+    }
+
     fViewMatrix = drawState->getViewMatrix();
     fRestoreMask = 0;
-    SkMatrix invVM;
-    bool inverted = false;
-
     for (int s = 0; s < GrDrawState::kNumStages; ++s) {
         if (drawState->isStageEnabled(s)) {
-            if (!inverted && !fViewMatrix.invert(&invVM)) {
-                // sad trombone sound
-                fDrawState = NULL;
-                return false;
-            } else {
-                inverted = true;
-            }
             fRestoreMask |= (1 << s);
-            GrEffectStage* stage = drawState->fStages + s;
-            stage->saveCoordChange(&fSavedCoordChanges[s]);
-            stage->localCoordChange(invVM);
+            drawState->fStages[s].saveCoordChange(&fSavedCoordChanges[s]);
         }
     }
-    drawState->viewMatrix()->reset();
+    if (!drawState->setIdentityViewMatrix()) {
+        return false;
+    }
+    fDrawState = drawState;
     return true;
 }
diff --git a/src/gpu/GrDrawState.h b/src/gpu/GrDrawState.h
index bf3ef74..26422aa 100644
--- a/src/gpu/GrDrawState.h
+++ b/src/gpu/GrDrawState.h
@@ -56,43 +56,39 @@
         kNumStages = GrPaint::kTotalStages + 2,
     };
 
-    GrDrawState() {
-        this->reset();
-    }
+    GrDrawState() { this->reset(); }
 
+    GrDrawState(const SkMatrix& initialViewMatrix) { this->reset(initialViewMatrix); }
+
+    /**
+     * Copies another draw state.
+     **/
     GrDrawState(const GrDrawState& state) {
         *this = state;
     }
 
-    virtual ~GrDrawState() {
-        this->disableStages();
+    /**
+     * Copies another draw state with a preconcat to the view matrix.
+     **/
+    GrDrawState(const GrDrawState& state, const SkMatrix& preConcatMatrix) {
+        *this = state;
+        if (!preConcatMatrix.isIdentity()) {
+            for (int i = 0; i < kNumStages; ++i) {
+                if (this->isStageEnabled(i)) {
+                    fStages[i].localCoordChange(preConcatMatrix);
+                }
+            }
+        }
     }
 
+    virtual ~GrDrawState() { this->disableStages(); }
+
     /**
-     * Resets to the default state.
-     * GrEffects will be removed from all stages.
+     * Resets to the default state. GrEffects will be removed from all stages.
      */
-    void reset() {
+    void reset() { this->onReset(NULL); }
 
-        this->disableStages();
-
-        fRenderTarget.reset(NULL);
-
-        this->setDefaultVertexAttribs();
-
-        fCommon.fColor = 0xffffffff;
-        fCommon.fViewMatrix.reset();
-        fCommon.fSrcBlend = kOne_GrBlendCoeff;
-        fCommon.fDstBlend = kZero_GrBlendCoeff;
-        fCommon.fBlendConstant = 0x0;
-        fCommon.fFlagBits = 0x0;
-        fCommon.fStencilSettings.setDisabled();
-        fCommon.fFirstCoverageStage = kNumStages;
-        fCommon.fCoverage = 0xffffffff;
-        fCommon.fColorFilterMode = SkXfermode::kDst_Mode;
-        fCommon.fColorFilterColor = 0x0;
-        fCommon.fDrawFace = kBoth_DrawFace;
-    }
+    void reset(const SkMatrix& initialViewMatrix) { this->onReset(&initialViewMatrix); }
 
     /**
      * Initializes the GrDrawState based on a GrPaint, view matrix and render target. Note that
@@ -616,42 +612,10 @@
     ////
 
     /**
-     * Sets the matrix applied to vertex positions.
-     *
-     * In the post-view-matrix space the rectangle [0,w]x[0,h]
-     * fully covers the render target. (w and h are the width and height of the
-     * the render-target.)
+     * Sets the view matrix to identity and updates any installed effects to compensate for the
+     * coord system change.
      */
-    void setViewMatrix(const SkMatrix& m) { fCommon.fViewMatrix = m; }
-
-    /**
-     * Gets a writable pointer to the view matrix.
-     */
-    SkMatrix* viewMatrix() { return &fCommon.fViewMatrix; }
-
-    /**
-     *  Multiplies the current view matrix by a matrix
-     *
-     *  After this call V' = V*m where V is the old view matrix,
-     *  m is the parameter to this function, and V' is the new view matrix.
-     *  (We consider positions to be column vectors so position vector p is
-     *  transformed by matrix X as p' = X*p.)
-     *
-     *  @param m the matrix used to modify the view matrix.
-     */
-    void preConcatViewMatrix(const SkMatrix& m) { fCommon.fViewMatrix.preConcat(m); }
-
-    /**
-     *  Multiplies the current view matrix by a matrix
-     *
-     *  After this call V' = m*V where V is the old view matrix,
-     *  m is the parameter to this function, and V' is the new view matrix.
-     *  (We consider positions to be column vectors so position vector p is
-     *  transformed by matrix X as p' = X*p.)
-     *
-     *  @param m the matrix used to modify the view matrix.
-     */
-    void postConcatViewMatrix(const SkMatrix& m) { fCommon.fViewMatrix.postConcat(m); }
+    bool setIdentityViewMatrix();
 
     /**
      * Retrieves the current view matrix
@@ -685,7 +649,7 @@
 
     /**
      * Preconcats the current view matrix and restores the previous view matrix in the destructor.
-     * Effect matrices are automatically adjusted to compensate.
+     * Effect matrices are automatically adjusted to compensate and adjusted back in the destructor.
      */
     class AutoViewMatrixRestore : public ::GrNoncopyable {
     public:
@@ -705,60 +669,9 @@
 
         void set(GrDrawState* drawState, const SkMatrix& preconcatMatrix);
 
-        bool isSet() const { return NULL != fDrawState; }
-
-    private:
-        GrDrawState*                        fDrawState;
-        SkMatrix                            fViewMatrix;
-        GrEffectStage::SavedCoordChange     fSavedCoordChanges[GrDrawState::kNumStages];
-        uint32_t                            fRestoreMask;
-    };
-
-    ////////////////////////////////////////////////////////////////////////////
-
-    /**
-     * This sets the view matrix to identity and adjusts stage matrices to compensate. The
-     * destructor undoes the changes, restoring the view matrix that was set before the
-     * constructor. It is similar to passing the inverse of the current view matrix to
-     * AutoViewMatrixRestore, but lazily computes the inverse only if necessary.
-     */
-    class AutoDeviceCoordDraw : ::GrNoncopyable {
-    public:
-        AutoDeviceCoordDraw() : fDrawState(NULL) {}
-        /**
-         * If a stage's texture matrix is applied to explicit per-vertex coords, rather than to
-         * positions, then we don't want to modify its matrix. The explicitCoordStageMask is used
-         * to specify such stages.
-         */
-        AutoDeviceCoordDraw(GrDrawState* drawState) {
-            fDrawState = NULL;
-            this->set(drawState);
-        }
-
-        ~AutoDeviceCoordDraw() { this->restore(); }
-
-        bool set(GrDrawState* drawState);
-
-        /**
-         * Returns true if this object was successfully initialized on to a GrDrawState. It may
-         * return false because a non-default constructor or set() were never called or because
-         * the view matrix was not invertible.
-         */
-        bool succeeded() const { return NULL != fDrawState; }
-
-        /**
-         * Returns the matrix that was set previously set on the drawState. This is only valid
-         * if succeeded returns true.
-         */
-        const SkMatrix& getOriginalMatrix() const {
-            GrAssert(this->succeeded());
-            return fViewMatrix;
-        }
-
-        /**
-         * Can be called prior to destructor to restore the original matrix.
-         */
-        void restore();
+        /** Sets the draw state's matrix to identity. This can fail because the current view matrix
+            is not invertible. */
+        bool setIdentity(GrDrawState* drawState);
 
     private:
         GrDrawState*                        fDrawState;
@@ -1027,6 +940,32 @@
 
 private:
 
+    void onReset(const SkMatrix* initialViewMatrix) {
+
+        this->disableStages();
+
+        fRenderTarget.reset(NULL);
+
+        this->setDefaultVertexAttribs();
+
+        fCommon.fColor = 0xffffffff;
+        if (NULL == initialViewMatrix) {
+            fCommon.fViewMatrix.reset();
+        } else {
+            fCommon.fViewMatrix = *initialViewMatrix;
+        }
+        fCommon.fSrcBlend = kOne_GrBlendCoeff;
+        fCommon.fDstBlend = kZero_GrBlendCoeff;
+        fCommon.fBlendConstant = 0x0;
+        fCommon.fFlagBits = 0x0;
+        fCommon.fStencilSettings.setDisabled();
+        fCommon.fFirstCoverageStage = kNumStages;
+        fCommon.fCoverage = 0xffffffff;
+        fCommon.fColorFilterMode = SkXfermode::kDst_Mode;
+        fCommon.fColorFilterColor = 0x0;
+        fCommon.fDrawFace = kBoth_DrawFace;
+    }
+
     /** Fields that are identical in GrDrawState and GrDrawState::DeferredState. */
     struct CommonState {
         // These fields are roughly sorted by decreasing likelihood of being different in op==
diff --git a/src/gpu/GrDrawTarget.cpp b/src/gpu/GrDrawTarget.cpp
index aa475b3..02bc8d7 100644
--- a/src/gpu/GrDrawTarget.cpp
+++ b/src/gpu/GrDrawTarget.cpp
@@ -657,9 +657,10 @@
 }
 
 GrDrawTarget::AutoStateRestore::AutoStateRestore(GrDrawTarget* target,
-                                                 ASRInit init) {
+                                                 ASRInit init,
+                                                 const SkMatrix* vm) {
     fDrawTarget = NULL;
-    this->set(target, init);
+    this->set(target, init, vm);
 }
 
 GrDrawTarget::AutoStateRestore::~AutoStateRestore() {
@@ -669,7 +670,31 @@
     }
 }
 
-void GrDrawTarget::AutoStateRestore::set(GrDrawTarget* target, ASRInit init) {
+void GrDrawTarget::AutoStateRestore::set(GrDrawTarget* target, ASRInit init, const SkMatrix* vm) {
+    GrAssert(NULL == fDrawTarget);
+    fDrawTarget = target;
+    fSavedState = target->drawState();
+    GrAssert(fSavedState);
+    fSavedState->ref();
+    if (kReset_ASRInit == init) {
+        if (NULL == vm) {
+            // calls the default cons
+            fTempState.init();
+        } else {
+            SkNEW_IN_TLAZY(&fTempState, GrDrawState, (*vm));
+        }
+    } else {
+        GrAssert(kPreserve_ASRInit == init);
+        if (NULL == vm) {
+            fTempState.set(*fSavedState);
+        } else {
+            SkNEW_IN_TLAZY(&fTempState, GrDrawState, (*fSavedState, *vm));
+        }
+    }
+    target->setDrawState(fTempState.get());
+}
+
+bool GrDrawTarget::AutoStateRestore::setIdentity(GrDrawTarget* target, ASRInit init) {
     GrAssert(NULL == fDrawTarget);
     fDrawTarget = target;
     fSavedState = target->drawState();
@@ -682,8 +707,17 @@
         GrAssert(kPreserve_ASRInit == init);
         // calls the copy cons
         fTempState.set(*fSavedState);
+        if (!fTempState.get()->setIdentityViewMatrix()) {
+            // let go of any resources held by the temp
+            fTempState.get()->reset();
+            fDrawTarget = NULL;
+            fSavedState->unref();
+            fSavedState = NULL;
+            return false;
+        }
     }
     target->setDrawState(fTempState.get());
+    return true;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/src/gpu/GrDrawTarget.h b/src/gpu/GrDrawTarget.h
index 8f5f09f..e876136 100644
--- a/src/gpu/GrDrawTarget.h
+++ b/src/gpu/GrDrawTarget.h
@@ -488,8 +488,12 @@
          *
          * @param init  Should the newly installed GrDrawState be a copy of the
          *              previous state or a default-initialized GrDrawState.
+         * @param viewMatrix Optional view matrix. If init = kPreserve then the draw state's
+         *                   matrix will be preconcat'ed with the param. All stages will be
+                             updated to compensate for the matrix change. If init == kReset
+                             then the draw state's matrix will be this matrix.
          */
-        AutoStateRestore(GrDrawTarget* target, ASRInit init);
+        AutoStateRestore(GrDrawTarget* target, ASRInit init, const SkMatrix* viewMatrix = NULL);
 
         ~AutoStateRestore();
 
@@ -501,13 +505,25 @@
          *
          * @param init  Should the newly installed GrDrawState be a copy of the
          *              previous state or a default-initialized GrDrawState.
+         * @param viewMatrix Optional view matrix. If init = kPreserve then the draw state's
+         *                   matrix will be preconcat'ed with the param. All stages will be
+                             updated to compensate for the matrix change. If init == kReset
+                             then the draw state's matrix will be this matrix.
          */
-        void set(GrDrawTarget* target, ASRInit init);
+        void set(GrDrawTarget* target, ASRInit init, const SkMatrix* viewMatrix = NULL);
+
+        /**
+         * Like set() but makes the view matrix identity. When init is kReset it is as though
+         * NULL was passed to set's viewMatrix param. When init is kPreserve it is as though
+         * the inverse view matrix was passed. If kPreserve is passed and the draw state's matrix
+         * is not invertible then this may fail.
+         */
+        bool setIdentity(GrDrawTarget* target, ASRInit init);
 
     private:
-        GrDrawTarget*        fDrawTarget;
-        SkTLazy<GrDrawState> fTempState;
-        GrDrawState*         fSavedState;
+        GrDrawTarget*                       fDrawTarget;
+        SkTLazy<GrDrawState>                fTempState;
+        GrDrawState*                        fSavedState;
     };
 
     ////////////////////////////////////////////////////////////////////////////
@@ -586,8 +602,10 @@
      */
     class AutoGeometryAndStatePush : ::GrNoncopyable {
     public:
-        AutoGeometryAndStatePush(GrDrawTarget* target, ASRInit init)
-            : fState(target, init){
+        AutoGeometryAndStatePush(GrDrawTarget* target,
+                                 ASRInit init,
+                                 const SkMatrix* viewMatrix = NULL)
+            : fState(target, init, viewMatrix) {
             GrAssert(NULL != target);
             fTarget = target;
             target->pushGeometrySource();
diff --git a/src/gpu/GrInOrderDrawBuffer.cpp b/src/gpu/GrInOrderDrawBuffer.cpp
index a0dce18..18b70dc 100644
--- a/src/gpu/GrInOrderDrawBuffer.cpp
+++ b/src/gpu/GrInOrderDrawBuffer.cpp
@@ -158,8 +158,8 @@
     // 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::AutoDeviceCoordDraw adcd(drawState);
-    if (!adcd.succeeded()) {
+    GrDrawState::AutoViewMatrixRestore avmr;
+    if (!avmr.setIdentity(drawState)) {
         return;
     }
 
diff --git a/src/gpu/GrOvalRenderer.cpp b/src/gpu/GrOvalRenderer.cpp
index dd9b19e..70b5c77 100644
--- a/src/gpu/GrOvalRenderer.cpp
+++ b/src/gpu/GrOvalRenderer.cpp
@@ -331,8 +331,8 @@
     SkScalar radius = vm.mapRadius(SkScalarHalf(circle.width()));
     SkScalar strokeWidth = vm.mapRadius(stroke.getWidth());
 
-    GrDrawState::AutoDeviceCoordDraw adcd(drawState);
-    if (!adcd.succeeded()) {
+    GrDrawState::AutoViewMatrixRestore avmr;
+    if (!avmr.setIdentity(drawState)) {
         return;
     }
 
@@ -493,8 +493,8 @@
         yRadius += scaledStroke.fY;
     }
 
-    GrDrawState::AutoDeviceCoordDraw adcd(drawState);
-    if (!adcd.succeeded()) {
+    GrDrawState::AutoViewMatrixRestore avmr;
+    if (!avmr.setIdentity(drawState)) {
         return false;
     }
 
@@ -650,8 +650,8 @@
 
     // reset to device coordinates
     GrDrawState* drawState = target->drawState();
-    GrDrawState::AutoDeviceCoordDraw adcd(drawState);
-    if (!adcd.succeeded()) {
+    GrDrawState::AutoViewMatrixRestore avmr;
+    if (!avmr.setIdentity(drawState)) {
         return false;
     }
 
diff --git a/src/gpu/GrSWMaskHelper.cpp b/src/gpu/GrSWMaskHelper.cpp
index 2cf56d6..fc34591 100644
--- a/src/gpu/GrSWMaskHelper.cpp
+++ b/src/gpu/GrSWMaskHelper.cpp
@@ -187,8 +187,8 @@
                                               const GrIRect& rect) {
     GrDrawState* drawState = target->drawState();
 
-    GrDrawState::AutoDeviceCoordDraw adcd(drawState);
-    if (!adcd.succeeded()) {
+    GrDrawState::AutoViewMatrixRestore avmr;
+    if (!avmr.setIdentity(drawState)) {
         return;
     }
     enum {
diff --git a/src/gpu/GrSoftwarePathRenderer.cpp b/src/gpu/GrSoftwarePathRenderer.cpp
index 36bdcff..21adc62 100644
--- a/src/gpu/GrSoftwarePathRenderer.cpp
+++ b/src/gpu/GrSoftwarePathRenderer.cpp
@@ -82,8 +82,8 @@
 void draw_around_inv_path(GrDrawTarget* target,
                           const GrIRect& devClipBounds,
                           const GrIRect& devPathBounds) {
-    GrDrawState::AutoDeviceCoordDraw adcd(target->drawState());
-    if (!adcd.succeeded()) {
+    GrDrawState::AutoViewMatrixRestore avmr;
+    if (!avmr.setIdentity(target->drawState())) {
         return;
     }
     GrRect rect;
diff --git a/src/gpu/GrStencilAndCoverPathRenderer.cpp b/src/gpu/GrStencilAndCoverPathRenderer.cpp
index fa87599..4f88acf 100644
--- a/src/gpu/GrStencilAndCoverPathRenderer.cpp
+++ b/src/gpu/GrStencilAndCoverPathRenderer.cpp
@@ -79,7 +79,7 @@
     // fill the path, zero out the stencil
     GrRect bounds = p->getBounds();
     SkScalar bloat = drawState->getViewMatrix().getMaxStretch() * SK_ScalarHalf;
-    GrDrawState::AutoDeviceCoordDraw adcd;
+    GrDrawState::AutoViewMatrixRestore avmr;
 
     if (nonInvertedFill == path.getFillType()) {
         GR_STATIC_CONST_SAME_STENCIL(kStencilPass,
@@ -111,7 +111,7 @@
             // theoretically could set bloat = 0, instead leave it because of matrix inversion
             // precision.
         } else {
-            adcd.set(drawState);
+            avmr.setIdentity(drawState);
             bloat = 0;
         }
         *drawState->stencil() = kInvertedStencilPass;