Clip mask manager sets stencil on draw type

BUG=skia:

Review URL: https://codereview.chromium.org/676983003
diff --git a/src/gpu/GrClipMaskManager.cpp b/src/gpu/GrClipMaskManager.cpp
index 349d51e..0738108 100644
--- a/src/gpu/GrClipMaskManager.cpp
+++ b/src/gpu/GrClipMaskManager.cpp
@@ -17,12 +17,12 @@
 #include "GrRenderTarget.h"
 #include "GrStencilBuffer.h"
 #include "GrSWMaskHelper.h"
-#include "effects/GrTextureDomain.h"
-#include "effects/GrConvexPolyEffect.h"
-#include "effects/GrRRectEffect.h"
 #include "SkRasterClip.h"
 #include "SkStrokeRec.h"
 #include "SkTLazy.h"
+#include "effects/GrTextureDomain.h"
+#include "effects/GrConvexPolyEffect.h"
+#include "effects/GrRRectEffect.h"
 
 #define GR_AA_CLIP 1
 
@@ -212,6 +212,7 @@
 // scissor, or entirely software
 bool GrClipMaskManager::setupClipping(const GrClipData* clipDataIn,
                                       GrDrawState::AutoRestoreEffects* are,
+                                      GrDrawState::AutoRestoreStencil* asr,
                                       const SkRect* devBounds) {
     fCurrClipMaskType = kNone_ClipMaskType;
 
@@ -228,7 +229,6 @@
     SkASSERT(rt);
 
     bool ignoreClip = !drawState->isClipState() || clipDataIn->fClipStack->isWideOpen();
-
     if (!ignoreClip) {
         SkIRect clipSpaceRTIBounds = SkIRect::MakeWH(rt->width(), rt->height());
         clipSpaceRTIBounds.offset(clipDataIn->fOrigin);
@@ -250,7 +250,7 @@
 
     if (ignoreClip) {
         fGpu->disableScissor();
-        this->setGpuStencil();
+        this->setDrawStateStencil(asr);
         return true;
     }
 
@@ -275,7 +275,7 @@
             } else {
                 fGpu->disableScissor();
             }
-            this->setGpuStencil();
+            this->setDrawStateStencil(asr);
             return true;
         }
     }
@@ -307,7 +307,7 @@
             are->set(fGpu->drawState());
             setup_drawstate_aaclip(fGpu, result, rtSpaceMaskBounds);
             fGpu->disableScissor();
-            this->setGpuStencil();
+            this->setDrawStateStencil(asr);
             return true;
         }
         // if alpha clip mask creation fails fall through to the non-AA code paths
@@ -335,7 +335,7 @@
     SkIRect scissorSpaceIBounds(clipSpaceIBounds);
     scissorSpaceIBounds.offset(clipSpaceToStencilSpaceOffset);
     fGpu->enableScissor(scissorSpaceIBounds);
-    this->setGpuStencil();
+    this->setDrawStateStencil(asr);
     return true;
 }
 
@@ -400,11 +400,11 @@
             // TODO: Do rects directly to the accumulator using a aa-rect GrProcessor that covers
             // the entire mask bounds and writes 0 outside the rect.
             if (element->isAA()) {
-                getContext()->getAARectRenderer()->fillAARect(fGpu,
-                                                              fGpu,
-                                                              element->getRect(),
-                                                              SkMatrix::I(),
-                                                              element->getRect());
+                this->getContext()->getAARectRenderer()->fillAARect(fGpu,
+                                                                    fGpu,
+                                                                    element->getRect(),
+                                                                    SkMatrix::I(),
+                                                                    element->getRect());
             } else {
                 fGpu->drawSimpleRect(element->getRect());
             }
@@ -707,7 +707,6 @@
     }
 
     if (stencilBuffer->mustRenderClip(elementsGenID, clipSpaceIBounds, clipSpaceToStencilOffset)) {
-
         stencilBuffer->setLastClip(elementsGenID, clipSpaceIBounds, clipSpaceToStencilOffset);
 
         // Set the matrix so that rendered clip elements are transformed from clip to stencil space.
@@ -903,7 +902,7 @@
 }
 }
 
