Modifications to GrPatherRenderer(Chain) interfaces to support clip mask manager.

R=robertphillips@google.com
Review URL: https://codereview.appspot.com/6904069

git-svn-id: http://skia.googlecode.com/svn/trunk@6741 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gyp/gpu.gypi b/gyp/gpu.gypi
index 3a6b1f2..7d3c0f2 100644
--- a/gyp/gpu.gypi
+++ b/gyp/gpu.gypi
@@ -25,6 +25,7 @@
       '<(skia_include_path)/gpu/GrKey.h',
       '<(skia_include_path)/gpu/GrNoncopyable.h',
       '<(skia_include_path)/gpu/GrPaint.h',
+      '<(skia_include_path)/gpu/GrPathRendererChain.h',
       '<(skia_include_path)/gpu/GrPoint.h',
       '<(skia_include_path)/gpu/GrRect.h',
       '<(skia_include_path)/gpu/GrRefCnt.h',
@@ -85,7 +86,6 @@
       '<(skia_src_path)/gpu/GrPath.cpp',
       '<(skia_src_path)/gpu/GrPath.h',
       '<(skia_src_path)/gpu/GrPathRendererChain.cpp',
-      '<(skia_src_path)/gpu/GrPathRendererChain.h',
       '<(skia_src_path)/gpu/GrPathRenderer.cpp',
       '<(skia_src_path)/gpu/GrPathRenderer.h',
       '<(skia_src_path)/gpu/GrPathUtils.cpp',
diff --git a/include/core/SkTLazy.h b/include/core/SkTLazy.h
index cd1e8f2..315bd95 100644
--- a/include/core/SkTLazy.h
+++ b/include/core/SkTLazy.h
@@ -116,10 +116,21 @@
 public:
     SkTCopyOnFirstWrite(const T& initial) : fObj(&initial) {}
 
