1 /* 2 * Copyright (C) 2005 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef SkRegion_DEFINED 18 #define SkRegion_DEFINED 19 20 #include "SkRect.h" 21 22 class SkPath; 23 class SkRgnBuilder; 24 25 namespace android { 26 class Region; 27 } 28 29 #define SkRegion_gEmptyRunHeadPtr ((SkRegion::RunHead*)-1) 30 #define SkRegion_gRectRunHeadPtr 0 31 32 /** \class SkRegion 33 34 The SkRegion class encapsulates the geometric region used to specify 35 clipping areas for drawing. 36 */ 37 class SkRegion { 38 public: 39 typedef int32_t RunType; 40 enum { 41 kRunTypeSentinel = 0x7FFFFFFF 42 }; 43 44 SkRegion(); 45 SkRegion(const SkRegion&); 46 explicit SkRegion(const SkIRect&); 47 ~SkRegion(); 48 49 SkRegion& operator=(const SkRegion&); 50 51 friend int operator==(const SkRegion& a, const SkRegion& b); 52 friend int operator!=(const SkRegion& a, const SkRegion& b) { 53 return !(a == b); 54 } 55 56 /** Replace this region with the specified region, and return true if the 57 resulting region is non-empty. 58 */ set(const SkRegion & src)59 bool set(const SkRegion& src) { 60 SkASSERT(&src); 61 *this = src; 62 return !this->isEmpty(); 63 } 64 65 /** Swap the contents of this and the specified region. This operation 66 is gauarenteed to never fail. 67 */ 68 void swap(SkRegion&); 69 70 /** Return true if this region is empty */ isEmpty()71 bool isEmpty() const { return fRunHead == SkRegion_gEmptyRunHeadPtr; } 72 /** Return true if this region is a single, non-empty rectangle */ isRect()73 bool isRect() const { return fRunHead == SkRegion_gRectRunHeadPtr; } 74 /** Return true if this region consists of more than 1 rectangular area */ isComplex()75 bool isComplex() const { return !this->isEmpty() && !this->isRect(); } 76 /** Return the bounds of this region. If the region is empty, returns an 77 empty rectangle. 78 */ getBounds()79 const SkIRect& getBounds() const { return fBounds; } 80 81 /** Returns true if the region is non-empty, and if so, sets the specified 82 path to the boundary(s) of the region. 83 */ 84 bool getBoundaryPath(SkPath* path) const; 85 86 /** Set the region to be empty, and return false, since the resulting 87 region is empty 88 */ 89 bool setEmpty(); 90 91 /** If rect is non-empty, set this region to that rectangle and return true, 92 otherwise set this region to empty and return false. 93 */ 94 bool setRect(const SkIRect&); 95 96 /** If left < right and top < bottom, set this region to that rectangle and 97 return true, otherwise set this region to empty and return false. 98 */ 99 bool setRect(int32_t left, int32_t top, int32_t right, int32_t bottom); 100 101 /** Set this region to the specified region, and return true if it is 102 non-empty. */ 103 bool setRegion(const SkRegion&); 104 105 /** Set this region to the area described by the path, clipped. 106 Return true if the resulting region is non-empty. 107 This produces a region that is identical to the pixels that would be 108 drawn by the path (with no antialiasing) with the specified clip. 109 */ 110 bool setPath(const SkPath&, const SkRegion& clip); 111 112 /** Returns true if the specified rectangle has a non-empty intersection 113 with this region. 114 */ 115 bool intersects(const SkIRect&) const; 116 117 /** Returns true if the specified region has a non-empty intersection 118 with this region. 119 */ 120 bool intersects(const SkRegion&) const; 121 122 /** Return true if the specified x,y coordinate is inside the region. 123 */ 124 bool contains(int32_t x, int32_t y) const; 125 126 /** Return true if the specified rectangle is completely inside the region. 127 This works for simple (rectangular) and complex regions, and always 128 returns the correct result. Note: if either this region or the rectangle 129 is empty, contains() returns false. 130 */ 131 bool contains(const SkIRect&) const; 132 133 /** Return true if the specified region is completely inside the region. 134 This works for simple (rectangular) and complex regions, and always 135 returns the correct result. Note: if either region is empty, contains() 136 returns false. 137 */ 138 bool contains(const SkRegion&) const; 139 140 /** Return true if this region is a single rectangle (not complex) and the 141 specified rectangle is contained by this region. Returning false is not 142 a guarantee that the rectangle is not contained by this region, but 143 return true is a guarantee that the rectangle is contained by this region. 144 */ quickContains(const SkIRect & r)145 bool quickContains(const SkIRect& r) const { 146 return this->quickContains(r.fLeft, r.fTop, r.fRight, r.fBottom); 147 } 148 149 /** Return true if this region is a single rectangle (not complex) and the 150 specified rectangle is contained by this region. Returning false is not 151 a guarantee that the rectangle is not contained by this region, but 152 return true is a guarantee that the rectangle is contained by this 153 region. 154 */ quickContains(int32_t left,int32_t top,int32_t right,int32_t bottom)155 bool quickContains(int32_t left, int32_t top, int32_t right, 156 int32_t bottom) const { 157 SkASSERT(this->isEmpty() == fBounds.isEmpty()); // valid region 158 159 return left < right && top < bottom && 160 fRunHead == SkRegion_gRectRunHeadPtr && // this->isRect() 161 /* fBounds.contains(left, top, right, bottom); */ 162 fBounds.fLeft <= left && fBounds.fTop <= top && 163 fBounds.fRight >= right && fBounds.fBottom >= bottom; 164 } 165 166 /** Return true if this region is empty, or if the specified rectangle does 167 not intersect the region. Returning false is not a guarantee that they 168 intersect, but returning true is a guarantee that they do not. 169 */ quickReject(const SkIRect & rect)170 bool quickReject(const SkIRect& rect) const 171 { 172 return this->isEmpty() || rect.isEmpty() || 173 !SkIRect::Intersects(fBounds, rect); 174 } 175 176 /** Return true if this region, or rgn, is empty, or if their bounds do not 177 intersect. Returning false is not a guarantee that they intersect, but 178 returning true is a guarantee that they do not. 179 */ quickReject(const SkRegion & rgn)180 bool quickReject(const SkRegion& rgn) const { 181 return this->isEmpty() || rgn.isEmpty() || 182 !SkIRect::Intersects(fBounds, rgn.fBounds); 183 } 184 185 /** Translate the region by the specified (dx, dy) amount. 186 */ translate(int dx,int dy)187 void translate(int dx, int dy) { this->translate(dx, dy, this); } 188 189 /** Translate the region by the specified (dx, dy) amount, writing the 190 resulting region into dst. Note: it is legal to pass this region as the 191 dst parameter, effectively translating the region in place. If dst is 192 null, nothing happens. 193 */ 194 void translate(int dx, int dy, SkRegion* dst) const; 195 196 /** The logical operations that can be performed when combining two regions. 197 */ 198 enum Op { 199 kDifference_Op, //!< subtract the op region from the first region 200 kIntersect_Op, //!< intersect the two regions 201 kUnion_Op, //!< union (inclusive-or) the two regions 202 kXOR_Op, //!< exclusive-or the two regions 203 /** subtract the first region from the op region */ 204 kReverseDifference_Op, 205 kReplace_Op //!< replace the dst region with the op region 206 }; 207 208 /** Set this region to the result of applying the Op to this region and the 209 specified rectangle: this = (this op rect). 210 Return true if the resulting region is non-empty. 211 */ op(const SkIRect & rect,Op op)212 bool op(const SkIRect& rect, Op op) { return this->op(*this, rect, op); } 213 214 /** Set this region to the result of applying the Op to this region and the 215 specified rectangle: this = (this op rect). 216 Return true if the resulting region is non-empty. 217 */ op(int left,int top,int right,int bottom,Op op)218 bool op(int left, int top, int right, int bottom, Op op) { 219 SkIRect rect; 220 rect.set(left, top, right, bottom); 221 return this->op(*this, rect, op); 222 } 223 224 /** Set this region to the result of applying the Op to this region and the 225 specified region: this = (this op rgn). 226 Return true if the resulting region is non-empty. 227 */ op(const SkRegion & rgn,Op op)228 bool op(const SkRegion& rgn, Op op) { return this->op(*this, rgn, op); } 229 /** Set this region to the result of applying the Op to the specified 230 rectangle and region: this = (rect op rgn). 231 Return true if the resulting region is non-empty. 232 */ 233 bool op(const SkIRect& rect, const SkRegion& rgn, Op); 234 /** Set this region to the result of applying the Op to the specified 235 region and rectangle: this = (rgn op rect). 236 Return true if the resulting region is non-empty. 237 */ 238 bool op(const SkRegion& rgn, const SkIRect& rect, Op); 239 /** Set this region to the result of applying the Op to the specified 240 regions: this = (rgna op rgnb). 241 Return true if the resulting region is non-empty. 242 */ 243 bool op(const SkRegion& rgna, const SkRegion& rgnb, Op op); 244 245 /** Returns the sequence of rectangles, sorted in Y and X, that make up 246 this region. 247 */ 248 class Iterator { 249 public: Iterator()250 Iterator() : fRgn(NULL), fDone(true) {} 251 Iterator(const SkRegion&); 252 // if we have a region, reset to it and return true, else return false 253 bool rewind(); 254 // reset the iterator, using the new region 255 void reset(const SkRegion&); done()256 bool done() { return fDone; } 257 void next(); rect()258 const SkIRect& rect() const { return fRect; } 259 260 private: 261 const SkRegion* fRgn; 262 const RunType* fRuns; 263 SkIRect fRect; 264 bool fDone; 265 }; 266 267 /** Returns the sequence of rectangles, sorted in Y and X, that make up 268 this region intersected with the specified clip rectangle. 269 */ 270 class Cliperator { 271 public: 272 Cliperator(const SkRegion&, const SkIRect& clip); done()273 bool done() { return fDone; } 274 void next(); rect()275 const SkIRect& rect() const { return fRect; } 276 277 private: 278 Iterator fIter; 279 SkIRect fClip; 280 SkIRect fRect; 281 bool fDone; 282 }; 283 284 /** Returns the sequence of runs that make up this region for the specified 285 Y scanline, clipped to the specified left and right X values. 286 */ 287 class Spanerator { 288 public: 289 Spanerator(const SkRegion&, int y, int left, int right); 290 bool next(int* left, int* right); 291 292 private: 293 const SkRegion::RunType* fRuns; 294 int fLeft, fRight; 295 bool fDone; 296 }; 297 298 /** Write the region to the buffer, and return the number of bytes written. 299 If buffer is NULL, it still returns the number of bytes. 300 */ 301 uint32_t flatten(void* buffer) const; 302 /** Initialized the region from the buffer, returning the number 303 of bytes actually read. 304 */ 305 uint32_t unflatten(const void* buffer); 306 307 SkDEBUGCODE(void dump() const;) 308 SkDEBUGCODE(void validate() const;) 309 SkDEBUGCODE(static void UnitTest();) 310 311 // expose this to allow for regression test on complex regions 312 SkDEBUGCODE(bool debugSetRuns(const RunType runs[], int count);) 313 314 private: 315 enum { 316 kOpCount = kReplace_Op + 1 317 }; 318 319 enum { 320 kRectRegionRuns = 6 // need to store a region of a rect [T B L R S S] 321 }; 322 323 friend class android::Region; // needed for marshalling efficiently 324 void allocateRuns(int count); // allocate space for count runs 325 326 struct RunHead; 327 328 SkIRect fBounds; 329 RunHead* fRunHead; 330 331 void freeRuns(); 332 const RunType* getRuns(RunType tmpStorage[], int* count) const; 333 bool setRuns(RunType runs[], int count); 334 335 int count_runtype_values(int* itop, int* ibot) const; 336 337 static void BuildRectRuns(const SkIRect& bounds, 338 RunType runs[kRectRegionRuns]); 339 // returns true if runs are just a rect 340 static bool ComputeRunBounds(const RunType runs[], int count, 341 SkIRect* bounds); 342 343 friend struct RunHead; 344 friend class Iterator; 345 friend class Spanerator; 346 friend class SkRgnBuilder; 347 friend class SkFlatRegion; 348 }; 349 350 351 #endif 352 353