Move clip off of draw target

BUG=skia:

Review URL: https://codereview.chromium.org/947443003
diff --git a/gm/beziereffects.cpp b/gm/beziereffects.cpp
index 578a597..45c6341 100644
--- a/gm/beziereffects.cpp
+++ b/gm/beziereffects.cpp
@@ -235,8 +235,8 @@
                     geometry.fColor = gp->color();
                     geometry.fBounds = bounds;
 
-                    SkAutoTUnref<GrBatch> batch(BezierCubicOrConicTestBatch::Create(gp, geometry, klmEqs,
-                                                                             klmSigns[c]));
+                    SkAutoTUnref<GrBatch> batch(
+                            BezierCubicOrConicTestBatch::Create(gp, geometry, klmEqs, klmSigns[c]));
 
                     tt.target()->drawBatch(&pipelineBuilder, batch, NULL);
                 }
@@ -379,8 +379,8 @@
                     geometry.fColor = gp->color();
                     geometry.fBounds = bounds;
 
-                    SkAutoTUnref<GrBatch> batch(BezierCubicOrConicTestBatch::Create(gp, geometry, klmEqs,
-                                                                             1.f));
+                    SkAutoTUnref<GrBatch> batch(
+                            BezierCubicOrConicTestBatch::Create(gp, geometry, klmEqs, 1.f));
 
                     tt.target()->drawBatch(&pipelineBuilder, batch, NULL);
                 }
diff --git a/gm/rrects.cpp b/gm/rrects.cpp
index 4b8e764..642376f 100644
--- a/gm/rrects.cpp
+++ b/gm/rrects.cpp
@@ -120,7 +120,9 @@
                             SkRect bounds = rrect.getBounds();
                             bounds.outset(2.f, 2.f);
 