+    // Constructor for delayed initialization.
+    SkTCopyOnFirstWrite() : fObj(NULL) {}
+
+    // Should only be called once, and only if the default constructor was used.
+    void init(const T& initial) {
+        SkASSERT(NULL == fObj);
+        SkASSERT(!fLazy.isValid());
+        fObj = &initial;
+    }
+
     /**
      * Returns a writable T*. The first time this is called the initial object is cloned.
      */
     T* writable() {
+        SkASSERT(NULL != fObj);
         if (!fLazy.isValid()) {
             fLazy.set(*fObj);
             fObj = fLazy.get();
diff --git a/include/gpu/GrContext.h b/include/gpu/GrContext.h
index 9bd6f7d..d6a91eb 100644
--- a/include/gpu/GrContext.h
+++ b/include/gpu/GrContext.h
@@ -15,6 +15,7 @@
 #include "GrClipData.h"
 #include "SkMatrix.h"
 #include "GrPaint.h"
+#include "GrPathRendererChain.h"
 // not strictly needed but requires WK change in LayerTextureUpdaterCanvas to
 // remove.
 #include "GrRenderTarget.h"
@@ -32,7 +33,6 @@
 class GrIndexBufferAllocPool;
 class GrInOrderDrawBuffer;
 class GrPathRenderer;
-class GrPathRendererChain;
 class GrResourceEntry;
 class GrResourceCache;
 class GrStencilBuffer;
@@ -851,11 +851,13 @@
     void addStencilBuffer(GrStencilBuffer* sb);
     GrStencilBuffer* findStencilBuffer(int width, int height, int sampleCnt);
 
-    GrPathRenderer* getPathRenderer(const SkPath& path,
-                                    const SkStroke& stroke,
-                                    const GrDrawTarget* target,
-                                    bool antiAlias,
-                                    bool allowSW);
+    GrPathRenderer* getPathRenderer(
+                    const SkPath& path,
+                    const SkStroke& stroke,
+                    const GrDrawTarget* target,
+                    bool allowSW,
+                    GrPathRendererChain::DrawType drawType = GrPathRendererChain::kColor_DrawType,
+                    GrPathRendererChain::StencilSupport* stencilSupport = NULL);
 
 #if GR_CACHE_STATS
     void printCacheStats() const;
diff --git a/include/gpu/GrPathRendererChain.h b/include/gpu/GrPathRendererChain.h
new file mode 100644
index 0000000..8b74ba3
--- /dev/null
+++ b/include/gpu/GrPathRendererChain.h
@@ -0,0 +1,83 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#ifndef GrPathRendererChain_DEFINED
+#define GrPathRendererChain_DEFINED
+
+#include "GrRefCnt.h"
+#include "SkTArray.h"
+
+class GrContext;
+class GrDrawTarget;
+class GrPathRenderer;
+class SkPath;
+class SkStroke;
+
+/**
+ * Keeps track of an ordered list of path renderers. When a path needs to be
+ * drawn this list is scanned to find the most preferred renderer. To add your
+ * path renderer to the list implement the GrPathRenderer::AddPathRenderers
+ * function.
+ */
+class GrPathRendererChain : public SkRefCnt {
+public:
+    // See comments in GrPathRenderer.h
+    enum StencilSupport {
+        kNoSupport_StencilSupport,
+        kStencilOnly_StencilSupport,
+        kNoRestriction_StencilSupport,
+    };
+
+    SK_DECLARE_INST_COUNT(GrPathRendererChain)
+
+    GrPathRendererChain(GrContext* context);
+
+    ~GrPathRendererChain();
+
+    // takes a ref and unrefs in destructor
+    GrPathRenderer* addPathRenderer(GrPathRenderer* pr);
+
+    /** Documents how the caller plans to use a GrPathRenderer to draw a path. It affects the PR
+        returned by getPathRenderer */
+    enum DrawType {
+        kColor_DrawType,                    // draw to the color buffer, no AA
+        kColorAntiAlias_DrawType,           // draw to color buffer, with partial coverage AA
+        kStencilOnly_DrawType,              // draw just to the stencil buffer
+        kStencilAndColor_DrawType,          // draw the stencil and color buffer, no AA
+        kStencilAndColorAntiAlias_DrawType  // draw the stencil and color buffer, with partial
+                                            // coverage AA.
+    };
+    /** Returns a GrPathRenderer compatible with the request if one is available. If the caller
+        is drawing the path to the stencil buffer then stencilSupport can be used to determine
+        whether the path can be rendered with arbitrary stencil rules or not. See comments on
+        StencilSupport in GrPathRenderer.h. */     
+    GrPathRenderer* getPathRenderer(const SkPath& path,
+                                    const SkStroke& stroke,
+                                    const GrDrawTarget* target,
+                                    DrawType drawType,
+                                    StencilSupport* stencilSupport);
+
+private:
+
+    GrPathRendererChain();
+
+    void init();
+
+    enum {
+        kPreAllocCount = 8,
+    };
+    bool fInit;
+    GrContext*                                          fOwner;
+    SkSTArray<kPreAllocCount, GrPathRenderer*, true>    fChain;
+
+    typedef SkRefCnt INHERITED;
+};
+
+
+#endif
diff --git a/src/gpu/GrAddPathRenderers_default.cpp b/src/gpu/GrAddPathRenderers_default.cpp
index 24f1017..9be6768 100644
--- a/src/gpu/GrAddPathRenderers_default.cpp
+++ b/src/gpu/GrAddPathRenderers_default.cpp
@@ -12,17 +12,12 @@
 #include "GrAAConvexPathRenderer.h"
 #include "GrSoftwarePathRenderer.h"
 
-void GrPathRenderer::AddPathRenderers(GrContext* ctx,
-                                      GrPathRendererChain::UsageFlags flags,
-                                      GrPathRendererChain* chain) {
+void GrPathRenderer::AddPathRenderers(GrContext* ctx, GrPathRendererChain* chain) {
     if (GrPathRenderer* pr = GrStencilAndCoverPathRenderer::Create(ctx)) {
         chain->addPathRenderer(pr)->unref();
     }
-    if (!(GrPathRendererChain::kNonAAOnly_UsageFlag & flags)) {
-
-        if (GrPathRenderer* pr = GrAAHairLinePathRenderer::Create(ctx)) {
-            chain->addPathRenderer(pr)->unref();
-        }
-        chain->addPathRenderer(SkNEW(GrAAConvexPathRenderer))->unref();
+    if (GrPathRenderer* pr = GrAAHairLinePathRenderer::Create(ctx)) {
+        chain->addPathRenderer(pr)->unref();
     }
+    chain->addPathRenderer(SkNEW(GrAAConvexPathRenderer))->unref();
 }
diff --git a/src/gpu/GrClipMaskManager.cpp b/src/gpu/GrClipMaskManager.cpp
index c400486..11b301d 100644
--- a/src/gpu/GrClipMaskManager.cpp
+++ b/src/gpu/GrClipMaskManager.cpp
@@ -70,7 +70,11 @@
         path.writable()->toggleInverseFillType();
     }
     // last (false) parameter disallows use of the SW path renderer
-    return NULL == context->getPathRenderer(*path, stroke, gpu, doAA, false);
+    GrPathRendererChain::DrawType type = doAA ?
+                                         GrPathRendererChain::kColorAntiAlias_DrawType :
+                                         GrPathRendererChain::kColor_DrawType;
+
+    return NULL == context->getPathRenderer(*path, stroke, gpu, false, type);
 }
 
 }
@@ -313,10 +317,14 @@
             }
             SkStroke stroke;
             stroke.setDoFill(true);
+            GrPathRendererChain::DrawType type = element->isAA() ?
+                GrPathRendererChain::kColorAntiAlias_DrawType :
+                GrPathRendererChain::kColor_DrawType;
             GrPathRenderer* pr = this->getContext()->getPathRenderer(*path,
                                                                      stroke,
                                                                      fGpu,
-                                                                     element->isAA(), false);
+                                                                     false,
+                                                                     type);
             if (NULL == pr) {
                 return false;
             }
@@ -580,10 +588,9 @@
                 drawState->setState(GrDrawState::kHWAntialias_StateBit, element->isAA());
             }
 
-            // Can the clip element be drawn directly to the stencil buffer
-            // with a non-inverted fill rule without extra passes to
-            // resolve in/out status?
-            bool canRenderDirectToStencil = false;
+            // This will be used to determine whether the clip shape can be rendered into the
+            // stencil with arbitrary stencil settings.
+            GrPathRenderer::StencilSupport stencilSupport;
 
             SkStroke stroke;
             stroke.setDoFill(true);
@@ -591,29 +598,37 @@
             SkRegion::Op op = element->getOp();
 
             GrPathRenderer* pr = NULL;
