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 */ 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 */ 74 bool isEmpty() const { return fRunHead == SkRegion_gEmptyRunHeadPtr; } 75 76 /** Return true if this region is a single, non-empty rectangle */ 77 bool isRect() const { return fRunHead == SkRegion_gRectRunHeadPtr; } 78 79 /** Return true if this region consists of more than 1 rectangular area */ 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 */ 86 const SkIRect& getBounds() const { return fBounds; } 87 88 /** 89 * Returns a value that grows approximately linearly with the number of 90 * intervals comprised in the region. Empty region will return 0, Rect 91 * will return 1, Complex will return a value > 1. 92 * 93 * Use this to compare two regions, where the larger count likely 94 * indicates a more complex region. 95 */ 96 int computeRegionComplexity() const; 97 98 /** 99 * Returns true if the region is non-empty, and if so, appends the 100 * boundary(s) of the region to the specified path. 101 * If the region is empty, returns false, and path is left unmodified. 102 */ 103 bool getBoundaryPath(SkPath* path) const; 104 105 /** 106 * Set the region to be empty, and return false, since the resulting 107 * region is empty 108 */ 109 bool setEmpty(); 110 111 /** 112 * If rect is non-empty, set this region to that rectangle and return true, 113 * otherwise set this region to empty and return false. 114 */ 115 bool setRect(const SkIRect&); 116 117 /** 118 * If left < right and top < bottom, set this region to that rectangle and 119 * return true, otherwise set this region to empty and return false. 120 */ 121 bool setRect(int32_t left, int32_t top, int32_t right, int32_t bottom); 122 123 /** 124 * Set this region to the union of an array of rects. This is generally 125 * faster than calling region.op(rect, kUnion_Op) in a loop. If count is 126 * 0, then this region is set to the empty region. 127 * @return true if the resulting region is non-empty 128 */ 129 bool setRects(const SkIRect rects[], int count); 130 131 /** 132 * Set this region to the specified region, and return true if it is 133 * non-empty. 134 */ 135 bool setRegion(const SkRegion&); 136 137 /** 138 * Set this region to the area described by the path, clipped. 139 * Return true if the resulting region is non-empty. 140 * This produces a region that is identical to the pixels that would be 141 * drawn by the path (with no antialiasing) with the specified clip. 142 */ 143 bool setPath(const SkPath&, const SkRegion& clip); 144 145 /** 146 * Returns true if the specified rectangle has a non-empty intersection 147 * with this region. 148 */ 149 bool intersects(const SkIRect&) const; 150 151 /** 152 * Returns true if the specified region has a non-empty intersection 153 * with this region. 154 */ 155 bool intersects(const SkRegion&) const; 156 157 /** 158 * Return true if the specified x,y coordinate is inside the region. 159 */ 160 bool contains(int32_t x, int32_t y) const; 161 162 /** 163 * Return true if the specified rectangle is completely inside the region. 164 * This works for simple (rectangular) and complex regions, and always 165 * returns the correct result. Note: if either this region or the rectangle 166 * is empty, contains() returns false. 167 */ 168 bool contains(const SkIRect&) const; 169 170 /** 171 * Return true if the specified region is completely inside the region. 172 * This works for simple (rectangular) and complex regions, and always 173 * returns the correct result. Note: if either region is empty, contains() 174 * returns false. 175 */ 176 bool contains(const SkRegion&) const; 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 region. 183 */ 184 bool quickContains(const SkIRect& r) const { 185 return this->quickContains(r.fLeft, r.fTop, r.fRight, r.fBottom); 186 } 187 188 /** 189 * Return true if this region is a single rectangle (not complex) and the 190 * specified rectangle is contained by this region. Returning false is not 191 * a guarantee that the rectangle is not contained by this region, but 192 * return true is a guarantee that the rectangle is contained by this 193 * region. 194 */ 195 bool quickContains(int32_t left, int32_t top, int32_t right, 196 int32_t bottom) const { 197 SkASSERT(this->isEmpty() == fBounds.isEmpty()); // valid region 198 199 return left < right && top < bottom && 200 fRunHead == SkRegion_gRectRunHeadPtr && // this->isRect() 201 /* fBounds.contains(left, top, right, bottom); */ 202 fBounds.fLeft <= left && fBounds.fTop <= top && 203 fBounds.fRight >= right && fBounds.fBottom >= bottom; 204 } 205 206 /** 207 * Return true if this region is empty, or if the specified rectangle does 208 * not intersect the region. Returning false is not a guarantee that they 209 * intersect, but returning true is a guarantee that they do not. 210 */ 211 bool quickReject(const SkIRect& rect) const { 212 return this->isEmpty() || rect.isEmpty() || 213 !SkIRect::Intersects(fBounds, rect); 214 } 215 216 /** 217 * Return true if this region, or rgn, is empty, or if their bounds do not 218 * intersect. Returning false is not a guarantee that they intersect, but 219 * returning true is a guarantee that they do not. 220 */ 221 bool quickReject(const SkRegion& rgn) const { 222 return this->isEmpty() || rgn.isEmpty() || 223 !SkIRect::Intersects(fBounds, rgn.fBounds); 224 } 225 226 /** Translate the region by the specified (dx, dy) amount. */ 227 void translate(int dx, int dy) { this->translate(dx, dy, this); } 228 229 /** 230 * Translate the region by the specified (dx, dy) amount, writing the 231 * resulting region into dst. Note: it is legal to pass this region as the 232 * dst parameter, effectively translating the region in place. If dst is 233 * null, nothing happens. 234 */ 235 void translate(int dx, int dy, SkRegion* dst) const; 236 237 /** 238 * The logical operations that can be performed when combining two regions. 239 */ 240 enum Op { 241 kDifference_Op, //!< subtract the op region from the first region 242 kIntersect_Op, //!< intersect the two regions 243 kUnion_Op, //!< union (inclusive-or) the two regions 244 kXOR_Op, //!< exclusive-or the two regions 245 /** subtract the first region from the op region */ 246 kReverseDifference_Op, 247 kReplace_Op, //!< replace the dst region with the op region 248 249 kLastOp = kReplace_Op 250 }; 251 252 static const int kOpCnt = kLastOp + 1; 253 254 /** 255 * Set this region to the result of applying the Op to this region and the 256 * specified rectangle: this = (this op rect). 257 * Return true if the resulting region is non-empty. 258 */ 259 bool op(const SkIRect& rect, Op op) { return this->op(*this, rect, op); } 260 261 /** 262 * Set this region to the result of applying the Op to this region and the 263 * specified rectangle: this = (this op rect). 264 * Return true if the resulting region is non-empty. 265 */ 266 bool op(int left, int top, int right, int bottom, Op op) { 267 SkIRect rect; 268 rect.set(left, top, right, bottom); 269 return this->op(*this, rect, op); 270 } 271 272 /** 273 * Set this region to the result of applying the Op to this region and the 274 * specified region: this = (this op rgn). 275 * Return true if the resulting region is non-empty. 276 */ 277 bool op(const SkRegion& rgn, Op op) { return this->op(*this, rgn, op); } 278 279 /** 280 * Set this region to the result of applying the Op to the specified 281 * rectangle and region: this = (rect op rgn). 282 * Return true if the resulting region is non-empty. 283 */ 284 bool op(const SkIRect& rect, const SkRegion& rgn, Op); 285 286 /** 287 * Set this region to the result of applying the Op to the specified 288 * region and rectangle: this = (rgn op rect). 289 * Return true if the resulting region is non-empty. 290 */ 291 bool op(const SkRegion& rgn, const SkIRect& rect, Op); 292 293 /** 294 * Set this region to the result of applying the Op to the specified 295 * regions: this = (rgna op rgnb). 296 * Return true if the resulting region is non-empty. 297 */ 298 bool op(const SkRegion& rgna, const SkRegion& rgnb, Op op); 299 300 #ifdef SK_BUILD_FOR_ANDROID 301 /** Returns a new char* containing the list of rectangles in this region 302 */ 303 char* toString(); 304 #endif 305 306 /** 307 * Returns the sequence of rectangles, sorted in Y and X, that make up 308 * this region. 309 */ 310 class SK_API Iterator { 311 public: 312 Iterator() : fRgn(NULL), fDone(true) {} 313 Iterator(const SkRegion&); 314 // if we have a region, reset to it and return true, else return false 315 bool rewind(); 316 // reset the iterator, using the new region 317 void reset(const SkRegion&); 318 bool done() const { return fDone; } 319 void next(); 320 const SkIRect& rect() const { return fRect; } 321 // may return null 322 const SkRegion* rgn() const { return fRgn; } 323 324 private: 325 const SkRegion* fRgn; 326 const RunType* fRuns; 327 SkIRect fRect; 328 bool fDone; 329 }; 330 331 /** 332 * Returns the sequence of rectangles, sorted in Y and X, that make up 333 * this region intersected with the specified clip rectangle. 334 */ 335 class SK_API Cliperator { 336 public: 337 Cliperator(const SkRegion&, const SkIRect& clip); 338 bool done() { return fDone; } 339 void next(); 340 const SkIRect& rect() const { return fRect; } 341 342 private: 343 Iterator fIter; 344 SkIRect fClip; 345 SkIRect fRect; 346 bool fDone; 347 }; 348 349 /** 350 * Returns the sequence of runs that make up this region for the specified 351 * Y scanline, clipped to the specified left and right X values. 352 */ 353 class Spanerator { 354 public: 355 Spanerator(const SkRegion&, int y, int left, int right); 356 bool next(int* left, int* right); 357 358 private: 359 const SkRegion::RunType* fRuns; 360 int fLeft, fRight; 361 bool fDone; 362 }; 363 364 /** 365 * Write the region to the buffer, and return the number of bytes written. 366 * If buffer is NULL, it still returns the number of bytes. 367 */ 368 size_t writeToMemory(void* buffer) const; 369 /** 370 * Initializes the region from the buffer 371 * 372 * @param buffer Memory to read from 373 * @param length Amount of memory available in the buffer 374 * @return number of bytes read (must be a multiple of 4) or 375 * 0 if there was not enough memory available 376 */ 377 size_t readFromMemory(const void* buffer, size_t length); 378 379 /** 380 * Returns a reference to a global empty region. Just a convenience for 381 * callers that need a const empty region. 382 */ 383 static const SkRegion& GetEmptyRegion(); 384 385 SkDEBUGCODE(void dump() const;) 386 SkDEBUGCODE(void validate() const;) 387 SkDEBUGCODE(static void UnitTest();) 388 389 // expose this to allow for regression test on complex regions 390 SkDEBUGCODE(bool debugSetRuns(const RunType runs[], int count);) 391 392 private: 393 enum { 394 kOpCount = kReplace_Op + 1 395 }; 396 397 enum { 398 // T 399 // [B N L R S] 400 // S 401 kRectRegionRuns = 7 402 }; 403 404 friend class android::Region; // needed for marshalling efficiently 405 406 struct RunHead; 407 408 // allocate space for count runs 409 void allocateRuns(int count); 410 void allocateRuns(int count, int ySpanCount, int intervalCount); 411 void allocateRuns(const RunHead& src); 412 413 SkIRect fBounds; 414 RunHead* fRunHead; 415 416 void freeRuns(); 417 418 /** 419 * Return the runs from this region, consing up fake runs if the region 420 * is empty or a rect. In those 2 cases, we use tmpStorage to hold the 421 * run data. 422 */ 423 const RunType* getRuns(RunType tmpStorage[], int* intervals) const; 424 425 // This is called with runs[] that do not yet have their interval-count 426 // field set on each scanline. That is computed as part of this call 427 // (inside ComputeRunBounds). 428 bool setRuns(RunType runs[], int count); 429 430 int count_runtype_values(int* itop, int* ibot) const; 431 432 static void BuildRectRuns(const SkIRect& bounds, 433 RunType runs[kRectRegionRuns]); 434 435 // If the runs define a simple rect, return true and set bounds to that 436 // rect. If not, return false and ignore bounds. 437 static bool RunsAreARect(const SkRegion::RunType runs[], int count, 438 SkIRect* bounds); 439 440 /** 441 * If the last arg is null, just return if the result is non-empty, 442 * else store the result in the last arg. 443 */ 444 static bool Oper(const SkRegion&, const SkRegion&, SkRegion::Op, SkRegion*); 445 446 friend struct RunHead; 447 friend class Iterator; 448 friend class Spanerator; 449 friend class SkRgnBuilder; 450 friend class SkFlatRegion; 451 }; 452 453 #endif 454