1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com/*
3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2011 Google Inc.
4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com *
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be
6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file.
7ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com */
85c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com#ifndef SkClipStack_DEFINED
95c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com#define SkClipStack_DEFINED
105c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com
115c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com#include "SkDeque.h"
128a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com#include "SkPath.h"
138a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com#include "SkRect.h"
14e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org#include "SkRRect.h"
155c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com#include "SkRegion.h"
1646f935002c2b25331e552520dc7b1a912e12dfdcrobertphillips@google.com#include "SkTDArray.h"
176f954b956fc5c36ebbcac404d93ba9349fb0355fcommit-bot@chromium.org#include "SkTLazy.h"
185c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com
19c3b589a24eb4d567a906189f882c259ecf5c2f58fmalitaclass SkCanvasClipVisitor;
205c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com
214c2a2f7c5e8ec77771153f94c454adf21fd33805robertphillips@google.com// Because a single save/restore state can have multiple clips, this class
224c2a2f7c5e8ec77771153f94c454adf21fd33805robertphillips@google.com// stores the stack depth (fSaveCount) and clips (fDeque) separately.
234c2a2f7c5e8ec77771153f94c454adf21fd33805robertphillips@google.com// Each clip in fDeque stores the stack state to which it belongs
244c2a2f7c5e8ec77771153f94c454adf21fd33805robertphillips@google.com// (i.e., the fSaveCount in force when it was added). Restores are thus
254c2a2f7c5e8ec77771153f94c454adf21fd33805robertphillips@google.com// implemented by removing clips from fDeque that have an fSaveCount larger
264c2a2f7c5e8ec77771153f94c454adf21fd33805robertphillips@google.com// then the freshly decremented count.
27de358a9946fb6cffa905c7aa0e5f29cf6960b927joshualittclass SK_API SkClipStack : public SkNVRefCnt<SkClipStack> {
285c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.compublic:
298a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com    enum BoundsType {
308a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com        // The bounding box contains all the pixels that can be written to
318a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com        kNormal_BoundsType,
328a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com        // The bounding box contains all the pixels that cannot be written to.
338a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com        // The real bound extends out to infinity and all the pixels outside
348a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com        // of the bound can be written to. Note that some of the pixels inside
358a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com        // the bound may also be writeable but all pixels that cannot be
368a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com        // written to are guaranteed to be inside.
378a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com        kInsideOut_BoundsType
388a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com    };
398a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com
408a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com    class Element {
418a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com    public:
428a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com        enum Type {
438a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com            //!< This element makes the clip empty (regardless of previous elements).
448a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com            kEmpty_Type,
458a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com            //!< This element combines a rect with the current clip using a set operation
468a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com            kRect_Type,
47e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org            //!< This element combines a round-rect with the current clip using a set operation
48e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org            kRRect_Type,
498a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com            //!< This element combines a path with the current clip using a set operation
508a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com            kPath_Type,
51b6b02526438d6839481fb40ccf610d28f7652397bsalomon
52b6b02526438d6839481fb40ccf610d28f7652397bsalomon            kLastType = kPath_Type
538a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com        };
54b6b02526438d6839481fb40ccf610d28f7652397bsalomon        static const int kTypeCnt = kLastType + 1;
558a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com
568a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com        Element() {
578a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com            this->initCommon(0, SkRegion::kReplace_Op, false);
588a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com            this->setEmpty();
598a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com        }
608a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com
616f954b956fc5c36ebbcac404d93ba9349fb0355fcommit-bot@chromium.org        Element(const Element&);
626f954b956fc5c36ebbcac404d93ba9349fb0355fcommit-bot@chromium.org
638a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com        Element(const SkRect& rect, SkRegion::Op op, bool doAA) {
648a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com            this->initRect(0, rect, op, doAA);
658a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com        }
668a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com
67e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org        Element(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
68e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org            this->initRRect(0, rrect, op, doAA);
69e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org        }
70e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org
718a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com        Element(const SkPath& path, SkRegion::Op op, bool doAA) {
728a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com            this->initPath(0, path, op, doAA);
738a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com        }
748a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com
75e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org        bool operator== (const Element& element) const;
768182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com        bool operator!= (const Element& element) const { return !(*this == element); }
778182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com
788a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com        //!< Call to get the type of the clip element.
798a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com        Type getType() const { return fType; }
808a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com
81c3b589a24eb4d567a906189f882c259ecf5c2f58fmalita        //!< Call to get the save count associated with this clip element.
82c3b589a24eb4d567a906189f882c259ecf5c2f58fmalita        int getSaveCount() const { return fSaveCount; }
83c3b589a24eb4d567a906189f882c259ecf5c2f58fmalita
848a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com        //!< Call if getType() is kPath to get the path.
856f954b956fc5c36ebbcac404d93ba9349fb0355fcommit-bot@chromium.org        const SkPath& getPath() const { SkASSERT(kPath_Type == fType); return *fPath.get(); }
86e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org
87e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org        //!< Call if getType() is kRRect to get the round-rect.
88e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org        const SkRRect& getRRect() const { SkASSERT(kRRect_Type == fType); return fRRect; }
898a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com
908a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com        //!< Call if getType() is kRect to get the rect.
91032a52fd4ceda001e44b80ff0462b570817bfe6fcommit-bot@chromium.org        const SkRect& getRect() const {
92032a52fd4ceda001e44b80ff0462b570817bfe6fcommit-bot@chromium.org            SkASSERT(kRect_Type == fType && (fRRect.isRect() || fRRect.isEmpty()));
93032a52fd4ceda001e44b80ff0462b570817bfe6fcommit-bot@chromium.org            return fRRect.getBounds();
94032a52fd4ceda001e44b80ff0462b570817bfe6fcommit-bot@chromium.org        }
958a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com
968a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com        //!< Call if getType() is not kEmpty to get the set operation used to combine this element.
978a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com        SkRegion::Op getOp() const { return fOp; }
988a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com
99e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org        //!< Call to get the element as a path, regardless of its type.
100e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org        void asPath(SkPath* path) const;
101e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org
1028a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com        /** If getType() is not kEmpty this indicates whether the clip shape should be anti-aliased
1038a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com            when it is rasterized. */
1048a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com        bool isAA() const { return fDoAA; }
1058a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com
106c6b3e48cb3a22d83ba3f4b9a614a5a35b05958a0bsalomon@google.com        //!< Inverts the fill of the clip shape. Note that a kEmpty element remains kEmpty.
107c6b3e48cb3a22d83ba3f4b9a614a5a35b05958a0bsalomon@google.com        void invertShapeFillType();
108c6b3e48cb3a22d83ba3f4b9a614a5a35b05958a0bsalomon@google.com
109c6b3e48cb3a22d83ba3f4b9a614a5a35b05958a0bsalomon@google.com        //!< Sets the set operation represented by the element.
1108182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com        void setOp(SkRegion::Op op) { fOp = op; }
1118182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com
1128a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com        /** The GenID can be used by clip stack clients to cache representations of the clip. The
1138a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com            ID corresponds to the set of clip elements up to and including this element within the
1148a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com            stack not to the element itself. That is the same clip path in different stacks will
1158a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com            have a different ID since the elements produce different clip result in the context of
1168a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com            their stacks. */
117d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org        int32_t getGenID() const { SkASSERT(kInvalidGenID != fGenID); return fGenID; }
1188a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com
1198182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com        /**
1208182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com         * Gets the bounds of the clip element, either the rect or path bounds. (Whether the shape
1218182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com         * is inverse filled is not considered.)
1228182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com         */
1238182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com        const SkRect& getBounds() const {
1248182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com            static const SkRect kEmpty = { 0, 0, 0, 0 };
1258182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com            switch (fType) {
126032a52fd4ceda001e44b80ff0462b570817bfe6fcommit-bot@chromium.org                case kRect_Type:  // fallthrough
127e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org                case kRRect_Type:
128e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org                    return fRRect.getBounds();
1298182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com                case kPath_Type:
1306f954b956fc5c36ebbcac404d93ba9349fb0355fcommit-bot@chromium.org                    return fPath.get()->getBounds();
1318182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com                case kEmpty_Type:
1328182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com                    return kEmpty;
1338182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com                default:
1348182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com                    SkDEBUGFAIL("Unexpected type.");
1358182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com                    return kEmpty;
1368182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com            }
1378182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com        }
1388182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com
1398182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com        /**
1408182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com         * Conservatively checks whether the clip shape contains the rect param. (Whether the shape
1418182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com         * is inverse filled is not considered.)
1428182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com         */
1438182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com        bool contains(const SkRect& rect) const {
1448182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com            switch (fType) {
1458182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com                case kRect_Type:
146032a52fd4ceda001e44b80ff0462b570817bfe6fcommit-bot@chromium.org                    return this->getRect().contains(rect);
147e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org                case kRRect_Type:
148e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org                    return fRRect.contains(rect);
1498182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com                case kPath_Type:
1506f954b956fc5c36ebbcac404d93ba9349fb0355fcommit-bot@chromium.org                    return fPath.get()->conservativelyContainsRect(rect);
1518182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com                case kEmpty_Type:
1528182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com                    return false;
1538182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com                default:
1548182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com                    SkDEBUGFAIL("Unexpected type.");
1558182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com                    return false;
1568182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com            }
1578182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com        }
1588182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com
1598182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com        /**
1608182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com         * Is the clip shape inverse filled.
1618182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com         */
1628182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com        bool isInverseFilled() const {
1636f954b956fc5c36ebbcac404d93ba9349fb0355fcommit-bot@chromium.org            return kPath_Type == fType && fPath.get()->isInverseFillType();
1648182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com        }
1658182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com
166c3b589a24eb4d567a906189f882c259ecf5c2f58fmalita        /**
167c3b589a24eb4d567a906189f882c259ecf5c2f58fmalita        * Replay this clip into the visitor.
168c3b589a24eb4d567a906189f882c259ecf5c2f58fmalita        */
169c3b589a24eb4d567a906189f882c259ecf5c2f58fmalita        void replay(SkCanvasClipVisitor*) const;
170c3b589a24eb4d567a906189f882c259ecf5c2f58fmalita
171b6b02526438d6839481fb40ccf610d28f7652397bsalomon#ifdef SK_DEVELOPER
172b6b02526438d6839481fb40ccf610d28f7652397bsalomon        /**
173b6b02526438d6839481fb40ccf610d28f7652397bsalomon         * Dumps the element to SkDebugf. This is intended for Skia development debugging
174b6b02526438d6839481fb40ccf610d28f7652397bsalomon         * Don't rely on the existence of this function or the formatting of its output.
175b6b02526438d6839481fb40ccf610d28f7652397bsalomon         */
176b6b02526438d6839481fb40ccf610d28f7652397bsalomon        void dump() const;
177b6b02526438d6839481fb40ccf610d28f7652397bsalomon#endif
178b6b02526438d6839481fb40ccf610d28f7652397bsalomon
1798a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com    private:
1808a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com        friend class SkClipStack;
1818a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com
1826f954b956fc5c36ebbcac404d93ba9349fb0355fcommit-bot@chromium.org        SkTLazy<SkPath> fPath;
183e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org        SkRRect         fRRect;
1848a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com        int             fSaveCount; // save count of stack when this element was added.
1858a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com        SkRegion::Op    fOp;
1868a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com        Type            fType;
1878a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com        bool            fDoAA;
1888a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com
1898a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com        /* fFiniteBoundType and fFiniteBound are used to incrementally update the clip stack's
1908a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com           bound. When fFiniteBoundType is kNormal_BoundsType, fFiniteBound represents the
1918a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com           conservative bounding box of the pixels that aren't clipped (i.e., any pixels that can be
1928a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com           drawn to are inside the bound). When fFiniteBoundType is kInsideOut_BoundsType (which
1938a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com           occurs when a clip is inverse filled), fFiniteBound represents the conservative bounding
1948a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com           box of the pixels that _are_ clipped (i.e., any pixels that cannot be drawn to are inside
1958a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com           the bound). When fFiniteBoundType is kInsideOut_BoundsType the actual bound is the
1968a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com           infinite plane. This behavior of fFiniteBoundType and fFiniteBound is required so that we
1978a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com           can capture the cancelling out of the extensions to infinity when two inverse filled
1988a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com           clips are Booleaned together. */
1998a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com        SkClipStack::BoundsType fFiniteBoundType;
2008a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com        SkRect                  fFiniteBound;
201c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com
2028a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com        // When element is applied to the previous elements in the stack is the result known to be
2038a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com        // equivalent to a single rect intersection? IIOW, is the clip effectively a rectangle.
2048a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com        bool                    fIsIntersectionOfRects;
2058a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com
2068a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com        int                     fGenID;
2078a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com
2088a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com        Element(int saveCount) {
2098a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com            this->initCommon(saveCount, SkRegion::kReplace_Op, false);
2108a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com            this->setEmpty();
2118a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com        }
2128a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com
213e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org        Element(int saveCount, const SkRRect& rrect, SkRegion::Op op, bool doAA) {
214e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org            this->initRRect(saveCount, rrect, op, doAA);
215e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org        }
216e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org
2178a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com        Element(int saveCount, const SkRect& rect, SkRegion::Op op, bool doAA) {
2188a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com            this->initRect(saveCount, rect, op, doAA);
2198a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com        }
2208a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com
2218a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com        Element(int saveCount, const SkPath& path, SkRegion::Op op, bool doAA) {
2228a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com            this->initPath(saveCount, path, op, doAA);
2238a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com        }
2248a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com
2258a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com        void initCommon(int saveCount, SkRegion::Op op, bool doAA) {
2268a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com            fSaveCount = saveCount;
2278a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com            fOp = op;
2288a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com            fDoAA = doAA;
2298a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com            // A default of inside-out and empty bounds means the bounds are effectively void as it
2308a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com            // indicates that nothing is known to be outside the clip.
2318a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com            fFiniteBoundType = kInsideOut_BoundsType;
2328a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com            fFiniteBound.setEmpty();
2338a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com            fIsIntersectionOfRects = false;
2348a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com            fGenID = kInvalidGenID;
2358a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com        }
2368a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com
2378a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com        void initRect(int saveCount, const SkRect& rect, SkRegion::Op op, bool doAA) {
238032a52fd4ceda001e44b80ff0462b570817bfe6fcommit-bot@chromium.org            fRRect.setRect(rect);
2398a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com            fType = kRect_Type;
2408a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com            this->initCommon(saveCount, op, doAA);
2418a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com        }
2428a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com
243e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org        void initRRect(int saveCount, const SkRRect& rrect, SkRegion::Op op, bool doAA) {
244032a52fd4ceda001e44b80ff0462b570817bfe6fcommit-bot@chromium.org            SkRRect::Type type = rrect.getType();
245032a52fd4ceda001e44b80ff0462b570817bfe6fcommit-bot@chromium.org            fRRect = rrect;
246032a52fd4ceda001e44b80ff0462b570817bfe6fcommit-bot@chromium.org            if (SkRRect::kRect_Type == type || SkRRect::kEmpty_Type == type) {
247e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org                fType = kRect_Type;
248e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org            } else {
249e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org                fType = kRRect_Type;
250e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org            }
2518a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com            this->initCommon(saveCount, op, doAA);
2528a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com        }
2538a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com
254e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org        void initPath(int saveCount, const SkPath& path, SkRegion::Op op, bool doAA);
255e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org
2569cb671a0017e8f2906e8351ff35efcd6d8fbf7b0commit-bot@chromium.org        void setEmpty();
2578a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com
2588a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com        // All Element methods below are only used within SkClipStack.cpp
2598a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com        inline void checkEmpty() const;
2608a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com        inline bool canBeIntersectedInPlace(int saveCount, SkRegion::Op op) const;
2618a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com        /* This method checks to see if two rect clips can be safely merged into one. The issue here
262c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com          is that to be strictly correct all the edges of the resulting rect must have the same
2638a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com          anti-aliasing. */
2648a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com        bool rectRectIntersectAllowed(const SkRect& newR, bool newAA) const;
2658a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com        /** Determines possible finite bounds for the Element given the previous element of the
2668a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com            stack */
2678a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com        void updateBoundAndGenID(const Element* prior);
2688a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com        // The different combination of fill & inverse fill when combining bounding boxes
2698a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com        enum FillCombo {
2708a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com            kPrev_Cur_FillCombo,
2718a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com            kPrev_InvCur_FillCombo,
2728a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com            kInvPrev_Cur_FillCombo,
2738a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com            kInvPrev_InvCur_FillCombo
2748a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com        };
2758a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com        // per-set operation functions used by updateBoundAndGenID().
2768a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com        inline void combineBoundsDiff(FillCombo combination, const SkRect& prevFinite);
2778a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com        inline void combineBoundsXOR(int combination, const SkRect& prevFinite);
2788a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com        inline void combineBoundsUnion(int combination, const SkRect& prevFinite);
2798a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com        inline void combineBoundsIntersection(int combination, const SkRect& prevFinite);
2808a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com        inline void combineBoundsRevDiff(int combination, const SkRect& prevFinite);
2818a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com    };
2828a98e3bd18f1a8914cbfe1461e1ff47f51286556bsalomon@google.com
2835c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com    SkClipStack();
2841e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org    SkClipStack(const SkClipStack& b);
285cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com    explicit SkClipStack(const SkRect& r);
286641f8b19a6799b6d73ac17b9c2d2f8a5e6f5ad4drobertphillips@google.com    explicit SkClipStack(const SkIRect& r);
287610f716b00f214e4899a102c1bbc1d6a323e114evandebo@chromium.org    ~SkClipStack();
2885c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com
2891e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org    SkClipStack& operator=(const SkClipStack& b);
2901e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org    bool operator==(const SkClipStack& b) const;
2911e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org    bool operator!=(const SkClipStack& b) const { return !(*this == b); }
2921e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org
2935c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com    void reset();
2945c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com
2955c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com    int getSaveCount() const { return fSaveCount; }
2965c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com    void save();
2975c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com    void restore();
2985c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com
299607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com    /**
300607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com     * getBounds places the current finite bound in its first parameter. In its
301fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com     * second, it indicates which kind of bound is being returned. If
3027b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com     * 'canvFiniteBound' is a normal bounding box then it encloses all writeable
303fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com     * pixels. If 'canvFiniteBound' is an inside out bounding box then it
304607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com     * encloses all the un-writeable pixels and the true/normal bound is the
3054c2a2f7c5e8ec77771153f94c454adf21fd33805robertphillips@google.com     * infinite plane. isIntersectionOfRects is an optional parameter
3067b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com     * that is true if 'canvFiniteBound' resulted from an intersection of rects.
307607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com     */
308fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com    void getBounds(SkRect* canvFiniteBound,
3094c2a2f7c5e8ec77771153f94c454adf21fd33805robertphillips@google.com                   BoundsType* boundType,
3104c2a2f7c5e8ec77771153f94c454adf21fd33805robertphillips@google.com                   bool* isIntersectionOfRects = NULL) const;
311607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com
3123ab43d5c5b4d77f46dd0266618f92e5fefce2021bsalomon@google.com    /**
3138cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org     * Returns true if the input rect in device space is entirely contained
3148cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org     * by the clip. A return value of false does not guarantee that the rect
3158cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org     * is not contained by the clip.
3168cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org     */
3178cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org    bool quickContains(const SkRect& devRect) const;
3188cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org
3191a481fe4bf632ed4f76cb337691236fabfd4ab03fmalita    /**
3201a481fe4bf632ed4f76cb337691236fabfd4ab03fmalita     * Flattens the clip stack into a single SkPath. Returns true if any of
3211a481fe4bf632ed4f76cb337691236fabfd4ab03fmalita     * the clip stack components requires anti-aliasing.
3221a481fe4bf632ed4f76cb337691236fabfd4ab03fmalita     */
3231a481fe4bf632ed4f76cb337691236fabfd4ab03fmalita    bool asPath(SkPath* path) const;
3241a481fe4bf632ed4f76cb337691236fabfd4ab03fmalita
325115d931d2fbd3a109a21b28c8a9c5099e6c49c54reed@google.com    void clipDevRect(const SkIRect& ir, SkRegion::Op op) {
3265c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com        SkRect r;
3275c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com        r.set(ir);
3280017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com        this->clipDevRect(r, op, false);
3295c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com    }
3300017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com    void clipDevRect(const SkRect&, SkRegion::Op, bool doAA);
331e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org    void clipDevRRect(const SkRRect&, SkRegion::Op, bool doAA);
3320017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com    void clipDevPath(const SkPath&, SkRegion::Op, bool doAA);
3330557d9ea94d5435a9072c9b4141a05190d648442reed@google.com    // An optimized version of clipDevRect(emptyRect, kIntersect, ...)
3340557d9ea94d5435a9072c9b4141a05190d648442reed@google.com    void clipEmpty();
3355c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com
336cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com    /**
337fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com     * isWideOpen returns true if the clip state corresponds to the infinite
338cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com     * plane (i.e., draws are not limited at all)
339cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com     */
340cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com    bool isWideOpen() const;
341cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com
34246f935002c2b25331e552520dc7b1a912e12dfdcrobertphillips@google.com    /**
34346f935002c2b25331e552520dc7b1a912e12dfdcrobertphillips@google.com     * The generation ID has three reserved values to indicate special
344e8ca6c6e3a55634ac76efe5aceafaf8d669f43babsalomon@google.com     * (potentially ignorable) cases
34546f935002c2b25331e552520dc7b1a912e12dfdcrobertphillips@google.com     */
346d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org    static const int32_t kInvalidGenID = 0;     //!< Invalid id that is never returned by
347d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org                                                //!< SkClipStack. Useful when caching clips
348d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org                                                //!< based on GenID.
34946f935002c2b25331e552520dc7b1a912e12dfdcrobertphillips@google.com    static const int32_t kEmptyGenID = 1;       // no pixels writeable
35046f935002c2b25331e552520dc7b1a912e12dfdcrobertphillips@google.com    static const int32_t kWideOpenGenID = 2;    // all pixels writeable
35146f935002c2b25331e552520dc7b1a912e12dfdcrobertphillips@google.com
35273e71023a05393ef0aa12bf3644a1c704feeec0crobertphillips@google.com    int32_t getTopmostGenID() const;
35373e71023a05393ef0aa12bf3644a1c704feeec0crobertphillips@google.com
354b6b02526438d6839481fb40ccf610d28f7652397bsalomon#ifdef SK_DEVELOPER
355b6b02526438d6839481fb40ccf610d28f7652397bsalomon    /**
356b6b02526438d6839481fb40ccf610d28f7652397bsalomon     * Dumps the contents of the clip stack to SkDebugf. This is intended for Skia development
357b6b02526438d6839481fb40ccf610d28f7652397bsalomon     * debugging. Don't rely on the existence of this function or the formatting of its output.
358b6b02526438d6839481fb40ccf610d28f7652397bsalomon     */
359b6b02526438d6839481fb40ccf610d28f7652397bsalomon    void dump() const;
360b6b02526438d6839481fb40ccf610d28f7652397bsalomon#endif
361b6b02526438d6839481fb40ccf610d28f7652397bsalomon
36252cb2c7cdf87f1e7d4b5d24b3609aaa514a26c10robertphillips@google.compublic:
36352cb2c7cdf87f1e7d4b5d24b3609aaa514a26c10robertphillips@google.com    class Iter {
3645c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com    public:
36552cb2c7cdf87f1e7d4b5d24b3609aaa514a26c10robertphillips@google.com        enum IterStart {
36680214e26c57c5fea954006400852e8999e201923robertphillips@google.com            kBottom_IterStart = SkDeque::Iter::kFront_IterStart,
36780214e26c57c5fea954006400852e8999e201923robertphillips@google.com            kTop_IterStart = SkDeque::Iter::kBack_IterStart
36852cb2c7cdf87f1e7d4b5d24b3609aaa514a26c10robertphillips@google.com        };
36952cb2c7cdf87f1e7d4b5d24b3609aaa514a26c10robertphillips@google.com
370d302f1401b3c9aea094804bad4e76de98782cfe8bsalomon@google.com        /**
371d302f1401b3c9aea094804bad4e76de98782cfe8bsalomon@google.com         * Creates an uninitialized iterator. Must be reset()
372d302f1401b3c9aea094804bad4e76de98782cfe8bsalomon@google.com         */
37352cb2c7cdf87f1e7d4b5d24b3609aaa514a26c10robertphillips@google.com        Iter();
374d302f1401b3c9aea094804bad4e76de98782cfe8bsalomon@google.com
37552cb2c7cdf87f1e7d4b5d24b3609aaa514a26c10robertphillips@google.com        Iter(const SkClipStack& stack, IterStart startLoc);
3765c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com
3775c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com        /**
3788182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com         *  Return the clip element for this iterator. If next()/prev() returns NULL, then the
3798182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com         *  iterator is done.
3805c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com         */
3818182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com        const Element* next();
3828182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com        const Element* prev();
3835c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com
384d302f1401b3c9aea094804bad4e76de98782cfe8bsalomon@google.com        /**
3858182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com         * Moves the iterator to the topmost element with the specified RegionOp and returns that
3868182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com         * element. If no clip element with that op is found, the first element is returned.
3875836b6dec5563e6273099fcf23984dd3818a168frobertphillips@google.com         */
3888182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com        const Element* skipToTopmost(SkRegion::Op op);
3895836b6dec5563e6273099fcf23984dd3818a168frobertphillips@google.com
3905836b6dec5563e6273099fcf23984dd3818a168frobertphillips@google.com        /**
391d302f1401b3c9aea094804bad4e76de98782cfe8bsalomon@google.com         * Restarts the iterator on a clip stack.
392d302f1401b3c9aea094804bad4e76de98782cfe8bsalomon@google.com         */
39352cb2c7cdf87f1e7d4b5d24b3609aaa514a26c10robertphillips@google.com        void reset(const SkClipStack& stack, IterStart startLoc);
394d302f1401b3c9aea094804bad4e76de98782cfe8bsalomon@google.com
3955c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com    private:
3965836b6dec5563e6273099fcf23984dd3818a168frobertphillips@google.com        const SkClipStack* fStack;
3975836b6dec5563e6273099fcf23984dd3818a168frobertphillips@google.com        SkDeque::Iter      fIter;
39852cb2c7cdf87f1e7d4b5d24b3609aaa514a26c10robertphillips@google.com    };
39952cb2c7cdf87f1e7d4b5d24b3609aaa514a26c10robertphillips@google.com
400fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com    /**
40180214e26c57c5fea954006400852e8999e201923robertphillips@google.com     * The B2TIter iterates from the bottom of the stack to the top.
40280214e26c57c5fea954006400852e8999e201923robertphillips@google.com     * It inherits privately from Iter to prevent access to reverse iteration.
40380214e26c57c5fea954006400852e8999e201923robertphillips@google.com     */
40480214e26c57c5fea954006400852e8999e201923robertphillips@google.com    class B2TIter : private Iter {
40552cb2c7cdf87f1e7d4b5d24b3609aaa514a26c10robertphillips@google.com    public:
40680214e26c57c5fea954006400852e8999e201923robertphillips@google.com        B2TIter() {}
40752cb2c7cdf87f1e7d4b5d24b3609aaa514a26c10robertphillips@google.com
40852cb2c7cdf87f1e7d4b5d24b3609aaa514a26c10robertphillips@google.com        /**
409fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com         * Wrap Iter's 2 parameter ctor to force initialization to the
41080214e26c57c5fea954006400852e8999e201923robertphillips@google.com         * beginning of the deque/bottom of the stack
41152cb2c7cdf87f1e7d4b5d24b3609aaa514a26c10robertphillips@google.com         */
412fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com        B2TIter(const SkClipStack& stack)
41380214e26c57c5fea954006400852e8999e201923robertphillips@google.com        : INHERITED(stack, kBottom_IterStart) {
41452cb2c7cdf87f1e7d4b5d24b3609aaa514a26c10robertphillips@google.com        }
41552cb2c7cdf87f1e7d4b5d24b3609aaa514a26c10robertphillips@google.com
41652cb2c7cdf87f1e7d4b5d24b3609aaa514a26c10robertphillips@google.com        using Iter::next;
41752cb2c7cdf87f1e7d4b5d24b3609aaa514a26c10robertphillips@google.com
41852cb2c7cdf87f1e7d4b5d24b3609aaa514a26c10robertphillips@google.com        /**
419fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com         * Wrap Iter::reset to force initialization to the
42080214e26c57c5fea954006400852e8999e201923robertphillips@google.com         * beginning of the deque/bottom of the stack
42152cb2c7cdf87f1e7d4b5d24b3609aaa514a26c10robertphillips@google.com         */
42252cb2c7cdf87f1e7d4b5d24b3609aaa514a26c10robertphillips@google.com        void reset(const SkClipStack& stack) {
42380214e26c57c5fea954006400852e8999e201923robertphillips@google.com            this->INHERITED::reset(stack, kBottom_IterStart);
42452cb2c7cdf87f1e7d4b5d24b3609aaa514a26c10robertphillips@google.com        }
42552cb2c7cdf87f1e7d4b5d24b3609aaa514a26c10robertphillips@google.com
42652cb2c7cdf87f1e7d4b5d24b3609aaa514a26c10robertphillips@google.com    private:
42752cb2c7cdf87f1e7d4b5d24b3609aaa514a26c10robertphillips@google.com
42852cb2c7cdf87f1e7d4b5d24b3609aaa514a26c10robertphillips@google.com        typedef Iter INHERITED;
4295c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com    };
4305c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com
431607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com    /**
432fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com     * GetConservativeBounds returns a conservative bound of the current clip.
433fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com     * Since this could be the infinite plane (if inverse fills were involved) the
434fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com     * maxWidth and maxHeight parameters can be used to limit the returned bound
435607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com     * to the expected drawing area. Similarly, the offsetX and offsetY parameters
436fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com     * allow the caller to offset the returned bound to account for translated
437607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com     * drawing areas (i.e., those resulting from a saveLayer). For finite bounds,
438fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com     * the translation (+offsetX, +offsetY) is applied before the clamp to the
439607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com     * maximum rectangle: [0,maxWidth) x [0,maxHeight).
440fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com     * isIntersectionOfRects is an optional parameter that is true when
441641f8b19a6799b6d73ac17b9c2d2f8a5e6f5ad4drobertphillips@google.com     * 'devBounds' is the result of an intersection of rects. In this case
442641f8b19a6799b6d73ac17b9c2d2f8a5e6f5ad4drobertphillips@google.com     * 'devBounds' is the exact answer/clip.
443607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com     */
444607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com    void getConservativeBounds(int offsetX,
445607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com                               int offsetY,
446607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com                               int maxWidth,
447607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com                               int maxHeight,
4487b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com                               SkRect* devBounds,
4494c2a2f7c5e8ec77771153f94c454adf21fd33805robertphillips@google.com                               bool* isIntersectionOfRects = NULL) const;
450607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com
4515c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.comprivate:
45252cb2c7cdf87f1e7d4b5d24b3609aaa514a26c10robertphillips@google.com    friend class Iter;
4535c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com
4545c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com    SkDeque fDeque;
4555c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com    int     fSaveCount;
45646f935002c2b25331e552520dc7b1a912e12dfdcrobertphillips@google.com
45746f935002c2b25331e552520dc7b1a912e12dfdcrobertphillips@google.com    // Generation ID for the clip stack. This is incremented for each
45846f935002c2b25331e552520dc7b1a912e12dfdcrobertphillips@google.com    // clipDevRect and clipDevPath call. 0 is reserved to indicate an
45946f935002c2b25331e552520dc7b1a912e12dfdcrobertphillips@google.com    // invalid ID.
46046f935002c2b25331e552520dc7b1a912e12dfdcrobertphillips@google.com    static int32_t     gGenID;
46146f935002c2b25331e552520dc7b1a912e12dfdcrobertphillips@google.com
46246f935002c2b25331e552520dc7b1a912e12dfdcrobertphillips@google.com    /**
463e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org     * Helper for clipDevPath, etc.
464e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org     */
465e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org    void pushElement(const Element& element);
466e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org
467e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org    /**
4686fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org     * Restore the stack back to the specified save count.
4696fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org     */
4706fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org    void restoreTo(int saveCount);
4716fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org
4726fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org    /**
47346f935002c2b25331e552520dc7b1a912e12dfdcrobertphillips@google.com     * Return the next unique generation ID.
47446f935002c2b25331e552520dc7b1a912e12dfdcrobertphillips@google.com     */
47546f935002c2b25331e552520dc7b1a912e12dfdcrobertphillips@google.com    static int32_t GetNextGenID();
4765c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com};
4775c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com
4785c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com#endif
479