Home | History | Annotate | Download | only in core
      1 /*
      2  * Copyright 2006 The Android Open Source Project
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #ifndef SkRect_DEFINED
      9 #define SkRect_DEFINED
     10 
     11 #include "SkPoint.h"
     12 #include "SkSize.h"
     13 
     14 struct SkRect;
     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     SkISize size() const { return SkISize::Make(this->width(), this->height()); }
     81 
     82     /**
     83      *  Since the center of an integer rect may fall on a factional value, this
     84      *  method is defined to return (right + left) >> 1.
     85      *
     86      *  This is a specific "truncation" of the average, which is different than
     87      *  (right + left) / 2 when the sum is negative.
     88      */
     89     int centerX() const { return (fRight + fLeft) >> 1; }
     90 
     91     /**
     92      *  Since the center of an integer rect may fall on a factional value, this
     93      *  method is defined to return (bottom + top) >> 1
     94      *
     95      *  This is a specific "truncation" of the average, which is different than
     96      *  (bottom + top) / 2 when the sum is negative.
     97      */
     98     int centerY() const { return (fBottom + fTop) >> 1; }
     99 
    100     /**
    101      *  Return true if the rectangle's width or height are <= 0
    102      */
    103     bool isEmpty() const { return fLeft >= fRight || fTop >= fBottom; }
    104 
    105     bool isLargest() const { return SK_MinS32 == fLeft &&
    106                                     SK_MinS32 == fTop &&
    107                                     SK_MaxS32 == fRight &&
    108                                     SK_MaxS32 == fBottom; }
    109 
    110     friend bool operator==(const SkIRect& a, const SkIRect& b) {
    111         return !memcmp(&a, &b, sizeof(a));
    112     }
    113 
    114     friend bool operator!=(const SkIRect& a, const SkIRect& b) {
    115         return !(a == b);
    116     }
    117 
    118     bool is16Bit() const {
    119         return  SkIsS16(fLeft) && SkIsS16(fTop) &&
    120                 SkIsS16(fRight) && SkIsS16(fBottom);
    121     }
    122 
    123     /** Set the rectangle to (0,0,0,0)
    124     */
    125     void setEmpty() { memset(this, 0, sizeof(*this)); }
    126 
    127     void set(int32_t left, int32_t top, int32_t right, int32_t bottom) {
    128         fLeft   = left;
    129         fTop    = top;
    130         fRight  = right;
    131         fBottom = bottom;
    132     }
    133     // alias for set(l, t, r, b)
    134     void setLTRB(int32_t left, int32_t top, int32_t right, int32_t bottom) {
    135         this->set(left, top, right, bottom);
    136     }
    137 
    138     void setXYWH(int32_t x, int32_t y, int32_t width, int32_t height) {
    139         fLeft = x;
    140         fTop = y;
    141         fRight = x + width;
    142         fBottom = y + height;
    143     }
    144 
    145     /**
    146      *  Make the largest representable rectangle
    147      */
    148     void setLargest() {
    149         fLeft = fTop = SK_MinS32;
    150         fRight = fBottom = SK_MaxS32;
    151     }
    152 
    153     /**
    154      *  Make the largest representable rectangle, but inverted (e.g. fLeft will
    155      *  be max 32bit and right will be min 32bit).
    156      */
    157     void setLargestInverted() {
    158         fLeft = fTop = SK_MaxS32;
    159         fRight = fBottom = SK_MinS32;
    160     }
    161 
    162     /**
    163      *  Return a new IRect, built as an offset of this rect.
    164      */
    165     SkIRect makeOffset(int32_t dx, int32_t dy) const {
    166         return MakeLTRB(fLeft + dx, fTop + dy, fRight + dx, fBottom + dy);
    167     }
    168 
    169     /**
    170      *  Return a new IRect, built as an inset of this rect.
    171      */
    172     SkIRect makeInset(int32_t dx, int32_t dy) const {
    173         return MakeLTRB(fLeft + dx, fTop + dy, fRight - dx, fBottom - dy);
    174     }
    175 
    176     /**
    177      *  Return a new Rect, built as an outset of this rect.
    178      */
    179     SkIRect makeOutset(int32_t dx, int32_t dy) const {
    180         return MakeLTRB(fLeft - dx, fTop - dy, fRight + dx, fBottom + dy);
    181     }
    182 
    183     /** Offset set the rectangle by adding dx to its left and right,
    184         and adding dy to its top and bottom.
    185     */
    186     void offset(int32_t dx, int32_t dy) {
    187         fLeft   += dx;
    188         fTop    += dy;
    189         fRight  += dx;
    190         fBottom += dy;
    191     }
    192 
    193     void offset(const SkIPoint& delta) {
    194         this->offset(delta.fX, delta.fY);
    195     }
    196 
    197     /**
    198      *  Offset this rect such its new x() and y() will equal newX and newY.
    199      */
    200     void offsetTo(int32_t newX, int32_t newY) {
    201         fRight += newX - fLeft;
    202         fBottom += newY - fTop;
    203         fLeft = newX;
    204         fTop = newY;
    205     }
    206 
    207     /** Inset the rectangle by (dx,dy). If dx is positive, then the sides are moved inwards,
    208         making the rectangle narrower. If dx is negative, then the sides are moved outwards,
    209         making the rectangle wider. The same holds true for dy and the top and bottom.
    210     */
    211     void inset(int32_t dx, int32_t dy) {
    212         fLeft   += dx;
    213         fTop    += dy;
    214         fRight  -= dx;
    215         fBottom -= dy;
    216     }
    217 
    218    /** Outset the rectangle by (dx,dy). If dx is positive, then the sides are
    219        moved outwards, making the rectangle wider. If dx is negative, then the
    220        sides are moved inwards, making the rectangle narrower. The same holds
    221        true for dy and the top and bottom.
    222     */
    223     void outset(int32_t dx, int32_t dy)  { this->inset(-dx, -dy); }
    224 
    225     bool quickReject(int l, int t, int r, int b) const {
    226         return l >= fRight || fLeft >= r || t >= fBottom || fTop >= b;
    227     }
    228 
    229     /** Returns true if (x,y) is inside the rectangle and the rectangle is not
    230         empty. The left and top are considered to be inside, while the right
    231         and bottom are not. Thus for the rectangle (0, 0, 5, 10), the
    232         points (0,0) and (0,9) are inside, while (-1,0) and (5,9) are not.
    233     */
    234     bool contains(int32_t x, int32_t y) const {
    235         return  (unsigned)(x - fLeft) < (unsigned)(fRight - fLeft) &&
    236                 (unsigned)(y - fTop) < (unsigned)(fBottom - fTop);
    237     }
    238 
    239     /** Returns true if the 4 specified sides of a rectangle are inside or equal to this rectangle.
    240         If either rectangle is empty, contains() returns false.
    241     */
    242     bool contains(int32_t left, int32_t top, int32_t right, int32_t bottom) const {
    243         return  left < right && top < bottom && !this->isEmpty() && // check for empties
    244                 fLeft <= left && fTop <= top &&
    245                 fRight >= right && fBottom >= bottom;
    246     }
    247 
    248     /** Returns true if the specified rectangle r is inside or equal to this rectangle.
    249     */
    250     bool contains(const SkIRect& r) const {
    251         return  !r.isEmpty() && !this->isEmpty() &&     // check for empties
    252                 fLeft <= r.fLeft && fTop <= r.fTop &&
    253                 fRight >= r.fRight && fBottom >= r.fBottom;
    254     }
    255 
    256     /** Returns true if the specified rectangle r is inside or equal to this rectangle.
    257     */
    258     bool contains(const SkRect& r) const;
    259 
    260     /** Return true if this rectangle contains the specified rectangle.
    261         For speed, this method does not check if either this or the specified
    262         rectangles are empty, and if either is, its return value is undefined.
    263         In the debugging build however, we assert that both this and the
    264         specified rectangles are non-empty.
    265     */
    266     bool containsNoEmptyCheck(int32_t left, int32_t top,
    267                               int32_t right, int32_t bottom) const {
    268         SkASSERT(fLeft < fRight && fTop < fBottom);
    269         SkASSERT(left < right && top < bottom);
    270 
    271         return fLeft <= left && fTop <= top &&
    272                fRight >= right && fBottom >= bottom;
    273     }
    274 
    275     bool containsNoEmptyCheck(const SkIRect& r) const {
    276         return containsNoEmptyCheck(r.fLeft, r.fTop, r.fRight, r.fBottom);
    277     }
    278 
    279     /** If r intersects this rectangle, return true and set this rectangle to that
    280         intersection, otherwise return false and do not change this rectangle.
    281         If either rectangle is empty, do nothing and return false.
    282     */
    283     bool SK_WARN_UNUSED_RESULT intersect(const SkIRect& r) {
    284         return this->intersect(r.fLeft, r.fTop, r.fRight, r.fBottom);
    285     }
    286 
    287     /** If rectangles a and b intersect, return true and set this rectangle to
    288         that intersection, otherwise return false and do not change this
    289         rectangle. If either rectangle is empty, do nothing and return false.
    290     */
    291     bool SK_WARN_UNUSED_RESULT intersect(const SkIRect& a, const SkIRect& b) {
    292 
    293         if (!a.isEmpty() && !b.isEmpty() &&
    294                 a.fLeft < b.fRight && b.fLeft < a.fRight &&
    295                 a.fTop < b.fBottom && b.fTop < a.fBottom) {
    296             fLeft   = SkMax32(a.fLeft,   b.fLeft);
    297             fTop    = SkMax32(a.fTop,    b.fTop);
    298             fRight  = SkMin32(a.fRight,  b.fRight);
    299             fBottom = SkMin32(a.fBottom, b.fBottom);
    300             return true;
    301         }
    302         return false;
    303     }
    304 
    305     /** If rectangles a and b intersect, return true and set this rectangle to
    306         that intersection, otherwise return false and do not change this
    307         rectangle. For speed, no check to see if a or b are empty is performed.
    308         If either is, then the return result is undefined. In the debug build,
    309         we assert that both rectangles are non-empty.
    310     */
    311     bool SK_WARN_UNUSED_RESULT intersectNoEmptyCheck(const SkIRect& a, const SkIRect& b) {
    312         SkASSERT(!a.isEmpty() && !b.isEmpty());
    313 
    314         if (a.fLeft < b.fRight && b.fLeft < a.fRight &&
    315                 a.fTop < b.fBottom && b.fTop < a.fBottom) {
    316             fLeft   = SkMax32(a.fLeft,   b.fLeft);
    317             fTop    = SkMax32(a.fTop,    b.fTop);
    318             fRight  = SkMin32(a.fRight,  b.fRight);
    319             fBottom = SkMin32(a.fBottom, b.fBottom);
    320             return true;
    321         }
    322         return false;
    323     }
    324 
    325     /** If the rectangle specified by left,top,right,bottom intersects this rectangle,
    326         return true and set this rectangle to that intersection,
    327         otherwise return false and do not change this rectangle.
    328         If either rectangle is empty, do nothing and return false.
    329     */
    330     bool SK_WARN_UNUSED_RESULT intersect(int32_t left, int32_t top,
    331                                          int32_t right, int32_t bottom) {
    332         if (left < right && top < bottom && !this->isEmpty() &&
    333                 fLeft < right && left < fRight && fTop < bottom && top < fBottom) {
    334             if (fLeft < left) fLeft = left;
    335             if (fTop < top) fTop = top;
    336             if (fRight > right) fRight = right;
    337             if (fBottom > bottom) fBottom = bottom;
    338             return true;
    339         }
    340         return false;
    341     }
    342 
    343     /** Returns true if a and b are not empty, and they intersect
    344      */
    345     static bool Intersects(const SkIRect& a, const SkIRect& b) {
    346         return  !a.isEmpty() && !b.isEmpty() &&              // check for empties
    347                 a.fLeft < b.fRight && b.fLeft < a.fRight &&
    348                 a.fTop < b.fBottom && b.fTop < a.fBottom;
    349     }
    350 
    351     /**
    352      *  Returns true if a and b intersect. debug-asserts that neither are empty.
    353      */
    354     static bool IntersectsNoEmptyCheck(const SkIRect& a, const SkIRect& b) {
    355         SkASSERT(!a.isEmpty());
    356         SkASSERT(!b.isEmpty());
    357         return  a.fLeft < b.fRight && b.fLeft < a.fRight &&
    358                 a.fTop < b.fBottom && b.fTop < a.fBottom;
    359     }
    360 
    361     /** Update this rectangle to enclose itself and the specified rectangle.
    362         If this rectangle is empty, just set it to the specified rectangle. If the specified
    363         rectangle is empty, do nothing.
    364     */
    365     void join(int32_t left, int32_t top, int32_t right, int32_t bottom);
    366 
    367     /** Update this rectangle to enclose itself and the specified rectangle.
    368         If this rectangle is empty, just set it to the specified rectangle. If the specified
    369         rectangle is empty, do nothing.
    370     */
    371     void join(const SkIRect& r) {
    372         this->join(r.fLeft, r.fTop, r.fRight, r.fBottom);
    373     }
    374 
    375     /** Swap top/bottom or left/right if there are flipped.
    376         This can be called if the edges are computed separately,
    377         and may have crossed over each other.
    378         When this returns, left <= right && top <= bottom
    379     */
    380     void sort();
    381 
    382     static const SkIRect& SK_WARN_UNUSED_RESULT EmptyIRect() {
    383         static const SkIRect gEmpty = { 0, 0, 0, 0 };
    384         return gEmpty;
    385     }
    386 };
    387 
    388 /** \struct SkRect
    389 */
    390 struct SK_API SkRect {
    391     SkScalar    fLeft, fTop, fRight, fBottom;
    392 
    393     static SkRect SK_WARN_UNUSED_RESULT MakeEmpty() {
    394         SkRect r;
    395         r.setEmpty();
    396         return r;
    397     }
    398 
    399     static SkRect SK_WARN_UNUSED_RESULT MakeLargest() {
    400         SkRect r;
    401         r.setLargest();
    402         return r;
    403     }
    404 
    405     static SkRect SK_WARN_UNUSED_RESULT MakeWH(SkScalar w, SkScalar h) {
    406         SkRect r;
    407         r.set(0, 0, w, h);
    408         return r;
    409     }
    410 
    411     static SkRect SK_WARN_UNUSED_RESULT MakeIWH(int w, int h) {
    412         SkRect r;
    413         r.set(0, 0, SkIntToScalar(w), SkIntToScalar(h));
    414         return r;
    415     }
    416 
    417     static SkRect SK_WARN_UNUSED_RESULT MakeSize(const SkSize& size) {
    418         SkRect r;
    419         r.set(0, 0, size.width(), size.height());
    420         return r;
    421     }
    422 
    423     static SkRect SK_WARN_UNUSED_RESULT MakeLTRB(SkScalar l, SkScalar t, SkScalar r, SkScalar b) {
    424         SkRect rect;
    425         rect.set(l, t, r, b);
    426         return rect;
    427     }
    428 
    429     static SkRect SK_WARN_UNUSED_RESULT MakeXYWH(SkScalar x, SkScalar y, SkScalar w, SkScalar h) {
    430         SkRect r;
    431         r.set(x, y, x + w, y + h);
    432         return r;
    433     }
    434 
    435     SK_ATTR_DEPRECATED("use Make()")
    436     static SkRect SK_WARN_UNUSED_RESULT MakeFromIRect(const SkIRect& irect) {
    437         SkRect r;
    438         r.set(SkIntToScalar(irect.fLeft),
    439               SkIntToScalar(irect.fTop),
    440               SkIntToScalar(irect.fRight),
    441               SkIntToScalar(irect.fBottom));
    442         return r;
    443     }
    444 
    445     static SkRect SK_WARN_UNUSED_RESULT Make(const SkIRect& irect) {
    446         SkRect r;
    447         r.set(SkIntToScalar(irect.fLeft),
    448               SkIntToScalar(irect.fTop),
    449               SkIntToScalar(irect.fRight),
    450               SkIntToScalar(irect.fBottom));
    451         return r;
    452     }
    453 
    454     /**
    455      *  Return true if the rectangle's width or height are <= 0
    456      */
    457     bool isEmpty() const { return fLeft >= fRight || fTop >= fBottom; }
    458 
    459     bool isLargest() const { return SK_ScalarMin == fLeft &&
    460                                     SK_ScalarMin == fTop &&
    461                                     SK_ScalarMax == fRight &&
    462                                     SK_ScalarMax == fBottom; }
    463 
    464     /**
    465      *  Returns true iff all values in the rect are finite. If any are
    466      *  infinite or NaN then this returns false.
    467      */
    468     bool isFinite() const {
    469         float accum = 0;
    470         accum *= fLeft;
    471         accum *= fTop;
    472         accum *= fRight;
    473         accum *= fBottom;
    474 
    475         // accum is either NaN or it is finite (zero).
    476         SkASSERT(0 == accum || SkScalarIsNaN(accum));
    477 
    478         // value==value will be true iff value is not NaN
    479         // TODO: is it faster to say !accum or accum==accum?
    480         return !SkScalarIsNaN(accum);
    481     }
    482 
    483     SkScalar    x() const { return fLeft; }
    484     SkScalar    y() const { return fTop; }
    485     SkScalar    left() const { return fLeft; }
    486     SkScalar    top() const { return fTop; }
    487     SkScalar    right() const { return fRight; }
    488     SkScalar    bottom() const { return fBottom; }
    489     SkScalar    width() const { return fRight - fLeft; }
    490     SkScalar    height() const { return fBottom - fTop; }
    491     SkScalar    centerX() const { return SkScalarHalf(fLeft + fRight); }
    492     SkScalar    centerY() const { return SkScalarHalf(fTop + fBottom); }
    493 
    494     friend bool operator==(const SkRect& a, const SkRect& b) {
    495         return SkScalarsEqual((SkScalar*)&a, (SkScalar*)&b, 4);
    496     }
    497 
    498     friend bool operator!=(const SkRect& a, const SkRect& b) {
    499         return !SkScalarsEqual((SkScalar*)&a, (SkScalar*)&b, 4);
    500     }
    501 
    502     /** return the 4 points that enclose the rectangle (top-left, top-right, bottom-right,
    503         bottom-left). TODO: Consider adding param to control whether quad is CW or CCW.
    504      */
    505     void toQuad(SkPoint quad[4]) const;
    506 
    507     /** Set this rectangle to the empty rectangle (0,0,0,0)
    508     */
    509     void setEmpty() { memset(this, 0, sizeof(*this)); }
    510 
    511     void set(const SkIRect& src) {
    512         fLeft   = SkIntToScalar(src.fLeft);
    513         fTop    = SkIntToScalar(src.fTop);
    514         fRight  = SkIntToScalar(src.fRight);
    515         fBottom = SkIntToScalar(src.fBottom);
    516     }
    517 
    518     void set(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) {
    519         fLeft   = left;
    520         fTop    = top;
    521         fRight  = right;
    522         fBottom = bottom;
    523     }
    524     // alias for set(l, t, r, b)
    525     void setLTRB(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) {
    526         this->set(left, top, right, bottom);
    527     }
    528 
    529     /** Initialize the rect with the 4 specified integers. The routine handles
    530         converting them to scalars (by calling SkIntToScalar)
    531      */
    532     void iset(int left, int top, int right, int bottom) {
    533         fLeft   = SkIntToScalar(left);
    534         fTop    = SkIntToScalar(top);
    535         fRight  = SkIntToScalar(right);
    536         fBottom = SkIntToScalar(bottom);
    537     }
    538 
    539     /**
    540      *  Set this rectangle to be left/top at 0,0, and have the specified width
    541      *  and height (automatically converted to SkScalar).
    542      */
    543     void isetWH(int width, int height) {
    544         fLeft = fTop = 0;
    545         fRight = SkIntToScalar(width);
    546         fBottom = SkIntToScalar(height);
    547     }
    548 
    549     /** Set this rectangle to be the bounds of the array of points.
    550         If the array is empty (count == 0), then set this rectangle
    551         to the empty rectangle (0,0,0,0)
    552     */
    553     void set(const SkPoint pts[], int count) {
    554         // set() had been checking for non-finite values, so keep that behavior
    555         // for now. Now that we have setBoundsCheck(), we may decide to make
    556         // set() be simpler/faster, and not check for those.
    557         (void)this->setBoundsCheck(pts, count);
    558     }
    559 
    560     // alias for set(pts, count)
    561     void setBounds(const SkPoint pts[], int count) {
    562         (void)this->setBoundsCheck(pts, count);
    563     }
    564 
    565     /**
    566      *  Compute the bounds of the array of points, and set this rect to that
    567      *  bounds and return true... unless a non-finite value is encountered,
    568      *  in which case this rect is set to empty and false is returned.
    569      */
    570     bool setBoundsCheck(const SkPoint pts[], int count);
    571 
    572     void set(const SkPoint& p0, const SkPoint& p1) {
    573         fLeft =   SkMinScalar(p0.fX, p1.fX);
    574         fRight =  SkMaxScalar(p0.fX, p1.fX);
    575         fTop =    SkMinScalar(p0.fY, p1.fY);
    576         fBottom = SkMaxScalar(p0.fY, p1.fY);
    577     }
    578 
    579     void setXYWH(SkScalar x, SkScalar y, SkScalar width, SkScalar height) {
    580         fLeft = x;
    581         fTop = y;
    582         fRight = x + width;
    583         fBottom = y + height;
    584     }
    585 
    586     void setWH(SkScalar width, SkScalar height) {
    587         fLeft = 0;
    588         fTop = 0;
    589         fRight = width;
    590         fBottom = height;
    591     }
    592 
    593     /**
    594      *  Make the largest representable rectangle
    595      */
    596     void setLargest() {
    597         fLeft = fTop = SK_ScalarMin;
    598         fRight = fBottom = SK_ScalarMax;
    599     }
    600 
    601     /**
    602      *  Make the largest representable rectangle, but inverted (e.g. fLeft will
    603      *  be max and right will be min).
    604      */
    605     void setLargestInverted() {
    606         fLeft = fTop = SK_ScalarMax;
    607         fRight = fBottom = SK_ScalarMin;
    608     }
    609 
    610     /**
    611      *  Return a new Rect, built as an offset of this rect.
    612      */
    613     SkRect makeOffset(SkScalar dx, SkScalar dy) const {
    614         return MakeLTRB(fLeft + dx, fTop + dy, fRight + dx, fBottom + dy);
    615     }
    616 
    617     /**
    618      *  Return a new Rect, built as an inset of this rect.
    619      */
    620     SkRect makeInset(SkScalar dx, SkScalar dy) const {
    621         return MakeLTRB(fLeft + dx, fTop + dy, fRight - dx, fBottom - dy);
    622     }
    623 
    624     /**
    625      *  Return a new Rect, built as an outset of this rect.
    626      */
    627     SkRect makeOutset(SkScalar dx, SkScalar dy) const {
    628         return MakeLTRB(fLeft - dx, fTop - dy, fRight + dx, fBottom + dy);
    629     }
    630 
    631     /** Offset set the rectangle by adding dx to its left and right,
    632         and adding dy to its top and bottom.
    633     */
    634     void offset(SkScalar dx, SkScalar dy) {
    635         fLeft   += dx;
    636         fTop    += dy;
    637         fRight  += dx;
    638         fBottom += dy;
    639     }
    640 
    641     void offset(const SkPoint& delta) {
    642         this->offset(delta.fX, delta.fY);
    643     }
    644 
    645     /**
    646      *  Offset this rect such its new x() and y() will equal newX and newY.
    647      */
    648     void offsetTo(SkScalar newX, SkScalar newY) {
    649         fRight += newX - fLeft;
    650         fBottom += newY - fTop;
    651         fLeft = newX;
    652         fTop = newY;
    653     }
    654 
    655     /** Inset the rectangle by (dx,dy). If dx is positive, then the sides are
    656         moved inwards, making the rectangle narrower. If dx is negative, then
    657         the sides are moved outwards, making the rectangle wider. The same holds
    658          true for dy and the top and bottom.
    659     */
    660     void inset(SkScalar dx, SkScalar dy)  {
    661         fLeft   += dx;
    662         fTop    += dy;
    663         fRight  -= dx;
    664         fBottom -= dy;
    665     }
    666 
    667    /** Outset the rectangle by (dx,dy). If dx is positive, then the sides are
    668        moved outwards, making the rectangle wider. If dx is negative, then the
    669        sides are moved inwards, making the rectangle narrower. The same holds
    670        true for dy and the top and bottom.
    671     */
    672     void outset(SkScalar dx, SkScalar dy)  { this->inset(-dx, -dy); }
    673 
    674     /** If this rectangle intersects r, return true and set this rectangle to that
    675         intersection, otherwise return false and do not change this rectangle.
    676         If either rectangle is empty, do nothing and return false.
    677     */
    678     bool SK_WARN_UNUSED_RESULT intersect(const SkRect& r);
    679 
    680     /** If this rectangle intersects the rectangle specified by left, top, right, bottom,
    681         return true and set this rectangle to that intersection, otherwise return false
    682         and do not change this rectangle.
    683         If either rectangle is empty, do nothing and return false.
    684     */
    685     bool SK_WARN_UNUSED_RESULT intersect(SkScalar left, SkScalar top,
    686                                          SkScalar right, SkScalar bottom);
    687 
    688     /**
    689      *  If rectangles a and b intersect, return true and set this rectangle to
    690      *  that intersection, otherwise return false and do not change this
    691      *  rectangle. If either rectangle is empty, do nothing and return false.
    692      */
    693     bool SK_WARN_UNUSED_RESULT intersect(const SkRect& a, const SkRect& b);
    694 
    695 
    696 private:
    697     static bool Intersects(SkScalar al, SkScalar at, SkScalar ar, SkScalar ab,
    698                            SkScalar bl, SkScalar bt, SkScalar br, SkScalar bb) {
    699         SkScalar L = SkMaxScalar(al, bl);
    700         SkScalar R = SkMinScalar(ar, br);
    701         SkScalar T = SkMaxScalar(at, bt);
    702         SkScalar B = SkMinScalar(ab, bb);
    703         return L < R && T < B;
    704     }
    705 
    706 public:
    707     /**
    708      *  Return true if this rectangle is not empty, and the specified sides of
    709      *  a rectangle are not empty, and they intersect.
    710      */
    711     bool intersects(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) const {
    712         return Intersects(fLeft, fTop, fRight, fBottom, left, top, right, bottom);
    713     }
    714 
    715     bool intersects(const SkRect& r) const {
    716         return Intersects(fLeft, fTop, fRight, fBottom,
    717                           r.fLeft, r.fTop, r.fRight, r.fBottom);
    718     }
    719 
    720     /**
    721      *  Return true if rectangles a and b are not empty and intersect.
    722      */
    723     static bool Intersects(const SkRect& a, const SkRect& b) {
    724         return Intersects(a.fLeft, a.fTop, a.fRight, a.fBottom,
    725                           b.fLeft, b.fTop, b.fRight, b.fBottom);
    726     }
    727 
    728     /**
    729      *  Update this rectangle to enclose itself and the specified rectangle.
    730      *  If this rectangle is empty, just set it to the specified rectangle.
    731      *  If the specified rectangle is empty, do nothing.
    732      */
    733     void join(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom);
    734 
    735     /** Update this rectangle to enclose itself and the specified rectangle.
    736         If this rectangle is empty, just set it to the specified rectangle. If the specified
    737         rectangle is empty, do nothing.
    738     */
    739     void join(const SkRect& r) {
    740         this->join(r.fLeft, r.fTop, r.fRight, r.fBottom);
    741     }
    742 
    743     void joinNonEmptyArg(const SkRect& r) {
    744         SkASSERT(!r.isEmpty());
    745         // if we are empty, just assign
    746         if (fLeft >= fRight || fTop >= fBottom) {
    747             *this = r;
    748         } else {
    749             this->joinPossiblyEmptyRect(r);
    750         }
    751     }
    752 
    753     /**
    754      * Joins the rectangle with another without checking if either are empty (may produce unexpected
    755      * results if either rect is inverted).
    756      */
    757     void joinPossiblyEmptyRect(const SkRect& r) {
    758         fLeft   = SkMinScalar(fLeft, r.left());
    759         fTop    = SkMinScalar(fTop, r.top());
    760         fRight  = SkMaxScalar(fRight, r.right());
    761         fBottom = SkMaxScalar(fBottom, r.bottom());
    762     }
    763 
    764     /**
    765      *  Grow the rect to include the specified (x,y). After this call, the
    766      *  following will be true: fLeft <= x <= fRight && fTop <= y <= fBottom.
    767      *
    768      *  This is close, but not quite the same contract as contains(), since
    769      *  contains() treats the left and top different from the right and bottom.
    770      *  contains(x,y) -> fLeft <= x < fRight && fTop <= y < fBottom. Also note
    771      *  that contains(x,y) always returns false if the rect is empty.
    772      */
    773     void growToInclude(SkScalar x, SkScalar y) {
    774         fLeft  = SkMinScalar(x, fLeft);
    775         fRight = SkMaxScalar(x, fRight);
    776         fTop    = SkMinScalar(y, fTop);
    777         fBottom = SkMaxScalar(y, fBottom);
    778     }
    779 
    780     /** Bulk version of growToInclude */
    781     void growToInclude(const SkPoint pts[], int count) {
    782         this->growToInclude(pts, sizeof(SkPoint), count);
    783     }
    784 
    785     /** Bulk version of growToInclude with stride. */
    786     void growToInclude(const SkPoint pts[], size_t stride, int count) {
    787         SkASSERT(count >= 0);
    788         SkASSERT(stride >= sizeof(SkPoint));
    789         const SkPoint* end = (const SkPoint*)((intptr_t)pts + count * stride);
    790         for (; pts < end; pts = (const SkPoint*)((intptr_t)pts + stride)) {
    791             this->growToInclude(pts->fX, pts->fY);
    792         }
    793     }
    794 
    795     /**
    796      *  Return true if this rectangle contains r, and if both rectangles are
    797      *  not empty.
    798      */
    799     bool contains(const SkRect& r) const {
    800         // todo: can we eliminate the this->isEmpty check?
    801         return  !r.isEmpty() && !this->isEmpty() &&
    802                 fLeft <= r.fLeft && fTop <= r.fTop &&
    803                 fRight >= r.fRight && fBottom >= r.fBottom;
    804     }
    805 
    806     /**
    807      * Returns true if the specified rectangle r is inside or equal to this rectangle.
    808      */
    809     bool contains(const SkIRect& r) const {
    810         // todo: can we eliminate the this->isEmpty check?
    811         return  !r.isEmpty() && !this->isEmpty() &&
    812                 fLeft <= SkIntToScalar(r.fLeft) && fTop <= SkIntToScalar(r.fTop) &&
    813                 fRight >= SkIntToScalar(r.fRight) && fBottom >= SkIntToScalar(r.fBottom);
    814     }
    815 
    816     /**
    817      *  Set the dst rectangle by rounding this rectangle's coordinates to their
    818      *  nearest integer values using SkScalarRoundToInt.
    819      */
    820     void round(SkIRect* dst) const {
    821         SkASSERT(dst);
    822         dst->set(SkScalarRoundToInt(fLeft), SkScalarRoundToInt(fTop),
    823                  SkScalarRoundToInt(fRight), SkScalarRoundToInt(fBottom));
    824     }
    825 
    826     /**
    827      *  Set the dst rectangle by rounding "out" this rectangle, choosing the
    828      *  SkScalarFloor of top and left, and the SkScalarCeil of right and bottom.
    829      */
    830     void roundOut(SkIRect* dst) const {
    831         SkASSERT(dst);
    832         dst->set(SkScalarFloorToInt(fLeft), SkScalarFloorToInt(fTop),
    833                  SkScalarCeilToInt(fRight), SkScalarCeilToInt(fBottom));
    834     }
    835 
    836     /**
    837      *  Set the dst rectangle by rounding "out" this rectangle, choosing the
    838      *  SkScalarFloorToScalar of top and left, and the SkScalarCeilToScalar of right and bottom.
    839      *
    840      *  It is safe for this == dst
    841      */
    842     void roundOut(SkRect* dst) const {
    843         dst->set(SkScalarFloorToScalar(fLeft),
    844                  SkScalarFloorToScalar(fTop),
    845                  SkScalarCeilToScalar(fRight),
    846                  SkScalarCeilToScalar(fBottom));
    847     }
    848 
    849     /**
    850      *  Set the dst rectangle by rounding "in" this rectangle, choosing the
    851      *  ceil of top and left, and the floor of right and bottom. This does *not*
    852      *  call sort(), so it is possible that the resulting rect is inverted...
    853      *  e.g. left >= right or top >= bottom. Call isEmpty() to detect that.
    854      */
    855     void roundIn(SkIRect* dst) const {
    856         SkASSERT(dst);
    857         dst->set(SkScalarCeilToInt(fLeft), SkScalarCeilToInt(fTop),
    858                  SkScalarFloorToInt(fRight), SkScalarFloorToInt(fBottom));
    859     }
    860 
    861     //! Returns the result of calling round(&dst)
    862     SkIRect round() const {
    863         SkIRect ir;
    864         this->round(&ir);
    865         return ir;
    866     }
    867 
    868     //! Returns the result of calling roundOut(&dst)
    869     SkIRect roundOut() const {
    870         SkIRect ir;
    871         this->roundOut(&ir);
    872         return ir;
    873     }
    874 
    875     /**
    876      *  Swap top/bottom or left/right if there are flipped (i.e. if width()
    877      *  or height() would have returned a negative value.) This should be called
    878      *  if the edges are computed separately, and may have crossed over each
    879      *  other. When this returns, left <= right && top <= bottom
    880      */
    881     void sort() {
    882         if (fLeft > fRight) {
    883             SkTSwap<SkScalar>(fLeft, fRight);
    884         }
    885 
    886         if (fTop > fBottom) {
    887             SkTSwap<SkScalar>(fTop, fBottom);
    888         }
    889     }
    890 
    891     /**
    892      *  cast-safe way to treat the rect as an array of (4) SkScalars.
    893      */
    894     const SkScalar* asScalars() const { return &fLeft; }
    895 
    896     void dump(bool asHex) const;
    897     void dump() const { this->dump(false); }
    898     void dumpHex() const { this->dump(true); }
    899 };
    900 
    901 inline bool SkIRect::contains(const SkRect& r) const {
    902     return  !r.isEmpty() && !this->isEmpty() &&     // check for empties
    903             (SkScalar)fLeft <= r.fLeft && (SkScalar)fTop <= r.fTop &&
    904             (SkScalar)fRight >= r.fRight && (SkScalar)fBottom >= r.fBottom;
    905 }
    906 
    907 #endif
    908