Home | History | Annotate | Download | only in core
      1 /*
      2  * Copyright (C) 2006 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #ifndef SkRect_DEFINED
     18 #define SkRect_DEFINED
     19 
     20 #include "SkPoint.h"
     21 #include "SkSize.h"
     22 
     23 /** \struct SkIRect
     24 
     25     SkIRect holds four 32 bit integer coordinates for a rectangle
     26 */
     27 struct SkIRect {
     28     int32_t fLeft, fTop, fRight, fBottom;
     29 
     30     /** Return true if the rectangle's width or height are <= 0
     31     */
     32     bool isEmpty() const { return fLeft >= fRight || fTop >= fBottom; }
     33 
     34     /** Returns the rectangle's width. This does not check for a valid rectangle (i.e. left <= right)
     35         so the result may be negative.
     36     */
     37     int width() const { return fRight - fLeft; }
     38 
     39     /** Returns the rectangle's height. This does not check for a valid rectangle (i.e. top <= bottom)
     40         so the result may be negative.
     41     */
     42     int height() const { return fBottom - fTop; }
     43 
     44     friend int operator==(const SkIRect& a, const SkIRect& b) {
     45         return !memcmp(&a, &b, sizeof(a));
     46     }
     47 
     48     friend int operator!=(const SkIRect& a, const SkIRect& b) {
     49         return memcmp(&a, &b, sizeof(a));
     50     }
     51 
     52     bool is16Bit() const {
     53         return  SkIsS16(fLeft) && SkIsS16(fTop) &&
     54                 SkIsS16(fRight) && SkIsS16(fBottom);
     55     }
     56 
     57     /** Set the rectangle to (0,0,0,0)
     58     */
     59     void setEmpty() { memset(this, 0, sizeof(*this)); }
     60 
     61     void set(int32_t left, int32_t top, int32_t right, int32_t bottom) {
     62         fLeft   = left;
     63         fTop    = top;
     64         fRight  = right;
     65         fBottom = bottom;
     66     }
     67 
     68     /** Offset set the rectangle by adding dx to its left and right,
     69         and adding dy to its top and bottom.
     70     */
     71     void offset(int32_t dx, int32_t dy) {
     72         fLeft   += dx;
     73         fTop    += dy;
     74         fRight  += dx;
     75         fBottom += dy;
     76     }
     77 
     78     void offset(const SkIPoint& delta) {
     79         this->offset(delta.fX, delta.fY);
     80     }
     81 
     82     /** Inset the rectangle by (dx,dy). If dx is positive, then the sides are moved inwards,
     83         making the rectangle narrower. If dx is negative, then the sides are moved outwards,
     84         making the rectangle wider. The same hods true for dy and the top and bottom.
     85     */
     86     void inset(int32_t dx, int32_t dy) {
     87         fLeft   += dx;
     88         fTop    += dy;
     89         fRight  -= dx;
     90         fBottom -= dy;
     91     }
     92 
     93     /** Returns true if (x,y) is inside the rectangle and the rectangle is not
     94         empty. The left and top are considered to be inside, while the right
     95         and bottom are not. Thus for the rectangle (0, 0, 5, 10), the
     96         points (0,0) and (0,9) are inside, while (-1,0) and (5,9) are not.
     97     */
     98     bool contains(int32_t x, int32_t y) const {
     99         return  (unsigned)(x - fLeft) < (unsigned)(fRight - fLeft) &&
    100                 (unsigned)(y - fTop) < (unsigned)(fBottom - fTop);
    101     }
    102 
    103     /** Returns true if the 4 specified sides of a rectangle are inside or equal to this rectangle.
    104         If either rectangle is empty, contains() returns false.
    105     */
    106     bool contains(int32_t left, int32_t top, int32_t right, int32_t bottom) const {
    107         return  left < right && top < bottom && !this->isEmpty() && // check for empties
    108                 fLeft <= left && fTop <= top &&
    109                 fRight >= right && fBottom >= bottom;
    110     }
    111 
    112     /** Returns true if the specified rectangle r is inside or equal to this rectangle.
    113     */
    114     bool contains(const SkIRect& r) const {
    115         return  !r.isEmpty() && !this->isEmpty() &&     // check for empties
    116                 fLeft <= r.fLeft && fTop <= r.fTop &&
    117                 fRight >= r.fRight && fBottom >= r.fBottom;
    118     }
    119 
    120     /** Return true if this rectangle contains the specified rectangle.
    121 		For speed, this method does not check if either this or the specified
    122 		rectangles are empty, and if either is, its return value is undefined.
    123 		In the debugging build however, we assert that both this and the
    124 		specified rectangles are non-empty.
    125     */
    126     bool containsNoEmptyCheck(int32_t left, int32_t top,
    127 							  int32_t right, int32_t bottom) const {
    128 		SkASSERT(fLeft < fRight && fTop < fBottom);
    129         SkASSERT(left < right && top < bottom);
    130 
    131         return fLeft <= left && fTop <= top &&
    132 			   fRight >= right && fBottom >= bottom;
    133     }
    134 
    135     /** If r intersects this rectangle, return true and set this rectangle to that
    136         intersection, otherwise return false and do not change this rectangle.
    137         If either rectangle is empty, do nothing and return false.
    138     */
    139     bool intersect(const SkIRect& r) {
    140         SkASSERT(&r);
    141         return this->intersect(r.fLeft, r.fTop, r.fRight, r.fBottom);
    142     }
    143 
    144     /** If rectangles a and b intersect, return true and set this rectangle to
    145         that intersection, otherwise return false and do not change this
    146         rectangle. If either rectangle is empty, do nothing and return false.
    147     */
    148     bool intersect(const SkIRect& a, const SkIRect& b) {
    149         SkASSERT(&a && &b);
    150 
    151         if (!a.isEmpty() && !b.isEmpty() &&
    152                 a.fLeft < b.fRight && b.fLeft < a.fRight &&
    153                 a.fTop < b.fBottom && b.fTop < a.fBottom) {
    154             fLeft   = SkMax32(a.fLeft,   b.fLeft);
    155             fTop    = SkMax32(a.fTop,    b.fTop);
    156             fRight  = SkMin32(a.fRight,  b.fRight);
    157             fBottom = SkMin32(a.fBottom, b.fBottom);
    158             return true;
    159         }
    160         return false;
    161     }
    162 
    163     /** If rectangles a and b intersect, return true and set this rectangle to
    164         that intersection, otherwise return false and do not change this
    165         rectangle. For speed, no check to see if a or b are empty is performed.
    166         If either is, then the return result is undefined. In the debug build,
    167         we assert that both rectangles are non-empty.
    168     */
    169     bool intersectNoEmptyCheck(const SkIRect& a, const SkIRect& b) {
    170         SkASSERT(&a && &b);
    171         SkASSERT(!a.isEmpty() && !b.isEmpty());
    172 
    173         if (a.fLeft < b.fRight && b.fLeft < a.fRight &&
    174                 a.fTop < b.fBottom && b.fTop < a.fBottom) {
    175             fLeft   = SkMax32(a.fLeft,   b.fLeft);
    176             fTop    = SkMax32(a.fTop,    b.fTop);
    177             fRight  = SkMin32(a.fRight,  b.fRight);
    178             fBottom = SkMin32(a.fBottom, b.fBottom);
    179             return true;
    180         }
    181         return false;
    182     }
    183 
    184     /** If the rectangle specified by left,top,right,bottom intersects this rectangle,
    185         return true and set this rectangle to that intersection,
    186         otherwise return false and do not change this rectangle.
    187         If either rectangle is empty, do nothing and return false.
    188     */
    189     bool intersect(int32_t left, int32_t top, int32_t right, int32_t bottom) {
    190         if (left < right && top < bottom && !this->isEmpty() &&
    191                 fLeft < right && left < fRight && fTop < bottom && top < fBottom) {
    192             if (fLeft < left) fLeft = left;
    193             if (fTop < top) fTop = top;
    194             if (fRight > right) fRight = right;
    195             if (fBottom > bottom) fBottom = bottom;
    196             return true;
    197         }
    198         return false;
    199     }
    200 
    201     /** Returns true if a and b are not empty, and they intersect
    202     */
    203     static bool Intersects(const SkIRect& a, const SkIRect& b) {
    204         return  !a.isEmpty() && !b.isEmpty() &&              // check for empties
    205                 a.fLeft < b.fRight && b.fLeft < a.fRight &&
    206                 a.fTop < b.fBottom && b.fTop < a.fBottom;
    207     }
    208 
    209     /** Update this rectangle to enclose itself and the specified rectangle.
    210         If this rectangle is empty, just set it to the specified rectangle. If the specified
    211         rectangle is empty, do nothing.
    212     */
    213     void join(int32_t left, int32_t top, int32_t right, int32_t bottom);
    214 
    215     /** Update this rectangle to enclose itself and the specified rectangle.
    216         If this rectangle is empty, just set it to the specified rectangle. If the specified
    217         rectangle is empty, do nothing.
    218     */
    219     void join(const SkIRect& r) {
    220         this->join(r.fLeft, r.fTop, r.fRight, r.fBottom);
    221     }
    222 
    223     /** Swap top/bottom or left/right if there are flipped.
    224         This can be called if the edges are computed separately,
    225         and may have crossed over each other.
    226         When this returns, left <= right && top <= bottom
    227     */
    228     void sort();
    229 };
    230 
    231 /** \struct SkRect
    232 */
    233 struct SkRect {
    234     SkScalar    fLeft, fTop, fRight, fBottom;
    235 
    236     static SkRect MakeSize(const SkSize& size) {
    237         SkRect r;
    238         r.set(0, 0, size.width(), size.height());
    239         return r;
    240     }
    241 
    242     static SkRect MakeLTRB(SkScalar l, SkScalar t, SkScalar r, SkScalar b) {
    243         SkRect rect;
    244         rect.set(l, t, r, b);
    245         return rect;
    246     }
    247 
    248     static SkRect MakeXYWH(SkScalar x, SkScalar y, SkScalar w, SkScalar h) {
    249         SkRect r;
    250         r.set(x, y, x + w, y + h);
    251         return r;
    252     }
    253 
    254     /** Return true if the rectangle's width or height are <= 0
    255     */
    256     bool        isEmpty() const { return fLeft >= fRight || fTop >= fBottom; }
    257     SkScalar    width() const { return fRight - fLeft; }
    258     SkScalar    height() const { return fBottom - fTop; }
    259     SkScalar    centerX() const { return SkScalarHalf(fLeft + fRight); }
    260     SkScalar    centerY() const { return SkScalarHalf(fTop + fBottom); }
    261 
    262     friend int operator==(const SkRect& a, const SkRect& b) {
    263         return !memcmp(&a, &b, sizeof(a));
    264     }
    265 
    266     friend int operator!=(const SkRect& a, const SkRect& b) {
    267         return memcmp(&a, &b, sizeof(a));
    268     }
    269 
    270     /** return the 4 points that enclose the rectangle
    271     */
    272     void toQuad(SkPoint quad[4]) const;
    273 
    274     /** Set this rectangle to the empty rectangle (0,0,0,0)
    275     */
    276     void setEmpty() { memset(this, 0, sizeof(*this)); }
    277 
    278     void set(const SkIRect& src) {
    279         fLeft   = SkIntToScalar(src.fLeft);
    280         fTop    = SkIntToScalar(src.fTop);
    281         fRight  = SkIntToScalar(src.fRight);
    282         fBottom = SkIntToScalar(src.fBottom);
    283     }
    284 
    285     void set(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) {
    286         fLeft   = left;
    287         fTop    = top;
    288         fRight  = right;
    289         fBottom = bottom;
    290     }
    291 
    292     /** Initialize the rect with the 4 specified integers. The routine handles
    293         converting them to scalars (by calling SkIntToScalar)
    294      */
    295     void iset(int left, int top, int right, int bottom) {
    296         fLeft   = SkIntToScalar(left);
    297         fTop    = SkIntToScalar(top);
    298         fRight  = SkIntToScalar(right);
    299         fBottom = SkIntToScalar(bottom);
    300     }
    301 
    302     /** Set this rectangle to be the bounds of the array of points.
    303         If the array is empty (count == 0), then set this rectangle
    304         to the empty rectangle (0,0,0,0)
    305     */
    306     void set(const SkPoint pts[], int count);
    307 
    308     /** Offset set the rectangle by adding dx to its left and right,
    309         and adding dy to its top and bottom.
    310     */
    311     void offset(SkScalar dx, SkScalar dy) {
    312         fLeft   += dx;
    313         fTop    += dy;
    314         fRight  += dx;
    315         fBottom += dy;
    316     }
    317 
    318     void offset(const SkPoint& delta) {
    319         this->offset(delta.fX, delta.fY);
    320     }
    321 
    322     /** Inset the rectangle by (dx,dy). If dx is positive, then the sides are moved inwards,
    323         making the rectangle narrower. If dx is negative, then the sides are moved outwards,
    324         making the rectangle wider. The same hods true for dy and the top and bottom.
    325     */
    326     void inset(SkScalar dx, SkScalar dy)  {
    327         fLeft   += dx;
    328         fTop    += dy;
    329         fRight  -= dx;
    330         fBottom -= dy;
    331     }
    332 
    333     /** If this rectangle intersects r, return true and set this rectangle to that
    334         intersection, otherwise return false and do not change this rectangle.
    335         If either rectangle is empty, do nothing and return false.
    336     */
    337     bool intersect(const SkRect& r);
    338 
    339     /** If this rectangle intersects the rectangle specified by left, top, right, bottom,
    340         return true and set this rectangle to that intersection, otherwise return false
    341         and do not change this rectangle.
    342         If either rectangle is empty, do nothing and return false.
    343     */
    344     bool intersect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom);
    345 
    346     /** Return true if this rectangle is not empty, and the specified sides of
    347         a rectangle are not empty, and they intersect.
    348     */
    349     bool intersects(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) const {
    350         return // first check that both are not empty
    351                left < right && top < bottom &&
    352                fLeft < fRight && fTop < fBottom &&
    353                // now check for intersection
    354                fLeft < right && left < fRight &&
    355                fTop < bottom && top < fBottom;
    356     }
    357 
    358     /** Return true if rectangles a and b are not empty and intersect.
    359         */
    360     static bool Intersects(const SkRect& a, const SkRect& b) {
    361         return  !a.isEmpty() && !b.isEmpty() &&             // check for empties
    362         a.fLeft < b.fRight && b.fLeft < a.fRight &&
    363         a.fTop < b.fBottom && b.fTop < a.fBottom;
    364     }
    365 
    366     /** Update this rectangle to enclose itself and the specified rectangle.
    367         If this rectangle is empty, just set it to the specified rectangle. If the specified
    368         rectangle is empty, do nothing.
    369     */
    370     void join(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom);
    371 
    372     /** Update this rectangle to enclose itself and the specified rectangle.
    373         If this rectangle is empty, just set it to the specified rectangle. If the specified
    374         rectangle is empty, do nothing.
    375     */
    376     void join(const SkRect& r) {
    377         this->join(r.fLeft, r.fTop, r.fRight, r.fBottom);
    378     }
    379 
    380     /** Returns true if (p.fX,p.fY) is inside the rectangle. The left and top coordinates of
    381         the rectangle are considered to be inside, while the right and bottom coordinates
    382         are not. Thus for the rectangle (0, 0, 5, 10), the points (0,0) and (0,9) are inside,
    383         while (-1,0) and (5,9) are not.
    384         If this rectangle is empty, return false.
    385     */
    386     bool contains(const SkPoint& p) const {
    387         return  !this->isEmpty() &&
    388                 fLeft <= p.fX && p.fX < fRight &&
    389                 fTop <= p.fY && p.fY < fBottom;
    390     }
    391 
    392     /** Returns true if (x,y) is inside the rectangle. The left and top coordinates of
    393         the rectangle are considered to be inside, while the right and bottom coordinates
    394         are not. Thus for the rectangle (0, 0, 5, 10), the points (0,0) and (0,9) are inside,
    395         while (-1,0) and (5,9) are not.
    396         If this rectangle is empty, return false.
    397     */
    398     bool contains(SkScalar x, SkScalar y) const {
    399         return  !this->isEmpty() &&
    400                 fLeft <= x && x < fRight &&
    401                 fTop <= y && y < fBottom;
    402     }
    403 
    404     /** Return true if this rectangle contains r.
    405         If either rectangle is empty, return false.
    406     */
    407     bool contains(const SkRect& r) const {
    408         return  !r.isEmpty() && !this->isEmpty() &&     // check for empties
    409                 fLeft <= r.fLeft && fTop <= r.fTop &&
    410                 fRight >= r.fRight && fBottom >= r.fBottom;
    411     }
    412 
    413     /** Set the dst integer rectangle by rounding this rectangle's coordinates
    414         to their nearest integer values.
    415     */
    416     void round(SkIRect* dst) const {
    417         SkASSERT(dst);
    418         dst->set(SkScalarRound(fLeft), SkScalarRound(fTop), SkScalarRound(fRight), SkScalarRound(fBottom));
    419     }
    420 
    421     /** Set the dst integer rectangle by rounding "out" this rectangle, choosing the floor of top and left,
    422         and the ceiling of right and bototm.
    423     */
    424     void roundOut(SkIRect* dst) const {
    425         SkASSERT(dst);
    426         dst->set(SkScalarFloor(fLeft), SkScalarFloor(fTop), SkScalarCeil(fRight), SkScalarCeil(fBottom));
    427     }
    428 
    429     /** Swap top/bottom or left/right if there are flipped.
    430         This can be called if the edges are computed separately,
    431         and may have crossed over each other.
    432         When this returns, left <= right && top <= bottom
    433     */
    434     void sort();
    435 };
    436 
    437 #endif
    438 
    439