Make SkClipStack::Element public.

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

git-svn-id: http://skia.googlecode.com/svn/trunk@6617 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/include/core/SkClipStack.h b/include/core/SkClipStack.h
index 7b3078d..eb825a9 100644
--- a/include/core/SkClipStack.h
+++ b/include/core/SkClipStack.h
@@ -9,11 +9,11 @@
 #define SkClipStack_DEFINED
 
 #include "SkDeque.h"
+#include "SkPath.h"
+#include "SkRect.h"
 #include "SkRegion.h"
 #include "SkTDArray.h"
 
-struct SkRect;
-class SkPath;
 
 // Because a single save/restore state can have multiple clips, this class
 // stores the stack depth (fSaveCount) and clips (fDeque) separately.
@@ -23,6 +23,167 @@
 // then the freshly decremented count.
 class SK_API SkClipStack {
 public:
+    enum BoundsType {
+        // The bounding box contains all the pixels that can be written to
+        kNormal_BoundsType,
+        // The bounding box contains all the pixels that cannot be written to.
+        // The real bound extends out to infinity and all the pixels outside
+        // of the bound can be written to. Note that some of the pixels inside
+        // the bound may also be writeable but all pixels that cannot be
+        // written to are guaranteed to be inside.
+        kInsideOut_BoundsType
+    };
+
+    class Element {
+    public:
+        enum Type {
+            //!< This element makes the clip empty (regardless of previous elements).
+            kEmpty_Type,
+            //!< This element combines a rect with the current clip using a set operation
+            kRect_Type,
+            //!< This element combines a path with the current clip using a set operation
+            kPath_Type,
+        };
+
+        Element() {
+            this->initCommon(0, SkRegion::kReplace_Op, false);
+            this->setEmpty();
+        }
+
+        Element(const SkRect& rect, SkRegion::Op op, bool doAA) {
+            this->initRect(0, rect, op, doAA);
+        }
+
+        Element(const SkPath& path, SkRegion::Op op, bool doAA) {
+            this->initPath(0, path, op, doAA);
+        }
+
+        //!< Call to get the type of the clip element.
+        Type getType() const { return fType; }
+
+        //!< Call if getType() is kPath to get the path.
+        const SkPath& getPath() const { return fPath; }
+
+        //!< Call if getType() is kRect to get the rect.
+        const SkRect& getRect() const { return fRect; }
+
+        //!< Call if getType() is not kEmpty to get the set operation used to combine this element.
+        SkRegion::Op getOp() const { return fOp; }
+
+        /** If getType() is not kEmpty this indicates whether the clip shape should be anti-aliased
+            when it is rasterized. */
+        bool isAA() const { return fDoAA; }
+
+        /** 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
+            have a different ID since the elements produce different clip result in the context of
+            their stacks. */
+        int32_t getGenID() const { return fGenID; }
+
+    private:
+        friend class SkClipStack;
+
+        SkPath          fPath;
+        SkRect          fRect;
+        int             fSaveCount; // save count of stack when this element was added.
+        SkRegion::Op    fOp;
+        Type            fType;
+        bool            fDoAA;
+
+        /* fFiniteBoundType and fFiniteBound are used to incrementally update the clip stack's
+           bound. When fFiniteBoundType is kNormal_BoundsType, fFiniteBound represents the
+           conservative bounding box of the pixels that aren't clipped (i.e., any pixels that can be
+           drawn to are inside the bound). When fFiniteBoundType is kInsideOut_BoundsType (which
+           occurs when a clip is inverse filled), fFiniteBound represents the conservative bounding
+           box of the pixels that _are_ clipped (i.e., any pixels that cannot be drawn to are inside
+           the bound). When fFiniteBoundType is kInsideOut_BoundsType the actual bound is the
+           infinite plane. This behavior of fFiniteBoundType and fFiniteBound is required so that we
+           can capture the cancelling out of the extensions to infinity when two inverse filled
+           clips are Booleaned together. */
+        SkClipStack::BoundsType fFiniteBoundType;
+        SkRect                  fFiniteBound;
+ 
+        // When element is applied to the previous elements in the stack is the result known to be
+        // equivalent to a single rect intersection? IIOW, is the clip effectively a rectangle.
+        bool                    fIsIntersectionOfRects;
+
+        int                     fGenID;
+
+        Element(int saveCount) {
+            this->initCommon(saveCount, SkRegion::kReplace_Op, false);
+            this->setEmpty();
+        }
+
+        Element(int saveCount, const SkRect& rect, SkRegion::Op op, bool doAA) {
+            this->initRect(saveCount, rect, op, doAA);
+        }
+
+        Element(int saveCount, const SkPath& path, SkRegion::Op op, bool doAA) {
+            this->initPath(saveCount, path, op, doAA);
+        }
+
+        void initCommon(int saveCount, SkRegion::Op op, bool doAA) {
+            fSaveCount = saveCount;
+            fOp = op;
+            fDoAA = doAA;
+            // A default of inside-out and empty bounds means the bounds are effectively void as it
+            // indicates that nothing is known to be outside the clip.
+            fFiniteBoundType = kInsideOut_BoundsType;
+            fFiniteBound.setEmpty();
+            fIsIntersectionOfRects = false;
+            fGenID = kInvalidGenID;
+        }
+
+        void initRect(int saveCount, const SkRect& rect, SkRegion::Op op, bool doAA) {
+            fRect = rect;
+            fType = kRect_Type;
+            this->initCommon(saveCount, op, doAA);
+        }
+
+        void initPath(int saveCount, const SkPath& path, SkRegion::Op op, bool doAA) {
+            fPath = path;
+            fType = kPath_Type;
+            this->initCommon(saveCount, op, doAA);
+        }
+
+        void setEmpty() {
+            fType = kEmpty_Type;
+            fFiniteBound.setEmpty();
+            fFiniteBoundType = kNormal_BoundsType;
+            fIsIntersectionOfRects = false;
+            fRect.setEmpty();
+            fPath.reset();
+            fGenID = kEmptyGenID;
+        }
+
+        // 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 
+          anti-aliasing. */
+        bool rectRectIntersectAllowed(const SkRect& newR, bool newAA) const;
+        /** Determines possible finite bounds for the Element given the previous element of the
+            stack */
+        void updateBoundAndGenID(const Element* prior);
+        // The different combination of fill & inverse fill when combining bounding boxes
+        enum FillCombo {
+            kPrev_Cur_FillCombo,
+            kPrev_InvCur_FillCombo,
+            kInvPrev_Cur_FillCombo,
+            kInvPrev_InvCur_FillCombo
+        };
+        // per-set operation functions used by updateBoundAndGenID().
+        inline void combineBoundsDiff(FillCombo combination, const SkRect& prevFinite);
+        inline void combineBoundsXOR(int combination, const SkRect& prevFinite);
+        inline void combineBoundsUnion(int combination, const SkRect& prevFinite);
+        inline void combineBoundsIntersection(int combination, const SkRect& prevFinite);
+        inline void combineBoundsRevDiff(int combination, const SkRect& prevFinite);
+    };
+
     SkClipStack();
     SkClipStack(const SkClipStack& b);
     explicit SkClipStack(const SkRect& r);
@@ -39,17 +200,6 @@
     void save();
     void restore();
 
-    enum BoundsType {
-        // The bounding box contains all the pixels that can be written to
-        kNormal_BoundsType,
-        // The bounding box contains all the pixels that cannot be written to.
-        // The real bound extends out to infinity and all the pixels outside
-        // of the bound can be written to. Note that some of the pixels inside
-        // the bound may also be writeable but all pixels that cannot be
-        // written to are guaranteed to be inside.
-        kInsideOut_BoundsType
-    };
-
     /**
      * getBounds places the current finite bound in its first parameter. In its
      * second, it indicates which kind of bound is being returned. If
@@ -111,9 +261,6 @@
 
     int32_t getTopmostGenID() const;
 
-private:
-    struct Element;
-
 public:
     class Iter {
     public: