Make SkClipStack::Iter use SkClipStack::Element.

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

git-svn-id: http://skia.googlecode.com/svn/trunk@6661 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/include/core/SkClipStack.h b/include/core/SkClipStack.h
index d4f6a52..6af60a2 100644
--- a/include/core/SkClipStack.h
+++ b/include/core/SkClipStack.h
@@ -58,6 +58,30 @@
             this->initPath(0, path, op, doAA);
         }
 
+        bool operator== (const Element& element) const {
+            if (this == &element) {
+                return true;
+            }
+            if (fOp != element.fOp ||
+                fType != element.fType ||
+                fDoAA != element.fDoAA ||
+                fSaveCount != element.fSaveCount) {
+                return false;
+            }
+            switch (fType) {
+                case kPath_Type:
+                    return fPath == element.fPath;
+                case kRect_Type:
+                    return fRect == element.fRect;
+                case kEmpty_Type:
+                    return true;
+                default:
+                    SkDEBUGFAIL("Unexpected type.");
+                    return false;
+            }
+        }
+        bool operator!= (const Element& element) const { return !(*this == element); }
+
         //!< Call to get the type of the clip element.
         Type getType() const { return fType; }
 
@@ -74,6 +98,8 @@
             when it is rasterized. */
         bool isAA() const { return fDoAA; }
 
+        void setOp(SkRegion::Op op) { fOp = op; }
+
         /** The GenID can be used by clip stack clients to cache representations of the clip. The
             ID corresponds to the set of clip elements up to and including this element within the
             stack not to the element itself. That is the same clip path in different stacks will
@@ -81,6 +107,50 @@
             their stacks. */
         int32_t getGenID() const { return fGenID; }
 
+        /**
+         * Gets the bounds of the clip element, either the rect or path bounds. (Whether the shape
+         * is inverse filled is not considered.)
+         */
+        const SkRect& getBounds() const {
+            static const SkRect kEmpty = { 0, 0, 0, 0 };
+            switch (fType) {
+                case kRect_Type:
+                    return fRect;
+                case kPath_Type:
+                    return fPath.getBounds();
+                case kEmpty_Type:
+                    return kEmpty;
+                default:
+                    SkDEBUGFAIL("Unexpected type.");
+                    return kEmpty;
+            }
+        }
+
+        /**
+         * Conservatively checks whether the clip shape contains the rect param. (Whether the shape
+         * is inverse filled is not considered.)
+         */
+        bool contains(const SkRect& rect) const {
+            switch (fType) {
+                case kRect_Type:
+                    return fRect.contains(rect);
+                case kPath_Type:
+                    return fPath.conservativelyContainsRect(rect);
+                case kEmpty_Type:
+                    return false;
+                default:
+                    SkDEBUGFAIL("Unexpected type.");
+                    return false;
+            }
+        }
+
+        /**
+         * Is the clip shape inverse filled.
+         */
+        bool isInverseFilled() const {
+            return kPath_Type == fType && fPath.isInverseFillType();
+        }
+
     private:
         friend class SkClipStack;
 
@@ -159,8 +229,6 @@
 
         // All Element methods below are only used within SkClipStack.cpp
         inline void checkEmpty() const;
-        inline bool operator==(const Element& b) const;
-        inline bool operator!=(const Element& b) const;
         inline bool canBeIntersectedInPlace(int saveCount, SkRegion::Op op) const;
         /* This method checks to see if two rect clips can be safely merged into one. The issue here
           is that to be strictly correct all the edges of the resulting rect must have the same
@@ -276,53 +344,18 @@
 
         Iter(const SkClipStack& stack, IterStart startLoc);
 
-        struct Clip {
-            Clip() : fRect(NULL), fPath(NULL), fOp(SkRegion::kIntersect_Op),
-                     fDoAA(false), fGenID(kInvalidGenID) {}
-            friend bool operator==(const Clip& a, const Clip& b);
-            friend bool operator!=(const Clip& a, const Clip& b);
-            /**
-             * Gets the bounds of the clip element, either the rect or path bounds. (Whether the
-             * shape is inverse filled is not considered)
-             */
-            const SkRect& getBounds() const;
-
-            /**
-             * Conservatively checks whether the clip shape (rect/path) contains the rect param.
-             * (Whether the shape is inverse filled is not considered)
-             */
-            bool contains(const SkRect&) const;
-
-            /**
-             * Is the clip shape inverse filled.
-             */
-            bool isInverseFilled() const;
-
-            const SkRect*   fRect;  // if non-null, this is a rect clip
-            const SkPath*   fPath;  // if non-null, this is a path clip
-            SkRegion::Op    fOp;
-            bool            fDoAA;
-            int32_t         fGenID;
-        };
+        /**
+         *  Return the clip element for this iterator. If next()/prev() returns NULL, then the
+         *  iterator is done.
+         */
+        const Element* next();
+        const Element* prev();
 
         /**
-         *  Return the clip for this element in the iterator. If next() returns
-         *  NULL, then the iterator is done. The type of clip is determined by
-         *  the pointers fRect and fPath:
-         *
-         *  fRect==NULL  fPath!=NULL    path clip
-         *  fRect!=NULL  fPath==NULL    rect clip
-         *  fRect==NULL  fPath==NULL    empty clip
+         * Moves the iterator to the topmost element with the specified RegionOp and returns that
+         * element. If no clip element with that op is found, the first element is returned.
          */
