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