Altered Ganesh's clip stack plumbing to pass down new GrClipData class

http://codereview.appspot.com/6454047/



git-svn-id: http://skia.googlecode.com/svn/trunk@4788 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/include/gpu/GrClip.h b/include/gpu/GrClip.h
index c802015..a017fe3 100644
--- a/include/gpu/GrClip.h
+++ b/include/gpu/GrClip.h
@@ -208,5 +208,40 @@
     };
     SkSTArray<kPreAllocElements, Element>   fList;
 };
+
+/**
+ * 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 : public SkNoncopyable {
+public:
+    const GrClip*       fClipStack;
+    SkIPoint            fOrigin;
+
+    GrClipData() 
+        : fClipStack(NULL) {
+        fOrigin.setZero();
+    }
+
+    bool operator==(const GrClipData& other) const {
+        if (fOrigin != other.fOrigin) {
+            return false;
+        }
+
+        if (NULL != fClipStack && NULL != other.fClipStack) {
+            return *fClipStack == *other.fClipStack;
+        }
+
+        return fClipStack == other.fClipStack;
+    }
+
+    bool operator!=(const GrClipData& other) const { 
+        return !(*this == other); 
+    }
+};
+
 #endif
 
diff --git a/include/gpu/GrContext.h b/include/gpu/GrContext.h
index e0f5827..2f05458 100644
--- a/include/gpu/GrContext.h
+++ b/include/gpu/GrContext.h
@@ -329,13 +329,13 @@
      * Gets the current clip.
      * @return the current clip.
      */
-    const GrClip& getClip() const;
+    const GrClipData* getClip() const;
 
     /**
      * Sets the clip.
-     * @param clip  the clip to set.
+     * @param clipData  the clip to set.
      */
-    void setClip(const GrClip& clip);
+    void setClip(const GrClipData* clipData);
 
     ///////////////////////////////////////////////////////////////////////////
     // Draws
@@ -694,9 +694,11 @@
     public:
         AutoClip(GrContext* context, const GrRect& newClipRect) 
         : fContext(context)
-        , fNewClip(newClipRect) {
+        , fNewClipStack(newClipRect) {
+            fNewClipData.fClipStack = &fNewClipStack;
+
             fOldClip = fContext->getClip();
-            fContext->setClip(fNewClip);
+            fContext->setClip(&fNewClipData);
         }
 
         ~AutoClip() {
@@ -705,9 +707,11 @@
             }
         }
     private:
-        GrContext*  fContext;
-        GrClip      fOldClip;
-        GrClip      fNewClip;
+        GrContext*        fContext;
+        const GrClipData* fOldClip;
+
+        GrClip            fNewClipStack;
+        GrClipData        fNewClipData;
     };
 
     ///////////////////////////////////////////////////////////////////////////
diff --git a/include/gpu/SkGpuDevice.h b/include/gpu/SkGpuDevice.h
index 4a62813..f576ae4 100644
--- a/include/gpu/SkGpuDevice.h
+++ b/include/gpu/SkGpuDevice.h
@@ -132,6 +132,8 @@
 
     // the clip stack - on loan to us from SkCanvas so it can be NULL.
     const SkClipStack*  fClipStack;
+    GrClip              fGrClip;
+    GrClipData          fClipData;
 
     // state for our offscreen render-target
     TexCache            fCache;
diff --git a/src/gpu/GrAAHairLinePathRenderer.cpp b/src/gpu/GrAAHairLinePathRenderer.cpp
index b0e2431..988cfa7 100644
--- a/src/gpu/GrAAHairLinePathRenderer.cpp
+++ b/src/gpu/GrAAHairLinePathRenderer.cpp
@@ -513,7 +513,9 @@
 
     GrIRect clip;
 
-    target->getClip().getConservativeBounds().roundOut(&clip);
+    const GrClipData* clipData = target->getClip();
+    GrRect conservativeBounds = clipData->fClipStack->getConservativeBounds();
+    conservativeBounds.roundOut(&clip);
 
     GrVertexLayout layout = GrDrawTarget::kEdge_VertexLayoutBit;
     GrMatrix viewM = drawState.getViewMatrix();