-            SkPath clipPath;
+            SkTCopyOnFirstWrite<SkPath> clipPath;
             if (Element::kRect_Type == element->getType()) {
-                canRenderDirectToStencil = true;
+                stencilSupport = GrPathRenderer::kNoRestriction_StencilSupport;
                 fill = SkPath::kEvenOdd_FillType;
                 fillInverted = false;
             } else {
                 GrAssert(Element::kPath_Type == element->getType());
-                clipPath = element->getPath();
-                fill = clipPath.getFillType();
-                fillInverted = clipPath.isInverseFillType();
-                fill = SkPath::NonInverseFill(fill);
-                clipPath.setFillType(fill);
-                pr = this->getContext()->getPathRenderer(clipPath, stroke, fGpu, false, true);
+                clipPath.init(element->getPath());
+                fill = clipPath->getFillType();
+                fillInverted = clipPath->isInverseFillType();
+                if (fillInverted) {
+                    clipPath.writable()->toggleInverseFillType();
+                    fill = clipPath->getFillType();
+                }
+                pr = this->getContext()->getPathRenderer(*clipPath,
+                                                         stroke,
+                                                         fGpu,
+                                                         false,
+                                                         GrPathRendererChain::kStencilOnly_DrawType,
+                                                         &stencilSupport);
                 if (NULL == pr) {
                     fGpu->setClip(oldClipData);
                     return false;
                 }
-                canRenderDirectToStencil = !pr->requiresStencilPass(clipPath, stroke, fGpu);
             }
 
             int passes;
             GrStencilSettings stencilSettings[GrStencilSettings::kMaxStencilClipPasses];
 
+            bool canRenderDirectToStencil =
+                GrPathRenderer::kNoRestriction_StencilSupport == stencilSupport;
             bool canDrawDirectToClip; // Given the renderer, the element,
                                       // fill rule, and set operation can
                                       // we render the element directly to
@@ -642,9 +657,9 @@
                     GrAssert(Element::kPath_Type == element->getType());
                     if (canRenderDirectToStencil) {
                         *drawState->stencil() = gDrawToStencil;
-                        pr->drawPath(clipPath, stroke, fGpu, false);
+                        pr->drawPath(*clipPath, stroke, fGpu, false);
                     } else {
-                        pr->drawPathToStencil(clipPath, stroke, fGpu);
+                        pr->stencilPath(*clipPath, stroke, fGpu);
                     }
                 }
             }
@@ -661,7 +676,7 @@
                     } else {
                         GrAssert(Element::kPath_Type == element->getType());
                         SET_RANDOM_COLOR
-                        pr->drawPath(clipPath, stroke, fGpu, false);
+                        pr->drawPath(*clipPath, stroke, fGpu, false);
                     }
                 } else {
                     SET_RANDOM_COLOR
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index d96a16e..c39ee75 100644
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -1112,7 +1112,10 @@
         prAA = false;
     }
 
-    GrPathRenderer* pr = this->getPathRenderer(path, stroke, target, prAA, true);
+    GrPathRendererChain::DrawType type = prAA ? GrPathRendererChain::kColorAntiAlias_DrawType :
+                                                GrPathRendererChain::kColor_DrawType;
+
+    GrPathRenderer* pr = this->getPathRenderer(path, stroke, target, true, type);
     if (NULL == pr) {
 #if GR_DEBUG
         GrPrintf("Unable to find path renderer compatible with path.\n");
@@ -1620,24 +1623,24 @@
 GrPathRenderer* GrContext::getPathRenderer(const SkPath& path,
                                            const SkStroke& stroke,
                                            const GrDrawTarget* target,
-                                           bool antiAlias,
-                                           bool allowSW) {
+                                           bool allowSW,
+                                           GrPathRendererChain::DrawType drawType,
+                                           GrPathRendererChain::StencilSupport* stencilSupport) {
+
     if (NULL == fPathRendererChain) {
-        fPathRendererChain =
-            SkNEW_ARGS(GrPathRendererChain,
-                       (this, GrPathRendererChain::kNone_UsageFlag));
+        fPathRendererChain = SkNEW_ARGS(GrPathRendererChain, (this));
     }
 
     GrPathRenderer* pr = fPathRendererChain->getPathRenderer(path,
                                                              stroke,
                                                              target,
-                                                             antiAlias);
+                                                             drawType,
+                                                             stencilSupport);
 
     if (NULL == pr && allowSW) {
         if (NULL == fSoftwarePathRenderer) {
             fSoftwarePathRenderer = SkNEW_ARGS(GrSoftwarePathRenderer, (this));
         }
-
         pr = fSoftwarePathRenderer;
     }
 
diff --git a/src/gpu/GrDefaultPathRenderer.cpp b/src/gpu/GrDefaultPathRenderer.cpp
index f80b4d7..b92b77d 100644
--- a/src/gpu/GrDefaultPathRenderer.cpp
+++ b/src/gpu/GrDefaultPathRenderer.cpp
@@ -162,10 +162,15 @@
 #endif
 }
 
-bool GrDefaultPathRenderer::requiresStencilPass(const SkPath& path,
-                                                const SkStroke& stroke,
-                                                const GrDrawTarget* target) const {
-    return !single_pass_path(path, stroke);
+GrPathRenderer::StencilSupport GrDefaultPathRenderer::onGetStencilSupport(
+                                                            const SkPath& path,
+                                                            const SkStroke& stroke,
+                                                            const GrDrawTarget*) const {
+    if (single_pass_path(path, stroke)) {
+        return GrPathRenderer::kNoRestriction_StencilSupport;
+    } else {
+        return GrPathRenderer::kStencilOnly_StencilSupport;
+    }
 }
 
 static inline void append_countour_edge_indices(bool hairLine,
@@ -508,9 +513,9 @@
                                   false);
 }
 
