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