15bb6825f10d64834ad1d1d967f590aebae285360epoger@google.com
25bb6825f10d64834ad1d1d967f590aebae285360epoger@google.com/*
35bb6825f10d64834ad1d1d967f590aebae285360epoger@google.com * Copyright 2011 Google Inc.
45bb6825f10d64834ad1d1d967f590aebae285360epoger@google.com *
55bb6825f10d64834ad1d1d967f590aebae285360epoger@google.com * Use of this source code is governed by a BSD-style license that can be
65bb6825f10d64834ad1d1d967f590aebae285360epoger@google.com * found in the LICENSE file.
75bb6825f10d64834ad1d1d967f590aebae285360epoger@google.com */
87ff121663ecde556b077c703c07b032c0d62dff8reed@google.com#ifndef SkClipStack_DEFINED
97ff121663ecde556b077c703c07b032c0d62dff8reed@google.com#define SkClipStack_DEFINED
107ff121663ecde556b077c703c07b032c0d62dff8reed@google.com
117ff121663ecde556b077c703c07b032c0d62dff8reed@google.com#include "SkDeque.h"
1223d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com#include "SkPath.h"
1323d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com#include "SkRect.h"
147ff121663ecde556b077c703c07b032c0d62dff8reed@google.com#include "SkRegion.h"
15e05469555381ff89713742474ebd0af0df461dd4robertphillips@google.com#include "SkTDArray.h"
167ff121663ecde556b077c703c07b032c0d62dff8reed@google.com
177ff121663ecde556b077c703c07b032c0d62dff8reed@google.com
18ea85e7af1781c4879d22e5e5ad399be6e9d9eefcrobertphillips@google.com// Because a single save/restore state can have multiple clips, this class
19ea85e7af1781c4879d22e5e5ad399be6e9d9eefcrobertphillips@google.com// stores the stack depth (fSaveCount) and clips (fDeque) separately.
20ea85e7af1781c4879d22e5e5ad399be6e9d9eefcrobertphillips@google.com// Each clip in fDeque stores the stack state to which it belongs
21ea85e7af1781c4879d22e5e5ad399be6e9d9eefcrobertphillips@google.com// (i.e., the fSaveCount in force when it was added). Restores are thus
22ea85e7af1781c4879d22e5e5ad399be6e9d9eefcrobertphillips@google.com// implemented by removing clips from fDeque that have an fSaveCount larger
23ea85e7af1781c4879d22e5e5ad399be6e9d9eefcrobertphillips@google.com// then the freshly decremented count.
242083387d719b933797044ad07efd3bb67f99a5c5ctguil@chromium.orgclass SK_API SkClipStack {
257ff121663ecde556b077c703c07b032c0d62dff8reed@google.compublic:
2623d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com    enum BoundsType {
2723d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        // The bounding box contains all the pixels that can be written to
2823d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        kNormal_BoundsType,
2923d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        // The bounding box contains all the pixels that cannot be written to.
3023d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        // The real bound extends out to infinity and all the pixels outside
3123d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        // of the bound can be written to. Note that some of the pixels inside
3223d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        // the bound may also be writeable but all pixels that cannot be
3323d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        // written to are guaranteed to be inside.
3423d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        kInsideOut_BoundsType
3523d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com    };
3623d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com
3723d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com    class Element {
3823d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com    public:
3923d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        enum Type {
4023d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com            //!< This element makes the clip empty (regardless of previous elements).
4123d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com            kEmpty_Type,
4223d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com            //!< This element combines a rect with the current clip using a set operation
4323d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com            kRect_Type,
4423d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com            //!< This element combines a path with the current clip using a set operation
4523d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com            kPath_Type,
4623d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        };
4723d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com
4823d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        Element() {
4923d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com            this->initCommon(0, SkRegion::kReplace_Op, false);
5023d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com            this->setEmpty();
5123d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        }
5223d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com
5323d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        Element(const SkRect& rect, SkRegion::Op op, bool doAA) {
5423d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com            this->initRect(0, rect, op, doAA);
5523d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        }
5623d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com
5723d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        Element(const SkPath& path, SkRegion::Op op, bool doAA) {
5823d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com            this->initPath(0, path, op, doAA);
5923d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        }
6023d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com
61e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com        bool operator== (const Element& element) const {
62e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com            if (this == &element) {
63e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com                return true;
64e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com            }
65e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com            if (fOp != element.fOp ||
66e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com                fType != element.fType ||
67e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com                fDoAA != element.fDoAA ||
68e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com                fSaveCount != element.fSaveCount) {
69e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com                return false;
70e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com            }
71e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com            switch (fType) {
72e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com                case kPath_Type:
73e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com                    return fPath == element.fPath;
74e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com                case kRect_Type:
75e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com                    return fRect == element.fRect;
76e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com                case kEmpty_Type:
77e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com                    return true;
78e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com                default:
79e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com                    SkDEBUGFAIL("Unexpected type.");
80e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com                    return false;
81e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com            }
82e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com        }
83e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com        bool operator!= (const Element& element) const { return !(*this == element); }
84e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com
8523d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        //!< Call to get the type of the clip element.
8623d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        Type getType() const { return fType; }
8723d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com
8823d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        //!< Call if getType() is kPath to get the path.
8923d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        const SkPath& getPath() const { return fPath; }
9023d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com
9123d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        //!< Call if getType() is kRect to get the rect.
9223d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        const SkRect& getRect() const { return fRect; }
9323d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com
9423d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        //!< Call if getType() is not kEmpty to get the set operation used to combine this element.
9523d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        SkRegion::Op getOp() const { return fOp; }
9623d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com
9723d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        /** If getType() is not kEmpty this indicates whether the clip shape should be anti-aliased
9823d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com            when it is rasterized. */
9923d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        bool isAA() const { return fDoAA; }
10023d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com
101c377c7fd83a90e27e92aca381ce2c2c2aac799e2bsalomon@google.com        //!< Inverts the fill of the clip shape. Note that a kEmpty element remains kEmpty.
102c377c7fd83a90e27e92aca381ce2c2c2aac799e2bsalomon@google.com        void invertShapeFillType();
103c377c7fd83a90e27e92aca381ce2c2c2aac799e2bsalomon@google.com
104c377c7fd83a90e27e92aca381ce2c2c2aac799e2bsalomon@google.com        //!< Sets the set operation represented by the element.
105e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com        void setOp(SkRegion::Op op) { fOp = op; }
106e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com
10723d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        /** The GenID can be used by clip stack clients to cache representations of the clip. The
10823d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com            ID corresponds to the set of clip elements up to and including this element within the
10923d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com            stack not to the element itself. That is the same clip path in different stacks will
11023d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com            have a different ID since the elements produce different clip result in the context of
11123d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com            their stacks. */
112a4e9612567d41005e0ade42c615050f2262f6a14commit-bot@chromium.org        int32_t getGenID() const { SkASSERT(kInvalidGenID != fGenID); return fGenID; }
11323d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com
114e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com        /**
115e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com         * Gets the bounds of the clip element, either the rect or path bounds. (Whether the shape
116e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com         * is inverse filled is not considered.)
117e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com         */
118e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com        const SkRect& getBounds() const {
119e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com            static const SkRect kEmpty = { 0, 0, 0, 0 };
120e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com            switch (fType) {
121e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com                case kRect_Type:
122e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com                    return fRect;
123e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com                case kPath_Type:
124e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com                    return fPath.getBounds();
125e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com                case kEmpty_Type:
126e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com                    return kEmpty;
127e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com                default:
128e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com                    SkDEBUGFAIL("Unexpected type.");
129e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com                    return kEmpty;
130e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com            }
131e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com        }
132e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com
133e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com        /**
134e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com         * Conservatively checks whether the clip shape contains the rect param. (Whether the shape
135e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com         * is inverse filled is not considered.)
136e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com         */
137e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com        bool contains(const SkRect& rect) const {
138e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com            switch (fType) {
139e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com                case kRect_Type:
140e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com                    return fRect.contains(rect);
141e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com                case kPath_Type:
142e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com                    return fPath.conservativelyContainsRect(rect);
143e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com                case kEmpty_Type:
144e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com                    return false;
145e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com                default:
146e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com                    SkDEBUGFAIL("Unexpected type.");
147e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com                    return false;
148e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com            }
149e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com        }
150e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com
151e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com        /**
152e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com         * Is the clip shape inverse filled.
153e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com         */
154e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com        bool isInverseFilled() const {
155e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com            return kPath_Type == fType && fPath.isInverseFillType();
156e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com        }
157e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com
15823d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com    private:
15923d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        friend class SkClipStack;
16023d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com
16123d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        SkPath          fPath;
16223d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        SkRect          fRect;
16323d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        int             fSaveCount; // save count of stack when this element was added.
16423d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        SkRegion::Op    fOp;
16523d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        Type            fType;
16623d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        bool            fDoAA;
16723d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com
16823d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        /* fFiniteBoundType and fFiniteBound are used to incrementally update the clip stack's
16923d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com           bound. When fFiniteBoundType is kNormal_BoundsType, fFiniteBound represents the
17023d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com           conservative bounding box of the pixels that aren't clipped (i.e., any pixels that can be
17123d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com           drawn to are inside the bound). When fFiniteBoundType is kInsideOut_BoundsType (which
17223d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com           occurs when a clip is inverse filled), fFiniteBound represents the conservative bounding
17323d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com           box of the pixels that _are_ clipped (i.e., any pixels that cannot be drawn to are inside
17423d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com           the bound). When fFiniteBoundType is kInsideOut_BoundsType the actual bound is the
17523d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com           infinite plane. This behavior of fFiniteBoundType and fFiniteBound is required so that we
17623d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com           can capture the cancelling out of the extensions to infinity when two inverse filled
17723d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com           clips are Booleaned together. */
17823d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        SkClipStack::BoundsType fFiniteBoundType;
17923d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        SkRect                  fFiniteBound;
180f8f29177dd064bcfa4a7458e24434a807bca20b4skia.committer@gmail.com
18123d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        // When element is applied to the previous elements in the stack is the result known to be
18223d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        // equivalent to a single rect intersection? IIOW, is the clip effectively a rectangle.
18323d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        bool                    fIsIntersectionOfRects;
18423d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com
18523d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        int                     fGenID;
18623d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com
18723d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        Element(int saveCount) {
18823d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com            this->initCommon(saveCount, SkRegion::kReplace_Op, false);
18923d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com            this->setEmpty();
19023d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        }
19123d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com
19223d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        Element(int saveCount, const SkRect& rect, SkRegion::Op op, bool doAA) {
19323d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com            this->initRect(saveCount, rect, op, doAA);
19423d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        }
19523d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com
19623d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        Element(int saveCount, const SkPath& path, SkRegion::Op op, bool doAA) {
19723d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com            this->initPath(saveCount, path, op, doAA);
19823d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        }
19923d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com
20023d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        void initCommon(int saveCount, SkRegion::Op op, bool doAA) {
20123d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com            fSaveCount = saveCount;
20223d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com            fOp = op;
20323d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com            fDoAA = doAA;
20423d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com            // A default of inside-out and empty bounds means the bounds are effectively void as it
20523d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com            // indicates that nothing is known to be outside the clip.
20623d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com            fFiniteBoundType = kInsideOut_BoundsType;
20723d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com            fFiniteBound.setEmpty();
20823d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com            fIsIntersectionOfRects = false;
20923d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com            fGenID = kInvalidGenID;
21023d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        }
21123d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com
21223d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        void initRect(int saveCount, const SkRect& rect, SkRegion::Op op, bool doAA) {
21323d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com            fRect = rect;
21423d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com            fType = kRect_Type;
21523d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com            this->initCommon(saveCount, op, doAA);
21623d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        }
21723d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com
21823d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        void initPath(int saveCount, const SkPath& path, SkRegion::Op op, bool doAA) {
21923d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com            fPath = path;
22023d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com            fType = kPath_Type;
22123d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com            this->initCommon(saveCount, op, doAA);
22223d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        }
22323d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com
22423d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        void setEmpty() {
22523d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com            fType = kEmpty_Type;
22623d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com            fFiniteBound.setEmpty();
22723d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com            fFiniteBoundType = kNormal_BoundsType;
22823d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com            fIsIntersectionOfRects = false;
22923d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com            fRect.setEmpty();
23023d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com            fPath.reset();
23123d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com            fGenID = kEmptyGenID;
23223d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        }
23323d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com
23423d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        // All Element methods below are only used within SkClipStack.cpp
23523d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        inline void checkEmpty() const;
23623d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        inline bool canBeIntersectedInPlace(int saveCount, SkRegion::Op op) const;
23723d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        /* This method checks to see if two rect clips can be safely merged into one. The issue here
238f8f29177dd064bcfa4a7458e24434a807bca20b4skia.committer@gmail.com          is that to be strictly correct all the edges of the resulting rect must have the same
23923d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com          anti-aliasing. */
24023d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        bool rectRectIntersectAllowed(const SkRect& newR, bool newAA) const;
24123d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        /** Determines possible finite bounds for the Element given the previous element of the
24223d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com            stack */
24323d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        void updateBoundAndGenID(const Element* prior);
24423d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        // The different combination of fill & inverse fill when combining bounding boxes
24523d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        enum FillCombo {
24623d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com            kPrev_Cur_FillCombo,
24723d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com            kPrev_InvCur_FillCombo,
24823d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com            kInvPrev_Cur_FillCombo,
24923d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com            kInvPrev_InvCur_FillCombo
25023d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        };
25123d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        // per-set operation functions used by updateBoundAndGenID().
25223d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        inline void combineBoundsDiff(FillCombo combination, const SkRect& prevFinite);
25323d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        inline void combineBoundsXOR(int combination, const SkRect& prevFinite);
25423d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        inline void combineBoundsUnion(int combination, const SkRect& prevFinite);
25523d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        inline void combineBoundsIntersection(int combination, const SkRect& prevFinite);
25623d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com        inline void combineBoundsRevDiff(int combination, const SkRect& prevFinite);
25723d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com    };
25823d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com
2597ff121663ecde556b077c703c07b032c0d62dff8reed@google.com    SkClipStack();
2602efaa066816c95dbbf50c10a7320c6ba215f3a45vandebo@chromium.org    SkClipStack(const SkClipStack& b);
26187788b18c6d052a419d83851ef6b5347b5b905bdrobertphillips@google.com    explicit SkClipStack(const SkRect& r);
2627ba33c7ac6383856dfe19f5fcf6968363037d393robertphillips@google.com    explicit SkClipStack(const SkIRect& r);
263deef1e7433887329d28d96bb184805b9970184e6vandebo@chromium.org    ~SkClipStack();
2647ff121663ecde556b077c703c07b032c0d62dff8reed@google.com
2652efaa066816c95dbbf50c10a7320c6ba215f3a45vandebo@chromium.org    SkClipStack& operator=(const SkClipStack& b);
2662efaa066816c95dbbf50c10a7320c6ba215f3a45vandebo@chromium.org    bool operator==(const SkClipStack& b) const;
2672efaa066816c95dbbf50c10a7320c6ba215f3a45vandebo@chromium.org    bool operator!=(const SkClipStack& b) const { return !(*this == b); }
2682efaa066816c95dbbf50c10a7320c6ba215f3a45vandebo@chromium.org
2697ff121663ecde556b077c703c07b032c0d62dff8reed@google.com    void reset();
2707ff121663ecde556b077c703c07b032c0d62dff8reed@google.com
2717ff121663ecde556b077c703c07b032c0d62dff8reed@google.com    int getSaveCount() const { return fSaveCount; }
2727ff121663ecde556b077c703c07b032c0d62dff8reed@google.com    void save();
2737ff121663ecde556b077c703c07b032c0d62dff8reed@google.com    void restore();
2747ff121663ecde556b077c703c07b032c0d62dff8reed@google.com
2756fd897d4dcf13d1c0de6a7cbd251487ae1095e42robertphillips@google.com    /**
2766fd897d4dcf13d1c0de6a7cbd251487ae1095e42robertphillips@google.com     * getBounds places the current finite bound in its first parameter. In its
2771fde19f3b72345b473a1a9bd64729237a388813frmistry@google.com     * second, it indicates which kind of bound is being returned. If
278e60c6253c3bca3e8800d02290ace13362ff7d724robertphillips@google.com     * 'canvFiniteBound' is a normal bounding box then it encloses all writeable
2791fde19f3b72345b473a1a9bd64729237a388813frmistry@google.com     * pixels. If 'canvFiniteBound' is an inside out bounding box then it
2806fd897d4dcf13d1c0de6a7cbd251487ae1095e42robertphillips@google.com     * encloses all the un-writeable pixels and the true/normal bound is the
281ea85e7af1781c4879d22e5e5ad399be6e9d9eefcrobertphillips@google.com     * infinite plane. isIntersectionOfRects is an optional parameter
282e60c6253c3bca3e8800d02290ace13362ff7d724robertphillips@google.com     * that is true if 'canvFiniteBound' resulted from an intersection of rects.
2836fd897d4dcf13d1c0de6a7cbd251487ae1095e42robertphillips@google.com     */
2841fde19f3b72345b473a1a9bd64729237a388813frmistry@google.com    void getBounds(SkRect* canvFiniteBound,
285ea85e7af1781c4879d22e5e5ad399be6e9d9eefcrobertphillips@google.com                   BoundsType* boundType,
286ea85e7af1781c4879d22e5e5ad399be6e9d9eefcrobertphillips@google.com                   bool* isIntersectionOfRects = NULL) const;
2876fd897d4dcf13d1c0de6a7cbd251487ae1095e42robertphillips@google.com
288a588ffb6f5d538b3f7bb021b391dea78dc1312cfbsalomon@google.com    /**
289a588ffb6f5d538b3f7bb021b391dea78dc1312cfbsalomon@google.com     * Takes an input rect in device space and conservatively clips it to the
290a588ffb6f5d538b3f7bb021b391dea78dc1312cfbsalomon@google.com     * clip-stack. If false is returned then the rect does not intersect the
291a588ffb6f5d538b3f7bb021b391dea78dc1312cfbsalomon@google.com     * clip and is unmodified.
292a588ffb6f5d538b3f7bb021b391dea78dc1312cfbsalomon@google.com     */
293a588ffb6f5d538b3f7bb021b391dea78dc1312cfbsalomon@google.com    bool intersectRectWithClip(SkRect* devRect) const;
294a588ffb6f5d538b3f7bb021b391dea78dc1312cfbsalomon@google.com
295c09cfc3f6d6d9a6ee9386fa5f36d605852693138junov@chromium.org    /**
296c09cfc3f6d6d9a6ee9386fa5f36d605852693138junov@chromium.org     * Returns true if the input rect in device space is entirely contained
297c09cfc3f6d6d9a6ee9386fa5f36d605852693138junov@chromium.org     * by the clip. A return value of false does not guarantee that the rect
298c09cfc3f6d6d9a6ee9386fa5f36d605852693138junov@chromium.org     * is not contained by the clip.
299c09cfc3f6d6d9a6ee9386fa5f36d605852693138junov@chromium.org     */
300c09cfc3f6d6d9a6ee9386fa5f36d605852693138junov@chromium.org    bool quickContains(const SkRect& devRect) const;
301c09cfc3f6d6d9a6ee9386fa5f36d605852693138junov@chromium.org
302ba80e479892aa491c507bd9efb41c43b0e75c559reed@google.com    void clipDevRect(const SkIRect& ir, SkRegion::Op op) {
3037ff121663ecde556b077c703c07b032c0d62dff8reed@google.com        SkRect r;
3047ff121663ecde556b077c703c07b032c0d62dff8reed@google.com        r.set(ir);
305e9438a94e1dc3a3be96ecc13e799278e90cf8ef5reed@google.com        this->clipDevRect(r, op, false);
3067ff121663ecde556b077c703c07b032c0d62dff8reed@google.com    }
307e9438a94e1dc3a3be96ecc13e799278e90cf8ef5reed@google.com    void clipDevRect(const SkRect&, SkRegion::Op, bool doAA);
308e9438a94e1dc3a3be96ecc13e799278e90cf8ef5reed@google.com    void clipDevPath(const SkPath&, SkRegion::Op, bool doAA);
30905b4f721bd077dd67c6d8a4457323e4efafe2d91reed@google.com    // An optimized version of clipDevRect(emptyRect, kIntersect, ...)
31005b4f721bd077dd67c6d8a4457323e4efafe2d91reed@google.com    void clipEmpty();
3117ff121663ecde556b077c703c07b032c0d62dff8reed@google.com
31287788b18c6d052a419d83851ef6b5347b5b905bdrobertphillips@google.com    /**
3131fde19f3b72345b473a1a9bd64729237a388813frmistry@google.com     * isWideOpen returns true if the clip state corresponds to the infinite
31487788b18c6d052a419d83851ef6b5347b5b905bdrobertphillips@google.com     * plane (i.e., draws are not limited at all)
31587788b18c6d052a419d83851ef6b5347b5b905bdrobertphillips@google.com     */
31687788b18c6d052a419d83851ef6b5347b5b905bdrobertphillips@google.com    bool isWideOpen() const;
31787788b18c6d052a419d83851ef6b5347b5b905bdrobertphillips@google.com
318e05469555381ff89713742474ebd0af0df461dd4robertphillips@google.com    /**
319e05469555381ff89713742474ebd0af0df461dd4robertphillips@google.com     * The generation ID has three reserved values to indicate special
3206a2ba9e48fd4418c403256dc2e55d6e31d03f7b8bsalomon@google.com     * (potentially ignorable) cases
321e05469555381ff89713742474ebd0af0df461dd4robertphillips@google.com     */
322a4e9612567d41005e0ade42c615050f2262f6a14commit-bot@chromium.org    static const int32_t kInvalidGenID = 0;     //!< Invalid id that is never returned by
323a4e9612567d41005e0ade42c615050f2262f6a14commit-bot@chromium.org                                                //!< SkClipStack. Useful when caching clips
324a4e9612567d41005e0ade42c615050f2262f6a14commit-bot@chromium.org                                                //!< based on GenID.
325e05469555381ff89713742474ebd0af0df461dd4robertphillips@google.com    static const int32_t kEmptyGenID = 1;       // no pixels writeable
326e05469555381ff89713742474ebd0af0df461dd4robertphillips@google.com    static const int32_t kWideOpenGenID = 2;    // all pixels writeable
327e05469555381ff89713742474ebd0af0df461dd4robertphillips@google.com
3287b4e881b6f0c5d4b77363cf4c4dd6dd15ebc1a3arobertphillips@google.com    int32_t getTopmostGenID() const;
3297b4e881b6f0c5d4b77363cf4c4dd6dd15ebc1a3arobertphillips@google.com
330de9abcab679c999d879edf19895a06c6acc5cd7erobertphillips@google.compublic:
331de9abcab679c999d879edf19895a06c6acc5cd7erobertphillips@google.com    class Iter {
3327ff121663ecde556b077c703c07b032c0d62dff8reed@google.com    public:
333de9abcab679c999d879edf19895a06c6acc5cd7erobertphillips@google.com        enum IterStart {
334897a162ac9fa65bcb4063ac76d603f51de8a5b48robertphillips@google.com            kBottom_IterStart = SkDeque::Iter::kFront_IterStart,
335897a162ac9fa65bcb4063ac76d603f51de8a5b48robertphillips@google.com            kTop_IterStart = SkDeque::Iter::kBack_IterStart
336de9abcab679c999d879edf19895a06c6acc5cd7erobertphillips@google.com        };
337de9abcab679c999d879edf19895a06c6acc5cd7erobertphillips@google.com
338c93d11c65ab5bd25a956ac1a68407b76610eed27bsalomon@google.com        /**
339c93d11c65ab5bd25a956ac1a68407b76610eed27bsalomon@google.com         * Creates an uninitialized iterator. Must be reset()
340c93d11c65ab5bd25a956ac1a68407b76610eed27bsalomon@google.com         */
341de9abcab679c999d879edf19895a06c6acc5cd7erobertphillips@google.com        Iter();
342c93d11c65ab5bd25a956ac1a68407b76610eed27bsalomon@google.com
343de9abcab679c999d879edf19895a06c6acc5cd7erobertphillips@google.com        Iter(const SkClipStack& stack, IterStart startLoc);
3447ff121663ecde556b077c703c07b032c0d62dff8reed@google.com
3457ff121663ecde556b077c703c07b032c0d62dff8reed@google.com        /**
346e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com         *  Return the clip element for this iterator. If next()/prev() returns NULL, then the
347e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com         *  iterator is done.
3487ff121663ecde556b077c703c07b032c0d62dff8reed@google.com         */
349e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com        const Element* next();
350e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com        const Element* prev();
3517ff121663ecde556b077c703c07b032c0d62dff8reed@google.com
352c93d11c65ab5bd25a956ac1a68407b76610eed27bsalomon@google.com        /**
353e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com         * Moves the iterator to the topmost element with the specified RegionOp and returns that
354e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com         * element. If no clip element with that op is found, the first element is returned.
355c0c941d072fc552f2d98dba299810e4333bd65a8robertphillips@google.com         */
356e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com        const Element* skipToTopmost(SkRegion::Op op);
357c0c941d072fc552f2d98dba299810e4333bd65a8robertphillips@google.com
358c0c941d072fc552f2d98dba299810e4333bd65a8robertphillips@google.com        /**
359c93d11c65ab5bd25a956ac1a68407b76610eed27bsalomon@google.com         * Restarts the iterator on a clip stack.
360c93d11c65ab5bd25a956ac1a68407b76610eed27bsalomon@google.com         */
361de9abcab679c999d879edf19895a06c6acc5cd7erobertphillips@google.com        void reset(const SkClipStack& stack, IterStart startLoc);
362c93d11c65ab5bd25a956ac1a68407b76610eed27bsalomon@google.com
3637ff121663ecde556b077c703c07b032c0d62dff8reed@google.com    private:
364c0c941d072fc552f2d98dba299810e4333bd65a8robertphillips@google.com        const SkClipStack* fStack;
365c0c941d072fc552f2d98dba299810e4333bd65a8robertphillips@google.com        SkDeque::Iter      fIter;
366de9abcab679c999d879edf19895a06c6acc5cd7erobertphillips@google.com    };
367de9abcab679c999d879edf19895a06c6acc5cd7erobertphillips@google.com
3681fde19f3b72345b473a1a9bd64729237a388813frmistry@google.com    /**
369897a162ac9fa65bcb4063ac76d603f51de8a5b48robertphillips@google.com     * The B2TIter iterates from the bottom of the stack to the top.
370897a162ac9fa65bcb4063ac76d603f51de8a5b48robertphillips@google.com     * It inherits privately from Iter to prevent access to reverse iteration.
371897a162ac9fa65bcb4063ac76d603f51de8a5b48robertphillips@google.com     */
372897a162ac9fa65bcb4063ac76d603f51de8a5b48robertphillips@google.com    class B2TIter : private Iter {
373de9abcab679c999d879edf19895a06c6acc5cd7erobertphillips@google.com    public:
374897a162ac9fa65bcb4063ac76d603f51de8a5b48robertphillips@google.com        B2TIter() {}
375de9abcab679c999d879edf19895a06c6acc5cd7erobertphillips@google.com
376de9abcab679c999d879edf19895a06c6acc5cd7erobertphillips@google.com        /**
3771fde19f3b72345b473a1a9bd64729237a388813frmistry@google.com         * Wrap Iter's 2 parameter ctor to force initialization to the
378897a162ac9fa65bcb4063ac76d603f51de8a5b48robertphillips@google.com         * beginning of the deque/bottom of the stack
379de9abcab679c999d879edf19895a06c6acc5cd7erobertphillips@google.com         */
3801fde19f3b72345b473a1a9bd64729237a388813frmistry@google.com        B2TIter(const SkClipStack& stack)
381897a162ac9fa65bcb4063ac76d603f51de8a5b48robertphillips@google.com        : INHERITED(stack, kBottom_IterStart) {
382de9abcab679c999d879edf19895a06c6acc5cd7erobertphillips@google.com        }
383de9abcab679c999d879edf19895a06c6acc5cd7erobertphillips@google.com
384de9abcab679c999d879edf19895a06c6acc5cd7erobertphillips@google.com        using Iter::next;
385de9abcab679c999d879edf19895a06c6acc5cd7erobertphillips@google.com
386de9abcab679c999d879edf19895a06c6acc5cd7erobertphillips@google.com        /**
3871fde19f3b72345b473a1a9bd64729237a388813frmistry@google.com         * Wrap Iter::reset to force initialization to the
388897a162ac9fa65bcb4063ac76d603f51de8a5b48robertphillips@google.com         * beginning of the deque/bottom of the stack
389de9abcab679c999d879edf19895a06c6acc5cd7erobertphillips@google.com         */
390de9abcab679c999d879edf19895a06c6acc5cd7erobertphillips@google.com        void reset(const SkClipStack& stack) {
391897a162ac9fa65bcb4063ac76d603f51de8a5b48robertphillips@google.com            this->INHERITED::reset(stack, kBottom_IterStart);
392de9abcab679c999d879edf19895a06c6acc5cd7erobertphillips@google.com        }
393de9abcab679c999d879edf19895a06c6acc5cd7erobertphillips@google.com
394de9abcab679c999d879edf19895a06c6acc5cd7erobertphillips@google.com    private:
395de9abcab679c999d879edf19895a06c6acc5cd7erobertphillips@google.com
396de9abcab679c999d879edf19895a06c6acc5cd7erobertphillips@google.com        typedef Iter INHERITED;
3977ff121663ecde556b077c703c07b032c0d62dff8reed@google.com    };
3987ff121663ecde556b077c703c07b032c0d62dff8reed@google.com
3996fd897d4dcf13d1c0de6a7cbd251487ae1095e42robertphillips@google.com    /**
4001fde19f3b72345b473a1a9bd64729237a388813frmistry@google.com     * GetConservativeBounds returns a conservative bound of the current clip.
4011fde19f3b72345b473a1a9bd64729237a388813frmistry@google.com     * Since this could be the infinite plane (if inverse fills were involved) the
4021fde19f3b72345b473a1a9bd64729237a388813frmistry@google.com     * maxWidth and maxHeight parameters can be used to limit the returned bound
4036fd897d4dcf13d1c0de6a7cbd251487ae1095e42robertphillips@google.com     * to the expected drawing area. Similarly, the offsetX and offsetY parameters
4041fde19f3b72345b473a1a9bd64729237a388813frmistry@google.com     * allow the caller to offset the returned bound to account for translated
4056fd897d4dcf13d1c0de6a7cbd251487ae1095e42robertphillips@google.com     * drawing areas (i.e., those resulting from a saveLayer). For finite bounds,
4061fde19f3b72345b473a1a9bd64729237a388813frmistry@google.com     * the translation (+offsetX, +offsetY) is applied before the clamp to the
4076fd897d4dcf13d1c0de6a7cbd251487ae1095e42robertphillips@google.com     * maximum rectangle: [0,maxWidth) x [0,maxHeight).
4081fde19f3b72345b473a1a9bd64729237a388813frmistry@google.com     * isIntersectionOfRects is an optional parameter that is true when
4097ba33c7ac6383856dfe19f5fcf6968363037d393robertphillips@google.com     * 'devBounds' is the result of an intersection of rects. In this case
4107ba33c7ac6383856dfe19f5fcf6968363037d393robertphillips@google.com     * 'devBounds' is the exact answer/clip.
4116fd897d4dcf13d1c0de6a7cbd251487ae1095e42robertphillips@google.com     */
4126fd897d4dcf13d1c0de6a7cbd251487ae1095e42robertphillips@google.com    void getConservativeBounds(int offsetX,
4136fd897d4dcf13d1c0de6a7cbd251487ae1095e42robertphillips@google.com                               int offsetY,
4146fd897d4dcf13d1c0de6a7cbd251487ae1095e42robertphillips@google.com                               int maxWidth,
4156fd897d4dcf13d1c0de6a7cbd251487ae1095e42robertphillips@google.com                               int maxHeight,
416e60c6253c3bca3e8800d02290ace13362ff7d724robertphillips@google.com                               SkRect* devBounds,
417ea85e7af1781c4879d22e5e5ad399be6e9d9eefcrobertphillips@google.com                               bool* isIntersectionOfRects = NULL) const;
4186fd897d4dcf13d1c0de6a7cbd251487ae1095e42robertphillips@google.com
4197ff121663ecde556b077c703c07b032c0d62dff8reed@google.comprivate:
420de9abcab679c999d879edf19895a06c6acc5cd7erobertphillips@google.com    friend class Iter;
4217ff121663ecde556b077c703c07b032c0d62dff8reed@google.com
4227ff121663ecde556b077c703c07b032c0d62dff8reed@google.com    SkDeque fDeque;
4237ff121663ecde556b077c703c07b032c0d62dff8reed@google.com    int     fSaveCount;
424e05469555381ff89713742474ebd0af0df461dd4robertphillips@google.com
425e05469555381ff89713742474ebd0af0df461dd4robertphillips@google.com    // Generation ID for the clip stack. This is incremented for each
426e05469555381ff89713742474ebd0af0df461dd4robertphillips@google.com    // clipDevRect and clipDevPath call. 0 is reserved to indicate an
427e05469555381ff89713742474ebd0af0df461dd4robertphillips@google.com    // invalid ID.
428e05469555381ff89713742474ebd0af0df461dd4robertphillips@google.com    static int32_t     gGenID;
429e05469555381ff89713742474ebd0af0df461dd4robertphillips@google.com
430e05469555381ff89713742474ebd0af0df461dd4robertphillips@google.com    /**
431b8f710fa222dbb717b8681350f84c6ea916e89a2commit-bot@chromium.org     * Restore the stack back to the specified save count.
432b8f710fa222dbb717b8681350f84c6ea916e89a2commit-bot@chromium.org     */
433b8f710fa222dbb717b8681350f84c6ea916e89a2commit-bot@chromium.org    void restoreTo(int saveCount);
434b8f710fa222dbb717b8681350f84c6ea916e89a2commit-bot@chromium.org
435b8f710fa222dbb717b8681350f84c6ea916e89a2commit-bot@chromium.org    /**
436e05469555381ff89713742474ebd0af0df461dd4robertphillips@google.com     * Return the next unique generation ID.
437e05469555381ff89713742474ebd0af0df461dd4robertphillips@google.com     */
438e05469555381ff89713742474ebd0af0df461dd4robertphillips@google.com    static int32_t GetNextGenID();
4397ff121663ecde556b077c703c07b032c0d62dff8reed@google.com};
4407ff121663ecde556b077c703c07b032c0d62dff8reed@google.com
4417ff121663ecde556b077c703c07b032c0d62dff8reed@google.com#endif
442