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 MakeEmptySkIRect23 static SkIRect SK_WARN_UNUSED_RESULT MakeEmpty() { 24 SkIRect r; 25 r.setEmpty(); 26 return r; 27 } 28 MakeLargestSkIRect29 static SkIRect SK_WARN_UNUSED_RESULT MakeLargest() { 30 SkIRect r; 31 r.setLargest(); 32 return r; 33 } 34 MakeWHSkIRect35 static SkIRect SK_WARN_UNUSED_RESULT MakeWH(int32_t w, int32_t h) { 36 SkIRect r; 37 r.set(0, 0, w, h); 38 return r; 39 } 40 MakeSizeSkIRect41 static SkIRect SK_WARN_UNUSED_RESULT MakeSize(const SkISize& size) { 42 SkIRect r; 43 r.set(0, 0, size.width(), size.height()); 44 return r; 45 } 46 MakeLTRBSkIRect47 static SkIRect SK_WARN_UNUSED_RESULT MakeLTRB(int32_t l, int32_t t, int32_t r, int32_t b) { 48 SkIRect rect; 49 rect.set(l, t, r, b); 50 return rect; 51 } 52 MakeXYWHSkIRect53 static SkIRect SK_WARN_UNUSED_RESULT MakeXYWH(int32_t x, int32_t y, int32_t w, int32_t h) { 54 SkIRect r; 55 r.set(x, y, x + w, y + h); 56 return r; 57 } 58 leftSkIRect59 int left() const { return fLeft; } topSkIRect60 int top() const { return fTop; } rightSkIRect61 int right() const { return fRight; } bottomSkIRect62 int bottom() const { return fBottom; } 63 64 /** return the left edge of the rect */ xSkIRect65 int x() const { return fLeft; } 66 /** return the top edge of the rect */ ySkIRect67 int y() const { return fTop; } 68 /** 69 * Returns the rectangle's width. This does not check for a valid rect 70 * (i.e. left <= right) so the result may be negative. 71 */ widthSkIRect72 int width() const { return fRight - fLeft; } 73 74 /** 75 * Returns the rectangle's height. This does not check for a valid rect 76 * (i.e. top <= bottom) so the result may be negative. 77 */ heightSkIRect78 int height() const { return fBottom - fTop; } 79 80 /** 81 * Since the center of an integer rect may fall on a factional value, this 82 * method is defined to return (right + left) >> 1. 83 * 84 * This is a specific "truncation" of the average, which is different than 85 * (right + left) / 2 when the sum is negative. 86 */ centerXSkIRect87 int centerX() const { return (fRight + fLeft) >> 1; } 88 89 /** 90 * Since the center of an integer rect may fall on a factional value, this 91 * method is defined to return (bottom + top) >> 1 92 * 93 * This is a specific "truncation" of the average, which is different than 94 * (bottom + top) / 2 when the sum is negative. 95 */ centerYSkIRect96 int centerY() const { return (fBottom + fTop) >> 1; } 97 98 /** 99 * Return true if the rectangle's width or height are <= 0 100 */ isEmptySkIRect101 bool isEmpty() const { return fLeft >= fRight || fTop >= fBottom; } 102 isLargestSkIRect103 bool isLargest() const { return SK_MinS32 == fLeft && 104 SK_MinS32 == fTop && 105 SK_MaxS32 == fRight && 106 SK_MaxS32 == fBottom; } 107 108 friend bool operator==(const SkIRect& a, const SkIRect& b) { 109 return !memcmp(&a, &b, sizeof(a)); 110 } 111 112 friend bool operator!=(const SkIRect& a, const SkIRect& b) { 113 return !(a == b); 114 } 115 is16BitSkIRect116 bool is16Bit() const { 117 return SkIsS16(fLeft) && SkIsS16(fTop) && 118 SkIsS16(fRight) && SkIsS16(fBottom); 119 } 120 121 /** Set the rectangle to (0,0,0,0) 122 */ setEmptySkIRect123 void setEmpty() { memset(this, 0, sizeof(*this)); } 124 setSkIRect125 void set(int32_t left, int32_t top, int32_t right, int32_t bottom) { 126 fLeft = left; 127 fTop = top; 128 fRight = right; 129 fBottom = bottom; 130 } 131 // alias for set(l, t, r, b) setLTRBSkIRect132 void setLTRB(int32_t left, int32_t top, int32_t right, int32_t bottom) { 133 this->set(left, top, right, bottom); 134 } 135 setXYWHSkIRect136 void setXYWH(int32_t x, int32_t y, int32_t width, int32_t height) { 137 fLeft = x; 138 fTop = y; 139 fRight = x + width; 140 fBottom = y + height; 141 } 142 143 /** 144 * Make the largest representable rectangle 145 */ setLargestSkIRect146 void setLargest() { 147 fLeft = fTop = SK_MinS32; 148 fRight = fBottom = SK_MaxS32; 149 } 150 151 /** 152 * Make the largest representable rectangle, but inverted (e.g. fLeft will 153 * be max 32bit and right will be min 32bit). 154 */ setLargestInvertedSkIRect155 void setLargestInverted() { 156 fLeft = fTop = SK_MaxS32; 157 fRight = fBottom = SK_MinS32; 158 } 159 160 /** Offset set the rectangle by adding dx to its left and right, 161 and adding dy to its top and bottom. 162 */ offsetSkIRect163 void offset(int32_t dx, int32_t dy) { 164 fLeft += dx; 165 fTop += dy; 166 fRight += dx; 167 fBottom += dy; 168 } 169 offsetSkIRect170 void offset(const SkIPoint& delta) { 171 this->offset(delta.fX, delta.fY); 172 } 173 174 /** 175 * Offset this rect such its new x() and y() will equal newX and newY. 176 */ offsetToSkIRect177 void offsetTo(int32_t newX, int32_t newY) { 178 fRight += newX - fLeft; 179 fBottom += newY - fTop; 180 fLeft = newX; 181 fTop = newY; 182 } 183 184 /** Inset the rectangle by (dx,dy). If dx is positive, then the sides are moved inwards, 185 making the rectangle narrower. If dx is negative, then the sides are moved outwards, 186 making the rectangle wider. The same holds true for dy and the top and bottom. 187 */ insetSkIRect188 void inset(int32_t dx, int32_t dy) { 189 fLeft += dx; 190 fTop += dy; 191 fRight -= dx; 192 fBottom -= dy; 193 } 194 195 /** Outset the rectangle by (dx,dy). If dx is positive, then the sides are 196 moved outwards, making the rectangle wider. If dx is negative, then the 197 sides are moved inwards, making the rectangle narrower. The same holds 198 true for dy and the top and bottom. 199 */ outsetSkIRect200 void outset(int32_t dx, int32_t dy) { this->inset(-dx, -dy); } 201 quickRejectSkIRect202 bool quickReject(int l, int t, int r, int b) const { 203 return l >= fRight || fLeft >= r || t >= fBottom || fTop >= b; 204 } 205 206 /** Returns true if (x,y) is inside the rectangle and the rectangle is not 207 empty. The left and top are considered to be inside, while the right 208 and bottom are not. Thus for the rectangle (0, 0, 5, 10), the 209 points (0,0) and (0,9) are inside, while (-1,0) and (5,9) are not. 210 */ containsSkIRect211 bool contains(int32_t x, int32_t y) const { 212 return (unsigned)(x - fLeft) < (unsigned)(fRight - fLeft) && 213 (unsigned)(y - fTop) < (unsigned)(fBottom - fTop); 214 } 215 216 /** Returns true if the 4 specified sides of a rectangle are inside or equal to this rectangle. 217 If either rectangle is empty, contains() returns false. 218 */ containsSkIRect219 bool contains(int32_t left, int32_t top, int32_t right, int32_t bottom) const { 220 return left < right && top < bottom && !this->isEmpty() && // check for empties 221 fLeft <= left && fTop <= top && 222 fRight >= right && fBottom >= bottom; 223 } 224 225 /** Returns true if the specified rectangle r is inside or equal to this rectangle. 226 */ containsSkIRect227 bool contains(const SkIRect& r) const { 228 return !r.isEmpty() && !this->isEmpty() && // check for empties 229 fLeft <= r.fLeft && fTop <= r.fTop && 230 fRight >= r.fRight && fBottom >= r.fBottom; 231 } 232 233 /** Return true if this rectangle contains the specified rectangle. 234 For speed, this method does not check if either this or the specified 235 rectangles are empty, and if either is, its return value is undefined. 236 In the debugging build however, we assert that both this and the 237 specified rectangles are non-empty. 238 */ containsNoEmptyCheckSkIRect239 bool containsNoEmptyCheck(int32_t left, int32_t top, 240 int32_t right, int32_t bottom) const { 241 SkASSERT(fLeft < fRight && fTop < fBottom); 242 SkASSERT(left < right && top < bottom); 243 244 return fLeft <= left && fTop <= top && 245 fRight >= right && fBottom >= bottom; 246 } 247 containsNoEmptyCheckSkIRect248 bool containsNoEmptyCheck(const SkIRect& r) const { 249 return containsNoEmptyCheck(r.fLeft, r.fTop, r.fRight, r.fBottom); 250 } 251 252 /** If r intersects this rectangle, return true and set this rectangle to that 253 intersection, otherwise return false and do not change this rectangle. 254 If either rectangle is empty, do nothing and return false. 255 */ intersectSkIRect256 bool intersect(const SkIRect& r) { 257 SkASSERT(&r); 258 return this->intersect(r.fLeft, r.fTop, r.fRight, r.fBottom); 259 } 260 261 /** If rectangles a and b intersect, return true and set this rectangle to 262 that intersection, otherwise return false and do not change this 263 rectangle. If either rectangle is empty, do nothing and return false. 264 */ intersectSkIRect265 bool intersect(const SkIRect& a, const SkIRect& b) { 266 SkASSERT(&a && &b); 267 268 if (!a.isEmpty() && !b.isEmpty() && 269 a.fLeft < b.fRight && b.fLeft < a.fRight && 270 a.fTop < b.fBottom && b.fTop < a.fBottom) { 271 fLeft = SkMax32(a.fLeft, b.fLeft); 272 fTop = SkMax32(a.fTop, b.fTop); 273 fRight = SkMin32(a.fRight, b.fRight); 274 fBottom = SkMin32(a.fBottom, b.fBottom); 275 return true; 276 } 277 return false; 278 } 279 280 /** If rectangles a and b intersect, return true and set this rectangle to 281 that intersection, otherwise return false and do not change this 282 rectangle. For speed, no check to see if a or b are empty is performed. 283 If either is, then the return result is undefined. In the debug build, 284 we assert that both rectangles are non-empty. 285 */ intersectNoEmptyCheckSkIRect286 bool intersectNoEmptyCheck(const SkIRect& a, const SkIRect& b) { 287 SkASSERT(&a && &b); 288 SkASSERT(!a.isEmpty() && !b.isEmpty()); 289 290 if (a.fLeft < b.fRight && b.fLeft < a.fRight && 291 a.fTop < b.fBottom && b.fTop < a.fBottom) { 292 fLeft = SkMax32(a.fLeft, b.fLeft); 293 fTop = SkMax32(a.fTop, b.fTop); 294 fRight = SkMin32(a.fRight, b.fRight); 295 fBottom = SkMin32(a.fBottom, b.fBottom); 296 return true; 297 } 298 return false; 299 } 300 301 /** If the rectangle specified by left,top,right,bottom intersects this rectangle, 302 return true and set this rectangle to that intersection, 303 otherwise return false and do not change this rectangle. 304 If either rectangle is empty, do nothing and return false. 305 */ intersectSkIRect306 bool intersect(int32_t left, int32_t top, int32_t right, int32_t bottom) { 307 if (left < right && top < bottom && !this->isEmpty() && 308 fLeft < right && left < fRight && fTop < bottom && top < fBottom) { 309 if (fLeft < left) fLeft = left; 310 if (fTop < top) fTop = top; 311 if (fRight > right) fRight = right; 312 if (fBottom > bottom) fBottom = bottom; 313 return true; 314 } 315 return false; 316 } 317 318 /** Returns true if a and b are not empty, and they intersect 319 */ IntersectsSkIRect320 static bool Intersects(const SkIRect& a, const SkIRect& b) { 321 return !a.isEmpty() && !b.isEmpty() && // check for empties 322 a.fLeft < b.fRight && b.fLeft < a.fRight && 323 a.fTop < b.fBottom && b.fTop < a.fBottom; 324 } 325 326 /** 327 * Returns true if a and b intersect. debug-asserts that neither are empty. 328 */ IntersectsNoEmptyCheckSkIRect329 static bool IntersectsNoEmptyCheck(const SkIRect& a, const SkIRect& b) { 330 SkASSERT(!a.isEmpty()); 331 SkASSERT(!b.isEmpty()); 332 return a.fLeft < b.fRight && b.fLeft < a.fRight && 333 a.fTop < b.fBottom && b.fTop < a.fBottom; 334 } 335 336 /** Update this rectangle to enclose itself and the specified rectangle. 337 If this rectangle is empty, just set it to the specified rectangle. If the specified 338 rectangle is empty, do nothing. 339 */ 340 void join(int32_t left, int32_t top, int32_t right, int32_t bottom); 341 342 /** Update this rectangle to enclose itself and the specified rectangle. 343 If this rectangle is empty, just set it to the specified rectangle. If the specified 344 rectangle is empty, do nothing. 345 */ joinSkIRect346 void join(const SkIRect& r) { 347 this->join(r.fLeft, r.fTop, r.fRight, r.fBottom); 348 } 349 350 /** Swap top/bottom or left/right if there are flipped. 351 This can be called if the edges are computed separately, 352 and may have crossed over each other. 353 When this returns, left <= right && top <= bottom 354 */ 355 void sort(); 356 EmptyIRectSkIRect357 static const SkIRect& SK_WARN_UNUSED_RESULT EmptyIRect() { 358 static const SkIRect gEmpty = { 0, 0, 0, 0 }; 359 return gEmpty; 360 } 361 }; 362 363 /** \struct SkRect 364 */ 365 struct SK_API SkRect { 366 SkScalar fLeft, fTop, fRight, fBottom; 367 MakeEmptySkRect368 static SkRect SK_WARN_UNUSED_RESULT MakeEmpty() { 369 SkRect r; 370 r.setEmpty(); 371 return r; 372 } 373 MakeLargestSkRect374 static SkRect SK_WARN_UNUSED_RESULT MakeLargest() { 375 SkRect r; 376 r.setLargest(); 377 return r; 378 } 379 MakeWHSkRect380 static SkRect SK_WARN_UNUSED_RESULT MakeWH(SkScalar w, SkScalar h) { 381 SkRect r; 382 r.set(0, 0, w, h); 383 return r; 384 } 385 MakeSizeSkRect386 static SkRect SK_WARN_UNUSED_RESULT MakeSize(const SkSize& size) { 387 SkRect r; 388 r.set(0, 0, size.width(), size.height()); 389 return r; 390 } 391 MakeLTRBSkRect392 static SkRect SK_WARN_UNUSED_RESULT MakeLTRB(SkScalar l, SkScalar t, SkScalar r, SkScalar b) { 393 SkRect rect; 394 rect.set(l, t, r, b); 395 return rect; 396 } 397 MakeXYWHSkRect398 static SkRect SK_WARN_UNUSED_RESULT MakeXYWH(SkScalar x, SkScalar y, SkScalar w, SkScalar h) { 399 SkRect r; 400 r.set(x, y, x + w, y + h); 401 return r; 402 } 403 404 SK_ATTR_DEPRECATED("use Make()") MakeFromIRectSkRect405 static SkRect SK_WARN_UNUSED_RESULT MakeFromIRect(const SkIRect& irect) { 406 SkRect r; 407 r.set(SkIntToScalar(irect.fLeft), 408 SkIntToScalar(irect.fTop), 409 SkIntToScalar(irect.fRight), 410 SkIntToScalar(irect.fBottom)); 411 return r; 412 } 413 MakeSkRect414 static SkRect SK_WARN_UNUSED_RESULT Make(const SkIRect& irect) { 415 SkRect r; 416 r.set(SkIntToScalar(irect.fLeft), 417 SkIntToScalar(irect.fTop), 418 SkIntToScalar(irect.fRight), 419 SkIntToScalar(irect.fBottom)); 420 return r; 421 } 422 423 /** 424 * Return true if the rectangle's width or height are <= 0 425 */ isEmptySkRect426 bool isEmpty() const { return fLeft >= fRight || fTop >= fBottom; } 427 isLargestSkRect428 bool isLargest() const { return SK_ScalarMin == fLeft && 429 SK_ScalarMin == fTop && 430 SK_ScalarMax == fRight && 431 SK_ScalarMax == fBottom; } 432 433 /** 434 * Returns true iff all values in the rect are finite. If any are 435 * infinite or NaN (or SK_FixedNaN when SkScalar is fixed) then this 436 * returns false. 437 */ isFiniteSkRect438 bool isFinite() const { 439 #ifdef SK_SCALAR_IS_FLOAT 440 float accum = 0; 441 accum *= fLeft; 442 accum *= fTop; 443 accum *= fRight; 444 accum *= fBottom; 445 446 // accum is either NaN or it is finite (zero). 447 SkASSERT(0 == accum || !(accum == accum)); 448 449 // value==value will be true iff value is not NaN 450 // TODO: is it faster to say !accum or accum==accum? 451 return accum == accum; 452 #else 453 // use bit-or for speed, since we don't care about short-circuting the 454 // tests, and we expect the common case will be that we need to check all. 455 int isNaN = (SK_FixedNaN == fLeft) | (SK_FixedNaN == fTop) | 456 (SK_FixedNaN == fRight) | (SK_FixedNaN == fBottom); 457 return !isNaN; 458 #endif 459 } 460 xSkRect461 SkScalar x() const { return fLeft; } ySkRect462 SkScalar y() const { return fTop; } leftSkRect463 SkScalar left() const { return fLeft; } topSkRect464 SkScalar top() const { return fTop; } rightSkRect465 SkScalar right() const { return fRight; } bottomSkRect466 SkScalar bottom() const { return fBottom; } widthSkRect467 SkScalar width() const { return fRight - fLeft; } heightSkRect468 SkScalar height() const { return fBottom - fTop; } centerXSkRect469 SkScalar centerX() const { return SkScalarHalf(fLeft + fRight); } centerYSkRect470 SkScalar centerY() const { return SkScalarHalf(fTop + fBottom); } 471 472 friend bool operator==(const SkRect& a, const SkRect& b) { 473 return SkScalarsEqual((SkScalar*)&a, (SkScalar*)&b, 4); 474 } 475 476 friend bool operator!=(const SkRect& a, const SkRect& b) { 477 return !SkScalarsEqual((SkScalar*)&a, (SkScalar*)&b, 4); 478 } 479 480 /** return the 4 points that enclose the rectangle (top-left, top-right, bottom-right, 481 bottom-left). TODO: Consider adding param to control whether quad is CW or CCW. 482 */ 483 void toQuad(SkPoint quad[4]) const; 484 485 /** Set this rectangle to the empty rectangle (0,0,0,0) 486 */ setEmptySkRect487 void setEmpty() { memset(this, 0, sizeof(*this)); } 488 setSkRect489 void set(const SkIRect& src) { 490 fLeft = SkIntToScalar(src.fLeft); 491 fTop = SkIntToScalar(src.fTop); 492 fRight = SkIntToScalar(src.fRight); 493 fBottom = SkIntToScalar(src.fBottom); 494 } 495 setSkRect496 void set(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) { 497 fLeft = left; 498 fTop = top; 499 fRight = right; 500 fBottom = bottom; 501 } 502 // alias for set(l, t, r, b) setLTRBSkRect503 void setLTRB(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) { 504 this->set(left, top, right, bottom); 505 } 506 507 /** Initialize the rect with the 4 specified integers. The routine handles 508 converting them to scalars (by calling SkIntToScalar) 509 */ isetSkRect510 void iset(int left, int top, int right, int bottom) { 511 fLeft = SkIntToScalar(left); 512 fTop = SkIntToScalar(top); 513 fRight = SkIntToScalar(right); 514 fBottom = SkIntToScalar(bottom); 515 } 516 517 /** 518 * Set this rectangle to be left/top at 0,0, and have the specified width 519 * and height (automatically converted to SkScalar). 520 */ isetWHSkRect521 void isetWH(int width, int height) { 522 fLeft = fTop = 0; 523 fRight = SkIntToScalar(width); 524 fBottom = SkIntToScalar(height); 525 } 526 527 /** Set this rectangle to be the bounds of the array of points. 528 If the array is empty (count == 0), then set this rectangle 529 to the empty rectangle (0,0,0,0) 530 */ setSkRect531 void set(const SkPoint pts[], int count) { 532 // set() had been checking for non-finite values, so keep that behavior 533 // for now. Now that we have setBoundsCheck(), we may decide to make 534 // set() be simpler/faster, and not check for those. 535 (void)this->setBoundsCheck(pts, count); 536 } 537 538 // alias for set(pts, count) setBoundsSkRect539 void setBounds(const SkPoint pts[], int count) { 540 (void)this->setBoundsCheck(pts, count); 541 } 542 543 /** 544 * Compute the bounds of the array of points, and set this rect to that 545 * bounds and return true... unless a non-finite value is encountered, 546 * in which case this rect is set to empty and false is returned. 547 */ 548 bool setBoundsCheck(const SkPoint pts[], int count); 549 setSkRect550 void set(const SkPoint& p0, const SkPoint& p1) { 551 fLeft = SkMinScalar(p0.fX, p1.fX); 552 fRight = SkMaxScalar(p0.fX, p1.fX); 553 fTop = SkMinScalar(p0.fY, p1.fY); 554 fBottom = SkMaxScalar(p0.fY, p1.fY); 555 } 556 setXYWHSkRect557 void setXYWH(SkScalar x, SkScalar y, SkScalar width, SkScalar height) { 558 fLeft = x; 559 fTop = y; 560 fRight = x + width; 561 fBottom = y + height; 562 } 563 setWHSkRect564 void setWH(SkScalar width, SkScalar height) { 565 fLeft = 0; 566 fTop = 0; 567 fRight = width; 568 fBottom = height; 569 } 570 571 /** 572 * Make the largest representable rectangle 573 */ setLargestSkRect574 void setLargest() { 575 fLeft = fTop = SK_ScalarMin; 576 fRight = fBottom = SK_ScalarMax; 577 } 578 579 /** 580 * Make the largest representable rectangle, but inverted (e.g. fLeft will 581 * be max and right will be min). 582 */ setLargestInvertedSkRect583 void setLargestInverted() { 584 fLeft = fTop = SK_ScalarMax; 585 fRight = fBottom = SK_ScalarMin; 586 } 587 588 /** Offset set the rectangle by adding dx to its left and right, 589 and adding dy to its top and bottom. 590 */ offsetSkRect591 void offset(SkScalar dx, SkScalar dy) { 592 fLeft += dx; 593 fTop += dy; 594 fRight += dx; 595 fBottom += dy; 596 } 597 offsetSkRect598 void offset(const SkPoint& delta) { 599 this->offset(delta.fX, delta.fY); 600 } 601 602 /** 603 * Offset this rect such its new x() and y() will equal newX and newY. 604 */ offsetToSkRect605 void offsetTo(SkScalar newX, SkScalar newY) { 606 fRight += newX - fLeft; 607 fBottom += newY - fTop; 608 fLeft = newX; 609 fTop = newY; 610 } 611 612 /** Inset the rectangle by (dx,dy). If dx is positive, then the sides are 613 moved inwards, making the rectangle narrower. If dx is negative, then 614 the sides are moved outwards, making the rectangle wider. The same holds 615 true for dy and the top and bottom. 616 */ insetSkRect617 void inset(SkScalar dx, SkScalar dy) { 618 fLeft += dx; 619 fTop += dy; 620 fRight -= dx; 621 fBottom -= dy; 622 } 623 624 /** Outset the rectangle by (dx,dy). If dx is positive, then the sides are 625 moved outwards, making the rectangle wider. If dx is negative, then the 626 sides are moved inwards, making the rectangle narrower. The same holds 627 true for dy and the top and bottom. 628 */ outsetSkRect629 void outset(SkScalar dx, SkScalar dy) { this->inset(-dx, -dy); } 630 631 /** If this rectangle intersects r, return true and set this rectangle to that 632 intersection, otherwise return false and do not change this rectangle. 633 If either rectangle is empty, do nothing and return false. 634 */ 635 bool intersect(const SkRect& r); 636 637 /** If this rectangle intersects the rectangle specified by left, top, right, bottom, 638 return true and set this rectangle to that intersection, otherwise return false 639 and do not change this rectangle. 640 If either rectangle is empty, do nothing and return false. 641 */ 642 bool intersect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom); 643 644 /** 645 * Return true if this rectangle is not empty, and the specified sides of 646 * a rectangle are not empty, and they intersect. 647 */ intersectsSkRect648 bool intersects(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) const { 649 return // first check that both are not empty 650 left < right && top < bottom && 651 fLeft < fRight && fTop < fBottom && 652 // now check for intersection 653 fLeft < right && left < fRight && 654 fTop < bottom && top < fBottom; 655 } 656 657 /** If rectangles a and b intersect, return true and set this rectangle to 658 * that intersection, otherwise return false and do not change this 659 * rectangle. If either rectangle is empty, do nothing and return false. 660 */ 661 bool intersect(const SkRect& a, const SkRect& b); 662 663 /** 664 * Return true if rectangles a and b are not empty and intersect. 665 */ IntersectsSkRect666 static bool Intersects(const SkRect& a, const SkRect& b) { 667 return !a.isEmpty() && !b.isEmpty() && 668 a.fLeft < b.fRight && b.fLeft < a.fRight && 669 a.fTop < b.fBottom && b.fTop < a.fBottom; 670 } 671 672 /** 673 * Update this rectangle to enclose itself and the specified rectangle. 674 * If this rectangle is empty, just set it to the specified rectangle. 675 * If the specified rectangle is empty, do nothing. 676 */ 677 void join(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom); 678 679 /** Update this rectangle to enclose itself and the specified rectangle. 680 If this rectangle is empty, just set it to the specified rectangle. If the specified 681 rectangle is empty, do nothing. 682 */ joinSkRect683 void join(const SkRect& r) { 684 this->join(r.fLeft, r.fTop, r.fRight, r.fBottom); 685 } 686 // alias for join() growToIncludeSkRect687 void growToInclude(const SkRect& r) { this->join(r); } 688 689 /** 690 * Grow the rect to include the specified (x,y). After this call, the 691 * following will be true: fLeft <= x <= fRight && fTop <= y <= fBottom. 692 * 693 * This is close, but not quite the same contract as contains(), since 694 * contains() treats the left and top different from the right and bottom. 695 * contains(x,y) -> fLeft <= x < fRight && fTop <= y < fBottom. Also note 696 * that contains(x,y) always returns false if the rect is empty. 697 */ growToIncludeSkRect698 void growToInclude(SkScalar x, SkScalar y) { 699 fLeft = SkMinScalar(x, fLeft); 700 fRight = SkMaxScalar(x, fRight); 701 fTop = SkMinScalar(y, fTop); 702 fBottom = SkMaxScalar(y, fBottom); 703 } 704 705 /** Bulk version of growToInclude */ growToIncludeSkRect706 void growToInclude(const SkPoint pts[], int count) { 707 this->growToInclude(pts, sizeof(SkPoint), count); 708 } 709 710 /** Bulk version of growToInclude with stride. */ growToIncludeSkRect711 void growToInclude(const SkPoint pts[], size_t stride, int count) { 712 SkASSERT(count >= 0); 713 SkASSERT(stride >= sizeof(SkPoint)); 714 const SkPoint* end = (const SkPoint*)((intptr_t)pts + count * stride); 715 for (; pts < end; pts = (const SkPoint*)((intptr_t)pts + stride)) { 716 this->growToInclude(pts->fX, pts->fY); 717 } 718 } 719 720 /** 721 * Return true if this rectangle contains r, and if both rectangles are 722 * not empty. 723 */ containsSkRect724 bool contains(const SkRect& r) const { 725 // todo: can we eliminate the this->isEmpty check? 726 return !r.isEmpty() && !this->isEmpty() && 727 fLeft <= r.fLeft && fTop <= r.fTop && 728 fRight >= r.fRight && fBottom >= r.fBottom; 729 } 730 731 /** 732 * Set the dst rectangle by rounding this rectangle's coordinates to their 733 * nearest integer values using SkScalarRoundToInt. 734 */ roundSkRect735 void round(SkIRect* dst) const { 736 SkASSERT(dst); 737 dst->set(SkScalarRoundToInt(fLeft), SkScalarRoundToInt(fTop), 738 SkScalarRoundToInt(fRight), SkScalarRoundToInt(fBottom)); 739 } 740 741 /** 742 * Set the dst rectangle by rounding "out" this rectangle, choosing the 743 * SkScalarFloor of top and left, and the SkScalarCeil of right and bottom. 744 */ roundOutSkRect745 void roundOut(SkIRect* dst) const { 746 SkASSERT(dst); 747 dst->set(SkScalarFloorToInt(fLeft), SkScalarFloorToInt(fTop), 748 SkScalarCeilToInt(fRight), SkScalarCeilToInt(fBottom)); 749 } 750 751 /** 752 * Expand this rectangle by rounding its coordinates "out", choosing the 753 * floor of top and left, and the ceil of right and bottom. If this rect 754 * is already on integer coordinates, then it will be unchanged. 755 */ roundOutSkRect756 void roundOut() { 757 this->set(SkScalarFloorToScalar(fLeft), 758 SkScalarFloorToScalar(fTop), 759 SkScalarCeilToScalar(fRight), 760 SkScalarCeilToScalar(fBottom)); 761 } 762 763 /** 764 * Set the dst rectangle by rounding "in" this rectangle, choosing the 765 * ceil of top and left, and the floor of right and bottom. This does *not* 766 * call sort(), so it is possible that the resulting rect is inverted... 767 * e.g. left >= right or top >= bottom. Call isEmpty() to detect that. 768 */ roundInSkRect769 void roundIn(SkIRect* dst) const { 770 SkASSERT(dst); 771 dst->set(SkScalarCeilToInt(fLeft), SkScalarCeilToInt(fTop), 772 SkScalarFloorToInt(fRight), SkScalarFloorToInt(fBottom)); 773 } 774 775 /** 776 * Return a new SkIRect which is contains the rounded coordinates of this 777 * rect using SkScalarRoundToInt. 778 */ roundSkRect779 SkIRect round() const { 780 SkIRect ir; 781 this->round(&ir); 782 return ir; 783 } 784 785 /** 786 * Swap top/bottom or left/right if there are flipped (i.e. if width() 787 * or height() would have returned a negative value.) This should be called 788 * if the edges are computed separately, and may have crossed over each 789 * other. When this returns, left <= right && top <= bottom 790 */ 791 void sort(); 792 793 /** 794 * cast-safe way to treat the rect as an array of (4) SkScalars. 795 */ asScalarsSkRect796 const SkScalar* asScalars() const { return &fLeft; } 797 }; 798 799 #endif 800