Home | History | Annotate | Download | only in core
      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 
     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 MakeLargest() {
     30         SkIRect r;
     31         r.setLargest();
     32         return r;
     33     }
     34 
     35     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 
     41     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 
     47     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 
     53     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 
     59     int left() const { return fLeft; }
     60     int top() const { return fTop; }
     61     int right() const { return fRight; }
     62     int bottom() const { return fBottom; }
     63 
     64     /** return the left edge of the rect */
     65     int x() const { return fLeft; }
     66     /** return the top edge of the rect */
     67     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      */
     72     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      */
     78     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      */
     87     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      */
     96     int centerY() const { return (fBottom + fTop) >> 1; }
     97 
     98     /**
     99      *  Return true if the rectangle's width or height are <= 0
    100      */
    101     bool isEmpty() const { return fLeft >= fRight || fTop >= fBottom; }
    102 
    103     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 
    116     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     */
    123     void setEmpty() { memset(this, 0, sizeof(*this)); }
    124 
    125     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)
    132     void setLTRB(int32_t left, int32_t top, int32_t right, int32_t bottom) {
    133         this->set(left, top, right, bottom);
    134     }
    135 
    136     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      */
    146     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      */
    155     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     */
    163     void offset(int32_t dx, int32_t dy) {
    164         fLeft   += dx;
    165         fTop    += dy;
    166         fRight  += dx;
    167         fBottom += dy;
    168     }
    169 
    170     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      */
    177     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     */
    188     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     */
    200     void outset(int32_t dx, int32_t dy)  { this->inset(-dx, -dy); }
    201 
    202     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     */
    211     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     */
    219     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     */
    227     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     */
    239     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 
    248     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     */
    256     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     */
    265     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     */
    286     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     */
    306     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      */
    320     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      */
    329     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     */
    346     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 
    357     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 
    368     static SkRect SK_WARN_UNUSED_RESULT MakeEmpty() {
    369         SkRect r;
    370         r.setEmpty();
    371         return r;
    372     }
    373 
    374     static SkRect SK_WARN_UNUSED_RESULT MakeWH(SkScalar w, SkScalar h) {
    375         SkRect r;
    376         r.set(0, 0, w, h);
    377         return r;
    378     }
    379 
    380     static SkRect SK_WARN_UNUSED_RESULT MakeSize(const SkSize& size) {
    381         SkRect r;
    382         r.set(0, 0, size.width(), size.height());
    383         return r;
    384     }
    385 
    386     static SkRect SK_WARN_UNUSED_RESULT MakeLTRB(SkScalar l, SkScalar t, SkScalar r, SkScalar b) {
    387         SkRect rect;
    388         rect.set(l, t, r, b);
    389         return rect;
    390     }
    391 
    392     static SkRect SK_WARN_UNUSED_RESULT MakeXYWH(SkScalar x, SkScalar y, SkScalar w, SkScalar h) {
    393         SkRect r;
    394         r.set(x, y, x + w, y + h);
    395         return r;
    396     }
    397 
    398     // DEPRECATED: call Make(r)
    399     static SkRect SK_WARN_UNUSED_RESULT MakeFromIRect(const SkIRect& irect) {
    400         SkRect r;
    401         r.set(SkIntToScalar(irect.fLeft),
    402               SkIntToScalar(irect.fTop),
    403               SkIntToScalar(irect.fRight),
    404               SkIntToScalar(irect.fBottom));
    405         return r;
    406     }
    407 
    408     static SkRect SK_WARN_UNUSED_RESULT Make(const SkIRect& irect) {
    409         SkRect r;
    410         r.set(SkIntToScalar(irect.fLeft),
    411               SkIntToScalar(irect.fTop),
    412               SkIntToScalar(irect.fRight),
    413               SkIntToScalar(irect.fBottom));
    414         return r;
    415     }
    416 
    417     /**
    418      *  Return true if the rectangle's width or height are <= 0
    419      */
    420     bool isEmpty() const { return fLeft >= fRight || fTop >= fBottom; }
    421 
    422     /**
    423      *  Returns true iff all values in the rect are finite. If any are
    424      *  infinite or NaN (or SK_FixedNaN when SkScalar is fixed) then this
    425      *  returns false.
    426      */
    427     bool isFinite() const {
    428 #ifdef SK_SCALAR_IS_FLOAT
    429         float accum = 0;
    430         accum *= fLeft;
    431         accum *= fTop;
    432         accum *= fRight;
    433         accum *= fBottom;
    434 
    435         // accum is either NaN or it is finite (zero).
    436         SkASSERT(0 == accum || !(accum == accum));
    437 
    438         // value==value will be true iff value is not NaN
    439         // TODO: is it faster to say !accum or accum==accum?
    440         return accum == accum;
    441 #else
    442         // use bit-or for speed, since we don't care about short-circuting the
    443         // tests, and we expect the common case will be that we need to check all.
    444         int isNaN = (SK_FixedNaN == fLeft)  | (SK_FixedNaN == fTop) |
    445                     (SK_FixedNaN == fRight) | (SK_FixedNaN == fBottom);
    446         return !isNaN;
    447 #endif
    448     }
    449 
    450     SkScalar    x() const { return fLeft; }
    451     SkScalar    y() const { return fTop; }
    452     SkScalar    left() const { return fLeft; }
    453     SkScalar    top() const { return fTop; }
    454     SkScalar    right() const { return fRight; }
    455     SkScalar    bottom() const { return fBottom; }
    456     SkScalar    width() const { return fRight - fLeft; }
    457     SkScalar    height() const { return fBottom - fTop; }
    458     SkScalar    centerX() const { return SkScalarHalf(fLeft + fRight); }
    459     SkScalar    centerY() const { return SkScalarHalf(fTop + fBottom); }
    460 
    461     friend bool operator==(const SkRect& a, const SkRect& b) {
    462         return SkScalarsEqual((SkScalar*)&a, (SkScalar*)&b, 4);
    463     }
    464 
    465     friend bool operator!=(const SkRect& a, const SkRect& b) {
    466         return !SkScalarsEqual((SkScalar*)&a, (SkScalar*)&b, 4);
    467     }
    468 
    469     /** return the 4 points that enclose the rectangle
    470     */
    471     void toQuad(SkPoint quad[4]) const;
    472 
    473     /** Set this rectangle to the empty rectangle (0,0,0,0)
    474     */
    475     void setEmpty() { memset(this, 0, sizeof(*this)); }
    476 
    477     void set(const SkIRect& src) {
    478         fLeft   = SkIntToScalar(src.fLeft);
    479         fTop    = SkIntToScalar(src.fTop);
    480         fRight  = SkIntToScalar(src.fRight);
    481         fBottom = SkIntToScalar(src.fBottom);
    482     }
    483 
    484     void set(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) {
    485         fLeft   = left;
    486         fTop    = top;
    487         fRight  = right;
    488         fBottom = bottom;
    489     }
    490     // alias for set(l, t, r, b)
    491     void setLTRB(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) {
    492         this->set(left, top, right, bottom);
    493     }
    494 
    495     /** Initialize the rect with the 4 specified integers. The routine handles
    496         converting them to scalars (by calling SkIntToScalar)
    497      */
    498     void iset(int left, int top, int right, int bottom) {
    499         fLeft   = SkIntToScalar(left);
    500         fTop    = SkIntToScalar(top);
    501         fRight  = SkIntToScalar(right);
    502         fBottom = SkIntToScalar(bottom);
    503     }
    504 
    505     /**
    506      *  Set this rectangle to be left/top at 0,0, and have the specified width
    507      *  and height (automatically converted to SkScalar).
    508      */
    509     void isetWH(int width, int height) {
    510         fLeft = fTop = 0;
    511         fRight = SkIntToScalar(width);
    512         fBottom = SkIntToScalar(height);
    513     }
    514 
    515     /** Set this rectangle to be the bounds of the array of points.
    516         If the array is empty (count == 0), then set this rectangle
    517         to the empty rectangle (0,0,0,0)
    518     */
    519     void set(const SkPoint pts[], int count) {
    520         // set() had been checking for non-finite values, so keep that behavior
    521         // for now. Now that we have setBoundsCheck(), we may decide to make
    522         // set() be simpler/faster, and not check for those.
    523         (void)this->setBoundsCheck(pts, count);
    524     }
    525 
    526     // alias for set(pts, count)
    527     void setBounds(const SkPoint pts[], int count) {
    528         (void)this->setBoundsCheck(pts, count);
    529     }
    530 
    531     /**
    532      *  Compute the bounds of the array of points, and set this rect to that
    533      *  bounds and return true... unless a non-finite value is encountered,
    534      *  in which case this rect is set to empty and false is returned.
    535      */
    536     bool setBoundsCheck(const SkPoint pts[], int count);
    537 
    538     void set(const SkPoint& p0, const SkPoint& p1) {
    539         fLeft =   SkMinScalar(p0.fX, p1.fX);
    540         fRight =  SkMaxScalar(p0.fX, p1.fX);
    541         fTop =    SkMinScalar(p0.fY, p1.fY);
    542         fBottom = SkMaxScalar(p0.fY, p1.fY);
    543     }
    544 
    545     void setXYWH(SkScalar x, SkScalar y, SkScalar width, SkScalar height) {
    546         fLeft = x;
    547         fTop = y;
    548         fRight = x + width;
    549         fBottom = y + height;
    550     }
    551 
    552     void setWH(SkScalar width, SkScalar height) {
    553         fLeft = 0;
    554         fTop = 0;
    555         fRight = width;
    556         fBottom = height;
    557     }
    558 
    559     /**
    560      *  Make the largest representable rectangle
    561      */
    562     void setLargest() {
    563         fLeft = fTop = SK_ScalarMin;
    564         fRight = fBottom = SK_ScalarMax;
    565     }
    566 
    567     /**
    568      *  Make the largest representable rectangle, but inverted (e.g. fLeft will
    569      *  be max and right will be min).
    570      */
    571     void setLargestInverted() {
    572         fLeft = fTop = SK_ScalarMax;
    573         fRight = fBottom = SK_ScalarMin;
    574     }
    575 
    576     /** Offset set the rectangle by adding dx to its left and right,
    577         and adding dy to its top and bottom.
    578     */
    579     void offset(SkScalar dx, SkScalar dy) {
    580         fLeft   += dx;
    581         fTop    += dy;
    582         fRight  += dx;
    583         fBottom += dy;
    584     }
    585 
    586     void offset(const SkPoint& delta) {
    587         this->offset(delta.fX, delta.fY);
    588     }
    589 
    590     /**
    591      *  Offset this rect such its new x() and y() will equal newX and newY.
    592      */
    593     void offsetTo(SkScalar newX, SkScalar newY) {
    594         fRight += newX - fLeft;
    595         fBottom += newY - fTop;
    596         fLeft = newX;
    597         fTop = newY;
    598     }
    599 
    600     /** Inset the rectangle by (dx,dy). If dx is positive, then the sides are
    601         moved inwards, making the rectangle narrower. If dx is negative, then
    602         the sides are moved outwards, making the rectangle wider. The same holds
    603          true for dy and the top and bottom.
    604     */
    605     void inset(SkScalar dx, SkScalar dy)  {
    606         fLeft   += dx;
    607         fTop    += dy;
    608         fRight  -= dx;
    609         fBottom -= dy;
    610     }
    611 
    612    /** Outset the rectangle by (dx,dy). If dx is positive, then the sides are
    613        moved outwards, making the rectangle wider. If dx is negative, then the
    614        sides are moved inwards, making the rectangle narrower. The same holds
    615        true for dy and the top and bottom.
    616     */
    617     void outset(SkScalar dx, SkScalar dy)  { this->inset(-dx, -dy); }
    618 
    619     /** If this rectangle intersects r, return true and set this rectangle to that
    620         intersection, otherwise return false and do not change this rectangle.
    621         If either rectangle is empty, do nothing and return false.
    622     */
    623     bool intersect(const SkRect& r);
    624 
    625     /** If this rectangle intersects the rectangle specified by left, top, right, bottom,
    626         return true and set this rectangle to that intersection, otherwise return false
    627         and do not change this rectangle.
    628         If either rectangle is empty, do nothing and return false.
    629     */
    630     bool intersect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom);
    631 
    632     /**
    633      *  Return true if this rectangle is not empty, and the specified sides of
    634      *  a rectangle are not empty, and they intersect.
    635      */
    636     bool intersects(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) const {
    637         return // first check that both are not empty
    638                left < right && top < bottom &&
    639                fLeft < fRight && fTop < fBottom &&
    640                // now check for intersection
    641                fLeft < right && left < fRight &&
    642                fTop < bottom && top < fBottom;
    643     }
    644 
    645     /** If rectangles a and b intersect, return true and set this rectangle to
    646      *  that intersection, otherwise return false and do not change this
    647      *  rectangle. If either rectangle is empty, do nothing and return false.
    648      */
    649     bool intersect(const SkRect& a, const SkRect& b);
    650 
    651     /**
    652      *  Return true if rectangles a and b are not empty and intersect.
    653      */
    654     static bool Intersects(const SkRect& a, const SkRect& b) {
    655         return  !a.isEmpty() && !b.isEmpty() &&
    656                 a.fLeft < b.fRight && b.fLeft < a.fRight &&
    657                 a.fTop < b.fBottom && b.fTop < a.fBottom;
    658     }
    659 
    660     /**
    661      *  Update this rectangle to enclose itself and the specified rectangle.
    662      *  If this rectangle is empty, just set it to the specified rectangle.
    663      *  If the specified rectangle is empty, do nothing.
    664      */
    665     void join(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom);
    666 
    667     /** Update this rectangle to enclose itself and the specified rectangle.
    668         If this rectangle is empty, just set it to the specified rectangle. If the specified
    669         rectangle is empty, do nothing.
    670     */
    671     void join(const SkRect& r) {
    672         this->join(r.fLeft, r.fTop, r.fRight, r.fBottom);
    673     }
    674     // alias for join()
    675     void growToInclude(const SkRect& r) { this->join(r); }
    676 
    677     /**
    678      *  Grow the rect to include the specified (x,y). After this call, the
    679      *  following will be true: fLeft <= x <= fRight && fTop <= y <= fBottom.
    680      *
    681      *  This is close, but not quite the same contract as contains(), since
    682      *  contains() treats the left and top different from the right and bottom.
    683      *  contains(x,y) -> fLeft <= x < fRight && fTop <= y < fBottom. Also note
    684      *  that contains(x,y) always returns false if the rect is empty.
    685      */
    686     void growToInclude(SkScalar x, SkScalar y) {
    687         fLeft  = SkMinScalar(x, fLeft);
    688         fRight = SkMaxScalar(x, fRight);
    689         fTop    = SkMinScalar(y, fTop);
    690         fBottom = SkMaxScalar(y, fBottom);
    691     }
    692 
    693     /**
    694      *  Returns true if (p.fX,p.fY) is inside the rectangle, and the rectangle
    695      *  is not empty.
    696      *
    697      *  Contains treats the left and top differently from the right and bottom.
    698      *  The left and top coordinates of the rectangle are themselves considered
    699      *  to be inside, while the right and bottom are not. Thus for the rectangle
    700      *  {0, 0, 5, 10}, (0,0) is contained, but (0,10), (5,0) and (5,10) are not.
    701      */
    702     bool contains(const SkPoint& p) const {
    703         return !this->isEmpty() &&
    704                fLeft <= p.fX && p.fX < fRight && fTop <= p.fY && p.fY < fBottom;
    705     }
    706 
    707     /**
    708      *  Returns true if (x,y) is inside the rectangle, and the rectangle
    709      *  is not empty.
    710      *
    711      *  Contains treats the left and top differently from the right and bottom.
    712      *  The left and top coordinates of the rectangle are themselves considered
    713      *  to be inside, while the right and bottom are not. Thus for the rectangle
    714      *  {0, 0, 5, 10}, (0,0) is contained, but (0,10), (5,0) and (5,10) are not.
    715      */
    716     bool contains(SkScalar x, SkScalar y) const {
    717         return  !this->isEmpty() &&
    718                 fLeft <= x && x < fRight && fTop <= y && y < fBottom;
    719     }
    720 
    721     /**
    722      *  Return true if this rectangle contains r, and if both rectangles are
    723      *  not empty.
    724      */
    725     bool contains(const SkRect& r) const {
    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 SkScalarRound.
    734      */
    735     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      */
    745     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      */
    756     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      */
    769     void roundIn(SkIRect* dst) const {
    770         SkASSERT(dst);
    771         dst->set(SkScalarCeilToInt(fLeft), SkScalarCeilToInt(fTop),
    772                  SkScalarFloorToInt(fRight), SkScalarFloorToInt(fBottom));
    773     }
    774 
    775 
    776     /**
    777      *  Swap top/bottom or left/right if there are flipped (i.e. if width()
    778      *  or height() would have returned a negative value.) This should be called
    779      *  if the edges are computed separately, and may have crossed over each
    780      *  other. When this returns, left <= right && top <= bottom
    781      */
    782     void sort();
    783 
    784     /**
    785      *  cast-safe way to treat the rect as an array of (4) SkScalars.
    786      */
    787     const SkScalar* asScalars() const { return &fLeft; }
    788 };
    789 
    790 #endif
    791