-void GrClipMaskManager::setGpuStencil() {
+void GrClipMaskManager::setDrawStateStencil(GrDrawState::AutoRestoreStencil* ars) {
     // We make two copies of the StencilSettings here (except in the early
     // exit scenario. One copy from draw state to the stack var. Then another
     // from the stack var to the gpu. We could make this class hold a ptr to
@@ -933,7 +932,6 @@
         if (GrClipMaskManager::kRespectClip_StencilClipMode == clipMode) {
             settings = basic_apply_stencil_clip_settings();
         } else {
-            fGpu->disableStencil();
             return;
         }
     } else {
@@ -942,8 +940,7 @@
 
     // TODO: dynamically attach a stencil buffer
     int stencilBits = 0;
-    GrStencilBuffer* stencilBuffer =
-        drawState.getRenderTarget()->getStencilBuffer();
+    GrStencilBuffer* stencilBuffer = drawState.getRenderTarget()->getStencilBuffer();
     if (stencilBuffer) {
         stencilBits = stencilBuffer->bits();
     }
@@ -951,7 +948,8 @@
     SkASSERT(fGpu->caps()->stencilWrapOpsSupport() || !settings.usesWrapOp());
     SkASSERT(fGpu->caps()->twoSidedStencilSupport() || !settings.isTwoSided());
     this->adjustStencilParams(&settings, clipMode, stencilBits);
-    fGpu->setStencilSettings(settings);
+    ars->set(fGpu->drawState());
+    fGpu->drawState()->setStencil(settings);
 }
 
 void GrClipMaskManager::adjustStencilParams(GrStencilSettings* settings,
diff --git a/src/gpu/GrClipMaskManager.h b/src/gpu/GrClipMaskManager.h
index c98648b..8a4b45a 100644
--- a/src/gpu/GrClipMaskManager.h
+++ b/src/gpu/GrClipMaskManager.h
@@ -50,7 +50,9 @@
      * the manager when it must install additional effects to implement the
      * clip. devBounds is optional but can help optimize clipping.
      */
-    bool setupClipping(const GrClipData* clipDataIn, GrDrawState::AutoRestoreEffects*,
+    bool setupClipping(const GrClipData* clipDataIn,
+                       GrDrawState::AutoRestoreEffects*,
+                       GrDrawState::AutoRestoreStencil*,
                        const SkRect* devBounds);
 
     /**
@@ -173,7 +175,7 @@
      * updates the GrGpu with stencil settings that account stencil-based
      * clipping.
      */
-    void setGpuStencil();
+    void setDrawStateStencil(GrDrawState::AutoRestoreStencil* asr);
 
     /**
      * Adjusts the stencil settings to account for interaction with stencil
diff --git a/src/gpu/GrDrawState.h b/src/gpu/GrDrawState.h
index 3043fd7..71c44d4 100644
--- a/src/gpu/GrDrawState.h
+++ b/src/gpu/GrDrawState.h
@@ -346,6 +346,36 @@
         int             fCoverageEffectCnt;
     };
 
+    /**
+     * AutoRestoreStencil
+     *
+     * This simple struct saves and restores the stencil settings
+     */
+    class AutoRestoreStencil : public ::SkNoncopyable {
+    public:
+        AutoRestoreStencil() : fDrawState(NULL) {}
+
+        AutoRestoreStencil(GrDrawState* ds) : fDrawState(NULL) { this->set(ds); }
+
+        ~AutoRestoreStencil() { this->set(NULL); }
+
+        void set(GrDrawState* ds) {
+            if (fDrawState) {
+                fDrawState->setStencil(fStencilSettings);
+            }
+            fDrawState = ds;
+            if (ds) {
+                fStencilSettings = ds->getStencil();
+            }
+        }
+
+        bool isSet() const { return SkToBool(fDrawState); }
+
+    private:
+        GrDrawState*       fDrawState;
+        GrStencilSettings  fStencilSettings;
+    };
+
     /// @}
 
     ///////////////////////////////////////////////////////////////////////////
diff --git a/src/gpu/GrGpu.cpp b/src/gpu/GrGpu.cpp
index 6510048..d8ffe67 100644
--- a/src/gpu/GrGpu.cpp
+++ b/src/gpu/GrGpu.cpp
@@ -298,10 +298,12 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-bool GrGpu::setupClipAndFlushState(DrawType type, const GrDeviceCoordTexture* dstCopy,
+bool GrGpu::setupClipAndFlushState(DrawType type,
+                                   const GrDeviceCoordTexture* dstCopy,
                                    GrDrawState::AutoRestoreEffects* are,
+                                   GrDrawState::AutoRestoreStencil* ars,
                                    const SkRect* devBounds) {
-    if (!fClipMaskManager.setupClipping(this->getClip(), are, devBounds)) {
+    if (!fClipMaskManager.setupClipping(this->getClip(), are, ars, devBounds)) {
         return false;
     }
 
@@ -344,8 +346,9 @@
 void GrGpu::onDraw(const DrawInfo& info) {
     this->handleDirtyContext();
     GrDrawState::AutoRestoreEffects are;
+    GrDrawState::AutoRestoreStencil asr;
     if (!this->setupClipAndFlushState(PrimTypeToDrawType(info.primitiveType()),
-                                      info.getDstCopy(), &are, info.getDevBounds())) {
+                                      info.getDstCopy(), &are, &asr, info.getDevBounds())) {
         return;
     }
     this->onGpuDraw(info);
@@ -355,7 +358,8 @@
     this->handleDirtyContext();
 
     GrDrawState::AutoRestoreEffects are;
-    if (!this->setupClipAndFlushState(kStencilPath_DrawType, NULL, &are, NULL)) {
+    GrDrawState::AutoRestoreStencil asr;
+    if (!this->setupClipAndFlushState(kStencilPath_DrawType, NULL, &are, &asr, NULL)) {
         return;
     }
 
@@ -370,7 +374,8 @@
     drawState()->setDefaultVertexAttribs();
 
     GrDrawState::AutoRestoreEffects are;
-    if (!this->setupClipAndFlushState(kDrawPath_DrawType, dstCopy, &are, NULL)) {
+    GrDrawState::AutoRestoreStencil asr;
+    if (!this->setupClipAndFlushState(kDrawPath_DrawType, dstCopy, &are, &asr, NULL)) {
         return;
     }
 
@@ -386,7 +391,8 @@
     drawState()->setDefaultVertexAttribs();
 
     GrDrawState::AutoRestoreEffects are;
-    if (!this->setupClipAndFlushState(kDrawPaths_DrawType, dstCopy, &are, NULL)) {
+    GrDrawState::AutoRestoreStencil asr;
+    if (!this->setupClipAndFlushState(kDrawPaths_DrawType, dstCopy, &are, &asr, NULL)) {
         return;
     }
 
diff --git a/src/gpu/GrGpu.h b/src/gpu/GrGpu.h
index e4669a2..5ce2528 100644
--- a/src/gpu/GrGpu.h
+++ b/src/gpu/GrGpu.h
@@ -306,18 +306,6 @@
     }
     void disableScissor() { fScissorState.fEnabled = false; }
 
-    /**
-     * Like the scissor methods above this is called by setupClipping and
-     * should be flushed by the GrGpu subclass in flushGraphicsState. These
-     * stencil settings should be used in place of those on the GrDrawState.
-     * They have been adjusted to account for any interactions between the
-     * GrDrawState's stencil settings and stencil clipping.
-     */
-    void setStencilSettings(const GrStencilSettings& settings) {
-        fStencilSettings = settings;
-    }
-    void disableStencil() { fStencilSettings.setDisabled(); }
-
     // GrGpu subclass sets clip bit in the stencil buffer. The subclass is
     // free to clear the remaining bits to zero if masked clears are more
     // expensive than clearing all bits.
@@ -369,7 +357,8 @@
     // prepares clip flushes gpu state before a draw
     bool setupClipAndFlushState(DrawType,
                                 const GrDeviceCoordTexture* dstCopy,
-                                GrDrawState::AutoRestoreEffects* are,
+                                GrDrawState::AutoRestoreEffects*,
+                                GrDrawState::AutoRestoreStencil*,
                                 const SkRect* devBounds);
 
     // Functions used to map clip-respecting stencil tests into normal
@@ -404,9 +393,6 @@
         SkIRect fRect;
     } fScissorState;
 
-    // The final stencil settings to use as determined by the clip manager.
-    GrStencilSettings fStencilSettings;
-
     // Helpers for setting up geometry state
     void finalizeReservedVertices();
     void finalizeReservedIndices();
diff --git a/src/gpu/gl/GrGpuGL.cpp b/src/gpu/gl/GrGpuGL.cpp
index c83a668..75c9b3a 100644
--- a/src/gpu/gl/GrGpuGL.cpp
+++ b/src/gpu/gl/GrGpuGL.cpp
@@ -1904,9 +1904,9 @@
 }
 }
 
-void GrGpuGL::flushStencil(DrawType type) {
-    if (kStencilPath_DrawType != type && fHWStencilSettings != fStencilSettings) {
-        if (fStencilSettings.isDisabled()) {
+void GrGpuGL::flushStencil(const GrStencilSettings& stencilSettings, DrawType type) {
+    if (kStencilPath_DrawType != type && fHWStencilSettings != stencilSettings) {
+        if (stencilSettings.isDisabled()) {
             if (kNo_TriState != fHWStencilTestEnabled) {
                 GL_CALL(Disable(GR_GL_STENCIL_TEST));
                 fHWStencilTestEnabled = kNo_TriState;
@@ -1917,24 +1917,24 @@
                 fHWStencilTestEnabled = kYes_TriState;
             }
         }
-        if (!fStencilSettings.isDisabled()) {
+        if (!stencilSettings.isDisabled()) {
             if (this->caps()->twoSidedStencilSupport()) {
                 set_gl_stencil(this->glInterface(),
-                               fStencilSettings,
+                               stencilSettings,
                                GR_GL_FRONT,
                                GrStencilSettings::kFront_Face);
                 set_gl_stencil(this->glInterface(),
-                               fStencilSettings,
+                               stencilSettings,
                                GR_GL_BACK,
                                GrStencilSettings::kBack_Face);
             } else {
                 set_gl_stencil(this->glInterface(),
-                               fStencilSettings,
+                               stencilSettings,
                                GR_GL_FRONT_AND_BACK,
                                GrStencilSettings::kFront_Face);
             }
         }
-        fHWStencilSettings = fStencilSettings;
+        fHWStencilSettings = stencilSettings;
     }
 }
 
diff --git a/src/gpu/gl/GrGpuGL.h b/src/gpu/gl/GrGpuGL.h
index 24ab4ec..f18962c 100644
--- a/src/gpu/gl/GrGpuGL.h
+++ b/src/gpu/gl/GrGpuGL.h
@@ -235,7 +235,7 @@
     // NULL means whole target. Can be an empty rect.
     void flushRenderTarget(GrGLRenderTarget*, const SkIRect* bounds);
 
-    void flushStencil(DrawType);
+    void flushStencil(const GrStencilSettings&, DrawType);
     void flushAAState(const GrOptDrawState&, DrawType);
 
     bool configToGLFormats(GrPixelConfig config,
diff --git a/src/gpu/gl/GrGpuGL_program.cpp b/src/gpu/gl/GrGpuGL_program.cpp
index 6a09ebf..ecfd813 100644
--- a/src/gpu/gl/GrGpuGL_program.cpp
+++ b/src/gpu/gl/GrGpuGL_program.cpp
@@ -258,7 +258,7 @@
     }
 
     GrGLRenderTarget* glRT = static_cast<GrGLRenderTarget*>(optState->getRenderTarget());
-    this->flushStencil(type);
+    this->flushStencil(optState->getStencil(), type);
     this->flushScissor(glRT->getViewport(), glRT->origin());
     this->flushAAState(*optState.get(), type);