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