blob: 95e41e6220872aebbf64ccd106ee1a7ab96e9f9e [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
2/*
3 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
reed@google.com5c3d1472011-02-22 19:12:23 +00008#ifndef SkClipStack_DEFINED
9#define SkClipStack_DEFINED
10
11#include "SkDeque.h"
bsalomon@google.com8a98e3b2012-11-29 21:05:13 +000012#include "SkPath.h"
13#include "SkRect.h"
commit-bot@chromium.orge5b2af92014-02-16 13:25:24 +000014#include "SkRRect.h"
reed@google.com5c3d1472011-02-22 19:12:23 +000015#include "SkRegion.h"
robertphillips@google.com46f93502012-08-07 15:38:08 +000016#include "SkTDArray.h"
commit-bot@chromium.org6f954b92014-02-27 17:39:46 +000017#include "SkTLazy.h"
reed@google.com5c3d1472011-02-22 19:12:23 +000018
fmalitac3b589a2014-06-05 12:40:07 -070019class SkCanvasClipVisitor;
reed@google.com5c3d1472011-02-22 19:12:23 +000020
robertphillips@google.com4c2a2f72012-07-24 22:07:50 +000021// Because a single save/restore state can have multiple clips, this class
22// stores the stack depth (fSaveCount) and clips (fDeque) separately.
23// Each clip in fDeque stores the stack state to which it belongs
24// (i.e., the fSaveCount in force when it was added). Restores are thus
25// implemented by removing clips from fDeque that have an fSaveCount larger
26// then the freshly decremented count.
ctguil@chromium.org7ffb1b22011-03-15 21:27:08 +000027class SK_API SkClipStack {
reed@google.com5c3d1472011-02-22 19:12:23 +000028public:
bsalomon@google.com8a98e3b2012-11-29 21:05:13 +000029 enum BoundsType {
30 // The bounding box contains all the pixels that can be written to
31 kNormal_BoundsType,
32 // The bounding box contains all the pixels that cannot be written to.
33 // The real bound extends out to infinity and all the pixels outside
34 // of the bound can be written to. Note that some of the pixels inside
35 // the bound may also be writeable but all pixels that cannot be
36 // written to are guaranteed to be inside.
37 kInsideOut_BoundsType
38 };
39
40 class Element {
41 public:
42 enum Type {
43 //!< This element makes the clip empty (regardless of previous elements).
44 kEmpty_Type,
45 //!< This element combines a rect with the current clip using a set operation
46 kRect_Type,
commit-bot@chromium.orge5b2af92014-02-16 13:25:24 +000047 //!< This element combines a round-rect with the current clip using a set operation
48 kRRect_Type,
bsalomon@google.com8a98e3b2012-11-29 21:05:13 +000049 //!< This element combines a path with the current clip using a set operation
50 kPath_Type,
bsalomonb6b02522014-06-09 07:59:06 -070051
52 kLastType = kPath_Type
bsalomon@google.com8a98e3b2012-11-29 21:05:13 +000053 };
bsalomonb6b02522014-06-09 07:59:06 -070054 static const int kTypeCnt = kLastType + 1;
bsalomon@google.com8a98e3b2012-11-29 21:05:13 +000055
56 Element() {
57 this->initCommon(0, SkRegion::kReplace_Op, false);
58 this->setEmpty();
59 }
60
commit-bot@chromium.org6f954b92014-02-27 17:39:46 +000061 Element(const Element&);
62
bsalomon@google.com8a98e3b2012-11-29 21:05:13 +000063 Element(const SkRect& rect, SkRegion::Op op, bool doAA) {
64 this->initRect(0, rect, op, doAA);
65 }
66
commit-bot@chromium.orge5b2af92014-02-16 13:25:24 +000067 Element(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
68 this->initRRect(0, rrect, op, doAA);
69 }
70
bsalomon@google.com8a98e3b2012-11-29 21:05:13 +000071 Element(const SkPath& path, SkRegion::Op op, bool doAA) {
72 this->initPath(0, path, op, doAA);
73 }
74
commit-bot@chromium.orge5b2af92014-02-16 13:25:24 +000075 bool operator== (const Element& element) const;
bsalomon@google.com8182fa02012-12-04 14:06:06 +000076 bool operator!= (const Element& element) const { return !(*this == element); }
77
bsalomon@google.com8a98e3b2012-11-29 21:05:13 +000078 //!< Call to get the type of the clip element.
79 Type getType() const { return fType; }
80
fmalitac3b589a2014-06-05 12:40:07 -070081 //!< Call to get the save count associated with this clip element.
82 int getSaveCount() const { return fSaveCount; }
83
bsalomon@google.com8a98e3b2012-11-29 21:05:13 +000084 //!< Call if getType() is kPath to get the path.
commit-bot@chromium.org6f954b92014-02-27 17:39:46 +000085 const SkPath& getPath() const { SkASSERT(kPath_Type == fType); return *fPath.get(); }
commit-bot@chromium.orge5b2af92014-02-16 13:25:24 +000086
87 //!< Call if getType() is kRRect to get the round-rect.
88 const SkRRect& getRRect() const { SkASSERT(kRRect_Type == fType); return fRRect; }
bsalomon@google.com8a98e3b2012-11-29 21:05:13 +000089
90 //!< Call if getType() is kRect to get the rect.
commit-bot@chromium.org032a52f2014-02-21 20:09:13 +000091 const SkRect& getRect() const {
92 SkASSERT(kRect_Type == fType && (fRRect.isRect() || fRRect.isEmpty()));
93 return fRRect.getBounds();
94 }
bsalomon@google.com8a98e3b2012-11-29 21:05:13 +000095
96 //!< Call if getType() is not kEmpty to get the set operation used to combine this element.
97 SkRegion::Op getOp() const { return fOp; }
98
commit-bot@chromium.orge5b2af92014-02-16 13:25:24 +000099 //!< Call to get the element as a path, regardless of its type.
100 void asPath(SkPath* path) const;
101
bsalomon@google.com8a98e3b2012-11-29 21:05:13 +0000102 /** If getType() is not kEmpty this indicates whether the clip shape should be anti-aliased
103 when it is rasterized. */
104 bool isAA() const { return fDoAA; }
105
bsalomon@google.comc6b3e482012-12-07 20:43:52 +0000106 //!< Inverts the fill of the clip shape. Note that a kEmpty element remains kEmpty.
107 void invertShapeFillType();
108
109 //!< Sets the set operation represented by the element.
bsalomon@google.com8182fa02012-12-04 14:06:06 +0000110 void setOp(SkRegion::Op op) { fOp = op; }
111
bsalomon@google.com8a98e3b2012-11-29 21:05:13 +0000112 /** The GenID can be used by clip stack clients to cache representations of the clip. The
113 ID corresponds to the set of clip elements up to and including this element within the
114 stack not to the element itself. That is the same clip path in different stacks will
115 have a different ID since the elements produce different clip result in the context of
116 their stacks. */
commit-bot@chromium.orgd3e58422013-11-05 15:03:08 +0000117 int32_t getGenID() const { SkASSERT(kInvalidGenID != fGenID); return fGenID; }
bsalomon@google.com8a98e3b2012-11-29 21:05:13 +0000118
bsalomon@google.com8182fa02012-12-04 14:06:06 +0000119 /**
120 * Gets the bounds of the clip element, either the rect or path bounds. (Whether the shape
121 * is inverse filled is not considered.)
122 */
123 const SkRect& getBounds() const {
124 static const SkRect kEmpty = { 0, 0, 0, 0 };
125 switch (fType) {
commit-bot@chromium.org032a52f2014-02-21 20:09:13 +0000126 case kRect_Type: // fallthrough
commit-bot@chromium.orge5b2af92014-02-16 13:25:24 +0000127 case kRRect_Type:
128 return fRRect.getBounds();
bsalomon@google.com8182fa02012-12-04 14:06:06 +0000129 case kPath_Type:
commit-bot@chromium.org6f954b92014-02-27 17:39:46 +0000130 return fPath.get()->getBounds();
bsalomon@google.com8182fa02012-12-04 14:06:06 +0000131 case kEmpty_Type:
132 return kEmpty;
133 default:
134 SkDEBUGFAIL("Unexpected type.");
135 return kEmpty;
136 }
137 }
138
139 /**
140 * Conservatively checks whether the clip shape contains the rect param. (Whether the shape
141 * is inverse filled is not considered.)
142 */
143 bool contains(const SkRect& rect) const {
144 switch (fType) {
145 case kRect_Type:
commit-bot@chromium.org032a52f2014-02-21 20:09:13 +0000146 return this->getRect().contains(rect);
commit-bot@chromium.orge5b2af92014-02-16 13:25:24 +0000147 case kRRect_Type:
148 return fRRect.contains(rect);
bsalomon@google.com8182fa02012-12-04 14:06:06 +0000149 case kPath_Type:
commit-bot@chromium.org6f954b92014-02-27 17:39:46 +0000150 return fPath.get()->conservativelyContainsRect(rect);
bsalomon@google.com8182fa02012-12-04 14:06:06 +0000151 case kEmpty_Type:
152 return false;
153 default:
154 SkDEBUGFAIL("Unexpected type.");
155 return false;
156 }
157 }
158
159 /**
160 * Is the clip shape inverse filled.
161 */
162 bool isInverseFilled() const {
commit-bot@chromium.org6f954b92014-02-27 17:39:46 +0000163 return kPath_Type == fType && fPath.get()->isInverseFillType();
bsalomon@google.com8182fa02012-12-04 14:06:06 +0000164 }
165
fmalitac3b589a2014-06-05 12:40:07 -0700166 /**
167 * Replay this clip into the visitor.
168 */
169 void replay(SkCanvasClipVisitor*) const;
170
bsalomonb6b02522014-06-09 07:59:06 -0700171#ifdef SK_DEVELOPER
172 /**
173 * Dumps the element to SkDebugf. This is intended for Skia development debugging
174 * Don't rely on the existence of this function or the formatting of its output.
175 */
176 void dump() const;
177#endif
178
bsalomon@google.com8a98e3b2012-11-29 21:05:13 +0000179 private:
180 friend class SkClipStack;
181
commit-bot@chromium.org6f954b92014-02-27 17:39:46 +0000182 SkTLazy<SkPath> fPath;
commit-bot@chromium.orge5b2af92014-02-16 13:25:24 +0000183 SkRRect fRRect;
bsalomon@google.com8a98e3b2012-11-29 21:05:13 +0000184 int fSaveCount; // save count of stack when this element was added.
185 SkRegion::Op fOp;
186 Type fType;
187 bool fDoAA;
188
189 /* fFiniteBoundType and fFiniteBound are used to incrementally update the clip stack's
190 bound. When fFiniteBoundType is kNormal_BoundsType, fFiniteBound represents the
191 conservative bounding box of the pixels that aren't clipped (i.e., any pixels that can be
192 drawn to are inside the bound). When fFiniteBoundType is kInsideOut_BoundsType (which
193 occurs when a clip is inverse filled), fFiniteBound represents the conservative bounding
194 box of the pixels that _are_ clipped (i.e., any pixels that cannot be drawn to are inside
195 the bound). When fFiniteBoundType is kInsideOut_BoundsType the actual bound is the
196 infinite plane. This behavior of fFiniteBoundType and fFiniteBound is required so that we
197 can capture the cancelling out of the extensions to infinity when two inverse filled
198 clips are Booleaned together. */
199 SkClipStack::BoundsType fFiniteBoundType;
200 SkRect fFiniteBound;
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +0000201
bsalomon@google.com8a98e3b2012-11-29 21:05:13 +0000202 // When element is applied to the previous elements in the stack is the result known to be
203 // equivalent to a single rect intersection? IIOW, is the clip effectively a rectangle.
204 bool fIsIntersectionOfRects;
205
206 int fGenID;
207
208 Element(int saveCount) {
209 this->initCommon(saveCount, SkRegion::kReplace_Op, false);
210 this->setEmpty();
211 }
212
commit-bot@chromium.orge5b2af92014-02-16 13:25:24 +0000213 Element(int saveCount, const SkRRect& rrect, SkRegion::Op op, bool doAA) {
214 this->initRRect(saveCount, rrect, op, doAA);
215 }
216
bsalomon@google.com8a98e3b2012-11-29 21:05:13 +0000217 Element(int saveCount, const SkRect& rect, SkRegion::Op op, bool doAA) {
218 this->initRect(saveCount, rect, op, doAA);
219 }
220
221 Element(int saveCount, const SkPath& path, SkRegion::Op op, bool doAA) {
222 this->initPath(saveCount, path, op, doAA);
223 }
224
225 void initCommon(int saveCount, SkRegion::Op op, bool doAA) {
226 fSaveCount = saveCount;
227 fOp = op;
228 fDoAA = doAA;
229 // A default of inside-out and empty bounds means the bounds are effectively void as it
230 // indicates that nothing is known to be outside the clip.
231 fFiniteBoundType = kInsideOut_BoundsType;
232 fFiniteBound.setEmpty();
233 fIsIntersectionOfRects = false;
234 fGenID = kInvalidGenID;
235 }
236
237 void initRect(int saveCount, const SkRect& rect, SkRegion::Op op, bool doAA) {
commit-bot@chromium.org032a52f2014-02-21 20:09:13 +0000238 fRRect.setRect(rect);
bsalomon@google.com8a98e3b2012-11-29 21:05:13 +0000239 fType = kRect_Type;
240 this->initCommon(saveCount, op, doAA);
241 }
242
commit-bot@chromium.orge5b2af92014-02-16 13:25:24 +0000243 void initRRect(int saveCount, const SkRRect& rrect, SkRegion::Op op, bool doAA) {
commit-bot@chromium.org032a52f2014-02-21 20:09:13 +0000244 SkRRect::Type type = rrect.getType();
245 fRRect = rrect;
246 if (SkRRect::kRect_Type == type || SkRRect::kEmpty_Type == type) {
commit-bot@chromium.orge5b2af92014-02-16 13:25:24 +0000247 fType = kRect_Type;
248 } else {
commit-bot@chromium.orge5b2af92014-02-16 13:25:24 +0000249 fType = kRRect_Type;
250 }
bsalomon@google.com8a98e3b2012-11-29 21:05:13 +0000251 this->initCommon(saveCount, op, doAA);
252 }
253
commit-bot@chromium.orge5b2af92014-02-16 13:25:24 +0000254 void initPath(int saveCount, const SkPath& path, SkRegion::Op op, bool doAA);
255
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +0000256 void setEmpty();
bsalomon@google.com8a98e3b2012-11-29 21:05:13 +0000257
258 // All Element methods below are only used within SkClipStack.cpp
259 inline void checkEmpty() const;
bsalomon@google.com8a98e3b2012-11-29 21:05:13 +0000260 inline bool canBeIntersectedInPlace(int saveCount, SkRegion::Op op) const;
261 /* This method checks to see if two rect clips can be safely merged into one. The issue here
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +0000262 is that to be strictly correct all the edges of the resulting rect must have the same
bsalomon@google.com8a98e3b2012-11-29 21:05:13 +0000263 anti-aliasing. */
264 bool rectRectIntersectAllowed(const SkRect& newR, bool newAA) const;
265 /** Determines possible finite bounds for the Element given the previous element of the
266 stack */
267 void updateBoundAndGenID(const Element* prior);
268 // The different combination of fill & inverse fill when combining bounding boxes
269 enum FillCombo {
270 kPrev_Cur_FillCombo,
271 kPrev_InvCur_FillCombo,
272 kInvPrev_Cur_FillCombo,
273 kInvPrev_InvCur_FillCombo
274 };
275 // per-set operation functions used by updateBoundAndGenID().
276 inline void combineBoundsDiff(FillCombo combination, const SkRect& prevFinite);
277 inline void combineBoundsXOR(int combination, const SkRect& prevFinite);
278 inline void combineBoundsUnion(int combination, const SkRect& prevFinite);
279 inline void combineBoundsIntersection(int combination, const SkRect& prevFinite);
280 inline void combineBoundsRevDiff(int combination, const SkRect& prevFinite);
281 };
282
reed@google.com5c3d1472011-02-22 19:12:23 +0000283 SkClipStack();
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +0000284 SkClipStack(const SkClipStack& b);
robertphillips@google.comcc6493b2012-07-26 18:39:13 +0000285 explicit SkClipStack(const SkRect& r);
robertphillips@google.com641f8b12012-07-31 19:15:58 +0000286 explicit SkClipStack(const SkIRect& r);
vandebo@chromium.org610f7162012-03-14 18:34:15 +0000287 ~SkClipStack();
reed@google.com5c3d1472011-02-22 19:12:23 +0000288
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +0000289 SkClipStack& operator=(const SkClipStack& b);
290 bool operator==(const SkClipStack& b) const;
291 bool operator!=(const SkClipStack& b) const { return !(*this == b); }
292
reed@google.com5c3d1472011-02-22 19:12:23 +0000293 void reset();
294
295 int getSaveCount() const { return fSaveCount; }
296 void save();
297 void restore();
298
robertphillips@google.com607fe072012-07-24 13:54:00 +0000299 /**
300 * getBounds places the current finite bound in its first parameter. In its
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000301 * second, it indicates which kind of bound is being returned. If
robertphillips@google.com7b112892012-07-31 15:18:21 +0000302 * 'canvFiniteBound' is a normal bounding box then it encloses all writeable
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000303 * pixels. If 'canvFiniteBound' is an inside out bounding box then it
robertphillips@google.com607fe072012-07-24 13:54:00 +0000304 * encloses all the un-writeable pixels and the true/normal bound is the
robertphillips@google.com4c2a2f72012-07-24 22:07:50 +0000305 * infinite plane. isIntersectionOfRects is an optional parameter
robertphillips@google.com7b112892012-07-31 15:18:21 +0000306 * that is true if 'canvFiniteBound' resulted from an intersection of rects.
robertphillips@google.com607fe072012-07-24 13:54:00 +0000307 */
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000308 void getBounds(SkRect* canvFiniteBound,
robertphillips@google.com4c2a2f72012-07-24 22:07:50 +0000309 BoundsType* boundType,
310 bool* isIntersectionOfRects = NULL) const;
robertphillips@google.com607fe072012-07-24 13:54:00 +0000311
bsalomon@google.com3ab43d52012-10-11 19:39:09 +0000312 /**
313 * Takes an input rect in device space and conservatively clips it to the
314 * clip-stack. If false is returned then the rect does not intersect the
315 * clip and is unmodified.
316 */
317 bool intersectRectWithClip(SkRect* devRect) const;
318
junov@chromium.org8cdf0f52012-12-12 17:58:15 +0000319 /**
320 * Returns true if the input rect in device space is entirely contained
321 * by the clip. A return value of false does not guarantee that the rect
322 * is not contained by the clip.
323 */
324 bool quickContains(const SkRect& devRect) const;
325
reed@google.com115d9312012-05-16 18:50:40 +0000326 void clipDevRect(const SkIRect& ir, SkRegion::Op op) {
reed@google.com5c3d1472011-02-22 19:12:23 +0000327 SkRect r;
328 r.set(ir);
reed@google.com00177082011-10-12 14:34:30 +0000329 this->clipDevRect(r, op, false);
reed@google.com5c3d1472011-02-22 19:12:23 +0000330 }
reed@google.com00177082011-10-12 14:34:30 +0000331 void clipDevRect(const SkRect&, SkRegion::Op, bool doAA);
commit-bot@chromium.orge5b2af92014-02-16 13:25:24 +0000332 void clipDevRRect(const SkRRect&, SkRegion::Op, bool doAA);
reed@google.com00177082011-10-12 14:34:30 +0000333 void clipDevPath(const SkPath&, SkRegion::Op, bool doAA);
reed@google.com0557d9e2012-08-16 15:59:59 +0000334 // An optimized version of clipDevRect(emptyRect, kIntersect, ...)
335 void clipEmpty();
reed@google.com5c3d1472011-02-22 19:12:23 +0000336
robertphillips@google.comcc6493b2012-07-26 18:39:13 +0000337 /**
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000338 * isWideOpen returns true if the clip state corresponds to the infinite
robertphillips@google.comcc6493b2012-07-26 18:39:13 +0000339 * plane (i.e., draws are not limited at all)
340 */
341 bool isWideOpen() const;
342
robertphillips@google.com46f93502012-08-07 15:38:08 +0000343 /**
robertphillips@google.com46f93502012-08-07 15:38:08 +0000344 * The generation ID has three reserved values to indicate special
bsalomon@google.come8ca6c62012-11-07 21:19:10 +0000345 * (potentially ignorable) cases
robertphillips@google.com46f93502012-08-07 15:38:08 +0000346 */
commit-bot@chromium.orgd3e58422013-11-05 15:03:08 +0000347 static const int32_t kInvalidGenID = 0; //!< Invalid id that is never returned by
348 //!< SkClipStack. Useful when caching clips
349 //!< based on GenID.
robertphillips@google.com46f93502012-08-07 15:38:08 +0000350 static const int32_t kEmptyGenID = 1; // no pixels writeable
351 static const int32_t kWideOpenGenID = 2; // all pixels writeable
352
robertphillips@google.com73e71022012-08-09 18:10:49 +0000353 int32_t getTopmostGenID() const;
354
bsalomonb6b02522014-06-09 07:59:06 -0700355#ifdef SK_DEVELOPER
356 /**
357 * Dumps the contents of the clip stack to SkDebugf. This is intended for Skia development
358 * debugging. Don't rely on the existence of this function or the formatting of its output.
359 */
360 void dump() const;
361#endif
362
robertphillips@google.com52cb2c72012-07-16 18:52:29 +0000363public:
364 class Iter {
reed@google.com5c3d1472011-02-22 19:12:23 +0000365 public:
robertphillips@google.com52cb2c72012-07-16 18:52:29 +0000366 enum IterStart {
robertphillips@google.com80214e22012-07-20 15:33:18 +0000367 kBottom_IterStart = SkDeque::Iter::kFront_IterStart,
368 kTop_IterStart = SkDeque::Iter::kBack_IterStart
robertphillips@google.com52cb2c72012-07-16 18:52:29 +0000369 };
370
bsalomon@google.comd302f142011-03-03 13:54:13 +0000371 /**
372 * Creates an uninitialized iterator. Must be reset()
373 */
robertphillips@google.com52cb2c72012-07-16 18:52:29 +0000374 Iter();
bsalomon@google.comd302f142011-03-03 13:54:13 +0000375
robertphillips@google.com52cb2c72012-07-16 18:52:29 +0000376 Iter(const SkClipStack& stack, IterStart startLoc);
reed@google.com5c3d1472011-02-22 19:12:23 +0000377
bsalomon@google.com8182fa02012-12-04 14:06:06 +0000378 /**
379 * Return the clip element for this iterator. If next()/prev() returns NULL, then the
380 * iterator is done.
381 */
382 const Element* next();
383 const Element* prev();
reed@google.com5c3d1472011-02-22 19:12:23 +0000384
385 /**
bsalomon@google.com8182fa02012-12-04 14:06:06 +0000386 * Moves the iterator to the topmost element with the specified RegionOp and returns that
387 * element. If no clip element with that op is found, the first element is returned.
reed@google.com5c3d1472011-02-22 19:12:23 +0000388 */
bsalomon@google.com8182fa02012-12-04 14:06:06 +0000389 const Element* skipToTopmost(SkRegion::Op op);
robertphillips@google.com5836b6d2012-07-18 12:06:15 +0000390
391 /**
bsalomon@google.comd302f142011-03-03 13:54:13 +0000392 * Restarts the iterator on a clip stack.
393 */
robertphillips@google.com52cb2c72012-07-16 18:52:29 +0000394 void reset(const SkClipStack& stack, IterStart startLoc);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000395
reed@google.com5c3d1472011-02-22 19:12:23 +0000396 private:
robertphillips@google.com5836b6d2012-07-18 12:06:15 +0000397 const SkClipStack* fStack;
robertphillips@google.com5836b6d2012-07-18 12:06:15 +0000398 SkDeque::Iter fIter;
robertphillips@google.com52cb2c72012-07-16 18:52:29 +0000399 };
400
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000401 /**
robertphillips@google.com80214e22012-07-20 15:33:18 +0000402 * The B2TIter iterates from the bottom of the stack to the top.
403 * It inherits privately from Iter to prevent access to reverse iteration.
404 */
405 class B2TIter : private Iter {
robertphillips@google.com52cb2c72012-07-16 18:52:29 +0000406 public:
robertphillips@google.com80214e22012-07-20 15:33:18 +0000407 B2TIter() {}
robertphillips@google.com52cb2c72012-07-16 18:52:29 +0000408
409 /**
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000410 * Wrap Iter's 2 parameter ctor to force initialization to the
robertphillips@google.com80214e22012-07-20 15:33:18 +0000411 * beginning of the deque/bottom of the stack
robertphillips@google.com52cb2c72012-07-16 18:52:29 +0000412 */
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000413 B2TIter(const SkClipStack& stack)
robertphillips@google.com80214e22012-07-20 15:33:18 +0000414 : INHERITED(stack, kBottom_IterStart) {
robertphillips@google.com52cb2c72012-07-16 18:52:29 +0000415 }
416
robertphillips@google.com52cb2c72012-07-16 18:52:29 +0000417 using Iter::next;
418
419 /**
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000420 * Wrap Iter::reset to force initialization to the
robertphillips@google.com80214e22012-07-20 15:33:18 +0000421 * beginning of the deque/bottom of the stack
robertphillips@google.com52cb2c72012-07-16 18:52:29 +0000422 */
423 void reset(const SkClipStack& stack) {
robertphillips@google.com80214e22012-07-20 15:33:18 +0000424 this->INHERITED::reset(stack, kBottom_IterStart);
robertphillips@google.com52cb2c72012-07-16 18:52:29 +0000425 }
426
427 private:
428
429 typedef Iter INHERITED;
reed@google.com5c3d1472011-02-22 19:12:23 +0000430 };
431
robertphillips@google.com607fe072012-07-24 13:54:00 +0000432 /**
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000433 * GetConservativeBounds returns a conservative bound of the current clip.
434 * Since this could be the infinite plane (if inverse fills were involved) the
435 * maxWidth and maxHeight parameters can be used to limit the returned bound
robertphillips@google.com607fe072012-07-24 13:54:00 +0000436 * to the expected drawing area. Similarly, the offsetX and offsetY parameters
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000437 * allow the caller to offset the returned bound to account for translated
robertphillips@google.com607fe072012-07-24 13:54:00 +0000438 * drawing areas (i.e., those resulting from a saveLayer). For finite bounds,
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000439 * the translation (+offsetX, +offsetY) is applied before the clamp to the
robertphillips@google.com607fe072012-07-24 13:54:00 +0000440 * maximum rectangle: [0,maxWidth) x [0,maxHeight).
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000441 * isIntersectionOfRects is an optional parameter that is true when
robertphillips@google.com641f8b12012-07-31 19:15:58 +0000442 * 'devBounds' is the result of an intersection of rects. In this case
443 * 'devBounds' is the exact answer/clip.
robertphillips@google.com607fe072012-07-24 13:54:00 +0000444 */
445 void getConservativeBounds(int offsetX,
446 int offsetY,
447 int maxWidth,
448 int maxHeight,
robertphillips@google.com7b112892012-07-31 15:18:21 +0000449 SkRect* devBounds,
robertphillips@google.com4c2a2f72012-07-24 22:07:50 +0000450 bool* isIntersectionOfRects = NULL) const;
robertphillips@google.com607fe072012-07-24 13:54:00 +0000451
reed@google.com5c3d1472011-02-22 19:12:23 +0000452private:
robertphillips@google.com52cb2c72012-07-16 18:52:29 +0000453 friend class Iter;
reed@google.com5c3d1472011-02-22 19:12:23 +0000454
455 SkDeque fDeque;
456 int fSaveCount;
robertphillips@google.com46f93502012-08-07 15:38:08 +0000457
458 // Generation ID for the clip stack. This is incremented for each
459 // clipDevRect and clipDevPath call. 0 is reserved to indicate an
460 // invalid ID.
461 static int32_t gGenID;
462
robertphillips@google.com46f93502012-08-07 15:38:08 +0000463 /**
commit-bot@chromium.orge5b2af92014-02-16 13:25:24 +0000464 * Helper for clipDevPath, etc.
465 */
466 void pushElement(const Element& element);
467
468 /**
commit-bot@chromium.org6fbe54c2013-06-11 11:01:48 +0000469 * Restore the stack back to the specified save count.
470 */
471 void restoreTo(int saveCount);
472
473 /**
robertphillips@google.com46f93502012-08-07 15:38:08 +0000474 * Return the next unique generation ID.
475 */
476 static int32_t GetNextGenID();
reed@google.com5c3d1472011-02-22 19:12:23 +0000477};
478
479#endif