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 MakeEmpty() { 24 SkIRect r; 25 r.setEmpty(); 26 return r; 27 } 28 MakeWHSkIRect29 static SkIRect MakeWH(int32_t w, int32_t h) { 30 SkIRect r; 31 r.set(0, 0, w, h); 32 return r; 33 } 34 MakeSizeSkIRect35 static SkIRect MakeSize(const SkISize& size) { 36 SkIRect r; 37 r.set(0, 0, size.width(), size.height()); 38 return r; 39 } 40 MakeLTRBSkIRect41 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 MakeXYWHSkIRect47 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 leftSkIRect53 int left() const { return fLeft; } topSkIRect54 int top() const { return fTop; } rightSkIRect55 int right() const { return fRight; } bottomSkIRect56 int bottom() const { return fBottom; } 57 58 /** return the left edge of the rect */ xSkIRect59 int x() const { return fLeft; } 60 /** return the top edge of the rect */ ySkIRect61 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 */ widthSkIRect66 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 */ heightSkIRect72 int height() const { return fBottom - fTop; } 73 74 /** 75 * Return true if the rectangle's width or height are <= 0 76 */ isEmptySkIRect77 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 is16BitSkIRect87 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 */ setEmptySkIRect94 void setEmpty() { memset(this, 0, sizeof(*this)); } 95 setSkIRect96 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) setLTRBSkIRect103 void setLTRB(int32_t left, int32_t top, int32_t right, int32_t bottom) { 104 this->set(left, top, right, bottom); 105 } 106 setXYWHSkIRect107 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 */ setLargestSkIRect117 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 */ setLargestInvertedSkIRect126 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 */ offsetSkIRect134 void offset(int32_t dx, int32_t dy) { 135 fLeft += dx; 136 fTop += dy; 137 fRight += dx; 138 fBottom += dy; 139 } 140 offsetSkIRect141 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 */ insetSkIRect149 void inset(int32_t dx, int32_t dy) { 150 fLeft += dx; 151 fTop += dy; 152 fRight -= dx; 153 fBottom -= dy; 154 } 155 quickRejectSkIRect156 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 */ containsSkIRect165 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 */ containsSkIRect173 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 */ containsSkIRect181 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 */ containsNoEmptyCheckSkIRect193 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 */ intersectSkIRect206 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 */ intersectSkIRect215 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 */ intersectNoEmptyCheckSkIRect236 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 */ intersectSkIRect256 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 */ IntersectsSkIRect270 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 */ joinSkIRect286 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 EmptyIRectSkIRect297 static const SkIRect& EmptyIRect() { 298 static const SkIRect gEmpty = { 0, 0, 0, 0 }; 299 return gEmpty; 300 } 301 }; 302 303 /** \struct SkRect 304 */ 305 struct SK_API SkRect { 306 SkScalar fLeft, fTop, fRight, fBottom; 307 MakeEmptySkRect308 static SkRect MakeEmpty() { 309 SkRect r; 310 r.setEmpty(); 311 return r; 312 } 313 MakeWHSkRect314 static SkRect MakeWH(SkScalar w, SkScalar h) { 315 SkRect r; 316 r.set(0, 0, w, h); 317 return r; 318 } 319 MakeSizeSkRect320 static SkRect MakeSize(const SkSize& size) { 321 SkRect r; 322 r.set(0, 0, size.width(), size.height()); 323 return r; 324 } 325 MakeLTRBSkRect326 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 MakeXYWHSkRect332 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 */ isEmptySkRect341 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 */ isFiniteSkRect348 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 leftSkRect366 SkScalar left() const { return fLeft; } topSkRect367 SkScalar top() const { return fTop; } rightSkRect368 SkScalar right() const { return fRight; } bottomSkRect369 SkScalar bottom() const { return fBottom; } widthSkRect370 SkScalar width() const { return fRight - fLeft; } heightSkRect371 SkScalar height() const { return fBottom - fTop; } centerXSkRect372 SkScalar centerX() const { return SkScalarHalf(fLeft + fRight); } centerYSkRect373 SkScalar centerY() const { return SkScalarHalf(fTop + fBottom); } 374 375 friend bool operator==(const SkRect& a, const SkRect& b) { 376 return 0 == memcmp(&a, &b, sizeof(a)); 377 } 378 379 friend bool operator!=(const SkRect& a, const SkRect& b) { 380 return 0 != memcmp(&a, &b, sizeof(a)); 381 } 382 383 /** return the 4 points that enclose the rectangle 384 */ 385 void toQuad(SkPoint quad[4]) const; 386 387 /** Set this rectangle to the empty rectangle (0,0,0,0) 388 */ setEmptySkRect389 void setEmpty() { memset(this, 0, sizeof(*this)); } 390 setSkRect391 void set(const SkIRect& src) { 392 fLeft = SkIntToScalar(src.fLeft); 393 fTop = SkIntToScalar(src.fTop); 394 fRight = SkIntToScalar(src.fRight); 395 fBottom = SkIntToScalar(src.fBottom); 396 } 397 setSkRect398 void set(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) { 399 fLeft = left; 400 fTop = top; 401 fRight = right; 402 fBottom = bottom; 403 } 404 // alias for set(l, t, r, b) setLTRBSkRect405 void setLTRB(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) { 406 this->set(left, top, right, bottom); 407 } 408 409 /** Initialize the rect with the 4 specified integers. The routine handles 410 converting them to scalars (by calling SkIntToScalar) 411 */ isetSkRect412 void iset(int left, int top, int right, int bottom) { 413 fLeft = SkIntToScalar(left); 414 fTop = SkIntToScalar(top); 415 fRight = SkIntToScalar(right); 416 fBottom = SkIntToScalar(bottom); 417 } 418 419 /** Set this rectangle to be the bounds of the array of points. 420 If the array is empty (count == 0), then set this rectangle 421 to the empty rectangle (0,0,0,0) 422 */ 423 void set(const SkPoint pts[], int count); 424 425 // alias for set(pts, count) setBoundsSkRect426 void setBounds(const SkPoint pts[], int count) { 427 this->set(pts, count); 428 } 429 setXYWHSkRect430 void setXYWH(SkScalar x, SkScalar y, SkScalar width, SkScalar height) { 431 fLeft = x; 432 fTop = y; 433 fRight = x + width; 434 fBottom = y + height; 435 } 436 437 /** 438 * Make the largest representable rectangle 439 */ setLargestSkRect440 void setLargest() { 441 fLeft = fTop = SK_ScalarMin; 442 fRight = fBottom = SK_ScalarMax; 443 } 444 445 /** 446 * Make the largest representable rectangle, but inverted (e.g. fLeft will 447 * be max and right will be min). 448 */ setLargestInvertedSkRect449 void setLargestInverted() { 450 fLeft = fTop = SK_ScalarMax; 451 fRight = fBottom = SK_ScalarMin; 452 } 453 454 /** Offset set the rectangle by adding dx to its left and right, 455 and adding dy to its top and bottom. 456 */ offsetSkRect457 void offset(SkScalar dx, SkScalar dy) { 458 fLeft += dx; 459 fTop += dy; 460 fRight += dx; 461 fBottom += dy; 462 } 463 offsetSkRect464 void offset(const SkPoint& delta) { 465 this->offset(delta.fX, delta.fY); 466 } 467 468 /** Inset the rectangle by (dx,dy). If dx is positive, then the sides are 469 moved inwards, making the rectangle narrower. If dx is negative, then 470 the sides are moved outwards, making the rectangle wider. The same holds 471 true for dy and the top and bottom. 472 */ insetSkRect473 void inset(SkScalar dx, SkScalar dy) { 474 fLeft += dx; 475 fTop += dy; 476 fRight -= dx; 477 fBottom -= dy; 478 } 479 480 /** Outset the rectangle by (dx,dy). If dx is positive, then the sides are 481 moved outwards, making the rectangle wider. If dx is negative, then the 482 sides are moved inwards, making the rectangle narrower. The same hods 483 true for dy and the top and bottom. 484 */ outsetSkRect485 void outset(SkScalar dx, SkScalar dy) { this->inset(-dx, -dy); } 486 487 /** If this rectangle intersects r, return true and set this rectangle to that 488 intersection, otherwise return false and do not change this rectangle. 489 If either rectangle is empty, do nothing and return false. 490 */ 491 bool intersect(const SkRect& r); 492 493 /** If this rectangle intersects the rectangle specified by left, top, right, bottom, 494 return true and set this rectangle to that intersection, otherwise return false 495 and do not change this rectangle. 496 If either rectangle is empty, do nothing and return false. 497 */ 498 bool intersect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom); 499 500 /** 501 * Return true if this rectangle is not empty, and the specified sides of 502 * a rectangle are not empty, and they intersect. 503 */ intersectsSkRect504 bool intersects(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) const { 505 return // first check that both are not empty 506 left < right && top < bottom && 507 fLeft < fRight && fTop < fBottom && 508 // now check for intersection 509 fLeft < right && left < fRight && 510 fTop < bottom && top < fBottom; 511 } 512 513 /** If rectangles a and b intersect, return true and set this rectangle to 514 * that intersection, otherwise return false and do not change this 515 * rectangle. If either rectangle is empty, do nothing and return false. 516 */ 517 bool intersect(const SkRect& a, const SkRect& b); 518 519 /** 520 * Return true if rectangles a and b are not empty and intersect. 521 */ IntersectsSkRect522 static bool Intersects(const SkRect& a, const SkRect& b) { 523 return !a.isEmpty() && !b.isEmpty() && 524 a.fLeft < b.fRight && b.fLeft < a.fRight && 525 a.fTop < b.fBottom && b.fTop < a.fBottom; 526 } 527 528 /** 529 * Update this rectangle to enclose itself and the specified rectangle. 530 * If this rectangle is empty, just set it to the specified rectangle. 531 * If the specified rectangle is empty, do nothing. 532 */ 533 void join(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom); 534 535 /** Update this rectangle to enclose itself and the specified rectangle. 536 If this rectangle is empty, just set it to the specified rectangle. If the specified 537 rectangle is empty, do nothing. 538 */ joinSkRect539 void join(const SkRect& r) { 540 this->join(r.fLeft, r.fTop, r.fRight, r.fBottom); 541 } 542 // alias for join() growToIncludeSkRect543 void growToInclude(const SkRect& r) { this->join(r); } 544 545 /** 546 * Grow the rect to include the specified (x,y). After this call, the 547 * following will be true: fLeft <= x <= fRight && fTop <= y <= fBottom. 548 * 549 * This is close, but not quite the same contract as contains(), since 550 * contains() treats the left and top different from the right and bottom. 551 * contains(x,y) -> fLeft <= x < fRight && fTop <= y < fBottom. Also note 552 * that contains(x,y) always returns false if the rect is empty. 553 */ growToIncludeSkRect554 void growToInclude(SkScalar x, SkScalar y) { 555 fLeft = SkMinScalar(x, fLeft); 556 fRight = SkMaxScalar(x, fRight); 557 fTop = SkMinScalar(y, fTop); 558 fBottom = SkMaxScalar(y, fBottom); 559 } 560 561 /** 562 * Returns true if (p.fX,p.fY) is inside the rectangle, and the rectangle 563 * is not empty. 564 * 565 * Contains treats the left and top differently from the right and bottom. 566 * The left and top coordinates of the rectangle are themselves considered 567 * to be inside, while the right and bottom are not. Thus for the rectangle 568 * {0, 0, 5, 10}, (0,0) is contained, but (0,10), (5,0) and (5,10) are not. 569 */ containsSkRect570 bool contains(const SkPoint& p) const { 571 return !this->isEmpty() && 572 fLeft <= p.fX && p.fX < fRight && fTop <= p.fY && p.fY < fBottom; 573 } 574 575 /** 576 * Returns true if (x,y) is inside the rectangle, and the rectangle 577 * is not empty. 578 * 579 * Contains treats the left and top differently from the right and bottom. 580 * The left and top coordinates of the rectangle are themselves considered 581 * to be inside, while the right and bottom are not. Thus for the rectangle 582 * {0, 0, 5, 10}, (0,0) is contained, but (0,10), (5,0) and (5,10) are not. 583 */ containsSkRect584 bool contains(SkScalar x, SkScalar y) const { 585 return !this->isEmpty() && 586 fLeft <= x && x < fRight && fTop <= y && y < fBottom; 587 } 588 589 /** 590 * Return true if this rectangle contains r, and if both rectangles are 591 * not empty. 592 */ containsSkRect593 bool contains(const SkRect& r) const { 594 return !r.isEmpty() && !this->isEmpty() && 595 fLeft <= r.fLeft && fTop <= r.fTop && 596 fRight >= r.fRight && fBottom >= r.fBottom; 597 } 598 599 /** 600 * Set the dst rectangle by rounding this rectangle's coordinates to their 601 * nearest integer values using SkScalarRound. 602 */ roundSkRect603 void round(SkIRect* dst) const { 604 SkASSERT(dst); 605 dst->set(SkScalarRound(fLeft), SkScalarRound(fTop), 606 SkScalarRound(fRight), SkScalarRound(fBottom)); 607 } 608 609 /** 610 * Set the dst rectangle by rounding "out" this rectangle, choosing the 611 * SkScalarFloor of top and left, and the SkScalarCeil of right and bottom. 612 */ roundOutSkRect613 void roundOut(SkIRect* dst) const { 614 SkASSERT(dst); 615 dst->set(SkScalarFloor(fLeft), SkScalarFloor(fTop), 616 SkScalarCeil(fRight), SkScalarCeil(fBottom)); 617 } 618 619 /** 620 * Expand this rectangle by rounding its coordinates "out", choosing the 621 * floor of top and left, and the ceil of right and bottom. If this rect 622 * is already on integer coordinates, then it will be unchanged. 623 */ roundOutSkRect624 void roundOut() { 625 this->set(SkScalarFloorToScalar(fLeft), 626 SkScalarFloorToScalar(fTop), 627 SkScalarCeilToScalar(fRight), 628 SkScalarCeilToScalar(fBottom)); 629 } 630 631 /** 632 * Swap top/bottom or left/right if there are flipped (i.e. if width() 633 * or height() would have returned a negative value.) This should be called 634 * if the edges are computed separately, and may have crossed over each 635 * other. When this returns, left <= right && top <= bottom 636 */ 637 void sort(); 638 }; 639 640 #endif 641 642