-                            tt.target()->drawSimpleRect(&pipelineBuilder, 0xff000000, SkMatrix::I(),
+                            tt.target()->drawSimpleRect(&pipelineBuilder,
+                                                        0xff000000,
+                                                        SkMatrix::I(),
                                                         bounds);
                         } else {
                             drew = false;
diff --git a/gm/texturedomaineffect.cpp b/gm/texturedomaineffect.cpp
index d39375b..72a5839 100644
--- a/gm/texturedomaineffect.cpp
+++ b/gm/texturedomaineffect.cpp
@@ -130,7 +130,9 @@
                     pipelineBuilder.setRenderTarget(rt);
                     pipelineBuilder.addColorProcessor(fp);
 
-                    tt.target()->drawSimpleRect(&pipelineBuilder, GrColor_WHITE, viewMatrix,
+                    tt.target()->drawSimpleRect(&pipelineBuilder,
+                                                GrColor_WHITE,
+                                                viewMatrix,
                                                 renderRect);
                     x += renderRect.width() + kTestPad;
                 }
diff --git a/gm/yuvtorgbeffect.cpp b/gm/yuvtorgbeffect.cpp
index 37af5e6..4448265 100644
--- a/gm/yuvtorgbeffect.cpp
+++ b/gm/yuvtorgbeffect.cpp
@@ -123,7 +123,9 @@
                     GrPipelineBuilder pipelineBuilder;
                     pipelineBuilder.setRenderTarget(rt);
                     pipelineBuilder.addColorProcessor(fp);
-                    tt.target()->drawSimpleRect(&pipelineBuilder, GrColor_WHITE, viewMatrix,
+                    tt.target()->drawSimpleRect(&pipelineBuilder,
+                                                GrColor_WHITE,
+                                                viewMatrix,
                                                 renderRect);
                 }
                 x += renderRect.width() + kTestPad;
diff --git a/gyp/gpu.gypi b/gyp/gpu.gypi
index e17cb7a..79c60c1 100644
--- a/gyp/gpu.gypi
+++ b/gyp/gpu.gypi
@@ -8,7 +8,7 @@
 {
   'variables': {
     'skgpu_sources': [
-      '<(skia_include_path)/gpu/GrClipData.h',
+      '<(skia_include_path)/gpu/GrClip.h',
       '<(skia_include_path)/gpu/GrColor.h',
       '<(skia_include_path)/gpu/GrConfig.h',
       '<(skia_include_path)/gpu/GrContext.h',
@@ -66,7 +66,7 @@
       '<(skia_src_path)/gpu/GrBlend.h',
       '<(skia_src_path)/gpu/GrBufferAllocPool.cpp',
       '<(skia_src_path)/gpu/GrBufferAllocPool.h',
-      '<(skia_src_path)/gpu/GrClipData.cpp',
+      '<(skia_src_path)/gpu/GrClip.cpp',
       '<(skia_src_path)/gpu/GrClipMaskCache.h',
       '<(skia_src_path)/gpu/GrClipMaskCache.cpp',
       '<(skia_src_path)/gpu/GrClipMaskManager.h',
diff --git a/include/core/SkRect.h b/include/core/SkRect.h
index 06f8abe..69c2dc9 100644
--- a/include/core/SkRect.h
+++ b/include/core/SkRect.h
@@ -11,6 +11,8 @@
 #include "SkPoint.h"
 #include "SkSize.h"
 
+struct SkRect;
+
 /** \struct SkIRect
 
     SkIRect holds four 32 bit integer coordinates for a rectangle
@@ -244,6 +246,10 @@
                 fRight >= r.fRight && fBottom >= r.fBottom;
     }
 
+    /** Returns true if the specified rectangle r is inside or equal to this rectangle.
+    */
+    bool contains(const SkRect& r) const;
+
     /** Return true if this rectangle contains the specified rectangle.
         For speed, this method does not check if either this or the specified
         rectangles are empty, and if either is, its return value is undefined.
@@ -880,4 +886,10 @@
     void dumpHex() const { this->dump(true); }
 };
 
+inline bool SkIRect::contains(const SkRect& r) const {
+    return  !r.isEmpty() && !this->isEmpty() &&     // check for empties
+            (SkScalar)fLeft <= r.fLeft && (SkScalar)fTop <= r.fTop &&
+            (SkScalar)fRight >= r.fRight && (SkScalar)fBottom >= r.fBottom;
+}
+
 #endif
diff --git a/include/gpu/GrClip.h b/include/gpu/GrClip.h
new file mode 100644
index 0000000..f07a974
--- /dev/null
+++ b/include/gpu/GrClip.h
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrClip_DEFINED
+#define GrClip_DEFINED
+
+#include "SkClipStack.h"
+#include "GrSurface.h"
+
+struct SkIRect;
+
+/**
+ * GrClip encapsulates the information required to construct the clip
+ * masks. 'A GrClip is either wide open, just an IRect, just a Rect(TODO), or a full clipstack.
+ * If the clip is a clipstack than the origin is used to translate the stack with
+ * respect to device coordinates. This allows us to use a clip stack that is
+ * specified for a root device with a layer device that is restricted to a subset
+ * of the original canvas. For other clip types the origin will always be (0,0).
+ *
+ * NOTE: GrClip *must* point to a const clipstack
+ */
+class GrClip : SkNoncopyable {
+public:
+    GrClip() : fClipType(kWideOpen_ClipType) {}
+    GrClip(const SkIRect& rect) : fClipType(kIRect_ClipType) {
+        fClip.fIRect = rect;
+    }
+    ~GrClip() { this->reset(); }
+
+    const GrClip& operator=(const GrClip& other) {
+        this->reset();
+        fClipType = other.fClipType;
+        switch (other.fClipType) {
+            default:
+                SkFAIL("Incomplete Switch\n");
+            case kWideOpen_ClipType:
+                break;
+            case kClipStack_ClipType:
+                fClip.fClipStack.fStack = SkRef(other.clipStack());
+                fClip.fClipStack.fOrigin = other.origin();
+                break;
+            case kIRect_ClipType:
+                fClip.fIRect = other.irect();
+                break;
+        }
+        return *this;
+    }
+
+    bool operator==(const GrClip& other) const {
+        if (this->clipType() != other.clipType()) {
+            return false;
+        }
+
+        switch (fClipType) {
+            default:
+                SkFAIL("Incomplete Switch\n");
+                return false;
+            case kWideOpen_ClipType:
+                return true;
+            case kClipStack_ClipType:
+                if (this->origin() != other.origin()) {
+                    return false;
+                }
+
+                if (this->clipStack() && other.clipStack()) {
+                    return *this->clipStack() == *other.clipStack();
+                } else {
+                    return this->clipStack() == other.clipStack();
+                }
+                break;
+            case kIRect_ClipType:
+                return this->irect() == other.irect();
+                break;
+        }
+    }
+
+    bool operator!=(const GrClip& other) const {
+        return !(*this == other);
+    }
+
+    const SkClipStack* clipStack() const {
+        SkASSERT(kClipStack_ClipType == fClipType);
+        return fClip.fClipStack.fStack;
+    }
+
+    void setClipStack(const SkClipStack* clipStack, const SkIPoint* origin = NULL) {
+        if (clipStack->isWideOpen()) {
+            fClipType = kWideOpen_ClipType;
+        } else {
+            fClipType = kClipStack_ClipType;
+            fClip.fClipStack.fStack = SkRef(clipStack);
+            if (origin) {
+                fClip.fClipStack.fOrigin = *origin;
+            } else {
+                fClip.fClipStack.fOrigin.setZero();
+            }
+        }
+    }
+
+    const SkIRect& irect() const {
+        SkASSERT(kIRect_ClipType == fClipType);
+        return fClip.fIRect;
+    }
+
+    void reset() {
+        if (kClipStack_ClipType == fClipType) {
+            fClip.fClipStack.fStack->unref();
+            fClip.fClipStack.fStack = NULL;
+        }
+        fClipType = kWideOpen_ClipType;
+    }
+
+    const SkIPoint& origin() const {
+        SkASSERT(kClipStack_ClipType == fClipType);
+        return fClip.fClipStack.fOrigin;
+    }
+
+    bool isWideOpen(const SkRect& rect) const {
+        return (kWideOpen_ClipType == fClipType) ||
+               (kClipStack_ClipType == fClipType && this->clipStack()->isWideOpen()) ||
+               (kIRect_ClipType == fClipType && this->irect().contains(rect));
+    }
+
+    bool isWideOpen(const SkIRect& rect) const {
+        return (kWideOpen_ClipType == fClipType) ||
+               (kClipStack_ClipType == fClipType && this->clipStack()->isWideOpen()) ||
+               (kIRect_ClipType == fClipType && this->irect().contains(rect));
+    }
+
+    bool isWideOpen() const {
+        return (kWideOpen_ClipType == fClipType) ||
+               (kClipStack_ClipType == fClipType && this->clipStack()->isWideOpen());
+    }
+
+    void getConservativeBounds(const GrSurface* surface,
+                               SkIRect* devResult,
+                               bool* isIntersectionOfRects = NULL) const {
+        this->getConservativeBounds(surface->width(), surface->height(),
+                                    devResult, isIntersectionOfRects);
+    }
+
+    void getConservativeBounds(int width, int height,
+                               SkIRect* devResult,
+                               bool* isIntersectionOfRects = NULL) const;
+
+    static const GrClip& WideOpen() {
+        static GrClip clip;
+        return clip;
+    }
+
+    enum ClipType {
+        kClipStack_ClipType,
+        kWideOpen_ClipType,
+        kIRect_ClipType,
+    };
+
+    ClipType clipType() const { return fClipType; }
+
+private:
+    union Clip {
+        struct ClipStack {
+            const SkClipStack* fStack;
+            SkIPoint fOrigin;
+        } fClipStack;
+        SkIRect fIRect;
+    } fClip;
+
+    ClipType fClipType;
+};
+
+#endif
diff --git a/include/gpu/GrClipData.h b/include/gpu/GrClipData.h
deleted file mode 100644
index bb7101d..0000000
--- a/include/gpu/GrClipData.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright 2010 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef GrClip_DEFINED
-#define GrClip_DEFINED
-
-#include "SkClipStack.h"
-#include "GrSurface.h"
-
-struct SkIRect;
-
-/**
- * GrClipData encapsulates the information required to construct the clip
- * masks. 'fOrigin' is only non-zero when saveLayer has been called
- * with an offset bounding box. The clips in 'fClipStack' are in
- * device coordinates (i.e., they have been translated by -fOrigin w.r.t.
- * the canvas' device coordinates).
- */
-class GrClipData : SkNoncopyable {
-public:
-    SkAutoTUnref<const SkClipStack>  fClipStack;
-    SkIPoint                         fOrigin;
-
-    GrClipData()
-        : fClipStack(NULL) {
-        fOrigin.setZero();
-    }
-
-    bool operator==(const GrClipData& other) const {
-        if (fOrigin != other.fOrigin) {
-            return false;
-        }
-
-        if (fClipStack && other.fClipStack) {
-            return *fClipStack == *other.fClipStack;
-        }
-
-        return fClipStack == other.fClipStack;
-    }
-
-    bool operator!=(const GrClipData& other) const {
-        return !(*this == other);
-    }
-
-    void getConservativeBounds(const GrSurface* surface,
-                               SkIRect* devResult,
-                               bool* isIntersectionOfRects = NULL) const {
-        this->getConservativeBounds(surface->width(), surface->height(),
-                                    devResult, isIntersectionOfRects);
-    }
-
-    void getConservativeBounds(int width, int height,
-                               SkIRect* devResult,
-                               bool* isIntersectionOfRects = NULL) const;
-};
-
-#endif
diff --git a/include/gpu/GrContext.h b/include/gpu/GrContext.h
index 846cd0f..2433b89 100644
--- a/include/gpu/GrContext.h
+++ b/include/gpu/GrContext.h
@@ -8,7 +8,7 @@
 #ifndef GrContext_DEFINED
 #define GrContext_DEFINED
 
-#include "GrClipData.h"
+#include "GrClip.h"
 #include "GrColor.h"
 #include "GrPaint.h"
 #include "GrPathRendererChain.h"
@@ -367,13 +367,13 @@
      * Gets the current clip.
      * @return the current clip.
      */
-    const GrClipData* getClip() const { return fClip; }
+    const GrClip* getClip() const { return fClip; }
 
     /**
      * Sets the clip.
      * @param clipData  the clip to set.
      */
-    void setClip(const GrClipData* clipData) { fClip = clipData; }
+    void setClip(const GrClip* clipData) { fClip = clipData; }
 
     ///////////////////////////////////////////////////////////////////////////
     // Draws
@@ -680,7 +680,7 @@
         AutoClip(GrContext* context, InitialClip SkDEBUGCODE(initialState))
         : fContext(context) {
             SkASSERT(kWideOpen_InitialClip == initialState);
-            fNewClipData.fClipStack.reset(SkRef(&fNewClipStack));
+            fNewClipData.setClipStack(&fNewClipStack);
 
             fOldClip = context->getClip();
             context->setClip(&fNewClipData);
@@ -689,7 +689,7 @@
         AutoClip(GrContext* context, const SkRect& newClipRect)
         : fContext(context)
         , fNewClipStack(newClipRect) {
-            fNewClipData.fClipStack.reset(SkRef(&fNewClipStack));
+            fNewClipData.setClipStack(&fNewClipStack);
 
             fOldClip = fContext->getClip();
             fContext->setClip(&fNewClipData);
@@ -702,10 +702,10 @@
         }
     private:
         GrContext*        fContext;
-        const GrClipData* fOldClip;
+        const GrClip* fOldClip;
 
         SkClipStack       fNewClipStack;
-        GrClipData        fNewClipData;
+        GrClip        fNewClipData;
     };
 
     class AutoWideOpenIdentityDraw {
@@ -761,7 +761,7 @@
 
 private:
     GrGpu*                          fGpu;
-    const GrClipData*               fClip;  // TODO: make this ref counted
+    const GrClip*                   fClip;
 
     GrResourceCache*                fResourceCache;
     GrFontCache*                    fFontCache;
diff --git a/src/core/SkRect.cpp b/src/core/SkRect.cpp
index afd8bd8..ecf6fa2 100644
--- a/src/core/SkRect.cpp
+++ b/src/core/SkRect.cpp
@@ -6,7 +6,6 @@
  * found in the LICENSE file.
  */
 
-
 #include "SkRect.h"
 
 void SkIRect::join(int32_t left, int32_t top, int32_t right, int32_t bottom) {
diff --git a/src/gpu/GrAAHairLinePathRenderer.cpp b/src/gpu/GrAAHairLinePathRenderer.cpp
index c1d1291..57c3b5a 100644
--- a/src/gpu/GrAAHairLinePathRenderer.cpp
+++ b/src/gpu/GrAAHairLinePathRenderer.cpp
@@ -1028,7 +1028,8 @@
     }
 
     SkIRect devClipBounds;
-    target->getClip()->getConservativeBounds(pipelineBuilder->getRenderTarget(), &devClipBounds);
+    pipelineBuilder->clip().getConservativeBounds(pipelineBuilder->getRenderTarget(),
+                                                  &devClipBounds);
 
     // This outset was determined experimentally by running skps and gms.  It probably could be a
     // bit tighter
diff --git a/src/gpu/GrAARectRenderer.cpp b/src/gpu/GrAARectRenderer.cpp
index 2cc8f95..7c34c25 100644
--- a/src/gpu/GrAARectRenderer.cpp
+++ b/src/gpu/GrAARectRenderer.cpp
@@ -511,8 +511,7 @@
     }
 
     if (spare <= 0 && miterStroke) {
-        this->fillAARect(target, pipelineBuilder, color, viewMatrix, devOutside,
-                         devOutside);
+        this->fillAARect(target, pipelineBuilder, color, viewMatrix, devOutside, devOutside);
         return;
     }
 
@@ -877,8 +876,7 @@
     viewMatrix.mapPoints((SkPoint*)&devInside, (const SkPoint*)&rects[1], 2);
 
     if (devInside.isEmpty()) {
-        this->fillAARect(target, pipelineBuilder, color, viewMatrix, devOutside,
-                         devOutside);
+        this->fillAARect(target, pipelineBuilder, color, viewMatrix, devOutside, devOutside);
         return;
     }
 
diff --git a/src/gpu/GrAARectRenderer.h b/src/gpu/GrAARectRenderer.h
index 5a96f2c..25fa00c 100644
--- a/src/gpu/GrAARectRenderer.h
+++ b/src/gpu/GrAARectRenderer.h
@@ -14,10 +14,11 @@
 #include "SkRefCnt.h"
 #include "SkStrokeRec.h"
 
-class GrGpu;
-class GrPipelineBuilder;
+class GrClip;
 class GrDrawTarget;
+class GrGpu;
 class GrIndexBuffer;
+class GrPipelineBuilder;
 
 /*
  * This class wraps helper functions that draw AA rects (filled & stroked)
diff --git a/src/gpu/GrBitmapTextContext.cpp b/src/gpu/GrBitmapTextContext.cpp
index 55904e6..30c9205 100755
--- a/src/gpu/GrBitmapTextContext.cpp
+++ b/src/gpu/GrBitmapTextContext.cpp
@@ -553,7 +553,7 @@
 
     if (fCurrVertex > 0) {
         GrPipelineBuilder pipelineBuilder;
-        pipelineBuilder.setFromPaint(fPaint, fRenderTarget);
+        pipelineBuilder.setFromPaint(fPaint, fRenderTarget, fClip);
 
         // setup our sampler state for our text texture/atlas
         SkASSERT(SkIsAlign4(fCurrVertex));
diff --git a/src/gpu/GrClip.cpp b/src/gpu/GrClip.cpp
new file mode 100644
index 0000000..0f8aac8
--- /dev/null
+++ b/src/gpu/GrClip.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrClip.h"
+
+#include "GrSurface.h"
+#include "SkRect.h"
+
+///////////////////////////////////////////////////////////////////////////////
+
+/**
+ * getConservativeBounds returns the conservative bounding box of the clip
+ * in device (as opposed to canvas) coordinates. If the bounding box is
+ * the result of purely intersections of rects (with an initial replace)
+ * isIntersectionOfRects will be set to true.
+ */
+void GrClip::getConservativeBounds(int width, int height, SkIRect* devResult,
+                                   bool* isIntersectionOfRects) const {
+    switch (fClipType) {
+        default:
+            SkFAIL("incomplete switch\n");
+        case kWideOpen_ClipType: {
+            devResult->setLTRB(0, 0, width, height);
+            if (isIntersectionOfRects) {
+                *isIntersectionOfRects = true;
+            }
+        } break;
+        case kIRect_ClipType: {
+            *devResult = this->irect();
+            if (isIntersectionOfRects) {
+                *isIntersectionOfRects = true;
+            }
+        } break;
+        case kClipStack_ClipType: {
+            SkRect devBounds;
+            this->clipStack()->getConservativeBounds(-this->origin().fX,
+                                                     -this->origin().fY,
+                                                     width,
+                                                     height,
+                                                     &devBounds,
+                                                     isIntersectionOfRects);
+            devBounds.roundOut(devResult);
+        } break;
+
+    }
+}
diff --git a/src/gpu/GrClipData.cpp b/src/gpu/GrClipData.cpp
deleted file mode 100644
index 40bdec8..0000000
--- a/src/gpu/GrClipData.cpp
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright 2010 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "GrClipData.h"
-
-#include "GrSurface.h"
-#include "SkRect.h"
-
-///////////////////////////////////////////////////////////////////////////////
-
-/**
- * getConservativeBounds returns the conservative bounding box of the clip
- * in device (as opposed to canvas) coordinates. If the bounding box is
- * the result of purely intersections of rects (with an initial replace)
- * isIntersectionOfRects will be set to true.
- */
-void GrClipData::getConservativeBounds(int width, int height,
-                                       SkIRect* devResult,
-                                       bool* isIntersectionOfRects) const {
-    SkRect devBounds;
-
-    fClipStack->getConservativeBounds(-fOrigin.fX,
-                                      -fOrigin.fY,
-                                      width,
-                                      height,
-                                      &devBounds,
-                                      isIntersectionOfRects);
-
-    devBounds.roundOut(devResult);
-}
diff --git a/src/gpu/GrClipMaskManager.cpp b/src/gpu/GrClipMaskManager.cpp
index 22785cb..4d96125 100644
--- a/src/gpu/GrClipMaskManager.cpp
+++ b/src/gpu/GrClipMaskManager.cpp
@@ -209,7 +209,6 @@
                                       GrPipelineBuilder::AutoRestoreEffects* are,
                                       GrPipelineBuilder::AutoRestoreStencil* ars,
                                       GrScissorState* scissorState,
-                                      const GrClipData* clipDataIn,
                                       const SkRect* devBounds) {
     fCurrClipMaskType = kNone_ClipMaskType;
     if (kRespectClip_StencilClipMode == fClipMode) {
@@ -226,22 +225,35 @@
     // GrDrawTarget should have filtered this for us
     SkASSERT(rt);
 
-    bool ignoreClip = !pipelineBuilder->isClipState() || clipDataIn->fClipStack->isWideOpen();
+    SkIRect clipSpaceRTIBounds = SkIRect::MakeWH(rt->width(), rt->height());
+    const GrClip& clip = pipelineBuilder->clip();
+    // TODO we shouldn't be ignoring the clip mask manager's clip.  This is temporary.
+    bool ignoreClip = clip.isWideOpen(clipSpaceRTIBounds) ||
+                      GrClip::kIRect_ClipType == clip.clipType();
     if (!ignoreClip) {
-        SkIRect clipSpaceRTIBounds = SkIRect::MakeWH(rt->width(), rt->height());
-        clipSpaceRTIBounds.offset(clipDataIn->fOrigin);
-        GrReducedClip::ReduceClipStack(*clipDataIn->fClipStack,
-                                       clipSpaceRTIBounds,
-                                       &elements,
-                                       &genID,
-                                       &initialState,
-                                       &clipSpaceIBounds,
-                                       &requiresAA);
-        if (elements.isEmpty()) {
-            if (GrReducedClip::kAllIn_InitialState == initialState) {
-                ignoreClip = clipSpaceIBounds == clipSpaceRTIBounds;
-            } else {
-                return false;
+        // The clip mask manager always draws with a single IRect so we special case that logic here
+        if (GrClip::kIRect_ClipType == clip.clipType()) {
+            initialState = GrReducedClip::kAllIn_InitialState;
+            clipSpaceIBounds = clip.irect();
+            SkNEW_INSERT_AT_LLIST_HEAD(&elements,
+                                       Element,
+                                       (SkRect::Make(clipSpaceIBounds),
+                                        SkRegion::kIntersect_Op, false));
+        } else {
+            clipSpaceRTIBounds.offset(clip.origin());
+            GrReducedClip::ReduceClipStack(*clip.clipStack(),
+                                           clipSpaceRTIBounds,
+                                           &elements,
+                                           &genID,
+                                           &initialState,
+                                           &clipSpaceIBounds,
+                                           &requiresAA);
+            if (elements.isEmpty()) {
+                if (GrReducedClip::kAllIn_InitialState == initialState) {
+                    ignoreClip = clipSpaceIBounds == clipSpaceRTIBounds;
+                } else {
+                    return false;
+                }
             }
         }
     }
@@ -260,12 +272,12 @@
     // configuration's relative costs of switching RTs to generate a mask vs
     // longer shaders.
     if (elements.count() <= 4) {
-        SkVector clipToRTOffset = { SkIntToScalar(-clipDataIn->fOrigin.fX),
-                                    SkIntToScalar(-clipDataIn->fOrigin.fY) };
+        SkVector clipToRTOffset = { SkIntToScalar(-clip.origin().fX),
+                                    SkIntToScalar(-clip.origin().fY) };
         if (elements.isEmpty() ||
             this->installClipEffects(pipelineBuilder, are, elements, clipToRTOffset, devBounds)) {
             SkIRect scissorSpaceIBounds(clipSpaceIBounds);
-            scissorSpaceIBounds.offset(-clipDataIn->fOrigin);
+            scissorSpaceIBounds.offset(-clip.origin());
             if (NULL == devBounds ||
                 !SkRect::Make(scissorSpaceIBounds).contains(*devBounds)) {
                 scissorState->set(scissorSpaceIBounds);
@@ -305,7 +317,7 @@
             // The mask's top left coord should be pinned to the rounded-out top left corner of
             // clipSpace bounds. We determine the mask's position WRT to the render target here.
             SkIRect rtSpaceMaskBounds = clipSpaceIBounds;
-            rtSpaceMaskBounds.offset(-clipDataIn->fOrigin);
+            rtSpaceMaskBounds.offset(-clip.origin());
             setup_drawstate_aaclip(rtSpaceMaskBounds, pipelineBuilder, result);
             this->setPipelineBuilderStencil(pipelineBuilder, ars);
             return true;
@@ -321,7 +333,7 @@
     fAACache.reset();
 
     // use the stencil clip if we can't represent the clip as a rectangle.
-    SkIPoint clipSpaceToStencilSpaceOffset = -clipDataIn->fOrigin;
+    SkIPoint clipSpaceToStencilSpaceOffset = -clip.origin();
     this->createStencilClipMask(rt,
                                 genID,
                                 initialState,
@@ -458,7 +470,9 @@
                                       GrTextureDomain::kDecal_Mode,
                                       GrTextureParams::kNone_FilterMode))->unref();
     // The color passed in here does not matter since the coverageSetOpXP won't read it.
-    fClipTarget->drawSimpleRect(pipelineBuilder, GrColor_WHITE, SkMatrix::I(),
+    fClipTarget->drawSimpleRect(pipelineBuilder,
+                                GrColor_WHITE,
+                                SkMatrix::I(),
                                 SkRect::Make(dstBound));
 }
 
@@ -555,7 +569,7 @@
     // The second pass that zeros the stencil buffer renders the rect maskSpaceIBounds so the first
     // pass must not set values outside of this bounds or stencil values outside the rect won't be
     // cleared.
-    GrDrawTarget::AutoClipRestore acr(fClipTarget, maskSpaceIBounds);
+    GrClip clip(maskSpaceIBounds);
     SkAutoTUnref<GrTexture> temp;
 
     // walk through each clip element and perform its set op
@@ -566,6 +580,7 @@
         if (invert || SkRegion::kIntersect_Op == op || SkRegion::kReverseDifference_Op == op) {
             GrPipelineBuilder pipelineBuilder;
 
+            pipelineBuilder.setClip(clip);
             GrPathRenderer* pr = NULL;
             bool useTemp = !this->canStencilAndDrawElement(&pipelineBuilder, result, &pr, element);
             GrTexture* dst;
@@ -693,7 +708,7 @@
         // We set the current clip to the bounds so that our recursive draws are scissored to them.
         SkIRect stencilSpaceIBounds(clipSpaceIBounds);
         stencilSpaceIBounds.offset(clipSpaceToStencilOffset);
-        GrDrawTarget::AutoClipRestore acr(fClipTarget, stencilSpaceIBounds);
+        GrClip clip(stencilSpaceIBounds);
 
         int clipBit = stencilBuffer->bits();
         SkASSERT((clipBit <= 16) && "Ganesh only handles 16b or smaller stencil buffers");
@@ -709,6 +724,7 @@
             const Element* element = iter.get();
 
             GrPipelineBuilder pipelineBuilder;
+            pipelineBuilder.setClip(clip);
             pipelineBuilder.setRenderTarget(rt);
 
             pipelineBuilder.setDisableColorXPFactory();
@@ -780,18 +796,20 @@
                                              0xffff);
                 if (Element::kRect_Type == element->getType()) {
                     *pipelineBuilder.stencil() = gDrawToStencil;
-                    fClipTarget->drawSimpleRect(&pipelineBuilder, GrColor_WHITE, viewMatrix,
+                    fClipTarget->drawSimpleRect(&pipelineBuilder,
+                                                GrColor_WHITE,
+                                                viewMatrix,
                                                 element->getRect());
                 } else {
                     if (!clipPath.isEmpty()) {
                         GrDrawTarget::AutoGeometryPush agp(fClipTarget);
                         if (canRenderDirectToStencil) {
                             *pipelineBuilder.stencil() = gDrawToStencil;
-                            pr->drawPath(fClipTarget, &pipelineBuilder, GrColor_WHITE, viewMatrix,
-                                         clipPath, stroke, false);
+                            pr->drawPath(fClipTarget, &pipelineBuilder, GrColor_WHITE,
+                                         viewMatrix, clipPath, stroke, false);
                         } else {
-                            pr->stencilPath(fClipTarget, &pipelineBuilder, viewMatrix, clipPath,
-                                            stroke);
+                            pr->stencilPath(fClipTarget, &pipelineBuilder, viewMatrix,
+                                            clipPath, stroke);
                         }
                     }
                 }
@@ -806,17 +824,21 @@
 
                 if (canDrawDirectToClip) {
                     if (Element::kRect_Type == element->getType()) {
-                        fClipTarget->drawSimpleRect(&pipelineBuilderCopy, GrColor_WHITE, viewMatrix,
+                        fClipTarget->drawSimpleRect(&pipelineBuilderCopy,
+                                                    GrColor_WHITE,
+                                                    viewMatrix,
                                                     element->getRect());
                     } else {
                         GrDrawTarget::AutoGeometryPush agp(fClipTarget);
-                        pr->drawPath(fClipTarget, &pipelineBuilderCopy, GrColor_WHITE, viewMatrix,
-                                     clipPath, stroke, false);
+                        pr->drawPath(fClipTarget, &pipelineBuilderCopy, GrColor_WHITE,
+                                     viewMatrix, clipPath, stroke, false);
                     }
                 } else {
                     // The view matrix is setup to do clip space -> stencil space translation, so
                     // draw rect in clip space.
-                    fClipTarget->drawSimpleRect(&pipelineBuilderCopy, GrColor_WHITE, viewMatrix,
+                    fClipTarget->drawSimpleRect(&pipelineBuilderCopy,
+                                                GrColor_WHITE,
+                                                viewMatrix,
                                                 SkRect::Make(clipSpaceIBounds));
                 }
             }
diff --git a/src/gpu/GrClipMaskManager.h b/src/gpu/GrClipMaskManager.h
index 7fcfa50..0ab74a7 100644
--- a/src/gpu/GrClipMaskManager.h
+++ b/src/gpu/GrClipMaskManager.h
@@ -52,7 +52,6 @@
                        GrPipelineBuilder::AutoRestoreEffects*,
                        GrPipelineBuilder::AutoRestoreStencil*,
                        GrScissorState*,
-                       const GrClipData* clipDataIn,
                        const SkRect* devBounds);
 
     /**
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index c444b66..0395e1b 100755
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -414,7 +414,12 @@
         }
 
         GR_CREATE_TRACE_MARKER("GrContext::drawPaintWithPerspective", target);
-        target->drawRect(&pipelineBuilder, paint->getColor(), SkMatrix::I(), r, NULL, &localMatrix);
+        target->drawRect(&pipelineBuilder,
+                         paint->getColor(),
+                         SkMatrix::I(),
+                         r,
+                         NULL,
+                         &localMatrix);
     }
 }
 
@@ -524,14 +529,13 @@
         SkRect rtRect;
         pipelineBuilder.getRenderTarget()->getBoundsRect(&rtRect);
         SkRect clipSpaceRTRect = rtRect;
-        bool checkClip = false;
-        if (this->getClip()) {
-            checkClip = true;
-            clipSpaceRTRect.offset(SkIntToScalar(this->getClip()->fOrigin.fX),
-                                   SkIntToScalar(this->getClip()->fOrigin.fY));
+        bool checkClip = fClip && GrClip::kWideOpen_ClipType != fClip->clipType();
+        if (checkClip) {
+            clipSpaceRTRect.offset(SkIntToScalar(this->getClip()->origin().fX),
+                                   SkIntToScalar(this->getClip()->origin().fY));
         }
         // Does the clip contain the entire RT?
-        if (!checkClip || target->getClip()->fClipStack->quickContains(clipSpaceRTRect)) {
+        if (!checkClip || fClip->clipStack()->quickContains(clipSpaceRTRect)) {
             SkMatrix invM;
             if (!viewMatrix.invert(&invM)) {
                 return;
@@ -644,7 +648,11 @@
 
     GR_CREATE_TRACE_MARKER("GrContext::drawRectToRect", target);
 
-    target->drawRect(&pipelineBuilder, paint.getColor(), viewMatrix, rectToDraw, &localRect,
+    target->drawRect(&pipelineBuilder,
+                     paint.getColor(),
+                     viewMatrix,
+                     rectToDraw,
+                     &localRect,
                      localMatrix);
 }
 
@@ -762,8 +770,13 @@
     const SkStrokeRec& strokeRec = strokeInfo.getStrokeRec();
 
     GrColor color = paint.getColor();
-    if (!fOvalRenderer->drawRRect(target, &pipelineBuilder, color, viewMatrix, paint.isAntiAlias(),
-                                  rrect, strokeRec)) {
+    if (!fOvalRenderer->drawRRect(target,
+                                  &pipelineBuilder,
+                                  color,
+                                  viewMatrix,
+                                  paint.isAntiAlias(),
+                                  rrect,
+                                  strokeRec)) {
         SkPath path;
         path.addRRect(rrect);
         this->internalDrawPath(target, &pipelineBuilder, viewMatrix, color, paint.isAntiAlias(),
@@ -789,8 +802,13 @@
     GR_CREATE_TRACE_MARKER("GrContext::drawDRRect", target);
 
     GrColor color = paint.getColor();
-    if (!fOvalRenderer->drawDRRect(target, &pipelineBuilder, color, viewMatrix, paint.isAntiAlias(),
-                                   outer, inner)) {
+    if (!fOvalRenderer->drawDRRect(target,
+                                   &pipelineBuilder,
+                                   color,
+                                   viewMatrix,
+                                   paint.isAntiAlias(),
+                                   outer,
+                                   inner)) {
         SkPath path;
         path.addRRect(inner);
         path.addRRect(outer);
@@ -832,8 +850,13 @@
     const SkStrokeRec& strokeRec = strokeInfo.getStrokeRec();
 
     GrColor color = paint.getColor();
-    if (!fOvalRenderer->drawOval(target, &pipelineBuilder, color, viewMatrix, paint.isAntiAlias(),
-                                 oval, strokeRec)) {
+    if (!fOvalRenderer->drawOval(target,
+                                 &pipelineBuilder,
+                                 color,
+                                 viewMatrix,
+                                 paint.isAntiAlias(),
+                                 oval,
+                                 strokeRec)) {
         SkPath path;
         path.addOval(oval);
         this->internalDrawPath(target, &pipelineBuilder, viewMatrix, color, paint.isAntiAlias(),
@@ -962,7 +985,7 @@
         SkRect rects[2];
 
         if (is_nested_rects(target, &pipelineBuilder, color, viewMatrix, path, strokeRec, rects)) {
-            fAARectRenderer->fillAANestedRects(target, &pipelineBuilder, color, viewMatrix,rects);
+            fAARectRenderer->fillAANestedRects(target, &pipelineBuilder, color, viewMatrix, rects);
             return;
         }
     }
@@ -971,8 +994,13 @@
     bool isOval = path.isOval(&ovalRect);
 
     if (!isOval || path.isInverseFillType() ||
-        !fOvalRenderer->drawOval(target, &pipelineBuilder, color, viewMatrix, paint.isAntiAlias(),
-                                 ovalRect, strokeRec)) {
+        !fOvalRenderer->drawOval(target,
+                                 &pipelineBuilder,
+                                 color,
+                                 viewMatrix,
+                                 paint.isAntiAlias(),
+                                 ovalRect,
+                                 strokeRec)) {
         this->internalDrawPath(target, &pipelineBuilder, viewMatrix, color, paint.isAntiAlias(),
                                path, strokeInfo);
     }
@@ -1175,7 +1203,9 @@
         GrPipelineBuilder pipelineBuilder;
         pipelineBuilder.addColorProcessor(fp);
         pipelineBuilder.setRenderTarget(renderTarget);
-        drawTarget->drawSimpleRect(&pipelineBuilder, GrColor_WHITE, matrix,
+        drawTarget->drawSimpleRect(&pipelineBuilder,
+                                   GrColor_WHITE,
+                                   matrix,
                                    SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height)));
     }
 
@@ -1297,7 +1327,9 @@
 
                     pipelineBuilder.setRenderTarget(tempTexture->asRenderTarget());
                     SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
-                    fDrawBuffer->drawSimpleRect(&pipelineBuilder, GrColor_WHITE, SkMatrix::I(),
+                    fDrawBuffer->drawSimpleRect(&pipelineBuilder,
+                                                GrColor_WHITE,
+                                                SkMatrix::I(),
                                                 rect);
                     // we want to read back from the scratch's origin
                     left = 0;
@@ -1397,11 +1429,8 @@
     if (pipelineBuilder) {
         ASSERT_OWNED_RESOURCE(rt);
         SkASSERT(rt && paint && acf);
-        pipelineBuilder->setFromPaint(*paint, rt);
-        pipelineBuilder->setState(GrPipelineBuilder::kClip_StateBit,
-                                  fClip && !fClip->fClipStack->isWideOpen());
+        pipelineBuilder->setFromPaint(*paint, rt, fClip);
     }
-    fDrawBuffer->setClip(fClip);
     return fDrawBuffer;
 }
 
diff --git a/src/gpu/GrDistanceFieldTextContext.cpp b/src/gpu/GrDistanceFieldTextContext.cpp
index 4e8b160..d2b34e6 100755
--- a/src/gpu/GrDistanceFieldTextContext.cpp
+++ b/src/gpu/GrDistanceFieldTextContext.cpp
@@ -668,7 +668,7 @@
 
     if (fCurrVertex > 0) {
         GrPipelineBuilder pipelineBuilder;
-        pipelineBuilder.setFromPaint(fPaint, fRenderTarget);
+        pipelineBuilder.setFromPaint(fPaint, fRenderTarget, fClip);
 
         // setup our sampler state for our text texture/atlas
         SkASSERT(SkIsAlign4(fCurrVertex));
diff --git a/src/gpu/GrDrawTarget.cpp b/src/gpu/GrDrawTarget.cpp
index ee111a6..7d39c20 100644
--- a/src/gpu/GrDrawTarget.cpp
+++ b/src/gpu/GrDrawTarget.cpp
@@ -92,8 +92,7 @@
 #define DEBUG_INVAL_START_IDX -1
 
 GrDrawTarget::GrDrawTarget(GrContext* context)
-    : fClip(NULL)
-    , fContext(context)
+    : fContext(context)
     , fGpuTraceMarkerCount(0) {
     SkASSERT(context);
     GeometrySrcState& geoSrc = fGeoSrcStateStack.push_back();
@@ -124,14 +123,6 @@
     this->resetIndexSource();
 }
 
-void GrDrawTarget::setClip(const GrClipData* clip) {
-    fClip = clip;
-}
-
-const GrClipData* GrDrawTarget::getClip() const {
-    return fClip;
-}
-
 bool GrDrawTarget::reserveVertexSpace(size_t vertexSize,
                                       int vertexCount,
                                       void** vertices) {
@@ -395,9 +386,8 @@
         return true;
     }
     SkIRect copyRect;
-    const GrClipData* clip = this->getClip();
     GrRenderTarget* rt = pipelineBuilder.getRenderTarget();
-    clip->getConservativeBounds(rt, &copyRect);
+    pipelineBuilder.clip().getConservativeBounds(rt, &copyRect);
 
     if (drawBounds) {
         SkIRect drawIBounds;
@@ -879,15 +869,6 @@
     fIndices = NULL;
 }
 
-GrDrawTarget::AutoClipRestore::AutoClipRestore(GrDrawTarget* target, const SkIRect& newClip) {
-    fTarget = target;
-    fClip = fTarget->getClip();
-    fStack.init();
-    fStack.get()->clipDevRect(newClip, SkRegion::kReplace_Op);
-    fReplacementClip.fClipStack.reset(SkRef(fStack.get()));
-    target->setClip(&fReplacementClip);
-}
-
 namespace {
 // returns true if the read/written rect intersects the src/dst and false if not.
 bool clip_srcrect_and_dstpoint(const GrSurface* dst,
@@ -1295,6 +1276,5 @@
                                           are,
                                           ars,
                                           scissorState,
-                                          this->getClip(),
                                           devBounds);
 }
diff --git a/src/gpu/GrDrawTarget.h b/src/gpu/GrDrawTarget.h
index 2da63d8..662b7e0 100644
--- a/src/gpu/GrDrawTarget.h
+++ b/src/gpu/GrDrawTarget.h
@@ -8,7 +8,7 @@
 #ifndef GrDrawTarget_DEFINED
 #define GrDrawTarget_DEFINED
 
-#include "GrClipData.h"
+#include "GrClip.h"
 #include "GrClipMaskManager.h"
 #include "GrContext.h"
 #include "GrPathProcessor.h"
@@ -29,7 +29,7 @@
 #include "SkXfermode.h"
 
 class GrBatch;
-class GrClipData;
+class GrClip;
 class GrDrawTargetCaps;
 class GrPath;
 class GrPathRange;
@@ -55,23 +55,6 @@
     const GrDrawTargetCaps* caps() const { return fCaps.get(); }
 
     /**
-     * Sets the current clip to the region specified by clip. All draws will be
-     * clipped against this clip if kClip_StateBit is enabled.
-     *
-     * Setting the clip may (or may not) zero out the client's stencil bits.
-     *
-     * @param description of the clipping region
-     */
-    void setClip(const GrClipData* clip);
-
-    /**
-     * Gets the current clip.
-     *
-     * @return the clip.
-     */
-    const GrClipData* getClip() const;
-
-    /**
      * There are two types of "sources" of geometry (vertices and indices) for
      * draw calls made on the target. When performing an indexed draw, the
      * indices and vertices can use different source types. Once a source is
@@ -264,9 +247,7 @@
                         const SkRect* devBounds = NULL);
 
     // TODO devbounds should live on the batch
-    void drawBatch(GrPipelineBuilder*,
-                   GrBatch*,
-                   const SkRect* devBounds = NULL);
+    void drawBatch(GrPipelineBuilder*, GrBatch*, const SkRect* devBounds = NULL);
 
     /**
      * Draws path into the stencil buffer. The fill must be either even/odd or
@@ -475,27 +456,6 @@
 
     ////////////////////////////////////////////////////////////////////////////
 
-    class AutoClipRestore : public ::SkNoncopyable {
-    public:
-        AutoClipRestore(GrDrawTarget* target) {
-            fTarget = target;
-            fClip = fTarget->getClip();
-        }
-
-        AutoClipRestore(GrDrawTarget* target, const SkIRect& newClip);
-
-        ~AutoClipRestore() {
-            fTarget->setClip(fClip);
-        }
-    private:
-        GrDrawTarget*           fTarget;
-        const GrClipData*       fClip;
-        SkTLazy<SkClipStack>    fStack;
-        GrClipData              fReplacementClip;
-    };
-
-    ////////////////////////////////////////////////////////////////////////////
-
     /**
      * Saves the geometry src state at construction and restores in the destructor. It also saves
      * and then restores the vertex attrib state.
@@ -688,11 +648,12 @@
 
     struct PipelineInfo {
         PipelineInfo(GrPipelineBuilder* pipelineBuilder, GrScissorState* scissor,
-                     const GrPrimitiveProcessor* primProc, const SkRect* devBounds,
-                     GrDrawTarget* target);
+                     const GrPrimitiveProcessor* primProc,
+                     const SkRect* devBounds, GrDrawTarget* target);
 
         PipelineInfo(GrPipelineBuilder* pipelineBuilder, GrScissorState* scissor,
-                     const GrBatch* batch, const SkRect* devBounds, GrDrawTarget* target);
+                     const GrBatch* batch, const SkRect* devBounds,
+                     GrDrawTarget* target);
 
         bool willBlendWithDst(const GrPrimitiveProcessor* primProc) const {
             return fPipelineBuilder->willBlendWithDst(primProc);
@@ -838,7 +799,6 @@
         kPreallocGeoSrcStateStackCnt = 4,
     };
     SkSTArray<kPreallocGeoSrcStateStackCnt, GeometrySrcState, true> fGeoSrcStateStack;
-    const GrClipData*                                               fClip;
     // The context owns us, not vice-versa, so this ptr is not ref'ed by DrawTarget.
     GrContext*                                                      fContext;
     // To keep track that we always have at least as many debug marker adds as removes
diff --git a/src/gpu/GrPipelineBuilder.cpp b/src/gpu/GrPipelineBuilder.cpp
index 9117a1f..faa20b1 100644
--- a/src/gpu/GrPipelineBuilder.cpp
+++ b/src/gpu/GrPipelineBuilder.cpp
@@ -32,6 +32,7 @@
     fXPFactory.reset(SkRef(that.getXPFactory()));
     fColorStages = that.fColorStages;
     fCoverageStages = that.fCoverageStages;
+    fClip = that.fClip;
 
     fColorProcInfoValid = that.fColorProcInfoValid;
     fCoverageProcInfoValid = that.fCoverageProcInfoValid;
@@ -46,7 +47,7 @@
     return *this;
 }
 
-void GrPipelineBuilder::setFromPaint(const GrPaint& paint, GrRenderTarget* rt) {
+void GrPipelineBuilder::setFromPaint(const GrPaint& paint, GrRenderTarget* rt, const GrClip* clip) {
     SkASSERT(0 == fBlockEffectRemovalCnt || 0 == this->numFragmentStages());
 
     fColorStages.reset();
@@ -69,8 +70,9 @@
     fStencilSettings.setDisabled();
     fFlagBits = 0;
 
-    // Enable the clip bit
-    this->enableState(GrPipelineBuilder::kClip_StateBit);
+    if (clip) {
+        fClip = *clip;
+    }
 
     this->setState(GrPipelineBuilder::kDither_StateBit, paint.isDither());
     this->setState(GrPipelineBuilder::kHWAntialias_StateBit, paint.isAntiAlias());
diff --git a/src/gpu/GrPipelineBuilder.h b/src/gpu/GrPipelineBuilder.h
index 904d382..54b06db 100644
--- a/src/gpu/GrPipelineBuilder.h
+++ b/src/gpu/GrPipelineBuilder.h
@@ -10,6 +10,7 @@
 
 #include "GrBatch.h"
 #include "GrBlend.h"
+#include "GrClip.h"
 #include "GrDrawTargetCaps.h"
 #include "GrGpuResourceRef.h"
 #include "GrFragmentStage.h"
@@ -44,7 +45,7 @@
      * no GrPaint equivalents are set to default values with the exception of vertex attribute state
      * which is unmodified by this function and clipping which will be enabled.
      */
-    void setFromPaint(const GrPaint&, GrRenderTarget*);
+    void setFromPaint(const GrPaint&, GrRenderTarget*, const GrClip*);
 
     /// @}
 
@@ -293,15 +294,10 @@
          * the 3D API.
          */
         kHWAntialias_StateBit   = 0x02,
-        /**
-         * Draws will respect the clip, otherwise the clip is ignored.
-         */
-        kClip_StateBit          = 0x04,
 
-        kLast_StateBit = kClip_StateBit,
+        kLast_StateBit = kHWAntialias_StateBit,
     };
 
-    bool isClipState() const { return 0 != (fFlagBits & kClip_StateBit); }
     bool isDither() const { return 0 != (fFlagBits & kDither_StateBit); }
     bool isHWAntialias() const { return 0 != (fFlagBits & kHWAntialias_StateBit); }
 
@@ -389,6 +385,10 @@
         this->calcCoverageInvariantOutput(batch);
         return fCoverageProcInfo;
     }
+
+    void setClip(const GrClip& clip) { fClip = clip; }
+    const GrClip& clip() const { return fClip; }
+
 private:
     // Calculating invariant color / coverage information is expensive, so we partially cache the
     // results.
@@ -436,6 +436,7 @@
     mutable SkAutoTUnref<const GrXPFactory> fXPFactory;
     FragmentStageArray                      fColorStages;
     FragmentStageArray                      fCoverageStages;
+    GrClip                                  fClip;
 
     mutable GrProcOptInfo fColorProcInfo;
     mutable GrProcOptInfo fCoverageProcInfo;
diff --git a/src/gpu/GrSWMaskHelper.h b/src/gpu/GrSWMaskHelper.h
index c180971..a69e4be 100644
--- a/src/gpu/GrSWMaskHelper.h
+++ b/src/gpu/GrSWMaskHelper.h
@@ -18,6 +18,7 @@
 #include "SkTextureCompressor.h"
 #include "SkTypes.h"
 
+class GrClip;
 class GrContext;
 class GrTexture;
 class SkPath;
diff --git a/src/gpu/GrSoftwarePathRenderer.cpp b/src/gpu/GrSoftwarePathRenderer.cpp
index 364c214..466ad81 100644
--- a/src/gpu/GrSoftwarePathRenderer.cpp
+++ b/src/gpu/GrSoftwarePathRenderer.cpp
@@ -50,7 +50,7 @@
         return false;
     }
 
-    target->getClip()->getConservativeBounds(rt, devClipBounds);
+    pipelineBuilder->clip().getConservativeBounds(rt, devClipBounds);
 
     if (devClipBounds->isEmpty()) {
         *devPathBounds = SkIRect::MakeWH(rt->width(), rt->height());
@@ -127,8 +127,8 @@
     }
 
     SkIRect devPathBounds, devClipBounds;
-    if (!get_path_and_clip_bounds(target, pipelineBuilder, path, viewMatrix,
-                                  &devPathBounds, &devClipBounds)) {
+    if (!get_path_and_clip_bounds(target, pipelineBuilder, path, viewMatrix, &devPathBounds,
+                                  &devClipBounds)) {
         if (path.isInverseFillType()) {
             draw_around_inv_path(target, pipelineBuilder, color, viewMatrix, devClipBounds,
                                  devPathBounds);
diff --git a/src/gpu/GrStencilAndCoverTextContext.cpp b/src/gpu/GrStencilAndCoverTextContext.cpp
index 9c3ba6a..6dbfe9f 100644
--- a/src/gpu/GrStencilAndCoverTextContext.cpp
+++ b/src/gpu/GrStencilAndCoverTextContext.cpp
@@ -354,7 +354,7 @@
 
     fStateRestore.set(&fPipelineBuilder);
 
-    fPipelineBuilder.setFromPaint(fPaint, fRenderTarget);
+    fPipelineBuilder.setFromPaint(fPaint, fRenderTarget, fClip);
 
     GR_STATIC_CONST_SAME_STENCIL(kStencilPass,
                                  kZero_StencilOp,
diff --git a/src/gpu/GrStencilBuffer.h b/src/gpu/GrStencilBuffer.h
index 3788e61..0589935 100644
--- a/src/gpu/GrStencilBuffer.h
+++ b/src/gpu/GrStencilBuffer.h
@@ -10,7 +10,7 @@
 #ifndef GrStencilBuffer_DEFINED
 #define GrStencilBuffer_DEFINED
 
-#include "GrClipData.h"
+#include "GrClip.h"
 #include "GrGpuResource.h"
 
 class GrRenderTarget;
diff --git a/src/gpu/GrTest.cpp b/src/gpu/GrTest.cpp
index 85f0d14..cefd015 100644
--- a/src/gpu/GrTest.cpp
+++ b/src/gpu/GrTest.cpp
@@ -19,7 +19,6 @@
     fContext.reset(SkRef(ctx));
     fDrawTarget.reset(SkRef(target));
 
-    SkNEW_IN_TLAZY(&fACR, GrDrawTarget::AutoClipRestore, (target));
     SkNEW_IN_TLAZY(&fAGP, GrDrawTarget::AutoGeometryPush, (target));
 }
 
diff --git a/src/gpu/GrTest.h b/src/gpu/GrTest.h
index e63d11e..47122c5 100644
--- a/src/gpu/GrTest.h
+++ b/src/gpu/GrTest.h
@@ -24,7 +24,6 @@
     GrDrawTarget* target() { return fDrawTarget.get(); }
 
 private:
-    SkTLazy<GrDrawTarget::AutoClipRestore>  fACR;
     SkTLazy<GrDrawTarget::AutoGeometryPush> fAGP;
 
     SkAutoTUnref<GrDrawTarget>              fDrawTarget;
diff --git a/src/gpu/GrTextContext.cpp b/src/gpu/GrTextContext.cpp
index c909aac..895e977 100644
--- a/src/gpu/GrTextContext.cpp
+++ b/src/gpu/GrTextContext.cpp
@@ -22,11 +22,11 @@
 }
 
 void GrTextContext::init(GrRenderTarget* rt, const GrPaint& grPaint, const SkPaint& skPaint) {
-    const GrClipData* clipData = fContext->getClip();
+    fClip = fContext->getClip();
 
     fRenderTarget.reset(SkRef(rt));
 
-    clipData->getConservativeBounds(fRenderTarget->width(), fRenderTarget->height(), &fClipRect);
+    fClip->getConservativeBounds(fRenderTarget->width(), fRenderTarget->height(), &fClipRect);
 
     fDrawTarget = fContext->getTextTarget();
 
diff --git a/src/gpu/GrTextContext.h b/src/gpu/GrTextContext.h
index 5a84454..581ff64 100644
--- a/src/gpu/GrTextContext.h
+++ b/src/gpu/GrTextContext.h
@@ -8,6 +8,7 @@
 #ifndef GrTextContext_DEFINED
 #define GrTextContext_DEFINED
 
+#include "GrClip.h"
 #include "GrGlyph.h"
 #include "GrPaint.h"
 #include "SkDeviceProperties.h"
@@ -33,15 +34,16 @@
                      const SkPoint& offset);
 
 protected:
-    GrTextContext*               fFallbackTextContext;
-    GrContext*                   fContext;
-    SkDeviceProperties           fDeviceProperties;
+    GrTextContext*                 fFallbackTextContext;
+    GrContext*                     fContext;
+    SkDeviceProperties             fDeviceProperties;
 
-    SkAutoTUnref<GrRenderTarget> fRenderTarget;
-    GrDrawTarget*                fDrawTarget;
-    SkIRect                      fClipRect;
-    GrPaint                      fPaint;
-    SkPaint                      fSkPaint;
+    SkAutoTUnref<GrRenderTarget>   fRenderTarget;
+    const GrClip*                  fClip;
+    GrDrawTarget*                  fDrawTarget;
+    SkIRect                        fClipRect;
+    GrPaint                        fPaint;
+    SkPaint                        fSkPaint;
 
     GrTextContext(GrContext*, const SkDeviceProperties&);
 
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index ad63393..d384cd1 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -276,22 +276,23 @@
     INHERITED::onAttachToCanvas(canvas);
 
     // Canvas promises that this ptr is valid until onDetachFromCanvas is called
-    fClipData.fClipStack.reset(SkRef(canvas->getClipStack()));
+    fClipStack.reset(SkRef(canvas->getClipStack()));
 }
 
 void SkGpuDevice::onDetachFromCanvas() {
     INHERITED::onDetachFromCanvas();
-    fClipData.fClipStack.reset(NULL);
+    fClipData.reset();
+    fClipStack.reset(NULL);
 }
 
 // call this every draw call, to ensure that the context reflects our state,
 // and not the state from some other canvas/device
 void SkGpuDevice::prepareDraw(const SkDraw& draw) {
-    SkASSERT(fClipData.fClipStack);
+    SkASSERT(fClipStack.get());
 
-    SkASSERT(draw.fClipStack && draw.fClipStack == fClipData.fClipStack);
+    SkASSERT(draw.fClipStack && draw.fClipStack == fClipStack);
 
-    fClipData.fOrigin = this->getOrigin();
+    fClipData.setClipStack(fClipStack, &this->getOrigin());
 
     fContext->setClip(&fClipData);
 
@@ -909,7 +910,7 @@
                                        const SkBitmap& bitmap,
                                        const SkRect* srcRectPtr,
                                        SkIRect* clippedSrcIRect) {
-    const GrClipData* clip = context->getClip();
+    const GrClip* clip = context->getClip();
     clip->getConservativeBounds(rt, clippedSrcIRect, NULL);
     SkMatrix inv;
     if (!viewMatrix.invert(&inv)) {
diff --git a/src/gpu/SkGpuDevice.h b/src/gpu/SkGpuDevice.h
index cd2dcdc..a6cc4ef 100644
--- a/src/gpu/SkGpuDevice.h
+++ b/src/gpu/SkGpuDevice.h
@@ -133,15 +133,17 @@
                                           const SkMatrix*, const SkPaint*) SK_OVERRIDE;
 
 private:
-    GrContext*      fContext;
-    GrSkDrawProcs*  fDrawProcs;
-    GrClipData      fClipData;
-    GrTextContext*  fTextContext;
-    SkSurfaceProps  fSurfaceProps;
-    GrRenderTarget* fRenderTarget;
+    GrContext*                      fContext;
+    GrSkDrawProcs*                  fDrawProcs;
+    SkAutoTUnref<const SkClipStack> fClipStack;
+    SkIPoint                        fClipOrigin;
+    GrClip                          fClipData;
+    GrTextContext*                  fTextContext;
+    SkSurfaceProps                  fSurfaceProps;
+    GrRenderTarget*                 fRenderTarget;
     // remove when our clients don't rely on accessBitmap()
-    SkBitmap        fLegacyBitmap;
-    bool            fNeedClear;
+    SkBitmap                        fLegacyBitmap;
+    bool                            fNeedClear;
 
     SkGpuDevice(GrRenderTarget*, const SkSurfaceProps*, unsigned flags);
 
diff --git a/src/gpu/effects/GrDashingEffect.cpp b/src/gpu/effects/GrDashingEffect.cpp
index 0b84c2c..afeff43 100644
--- a/src/gpu/effects/GrDashingEffect.cpp
+++ b/src/gpu/effects/GrDashingEffect.cpp
@@ -513,8 +513,8 @@
     }
 
     target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
-    target->drawIndexedInstances(pipelineBuilder, gp, kTriangles_GrPrimitiveType,
-                                 totalRectCnt, 4, 6);
+    target->drawIndexedInstances(pipelineBuilder, gp, kTriangles_GrPrimitiveType, totalRectCnt,
+                                 4, 6);
     target->resetIndexSource();
     return true;
 }
diff --git a/src/gpu/effects/GrDashingEffect.h b/src/gpu/effects/GrDashingEffect.h
index b8cb826..26b016b 100644
--- a/src/gpu/effects/GrDashingEffect.h
+++ b/src/gpu/effects/GrDashingEffect.h
@@ -13,8 +13,9 @@
 #include "GrTypesPriv.h"
 #include "SkPathEffect.h"
 
-class GrGpu;
+class GrClip;
 class GrDrawTarget;
+class GrGpu;
 class GrPaint;
 class GrPipelineBuilder;
 class GrStrokeInfo;
diff --git a/tests/ClipCacheTest.cpp b/tests/ClipCacheTest.cpp
index 1e195cc..0e5fe1e 100644
--- a/tests/ClipCacheTest.cpp
+++ b/tests/ClipCacheTest.cpp
@@ -85,8 +85,8 @@
     REPORTER_ASSERT(reporter, isIntersectionOfRects);
 
     // wrap the SkClipStack in a GrClipData
-    GrClipData clipData;
-    clipData.fClipStack.reset(SkRef(&stack));
+    GrClip clipData;
+    clipData.setClipStack(&stack);
 
     SkIRect devGrClipDataBound;
     clipData.getConservativeBounds(texture,
diff --git a/tests/GLProgramsTest.cpp b/tests/GLProgramsTest.cpp
index aeb97c4..d96c56c 100644
--- a/tests/GLProgramsTest.cpp
+++ b/tests/GLProgramsTest.cpp
@@ -248,9 +248,8 @@
     stack.clipDevRect(screen, SkRegion::kReplace_Op, false);
 
     // wrap the SkClipStack in a GrClipData
-    GrClipData clipData;
-    clipData.fClipStack.reset(SkRef(&stack));
-    this->setClip(&clipData);
+    GrClip clip;
+    clip.setClipStack(&stack);
 
     SkRandom random;
     static const int NUM_TESTS = 512;
@@ -264,6 +263,7 @@
 
         GrPipelineBuilder pipelineBuilder;
         pipelineBuilder.setRenderTarget(rt.get());
+        pipelineBuilder.setClip(clip);
 
         // if path rendering we have to setup a couple of things like the draw type
         bool usePathRendering = gpu->glCaps().pathRenderingSupport() && random.nextBool();