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 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 intersect(int32_t left, int32_t top, int32_t right, int32_t bottom) {
    331         if (left < right && top < bottom && !this->isEmpty() &&
    332                 fLeft < right && left < fRight && fTop < bottom && top < fBottom) {
    333             if (fLeft < left) fLeft = left;
    334             if (fTop < top) fTop = top;
    335             if (fRight > right) fRight = right;
    336             if (fBottom > bottom) fBottom = bottom;
    337             return true;
    338         }
    339         return false;
    340     }
    341 
    342     /** Returns true if a and b are not empty, and they intersect
    343      */
    344     static bool Intersects(const SkIRect& a, const SkIRect& b) {
    345         return  !a.isEmpty() && !b.isEmpty() &&              // check for empties
    346                 a.fLeft < b.fRight && b.fLeft < a.fRight &&
    347                 a.fTop < b.fBottom && b.fTop < a.fBottom;
    348     }
    349 
    350     /**
    351      *  Returns true if a and b intersect. debug-asserts that neither are empty.
    352      */
    353     static bool IntersectsNoEmptyCheck(const SkIRect& a, const SkIRect& b) {
    354         SkASSERT(!a.isEmpty());
    355         SkASSERT(!b.isEmpty());
    356         return  a.fLeft < b.fRight && b.fLeft < a.fRight &&
    357                 a.fTop < b.fBottom && b.fTop < a.fBottom;
    358     }
    359 
    360     /** Update this rectangle to enclose itself and the specified rectangle.
    361         If this rectangle is empty, just set it to the specified rectangle. If the specified
    362         rectangle is empty, do nothing.
    363     */
    364     void join(int32_t left, int32_t top, int32_t right, int32_t bottom);
    365 
    366     /** Update this rectangle to enclose itself and the specified rectangle.
    367         If this rectangle is empty, just set it to the specified rectangle. If the specified
    368         rectangle is empty, do nothing.
    369     */
    370     void join(const SkIRect& r) {
    371         this->join(r.fLeft, r.fTop, r.fRight, r.fBottom);
    372     }
    373 
    374     /** Swap top/bottom or left/right if there are flipped.
    375         This can be called if the edges are computed separately,
    376         and may have crossed over each other.
    377         When this returns, left <= right && top <= bottom
    378     */
    379     void sort() {
    380         if (fLeft > fRight) {
    381             SkTSwap<int32_t>(fLeft, fRight);
    382         }
    383         if (fTop > fBottom) {
    384             SkTSwap<int32_t>(fTop, fBottom);
    385         }
    386     }
    387 
    388     /**
    389      *  Return a new Rect that is the sorted version of this rect (left <= right, top <= bottom).
    390      */
    391     SkIRect makeSorted() const {
    392         return MakeLTRB(SkMin32(fLeft, fRight), SkMin32(fTop, fBottom),
    393                         SkMax32(fLeft, fRight), SkMax32(fTop, fBottom));
    394     }
    395 
    396     static const SkIRect& SK_WARN_UNUSED_RESULT EmptyIRect() {
    397         static const SkIRect gEmpty = { 0, 0, 0, 0 };
    398         return gEmpty;
    399     }
    400 };
    401 
    402 /** \struct SkRect
    403 */
    404 struct SK_API SkRect {
    405     SkScalar    fLeft, fTop, fRight, fBottom;
    406 
    407     static constexpr SkRect SK_WARN_UNUSED_RESULT MakeEmpty() {
    408         return SkRect{0, 0, 0, 0};
    409     }
    410 
    411     static SkRect SK_WARN_UNUSED_RESULT MakeLargest() {
    412         SkRect r;
    413         r.setLargest();
    414         return r;
    415     }
    416 
    417     static SkRect SK_WARN_UNUSED_RESULT MakeWH(SkScalar w, SkScalar h) {
    418         SkRect r;
    419         r.set(0, 0, w, h);
    420         return r;
    421     }
    422 
    423     static SkRect SK_WARN_UNUSED_RESULT MakeIWH(int w, int h) {
    424         SkRect r;
    425         r.set(0, 0, SkIntToScalar(w), SkIntToScalar(h));
    426         return r;
    427     }
    428 
    429     static SkRect SK_WARN_UNUSED_RESULT MakeSize(const SkSize& size) {
    430         SkRect r;
    431         r.set(0, 0, size.width(), size.height());
    432         return r;
    433     }
    434 
    435     static constexpr SkRect SK_WARN_UNUSED_RESULT MakeLTRB(SkScalar l, SkScalar t, SkScalar r,
    436                                                            SkScalar b) {
    437         return SkRect {l, t, r, b};
    438     }
    439 
    440     static SkRect SK_WARN_UNUSED_RESULT MakeXYWH(SkScalar x, SkScalar y, SkScalar w, SkScalar h) {
    441         SkRect r;
    442         r.set(x, y, x + w, y + h);
    443         return r;
    444     }
    445 
    446     SK_ATTR_DEPRECATED("use Make()")
    447     static SkRect SK_WARN_UNUSED_RESULT MakeFromIRect(const SkIRect& irect) {
    448         SkRect r;
    449         r.set(SkIntToScalar(irect.fLeft),
    450               SkIntToScalar(irect.fTop),
    451               SkIntToScalar(irect.fRight),
    452               SkIntToScalar(irect.fBottom));
    453         return r;
    454     }
    455 
    456     static SkRect Make(const SkISize& size) {
    457         return MakeIWH(size.width(), size.height());
    458     }
    459 
    460     static SkRect SK_WARN_UNUSED_RESULT Make(const SkIRect& irect) {
    461         SkRect r;
    462         r.set(SkIntToScalar(irect.fLeft),
    463               SkIntToScalar(irect.fTop),
    464               SkIntToScalar(irect.fRight),
    465               SkIntToScalar(irect.fBottom));
    466         return r;
    467     }
    468 
    469     /**
    470      *  Return true if the rectangle's width or height are <= 0
    471      */
    472     bool isEmpty() const { return fLeft >= fRight || fTop >= fBottom; }
    473 
    474     /**
    475      *  Return true if the rectangle's width and height are >= 0
    476      */
    477     bool isSorted() const { return fLeft <= fRight && fTop <= fBottom; }
    478 
    479     bool isLargest() const { return SK_ScalarMin == fLeft &&
    480                                     SK_ScalarMin == fTop &&
    481                                     SK_ScalarMax == fRight &&
    482                                     SK_ScalarMax == fBottom; }
    483 
    484     /**
    485      *  Returns true iff all values in the rect are finite. If any are
    486      *  infinite or NaN then this returns false.
    487      */
    488     bool isFinite() const {
    489         float accum = 0;
    490         accum *= fLeft;
    491         accum *= fTop;
    492         accum *= fRight;
    493         accum *= fBottom;
    494 
    495         // accum is either NaN or it is finite (zero).
    496         SkASSERT(0 == accum || SkScalarIsNaN(accum));
    497 
    498         // value==value will be true iff value is not NaN
    499         // TODO: is it faster to say !accum or accum==accum?
    500         return !SkScalarIsNaN(accum);
    501     }
    502 
    503     SkScalar    x() const { return fLeft; }
    504     SkScalar    y() const { return fTop; }
    505     SkScalar    left() const { return fLeft; }
    506     SkScalar    top() const { return fTop; }
    507     SkScalar    right() const { return fRight; }
    508     SkScalar    bottom() const { return fBottom; }
    509     SkScalar    width() const { return fRight - fLeft; }
    510     SkScalar    height() const { return fBottom - fTop; }
    511     SkScalar    centerX() const { return SkScalarHalf(fLeft + fRight); }
    512     SkScalar    centerY() const { return SkScalarHalf(fTop + fBottom); }
    513 
    514     friend bool operator==(const SkRect& a, const SkRect& b) {
    515         return SkScalarsEqual((SkScalar*)&a, (SkScalar*)&b, 4);
    516     }
    517 
    518     friend bool operator!=(const SkRect& a, const SkRect& b) {
    519         return !SkScalarsEqual((SkScalar*)&a, (SkScalar*)&b, 4);
    520     }
    521 
    522     /** return the 4 points that enclose the rectangle (top-left, top-right, bottom-right,
    523         bottom-left). TODO: Consider adding param to control whether quad is CW or CCW.
    524      */
    525     void toQuad(SkPoint quad[4]) const;
    526 
    527     /** Set this rectangle to the empty rectangle (0,0,0,0)
    528     */
    529     void setEmpty() { *this = MakeEmpty(); }
    530 
    531     void set(const SkIRect& src) {
    532         fLeft   = SkIntToScalar(src.fLeft);
    533         fTop    = SkIntToScalar(src.fTop);
    534         fRight  = SkIntToScalar(src.fRight);
    535         fBottom = SkIntToScalar(src.fBottom);
    536     }
    537 
    538     void set(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) {
    539         fLeft   = left;
    540         fTop    = top;
    541         fRight  = right;
    542         fBottom = bottom;
    543     }
    544     // alias for set(l, t, r, b)
    545     void setLTRB(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) {
    546         this->set(left, top, right, bottom);
    547     }
    548 
    549     /** Initialize the rect with the 4 specified integers. The routine handles
    550         converting them to scalars (by calling SkIntToScalar)
    551      */
    552     void iset(int left, int top, int right, int bottom) {
    553         fLeft   = SkIntToScalar(left);
    554         fTop    = SkIntToScalar(top);
    555         fRight  = SkIntToScalar(right);
    556         fBottom = SkIntToScalar(bottom);
    557     }
    558 
    559     /**
    560      *  Set this rectangle to be left/top at 0,0, and have the specified width
    561      *  and height (automatically converted to SkScalar).
    562      */
    563     void isetWH(int width, int height) {
    564         fLeft = fTop = 0;
    565         fRight = SkIntToScalar(width);
    566         fBottom = SkIntToScalar(height);
    567     }
    568 
    569     /** Set this rectangle to be the bounds of the array of points.
    570         If the array is empty (count == 0), then set this rectangle
    571         to the empty rectangle (0,0,0,0)
    572     */
    573     void set(const SkPoint pts[], int count) {
    574         // set() had been checking for non-finite values, so keep that behavior
    575         // for now. Now that we have setBoundsCheck(), we may decide to make
    576         // set() be simpler/faster, and not check for those.
    577         (void)this->setBoundsCheck(pts, count);
    578     }
    579 
    580     // alias for set(pts, count)
    581     void setBounds(const SkPoint pts[], int count) {
    582         (void)this->setBoundsCheck(pts, count);
    583     }
    584 
    585     /**
    586      *  Compute the bounds of the array of points, and set this rect to that
    587      *  bounds and return true... unless a non-finite value is encountered,
    588      *  in which case this rect is set to empty and false is returned.
    589      */
    590     bool setBoundsCheck(const SkPoint pts[], int count);
    591 
    592     void set(const SkPoint& p0, const SkPoint& p1) {
    593         fLeft =   SkMinScalar(p0.fX, p1.fX);
    594         fRight =  SkMaxScalar(p0.fX, p1.fX);
    595         fTop =    SkMinScalar(p0.fY, p1.fY);
    596         fBottom = SkMaxScalar(p0.fY, p1.fY);
    597     }
    598 
    599     void setXYWH(SkScalar x, SkScalar y, SkScalar width, SkScalar height) {
    600         fLeft = x;
    601         fTop = y;
    602         fRight = x + width;
    603         fBottom = y + height;
    604     }
    605 
    606     void setWH(SkScalar width, SkScalar height) {
    607         fLeft = 0;
    608         fTop = 0;
    609         fRight = width;
    610         fBottom = height;
    611     }
    612 
    613     /**
    614      *  Make the largest representable rectangle
    615      */
    616     void setLargest() {
    617         fLeft = fTop = SK_ScalarMin;
    618         fRight = fBottom = SK_ScalarMax;
    619     }
    620 
    621     /**
    622      *  Make the largest representable rectangle, but inverted (e.g. fLeft will
    623      *  be max and right will be min).
    624      */
    625     void setLargestInverted() {
    626         fLeft = fTop = SK_ScalarMax;
    627         fRight = fBottom = SK_ScalarMin;
    628     }
    629 
    630     /**
    631      *  Return a new Rect, built as an offset of this rect.
    632      */
    633     SkRect makeOffset(SkScalar dx, SkScalar dy) const {
    634         return MakeLTRB(fLeft + dx, fTop + dy, fRight + dx, fBottom + dy);
    635     }
    636 
    637     /**
    638      *  Return a new Rect, built as an inset of this rect.
    639      */
    640     SkRect makeInset(SkScalar dx, SkScalar dy) const {
    641         return MakeLTRB(fLeft + dx, fTop + dy, fRight - dx, fBottom - dy);
    642     }
    643 
    644     /**
    645      *  Return a new Rect, built as an outset of this rect.
    646      */
    647     SkRect makeOutset(SkScalar dx, SkScalar dy) const {
    648         return MakeLTRB(fLeft - dx, fTop - dy, fRight + dx, fBottom + dy);
    649     }
    650 
    651     /** Offset set the rectangle by adding dx to its left and right,
    652         and adding dy to its top and bottom.
    653     */
    654     void offset(SkScalar dx, SkScalar dy) {
    655         fLeft   += dx;
    656         fTop    += dy;
    657         fRight  += dx;
    658         fBottom += dy;
    659     }
    660 
    661     void offset(const SkPoint& delta) {
    662         this->offset(delta.fX, delta.fY);
    663     }
    664 
    665     /**
    666      *  Offset this rect such its new x() and y() will equal newX and newY.
    667      */
    668     void offsetTo(SkScalar newX, SkScalar newY) {
    669         fRight += newX - fLeft;
    670         fBottom += newY - fTop;
    671         fLeft = newX;
    672         fTop = newY;
    673     }
    674 
    675     /** Inset the rectangle by (dx,dy). If dx is positive, then the sides are
    676         moved inwards, making the rectangle narrower. If dx is negative, then
    677         the sides are moved outwards, making the rectangle wider. The same holds
    678          true for dy and the top and bottom.
    679     */
    680     void inset(SkScalar dx, SkScalar dy)  {
    681         fLeft   += dx;
    682         fTop    += dy;
    683         fRight  -= dx;
    684         fBottom -= dy;
    685     }
    686 
    687    /** Outset the rectangle by (dx,dy). If dx is positive, then the sides are
    688        moved outwards, making the rectangle wider. If dx is negative, then the
    689        sides are moved inwards, making the rectangle narrower. The same holds
    690        true for dy and the top and bottom.
    691     */
    692     void outset(SkScalar dx, SkScalar dy)  { this->inset(-dx, -dy); }
    693 
    694     /** If this rectangle intersects r, return true and set this rectangle to that
    695         intersection, otherwise return false and do not change this rectangle.
    696         If either rectangle is empty, do nothing and return false.
    697     */
    698     bool intersect(const SkRect& r);
    699 
    700     /** If this rectangle intersects the rectangle specified by left, top, right, bottom,
    701         return true and set this rectangle to that intersection, otherwise return false
    702         and do not change this rectangle.
    703         If either rectangle is empty, do nothing and return false.
    704     */
    705     bool intersect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom);
    706 
    707     /**
    708      *  If rectangles a and b intersect, return true and set this rectangle to
    709      *  that intersection, otherwise return false and do not change this
    710      *  rectangle. If either rectangle is empty, do nothing and return false.
    711      */
    712     bool SK_WARN_UNUSED_RESULT intersect(const SkRect& a, const SkRect& b);
    713 
    714 
    715 private:
    716     static bool Intersects(SkScalar al, SkScalar at, SkScalar ar, SkScalar ab,
    717                            SkScalar bl, SkScalar bt, SkScalar br, SkScalar bb) {
    718         SkScalar L = SkMaxScalar(al, bl);
    719         SkScalar R = SkMinScalar(ar, br);
    720         SkScalar T = SkMaxScalar(at, bt);
    721         SkScalar B = SkMinScalar(ab, bb);
    722         return L < R && T < B;
    723     }
    724 
    725 public:
    726     /**
    727      *  Return true if this rectangle is not empty, and the specified sides of
    728      *  a rectangle are not empty, and they intersect.
    729      */
    730     bool intersects(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) const {
    731         return Intersects(fLeft, fTop, fRight, fBottom, left, top, right, bottom);
    732     }
    733 
    734     bool intersects(const SkRect& r) const {
    735         return Intersects(fLeft, fTop, fRight, fBottom,
    736                           r.fLeft, r.fTop, r.fRight, r.fBottom);
    737     }
    738 
    739     /**
    740      *  Return true if rectangles a and b are not empty and intersect.
    741      */
    742     static bool Intersects(const SkRect& a, const SkRect& b) {
    743         return Intersects(a.fLeft, a.fTop, a.fRight, a.fBottom,
    744                           b.fLeft, b.fTop, b.fRight, b.fBottom);
    745     }
    746 
    747     /**
    748      *  Update this rectangle to enclose itself and the specified rectangle.
    749      *  If this rectangle is empty, just set it to the specified rectangle.
    750      *  If the specified rectangle is empty, do nothing.
    751      */
    752     void join(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom);
    753 
    754     /** Update this rectangle to enclose itself and the specified rectangle.
    755         If this rectangle is empty, just set it to the specified rectangle. If the specified
    756         rectangle is empty, do nothing.
    757     */
    758     void join(const SkRect& r) {
    759         this->join(r.fLeft, r.fTop, r.fRight, r.fBottom);
    760     }
    761 
    762     void joinNonEmptyArg(const SkRect& r) {
    763         SkASSERT(!r.isEmpty());
    764         // if we are empty, just assign
    765         if (fLeft >= fRight || fTop >= fBottom) {
    766             *this = r;
    767         } else {
    768             this->joinPossiblyEmptyRect(r);
    769         }
    770     }
    771 
    772     /**
    773      * Joins the rectangle with another without checking if either are empty (may produce unexpected
    774      * results if either rect is inverted).
    775      */
    776     void joinPossiblyEmptyRect(const SkRect& r) {
    777         fLeft   = SkMinScalar(fLeft, r.left());
    778         fTop    = SkMinScalar(fTop, r.top());
    779         fRight  = SkMaxScalar(fRight, r.right());
    780         fBottom = SkMaxScalar(fBottom, r.bottom());
    781     }
    782 
    783     /**
    784      *  Grow the rect to include the specified (x,y). After this call, the
    785      *  following will be true: fLeft <= x <= fRight && fTop <= y <= fBottom.
    786      *
    787      *  This is close, but not quite the same contract as contains(), since
    788      *  contains() treats the left and top different from the right and bottom.
    789      *  contains(x,y) -> fLeft <= x < fRight && fTop <= y < fBottom. Also note
    790      *  that contains(x,y) always returns false if the rect is empty.
    791      */
    792     void growToInclude(SkScalar x, SkScalar y) {
    793         fLeft  = SkMinScalar(x, fLeft);
    794         fRight = SkMaxScalar(x, fRight);
    795         fTop    = SkMinScalar(y, fTop);
    796         fBottom = SkMaxScalar(y, fBottom);
    797     }
    798 
    799     /** Bulk version of growToInclude */
    800     void growToInclude(const SkPoint pts[], int count) {
    801         this->growToInclude(pts, sizeof(SkPoint), count);
    802     }
    803 
    804     /** Bulk version of growToInclude with stride. */
    805     void growToInclude(const SkPoint pts[], size_t stride, int count) {
    806         SkASSERT(count >= 0);
    807         SkASSERT(stride >= sizeof(SkPoint));
    808         const SkPoint* end = (const SkPoint*)((intptr_t)pts + count * stride);
    809         for (; pts < end; pts = (const SkPoint*)((intptr_t)pts + stride)) {
    810             this->growToInclude(pts->fX, pts->fY);
    811         }
    812     }
    813 
    814     /**
    815      *  Return true if this rectangle contains r, and if both rectangles are
    816      *  not empty.
    817      */
    818     bool contains(const SkRect& r) const {
    819         // todo: can we eliminate the this->isEmpty check?
    820         return  !r.isEmpty() && !this->isEmpty() &&
    821                 fLeft <= r.fLeft && fTop <= r.fTop &&
    822                 fRight >= r.fRight && fBottom >= r.fBottom;
    823     }
    824 
    825     /**
    826      * Returns true if the specified rectangle r is inside or equal to this rectangle.
    827      */
    828     bool contains(const SkIRect& r) const {
    829         // todo: can we eliminate the this->isEmpty check?
    830         return  !r.isEmpty() && !this->isEmpty() &&
    831                 fLeft <= SkIntToScalar(r.fLeft) && fTop <= SkIntToScalar(r.fTop) &&
    832                 fRight >= SkIntToScalar(r.fRight) && fBottom >= SkIntToScalar(r.fBottom);
    833     }
    834 
    835     /**
    836      *  Set the dst rectangle by rounding this rectangle's coordinates to their
    837      *  nearest integer values using SkScalarRoundToInt.
    838      */
    839     void round(SkIRect* dst) const {
    840         SkASSERT(dst);
    841         dst->set(SkScalarRoundToInt(fLeft), SkScalarRoundToInt(fTop),
    842                  SkScalarRoundToInt(fRight), SkScalarRoundToInt(fBottom));
    843     }
    844 
    845     /**
    846      *  Set the dst rectangle by rounding "out" this rectangle, choosing the
    847      *  SkScalarFloor of top and left, and the SkScalarCeil of right and bottom.
    848      */
    849     void roundOut(SkIRect* dst) const {
    850         SkASSERT(dst);
    851         dst->set(SkScalarFloorToInt(fLeft), SkScalarFloorToInt(fTop),
    852                  SkScalarCeilToInt(fRight), SkScalarCeilToInt(fBottom));
    853     }
    854 
    855     /**
    856      *  Set the dst rectangle by rounding "out" this rectangle, choosing the
    857      *  SkScalarFloorToScalar of top and left, and the SkScalarCeilToScalar of right and bottom.
    858      *
    859      *  It is safe for this == dst
    860      */
    861     void roundOut(SkRect* dst) const {
    862         dst->set(SkScalarFloorToScalar(fLeft),
    863                  SkScalarFloorToScalar(fTop),
    864                  SkScalarCeilToScalar(fRight),
    865                  SkScalarCeilToScalar(fBottom));
    866     }
    867 
    868     /**
    869      *  Set the dst rectangle by rounding "in" this rectangle, choosing the
    870      *  ceil of top and left, and the floor of right and bottom. This does *not*
    871      *  call sort(), so it is possible that the resulting rect is inverted...
    872      *  e.g. left >= right or top >= bottom. Call isEmpty() to detect that.
    873      */
    874     void roundIn(SkIRect* dst) const {
    875         SkASSERT(dst);
    876         dst->set(SkScalarCeilToInt(fLeft), SkScalarCeilToInt(fTop),
    877                  SkScalarFloorToInt(fRight), SkScalarFloorToInt(fBottom));
    878     }
    879 
    880     //! Returns the result of calling round(&dst)
    881     SkIRect round() const {
    882         SkIRect ir;
    883         this->round(&ir);
    884         return ir;
    885     }
    886 
    887     //! Returns the result of calling roundOut(&dst)
    888     SkIRect roundOut() const {
    889         SkIRect ir;
    890         this->roundOut(&ir);
    891         return ir;
    892     }
    893 
    894     /**
    895      *  Swap top/bottom or left/right if there are flipped (i.e. if width()
    896      *  or height() would have returned a negative value.) This should be called
    897      *  if the edges are computed separately, and may have crossed over each
    898      *  other. When this returns, left <= right && top <= bottom
    899      */
    900     void sort() {
    901         if (fLeft > fRight) {
    902             SkTSwap<SkScalar>(fLeft, fRight);
    903         }
    904 
    905         if (fTop > fBottom) {
    906             SkTSwap<SkScalar>(fTop, fBottom);
    907         }
    908     }
    909 
    910     /**
    911      *  Return a new Rect that is the sorted version of this rect (left <= right, top <= bottom).
    912      */
    913     SkRect makeSorted() const {
    914         return MakeLTRB(SkMinScalar(fLeft, fRight), SkMinScalar(fTop, fBottom),
    915                         SkMaxScalar(fLeft, fRight), SkMaxScalar(fTop, fBottom));
    916     }
    917 
    918     /**
    919      *  cast-safe way to treat the rect as an array of (4) SkScalars.
    920      */
    921     const SkScalar* asScalars() const { return &fLeft; }
    922 
    923     void dump(bool asHex) const;
    924     void dump() const { this->dump(false); }
    925     void dumpHex() const { this->dump(true); }
    926 };
    927 
    928 inline bool SkIRect::contains(const SkRect& r) const {
    929     return  !r.isEmpty() && !this->isEmpty() &&     // check for empties
    930             (SkScalar)fLeft <= r.fLeft && (SkScalar)fTop <= r.fTop &&
    931             (SkScalar)fRight >= r.fRight && (SkScalar)fBottom >= r.fBottom;
    932 }
    933 
    934 #endif
    935