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         SkASSERT(&a && &b);
    281 
    282         if (!a.isEmpty() && !b.isEmpty() &&
    283                 a.fLeft < b.fRight && b.fLeft < a.fRight &&
    284                 a.fTop < b.fBottom && b.fTop < a.fBottom) {
    285             fLeft   = SkMax32(a.fLeft,   b.fLeft);
    286             fTop    = SkMax32(a.fTop,    b.fTop);
    287             fRight  = SkMin32(a.fRight,  b.fRight);
    288             fBottom = SkMin32(a.fBottom, b.fBottom);
    289             return true;
    290         }
    291         return false;
    292     }
    293 
    294     /** If rectangles a and b intersect, return true and set this rectangle to
    295         that intersection, otherwise return false and do not change this
    296         rectangle. For speed, no check to see if a or b are empty is performed.
    297         If either is, then the return result is undefined. In the debug build,
    298         we assert that both rectangles are non-empty.
    299     */
    300     bool intersectNoEmptyCheck(const SkIRect& a, const SkIRect& b) {
    301         SkASSERT(&a && &b);
    302         SkASSERT(!a.isEmpty() && !b.isEmpty());
    303 
    304         if (a.fLeft < b.fRight && b.fLeft < a.fRight &&
    305                 a.fTop < b.fBottom && b.fTop < a.fBottom) {
    306             fLeft   = SkMax32(a.fLeft,   b.fLeft);
    307             fTop    = SkMax32(a.fTop,    b.fTop);
    308             fRight  = SkMin32(a.fRight,  b.fRight);
    309             fBottom = SkMin32(a.fBottom, b.fBottom);
    310             return true;
    311         }
    312         return false;
    313     }
    314 
    315     /** If the rectangle specified by left,top,right,bottom intersects this rectangle,
    316         return true and set this rectangle to that intersection,
    317         otherwise return false and do not change this rectangle.
    318         If either rectangle is empty, do nothing and return false.
    319     */
    320     bool intersect(int32_t left, int32_t top, int32_t right, int32_t bottom) {
    321         if (left < right && top < bottom && !this->isEmpty() &&
    322                 fLeft < right && left < fRight && fTop < bottom && top < fBottom) {
    323             if (fLeft < left) fLeft = left;
    324             if (fTop < top) fTop = top;
    325             if (fRight > right) fRight = right;
    326             if (fBottom > bottom) fBottom = bottom;
    327             return true;
    328         }
    329         return false;
    330     }
    331 
    332     /** Returns true if a and b are not empty, and they intersect
    333      */
    334     static bool Intersects(const SkIRect& a, const SkIRect& b) {
    335         return  !a.isEmpty() && !b.isEmpty() &&              // check for empties
    336         a.fLeft < b.fRight && b.fLeft < a.fRight &&
    337         a.fTop < b.fBottom && b.fTop < a.fBottom;
    338     }
    339 
    340     /**
    341      *  Returns true if a and b intersect. debug-asserts that neither are empty.
    342      */
    343     static bool IntersectsNoEmptyCheck(const SkIRect& a, const SkIRect& b) {
    344         SkASSERT(!a.isEmpty());
    345         SkASSERT(!b.isEmpty());
    346         return  a.fLeft < b.fRight && b.fLeft < a.fRight &&
    347                 a.fTop < b.fBottom && b.fTop < a.fBottom;
    348     }
    349 
    350     /** Update this rectangle to enclose itself and the specified rectangle.
    351         If this rectangle is empty, just set it to the specified rectangle. If the specified
    352         rectangle is empty, do nothing.
    353     */
    354     void join(int32_t left, int32_t top, int32_t right, int32_t bottom);
    355 
    356     /** Update this rectangle to enclose itself and the specified rectangle.
    357         If this rectangle is empty, just set it to the specified rectangle. If the specified
    358         rectangle is empty, do nothing.
    359     */
    360     void join(const SkIRect& r) {
    361         this->join(r.fLeft, r.fTop, r.fRight, r.fBottom);
    362     }
    363 
    364     /** Swap top/bottom or left/right if there are flipped.
    365         This can be called if the edges are computed separately,
    366         and may have crossed over each other.
    367         When this returns, left <= right && top <= bottom
    368     */
    369     void sort();
    370 
    371     static const SkIRect& SK_WARN_UNUSED_RESULT EmptyIRect() {
    372         static const SkIRect gEmpty = { 0, 0, 0, 0 };
    373         return gEmpty;
    374     }
    375 };
    376 
    377 /** \struct SkRect
    378 */
    379 struct SK_API SkRect {
    380     SkScalar    fLeft, fTop, fRight, fBottom;
    381 
    382     static SkRect SK_WARN_UNUSED_RESULT MakeEmpty() {
    383         SkRect r;
    384         r.setEmpty();
    385         return r;
    386     }
    387 
    388     static SkRect SK_WARN_UNUSED_RESULT MakeLargest() {
    389         SkRect r;
    390         r.setLargest();
    391         return r;
    392     }
    393 
    394     static SkRect SK_WARN_UNUSED_RESULT MakeWH(SkScalar w, SkScalar h) {
    395         SkRect r;
    396         r.set(0, 0, w, h);
    397         return r;
    398     }
    399 
    400     static SkRect SK_WARN_UNUSED_RESULT MakeSize(const SkSize& size) {
    401         SkRect r;
    402         r.set(0, 0, size.width(), size.height());
    403         return r;
    404     }
    405 
    406     static SkRect SK_WARN_UNUSED_RESULT MakeLTRB(SkScalar l, SkScalar t, SkScalar r, SkScalar b) {
    407         SkRect rect;
    408         rect.set(l, t, r, b);
    409         return rect;
    410     }
    411 
    412     static SkRect SK_WARN_UNUSED_RESULT MakeXYWH(SkScalar x, SkScalar y, SkScalar w, SkScalar h) {
    413         SkRect r;
    414         r.set(x, y, x + w, y + h);
    415         return r;
    416     }
    417 
    418     SK_ATTR_DEPRECATED("use Make()")
    419     static SkRect SK_WARN_UNUSED_RESULT MakeFromIRect(const SkIRect& irect) {
    420         SkRect r;
    421         r.set(SkIntToScalar(irect.fLeft),
    422               SkIntToScalar(irect.fTop),
    423               SkIntToScalar(irect.fRight),
    424               SkIntToScalar(irect.fBottom));
    425         return r;
    426     }
    427 
    428     static SkRect SK_WARN_UNUSED_RESULT Make(const SkIRect& irect) {
    429         SkRect r;
    430         r.set(SkIntToScalar(irect.fLeft),
    431               SkIntToScalar(irect.fTop),
    432               SkIntToScalar(irect.fRight),
    433               SkIntToScalar(irect.fBottom));
    434         return r;
    435     }
    436 
    437     /**
    438      *  Return true if the rectangle's width or height are <= 0
    439      */
    440     bool isEmpty() const { return fLeft >= fRight || fTop >= fBottom; }
    441 
    442     bool isLargest() const { return SK_ScalarMin == fLeft &&
    443                                     SK_ScalarMin == fTop &&
    444                                     SK_ScalarMax == fRight &&
    445                                     SK_ScalarMax == fBottom; }
    446 
    447     /**
    448      *  Returns true iff all values in the rect are finite. If any are
    449      *  infinite or NaN (or SK_FixedNaN when SkScalar is fixed) then this
    450      *  returns false.
    451      */
    452     bool isFinite() const {
    453         float accum = 0;
    454         accum *= fLeft;
    455         accum *= fTop;
    456         accum *= fRight;
    457         accum *= fBottom;
    458 
    459         // accum is either NaN or it is finite (zero).
    460         SkASSERT(0 == accum || !(accum == accum));
    461 
    462         // value==value will be true iff value is not NaN
    463         // TODO: is it faster to say !accum or accum==accum?
    464         return accum == accum;
    465     }
    466 
    467     SkScalar    x() const { return fLeft; }
    468     SkScalar    y() const { return fTop; }
    469     SkScalar    left() const { return fLeft; }
    470     SkScalar    top() const { return fTop; }
    471     SkScalar    right() const { return fRight; }
    472     SkScalar    bottom() const { return fBottom; }
    473     SkScalar    width() const { return fRight - fLeft; }
    474     SkScalar    height() const { return fBottom - fTop; }
    475     SkScalar    centerX() const { return SkScalarHalf(fLeft + fRight); }
    476     SkScalar    centerY() const { return SkScalarHalf(fTop + fBottom); }
    477 
    478     friend bool operator==(const SkRect& a, const SkRect& b) {
    479         return SkScalarsEqual((SkScalar*)&a, (SkScalar*)&b, 4);
    480     }
    481 
    482     friend bool operator!=(const SkRect& a, const SkRect& b) {
    483         return !SkScalarsEqual((SkScalar*)&a, (SkScalar*)&b, 4);
    484     }
    485 
    486     /** return the 4 points that enclose the rectangle (top-left, top-right, bottom-right,
    487         bottom-left). TODO: Consider adding param to control whether quad is CW or CCW.
    488      */
    489     void toQuad(SkPoint quad[4]) const;
    490 
    491     /** Set this rectangle to the empty rectangle (0,0,0,0)
    492     */
    493     void setEmpty() { memset(this, 0, sizeof(*this)); }
    494 
    495     void set(const SkIRect& src) {
    496         fLeft   = SkIntToScalar(src.fLeft);
    497         fTop    = SkIntToScalar(src.fTop);
    498         fRight  = SkIntToScalar(src.fRight);
    499         fBottom = SkIntToScalar(src.fBottom);
    500     }
    501 
    502     void set(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) {
    503         fLeft   = left;
    504         fTop    = top;
    505         fRight  = right;
    506         fBottom = bottom;
    507     }
    508     // alias for set(l, t, r, b)
    509     void setLTRB(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) {
    510         this->set(left, top, right, bottom);
    511     }
    512 
    513     /** Initialize the rect with the 4 specified integers. The routine handles
    514         converting them to scalars (by calling SkIntToScalar)
    515      */
    516     void iset(int left, int top, int right, int bottom) {
    517         fLeft   = SkIntToScalar(left);
    518         fTop    = SkIntToScalar(top);
    519         fRight  = SkIntToScalar(right);
    520         fBottom = SkIntToScalar(bottom);
    521     }
    522 
    523     /**
    524      *  Set this rectangle to be left/top at 0,0, and have the specified width
    525      *  and height (automatically converted to SkScalar).
    526      */
    527     void isetWH(int width, int height) {
    528         fLeft = fTop = 0;
    529         fRight = SkIntToScalar(width);
    530         fBottom = SkIntToScalar(height);
    531     }
    532 
    533     /** Set this rectangle to be the bounds of the array of points.
    534         If the array is empty (count == 0), then set this rectangle
    535         to the empty rectangle (0,0,0,0)
    536     */
    537     void set(const SkPoint pts[], int count) {
    538         // set() had been checking for non-finite values, so keep that behavior
    539         // for now. Now that we have setBoundsCheck(), we may decide to make
    540         // set() be simpler/faster, and not check for those.
    541         (void)this->setBoundsCheck(pts, count);
    542     }
    543 
    544     // alias for set(pts, count)
    545     void setBounds(const SkPoint pts[], int count) {
    546         (void)this->setBoundsCheck(pts, count);
    547     }
    548 
    549     /**
    550      *  Compute the bounds of the array of points, and set this rect to that
    551      *  bounds and return true... unless a non-finite value is encountered,
    552      *  in which case this rect is set to empty and false is returned.
    553      */
    554     bool setBoundsCheck(const SkPoint pts[], int count);
    555 
    556     void set(const SkPoint& p0, const SkPoint& p1) {
    557         fLeft =   SkMinScalar(p0.fX, p1.fX);
    558         fRight =  SkMaxScalar(p0.fX, p1.fX);
    559         fTop =    SkMinScalar(p0.fY, p1.fY);
    560         fBottom = SkMaxScalar(p0.fY, p1.fY);
    561     }
    562 
    563     void setXYWH(SkScalar x, SkScalar y, SkScalar width, SkScalar height) {
    564         fLeft = x;
    565         fTop = y;
    566         fRight = x + width;
    567         fBottom = y + height;
    568     }
    569 
    570     void setWH(SkScalar width, SkScalar height) {
    571         fLeft = 0;
    572         fTop = 0;
    573         fRight = width;
    574         fBottom = height;
    575     }
    576 
    577     /**
    578      *  Make the largest representable rectangle
    579      */
    580     void setLargest() {
    581         fLeft = fTop = SK_ScalarMin;
    582         fRight = fBottom = SK_ScalarMax;
    583     }
    584 
    585     /**
    586      *  Make the largest representable rectangle, but inverted (e.g. fLeft will
    587      *  be max and right will be min).
    588      */
    589     void setLargestInverted() {
    590         fLeft = fTop = SK_ScalarMax;
    591         fRight = fBottom = SK_ScalarMin;
    592     }
    593 
    594     /**
    595      *  Return a new Rect, built as an offset of this rect.
    596      */
    597     SkRect makeOffset(SkScalar dx, SkScalar dy) const {
    598         return MakeLTRB(fLeft + dx, fTop + dy, fRight + dx, fBottom + dy);
    599     }
    600 
    601     /**
    602      *  Return a new Rect, built as an inset of this rect.
    603      */
    604     SkRect makeInset(SkScalar dx, SkScalar dy) const {
    605         return MakeLTRB(fLeft + dx, fTop + dy, fRight - dx, fBottom - dy);
    606     }
    607 
    608     /** Offset set the rectangle by adding dx to its left and right,
    609         and adding dy to its top and bottom.
    610     */
    611     void offset(SkScalar dx, SkScalar dy) {
    612         fLeft   += dx;
    613         fTop    += dy;
    614         fRight  += dx;
    615         fBottom += dy;
    616     }
    617 
    618     void offset(const SkPoint& delta) {
    619         this->offset(delta.fX, delta.fY);
    620     }
    621 
    622     /**
    623      *  Offset this rect such its new x() and y() will equal newX and newY.
    624      */
    625     void offsetTo(SkScalar newX, SkScalar newY) {
    626         fRight += newX - fLeft;
    627         fBottom += newY - fTop;
    628         fLeft = newX;
    629         fTop = newY;
    630     }
    631 
    632     /** Inset the rectangle by (dx,dy). If dx is positive, then the sides are
    633         moved inwards, making the rectangle narrower. If dx is negative, then
    634         the sides are moved outwards, making the rectangle wider. The same holds
    635          true for dy and the top and bottom.
    636     */
    637     void inset(SkScalar dx, SkScalar dy)  {
    638         fLeft   += dx;
    639         fTop    += dy;
    640         fRight  -= dx;
    641         fBottom -= dy;
    642     }
    643 
    644    /** Outset the rectangle by (dx,dy). If dx is positive, then the sides are
    645        moved outwards, making the rectangle wider. If dx is negative, then the
    646        sides are moved inwards, making the rectangle narrower. The same holds
    647        true for dy and the top and bottom.
    648     */
    649     void outset(SkScalar dx, SkScalar dy)  { this->inset(-dx, -dy); }
    650 
    651     /** If this rectangle intersects r, return true and set this rectangle to that
    652         intersection, otherwise return false and do not change this rectangle.
    653         If either rectangle is empty, do nothing and return false.
    654     */
    655     bool intersect(const SkRect& r);
    656     bool intersect2(const SkRect& r);
    657 
    658     /** If this rectangle intersects the rectangle specified by left, top, right, bottom,
    659         return true and set this rectangle to that intersection, otherwise return false
    660         and do not change this rectangle.
    661         If either rectangle is empty, do nothing and return false.
    662     */
    663     bool intersect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom);
    664 
    665     /**
    666      *  Return true if this rectangle is not empty, and the specified sides of
    667      *  a rectangle are not empty, and they intersect.
    668      */
    669     bool intersects(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) const {
    670         return // first check that both are not empty
    671                left < right && top < bottom &&
    672                fLeft < fRight && fTop < fBottom &&
    673                // now check for intersection
    674                fLeft < right && left < fRight &&
    675                fTop < bottom && top < fBottom;
    676     }
    677 
    678     /** If rectangles a and b intersect, return true and set this rectangle to
    679      *  that intersection, otherwise return false and do not change this
    680      *  rectangle. If either rectangle is empty, do nothing and return false.
    681      */
    682     bool intersect(const SkRect& a, const SkRect& b);
    683 
    684     /**
    685      *  Return true if rectangles a and b are not empty and intersect.
    686      */
    687     static bool Intersects(const SkRect& a, const SkRect& b) {
    688         return  !a.isEmpty() && !b.isEmpty() &&
    689                 a.fLeft < b.fRight && b.fLeft < a.fRight &&
    690                 a.fTop < b.fBottom && b.fTop < a.fBottom;
    691     }
    692 
    693     /**
    694      *  Update this rectangle to enclose itself and the specified rectangle.
    695      *  If this rectangle is empty, just set it to the specified rectangle.
    696      *  If the specified rectangle is empty, do nothing.
    697      */
    698     void join(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom);
    699 
    700     /** Update this rectangle to enclose itself and the specified rectangle.
    701         If this rectangle is empty, just set it to the specified rectangle. If the specified
    702         rectangle is empty, do nothing.
    703     */
    704     void join(const SkRect& r) {
    705         this->join(r.fLeft, r.fTop, r.fRight, r.fBottom);
    706     }
    707     // alias for join()
    708     void growToInclude(const SkRect& r) { this->join(r); }
    709 
    710     /**
    711      *  Grow the rect to include the specified (x,y). After this call, the
    712      *  following will be true: fLeft <= x <= fRight && fTop <= y <= fBottom.
    713      *
    714      *  This is close, but not quite the same contract as contains(), since
    715      *  contains() treats the left and top different from the right and bottom.
    716      *  contains(x,y) -> fLeft <= x < fRight && fTop <= y < fBottom. Also note
    717      *  that contains(x,y) always returns false if the rect is empty.
    718      */
    719     void growToInclude(SkScalar x, SkScalar y) {
    720         fLeft  = SkMinScalar(x, fLeft);
    721         fRight = SkMaxScalar(x, fRight);
    722         fTop    = SkMinScalar(y, fTop);
    723         fBottom = SkMaxScalar(y, fBottom);
    724     }
    725 
    726     /** Bulk version of growToInclude */
    727     void growToInclude(const SkPoint pts[], int count) {
    728         this->growToInclude(pts, sizeof(SkPoint), count);
    729     }
    730 
    731     /** Bulk version of growToInclude with stride. */
    732     void growToInclude(const SkPoint pts[], size_t stride, int count) {
    733         SkASSERT(count >= 0);
    734         SkASSERT(stride >= sizeof(SkPoint));
    735         const SkPoint* end = (const SkPoint*)((intptr_t)pts + count * stride);
    736         for (; pts < end; pts = (const SkPoint*)((intptr_t)pts + stride)) {
    737             this->growToInclude(pts->fX, pts->fY);
    738         }
    739     }
    740 
    741     /**
    742      *  Return true if this rectangle contains r, and if both rectangles are
    743      *  not empty.
    744      */
    745     bool contains(const SkRect& r) const {
    746         // todo: can we eliminate the this->isEmpty check?
    747         return  !r.isEmpty() && !this->isEmpty() &&
    748                 fLeft <= r.fLeft && fTop <= r.fTop &&
    749                 fRight >= r.fRight && fBottom >= r.fBottom;
    750     }
    751 
    752     /**
    753      *  Set the dst rectangle by rounding this rectangle's coordinates to their
    754      *  nearest integer values using SkScalarRoundToInt.
    755      */
    756     void round(SkIRect* dst) const {
    757         SkASSERT(dst);
    758         dst->set(SkScalarRoundToInt(fLeft), SkScalarRoundToInt(fTop),
    759                  SkScalarRoundToInt(fRight), SkScalarRoundToInt(fBottom));
    760     }
    761 
    762     /**
    763      *  Variant of round() that explicitly performs the rounding step (i.e. floor(x + 0.5)) using
    764      *  double instead of SkScalar (float). It does this by calling SkDScalarRoundToInt(), which
    765      *  may be slower than calling SkScalarRountToInt(), but gives slightly more accurate results.
    766      *
    767      *  e.g.
    768      *      SkScalar x = 0.49999997f;
    769      *      int ix = SkScalarRoundToInt(x);
    770      *      SkASSERT(0 == ix);  // <--- fails
    771      *      ix = SkDScalarRoundToInt(x);
    772      *      SkASSERT(0 == ix);  // <--- succeeds
    773      */
    774     void dround(SkIRect* dst) const {
    775         SkASSERT(dst);
    776         dst->set(SkDScalarRoundToInt(fLeft), SkDScalarRoundToInt(fTop),
    777                  SkDScalarRoundToInt(fRight), SkDScalarRoundToInt(fBottom));
    778     }
    779 
    780     /**
    781      *  Set the dst rectangle by rounding "out" this rectangle, choosing the
    782      *  SkScalarFloor of top and left, and the SkScalarCeil of right and bottom.
    783      */
    784     void roundOut(SkIRect* dst) const {
    785         SkASSERT(dst);
    786         dst->set(SkScalarFloorToInt(fLeft), SkScalarFloorToInt(fTop),
    787                  SkScalarCeilToInt(fRight), SkScalarCeilToInt(fBottom));
    788     }
    789 
    790     /**
    791      *  Expand this rectangle by rounding its coordinates "out", choosing the
    792      *  floor of top and left, and the ceil of right and bottom. If this rect
    793      *  is already on integer coordinates, then it will be unchanged.
    794      */
    795     void roundOut() {
    796         this->set(SkScalarFloorToScalar(fLeft),
    797                   SkScalarFloorToScalar(fTop),
    798                   SkScalarCeilToScalar(fRight),
    799                   SkScalarCeilToScalar(fBottom));
    800     }
    801 
    802     /**
    803      *  Set the dst rectangle by rounding "in" this rectangle, choosing the
    804      *  ceil of top and left, and the floor of right and bottom. This does *not*
    805      *  call sort(), so it is possible that the resulting rect is inverted...
    806      *  e.g. left >= right or top >= bottom. Call isEmpty() to detect that.
    807      */
    808     void roundIn(SkIRect* dst) const {
    809         SkASSERT(dst);
    810         dst->set(SkScalarCeilToInt(fLeft), SkScalarCeilToInt(fTop),
    811                  SkScalarFloorToInt(fRight), SkScalarFloorToInt(fBottom));
    812     }
    813 
    814     /**
    815      *  Return a new SkIRect which is contains the rounded coordinates of this
    816      *  rect using SkScalarRoundToInt.
    817      */
    818     SkIRect round() const {
    819         SkIRect ir;
    820         this->round(&ir);
    821         return ir;
    822     }
    823 
    824     /**
    825      *  Swap top/bottom or left/right if there are flipped (i.e. if width()
    826      *  or height() would have returned a negative value.) This should be called
    827      *  if the edges are computed separately, and may have crossed over each
    828      *  other. When this returns, left <= right && top <= bottom
    829      */
    830     void sort();
    831 
    832     /**
    833      *  cast-safe way to treat the rect as an array of (4) SkScalars.
    834      */
    835     const SkScalar* asScalars() const { return &fLeft; }
    836 
    837 #ifdef SK_DEVELOPER
    838     /**
    839      * Dumps the rect using SkDebugf. This is intended for Skia development debugging. Don't
    840      * rely on the existence of this function or the formatting of its output.
    841      */
    842     void dump() const {
    843         SkDebugf("{ l: %f, t: %f, r: %f, b: %f }", fLeft, fTop, fRight, fBottom);
    844     }
    845 #endif
    846 
    847 };
    848 
    849 #endif
    850