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