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