1 /* 2 * Copyright 2005 The Android Open Source Project 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #ifndef SkRegion_DEFINED 9 #define SkRegion_DEFINED 10 11 #include "include/core/SkRect.h" 12 13 class SkPath; 14 class SkRgnBuilder; 15 16 /** \class SkRegion 17 SkRegion describes the set of pixels used to clip SkCanvas. SkRegion is compact, 18 efficiently storing a single integer rectangle, or a run length encoded array 19 of rectangles. SkRegion may reduce the current SkCanvas clip, or may be drawn as 20 one or more integer rectangles. SkRegion iterator returns the scan lines or 21 rectangles contained by it, optionally intersecting a bounding rectangle. 22 */ 23 class SK_API SkRegion { 24 typedef int32_t RunType; 25 public: 26 27 /** Constructs an empty SkRegion. SkRegion is set to empty bounds 28 at (0, 0) with zero width and height. 29 30 @return empty SkRegion 31 32 example: https://fiddle.skia.org/c/@Region_empty_constructor 33 */ 34 SkRegion(); 35 36 /** Constructs a copy of an existing region. 37 Copy constructor makes two regions identical by value. Internally, region and 38 the returned result share pointer values. The underlying SkRect array is 39 copied when modified. 40 41 Creating a SkRegion copy is very efficient and never allocates memory. 42 SkRegion are always copied by value from the interface; the underlying shared 43 pointers are not exposed. 44 45 @param region SkRegion to copy by value 46 @return copy of SkRegion 47 48 example: https://fiddle.skia.org/c/@Region_copy_const_SkRegion 49 */ 50 SkRegion(const SkRegion& region); 51 52 /** Constructs a rectangular SkRegion matching the bounds of rect. 53 54 @param rect bounds of constructed SkRegion 55 @return rectangular SkRegion 56 57 example: https://fiddle.skia.org/c/@Region_copy_const_SkIRect 58 */ 59 explicit SkRegion(const SkIRect& rect); 60 61 /** Releases ownership of any shared data and deletes data if SkRegion is sole owner. 62 63 example: https://fiddle.skia.org/c/@Region_destructor 64 */ 65 ~SkRegion(); 66 67 /** Constructs a copy of an existing region. 68 Makes two regions identical by value. Internally, region and 69 the returned result share pointer values. The underlying SkRect array is 70 copied when modified. 71 72 Creating a SkRegion copy is very efficient and never allocates memory. 73 SkRegion are always copied by value from the interface; the underlying shared 74 pointers are not exposed. 75 76 @param region SkRegion to copy by value 77 @return SkRegion to copy by value 78 79 example: https://fiddle.skia.org/c/@Region_copy_operator 80 */ 81 SkRegion& operator=(const SkRegion& region); 82 83 /** Compares SkRegion and other; returns true if they enclose exactly 84 the same area. 85 86 @param other SkRegion to compare 87 @return true if SkRegion pair are equivalent 88 89 example: https://fiddle.skia.org/c/@Region_equal1_operator 90 */ 91 bool operator==(const SkRegion& other) const; 92 93 /** Compares SkRegion and other; returns true if they do not enclose the same area. 94 95 @param other SkRegion to compare 96 @return true if SkRegion pair are not equivalent 97 */ 98 bool operator!=(const SkRegion& other) const { 99 return !(*this == other); 100 } 101 102 /** Sets SkRegion to src, and returns true if src bounds is not empty. 103 This makes SkRegion and src identical by value. Internally, 104 SkRegion and src share pointer values. The underlying SkRect array is 105 copied when modified. 106 107 Creating a SkRegion copy is very efficient and never allocates memory. 108 SkRegion are always copied by value from the interface; the underlying shared 109 pointers are not exposed. 110 111 @param src SkRegion to copy 112 @return copy of src 113 */ set(const SkRegion & src)114 bool set(const SkRegion& src) { 115 *this = src; 116 return !this->isEmpty(); 117 } 118 119 /** Exchanges SkIRect array of SkRegion and other. swap() internally exchanges pointers, 120 so it is lightweight and does not allocate memory. 121 122 swap() usage has largely been replaced by operator=(const SkRegion& region). 123 SkPath do not copy their content on assignment until they are written to, 124 making assignment as efficient as swap(). 125 126 @param other operator=(const SkRegion& region) set 127 128 example: https://fiddle.skia.org/c/@Region_swap 129 */ 130 void swap(SkRegion& other); 131 132 /** Returns true if SkRegion is empty. 133 Empty SkRegion has bounds width or height less than or equal to zero. 134 SkRegion() constructs empty SkRegion; setEmpty() 135 and setRect() with dimensionless data make SkRegion empty. 136 137 @return true if bounds has no width or height 138 */ isEmpty()139 bool isEmpty() const { return fRunHead == emptyRunHeadPtr(); } 140 141 /** Returns true if SkRegion is one SkIRect with positive dimensions. 142 143 @return true if SkRegion contains one SkIRect 144 */ isRect()145 bool isRect() const { return fRunHead == kRectRunHeadPtr; } 146 147 /** Returns true if SkRegion is described by more than one rectangle. 148 149 @return true if SkRegion contains more than one SkIRect 150 */ isComplex()151 bool isComplex() const { return !this->isEmpty() && !this->isRect(); } 152 153 /** Returns minimum and maximum axes values of SkIRect array. 154 Returns (0, 0, 0, 0) if SkRegion is empty. 155 156 @return combined bounds of all SkIRect elements 157 */ getBounds()158 const SkIRect& getBounds() const { return fBounds; } 159 160 /** Returns a value that increases with the number of 161 elements in SkRegion. Returns zero if SkRegion is empty. 162 Returns one if SkRegion equals SkIRect; otherwise, returns 163 value greater than one indicating that SkRegion is complex. 164 165 Call to compare SkRegion for relative complexity. 166 167 @return relative complexity 168 169 example: https://fiddle.skia.org/c/@Region_computeRegionComplexity 170 */ 171 int computeRegionComplexity() const; 172 173 /** Appends outline of SkRegion to path. 174 Returns true if SkRegion is not empty; otherwise, returns false, and leaves path 175 unmodified. 176 177 @param path SkPath to append to 178 @return true if path changed 179 180 example: https://fiddle.skia.org/c/@Region_getBoundaryPath 181 */ 182 bool getBoundaryPath(SkPath* path) const; 183 184 /** Constructs an empty SkRegion. SkRegion is set to empty bounds 185 at (0, 0) with zero width and height. Always returns false. 186 187 @return false 188 189 example: https://fiddle.skia.org/c/@Region_setEmpty 190 */ 191 bool setEmpty(); 192 193 /** Constructs a rectangular SkRegion matching the bounds of rect. 194 If rect is empty, constructs empty and returns false. 195 196 @param rect bounds of constructed SkRegion 197 @return true if rect is not empty 198 199 example: https://fiddle.skia.org/c/@Region_setRect 200 */ 201 bool setRect(const SkIRect& rect); 202 203 /** Constructs SkRegion as the union of SkIRect in rects array. If count is 204 zero, constructs empty SkRegion. Returns false if constructed SkRegion is empty. 205 206 May be faster than repeated calls to op(). 207 208 @param rects array of SkIRect 209 @param count array size 210 @return true if constructed SkRegion is not empty 211 212 example: https://fiddle.skia.org/c/@Region_setRects 213 */ 214 bool setRects(const SkIRect rects[], int count); 215 216 /** Constructs a copy of an existing region. 217 Makes two regions identical by value. Internally, region and 218 the returned result share pointer values. The underlying SkRect array is 219 copied when modified. 220 221 Creating a SkRegion copy is very efficient and never allocates memory. 222 SkRegion are always copied by value from the interface; the underlying shared 223 pointers are not exposed. 224 225 @param region SkRegion to copy by value 226 @return SkRegion to copy by value 227 228 example: https://fiddle.skia.org/c/@Region_setRegion 229 */ 230 bool setRegion(const SkRegion& region); 231 232 /** Constructs SkRegion to match outline of path within clip. 233 Returns false if constructed SkRegion is empty. 234 235 Constructed SkRegion draws the same pixels as path through clip when 236 anti-aliasing is disabled. 237 238 @param path SkPath providing outline 239 @param clip SkRegion containing path 240 @return true if constructed SkRegion is not empty 241 242 example: https://fiddle.skia.org/c/@Region_setPath 243 */ 244 bool setPath(const SkPath& path, const SkRegion& clip); 245 246 /** Returns true if SkRegion intersects rect. 247 Returns false if either rect or SkRegion is empty, or do not intersect. 248 249 @param rect SkIRect to intersect 250 @return true if rect and SkRegion have area in common 251 252 example: https://fiddle.skia.org/c/@Region_intersects 253 */ 254 bool intersects(const SkIRect& rect) const; 255 256 /** Returns true if SkRegion intersects other. 257 Returns false if either other or SkRegion is empty, or do not intersect. 258 259 @param other SkRegion to intersect 260 @return true if other and SkRegion have area in common 261 262 example: https://fiddle.skia.org/c/@Region_intersects_2 263 */ 264 bool intersects(const SkRegion& other) const; 265 266 /** Returns true if SkIPoint (x, y) is inside SkRegion. 267 Returns false if SkRegion is empty. 268 269 @param x test SkIPoint x-coordinate 270 @param y test SkIPoint y-coordinate 271 @return true if (x, y) is inside SkRegion 272 273 example: https://fiddle.skia.org/c/@Region_contains 274 */ 275 bool contains(int32_t x, int32_t y) const; 276 277 /** Returns true if other is completely inside SkRegion. 278 Returns false if SkRegion or other is empty. 279 280 @param other SkIRect to contain 281 @return true if other is inside SkRegion 282 283 example: https://fiddle.skia.org/c/@Region_contains_2 284 */ 285 bool contains(const SkIRect& other) const; 286 287 /** Returns true if other is completely inside SkRegion. 288 Returns false if SkRegion or other is empty. 289 290 @param other SkRegion to contain 291 @return true if other is inside SkRegion 292 293 example: https://fiddle.skia.org/c/@Region_contains_3 294 */ 295 bool contains(const SkRegion& other) const; 296 297 /** Returns true if SkRegion is a single rectangle and contains r. 298 May return false even though SkRegion contains r. 299 300 @param r SkIRect to contain 301 @return true quickly if r points are equal or inside 302 */ quickContains(const SkIRect & r)303 bool quickContains(const SkIRect& r) const { 304 SkASSERT(this->isEmpty() == fBounds.isEmpty()); // valid region 305 306 return r.fLeft < r.fRight && r.fTop < r.fBottom && 307 fRunHead == kRectRunHeadPtr && // this->isRect() 308 /* fBounds.contains(left, top, right, bottom); */ 309 fBounds.fLeft <= r.fLeft && fBounds.fTop <= r.fTop && 310 fBounds.fRight >= r.fRight && fBounds.fBottom >= r.fBottom; 311 } 312 313 /** Returns true if SkRegion does not intersect rect. 314 Returns true if rect is empty or SkRegion is empty. 315 May return false even though SkRegion does not intersect rect. 316 317 @param rect SkIRect to intersect 318 @return true if rect does not intersect 319 */ quickReject(const SkIRect & rect)320 bool quickReject(const SkIRect& rect) const { 321 return this->isEmpty() || rect.isEmpty() || 322 !SkIRect::Intersects(fBounds, rect); 323 } 324 325 /** Returns true if SkRegion does not intersect rgn. 326 Returns true if rgn is empty or SkRegion is empty. 327 May return false even though SkRegion does not intersect rgn. 328 329 @param rgn SkRegion to intersect 330 @return true if rgn does not intersect 331 */ quickReject(const SkRegion & rgn)332 bool quickReject(const SkRegion& rgn) const { 333 return this->isEmpty() || rgn.isEmpty() || 334 !SkIRect::Intersects(fBounds, rgn.fBounds); 335 } 336 337 /** Offsets SkRegion by ivector (dx, dy). Has no effect if SkRegion is empty. 338 339 @param dx x-axis offset 340 @param dy y-axis offset 341 */ translate(int dx,int dy)342 void translate(int dx, int dy) { this->translate(dx, dy, this); } 343 344 /** Offsets SkRegion by ivector (dx, dy), writing result to dst. SkRegion may be passed 345 as dst parameter, translating SkRegion in place. Has no effect if dst is nullptr. 346 If SkRegion is empty, sets dst to empty. 347 348 @param dx x-axis offset 349 @param dy y-axis offset 350 @param dst translated result 351 352 example: https://fiddle.skia.org/c/@Region_translate_2 353 */ 354 void translate(int dx, int dy, SkRegion* dst) const; 355 356 /** \enum SkRegion::Op 357 The logical operations that can be performed when combining two SkRegion. 358 */ 359 enum Op { 360 kDifference_Op, //!< target minus operand 361 kIntersect_Op, //!< target intersected with operand 362 kUnion_Op, //!< target unioned with operand 363 kXOR_Op, //!< target exclusive or with operand 364 kReverseDifference_Op, //!< operand minus target 365 kReplace_Op, //!< replace target with operand 366 kLastOp = kReplace_Op, //!< last operator 367 }; 368 369 static const int kOpCnt = kLastOp + 1; 370 371 /** Replaces SkRegion with the result of SkRegion op rect. 372 Returns true if replaced SkRegion is not empty. 373 374 @param rect SkIRect operand 375 @return false if result is empty 376 */ op(const SkIRect & rect,Op op)377 bool op(const SkIRect& rect, Op op) { 378 if (this->isRect() && kIntersect_Op == op) { 379 if (!fBounds.intersect(rect)) { 380 return this->setEmpty(); 381 } 382 return true; 383 } 384 return this->op(*this, rect, op); 385 } 386 387 /** Replaces SkRegion with the result of SkRegion op rgn. 388 Returns true if replaced SkRegion is not empty. 389 390 @param rgn SkRegion operand 391 @return false if result is empty 392 */ op(const SkRegion & rgn,Op op)393 bool op(const SkRegion& rgn, Op op) { return this->op(*this, rgn, op); } 394 395 /** Replaces SkRegion with the result of rect op rgn. 396 Returns true if replaced SkRegion is not empty. 397 398 @param rect SkIRect operand 399 @param rgn SkRegion operand 400 @return false if result is empty 401 402 example: https://fiddle.skia.org/c/@Region_op_4 403 */ 404 bool op(const SkIRect& rect, const SkRegion& rgn, Op op); 405 406 /** Replaces SkRegion with the result of rgn op rect. 407 Returns true if replaced SkRegion is not empty. 408 409 @param rgn SkRegion operand 410 @param rect SkIRect operand 411 @return false if result is empty 412 413 example: https://fiddle.skia.org/c/@Region_op_5 414 */ 415 bool op(const SkRegion& rgn, const SkIRect& rect, Op op); 416 417 /** Replaces SkRegion with the result of rgna op rgnb. 418 Returns true if replaced SkRegion is not empty. 419 420 @param rgna SkRegion operand 421 @param rgnb SkRegion operand 422 @return false if result is empty 423 424 example: https://fiddle.skia.org/c/@Region_op_6 425 */ 426 bool op(const SkRegion& rgna, const SkRegion& rgnb, Op op); 427 428 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK 429 /** Private. Android framework only. 430 431 @return string representation of SkRegion 432 */ 433 char* toString(); 434 #endif 435 436 /** \class SkRegion::Iterator 437 Returns sequence of rectangles, sorted along y-axis, then x-axis, that make 438 up SkRegion. 439 */ 440 class SK_API Iterator { 441 public: 442 443 /** Initializes SkRegion::Iterator with an empty SkRegion. done() on SkRegion::Iterator 444 returns true. 445 Call reset() to initialized SkRegion::Iterator at a later time. 446 447 @return empty SkRegion iterator 448 */ Iterator()449 Iterator() : fRgn(nullptr), fDone(true) {} 450 451 /** Sets SkRegion::Iterator to return elements of SkIRect array in region. 452 453 @param region SkRegion to iterate 454 @return SkRegion iterator 455 456 example: https://fiddle.skia.org/c/@Region_Iterator_copy_const_SkRegion 457 */ 458 Iterator(const SkRegion& region); 459 460 /** SkPoint SkRegion::Iterator to start of SkRegion. 461 Returns true if SkRegion was set; otherwise, returns false. 462 463 @return true if SkRegion was set 464 465 example: https://fiddle.skia.org/c/@Region_Iterator_rewind 466 */ 467 bool rewind(); 468 469 /** Resets iterator, using the new SkRegion. 470 471 @param region SkRegion to iterate 472 473 example: https://fiddle.skia.org/c/@Region_Iterator_reset 474 */ 475 void reset(const SkRegion& region); 476 477 /** Returns true if SkRegion::Iterator is pointing to final SkIRect in SkRegion. 478 479 @return true if data parsing is complete 480 */ done()481 bool done() const { return fDone; } 482 483 /** Advances SkRegion::Iterator to next SkIRect in SkRegion if it is not done. 484 485 example: https://fiddle.skia.org/c/@Region_Iterator_next 486 */ 487 void next(); 488 489 /** Returns SkIRect element in SkRegion. Does not return predictable results if SkRegion 490 is empty. 491 492 @return part of SkRegion as SkIRect 493 */ rect()494 const SkIRect& rect() const { return fRect; } 495 496 /** Returns SkRegion if set; otherwise, returns nullptr. 497 498 @return iterated SkRegion 499 */ rgn()500 const SkRegion* rgn() const { return fRgn; } 501 502 private: 503 const SkRegion* fRgn; 504 const SkRegion::RunType* fRuns; 505 SkIRect fRect = {0, 0, 0, 0}; 506 bool fDone; 507 }; 508 509 /** \class SkRegion::Cliperator 510 Returns the sequence of rectangles, sorted along y-axis, then x-axis, that make 511 up SkRegion intersected with the specified clip rectangle. 512 */ 513 class SK_API Cliperator { 514 public: 515 516 /** Sets SkRegion::Cliperator to return elements of SkIRect array in SkRegion within clip. 517 518 @param region SkRegion to iterate 519 @param clip bounds of iteration 520 @return SkRegion iterator 521 522 example: https://fiddle.skia.org/c/@Region_Cliperator_const_SkRegion_const_SkIRect 523 */ 524 Cliperator(const SkRegion& region, const SkIRect& clip); 525 526 /** Returns true if SkRegion::Cliperator is pointing to final SkIRect in SkRegion. 527 528 @return true if data parsing is complete 529 */ done()530 bool done() { return fDone; } 531 532 /** Advances iterator to next SkIRect in SkRegion contained by clip. 533 534 example: https://fiddle.skia.org/c/@Region_Cliperator_next 535 */ 536 void next(); 537 538 /** Returns SkIRect element in SkRegion, intersected with clip passed to 539 SkRegion::Cliperator constructor. Does not return predictable results if SkRegion 540 is empty. 541 542 @return part of SkRegion inside clip as SkIRect 543 */ rect()544 const SkIRect& rect() const { return fRect; } 545 546 private: 547 Iterator fIter; 548 SkIRect fClip; 549 SkIRect fRect = {0, 0, 0, 0}; 550 bool fDone; 551 }; 552 553 /** \class SkRegion::Spanerator 554 Returns the line segment ends within SkRegion that intersect a horizontal line. 555 */ 556 class Spanerator { 557 public: 558 559 /** Sets SkRegion::Spanerator to return line segments in SkRegion on scan line. 560 561 @param region SkRegion to iterate 562 @param y horizontal line to intersect 563 @param left bounds of iteration 564 @param right bounds of iteration 565 @return SkRegion iterator 566 567 example: https://fiddle.skia.org/c/@Region_Spanerator_const_SkRegion_int_int_int 568 */ 569 Spanerator(const SkRegion& region, int y, int left, int right); 570 571 /** Advances iterator to next span intersecting SkRegion within line segment provided 572 in constructor. Returns true if interval was found. 573 574 @param left pointer to span start; may be nullptr 575 @param right pointer to span end; may be nullptr 576 @return true if interval was found 577 578 example: https://fiddle.skia.org/c/@Region_Spanerator_next 579 */ 580 bool next(int* left, int* right); 581 582 private: 583 const SkRegion::RunType* fRuns; 584 int fLeft, fRight; 585 bool fDone; 586 }; 587 588 /** Writes SkRegion to buffer, and returns number of bytes written. 589 If buffer is nullptr, returns number number of bytes that would be written. 590 591 @param buffer storage for binary data 592 @return size of SkRegion 593 594 example: https://fiddle.skia.org/c/@Region_writeToMemory 595 */ 596 size_t writeToMemory(void* buffer) const; 597 598 /** Constructs SkRegion from buffer of size length. Returns bytes read. 599 Returned value will be multiple of four or zero if length was too small. 600 601 @param buffer storage for binary data 602 @param length size of buffer 603 @return bytes read 604 605 example: https://fiddle.skia.org/c/@Region_readFromMemory 606 */ 607 size_t readFromMemory(const void* buffer, size_t length); 608 609 /** Writes text representation of SkRegion to string. 610 611 @param desc the string storing a description of parameters. 612 @param depth the number of tabs preceding each line. 613 */ 614 void dump(std::string& desc, int depth) const; 615 616 private: 617 static constexpr int kOpCount = kReplace_Op + 1; 618 619 // T 620 // [B N L R S] 621 // S 622 static constexpr int kRectRegionRuns = 7; 623 624 struct RunHead; 625 emptyRunHeadPtr()626 static RunHead* emptyRunHeadPtr() { return (SkRegion::RunHead*) -1; } 627 static constexpr RunHead* kRectRunHeadPtr = nullptr; 628 629 // allocate space for count runs 630 void allocateRuns(int count); 631 void allocateRuns(int count, int ySpanCount, int intervalCount); 632 void allocateRuns(const RunHead& src); 633 634 SkDEBUGCODE(void dump() const;) 635 636 SkIRect fBounds; 637 RunHead* fRunHead; 638 639 void freeRuns(); 640 641 /** 642 * Return the runs from this region, consing up fake runs if the region 643 * is empty or a rect. In those 2 cases, we use tmpStorage to hold the 644 * run data. 645 */ 646 const RunType* getRuns(RunType tmpStorage[], int* intervals) const; 647 648 // This is called with runs[] that do not yet have their interval-count 649 // field set on each scanline. That is computed as part of this call 650 // (inside ComputeRunBounds). 651 bool setRuns(RunType runs[], int count); 652 653 int count_runtype_values(int* itop, int* ibot) const; 654 655 bool isValid() const; 656 657 static void BuildRectRuns(const SkIRect& bounds, 658 RunType runs[kRectRegionRuns]); 659 660 // If the runs define a simple rect, return true and set bounds to that 661 // rect. If not, return false and ignore bounds. 662 static bool RunsAreARect(const SkRegion::RunType runs[], int count, 663 SkIRect* bounds); 664 665 /** 666 * If the last arg is null, just return if the result is non-empty, 667 * else store the result in the last arg. 668 */ 669 static bool Oper(const SkRegion&, const SkRegion&, SkRegion::Op, SkRegion*); 670 671 friend struct RunHead; 672 friend class Iterator; 673 friend class Spanerator; 674 friend class SkRegionPriv; 675 friend class SkRgnBuilder; 676 friend class SkFlatRegion; 677 }; 678 679 #endif 680