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