1 /*
2  * Copyright 2010 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #ifndef GrClip_DEFINED
9 #define GrClip_DEFINED
10 
11 #include "SkClipStack.h"
12 
13 struct SkIRect;
14 
15 /**
16  * GrClip encapsulates the information required to construct the clip
17  * masks. 'A GrClip is either wide open, just an IRect, just a Rect, or a full clipstack.
18  * If the clip is a clipstack than the origin is used to translate the stack with
19  * respect to device coordinates. This allows us to use a clip stack that is
20  * specified for a root device with a layer device that is restricted to a subset
21  * of the original canvas. For other clip types the origin will always be (0,0).
22  *
23  * NOTE: GrClip *must* point to a const clipstack
24  */
25 class GrClip : SkNoncopyable {
26 public:
GrClip()27     GrClip() : fClipType(kWideOpen_ClipType) {
28         fOrigin.setZero();
29     }
30 
GrClip(const SkIRect & rect)31     GrClip(const SkIRect& rect) : fClipType(kIRect_ClipType) {
32         fOrigin.setZero();
33         fClip.fIRect = rect;
34     }
35 
GrClip(const SkRect & rect)36     GrClip(const SkRect& rect) : fClipType(kIRect_ClipType) {
37         fOrigin.setZero();
38         fClip.fIRect.fLeft   = SkScalarRoundToInt(rect.fLeft);
39         fClip.fIRect.fTop    = SkScalarRoundToInt(rect.fTop);
40         fClip.fIRect.fRight  = SkScalarRoundToInt(rect.fRight);
41         fClip.fIRect.fBottom = SkScalarRoundToInt(rect.fBottom);
42     }
43 
~GrClip()44     ~GrClip() { this->reset(); }
45 
46     const GrClip& operator=(const GrClip& other) {
47         this->reset();
48         fClipType = other.fClipType;
49         switch (other.fClipType) {
50             case kWideOpen_ClipType:
51                 fOrigin.setZero();
52                 break;
53             case kClipStack_ClipType:
54                 fClip.fStack = SkRef(other.clipStack());
55                 fOrigin = other.origin();
56                 break;
57             case kIRect_ClipType:
58                 fClip.fIRect = other.irect();
59                 fOrigin.setZero();
60                 break;
61         }
62         return *this;
63     }
64 
65     bool operator==(const GrClip& other) const {
66         if (this->clipType() != other.clipType()) {
67             return false;
68         }
69 
70         switch (fClipType) {
71             case kWideOpen_ClipType:
72                 return true;
73             case kClipStack_ClipType:
74                 if (this->origin() != other.origin()) {
75                     return false;
76                 }
77 
78                 if (this->clipStack() && other.clipStack()) {
79                     return *this->clipStack() == *other.clipStack();
80                 } else {
81                     return this->clipStack() == other.clipStack();
82                 }
83                 break;
84             case kIRect_ClipType:
85                 return this->irect() == other.irect();
86                 break;
87         }
88         SkFAIL("This should not occur\n");
89         return false;
90     }
91 
92     bool operator!=(const GrClip& other) const {
93         return !(*this == other);
94     }
95 
clipStack()96     const SkClipStack* clipStack() const {
97         SkASSERT(kClipStack_ClipType == fClipType);
98         return fClip.fStack;
99     }
100 
101     void setClipStack(const SkClipStack* clipStack, const SkIPoint* origin = NULL) {
102         this->reset();
103         if (clipStack->isWideOpen()) {
104             fClipType = kWideOpen_ClipType;
105             fOrigin.setZero();
106         } else {
107             fClipType = kClipStack_ClipType;
108             fClip.fStack = SkRef(clipStack);
109             if (origin) {
110                 fOrigin = *origin;
111             } else {
112                 fOrigin.setZero();
113             }
114         }
115     }
116 
irect()117     const SkIRect& irect() const {
118         SkASSERT(kIRect_ClipType == fClipType);
119         return fClip.fIRect;
120     }
121 
reset()122     void reset() {
123         if (kClipStack_ClipType == fClipType) {
124             fClip.fStack->unref();
125             fClip.fStack = NULL;
126         }
127         fClipType = kWideOpen_ClipType;
128         fOrigin.setZero();
129     }
130 
131     // We support this for all cliptypes to simplify the logic a bit in clip mask manager.
132     // non clipstack clip types MUST have a (0,0) origin
origin()133     const SkIPoint& origin() const {
134         SkASSERT(fClipType == kClipStack_ClipType || (fOrigin.fX == 0 && fOrigin.fY == 0));
135         return fOrigin;
136     }
137 
isWideOpen(const SkRect & rect)138     bool isWideOpen(const SkRect& rect) const {
139         return (kWideOpen_ClipType == fClipType) ||
140                (kClipStack_ClipType == fClipType && this->clipStack()->isWideOpen()) ||
141                (kIRect_ClipType == fClipType && this->irect().contains(rect));
142     }
143 
isWideOpen(const SkIRect & rect)144     bool isWideOpen(const SkIRect& rect) const {
145         return (kWideOpen_ClipType == fClipType) ||
146                (kClipStack_ClipType == fClipType && this->clipStack()->isWideOpen()) ||
147                (kIRect_ClipType == fClipType && this->irect().contains(rect));
148     }
149 
isWideOpen()150     bool isWideOpen() const {
151         return (kWideOpen_ClipType == fClipType) ||
152                (kClipStack_ClipType == fClipType && this->clipStack()->isWideOpen());
153     }
154 
quickContains(const SkRect & rect)155     bool quickContains(const SkRect& rect) const {
156         return (kWideOpen_ClipType == fClipType) ||
157                (kClipStack_ClipType == fClipType && this->clipStack()->quickContains(rect)) ||
158                (kIRect_ClipType == fClipType && this->irect().contains(rect));
159     }
160 
161     void getConservativeBounds(int width, int height,
162                                SkIRect* devResult,
163                                bool* isIntersectionOfRects = NULL) const;
164 
165     static const GrClip& WideOpen();
166 
167     enum ClipType {
168         kClipStack_ClipType,
169         kWideOpen_ClipType,
170         kIRect_ClipType,
171     };
172 
clipType()173     ClipType clipType() const { return fClipType; }
174 
175 private:
176     union Clip {
177         const SkClipStack* fStack;
178         SkIRect fIRect;
179     } fClip;
180 
181     SkIPoint fOrigin;
182     ClipType fClipType;
183 };
184 
185 #endif
186