diff --git a/src/gpu/GrClipMaskManager.cpp b/src/gpu/GrClipMaskManager.cpp
index d7287ea..a3c8537 100644
--- a/src/gpu/GrClipMaskManager.cpp
+++ b/src/gpu/GrClipMaskManager.cpp
@@ -132,11 +132,11 @@
 ////////////////////////////////////////////////////////////////////////////////
 // sort out what kind of clip mask needs to be created: alpha, stencil,
 // scissor, or entirely software
-bool GrClipMaskManager::setupClipping(const GrClip& clipIn) {
+bool GrClipMaskManager::setupClipping(const GrClipData* clipDataIn) {
     fCurrClipMaskType = kNone_ClipMaskType;
 
     GrDrawState* drawState = fGpu->drawState();
-    if (!drawState->isClipState() || clipIn.isEmpty()) {
+    if (!drawState->isClipState() || clipDataIn->fClipStack->isEmpty()) {
         fGpu->disableScissor();
         this->setGpuStencil();
         return true;
@@ -150,7 +150,10 @@
     GrIRect rtRect;
     rtRect.setLTRB(0, 0, rt->width(), rt->height());
 
-    clipIn.getConservativeBounds().roundOut(&bounds);
+
+    GrRect conservativeBounds = clipDataIn->fClipStack->getConservativeBounds();
+
+    conservativeBounds.roundOut(&bounds);
     if (!bounds.intersect(rtRect)) {
         bounds.setEmpty();
     }
@@ -158,20 +161,22 @@
         return false;
     }
 
-    bool requiresAA = requires_AA(clipIn);
-    GrAssert(requiresAA == clipIn.requiresAA());
+    bool requiresAA = requires_AA(*clipDataIn->fClipStack);
+    GrAssert(requiresAA == clipDataIn->fClipStack->requiresAA());
 
 #if GR_SW_CLIP
     // If MSAA is enabled we can do everything in the stencil buffer.
     // Otherwise check if we should just create the entire clip mask 
     // in software (this will only happen if the clip mask is anti-aliased
     // and too complex for the gpu to handle in its entirety)
-    if (0 == rt->numSamples() && requiresAA && this->useSWOnlyPath(clipIn)) {
+    if (0 == rt->numSamples() && 
+        requiresAA && 
+        this->useSWOnlyPath(*clipDataIn->fClipStack)) {
         // The clip geometry is complex enough that it will be more
         // efficient to create it entirely in software
         GrTexture* result = NULL;
         GrIRect bound;
-        if (this->createSoftwareClipMask(clipIn, &result, &bound)) {
+        if (this->createSoftwareClipMask(*clipDataIn, &result, &bound)) {
             setup_drawstate_aaclip(fGpu, result, bound);
             fGpu->disableScissor();
             this->setGpuStencil();
@@ -193,7 +198,7 @@
         // path does (see scissorSettings below)
         GrTexture* result = NULL;
         GrIRect bound;
-        if (this->createAlphaClipMask(clipIn, &result, &bound)) {
+        if (this->createAlphaClipMask(*clipDataIn, &result, &bound)) {
             setup_drawstate_aaclip(fGpu, result, bound);
             fGpu->disableScissor();
             this->setGpuStencil();
@@ -216,18 +221,17 @@
 
     // If the clip is a rectangle then just set the scissor. Otherwise, create
     // a stencil mask.
-    if (clipIn.isRect()) {
+    if (clipDataIn->fClipStack->isRect()) {
         fGpu->enableScissor(bounds);
         this->setGpuStencil();
         return true;
     }
 
     // use the stencil clip if we can't represent the clip as a rectangle.
-    bool useStencil = !clipIn.isRect() && !clipIn.isEmpty() &&
-                      !bounds.isEmpty();
+    bool useStencil = !clipDataIn->fClipStack->isEmpty() && !bounds.isEmpty();
 
     if (useStencil) {
-        this->createStencilClipMask(clipIn, bounds);
+        this->createStencilClipMask(*clipDataIn, bounds);
     }
     // This must occur after createStencilClipMask. That function may change
     // the scissor. Also, it only guarantees that the stencil mask is correct
@@ -529,7 +533,7 @@
 // Handles caching, determination of clip mask bound & allocation (if needed)
 // of the result texture
 // Returns true if there is no more work to be done (i.e., we got a cache hit)
-bool GrClipMaskManager::clipMaskPreamble(const GrClip& clipIn,
+bool GrClipMaskManager::clipMaskPreamble(const GrClipData& clipDataIn,
                                          GrTexture** result,
                                          GrIRect* resultBounds) {
     GrDrawState* origDrawState = fGpu->drawState();
@@ -544,7 +548,8 @@
 
     // unlike the stencil path the alpha path is not bound to the size of the
     // render target - determine the minimum size required for the mask
-    GrRect bounds = clipIn.getConservativeBounds();
+    GrRect bounds = clipDataIn.fClipStack->getConservativeBounds();
+
     if (!bounds.intersect(rtRect)) {
         // the mask will be empty in this case
         GrAssert(false);
@@ -560,7 +565,7 @@
 
     // TODO: make sure we don't outset if bounds are still 0,0 @ min
 
-    if (fAACache.canReuse(clipIn, 
+    if (fAACache.canReuse(*clipDataIn.fClipStack, 
                           intBounds.width(),
                           intBounds.height())) {
         *result = fAACache.getLastMask();
@@ -568,7 +573,7 @@
         return true;
     }
 
-    this->setupCache(clipIn, intBounds);
+    this->setupCache(*clipDataIn.fClipStack, intBounds);
 
     *resultBounds = intBounds;
     return false;
@@ -576,13 +581,13 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 // Create a 8-bit clip mask in alpha
-bool GrClipMaskManager::createAlphaClipMask(const GrClip& clipIn,
+bool GrClipMaskManager::createAlphaClipMask(const GrClipData& clipDataIn,
                                             GrTexture** result,
                                             GrIRect *resultBounds) {
     GrAssert(NULL != resultBounds);
     GrAssert(kNone_ClipMaskType == fCurrClipMaskType);
 
-    if (this->clipMaskPreamble(clipIn, result, resultBounds)) {
+    if (this->clipMaskPreamble(clipDataIn, result, resultBounds)) {
         fCurrClipMaskType = kAlpha_ClipMaskType;
         return true;
     }
@@ -612,7 +617,7 @@
     bool clearToInside;
     SkRegion::Op firstOp = SkRegion::kReplace_Op; // suppress warning
 
-    GrClip::Iter iter(clipIn, GrClip::Iter::kBottom_IterStart);
+    GrClip::Iter iter(*clipDataIn.fClipStack, GrClip::Iter::kBottom_IterStart);
     const GrClip::Iter::Clip* clip = process_initial_clip_elements(&iter,
                                                               *resultBounds,
                                                               &clearToInside,
@@ -706,7 +711,7 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 // Create a 1-bit clip mask in the stencil buffer
-bool GrClipMaskManager::createStencilClipMask(const GrClip& clipIn,
+bool GrClipMaskManager::createStencilClipMask(const GrClipData& clipDataIn,
                                               const GrIRect& bounds) {
 
     GrAssert(kNone_ClipMaskType == fCurrClipMaskType);
@@ -723,16 +728,21 @@
         return false;
     }
 
-    if (stencilBuffer->mustRenderClip(clipIn, rt->width(), rt->height())) {
+    if (stencilBuffer->mustRenderClip(clipDataIn, rt->width(), rt->height())) {
 
-        stencilBuffer->setLastClip(clipIn, rt->width(), rt->height());
+        stencilBuffer->setLastClip(clipDataIn, rt->width(), rt->height());
 
         // 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
         // we just stashed on the SB to render from. We set it back after
         // we finish drawing it into the stencil.
-        const GrClip& clipCopy = stencilBuffer->getLastClip();
-        fGpu->setClip(GrClip(bounds));
+        const GrClipData* oldClipData = fGpu->getClip();
+
+        GrClip newClipStack(bounds);
+        GrClipData newClipData;
+        newClipData.fClipStack = &newClipStack;
+
+        fGpu->setClip(&newClipData);
 
         GrDrawTarget::AutoStateRestore asr(fGpu, GrDrawTarget::kReset_ASRInit);
         drawState = fGpu->drawState();
@@ -753,7 +763,8 @@
         bool clearToInside;
         SkRegion::Op firstOp = SkRegion::kReplace_Op; // suppress warning
 
-        GrClip::Iter iter(clipCopy, GrClip::Iter::kBottom_IterStart);
+        GrClip::Iter iter(*oldClipData->fClipStack, 
+                          GrClip::Iter::kBottom_IterStart);
         const GrClip::Iter::Clip* clip = process_initial_clip_elements(&iter,
                                                   rtRect,
                                                   &clearToInside,
@@ -811,7 +822,7 @@
                                                          fill, fGpu, false,
                                                          true);
                 if (NULL == pr) {
-                    fGpu->setClip(clipCopy);     // restore to the original
+                    fGpu->setClip(oldClipData);     // restore to the original
                     return false;
                 }
                 canRenderDirectToStencil =
@@ -880,7 +891,7 @@
             }
         }
         // restore clip
-        fGpu->setClip(clipCopy);
+        fGpu->setClip(oldClipData);
     }
     // set this last because recursive draws may overwrite it back to kNone.
     GrAssert(kNone_ClipMaskType == fCurrClipMaskType);
@@ -1096,12 +1107,12 @@
 
 }
 
-bool GrClipMaskManager::createSoftwareClipMask(const GrClip& clipIn,
+bool GrClipMaskManager::createSoftwareClipMask(const GrClipData& clipDataIn,
                                                GrTexture** result,
                                                GrIRect* resultBounds) {
     GrAssert(kNone_ClipMaskType == fCurrClipMaskType);
 
-    if (this->clipMaskPreamble(clipIn, result, resultBounds)) {
+    if (this->clipMaskPreamble(clipDataIn, result, resultBounds)) {
         return true;
     }
 
@@ -1118,7 +1129,7 @@
     bool clearToInside;
     SkRegion::Op firstOp = SkRegion::kReplace_Op; // suppress warning
 
-    GrClip::Iter iter(clipIn, GrClip::Iter::kBottom_IterStart);
+    GrClip::Iter iter(*clipDataIn.fClipStack, GrClip::Iter::kBottom_IterStart);
     const GrClip::Iter::Clip* clip = process_initial_clip_elements(&iter,
                                               *resultBounds,
                                               &clearToInside,
diff --git a/src/gpu/GrClipMaskManager.h b/src/gpu/GrClipMaskManager.h
index 4346c21..0551b8c 100644
--- a/src/gpu/GrClipMaskManager.h
+++ b/src/gpu/GrClipMaskManager.h
@@ -33,7 +33,7 @@
  */
 class GrClipMaskCache : public GrNoncopyable {
 public:
-    GrClipMaskCache() 
+    GrClipMaskCache()
     : fContext(NULL)
     , fStack(sizeof(GrClipStackFrame)) {
         // We need an initial frame to capture the clip state prior to 
@@ -280,7 +280,7 @@
      * and sets the GrGpu's scissor and stencil state. If the return is false
      * then the draw can be skipped.
      */
-    bool setupClipping(const GrClip& clip);
+    bool setupClipping(const GrClipData* clipDataIn);
 
     void releaseResources();
 
@@ -335,15 +335,15 @@
     
     GrClipMaskCache fAACache;       // cache for the AA path
 
-    bool createStencilClipMask(const GrClip& clip,
+    bool createStencilClipMask(const GrClipData& clipDataIn,
                                const GrIRect& bounds);
-    bool createAlphaClipMask(const GrClip& clipIn,
+    bool createAlphaClipMask(const GrClipData& clipDataIn,
                              GrTexture** result,
                              GrIRect *resultBounds);
-    bool createSoftwareClipMask(const GrClip& clipIn,
+    bool createSoftwareClipMask(const GrClipData& clipDataIn,
                                 GrTexture** result,
                                 GrIRect *resultBounds);
-    bool clipMaskPreamble(const GrClip& clipIn,
+    bool clipMaskPreamble(const GrClipData& clipDataIn,
                           GrTexture** result,
                           GrIRect *resultBounds);
 
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index cd2b5a6..e14456a 100644
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -579,10 +579,12 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
+const GrClipData* GrContext::getClip() const {
+    return fGpu->getClip(); 
+}
 
-void GrContext::setClip(const GrClip& clip) {
-    fGpu->setClip(clip);
+void GrContext::setClip(const GrClipData* clipData) {
+    fGpu->setClip(clipData);
     fDrawState->enableState(GrDrawState::kClip_StateBit);
 }
 
@@ -1905,7 +1907,7 @@
     AutoMatrix avm(this, GrMatrix::I());
 
     AutoClip acs(this, GrRect::MakeWH(SkIntToScalar(srcTexture->width()), 
-                                           SkIntToScalar(srcTexture->height())));
+                                      SkIntToScalar(srcTexture->height())));
     GrTextureDesc desc;
     desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit;
     desc.fWidth = SkScalarCeilToInt(rect.width());
diff --git a/src/gpu/GrDrawTarget.cpp b/src/gpu/GrDrawTarget.cpp
index 75a2cd7..8afe5b9 100644
--- a/src/gpu/GrDrawTarget.cpp
+++ b/src/gpu/GrDrawTarget.cpp
@@ -440,7 +440,7 @@
 #define DEBUG_INVAL_BUFFER 0xdeadcafe
 #define DEBUG_INVAL_START_IDX -1
 
-GrDrawTarget::GrDrawTarget() {
+GrDrawTarget::GrDrawTarget() : fClip(NULL) {
 #if GR_DEBUG
     VertexLayoutUnitTest();
 #endif
@@ -476,12 +476,12 @@
     this->resetIndexSource();
 }
 
-void GrDrawTarget::setClip(const GrClip& clip) {
+void GrDrawTarget::setClip(const GrClipData* clip) {
     clipWillBeSet(clip);
     fClip = clip;
 }
 
-const GrClip& GrDrawTarget::getClip() const {
+const GrClipData* GrDrawTarget::getClip() const {
     return fClip;
 }
 
diff --git a/src/gpu/GrDrawTarget.h b/src/gpu/GrDrawTarget.h
index a51e2cf..3fb6201 100644
--- a/src/gpu/GrDrawTarget.h
+++ b/src/gpu/GrDrawTarget.h
@@ -73,14 +73,14 @@
      *
      * @param description of the clipping region
      */
-    void setClip(const GrClip& clip);
+    void setClip(const GrClipData* clip);
 
     /**
      * Gets the current clip.
      *
      * @return the clip.
      */
-    const GrClip& getClip() const;
+    const GrClipData* getClip() const;
 
     /**
      * Sets the draw state object for the draw target. Note that this does not
@@ -641,8 +641,8 @@
             fTarget->setClip(fClip);
         }
     private:
-        GrDrawTarget* fTarget;
-        GrClip        fClip;
+        GrDrawTarget*      fTarget;
+        const GrClipData*  fClip;
     };
     
     ////////////////////////////////////////////////////////////////////////////
@@ -987,7 +987,7 @@
 
     // subclass overrides to be notified when clip is set. Must call
     // INHERITED::clipwillBeSet
-    virtual void clipWillBeSet(const GrClip& clip) {}
+    virtual void clipWillBeSet(const GrClipData* clipData) {}
 
     // Helpers for drawRect, protected so subclasses that override drawRect
     // can use them.
@@ -1013,7 +1013,7 @@
         return this->getGeomSrc().fVertexLayout;
     }
 
-    GrClip fClip;
+    const GrClipData* fClip;
 
     GrDrawState* fDrawState;
     GrDrawState fDefaultDrawState;
diff --git a/src/gpu/GrInOrderDrawBuffer.cpp b/src/gpu/GrInOrderDrawBuffer.cpp
index d0bb225..d5d03cd 100644
--- a/src/gpu/GrInOrderDrawBuffer.cpp
+++ b/src/gpu/GrInOrderDrawBuffer.cpp
@@ -124,9 +124,10 @@
         // simply because the clip has changed if the clip doesn't affect
         // the rect.
         bool disabledClip = false;
-        if (drawState->isClipState() && fClip.isRect()) {
 
-            GrClip::Iter iter(fClip, GrClip::Iter::kBottom_IterStart);
+        if (drawState->isClipState() && fClip->fClipStack->isRect()) {
+
+            GrClip::Iter iter(*fClip->fClipStack, GrClip::Iter::kBottom_IterStart);
             const GrClip::Iter::Clip* clip = iter.next();
             GrAssert(NULL != clip && NULL != clip->fRect);
 
@@ -493,6 +494,7 @@
     fVertexPool.reset();
     fIndexPool.reset();
     fClips.reset();
+    fClipOrigins.reset();
     fClipSet = true;
 
     this->resetDrawTracking();
@@ -527,6 +529,8 @@
     GrDrawState* prevDrawState = target->drawState();
     prevDrawState->ref();
 
+    GrClipData clipData;
+
     int currState       = 0;
     int currClip        = 0;
     int currClear       = 0;
@@ -567,7 +571,9 @@
                 ++currState;
                 break;
             case kSetClip_Cmd:
-                target->setClip(fClips[currClip]);
+                clipData.fClipStack = &fClips[currClip];
+                clipData.fOrigin = fClipOrigins[currClip];
+                target->setClip(&clipData);
                 ++currClip;
                 break;
             case kClear_Cmd:
@@ -581,6 +587,7 @@
     // we should have consumed all the states, clips, etc.
     GrAssert(fStates.count() == currState);
     GrAssert(fClips.count() == currClip);
+    GrAssert(fClipOrigins.count() == currClip);
     GrAssert(fClears.count() == currClear);
     GrAssert(fDraws.count()  == currDraw);
 
@@ -809,7 +816,9 @@
 
 bool GrInOrderDrawBuffer::needsNewClip() const {
    if (this->getDrawState().isClipState()) {
-       if (fClipSet && fClips.back() != fClip) {
+       if (fClipSet && 
+           (fClips.back() != *fClip->fClipStack ||
+            fClipOrigins.back() != fClip->fOrigin)) {
            return true;
        }
     }
@@ -817,13 +826,15 @@
 }
 
 void GrInOrderDrawBuffer::recordClip() {
-    fClips.push_back() = fClip;
+    fClips.push_back() = *fClip->fClipStack;
+    fClipOrigins.push_back() = fClip->fOrigin;
     fClipSet = false;
     fCmds.push_back(kSetClip_Cmd);
 }
 
 void GrInOrderDrawBuffer::recordDefaultClip() {
     fClips.push_back() = GrClip();
+    fClipOrigins.push_back() = SkIPoint::Make(0, 0);
     fCmds.push_back(kSetClip_Cmd);
 }
 
@@ -852,7 +863,7 @@
     return &fClears.push_back();
 }
 
-void GrInOrderDrawBuffer::clipWillBeSet(const GrClip& newClip) {
-    INHERITED::clipWillBeSet(newClip);
+void GrInOrderDrawBuffer::clipWillBeSet(const GrClipData* newClipData) {
+    INHERITED::clipWillBeSet(newClipData);
     fClipSet = true;
 }
diff --git a/src/gpu/GrInOrderDrawBuffer.h b/src/gpu/GrInOrderDrawBuffer.h
index 00cf71a..9dfb18e 100644
--- a/src/gpu/GrInOrderDrawBuffer.h
+++ b/src/gpu/GrInOrderDrawBuffer.h
@@ -196,7 +196,7 @@
     virtual void geometrySourceWillPush() SK_OVERRIDE;
     virtual void geometrySourceWillPop(
         const GeometrySrcState& restoredState) SK_OVERRIDE;
-    virtual void clipWillBeSet(const GrClip& newClip) SK_OVERRIDE;
+    virtual void clipWillBeSet(const GrClipData* newClip) SK_OVERRIDE;
 
     // we lazily record state and clip changes in order to skip clips and states
     // that have no effect.
@@ -231,7 +231,9 @@
     GrSTAllocator<kStatePreallocCnt, StencilPath>       fStencilPaths;
     GrSTAllocator<kStatePreallocCnt, GrDrawState>       fStates;
     GrSTAllocator<kClearPreallocCnt, Clear>             fClears;
+
     GrSTAllocator<kClipPreallocCnt, GrClip>             fClips;
+    GrSTAllocator<kClipPreallocCnt, SkIPoint>           fClipOrigins;
 
     GrDrawTarget*                   fAutoFlushTarget;
 
diff --git a/src/gpu/GrSoftwarePathRenderer.cpp b/src/gpu/GrSoftwarePathRenderer.cpp
index ddd5b7a..0bf1cab 100644
--- a/src/gpu/GrSoftwarePathRenderer.cpp
+++ b/src/gpu/GrSoftwarePathRenderer.cpp
@@ -45,9 +45,11 @@
         return false;
     }
     *pathBounds = GrIRect::MakeWH(rt->width(), rt->height());
-    const GrClip& clip = target->getClip();
 
-    clip.getConservativeBounds().roundOut(clipBounds);
+    const GrClipData* clipData = target->getClip();
+
+    SkRect conservativeBounds = clipData->fClipStack->getConservativeBounds();
+    conservativeBounds.roundOut(clipBounds);
     if (!pathBounds->intersect(*clipBounds)) {
         return false;
     }
diff --git a/src/gpu/GrStencilBuffer.h b/src/gpu/GrStencilBuffer.h
index 5249ce8..506e5ce 100644
--- a/src/gpu/GrStencilBuffer.h
+++ b/src/gpu/GrStencilBuffer.h
@@ -30,8 +30,12 @@
     int numSamples() const { return fSampleCnt; }
 
     // called to note the last clip drawn to this buffer.
-    void setLastClip(const GrClip& clip, int width, int height) {
-        fLastClip = clip;
+    void setLastClip(const GrClipData& clipData, int width, int height) {
+        // the clip stack needs to be copied separately (and deeply) since
+        // it could change beneath the stencil buffer
+        fLastClipStack = *clipData.fClipStack;
+        fLastClipData.fClipStack = &fLastClipStack;
+        fLastClipData.fOrigin = clipData.fOrigin;
         fLastClipWidth = width;
         fLastClipHeight = height;
         GrAssert(width <= fWidth);
@@ -39,18 +43,18 @@
     }
 
     // called to determine if we have to render the clip into SB.
-    bool mustRenderClip(const GrClip& clip, int width, int height) const {
+    bool mustRenderClip(const GrClipData& clipData, int width, int height) const {
         // The clip is in device space. That is it doesn't scale to fit a
         // smaller RT. It is just truncated on the right / bottom edges.
         // Note that this assumes that the viewport origin never moves within
         // the stencil buffer. This is valid today.
         return width > fLastClipWidth ||
                height > fLastClipHeight ||
-               clip != fLastClip;
+               clipData != fLastClipData;
     }
 
-    const GrClip& getLastClip() const {
-        return fLastClip;
+    const GrClipData& getLastClip() const {
+        return fLastClipData;
     }
 
     // places the sb in the cache and locks it. Caller transfers
@@ -70,7 +74,8 @@
         , fHeight(height)
         , fBits(bits)
         , fSampleCnt(sampleCnt)
-        , fLastClip()
+        , fLastClipStack()
+        , fLastClipData()
         , fLastClipWidth(-1)
         , fLastClipHeight(-1)
         , fCacheEntry(NULL)
@@ -93,9 +98,10 @@
     int fBits;
     int fSampleCnt;
 
-    GrClip     fLastClip;
-    int        fLastClipWidth;
-    int        fLastClipHeight;
+    GrClip      fLastClipStack;
+    GrClipData  fLastClipData;
+    int         fLastClipWidth;
+    int         fLastClipHeight;
 
     GrResourceEntry* fCacheEntry;
     int              fRTAttachmentCnt;
diff --git a/src/gpu/GrTextContext.cpp b/src/gpu/GrTextContext.cpp
index 86b73f8..36e6646 100644
--- a/src/gpu/GrTextContext.cpp
+++ b/src/gpu/GrTextContext.cpp
@@ -85,17 +85,19 @@
         fExtMatrix.reset();
     }
 
+    const GrClipData* clipData = context->getClip();
+
+    GrRect conservativeBound = clipData->fClipStack->getConservativeBounds();
+
     if (!fExtMatrix.isIdentity()) {
         GrMatrix inverse;
-        GrRect r = context->getClip().getConservativeBounds();
         if (fExtMatrix.invert(&inverse)) {
-            inverse.mapRect(&r);
-            r.roundOut(&fClipRect);
+            inverse.mapRect(&conservativeBound);
         }
-    } else {
-        context->getClip().getConservativeBounds().roundOut(&fClipRect);
     }
 
+    conservativeBound.roundOut(&fClipRect);
+
     // save the context's original matrix off and restore in destructor
     // this must be done before getTextTarget.
     fOrigViewMatrix = fContext->getMatrix();
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index f290239..cb33d76 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -353,12 +353,16 @@
 
     // Canvas promises that this ptr is valid until onDetachFromCanvas is called
     fClipStack = canvas->getClipStack();
+
+    fClipData.fClipStack = NULL;
 }
 
 void SkGpuDevice::onDetachFromCanvas() {
     INHERITED::onDetachFromCanvas();
 
     fClipStack = NULL;
+
+    fClipData.fClipStack = NULL;
 }
 
 #ifdef SK_DEBUG
@@ -395,9 +399,11 @@
 
 static void convert_matrixclip(GrContext* context, const SkMatrix& matrix,
                                const SkClipStack& clipStack,
+                               GrClipData& clipData,
                                const SkRegion& clipRegion,
                                const SkIPoint& origin,
-                               int renderTargetWidth, int renderTargetHeight) {
+                               int renderTargetWidth, int renderTargetHeight,
+                               GrClip* result) {
     context->setMatrix(matrix);
 
     SkGrClipIterator iter;
@@ -417,15 +423,19 @@
                                     &bounds,
                                     &isIntersectionOfRects);
 
-    GrClip grc(&iter, GrIntToScalar(-origin.x()), GrIntToScalar(-origin.y()),
-               bounds);
+    result->setFromIterator(&iter,
+                            GrIntToScalar(-origin.x()),
+                            GrIntToScalar(-origin.y()),
+                            bounds);
 
-    GrAssert(grc.isRect() == isIntersectionOfRects);
+    GrAssert(result->isRect() == isIntersectionOfRects);
 
-    context->setClip(grc);
+    clipData.fClipStack = result;
+    clipData.fOrigin = origin;
+    context->setClip(&clipData);
 }
 
-// call this ever each draw call, to ensure that the context reflects our state,
+// call this every draw call, to ensure that the context reflects our state,
 // and not the state from some other canvas/device
 void SkGpuDevice::prepareRenderTarget(const SkDraw& draw) {
     GrAssert(NULL != fClipStack);
@@ -436,9 +446,10 @@
         fContext->setRenderTarget(fRenderTarget);
         SkASSERT(draw.fClipStack && draw.fClipStack == fClipStack);
 
-        convert_matrixclip(fContext, *draw.fMatrix,
-                           *fClipStack, *draw.fClip, this->getOrigin(),
-                           fRenderTarget->width(), fRenderTarget->height());
+        convert_matrixclip(fContext, *draw.fMatrix, 
+                           *fClipStack, fClipData, *draw.fClip, this->getOrigin(),
+                           fRenderTarget->width(), fRenderTarget->height(),
+                           &fGrClip);
         fNeedPrepareRenderTarget = false;
     }
 }
@@ -458,8 +469,8 @@
 
     this->INHERITED::gainFocus(matrix, clip);
 
-    convert_matrixclip(fContext, matrix, *fClipStack, clip, this->getOrigin(),
-                       fRenderTarget->width(), fRenderTarget->height());
+    convert_matrixclip(fContext, matrix, *fClipStack, fClipData, clip, this->getOrigin(),
+                       fRenderTarget->width(), fRenderTarget->height(), &fGrClip);
 
     DO_DEFERRED_CLEAR;
 }
@@ -889,11 +900,14 @@
     GrRenderTarget* oldRenderTarget = context->getRenderTarget();
     // Once this code moves into GrContext, this should be changed to use
     // an AutoClipRestore.
-    GrClip oldClip = context->getClip();
+    const GrClipData* oldClipData = context->getClip();
+
     context->setRenderTarget(pathTexture->asRenderTarget());
 
-    GrClip newClip(srcRect);
-    context->setClip(newClip);
+    GrClip newClipStack(srcRect);
+    GrClipData newClipData;
+    newClipData.fClipStack = &newClipStack;
+    context->setClip(&newClipData);
 
     context->clear(NULL, 0);
     GrPaint tempPaint;
@@ -948,7 +962,7 @@
         context->drawRect(paint, srcRect);
     }
     context->setRenderTarget(oldRenderTarget);
-    context->setClip(oldClip);
+    context->setClip(oldClipData);
 
     if (!grp->preConcatSamplerMatricesWithInverse(matrix)) {
         return false;
diff --git a/src/gpu/gl/GrGpuGL_program.cpp b/src/gpu/gl/GrGpuGL_program.cpp
index f4044fc..b7ae6c7 100644
--- a/src/gpu/gl/GrGpuGL_program.cpp
+++ b/src/gpu/gl/GrGpuGL_program.cpp
@@ -436,7 +436,8 @@
     GrIRect* rect = NULL;
     GrIRect clipBounds;
     if (drawState.isClipState()) {
-        fClip.getConservativeBounds().roundOut(&clipBounds);
+        GrRect conservativeBounds = fClip->fClipStack->getConservativeBounds();
+        conservativeBounds.roundOut(&clipBounds);
         rect = &clipBounds;
     }
     // This must come after textures are flushed because a texture may need