-        const Clip* next();
-        const Clip* prev();
-
-        /**
-         * Moves the iterator to the topmost clip with the specified RegionOp
-         * and returns that clip. If no clip with that op is found,
-         * returns NULL.
-         */
-        const Clip* skipToTopmost(SkRegion::Op op);
+        const Element* skipToTopmost(SkRegion::Op op);
 
         /**
          * Restarts the iterator on a clip stack.
@@ -331,13 +364,7 @@
 
     private:
         const SkClipStack* fStack;
-        Clip               fClip;
         SkDeque::Iter      fIter;
-        /**
-         * updateClip updates fClip to the current state of fIter. It unifies
-         * functionality needed by both next() and prev().
-         */
-        const Clip* updateClip(const SkClipStack::Element* element);
     };
 
     /**
@@ -356,7 +383,6 @@
         : INHERITED(stack, kBottom_IterStart) {
         }
 
-        using Iter::Clip;
         using Iter::next;
 
         /**
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index c38ed76..34310c8 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -1194,15 +1194,23 @@
     SkRasterClip tmpClip(ir);
 
     SkClipStack::B2TIter                iter(fClipStack);
-    const SkClipStack::B2TIter::Clip*   clip;
-    while ((clip = iter.next()) != NULL) {
-        if (clip->fPath) {
-            clipPathHelper(this, &tmpClip, *clip->fPath, clip->fOp, clip->fDoAA);
-        } else if (clip->fRect) {
-            clip->fRect->round(&ir);
-            tmpClip.op(ir, clip->fOp);
-        } else {
-            tmpClip.setEmpty();
+    const SkClipStack::Element* element;
+    while ((element = iter.next()) != NULL) {
+        switch (element->getType()) {
+            case SkClipStack::Element::kPath_Type:
+                clipPathHelper(this,
+                               &tmpClip,
+                               element->getPath(),
+                               element->getOp(),
+                               element->isAA());
+                break;
+            case SkClipStack::Element::kRect_Type:
+                element->getRect().round(&ir);
+                tmpClip.op(ir, element->getOp());
+                break;
+            case SkClipStack::Element::kEmpty_Type:
+                tmpClip.setEmpty();
+                break;
         }
     }
 
@@ -1216,16 +1224,20 @@
 
 void SkCanvas::replayClips(ClipVisitor* visitor) const {
     SkClipStack::B2TIter                iter(fClipStack);
-    const SkClipStack::B2TIter::Clip*   clip;
+    const SkClipStack::Element*         element;
 
-    SkRect empty = { 0, 0, 0, 0 };
-    while ((clip = iter.next()) != NULL) {
-        if (clip->fPath) {
-            visitor->clipPath(*clip->fPath, clip->fOp, clip->fDoAA);
-        } else if (clip->fRect) {
-            visitor->clipRect(*clip->fRect, clip->fOp, clip->fDoAA);
-        } else {
-            visitor->clipRect(empty, SkRegion::kIntersect_Op, false);
+    static const SkRect kEmpty = { 0, 0, 0, 0 };
+    while ((element = iter.next()) != NULL) {
+        switch (element->getType()) {
+            case SkClipStack::Element::kPath_Type:
+                visitor->clipPath(element->getPath(), element->getOp(), element->isAA());
+                break;
+            case SkClipStack::Element::kRect_Type:
+                visitor->clipRect(element->getRect(), element->getOp(), element->isAA());
+                break;
+            case SkClipStack::Element::kEmpty_Type:
+                visitor->clipRect(kEmpty, SkRegion::kIntersect_Op, false);
+                break;
         }
     }
 }
diff --git a/src/core/SkClipStack.cpp b/src/core/SkClipStack.cpp
index 33cd41f..107c20f 100644
--- a/src/core/SkClipStack.cpp
+++ b/src/core/SkClipStack.cpp
@@ -24,28 +24,6 @@
     SkASSERT(fPath.isEmpty());
 }
 
-bool SkClipStack::Element::operator==(const Element& b) const {
-    if (fSaveCount != b.fSaveCount ||
-        fOp != b.fOp ||
-        fType != b.fType ||
-        fDoAA != b.fDoAA) {
-        return false;
-    }
-    switch (fType) {
-        case kEmpty_Type:
-            return true;
-        case kRect_Type:
-            return fRect == b.fRect;
-        case kPath_Type:
-            return fPath == b.fPath;
-    }
-    return false;  // Silence the compiler.
-}
-
-bool SkClipStack::Element::operator!=(const Element& b) const {
-    return !(*this == b);
-}
-
 bool SkClipStack::Element::canBeIntersectedInPlace(int saveCount, SkRegion::Op op) const {
     if (kEmpty_Type == fType &&
         (SkRegion::kDifference_Op == op || SkRegion::kIntersect_Op == op)) {
@@ -622,92 +600,20 @@
 SkClipStack::Iter::Iter() : fStack(NULL) {
 }
 
-bool operator==(const SkClipStack::Iter::Clip& a,
-                const SkClipStack::Iter::Clip& b) {
-    return a.fOp == b.fOp && a.fDoAA == b.fDoAA &&
-           ((a.fRect == NULL && b.fRect == NULL) ||
-               (a.fRect != NULL && b.fRect != NULL && *a.fRect == *b.fRect)) &&
-           ((a.fPath == NULL && b.fPath == NULL) ||
-               (a.fPath != NULL && b.fPath != NULL && *a.fPath == *b.fPath));
-}
-
-bool operator!=(const SkClipStack::Iter::Clip& a,
-                const SkClipStack::Iter::Clip& b) {
-    return !(a == b);
-}
-
-const SkRect& SkClipStack::Iter::Clip::getBounds() const {
-    if (NULL != fRect) {
-        return *fRect;
-    } else if (NULL != fPath) {
-        return fPath->getBounds();
-    } else {
-        static const SkRect kEmpty = {0, 0, 0, 0};
-        return kEmpty;
-    }
-}
-
-bool SkClipStack::Iter::Clip::contains(const SkRect& rect) const {
-    if (NULL != fRect) {
-        return fRect->contains(rect);
-    } else if (NULL != fPath) {
-        return fPath->conservativelyContainsRect(rect);
-    } else {
-        return false;
-    }
-}
-
-bool SkClipStack::Iter::Clip::isInverseFilled() const {
-    return NULL != fPath && fPath->isInverseFillType();
-}
-
 SkClipStack::Iter::Iter(const SkClipStack& stack, IterStart startLoc)
     : fStack(&stack) {
     this->reset(stack, startLoc);
 }
 
-const SkClipStack::Iter::Clip* SkClipStack::Iter::updateClip(
-                        const SkClipStack::Element* element) {
-    switch (element->fType) {
-        case SkClipStack::Element::kEmpty_Type:
-            fClip.fRect = NULL;
-            fClip.fPath = NULL;
-            element->checkEmpty();
-            break;
-        case SkClipStack::Element::kRect_Type:
-            fClip.fRect = &element->fRect;
-            fClip.fPath = NULL;
-            break;
-        case SkClipStack::Element::kPath_Type:
-            fClip.fRect = NULL;
-            fClip.fPath = &element->fPath;
-            break;
-    }
-    fClip.fOp = element->fOp;
-    fClip.fDoAA = element->fDoAA;
-    fClip.fGenID = element->fGenID;
-    return &fClip;
+const SkClipStack::Element* SkClipStack::Iter::next() {
+    return (const SkClipStack::Element*)fIter.next();
 }
 
-const SkClipStack::Iter::Clip* SkClipStack::Iter::next() {
-    const SkClipStack::Element* element = (const SkClipStack::Element*)fIter.next();
-    if (NULL == element) {
-        return NULL;
-    }
-
-    return this->updateClip(element);
+const SkClipStack::Element* SkClipStack::Iter::prev() {
+    return (const SkClipStack::Element*)fIter.prev();
 }
 
-const SkClipStack::Iter::Clip* SkClipStack::Iter::prev() {
-    const SkClipStack::Element* element = (const SkClipStack::Element*)fIter.prev();
-    if (NULL == element) {
-        return NULL;
-    }
-
-    return this->updateClip(element);
-}
-
-const SkClipStack::Iter::Clip* SkClipStack::Iter::skipToTopmost(SkRegion::Op op) {
+const SkClipStack::Element* SkClipStack::Iter::skipToTopmost(SkRegion::Op op) {
 
     if (NULL == fStack) {
         return NULL;
diff --git a/src/core/SkTLList.h b/src/core/SkTLList.h
index 87fd52d..30d440f 100644
--- a/src/core/SkTLList.h
+++ b/src/core/SkTLList.h
@@ -350,7 +350,13 @@
 }
 
 #define SkNEW_INSERT_IN_LLIST_BEFORE(list, location, type_name, args) \
-    (new (list, SkTLList< type_name >::kBefore_Placement, location) type_name args)
+    (new ((list), SkTLList< type_name >::kBefore_Placement, (location)) type_name args)
 
 #define SkNEW_INSERT_IN_LLIST_AFTER(list, location, type_name, args) \
-    (new (list, SkTLList< type_name >::kAfter_Placement, location) type_name args)
+    (new ((list), SkTLList< type_name >::kAfter_Placement, (location)) type_name args)
+
+#define SkNEW_INSERT_AT_LLIST_HEAD(list, type_name, args) \
+    SkNEW_INSERT_IN_LLIST_BEFORE((list), (list)->headIter(), type_name, args)
+
+#define SkNEW_INSERT_AT_LLIST_TAIL(list, type_name, args) \
+    SkNEW_INSERT_IN_LLIST_AFTER((list), (list)->tailIter(), type_name, args)
\ No newline at end of file
diff --git a/src/gpu/GrClipMaskManager.cpp b/src/gpu/GrClipMaskManager.cpp
index fdaa067..64ead1a 100644
--- a/src/gpu/GrClipMaskManager.cpp
+++ b/src/gpu/GrClipMaskManager.cpp
@@ -24,6 +24,7 @@
 #define GR_AA_CLIP 1
 #define GR_SW_CLIP 1
 
+typedef SkClipStack::Element Element;
 ////////////////////////////////////////////////////////////////////////////////
 
 namespace GrReducedClip {
@@ -38,11 +39,11 @@
 take a rect in case the caller knows a bound on what is to be drawn through this clip.
 */
 void GrReduceClipStack(const SkClipStack& stack,
-                       SkTDArray<SkClipStack::Iter::Clip>* resultClips,
+                       ElementList* result,
                        SkRect* resultBounds,
                        bool* resultsAreBounded,
                        InitialState* initialState) {
-    resultClips->reset();
+    result->reset();
 
     if (stack.isWideOpen()) {
         *initialState = kAllIn_InitialState;
@@ -56,15 +57,10 @@
     if (iior) {
         *resultsAreBounded = true;
         *initialState = kAllOut_InitialState;
-        SkClipStack::Iter::Clip* clip = resultClips->append();
-        // append doesn't call the default cons.
-        *clip = SkClipStack::Iter::Clip();
-
-        // iior should only be true if aa/non-aa status matches.
         SkClipStack::Iter iter(stack, SkClipStack::Iter::kTop_IterStart);
-        clip->fDoAA = iter.prev()->fDoAA;
-        clip->fOp = SkRegion::kReplace_Op;
-        clip->fRect = resultBounds;
+        // iior should only be true if aa/non-aa status matches among all elements.
+        bool doAA = iter.prev()->isAA();
+        SkNEW_INSERT_AT_LLIST_TAIL(result, Element, (*resultBounds, SkRegion::kReplace_Op, doAA));
         return;
     }
 
@@ -85,16 +81,16 @@
 
     SkClipStack::Iter iter(stack, SkClipStack::Iter::kTop_IterStart);
     while ((kUnknown_InitialState == *initialState)) {
-        const SkClipStack::Iter::Clip* clip = iter.prev();
-        if (NULL == clip) {
+        const Element* element = iter.prev();
+        if (NULL == element) {
             *initialState = kAllIn_InitialState;
             break;
         }
-        if (SkClipStack::kEmptyGenID == clip->fGenID) {
+        if (SkClipStack::kEmptyGenID == element->getGenID()) {
             *initialState = kAllOut_InitialState;
             break;
         }
-        if (SkClipStack::kWideOpenGenID == clip->fGenID) {
+        if (SkClipStack::kWideOpenGenID == element->getGenID()) {
             *initialState = kAllIn_InitialState;
             break;
         }
@@ -102,23 +98,23 @@
         bool skippable = false;
         bool isFlip = false; // does this op just flip the in/out state of every point in the bounds
 
-        switch (clip->fOp) {
+        switch (element->getOp()) {
             case SkRegion::kDifference_Op:
                 if (*resultsAreBounded) {
                     // check if the shape subtracted either contains the entire bounds (and makes
                     // the clip empty) or is outside the bounds and therefore can be skipped.
-                    if (clip->isInverseFilled()) {
-                        if (clip->contains(*resultBounds)) {
+                    if (element->isInverseFilled()) {
+                        if (element->contains(*resultBounds)) {
                             skippable = true;
-                        } else if (!SkRect::Intersects(clip->getBounds(), *resultBounds)) {
+                        } else if (!SkRect::Intersects(element->getBounds(), *resultBounds)) {
                             *initialState = kAllOut_InitialState;
                             skippable = true;
                         }
                     } else {
-                        if (clip->contains(*resultBounds)) {
+                        if (element->contains(*resultBounds)) {
                             *initialState = kAllOut_InitialState;
                             skippable = true;
-                        } else if (!SkRect::Intersects(clip->getBounds(), *resultBounds)) {
+                        } else if (!SkRect::Intersects(element->getBounds(), *resultBounds)) {
                             skippable = true;
                         }
                     }
@@ -132,17 +128,17 @@
                     // check if the shape intersected contains the entire bounds and therefore can
                     // be skipped or it is outside the entire bounds and therefore makes the clip
                     // empty.
-                    if (clip->isInverseFilled()) {
-                        if (clip->contains(*resultBounds)) {
+                    if (element->isInverseFilled()) {
+                        if (element->contains(*resultBounds)) {
                             *initialState = kAllOut_InitialState;
                             skippable = true;
-                        } else if (!SkRect::Intersects(clip->getBounds(), *resultBounds)) {
+                        } else if (!SkRect::Intersects(element->getBounds(), *resultBounds)) {
                             skippable = true;
                         }
                     } else {
-                        if (clip->contains(*resultBounds)) {
+                        if (element->contains(*resultBounds)) {
                             skippable = true;
-                        } else if (!SkRect::Intersects(clip->getBounds(), *resultBounds)) {
+                        } else if (!SkRect::Intersects(element->getBounds(), *resultBounds)) {
                             *initialState = kAllOut_InitialState;
                             skippable = true;
                         }
@@ -157,18 +153,18 @@
                     // If the union-ed shape contains the entire bounds then after this element
                     // the bounds is entirely inside the clip. If the union-ed shape is outside the
                     // bounds then this op can be skipped.
-                    if (clip->isInverseFilled()) {
-                        if (clip->contains(*resultBounds)) {
+                    if (element->isInverseFilled()) {
+                        if (element->contains(*resultBounds)) {
                             skippable = true;
-                        } else if (!SkRect::Intersects(clip->getBounds(), *resultBounds)) {
+                        } else if (!SkRect::Intersects(element->getBounds(), *resultBounds)) {
                             *initialState = kAllIn_InitialState;
                             skippable = true;
                         }
                     } else {
-                        if (clip->contains(*resultBounds)) {
+                        if (element->contains(*resultBounds)) {
                             *initialState = kAllIn_InitialState;
                             skippable = true;
-                        } else if (!SkRect::Intersects(clip->getBounds(), *resultBounds)) {
+                        } else if (!SkRect::Intersects(element->getBounds(), *resultBounds)) {
                             skippable = true;
                         }
                     }
@@ -183,16 +179,16 @@
                     // to flip the inside/outside state of every point in the bounds. We may be
                     // able to take advantage of this in the forward pass. If the xor-ed shape
                     // doesn't intersect the bounds then it can be skipped.
-                    if (clip->isInverseFilled()) {
-                        if (clip->contains(*resultBounds)) {
+                    if (element->isInverseFilled()) {
+                        if (element->contains(*resultBounds)) {
                             skippable = true;
-                        } else if (!SkRect::Intersects(clip->getBounds(), *resultBounds)) {
+                        } else if (!SkRect::Intersects(element->getBounds(), *resultBounds)) {
                             isFlip = true;
                         }
                     } else {
-                        if (clip->contains(*resultBounds)) {
+                        if (element->contains(*resultBounds)) {
                             isFlip = true;
-                        } else if (!SkRect::Intersects(clip->getBounds(), *resultBounds)) {
+                        } else if (!SkRect::Intersects(element->getBounds(), *resultBounds)) {
                             skippable = true;
                         }
                     }
@@ -207,17 +203,17 @@
                 // the bounds then we know after this element is applied that the bounds will be
                 // all outside the current clip.B
                 if (*resultsAreBounded) {
-                    if (clip->isInverseFilled()) {
-                        if (clip->contains(*resultBounds)) {
+                    if (element->isInverseFilled()) {
+                        if (element->contains(*resultBounds)) {
                             *initialState = kAllOut_InitialState;
                             skippable = true;
-                        } else if (!SkRect::Intersects(clip->getBounds(), *resultBounds)) {
+                        } else if (!SkRect::Intersects(element->getBounds(), *resultBounds)) {
                             isFlip = true;
                         }
                     } else {
-                        if (clip->contains(*resultBounds)) {
+                        if (element->contains(*resultBounds)) {
                             isFlip = true;
-                        } else if (!SkRect::Intersects(clip->getBounds(), *resultBounds)) {
+                        } else if (!SkRect::Intersects(element->getBounds(), *resultBounds)) {
                             *initialState = kAllOut_InitialState;
                             skippable = true;
                         }
@@ -233,19 +229,19 @@
                 // or completely outside the bounds. In this latter case it can be skipped by
                 // setting the correct value for initialState.
                 if (*resultsAreBounded) {
-                    if (clip->isInverseFilled()) {
-                        if (clip->contains(*resultBounds)) {
+                    if (element->isInverseFilled()) {
+                        if (element->contains(*resultBounds)) {
                             *initialState = kAllOut_InitialState;
                             skippable = true;
-                        } else if (!SkRect::Intersects(clip->getBounds(), *resultBounds)) {
+                        } else if (!SkRect::Intersects(element->getBounds(), *resultBounds)) {
                             *initialState = kAllIn_InitialState;
                             skippable = true;
                         }
                     } else {
-                        if (clip->contains(*resultBounds)) {
+                        if (element->contains(*resultBounds)) {
                             *initialState = kAllIn_InitialState;
                             skippable = true;
-                        } else if (!SkRect::Intersects(clip->getBounds(), *resultBounds)) {
+                        } else if (!SkRect::Intersects(element->getBounds(), *resultBounds)) {
                             *initialState = kAllOut_InitialState;
                             skippable = true;
                         }
@@ -261,32 +257,28 @@
                 break;
         }
         if (!skippable) {
-            SkClipStack::Iter::Clip* newClip = resultClips->prepend();
             // if it is a flip, change it to a bounds-filling rect
             if (isFlip) {
-                SkASSERT(SkRegion::kXOR_Op == clip->fOp ||
-                         SkRegion::kReverseDifference_Op == clip->fOp);
-                newClip->fPath = NULL;
-                newClip->fRect = resultBounds;
-                // assuming this is faster to perform on GPU with stenciling than xor.
-                newClip->fOp = SkRegion::kReverseDifference_Op;
-                newClip->fDoAA = false;
-                newClip->fGenID = SkClipStack::kInvalidGenID;
+                SkASSERT(SkRegion::kXOR_Op == element->getOp() ||
+                         SkRegion::kReverseDifference_Op == element->getOp());
+                SkNEW_INSERT_AT_LLIST_HEAD(result,
+                                           Element,
+                                           (*resultBounds, SkRegion::kReverseDifference_Op, false));
             } else {
-                *newClip = *clip;
+                result->addToHead(*element);
             }
         }
     }
 
     if ((kAllOut_InitialState == *initialState && !embiggens) ||
         (kAllIn_InitialState == *initialState && !emsmallens)) {
-        resultClips->reset();
+        result->reset();
     } else {
         int clipsToSkip = 0;
-        while (1) {
-            SkClipStack::Iter::Clip* clip = &(*resultClips)[clipsToSkip];
+        Element* element = result->headIter().get();
+        while (NULL != element) {            
             bool skippable = false;
-            switch (clip->fOp) {
+            switch (element->getOp()) {
                 case SkRegion::kDifference_Op:
                     // subtracting from the empty set yields the empty set.
                     skippable = kAllOut_InitialState == *initialState;
@@ -301,13 +293,13 @@
                         skippable = true;
                     } else {
                         // unioning the empty set with a shape is the shape.
-                        clip->fOp = SkRegion::kReplace_Op;
+                        element->setOp(SkRegion::kReplace_Op);
                     }
                     break;
                 case SkRegion::kXOR_Op:
                     if (kAllOut_InitialState == *initialState) {
                         // xor could be changed to diff in the kAllIn case, not sure it's a win.
-                        clip->fOp = SkRegion::kReplace_Op;
+                        element->setOp(SkRegion::kReplace_Op);
                     }
                     break;
                 case SkRegion::kReverseDifference_Op:
@@ -317,15 +309,15 @@
                         *initialState = kAllOut_InitialState;
                     } else {
                         // this picks up flips inserted in the backwards pass.
-                        if (*resultsAreBounded && NULL != clip->fRect) {
-                            skippable = clip->isInverseFilled() ?
-                                !SkRect::Intersects(clip->getBounds(), *resultBounds) :
-                                clip->contains(*resultBounds);
+                        if (*resultsAreBounded) {
+                            skippable = element->isInverseFilled() ?
+                                !SkRect::Intersects(element->getBounds(), *resultBounds) :
+                                element->contains(*resultBounds);
                         }
                         if (skippable) {
                             *initialState = kAllIn_InitialState;
                         } else {
-                            clip->fOp = SkRegion::kReplace_Op;
+                            element->setOp(SkRegion::kReplace_Op);
                         }
                     }
                     break;
@@ -341,13 +333,10 @@
             if (!skippable) {
                 break;
             } else {
-                ++clipsToSkip;
-                if (clipsToSkip == resultClips->count()) {
-                    break;
-                }
+                result->popHead();
+                element = result->headIter().get();
             }
         }
-        resultClips->remove(0, clipsToSkip);
     }
 }
 } // namespace GrReducedClip
@@ -413,12 +402,12 @@
     SkClipStack::Iter iter;
     iter.reset(clipIn, SkClipStack::Iter::kBottom_IterStart);
 
-    const SkClipStack::Iter::Clip* clip = NULL;
-    for (clip = iter.skipToTopmost(SkRegion::kReplace_Op);
-         NULL != clip;
-         clip = iter.next()) {
+    const Element* element = NULL;
+    for (element = iter.skipToTopmost(SkRegion::kReplace_Op);
+         NULL != element;
+         element = iter.next()) {
 
-        if (clip->fDoAA) {
+        if (element->isAA()) {
             return true;
         }
     }
@@ -441,19 +430,19 @@
     bool useSW = false;
 
     SkClipStack::Iter iter(clipIn, SkClipStack::Iter::kBottom_IterStart);
-    const SkClipStack::Iter::Clip* clip = NULL;
+    const Element* element = NULL;
 
-    for (clip = iter.skipToTopmost(SkRegion::kReplace_Op);
-         NULL != clip;
-         clip = iter.next()) {
+    for (element = iter.skipToTopmost(SkRegion::kReplace_Op);
+         NULL != element;
+         element = iter.next()) {
 
         // rects can always be drawn directly w/o using the software path
         // so only paths need to be checked
-        if (NULL != clip->fPath &&
+        if (Element::kPath_Type == element->getType() &&
             path_needs_SW_renderer(this->getContext(), fGpu,
-                                   *clip->fPath,
-                                   get_path_fill(*clip->fPath),
-                                   clip->fDoAA)) {
+                                   element->getPath(),
+                                   get_path_fill(element->getPath()),
+                                   element->isAA())) {
             useSW = true;
         }
     }
@@ -598,7 +587,7 @@
 // determines how many elements at the head of the clip can be skipped and
 // whether the initial clear should be to the inside- or outside-the-clip value,
 // and what op should be used to draw the first element that isn't skipped.
-const SkClipStack::Iter::Clip* process_initial_clip_elements(
+const SkClipStack::Element* process_initial_clip_elements(
                                   SkClipStack::Iter* iter,
                                   const GrIRect& devBounds,
                                   bool* clearToInside,
@@ -615,12 +604,12 @@
     bool done = false;
     *clearToInside = true;
 
-    const SkClipStack::Iter::Clip* clip = NULL;
+    const SkClipStack::Element* element = NULL;
 
-    for (clip = iter->skipToTopmost(SkRegion::kReplace_Op);
-         NULL != clip && !done;
-         clip = iter->next()) {
-        switch (clip->fOp) {
+    for (element = iter->skipToTopmost(SkRegion::kReplace_Op);
+         NULL != element && !done;
+         element = iter->next()) {
+        switch (element->getOp()) {
             case SkRegion::kReplace_Op:
                 // replace ignores everything previous
                 *firstOp = SkRegion::kReplace_Op;
@@ -630,8 +619,8 @@
             case SkRegion::kIntersect_Op:
                 // if this element contains the entire bounds then we
                 // can skip it.
-                if (NULL != clip->fRect &&
-                    contains(*clip->fRect, devBounds, clipData.fOrigin)) {
+                if (Element::kRect_Type == element->getType() &&
+                    contains(element->getRect(), devBounds, clipData.fOrigin)) {
                     break;
                 }
                 // if everything is initially clearToInside then intersect is
@@ -674,7 +663,7 @@
                 break;
             case SkRegion::kReverseDifference_Op:
                 // if all pixels are clearToInside then reverse difference
-                // produces empty set. Otherise it is same as replace
+                // produces empty set. Otherwise it is same as replace
                 if (*clearToInside) {
                     *clearToInside = false;
                 } else {
@@ -692,7 +681,7 @@
             break;
         }
     }
-    return clip;
+    return element;
 }
 
 }
@@ -786,27 +775,31 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 bool GrClipMaskManager::drawClipShape(GrTexture* target,
-                                      const SkClipStack::Iter::Clip* clip,
+                                      const SkClipStack::Element* element,
                                       const GrIRect& resultBounds) {
     GrDrawState* drawState = fGpu->drawState();
     GrAssert(NULL != drawState);
 
     drawState->setRenderTarget(target->asRenderTarget());
 
-    if (NULL != clip->fRect) {
-        if (clip->fDoAA) {
-            getContext()->getAARectRenderer()->fillAARect(fGpu, fGpu,
-                                                          *clip->fRect,
-                                                          true);
-        } else {
-            fGpu->drawSimpleRect(*clip->fRect, NULL);
-        }
-    } else if (NULL != clip->fPath) {
-        return draw_path(this->getContext(), fGpu,
-                         *clip->fPath,
-                         get_path_fill(*clip->fPath),
-                         clip->fDoAA,
-                         resultBounds);
+    switch (element->getType()) {
+        case Element::kRect_Type:
+            if (element->isAA()) {
+                getContext()->getAARectRenderer()->fillAARect(fGpu, fGpu, element->getRect(), true);
+            } else {
+                fGpu->drawSimpleRect(element->getRect(), NULL);
+            }
+            return true;
+        case Element::kPath_Type:
+            return draw_path(this->getContext(), fGpu,
+                             element->getPath(),
+                             get_path_fill(element->getPath()),
+                             element->isAA(),
+                             resultBounds);
+        default:
+            // something is wrong if we're trying to draw an empty element.
+            GrCrash("Unexpected element type");
+            return false;
     }
     return true;
 }
@@ -951,11 +944,11 @@
 
     SkClipStack::Iter iter(*clipDataIn.fClipStack,
                            SkClipStack::Iter::kBottom_IterStart);
-    const SkClipStack::Iter::Clip* clip = process_initial_clip_elements(&iter,
-                                                              *devResultBounds,
-                                                              &clearToInside,
-                                                              &firstOp,
-                                                              clipDataIn);
+    const Element* element = process_initial_clip_elements(&iter,
+                                                           *devResultBounds,
+                                                           &clearToInside,
+                                                           &firstOp,
+                                                           clipDataIn);
     // The scratch texture that we are drawing into can be substantially larger than the mask. Only
     // clear the part that we care about.
     fGpu->clear(&maskResultBounds,
@@ -966,9 +959,9 @@
     GrAutoScratchTexture temp;
     bool first = true;
     // walk through each clip element and perform its set op
-    for ( ; NULL != clip; clip = iter.next()) {
+    for ( ; NULL != element; element = iter.next()) {
 
-        SkRegion::Op op = clip->fOp;
+        SkRegion::Op op = element->getOp();
         if (first) {
             first = false;
             op = firstOp;
@@ -981,13 +974,13 @@
             }
 
             setup_boolean_blendcoeffs(drawState, op);
-            this->drawClipShape(accum, clip, *devResultBounds);
+            this->drawClipShape(accum, element, *devResultBounds);
 
         } else if (SkRegion::kReverseDifference_Op == op ||
                    SkRegion::kIntersect_Op == op) {
             // there is no point in intersecting a screen filling rectangle.
-            if (SkRegion::kIntersect_Op == op && NULL != clip->fRect &&
-                contains(*clip->fRect, *devResultBounds, clipDataIn.fOrigin)) {
+            if (SkRegion::kIntersect_Op == op && Element::kRect_Type == element->getType() &&
+                contains(element->getRect(), *devResultBounds, clipDataIn.fOrigin)) {
                 continue;
             }
 
@@ -1001,7 +994,7 @@
             // mask buffer can be substantially larger than the actually clip stack element. We
             // touch the minimum number of pixels necessary and use decal mode to combine it with
             // the accumulator
-            GrRect elementMaskBounds = clip->getBounds();
+            GrRect elementMaskBounds = element->getBounds();
             elementMaskBounds.offset(clipToMaskOffset);
             GrIRect elementMaskIBounds;
             elementMaskBounds.roundOut(&elementMaskIBounds);
@@ -1010,7 +1003,7 @@
             fGpu->clear(&elementMaskIBounds, 0x00000000, temp.texture()->asRenderTarget());
 
             setup_boolean_blendcoeffs(drawState, SkRegion::kReplace_Op);
-            this->drawClipShape(temp.texture(), clip, elementMaskIBounds);
+            this->drawClipShape(temp.texture(), element, elementMaskIBounds);
 
             // Now draw into the accumulator using the real operation
             // and the temp buffer as a texture
@@ -1019,7 +1012,7 @@
             // all the remaining ops can just be directly draw into
             // the accumulation buffer
             setup_boolean_blendcoeffs(drawState, op);
-            this->drawClipShape(accum, clip, *devResultBounds);
+            this->drawClipShape(accum, element, *devResultBounds);
         }
         accumClearedToZero = false;
     }
@@ -1096,25 +1089,25 @@
 
         SkClipStack::Iter iter(*oldClipData->fClipStack,
                                SkClipStack::Iter::kBottom_IterStart);
-        const SkClipStack::Iter::Clip* clip = process_initial_clip_elements(&iter,
-                                                  devRTRect,
-                                                  &clearToInside,
-                                                  &firstOp,
-                                                  clipDataIn);
+        const Element* element = process_initial_clip_elements(&iter,
+                                                               devRTRect,
+                                                               &clearToInside,
+                                                               &firstOp,
+                                                               clipDataIn);
 
         fGpu->clearStencilClip(devClipBounds, clearToInside);
         bool first = true;
 
         // walk through each clip element and perform its set op
         // with the existing clip.
-        for ( ; NULL != clip; clip = iter.next()) {
+        for ( ; NULL != element; element = iter.next()) {
             GrPathFill fill;
             bool fillInverted = false;
             // enabled at bottom of loop
             drawState->disableState(GrGpu::kModifyStencilClip_StateBit);
             // if the target is MSAA then we want MSAA enabled when the clip is soft
             if (rt->isMultisampled()) {
-                drawState->setState(GrDrawState::kHWAntialias_StateBit, clip->fDoAA);
+                drawState->setState(GrDrawState::kHWAntialias_StateBit, element->isAA());
             }
 
             // Can the clip element be drawn directly to the stencil buffer
@@ -1122,7 +1115,7 @@
             // resolve in/out status?
             bool canRenderDirectToStencil = false;
 
-            SkRegion::Op op = clip->fOp;
+            SkRegion::Op op = element->getOp();
             if (first) {
                 first = false;
                 op = firstOp;
@@ -1130,22 +1123,22 @@
 
             GrPathRenderer* pr = NULL;
             const SkPath* clipPath = NULL;
-            if (NULL != clip->fRect) {
+            if (Element::kRect_Type == element->getType()) {
                 canRenderDirectToStencil = true;
                 fill = kEvenOdd_GrPathFill;
                 fillInverted = false;
                 // there is no point in intersecting a screen filling
                 // rectangle.
                 if (SkRegion::kIntersect_Op == op &&
-                    contains(*clip->fRect, devRTRect, oldClipData->fOrigin)) {
+                    contains(element->getRect(), devRTRect, oldClipData->fOrigin)) {
                     continue;
                 }
             } else {
-                GrAssert(NULL != clip->fPath);
-                fill = get_path_fill(*clip->fPath);
+                GrAssert(Element::kPath_Type == element->getType());
+                clipPath = &element->getPath();
+                fill = get_path_fill(*clipPath);
                 fillInverted = GrIsFillInverted(fill);
                 fill = GrNonInvertedFill(fill);
-                clipPath = clip->fPath;
                 pr = this->getContext()->getPathRenderer(*clipPath, fill, fGpu, false, true);
                 if (NULL == pr) {
                     fGpu->setClip(oldClipData);
@@ -1180,10 +1173,11 @@
                     0x0000,
                     0xffff);
                 SET_RANDOM_COLOR
-                if (NULL != clip->fRect) {
+                if (Element::kRect_Type == element->getType()) {
                     *drawState->stencil() = gDrawToStencil;
-                    fGpu->drawSimpleRect(*clip->fRect, NULL);
+                    fGpu->drawSimpleRect(element->getRect(), NULL);
                 } else {
+                    GrAssert(Element::kPath_Type == element->getType());
                     if (canRenderDirectToStencil) {
                         *drawState->stencil() = gDrawToStencil;
                         pr->drawPath(*clipPath, fill, fGpu, false);
@@ -1199,10 +1193,11 @@
             for (int p = 0; p < passes; ++p) {
                 *drawState->stencil() = stencilSettings[p];
                 if (canDrawDirectToClip) {
-                    if (NULL != clip->fRect) {
+                    if (Element::kRect_Type == element->getType()) {
                         SET_RANDOM_COLOR
-                        fGpu->drawSimpleRect(*clip->fRect, NULL);
+                        fGpu->drawSimpleRect(element->getRect(), NULL);
                     } else {
+                        GrAssert(Element::kPath_Type == element->getType());
                         SET_RANDOM_COLOR
                         pr->drawPath(*clipPath, fill, fGpu, false);
                     }
@@ -1464,18 +1459,18 @@
 
     SkClipStack::Iter iter(*clipDataIn.fClipStack,
                            SkClipStack::Iter::kBottom_IterStart);
-    const SkClipStack::Iter::Clip* clip = process_initial_clip_elements(&iter,
-                                              *devResultBounds,
-                                              &clearToInside,
-                                              &firstOp,
-                                              clipDataIn);
+    const Element* element = process_initial_clip_elements(&iter,
+                                                           *devResultBounds,
+                                                           &clearToInside,
+                                                           &firstOp,
+                                                           clipDataIn);
 
     helper.clear(clearToInside ? 0xFF : 0x00);
 
     bool first = true;
-    for ( ; NULL != clip; clip = iter.next()) {
+    for ( ; NULL != element; element = iter.next()) {
 
-        SkRegion::Op op = clip->fOp;
+        SkRegion::Op op = element->getOp();
         if (first) {
             first = false;
             op = firstOp;
@@ -1499,20 +1494,20 @@
                 helper.draw(temp, SkRegion::kXOR_Op, false, 0xFF);
             }
 
-            if (NULL != clip->fRect) {
-
+            if (Element::kRect_Type == element->getType()) {
                 // convert the rect to a path so we can invert the fill
                 SkPath temp;
-                temp.addRect(*clip->fRect);
+                temp.addRect(element->getRect());
 
                 helper.draw(temp, SkRegion::kReplace_Op,
-                            kInverseEvenOdd_GrPathFill, clip->fDoAA,
+                            kInverseEvenOdd_GrPathFill, element->isAA(),
                             0x00);
-            } else if (NULL != clip->fPath) {
-                helper.draw(*clip->fPath,
+            } else {
+                GrAssert(Element::kPath_Type == element->getType());
+                helper.draw(element->getPath(),
                             SkRegion::kReplace_Op,
-                            invert_fill(get_path_fill(*clip->fPath)),
-                            clip->fDoAA,
+                            invert_fill(get_path_fill(element->getPath())),
+                            element->isAA(),
                             0x00);
             }
 
@@ -1521,17 +1516,14 @@
 
         // The other ops (union, xor, diff) only affect pixels inside
         // the geometry so they can just be drawn normally
-        if (NULL != clip->fRect) {
-
-            helper.draw(*clip->fRect,
+        if (Element::kRect_Type == element->getType()) {
+            helper.draw(element->getRect(), op, element->isAA(), 0xFF);
+        } else {
+            GrAssert(Element::kPath_Type == element->getType());
+            helper.draw(element->getPath(),
                         op,
-                        clip->fDoAA, 0xFF);
-
-        } else if (NULL != clip->fPath) {
-            helper.draw(*clip->fPath,
-                        op,
-                        get_path_fill(*clip->fPath),
-                        clip->fDoAA, 0xFF);
+                        get_path_fill(element->getPath()),
+                        element->isAA(), 0xFF);
         }
     }
 
diff --git a/src/gpu/GrClipMaskManager.h b/src/gpu/GrClipMaskManager.h
index 4894a3a..c3a1b5e 100644
--- a/src/gpu/GrClipMaskManager.h
+++ b/src/gpu/GrClipMaskManager.h
@@ -19,6 +19,7 @@
 #include "SkDeque.h"
 #include "SkPath.h"
 #include "SkRefCnt.h"
+#include "SkTLList.h"
 
 #include "GrClipMaskCache.h"
 
@@ -125,7 +126,7 @@
     bool useSWOnlyPath(const SkClipStack& clipIn);
 
     bool drawClipShape(GrTexture* target,
-                       const SkClipStack::Iter::Clip* clip,
+                       const SkClipStack::Element* element,
                        const GrIRect& resultBounds);
 
     void mergeMask(GrTexture* dstMask,
@@ -157,9 +158,10 @@
     typedef GrNoncopyable INHERITED;
 };
 
-
 namespace GrReducedClip {
 
+typedef SkTLList<SkClipStack::Element> ElementList;
+
 enum InitialState {
     kAllIn_InitialState,
     kAllOut_InitialState,
@@ -175,7 +177,7 @@
  *  may become a member function of SkClipStack when its interface is determined to be stable.
  */
 void GrReduceClipStack(const SkClipStack& stack,
-                       SkTDArray<SkClipStack::Iter::Clip>* resultClips,
+                       ElementList* result,
                        SkRect* resultBounds,
                        bool* resultsAreBounded,
                        InitialState* initialState);
diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp
index 929ca10..0de011c 100644
--- a/src/pdf/SkPDFDevice.cpp
+++ b/src/pdf/SkPDFDevice.cpp
@@ -226,8 +226,8 @@
     SkClipStack::B2TIter prefixIter(prefix);
     iter->reset(stack, SkClipStack::Iter::kBottom_IterStart);
 
-    const SkClipStack::B2TIter::Clip* prefixEntry;
-    const SkClipStack::B2TIter::Clip* iterEntry;
+    const SkClipStack::Element* prefixEntry;
+    const SkClipStack::Element* iterEntry;
 
     for (prefixEntry = prefixIter.next(); prefixEntry;
             prefixEntry = prefixIter.next()) {
@@ -236,12 +236,9 @@
         // Because of SkClipStack does internal intersection, the last clip
         // entry may differ.
         if (*prefixEntry != *iterEntry) {
-            SkASSERT(prefixEntry->fOp == SkRegion::kIntersect_Op);
-            SkASSERT(iterEntry->fOp == SkRegion::kIntersect_Op);
-            SkASSERT((iterEntry->fRect == NULL) ==
-                    (prefixEntry->fRect == NULL));
-            SkASSERT((iterEntry->fPath == NULL) ==
-                    (prefixEntry->fPath == NULL));
+            SkASSERT(prefixEntry->getOp() == SkRegion::kIntersect_Op);
+            SkASSERT(iterEntry->getOp() == SkRegion::kIntersect_Op);
+            SkASSERT(iterEntry->getType() == prefixEntry->getType());
             // back up the iterator by one
             iter->prev();
             prefixEntry = prefixIter.next();
@@ -306,10 +303,9 @@
     // If the clip stack does anything other than intersect or if it uses
     // an inverse fill type, we have to fall back to the clip region.
     bool needRegion = false;
-    const SkClipStack::B2TIter::Clip* clipEntry;
+    const SkClipStack::Element* clipEntry;
     for (clipEntry = iter.next(); clipEntry; clipEntry = iter.next()) {
-        if (clipEntry->fOp != SkRegion::kIntersect_Op ||
-                (clipEntry->fPath && clipEntry->fPath->isInverseFillType())) {
+        if (clipEntry->getOp() != SkRegion::kIntersect_Op || clipEntry->isInverseFilled()) {
             needRegion = true;
             break;
         }
@@ -323,19 +319,24 @@
         skip_clip_stack_prefix(fEntries[0].fClipStack, clipStack, &iter);
         SkMatrix transform;
         transform.setTranslate(translation.fX, translation.fY);
-        const SkClipStack::B2TIter::Clip* clipEntry;
+        const SkClipStack::Element* clipEntry;
         for (clipEntry = iter.next(); clipEntry; clipEntry = iter.next()) {
-            SkASSERT(clipEntry->fOp == SkRegion::kIntersect_Op);
-            if (clipEntry->fRect) {
-                SkRect translatedClip;
-                transform.mapRect(&translatedClip, *clipEntry->fRect);
-                emit_clip(NULL, &translatedClip, fContentStream);
-            } else if (clipEntry->fPath) {
-                SkPath translatedPath;
-                clipEntry->fPath->transform(transform, &translatedPath);
-                emit_clip(&translatedPath, NULL, fContentStream);
-            } else {
-                SkASSERT(false);
+            SkASSERT(clipEntry->getOp() == SkRegion::kIntersect_Op);
+            switch (clipEntry->getType()) {
+                case SkClipStack::Element::kRect_Type: {
+                    SkRect translatedClip;
+                    transform.mapRect(&translatedClip, clipEntry->getRect());
+                    emit_clip(NULL, &translatedClip, fContentStream);
+                    break;
+                }
+                case SkClipStack::Element::kPath_Type: {
+                    SkPath translatedPath;
+                    clipEntry->getPath().transform(transform, &translatedPath);
+                    emit_clip(&translatedPath, NULL, fContentStream);
+                    break;
+                }
+                default:
+                    SkASSERT(false);
             }
         }
     }
diff --git a/tests/ClipStackTest.cpp b/tests/ClipStackTest.cpp
index adce741..bbd833b 100644
--- a/tests/ClipStackTest.cpp
+++ b/tests/ClipStackTest.cpp
@@ -152,13 +152,14 @@
 
     // bottom to top iteration
     {
-        const SkClipStack::B2TIter::Clip* clip = NULL;
+        const SkClipStack::Element* element = NULL;
 
         SkClipStack::B2TIter iter(stack);
         int i;
 
-        for (i = 0, clip = iter.next(); clip; ++i, clip = iter.next()) {
-            REPORTER_ASSERT(reporter, *clip->fRect == gRects[i]);
+        for (i = 0, element = iter.next(); element; ++i, element = iter.next()) {
+            REPORTER_ASSERT(reporter, SkClipStack::Element::kRect_Type == element->getType());
+            REPORTER_ASSERT(reporter, element->getRect() == gRects[i]);
         }
 
         SkASSERT(i == 4);
@@ -166,13 +167,14 @@
 
     // top to bottom iteration
     {
-        const SkClipStack::Iter::Clip* clip = NULL;
+        const SkClipStack::Element* element = NULL;
 
         SkClipStack::Iter iter(stack, SkClipStack::Iter::kTop_IterStart);
         int i;
 
-        for (i = 3, clip = iter.prev(); clip; --i, clip = iter.prev()) {
-            REPORTER_ASSERT(reporter, *clip->fRect == gRects[i]);
+        for (i = 3, element = iter.prev(); element; --i, element = iter.prev()) {
+            REPORTER_ASSERT(reporter, SkClipStack::Element::kRect_Type == element->getType());
+            REPORTER_ASSERT(reporter, element->getRect() == gRects[i]);
         }
 
         SkASSERT(i == -1);
@@ -180,12 +182,13 @@
 
     // skipToTopmost
     {
-        const SkClipStack::Iter::Clip*clip = NULL;
+        const SkClipStack::Element* element = NULL;
 
         SkClipStack::Iter iter(stack, SkClipStack::Iter::kBottom_IterStart);
 
-        clip = iter.skipToTopmost(SkRegion::kUnion_Op);
-        REPORTER_ASSERT(reporter, *clip->fRect == gRects[3]);
+        element = iter.skipToTopmost(SkRegion::kUnion_Op);
+        REPORTER_ASSERT(reporter, SkClipStack::Element::kRect_Type == element->getType());
+        REPORTER_ASSERT(reporter, element->getRect() == gRects[3]);
     }
 }
 
@@ -362,10 +365,10 @@
 
     SkClipStack::Iter iter(stack, SkClipStack::Iter::kTop_IterStart);
 
-    const SkClipStack::Iter::Clip* clip = NULL;
+    const SkClipStack::Element* element = NULL;
     int count = 0;
 
-    for (clip = iter.prev(); clip; clip = iter.prev(), ++count) {
+    for (element = iter.prev(); element; element = iter.prev(), ++count) {
         ;
     }
 
@@ -520,36 +523,47 @@
     stack->clipDevPath(path, op, false);
 };
 
-static void add_elem_to_stack(const SkClipStack::Iter::Clip& clip, SkClipStack* stack) {
-    if (NULL != clip.fPath) {
-        stack->clipDevPath(*clip.fPath, clip.fOp, clip.fDoAA);
-    } else if (NULL != clip.fRect) {
-        stack->clipDevRect(*clip.fRect, clip.fOp, clip.fDoAA);
+static void add_elem_to_stack(const SkClipStack::Element& element, SkClipStack* stack) {
+    switch (element.getType()) {
+        case SkClipStack::Element::kRect_Type:
+            stack->clipDevRect(element.getRect(), element.getOp(), element.isAA());
+            break;
+        case SkClipStack::Element::kPath_Type:
+            stack->clipDevPath(element.getPath(), element.getOp(), element.isAA());
+            break;
+        case SkClipStack::Element::kEmpty_Type:
+            SkDEBUGFAIL("Why did the reducer produce an explicit empty.");
+            stack->clipEmpty();
+            break;
     }
 }
 
-static void add_elem_to_region(const SkClipStack::Iter::Clip& clip,
+static void add_elem_to_region(const SkClipStack::Element& element,
                                const SkIRect& bounds,
                                SkRegion* region) {
     SkRegion elemRegion;
     SkRegion boundsRgn(bounds);
 
-    if (NULL != clip.fPath) {
-        elemRegion.setPath(*clip.fPath, boundsRgn);
-    } else if (NULL != clip.fRect) {
-        SkPath path;
-        path.addRect(*clip.fRect);
-        elemRegion.setPath(path, boundsRgn);
-    } else {
-        // TODO: Figure out why we sometimes get here in the reduced clip stack.
-        region->setEmpty();
-        return;
+    switch (element.getType()) {
+        case SkClipStack::Element::kRect_Type: {
+            SkPath path;
+            path.addRect(element.getRect());
+            elemRegion.setPath(path, boundsRgn);
+            break;
+        }
+        case SkClipStack::Element::kPath_Type:
+            elemRegion.setPath(element.getPath(), boundsRgn);
+            break;
+        case SkClipStack::Element::kEmpty_Type:
+            // 
+            region->setEmpty();
+            return;
     }
-    region->op(elemRegion, clip.fOp);
+    region->op(elemRegion, element.getOp());
 }
 
 // This can assist with debugging the clip stack reduction code when the test below fails.
-static void print_clip(const SkClipStack::Iter::Clip& clip) {
+static void print_clip(const SkClipStack::Element& element) {
     static const char* kOpStrs[] = {
         "DF",
         "IS",
@@ -558,12 +572,13 @@
         "RD",
         "RP",
     };
-    if (NULL != clip.fRect || NULL != clip.fPath) {
-        const SkRect& bounds = clip.getBounds();
+    if (SkClipStack::Element::kEmpty_Type != element.getType()) {
+        const SkRect& bounds = element.getBounds();
+        bool isRect = SkClipStack::Element::kRect_Type == element.getType();
         SkDebugf("%s %s %s [%f %f] x [%f %f]\n",
-                 kOpStrs[clip.fOp],
-                 (NULL != clip.fRect ? "R" : "P"),
-                 ((NULL != clip.fPath && clip.fPath->isInverseFillType() ? "I" : " ")),
+                 kOpStrs[element.getOp()],
+                 (isRect ? "R" : "P"),
+                 (element.isInverseFilled() ? "I" : " "),
                  bounds.fLeft, bounds.fRight, bounds.fTop, bounds.fBottom);
     } else {
         SkDebugf("EM\n");
@@ -644,8 +659,9 @@
             }
         }
 
+        typedef GrReducedClip::ElementList ElementList;
         // Get the reduced version of the stack.
-        SkTDArray<SkClipStack::Iter::Clip> reducedClips;
+        ElementList reducedClips;
         SkRect resultBounds;
         bool bounded;
         GrReducedClip::InitialState initial;
@@ -657,8 +673,8 @@
             // whether the result is bounded or not, the whole plane should start outside the clip.
             reducedStack.clipEmpty();
         }
-        for (int c = 0; c < reducedClips.count(); ++c) {
-            add_elem_to_stack(reducedClips[c], &reducedStack);
+        for (ElementList::Iter iter = reducedClips.headIter(); NULL != iter.get(); iter.next()) {
+            add_elem_to_stack(*iter.get(), &reducedStack);
         }
         if (bounded) {
             // GrReduceClipStack() assumes that there is an implicit clip to the bounds
@@ -675,16 +691,16 @@
         SkRegion reducedRegion;
 
         region.setRect(inflatedIBounds);
-        const SkClipStack::Iter::Clip* clip;
+        const SkClipStack::Element* element;
         SkClipStack::Iter iter(stack, SkClipStack::Iter::kBottom_IterStart);
-        while ((clip = iter.next())) {
-            add_elem_to_region(*clip, inflatedIBounds, &region);
+        while ((element = iter.next())) {
+            add_elem_to_region(*element, inflatedIBounds, &region);
         }
 
         reducedRegion.setRect(inflatedIBounds);
         iter.reset(reducedStack, SkClipStack::Iter::kBottom_IterStart);
-        while ((clip = iter.next())) {
-            add_elem_to_region(*clip, inflatedIBounds, &reducedRegion);
+        while ((element = iter.next())) {
+            add_elem_to_region(*element, inflatedIBounds, &reducedRegion);
         }
 
         REPORTER_ASSERT(reporter, region == reducedRegion);
@@ -712,15 +728,14 @@
 
     // all of the above rects should have been intersected, leaving only 1 rect
     SkClipStack::B2TIter iter(stack);
-    const SkClipStack::B2TIter::Clip* clip = iter.next();
+    const SkClipStack::Element* element = iter.next();
     SkRect answer;
     answer.iset(25, 25, 75, 75);
 
-    REPORTER_ASSERT(reporter, clip);
-    REPORTER_ASSERT(reporter, clip->fRect);
-    REPORTER_ASSERT(reporter, !clip->fPath);
-    REPORTER_ASSERT(reporter, SkRegion::kIntersect_Op == clip->fOp);
-    REPORTER_ASSERT(reporter, *clip->fRect == answer);
+    REPORTER_ASSERT(reporter, NULL != element);
+    REPORTER_ASSERT(reporter, SkClipStack::Element::kRect_Type == element->getType());
+    REPORTER_ASSERT(reporter, SkRegion::kIntersect_Op == element->getOp());
+    REPORTER_ASSERT(reporter, element->getRect() == answer);
     // now check that we only had one in our iterator
     REPORTER_ASSERT(reporter, !iter.next());