1 2 /* 3 * Copyright 2006 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 SkRect_DEFINED 11 #define SkRect_DEFINED 12 13 #include "SkPoint.h" 14 #include "SkSize.h" 15 16 /** \struct SkIRect 17 18 SkIRect holds four 32 bit integer coordinates for a rectangle 19 */ 20 struct SK_API SkIRect { 21 int32_t fLeft, fTop, fRight, fBottom; 22 23 static SkIRect SK_WARN_UNUSED_RESULT MakeEmpty() { 24 SkIRect r; 25 r.setEmpty(); 26 return r; 27 } 28 29 static SkIRect SK_WARN_UNUSED_RESULT MakeWH(int32_t w, int32_t h) { 30 SkIRect r; 31 r.set(0, 0, w, h); 32 return r; 33 } 34 35 static SkIRect SK_WARN_UNUSED_RESULT MakeSize(const SkISize& size) { 36 SkIRect r; 37 r.set(0, 0, size.width(), size.height()); 38 return r; 39 } 40 41 static SkIRect SK_WARN_UNUSED_RESULT MakeLTRB(int32_t l, int32_t t, int32_t r, int32_t b) { 42 SkIRect rect; 43 rect.set(l, t, r, b); 44 return rect; 45 } 46 47 static SkIRect SK_WARN_UNUSED_RESULT MakeXYWH(int32_t x, int32_t y, int32_t w, int32_t h) { 48 SkIRect r; 49 r.set(x, y, x + w, y + h); 50 return r; 51 } 52 53 int left() const { return fLeft; } 54 int top() const { return fTop; } 55 int right() const { return fRight; } 56 int bottom() const { return fBottom; } 57 58 /** return the left edge of the rect */ 59 int x() const { return fLeft; } 60 /** return the top edge of the rect */ 61 int y() const { return fTop; } 62 /** 63 * Returns the rectangle's width. This does not check for a valid rect 64 * (i.e. left <= right) so the result may be negative. 65 */ 66 int width() const { return fRight - fLeft; } 67 68 /** 69 * Returns the rectangle's height. This does not check for a valid rect 70 * (i.e. top <= bottom) so the result may be negative. 71 */ 72 int height() const { return fBottom - fTop; } 73 74 /** 75 * Since the center of an integer rect may fall on a factional value, this 76 * method is defined to return (right + left) >> 1. 77 * 78 * This is a specific "truncation" of the average, which is different than 79 * (right + left) / 2 when the sum is negative. 80 */ 81 int centerX() const { return (fRight + fLeft) >> 1; } 82 83 /** 84 * Since the center of an integer rect may fall on a factional value, this 85 * method is defined to return (bottom + top) >> 1 86 * 87 * This is a specific "truncation" of the average, which is different than 88 * (bottom + top) / 2 when the sum is negative. 89 */ 90 int centerY() const { return (fBottom + fTop) >> 1; } 91 92 /** 93 * Return true if the rectangle's width or height are <= 0 94 */ 95 bool isEmpty() const { return fLeft >= fRight || fTop >= fBottom; } 96 97 friend bool operator==(const SkIRect& a, const SkIRect& b) { 98 return !memcmp(&a, &b, sizeof(a)); 99 } 100 101 friend bool operator!=(const SkIRect& a, const SkIRect& b) { 102 return !(a == b); 103 } 104 105 bool is16Bit() const { 106 return SkIsS16(fLeft) && SkIsS16(fTop) && 107 SkIsS16(fRight) && SkIsS16(fBottom); 108 } 109 110 /** Set the rectangle to (0,0,0,0) 111 */ 112 void setEmpty() { memset(this, 0, sizeof(*this)); } 113 114 void set(int32_t left, int32_t top, int32_t right, int32_t bottom) { 115 fLeft = left; 116 fTop = top; 117 fRight = right; 118 fBottom = bottom; 119 } 120 // alias for set(l, t, r, b) 121 void setLTRB(int32_t left, int32_t top, int32_t right, int32_t bottom) { 122 this->set(left, top, right, bottom); 123 } 124 125 void setXYWH(int32_t x, int32_t y, int32_t width, int32_t height) { 126 fLeft = x; 127 fTop = y; 128 fRight = x + width; 129 fBottom = y + height; 130 } 131 132 /** 133 * Make the largest representable rectangle 134 */ 135 void setLargest() { 136 fLeft = fTop = SK_MinS32; 137 fRight = fBottom = SK_MaxS32; 138 } 139 140 /** 141 * Make the largest representable rectangle, but inverted (e.g. fLeft will 142 * be max 32bit and right will be min 32bit). 143 */ 144 void setLargestInverted() { 145 fLeft = fTop = SK_MaxS32; 146 fRight = fBottom = SK_MinS32; 147 } 148 149 /** Offset set the rectangle by adding dx to its left and right, 150 and adding dy to its top and bottom. 151 */ 152 void offset(int32_t dx, int32_t dy) { 153 fLeft += dx; 154 fTop += dy; 155 fRight += dx; 156 fBottom += dy; 157 } 158 159 void offset(const SkIPoint& delta) { 160 this->offset(delta.fX, delta.fY); 161 } 162 163 /** 164 * Offset this rect such its new x() and y() will equal newX and newY. 165 */ 166 void offsetTo(int32_t newX, int32_t newY) { 167 fRight += newX - fLeft; 168 fBottom += newY - fTop; 169 fLeft = newX; 170 fTop = newY; 171 } 172 173 /** Inset the rectangle by (dx,dy). If dx is positive, then the sides are moved inwards, 174 making the rectangle narrower. If dx is negative, then the sides are moved outwards, 175 making the rectangle wider. The same holds true for dy and the top and bottom. 176 */ 177 void inset(int32_t dx, int32_t dy) { 178 fLeft += dx; 179 fTop += dy; 180 fRight -= dx; 181 fBottom -= dy; 182 } 183 184 /** Outset the rectangle by (dx,dy). If dx is positive, then the sides are 185 moved outwards, making the rectangle wider. If dx is negative, then the 186 sides are moved inwards, making the rectangle narrower. The same holds 187 true for dy and the top and bottom. 188 */ 189 void outset(int32_t dx, int32_t dy) { this->inset(-dx, -dy); } 190 191 bool quickReject(int l, int t, int r, int b) const { 192 return l >= fRight || fLeft >= r || t >= fBottom || fTop >= b; 193 } 194 195 /** Returns true if (x,y) is inside the rectangle and the rectangle is not 196 empty. The left and top are considered to be inside, while the right 197 and bottom are not. Thus for the rectangle (0, 0, 5, 10), the 198 points (0,0) and (0,9) are inside, while (-1,0) and (5,9) are not. 199 */ 200 bool contains(int32_t x, int32_t y) const { 201 return (unsigned)(x - fLeft) < (unsigned)(fRight - fLeft) && 202 (unsigned)(y - fTop) < (unsigned)(fBottom - fTop); 203 } 204 205 /** Returns true if the 4 specified sides of a rectangle are inside or equal to this rectangle. 206 If either rectangle is empty, contains() returns false. 207 */ 208 bool contains(int32_t left, int32_t top, int32_t right, int32_t bottom) const { 209 return left < right && top < bottom && !this->isEmpty() && // check for empties 210 fLeft <= left && fTop <= top && 211 fRight >= right && fBottom >= bottom; 212 } 213 214 /** Returns true if the specified rectangle r is inside or equal to this rectangle. 215 */ 216 bool contains(const SkIRect& r) const { 217 return !r.isEmpty() && !this->isEmpty() && // check for empties 218 fLeft <= r.fLeft && fTop <= r.fTop && 219 fRight >= r.fRight && fBottom >= r.fBottom; 220 } 221 222 /** Return true if this rectangle contains the specified rectangle. 223 For speed, this method does not check if either this or the specified 224 rectangles are empty, and if either is, its return value is undefined. 225 In the debugging build however, we assert that both this and the 226 specified rectangles are non-empty. 227 */ 228 bool containsNoEmptyCheck(int32_t left, int32_t top, 229 int32_t right, int32_t bottom) const { 230 SkASSERT(fLeft < fRight && fTop < fBottom); 231 SkASSERT(left < right && top < bottom); 232 233 return fLeft <= left && fTop <= top && 234 fRight >= right && fBottom >= bottom; 235 } 236 237 bool containsNoEmptyCheck(const SkIRect& r) const { 238 return containsNoEmptyCheck(r.fLeft, r.fTop, r.fRight, r.fBottom); 239 } 240 241 /** If r intersects this rectangle, return true and set this rectangle to that 242 intersection, otherwise return false and do not change this rectangle. 243 If either rectangle is empty, do nothing and return false. 244 */ 245 bool intersect(const SkIRect& r) { 246 SkASSERT(&r); 247 return this->intersect(r.fLeft, r.fTop, r.fRight, r.fBottom); 248 } 249 250 /** If rectangles a and b intersect, return true and set this rectangle to 251 that intersection, otherwise return false and do not change this 252 rectangle. If either rectangle is empty, do nothing and return false. 253 */ 254 bool intersect(const SkIRect& a, const SkIRect& b) { 255 SkASSERT(&a && &b); 256 257 if (!a.isEmpty() && !b.isEmpty() && 258 a.fLeft < b.fRight && b.fLeft < a.fRight && 259 a.fTop < b.fBottom && b.fTop < a.fBottom) { 260 fLeft = SkMax32(a.fLeft, b.fLeft); 261 fTop = SkMax32(a.fTop, b.fTop); 262 fRight = SkMin32(a.fRight, b.fRight); 263 fBottom = SkMin32(a.fBottom, b.fBottom); 264 return true; 265 } 266 return false; 267 } 268 269 /** If rectangles a and b intersect, return true and set this rectangle to 270 that intersection, otherwise return false and do not change this 271 rectangle. For speed, no check to see if a or b are empty is performed. 272 If either is, then the return result is undefined. In the debug build, 273 we assert that both rectangles are non-empty. 274 */ 275 bool intersectNoEmptyCheck(const SkIRect& a, const SkIRect& b) { 276 SkASSERT(&a && &b); 277 SkASSERT(!a.isEmpty() && !b.isEmpty()); 278 279 if (a.fLeft < b.fRight && b.fLeft < a.fRight && 280 a.fTop < b.fBottom && b.fTop < a.fBottom) { 281 fLeft = SkMax32(a.fLeft, b.fLeft); 282 fTop = SkMax32(a.fTop, b.fTop); 283 fRight = SkMin32(a.fRight, b.fRight); 284 fBottom = SkMin32(a.fBottom, b.fBottom); 285 return true; 286 } 287 return false; 288 } 289 290 /** If the rectangle specified by left,top,right,bottom intersects this rectangle, 291 return true and set this rectangle to that intersection, 292 otherwise return false and do not change this rectangle. 293 If either rectangle is empty, do nothing and return false. 294 */ 295 bool intersect(int32_t left, int32_t top, int32_t right, int32_t bottom) { 296 if (left < right && top < bottom && !this->isEmpty() && 297 fLeft < right && left < fRight && fTop < bottom && top < fBottom) { 298 if (fLeft < left) fLeft = left; 299 if (fTop < top) fTop = top; 300 if (fRight > right) fRight = right; 301 if (fBottom > bottom) fBottom = bottom; 302 return true; 303 } 304 return false; 305 } 306 307 /** Returns true if a and b are not empty, and they intersect 308 */ 309 static bool Intersects(const SkIRect& a, const SkIRect& b) { 310 return !a.isEmpty() && !b.isEmpty() && // check for empties 311 a.fLeft < b.fRight && b.fLeft < a.fRight && 312 a.fTop < b.fBottom && b.fTop < a.fBottom; 313 } 314 315 /** 316 * Returns true if a and b intersect. debug-asserts that neither are empty. 317 */ 318 static bool IntersectsNoEmptyCheck(const SkIRect& a, const SkIRect& b) { 319 SkASSERT(!a.isEmpty()); 320 SkASSERT(!b.isEmpty()); 321 return a.fLeft < b.fRight && b.fLeft < a.fRight && 322 a.fTop < b.fBottom && b.fTop < a.fBottom; 323 } 324 325 /** Update this rectangle to enclose itself and the specified rectangle. 326 If this rectangle is empty, just set it to the specified rectangle. If the specified 327 rectangle is empty, do nothing. 328 */ 329 void join(int32_t left, int32_t top, int32_t right, int32_t bottom); 330 331 /** Update this rectangle to enclose itself and the specified rectangle. 332 If this rectangle is empty, just set it to the specified rectangle. If the specified 333 rectangle is empty, do nothing. 334 */ 335 void join(const SkIRect& r) { 336 this->join(r.fLeft, r.fTop, r.fRight, r.fBottom); 337 } 338 339 /** Swap top/bottom or left/right if there are flipped. 340 This can be called if the edges are computed separately, 341 and may have crossed over each other. 342 When this returns, left <= right && top <= bottom 343 */ 344 void sort(); 345 346 static const SkIRect& SK_WARN_UNUSED_RESULT EmptyIRect() { 347 static const SkIRect gEmpty = { 0, 0, 0, 0 }; 348 return gEmpty; 349 } 350 }; 351 352 /** \struct SkRect 353 */ 354 struct SK_API SkRect { 355 SkScalar fLeft, fTop, fRight, fBottom; 356 357 static SkRect SK_WARN_UNUSED_RESULT MakeEmpty() { 358 SkRect r; 359 r.setEmpty(); 360 return r; 361 } 362 363 static SkRect SK_WARN_UNUSED_RESULT MakeWH(SkScalar w, SkScalar h) { 364 SkRect r; 365 r.set(0, 0, w, h); 366 return r; 367 } 368 369 static SkRect SK_WARN_UNUSED_RESULT MakeSize(const SkSize& size) { 370 SkRect r; 371 r.set(0, 0, size.width(), size.height()); 372 return r; 373 } 374 375 static SkRect SK_WARN_UNUSED_RESULT MakeLTRB(SkScalar l, SkScalar t, SkScalar r, SkScalar b) { 376 SkRect rect; 377 rect.set(l, t, r, b); 378 return rect; 379 } 380 381 static SkRect SK_WARN_UNUSED_RESULT MakeXYWH(SkScalar x, SkScalar y, SkScalar w, SkScalar h) { 382 SkRect r; 383 r.set(x, y, x + w, y + h); 384 return r; 385 } 386 387 // DEPRECATED: call Make(r) 388 static SkRect SK_WARN_UNUSED_RESULT MakeFromIRect(const SkIRect& irect) { 389 SkRect r; 390 r.set(SkIntToScalar(irect.fLeft), 391 SkIntToScalar(irect.fTop), 392 SkIntToScalar(irect.fRight), 393 SkIntToScalar(irect.fBottom)); 394 return r; 395 } 396 397 static SkRect SK_WARN_UNUSED_RESULT Make(const SkIRect& irect) { 398 SkRect r; 399 r.set(SkIntToScalar(irect.fLeft), 400 SkIntToScalar(irect.fTop), 401 SkIntToScalar(irect.fRight), 402 SkIntToScalar(irect.fBottom)); 403 return r; 404 } 405 406 /** 407 * Return true if the rectangle's width or height are <= 0 408 */ 409 bool isEmpty() const { return fLeft >= fRight || fTop >= fBottom; } 410 411 /** 412 * Returns true iff all values in the rect are finite. If any are 413 * infinite or NaN (or SK_FixedNaN when SkScalar is fixed) then this 414 * returns false. 415 */ 416 bool isFinite() const { 417 #ifdef SK_SCALAR_IS_FLOAT 418 float accum = 0; 419 accum *= fLeft; 420 accum *= fTop; 421 accum *= fRight; 422 accum *= fBottom; 423 424 // accum is either NaN or it is finite (zero). 425 SkASSERT(0 == accum || !(accum == accum)); 426 427 // value==value will be true iff value is not NaN 428 // TODO: is it faster to say !accum or accum==accum? 429 return accum == accum; 430 #else 431 // use bit-or for speed, since we don't care about short-circuting the 432 // tests, and we expect the common case will be that we need to check all. 433 int isNaN = (SK_FixedNaN == fLeft) | (SK_FixedNaN == fTop) | 434 (SK_FixedNaN == fRight) | (SK_FixedNaN == fBottom); 435 return !isNaN; 436 #endif 437 } 438 439 SkScalar x() const { return fLeft; } 440 SkScalar y() const { return fTop; } 441 SkScalar left() const { return fLeft; } 442 SkScalar top() const { return fTop; } 443 SkScalar right() const { return fRight; } 444 SkScalar bottom() const { return fBottom; } 445 SkScalar width() const { return fRight - fLeft; } 446 SkScalar height() const { return fBottom - fTop; } 447 SkScalar centerX() const { return SkScalarHalf(fLeft + fRight); } 448 SkScalar centerY() const { return SkScalarHalf(fTop + fBottom); } 449 450 friend bool operator==(const SkRect& a, const SkRect& b) { 451 return SkScalarsEqual((SkScalar*)&a, (SkScalar*)&b, 4); 452 } 453 454 friend bool operator!=(const SkRect& a, const SkRect& b) { 455 return !SkScalarsEqual((SkScalar*)&a, (SkScalar*)&b, 4); 456 } 457 458 /** return the 4 points that enclose the rectangle 459 */ 460 void toQuad(SkPoint quad[4]) const; 461 462 /** Set this rectangle to the empty rectangle (0,0,0,0) 463 */ 464 void setEmpty() { memset(this, 0, sizeof(*this)); } 465 466 void set(const SkIRect& src) { 467 fLeft = SkIntToScalar(src.fLeft); 468 fTop = SkIntToScalar(src.fTop); 469 fRight = SkIntToScalar(src.fRight); 470 fBottom = SkIntToScalar(src.fBottom); 471 } 472 473 void set(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) { 474 fLeft = left; 475 fTop = top; 476 fRight = right; 477 fBottom = bottom; 478 } 479 // alias for set(l, t, r, b) 480 void setLTRB(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) { 481 this->set(left, top, right, bottom); 482 } 483 484 /** Initialize the rect with the 4 specified integers. The routine handles 485 converting them to scalars (by calling SkIntToScalar) 486 */ 487 void iset(int left, int top, int right, int bottom) { 488 fLeft = SkIntToScalar(left); 489 fTop = SkIntToScalar(top); 490 fRight = SkIntToScalar(right); 491 fBottom = SkIntToScalar(bottom); 492 } 493 494 /** 495 * Set this rectangle to be left/top at 0,0, and have the specified width 496 * and height (automatically converted to SkScalar). 497 */ 498 void isetWH(int width, int height) { 499 fLeft = fTop = 0; 500 fRight = SkIntToScalar(width); 501 fBottom = SkIntToScalar(height); 502 } 503 504 /** Set this rectangle to be the bounds of the array of points. 505 If the array is empty (count == 0), then set this rectangle 506 to the empty rectangle (0,0,0,0) 507 */ 508 void set(const SkPoint pts[], int count) { 509 // set() had been checking for non-finite values, so keep that behavior 510 // for now. Now that we have setBoundsCheck(), we may decide to make 511 // set() be simpler/faster, and not check for those. 512 (void)this->setBoundsCheck(pts, count); 513 } 514 515 // alias for set(pts, count) 516 void setBounds(const SkPoint pts[], int count) { 517 (void)this->setBoundsCheck(pts, count); 518 } 519 520 /** 521 * Compute the bounds of the array of points, and set this rect to that 522 * bounds and return true... unless a non-finite value is encountered, 523 * in which case this rect is set to empty and false is returned. 524 */ 525 bool setBoundsCheck(const SkPoint pts[], int count); 526 527 void set(const SkPoint& p0, const SkPoint& p1) { 528 fLeft = SkMinScalar(p0.fX, p1.fX); 529 fRight = SkMaxScalar(p0.fX, p1.fX); 530 fTop = SkMinScalar(p0.fY, p1.fY); 531 fBottom = SkMaxScalar(p0.fY, p1.fY); 532 } 533 534 void setXYWH(SkScalar x, SkScalar y, SkScalar width, SkScalar height) { 535 fLeft = x; 536 fTop = y; 537 fRight = x + width; 538 fBottom = y + height; 539 } 540 541 void setWH(SkScalar width, SkScalar height) { 542 fLeft = 0; 543 fTop = 0; 544 fRight = width; 545 fBottom = height; 546 } 547 548 /** 549 * Make the largest representable rectangle 550 */ 551 void setLargest() { 552 fLeft = fTop = SK_ScalarMin; 553 fRight = fBottom = SK_ScalarMax; 554 } 555 556 /** 557 * Make the largest representable rectangle, but inverted (e.g. fLeft will 558 * be max and right will be min). 559 */ 560 void setLargestInverted() { 561 fLeft = fTop = SK_ScalarMax; 562 fRight = fBottom = SK_ScalarMin; 563 } 564 565 /** Offset set the rectangle by adding dx to its left and right, 566 and adding dy to its top and bottom. 567 */ 568 void offset(SkScalar dx, SkScalar dy) { 569 fLeft += dx; 570 fTop += dy; 571 fRight += dx; 572 fBottom += dy; 573 } 574 575 void offset(const SkPoint& delta) { 576 this->offset(delta.fX, delta.fY); 577 } 578 579 /** 580 * Offset this rect such its new x() and y() will equal newX and newY. 581 */ 582 void offsetTo(SkScalar newX, SkScalar newY) { 583 fRight += newX - fLeft; 584 fBottom += newY - fTop; 585 fLeft = newX; 586 fTop = newY; 587 } 588 589 /** Inset the rectangle by (dx,dy). If dx is positive, then the sides are 590 moved inwards, making the rectangle narrower. If dx is negative, then 591 the sides are moved outwards, making the rectangle wider. The same holds 592 true for dy and the top and bottom. 593 */ 594 void inset(SkScalar dx, SkScalar dy) { 595 fLeft += dx; 596 fTop += dy; 597 fRight -= dx; 598 fBottom -= dy; 599 } 600 601 /** Outset the rectangle by (dx,dy). If dx is positive, then the sides are 602 moved outwards, making the rectangle wider. If dx is negative, then the 603 sides are moved inwards, making the rectangle narrower. The same holds 604 true for dy and the top and bottom. 605 */ 606 void outset(SkScalar dx, SkScalar dy) { this->inset(-dx, -dy); } 607 608 /** If this rectangle intersects r, return true and set this rectangle to that 609 intersection, otherwise return false and do not change this rectangle. 610 If either rectangle is empty, do nothing and return false. 611 */ 612 bool intersect(const SkRect& r); 613 614 /** If this rectangle intersects the rectangle specified by left, top, right, bottom, 615 return true and set this rectangle to that intersection, otherwise return false 616 and do not change this rectangle. 617 If either rectangle is empty, do nothing and return false. 618 */ 619 bool intersect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom); 620 621 /** 622 * Return true if this rectangle is not empty, and the specified sides of 623 * a rectangle are not empty, and they intersect. 624 */ 625 bool intersects(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) const { 626 return // first check that both are not empty 627 left < right && top < bottom && 628 fLeft < fRight && fTop < fBottom && 629 // now check for intersection 630 fLeft < right && left < fRight && 631 fTop < bottom && top < fBottom; 632 } 633 634 /** If rectangles a and b intersect, return true and set this rectangle to 635 * that intersection, otherwise return false and do not change this 636 * rectangle. If either rectangle is empty, do nothing and return false. 637 */ 638 bool intersect(const SkRect& a, const SkRect& b); 639 640 /** 641 * Return true if rectangles a and b are not empty and intersect. 642 */ 643 static bool Intersects(const SkRect& a, const SkRect& b) { 644 return !a.isEmpty() && !b.isEmpty() && 645 a.fLeft < b.fRight && b.fLeft < a.fRight && 646 a.fTop < b.fBottom && b.fTop < a.fBottom; 647 } 648 649 /** 650 * Update this rectangle to enclose itself and the specified rectangle. 651 * If this rectangle is empty, just set it to the specified rectangle. 652 * If the specified rectangle is empty, do nothing. 653 */ 654 void join(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom); 655 656 /** Update this rectangle to enclose itself and the specified rectangle. 657 If this rectangle is empty, just set it to the specified rectangle. If the specified 658 rectangle is empty, do nothing. 659 */ 660 void join(const SkRect& r) { 661 this->join(r.fLeft, r.fTop, r.fRight, r.fBottom); 662 } 663 // alias for join() 664 void growToInclude(const SkRect& r) { this->join(r); } 665 666 /** 667 * Grow the rect to include the specified (x,y). After this call, the 668 * following will be true: fLeft <= x <= fRight && fTop <= y <= fBottom. 669 * 670 * This is close, but not quite the same contract as contains(), since 671 * contains() treats the left and top different from the right and bottom. 672 * contains(x,y) -> fLeft <= x < fRight && fTop <= y < fBottom. Also note 673 * that contains(x,y) always returns false if the rect is empty. 674 */ 675 void growToInclude(SkScalar x, SkScalar y) { 676 fLeft = SkMinScalar(x, fLeft); 677 fRight = SkMaxScalar(x, fRight); 678 fTop = SkMinScalar(y, fTop); 679 fBottom = SkMaxScalar(y, fBottom); 680 } 681 682 /** 683 * Returns true if (p.fX,p.fY) is inside the rectangle, and the rectangle 684 * is not empty. 685 * 686 * Contains treats the left and top differently from the right and bottom. 687 * The left and top coordinates of the rectangle are themselves considered 688 * to be inside, while the right and bottom are not. Thus for the rectangle 689 * {0, 0, 5, 10}, (0,0) is contained, but (0,10), (5,0) and (5,10) are not. 690 */ 691 bool contains(const SkPoint& p) const { 692 return !this->isEmpty() && 693 fLeft <= p.fX && p.fX < fRight && fTop <= p.fY && p.fY < fBottom; 694 } 695 696 /** 697 * Returns true if (x,y) is inside the rectangle, and the rectangle 698 * is not empty. 699 * 700 * Contains treats the left and top differently from the right and bottom. 701 * The left and top coordinates of the rectangle are themselves considered 702 * to be inside, while the right and bottom are not. Thus for the rectangle 703 * {0, 0, 5, 10}, (0,0) is contained, but (0,10), (5,0) and (5,10) are not. 704 */ 705 bool contains(SkScalar x, SkScalar y) const { 706 return !this->isEmpty() && 707 fLeft <= x && x < fRight && fTop <= y && y < fBottom; 708 } 709 710 /** 711 * Return true if this rectangle contains r, and if both rectangles are 712 * not empty. 713 */ 714 bool contains(const SkRect& r) const { 715 return !r.isEmpty() && !this->isEmpty() && 716 fLeft <= r.fLeft && fTop <= r.fTop && 717 fRight >= r.fRight && fBottom >= r.fBottom; 718 } 719 720 /** 721 * Set the dst rectangle by rounding this rectangle's coordinates to their 722 * nearest integer values using SkScalarRound. 723 */ 724 void round(SkIRect* dst) const { 725 SkASSERT(dst); 726 dst->set(SkScalarRoundToInt(fLeft), SkScalarRoundToInt(fTop), 727 SkScalarRoundToInt(fRight), SkScalarRoundToInt(fBottom)); 728 } 729 730 /** 731 * Set the dst rectangle by rounding "out" this rectangle, choosing the 732 * SkScalarFloor of top and left, and the SkScalarCeil of right and bottom. 733 */ 734 void roundOut(SkIRect* dst) const { 735 SkASSERT(dst); 736 dst->set(SkScalarFloorToInt(fLeft), SkScalarFloorToInt(fTop), 737 SkScalarCeilToInt(fRight), SkScalarCeilToInt(fBottom)); 738 } 739 740 /** 741 * Expand this rectangle by rounding its coordinates "out", choosing the 742 * floor of top and left, and the ceil of right and bottom. If this rect 743 * is already on integer coordinates, then it will be unchanged. 744 */ 745 void roundOut() { 746 this->set(SkScalarFloorToScalar(fLeft), 747 SkScalarFloorToScalar(fTop), 748 SkScalarCeilToScalar(fRight), 749 SkScalarCeilToScalar(fBottom)); 750 } 751 752 /** 753 * Set the dst rectangle by rounding "in" this rectangle, choosing the 754 * ceil of top and left, and the floor of right and bottom. This does *not* 755 * call sort(), so it is possible that the resulting rect is inverted... 756 * e.g. left >= right or top >= bottom. Call isEmpty() to detect that. 757 */ 758 void roundIn(SkIRect* dst) const { 759 SkASSERT(dst); 760 dst->set(SkScalarCeilToInt(fLeft), SkScalarCeilToInt(fTop), 761 SkScalarFloorToInt(fRight), SkScalarFloorToInt(fBottom)); 762 } 763 764 765 /** 766 * Swap top/bottom or left/right if there are flipped (i.e. if width() 767 * or height() would have returned a negative value.) This should be called 768 * if the edges are computed separately, and may have crossed over each 769 * other. When this returns, left <= right && top <= bottom 770 */ 771 void sort(); 772 }; 773 774 #endif 775