SkRect.h revision d6195f956fdccef865224520a624e3fd968573d0
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 MakeEmpty() { 24 SkIRect r; 25 r.setEmpty(); 26 return r; 27 } 28 29 static SkIRect 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 MakeSize(const SkISize& size) { 36 SkIRect r; 37 r.set(0, 0, size.width(), size.height()); 38 return r; 39 } 40 41 static SkIRect 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 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 /** Inset the rectangle by (dx,dy). If dx is positive, then the sides are moved inwards, 146 making the rectangle narrower. If dx is negative, then the sides are moved outwards, 147 making the rectangle wider. The same hods true for dy and the top and bottom. 148 */ 149 void inset(int32_t dx, int32_t dy) { 150 fLeft += dx; 151 fTop += dy; 152 fRight -= dx; 153 fBottom -= dy; 154 } 155 156 bool quickReject(int l, int t, int r, int b) const { 157 return l >= fRight || fLeft >= r || t >= fBottom || fTop >= b; 158 } 159 160 /** Returns true if (x,y) is inside the rectangle and the rectangle is not 161 empty. The left and top are considered to be inside, while the right 162 and bottom are not. Thus for the rectangle (0, 0, 5, 10), the 163 points (0,0) and (0,9) are inside, while (-1,0) and (5,9) are not. 164 */ 165 bool contains(int32_t x, int32_t y) const { 166 return (unsigned)(x - fLeft) < (unsigned)(fRight - fLeft) && 167 (unsigned)(y - fTop) < (unsigned)(fBottom - fTop); 168 } 169 170 /** Returns true if the 4 specified sides of a rectangle are inside or equal to this rectangle. 171 If either rectangle is empty, contains() returns false. 172 */ 173 bool contains(int32_t left, int32_t top, int32_t right, int32_t bottom) const { 174 return left < right && top < bottom && !this->isEmpty() && // check for empties 175 fLeft <= left && fTop <= top && 176 fRight >= right && fBottom >= bottom; 177 } 178 179 /** Returns true if the specified rectangle r is inside or equal to this rectangle. 180 */ 181 bool contains(const SkIRect& r) const { 182 return !r.isEmpty() && !this->isEmpty() && // check for empties 183 fLeft <= r.fLeft && fTop <= r.fTop && 184 fRight >= r.fRight && fBottom >= r.fBottom; 185 } 186 187 /** Return true if this rectangle contains the specified rectangle. 188 For speed, this method does not check if either this or the specified 189 rectangles are empty, and if either is, its return value is undefined. 190 In the debugging build however, we assert that both this and the 191 specified rectangles are non-empty. 192 */ 193 bool containsNoEmptyCheck(int32_t left, int32_t top, 194 int32_t right, int32_t bottom) const { 195 SkASSERT(fLeft < fRight && fTop < fBottom); 196 SkASSERT(left < right && top < bottom); 197 198 return fLeft <= left && fTop <= top && 199 fRight >= right && fBottom >= bottom; 200 } 201 202 /** If r intersects this rectangle, return true and set this rectangle to that 203 intersection, otherwise return false and do not change this rectangle. 204 If either rectangle is empty, do nothing and return false. 205 */ 206 bool intersect(const SkIRect& r) { 207 SkASSERT(&r); 208 return this->intersect(r.fLeft, r.fTop, r.fRight, r.fBottom); 209 } 210 211 /** If rectangles a and b intersect, return true and set this rectangle to 212 that intersection, otherwise return false and do not change this 213 rectangle. If either rectangle is empty, do nothing and return false. 214 */ 215 bool intersect(const SkIRect& a, const SkIRect& b) { 216 SkASSERT(&a && &b); 217 218 if (!a.isEmpty() && !b.isEmpty() && 219 a.fLeft < b.fRight && b.fLeft < a.fRight && 220 a.fTop < b.fBottom && b.fTop < a.fBottom) { 221 fLeft = SkMax32(a.fLeft, b.fLeft); 222 fTop = SkMax32(a.fTop, b.fTop); 223 fRight = SkMin32(a.fRight, b.fRight); 224 fBottom = SkMin32(a.fBottom, b.fBottom); 225 return true; 226 } 227 return false; 228 } 229 230 /** If rectangles a and b intersect, return true and set this rectangle to 231 that intersection, otherwise return false and do not change this 232 rectangle. For speed, no check to see if a or b are empty is performed. 233 If either is, then the return result is undefined. In the debug build, 234 we assert that both rectangles are non-empty. 235 */ 236 bool intersectNoEmptyCheck(const SkIRect& a, const SkIRect& b) { 237 SkASSERT(&a && &b); 238 SkASSERT(!a.isEmpty() && !b.isEmpty()); 239 240 if (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 the rectangle specified by left,top,right,bottom intersects this rectangle, 252 return true and set this rectangle to that intersection, 253 otherwise return false and do not change this rectangle. 254 If either rectangle is empty, do nothing and return false. 255 */ 256 bool intersect(int32_t left, int32_t top, int32_t right, int32_t bottom) { 257 if (left < right && top < bottom && !this->isEmpty() && 258 fLeft < right && left < fRight && fTop < bottom && top < fBottom) { 259 if (fLeft < left) fLeft = left; 260 if (fTop < top) fTop = top; 261 if (fRight > right) fRight = right; 262 if (fBottom > bottom) fBottom = bottom; 263 return true; 264 } 265 return false; 266 } 267 268 /** Returns true if a and b are not empty, and they intersect 269 */ 270 static bool Intersects(const SkIRect& a, const SkIRect& b) { 271 return !a.isEmpty() && !b.isEmpty() && // check for empties 272 a.fLeft < b.fRight && b.fLeft < a.fRight && 273 a.fTop < b.fBottom && b.fTop < a.fBottom; 274 } 275 276 /** Update this rectangle to enclose itself and the specified rectangle. 277 If this rectangle is empty, just set it to the specified rectangle. If the specified 278 rectangle is empty, do nothing. 279 */ 280 void join(int32_t left, int32_t top, int32_t right, int32_t bottom); 281 282 /** Update this rectangle to enclose itself and the specified rectangle. 283 If this rectangle is empty, just set it to the specified rectangle. If the specified 284 rectangle is empty, do nothing. 285 */ 286 void join(const SkIRect& r) { 287 this->join(r.fLeft, r.fTop, r.fRight, r.fBottom); 288 } 289 290 /** Swap top/bottom or left/right if there are flipped. 291 This can be called if the edges are computed separately, 292 and may have crossed over each other. 293 When this returns, left <= right && top <= bottom 294 */ 295 void sort(); 296 297 static const SkIRect& EmptyIRect() { 298 static const SkIRect gEmpty = { 0, 0, 0, 0 }; 299 return gEmpty; 300 } 301}; 302 303/** \struct SkRect 304*/ 305struct SK_API SkRect { 306 SkScalar fLeft, fTop, fRight, fBottom; 307 308 static SkRect MakeEmpty() { 309 SkRect r; 310 r.setEmpty(); 311 return r; 312 } 313 314 static SkRect MakeWH(SkScalar w, SkScalar h) { 315 SkRect r; 316 r.set(0, 0, w, h); 317 return r; 318 } 319 320 static SkRect MakeSize(const SkSize& size) { 321 SkRect r; 322 r.set(0, 0, size.width(), size.height()); 323 return r; 324 } 325 326 static SkRect MakeLTRB(SkScalar l, SkScalar t, SkScalar r, SkScalar b) { 327 SkRect rect; 328 rect.set(l, t, r, b); 329 return rect; 330 } 331 332 static SkRect MakeXYWH(SkScalar x, SkScalar y, SkScalar w, SkScalar h) { 333 SkRect r; 334 r.set(x, y, x + w, y + h); 335 return r; 336 } 337 338 /** 339 * Return true if the rectangle's width or height are <= 0 340 */ 341 bool isEmpty() const { return fLeft >= fRight || fTop >= fBottom; } 342 343 /** 344 * Returns true iff all values in the rect are finite. If any are 345 * infinite or NaN (or SK_FixedNaN when SkScalar is fixed) then this 346 * returns false. 347 */ 348 bool isFinite() const { 349#ifdef SK_SCALAR_IS_FLOAT 350 // x * 0 will be NaN iff x is infinity or NaN. 351 // a + b will be NaN iff either a or b is NaN. 352 float value = fLeft * 0 + fTop * 0 + fRight * 0 + fBottom * 0; 353 354 // value is either NaN or it is finite (zero). 355 // value==value will be true iff value is not NaN 356 return value == value; 357#else 358 // use bit-or for speed, since we don't care about short-circuting the 359 // tests, and we expect the common case will be that we need to check all. 360 int isNaN = (SK_FixedNaN == fLeft) | (SK_FixedNaN == fTop) | 361 (SK_FixedNaN == fRight) | (SK_FixedNaN == fBottom); 362 return !isNaN; 363#endif 364 } 365 366 SkScalar x() const { return fLeft; } 367 SkScalar y() const { return fTop; } 368 SkScalar left() const { return fLeft; } 369 SkScalar top() const { return fTop; } 370 SkScalar right() const { return fRight; } 371 SkScalar bottom() const { return fBottom; } 372 SkScalar width() const { return fRight - fLeft; } 373 SkScalar height() const { return fBottom - fTop; } 374 SkScalar centerX() const { return SkScalarHalf(fLeft + fRight); } 375 SkScalar centerY() const { return SkScalarHalf(fTop + fBottom); } 376 377 friend bool operator==(const SkRect& a, const SkRect& b) { 378 return 0 == memcmp(&a, &b, sizeof(a)); 379 } 380 381 friend bool operator!=(const SkRect& a, const SkRect& b) { 382 return 0 != memcmp(&a, &b, sizeof(a)); 383 } 384 385 /** return the 4 points that enclose the rectangle 386 */ 387 void toQuad(SkPoint quad[4]) const; 388 389 /** Set this rectangle to the empty rectangle (0,0,0,0) 390 */ 391 void setEmpty() { memset(this, 0, sizeof(*this)); } 392 393 void set(const SkIRect& src) { 394 fLeft = SkIntToScalar(src.fLeft); 395 fTop = SkIntToScalar(src.fTop); 396 fRight = SkIntToScalar(src.fRight); 397 fBottom = SkIntToScalar(src.fBottom); 398 } 399 400 void set(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) { 401 fLeft = left; 402 fTop = top; 403 fRight = right; 404 fBottom = bottom; 405 } 406 // alias for set(l, t, r, b) 407 void setLTRB(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) { 408 this->set(left, top, right, bottom); 409 } 410 411 /** Initialize the rect with the 4 specified integers. The routine handles 412 converting them to scalars (by calling SkIntToScalar) 413 */ 414 void iset(int left, int top, int right, int bottom) { 415 fLeft = SkIntToScalar(left); 416 fTop = SkIntToScalar(top); 417 fRight = SkIntToScalar(right); 418 fBottom = SkIntToScalar(bottom); 419 } 420 421 /** Set this rectangle to be the bounds of the array of points. 422 If the array is empty (count == 0), then set this rectangle 423 to the empty rectangle (0,0,0,0) 424 */ 425 void set(const SkPoint pts[], int count); 426 427 // alias for set(pts, count) 428 void setBounds(const SkPoint pts[], int count) { 429 this->set(pts, count); 430 } 431 432 void setXYWH(SkScalar x, SkScalar y, SkScalar width, SkScalar height) { 433 fLeft = x; 434 fTop = y; 435 fRight = x + width; 436 fBottom = y + height; 437 } 438 439 /** 440 * Make the largest representable rectangle 441 */ 442 void setLargest() { 443 fLeft = fTop = SK_ScalarMin; 444 fRight = fBottom = SK_ScalarMax; 445 } 446 447 /** 448 * Make the largest representable rectangle, but inverted (e.g. fLeft will 449 * be max and right will be min). 450 */ 451 void setLargestInverted() { 452 fLeft = fTop = SK_ScalarMax; 453 fRight = fBottom = SK_ScalarMin; 454 } 455 456 /** Offset set the rectangle by adding dx to its left and right, 457 and adding dy to its top and bottom. 458 */ 459 void offset(SkScalar dx, SkScalar dy) { 460 fLeft += dx; 461 fTop += dy; 462 fRight += dx; 463 fBottom += dy; 464 } 465 466 void offset(const SkPoint& delta) { 467 this->offset(delta.fX, delta.fY); 468 } 469 470 /** Inset the rectangle by (dx,dy). If dx is positive, then the sides are 471 moved inwards, making the rectangle narrower. If dx is negative, then 472 the sides are moved outwards, making the rectangle wider. The same holds 473 true for dy and the top and bottom. 474 */ 475 void inset(SkScalar dx, SkScalar dy) { 476 fLeft += dx; 477 fTop += dy; 478 fRight -= dx; 479 fBottom -= dy; 480 } 481 482 /** Outset the rectangle by (dx,dy). If dx is positive, then the sides are 483 moved outwards, making the rectangle wider. If dx is negative, then the 484 sides are moved inwards, making the rectangle narrower. The same hods 485 true for dy and the top and bottom. 486 */ 487 void outset(SkScalar dx, SkScalar dy) { this->inset(-dx, -dy); } 488 489 /** If this rectangle intersects r, return true and set this rectangle to that 490 intersection, otherwise return false and do not change this rectangle. 491 If either rectangle is empty, do nothing and return false. 492 */ 493 bool intersect(const SkRect& r); 494 495 /** If this rectangle intersects the rectangle specified by left, top, right, bottom, 496 return true and set this rectangle to that intersection, otherwise return false 497 and do not change this rectangle. 498 If either rectangle is empty, do nothing and return false. 499 */ 500 bool intersect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom); 501 502 /** 503 * Return true if this rectangle is not empty, and the specified sides of 504 * a rectangle are not empty, and they intersect. 505 */ 506 bool intersects(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) const { 507 return // first check that both are not empty 508 left < right && top < bottom && 509 fLeft < fRight && fTop < fBottom && 510 // now check for intersection 511 fLeft < right && left < fRight && 512 fTop < bottom && top < fBottom; 513 } 514 515 /** If rectangles a and b intersect, return true and set this rectangle to 516 * that intersection, otherwise return false and do not change this 517 * rectangle. If either rectangle is empty, do nothing and return false. 518 */ 519 bool intersect(const SkRect& a, const SkRect& b); 520 521 /** 522 * Return true if rectangles a and b are not empty and intersect. 523 */ 524 static bool Intersects(const SkRect& a, const SkRect& b) { 525 return !a.isEmpty() && !b.isEmpty() && 526 a.fLeft < b.fRight && b.fLeft < a.fRight && 527 a.fTop < b.fBottom && b.fTop < a.fBottom; 528 } 529 530 /** 531 * Update this rectangle to enclose itself and the specified rectangle. 532 * If this rectangle is empty, just set it to the specified rectangle. 533 * If the specified rectangle is empty, do nothing. 534 */ 535 void join(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom); 536 537 /** Update this rectangle to enclose itself and the specified rectangle. 538 If this rectangle is empty, just set it to the specified rectangle. If the specified 539 rectangle is empty, do nothing. 540 */ 541 void join(const SkRect& r) { 542 this->join(r.fLeft, r.fTop, r.fRight, r.fBottom); 543 } 544 // alias for join() 545 void growToInclude(const SkRect& r) { this->join(r); } 546 547 /** 548 * Grow the rect to include the specified (x,y). After this call, the 549 * following will be true: fLeft <= x <= fRight && fTop <= y <= fBottom. 550 * 551 * This is close, but not quite the same contract as contains(), since 552 * contains() treats the left and top different from the right and bottom. 553 * contains(x,y) -> fLeft <= x < fRight && fTop <= y < fBottom. Also note 554 * that contains(x,y) always returns false if the rect is empty. 555 */ 556 void growToInclude(SkScalar x, SkScalar y) { 557 fLeft = SkMinScalar(x, fLeft); 558 fRight = SkMaxScalar(x, fRight); 559 fTop = SkMinScalar(y, fTop); 560 fBottom = SkMaxScalar(y, fBottom); 561 } 562 563 /** 564 * Returns true if (p.fX,p.fY) is inside the rectangle, and the rectangle 565 * is not empty. 566 * 567 * Contains treats the left and top differently from the right and bottom. 568 * The left and top coordinates of the rectangle are themselves considered 569 * to be inside, while the right and bottom are not. Thus for the rectangle 570 * {0, 0, 5, 10}, (0,0) is contained, but (0,10), (5,0) and (5,10) are not. 571 */ 572 bool contains(const SkPoint& p) const { 573 return !this->isEmpty() && 574 fLeft <= p.fX && p.fX < fRight && fTop <= p.fY && p.fY < fBottom; 575 } 576 577 /** 578 * Returns true if (x,y) is inside the rectangle, and the rectangle 579 * is not empty. 580 * 581 * Contains treats the left and top differently from the right and bottom. 582 * The left and top coordinates of the rectangle are themselves considered 583 * to be inside, while the right and bottom are not. Thus for the rectangle 584 * {0, 0, 5, 10}, (0,0) is contained, but (0,10), (5,0) and (5,10) are not. 585 */ 586 bool contains(SkScalar x, SkScalar y) const { 587 return !this->isEmpty() && 588 fLeft <= x && x < fRight && fTop <= y && y < fBottom; 589 } 590 591 /** 592 * Return true if this rectangle contains r, and if both rectangles are 593 * not empty. 594 */ 595 bool contains(const SkRect& r) const { 596 return !r.isEmpty() && !this->isEmpty() && 597 fLeft <= r.fLeft && fTop <= r.fTop && 598 fRight >= r.fRight && fBottom >= r.fBottom; 599 } 600 601 /** 602 * Set the dst rectangle by rounding this rectangle's coordinates to their 603 * nearest integer values using SkScalarRound. 604 */ 605 void round(SkIRect* dst) const { 606 SkASSERT(dst); 607 dst->set(SkScalarRound(fLeft), SkScalarRound(fTop), 608 SkScalarRound(fRight), SkScalarRound(fBottom)); 609 } 610 611 /** 612 * Set the dst rectangle by rounding "out" this rectangle, choosing the 613 * SkScalarFloor of top and left, and the SkScalarCeil of right and bottom. 614 */ 615 void roundOut(SkIRect* dst) const { 616 SkASSERT(dst); 617 dst->set(SkScalarFloor(fLeft), SkScalarFloor(fTop), 618 SkScalarCeil(fRight), SkScalarCeil(fBottom)); 619 } 620 621 /** 622 * Expand this rectangle by rounding its coordinates "out", choosing the 623 * floor of top and left, and the ceil of right and bottom. If this rect 624 * is already on integer coordinates, then it will be unchanged. 625 */ 626 void roundOut() { 627 this->set(SkScalarFloorToScalar(fLeft), 628 SkScalarFloorToScalar(fTop), 629 SkScalarCeilToScalar(fRight), 630 SkScalarCeilToScalar(fBottom)); 631 } 632 633 /** 634 * Swap top/bottom or left/right if there are flipped (i.e. if width() 635 * or height() would have returned a negative value.) This should be called 636 * if the edges are computed separately, and may have crossed over each 637 * other. When this returns, left <= right && top <= bottom 638 */ 639 void sort(); 640}; 641 642#endif 643 644