1 /* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef SkRect_DEFINED 18 #define SkRect_DEFINED 19 20 #include "SkPoint.h" 21 #include "SkSize.h" 22 23 /** \struct SkIRect 24 25 SkIRect holds four 32 bit integer coordinates for a rectangle 26 */ 27 struct SK_API SkIRect { 28 int32_t fLeft, fTop, fRight, fBottom; 29 30 static SkIRect MakeEmpty() { 31 SkIRect r; 32 r.setEmpty(); 33 return r; 34 } 35 36 static SkIRect MakeWH(int32_t w, int32_t h) { 37 SkIRect r; 38 r.set(0, 0, w, h); 39 return r; 40 } 41 42 static SkIRect MakeSize(const SkISize& size) { 43 SkIRect r; 44 r.set(0, 0, size.width(), size.height()); 45 return r; 46 } 47 48 static SkIRect MakeLTRB(int32_t l, int32_t t, int32_t r, int32_t b) { 49 SkIRect rect; 50 rect.set(l, t, r, b); 51 return rect; 52 } 53 54 static SkIRect MakeXYWH(int32_t x, int32_t y, int32_t w, int32_t h) { 55 SkIRect r; 56 r.set(x, y, x + w, y + h); 57 return r; 58 } 59 60 /** Return true if the rectangle's width or height are <= 0 61 */ 62 bool isEmpty() const { return fLeft >= fRight || fTop >= fBottom; } 63 64 /** Returns the rectangle's width. This does not check for a valid rectangle (i.e. left <= right) 65 so the result may be negative. 66 */ 67 int width() const { return fRight - fLeft; } 68 69 /** Returns the rectangle's height. This does not check for a valid rectangle (i.e. top <= bottom) 70 so the result may be negative. 71 */ 72 int height() const { return fBottom - fTop; } 73 74 friend int operator==(const SkIRect& a, const SkIRect& b) { 75 return !memcmp(&a, &b, sizeof(a)); 76 } 77 78 friend int operator!=(const SkIRect& a, const SkIRect& b) { 79 return memcmp(&a, &b, sizeof(a)); 80 } 81 82 bool is16Bit() const { 83 return SkIsS16(fLeft) && SkIsS16(fTop) && 84 SkIsS16(fRight) && SkIsS16(fBottom); 85 } 86 87 /** Set the rectangle to (0,0,0,0) 88 */ 89 void setEmpty() { memset(this, 0, sizeof(*this)); } 90 91 void set(int32_t left, int32_t top, int32_t right, int32_t bottom) { 92 fLeft = left; 93 fTop = top; 94 fRight = right; 95 fBottom = bottom; 96 } 97 // alias for set(l, t, r, b) 98 void setLTRB(int32_t left, int32_t top, int32_t right, int32_t bottom) { 99 this->set(left, top, right, bottom); 100 } 101 102 void setXYWH(int32_t x, int32_t y, int32_t width, int32_t height) { 103 fLeft = x; 104 fTop = y; 105 fRight = x + width; 106 fBottom = y + height; 107 } 108 109 /** 110 * Make the largest representable rectangle 111 */ 112 void setLargest() { 113 fLeft = fTop = SK_MinS32; 114 fRight = fBottom = SK_MaxS32; 115 } 116 117 /** 118 * Make the largest representable rectangle, but inverted (e.g. fLeft will 119 * be max 32bit and right will be min 32bit). 120 */ 121 void setLargestInverted() { 122 fLeft = fTop = SK_MaxS32; 123 fRight = fBottom = SK_MinS32; 124 } 125 126 /** Offset set the rectangle by adding dx to its left and right, 127 and adding dy to its top and bottom. 128 */ 129 void offset(int32_t dx, int32_t dy) { 130 fLeft += dx; 131 fTop += dy; 132 fRight += dx; 133 fBottom += dy; 134 } 135 136 void offset(const SkIPoint& delta) { 137 this->offset(delta.fX, delta.fY); 138 } 139 140 /** Inset the rectangle by (dx,dy). If dx is positive, then the sides are moved inwards, 141 making the rectangle narrower. If dx is negative, then the sides are moved outwards, 142 making the rectangle wider. The same hods true for dy and the top and bottom. 143 */ 144 void inset(int32_t dx, int32_t dy) { 145 fLeft += dx; 146 fTop += dy; 147 fRight -= dx; 148 fBottom -= dy; 149 } 150 151 bool quickReject(int l, int t, int r, int b) const { 152 return l >= fRight || fLeft >= r || t >= fBottom || fTop >= b; 153 } 154 155 /** Returns true if (x,y) is inside the rectangle and the rectangle is not 156 empty. The left and top are considered to be inside, while the right 157 and bottom are not. Thus for the rectangle (0, 0, 5, 10), the 158 points (0,0) and (0,9) are inside, while (-1,0) and (5,9) are not. 159 */ 160 bool contains(int32_t x, int32_t y) const { 161 return (unsigned)(x - fLeft) < (unsigned)(fRight - fLeft) && 162 (unsigned)(y - fTop) < (unsigned)(fBottom - fTop); 163 } 164 165 /** Returns true if the 4 specified sides of a rectangle are inside or equal to this rectangle. 166 If either rectangle is empty, contains() returns false. 167 */ 168 bool contains(int32_t left, int32_t top, int32_t right, int32_t bottom) const { 169 return left < right && top < bottom && !this->isEmpty() && // check for empties 170 fLeft <= left && fTop <= top && 171 fRight >= right && fBottom >= bottom; 172 } 173 174 /** Returns true if the specified rectangle r is inside or equal to this rectangle. 175 */ 176 bool contains(const SkIRect& r) const { 177 return !r.isEmpty() && !this->isEmpty() && // check for empties 178 fLeft <= r.fLeft && fTop <= r.fTop && 179 fRight >= r.fRight && fBottom >= r.fBottom; 180 } 181 182 /** Return true if this rectangle contains the specified rectangle. 183 For speed, this method does not check if either this or the specified 184 rectangles are empty, and if either is, its return value is undefined. 185 In the debugging build however, we assert that both this and the 186 specified rectangles are non-empty. 187 */ 188 bool containsNoEmptyCheck(int32_t left, int32_t top, 189 int32_t right, int32_t bottom) const { 190 SkASSERT(fLeft < fRight && fTop < fBottom); 191 SkASSERT(left < right && top < bottom); 192 193 return fLeft <= left && fTop <= top && 194 fRight >= right && fBottom >= bottom; 195 } 196 197 /** If r intersects this rectangle, return true and set this rectangle to that 198 intersection, otherwise return false and do not change this rectangle. 199 If either rectangle is empty, do nothing and return false. 200 */ 201 bool intersect(const SkIRect& r) { 202 SkASSERT(&r); 203 return this->intersect(r.fLeft, r.fTop, r.fRight, r.fBottom); 204 } 205 206 /** If rectangles a and b intersect, return true and set this rectangle to 207 that intersection, otherwise return false and do not change this 208 rectangle. If either rectangle is empty, do nothing and return false. 209 */ 210 bool intersect(const SkIRect& a, const SkIRect& b) { 211 SkASSERT(&a && &b); 212 213 if (!a.isEmpty() && !b.isEmpty() && 214 a.fLeft < b.fRight && b.fLeft < a.fRight && 215 a.fTop < b.fBottom && b.fTop < a.fBottom) { 216 fLeft = SkMax32(a.fLeft, b.fLeft); 217 fTop = SkMax32(a.fTop, b.fTop); 218 fRight = SkMin32(a.fRight, b.fRight); 219 fBottom = SkMin32(a.fBottom, b.fBottom); 220 return true; 221 } 222 return false; 223 } 224 225 /** If rectangles a and b intersect, return true and set this rectangle to 226 that intersection, otherwise return false and do not change this 227 rectangle. For speed, no check to see if a or b are empty is performed. 228 If either is, then the return result is undefined. In the debug build, 229 we assert that both rectangles are non-empty. 230 */ 231 bool intersectNoEmptyCheck(const SkIRect& a, const SkIRect& b) { 232 SkASSERT(&a && &b); 233 SkASSERT(!a.isEmpty() && !b.isEmpty()); 234 235 if (a.fLeft < b.fRight && b.fLeft < a.fRight && 236 a.fTop < b.fBottom && b.fTop < a.fBottom) { 237 fLeft = SkMax32(a.fLeft, b.fLeft); 238 fTop = SkMax32(a.fTop, b.fTop); 239 fRight = SkMin32(a.fRight, b.fRight); 240 fBottom = SkMin32(a.fBottom, b.fBottom); 241 return true; 242 } 243 return false; 244 } 245 246 /** If the rectangle specified by left,top,right,bottom intersects this rectangle, 247 return true and set this rectangle to that intersection, 248 otherwise return false and do not change this rectangle. 249 If either rectangle is empty, do nothing and return false. 250 */ 251 bool intersect(int32_t left, int32_t top, int32_t right, int32_t bottom) { 252 if (left < right && top < bottom && !this->isEmpty() && 253 fLeft < right && left < fRight && fTop < bottom && top < fBottom) { 254 if (fLeft < left) fLeft = left; 255 if (fTop < top) fTop = top; 256 if (fRight > right) fRight = right; 257 if (fBottom > bottom) fBottom = bottom; 258 return true; 259 } 260 return false; 261 } 262 263 /** Returns true if a and b are not empty, and they intersect 264 */ 265 static bool Intersects(const SkIRect& a, const SkIRect& b) { 266 return !a.isEmpty() && !b.isEmpty() && // check for empties 267 a.fLeft < b.fRight && b.fLeft < a.fRight && 268 a.fTop < b.fBottom && b.fTop < a.fBottom; 269 } 270 271 /** Update this rectangle to enclose itself and the specified rectangle. 272 If this rectangle is empty, just set it to the specified rectangle. If the specified 273 rectangle is empty, do nothing. 274 */ 275 void join(int32_t left, int32_t top, int32_t right, int32_t bottom); 276 277 /** Update this rectangle to enclose itself and the specified rectangle. 278 If this rectangle is empty, just set it to the specified rectangle. If the specified 279 rectangle is empty, do nothing. 280 */ 281 void join(const SkIRect& r) { 282 this->join(r.fLeft, r.fTop, r.fRight, r.fBottom); 283 } 284 285 /** Swap top/bottom or left/right if there are flipped. 286 This can be called if the edges are computed separately, 287 and may have crossed over each other. 288 When this returns, left <= right && top <= bottom 289 */ 290 void sort(); 291 292 static const SkIRect& EmptyIRect() { 293 static const SkIRect gEmpty = { 0, 0, 0, 0 }; 294 return gEmpty; 295 } 296 }; 297 298 /** \struct SkRect 299 */ 300 struct SK_API SkRect { 301 SkScalar fLeft, fTop, fRight, fBottom; 302 303 static SkRect MakeEmpty() { 304 SkRect r; 305 r.setEmpty(); 306 return r; 307 } 308 309 static SkRect MakeWH(SkScalar w, SkScalar h) { 310 SkRect r; 311 r.set(0, 0, w, h); 312 return r; 313 } 314 315 static SkRect MakeSize(const SkSize& size) { 316 SkRect r; 317 r.set(0, 0, size.width(), size.height()); 318 return r; 319 } 320 321 static SkRect MakeLTRB(SkScalar l, SkScalar t, SkScalar r, SkScalar b) { 322 SkRect rect; 323 rect.set(l, t, r, b); 324 return rect; 325 } 326 327 static SkRect MakeXYWH(SkScalar x, SkScalar y, SkScalar w, SkScalar h) { 328 SkRect r; 329 r.set(x, y, x + w, y + h); 330 return r; 331 } 332 333 /** Return true if the rectangle's width or height are <= 0 334 */ 335 bool isEmpty() const { return fLeft >= fRight || fTop >= fBottom; } 336 bool hasValidCoordinates() const; 337 SkScalar left() const { return fLeft; } 338 SkScalar top() const { return fTop; } 339 SkScalar right() const { return fRight; } 340 SkScalar bottom() const { return fBottom; } 341 SkScalar width() const { return fRight - fLeft; } 342 SkScalar height() const { return fBottom - fTop; } 343 SkScalar centerX() const { return SkScalarHalf(fLeft + fRight); } 344 SkScalar centerY() const { return SkScalarHalf(fTop + fBottom); } 345 346 friend int operator==(const SkRect& a, const SkRect& b) { 347 return !memcmp(&a, &b, sizeof(a)); 348 } 349 350 friend int operator!=(const SkRect& a, const SkRect& b) { 351 return memcmp(&a, &b, sizeof(a)); 352 } 353 354 /** return the 4 points that enclose the rectangle 355 */ 356 void toQuad(SkPoint quad[4]) const; 357 358 /** Set this rectangle to the empty rectangle (0,0,0,0) 359 */ 360 void setEmpty() { memset(this, 0, sizeof(*this)); } 361 362 void set(const SkIRect& src) { 363 fLeft = SkIntToScalar(src.fLeft); 364 fTop = SkIntToScalar(src.fTop); 365 fRight = SkIntToScalar(src.fRight); 366 fBottom = SkIntToScalar(src.fBottom); 367 } 368 369 void set(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) { 370 fLeft = left; 371 fTop = top; 372 fRight = right; 373 fBottom = bottom; 374 } 375 // alias for set(l, t, r, b) 376 void setLTRB(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) { 377 this->set(left, top, right, bottom); 378 } 379 380 /** Initialize the rect with the 4 specified integers. The routine handles 381 converting them to scalars (by calling SkIntToScalar) 382 */ 383 void iset(int left, int top, int right, int bottom) { 384 fLeft = SkIntToScalar(left); 385 fTop = SkIntToScalar(top); 386 fRight = SkIntToScalar(right); 387 fBottom = SkIntToScalar(bottom); 388 } 389 390 /** Set this rectangle to be the bounds of the array of points. 391 If the array is empty (count == 0), then set this rectangle 392 to the empty rectangle (0,0,0,0) 393 */ 394 void set(const SkPoint pts[], int count); 395 396 // alias for set(pts, count) 397 void setBounds(const SkPoint pts[], int count) { 398 this->set(pts, count); 399 } 400 401 void setXYWH(SkScalar x, SkScalar y, SkScalar width, SkScalar height) { 402 fLeft = x; 403 fTop = y; 404 fRight = x + width; 405 fBottom = y + height; 406 } 407 408 /** 409 * Make the largest representable rectangle 410 */ 411 void setLargest() { 412 fLeft = fTop = SK_ScalarMin; 413 fRight = fBottom = SK_ScalarMax; 414 } 415 416 /** 417 * Make the largest representable rectangle, but inverted (e.g. fLeft will 418 * be max and right will be min). 419 */ 420 void setLargestInverted() { 421 fLeft = fTop = SK_ScalarMax; 422 fRight = fBottom = SK_ScalarMin; 423 } 424 425 /** Offset set the rectangle by adding dx to its left and right, 426 and adding dy to its top and bottom. 427 */ 428 void offset(SkScalar dx, SkScalar dy) { 429 fLeft += dx; 430 fTop += dy; 431 fRight += dx; 432 fBottom += dy; 433 } 434 435 void offset(const SkPoint& delta) { 436 this->offset(delta.fX, delta.fY); 437 } 438 439 /** Inset the rectangle by (dx,dy). If dx is positive, then the sides are moved inwards, 440 making the rectangle narrower. If dx is negative, then the sides are moved outwards, 441 making the rectangle wider. The same hods true for dy and the top and bottom. 442 */ 443 void inset(SkScalar dx, SkScalar dy) { 444 fLeft += dx; 445 fTop += dy; 446 fRight -= dx; 447 fBottom -= dy; 448 } 449 450 /** If this rectangle intersects r, return true and set this rectangle to that 451 intersection, otherwise return false and do not change this rectangle. 452 If either rectangle is empty, do nothing and return false. 453 */ 454 bool intersect(const SkRect& r); 455 456 /** If this rectangle intersects the rectangle specified by left, top, right, bottom, 457 return true and set this rectangle to that intersection, otherwise return false 458 and do not change this rectangle. 459 If either rectangle is empty, do nothing and return false. 460 */ 461 bool intersect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom); 462 463 /** 464 * Return true if this rectangle is not empty, and the specified sides of 465 * a rectangle are not empty, and they intersect. 466 */ 467 bool intersects(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) const { 468 return // first check that both are not empty 469 left < right && top < bottom && 470 fLeft < fRight && fTop < fBottom && 471 // now check for intersection 472 fLeft < right && left < fRight && 473 fTop < bottom && top < fBottom; 474 } 475 476 /** 477 * Return true if rectangles a and b are not empty and intersect. 478 */ 479 static bool Intersects(const SkRect& a, const SkRect& b) { 480 return !a.isEmpty() && !b.isEmpty() && 481 a.fLeft < b.fRight && b.fLeft < a.fRight && 482 a.fTop < b.fBottom && b.fTop < a.fBottom; 483 } 484 485 /** 486 * Update this rectangle to enclose itself and the specified rectangle. 487 * If this rectangle is empty, just set it to the specified rectangle. 488 * If the specified rectangle is empty, do nothing. 489 */ 490 void join(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom); 491 492 /** Update this rectangle to enclose itself and the specified rectangle. 493 If this rectangle is empty, just set it to the specified rectangle. If the specified 494 rectangle is empty, do nothing. 495 */ 496 void join(const SkRect& r) { 497 this->join(r.fLeft, r.fTop, r.fRight, r.fBottom); 498 } 499 // alias for join() 500 void growToInclude(const SkRect& r) { this->join(r); } 501 502 /** 503 * Grow the rect to include the specified (x,y). After this call, the 504 * following will be true: fLeft <= x <= fRight && fTop <= y <= fBottom. 505 * 506 * This is close, but not quite the same contract as contains(), since 507 * contains() treats the left and top different from the right and bottom. 508 * contains(x,y) -> fLeft <= x < fRight && fTop <= y < fBottom. Also note 509 * that contains(x,y) always returns false if the rect is empty. 510 */ 511 void growToInclude(SkScalar x, SkScalar y) { 512 fLeft = SkMinScalar(x, fLeft); 513 fRight = SkMaxScalar(x, fRight); 514 fTop = SkMinScalar(y, fTop); 515 fBottom = SkMaxScalar(y, fBottom); 516 } 517 518 /** 519 * Returns true if (p.fX,p.fY) is inside the rectangle, and the rectangle 520 * is not empty. 521 * 522 * Contains treats the left and top differently from the right and bottom. 523 * The left and top coordinates of the rectangle are themselves considered 524 * to be inside, while the right and bottom are not. Thus for the rectangle 525 * {0, 0, 5, 10}, (0,0) is contained, but (0,10), (5,0) and (5,10) are not. 526 */ 527 bool contains(const SkPoint& p) const { 528 return !this->isEmpty() && 529 fLeft <= p.fX && p.fX < fRight && fTop <= p.fY && p.fY < fBottom; 530 } 531 532 /** 533 * Returns true if (x,y) is inside the rectangle, and the rectangle 534 * is not empty. 535 * 536 * Contains treats the left and top differently from the right and bottom. 537 * The left and top coordinates of the rectangle are themselves considered 538 * to be inside, while the right and bottom are not. Thus for the rectangle 539 * {0, 0, 5, 10}, (0,0) is contained, but (0,10), (5,0) and (5,10) are not. 540 */ 541 bool contains(SkScalar x, SkScalar y) const { 542 return !this->isEmpty() && 543 fLeft <= x && x < fRight && fTop <= y && y < fBottom; 544 } 545 546 /** 547 * Return true if this rectangle contains r, and if both rectangles are 548 * not empty. 549 */ 550 bool contains(const SkRect& r) const { 551 return !r.isEmpty() && !this->isEmpty() && 552 fLeft <= r.fLeft && fTop <= r.fTop && 553 fRight >= r.fRight && fBottom >= r.fBottom; 554 } 555 556 /** 557 * Set the dst rectangle by rounding this rectangle's coordinates to their 558 * nearest integer values using SkScalarRound. 559 */ 560 void round(SkIRect* dst) const { 561 SkASSERT(dst); 562 dst->set(SkScalarRound(fLeft), SkScalarRound(fTop), 563 SkScalarRound(fRight), SkScalarRound(fBottom)); 564 } 565 566 /** 567 * Set the dst rectangle by rounding "out" this rectangle, choosing the 568 * SkScalarFloor of top and left, and the SkScalarCeil of right and bottom. 569 */ 570 void roundOut(SkIRect* dst) const { 571 SkASSERT(dst); 572 dst->set(SkScalarFloor(fLeft), SkScalarFloor(fTop), 573 SkScalarCeil(fRight), SkScalarCeil(fBottom)); 574 } 575 576 /** 577 * Swap top/bottom or left/right if there are flipped (i.e. if width() 578 * or height() would have returned a negative value.) This should be called 579 * if the edges are computed separately, and may have crossed over each 580 * other. When this returns, left <= right && top <= bottom 581 */ 582 void sort(); 583 }; 584 585 #endif 586 587