blob: 3f79f92a5b08f295168c8f301f889dfa76f74407 [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.
joshualittde358a92015-02-05 08:19:35 -080027class SK_API SkClipStack : public SkNVRefCnt<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
fmalita1a481fe2015-02-04 07:39:34 -0800326 /**
327 * Flattens the clip stack into a single SkPath. Returns true if any of
328 * the clip stack components requires anti-aliasing.
329 */
330 bool asPath(SkPath* path) const;
331
reed@google.com115d9312012-05-16 18:50:40 +0000332 void clipDevRect(const SkIRect& ir, SkRegion::Op op) {
reed@google.com5c3d1472011-02-22 19:12:23 +0000333 SkRect r;
334 r.set(ir);
reed@google.com00177082011-10-12 14:34:30 +0000335 this->clipDevRect(r, op, false);
reed@google.com5c3d1472011-02-22 19:12:23 +0000336 }
reed@google.com00177082011-10-12 14:34:30 +0000337 void clipDevRect(const SkRect&, SkRegion::Op, bool doAA);
commit-bot@chromium.orge5b2af92014-02-16 13:25:24 +0000338 void clipDevRRect(const SkRRect&, SkRegion::Op, bool doAA);
reed@google.com00177082011-10-12 14:34:30 +0000339 void clipDevPath(const SkPath&, SkRegion::Op, bool doAA);
reed@google.com0557d9e2012-08-16 15:59:59 +0000340 // An optimized version of clipDevRect(emptyRect, kIntersect, ...)
341 void clipEmpty();
reed@google.com5c3d1472011-02-22 19:12:23 +0000342
robertphillips@google.comcc6493b2012-07-26 18:39:13 +0000343 /**
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000344 * isWideOpen returns true if the clip state corresponds to the infinite
robertphillips@google.comcc6493b2012-07-26 18:39:13 +0000345 * plane (i.e., draws are not limited at all)
346 */
347 bool isWideOpen() const;
348
robertphillips@google.com46f93502012-08-07 15:38:08 +0000349 /**
robertphillips@google.com46f93502012-08-07 15:38:08 +0000350 * The generation ID has three reserved values to indicate special
bsalomon@google.come8ca6c62012-11-07 21:19:10 +0000351 * (potentially ignorable) cases
robertphillips@google.com46f93502012-08-07 15:38:08 +0000352 */
commit-bot@chromium.orgd3e58422013-11-05 15:03:08 +0000353 static const int32_t kInvalidGenID = 0; //!< Invalid id that is never returned by
354 //!< SkClipStack. Useful when caching clips
355 //!< based on GenID.
robertphillips@google.com46f93502012-08-07 15:38:08 +0000356 static const int32_t kEmptyGenID = 1; // no pixels writeable
357 static const int32_t kWideOpenGenID = 2; // all pixels writeable
358
robertphillips@google.com73e71022012-08-09 18:10:49 +0000359 int32_t getTopmostGenID() const;
360
bsalomonb6b02522014-06-09 07:59:06 -0700361#ifdef SK_DEVELOPER
362 /**
363 * Dumps the contents of the clip stack to SkDebugf. This is intended for Skia development
364 * debugging. Don't rely on the existence of this function or the formatting of its output.
365 */
366 void dump() const;
367#endif
368
robertphillips@google.com52cb2c72012-07-16 18:52:29 +0000369public:
370 class Iter {
reed@google.com5c3d1472011-02-22 19:12:23 +0000371 public:
robertphillips@google.com52cb2c72012-07-16 18:52:29 +0000372 enum IterStart {
robertphillips@google.com80214e22012-07-20 15:33:18 +0000373 kBottom_IterStart = SkDeque::Iter::kFront_IterStart,
374 kTop_IterStart = SkDeque::Iter::kBack_IterStart
robertphillips@google.com52cb2c72012-07-16 18:52:29 +0000375 };
376
bsalomon@google.comd302f142011-03-03 13:54:13 +0000377 /**
378 * Creates an uninitialized iterator. Must be reset()
379 */
robertphillips@google.com52cb2c72012-07-16 18:52:29 +0000380 Iter();
bsalomon@google.comd302f142011-03-03 13:54:13 +0000381
robertphillips@google.com52cb2c72012-07-16 18:52:29 +0000382 Iter(const SkClipStack& stack, IterStart startLoc);
reed@google.com5c3d1472011-02-22 19:12:23 +0000383
bsalomon@google.com8182fa02012-12-04 14:06:06 +0000384 /**
385 * Return the clip element for this iterator. If next()/prev() returns NULL, then the
386 * iterator is done.
387 */
388 const Element* next();
389 const Element* prev();
reed@google.com5c3d1472011-02-22 19:12:23 +0000390
391 /**
bsalomon@google.com8182fa02012-12-04 14:06:06 +0000392 * Moves the iterator to the topmost element with the specified RegionOp and returns that
393 * element. If no clip element with that op is found, the first element is returned.
reed@google.com5c3d1472011-02-22 19:12:23 +0000394 */
bsalomon@google.com8182fa02012-12-04 14:06:06 +0000395 const Element* skipToTopmost(SkRegion::Op op);
robertphillips@google.com5836b6d2012-07-18 12:06:15 +0000396
397 /**
bsalomon@google.comd302f142011-03-03 13:54:13 +0000398 * Restarts the iterator on a clip stack.
399 */
robertphillips@google.com52cb2c72012-07-16 18:52:29 +0000400 void reset(const SkClipStack& stack, IterStart startLoc);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000401
reed@google.com5c3d1472011-02-22 19:12:23 +0000402 private:
robertphillips@google.com5836b6d2012-07-18 12:06:15 +0000403 const SkClipStack* fStack;
robertphillips@google.com5836b6d2012-07-18 12:06:15 +0000404 SkDeque::Iter fIter;
robertphillips@google.com52cb2c72012-07-16 18:52:29 +0000405 };
406
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000407 /**
robertphillips@google.com80214e22012-07-20 15:33:18 +0000408 * The B2TIter iterates from the bottom of the stack to the top.
409 * It inherits privately from Iter to prevent access to reverse iteration.
410 */
411 class B2TIter : private Iter {
robertphillips@google.com52cb2c72012-07-16 18:52:29 +0000412 public:
robertphillips@google.com80214e22012-07-20 15:33:18 +0000413 B2TIter() {}
robertphillips@google.com52cb2c72012-07-16 18:52:29 +0000414
415 /**
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000416 * Wrap Iter's 2 parameter ctor to force initialization to the
robertphillips@google.com80214e22012-07-20 15:33:18 +0000417 * beginning of the deque/bottom of the stack
robertphillips@google.com52cb2c72012-07-16 18:52:29 +0000418 */
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000419 B2TIter(const SkClipStack& stack)
robertphillips@google.com80214e22012-07-20 15:33:18 +0000420 : INHERITED(stack, kBottom_IterStart) {
robertphillips@google.com52cb2c72012-07-16 18:52:29 +0000421 }
422
robertphillips@google.com52cb2c72012-07-16 18:52:29 +0000423 using Iter::next;
424
425 /**
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000426 * Wrap Iter::reset to force initialization to the
robertphillips@google.com80214e22012-07-20 15:33:18 +0000427 * beginning of the deque/bottom of the stack
robertphillips@google.com52cb2c72012-07-16 18:52:29 +0000428 */
429 void reset(const SkClipStack& stack) {
robertphillips@google.com80214e22012-07-20 15:33:18 +0000430 this->INHERITED::reset(stack, kBottom_IterStart);
robertphillips@google.com52cb2c72012-07-16 18:52:29 +0000431 }
432
433 private:
434
435 typedef Iter INHERITED;
reed@google.com5c3d1472011-02-22 19:12:23 +0000436 };
437
robertphillips@google.com607fe072012-07-24 13:54:00 +0000438 /**
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000439 * GetConservativeBounds returns a conservative bound of the current clip.
440 * Since this could be the infinite plane (if inverse fills were involved) the
441 * maxWidth and maxHeight parameters can be used to limit the returned bound
robertphillips@google.com607fe072012-07-24 13:54:00 +0000442 * to the expected drawing area. Similarly, the offsetX and offsetY parameters
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000443 * allow the caller to offset the returned bound to account for translated
robertphillips@google.com607fe072012-07-24 13:54:00 +0000444 * drawing areas (i.e., those resulting from a saveLayer). For finite bounds,
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000445 * the translation (+offsetX, +offsetY) is applied before the clamp to the
robertphillips@google.com607fe072012-07-24 13:54:00 +0000446 * maximum rectangle: [0,maxWidth) x [0,maxHeight).
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000447 * isIntersectionOfRects is an optional parameter that is true when
robertphillips@google.com641f8b12012-07-31 19:15:58 +0000448 * 'devBounds' is the result of an intersection of rects. In this case
449 * 'devBounds' is the exact answer/clip.
robertphillips@google.com607fe072012-07-24 13:54:00 +0000450 */
451 void getConservativeBounds(int offsetX,
452 int offsetY,
453 int maxWidth,
454 int maxHeight,
robertphillips@google.com7b112892012-07-31 15:18:21 +0000455 SkRect* devBounds,
robertphillips@google.com4c2a2f72012-07-24 22:07:50 +0000456 bool* isIntersectionOfRects = NULL) const;
robertphillips@google.com607fe072012-07-24 13:54:00 +0000457
reed@google.com5c3d1472011-02-22 19:12:23 +0000458private:
robertphillips@google.com52cb2c72012-07-16 18:52:29 +0000459 friend class Iter;
reed@google.com5c3d1472011-02-22 19:12:23 +0000460
461 SkDeque fDeque;
462 int fSaveCount;
robertphillips@google.com46f93502012-08-07 15:38:08 +0000463
464 // Generation ID for the clip stack. This is incremented for each
465 // clipDevRect and clipDevPath call. 0 is reserved to indicate an
466 // invalid ID.
467 static int32_t gGenID;
468
robertphillips@google.com46f93502012-08-07 15:38:08 +0000469 /**
commit-bot@chromium.orge5b2af92014-02-16 13:25:24 +0000470 * Helper for clipDevPath, etc.
471 */
472 void pushElement(const Element& element);
473
474 /**
commit-bot@chromium.org6fbe54c2013-06-11 11:01:48 +0000475 * Restore the stack back to the specified save count.
476 */
477 void restoreTo(int saveCount);
478
479 /**
robertphillips@google.com46f93502012-08-07 15:38:08 +0000480 * Return the next unique generation ID.
481 */
482 static int32_t GetNextGenID();
reed@google.com5c3d1472011-02-22 19:12:23 +0000483};
484
485#endif