-void GrDefaultPathRenderer::drawPathToStencil(const SkPath& path,
-                                              const SkStroke& stroke,
-                                              GrDrawTarget* target) {
+void GrDefaultPathRenderer::onStencilPath(const SkPath& path,
+                                          const SkStroke& stroke,
+                                          GrDrawTarget* target) {
     GrAssert(SkPath::kInverseEvenOdd_FillType != path.getFillType());
     GrAssert(SkPath::kInverseWinding_FillType != path.getFillType());
     this->internalDrawPath(path, stroke, target, true);
diff --git a/src/gpu/GrDefaultPathRenderer.h b/src/gpu/GrDefaultPathRenderer.h
index e98f2d7..657537a 100644
--- a/src/gpu/GrDefaultPathRenderer.h
+++ b/src/gpu/GrDefaultPathRenderer.h
@@ -12,48 +12,46 @@
 #include "SkTemplates.h"
 
 /**
- *  Subclass that renders the path using the stencil buffer to resolve fill
- *  rules (e.g. winding, even-odd)
+ *  Subclass that renders the path using the stencil buffer to resolve fill rules
+ * (e.g. winding, even-odd)
  */
 class GR_API GrDefaultPathRenderer : public GrPathRenderer {
 public:
-    GrDefaultPathRenderer(bool separateStencilSupport,
-                          bool stencilWrapOpsSupport);
+    GrDefaultPathRenderer(bool separateStencilSupport, bool stencilWrapOpsSupport);
 
-
-    virtual bool requiresStencilPass(const SkPath& path,
-                                     const SkStroke& stroke,
-                                     const GrDrawTarget* target) const SK_OVERRIDE;
-
-    virtual bool canDrawPath(const SkPath& path,
-                             const SkStroke& stroke,
-                             const GrDrawTarget* target,
+    virtual bool canDrawPath(const SkPath&,
+                             const SkStroke&,
+                             const GrDrawTarget*,
                              bool antiAlias) const SK_OVERRIDE;
 
-    virtual void drawPathToStencil(const SkPath& path,
-                                   const SkStroke& stroke,
-                                   GrDrawTarget* target) SK_OVERRIDE;
-
 private:
 
-    virtual bool onDrawPath(const SkPath& path,
-                            const SkStroke& stroke,
-                            GrDrawTarget* target,
+    virtual StencilSupport onGetStencilSupport(const SkPath&,
+                                               const SkStroke&,
+                                               const GrDrawTarget*) const SK_OVERRIDE;
+
+    virtual bool onDrawPath(const SkPath&,
+                            const SkStroke&,
+                            GrDrawTarget*,
                             bool antiAlias) SK_OVERRIDE;
 
-    bool internalDrawPath(const SkPath& path,
-                          const SkStroke& stroke,
-                          GrDrawTarget* target,
+    virtual void onStencilPath(const SkPath&,
+                               const SkStroke&,
+                               GrDrawTarget*) SK_OVERRIDE;
+
+    bool internalDrawPath(const SkPath&,
+                          const SkStroke&,
+                          GrDrawTarget*,
                           bool stencilOnly);
 
-    bool createGeom(const SkPath& path,
-                    const SkStroke& stroke,
+    bool createGeom(const SkPath&,
+                    const SkStroke&,
                     SkScalar srcSpaceTol,
-                    GrDrawTarget* target,
-                    GrPrimitiveType* primType,
+                    GrDrawTarget*,
+                    GrPrimitiveType*,
                     int* vertexCnt,
                     int* indexCnt,
-                    GrDrawTarget::AutoReleaseGeometry* arg);
+                    GrDrawTarget::AutoReleaseGeometry*);
 
     bool    fSeparateStencil;
     bool    fStencilWrapOps;
diff --git a/src/gpu/GrPathRenderer.h b/src/gpu/GrPathRenderer.h
index afcd3c9..9d52566 100644
--- a/src/gpu/GrPathRenderer.h
+++ b/src/gpu/GrPathRenderer.h
@@ -12,72 +12,86 @@
 
 #include "GrDrawTarget.h"
 #include "GrPathRendererChain.h"
+#include "GrStencil.h"
 
+#include "SkStroke.h"
 #include "SkTArray.h"
 
 class SkPath;
-class SkStroke;
 
 struct GrPoint;
 
 /**
  *  Base class for drawing paths into a GrDrawTarget.
  *
- *  Derived classes can use stages GrPaint::kTotalStages through
- *  GrDrawState::kNumStages-1. The stages before GrPaint::kTotalStages
- *  are reserved for setting up the draw (i.e., textures and filter masks).
+ *  Derived classes can use stages GrPaint::kTotalStages through GrDrawState::kNumStages-1. The
+ *  stages before GrPaint::kTotalStages are reserved for setting up the draw (i.e., textures and
+ *  filter masks).
  */
 class GR_API GrPathRenderer : public GrRefCnt {
 public:
     SK_DECLARE_INST_COUNT(GrPathRenderer)
 
     /**
-     * This is called to install custom path renderers in every GrContext at
-     * create time. The default implementation in GrCreatePathRenderer_none.cpp
-     * does not add any additional renderers. Link against another
-     * implementation to install your own. The first added is the most preferred
-     * path renderer, second is second most preferred, etc.
+     * This is called to install custom path renderers in every GrContext at create time. The
+     * default implementation in GrCreatePathRenderer_none.cpp does not add any additional
+     * renderers. Link against another implementation to install your own. The first added is the
+     * most preferred path renderer, second is second most preferred, etc.
      *
      * @param context   the context that will use the path renderer
-     * @param flags     flags indicating how path renderers will be used
      * @param prChain   the chain to add path renderers to.
      */
-    static void AddPathRenderers(GrContext* context,
-                                 GrPathRendererChain::UsageFlags flags,
-                                 GrPathRendererChain* prChain);
+    static void AddPathRenderers(GrContext* context, GrPathRendererChain* prChain);
 
 
     GrPathRenderer();
 
     /**
-     * For complex clips Gr uses the stencil buffer. The path renderer must be
-     * able to render paths into the stencil buffer. However, the path renderer
-     * itself may require the stencil buffer to resolve the path fill rule.
-     * This function queries whether the path render needs its own stencil
-     * pass. If this returns false then drawPath() should not modify the
-     * the target's stencil settings but use those already set on target. The
-     * target is passed as a param in case the answer depends upon draw state.
+     * A caller may wish to use a path renderer to draw a path into the stencil buffer. However,
+     * the path renderer itself may require use of the stencil buffer. Also a path renderer may
+     * use a GrEffect coverage stage that sets coverage to zero to eliminate pixels that are covered
+     * by bounding geometry but outside the path. These exterior pixels would still be rendered into
+     * the stencil.
+     *
+     * A GrPathRenderer can provide three levels of support for stenciling paths:
+     * 1) kNoRestriction: This is the most general. The caller sets up the GrDrawState on the target
+     *                    and calls drawPath(). The path is rendered exactly as the draw state
+     *                    indicates including support for simultaneous color and stenciling with
+     *                    arbitrary stenciling rules. Pixels partially covered by AA paths are
+     *                    affected by the stencil settings.
+     * 2) kStencilOnly: The path renderer cannot apply arbitrary stencil rules nor shade and stencil
+     *                  simultaneously. The path renderer does support the stencilPath() function
+     *                  which performs no color writes and writes a non-zero stencil value to pixels
+     *                  covered by the path.
+     * 3) kNoSupport: This path renderer cannot be used to stencil the path.
+     */
+    typedef GrPathRendererChain::StencilSupport StencilSupport;
+    static const StencilSupport kNoSupport_StencilSupport =
+        GrPathRendererChain::kNoSupport_StencilSupport;
+    static const StencilSupport kStencilOnly_StencilSupport =
+        GrPathRendererChain::kStencilOnly_StencilSupport;
+    static const StencilSupport kNoRestriction_StencilSupport =
+        GrPathRendererChain::kNoRestriction_StencilSupport;
+
+    /**
+     * This function is to get the stencil support for a particular path. The path's fill must
+     * not be an inverse type.
      *
      * @param target    target that the path will be rendered to
      * @param path      the path that will be drawn
      * @param stroke    the stroke information (width, join, cap).
-     *
-     * @return false if this path renderer can generate interior-only fragments
-     *         without changing the stencil settings on the target. If it
-     *         returns true the drawPathToStencil will be used when rendering
-     *         clips.
      */
-    virtual bool requiresStencilPass(const SkPath& path,
+    StencilSupport getStencilSupport(const SkPath& path,
                                      const SkStroke& stroke,
                                      const GrDrawTarget* target) const {
-        return false;
+        GrAssert(!path.isInverseFillType());
+        return this->onGetStencilSupport(path, stroke, target);
     }
 
     /**
-     * Returns true if this path renderer is able to render the path.
-     * Returning false allows the caller to fallback to another path renderer
-     * This function is called when searching for a path renderer capable of
-     * rendering a path.
+     * Returns true if this path renderer is able to render the path. Returning false allows the
+     * caller to fallback to another path renderer This function is called when searching for a path
+     * renderer capable of rendering a path.
      *
      * @param path       The path to draw
      * @param stroke     The stroke information (width, join, cap)
@@ -91,55 +105,72 @@
                              const GrDrawTarget* target,
                              bool antiAlias) const = 0;
     /**
-     * Draws the path into the draw target. If requiresStencilBuffer returned
-     * false then the target may be setup for stencil rendering (since the
-     * path renderer didn't claim that it needs to use the stencil internally).
+     * Draws the path into the draw target. If getStencilSupport() would return kNoRestriction then
+     * the subclass must respect the stencil settings of the target's draw state.
      *
      * @param path                  the path to draw.
      * @param stroke                the stroke information (width, join, cap)
      * @param target                target that the path will be rendered to
      * @param antiAlias             true if anti-aliasing is required.
      */
-    virtual bool drawPath(const SkPath& path,
-                          const SkStroke& stroke,
-                          GrDrawTarget* target,
-                          bool antiAlias) {
+    bool drawPath(const SkPath& path,
+                  const SkStroke& stroke,
+                  GrDrawTarget* target,
+                  bool antiAlias) {
         GrAssert(this->canDrawPath(path, stroke, target, antiAlias));
         return this->onDrawPath(path, stroke, target, antiAlias);
     }
 
     /**
-     * Draws the path to the stencil buffer. Assume the writable stencil bits
-     * are already initialized to zero. Fill will always be either
-     * kWinding_FillType or kEvenOdd_FillType.
-     *
-     * Only called if requiresStencilPass returns true for the same combo of
-     * target, path, and fill. Never called with an inverse fill.
-     *
-     * The default implementation assumes the path filling algorithm doesn't
-     * require a separate stencil pass and so crashes.
-     *
-     */
-    virtual void drawPathToStencil(const SkPath& path,
-                                   const SkStroke& stroke,
-                                   GrDrawTarget* target) {
-        GrCrash("Unexpected call to drawPathToStencil.");
-    }
-
-protected:
-    /**
-     * Draws the path into the draw target.
+     * Draws the path to the stencil buffer. Assume the writable stencil bits are already
+     * initialized to zero. The pixels inside the path will have non-zero stencil values afterwards.
      *
      * @param path                  the path to draw.
      * @param stroke                the stroke information (width, join, cap)
      * @param target                target that the path will be rendered to
-     * @param antiAlias             whether antialiasing is enabled or not.
+     */
+    void stencilPath(const SkPath& path, const SkStroke& stroke, GrDrawTarget* target) {
+        GrAssert(kNoSupport_StencilSupport != this->getStencilSupport(path, stroke, target));
+        this->onStencilPath(path, stroke, target);
+    }
+
+protected:
+    /**
+     * Subclass overrides if it has any limitations of stenciling support.
+     */
+    virtual StencilSupport onGetStencilSupport(const SkPath&,
+                                               const SkStroke&,
+                                               const GrDrawTarget*) const {
+        return kNoRestriction_StencilSupport;
+    }
+
+    /**
+     * Subclass implementation of drawPath()
      */
     virtual bool onDrawPath(const SkPath& path,
                             const SkStroke& stroke,
                             GrDrawTarget* target,
                             bool antiAlias) = 0;
 
+    /**
+     * Subclass implementation of stencilPath(). Subclass must override iff it ever returns
+     * kStencilOnly in onGetStencilSupport().
+     */
+    virtual void onStencilPath(const SkPath& path,  const SkStroke& stroke, GrDrawTarget* target) {
+        GrDrawTarget::AutoStateRestore asr(target, GrDrawTarget::kPreserve_ASRInit);
+        GrDrawState* drawState = target->drawState();
+        GR_STATIC_CONST_SAME_STENCIL(kIncrementStencil,
+                                     kReplace_StencilOp,
+                                     kReplace_StencilOp,
+                                     kAlways_StencilFunc,
+                                     0xffff,
+                                     0xffff,
+                                     0xffff);
+        drawState->setStencil(kIncrementStencil);
+        drawState->enableState(GrDrawState::kNoColorWrites_StateBit);
+        this->drawPath(path, stroke, target, false);
+    }
+
 private:
 
     typedef GrRefCnt INHERITED;
diff --git a/src/gpu/GrPathRendererChain.cpp b/src/gpu/GrPathRendererChain.cpp
index 8ccafcf..6cb45fa 100644
--- a/src/gpu/GrPathRendererChain.cpp
+++ b/src/gpu/GrPathRendererChain.cpp
@@ -15,10 +15,9 @@
 
 SK_DEFINE_INST_COUNT(GrPathRendererChain)
 
-GrPathRendererChain::GrPathRendererChain(GrContext* context, UsageFlags flags)
+GrPathRendererChain::GrPathRendererChain(GrContext* context)
     : fInit(false)
-    , fOwner(context)
-    , fFlags(flags) {
+    , fOwner(context) {
 }
 
 GrPathRendererChain::~GrPathRendererChain() {
@@ -36,12 +35,41 @@
 GrPathRenderer* GrPathRendererChain::getPathRenderer(const SkPath& path,
                                                      const SkStroke& stroke,
                                                      const GrDrawTarget* target,
-                                                     bool antiAlias) {
+                                                     DrawType drawType,
+                                                     StencilSupport* stencilSupport) {
     if (!fInit) {
         this->init();
     }
+    bool antiAlias = (kColorAntiAlias_DrawType == drawType ||
+                      kStencilAndColorAntiAlias_DrawType == drawType);
+
+    GR_STATIC_ASSERT(GrPathRenderer::kNoSupport_StencilSupport <
+                     GrPathRenderer::kStencilOnly_StencilSupport);
+    GR_STATIC_ASSERT(GrPathRenderer::kStencilOnly_StencilSupport <
+                     GrPathRenderer::kNoRestriction_StencilSupport);
+    GrPathRenderer::StencilSupport minStencilSupport;
+    if (kStencilOnly_DrawType == drawType) {
+        minStencilSupport = GrPathRenderer::kStencilOnly_StencilSupport;
+    } else if (kStencilAndColor_DrawType == drawType ||
+               kStencilAndColorAntiAlias_DrawType == drawType) {
+        minStencilSupport = GrPathRenderer::kNoRestriction_StencilSupport;
+    } else {
+        minStencilSupport = GrPathRenderer::kNoSupport_StencilSupport;
+    }
+
+
     for (int i = 0; i < fChain.count(); ++i) {
         if (fChain[i]->canDrawPath(path, stroke, target, antiAlias)) {
+            if (GrPathRenderer::kNoSupport_StencilSupport != minStencilSupport) {
+                GrPathRenderer::StencilSupport support = fChain[i]->getStencilSupport(path,
+                                                                                      stroke,
+                                                                                      target);
+                if (support < minStencilSupport) {
+                    continue;
+                } else if (NULL != stencilSupport) {
+                    *stencilSupport = support;
+                }
+            }
             return fChain[i];
         }
     }
@@ -53,7 +81,7 @@
     GrGpu* gpu = fOwner->getGpu();
     bool twoSided = gpu->getCaps().twoSidedStencilSupport();
     bool wrapOp = gpu->getCaps().stencilWrapOpsSupport();
-    GrPathRenderer::AddPathRenderers(fOwner, fFlags, this);
+    GrPathRenderer::AddPathRenderers(fOwner, this);
     this->addPathRenderer(SkNEW_ARGS(GrDefaultPathRenderer,
                                      (twoSided, wrapOp)))->unref();
     fInit = true;
diff --git a/src/gpu/GrPathRendererChain.h b/src/gpu/GrPathRendererChain.h
deleted file mode 100644
index dfc696d..0000000
--- a/src/gpu/GrPathRendererChain.h
+++ /dev/null
@@ -1,69 +0,0 @@
-
-/*
- * Copyright 2011 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-
-#ifndef GrPathRendererChain_DEFINED
-#define GrPathRendererChain_DEFINED
-
-#include "GrDrawTarget.h"
-#include "GrRefCnt.h"
-#include "SkTArray.h"
-
-class GrContext;
-
-class SkPath;
-class SkStroke;
-class GrPathRenderer;
-
-/**
- * Keeps track of an ordered list of path renderers. When a path needs to be
- * drawn this list is scanned to find the most preferred renderer. To add your
- * path renderer to the list implement the GrPathRenderer::AddPathRenderers
- * function.
- */
-class GrPathRendererChain : public SkRefCnt {
-public:
-    SK_DECLARE_INST_COUNT(GrPathRendererChain)
-
-    enum UsageFlags {
-        kNone_UsageFlag      = 0,
-        kNonAAOnly_UsageFlag = 1,
-    };
-
-    GrPathRendererChain(GrContext* context, UsageFlags flags);
-
-    ~GrPathRendererChain();
-
-    // takes a ref and unrefs in destructor
-    GrPathRenderer* addPathRenderer(GrPathRenderer* pr);
-
-    GrPathRenderer* getPathRenderer(const SkPath& path,
-                                    const SkStroke& stroke,
-                                    const GrDrawTarget* target,
-                                    bool antiAlias);
-
-private:
-
-    GrPathRendererChain();
-
-    void init();
-
-    enum {
-        kPreAllocCount = 8,
-    };
-    bool fInit;
-    GrContext*                                          fOwner;
-    UsageFlags                                          fFlags;
-    SkSTArray<kPreAllocCount, GrPathRenderer*, true>    fChain;
-
-    typedef SkRefCnt INHERITED;
-};
-
-GR_MAKE_BITFIELD_OPS(GrPathRendererChain::UsageFlags)
-
-#endif
diff --git a/src/gpu/GrReducedClip.cpp b/src/gpu/GrReducedClip.cpp
index 5287858..da42e8c 100644
--- a/src/gpu/GrReducedClip.cpp
+++ b/src/gpu/GrReducedClip.cpp
@@ -325,7 +325,7 @@
                     ++numAAElements;
                 }
                 // Intersecting an inverse shape is the same as differencing the non-inverse shape.
-                // Replacing with a inverse shape the same as setting initialState=kAllIn and
+                // Replacing with an inverse shape is the same as setting initialState=kAllIn and
                 // differencing the non-inverse shape.
                 bool isReplace = SkRegion::kReplace_Op == newElement->getOp();
                 if (newElement->isInverseFilled() &&
diff --git a/src/gpu/GrSoftwarePathRenderer.cpp b/src/gpu/GrSoftwarePathRenderer.cpp
index a521eef..36a4156 100644
--- a/src/gpu/GrSoftwarePathRenderer.cpp
+++ b/src/gpu/GrSoftwarePathRenderer.cpp
@@ -28,6 +28,13 @@
     return true;
 }
 
+GrPathRenderer::StencilSupport GrSoftwarePathRenderer::onGetStencilSupport(
+                                                                        const SkPath&,
+                                                                        const SkStroke&,
+                                                                        const GrDrawTarget*) const {
+    return GrPathRenderer::kNoSupport_StencilSupport;
+}
+
 namespace {
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/src/gpu/GrSoftwarePathRenderer.h b/src/gpu/GrSoftwarePathRenderer.h
index 7c7382c..dd78d6b 100644
--- a/src/gpu/GrSoftwarePathRenderer.h
+++ b/src/gpu/GrSoftwarePathRenderer.h
@@ -24,14 +24,18 @@
         : fContext(context) {
     }
 
-    virtual bool canDrawPath(const SkPath& path,
-                             const SkStroke& stroke,
-                             const GrDrawTarget* target,
+    virtual bool canDrawPath(const SkPath&,
+                             const SkStroke&,
+                             const GrDrawTarget*,
                              bool antiAlias) const SK_OVERRIDE;
 protected:
-    virtual bool onDrawPath(const SkPath& path,
-                            const SkStroke& stroke,
-                            GrDrawTarget* target,
+    virtual StencilSupport onGetStencilSupport(const SkPath&,
+                                               const SkStroke&,
+                                               const GrDrawTarget*) const SK_OVERRIDE;
+
+    virtual bool onDrawPath(const SkPath&,
+                            const SkStroke&,
+                            GrDrawTarget*,
                             bool antiAlias) SK_OVERRIDE;
 
 private:
diff --git a/src/gpu/GrStencilAndCoverPathRenderer.cpp b/src/gpu/GrStencilAndCoverPathRenderer.cpp
index 28e18ed..a9bddda 100644
--- a/src/gpu/GrStencilAndCoverPathRenderer.cpp
+++ b/src/gpu/GrStencilAndCoverPathRenderer.cpp
@@ -42,15 +42,16 @@
            target->getDrawState().getStencil().isDisabled();
 }
 
-bool GrStencilAndCoverPathRenderer::requiresStencilPass(const SkPath& path,
-                                                        const SkStroke& stroke,
-                                                        const GrDrawTarget* target) const {
-    return true;
+GrPathRenderer::StencilSupport GrStencilAndCoverPathRenderer::onGetStencilSupport(
+                                                        const SkPath&,
+                                                        const SkStroke& ,
+                                                        const GrDrawTarget*) const {
+    return GrPathRenderer::kStencilOnly_StencilSupport;
 }
 
-void GrStencilAndCoverPathRenderer::drawPathToStencil(const SkPath& path,
-                                                      const SkStroke& stroke,
-                                                      GrDrawTarget* target) {
+void GrStencilAndCoverPathRenderer::onStencilPath(const SkPath& path,
+                                                  const SkStroke& stroke,
+                                                  GrDrawTarget* target) {
     GrAssert(!path.isInverseFillType());
     SkAutoTUnref<GrPath> p(fGpu->createPath(path));
     target->stencilPath(p, stroke, path.getFillType());
diff --git a/src/gpu/GrStencilAndCoverPathRenderer.h b/src/gpu/GrStencilAndCoverPathRenderer.h
index 9a8dd57..3b830e3 100644
--- a/src/gpu/GrStencilAndCoverPathRenderer.h
+++ b/src/gpu/GrStencilAndCoverPathRenderer.h
@@ -21,31 +21,31 @@
 class GrStencilAndCoverPathRenderer : public GrPathRenderer {
 public:
 
-    static GrPathRenderer* Create(GrContext* context);
+    static GrPathRenderer* Create(GrContext*);
 
     virtual ~GrStencilAndCoverPathRenderer();
 
-    virtual bool canDrawPath(const SkPath& path,
-                             const SkStroke& stroke,
-                             const GrDrawTarget* target,
+    virtual bool canDrawPath(const SkPath&,
+                             const SkStroke&,
+                             const GrDrawTarget*,
                              bool antiAlias) const SK_OVERRIDE;
 
-    virtual bool requiresStencilPass(const SkPath& path,
-                                     const SkStroke& stroke,
-                                     const GrDrawTarget* target) const SK_OVERRIDE;
-
-    virtual void drawPathToStencil(const SkPath& path,
-                                   const SkStroke& stroke,
-                                   GrDrawTarget* target) SK_OVERRIDE;
-
 protected:
-    virtual bool onDrawPath(const SkPath& path,
-                            const SkStroke& stroke,
-                            GrDrawTarget* target,
+    virtual StencilSupport onGetStencilSupport(const SkPath&,
+                                               const SkStroke&,
+                                               const GrDrawTarget*) const SK_OVERRIDE;
+
+    virtual bool onDrawPath(const SkPath&,
+                            const SkStroke&,
+                            GrDrawTarget*,
                             bool antiAlias) SK_OVERRIDE;
 
+    virtual void onStencilPath(const SkPath&,  
+                               const SkStroke&,
+                               GrDrawTarget*) SK_OVERRIDE;
+
 private:
-    GrStencilAndCoverPathRenderer(GrGpu* gpu);
+    GrStencilAndCoverPathRenderer(GrGpu*);
 
     GrGpu* fGpu;
 
diff --git a/src/gpu/gl/GrGLProgram.cpp b/src/gpu/gl/GrGLProgram.cpp
index 0283a5a..ba86383 100644
--- a/src/gpu/gl/GrGLProgram.cpp
+++ b/src/gpu/gl/GrGLProgram.cpp
@@ -284,6 +284,9 @@
             GrCrash("Unknown Edge Type!");
             break;
         }
+        if (fDesc.fDiscardIfOutsideEdge) {
+            builder->fFSCode.appendf("\tif (edgeAlpha <= 0) {\n\t\tdiscard;\n\t}\n");
+        }
         *coverageVar = "edgeAlpha";
         return true;
     } else {
diff --git a/src/gpu/gl/GrGLProgram.h b/src/gpu/gl/GrGLProgram.h
index d385e60..3902a8c 100644
--- a/src/gpu/gl/GrGLProgram.h
+++ b/src/gpu/gl/GrGLProgram.h
@@ -108,7 +108,10 @@
             kDualSrcOutputCnt
         };
 
+        // TODO: remove these two members when edge-aa can be rewritten as a GrEffect.
         GrDrawState::VertexEdgeType fVertexEdgeType;
+        // should the FS discard if the edge-aa coverage is zero (to avoid stencil manipulation)
+        bool                        fDiscardIfOutsideEdge;
 
         // stripped of bits that don't affect program generation
         GrVertexLayout fVertexLayout;
diff --git a/src/gpu/gl/GrGpuGL_program.cpp b/src/gpu/gl/GrGpuGL_program.cpp
index 73f60ca..5850fc4 100644
--- a/src/gpu/gl/GrGpuGL_program.cpp
+++ b/src/gpu/gl/GrGpuGL_program.cpp
@@ -553,9 +553,11 @@
 
     if (!skipCoverage && (desc->fVertexLayout &GrDrawTarget::kEdge_VertexLayoutBit)) {
         desc->fVertexEdgeType = drawState.getVertexEdgeType();
+        desc->fDiscardIfOutsideEdge = drawState.getStencil().doesWrite();
     } else {
-        // use canonical value when not set to avoid cache misses
+        // Use canonical values when edge-aa is not enabled to avoid program cache misses.
         desc->fVertexEdgeType = GrDrawState::kHairLine_EdgeType;
+        desc->fDiscardIfOutsideEdge = false;
     }
 
     for (int s = 0; s < GrDrawState::kNumStages; ++s) {
diff --git a/tests/GLProgramsTest.cpp b/tests/GLProgramsTest.cpp
index 1aaefbf..46d0820 100644
--- a/tests/GLProgramsTest.cpp
+++ b/tests/GLProgramsTest.cpp
@@ -92,8 +92,10 @@
             pdesc.fVertexLayout |= GrDrawTarget::kEdge_VertexLayoutBit;
             if (this->getCaps().shaderDerivativeSupport()) {
                 pdesc.fVertexEdgeType = (GrDrawState::VertexEdgeType) random_int(&random, GrDrawState::kVertexEdgeTypeCnt);
+                pdesc.fDiscardIfOutsideEdge = random.nextBool();
             } else {
                 pdesc.fVertexEdgeType = GrDrawState::kHairLine_EdgeType;
+                pdesc.fDiscardIfOutsideEdge = false;
             }
         } else {
         }