Add support for clipstack to Gr. GrClip is now a list of rects and paths with set operations to combine them. The stencil buffer is used to perform the set operations to put the clip into the stencil buffer. Building Gr's clip from Skia's clipStack is currently disabled due to the fact that Skia's clipStack is relative to the root layer not the current layer. This will be fixed in a subsequent CL.

git-svn-id: http://skia.googlecode.com/svn/trunk@878 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gpu/include/GrClip.h b/gpu/include/GrClip.h
index 8e3030c..414a6d6 100644
--- a/gpu/include/GrClip.h
+++ b/gpu/include/GrClip.h
@@ -20,96 +20,116 @@
 
 #include "GrClipIterator.h"
 #include "GrRect.h"
-#include "GrTDArray.h"
+#include "GrPath.h"
+#include "GrTArray.h"
+
 
 class GrClip {
 public:
     GrClip();
     GrClip(const GrClip& src);
-    GrClip(GrClipIterator* iter);
+    GrClip(GrClipIterator* iter, const GrRect* bounds = NULL);
+    GrClip(const GrIRect& rect);
+    GrClip(const GrRect& rect);
+
     ~GrClip();
 
     GrClip& operator=(const GrClip& src);
 
-    bool isEmpty() const { return fBounds.isEmpty(); }
-    bool isComplex() const { return fList.count() > 0; }
-    bool isRect() const {
-        return !this->isEmpty() && !this->isComplex();
+    bool hasBounds() const { return fBoundsValid; }
+
+    const GrRect& getBounds() const { return fBounds; }
+
+    int getElementCount() const { return fList.count(); }
+
+    GrClipType getElementType(int i) const { return fList[i].fType; }
+
+    const GrPath& getPath(int i) const {
+        GrAssert(kPath_ClipType == fList[i].fType);
+        return fList[i].fPath;
     }
-    
-    const GrIRect& getBounds() const { return fBounds; }
+
+    GrPathFill getPathFill(int i) const {
+        GrAssert(kPath_ClipType == fList[i].fType);
+        return fList[i].fPathFill;
+    }
+
+    const GrRect& getRect(int i) const {
+        GrAssert(kRect_ClipType == fList[i].fType);
+        return fList[i].fRect;
+    }
+
+    const GrSetOp getOp(int i) const { return fList[i].fOp; }
+
+    bool isRect() const {
+        if (1 == fList.count() && kRect_ClipType == fList[0].fType) {
+            GrAssert(fBoundsValid);
+            GrAssert(fBounds == fList[0].fRect);
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    bool isEmpty() const { return 0 == fList.count(); }
 
     /**
-     *  Resets this clip to be empty (fBounds is empty, and fList is empty)
+     *  Resets this clip to be empty
      */
     void setEmpty();
-
-    /**
-     *  Resets this clip to have fBounds == rect, and fList is empty.
-     */
-    void setRect(const GrIRect& rect);
-
-    /**
-     *  Append a rect to an existing clip. The call must ensure that rect does
-     *  not overlap with any previous rect in this clip (either from setRect
-     *  or addRect). fBounds is automatically updated to reflect the union of
-     *  all rects that have been added.
-     */
-    void addRect(const GrIRect&);
-
-    void setFromIterator(GrClipIterator* iter);
+    void setFromIterator(GrClipIterator* iter, const GrRect* bounds = NULL);
+    void setFromRect(const GrRect& rect);
+    void setFromIRect(const GrIRect& rect);
 
     friend bool operator==(const GrClip& a, const GrClip& b) {
-        return a.fBounds == b.fBounds && a.fList == b.fList;
+        if (a.fList.count() != b.fList.count()) {
+            return false;
+        }
+        int count = a.fList.count();
+        for (int i = 0; i < count; ++i) {
+            if (a.fList[i] != b.fList[i]) {
+                return false;
+            }
+        }
+        return true;
     }
     friend bool operator!=(const GrClip& a, const GrClip& b) {
         return !(a == b);
     }
 
-    /**
-     *  Return the number of rects in this clip: 0 for empty, 1 for a rect,
-     *  or N for a complex clip.
-     */
-    int countRects() const {
-        return this->isEmpty() ? 0 : GrMax<int>(1, fList.count());
-    }
-
-    /**
-     *  Return an array of rects for this clip. Use countRects() to know the
-     *  number of entries.
-     */
-    const GrIRect* getRects() const {
-        return fList.count() > 0 ? fList.begin() : &fBounds;
-    }
-
-#if GR_DEBUG
-    void validate() const;
-#else
-    void validate() const {}
-#endif
-
 private:
-    GrTDArray<GrIRect>  fList;
-    GrIRect             fBounds;
-};
+    struct Element {
+        GrClipType  fType;
+        GrRect      fRect;
+        GrPath      fPath;
+        GrPathFill  fPathFill;
+        GrSetOp     fOp;
+        bool operator ==(const Element& e) const {
+            if (e.fType != fType || e.fOp != fOp) {
+                return false;
+            }
+            switch (fType) {
+                case kRect_ClipType:
+                    return fRect == e.fRect;
+                    break;
+                case kPath_ClipType:
+                    return fPath == e.fPath;
+                default:
+                    GrCrash("Unknown clip element type.");
+                    return false; // suppress warning
+            }
+        }
+        bool operator !=(const Element& e) const { return !(*this == e); }
+    };
 
-class GrClipIter : public GrClipIterator {
-public:
-    GrClipIter(const GrClip& clip) : fClip(&clip), fIndex(0) {}
-    GrClipIter() : fClip(NULL), fIndex(0) {}
-    
-    void reset(const GrClip& clip);
-    
-    virtual bool isDone();
-    virtual void rewind();
-    virtual void getRect(GrIRect* r);
-    virtual void next();
-    virtual void computeBounds(GrIRect* r);
-    
-private:
-    const GrClip*   fClip;
-    int             fIndex;
-};
+    GrRect              fBounds;
+    bool                fBoundsValid;
 
+    enum {
+        kPreAllocElements = 4,
+    };
+    uint8_t             fListMemory[sizeof(Element) * kPreAllocElements];
+    GrTArray<Element>   fList;
+};
 #endif
 
diff --git a/gpu/include/GrClipIterator.h b/gpu/include/GrClipIterator.h
index d1fe4dd..abad619 100644
--- a/gpu/include/GrClipIterator.h
+++ b/gpu/include/GrClipIterator.h
@@ -18,54 +18,60 @@
 #ifndef GrClipIterator_DEFINED
 #define GrClipIterator_DEFINED
 
+#include "GrPath.h"
 #include "GrRect.h"
 
+/**
+ * A clip is a list of paths and/or rects with set operations to combine them.
+ */
 class GrClipIterator {
 public:
-    GrClipIterator() : fNeedBounds(true) {}
     virtual ~GrClipIterator() {}
 
     /**
      *  Returns true if there are no more rects to process
      */
-    virtual bool isDone() = 0;
+    virtual bool isDone() const = 0;
 
     /**
-     *  Rewind the iterate to replay the set of rects again
+     *  Rewind the iterator to replay the set of clip elements again
      */
     virtual void rewind() = 0;
 
     /**
-     *  Return the current rect. It is an error to call this when done() is true
+     * Get the type of the current clip element
      */
-    virtual void getRect(GrIRect*) = 0;
+    virtual GrClipType getType() const = 0;
 
     /**
-     *  Call to move to the next rect in the set
+     * Return the current path. It is an error to call this when isDone() is
+     * true or when getType() is kRect_Type.
+     */
+    virtual GrPathIter* getPathIter() = 0;
+
+    /**
+     * Return the fill rule for the path. It is an error to call this when
+     * isDone() is true or when getType is kRect_Type.
+     */
+    virtual GrPathFill getPathFill() const = 0;
+
+    /**
+    * Return the current rect. It is an error to call this when isDone is true
+    * or when getType() is kPath_Type.
+    */
+    virtual void getRect(GrRect* rect) const = 0;
+
+    /**
+     * Gets the operation used to apply the current item to previously iterated
+     * items. Iterators should not produce a Replace op.
+     */
+    virtual GrSetOp getOp() const = 0;
+
+    /**
+     *  Call to move to the next rect in the set, previous path iter can be made
+     *  invalid.
      */
     virtual void next() = 0;
-
-    /**
-     *  Set bounds to be the bounds of the clip.
-     */
-    virtual void computeBounds(GrIRect* bounds) = 0;
-
-    /**
-     *  Subclass should call this whenever their underlying bounds has changed.
-     */
-    void invalidateBoundsCache() { fNeedBounds = true; }
-
-    const GrIRect& getBounds() {
-        if (fNeedBounds) {
-            this->computeBounds(&fBounds);
-            fNeedBounds = false;
-        }
-        return fBounds;
-    }
-
-private:
-    GrIRect fBounds;
-    bool    fNeedBounds;
 };
 
 /**
diff --git a/gpu/include/GrContext.h b/gpu/include/GrContext.h
index caba6ef..b43375c 100644
--- a/gpu/include/GrContext.h
+++ b/gpu/include/GrContext.h
@@ -278,16 +278,23 @@
                         const GrMatrix* srcMatrix = NULL);
 
     /**
-     * Tessellates and draws a path.
+     * Draws a path.
      *
      * @param paint         describes how to color pixels.
-     * @param path          the path to draw
+     * @param pathIter      the path to draw
      * @param fill          the path filling rule to use.
      * @param translate     optional additional translation applied to the
      *                      path.
      */
     void drawPath(const GrPaint& paint,
-                  GrPathIter* path,
+                  GrPathIter* pathIter,
+                  GrPathFill fill,
+                  const GrPoint* translate = NULL);
+    /**
+     * Helper version of drawPath that takes a GrPath
+     */
+    void drawPath(const GrPaint& paint,
+                  const GrPath& path,
                   GrPathFill fill,
                   const GrPoint* translate = NULL);
     /**
diff --git a/gpu/include/GrDrawTarget.h b/gpu/include/GrDrawTarget.h
index 10c6d48..576bd7a 100644
--- a/gpu/include/GrDrawTarget.h
+++ b/gpu/include/GrDrawTarget.h
@@ -23,9 +23,10 @@
 #include "GrRefCnt.h"
 #include "GrSamplerState.h"
 #include "GrClip.h"
+#include "GrTexture.h"
+#include "GrStencil.h"
 
 class GrTexture;
-class GrRenderTarget;
 class GrClipIterator;
 class GrVertexBuffer;
 class GrIndexBuffer;
@@ -72,56 +73,63 @@
         kClip_StateBit            = 0x4,//<! Controls whether drawing is clipped
                                         //   against the region specified by
                                         //   setClip.
+        kNoColorWrites_StateBit   = 0x8,//<! If set it disables writing colors.
+                                        //   Useful while performing stencil ops.
+
+        // subclass may use additional bits internally
+        kDummyStateBit,
+        kLastPublicStateBit = kDummyStateBit-1
+    };
+
+    enum DrawFace {
+        kBoth_DrawFace,
+        kCCW_DrawFace,
+        kCW_DrawFace,
     };
 
     /**
-     * StencilPass
-     *
-     * Sets the stencil state for subsequent draw calls. Used to fill paths.
-     *
-     * Winding requires two passes when the GPU/API doesn't support separate
-     * stencil.
-     *
-     * The color pass for path fill is used to zero out stencil bits used for
-     * path filling. Every pixel covere by a winding/EO stencil pass must get
-     * covered by the color pass in order to leave stencil buffer in the correct
-     * state for the next path draw.
-     *
-     * NOTE: Stencil-based Winding fill has alias-to-zero problems. (e.g. A
-     * winding count of 128,256,512,etc with a 8 bit stencil buffer
-     * will be unfilled)
+     * The DrawTarget may reserve some of the high bits of the stencil. The draw
+     * target will automatically trim reference and mask values so that the
+     * client doesn't overwrite these bits.
+     * The number of bits available is relative to the currently set render
+      *target.
+     * @return the number of bits usable by the draw target client.
      */
-    enum StencilPass {
-        kNone_StencilPass,            //<! Not drawing a path or clip.
-        kEvenOddStencil_StencilPass,  //<! records in/out in stencil buffer
-                                      //   using the Even/Odd fill rule.
-        kEvenOddColor_StencilPass,    //<! writes colors to color target in
-                                      //   pixels marked inside the fill by
-                                      //   kEOFillStencil_StencilPass. Clears
-                                      //   stencil in pixels covered by
-                                      //   geometry.
-        kWindingStencil1_StencilPass, //<! records in/out in stencil buffer
-                                      //   using the Winding fill rule.
-        kWindingStencil2_StencilPass, //<! records in/out in stencil buffer
-                                      //   using the Winding fill rule.
-                                      //   Run when single-stencil-pass winding
-                                      //   not supported (i.e. no separate
-                                      //   stencil support)
-        kWindingColor_StencilPass,    //<! writes colors to color target in
-                                      //   pixels marked inside the fill by
-                                      //   kWindFillStencil_StencilPass. Clears
-                                      //   stencil in pixels covered by
-                                      //   geometry.
-        kDrawTargetCount_StencilPass  //<! Subclass may extend this enum to use
-                                      //   the stencil for other purposes (e.g.
-                                      //   to do stencil-based clipping)
-                                      //   This value is provided as basis for
-                                      //   defining these extended enum values.
-    };
+    int getUsableStencilBits() const {
+        int bits = fCurrDrawState.fRenderTarget->stencilBits();
+        if (bits) {
+            return bits - 1;
+        } else {
+            return 0;
+        }
+    }
+
+    /**
+     * Sets the stencil settings to use for the next draw.
+     * @param settings  the stencil settings to use.
+     */
+    void setStencil(const GrStencilSettings& settings) {
+        fCurrDrawState.fStencilSettings = settings;
+    }
+
+    /**
+     * Shortcut to disable stencil testing and ops.
+     */
+    void disableStencil() {
+        fCurrDrawState.fStencilSettings.setDisabled();
+    }
 
 protected:
 
     struct DrState {
+        DrState() {
+            // make sure any pad is zero for memcmp
+            // all DrState members should default to something
+            // valid by the memset
+            memset(this, 0, sizeof(DrState));
+            GrAssert((intptr_t)(void*)NULL == 0LL);
+            GrAssert(fStencilSettings.isDisabled());
+        }
         uint32_t                fFlagBits;
         GrBlendCoeff            fSrcBlend;
         GrBlendCoeff            fDstBlend;
@@ -129,8 +137,9 @@
         GrSamplerState          fSamplerStates[kNumStages];
         GrRenderTarget*         fRenderTarget;
         GrColor                 fColor;
-        StencilPass             fStencilPass;
-        bool                    fReverseFill;
+        DrawFace                fDrawFace;
+
+        GrStencilSettings       fStencilSettings;
         GrMatrix                fViewMatrix;
         bool operator ==(const DrState& s) const {
             return 0 == memcmp(this, &s, sizeof(DrState));
@@ -196,7 +205,7 @@
     /**
      * Sets the sampler state for a stage used in subsequent draws.
      *
-     * The sampler state determines how texture coordinates are 
+     * The sampler state determines how texture coordinates are
      * intepretted and used to sample the texture.
      *
      * @param stage           the stage of the sampler to set
@@ -291,19 +300,17 @@
     void setAlpha(uint8_t alpha);
 
     /**
-     * Sets pass for path rendering
-     *
-     * @param pass of path rendering
+     * Controls whether clockwise, counterclockwise, or both faces are drawn.
+     * @param face  the face(s) to draw.
      */
-    void setStencilPass(StencilPass pass);
+    void setDrawFace(DrawFace face) { fCurrDrawState.fDrawFace = face; }
 
     /**
-     * Reveses the in/out decision of the fill rule for path rendering.
-     * Only affects kEOFillColor_StencilPass and kWindingFillColor_StencilPass
-     *
-     * @param reverse true to reverse, false otherwise
+     * Gets whether the target is drawing clockwise, counterclockwise,
+     * or both faces.
+     * @return the current draw face(s).
      */
-    void setReverseFill(bool reverse);
+    DrawFace getDrawFace() const { return fCurrDrawState.fDrawFace; }
 
     /**
      * Enable render state settings.
@@ -327,6 +334,10 @@
         return 0 != (fCurrDrawState.fFlagBits & kClip_StateBit);
     }
 
+    bool isColorWriteDisabled() const {
+        return 0 != (fCurrDrawState.fFlagBits & kNoColorWrites_StateBit);
+    }
+
     /**
      * Sets the blending function coeffecients.
      *
@@ -457,8 +468,8 @@
                                                 //   text [GrGpuTextVertex vs
                                                 //   GrPoint].)
         // for below assert
-        kDummy,
-        kHighVertexLayoutBit = kDummy - 1
+        kDummyVertexLayoutBit,
+        kHighVertexLayoutBit = kDummyVertexLayoutBit - 1
     };
     // make sure we haven't exceeded the number of bits in GrVertexLayout.
     GR_STATIC_ASSERT(kHighVertexLayoutBit < (1 << 8*sizeof(GrVertexLayout)));
@@ -648,7 +659,7 @@
      * have changed. They should be reestablished before the next drawIndexed
      * or drawNonIndexed. This cannot be called between reserving and releasing
      * geometry. The GrDrawTarget subclass may be able to perform additional
-     * optimizations if drawRect is used rather than drawIndexed or 
+     * optimizations if drawRect is used rather than drawIndexed or
      * drawNonIndexed.
      * @param rect      the rect to draw
      * @param matrix    optional matrix applied to rect (before viewMatrix)
@@ -665,18 +676,18 @@
      *                      srcMatrix[i]. srcMatrices can be NULL when no
      *                      srcMatrices are desired.
      */
-    virtual void drawRect(const GrRect& rect, 
+    virtual void drawRect(const GrRect& rect,
                           const GrMatrix* matrix,
                           StageBitfield stageEnableBitfield,
                           const GrRect* srcRects[],
                           const GrMatrix* srcMatrices[]);
 
     /**
-     * Helper for drawRect when the caller doesn't need separate src rects or 
+     * Helper for drawRect when the caller doesn't need separate src rects or
      * matrices.
      */
-    void drawSimpleRect(const GrRect& rect, 
-                        const GrMatrix* matrix, 
+    void drawSimpleRect(const GrRect& rect,
+                        const GrMatrix* matrix,
                         StageBitfield stageEnableBitfield) {
          drawRect(rect, matrix, stageEnableBitfield, NULL, NULL);
     }
@@ -912,20 +923,20 @@
      *                      Defaults to zero (corresponding to vertex position)
      * @return pointer to the vertex component as a GrPoint
      */
-    static GrPoint* GetVertexPoint(void* vertices, 
+    static GrPoint* GetVertexPoint(void* vertices,
                                    int vertexIndex,
                                    int vertexSize,
                                    int offset = 0) {
         intptr_t start = GrTCast<intptr_t>(vertices);
-        return GrTCast<GrPoint*>(start + offset + 
+        return GrTCast<GrPoint*>(start + offset +
                                  vertexIndex * vertexSize);
     }
     static const GrPoint* GetVertexPoint(const void* vertices,
                                          int vertexIndex,
-                                         int vertexSize, 
+                                         int vertexSize,
                                          int offset = 0) {
         intptr_t start = GrTCast<intptr_t>(vertices);
-        return GrTCast<const GrPoint*>(start + offset + 
+        return GrTCast<const GrPoint*>(start + offset +
                                        vertexIndex * vertexSize);
     }
 
@@ -937,20 +948,20 @@
      * @param offset        the offset in bytes of the vertex color
      * @return pointer to the vertex component as a GrColor
      */
-    static GrColor* GetVertexColor(void* vertices, 
+    static GrColor* GetVertexColor(void* vertices,
                                    int vertexIndex,
                                    int vertexSize,
                                    int offset) {
         intptr_t start = GrTCast<intptr_t>(vertices);
-        return GrTCast<GrColor*>(start + offset + 
+        return GrTCast<GrColor*>(start + offset +
                                  vertexIndex * vertexSize);
     }
     static const GrColor* GetVertexColor(const void* vertices,
                                          int vertexIndex,
-                                         int vertexSize, 
+                                         int vertexSize,
                                          int offset) {
         const intptr_t start = GrTCast<intptr_t>(vertices);
-        return GrTCast<const GrColor*>(start + offset + 
+        return GrTCast<const GrColor*>(start + offset +
                                        vertexIndex * vertexSize);
     }
 
@@ -985,10 +996,10 @@
                                               const GrRect* srcRects[]);
 
     static void SetRectVertices(const GrRect& rect,
-                                const GrMatrix* matrix, 
-                                const GrRect* srcRects[], 
+                                const GrMatrix* matrix,
+                                const GrRect* srcRects[],
                                 const GrMatrix* srcMatrices[],
-                                GrVertexLayout layout, 
+                                GrVertexLayout layout,
                                 void* vertices);
 
     enum GeometrySrcType {
@@ -997,7 +1008,7 @@
         kBuffer_GeometrySrcType     // src was set using set*SourceToBuffer
     };
 
-    struct {
+    struct ReservedGeometry {
         bool            fLocked;
         uint32_t        fVertexCount;
         uint32_t        fIndexCount;
diff --git a/gpu/include/GrGLTexture.h b/gpu/include/GrGLTexture.h
index fc12ee0..14370ab 100644
--- a/gpu/include/GrGLTexture.h
+++ b/gpu/include/GrGLTexture.h
@@ -36,9 +36,6 @@
     GLuint renderFBOID() const { return fRTFBOID; }
     GLuint textureFBOID() const { return fTexFBOID; }
 
-    GLuint getStencilBits() const { return fStencilBits; }
-
-    const GrGLIRect& viewport() const { return fViewport; }
     void   abandon();
 
 protected:
@@ -58,17 +55,13 @@
                      GrGpuGL* gl);
     
     void setViewport(const GrGLIRect& rect) { fViewport = rect; }
-    
-    virtual int width() const { return fViewport.fWidth; }
-    virtual int height() const { return fViewport.fHeight; }
-
+    const GrGLIRect& getViewport() const { return fViewport; }
 private:
     GrGpuGL*    fGL;
     GLuint      fRTFBOID;
     GLuint      fTexFBOID;    
     GLuint      fStencilRenderbufferID;
     GLuint      fMSColorRenderbufferID;
-    GLuint      fStencilBits;
    
     // Should this object delete IDs when it is destroyed or does someone
     // else own them.
diff --git a/gpu/include/GrGpu.h b/gpu/include/GrGpu.h
index 661708b..5a88ef4 100644
--- a/gpu/include/GrGpu.h
+++ b/gpu/include/GrGpu.h
@@ -25,6 +25,7 @@
 
 class GrVertexBufferAllocPool;
 class GrIndexBufferAllocPool;
+class GrPathRenderer;
 
 class GrGpu : public GrDrawTarget {
 
@@ -229,15 +230,21 @@
     bool supports8BitPalette() const { return f8bitPaletteSupport; }
 
     /**
-     * If single stencil pass winding is supported then one stencil pass
-     * (kWindingStencil1_PathPass) is required to do winding rule path filling
-     * (or inverse winding rule). Otherwise, two passes are required
-     * (kWindingStencil1_PathPass followed by kWindingStencil2_PathPass).
-     *
+     * returns true if two sided stenciling is supported. If false then only
+     * the front face values of the GrStencilSettings
      * @return    true if only a single stencil pass is needed.
      */
-    bool supportsSingleStencilPassWinding() const
-                                        { return fSingleStencilPassForWinding; }
+    bool supportsTwoSidedStencil() const
+                                        { return fTwoSidedStencilSupport; }
+
+    /**
+     * returns true if stencil wrap is supported. If false then
+     * kIncWrap_StencilOp and kDecWrap_StencilOp are treated as
+     * kIncClamp_StencilOp and kDecClamp_StencilOp, respectively.
+     * @return    true if stencil wrap ops are supported.
+     */
+    bool supportsStencilWrapOps() const
+                                        { return fStencilWrapOpsSupport; }
 
     /**
      * Checks whether locking vertex and index buffers is supported.
@@ -304,7 +311,7 @@
     const GrIndexBuffer* getQuadIndexBuffer() const;
 
     /**
-     * Returns a vertex buffer with four position-only vertices [(0,0), (1,0), 
+     * Returns a vertex buffer with four position-only vertices [(0,0), (1,0),
      * (1,1), (0,1)].
      * @ return unit square vertex buffer
      */
@@ -326,16 +333,12 @@
     void printStats() const;
 
 protected:
-    /**
-     * Extensions to GrDrawTarget::StencilPass to implement stencil clipping
-     */
-    enum GpuStencilPass {
-        kSetClip_StencilPass = kDrawTargetCount_StencilPass,
-                                        /* rendering a hard clip to the stencil
-                                           buffer. Subsequent draws with other
-                                           StencilPass values will be clipped
-                                           if kClip_StateBit is set. */
-        kGpuCount_StencilPass
+    enum PrivateStateBits {
+        kFirstBit = (kLastPublicStateBit << 1),
+
+        kModifyStencilClip_StateBit = kFirstBit, // allows draws to modify
+                                                 // stencil bits used for
+                                                 // clipping.
     };
 
     /**
@@ -344,7 +347,6 @@
     struct ClipState {
         bool            fClipInStencil;
         bool            fClipIsDirty;
-        GrRenderTarget* fStencilClipTarget;
     } fClipState;
 
     // GrDrawTarget override
@@ -353,6 +355,21 @@
     // prepares clip flushes gpu state before a draw
     bool setupClipAndFlushState(GrPrimitiveType type);
 
+    // Functions used to map clip-respecting stencil tests into normal
+    // stencil funcs supported by GPUs.
+    static GrStencilFunc ConvertStencilFunc(bool stencilInClip, 
+                                            GrStencilFunc func);
+    static void ConvertStencilFuncAndMask(GrStencilFunc func,
+                                          bool clipInStencil,
+                                          unsigned int clipBit,
+                                          unsigned int userBits,
+                                          unsigned int* ref,
+                                          unsigned int* mask);
+
+    // stencil settings to clip drawing when stencil clipping is in effect
+    // and the client isn't using the stencil test.
+    static const GrStencilSettings gClipStencilSettings;
+
     // defaults to false, subclass can set true to support palleted textures
     bool f8bitPaletteSupport;
 
@@ -360,10 +377,8 @@
     bool fNPOTTextureSupport;
     bool fNPOTTextureTileSupport;
     bool fNPOTRenderTargetSupport;
-
-    // True if only one stencil pass is required to implement the winding path
-    // fill rule. Subclass responsible for setting this value.
-    bool fSingleStencilPassForWinding;
+    bool fTwoSidedStencilSupport;
+    bool fStencilWrapOpsSupport;
 
     // set by subclass to true if index and vertex buffers can be locked, false
     // otherwise.
@@ -427,13 +442,15 @@
     virtual void flushScissor(const GrIRect* rect) = 0;
 
     // GrGpu subclass removes the clip from the stencil buffer
-    virtual void eraseStencilClip() = 0;
+    virtual void eraseStencilClip(const GrIRect& rect) = 0;
 
 private:
-
+    // readies the pools to provide vertex/index data.
     void prepareVertexPool();
     void prepareIndexPool();
 
+    GrPathRenderer* getPathRenderer();
+
     GrVertexBufferAllocPool*    fVertexPool;
 
     GrIndexBufferAllocPool*     fIndexPool;
@@ -443,6 +460,61 @@
 
     mutable GrVertexBuffer*     fUnitSquareVertexBuffer; // mutable so it can be
                                                          // created on-demand
+
+    GrPathRenderer*             fPathRenderer;
+
+    // when in an internal draw these indicate whether the pools are in use
+    // by one of the outer draws. If false then it is safe to reset the
+    // pool.
+    bool                        fVertexPoolInUse;
+    bool                        fIndexPoolInUse;
+
+    // used to save and restore state when the GrGpu needs
+    // to make its geometry pools available internally
+    class AutoInternalDrawGeomRestore {
+    public:
+        AutoInternalDrawGeomRestore(GrGpu* gpu) : fAgsr(gpu) {
+            fGpu = gpu;
+
+            fVertexPoolWasInUse = gpu->fVertexPoolInUse;
+            fIndexPoolWasInUse  = gpu->fIndexPoolInUse;
+
+            gpu->fVertexPoolInUse = fVertexPoolWasInUse ||
+                                   (kBuffer_GeometrySrcType !=
+                                    gpu->fGeometrySrc.fVertexSrc);
+            gpu->fIndexPoolInUse  = fIndexPoolWasInUse ||
+                                   (kBuffer_GeometrySrcType !=
+                                    gpu->fGeometrySrc.fIndexSrc);;
+
+            fSavedPoolVertexBuffer = gpu->fCurrPoolVertexBuffer;
+            fSavedPoolStartVertex  = gpu->fCurrPoolStartVertex;
+            fSavedPoolIndexBuffer  = gpu->fCurrPoolIndexBuffer;
+            fSavedPoolStartIndex   = gpu->fCurrPoolStartIndex;
+
+            fSavedReservedGeometry = gpu->fReservedGeometry;
+            gpu->fReservedGeometry.fLocked = false;
+        }
+        ~AutoInternalDrawGeomRestore() {
+            fGpu->fCurrPoolVertexBuffer = fSavedPoolVertexBuffer;
+            fGpu->fCurrPoolStartVertex  = fSavedPoolStartVertex;
+            fGpu->fCurrPoolIndexBuffer  = fSavedPoolIndexBuffer;
+            fGpu->fCurrPoolStartIndex   = fSavedPoolStartIndex;
+            fGpu->fVertexPoolInUse = fVertexPoolWasInUse;
+            fGpu->fIndexPoolInUse  = fIndexPoolWasInUse;
+            fGpu->fReservedGeometry = fSavedReservedGeometry;
+        }
+    private:
+        AutoGeometrySrcRestore  fAgsr;
+        GrGpu*                  fGpu;
+        const GrVertexBuffer*   fSavedPoolVertexBuffer;
+        int                     fSavedPoolStartVertex;
+        const GrIndexBuffer*    fSavedPoolIndexBuffer;
+        int                     fSavedPoolStartIndex;
+        bool                    fVertexPoolWasInUse;
+        bool                    fIndexPoolWasInUse;
+        ReservedGeometry        fSavedReservedGeometry;
+    };
+
     typedef GrDrawTarget INHERITED;
 };
 
diff --git a/gpu/include/GrPath.h b/gpu/include/GrPath.h
index cf7b97f..23fc4a8 100644
--- a/gpu/include/GrPath.h
+++ b/gpu/include/GrPath.h
@@ -35,6 +35,8 @@
 
     void resetFromIter(GrPathIter*);
 
+    bool operator ==(const GrPath& path) const;
+    bool operator !=(const GrPath& path) const { return !(*this == path); }
     // overrides from GrPathSink
 
     virtual void moveTo(GrScalar x, GrScalar y);
@@ -50,7 +52,7 @@
 
         // overrides from GrPathIter
         virtual Command next(GrPoint points[]);
-        virtual ConvexHint hint() const;
+        virtual ConvexHint convexHint() const;
         virtual Command next();
         virtual void rewind();
     private:
diff --git a/gpu/include/GrPathIter.h b/gpu/include/GrPathIter.h
index 028faaa..140cbcb 100644
--- a/gpu/include/GrPathIter.h
+++ b/gpu/include/GrPathIter.h
@@ -30,7 +30,7 @@
 class GrPathIter {
 public:
     /**
-     Returned by next(). Indicates the next piece of the path. 
+     Returned by next(). Indicates the next piece of the path.
      */
     enum Command {
         kMove_Command,      //!< next() returns 1 pt
@@ -44,35 +44,35 @@
                             //   Adds a cubic segment
         kClose_Command,     //!< next() returns 0 pts
         kEnd_Command        //!< next() returns 0 pts
-                            //   Implictly closes the last 
+                            //   Implictly closes the last
                             //   point
     };
-    
+
     enum ConvexHint {
-        kNone_ConvexHint,                         //<! No hint about convexity 
+        kNone_ConvexHint,                         //<! No hint about convexity
                                                   //   of the path
         kConvex_ConvexHint,                       //<! Path is one convex piece
-        kNonOverlappingConvexPieces_ConvexHint,   //<! Multiple convex pieces, 
+        kNonOverlappingConvexPieces_ConvexHint,   //<! Multiple convex pieces,
                                                   //   pieces are known to be
                                                   //   disjoint
-        kSameWindingConvexPieces_ConvexHint,      //<! Multiple convex pieces, 
+        kSameWindingConvexPieces_ConvexHint,      //<! Multiple convex pieces,
                                                   //   may or may not intersect,
-                                                  //   either all wind cw or all 
+                                                  //   either all wind cw or all
                                                   //   wind ccw.
-        kConcave_ConvexHint                       //<! Path is known to be 
+        kConcave_ConvexHint                       //<! Path is known to be
                                                   //   concave
     };
-    
+
     static int NumCommandPoints(Command cmd) {
         static const int numPoints[] = {
             1, 2, 3, 4, 0, 0
         };
         return numPoints[cmd];
     }
-    
+
     virtual ~GrPathIter() {};
 
-    /** 
+    /**
      Iterates through the path. Should not be called after
      kEnd_Command has been returned once. This version retrieves the
      points for the command.
@@ -85,14 +85,14 @@
     /**
      * If the host API has knowledge of the convexity of the path
      * it can be communicated by this hint. Ganesh can make these
-     * determinations itself. So it is not necessary to compute 
+     * determinations itself. So it is not necessary to compute
      * convexity status if it isn't already determined.
      *
      * @return a hint about the convexity of the path.
-     */     
-    virtual ConvexHint hint() const { return kNone_ConvexHint; }
+     */
+    virtual ConvexHint convexHint() const { return kNone_ConvexHint; }
 
-     /** 
+     /**
      Iterates through the path. Should not be called after
      kEnd_Command has been returned once. This version does not retrieve the
      points for the command.
diff --git a/gpu/include/GrRect.h b/gpu/include/GrRect.h
index e98913a..96d302f 100644
--- a/gpu/include/GrRect.h
+++ b/gpu/include/GrRect.h
@@ -22,7 +22,7 @@
 
 struct GrIRect {
     int32_t fLeft, fTop, fRight, fBottom;
-    
+
     GrIRect() {}
     GrIRect(int32_t left, int32_t top, int32_t right, int32_t bottom) {
         fLeft = left;
@@ -47,23 +47,22 @@
         fRight = x + w;
         fBottom = y + h;
     }
-    
+
     void setLTRB(int32_t l, int32_t t, int32_t r, int32_t b) {
         fLeft = l;
         fTop = t;
         fRight = r;
         fBottom = b;
     }
-    
+
     /**
      *  Make the largest representable rectangle
-
      */
     void setLargest() {
         fLeft = fTop = GR_Int32Min;
         fRight = fBottom = GR_Int32Max;
     }
-    
+
     bool quickReject(int l, int t, int r, int b) const {
         return l >= fRight || fLeft >= r || t >= fBottom || fTop >= b;
     }
@@ -75,10 +74,28 @@
         if (fBottom < r.fBottom) fBottom = r.fBottom;
     }
 
+    /**
+     * Sets this rect to the intersection with a clip rect. If there is no
+     * intersection then this rect will be made empty.
+     */
+    void intersectWith(const GrIRect& clipRect) {
+        if (fRight < clipRect.fLeft ||
+            fLeft > clipRect.fRight ||
+            fBottom < clipRect.fTop ||
+            fTop > clipRect.fBottom) {
+            this->setEmpty();
+        } else {
+            fLeft = GrMax(fLeft, clipRect.fLeft);
+            fRight = GrMin(fRight, clipRect.fRight);
+            fTop = GrMax(fTop, clipRect.fTop);
+            fBottom = GrMin(fBottom, clipRect.fBottom);
+        }
+    }
+
     friend bool operator==(const GrIRect& a, const GrIRect& b) {
         return 0 == memcmp(&a, &b, sizeof(a));
     }
-    
+
     friend bool operator!=(const GrIRect& a, const GrIRect& b) {
         return 0 != memcmp(&a, &b, sizeof(a));
     }
@@ -91,7 +108,7 @@
         return fLeft == x && fTop == y &&
                this->width() == w && this->height() == h;
     }
-    
+
     bool contains(const GrIRect& r) const {
         return fLeft   <= r.fLeft &&
                fRight  >= r.fRight &&
@@ -102,12 +119,12 @@
 
 struct GrIRect16 {
     int16_t fLeft, fTop, fRight, fBottom;
-    
+
     int width() const { return fRight - fLeft; }
     int height() const { return fBottom - fTop; }
     int area() const { return this->width() * this->height(); }
     bool isEmpty() const { return fLeft >= fRight || fTop >= fBottom; }
-    
+
     void set(const GrIRect& r) {
         fLeft   = GrToS16(r.fLeft);
         fTop    = GrToS16(r.fTop);
@@ -116,12 +133,12 @@
     }
 };
 
-/** 
+/**
  *  2D Rect struct
  */
 struct GrRect {
     GrScalar fLeft, fTop, fRight, fBottom;
-    
+
     /**
      *  Uninitialized rectangle.
      */
@@ -158,7 +175,7 @@
     GrScalar top() const { return fTop; }
     GrScalar right() const { return fRight; }
     GrScalar bottom() const { return fBottom; }
-    
+
     GrScalar diagonalLengthSqd() const {
         GrScalar w = width();
         GrScalar h = height();
@@ -169,18 +186,18 @@
         // TODO: fixed point sqrt
         return GrFloatToScalar(sqrtf(GrScalarToFloat(diagonalLengthSqd())));
     }
-    
+
     /**
      *  Returns true if the width or height is <= 0
      */
     bool isEmpty() const {
         return fLeft >= fRight || fTop >= fBottom;
     }
-    
+
     void setEmpty() {
         fLeft = fTop = fRight = fBottom = 0;
     }
-    
+
     /**
      *  returns true if the rectangle is inverted either in x or y
      */
@@ -192,7 +209,7 @@
         return point.fX >= fLeft && point.fX < fRight &&
                point.fY >= fTop && point.fY < fBottom;
     }
-    
+
     /**
      *  Initialize a rectangle to a point.
      *  @param pt the point used to initialize the rectangle.
@@ -226,16 +243,16 @@
 
     /**
      *  Make the largest representable rectangle
-     *  Set the rect to fLeft = fTop = GR_ScalarMin and 
+     *  Set the rect to fLeft = fTop = GR_ScalarMin and
      *  fRight = fBottom = GR_ScalarMax.
      */
     void setLargest() {
         fLeft = fTop = GR_ScalarMin;
         fRight = fBottom = GR_ScalarMax;
     }
-    
+
     /**
-     Set the rect to fLeft = fTop = GR_ScalarMax and 
+     Set the rect to fLeft = fTop = GR_ScalarMax and
      fRight = fBottom = GR_ScalarMin.
      Useful for initializing a bounding rectangle.
      */
@@ -243,24 +260,24 @@
         fLeft = fTop = GR_ScalarMax;
         fRight = fBottom = GR_ScalarMin;
     }
-    
-    void setLTRB(GrScalar left, 
-                 GrScalar top, 
-                 GrScalar right, 
+
+    void setLTRB(GrScalar left,
+                 GrScalar top,
+                 GrScalar right,
                  GrScalar bottom) {
         fLeft = left;
         fTop = top;
         fRight = right;
         fBottom = bottom;
     }
-    
+
     void setXYWH(GrScalar x, GrScalar y, GrScalar width, GrScalar height) {
         fLeft = x;
         fTop = y;
         fRight = x + width;
         fBottom = y + height;
     }
-    
+
     /**
      Expand the edges of the rectangle to include a point.
      Useful for constructing a bounding rectangle.
@@ -269,12 +286,43 @@
     void growToInclude(const GrPoint& pt) {
         fLeft  = GrMin(pt.fX, fLeft);
         fRight = GrMax(pt.fX, fRight);
-        
+
         fTop    = GrMin(pt.fY, fTop);
         fBottom = GrMax(pt.fY, fBottom);
     }
 
     /**
+     * Grows a rect to include another rect.
+     * @param rect the rect to include
+     */
+    void growToInclude(const GrRect& rect) {
+        GrAssert(!rect.isEmpty());
+        fLeft  = GrMin(rect.fLeft, fLeft);
+        fRight = GrMax(rect.fRight, fRight);
+
+        fTop    = GrMin(rect.fTop, fTop);
+        fBottom = GrMax(rect.fBottom, fBottom);
+    }
+
+    /**
+     * Sets this rect to the intersection with a clip rect. If there is no
+     * intersection then this rect will be made empty.
+     */
+    void intersectWith(const GrRect& clipRect) {
+        if (fRight < clipRect.fLeft ||
+            fLeft > clipRect.fRight ||
+            fBottom < clipRect.fTop ||
+            fTop > clipRect.fBottom) {
+            this->setEmpty();
+        } else {
+            fLeft = GrMax(fLeft, clipRect.fLeft);
+            fRight = GrMin(fRight, clipRect.fRight);
+            fTop = GrMax(fTop, clipRect.fTop);
+            fBottom = GrMin(fBottom, clipRect.fBottom);
+        }
+    }
+
+    /**
      *  Assigns 4 sequential points in order to construct a counter-clockwise
      *  triangle fan, given the corners of this rect. Returns the address of
      *  the next point, treating pts as an array.
@@ -283,6 +331,13 @@
         pts->setRectFan(fLeft, fTop, fRight, fBottom);
         return pts + 4;
     }
+
+    bool operator ==(const GrRect& r) const {
+        return fLeft == r.fLeft     &&
+               fTop == r.fTop       &&
+               fRight == r.fRight   &&
+               fBottom == r.fBottom;
+    }
 };
 
 #endif
diff --git a/gpu/include/GrStencil.h b/gpu/include/GrStencil.h
new file mode 100644
index 0000000..be3e0f6
--- /dev/null
+++ b/gpu/include/GrStencil.h
@@ -0,0 +1,211 @@
+/*
+    Copyright 2011 Google Inc.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+ */
+
+#ifndef GrStencil_DEFINED
+#define GrStencil_DEFINED
+
+#include "GrTypes.h"
+/**
+ * Gr uses the stencil buffer to implement complex clipping inside the
+ * GrDrawTarget class. The GrDrawTarget makes a subset of the stencil buffer
+ * bits available for other uses by external code (clients). Client code can
+ * modify these bits. GrDrawTarget will ignore ref, mask, and writemask bits
+ * provided by clients that overlap the bits used to implement clipping. The
+ * client can use the getUsableStencilBits() function to find out how many
+ * client accessible stencil bits are available.
+ *
+ * When code outside the GrDrawTarget class uses the stencil buffer the contract
+ * is as follows:
+ *
+ * > Normal stencil funcs allow the GrGpu client to modify the client bits of
+ *   the stencil buffer outside of the clip.
+ * > Special functions allow a test against the clip. These are more limited
+ *   than the general stencil functions.
+ * > Client can assume all client bits are zero initially.
+ * > Client must ensure that after all its passes are finished it has only
+ *   written to the color buffer in the region inside the clip. Furthermore, it
+ *   must zero all client bits that were modifed (both inside and outside the
+ *   clip).
+ */
+
+/**
+ * Determines which pixels pass / fail the stencil test.
+ * Stencil test passes if (ref & mask) FUNC (stencil & mask) is true
+ */
+enum GrStencilFunc {
+    kAlways_StencilFunc = 0,
+    kNever_StencilFunc,
+    kGreater_StencilFunc,
+    kGEqual_StencilFunc,
+    kLess_StencilFunc,
+    kLEqual_StencilFunc,
+    kEqual_StencilFunc,
+    kNotEqual_StencilFunc,
+
+    // Gr stores the current clip in the
+    // stencil buffer in the high bits that
+    // are not directly accessible modifiable
+    // via the GrDrawTarget interface. The below
+    // stencil funcs test against the current
+    // clip in addition to the GrDrawTarget
+    // client's stencil bits.
+
+    // pass if inside the clip
+    kAlwaysIfInClip_StencilFunc,
+    kEqualIfInClip_StencilFunc,
+    kLessIfInClip_StencilFunc,
+    kLEqualIfInClip_StencilFunc,
+    kNonZeroIfInClip_StencilFunc, // this one forces the ref to be 0
+
+    // counts
+    kStencilFuncCount,
+    kClipStencilFuncCount = kNonZeroIfInClip_StencilFunc -
+                            kAlwaysIfInClip_StencilFunc + 1,
+    kBasicStencilFuncCount = kStencilFuncCount - kClipStencilFuncCount
+};
+
+/**
+ * Operations to perform based on whether stencil test passed failed.
+ */
+enum GrStencilOp {
+    kKeep_StencilOp = 0,    // preserve existing stencil value
+    kReplace_StencilOp,     // replace with reference value from stencl test
+    kIncWrap_StencilOp,     // increment and wrap at max
+    kIncClamp_StencilOp,    // increment and clamp at max
+    kDecWrap_StencilOp,     // decrement and wrap at 0
+    kDecClamp_StencilOp,    // decrement and clamp at 0
+    kZero_StencilOp,        // zero stencil bits
+    kInvert_StencilOp,      // invert stencil bits
+
+    kStencilOpCount
+};
+
+/**
+ * Struct representing stencil state.
+ */
+struct GrStencilSettings {
+    GrStencilOp   fFrontPassOp;     // op to perform when front faces pass
+    GrStencilOp   fBackPassOp;      // op to perform when back faces pass
+    GrStencilOp   fFrontFailOp;     // op to perform when front faces fail
+    GrStencilOp   fBackFailOp;      // op to perform when back faces fail
+    GrStencilFunc fFrontFunc;       // test function for front faces
+    GrStencilFunc fBackFunc;        // test function for back faces
+    unsigned int fFrontFuncMask;    // mask for front face test
+    unsigned int fBackFuncMask;     // mask for back face test
+    unsigned int fFrontFuncRef;     // reference value for front face test
+    unsigned int fBackFuncRef;      // reference value for back face test
+    unsigned int fFrontWriteMask;   // stencil write mask for front faces
+    unsigned int fBackWriteMask;    // stencil write mask for back faces
+
+    bool operator == (const GrStencilSettings& s) const {
+        // make sure this is tightly packed.
+        GR_STATIC_ASSERT(0 == sizeof(GrStencilOp)%4);
+        GR_STATIC_ASSERT(0 == sizeof(GrStencilFunc)%4);
+        GR_STATIC_ASSERT(sizeof(GrStencilSettings) ==
+                        4*sizeof(GrStencilOp) +
+                        2*sizeof(GrStencilFunc) +
+                        6*sizeof(unsigned int));
+        return 0 == memcmp(this, &s, sizeof(GrStencilSettings));
+    }
+
+    bool operator != (const GrStencilSettings& s) const {
+        return !(*this == s);
+    }
+
+    GrStencilSettings& operator =(const GrStencilSettings& s) {
+        memcpy(this, &s, sizeof(GrStencilSettings));
+        return *this;
+    }
+
+    void setSame(GrStencilOp passOp,
+                 GrStencilOp failOp,
+                 GrStencilFunc func,
+                 unsigned int funcMask,
+                 unsigned int funcRef,
+                 unsigned int writeMask) {
+        fFrontPassOp        = passOp;
+        fBackPassOp         = passOp;
+        fFrontFailOp        = failOp;
+        fBackFailOp         = failOp;
+        fFrontFunc          = func;
+        fBackFunc           = func;
+        fFrontFuncMask      = funcMask;
+        fBackFuncMask       = funcMask;
+        fFrontFuncRef       = funcRef;
+        fBackFuncRef        = funcRef;
+        fFrontWriteMask     = writeMask;
+        fBackWriteMask      = writeMask;
+    }
+
+    // canonical value for disabled stenciling
+    static const GrStencilSettings gDisabled;
+    void setDisabled() {
+        *this = gDisabled;
+    }
+    bool isDisabled() const {
+        return kKeep_StencilOp == fFrontPassOp   &&
+               kKeep_StencilOp == fBackPassOp    &&
+               kKeep_StencilOp == fFrontFailOp   &&
+               kKeep_StencilOp == fFrontFailOp   &&
+               kAlways_StencilFunc == fFrontFunc &&
+               kAlways_StencilFunc == fBackFunc;
+    }
+    void invalidate()  {
+        // just write an illegal value to the first member
+        fFrontPassOp = (GrStencilOp)-1;
+    }
+
+private:
+    friend class GrGpu;
+
+    enum {
+        kMaxStencilClipPasses = 2  // maximum number of passes to add a clip 
+                                   // element to the stencil buffer.
+    };
+
+    /**
+     * Given a thing to draw into the stencil clip, a fill type, and a set op
+     * this function determines:
+     *      1. Whether the thing can be draw directly to the stencil clip or
+     *      needs to be drawn to the client portion of the stencil first.
+     *      2. How many passes are needed.
+     *      3. What those passes are.
+     *      4. The fill rule that should actually be used to render (will 
+     *         always be non-inverted).
+     *
+     * @param op                the set op to combine this element with the 
+     *                          existing clip
+     * @param stencilClipMask   mask with just the stencil bit used for clipping
+     *                          enabled.
+     * @param fill              in: the fill rule of the element to draw.
+     *                          out: the fill rule that should be used to draw
+     * @param numPasses         out: the number of passes needed to add the 
+     *                               element to the clip.
+     * @param settings          out: the stencil settings to use for each pass
+     *
+     * @return true if the clip element's geometry can be drawn directly to the
+     *         stencil clip bit. Will only be true if canBeDirect is true.
+     *         numPasses will be 1 if return value is true.
+     */
+    static bool GetClipPasses(GrSetOp op, 
+                              bool canBeDirect,
+                              unsigned int stencilClipMask,
+                              GrPathFill* fill,
+                              int* numPasses,
+                              GrStencilSettings settings[kMaxStencilClipPasses]);
+};
+
+#endif
diff --git a/gpu/include/GrTArray.h b/gpu/include/GrTArray.h
index c31c820..6ef1a13 100644
--- a/gpu/include/GrTArray.h
+++ b/gpu/include/GrTArray.h
@@ -176,6 +176,8 @@
         }
     }
 
+    void reset() { this->pop_back_n(fCount); }
+
     int count() const { return fCount; }
 
     bool empty() const { return !fCount; }
diff --git a/gpu/include/GrTexture.h b/gpu/include/GrTexture.h
index 098ac59..2d3928c 100644
--- a/gpu/include/GrTexture.h
+++ b/gpu/include/GrTexture.h
@@ -19,6 +19,7 @@
 #define GrTexture_DEFINED
 
 #include "GrRefCnt.h"
+#include "GrClip.h"
 
 class GrTexture;
 
@@ -34,11 +35,16 @@
     /**
      * @return the width of the rendertarget
      */
-    virtual int width() const = 0;
+    int width() const { return fWidth; }
     /**
      * @return the height of the rendertarget
      */
-    virtual int height() const = 0;
+    int height() const { return fHeight; }
+
+    /**
+     * @return the number of stencil bits in the rendertarget
+     */
+    int stencilBits() const { return fStencilBits; }
 
     /**
      * @return the texture associated with the rendertarget, may be NULL.
@@ -46,8 +52,28 @@
     GrTexture* asTexture() {return fTexture;}
 
 protected:
-    GrRenderTarget(GrTexture* texture) : fTexture(texture) {}
+    GrRenderTarget(GrTexture* texture,
+                   int width,
+                   int height,
+                   int stencilBits)
+        : fTexture(texture),
+          fWidth(width),
+          fHeight(height),
+          fStencilBits(stencilBits) {}
+
+
     GrTexture* fTexture;
+    int        fWidth;
+    int        fHeight;
+    int        fStencilBits;
+
+private:
+    // GrGpu keeps a cached clip in the render target to avoid redundantly
+    // rendering the clip into the same stencil buffer.
+    friend class GrGpu;
+    GrClip     fLastStencilClip;
+
+    typedef GrRefCnt INHERITED;
 };
 
 class GrTexture : public GrRefCnt {
diff --git a/gpu/include/GrTypes.h b/gpu/include/GrTypes.h
index 02a652a..29e847f 100644
--- a/gpu/include/GrTypes.h
+++ b/gpu/include/GrTypes.h
@@ -201,6 +201,26 @@
     kIDA_BlendCoeff,     //<! one minus dst alpha
 };
 
+/**
+ * Set Operations used to construct clips.
+ */
+enum GrSetOp {
+    kReplace_SetOp,
+    kIntersect_SetOp,
+    kUnion_SetOp,
+    kXor_SetOp,
+    kDifference_SetOp,
+    kReverseDifference_SetOp,
+};
+
+/**
+ * Clips are composed from these objects.
+ */
+enum GrClipType {
+    kRect_ClipType,
+    kPath_ClipType
+};
+
 ///////////////////////////////////////////////////////////////////////////////
 
 // this is included only to make it easy to use this debugging facility
diff --git a/gpu/src/GrClip.cpp b/gpu/src/GrClip.cpp
index b7a839b..924c01b 100644
--- a/gpu/src/GrClip.cpp
+++ b/gpu/src/GrClip.cpp
@@ -17,18 +17,30 @@
 
 #include "GrClip.h"
 
-GrClip::GrClip() {
+GrClip::GrClip()
+    : fList(fListMemory, kPreAllocElements) {
     fBounds.setEmpty();
-    this->validate();
+    fBoundsValid = true;
 }
 
-GrClip::GrClip(const GrClip& src) {
+GrClip::GrClip(const GrClip& src)
+    : fList(fListMemory, kPreAllocElements) {
     *this = src;
 }
 
-GrClip::GrClip(GrClipIterator* iter) {
-    fBounds.setEmpty();
-    this->setFromIterator(iter);
+GrClip::GrClip(const GrIRect& rect)
+    : fList(fListMemory, kPreAllocElements) {
+    this->setFromIRect(rect);
+}
+
+GrClip::GrClip(const GrRect& rect)
+    : fList(fListMemory, kPreAllocElements) {
+    this->setFromRect(rect);
+}
+
+GrClip::GrClip(GrClipIterator* iter, const GrRect* bounds)
+    : fList(fListMemory, kPreAllocElements) {
+    this->setFromIterator(iter, bounds);
 }
 
 GrClip::~GrClip() {}
@@ -36,101 +48,100 @@
 GrClip& GrClip::operator=(const GrClip& src) {
     fList = src.fList;
     fBounds = src.fBounds;
-    this->validate();
+    fBoundsValid = src.fBoundsValid;
     return *this;
 }
 
 void GrClip::setEmpty() {
     fList.reset();
     fBounds.setEmpty();
-    this->validate();
+    fBoundsValid = true;
 }
 
-void GrClip::setRect(const GrIRect& r) {
+void GrClip::setFromRect(const GrRect& r) {
+    fList.reset();
+    if (r.isEmpty()) {
+        // use a canonical empty rect for == testing.
+        setEmpty();
+    } else {
+        fList.push_back();
+        fList.back().fRect = r;
+        fList.back().fType = kRect_ClipType;
+        fBounds = r;
+        fBoundsValid = true;
+    }
+}
+
+void GrClip::setFromIRect(const GrIRect& r) {
+    fList.reset();
+    if (r.isEmpty()) {
+        // use a canonical empty rect for == testing.
+        setEmpty();
+    } else {
+        fList.push_back();
+        fList.back().fRect.set(r);
+        fList.back().fType = kRect_ClipType;
+        fBounds.set(r);
+        fBoundsValid = true;
+    }
+}
+
+void GrClip::setFromIterator(GrClipIterator* iter, const GrRect* bounds) {
     fList.reset();
 
-    // we need a canonical "empty" rect, so that our operator== will behave
-    // correctly with two empty clips.
-    if (r.isEmpty()) {
-        fBounds.setEmpty();
-    } else {
-        fBounds = r;
-    }
-    this->validate();
-}
+    int rectCount = 0;
 
-void GrClip::addRect(const GrIRect& r) {
-    if (!r.isEmpty()) {
-        this->validate();
-        if (this->isEmpty()) {
-            GrAssert(fList.count() == 0);
-            fBounds = r;
-        } else {
-            if (this->isRect()) {
-                *fList.append() = fBounds;
-            }
-            *fList.append() = r;
-            fBounds.unionWith(r);
-        }
-        this->validate();
-    }
-}
+    // compute bounds for common case of series of intersecting rects.
+    bool isectRectValid = true;
 
-void GrClip::setFromIterator(GrClipIterator* iter) {
-    this->setEmpty();
     if (iter) {
         for (iter->rewind(); !iter->isDone(); iter->next()) {
-            GrIRect r;
-            iter->getRect(&r);
-            this->addRect(r);
-        }
-    }
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-void GrClipIter::reset(const GrClip& clip) { fClip = &clip; fIndex = 0; }
-
-bool GrClipIter::isDone() { 
-    return (NULL == fClip) || (fIndex >= fClip->countRects()); 
-}
-
-void GrClipIter::rewind() { fIndex = 0; }
-void GrClipIter::getRect(GrIRect* r) { *r = fClip->getRects()[fIndex]; }
-void GrClipIter::next() { fIndex += 1; }
-void GrClipIter::computeBounds(GrIRect* r) { 
-    if (NULL == fClip) {
-        r->setEmpty();
-    } else {
-        *r = fClip->getBounds();
-    }
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-#if GR_DEBUG
-
-void GrClip::validate() const {
-    if (fBounds.isEmpty()) {
-        GrAssert(0 == fBounds.fLeft);
-        GrAssert(0 == fBounds.fTop);
-        GrAssert(0 == fBounds.fRight);
-        GrAssert(0 == fBounds.fBottom);
-        GrAssert(0 == fList.count());
-    } else {
-        int count = fList.count();
-        if (count > 0) {
-            GrAssert(count > 1);
-            GrAssert(!fList[0].isEmpty());
-            GrIRect bounds = fList[0];
-            for (int i = 1; i < count; i++) {
-                GrAssert(!fList[i].isEmpty());
-                bounds.unionWith(fList[i]);
+            Element& e = fList.push_back();
+            e.fType = iter->getType();
+            e.fOp = iter->getOp();
+            // iterators should not emit replace
+            GrAssert(kReplace_SetOp != e.fOp);
+            switch (e.fType) {
+                case kRect_ClipType:
+                    iter->getRect(&e.fRect);
+                    ++rectCount;
+                    if (isectRectValid) {
+                        if (1 == rectCount || kIntersect_SetOp == e.fOp) {
+                            GrAssert(fList.count() <= 2);
+                            if (fList.count() > 1) {
+                                GrAssert(2 == rectCount);
+                                rectCount = 1;
+                                fList.pop_back();
+                                GrAssert(kRect_ClipType == fList.back().fType);
+                                fList.back().fRect.intersectWith(e.fRect);
+                            }
+                        } else {
+                            isectRectValid = false;
+                        }
+                    }
+                    break;
+                case kPath_ClipType:
+                    e.fPath.resetFromIter(iter->getPathIter());
+                    e.fPathFill = iter->getPathFill();
+                    isectRectValid = false;
+                    break;
+                default:
+                    GrCrash("Unknown clip element type.");
             }
-            GrAssert(fBounds == bounds);
         }
     }
+    fBoundsValid = false;
+    if (NULL == bounds) {
+        if (isectRectValid) {
+            fBoundsValid = true;
+            if (rectCount > 0) {
+                fBounds = fList[0].fRect;
+            } else {
+                fBounds.setEmpty();
+            }
+        }
+    } else {
+        fBounds = *bounds;
+        fBoundsValid = true;
+    }
 }
-
-#endif
-
diff --git a/gpu/src/GrContext.cpp b/gpu/src/GrContext.cpp
index 840e773..a047895 100644
--- a/gpu/src/GrContext.cpp
+++ b/gpu/src/GrContext.cpp
@@ -145,7 +145,7 @@
             GrDrawTarget::AutoStateRestore asr(fGpu);
             fGpu->setRenderTarget(texture->asRenderTarget());
             fGpu->setTexture(0, clampEntry->texture());
-            fGpu->setStencilPass(GrDrawTarget::kNone_StencilPass);
+            fGpu->disableStencil();
             fGpu->setViewMatrix(GrMatrix::I());
             fGpu->setAlpha(0xff);
             fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
@@ -284,7 +284,7 @@
 
 void GrContext::setClip(const GrIRect& rect) {
     GrClip clip;
-    clip.setRect(rect);
+    clip.setFromIRect(rect);
     fGpu->setClip(clip);
 }
 
@@ -297,7 +297,10 @@
 void GrContext::drawPaint(const GrPaint& paint) {
     // set rect to be big enough to fill the space, but not super-huge, so we
     // don't overflow fixed-point implementations
-    GrRect r(fGpu->getClip().getBounds());
+    GrRect r;
+    r.setLTRB(0, 0,
+              GrIntToScalar(getRenderTarget()->width()),
+              GrIntToScalar(getRenderTarget()->height()));
     GrMatrix inverse;
     if (fGpu->getViewInverse(&inverse)) {
         inverse.mapRect(&r);
@@ -546,6 +549,15 @@
     fPathRenderer->drawPath(target, enabledStages, path, fill, translate);
 }
 
+void GrContext::drawPath(const GrPaint& paint,
+                         const GrPath& path,
+                         GrPathFill fill,
+                         const GrPoint* translate) {
+    GrPath::Iter iter(path);
+    this->drawPath(paint, &iter, fill, translate);
+}
+
+
 ////////////////////////////////////////////////////////////////////////////////
 
 void GrContext::flush(bool flushRenderTarget) {
@@ -751,7 +763,8 @@
 #if BATCH_RECT_TO_RECT
     fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
 #endif
-    fPathRenderer = new GrDefaultPathRenderer(fGpu->supportsSingleStencilPassWinding());
+    fPathRenderer = new GrDefaultPathRenderer(fGpu->supportsTwoSidedStencil(),
+                                              fGpu->supportsStencilWrapOps());
 }
 
 bool GrContext::finalizeTextureKey(GrTextureKey* key,
diff --git a/gpu/src/GrDrawTarget.cpp b/gpu/src/GrDrawTarget.cpp
index ca525b3..7973361 100644
--- a/gpu/src/GrDrawTarget.cpp
+++ b/gpu/src/GrDrawTarget.cpp
@@ -358,14 +358,6 @@
     fCurrDrawState.fSamplerStates[stage] = state;
 }
 
-void GrDrawTarget::setStencilPass(StencilPass pass) {
-    fCurrDrawState.fStencilPass = pass;
-}
-
-void GrDrawTarget::setReverseFill(bool reverse) {
-    fCurrDrawState.fReverseFill = reverse;
-}
-
 void GrDrawTarget::enableState(uint32_t bits) {
     fCurrDrawState.fFlagBits |= bits;
 }
diff --git a/gpu/src/GrGLTexture.cpp b/gpu/src/GrGLTexture.cpp
index 9fd1f57..ae991e8 100644
--- a/gpu/src/GrGLTexture.cpp
+++ b/gpu/src/GrGLTexture.cpp
@@ -22,12 +22,14 @@
                                    GLuint stencilBits,
                                    const GrGLIRect& viewport,
                                    GrGLTexture* texture,
-                                   GrGpuGL* gl) : INHERITED(texture) {
+                                   GrGpuGL* gl) : INHERITED(texture,
+                                                            viewport.fWidth,
+                                                            viewport.fHeight,
+                                                            stencilBits) {
     fGL                     = gl;
     fRTFBOID                = ids.fRTFBOID;
     fTexFBOID               = ids.fTexFBOID;
     fStencilRenderbufferID  = ids.fStencilRenderbufferID;
-    fStencilBits            = stencilBits;
     fMSColorRenderbufferID  = ids.fMSColorRenderbufferID;
     fNeedsResolve           = false;
     fViewport               = viewport;
diff --git a/gpu/src/GrGpu.cpp b/gpu/src/GrGpu.cpp
index 019c99f..f42e316 100644
--- a/gpu/src/GrGpu.cpp
+++ b/gpu/src/GrGpu.cpp
@@ -22,12 +22,13 @@
 #include "GrIndexBuffer.h"
 #include "GrVertexBuffer.h"
 #include "GrBufferAllocPool.h"
+#include "GrPathRenderer.h"
 
 // probably makes no sense for this to be less than a page
 static const size_t VERTEX_POOL_VB_SIZE = 1 << 12;
 static const int VERTEX_POOL_VB_COUNT = 1;
 
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
 
 size_t GrTexture::BytesPerPixel(PixelConfig config) {
     switch (config) {
@@ -56,7 +57,7 @@
 }
 
 
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
 
 extern void gr_run_unittests();
 
@@ -68,7 +69,10 @@
                  fVertexPool(NULL),
                  fIndexPool(NULL),
                  fQuadIndexBuffer(NULL),
-                 fUnitSquareVertexBuffer(NULL) {
+                 fUnitSquareVertexBuffer(NULL),
+                 fPathRenderer(NULL),
+                 fVertexPoolInUse(false),
+                 fIndexPoolInUse(false) {
 #if GR_DEBUG
 //    gr_run_unittests();
 #endif
@@ -80,6 +84,7 @@
     GrSafeUnref(fUnitSquareVertexBuffer);
     delete fVertexPool;
     delete fIndexPool;
+    delete fPathRenderer;
 }
 
 void GrGpu::resetContext() {
@@ -91,7 +96,7 @@
 #endif
 }
 
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
 
 static const int MAX_QUADS = 1 << 12; // max possible: (1 << 14) - 1;
 
@@ -159,7 +164,7 @@
     return fUnitSquareVertexBuffer;
 }
 
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
 
 void GrGpu::clipWillBeSet(const GrClip& newClip) {
     if (newClip != fClip) {
@@ -167,8 +172,113 @@
     }
 }
 
+////////////////////////////////////////////////////////////////////////////////
+
+// stencil settings to use when clip is in stencil
+const GrStencilSettings GrGpu::gClipStencilSettings = {
+    kKeep_StencilOp,             kKeep_StencilOp,
+    kKeep_StencilOp,             kKeep_StencilOp,
+    kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
+    0,                           0,
+    0,                           0,
+    0,                           0
+};
+
+// converts special stencil func to
+static const GrStencilFunc gGrClipToNormalStencilFunc[2][kClipStencilFuncCount] = {
+    {// Stencil-Clipping is DISABLED, effectively always inside the clip
+        // In the Clip Funcs
+        kAlways_StencilFunc,          // kAlwaysIfInClip_StencilFunc
+        kEqual_StencilFunc,           // kEqualIfInClip_StencilFunc
+        kLess_StencilFunc,            // kLessIfInClip_StencilFunc
+        kLEqual_StencilFunc,          // kLEqualIfInClip_StencilFunc
+        // Special in the clip func that forces user's ref to be 0.
+        kNotEqual_StencilFunc,        // kNonZeroIfInClip_StencilFunc
+                                      // make ref 0 and do normal nequal.
+    },
+    {// Stencil-Clipping is ENABLED
+        // In the Clip Funcs
+        kEqual_StencilFunc,           // kAlwaysIfInClip_StencilFunc
+                                      // eq stencil clip bit, mask
+                                      // out user bits.
+
+        kEqual_StencilFunc,           // kEqualIfInClip_StencilFunc
+                                      // add stencil bit to mask and ref
+
+        kLess_StencilFunc,            // kLessIfInClip_StencilFunc
+        kLEqual_StencilFunc,          // kLEqualIfInClip_StencilFunc
+                                      // for both of these we can add
+                                      // the clip bit to the mask and
+                                      // ref and compare as normal
+        // Special in the clip func that forces user's ref to be 0.
+        kLess_StencilFunc,            // kNonZeroIfInClip_StencilFunc
+                                      // make ref have only the clip bit set
+                                      // and make comparison be less
+                                      // 10..0 < 1..user_bits..
+    }
+};
+
+GrStencilFunc GrGpu::ConvertStencilFunc(bool stencilInClip, GrStencilFunc func) {
+    GrAssert(func >= 0);
+    if (func >= kBasicStencilFuncCount) {
+        GrAssert(func < kStencilFuncCount);
+        func = gGrClipToNormalStencilFunc[stencilInClip ? 1 : 0][func - kBasicStencilFuncCount];
+        GrAssert(func >= 0 && func < kBasicStencilFuncCount);
+    }
+    return func;
+}
+
+void GrGpu::ConvertStencilFuncAndMask(GrStencilFunc func,
+                                      bool clipInStencil,
+                                      unsigned int clipBit,
+                                      unsigned int userBits,
+                                      unsigned int* ref,
+                                      unsigned int* mask) {
+    if (func < kBasicStencilFuncCount) {
+        *mask &= userBits;
+        *ref &= userBits;
+    } else {
+        if (clipInStencil) {
+            switch (func) {
+                case kAlwaysIfInClip_StencilFunc:
+                    *mask = clipBit;
+                    *ref = clipBit;
+                    break;
+                case kEqualIfInClip_StencilFunc:
+                case kLessIfInClip_StencilFunc:
+                case kLEqualIfInClip_StencilFunc:
+                    *mask = (*mask & userBits) | clipBit;
+                    *ref = (*ref & userBits) | clipBit;
+                    break;
+                case kNonZeroIfInClip_StencilFunc:
+                    *mask = (*mask & userBits) | clipBit;
+                    *ref = clipBit;
+                    break;
+                default:
+                    GrCrash("Unknown stencil func");
+            }
+        } else {
+            *mask &= userBits;
+            *ref &= userBits;
+        }
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+#define VISUALIZE_COMPLEX_CLIP 0
+
+#if VISUALIZE_COMPLEX_CLIP
+    #include "GrRandom.h"
+    GrRandom gRandom;
+    #define SET_RANDOM_COLOR this->setColor(0xff000000 | gRandom.nextU());
+#else
+    #define SET_RANDOM_COLOR
+#endif
+
 bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
     const GrIRect* r = NULL;
+    GrIRect clipRect;
 
     // we check this early because we need a valid
     // render target to setup stencil clipping
@@ -179,80 +289,135 @@
     }
 
     if (fCurrDrawState.fFlagBits & kClip_StateBit) {
-        fClipState.fClipInStencil = fClip.countRects() > 1;
+        GrRenderTarget& rt = *fCurrDrawState.fRenderTarget;
+
+        GrRect bounds;
+        GrRect rtRect;
+        rtRect.setLTRB(0, 0,
+                       GrIntToScalar(rt.width()), GrIntToScalar(rt.height()));
+        if (fClip.hasBounds()) {
+            bounds = fClip.getBounds();
+            bounds.intersectWith(rtRect);
+        } else {
+            bounds = rtRect;
+        }
+
+        bounds.roundOut(&clipRect);
+        if  (clipRect.isEmpty()) {
+            clipRect.setLTRB(0,0,0,0);
+        }
+        r = &clipRect;
+
+        fClipState.fClipInStencil = !fClip.isRect() &&
+                                    !fClip.isEmpty() &&
+                                    !bounds.isEmpty();
 
         if (fClipState.fClipInStencil &&
             (fClipState.fClipIsDirty ||
-             fClipState.fStencilClipTarget != fCurrDrawState.fRenderTarget)) {
+             fClip != rt.fLastStencilClip)) {
+
+            rt.fLastStencilClip = fClip;
+            // we set the current clip to the bounds so that our recursive
+            // draws are scissored to them. We use the copy of the complex clip
+            // in the rt to render
+            const GrClip& clip = rt.fLastStencilClip;
+            fClip.setFromRect(bounds);
 
             AutoStateRestore asr(this);
-            AutoGeometrySrcRestore agsr(this);
+            AutoInternalDrawGeomRestore aidgr(this);
 
-            // We have to use setVertexSourceToBuffer (and index) in order
-            // to ensure we correctly restore the client's geom sources.
-            // We tack the clip verts onto the vertex pool but we don't
-            // use the various helper functions because of their side effects.
-
-            int rectTotal = fClip.countRects();
-            if (NULL == fVertexPool) {
-                fVertexPool = new GrVertexBufferAllocPool(this,
-                                                          true,
-                                                          VERTEX_POOL_VB_SIZE,
-                                                          VERTEX_POOL_VB_COUNT);
-            } else if (kBuffer_GeometrySrcType == fGeometrySrc.fVertexSrc) {
-                // we can't reset if vertex source is array or reserved
-                // because then the client data is in the pool!
-                fVertexPool->reset();
-            }
-            const GrVertexBuffer* vertexBuffer;
-            int vStart;
-            GrPoint* rectVertices =
-                reinterpret_cast<GrPoint*>(fVertexPool->makeSpace(0,
-                                                                  rectTotal * 4,
-                                                                  &vertexBuffer,
-                                                                  &vStart));
-            for (int r = 0; r < rectTotal; ++r) {
-                const GrIRect& rect = fClip.getRects()[r];
-                rectVertices[4 * r].setIRectFan(rect.fLeft, rect.fTop,
-                                                rect.fRight, rect.fBottom);
-            }
-            fVertexPool->unlock();
-            this->setVertexSourceToBuffer(0, vertexBuffer);
-            this->setIndexSourceToBuffer(getQuadIndexBuffer());
             this->setViewMatrix(GrMatrix::I());
-            // don't clip the clip or recurse!
-            this->disableState(kClip_StateBit);
-            this->eraseStencilClip();
-            this->setStencilPass((GrDrawTarget::StencilPass)kSetClip_StencilPass);
-            int currRect = 0;
-            while (currRect < rectTotal) {
-                int rectCount = GrMin(MAX_QUADS,
-                                      rectTotal - currRect);
-                this->drawIndexed(kTriangles_PrimitiveType,
-                                  vStart + currRect * 4,
-                                  0,
-                                  rectCount*4,
-                                  rectCount*6);
-                currRect += rectCount;
+            this->eraseStencilClip(clipRect);
+            this->flushScissor(NULL);
+#if !VISUALIZE_COMPLEX_CLIP
+            this->enableState(kNoColorWrites_StateBit);
+#else
+            this->disableState(kNoColorWrites_StateBit);
+#endif
+            int count = clip.getElementCount();
+            int clipBit = rt.stencilBits();
+            clipBit = (1 << (clipBit-1));
+
+            // walk through each clip element and perform its set op
+            // with the existing clip.
+            for (int c = 0; c < count; ++c) {
+                GrPathFill fill;
+                // enabled at bottom of loop
+                this->disableState(kModifyStencilClip_StateBit);
+
+                bool canDrawDirectToClip;
+                if (kRect_ClipType == clip.getElementType(c)) {
+                    canDrawDirectToClip = true;
+                    fill = kEvenOdd_PathFill;
+                } else {
+                    fill = clip.getPathFill(c);
+                    canDrawDirectToClip = getPathRenderer()->requiresStencilPass(clip.getPath(c));
+                }
+
+                GrSetOp op = 0 == c ? kReplace_SetOp : clip.getOp(c);
+                int passes;
+                GrStencilSettings stencilSettings[GrStencilSettings::kMaxStencilClipPasses];
+
+                canDrawDirectToClip = GrStencilSettings::GetClipPasses(op,  canDrawDirectToClip,
+                                                                       clipBit, &fill,
+                                                                       &passes, stencilSettings);
+
+                // draw the element to the client stencil bits if necessary
+                if (!canDrawDirectToClip) {
+                    if (kRect_ClipType == clip.getElementType(c)) {
+                        static const GrStencilSettings gDrawToStencil = {
+                            kIncClamp_StencilOp, kIncClamp_StencilOp,
+                            kIncClamp_StencilOp, kIncClamp_StencilOp,
+                            kAlways_StencilFunc, kAlways_StencilFunc,
+                            0xffffffff,          0xffffffff,
+                            0x00000000,          0x00000000,
+                            0xffffffff,          0xffffffff,
+                        };
+                        this->setStencil(gDrawToStencil);
+                        SET_RANDOM_COLOR
+                        this->drawSimpleRect(clip.getRect(c), NULL, 0);
+                    } else {
+                        SET_RANDOM_COLOR
+                        getPathRenderer()->drawPathToStencil(this, clip.getPath(c), fill, NULL);
+                    }
+                }
+
+                // now we modify the clip bit by rendering either the clip
+                // element directly or a bounding rect of the entire clip.
+                this->enableState(kModifyStencilClip_StateBit);
+                for (int p = 0; p < passes; ++p) {
+                    this->setStencil(stencilSettings[p]);
+                    if (canDrawDirectToClip) {
+                        if (kRect_ClipType == clip.getElementType(c)) {
+                            SET_RANDOM_COLOR
+                            this->drawSimpleRect(clip.getRect(c), NULL, 0);
+                        } else {
+                            SET_RANDOM_COLOR
+                            getPathRenderer()->drawPath(this, 0, clip.getPath(c), fill, NULL);
+                        }
+                    } else {
+                        SET_RANDOM_COLOR
+                        this->drawSimpleRect(bounds, 0, NULL);
+                    }
+                }
             }
-            fClipState.fStencilClipTarget = fCurrDrawState.fRenderTarget;
+            fClip = clip;
+            // recusive draws would have disabled this.
+            fClipState.fClipInStencil = true;
         }
 
         fClipState.fClipIsDirty = false;
-        if (!fClipState.fClipInStencil) {
-            r = &fClip.getBounds();
-        }
     }
+
     // Must flush the scissor after graphics state
-    if (!flushGraphicsState(type)) {
+    if (!this->flushGraphicsState(type)) {
         return false;
     }
-    flushScissor(r);
+    this->flushScissor(r);
     return true;
 }
 
-
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
 
 void GrGpu::drawIndexed(GrPrimitiveType type,
                         int startVertex,
@@ -314,10 +479,11 @@
 
 void GrGpu::prepareVertexPool() {
     if (NULL == fVertexPool) {
-        fVertexPool = new GrVertexBufferAllocPool(this, true, 
-                                                  VERTEX_POOL_VB_SIZE, 
+        fVertexPool = new GrVertexBufferAllocPool(this, true,
+                                                  VERTEX_POOL_VB_SIZE,
                                                   VERTEX_POOL_VB_COUNT);
-    } else {
+    } else if (!fVertexPoolInUse) {
+        // the client doesn't have valid data in the pool
         fVertexPool->reset();
     }
 }
@@ -325,7 +491,8 @@
 void GrGpu::prepareIndexPool() {
     if (NULL == fVertexPool) {
         fIndexPool = new GrIndexBufferAllocPool(this, true, 0, 1);
-    } else {
+    } else if (!fIndexPoolInUse) {
+        // the client doesn't have valid data in the pool
         fIndexPool->reset();
     }
 }
@@ -339,7 +506,7 @@
     if (fReservedGeometry.fVertexCount) {
         GrAssert(NULL != vertices);
 
-        prepareVertexPool();
+        this->prepareVertexPool();
 
         *vertices = fVertexPool->makeSpace(vertexLayout,
                                            fReservedGeometry.fVertexCount,
@@ -354,7 +521,7 @@
     if (fReservedGeometry.fIndexCount) {
         GrAssert(NULL != indices);
 
-        prepareIndexPool();
+        this->prepareIndexPool();
 
         *indices = fIndexPool->makeSpace(fReservedGeometry.fIndexCount,
                                          &fCurrPoolIndexBuffer,
@@ -397,7 +564,17 @@
     GR_DEBUGASSERT(success);
 }
 
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+GrPathRenderer* GrGpu::getPathRenderer() {
+    if (NULL == fPathRenderer) {
+        fPathRenderer = new GrDefaultPathRenderer(this->supportsTwoSidedStencil(),
+                                                  this->supportsStencilWrapOps());
+    }
+    return fPathRenderer;
+}
+
+////////////////////////////////////////////////////////////////////////////////
 
 const GrGpu::Stats& GrGpu::getStats() const {
     return fStats;
diff --git a/gpu/src/GrGpuGL.cpp b/gpu/src/GrGpuGL.cpp
index b30dd02..2574b15 100644
--- a/gpu/src/GrGpuGL.cpp
+++ b/gpu/src/GrGpuGL.cpp
@@ -49,8 +49,8 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-void GrGpuGL::AdjustTextureMatrix(const GrGLTexture* texture, 
-                                  GrSamplerState::SampleMode mode, 
+void GrGpuGL::AdjustTextureMatrix(const GrGLTexture* texture,
+                                  GrSamplerState::SampleMode mode,
                                   GrMatrix* matrix) {
     GrAssert(NULL != texture);
     GrAssert(NULL != matrix);
@@ -80,7 +80,7 @@
     }
 }
 
-bool GrGpuGL::TextureMatrixIsIdentity(const GrGLTexture* texture, 
+bool GrGpuGL::TextureMatrixIsIdentity(const GrGLTexture* texture,
                                       const GrSamplerState& sampler) {
     GrAssert(NULL != texture);
     if (!sampler.getMatrix().isIdentity()) {
@@ -104,7 +104,7 @@
 static bool gPrintStartupSpew;
 
 
-bool fbo_test(GrGLExts exts, int w, int h) {
+static bool fbo_test(GrGLExts exts, int w, int h) {
 
     GLint savedFBO;
     GLint savedTexUnit;
@@ -169,8 +169,6 @@
     GrAssert(maxTextureUnits > kNumStages);
 #endif
 
-    fCurrDrawState = fHWDrawState;
-
     ////////////////////////////////////////////////////////////////////////////
     // Check for supported features.
 
@@ -263,14 +261,24 @@
     // we could also look for GL_ATI_separate_stencil extension or
     // GL_EXT_stencil_two_side but they use different function signatures
     // than GL2.0+ (and than each other).
-    fSingleStencilPassForWinding = (major >= 2);
+    fTwoSidedStencilSupport = (major >= 2);
+    // supported on GL 1.4 and higher or by extension
+    fStencilWrapOpsSupport = (major > 1) ||
+                             (1 == major) && (minor >= 4) ||
+                              has_gl_extension("GL_EXT_stencil_wrap");
 #else
     // ES 2 has two sided stencil but 1.1 doesn't. There doesn't seem to be
     // an ES1 extension.
-    fSingleStencilPassForWinding = (major >= 2);
+    fTwoSidedStencilSupport = (major >= 2);
+    // stencil wrap support is in ES2, ES1 requires extension.
+    fStencilWrapOpsSupport = (major > 1) ||
+                              has_gl_extension("GL_OES_stencil_wrap");
+
 #endif
     if (gPrintStartupSpew) {
-        GrPrintf("Single Stencil Pass For Winding: %s\n", (fSingleStencilPassForWinding ? "YES" : "NO"));
+        GrPrintf("Stencil Caps: TwoSide: %s, Wrap: %s\n",
+                (fTwoSidedStencilSupport ? "YES" : "NO"),
+                (fStencilWrapOpsSupport ? "YES" : "NO"));
     }
 
 #if GR_SUPPORT_GLDESKTOP
@@ -424,8 +432,9 @@
     fHWBlendDisabled = false;
     GR_GL(Enable(GL_BLEND));
 
-    // this is always disabled
     GR_GL(Disable(GL_CULL_FACE));
+    GR_GL(FrontFace(GL_CCW));
+    fHWDrawState.fDrawFace = kBoth_DrawFace;
 
     GR_GL(Disable(GL_DITHER));
 #if GR_SUPPORT_GLDESKTOP
@@ -434,14 +443,15 @@
     GR_GL(Disable(GL_MULTISAMPLE));
 #endif
 
+    GR_GL(ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
+    fHWDrawState.fFlagBits = 0;
+
     // we only ever use lines in hairline mode
     GR_GL(LineWidth(1));
 
     // invalid
     fActiveTextureUnitIdx = -1;
 
-    fHWDrawState.fFlagBits = 0;
-
     // illegal values
     fHWDrawState.fSrcBlend = (GrBlendCoeff)-1;
     fHWDrawState.fDstBlend = (GrBlendCoeff)-1;
@@ -454,7 +464,7 @@
         fHWDrawState.fSamplerStates[s].setRadial2Params(-GR_ScalarMax,
                                                         -GR_ScalarMax,
                                                         true);
-        
+
         fHWDrawState.fSamplerStates[s].setMatrix(GrMatrix::InvalidMatrix());
     }
 
@@ -463,16 +473,9 @@
     GR_GL(Disable(GL_SCISSOR_TEST));
     fHWBounds.fViewportRect.invalidate();
 
-    // disabling the stencil test also disables
-    // stencil buffer writes
-    GR_GL(Disable(GL_STENCIL_TEST));
-    GR_GL(StencilMask(0xffffffff));
-    GR_GL(ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
-    fHWDrawState.fReverseFill = false;
-    fHWDrawState.fStencilPass = kNone_StencilPass;
+    fHWDrawState.fStencilSettings.invalidate();
     fHWStencilClip = false;
     fClipState.fClipIsDirty = true;
-    fClipState.fStencilClipTarget = NULL;
 
     fHWGeometryState.fIndexBuffer = NULL;
     fHWGeometryState.fVertexBuffer = NULL;
@@ -480,6 +483,7 @@
     GR_GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
     fHWGeometryState.fArrayPtrsDirty = true;
 
+    GR_GL(ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
     fHWDrawState.fRenderTarget = NULL;
 }
 
@@ -491,7 +495,7 @@
 GrRenderTarget* GrGpuGL::createPlatformRenderTarget(
                                                 intptr_t platformRenderTarget,
                                                 int stencilBits,
-                                                int width, 
+                                                int width,
                                                 int height) {
     GrGLRenderTarget::GLRenderTargetIDs rtIDs;
     rtIDs.fStencilRenderbufferID = 0;
@@ -1030,11 +1034,11 @@
 void GrGpuGL::flushScissor(const GrIRect* rect) {
     GrAssert(NULL != fCurrDrawState.fRenderTarget);
     const GrGLIRect& vp =
-            ((GrGLRenderTarget*)fCurrDrawState.fRenderTarget)->viewport();
+            ((GrGLRenderTarget*)fCurrDrawState.fRenderTarget)->getViewport();
 
     GrGLIRect scissor;
     if (NULL != rect) {
-        scissor.setRelativeTo(vp, rect->fLeft, rect->fTop, 
+        scissor.setRelativeTo(vp, rect->fLeft, rect->fTop,
                               rect->width(), rect->height());
         if (scissor.contains(vp)) {
             rect = NULL;
@@ -1068,12 +1072,12 @@
         fHWBounds.fScissorEnabled = false;
     }
     GR_GL(ColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE));
+    fHWDrawState.fFlagBits &= ~kNoColorWrites_StateBit;
     GR_GL(ClearColor(GrColorUnpackR(color)/255.f,
                      GrColorUnpackG(color)/255.f,
                      GrColorUnpackB(color)/255.f,
                      GrColorUnpackA(color)/255.f));
     GR_GL(Clear(GL_COLOR_BUFFER_BIT));
-    fDirtyFlags.fWriteMaskChanged = true;
 }
 
 void GrGpuGL::eraseStencil(uint32_t value, uint32_t mask) {
@@ -1088,15 +1092,21 @@
     GR_GL(StencilMask(mask));
     GR_GL(ClearStencil(value));
     GR_GL(Clear(GL_STENCIL_BUFFER_BIT));
-    fDirtyFlags.fWriteMaskChanged = true;
+    fHWDrawState.fStencilSettings.invalidate();
 }
 
-void GrGpuGL::eraseStencilClip() {    
+void GrGpuGL::eraseStencilClip(const GrIRect& rect) {
     GrAssert(NULL != fCurrDrawState.fRenderTarget);
-    GLint stencilBitCount = ((GrGLRenderTarget*)fCurrDrawState.fRenderTarget)->getStencilBits();
+    GLint stencilBitCount = fCurrDrawState.fRenderTarget->stencilBits();
     GrAssert(stencilBitCount > 0);
     GLint clipStencilMask  = (1 << (stencilBitCount - 1));
-    eraseStencil(0, clipStencilMask);
+
+    flushRenderTarget();
+    flushScissor(&rect);
+    GR_GL(StencilMask(clipStencilMask));
+    GR_GL(ClearStencil(0));
+    GR_GL(Clear(GL_STENCIL_BUFFER_BIT));
+    fHWDrawState.fStencilSettings.invalidate();
 }
 
 void GrGpuGL::forceRenderTargetFlush() {
@@ -1117,13 +1127,13 @@
     }
     flushRenderTarget();
 
-    const GrGLIRect& glvp = ((GrGLRenderTarget*)fCurrDrawState.fRenderTarget)->viewport();
-    
+    const GrGLIRect& glvp = ((GrGLRenderTarget*)fCurrDrawState.fRenderTarget)->getViewport();
+
     // the read rect is viewport-relative
     GrGLIRect readRect;
     readRect.setRelativeTo(glvp, left, top, width, height);
     GR_GL(ReadPixels(readRect.fLeft, readRect.fBottom,
-                     readRect.fWidth, readRect.fHeight, 
+                     readRect.fWidth, readRect.fHeight,
                      format, type, buffer));
 
     // now reverse the order of the rows, since GL's are bottom-to-top, but our
@@ -1166,7 +1176,7 @@
     #endif
         fDirtyFlags.fRenderTargetChanged = true;
         fHWDrawState.fRenderTarget = fCurrDrawState.fRenderTarget;
-        const GrGLIRect& vp = rt->viewport();
+        const GrGLIRect& vp = rt->getViewport();
         if (true || fHWBounds.fViewportRect != vp) {
             vp.pushToGLViewport();
             fHWBounds.fViewportRect = vp;
@@ -1183,6 +1193,27 @@
     GL_LINE_STRIP
 };
 
+#define SWAP_PER_DRAW 0
+
+#if SWAP_PER_DRAW 
+    #if GR_MAC_BUILD
+        #include <AGL/agl.h>
+    #elif GR_WIN32_BUILD
+        void SwapBuf() {
+            DWORD procID = GetCurrentProcessId();
+            HWND hwnd = GetTopWindow(GetDesktopWindow());
+            while(hwnd) {
+                DWORD wndProcID = 0;
+                GetWindowThreadProcessId(hwnd, &wndProcID);
+                if(wndProcID == procID) {
+                    SwapBuffers(GetDC(hwnd));
+                }
+                hwnd = GetNextWindow(hwnd, GW_HWNDNEXT);
+            }
+         }
+    #endif
+#endif
+
 void GrGpuGL::drawIndexedHelper(GrPrimitiveType type,
                                 uint32_t startVertex,
                                 uint32_t startIndex,
@@ -1201,6 +1232,18 @@
 
     GR_GL(DrawElements(gPrimitiveType2GLMode[type], indexCount,
                        GL_UNSIGNED_SHORT, indices));
+#if SWAP_PER_DRAW
+    glFlush();
+    #if GR_MAC_BUILD
+        aglSwapBuffers(aglGetCurrentContext());
+        int set_a_break_pt_here = 9;
+        aglSwapBuffers(aglGetCurrentContext());
+    #elif GR_WIN32_BUILD
+        SwapBuf();
+        int set_a_break_pt_here = 9;
+        SwapBuf();
+    #endif
+#endif
 }
 
 void GrGpuGL::drawNonIndexedHelper(GrPrimitiveType type,
@@ -1218,6 +1261,18 @@
     // account for startVertex in the DrawElements case. So we always
     // rely on setupGeometry to have accounted for startVertex.
     GR_GL(DrawArrays(gPrimitiveType2GLMode[type], 0, vertexCount));
+#if SWAP_PER_DRAW
+    glFlush();
+    #if GR_MAC_BUILD
+        aglSwapBuffers(aglGetCurrentContext());
+        int set_a_break_pt_here = 9;
+        aglSwapBuffers(aglGetCurrentContext());
+    #elif GR_WIN32_BUILD
+        SwapBuf();
+        int set_a_break_pt_here = 9;
+        SwapBuf();
+    #endif
+#endif
 }
 
 void GrGpuGL::resolveTextureRenderTarget(GrGLTexture* texture) {
@@ -1257,203 +1312,162 @@
     }
 }
 
+static const GLenum grToGLStencilFunc[] = {
+    GL_ALWAYS,           // kAlways_StencilFunc
+    GL_NEVER,            // kNever_StencilFunc
+    GL_GREATER,          // kGreater_StencilFunc
+    GL_GEQUAL,           // kGEqual_StencilFunc
+    GL_LESS,             // kLess_StencilFunc
+    GL_LEQUAL,           // kLEqual_StencilFunc,
+    GL_EQUAL,            // kEqual_StencilFunc,
+    GL_NOTEQUAL,         // kNotEqual_StencilFunc,
+};
+GR_STATIC_ASSERT(GR_ARRAY_COUNT(grToGLStencilFunc) == kBasicStencilFuncCount);
+GR_STATIC_ASSERT(0 == kAlways_StencilFunc);
+GR_STATIC_ASSERT(1 == kNever_StencilFunc);
+GR_STATIC_ASSERT(2 == kGreater_StencilFunc);
+GR_STATIC_ASSERT(3 == kGEqual_StencilFunc);
+GR_STATIC_ASSERT(4 == kLess_StencilFunc);
+GR_STATIC_ASSERT(5 == kLEqual_StencilFunc);
+GR_STATIC_ASSERT(6 == kEqual_StencilFunc);
+GR_STATIC_ASSERT(7 == kNotEqual_StencilFunc);
+
+static const GLenum grToGLStencilOp[] = {
+    GL_KEEP,        // kKeep_StencilOp
+    GL_REPLACE,     // kReplace_StencilOp
+    GL_INCR_WRAP,   // kIncWrap_StencilOp
+    GL_INCR,        // kIncClamp_StencilOp
+    GL_DECR_WRAP,   // kDecWrap_StencilOp
+    GL_DECR,        // kDecClamp_StencilOp
+    GL_ZERO,        // kZero_StencilOp
+    GL_INVERT,      // kInvert_StencilOp
+};
+GR_STATIC_ASSERT(GR_ARRAY_COUNT(grToGLStencilOp) == kStencilOpCount);
+GR_STATIC_ASSERT(0 == kKeep_StencilOp);
+GR_STATIC_ASSERT(1 == kReplace_StencilOp);
+GR_STATIC_ASSERT(2 == kIncWrap_StencilOp);
+GR_STATIC_ASSERT(3 == kIncClamp_StencilOp);
+GR_STATIC_ASSERT(4 == kDecWrap_StencilOp);
+GR_STATIC_ASSERT(5 == kDecClamp_StencilOp);
+GR_STATIC_ASSERT(6 == kZero_StencilOp);
+GR_STATIC_ASSERT(7 == kInvert_StencilOp);
+
 void GrGpuGL::flushStencil() {
+    const GrStencilSettings* settings = &fCurrDrawState.fStencilSettings;
 
     // use stencil for clipping if clipping is enabled and the clip
     // has been written into the stencil.
     bool stencilClip = fClipState.fClipInStencil &&
                        (kClip_StateBit & fCurrDrawState.fFlagBits);
-    bool stencilChange =
-        fDirtyFlags.fWriteMaskChanged                             ||
-        fHWStencilClip != stencilClip                             ||
-        fHWDrawState.fStencilPass != fCurrDrawState.fStencilPass  ||
-        (kNone_StencilPass != fCurrDrawState.fStencilPass &&
-         (StencilPass)kSetClip_StencilPass != fCurrDrawState.fStencilPass &&
-         fHWDrawState.fReverseFill != fCurrDrawState.fReverseFill);
+    bool stencilChange = fHWStencilClip != stencilClip  ||
+                         fHWDrawState.fStencilSettings != *settings ||
+                         ((fHWDrawState.fFlagBits & kModifyStencilClip_StateBit) !=
+                          (fCurrDrawState.fFlagBits & kModifyStencilClip_StateBit));
 
     if (stencilChange) {
-        GLint clipStencilMask;
-        GLint pathStencilMask;
-        GLint stencilBitCount = ((GrGLRenderTarget*)fCurrDrawState.fRenderTarget)->getStencilBits();
-        GrAssert(stencilBitCount > 0 ||
-                 kNone_StencilPass == fCurrDrawState.fStencilPass);
-        clipStencilMask  = (1 << (stencilBitCount - 1));
-        pathStencilMask = clipStencilMask - 1;
-        switch (fCurrDrawState.fStencilPass) {
-            case kNone_StencilPass:
-                if (stencilClip) {
-                    GR_GL(Enable(GL_STENCIL_TEST));
-                    GR_GL(StencilFunc(GL_EQUAL,
-                                      clipStencilMask,
-                                      clipStencilMask));
-                    GR_GL(StencilOp(GL_KEEP, GL_KEEP, GL_KEEP));
-                } else {
-                    GR_GL(Disable(GL_STENCIL_TEST));
-                }
-                GR_GL(ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
-                if (!fSingleStencilPassForWinding) {
-                    GR_GL(Disable(GL_CULL_FACE));
-                }
-                break;
-            case kEvenOddStencil_StencilPass:
-                GR_GL(Enable(GL_STENCIL_TEST));
-                if (stencilClip) {
-                    GR_GL(StencilFunc(GL_EQUAL, clipStencilMask, clipStencilMask));
-                } else {
-                    GR_GL(StencilFunc(GL_ALWAYS, 0x0, 0x0));
-                }
-                GR_GL(StencilMask(pathStencilMask));
-                GR_GL(ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
-                GR_GL(StencilOp(GL_KEEP, GL_INVERT, GL_INVERT));
-                GR_GL(ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE));
-                if (!fSingleStencilPassForWinding) {
-                    GR_GL(Disable(GL_CULL_FACE));
-                }
-                break;
-            case kEvenOddColor_StencilPass: {
-                GR_GL(Enable(GL_STENCIL_TEST));
-                GLint  funcRef  = 0;
-                GLuint funcMask = pathStencilMask;
-                if (stencilClip) {
-                    funcRef  |= clipStencilMask;
-                    funcMask |= clipStencilMask;
-                }
-                if (!fCurrDrawState.fReverseFill) {
-                    funcRef |= pathStencilMask;
-                }
 
-                GR_GL(StencilFunc(GL_EQUAL, funcRef, funcMask));
-                GR_GL(StencilMask(pathStencilMask));
-                GR_GL(StencilOp(GL_ZERO, GL_ZERO, GL_ZERO));
-                GR_GL(ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
-                if (!fSingleStencilPassForWinding) {
-                    GR_GL(Disable(GL_CULL_FACE));
-                }
-                } break;
-            case kWindingStencil1_StencilPass:
-                GR_GL(Enable(GL_STENCIL_TEST));
-                if (fHasStencilWrap) {
-                    if (stencilClip) {
-                        GR_GL(StencilFunc(GL_EQUAL,
-                                          clipStencilMask,
-                                          clipStencilMask));
-                    } else {
-                        GR_GL(StencilFunc(GL_ALWAYS, 0x0, 0x0));
-                    }
-                    if (fSingleStencilPassForWinding) {
-                        GR_GL(StencilOpSeparate(GL_FRONT, GL_KEEP,
-                                                GL_INCR_WRAP, GL_INCR_WRAP));
-                        GR_GL(StencilOpSeparate(GL_BACK,  GL_KEEP,
-                                                GL_DECR_WRAP, GL_DECR_WRAP));
-                    } else {
-                        GR_GL(StencilOp(GL_KEEP, GL_INCR_WRAP, GL_INCR_WRAP));
-                        GR_GL(Enable(GL_CULL_FACE));
-                        GR_GL(CullFace(GL_BACK));
-                    }
-                } else {
-                    // If we don't have wrap then we use the Func to detect
-                    // values that would wrap (0 on decr and mask on incr). We
-                    // make the func fail on these values and use the sfail op
-                    // to effectively wrap by inverting.
-                    // This applies whether we are doing a two-pass (front faces
-                    // followed by back faces) or a single pass (separate func/op)
+        // we can't simultaneously perform stencil-clipping and modify the stencil clip
+        GrAssert(!stencilClip || !(fCurrDrawState.fFlagBits & kModifyStencilClip_StateBit));
 
-                    // Note that in the case where we are also using stencil to
-                    // clip this means we will write into the path bits in clipped
-                    // out pixels. We still apply the clip bit in the color pass
-                    // stencil func so we don't draw color outside the clip.
-                    // We also will clear the stencil bits in clipped pixels by
-                    // using zero in the sfail op with write mask set to the
-                    // path mask.
-                    GR_GL(Enable(GL_STENCIL_TEST));
-                    if (fSingleStencilPassForWinding) {
-                        GR_GL(StencilFuncSeparate(GL_FRONT,
-                                                  GL_NOTEQUAL,
-                                                  pathStencilMask,
-                                                  pathStencilMask));
-                        GR_GL(StencilFuncSeparate(GL_BACK,
-                                                  GL_NOTEQUAL,
-                                                  0x0,
-                                                  pathStencilMask));
-                        GR_GL(StencilOpSeparate(GL_FRONT, GL_INVERT,
-                                                GL_INCR, GL_INCR));
-                        GR_GL(StencilOpSeparate(GL_BACK,  GL_INVERT,
-                                                GL_DECR, GL_DECR));
-                    } else {
-                        GR_GL(StencilFunc(GL_NOTEQUAL,
-                                          pathStencilMask,
-                                          pathStencilMask));
-                        GR_GL(StencilOp(GL_INVERT, GL_INCR, GL_INCR));
-                        GR_GL(Enable(GL_CULL_FACE));
-                        GR_GL(CullFace(GL_BACK));
-                    }
-                }
-                GR_GL(StencilMask(pathStencilMask));
-                GR_GL(ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE));
-                break;
-            case kWindingStencil2_StencilPass:
-                GrAssert(!fSingleStencilPassForWinding);
-                GR_GL(Enable(GL_STENCIL_TEST));
-                if (fHasStencilWrap) {
-                    if (stencilClip) {
-                        GR_GL(StencilFunc(GL_EQUAL,
-                                          clipStencilMask,
-                                          clipStencilMask));
-                    } else {
-                        GR_GL(StencilFunc(GL_ALWAYS, 0x0, 0x0));
-                    }
-                    GR_GL(StencilOp(GL_DECR_WRAP, GL_DECR_WRAP, GL_DECR_WRAP));
-                } else {
-                    GR_GL(StencilFunc(GL_NOTEQUAL, 0x0, pathStencilMask));
-                    GR_GL(StencilOp(GL_INVERT, GL_DECR, GL_DECR));
-                }
-                GR_GL(StencilMask(pathStencilMask));
-                GR_GL(Enable(GL_CULL_FACE));
-                GR_GL(CullFace(GL_FRONT));
-                GR_GL(ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE));
-                break;
-            case kWindingColor_StencilPass: {
-                GR_GL(Enable(GL_STENCIL_TEST));
-                GLint  funcRef   = 0;
-                GLuint funcMask  = pathStencilMask;
-                GLenum funcFunc;
-
-                if (stencilClip) {
-                    funcRef  |= clipStencilMask;
-                    funcMask |= clipStencilMask;
-                }
-                if (fCurrDrawState.fReverseFill) {
-                    funcFunc = GL_EQUAL;
-                } else {
-                    funcFunc = GL_LESS;
-                }
-                GR_GL(StencilFunc(funcFunc, funcRef, funcMask));
-                GR_GL(StencilMask(pathStencilMask));
-                // must zero in sfail because winding w/o wrap will write
-                // path stencil bits in clipped out pixels
-                GR_GL(StencilOp(GL_ZERO, GL_ZERO, GL_ZERO));
-                GR_GL(ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
-                if (!fSingleStencilPassForWinding) {
-                    GR_GL(Disable(GL_CULL_FACE));
-                }
-                } break;
-            case kSetClip_StencilPass:
-                GR_GL(Enable(GL_STENCIL_TEST));
-                GR_GL(StencilFunc(GL_ALWAYS, clipStencilMask, clipStencilMask));
-                GR_GL(StencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE));
-                GR_GL(StencilMask(clipStencilMask));
-                GR_GL(ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE));
-                if (!fSingleStencilPassForWinding) {
-                    GR_GL(Disable(GL_CULL_FACE));
-                }
-                break;
-            default:
-                GrAssert(!"Unexpected stencil pass.");
-                break;
-
+        if (settings->isDisabled()) {
+            if (stencilClip) {
+                settings = &gClipStencilSettings;
+            }
         }
-        fHWDrawState.fStencilPass = fCurrDrawState.fStencilPass;
-        fHWDrawState.fReverseFill = fCurrDrawState.fReverseFill;
+
+        if (settings->isDisabled()) {
+            GR_GL(Disable(GL_STENCIL_TEST));
+        } else {
+            GR_GL(Enable(GL_STENCIL_TEST));
+    #if GR_DEBUG
+            if (!fStencilWrapOpsSupport) {
+                GrAssert(settings->fFrontPassOp != kIncWrap_StencilOp);
+                GrAssert(settings->fFrontPassOp != kDecWrap_StencilOp);
+                GrAssert(settings->fFrontFailOp != kIncWrap_StencilOp);
+                GrAssert(settings->fBackFailOp != kDecWrap_StencilOp);
+                GrAssert(settings->fBackPassOp != kIncWrap_StencilOp);
+                GrAssert(settings->fBackPassOp != kDecWrap_StencilOp);
+                GrAssert(settings->fBackFailOp != kIncWrap_StencilOp);
+                GrAssert(settings->fFrontFailOp != kDecWrap_StencilOp);
+            }
+    #endif
+            int stencilBits = fCurrDrawState.fRenderTarget->stencilBits();
+            GrAssert(stencilBits ||
+                     (GrStencilSettings::gDisabled ==
+                      fCurrDrawState.fStencilSettings));
+            GLuint clipStencilMask = 1 << (stencilBits - 1);
+            GLuint userStencilMask = clipStencilMask - 1;
+
+            unsigned int frontRef  = settings->fFrontFuncRef;
+            unsigned int frontMask = settings->fFrontFuncMask;
+            unsigned int frontWriteMask = settings->fFrontWriteMask;
+            GLenum frontFunc;
+
+            if (fCurrDrawState.fFlagBits & kModifyStencilClip_StateBit) {
+
+                GrAssert(settings->fFrontFunc < kBasicStencilFuncCount);
+                frontFunc = grToGLStencilFunc[settings->fFrontFunc];
+            } else {
+                frontFunc = grToGLStencilFunc[ConvertStencilFunc(stencilClip, settings->fFrontFunc)];
+
+                ConvertStencilFuncAndMask(settings->fFrontFunc,
+                                          stencilClip,
+                                          clipStencilMask,
+                                          userStencilMask,
+                                          &frontRef,
+                                          &frontMask);
+                frontWriteMask &= userStencilMask;
+            }
+            GrAssert(settings->fFrontFailOp >= 0 &&
+                     settings->fFrontFailOp < GR_ARRAY_COUNT(grToGLStencilOp));
+            GrAssert(settings->fFrontPassOp >= 0 &&
+                     settings->fFrontPassOp < GR_ARRAY_COUNT(grToGLStencilOp));
+            GrAssert(settings->fBackFailOp >= 0 &&
+                     settings->fBackFailOp < GR_ARRAY_COUNT(grToGLStencilOp));
+            GrAssert(settings->fBackPassOp >= 0 &&
+                     settings->fBackPassOp < GR_ARRAY_COUNT(grToGLStencilOp));
+            if (fTwoSidedStencilSupport) {
+                GLenum backFunc;
+
+                unsigned int backRef  = settings->fBackFuncRef;
+                unsigned int backMask = settings->fBackFuncMask;
+                unsigned int backWriteMask = settings->fBackWriteMask;
+
+
+                if (fCurrDrawState.fFlagBits & kModifyStencilClip_StateBit) {
+                    GrAssert(settings->fBackFunc < kBasicStencilFuncCount);
+                    backFunc = grToGLStencilFunc[settings->fBackFunc];
+                } else {
+                    backFunc = grToGLStencilFunc[ConvertStencilFunc(stencilClip, settings->fBackFunc)];
+                    ConvertStencilFuncAndMask(settings->fBackFunc,
+                                              stencilClip,
+                                              clipStencilMask,
+                                              userStencilMask,
+                                              &backRef,
+                                              &backMask);
+                    backWriteMask &= userStencilMask;
+                }
+
+                GR_GL(StencilFuncSeparate(GL_FRONT, frontFunc, frontRef, frontMask));
+                GR_GL(StencilMaskSeparate(GL_FRONT, frontWriteMask));
+                GR_GL(StencilFuncSeparate(GL_BACK, backFunc, backRef, backMask));
+                GR_GL(StencilMaskSeparate(GL_BACK, backWriteMask));
+                GR_GL(StencilOpSeparate(GL_FRONT, grToGLStencilOp[settings->fFrontFailOp],
+                                                  grToGLStencilOp[settings->fFrontPassOp],
+                                                  grToGLStencilOp[settings->fFrontPassOp]));
+
+                GR_GL(StencilOpSeparate(GL_BACK,  grToGLStencilOp[settings->fBackFailOp],
+                                                  grToGLStencilOp[settings->fBackPassOp],
+                                                  grToGLStencilOp[settings->fBackPassOp]));
+            } else {
+                GR_GL(StencilFunc(frontFunc, frontRef, frontMask));
+                GR_GL(StencilMask(frontWriteMask));
+                GR_GL(StencilOp(grToGLStencilOp[settings->fFrontFailOp],
+                                grToGLStencilOp[settings->fFrontPassOp],
+                                grToGLStencilOp[settings->fFrontPassOp]));
+            }
+        }
+        fHWDrawState.fStencilSettings = fCurrDrawState.fStencilSettings;
         fHWStencilClip = stencilClip;
     }
 }
@@ -1544,6 +1558,17 @@
         }
     }
 
+    if ((fCurrDrawState.fFlagBits & kNoColorWrites_StateBit) !=
+        (fHWDrawState.fFlagBits & kNoColorWrites_StateBit)) {
+        GLenum mask;
+        if (fCurrDrawState.fFlagBits & kNoColorWrites_StateBit) {
+            mask = GL_FALSE;
+        } else {
+            mask = GL_TRUE;
+        }
+        GR_GL(ColorMask(mask, mask, mask, mask));
+    }
+
 #if GR_SUPPORT_GLDESKTOP
     // ES doesn't support toggling GL_MULTISAMPLE and doesn't have
     // smooth lines.
@@ -1592,6 +1617,25 @@
         }
     }
 
+    if (fHWDrawState.fDrawFace != fCurrDrawState.fDrawFace) {
+        switch (fCurrDrawState.fDrawFace) {
+            case kCCW_DrawFace:
+                glEnable(GL_CULL_FACE);
+                GR_GL(CullFace(GL_BACK));
+                break;
+            case kCW_DrawFace:
+                GR_GL(Enable(GL_CULL_FACE));
+                GR_GL(CullFace(GL_FRONT));
+                break;
+            case kBoth_DrawFace:
+                GR_GL(Disable(GL_CULL_FACE));
+                break;
+            default:
+                GrCrash("Unknown draw face.");
+        }
+        fHWDrawState.fDrawFace = fCurrDrawState.fDrawFace;
+    }
+
 #if GR_DEBUG
     // check for circular rendering
     for (int s = 0; s < kNumStages; ++s) {
@@ -1605,6 +1649,7 @@
 
     flushStencil();
 
+    // flushStencil may look at the private state bits, so keep it before this.
     fHWDrawState.fFlagBits = fCurrDrawState.fFlagBits;
     return true;
 }
@@ -1654,9 +1699,6 @@
     if (fHWDrawState.fRenderTarget == renderTarget) {
         fHWDrawState.fRenderTarget = NULL;
     }
-    if (fClipState.fStencilClipTarget == renderTarget) {
-        fClipState.fStencilClipTarget = NULL;
-    }
 }
 
 void GrGpuGL::notifyTextureDelete(GrGLTexture* texture) {
diff --git a/gpu/src/GrGpuGL.h b/gpu/src/GrGpuGL.h
index f6216c5..a2905c5 100644
--- a/gpu/src/GrGpuGL.h
+++ b/gpu/src/GrGpuGL.h
@@ -80,7 +80,6 @@
     // call resetDirtyFlags after its flush is complete
     struct {
         bool fRenderTargetChanged : 1;
-        bool fWriteMaskChanged : 1;
         int  fTextureChangedMask;
     } fDirtyFlags;
     GR_STATIC_ASSERT(8 * sizeof(int) >= kNumStages);
@@ -108,7 +107,7 @@
                                       uint32_t numVertices);
     virtual void flushScissor(const GrIRect* rect);
     void eraseStencil(uint32_t value, uint32_t mask);
-    virtual void eraseStencilClip();
+    virtual void eraseStencilClip(const GrIRect& rect);
 
     // binds texture unit in GL
     void setTextureUnit(int unitIdx);
diff --git a/gpu/src/GrInOrderDrawBuffer.cpp b/gpu/src/GrInOrderDrawBuffer.cpp
index 68590fc..a249364 100644
--- a/gpu/src/GrInOrderDrawBuffer.cpp
+++ b/gpu/src/GrInOrderDrawBuffer.cpp
@@ -67,17 +67,17 @@
         fCurrQuad = 0;
         fMaxQuads = (NULL == indexBuffer) ? 0 : indexBuffer->maxQuads();
     } else {
-        GrAssert((NULL == indexBuffer && 0 == fMaxQuads) || 
+        GrAssert((NULL == indexBuffer && 0 == fMaxQuads) ||
                  (indexBuffer->maxQuads() == fMaxQuads));
     }
 }
 
-void GrInOrderDrawBuffer::drawRect(const GrRect& rect, 
+void GrInOrderDrawBuffer::drawRect(const GrRect& rect,
                                    const GrMatrix* matrix,
                                    StageBitfield stageEnableBitfield,
                                    const GrRect* srcRects[],
                                    const GrMatrix* srcMatrices[]) {
-    
+
     GrAssert(!(NULL == fQuadIndexBuffer && fCurrQuad));
     GrAssert(!(fDraws.empty() && fCurrQuad));
     GrAssert(!(0 != fMaxQuads && NULL == fQuadIndexBuffer));
@@ -85,7 +85,7 @@
     // if we have a quad IB then either append to the previous run of
     // rects or start a new run
     if (fMaxQuads) {
-        
+
         bool appendToPreviousDraw = false;
         GrVertexLayout layout = GetRectVertexLayout(stageEnableBitfield, srcRects);
         AutoReleaseGeometry geo(this, layout, 4, 0);
@@ -103,10 +103,14 @@
         // the rect.
         bool disabledClip = false;
         if (this->isClipState() && fClip.isRect()) {
-            GrRect clipRect = GrRect(*fClip.getRects());
+
+            // single rect clip should have bounds
+            GrAssert(fClip.hasBounds());
+
+            GrRect clipRect = GrRect(fClip.getBounds());
             // If the clip rect touches the edge of the viewport, extended it
             // out (close) to infinity to avoid bogus intersections.
-            // We might consider a more exact clip to viewport if this 
+            // We might consider a more exact clip to viewport if this
             // conservative test fails.
             const GrRenderTarget* target = this->getRenderTarget();
             if (0 >= clipRect.fLeft) {
@@ -135,11 +139,11 @@
                 disabledClip = true;
             }
         }
-        if (!needsNewClip() && !needsNewState() && fCurrQuad > 0 && 
+        if (!needsNewClip() && !needsNewState() && fCurrQuad > 0 &&
             fCurrQuad < fMaxQuads && layout == fLastRectVertexLayout) {
 
             int vsize = VertexSize(layout);
-        
+
             Draw& lastDraw = fDraws.back();
 
             GrAssert(lastDraw.fIndexBuffer == fQuadIndexBuffer);
@@ -500,7 +504,7 @@
     }
     this->saveCurrentDrawState(&fStates.push_back());
  }
- 
+
 bool GrInOrderDrawBuffer::needsNewClip() const {
    if (fCurrDrawState.fFlagBits & kClip_StateBit) {
        if (fClips.empty() || (fClipSet && fClips.back() != fClip)) {
@@ -509,12 +513,12 @@
     }
     return false;
 }
- 
+
 void GrInOrderDrawBuffer::pushClip() {
     fClips.push_back() = fClip;
     fClipSet = false;
 }
- 
+
 void GrInOrderDrawBuffer::clipWillBeSet(const GrClip& newClip)  {
     fClipSet = true;
 }
diff --git a/gpu/src/GrPath.cpp b/gpu/src/GrPath.cpp
index 554b3b9..ca5c43b 100644
--- a/gpu/src/GrPath.cpp
+++ b/gpu/src/GrPath.cpp
@@ -3,6 +3,8 @@
 GrPath::GrPath() {}
 
 GrPath::GrPath(const GrPath& src) : INHERITED() {
+    GrPath::Iter iter(src);
+    this->resetFromIter(&iter);
 }
 
 GrPath::GrPath(GrPathIter& iter) {
@@ -12,6 +14,26 @@
 GrPath::~GrPath() {
 }
 
+bool GrPath::operator ==(const GrPath& path) const {
+    if (fVerbs.count() != path.fVerbs.count() ||
+        fPts.count() != path.fPts.count()) {
+        return false;
+    }
+
+    for (int v = 0; v < fVerbs.count(); ++v) {
+        if (fVerbs[v] != path.fVerbs[v]) {
+            return false;
+        }
+    }
+
+    for (int p = 0; p < fPts.count(); ++p) {
+        if (fPts[p] != path.fPts[p]) {
+            return false;
+        }
+    }
+    return true;
+}
+
 void GrPath::ensureMoveTo() {
     if (fVerbs.isEmpty() || this->wasLastVerb(kClose)) {
         *fVerbs.append() = kMove;
@@ -90,6 +112,7 @@
                 break;
         }
     }
+    fConvexHint = iter->convexHint();
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -157,7 +180,7 @@
     return (GrPathIter::Command)cmd;
 }
 
-GrPathIter::ConvexHint GrPath::Iter::hint() const {
+GrPathIter::ConvexHint GrPath::Iter::convexHint() const {
     return fPath.getConvexHint();
 }
 
diff --git a/gpu/src/GrPathRenderer.cpp b/gpu/src/GrPathRenderer.cpp
index c47b6e5..3e2b4b3 100644
--- a/gpu/src/GrPathRenderer.cpp
+++ b/gpu/src/GrPathRenderer.cpp
@@ -6,15 +6,145 @@
 #include "GrMemory.h"
 #include "GrTexture.h"
 
-
-
-GrDefaultPathRenderer::GrDefaultPathRenderer(bool singlePassWindingStencil)
-    : fSinglePassWindingStencil(singlePassWindingStencil) {
+GrDefaultPathRenderer::GrDefaultPathRenderer(bool separateStencilSupport,
+                                             bool stencilWrapOpsSupport)
+    : fSeparateStencil(separateStencilSupport),
+      fStencilWrapOps(stencilWrapOpsSupport) {
 
 }
 
 ////////////////////////////////////////////////////////////////////////////////
-// Helpers for draw Path
+// 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
 
 #define STENCIL_OFF     0   // Always disable stencil (even when needed)
 static const GrScalar gTolerance = GR_Scalar1;
@@ -146,11 +276,11 @@
     return true;
 #else
     if (kEvenOdd_PathFill == fill) {
-        GrPathIter::ConvexHint hint = path.hint();
+        GrPathIter::ConvexHint hint = path.convexHint();
         return hint == GrPathIter::kConvex_ConvexHint ||
                hint == GrPathIter::kNonOverlappingConvexPieces_ConvexHint;
     } else if (kWinding_PathFill == fill) {
-        GrPathIter::ConvexHint hint = path.hint();
+        GrPathIter::ConvexHint hint = path.convexHint();
         return hint == GrPathIter::kConvex_ConvexHint ||
                hint == GrPathIter::kNonOverlappingConvexPieces_ConvexHint ||
                (hint == GrPathIter::kSameWindingConvexPieces_ConvexHint &&
@@ -161,13 +291,17 @@
 #endif
 }
 
-void GrDefaultPathRenderer::drawPath(GrDrawTarget* target,
-                                     GrDrawTarget::StageBitfield stages,
-                                     GrPathIter* path,
-                                     GrPathFill fill,
-                                     const GrPoint* translate) {
+void GrDefaultPathRenderer::drawPathHelper(GrDrawTarget* target,
+                                           GrDrawTarget::StageBitfield stages,
+                                           GrPathIter* path,
+                                           GrPathFill fill,
+                                           const GrPoint* translate,
+                                           bool stencilOnly) {
 
     GrDrawTarget::AutoStateRestore asr(target);
+    bool colorWritesWereDisabled = target->isColorWriteDisabled();
+    // face culling doesn't make sense here
+    GrAssert(GrDrawTarget::kBoth_DrawFace == target->getDrawFace());
 
     GrMatrix viewM = target->getViewMatrix();
     // In order to tesselate the path we get a bound on how much the matrix can
@@ -185,6 +319,8 @@
     }
     GrScalar tolSqd = GrMul(tol, tol);
 
+    path->rewind();
+
     int subpathCnt;
     int maxPts = worst_case_point_count(path,
                                         &subpathCnt,
@@ -211,42 +347,91 @@
     // TODO: use primitve restart if available rather than multiple draws
     GrPrimitiveType             type;
     int                         passCount = 0;
-    GrDrawTarget::StencilPass   passes[3];
+    const GrStencilSettings*    passes[3];
+    GrDrawTarget::DrawFace      drawFace[3];
     bool                        reverse = false;
+    bool                        lastPassIsBounds;
 
     if (kHairLine_PathFill == fill) {
         type = kLineStrip_PrimitiveType;
         passCount = 1;
-        passes[0] = GrDrawTarget::kNone_StencilPass;
+        if (stencilOnly) {
+            passes[0] = &gDirectToStencil;
+        } else {
+            passes[0] = &GrStencilSettings::gDisabled;
+        }
+        lastPassIsBounds = false;
+        drawFace[0] = GrDrawTarget::kBoth_DrawFace;
     } else {
         type = kTriangleFan_PrimitiveType;
         if (single_pass_path(*path, fill, *target)) {
             passCount = 1;
-            passes[0] = GrDrawTarget::kNone_StencilPass;
+            if (stencilOnly) {
+                passes[0] = &gDirectToStencil;
+            } else {
+                passes[0] = &GrStencilSettings::gDisabled;
+            }
+            drawFace[0] = GrDrawTarget::kBoth_DrawFace;
+            lastPassIsBounds = false;
         } else {
             switch (fill) {
                 case kInverseEvenOdd_PathFill:
                     reverse = true;
                     // fallthrough
                 case kEvenOdd_PathFill:
-                    passCount = 2;
-                    passes[0] = GrDrawTarget::kEvenOddStencil_StencilPass;
-                    passes[1] = GrDrawTarget::kEvenOddColor_StencilPass;
+                    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:
-                    passes[0] = GrDrawTarget::kWindingStencil1_StencilPass;
-                    if (fSinglePassWindingStencil) {
-                        passes[1] = GrDrawTarget::kWindingColor_StencilPass;
+                    if (fSeparateStencil) {
+                        if (fStencilWrapOps) {
+                            passes[0] = &gWindStencilSeparateWithWrap;
+                        } else {
+                            passes[0] = &gWindStencilSeparateNoWrap;
+                        }
                         passCount = 2;
+                        drawFace[0] = GrDrawTarget::kBoth_DrawFace;
                     } else {
-                        passes[1] = GrDrawTarget::kWindingStencil2_StencilPass;
-                        passes[2] = GrDrawTarget::kWindingColor_StencilPass;
+                        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 fill!");
@@ -254,7 +439,6 @@
             }
         }
     }
-    target->setReverseFill(reverse);
 
     GrPoint pts[4];
 
@@ -309,11 +493,12 @@
         }
     }
 
-    // arbitrary path complexity cutoff
-    bool useBounds = fill != kHairLine_PathFill &&
-                    (reverse || (vert - base) > 8);
-    GrPoint* boundsVerts = base + maxPts;
-    if (useBounds) {
+    // if we're stenciling we will follow with a pass that draws
+    // a bounding rect to set the color. We're stenciling when
+    // passCount > 1.
+    const int& boundVertexStart = maxPts;
+    GrPoint* boundsVerts = base + boundVertexStart;
+    if (lastPassIsBounds) {
         GrRect bounds;
         if (reverse) {
             GrAssert(NULL != target->getRenderTarget());
@@ -333,20 +518,44 @@
     }
 
     for (int p = 0; p < passCount; ++p) {
-        target->setStencilPass(passes[p]);
-        if (useBounds && (GrDrawTarget::kEvenOddColor_StencilPass == passes[p] ||
-                          GrDrawTarget::kWindingColor_StencilPass == passes[p])) {
+        target->setDrawFace(drawFace[p]);
+        target->setStencil(*passes[p]);
+
+        if (lastPassIsBounds && (p == passCount-1)) {
+            if (!colorWritesWereDisabled) {
+                target->disableState(GrDrawTarget::kNoColorWrites_StateBit);
+            }
             target->drawNonIndexed(kTriangleFan_PrimitiveType,
-                                 maxPts, 4);
+                                   boundVertexStart, 4);
 
         } else {
+            if (passCount > 1) {
+                target->enableState(GrDrawTarget::kNoColorWrites_StateBit);
+            }
             int baseVertex = 0;
             for (int sp = 0; sp < subpathCnt; ++sp) {
                 target->drawNonIndexed(type,
-                                     baseVertex,
-                                     subpathVertCount[sp]);
+                                      baseVertex,
+                                      subpathVertCount[sp]);
                 baseVertex += subpathVertCount[sp];
             }
         }
     }
 }
+
+void GrDefaultPathRenderer::drawPath(GrDrawTarget* target,
+                                     GrDrawTarget::StageBitfield stages,
+                                     GrPathIter* path,
+                                     GrPathFill fill,
+                                     const GrPoint* translate) {
+    this->drawPathHelper(target, stages, path, fill, translate, false);
+}
+
+void GrDefaultPathRenderer::drawPathToStencil(GrDrawTarget* target,
+                                              GrPathIter* path,
+                                              GrPathFill fill,
+                                              const GrPoint* translate) {
+     GrAssert(kInverseEvenOdd_PathFill != fill);
+     GrAssert(kInverseWinding_PathFill != fill);
+     this->drawPathHelper(target, 0, path, fill, translate, true);
+ }
diff --git a/gpu/src/GrPathRenderer.h b/gpu/src/GrPathRenderer.h
index e3fd715..467b0a0 100644
--- a/gpu/src/GrPathRenderer.h
+++ b/gpu/src/GrPathRenderer.h
@@ -34,31 +34,107 @@
      * @param stages                indicates which stages the are already
      *                              in use. All enabled stages expect positions
      *                              as texture coordinates. The path renderer
-     *                              use the remaining stages for its path 
+     *                              use the remaining stages for its path
      *                              filling algorithm.
      * @param path                  the path to draw.
      * @param fill                  the fill rule to apply.
      * @param translate             optional additional translation to apply to
-     *                              the path NULL means (0,0).
+     *                              the path. NULL means (0,0).
      */
     virtual void drawPath(GrDrawTarget* target,
                           GrDrawTarget::StageBitfield stages,
                           GrPathIter* path,
                           GrPathFill fill,
                           const GrPoint* translate) = 0;
+
+    void drawPath(GrDrawTarget* target,
+                  GrDrawTarget::StageBitfield stages,
+                  const GrPath& path,
+                  GrPathFill fill,
+                  const GrPoint* translate) {
+            GrPath::Iter iter(path);
+            this->drawPath(target, stages, &iter, fill, translate);
+    }
+
+    /**
+     * 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 requires its own stencil
+     * pass. If this returns false then drawPath() should not modify the
+     * the target's stencil settings.
+     *
+     * @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(GrPathIter*) const { return false; }
+    
+    bool requiresStencilPass(const GrPath& path) const { 
+        GrPath::Iter iter(path);
+        return requiresStencilPass(&iter);
+    }
+
+    /**
+     * Draws a path to the stencil buffer. Assume the writable bits are zero
+     * prior and write a nonzero value in interior samples. The default
+     * implementation assumes the path filling algorithm doesn't require a
+     * separate stencil pass and so just calls drawPath.
+     *
+     * Fill will never be an inverse fill rule.
+     *
+     * @param target                the target to draw into.
+     * @param path                  the path to draw.
+     * @param fill                  the fill rule to apply.
+     * @param translate             optional additional translation to apply to
+     *                              the path. NULL means (0,0).
+     */
+    virtual void drawPathToStencil(GrDrawTarget* target,
+                                   GrPathIter* path,
+                                   GrPathFill fill,
+                                   const GrPoint* translate) {
+        GrAssert(kInverseEvenOdd_PathFill != fill);
+        GrAssert(kInverseWinding_PathFill != fill);
+
+        this->drawPath(target, 0, path, fill, translate);
+    }
+
+    void drawPathToStencil(GrDrawTarget* target,
+                           const GrPath& path,
+                           GrPathFill fill,
+                           const GrPoint* translate) {
+        GrPath::Iter iter(path);
+        this->drawPathToStencil(target, &iter, fill, translate);
+    }
 };
 
 class GrDefaultPathRenderer : public GrPathRenderer {
 public:
-    GrDefaultPathRenderer(bool singlePassWindingStencil);
+    GrDefaultPathRenderer(bool separateStencilSupport,
+                          bool stencilWrapOpsSupport);
 
     virtual void drawPath(GrDrawTarget* target,
                           GrDrawTarget::StageBitfield stages,
                           GrPathIter* path,
                           GrPathFill fill,
                           const GrPoint* translate);
+    virtual bool requiresStencilPass(GrPath&) const { return true; }
+    virtual void drawPathToStencil(GrDrawTarget* target,
+                                   GrPathIter* path,
+                                   GrPathFill fill,
+                                   const GrPoint* translate);
 private:
-    bool    fSinglePassWindingStencil;
+
+    void drawPathHelper(GrDrawTarget* target,
+                        GrDrawTarget::StageBitfield stages,
+                        GrPathIter* path,
+                        GrPathFill fill,
+                        const GrPoint* translate,
+                        bool stencilOnly);
+
+    bool    fSeparateStencil;
+    bool    fStencilWrapOps;
 };
 
 #endif
\ No newline at end of file
diff --git a/gpu/src/GrStencil.cpp b/gpu/src/GrStencil.cpp
new file mode 100644
index 0000000..9d68c65
--- /dev/null
+++ b/gpu/src/GrStencil.cpp
@@ -0,0 +1,398 @@
+/*
+    Copyright 2011 Google Inc.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+ */
+
+#include "GrStencil.h"
+
+const GrStencilSettings GrStencilSettings::gDisabled = {};
+GR_STATIC_ASSERT(0 == kKeep_StencilOp);
+GR_STATIC_ASSERT(0 == kAlways_StencilFunc);
+
+////////////////////////////////////////////////////////////////////////////////
+// Stencil Rules for Merging user stencil space into clip
+
+// We can't include the clip bit in the ref or mask values because the division
+// between user and clip bits in the stencil depends on the number of stencil
+// bits in the runtime. Comments below indicate what the code should do to
+// incorporate the clip bit into these settings.
+
+///////
+// Replace
+
+// set the ref to be the clip bit, but mask it out for the test
+static const GrStencilSettings gUserToClipReplace = {
+    kReplace_StencilOp,  kReplace_StencilOp,
+    kZero_StencilOp,     kZero_StencilOp,
+    kLess_StencilFunc,   kLess_StencilFunc,
+    0xffffffff,          0xffffffff,    // unset clip bit
+    0x0,                 0x0,           // set clip bit
+    0xffffffff,          0xffffffff
+};
+static const GrStencilSettings gInvUserToClipReplace = {
+    kReplace_StencilOp,  kReplace_StencilOp,
+    kZero_StencilOp,     kZero_StencilOp,
+    kEqual_StencilFunc,  kEqual_StencilFunc,
+    0xffffffff,          0xffffffff,    // unset clip bit
+    0x0,                 0x0,           // set clip bit
+    0xffffffff,          0xffffffff
+};
+
+///////
+// Intersect
+static const GrStencilSettings gUserToClipIsect = {
+    kReplace_StencilOp,  kReplace_StencilOp,
+    kZero_StencilOp,     kZero_StencilOp,
+    kLess_StencilFunc,   kLess_StencilFunc,
+    0xffffffff,          0xffffffff,
+    0x0,                 0x0,           // set clip bit
+    0xffffffff,          0xffffffff
+};
+static const GrStencilSettings gInvUserToClipIsect = {
+    kReplace_StencilOp,  kReplace_StencilOp,
+    kZero_StencilOp,     kZero_StencilOp,
+    kEqual_StencilFunc,  kEqual_StencilFunc,
+    0xffffffff,          0xffffffff,
+    0x0,                 0x0,           // set clip bit
+    0xffffffff,          0xffffffff
+};
+
+///////
+// Difference
+static const GrStencilSettings gUserToClipDiff = {
+    kReplace_StencilOp,  kReplace_StencilOp,
+    kZero_StencilOp,     kZero_StencilOp,
+    kEqual_StencilFunc,  kEqual_StencilFunc,
+    0xffffffff,          0xffffffff,
+    0x0,                 0x0,           // set clip bit
+    0xffffffff,          0xffffffff
+};
+static const GrStencilSettings gInvUserToClipDiff = {
+    kReplace_StencilOp,  kReplace_StencilOp,
+    kZero_StencilOp,     kZero_StencilOp,
+    kLess_StencilFunc,   kLess_StencilFunc,
+    0xffffffff,          0xffffffff,
+    0x0,                 0x0,           // set clip bit
+    0xffffffff,          0xffffffff
+};
+
+///////
+// Union
+
+// first pass makes all the passing cases >= just clip bit set.
+static const GrStencilSettings gUserToClipUnionPass0 = {
+    kReplace_StencilOp,  kReplace_StencilOp,
+    kKeep_StencilOp,     kKeep_StencilOp,
+    kLEqual_StencilFunc, kLEqual_StencilFunc,
+    0xffffffff,          0xffffffff,    // unset clip bit
+    0x00000001,          0x00000001,    // set clip bit
+    0xffffffff,          0xffffffff
+};
+
+// second pass allows anything greater than just clip bit set to pass
+static const GrStencilSettings gUserToClipUnionPass1 = {
+    kReplace_StencilOp,  kReplace_StencilOp,
+    kZero_StencilOp,     kZero_StencilOp,
+    kLEqual_StencilFunc, kLEqual_StencilFunc,
+    0xffffffff,          0xffffffff,
+    0x00000000,          0x00000000,    // set clip bit
+    0xffffffff,          0xffffffff
+};
+
+// for inverse first pass finds non-zerp user with clip bit set
+// and converts it to just clip bit set
+static const GrStencilSettings gInvUserToClipUnionPass0 = {
+    kReplace_StencilOp,  kReplace_StencilOp,
+    kKeep_StencilOp,     kKeep_StencilOp,
+    kLess_StencilFunc,   kLess_StencilFunc,
+    0xffffffff,          0xffffffff,
+    0x00000000,          0x00000000,    // set clip bit
+    0xffffffff,          0xffffffff
+};
+
+// second pass lets anything through with a nonzero user portion
+// and writes a ref value with just the clip bit set to it.
+static const GrStencilSettings gInvUserToClipUnionPass1 = {
+    kReplace_StencilOp,  kReplace_StencilOp,
+    kZero_StencilOp,     kZero_StencilOp,
+    kLess_StencilFunc,   kLess_StencilFunc,
+    0xffffffff,          0xffffffff,    // unset clip bit
+    0x00000000,          0x00000000,    // set clip bit
+    0xffffffff,          0xffffffff
+};
+
+///////
+// Xor
+static const GrStencilSettings gUserToClipXorPass0 = {
+    kInvert_StencilOp,   kInvert_StencilOp,
+    kKeep_StencilOp,     kKeep_StencilOp,
+    kEqual_StencilFunc,  kEqual_StencilFunc,
+    0xffffffff,          0xffffffff,    // unset clip bit
+    0x00000000,          0x00000000,
+    0xffffffff,          0xffffffff
+};
+
+static const GrStencilSettings gUserToClipXorPass1 = {
+    kReplace_StencilOp,   kReplace_StencilOp,
+    kZero_StencilOp,      kZero_StencilOp,
+    kGreater_StencilFunc, kGreater_StencilFunc,
+    0xffffffff,           0xffffffff,
+    0x00000000,           0x00000000,   // set clip bit
+    0xffffffff,           0xffffffff
+};
+
+static const GrStencilSettings gInvUserToClipXorPass0 = {
+    kInvert_StencilOp,   kInvert_StencilOp,
+    kKeep_StencilOp,     kKeep_StencilOp,
+    kEqual_StencilFunc,  kEqual_StencilFunc,
+    0xffffffff,          0xffffffff,    // unset clip bit
+    0x00000000,          0x00000000,
+    0xffffffff,          0xffffffff
+};
+
+static const GrStencilSettings gInvUserToClipXorPass1 = {
+    kReplace_StencilOp,   kReplace_StencilOp,
+    kZero_StencilOp,      kZero_StencilOp,
+    kLess_StencilFunc,    kLess_StencilFunc,
+    0xffffffff,           0xffffffff,
+    0x00000000,           0x00000000,   // set clip bit
+    0xffffffff,           0xffffffff
+};
+
+///////
+// Reverse Diff
+static const GrStencilSettings gUserToClipRDiffPass0 = {
+    kInvert_StencilOp,   kInvert_StencilOp,
+    kZero_StencilOp,     kZero_StencilOp,
+    kLess_StencilFunc,   kLess_StencilFunc,
+    0xffffffff,          0xffffffff,  // unset clip bit
+    0x00000000,          0x00000000,  // set clip bit
+    0xffffffff,          0xffffffff
+};
+
+static const GrStencilSettings gUserToClipRDiffPass1 = {
+    kReplace_StencilOp,   kReplace_StencilOp,
+    kZero_StencilOp,      kZero_StencilOp,
+    kEqual_StencilFunc,   kEqual_StencilFunc,
+    0x00000000,           0x00000000,   // set clip bit
+    0x00000000,           0x00000000,   // set clip bit
+    0xffffffff,           0xffffffff
+};
+
+static const GrStencilSettings gInvUserToClipRDiff = {
+    kInvert_StencilOp,    kInvert_StencilOp,
+    kZero_StencilOp,      kZero_StencilOp,
+    kEqual_StencilFunc,   kEqual_StencilFunc,
+    0xffffffff,           0xffffffff,
+    0x00000000,           0x00000000, 
+    0x00000000,           0x00000000    // set clip bit
+};
+///////
+// Direct to Stencil
+
+// We can render a clip element directly without first writing to the client
+// portion of the clip when the fill is not inverse and the set operation will
+// only modify the in/out status of samples covered by the clip element.
+
+// this one only works if used right after stencil clip was cleared.
+// Our GrClip doesn't allow midstream replace ops.
+static const GrStencilSettings gReplaceClip = {
+    kReplace_StencilOp,  kReplace_StencilOp,
+    kReplace_StencilOp,  kReplace_StencilOp,
+    kAlways_StencilFunc, kAlways_StencilFunc,
+    0xffffffff,          0xffffffff,
+    0x00000000,          0x00000000,    // set clip bit
+    0x00000000,          0x00000000     // set clipBit
+};
+
+static const GrStencilSettings gUnionClip = {
+    kReplace_StencilOp,  kReplace_StencilOp,
+    kReplace_StencilOp,  kReplace_StencilOp,
+    kAlways_StencilFunc, kAlways_StencilFunc,
+    0xffffffff,          0xffffffff,
+    0x00000000,          0x00000000,    // set clip bit
+    0x00000000,          0x00000000     // set clip bit
+};
+
+static const GrStencilSettings gXorClip = {
+    kInvert_StencilOp,   kInvert_StencilOp,
+    kInvert_StencilOp,   kInvert_StencilOp,
+    kAlways_StencilFunc, kAlways_StencilFunc,
+    0xffffffff,          0xffffffff,
+    0x00000000,          0x00000000,
+    0x00000000,          0x00000000     // set clip bit
+};
+
+static const GrStencilSettings gDiffClip = {
+    kZero_StencilOp,     kZero_StencilOp,
+    kZero_StencilOp,     kZero_StencilOp,
+    kAlways_StencilFunc, kAlways_StencilFunc,
+    0xffffffff,          0xffffffff,
+    0x00000000,          0x00000000,
+    0x00000000,          0x00000000     // set clip bit
+};
+
+static const GrPathFill gNonInvertedFills[] = {
+    kWinding_PathFill, // kWinding_PathFill
+    kEvenOdd_PathFill, // kEvenOdd_PathFill
+    kWinding_PathFill, // kInverseWinding_PathFill
+    kEvenOdd_PathFill, // kInverseEvenOdd_PathFill
+    kWinding_PathFill, // kHairLine_PathFill
+};
+
+static const bool gIsFillInverted[] = {
+    false, // kWinding_PathFill
+    false, // kEvenOdd_PathFill
+    true,  // kInverseWinding_PathFill
+    true,  // kInverseEvenOdd_PathFill
+    false, // kHairLine_PathFill
+};
+GR_STATIC_ASSERT(0 == kWinding_PathFill);
+GR_STATIC_ASSERT(1 == kEvenOdd_PathFill);
+GR_STATIC_ASSERT(2 == kInverseWinding_PathFill);
+GR_STATIC_ASSERT(3 == kInverseEvenOdd_PathFill);
+GR_STATIC_ASSERT(4 == kHairLine_PathFill);
+GR_STATIC_ASSERT(5 == kPathFillCount);
+
+bool GrStencilSettings::GetClipPasses(GrSetOp op, 
+                                      bool canBeDirect,
+                                      unsigned int stencilClipMask,
+                                      GrPathFill* fill,
+                                      int* numPasses,
+                                      GrStencilSettings settings[kMaxStencilClipPasses]) {
+    if (canBeDirect) {
+        if (!gIsFillInverted[*fill]) {
+            *numPasses = 0;
+            switch (op) {
+                case kReplace_SetOp:
+                    *numPasses = 1;
+                    settings[0] = gReplaceClip;
+                    break;
+                case kUnion_SetOp:
+                    *numPasses = 1;
+                    settings[0] = gUnionClip;
+                    break;
+                case kXor_SetOp:
+                    *numPasses = 1;
+                    settings[0] = gXorClip;
+                    break;
+                case kDifference_SetOp:
+                    *numPasses = 1;
+                    settings[0] = gDiffClip;
+                    break;
+                default: // suppress warning
+                    break;
+            }
+            if (1 == *numPasses) {
+                settings[0].fFrontFuncRef |= stencilClipMask;
+                settings[0].fFrontWriteMask |= stencilClipMask;
+                settings[0].fBackFuncRef = settings[0].fFrontFuncRef;
+                settings[0].fBackWriteMask = settings[0].fFrontWriteMask;
+                return true;
+            }
+        }
+    }
+    switch (op) {
+        case kReplace_SetOp:
+            *numPasses= 1;
+            settings[0] = gIsFillInverted[*fill] ? gInvUserToClipReplace : gUserToClipReplace;
+            settings[0].fFrontFuncMask &= ~stencilClipMask;
+            settings[0].fFrontFuncRef |= stencilClipMask;
+            settings[0].fBackFuncMask = settings[0].fFrontFuncMask;
+            settings[0].fBackFuncRef = settings[0].fFrontFuncRef;
+
+        case kIntersect_SetOp:
+            *numPasses = 1;
+            settings[0] = gIsFillInverted[*fill] ? gInvUserToClipIsect : gUserToClipIsect;
+            settings[0].fFrontFuncRef = stencilClipMask;
+            settings[0].fBackFuncRef = settings[0].fFrontFuncRef;
+            break;
+        case kUnion_SetOp:
+            *numPasses = 2;
+            if (gIsFillInverted[*fill]) {
+                settings[0] = gInvUserToClipUnionPass0;
+                settings[0].fFrontFuncRef |= stencilClipMask;
+                settings[0].fBackFuncRef = settings[0].fFrontFuncMask;
+
+                settings[1] = gInvUserToClipUnionPass1;
+                settings[1].fFrontFuncMask &= ~stencilClipMask;
+                settings[1].fFrontFuncRef |= stencilClipMask;
+                settings[1].fBackFuncMask = settings[1].fFrontFuncMask;
+                settings[1].fBackFuncRef = settings[1].fFrontFuncRef;
+
+            } else {
+                settings[0] = gUserToClipUnionPass0;
+                settings[0].fFrontFuncMask &= ~stencilClipMask;
+                settings[0].fFrontFuncRef |= stencilClipMask;
+                settings[0].fBackFuncMask = settings[0].fFrontFuncMask;
+                settings[0].fBackFuncRef = settings[0].fFrontFuncRef;
+
+                settings[1] = gUserToClipUnionPass1;
+                settings[1].fFrontFuncRef |= stencilClipMask;
+                settings[1].fBackFuncRef = settings[1].fFrontFuncRef;
+            }
+            break;
+        case kXor_SetOp:
+            *numPasses = 2;
+            if (gIsFillInverted[*fill]) {
+                settings[0] = gInvUserToClipXorPass0;
+                settings[0].fFrontFuncMask &= ~stencilClipMask;
+                settings[0].fBackFuncMask = settings[0].fFrontFuncMask;
+
+                settings[1] = gInvUserToClipXorPass1;
+                settings[1].fFrontFuncRef |= stencilClipMask;
+                settings[1].fBackFuncRef = settings[1].fFrontFuncRef;
+            } else {
+                settings[0] = gUserToClipXorPass0;
+                settings[0].fFrontFuncMask &= ~stencilClipMask;
+                settings[0].fBackFuncMask = settings[0].fFrontFuncMask;
+
+                settings[1] = gUserToClipXorPass1;
+                settings[1].fFrontFuncRef |= stencilClipMask;
+                settings[1].fBackFuncRef = settings[1].fFrontFuncRef;
+            }
+            break;
+        case kDifference_SetOp:
+            *numPasses = 1;
+            settings[0] = gIsFillInverted[*fill] ? gInvUserToClipDiff : gUserToClipDiff;
+            settings[0].fFrontFuncRef |= stencilClipMask;
+            settings[0].fBackFuncRef = settings[0].fFrontFuncRef;
+            break;
+        case kReverseDifference_SetOp:
+            if (gIsFillInverted[*fill]) {
+                *numPasses = 1;
+                settings[0] = gInvUserToClipRDiff;
+                settings[0].fFrontWriteMask |= stencilClipMask;
+                settings[0].fBackWriteMask = settings[0].fFrontWriteMask;
+            } else {
+                *numPasses = 2;
+                settings[0] = gUserToClipRDiffPass0;
+                settings[0].fFrontFuncMask &= ~stencilClipMask;
+                settings[0].fBackFuncMask = settings[0].fFrontFuncMask;
+                settings[0].fFrontFuncRef |= stencilClipMask;
+                settings[0].fBackFuncRef = settings[0].fFrontFuncRef;
+
+                settings[1] = gUserToClipRDiffPass1;
+                settings[1].fFrontFuncMask |= stencilClipMask;
+                settings[1].fFrontFuncRef |= stencilClipMask;
+                settings[1].fBackFuncMask = settings[1].fFrontFuncMask;
+                settings[1].fBackFuncRef = settings[1].fFrontFuncRef;
+            }
+            break;
+        default:
+            GrCrash("Unknown set op");
+    }
+    *fill = gNonInvertedFills[*fill];
+    return false;
+}
\ No newline at end of file
diff --git a/gpu/src/GrTextContext.cpp b/gpu/src/GrTextContext.cpp
index 8ce45e4..802e3e3 100644
--- a/gpu/src/GrTextContext.cpp
+++ b/gpu/src/GrTextContext.cpp
@@ -67,21 +67,25 @@
 
     fCurrTexture = NULL;
     fCurrVertex = 0;
-    fClipRect = context->getClip().getBounds();
 
     if (NULL != extMatrix) {
         fExtMatrix = *extMatrix;
     } else {
         fExtMatrix = GrMatrix::I();
     }
-    if (!fExtMatrix.isIdentity()) {
-        GrMatrix inverse;
-        GrRect r;
-        r.set(fClipRect);
-        if (fExtMatrix.invert(&inverse)) {
-            inverse.mapRect(&r);
-            r.roundOut(&fClipRect);
+    if (context->getClip().hasBounds()) {
+        if (!fExtMatrix.isIdentity()) {
+            GrMatrix inverse;
+            GrRect r = context->getClip().getBounds();
+            if (fExtMatrix.invert(&inverse)) {
+                inverse.mapRect(&r);
+                r.roundOut(&fClipRect);
+            }
+        } else {
+            context->getClip().getBounds().roundOut(&fClipRect);
         }
+    } else {
+        fClipRect.setLargest();
     }
 
     // save the context's original matrix off and restore in destructor
diff --git a/gpu/src/gr_files.mk b/gpu/src/gr_files.mk
index 88aa84b..d0f41e7 100644
--- a/gpu/src/gr_files.mk
+++ b/gpu/src/gr_files.mk
@@ -22,4 +22,5 @@
     GrTextContext.cpp \
     GrTextStrike.cpp \
     GrBufferAllocPool.cpp\
-    GrPathRenderer.cpp
+    GrPathRenderer.cpp \
+    GrStencil.cpp
diff --git a/gpu/src/gr_unittests.cpp b/gpu/src/gr_unittests.cpp
index 8ef61b1..9caaa1f 100644
--- a/gpu/src/gr_unittests.cpp
+++ b/gpu/src/gr_unittests.cpp
@@ -73,71 +73,9 @@
     }
 }
 
-static void dump(const GrClip& clip, const char message[]) {
-    GrPrintf("--- dump clip %s\n", message);
-    GrClipIter iter(clip);
-    while (!iter.isDone()) {
-        GrIRect r;
-        iter.getRect(&r);
-        GrPrintf("--- [%d %d %d %d]\n", r.fLeft, r.fTop, r.fRight, r.fBottom);
-        iter.next();
-    }
-}
-
-static void test_clip() {
-    GrClip  clip;
-    GrAssert(clip.isEmpty());
-    GrAssert(!clip.isRect());
-    GrAssert(!clip.isComplex());
-    GrAssert(clip.getBounds().equalsLTRB(0, 0, 0, 0));
-    GrAssert(0 == clip.countRects());
-
-    clip.setRect(GrIRect(10, 10, 10, 10));
-    GrAssert(clip.isEmpty());
-    GrAssert(!clip.isRect());
-    GrAssert(!clip.isComplex());
-    GrAssert(clip.getBounds().equalsLTRB(0, 0, 0, 0));
-    GrAssert(0 == clip.countRects());
-    dump(clip, "empty");
-
-    clip.setRect(GrIRect(10, 10, 20, 20));
-    GrAssert(!clip.isEmpty());
-    GrAssert(clip.isRect());
-    GrAssert(!clip.isComplex());
-    GrAssert(clip.getBounds().equalsLTRB(10, 10, 20, 20));
-    GrAssert(1 == clip.countRects());
-    GrAssert(clip.getRects()[0] == clip.getBounds());
-    dump(clip, "rect");
-
-    clip.addRect(GrIRect(20, 20, 25, 25));
-    GrAssert(!clip.isEmpty());
-    GrAssert(!clip.isRect());
-    GrAssert(clip.isComplex());
-    GrAssert(clip.getBounds().equalsLTRB(10, 10, 25, 25));
-    GrAssert(2 == clip.countRects());
-    dump(clip, "complex");
-
-    GrClip c1(clip);
-    GrAssert(c1 == clip);
-    GrClip c2;
-    GrAssert(c2 != c1);
-    c2 = clip;
-    GrAssert(c2 == clip);
-
-    clip.setEmpty();
-    GrAssert(clip.isEmpty());
-    GrAssert(!clip.isRect());
-    GrAssert(!clip.isComplex());
-    GrAssert(clip.getBounds().equalsLTRB(0, 0, 0, 0));
-
-    GrAssert(c1 != clip);
-    GrAssert(c2 != clip);
-}
-
 void gr_run_unittests() {
     test_tdarray();
     test_bsearch();
-    test_clip();
     GrMatrix::UnitTest();
     GrRedBlackTree<int>::UnitTest();
 }
diff --git a/include/core/SkCanvas.h b/include/core/SkCanvas.h
index 1e15307..eef3aea 100644
--- a/include/core/SkCanvas.h
+++ b/include/core/SkCanvas.h
@@ -794,7 +794,8 @@
     SkDevice*   fLastDeviceToGainFocus;
     SkDeviceFactory* fDeviceFactory;
 
-    void prepareForDeviceDraw(SkDevice*, const SkMatrix&, const SkRegion&);
+    void prepareForDeviceDraw(SkDevice*, const SkMatrix&, const SkRegion&,
+                              const SkClipStack& clipStack);
 
     bool fDeviceCMDirty;            // cleared by updateDeviceCMCache()
     void updateDeviceCMCache();
diff --git a/include/core/SkClipStack.h b/include/core/SkClipStack.h
index fb94155..db42e4d 100644
--- a/include/core/SkClipStack.h
+++ b/include/core/SkClipStack.h
@@ -29,6 +29,11 @@
 
     class B2FIter {
     public:
+        /**
+         * Creates an uninitialized iterator. Must be reset()
+         */
+        B2FIter();
+
         B2FIter(const SkClipStack& stack);
 
         struct Clip {
@@ -48,6 +53,11 @@
          */
         const Clip* next();
 
+        /**
+         * Restarts the iterator on a clip stack.
+         */
+        void reset(const SkClipStack& stack);
+
     private:
         Clip             fClip;
         SkDeque::F2BIter fIter;
diff --git a/include/core/SkDeque.h b/include/core/SkDeque.h
index 99c8dd4..92d5153 100644
--- a/include/core/SkDeque.h
+++ b/include/core/SkDeque.h
@@ -52,9 +52,16 @@
 public:
     class F2BIter {
     public:
+        /**
+         * Creates an uninitialized iterator. Must be reset()
+         */
+        F2BIter();
+
         F2BIter(const SkDeque& d);
         void* next();
 
+        void reset(const SkDeque& d);
+
     private:
         SkDeque::Head*  fHead;
         char*           fPos;
diff --git a/include/core/SkDevice.h b/include/core/SkDevice.h
index a790399..c0d71c3 100644
--- a/include/core/SkDevice.h
+++ b/include/core/SkDevice.h
@@ -141,7 +141,8 @@
     /** Called when this device gains focus (i.e becomes the current device
         for drawing).
     */
-    virtual void gainFocus(SkCanvas*, const SkMatrix&, const SkRegion&) {}
+    virtual void gainFocus(SkCanvas*, const SkMatrix&, const SkRegion&,
+                           const SkClipStack&) {}
 
     /** Causes any deferred drawing to the device to be completed.
      */
diff --git a/include/core/SkRegion.h b/include/core/SkRegion.h
index 8d9ff01..58f4f3f 100644
--- a/include/core/SkRegion.h
+++ b/include/core/SkRegion.h
@@ -260,7 +260,7 @@
         bool rewind();
         // reset the iterator, using the new region
         void reset(const SkRegion&);
-        bool done() { return fDone; }
+        bool done() const { return fDone; }
         void next();
         const SkIRect& rect() const { return fRect; }
         // may return null
diff --git a/include/gpu/SkGpuDevice.h b/include/gpu/SkGpuDevice.h
index 2db3380..3fed99a 100644
--- a/include/gpu/SkGpuDevice.h
+++ b/include/gpu/SkGpuDevice.h
@@ -68,7 +68,8 @@
      *  Override from SkGpuDevice, so we can set our FBO to be the render target
      *  The canvas parameter must be a SkGpuCanvas
      */
-    virtual void gainFocus(SkCanvas*, const SkMatrix&, const SkRegion&);
+    virtual void gainFocus(SkCanvas*, const SkMatrix&, const SkRegion&,
+                           const SkClipStack& clipStack);
 
     virtual SkGpuTexture* accessTexture() { return (SkGpuTexture*)fTexture; }
 
diff --git a/include/gpu/SkGr.h b/include/gpu/SkGr.h
index ccdd400..d6a3fab 100644
--- a/include/gpu/SkGr.h
+++ b/include/gpu/SkGr.h
@@ -20,7 +20,7 @@
 
 #include <stddef.h>
 
-// tetrark headers
+// Gr headers
 #include "GrConfig.h"
 #include "GrContext.h"
 #include "GrFontScaler.h"
@@ -33,6 +33,7 @@
 #include "SkPoint.h"
 #include "SkRegion.h"
 #include "SkShader.h"
+#include "SkClipStack.h"
 
 #if (GR_DEBUG && defined(SK_RELEASE)) || (GR_RELEASE && defined(SK_DEBUG))
 //    #error "inconsistent GR_DEBUG and SK_DEBUG"
@@ -170,39 +171,99 @@
 
 class SkGrPathIter : public GrPathIter {
 public:
-    SkGrPathIter(const SkPath& path) : fIter(path, false), fPath(path) {}
+    SkGrPathIter() { fPath = NULL; }
+    SkGrPathIter(const SkPath& path) { reset(path); }
     virtual Command next(GrPoint pts[]);
     virtual Command next();
     virtual void rewind();
     virtual ConvexHint hint() const;
+
+    void reset(const SkPath& path) {
+        fPath = &path;
+        fIter.setPath(path, false);
+    }
 private:
 
 #if !SK_SCALAR_IS_GR_SCALAR
     SkPoint             fPoints[4];
 #endif
     SkPath::Iter        fIter;
-    const SkPath&       fPath;
+    const SkPath*       fPath;
 };
 
 class SkGrClipIterator : public GrClipIterator {
 public:
-    void reset(const SkRegion& clip) {
-        fIter.reset(clip);
-        this->invalidateBoundsCache();
+    SkGrClipIterator() { fClipStack = NULL;  fCurr = NULL; }
+    SkGrClipIterator(const SkClipStack& clipStack) { this->reset(clipStack); }
+
+    void reset(const SkClipStack& clipStack);
+
+    // overrides
+    virtual bool isDone() const { return NULL == fCurr; }
+    virtual void next() { fCurr = fIter.next(); }
+    virtual void rewind() { this->reset(*fClipStack); }
+    virtual GrClipType getType() const;
+
+    virtual GrSetOp getOp() const;
+
+    virtual void getRect(GrRect* rect) const {
+        *rect = Sk2Gr(*fCurr->fRect);
+    }
+
+    virtual GrPathIter* getPathIter() {
+        fPathIter.reset(*fCurr->fPath);
+        return &fPathIter;
+    }
+
+    virtual GrPathFill getPathFill() const;
+
+private:
+    const SkClipStack*                  fClipStack;
+    SkClipStack::B2FIter                fIter;
+    SkGrPathIter                        fPathIter;
+    // SkClipStack's auto advances on each get
+    // so we store the current pos here.
+    const SkClipStack::B2FIter::Clip*   fCurr;
+};
+
+class SkGrRegionIterator : public GrClipIterator {
+public:
+    SkGrRegionIterator() {}
+    SkGrRegionIterator(const SkRegion& region) { this->reset(region); }
+
+    void reset(const SkRegion& region) { 
+        fRegion = &region;
+        fIter.reset(region);
     }
 
     // overrides
-
-    virtual bool isDone() { return fIter.done(); }
-    virtual void getRect(GrIRect* rect) {
-        SkGr::SetIRect(rect, fIter.rect());
-    }
+    virtual bool isDone() const { return fIter.done(); }
     virtual void next() { fIter.next(); }
-    virtual void rewind() { fIter.rewind(); }
-    virtual void computeBounds(GrIRect* bounds);
+    virtual void rewind() { this->reset(*fRegion); }
+    virtual GrClipType getType() const { return kRect_ClipType; }
 
+    virtual GrSetOp getOp() const { return kUnion_SetOp; }
+
+    virtual void getRect(GrRect* rect) const {
+        const SkIRect& r = fIter.rect();
+        rect->fLeft   = GrIntToScalar(r.fLeft);
+        rect->fTop    = GrIntToScalar(r.fTop);
+        rect->fRight  = GrIntToScalar(r.fRight);
+        rect->fBottom = GrIntToScalar(r.fBottom);
+    }
+
+    virtual GrPathIter* getPathIter() {
+        SkASSERT(0);
+        return NULL;
+    }
+
+    virtual GrPathFill getPathFill() const {
+        SkASSERT(0);
+        return kWinding_PathFill;
+    }
 private:
-    SkRegion::Iterator fIter;
+    const SkRegion*     fRegion;
+    SkRegion::Iterator  fIter;
 };
 
 class SkGlyphCache;
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index e2d6af4..e636d2b 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -264,7 +264,7 @@
             }
             // fCurrLayer may be NULL now
 
-            fCanvas->prepareForDeviceDraw(fDevice, *fMatrix, *fClip);
+            fCanvas->prepareForDeviceDraw(fDevice, *fMatrix, *fClip, *fClipStack);
             return true;
         }
         return false;
@@ -632,10 +632,11 @@
 }
 
 void SkCanvas::prepareForDeviceDraw(SkDevice* device, const SkMatrix& matrix,
-                                    const SkRegion& clip) {
+                                    const SkRegion& clip,
+                                    const SkClipStack& clipStack) {
     SkASSERT(device);
     if (fLastDeviceToGainFocus != device) {
-        device->gainFocus(this, matrix, clip);
+        device->gainFocus(this, matrix, clip, clipStack);
         fLastDeviceToGainFocus = device;
     }
 }
diff --git a/src/core/SkClipStack.cpp b/src/core/SkClipStack.cpp
index 2b63aea..864f23a 100644
--- a/src/core/SkClipStack.cpp
+++ b/src/core/SkClipStack.cpp
@@ -116,7 +116,11 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-SkClipStack::B2FIter::B2FIter(const SkClipStack& stack) : fIter(stack.fDeque) {
+SkClipStack::B2FIter::B2FIter() {
+}
+
+SkClipStack::B2FIter::B2FIter(const SkClipStack& stack) {
+    this->reset(stack);
 }
 
 const SkClipStack::B2FIter::Clip* SkClipStack::B2FIter::next() {
@@ -142,3 +146,7 @@
     fClip.fOp = rec->fOp;
     return &fClip;
 }
+
+void SkClipStack::B2FIter::reset(const SkClipStack& stack) {
+    fIter.reset(stack.fDeque);
+}
diff --git a/src/core/SkDeque.cpp b/src/core/SkDeque.cpp
index 2c6ce64..9d685ee 100644
--- a/src/core/SkDeque.cpp
+++ b/src/core/SkDeque.cpp
@@ -225,12 +225,12 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-SkDeque::F2BIter::F2BIter(const SkDeque& d) : fElemSize(d.fElemSize) {
-    fHead = d.fFront;
-    while (fHead != NULL && fHead->fBegin == NULL) {
-        fHead = fHead->fNext;
-    }
-    fPos = fHead ? fHead->fBegin : NULL;
+SkDeque::F2BIter::F2BIter() {
+    fPos = NULL;
+}
+
+SkDeque::F2BIter::F2BIter(const SkDeque& d) {
+    this->reset(d);
 }
 
 void* SkDeque::F2BIter::next() {
@@ -250,3 +250,11 @@
     return pos;
 }
 
+void SkDeque::F2BIter::reset(const SkDeque& d) {
+    fElemSize = d.fElemSize;
+    fHead = d.fFront;
+    while (fHead != NULL && fHead->fBegin == NULL) {
+        fHead = fHead->fNext;
+    }
+    fPos = fHead ? fHead->fBegin : NULL;
+}
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index 3dfe02a..e925e53 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -267,19 +267,30 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
+#define USE_CLIP_STACK 0
+
 static void convert_matrixclip(GrContext* context, const SkMatrix& matrix,
-                               const SkRegion& clip) {
+                               const SkClipStack& clipStack,
+                               const SkRegion& clipRegion) {
     GrMatrix grmat;
     SkGr::SkMatrix2GrMatrix(matrix, &grmat);
     context->setMatrix(grmat);
 
+#if USE_CLIP_STACK
     SkGrClipIterator iter;
-    iter.reset(clip);
-    GrClip grc(&iter);
-    if (context->getClip() == grc) {
-    } else {
-        context->setClip(grc);
-    }
+    iter.reset(clipStack);
+#else
+    SkGrRegionIterator iter;
+    iter.reset(clipRegion);
+#endif
+    const SkIRect& skBounds = clipRegion.getBounds();
+    GrRect bounds;
+    bounds.setLTRB(GrIntToScalar(skBounds.fLeft),
+                   GrIntToScalar(skBounds.fTop),
+                   GrIntToScalar(skBounds.fRight),
+                   GrIntToScalar(skBounds.fBottom));
+    GrClip grc(&iter, NULL);
+    context->setClip(grc);
 }
 
 // call this ever each draw call, to ensure that the context reflects our state,
@@ -289,7 +300,9 @@
         fContext->getRenderTarget() != fRenderTarget) {
 
         fContext->setRenderTarget(fRenderTarget);
-        convert_matrixclip(fContext, *draw.fMatrix, *draw.fClip);
+        SkASSERT(draw.fClipStack);
+        convert_matrixclip(fContext, *draw.fMatrix,
+                           *draw.fClipStack, *draw.fClip);
         fNeedPrepareRenderTarget = false;
     }
 }
@@ -298,16 +311,17 @@
                                 const SkClipStack& clipStack) {
     this->INHERITED::setMatrixClip(matrix, clip, clipStack);
 
-    convert_matrixclip(fContext, matrix, clip);
+    convert_matrixclip(fContext, matrix, clipStack, clip);
 }
 
 void SkGpuDevice::gainFocus(SkCanvas* canvas, const SkMatrix& matrix,
-                            const SkRegion& clip) {
+                            const SkRegion& clip, const SkClipStack& clipStack) {
+
     fContext->setRenderTarget(fRenderTarget);
 
-    this->INHERITED::gainFocus(canvas, matrix, clip);
+    this->INHERITED::gainFocus(canvas, matrix, clip, clipStack);
 
-    convert_matrixclip(fContext, matrix, clip);
+    convert_matrixclip(fContext, matrix, clipStack, clip);
 
     if (fNeedClear) {
         fContext->eraseColor(0x0);
diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp
index 41cf1bd..4c7bf6c 100644
--- a/src/gpu/SkGr.cpp
+++ b/src/gpu/SkGr.cpp
@@ -135,22 +135,80 @@
 }
 
 void SkGrPathIter::rewind() {
-    fIter.setPath(fPath, false);
+    fIter.setPath(*fPath, false);
 }
 
 GrPathIter::ConvexHint SkGrPathIter::hint() const {
-    return fPath.isConvex() ? GrPathIter::kConvex_ConvexHint :
-                              GrPathIter::kNone_ConvexHint;
+    return fPath->isConvex() ? GrPathIter::kConvex_ConvexHint :
+                               GrPathIter::kNone_ConvexHint;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 
-void SkGrClipIterator::computeBounds(GrIRect* bounds) {
-    const SkRegion* rgn = fIter.rgn();
-    if (rgn) {
-        SkGr::SetIRect(bounds, rgn->getBounds());
+void SkGrClipIterator::reset(const SkClipStack& clipStack) {
+    fClipStack = &clipStack;
+    fIter.reset(clipStack);
+    // Gr has no notion of replace, skip to the
+    // last replace in the clip stack.
+    int lastReplace = 0;
+    int curr = 0;
+    while (NULL != (fCurr = fIter.next())) {
+        if (SkRegion::kReplace_Op == fCurr->fOp) {
+            lastReplace = curr;
+        }
+        ++curr;
+    }
+    fIter.reset(clipStack);
+    for (int i = 0; i < lastReplace+1; ++i) {
+        fCurr = fIter.next();
+    }
+}
+
+GrClipType SkGrClipIterator::getType() const {
+    GrAssert(!this->isDone());
+    if (NULL != fCurr->fRect) {
+        return kRect_ClipType;
     } else {
-        bounds->setEmpty();
+        GrAssert(NULL != fCurr->fPath);
+        return kPath_ClipType;
+    }
+}
+
+GrSetOp SkGrClipIterator::getOp() const {
+    // we skipped to the last "replace" op
+    // when this iter was reset.
+    // GrClip doesn't allow replace, so treat it as
+    // intersect.
+    GrSetOp skToGrOps[] = {
+        kDifference_SetOp,         // kDifference_Op
+        kIntersect_SetOp,          // kIntersect_Op
+        kUnion_SetOp,              // kUnion_Op
+        kXor_SetOp,                // kXOR_Op
+        kReverseDifference_SetOp,  // kReverseDifference_Op
+        kIntersect_SetOp           // kReplace_op
+    };
+    GR_STATIC_ASSERT(0 == SkRegion::kDifference_Op);
+    GR_STATIC_ASSERT(1 == SkRegion::kIntersect_Op);
+    GR_STATIC_ASSERT(2 == SkRegion::kUnion_Op);
+    GR_STATIC_ASSERT(3 == SkRegion::kXOR_Op);
+    GR_STATIC_ASSERT(4 == SkRegion::kReverseDifference_Op);
+    GR_STATIC_ASSERT(5 == SkRegion::kReplace_Op);
+    return skToGrOps[fCurr->fOp];
+}
+
+GrPathFill SkGrClipIterator::getPathFill() const {
+    switch (fCurr->fPath->getFillType()) {
+        case SkPath::kWinding_FillType:
+            return kWinding_PathFill;
+        case SkPath::kEvenOdd_FillType:
+            return  kEvenOdd_PathFill;
+        case SkPath::kInverseWinding_FillType:
+            return kInverseWinding_PathFill;
+        case SkPath::kInverseEvenOdd_FillType:
+            return kInverseEvenOdd_PathFill;
+        default:
+            GrCrash("Unsupported path fill in clip.");
+            return kWinding_PathFill; // suppress warning
     }
 }
 
diff --git a/src/utils/mac/SkOSWindow_Mac.cpp b/src/utils/mac/SkOSWindow_Mac.cpp
index 7716185..05f97a7 100644
--- a/src/utils/mac/SkOSWindow_Mac.cpp
+++ b/src/utils/mac/SkOSWindow_Mac.cpp
@@ -531,7 +531,6 @@
 
 void SkOSWindow::presentGL() {
     aglSwapBuffers((AGLContext)fAGLCtx);
-    glFlush();
 }
 
 #endif
diff --git a/src/utils/win/SkOSWindow_Win.cpp b/src/utils/win/SkOSWindow_Win.cpp
index 3594c2f..96a026d 100644
--- a/src/utils/win/SkOSWindow_Win.cpp
+++ b/src/utils/win/SkOSWindow_Win.cpp
@@ -444,10 +444,6 @@
         }
     }
     if (wglMakeCurrent(GetDC((HWND)fHWND), (HGLRC)fHGLRC)) {
-        glViewport(0, 0, this->width(), this->height());
-        glClearColor(0, 0, 0, 0);
-        glClearStencil(0);
-        glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
         fGLAttached = true;
         return true;
     }
@@ -462,9 +458,6 @@
 void SkOSWindow::presentGL() {
     glFlush();
     SwapBuffers(GetDC((HWND)fHWND));
-    glClearColor(0,0,0,0);
-    glClearStencil(0);
-    glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
 }
 
 IDirect3DDevice9* create_d3d9_device(HWND hwnd) {
diff --git a/vs/SampleApp/SampleApp.vcxproj b/vs/SampleApp/SampleApp.vcxproj
index 8c6fe83..8de34d0 100644
--- a/vs/SampleApp/SampleApp.vcxproj
+++ b/vs/SampleApp/SampleApp.vcxproj
@@ -133,6 +133,7 @@
     <ClInclude Include="..\..\gpu\include\GrRefCnt.h" />

     <ClInclude Include="..\..\gpu\include\GrSamplerState.h" />

     <ClInclude Include="..\..\gpu\include\GrScalar.h" />

+    <ClInclude Include="..\..\gpu\include\GrStencil.h" />

     <ClInclude Include="..\..\gpu\include\GrStopwatch.h" />

     <ClInclude Include="..\..\gpu\include\GrStringBuilder.h" />

     <ClInclude Include="..\..\gpu\include\GrTArray.h" />

@@ -233,6 +234,7 @@
     <ClCompile Include="..\..\gpu\src\GrPath.cpp" />

     <ClCompile Include="..\..\gpu\src\GrPathRenderer.cpp" />

     <ClCompile Include="..\..\gpu\src\GrRectanizer.cpp" />

+    <ClCompile Include="..\..\gpu\src\GrStencil.cpp" />

     <ClCompile Include="..\..\gpu\src\GrTextContext.cpp" />

     <ClCompile Include="..\..\gpu\src\GrTextStrike.cpp" />

     <ClCompile Include="..\..\gpu\src\GrTextureCache.cpp" />

@@ -246,6 +248,7 @@
     <ClCompile Include="..\..\samplecode\SampleBlur.cpp" />

     <ClCompile Include="..\..\samplecode\SampleCamera.cpp" />

     <ClCompile Include="..\..\samplecode\SampleCircle.cpp" />

+    <ClCompile Include="..\..\samplecode\SampleComplexClip.cpp" />

     <ClCompile Include="..\..\samplecode\SampleCull.cpp" />

     <ClCompile Include="..\..\samplecode\SampleDither.cpp" />

     <ClCompile Include="..\..\samplecode\SampleDitherBitmap.cpp" />

diff --git a/xcode/gpu/gpu.xcodeproj/project.pbxproj b/xcode/gpu/gpu.xcodeproj/project.pbxproj
index 58a6358..e891f26 100644
--- a/xcode/gpu/gpu.xcodeproj/project.pbxproj
+++ b/xcode/gpu/gpu.xcodeproj/project.pbxproj
@@ -90,6 +90,8 @@
 		00216E5E130F0B03009A2160 /* GrGLIRect.h in Headers */ = {isa = PBXBuildFile; fileRef = 00216E5D130F0B03009A2160 /* GrGLIRect.h */; };
 		D539049B12EA01E30025F3D6 /* GrContext_impl.h in Headers */ = {isa = PBXBuildFile; fileRef = D539049A12EA01E30025F3D6 /* GrContext_impl.h */; };
 		D53904A112EA026E0025F3D6 /* GrPaint.h in Headers */ = {isa = PBXBuildFile; fileRef = D53904A012EA026E0025F3D6 /* GrPaint.h */; };
+		D542EAAD131C87E90065FC9D /* GrStencil.h in Headers */ = {isa = PBXBuildFile; fileRef = D542EAAC131C87E90065FC9D /* GrStencil.h */; };
+		D5558AE3131EB9BB00C71009 /* GrStencil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D5558AE2131EB9BB00C71009 /* GrStencil.cpp */; };
 		D58CAF9A12E7212100CB9277 /* GrGLUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D58CAF9812E7212100CB9277 /* GrGLUtil.cpp */; };
 		D5ED886F1313F92C00B98D64 /* GrRedBlackTree.h in Headers */ = {isa = PBXBuildFile; fileRef = D5ED886E1313F92C00B98D64 /* GrRedBlackTree.h */; };
 		D5ED88EB13144FD600B98D64 /* GrPathRenderer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D5ED88E913144FD600B98D64 /* GrPathRenderer.cpp */; };
@@ -184,6 +186,8 @@
 		D2AAC046055464E500DB518D /* libgpu.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libgpu.a; sourceTree = BUILT_PRODUCTS_DIR; };
 		D539049A12EA01E30025F3D6 /* GrContext_impl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GrContext_impl.h; path = ../../gpu/include/GrContext_impl.h; sourceTree = SOURCE_ROOT; };
 		D53904A012EA026E0025F3D6 /* GrPaint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GrPaint.h; path = ../../gpu/include/GrPaint.h; sourceTree = SOURCE_ROOT; };
+		D542EAAC131C87E90065FC9D /* GrStencil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GrStencil.h; path = ../../gpu/include/GrStencil.h; sourceTree = SOURCE_ROOT; };
+		D5558AE2131EB9BB00C71009 /* GrStencil.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GrStencil.cpp; path = ../../gpu/src/GrStencil.cpp; sourceTree = SOURCE_ROOT; };
 		D58CAF9812E7212100CB9277 /* GrGLUtil.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GrGLUtil.cpp; path = ../../gpu/src/GrGLUtil.cpp; sourceTree = SOURCE_ROOT; };
 		D5ED886E1313F92C00B98D64 /* GrRedBlackTree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GrRedBlackTree.h; path = ../../gpu/src/GrRedBlackTree.h; sourceTree = SOURCE_ROOT; };
 		D5ED88E913144FD600B98D64 /* GrPathRenderer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GrPathRenderer.cpp; path = ../../gpu/src/GrPathRenderer.cpp; sourceTree = SOURCE_ROOT; };
@@ -263,6 +267,7 @@
 				00115E6D12C116CA008296FE /* GrUserConfig.h */,
 				00115E6E12C116CA008296FE /* GrVertexBuffer.h */,
 				D53904A012EA026E0025F3D6 /* GrPaint.h */,
+				D542EAAC131C87E90065FC9D /* GrStencil.h */,
 			);
 			name = include;
 			sourceTree = "<group>";
@@ -281,8 +286,6 @@
 		08FB7795FE84155DC02AAC07 /* Source */ = {
 			isa = PBXGroup;
 			children = (
-				D5ED88E913144FD600B98D64 /* GrPathRenderer.cpp */,
-				D5ED88EA13144FD600B98D64 /* GrPathRenderer.h */,
 				D5ED886E1313F92C00B98D64 /* GrRedBlackTree.h */,
 				D539049A12EA01E30025F3D6 /* GrContext_impl.h */,
 				00115DD812C1167A008296FE /* gr_unittests.cpp */,
@@ -308,8 +311,11 @@
 				00115DEE12C1167A008296FE /* GrMatrix.cpp */,
 				00115DEF12C1167A008296FE /* GrMemory.cpp */,
 				00115DF012C1167A008296FE /* GrPath.cpp */,
+				D5ED88EA13144FD600B98D64 /* GrPathRenderer.h */,
+				D5ED88E913144FD600B98D64 /* GrPathRenderer.cpp */,
 				00115DF412C1167A008296FE /* GrRectanizer_fifo.cpp */,
 				00115DF512C1167A008296FE /* GrRectanizer.cpp */,
+				D5558AE2131EB9BB00C71009 /* GrStencil.cpp */,
 				00115DF612C1167A008296FE /* GrTextContext.cpp */,
 				00115DF712C1167A008296FE /* GrTextStrike_impl.h */,
 				00115DF812C1167A008296FE /* GrTextStrike.cpp */,
@@ -405,6 +411,7 @@
 				00216E5E130F0B03009A2160 /* GrGLIRect.h in Headers */,
 				D5ED886F1313F92C00B98D64 /* GrRedBlackTree.h in Headers */,
 				D5ED88EC13144FD600B98D64 /* GrPathRenderer.h in Headers */,
+				D542EAAD131C87E90065FC9D /* GrStencil.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -483,6 +490,7 @@
 				D58CAF9A12E7212100CB9277 /* GrGLUtil.cpp in Sources */,
 				D5FAF22313072C27001550A4 /* GrBufferAllocPool.cpp in Sources */,
 				D5ED88EB13144FD600B98D64 /* GrPathRenderer.cpp in Sources */,
+				D5558AE3131EB9BB00C71009 /* GrStencil.cpp in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
diff --git a/xcode/sampleapp/SampleApp.xcodeproj/project.pbxproj b/xcode/sampleapp/SampleApp.xcodeproj/project.pbxproj
index 1a39d9a..2820546 100644
--- a/xcode/sampleapp/SampleApp.xcodeproj/project.pbxproj
+++ b/xcode/sampleapp/SampleApp.xcodeproj/project.pbxproj
@@ -30,7 +30,6 @@
 		0021F3A21120B29C0062682F /* SkStaticTextView.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0021F3A11120B29C0062682F /* SkStaticTextView.cpp */; };
 		0021F3D31120B61F0062682F /* SampleUnitMapper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00995E1510A079D80054AD6D /* SampleUnitMapper.cpp */; };
 		00244D1B10642BBA00B8F4D8 /* SampleStrokePath.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0009E21F1057E96800B0DE6F /* SampleStrokePath.cpp */; };
-		00244D97106A539500B8F4D8 /* SampleXfermodes.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 007A7CB20F01658C00A2D6EE /* SampleXfermodes.cpp */; };
 		00244DE2106A681600B8F4D8 /* SampleShaders.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 007A7CA80F01658C00A2D6EE /* SampleShaders.cpp */; };
 		00281C751083CF7E00BCCB06 /* libAnimator.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00281C711083CF6600BCCB06 /* libAnimator.a */; };
 		00281D071084ED1200BCCB06 /* SkXMLParser_expat.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00281D061084ED1200BCCB06 /* SkXMLParser_expat.cpp */; };
@@ -81,7 +80,6 @@
 		009F9D1A12C3EB2600C7FD4A /* SampleGM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 27C4625412BFB2F300DBB1F6 /* SampleGM.cpp */; };
 		00A728270FD43D0400D5051F /* SampleMovie.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2762F6760FCCCB01002BD8B4 /* SampleMovie.cpp */; };
 		00A7282F0FD43D3700D5051F /* SkMovie.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00A7282D0FD43D3700D5051F /* SkMovie.cpp */; };
-		00A7295D0FD8397600D5051F /* SampleAll.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2762F6740FCCCB01002BD8B4 /* SampleAll.cpp */; };
 		00AF787E0FE94433007F9650 /* SamplePath.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00003C640EFC22A8000FF73A /* SamplePath.cpp */; };
 		00AF9B18103CD5EB00CBBCB3 /* SampleDitherBitmap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00AF9B17103CD5EB00CBBCB3 /* SampleDitherBitmap.cpp */; };
 		00BB289B104781D00057BF7E /* SampleForth.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00BB289A104781D00057BF7E /* SampleForth.cpp */; };
@@ -148,10 +146,13 @@
 		8D0C4E8D0486CD37000505A6 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 0867D6AAFE840B52C02AAC07 /* InfoPlist.strings */; };
 		8D0C4E8E0486CD37000505A6 /* main.nib in Resources */ = {isa = PBXBuildFile; fileRef = 02345980000FD03B11CA0E72 /* main.nib */; };
 		8D0C4E920486CD37000505A6 /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 20286C33FDCF999611CA2CEA /* Carbon.framework */; };
+		D5558AEF131EBA1E00C71009 /* SampleComplexClip.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D5558AEE131EBA1E00C71009 /* SampleComplexClip.cpp */; };
+		D5558B29131EBC9C00C71009 /* SampleFillType.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0041CE270F00A12400695E8C /* SampleFillType.cpp */; };
 		D55BEE6712EF44B90055D6FD /* shadertext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D55BEE6612EF44B90055D6FD /* shadertext.cpp */; };
 		D5962B3A12EDFC7600B478DF /* SampleShaderText.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D5962B3812EDFC7600B478DF /* SampleShaderText.cpp */; };
 		D5A682D712E9CE8500CDDDC6 /* SamplePatch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0041CE340F00A12400695E8C /* SamplePatch.cpp */; };
-		D5F4A21F12E9D75300DE986A /* SampleFillType.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0041CE270F00A12400695E8C /* SampleFillType.cpp */; };
+		D5BF1C5A131D449500C4B94B /* SampleAll.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2762F6740FCCCB01002BD8B4 /* SampleAll.cpp */; };
+		D5BF1CFD131D500A00C4B94B /* SampleXfermodes.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 007A7CB20F01658C00A2D6EE /* SampleXfermodes.cpp */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXContainerItemProxy section */
@@ -414,6 +415,7 @@
 		4A9504CAFFE6A41611CA0CBA /* CoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreServices.framework; path = /System/Library/Frameworks/CoreServices.framework; sourceTree = "<absolute>"; };
 		8D0C4E960486CD37000505A6 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
 		8D0C4E970486CD37000505A6 /* CICarbonSample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = CICarbonSample.app; sourceTree = BUILT_PRODUCTS_DIR; };
+		D5558AEE131EBA1E00C71009 /* SampleComplexClip.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SampleComplexClip.cpp; path = ../../samplecode/SampleComplexClip.cpp; sourceTree = SOURCE_ROOT; };
 		D55BEE6612EF44B90055D6FD /* shadertext.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = shadertext.cpp; path = ../../gm/shadertext.cpp; sourceTree = SOURCE_ROOT; };
 		D5962B3812EDFC7600B478DF /* SampleShaderText.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SampleShaderText.cpp; path = ../../samplecode/SampleShaderText.cpp; sourceTree = SOURCE_ROOT; };
 /* End PBXFileReference section */
@@ -442,6 +444,7 @@
 		00003C610EFC2287000FF73A /* samples */ = {
 			isa = PBXGroup;
 			children = (
+				D5558AEE131EBA1E00C71009 /* SampleComplexClip.cpp */,
 				27C4625412BFB2F300DBB1F6 /* SampleGM.cpp */,
 				003EE651111239D5001AB759 /* SampleWarp.cpp */,
 				27A34E8B119892DD00860515 /* SampleTextBox.cpp */,
@@ -937,7 +940,6 @@
 				2762F66E0FCCCABE002BD8B4 /* SkPageFlipper.cpp in Sources */,
 				00A728270FD43D0400D5051F /* SampleMovie.cpp in Sources */,
 				00A7282F0FD43D3700D5051F /* SkMovie.cpp in Sources */,
-				00A7295D0FD8397600D5051F /* SampleAll.cpp in Sources */,
 				00AF787E0FE94433007F9650 /* SamplePath.cpp in Sources */,
 				005E92DC0FF08507008965B9 /* SampleFilter2.cpp in Sources */,
 				27005D16100903C100E275B6 /* SampleLines.cpp in Sources */,
@@ -950,7 +952,6 @@
 				00EB4593104DBB18002B413E /* ForthTests.cpp in Sources */,
 				009887F1106142FC0020D19B /* SampleNinePatch.cpp in Sources */,
 				00244D1B10642BBA00B8F4D8 /* SampleStrokePath.cpp in Sources */,
-				00244D97106A539500B8F4D8 /* SampleXfermodes.cpp in Sources */,
 				00244DE2106A681600B8F4D8 /* SampleShaders.cpp in Sources */,
 				00281D071084ED1200BCCB06 /* SkXMLParser_expat.cpp in Sources */,
 				009230D8109F111F00AD3F12 /* OverView.cpp in Sources */,
@@ -1027,9 +1028,12 @@
 				009F9D0A12C3E8AF00C7FD4A /* SampleFilter.cpp in Sources */,
 				009F9D1A12C3EB2600C7FD4A /* SampleGM.cpp in Sources */,
 				D5A682D712E9CE8500CDDDC6 /* SamplePatch.cpp in Sources */,
-				D5F4A21F12E9D75300DE986A /* SampleFillType.cpp in Sources */,
 				D5962B3A12EDFC7600B478DF /* SampleShaderText.cpp in Sources */,
 				D55BEE6712EF44B90055D6FD /* shadertext.cpp in Sources */,
+				D5BF1C5A131D449500C4B94B /* SampleAll.cpp in Sources */,
+				D5BF1CFD131D500A00C4B94B /* SampleXfermodes.cpp in Sources */,
+				D5558AEF131EBA1E00C71009 /* SampleComplexClip.cpp in Sources */,
+				D5558B29131EBC9C00C71009 /* SampleFillType.cpp in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};