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