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 250 /** 251 * Set this region to the result of applying the Op to this region and the 252 * specified rectangle: this = (this op rect). 253 * Return true if the resulting region is non-empty. 254 */ 255 bool op(const SkIRect& rect, Op op) { return this->op(*this, rect, op); } 256 257 /** 258 * Set this region to the result of applying the Op to this region and the 259 * specified rectangle: this = (this op rect). 260 * Return true if the resulting region is non-empty. 261 */ 262 bool op(int left, int top, int right, int bottom, Op op) { 263 SkIRect rect; 264 rect.set(left, top, right, bottom); 265 return this->op(*this, rect, op); 266 } 267 268 /** 269 * Set this region to the result of applying the Op to this region and the 270 * specified region: this = (this op rgn). 271 * Return true if the resulting region is non-empty. 272 */ 273 bool op(const SkRegion& rgn, Op op) { return this->op(*this, rgn, op); } 274 275 /** 276 * Set this region to the result of applying the Op to the specified 277 * rectangle and region: this = (rect op rgn). 278 * Return true if the resulting region is non-empty. 279 */ 280 bool op(const SkIRect& rect, const SkRegion& rgn, Op); 281 282 /** 283 * Set this region to the result of applying the Op to the specified 284 * region and rectangle: this = (rgn op rect). 285 * Return true if the resulting region is non-empty. 286 */ 287 bool op(const SkRegion& rgn, const SkIRect& rect, Op); 288 289 /** 290 * Set this region to the result of applying the Op to the specified 291 * regions: this = (rgna op rgnb). 292 * Return true if the resulting region is non-empty. 293 */ 294 bool op(const SkRegion& rgna, const SkRegion& rgnb, Op op); 295 296 #ifdef SK_BUILD_FOR_ANDROID 297 /** Returns a new char* containing the list of rectangles in this region 298 */ 299 char* toString(); 300 #endif 301 302 /** 303 * Returns the sequence of rectangles, sorted in Y and X, that make up 304 * this region. 305 */ 306 class SK_API Iterator { 307 public: 308 Iterator() : fRgn(NULL), fDone(true) {} 309 Iterator(const SkRegion&); 310 // if we have a region, reset to it and return true, else return false 311 bool rewind(); 312 // reset the iterator, using the new region 313 void reset(const SkRegion&); 314 bool done() const { return fDone; } 315 void next(); 316 const SkIRect& rect() const { return fRect; } 317 // may return null 318 const SkRegion* rgn() const { return fRgn; } 319 320 private: 321 const SkRegion* fRgn; 322 const RunType* fRuns; 323 SkIRect fRect; 324 bool fDone; 325 }; 326 327 /** 328 * Returns the sequence of rectangles, sorted in Y and X, that make up 329 * this region intersected with the specified clip rectangle. 330 */ 331 class SK_API Cliperator { 332 public: 333 Cliperator(const SkRegion&, const SkIRect& clip); 334 bool done() { return fDone; } 335 void next(); 336 const SkIRect& rect() const { return fRect; } 337 338 private: 339 Iterator fIter; 340 SkIRect fClip; 341 SkIRect fRect; 342 bool fDone; 343 }; 344 345 /** 346 * Returns the sequence of runs that make up this region for the specified 347 * Y scanline, clipped to the specified left and right X values. 348 */ 349 class Spanerator { 350 public: 351 Spanerator(const SkRegion&, int y, int left, int right); 352 bool next(int* left, int* right); 353 354 private: 355 const SkRegion::RunType* fRuns; 356 int fLeft, fRight; 357 bool fDone; 358 }; 359 360 /** 361 * Write the region to the buffer, and return the number of bytes written. 362 * If buffer is NULL, it still returns the number of bytes. 363 */ 364 size_t writeToMemory(void* buffer) const; 365 /** 366 * Initializes the region from the buffer 367 * 368 * @param buffer Memory to read from 369 * @param length Amount of memory available in the buffer 370 * @return number of bytes read (must be a multiple of 4) or 371 * 0 if there was not enough memory available 372 */ 373 size_t readFromMemory(const void* buffer, size_t length); 374 375 /** 376 * Returns a reference to a global empty region. Just a convenience for 377 * callers that need a const empty region. 378 */ 379 static const SkRegion& GetEmptyRegion(); 380 381 SkDEBUGCODE(void dump() const;) 382 SkDEBUGCODE(void validate() const;) 383 SkDEBUGCODE(static void UnitTest();) 384 385 // expose this to allow for regression test on complex regions 386 SkDEBUGCODE(bool debugSetRuns(const RunType runs[], int count);) 387 388 private: 389 enum { 390 kOpCount = kReplace_Op + 1 391 }; 392 393 enum { 394 // T 395 // [B N L R S] 396 // S 397 kRectRegionRuns = 7 398 }; 399 400 friend class android::Region; // needed for marshalling efficiently 401 402 struct RunHead; 403 404 // allocate space for count runs 405 void allocateRuns(int count); 406 void allocateRuns(int count, int ySpanCount, int intervalCount); 407 void allocateRuns(const RunHead& src); 408 409 SkIRect fBounds; 410 RunHead* fRunHead; 411 412 void freeRuns(); 413 414 /** 415 * Return the runs from this region, consing up fake runs if the region 416 * is empty or a rect. In those 2 cases, we use tmpStorage to hold the 417 * run data. 418 */ 419 const RunType* getRuns(RunType tmpStorage[], int* intervals) const; 420 421 // This is called with runs[] that do not yet have their interval-count 422 // field set on each scanline. That is computed as part of this call 423 // (inside ComputeRunBounds). 424 bool setRuns(RunType runs[], int count); 425 426 int count_runtype_values(int* itop, int* ibot) const; 427 428 static void BuildRectRuns(const SkIRect& bounds, 429 RunType runs[kRectRegionRuns]); 430 431 // If the runs define a simple rect, return true and set bounds to that 432 // rect. If not, return false and ignore bounds. 433 static bool RunsAreARect(const SkRegion::RunType runs[], int count, 434 SkIRect* bounds); 435 436 /** 437 * If the last arg is null, just return if the result is non-empty, 438 * else store the result in the last arg. 439 */ 440 static bool Oper(const SkRegion&, const SkRegion&, SkRegion::Op, SkRegion*); 441 442 friend struct RunHead; 443 friend class Iterator; 444 friend class Spanerator; 445 friend class SkRgnBuilder; 446 friend class SkFlatRegion; 447 }; 448 449 #endif 450