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