Use a prioritized list of path renderers in Gr.

http://codereview.appspot.com/4867058



git-svn-id: http://skia.googlecode.com/svn/trunk@2143 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gpu/include/GrContext.h b/gpu/include/GrContext.h
index 2f64996..ee16321 100644
--- a/gpu/include/GrContext.h
+++ b/gpu/include/GrContext.h
@@ -16,7 +16,6 @@
 // remove.
 #include "GrRenderTarget.h" 
 
-class GrDefaultPathRenderer;
 class GrDrawTarget;
 class GrFontCache;
 class GrGpu;
@@ -25,6 +24,7 @@
 class GrIndexBufferAllocPool;
 class GrInOrderDrawBuffer;
 class GrPathRenderer;
+class GrPathRendererChain;
 class GrResourceEntry;
 class GrResourceCache;
 class GrStencilBuffer;
@@ -556,8 +556,7 @@
     GrResourceCache*    fTextureCache;
     GrFontCache*        fFontCache;
 
-    GrPathRenderer*         fCustomPathRenderer;
-    GrDefaultPathRenderer*  fDefaultPathRenderer;
+    GrPathRendererChain*        fPathRendererChain;
 
     GrVertexBufferAllocPool*    fDrawBufferVBAllocPool;
     GrIndexBufferAllocPool*     fDrawBufferIBAllocPool;
@@ -592,9 +591,9 @@
 
     GrDrawTarget* prepareToDraw(const GrPaint& paint, DrawCategory drawType);
 
-    void drawClipIntoStencil();
-
-    GrPathRenderer* getPathRenderer(const GrPath&, GrPathFill);
+    GrPathRenderer* getPathRenderer(const GrDrawTarget* target,
+                                    const GrPath& path,
+                                    GrPathFill fill);
 
     struct OffscreenRecord;
 
diff --git a/gpu/src/GrAddPathRenderers_none.cpp b/gpu/src/GrAddPathRenderers_none.cpp
new file mode 100644
index 0000000..46855db
--- /dev/null
+++ b/gpu/src/GrAddPathRenderers_none.cpp
@@ -0,0 +1,15 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#include "GrPathRenderer.h"
+
+
+void GrPathRenderer::AddPathRenderers(GrContext*, 
+                                      GrPathRendererChain::UsageFlags,
+                                      GrPathRendererChain*) {}
diff --git a/gpu/src/GrAddPathRenderers_tesselated.cpp b/gpu/src/GrAddPathRenderers_tesselated.cpp
new file mode 100644
index 0000000..a1cde13
--- /dev/null
+++ b/gpu/src/GrAddPathRenderers_tesselated.cpp
@@ -0,0 +1,17 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#include "GrTesselatedPathRenderer.h"
+
+
+void GrPathRenderer::AddPathRenderers(GrContext*,
+                                      GrPathRendererChain::UsageFlags flags,
+                                      GrPathRendererChain* chain) {
+    chain->addPathRenderer(new GrTesselatedPathRenderer())->unref();
+}
diff --git a/gpu/src/GrContext.cpp b/gpu/src/GrContext.cpp
index b3e902d..506cb9f 100644
--- a/gpu/src/GrContext.cpp
+++ b/gpu/src/GrContext.cpp
@@ -61,11 +61,11 @@
     delete fDrawBuffer;
     delete fDrawBufferVBAllocPool;
     delete fDrawBufferIBAllocPool;
-    GrSafeUnref(fDefaultPathRenderer);
-    GrSafeUnref(fCustomPathRenderer);
+
     GrSafeUnref(fAAFillRectIndexBuffer);
     GrSafeUnref(fAAStrokeRectIndexBuffer);
     fGpu->unref();
+    GrSafeUnref(fPathRendererChain);
 }
 
 void GrContext::contextLost() {
@@ -78,6 +78,10 @@
     // don't try to free the resources in the API.
     fGpu->abandonResources();
 
+    // a path renderer may be holding onto resources that
+    // are now unusable
+    GrSafeSetNull(fPathRendererChain);
+
     delete fDrawBuffer;
     fDrawBuffer = NULL;
 
@@ -103,6 +107,8 @@
     this->flush();
     fTextureCache->removeAll();
     fFontCache->freeAll();
+    // a path renderer may be holding onto resources
+    GrSafeSetNull(fPathRendererChain);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -1411,7 +1417,12 @@
                          GrPathFill fill, const GrPoint* translate) {
 
     GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
-    GrPathRenderer* pr = this->getPathRenderer(path, fill);
+    GrPathRenderer* pr = this->getPathRenderer(target, path, fill);
+    if (NULL == pr) {
+        GrPrintf("Unable to find path renderer compatible with path.\n");
+        return;
+    }
+
     GrPathRenderer::AutoClearPath arp(pr, target, &path, fill, translate);
     GrDrawTarget::StageBitfield stageMask = paint.getActiveStageMask();
 
@@ -1658,6 +1669,16 @@
     return target;
 }
 
+GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target,
+                                           const GrPath& path,
+                                           GrPathFill fill) {
+    if (NULL == fPathRendererChain) {
+        fPathRendererChain = 
+            new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
+    }
+    return fPathRendererChain->getPathRenderer(target, path, fill);
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 
 void GrContext::setRenderTarget(GrRenderTarget* target) {
@@ -1712,11 +1733,7 @@
     fGpu->ref();
     fGpu->setContext(this);
 
-    fDefaultPathRenderer = 
-        new GrDefaultPathRenderer(gpu->supportsTwoSidedStencil(),
-                                  gpu->supportsStencilWrapOps());
-    fCustomPathRenderer = GrPathRenderer::CreatePathRenderer();
-    fGpu->setClipPathRenderer(fCustomPathRenderer);
+    fPathRendererChain = NULL;
 
     fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
                                         MAX_TEXTURE_CACHE_BYTES);
@@ -1780,17 +1797,6 @@
     return fGpu->getQuadIndexBuffer();
 }
 
