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