-GrPathRenderer* GrContext::getPathRenderer(const GrPath& path,
-                                           GrPathFill fill) {
-    if (NULL != fCustomPathRenderer &&
-        fCustomPathRenderer->canDrawPath(path, fill)) {
-        return fCustomPathRenderer;
-    } else {
-        GrAssert(fDefaultPathRenderer->canDrawPath(path, fill));
-        return fDefaultPathRenderer;
-    }
-}
-
 void GrContext::convolveInX(GrTexture* texture,
                             const SkRect& rect,
                             const float* kernel,
diff --git a/gpu/src/GrCreatePathRenderer_none.cpp b/gpu/src/GrCreatePathRenderer_none.cpp
deleted file mode 100644
index 5072afa..0000000
--- a/gpu/src/GrCreatePathRenderer_none.cpp
+++ /dev/null
@@ -1,13 +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.
- */
-
-
-#include "GrPathRenderer.h"
-
-
-GrPathRenderer* GrPathRenderer::CreatePathRenderer() { return NULL; }
diff --git a/gpu/src/GrCreatePathRenderer_tesselated.cpp b/gpu/src/GrCreatePathRenderer_tesselated.cpp
deleted file mode 100644
index 38d7aa2..0000000
--- a/gpu/src/GrCreatePathRenderer_tesselated.cpp
+++ /dev/null
@@ -1,13 +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.
- */
-
-
-#include "GrTesselatedPathRenderer.h"
-
-
-GrPathRenderer* GrPathRenderer::CreatePathRenderer() { return new GrTesselatedPathRenderer(); }
diff --git a/gpu/src/GrDefaultPathRenderer.cpp b/gpu/src/GrDefaultPathRenderer.cpp
new file mode 100644
index 0000000..b8b7f62
--- /dev/null
+++ b/gpu/src/GrDefaultPathRenderer.cpp
@@ -0,0 +1,562 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrDefaultPathRenderer.h"
+
+#include "GrContext.h"
+#include "GrPathUtils.h"
+#include "SkTrace.h"
+
+
+GrDefaultPathRenderer::GrDefaultPathRenderer(bool separateStencilSupport,
+                                             bool stencilWrapOpsSupport)
+    : fSeparateStencil(separateStencilSupport)
+    , fStencilWrapOps(stencilWrapOpsSupport)
+    , fSubpathCount(0)
+    , fSubpathVertCount(0)
+    , fPreviousSrcTol(-GR_Scalar1)
+    , fPreviousStages(-1) {
+    fTarget = NULL;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Stencil rules for paths
+
+////// Even/Odd
+
+static const GrStencilSettings gEOStencilPass = {
+    kInvert_StencilOp,           kInvert_StencilOp,
+    kKeep_StencilOp,             kKeep_StencilOp,
+    kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
+    0xffffffff,                  0xffffffff,
+    0xffffffff,                  0xffffffff,
+    0xffffffff,                  0xffffffff
+};
+
+// ok not to check clip b/c stencil pass only wrote inside clip
+static const GrStencilSettings gEOColorPass = {
+    kZero_StencilOp,          kZero_StencilOp,
+    kZero_StencilOp,          kZero_StencilOp,
+    kNotEqual_StencilFunc,    kNotEqual_StencilFunc,
+    0xffffffff,               0xffffffff,
+    0x0,                      0x0,
+    0xffffffff,               0xffffffff
+};
+
+// have to check clip b/c outside clip will always be zero.
+static const GrStencilSettings gInvEOColorPass = {
+    kZero_StencilOp,            kZero_StencilOp,
+    kZero_StencilOp,            kZero_StencilOp,
+    kEqualIfInClip_StencilFunc, kEqualIfInClip_StencilFunc,
+    0xffffffff,                 0xffffffff,
+    0x0,                        0x0,
+    0xffffffff,                 0xffffffff
+};
+
+////// Winding
+
+// when we have separate stencil we increment front faces / decrement back faces
+// when we don't have wrap incr and decr we use the stencil test to simulate
+// them.
+
+static const GrStencilSettings gWindStencilSeparateWithWrap = {
+    kIncWrap_StencilOp,             kDecWrap_StencilOp,
+    kKeep_StencilOp,                kKeep_StencilOp,
+    kAlwaysIfInClip_StencilFunc,    kAlwaysIfInClip_StencilFunc,
+    0xffffffff,                     0xffffffff,
+    0xffffffff,                     0xffffffff,
+    0xffffffff,                     0xffffffff
+};
+
+// if inc'ing the max value, invert to make 0
+// if dec'ing zero invert to make all ones.
+// we can't avoid touching the stencil on both passing and
+// failing, so we can't resctrict ourselves to the clip.
+static const GrStencilSettings gWindStencilSeparateNoWrap = {
+    kInvert_StencilOp,              kInvert_StencilOp,
+    kIncClamp_StencilOp,            kDecClamp_StencilOp,
+    kEqual_StencilFunc,             kEqual_StencilFunc,
+    0xffffffff,                     0xffffffff,
+    0xffffffff,                     0x0,
+    0xffffffff,                     0xffffffff
+};
+
+// When there are no separate faces we do two passes to setup the winding rule
+// stencil. First we draw the front faces and inc, then we draw the back faces
+// and dec. These are same as the above two split into the incrementing and
+// decrementing passes.
+static const GrStencilSettings gWindSingleStencilWithWrapInc = {
+    kIncWrap_StencilOp,             kIncWrap_StencilOp,
+    kKeep_StencilOp,                kKeep_StencilOp,
+    kAlwaysIfInClip_StencilFunc,    kAlwaysIfInClip_StencilFunc,
+    0xffffffff,                     0xffffffff,
+    0xffffffff,                     0xffffffff,
+    0xffffffff,                     0xffffffff
+};
+static const GrStencilSettings gWindSingleStencilWithWrapDec = {
+    kDecWrap_StencilOp,             kDecWrap_StencilOp,
+    kKeep_StencilOp,                kKeep_StencilOp,
+    kAlwaysIfInClip_StencilFunc,    kAlwaysIfInClip_StencilFunc,
+    0xffffffff,                     0xffffffff,
+    0xffffffff,                     0xffffffff,
+    0xffffffff,                     0xffffffff
+};
+static const GrStencilSettings gWindSingleStencilNoWrapInc = {
+    kInvert_StencilOp,              kInvert_StencilOp,
+    kIncClamp_StencilOp,            kIncClamp_StencilOp,
+    kEqual_StencilFunc,             kEqual_StencilFunc,
+    0xffffffff,                     0xffffffff,
+    0xffffffff,                     0xffffffff,
+    0xffffffff,                     0xffffffff
+};
+static const GrStencilSettings gWindSingleStencilNoWrapDec = {
+    kInvert_StencilOp,              kInvert_StencilOp,
+    kDecClamp_StencilOp,            kDecClamp_StencilOp,
+    kEqual_StencilFunc,             kEqual_StencilFunc,
+    0xffffffff,                     0xffffffff,
+    0x0,                            0x0,
+    0xffffffff,                     0xffffffff
+};
+
+static const GrStencilSettings gWindColorPass = {
+    kZero_StencilOp,                kZero_StencilOp,
+    kZero_StencilOp,                kZero_StencilOp,
+    kNonZeroIfInClip_StencilFunc,   kNonZeroIfInClip_StencilFunc,
+    0xffffffff,                     0xffffffff,
+    0x0,                            0x0,
+    0xffffffff,                     0xffffffff
+};
+
+static const GrStencilSettings gInvWindColorPass = {
+    kZero_StencilOp,                kZero_StencilOp,
+    kZero_StencilOp,                kZero_StencilOp,
+    kEqualIfInClip_StencilFunc,     kEqualIfInClip_StencilFunc,
+    0xffffffff,                     0xffffffff,
+    0x0,                            0x0,
+    0xffffffff,                     0xffffffff
+};
+
+////// Normal render to stencil
+
+// Sometimes the default path renderer can draw a path directly to the stencil
+// buffer without having to first resolve the interior / exterior.
+static const GrStencilSettings gDirectToStencil = {
+    kZero_StencilOp,                kZero_StencilOp,
+    kIncClamp_StencilOp,            kIncClamp_StencilOp,
+    kAlwaysIfInClip_StencilFunc,    kAlwaysIfInClip_StencilFunc,
+    0xffffffff,                     0xffffffff,
+    0x0,                            0x0,
+    0xffffffff,                     0xffffffff
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// Helpers for drawPath
+
+static GrConvexHint getConvexHint(const SkPath& path) {
+    return path.isConvex() ? kConvex_ConvexHint : kConcave_ConvexHint;
+}
+
+#define STENCIL_OFF     0   // Always disable stencil (even when needed)
+
+static inline bool single_pass_path(const GrDrawTarget& target,
+                                    const GrPath& path,
+                                    GrPathFill fill) {
+#if STENCIL_OFF
+    return true;
+#else
+    if (kEvenOdd_PathFill == fill) {
+        GrConvexHint hint = getConvexHint(path);
+        return hint == kConvex_ConvexHint ||
+               hint == kNonOverlappingConvexPieces_ConvexHint;
+    } else if (kWinding_PathFill == fill) {
+        GrConvexHint hint = getConvexHint(path);
+        return hint == kConvex_ConvexHint ||
+               hint == kNonOverlappingConvexPieces_ConvexHint ||
+               (hint == kSameWindingConvexPieces_ConvexHint &&
+                target.canDisableBlend() && !target.isDitherState());
+
+    }
+    return false;
+#endif
+}
+
+bool GrDefaultPathRenderer::requiresStencilPass(const GrDrawTarget* target,
+                                                const GrPath& path, 
+                                                GrPathFill fill) const {
+    return !single_pass_path(*target, path, fill);
+}
+
+void GrDefaultPathRenderer::pathWillClear() {
+    fSubpathVertCount.realloc(0);
+    fTarget->resetVertexSource();
+    if (fUseIndexedDraw) {
+        fTarget->resetIndexSource();
+    }
+    fPreviousSrcTol = -GR_Scalar1;
+    fPreviousStages = -1;
+}
+
+static inline void append_countour_edge_indices(GrPathFill fillType,
+                                                uint16_t fanCenterIdx,
+                                                uint16_t edgeV0Idx,
+                                                uint16_t** indices) {
+    // when drawing lines we're appending line segments along
+    // the contour. When applying the other fill rules we're
+    // drawing triangle fans around fanCenterIdx.
+    if (kHairLine_PathFill != fillType) {
+        *((*indices)++) = fanCenterIdx;
+    }
+    *((*indices)++) = edgeV0Idx;
+    *((*indices)++) = edgeV0Idx + 1;
+}
+
+bool GrDefaultPathRenderer::createGeom(GrScalar srcSpaceTol, 
+                                       GrDrawTarget::StageBitfield stages) {
+    {
+    SK_TRACE_EVENT0("GrDefaultPathRenderer::createGeom");
+
+    GrScalar srcSpaceTolSqd = GrMul(srcSpaceTol, srcSpaceTol);
+    int maxPts = GrPathUtils::worstCasePointCount(*fPath, &fSubpathCount,
+                                                  srcSpaceTol);
+
+    if (maxPts <= 0) {
+        return false;
+    }
+    if (maxPts > ((int)SK_MaxU16 + 1)) {
+        GrPrintf("Path not rendered, too many verts (%d)\n", maxPts);
+        return false;
+    }
+
+    GrVertexLayout layout = 0;
+    for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
+        if ((1 << s) & stages) {
+            layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
+        }
+    }
+
+    fUseIndexedDraw = fSubpathCount > 1;
+
+    int maxIdxs = 0;
+    if (kHairLine_PathFill == fFill) {
+        if (fUseIndexedDraw) {
+            maxIdxs = 2 * maxPts;
+            fPrimitiveType = kLines_PrimitiveType;
+        } else {
+            fPrimitiveType = kLineStrip_PrimitiveType;
+        }
+    } else {
+        if (fUseIndexedDraw) {
+            maxIdxs = 3 * maxPts;
+            fPrimitiveType = kTriangles_PrimitiveType;
+        } else {
+            fPrimitiveType = kTriangleFan_PrimitiveType;
+        }
+    }
+
+    GrPoint* base;
+    if (!fTarget->reserveVertexSpace(layout, maxPts, (void**)&base)) {
+        return false;
+    }
+    GrAssert(NULL != base);
+    GrPoint* vert = base;
+
+    uint16_t* idxBase = NULL;
+    uint16_t* idx = NULL;
+    uint16_t subpathIdxStart = 0;
+    if (fUseIndexedDraw) {
+        if (!fTarget->reserveIndexSpace(maxIdxs, (void**)&idxBase)) {
+            fTarget->resetVertexSource();
+            return false;
+        }
+        GrAssert(NULL != idxBase);
+        idx = idxBase;
+    }
+
+    fSubpathVertCount.realloc(fSubpathCount);
+
+    GrPoint pts[4];
+
+    bool first = true;
+    int subpath = 0;
+
+    SkPath::Iter iter(*fPath, false);
+
+    for (;;) {
+        GrPathCmd cmd = (GrPathCmd)iter.next(pts);
+        switch (cmd) {
+            case kMove_PathCmd:
+                if (!first) {
+                    uint16_t currIdx = (uint16_t) (vert - base);
+                    fSubpathVertCount[subpath] = currIdx - subpathIdxStart;
+                    subpathIdxStart = currIdx;
+                    ++subpath;
+                }
+                *vert = pts[0];
+                vert++;
+                break;
+            case kLine_PathCmd:
+                if (fUseIndexedDraw) {
+                    uint16_t prevIdx = (uint16_t)(vert - base) - 1;
+                    append_countour_edge_indices(fFill, subpathIdxStart,
+                                                 prevIdx, &idx);
+                }
+                *(vert++) = pts[1];
+                break;
+            case kQuadratic_PathCmd: {
+                // first pt of quad is the pt we ended on in previous step
+                uint16_t firstQPtIdx = (uint16_t)(vert - base) - 1;
+                uint16_t numPts =  (uint16_t) 
+                    GrPathUtils::generateQuadraticPoints(
+                            pts[0], pts[1], pts[2],
+                            srcSpaceTolSqd, &vert,
+                            GrPathUtils::quadraticPointCount(pts, srcSpaceTol));
+                if (fUseIndexedDraw) {
+                    for (uint16_t i = 0; i < numPts; ++i) {
+                        append_countour_edge_indices(fFill, subpathIdxStart,
+                                                     firstQPtIdx + i, &idx);
+                    }
+                }
+                break;
+            }
+            case kCubic_PathCmd: {
+                // first pt of cubic is the pt we ended on in previous step
+                uint16_t firstCPtIdx = (uint16_t)(vert - base) - 1;
+                uint16_t numPts = (uint16_t) GrPathUtils::generateCubicPoints(
+                                pts[0], pts[1], pts[2], pts[3],
+                                srcSpaceTolSqd, &vert,
+                                GrPathUtils::cubicPointCount(pts, srcSpaceTol));
+                if (fUseIndexedDraw) {
+                    for (uint16_t i = 0; i < numPts; ++i) {
+                        append_countour_edge_indices(fFill, subpathIdxStart,
+                                                     firstCPtIdx + i, &idx);
+                    }
+                }
+                break;
+            }
+            case kClose_PathCmd:
+                break;
+            case kEnd_PathCmd:
+                uint16_t currIdx = (uint16_t) (vert - base);
+                fSubpathVertCount[subpath] = currIdx - subpathIdxStart;
+                goto FINISHED;
+        }
+        first = false;
+    }
+FINISHED:
+    GrAssert((vert - base) <= maxPts);
+    GrAssert((idx - idxBase) <= maxIdxs);
+
+    fVertexCnt = vert - base;
+    fIndexCnt = idx - idxBase;
+
+    if (fTranslate.fX || fTranslate.fY) {
+        int count = vert - base;
+        for (int i = 0; i < count; i++) {
+            base[i].offset(fTranslate.fX, fTranslate.fY);
+        }
+    }
+    }
+    // set these at the end so if we failed on first drawPath inside a
+    // setPath/clearPath block we won't assume geom was created on a subsequent
+    // drawPath in the same block.
+    fPreviousSrcTol = srcSpaceTol;
+    fPreviousStages = stages;
+    return true;
+}
+
+void GrDefaultPathRenderer::onDrawPath(GrDrawTarget::StageBitfield stages,
+                                       bool stencilOnly) {
+
+    SK_TRACE_EVENT1("GrDefaultPathRenderer::onDrawPath",
+                    "points", SkStringPrintf("%i", path.countPoints()).c_str());
+
+    GrMatrix viewM = fTarget->getViewMatrix();
+    // In order to tesselate the path we get a bound on how much the matrix can
+    // stretch when mapping to screen coordinates.
+    GrScalar stretch = viewM.getMaxStretch();
+    bool useStretch = stretch > 0;
+    GrScalar tol = fCurveTolerance;
+
+    if (!useStretch) {
+        // TODO: deal with perspective in some better way.
+        tol /= 10;
+    } else {
+        tol = GrScalarDiv(tol, stretch);
+    }
+    // FIXME: It's really dumb that we recreate the verts for a new vertex
+    // layout. We only do that because the GrDrawTarget API doesn't allow
+    // us to change the vertex layout after reserveVertexSpace(). We won't
+    // actually change the vertex data when the layout changes since all the
+    // stages reference the positions (rather than having separate tex coords)
+    // and we don't ever have per-vert colors. In practice our call sites
+    // won't change the stages in use inside a setPath / removePath pair. But
+    // it is a silly limitation of the GrDrawTarget design that should be fixed.
+    if (tol != fPreviousSrcTol ||
+        stages != fPreviousStages) {
+        if (!this->createGeom(tol, stages)) {
+            return;
+        }
+    }
+
+    GrAssert(NULL != fTarget);
+    GrDrawTarget::AutoStateRestore asr(fTarget);
+    bool colorWritesWereDisabled = fTarget->isColorWriteDisabled();
+    // face culling doesn't make sense here
+    GrAssert(GrDrawTarget::kBoth_DrawFace == fTarget->getDrawFace());
+
+    int                         passCount = 0;
+    const GrStencilSettings*    passes[3];
+    GrDrawTarget::DrawFace      drawFace[3];
+    bool                        reverse = false;
+    bool                        lastPassIsBounds;
+
+    if (kHairLine_PathFill == fFill) {
+        passCount = 1;
+        if (stencilOnly) {
+            passes[0] = &gDirectToStencil;
+        } else {
+            passes[0] = NULL;
+        }
+        lastPassIsBounds = false;
+        drawFace[0] = GrDrawTarget::kBoth_DrawFace;
+    } else {
+        if (single_pass_path(*fTarget, *fPath, fFill)) {
+            passCount = 1;
+            if (stencilOnly) {
+                passes[0] = &gDirectToStencil;
+            } else {
+                passes[0] = NULL;
+            }
+            drawFace[0] = GrDrawTarget::kBoth_DrawFace;
+            lastPassIsBounds = false;
+        } else {
+            switch (fFill) {
+                case kInverseEvenOdd_PathFill:
+                    reverse = true;
+                    // fallthrough
+                case kEvenOdd_PathFill:
+                    passes[0] = &gEOStencilPass;
+                    if (stencilOnly) {
+                        passCount = 1;
+                        lastPassIsBounds = false;
+                    } else {
+                        passCount = 2;
+                        lastPassIsBounds = true;
+                        if (reverse) {
+                            passes[1] = &gInvEOColorPass;
+                        } else {
+                            passes[1] = &gEOColorPass;
+                        }
+                    }
+                    drawFace[0] = drawFace[1] = GrDrawTarget::kBoth_DrawFace;
+                    break;
+
+                case kInverseWinding_PathFill:
+                    reverse = true;
+                    // fallthrough
+                case kWinding_PathFill:
+                    if (fSeparateStencil) {
+                        if (fStencilWrapOps) {
+                            passes[0] = &gWindStencilSeparateWithWrap;
+                        } else {
+                            passes[0] = &gWindStencilSeparateNoWrap;
+                        }
+                        passCount = 2;
+                        drawFace[0] = GrDrawTarget::kBoth_DrawFace;
+                    } else {
+                        if (fStencilWrapOps) {
+                            passes[0] = &gWindSingleStencilWithWrapInc;
+                            passes[1] = &gWindSingleStencilWithWrapDec;
+                        } else {
+                            passes[0] = &gWindSingleStencilNoWrapInc;
+                            passes[1] = &gWindSingleStencilNoWrapDec;
+                        }
+                        // which is cw and which is ccw is arbitrary.
+                        drawFace[0] = GrDrawTarget::kCW_DrawFace;
+                        drawFace[1] = GrDrawTarget::kCCW_DrawFace;
+                        passCount = 3;
+                    }
+                    if (stencilOnly) {
+                        lastPassIsBounds = false;
+                        --passCount;
+                    } else {
+                        lastPassIsBounds = true;
+                        drawFace[passCount-1] = GrDrawTarget::kBoth_DrawFace;
+                        if (reverse) {
+                            passes[passCount-1] = &gInvWindColorPass;
+                        } else {
+                            passes[passCount-1] = &gWindColorPass;
+                        }
+                    }
+                    break;
+                default:
+                    GrAssert(!"Unknown path fFill!");
+                    return;
+            }
+        }
+    }
+
+    {
+    SK_TRACE_EVENT1("GrDefaultPathRenderer::onDrawPath::renderPasses",
+                    "verts", SkStringPrintf("%i", vert - base).c_str());
+    for (int p = 0; p < passCount; ++p) {
+        fTarget->setDrawFace(drawFace[p]);
+        if (NULL != passes[p]) {
+            fTarget->setStencil(*passes[p]);
+        }
+
+        if (lastPassIsBounds && (p == passCount-1)) {
+            if (!colorWritesWereDisabled) {
+                fTarget->disableState(GrDrawTarget::kNoColorWrites_StateBit);
+            }
+            GrRect bounds;
+            if (reverse) {
+                GrAssert(NULL != fTarget->getRenderTarget());
+                // draw over the whole world.
+                bounds.setLTRB(0, 0,
+                               GrIntToScalar(fTarget->getRenderTarget()->width()),
+                               GrIntToScalar(fTarget->getRenderTarget()->height()));
+                GrMatrix vmi;
+                if (fTarget->getViewInverse(&vmi)) {
+                    vmi.mapRect(&bounds);
+                }
+            } else {
+                bounds = fPath->getBounds();
+                bounds.offset(fTranslate);
+            }
+            GrDrawTarget::AutoGeometryPush agp(fTarget);
+            fTarget->drawSimpleRect(bounds, NULL, stages);
+        } else {
+            if (passCount > 1) {
+                fTarget->enableState(GrDrawTarget::kNoColorWrites_StateBit);
+            }
+            if (fUseIndexedDraw) {
+                fTarget->drawIndexed(fPrimitiveType, 0, 0, 
+                                     fVertexCnt, fIndexCnt);
+            } else {
+                int baseVertex = 0;
+                for (int sp = 0; sp < fSubpathCount; ++sp) {
+                    fTarget->drawNonIndexed(fPrimitiveType, baseVertex,
+                                            fSubpathVertCount[sp]);
+                    baseVertex += fSubpathVertCount[sp];
+                }
+            }
+        }
+    }
+    }
+}
+
+void GrDefaultPathRenderer::drawPath(GrDrawTarget::StageBitfield stages) {
+    this->onDrawPath(stages, false);
+}
+
+void GrDefaultPathRenderer::drawPathToStencil() {
+    GrAssert(kInverseEvenOdd_PathFill != fFill);
+    GrAssert(kInverseWinding_PathFill != fFill);
+    this->onDrawPath(0, true);
+}
diff --git a/gpu/src/GrDefaultPathRenderer.h b/gpu/src/GrDefaultPathRenderer.h
new file mode 100644
index 0000000..e11716e
--- /dev/null
+++ b/gpu/src/GrDefaultPathRenderer.h
@@ -0,0 +1,58 @@
+/*
+ * 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 GrDefaultPathRenderer_DEFINED
+#define GrDefaultPathRenderer_DEFINED
+
+#include "GrPathRenderer.h"
+#include "SkTemplates.h"
+
+/**
+ *  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);
+
+    virtual bool canDrawPath(const SkPath& path,
+                             GrPathFill fill) const { return true; }
+
+    virtual bool requiresStencilPass(const GrDrawTarget* target,
+                                     const SkPath& path,
+                                     GrPathFill fill) const;
+
+    virtual void drawPath(GrDrawTarget::StageBitfield stages);
+    virtual void drawPathToStencil();
+
+protected:
+    virtual void pathWillClear();
+
+private:
+
+    void onDrawPath(GrDrawTarget::StageBitfield stages, bool stencilOnly);
+
+    bool createGeom(GrScalar srcSpaceTol,
+                    GrDrawTarget::StageBitfield stages);
+
+    bool    fSeparateStencil;
+    bool    fStencilWrapOps;
+
+    int                         fSubpathCount;
+    SkAutoSTMalloc<8, uint16_t> fSubpathVertCount;
+    int                         fIndexCnt;
+    int                         fVertexCnt;
+    GrScalar                    fPreviousSrcTol;
+    GrDrawTarget::StageBitfield fPreviousStages;
+    GrPrimitiveType             fPrimitiveType;
+    bool                        fUseIndexedDraw;
+
+    typedef GrPathRenderer INHERITED;
+};
+
+#endif
diff --git a/gpu/src/GrGpu.cpp b/gpu/src/GrGpu.cpp
index cde851d..7744e6a 100644
--- a/gpu/src/GrGpu.cpp
+++ b/gpu/src/GrGpu.cpp
@@ -40,8 +40,7 @@
     , fGeomPoolStateStack(&fGeoSrcStateStackStorage)
     , fQuadIndexBuffer(NULL)
     , fUnitSquareVertexBuffer(NULL)
-    , fDefaultPathRenderer(NULL)
-    , fClientPathRenderer(NULL)
+    , fPathRendererChain(NULL)
     , fContextIsDirty(true)
     , fResourceHead(NULL) {
 
@@ -62,8 +61,6 @@
 
 GrGpu::~GrGpu() {
     this->releaseResources();
-    GrSafeUnref(fDefaultPathRenderer);
-    GrSafeUnref(fClientPathRenderer);
 }
 
 void GrGpu::abandonResources() {
@@ -81,6 +78,8 @@
     fVertexPool = NULL;
     delete fIndexPool;
     fIndexPool = NULL;
+    // in case path renderer has any GrResources, start from scratch
+    GrSafeSetNull(fPathRendererChain);
 }
 
 void GrGpu::releaseResources() {
@@ -98,6 +97,8 @@
     fVertexPool = NULL;
     delete fIndexPool;
     fIndexPool = NULL;
+    // in case path renderer has any GrResources, start from scratch
+    GrSafeSetNull(fPathRendererChain);
 }
 
 void GrGpu::insertResource(GrResource* resource) {
@@ -521,6 +522,11 @@
                     fill = NonInvertedFill(fill);
                     clipPath = &clip.getPath(c);
                     pr = this->getClipPathRenderer(*clipPath, fill);
+                    if (NULL == pr) {
+                        fClipInStencil = false;
+                        fClip = clip;
+                        return false;
+                    }
                     canRenderDirectToStencil =
                         !pr->requiresStencilPass(this, *clipPath, fill);
                     arp.set(pr, this, clipPath, fill, NULL);
@@ -602,18 +608,12 @@
 
 GrPathRenderer* GrGpu::getClipPathRenderer(const GrPath& path,
                                            GrPathFill fill) {
-    if (NULL != fClientPathRenderer &&
-        fClientPathRenderer->canDrawPath(path, fill)) {
-            return fClientPathRenderer;
-    } else {
-        if (NULL == fDefaultPathRenderer) {
-            fDefaultPathRenderer =
-                new GrDefaultPathRenderer(this->supportsTwoSidedStencil(),
-                                          this->supportsStencilWrapOps());
-        }
-        GrAssert(fDefaultPathRenderer->canDrawPath(path, fill));
-        return fDefaultPathRenderer;
+    if (NULL == fPathRendererChain) {
+        fPathRendererChain = 
+            new GrPathRendererChain(this->getContext(),
+                                    GrPathRendererChain::kNonAAOnly_UsageFlag);
     }
+    return fPathRendererChain->getPathRenderer(this, path, fill);
 }
 
 
diff --git a/gpu/src/GrGpu.h b/gpu/src/GrGpu.h
index d3c6c9d..e1e85f7 100644
--- a/gpu/src/GrGpu.h
+++ b/gpu/src/GrGpu.h
@@ -11,13 +11,14 @@
 #define GrGpu_DEFINED
 
 #include "GrDrawTarget.h"
-#include "GrPathRenderer.h"
 #include "GrRect.h"
 #include "GrRefCnt.h"
 #include "GrTexture.h"
 
 class GrContext;
 class GrIndexBufferAllocPool;
+class GrPathRenderer;
+class GrPathRendererChain;
 class GrResource;
 class GrStencilBuffer;
 class GrVertexBufferAllocPool;
@@ -259,14 +260,6 @@
     virtual void clear(const GrIRect* rect, GrColor color);
 
     /**
-     * Installs a path renderer that will be used to draw paths that are
-     * part of the clip.
-     */
-    void setClipPathRenderer(GrPathRenderer* pathRenderer) {
-        GrSafeAssign(fClientPathRenderer, pathRenderer);
-    }
-
-    /**
      * Returns an index buffer that can be used to render quads.
      * Six indices per quad: 0, 1, 2, 0, 2, 3, etc.
      * The max number of quads can be queried using GrIndexBuffer::maxQuads().
@@ -520,8 +513,9 @@
     mutable GrVertexBuffer*     fUnitSquareVertexBuffer; // mutable so it can be
                                                          // created on-demand
 
-    GrDefaultPathRenderer*      fDefaultPathRenderer;
-    GrPathRenderer*             fClientPathRenderer;
+    // must be instantiated after GrGpu object has been given its owning
+    // GrContext ptr. (GrGpu is constructed first then handed off to GrContext).
+    GrPathRendererChain*        fPathRendererChain;
 
     bool                        fContextIsDirty;
 
diff --git a/gpu/src/GrPathRenderer.cpp b/gpu/src/GrPathRenderer.cpp
index 26c92b8..06a00e4 100644
--- a/gpu/src/GrPathRenderer.cpp
+++ b/gpu/src/GrPathRenderer.cpp
@@ -5,24 +5,15 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
+
 #include "GrPathRenderer.h"
 
-#include "GrPoint.h"
-#include "GrDrawTarget.h"
-#include "GrPathUtils.h"
-#include "GrTexture.h"
-
-#include "SkString.h"
-#include "SkTemplates.h"
-#include "SkTrace.h"
-
 GrPathRenderer::GrPathRenderer()
     : fCurveTolerance (GR_Scalar1)
     , fPath(NULL)
     , fTarget(NULL) {
 }
 
-
 void GrPathRenderer::setPath(GrDrawTarget* target,
                              const SkPath* path,
                              GrPathFill fill,
@@ -49,553 +40,3 @@
     fTarget = NULL;
     fPath = NULL;
 }
-
-////////////////////////////////////////////////////////////////////////////////
-
-GrDefaultPathRenderer::GrDefaultPathRenderer(bool separateStencilSupport,
-                                             bool stencilWrapOpsSupport)
-    : fSeparateStencil(separateStencilSupport)
-    , fStencilWrapOps(stencilWrapOpsSupport)
-    , fSubpathCount(0)
-    , fSubpathVertCount(0)
-    , fPreviousSrcTol(-GR_Scalar1)
-    , fPreviousStages(-1) {
-    fTarget = NULL;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Stencil rules for paths
-
-////// Even/Odd
-
-static const GrStencilSettings gEOStencilPass = {
-    kInvert_StencilOp,           kInvert_StencilOp,
-    kKeep_StencilOp,             kKeep_StencilOp,
-    kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
-    0xffffffff,                  0xffffffff,
-    0xffffffff,                  0xffffffff,
-    0xffffffff,                  0xffffffff
-};
-
-// ok not to check clip b/c stencil pass only wrote inside clip
-static const GrStencilSettings gEOColorPass = {
-    kZero_StencilOp,          kZero_StencilOp,
-    kZero_StencilOp,          kZero_StencilOp,
-    kNotEqual_StencilFunc,    kNotEqual_StencilFunc,
-    0xffffffff,               0xffffffff,
-    0x0,                      0x0,
-    0xffffffff,               0xffffffff
-};
-
-// have to check clip b/c outside clip will always be zero.
-static const GrStencilSettings gInvEOColorPass = {
-    kZero_StencilOp,            kZero_StencilOp,
-    kZero_StencilOp,            kZero_StencilOp,
-    kEqualIfInClip_StencilFunc, kEqualIfInClip_StencilFunc,
-    0xffffffff,                 0xffffffff,
-    0x0,                        0x0,
-    0xffffffff,                 0xffffffff
-};
-
-////// Winding
-
-// when we have separate stencil we increment front faces / decrement back faces
-// when we don't have wrap incr and decr we use the stencil test to simulate
-// them.
-
-static const GrStencilSettings gWindStencilSeparateWithWrap = {
-    kIncWrap_StencilOp,             kDecWrap_StencilOp,
-    kKeep_StencilOp,                kKeep_StencilOp,
-    kAlwaysIfInClip_StencilFunc,    kAlwaysIfInClip_StencilFunc,
-    0xffffffff,                     0xffffffff,
-    0xffffffff,                     0xffffffff,
-    0xffffffff,                     0xffffffff
-};
-
-// if inc'ing the max value, invert to make 0
-// if dec'ing zero invert to make all ones.
-// we can't avoid touching the stencil on both passing and
-// failing, so we can't resctrict ourselves to the clip.
-static const GrStencilSettings gWindStencilSeparateNoWrap = {
-    kInvert_StencilOp,              kInvert_StencilOp,
-    kIncClamp_StencilOp,            kDecClamp_StencilOp,
-    kEqual_StencilFunc,             kEqual_StencilFunc,
-    0xffffffff,                     0xffffffff,
-    0xffffffff,                     0x0,
-    0xffffffff,                     0xffffffff
-};
-
-// When there are no separate faces we do two passes to setup the winding rule
-// stencil. First we draw the front faces and inc, then we draw the back faces
-// and dec. These are same as the above two split into the incrementing and
-// decrementing passes.
-static const GrStencilSettings gWindSingleStencilWithWrapInc = {
-    kIncWrap_StencilOp,             kIncWrap_StencilOp,
-    kKeep_StencilOp,                kKeep_StencilOp,
-    kAlwaysIfInClip_StencilFunc,    kAlwaysIfInClip_StencilFunc,
-    0xffffffff,                     0xffffffff,
-    0xffffffff,                     0xffffffff,
-    0xffffffff,                     0xffffffff
-};
-static const GrStencilSettings gWindSingleStencilWithWrapDec = {
-    kDecWrap_StencilOp,             kDecWrap_StencilOp,
-    kKeep_StencilOp,                kKeep_StencilOp,
-    kAlwaysIfInClip_StencilFunc,    kAlwaysIfInClip_StencilFunc,
-    0xffffffff,                     0xffffffff,
-    0xffffffff,                     0xffffffff,
-    0xffffffff,                     0xffffffff
-};
-static const GrStencilSettings gWindSingleStencilNoWrapInc = {
-    kInvert_StencilOp,              kInvert_StencilOp,
-    kIncClamp_StencilOp,            kIncClamp_StencilOp,
-    kEqual_StencilFunc,             kEqual_StencilFunc,
-    0xffffffff,                     0xffffffff,
-    0xffffffff,                     0xffffffff,
-    0xffffffff,                     0xffffffff
-};
-static const GrStencilSettings gWindSingleStencilNoWrapDec = {
-    kInvert_StencilOp,              kInvert_StencilOp,
-    kDecClamp_StencilOp,            kDecClamp_StencilOp,
-    kEqual_StencilFunc,             kEqual_StencilFunc,
-    0xffffffff,                     0xffffffff,
-    0x0,                            0x0,
-    0xffffffff,                     0xffffffff
-};
-
-static const GrStencilSettings gWindColorPass = {
-    kZero_StencilOp,                kZero_StencilOp,
-    kZero_StencilOp,                kZero_StencilOp,
-    kNonZeroIfInClip_StencilFunc,   kNonZeroIfInClip_StencilFunc,
-    0xffffffff,                     0xffffffff,
-    0x0,                            0x0,
-    0xffffffff,                     0xffffffff
-};
-
-static const GrStencilSettings gInvWindColorPass = {
-    kZero_StencilOp,                kZero_StencilOp,
-    kZero_StencilOp,                kZero_StencilOp,
-    kEqualIfInClip_StencilFunc,     kEqualIfInClip_StencilFunc,
-    0xffffffff,                     0xffffffff,
-    0x0,                            0x0,
-    0xffffffff,                     0xffffffff
-};
-
-////// Normal render to stencil
-
-// Sometimes the default path renderer can draw a path directly to the stencil
-// buffer without having to first resolve the interior / exterior.
-static const GrStencilSettings gDirectToStencil = {
-    kZero_StencilOp,                kZero_StencilOp,
-    kIncClamp_StencilOp,            kIncClamp_StencilOp,
-    kAlwaysIfInClip_StencilFunc,    kAlwaysIfInClip_StencilFunc,
-    0xffffffff,                     0xffffffff,
-    0x0,                            0x0,
-    0xffffffff,                     0xffffffff
-};
-
-////////////////////////////////////////////////////////////////////////////////
-// Helpers for drawPath
-
-static GrConvexHint getConvexHint(const SkPath& path) {
-    return path.isConvex() ? kConvex_ConvexHint : kConcave_ConvexHint;
-}
-
-#define STENCIL_OFF     0   // Always disable stencil (even when needed)
-
-static inline bool single_pass_path(const GrDrawTarget& target,
-                                    const GrPath& path,
-                                    GrPathFill fill) {
-#if STENCIL_OFF
-    return true;
-#else
-    if (kEvenOdd_PathFill == fill) {
-        GrConvexHint hint = getConvexHint(path);
-        return hint == kConvex_ConvexHint ||
-               hint == kNonOverlappingConvexPieces_ConvexHint;
-    } else if (kWinding_PathFill == fill) {
-        GrConvexHint hint = getConvexHint(path);
-        return hint == kConvex_ConvexHint ||
-               hint == kNonOverlappingConvexPieces_ConvexHint ||
-               (hint == kSameWindingConvexPieces_ConvexHint &&
-                target.canDisableBlend() && !target.isDitherState());
-
-    }
-    return false;
-#endif
-}
-
-bool GrDefaultPathRenderer::requiresStencilPass(const GrDrawTarget* target,
-                                                const GrPath& path, 
-                                                GrPathFill fill) const {
-    return !single_pass_path(*target, path, fill);
-}
-
-void GrDefaultPathRenderer::pathWillClear() {
-    fSubpathVertCount.realloc(0);
-    fTarget->resetVertexSource();
-    if (fUseIndexedDraw) {
-        fTarget->resetIndexSource();
-    }
-    fPreviousSrcTol = -GR_Scalar1;
-    fPreviousStages = -1;
-}
-
-static inline void append_countour_edge_indices(GrPathFill fillType,
-                                                uint16_t fanCenterIdx,
-                                                uint16_t edgeV0Idx,
-                                                uint16_t** indices) {
-    // when drawing lines we're appending line segments along
-    // the contour. When applying the other fill rules we're
-    // drawing triangle fans around fanCenterIdx.
-    if (kHairLine_PathFill != fillType) {
-        *((*indices)++) = fanCenterIdx;
-    }
-    *((*indices)++) = edgeV0Idx;
-    *((*indices)++) = edgeV0Idx + 1;
-}
-
-bool GrDefaultPathRenderer::createGeom(GrScalar srcSpaceTol, 
-                                       GrDrawTarget::StageBitfield stages) {
-    {
-    SK_TRACE_EVENT0("GrDefaultPathRenderer::createGeom");
-
-    GrScalar srcSpaceTolSqd = GrMul(srcSpaceTol, srcSpaceTol);
-    int maxPts = GrPathUtils::worstCasePointCount(*fPath, &fSubpathCount,
-                                                  srcSpaceTol);
-
-    if (maxPts <= 0) {
-        return false;
-    }
-    if (maxPts > ((int)SK_MaxU16 + 1)) {
-        GrPrintf("Path not rendered, too many verts (%d)\n", maxPts);
-        return false;
-    }
-
-    GrVertexLayout layout = 0;
-    for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
-        if ((1 << s) & stages) {
-            layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
-        }
-    }
-
-    fUseIndexedDraw = fSubpathCount > 1;
-
-    int maxIdxs = 0;
-    if (kHairLine_PathFill == fFill) {
-        if (fUseIndexedDraw) {
-            maxIdxs = 2 * maxPts;
-            fPrimitiveType = kLines_PrimitiveType;
-        } else {
-            fPrimitiveType = kLineStrip_PrimitiveType;
-        }
-    } else {
-        if (fUseIndexedDraw) {
-            maxIdxs = 3 * maxPts;
-            fPrimitiveType = kTriangles_PrimitiveType;
-        } else {
-            fPrimitiveType = kTriangleFan_PrimitiveType;
-        }
-    }
-
-    GrPoint* base;
-    if (!fTarget->reserveVertexSpace(layout, maxPts, (void**)&base)) {
-        return false;
-    }
-    GrAssert(NULL != base);
-    GrPoint* vert = base;
-
-    uint16_t* idxBase = NULL;
-    uint16_t* idx = NULL;
-    uint16_t subpathIdxStart = 0;
-    if (fUseIndexedDraw) {
-        if (!fTarget->reserveIndexSpace(maxIdxs, (void**)&idxBase)) {
-            fTarget->resetVertexSource();
-            return false;
-        }
-        GrAssert(NULL != idxBase);
-        idx = idxBase;
-    }
-
-    fSubpathVertCount.realloc(fSubpathCount);
-
-    GrPoint pts[4];
-
-    bool first = true;
-    int subpath = 0;
-
-    SkPath::Iter iter(*fPath, false);
-
-    for (;;) {
-        GrPathCmd cmd = (GrPathCmd)iter.next(pts);
-        switch (cmd) {
-            case kMove_PathCmd:
-                if (!first) {
-                    uint16_t currIdx = (uint16_t) (vert - base);
-                    fSubpathVertCount[subpath] = currIdx - subpathIdxStart;
-                    subpathIdxStart = currIdx;
-                    ++subpath;
-                }
-                *vert = pts[0];
-                vert++;
-                break;
-            case kLine_PathCmd:
-                if (fUseIndexedDraw) {
-                    uint16_t prevIdx = (uint16_t)(vert - base) - 1;
-                    append_countour_edge_indices(fFill, subpathIdxStart,
-                                                 prevIdx, &idx);
-                }
-                *(vert++) = pts[1];
-                break;
-            case kQuadratic_PathCmd: {
-                // first pt of quad is the pt we ended on in previous step
-                uint16_t firstQPtIdx = (uint16_t)(vert - base) - 1;
-                uint16_t numPts =  (uint16_t) 
-                    GrPathUtils::generateQuadraticPoints(
-                            pts[0], pts[1], pts[2],
-                            srcSpaceTolSqd, &vert,
-                            GrPathUtils::quadraticPointCount(pts, srcSpaceTol));
-                if (fUseIndexedDraw) {
-                    for (uint16_t i = 0; i < numPts; ++i) {
-                        append_countour_edge_indices(fFill, subpathIdxStart,
-                                                     firstQPtIdx + i, &idx);
-                    }
-                }
-                break;
-            }
-            case kCubic_PathCmd: {
-                // first pt of cubic is the pt we ended on in previous step
-                uint16_t firstCPtIdx = (uint16_t)(vert - base) - 1;
-                uint16_t numPts = (uint16_t) GrPathUtils::generateCubicPoints(
-                                pts[0], pts[1], pts[2], pts[3],
-                                srcSpaceTolSqd, &vert,
-                                GrPathUtils::cubicPointCount(pts, srcSpaceTol));
-                if (fUseIndexedDraw) {
-                    for (uint16_t i = 0; i < numPts; ++i) {
-                        append_countour_edge_indices(fFill, subpathIdxStart,
-                                                     firstCPtIdx + i, &idx);
-                    }
-                }
-                break;
-            }
-            case kClose_PathCmd:
-                break;
-            case kEnd_PathCmd:
-                uint16_t currIdx = (uint16_t) (vert - base);
-                fSubpathVertCount[subpath] = currIdx - subpathIdxStart;
-                goto FINISHED;
-        }
-        first = false;
-    }
-FINISHED:
-    GrAssert((vert - base) <= maxPts);
-    GrAssert((idx - idxBase) <= maxIdxs);
-
-    fVertexCnt = vert - base;
-    fIndexCnt = idx - idxBase;
-
-    if (fTranslate.fX || fTranslate.fY) {
-        int count = vert - base;
-        for (int i = 0; i < count; i++) {
-            base[i].offset(fTranslate.fX, fTranslate.fY);
-        }
-    }
-    }
-    // set these at the end so if we failed on first drawPath inside a
-    // setPath/clearPath block we won't assume geom was created on a subsequent
-    // drawPath in the same block.
-    fPreviousSrcTol = srcSpaceTol;
-    fPreviousStages = stages;
-    return true;
-}
-
-void GrDefaultPathRenderer::onDrawPath(GrDrawTarget::StageBitfield stages,
-                                       bool stencilOnly) {
-
-    SK_TRACE_EVENT1("GrDefaultPathRenderer::onDrawPath",
-                    "points", SkStringPrintf("%i", path.countPoints()).c_str());
-
-    GrMatrix viewM = fTarget->getViewMatrix();
-    // In order to tesselate the path we get a bound on how much the matrix can
-    // stretch when mapping to screen coordinates.
-    GrScalar stretch = viewM.getMaxStretch();
-    bool useStretch = stretch > 0;
-    GrScalar tol = fCurveTolerance;
-
-    if (!useStretch) {
-        // TODO: deal with perspective in some better way.
-        tol /= 10;
-    } else {
-        tol = GrScalarDiv(tol, stretch);
-    }
-    // FIXME: It's really dumb that we recreate the verts for a new vertex
-    // layout. We only do that because the GrDrawTarget API doesn't allow
-    // us to change the vertex layout after reserveVertexSpace(). We won't
-    // actually change the vertex data when the layout changes since all the
-    // stages reference the positions (rather than having separate tex coords)
-    // and we don't ever have per-vert colors. In practice our call sites
-    // won't change the stages in use inside a setPath / removePath pair. But
-    // it is a silly limitation of the GrDrawTarget design that should be fixed.
-    if (tol != fPreviousSrcTol ||
-        stages != fPreviousStages) {
-        if (!this->createGeom(tol, stages)) {
-            return;
-        }
-    }
-
-    GrAssert(NULL != fTarget);
-    GrDrawTarget::AutoStateRestore asr(fTarget);
-    bool colorWritesWereDisabled = fTarget->isColorWriteDisabled();
-    // face culling doesn't make sense here
-    GrAssert(GrDrawTarget::kBoth_DrawFace == fTarget->getDrawFace());
-
-    int                         passCount = 0;
-    const GrStencilSettings*    passes[3];
-    GrDrawTarget::DrawFace      drawFace[3];
-    bool                        reverse = false;
-    bool                        lastPassIsBounds;
-
-    if (kHairLine_PathFill == fFill) {
-        passCount = 1;
-        if (stencilOnly) {
-            passes[0] = &gDirectToStencil;
-        } else {
-            passes[0] = NULL;
-        }
-        lastPassIsBounds = false;
-        drawFace[0] = GrDrawTarget::kBoth_DrawFace;
-    } else {
-        if (single_pass_path(*fTarget, *fPath, fFill)) {
-            passCount = 1;
-            if (stencilOnly) {
-                passes[0] = &gDirectToStencil;
-            } else {
-                passes[0] = NULL;
-            }
-            drawFace[0] = GrDrawTarget::kBoth_DrawFace;
-            lastPassIsBounds = false;
-        } else {
-            switch (fFill) {
-                case kInverseEvenOdd_PathFill:
-                    reverse = true;
-                    // fallthrough
-                case kEvenOdd_PathFill:
-                    passes[0] = &gEOStencilPass;
-                    if (stencilOnly) {
-                        passCount = 1;
-                        lastPassIsBounds = false;
-                    } else {
-                        passCount = 2;
-                        lastPassIsBounds = true;
-                        if (reverse) {
-                            passes[1] = &gInvEOColorPass;
-                        } else {
-                            passes[1] = &gEOColorPass;
-                        }
-                    }
-                    drawFace[0] = drawFace[1] = GrDrawTarget::kBoth_DrawFace;
-                    break;
-
-                case kInverseWinding_PathFill:
-                    reverse = true;
-                    // fallthrough
-                case kWinding_PathFill:
-                    if (fSeparateStencil) {
-                        if (fStencilWrapOps) {
-                            passes[0] = &gWindStencilSeparateWithWrap;
-                        } else {
-                            passes[0] = &gWindStencilSeparateNoWrap;
-                        }
-                        passCount = 2;
-                        drawFace[0] = GrDrawTarget::kBoth_DrawFace;
-                    } else {
-                        if (fStencilWrapOps) {
-                            passes[0] = &gWindSingleStencilWithWrapInc;
-                            passes[1] = &gWindSingleStencilWithWrapDec;
-                        } else {
-                            passes[0] = &gWindSingleStencilNoWrapInc;
-                            passes[1] = &gWindSingleStencilNoWrapDec;
-                        }
-                        // which is cw and which is ccw is arbitrary.
-                        drawFace[0] = GrDrawTarget::kCW_DrawFace;
-                        drawFace[1] = GrDrawTarget::kCCW_DrawFace;
-                        passCount = 3;
-                    }
-                    if (stencilOnly) {
-                        lastPassIsBounds = false;
-                        --passCount;
-                    } else {
-                        lastPassIsBounds = true;
-                        drawFace[passCount-1] = GrDrawTarget::kBoth_DrawFace;
-                        if (reverse) {
-                            passes[passCount-1] = &gInvWindColorPass;
-                        } else {
-                            passes[passCount-1] = &gWindColorPass;
-                        }
-                    }
-                    break;
-                default:
-                    GrAssert(!"Unknown path fFill!");
-                    return;
-            }
-        }
-    }
-
-    {
-    SK_TRACE_EVENT1("GrDefaultPathRenderer::onDrawPath::renderPasses",
-                    "verts", SkStringPrintf("%i", vert - base).c_str());
-    for (int p = 0; p < passCount; ++p) {
-        fTarget->setDrawFace(drawFace[p]);
-        if (NULL != passes[p]) {
-            fTarget->setStencil(*passes[p]);
-        }
-
-        if (lastPassIsBounds && (p == passCount-1)) {
-            if (!colorWritesWereDisabled) {
-                fTarget->disableState(GrDrawTarget::kNoColorWrites_StateBit);
-            }
-            GrRect bounds;
-            if (reverse) {
-                GrAssert(NULL != fTarget->getRenderTarget());
-                // draw over the whole world.
-                bounds.setLTRB(0, 0,
-                               GrIntToScalar(fTarget->getRenderTarget()->width()),
-                               GrIntToScalar(fTarget->getRenderTarget()->height()));
-                GrMatrix vmi;
-                if (fTarget->getViewInverse(&vmi)) {
-                    vmi.mapRect(&bounds);
-                }
-            } else {
-                bounds = fPath->getBounds();
-                bounds.offset(fTranslate);
-            }
-            GrDrawTarget::AutoGeometryPush agp(fTarget);
-            fTarget->drawSimpleRect(bounds, NULL, stages);
-        } else {
-            if (passCount > 1) {
-                fTarget->enableState(GrDrawTarget::kNoColorWrites_StateBit);
-            }
-            if (fUseIndexedDraw) {
-                fTarget->drawIndexed(fPrimitiveType, 0, 0, 
-                                     fVertexCnt, fIndexCnt);
-            } else {
-                int baseVertex = 0;
-                for (int sp = 0; sp < fSubpathCount; ++sp) {
-                    fTarget->drawNonIndexed(fPrimitiveType, baseVertex,
-                                            fSubpathVertCount[sp]);
-                    baseVertex += fSubpathVertCount[sp];
-                }
-            }
-        }
-    }
-    }
-}
-
-void GrDefaultPathRenderer::drawPath(GrDrawTarget::StageBitfield stages) {
-    this->onDrawPath(stages, false);
-}
-
-void GrDefaultPathRenderer::drawPathToStencil() {
-    GrAssert(kInverseEvenOdd_PathFill != fFill);
-    GrAssert(kInverseWinding_PathFill != fFill);
-    this->onDrawPath(0, true);
-}
diff --git a/gpu/src/GrPathRenderer.h b/gpu/src/GrPathRenderer.h
index 67c3a93..25dfafb 100644
--- a/gpu/src/GrPathRenderer.h
+++ b/gpu/src/GrPathRenderer.h
@@ -11,9 +11,11 @@
 #define GrPathRenderer_DEFINED
 
 #include "GrDrawTarget.h"
-#include "SkTemplates.h"
+#include "GrTArray.h"
+#include "GrPathRendererChain.h"
 
 class SkPath;
+
 struct GrPoint;
 
 /**
@@ -29,6 +31,23 @@
  */
 class GR_API GrPathRenderer : public GrRefCnt {
 public:
+
+    /**
+     * 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 most recently added is the
+     * most preferred path renderer.
+     *
+     * @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);
+
+
     GrPathRenderer(void);
     /**
      * Returns true if this path renderer is able to render the path.
@@ -71,7 +90,7 @@
      * having FSAA enabled for a render target). Target is provided to
      * communicate the draw state (blend mode, stage settings, etc).
      */
-    virtual bool supportsAA(GrDrawTarget* target,
+    virtual bool supportsAA(const GrDrawTarget* target,
                             const SkPath& path,
                             GrPathFill fill) { return false; }
 
@@ -136,13 +155,6 @@
     }
 
     /**
-     * This is called to install a custom path renderer in every GrContext at
-     * create time. The default implementation in GrCreatePathRenderer_none.cpp
-     * returns NULL. Link against another implementation to install your own.
-     */
-    static GrPathRenderer* CreatePathRenderer();
-
-    /**
      * Multiply curve tolerance by the given value, increasing or decreasing
      * the maximum error permitted in tesselating curves with short straight
      * line segments.
@@ -208,49 +220,5 @@
     typedef GrRefCnt INHERITED;
 };
 
-/**
- *  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);
-
-    virtual bool canDrawPath(const SkPath& path,
-                             GrPathFill fill) const { return true; }
-
-    virtual bool requiresStencilPass(const GrDrawTarget* target,
-                                     const SkPath& path,
-                                     GrPathFill fill) const;
-
-    virtual void drawPath(GrDrawTarget::StageBitfield stages);
-    virtual void drawPathToStencil();
-
-protected:
-    virtual void pathWillClear();
-
-private:
-
-    void onDrawPath(GrDrawTarget::StageBitfield stages, bool stencilOnly);
-
-    bool createGeom(GrScalar srcSpaceTol,
-                    GrDrawTarget::StageBitfield stages);
-
-    bool    fSeparateStencil;
-    bool    fStencilWrapOps;
-
-    int                         fSubpathCount;
-    SkAutoSTMalloc<8, uint16_t> fSubpathVertCount;
-    int                         fIndexCnt;
-    int                         fVertexCnt;
-    GrScalar                    fPreviousSrcTol;
-    GrDrawTarget::StageBitfield fPreviousStages;
-    GrPrimitiveType             fPrimitiveType;
-    bool                        fUseIndexedDraw;
-
-    typedef GrPathRenderer INHERITED;
-};
-
 #endif
 
diff --git a/gpu/src/GrPathRendererChain.cpp b/gpu/src/GrPathRendererChain.cpp
new file mode 100644
index 0000000..afae912
--- /dev/null
+++ b/gpu/src/GrPathRendererChain.cpp
@@ -0,0 +1,65 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#include "GrPathRendererChain.h"
+
+#include "GrContext.h"
+#include "GrDefaultPathRenderer.h"
+#include "GrGpu.h"
+
+GrPathRendererChain::GrPathRendererChain(GrContext* context, UsageFlags flags)
+    : fInit(false)
+    , fFlags(flags)
+    , fOwner(context)
+    , fChain(fStorage.get(), kPreAllocCount) {
+    fInit = false;
+}
+    
+GrPathRendererChain::~GrPathRendererChain() {
+    for (int i = 0; i < fChain.count(); ++i) {
+        fChain[i]->unref();
+    }
+}
+
+GrPathRenderer* GrPathRendererChain::addPathRenderer(GrPathRenderer* pr) {
+    fChain.push_back() = pr;
+    pr->ref();
+    return pr;
+}
+
+GrPathRenderer* GrPathRendererChain::getPathRenderer(const GrDrawTarget* target,
+                                                     const GrPath& path,
+                                                     GrPathFill fill) {
+    if (!fInit) {
+        this->init();
+    }
+    bool preferAA = target->isAntialiasState() && 
+                    !target->getRenderTarget()->isMultisampled();
+    GrPathRenderer* nonAAPR = NULL;
+    for (int i = 0; i < fChain.count(); ++i) {
+        if (fChain[i]->canDrawPath(path, fill)) {
+            if (!preferAA || fChain[i]->supportsAA(target, path, fill)) {
+                return fChain[i];
+            } else {
+                nonAAPR = fChain[i];
+            }
+        }
+    }
+    return nonAAPR;
+}
+
+void GrPathRendererChain::init() {
+    GrAssert(!fInit);
+    GrGpu* gpu = fOwner->getGpu();
+    this->addPathRenderer(
+                    new GrDefaultPathRenderer(gpu->supportsTwoSidedStencil(),
+                    gpu->supportsStencilWrapOps()))->unref();
+    GrPathRenderer::AddPathRenderers(fOwner, fFlags, this);
+    fInit = true;
+}
diff --git a/gpu/src/GrPathRendererChain.h b/gpu/src/GrPathRendererChain.h
new file mode 100644
index 0000000..5fa8c2e
--- /dev/null
+++ b/gpu/src/GrPathRendererChain.h
@@ -0,0 +1,64 @@
+
+/*
+ * 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 "GrTArray.h"
+
+class GrContext;
+class GrDrawTarget;
+class SkPath;
+class GrPathRenderer;
+
+/**
+ * Keeps track of a 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:
+
+    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 GrDrawTarget* target,
+                                    const SkPath& path,
+                                    GrPathFill fill);
+
+private:
+
+    GrPathRendererChain();
+
+    void init();
+
+    enum {
+        kPreAllocCount = 8,
+    };
+    bool fInit;
+    GrContext*                                          fOwner;
+    UsageFlags                                          fFlags;
+    GrAlignedSTStorage<kPreAllocCount, GrPathRenderer*> fStorage;
+    GrTArray<GrPathRenderer*, true>                     fChain;
+};
+
+GR_MAKE_BITFIELD_OPS(GrPathRendererChain::UsageFlags)
+
+#endif
\ No newline at end of file
diff --git a/gpu/src/GrTesselatedPathRenderer.cpp b/gpu/src/GrTesselatedPathRenderer.cpp
index 9a72101..aca6ec2 100644
--- a/gpu/src/GrTesselatedPathRenderer.cpp
+++ b/gpu/src/GrTesselatedPathRenderer.cpp
@@ -608,8 +608,8 @@
     GrAlwaysAssert(!"multipass stencil should not be needed");
 }
 
-bool GrTesselatedPathRenderer::supportsAA(GrDrawTarget* target,
-                                                  const SkPath& path,
-                                                  GrPathFill fill) {
+bool GrTesselatedPathRenderer::supportsAA(const GrDrawTarget* target,
+                                          const SkPath& path,
+                                          GrPathFill fill) {
     return true;
 }
diff --git a/gpu/src/GrTesselatedPathRenderer.h b/gpu/src/GrTesselatedPathRenderer.h
index 5791be6..c815f50 100644
--- a/gpu/src/GrTesselatedPathRenderer.h
+++ b/gpu/src/GrTesselatedPathRenderer.h
@@ -24,7 +24,7 @@
                                      const GrPath& path,
                                      GrPathFill fill) const { return false; }
     virtual void drawPathToStencil();
-    virtual bool supportsAA(GrDrawTarget* target,
+    virtual bool supportsAA(const GrDrawTarget* target,
                             const GrPath& path,
                             GrPathFill fill);
 };