SkRect.h revision 72b2e6fff3f54c6aa80a98eab4c73f02a8cd450d
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*/
20struct 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 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 SK_WARN_UNUSED_RESULT MakeSize(const SkISize& size) {
36        SkIRect r;
37        r.set(0, 0, size.width(), size.height());
38        return r;
39    }
40
41    static SkIRect SK_WARN_UNUSED_RESULT 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 SK_WARN_UNUSED_RESULT 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    /**
146     *  Offset this rect such its new x() and y() will equal newX and newY.
147     */
148    void offsetTo(int32_t newX, int32_t newY) {
149        fRight += newX - fLeft;
150        fBottom += newY - fTop;
151        fLeft = newX;
152        fTop = newY;
153    }
154
155    /** Inset the rectangle by (dx,dy). If dx is positive, then the sides are moved inwards,
156        making the rectangle narrower. If dx is negative, then the sides are moved outwards,
157        making the rectangle wider. The same holds true for dy and the top and bottom.
158    */
159    void inset(int32_t dx, int32_t dy) {
160        fLeft   += dx;
161        fTop    += dy;
162        fRight  -= dx;
163        fBottom -= dy;
164    }
165
166   /** Outset the rectangle by (dx,dy). If dx is positive, then the sides are
167       moved outwards, making the rectangle wider. If dx is negative, then the
168       sides are moved inwards, making the rectangle narrower. The same holds
169       true for dy and the top and bottom.
170    */
171    void outset(int32_t dx, int32_t dy)  { this->inset(-dx, -dy); }
172
173    bool quickReject(int l, int t, int r, int b) const {
174        return l >= fRight || fLeft >= r || t >= fBottom || fTop >= b;
175    }
176
177    /** Returns true if (x,y) is inside the rectangle and the rectangle is not
178        empty. The left and top are considered to be inside, while the right
179        and bottom are not. Thus for the rectangle (0, 0, 5, 10), the
180        points (0,0) and (0,9) are inside, while (-1,0) and (5,9) are not.
181    */
182    bool contains(int32_t x, int32_t y) const {
183        return  (unsigned)(x - fLeft) < (unsigned)(fRight - fLeft) &&
184                (unsigned)(y - fTop) < (unsigned)(fBottom - fTop);
185    }
186
187    /** Returns true if the 4 specified sides of a rectangle are inside or equal to this rectangle.
188        If either rectangle is empty, contains() returns false.
189    */
190    bool contains(int32_t left, int32_t top, int32_t right, int32_t bottom) const {
191        return  left < right && top < bottom && !this->isEmpty() && // check for empties
192                fLeft <= left && fTop <= top &&
193                fRight >= right && fBottom >= bottom;
194    }
195
196    /** Returns true if the specified rectangle r is inside or equal to this rectangle.
197    */
198    bool contains(const SkIRect& r) const {
199        return  !r.isEmpty() && !this->isEmpty() &&     // check for empties
200                fLeft <= r.fLeft && fTop <= r.fTop &&
201                fRight >= r.fRight && fBottom >= r.fBottom;
202    }
203
204    /** Return true if this rectangle contains the specified rectangle.
205        For speed, this method does not check if either this or the specified
206        rectangles are empty, and if either is, its return value is undefined.
207        In the debugging build however, we assert that both this and the
208        specified rectangles are non-empty.
209    */
210    bool containsNoEmptyCheck(int32_t left, int32_t top,
211                              int32_t right, int32_t bottom) const {
212        SkASSERT(fLeft < fRight && fTop < fBottom);
213        SkASSERT(left < right && top < bottom);
214
215        return fLeft <= left && fTop <= top &&
216               fRight >= right && fBottom >= bottom;
217    }
218
219    bool containsNoEmptyCheck(const SkIRect& r) const {
220        return containsNoEmptyCheck(r.fLeft, r.fTop, r.fRight, r.fBottom);
221    }
222
223    /** If r intersects this rectangle, return true and set this rectangle to that
224        intersection, otherwise return false and do not change this rectangle.
225        If either rectangle is empty, do nothing and return false.
226    */
227    bool intersect(const SkIRect& r) {
228        SkASSERT(&r);
229        return this->intersect(r.fLeft, r.fTop, r.fRight, r.fBottom);
230    }
231
232    /** If rectangles a and b intersect, return true and set this rectangle to
233        that intersection, otherwise return false and do not change this
234        rectangle. If either rectangle is empty, do nothing and return false.
235    */
236    bool intersect(const SkIRect& a, const SkIRect& b) {
237        SkASSERT(&a && &b);
238
239        if (!a.isEmpty() && !b.isEmpty() &&
240                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 rectangles a and b intersect, return true and set this rectangle to
252        that intersection, otherwise return false and do not change this
253        rectangle. For speed, no check to see if a or b are empty is performed.
254        If either is, then the return result is undefined. In the debug build,
255        we assert that both rectangles are non-empty.
256    */
257    bool intersectNoEmptyCheck(const SkIRect& a, const SkIRect& b) {
258        SkASSERT(&a && &b);
259        SkASSERT(!a.isEmpty() && !b.isEmpty());
260
261        if (a.fLeft < b.fRight && b.fLeft < a.fRight &&
262                a.fTop < b.fBottom && b.fTop < a.fBottom) {
263            fLeft   = SkMax32(a.fLeft,   b.fLeft);
264            fTop    = SkMax32(a.fTop,    b.fTop);
265            fRight  = SkMin32(a.fRight,  b.fRight);
266            fBottom = SkMin32(a.fBottom, b.fBottom);
267            return true;
268        }
269        return false;
270    }
271
272    /** If the rectangle specified by left,top,right,bottom intersects this rectangle,
273        return true and set this rectangle to that intersection,
274        otherwise return false and do not change this rectangle.
275        If either rectangle is empty, do nothing and return false.
276    */
277    bool intersect(int32_t left, int32_t top, int32_t right, int32_t bottom) {
278        if (left < right && top < bottom && !this->isEmpty() &&
279                fLeft < right && left < fRight && fTop < bottom && top < fBottom) {
280            if (fLeft < left) fLeft = left;
281            if (fTop < top) fTop = top;
282            if (fRight > right) fRight = right;
283            if (fBottom > bottom) fBottom = bottom;
284            return true;
285        }
286        return false;
287    }
288
289    /** Returns true if a and b are not empty, and they intersect
290     */
291    static bool Intersects(const SkIRect& a, const SkIRect& b) {
292        return  !a.isEmpty() && !b.isEmpty() &&              // check for empties
293        a.fLeft < b.fRight && b.fLeft < a.fRight &&
294        a.fTop < b.fBottom && b.fTop < a.fBottom;
295    }
296
297    /**
298     *  Returns true if a and b intersect. debug-asserts that neither are empty.
299     */
300    static bool IntersectsNoEmptyCheck(const SkIRect& a, const SkIRect& b) {
301        SkASSERT(!a.isEmpty());
302        SkASSERT(!b.isEmpty());
303        return  a.fLeft < b.fRight && b.fLeft < a.fRight &&
304                a.fTop < b.fBottom && b.fTop < a.fBottom;
305    }
306
307    /** Update this rectangle to enclose itself and the specified rectangle.
308        If this rectangle is empty, just set it to the specified rectangle. If the specified
309        rectangle is empty, do nothing.
310    */
311    void join(int32_t left, int32_t top, int32_t right, int32_t bottom);
312
313    /** Update this rectangle to enclose itself and the specified rectangle.
314        If this rectangle is empty, just set it to the specified rectangle. If the specified
315        rectangle is empty, do nothing.
316    */
317    void join(const SkIRect& r) {
318        this->join(r.fLeft, r.fTop, r.fRight, r.fBottom);
319    }
320
321    /** Swap top/bottom or left/right if there are flipped.
322        This can be called if the edges are computed separately,
323        and may have crossed over each other.
324        When this returns, left <= right && top <= bottom
325    */
326    void sort();
327
328    static const SkIRect& SK_WARN_UNUSED_RESULT EmptyIRect() {
329        static const SkIRect gEmpty = { 0, 0, 0, 0 };
330        return gEmpty;
331    }
332};
333
334/** \struct SkRect
335*/
336struct SK_API SkRect {
337    SkScalar    fLeft, fTop, fRight, fBottom;
338
339    static SkRect SK_WARN_UNUSED_RESULT MakeEmpty() {
340        SkRect r;
341        r.setEmpty();
342        return r;
343    }
344
345    static SkRect SK_WARN_UNUSED_RESULT MakeWH(SkScalar w, SkScalar h) {
346        SkRect r;
347        r.set(0, 0, w, h);
348        return r;
349    }
350
351    static SkRect SK_WARN_UNUSED_RESULT MakeSize(const SkSize& size) {
352        SkRect r;
353        r.set(0, 0, size.width(), size.height());
354        return r;
355    }
356
357    static SkRect SK_WARN_UNUSED_RESULT MakeLTRB(SkScalar l, SkScalar t, SkScalar r, SkScalar b) {
358        SkRect rect;
359        rect.set(l, t, r, b);
360        return rect;
361    }
362
363    static SkRect SK_WARN_UNUSED_RESULT MakeXYWH(SkScalar x, SkScalar y, SkScalar w, SkScalar h) {
364        SkRect r;
365        r.set(x, y, x + w, y + h);
366        return r;
367    }
368
369    static SkRect SK_WARN_UNUSED_RESULT MakeFromIRect(const SkIRect& irect) {
370        SkRect r;
371        r.set(SkIntToScalar(irect.fLeft),
372              SkIntToScalar(irect.fTop),
373              SkIntToScalar(irect.fRight),
374              SkIntToScalar(irect.fBottom));
375        return r;
376    }
377
378    /**
379     *  Return true if the rectangle's width or height are <= 0
380     */
381    bool isEmpty() const { return fLeft >= fRight || fTop >= fBottom; }
382
383    /**
384     *  Returns true iff all values in the rect are finite. If any are
385     *  infinite or NaN (or SK_FixedNaN when SkScalar is fixed) then this
386     *  returns false.
387     */
388    bool isFinite() const {
389#ifdef SK_SCALAR_IS_FLOAT
390        float accum = 0;
391        accum *= fLeft;
392        accum *= fTop;
393        accum *= fRight;
394        accum *= fBottom;
395
396        // accum is either NaN or it is finite (zero).
397        SkASSERT(0 == accum || !(accum == accum));
398
399        // value==value will be true iff value is not NaN
400        // TODO: is it faster to say !accum or accum==accum?
401        return accum == accum;
402#else
403        // use bit-or for speed, since we don't care about short-circuting the
404        // tests, and we expect the common case will be that we need to check all.
405        int isNaN = (SK_FixedNaN == fLeft)  | (SK_FixedNaN == fTop) |
406                    (SK_FixedNaN == fRight) | (SK_FixedNaN == fBottom);
407        return !isNaN;
408#endif
409    }
410
411    SkScalar    x() const { return fLeft; }
412    SkScalar    y() const { return fTop; }
413    SkScalar    left() const { return fLeft; }
414    SkScalar    top() const { return fTop; }
415    SkScalar    right() const { return fRight; }
416    SkScalar    bottom() const { return fBottom; }
417    SkScalar    width() const { return fRight - fLeft; }
418    SkScalar    height() const { return fBottom - fTop; }
419    SkScalar    centerX() const { return SkScalarHalf(fLeft + fRight); }
420    SkScalar    centerY() const { return SkScalarHalf(fTop + fBottom); }
421
422    friend bool operator==(const SkRect& a, const SkRect& b) {
423        return SkScalarsEqual((SkScalar*)&a, (SkScalar*)&b, 4);
424    }
425
426    friend bool operator!=(const SkRect& a, const SkRect& b) {
427        return !SkScalarsEqual((SkScalar*)&a, (SkScalar*)&b, 4);
428    }
429
430    /** return the 4 points that enclose the rectangle
431    */
432    void toQuad(SkPoint quad[4]) const;
433
434    /** Set this rectangle to the empty rectangle (0,0,0,0)
435    */
436    void setEmpty() { memset(this, 0, sizeof(*this)); }
437
438    void set(const SkIRect& src) {
439        fLeft   = SkIntToScalar(src.fLeft);
440        fTop    = SkIntToScalar(src.fTop);
441        fRight  = SkIntToScalar(src.fRight);
442        fBottom = SkIntToScalar(src.fBottom);
443    }
444
445    void set(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) {
446        fLeft   = left;
447        fTop    = top;
448        fRight  = right;
449        fBottom = bottom;
450    }
451    // alias for set(l, t, r, b)
452    void setLTRB(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) {
453        this->set(left, top, right, bottom);
454    }
455
456    /** Initialize the rect with the 4 specified integers. The routine handles
457        converting them to scalars (by calling SkIntToScalar)
458     */
459    void iset(int left, int top, int right, int bottom) {
460        fLeft   = SkIntToScalar(left);
461        fTop    = SkIntToScalar(top);
462        fRight  = SkIntToScalar(right);
463        fBottom = SkIntToScalar(bottom);
464    }
465
466    /** Set this rectangle to be the bounds of the array of points.
467        If the array is empty (count == 0), then set this rectangle
468        to the empty rectangle (0,0,0,0)
469    */
470    void set(const SkPoint pts[], int count) {
471        // set() had been checking for non-finite values, so keep that behavior
472        // for now. Now that we have setBoundsCheck(), we may decide to make
473        // set() be simpler/faster, and not check for those.
474        (void)this->setBoundsCheck(pts, count);
475    }
476
477    // alias for set(pts, count)
478    void setBounds(const SkPoint pts[], int count) {
479        (void)this->setBoundsCheck(pts, count);
480    }
481
482    /**
483     *  Compute the bounds of the array of points, and set this rect to that
484     *  bounds and return true... unless a non-finite value is encountered,
485     *  in which case this rect is set to empty and false is returned.
486     */
487    bool setBoundsCheck(const SkPoint pts[], int count);
488
489    void set(const SkPoint& p0, const SkPoint& p1) {
490        fLeft =   SkMinScalar(p0.fX, p1.fX);
491        fRight =  SkMaxScalar(p0.fX, p1.fX);
492        fTop =    SkMinScalar(p0.fY, p1.fY);
493        fBottom = SkMaxScalar(p0.fY, p1.fY);
494    }
495
496    void setXYWH(SkScalar x, SkScalar y, SkScalar width, SkScalar height) {
497        fLeft = x;
498        fTop = y;
499        fRight = x + width;
500        fBottom = y + height;
501    }
502
503    void setWH(SkScalar width, SkScalar height) {
504        fLeft = 0;
505        fTop = 0;
506        fRight = width;
507        fBottom = height;
508    }
509
510    /**
511     *  Make the largest representable rectangle
512     */
513    void setLargest() {
514        fLeft = fTop = SK_ScalarMin;
515        fRight = fBottom = SK_ScalarMax;
516    }
517
518    /**
519     *  Make the largest representable rectangle, but inverted (e.g. fLeft will
520     *  be max and right will be min).
521     */
522    void setLargestInverted() {
523        fLeft = fTop = SK_ScalarMax;
524        fRight = fBottom = SK_ScalarMin;
525    }
526
527    /** Offset set the rectangle by adding dx to its left and right,
528        and adding dy to its top and bottom.
529    */
530    void offset(SkScalar dx, SkScalar dy) {
531        fLeft   += dx;
532        fTop    += dy;
533        fRight  += dx;
534        fBottom += dy;
535    }
536
537    void offset(const SkPoint& delta) {
538        this->offset(delta.fX, delta.fY);
539    }
540
541    /**
542     *  Offset this rect such its new x() and y() will equal newX and newY.
543     */
544    void offsetTo(SkScalar newX, SkScalar newY) {
545        fRight += newX - fLeft;
546        fBottom += newY - fTop;
547        fLeft = newX;
548        fTop = newY;
549    }
550
551    /** Inset the rectangle by (dx,dy). If dx is positive, then the sides are
552        moved inwards, making the rectangle narrower. If dx is negative, then
553        the sides are moved outwards, making the rectangle wider. The same holds
554         true for dy and the top and bottom.
555    */
556    void inset(SkScalar dx, SkScalar dy)  {
557        fLeft   += dx;
558        fTop    += dy;
559        fRight  -= dx;
560        fBottom -= dy;
561    }
562
563   /** Outset the rectangle by (dx,dy). If dx is positive, then the sides are
564       moved outwards, making the rectangle wider. If dx is negative, then the
565       sides are moved inwards, making the rectangle narrower. The same holds
566       true for dy and the top and bottom.
567    */
568    void outset(SkScalar dx, SkScalar dy)  { this->inset(-dx, -dy); }
569
570    /** If this rectangle intersects r, return true and set this rectangle to that
571        intersection, otherwise return false and do not change this rectangle.
572        If either rectangle is empty, do nothing and return false.
573    */
574    bool intersect(const SkRect& r);
575
576    /** If this rectangle intersects the rectangle specified by left, top, right, bottom,
577        return true and set this rectangle to that intersection, otherwise return false
578        and do not change this rectangle.
579        If either rectangle is empty, do nothing and return false.
580    */
581    bool intersect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom);
582
583    /**
584     *  Return true if this rectangle is not empty, and the specified sides of
585     *  a rectangle are not empty, and they intersect.
586     */
587    bool intersects(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) const {
588        return // first check that both are not empty
589               left < right && top < bottom &&
590               fLeft < fRight && fTop < fBottom &&
591               // now check for intersection
592               fLeft < right && left < fRight &&
593               fTop < bottom && top < fBottom;
594    }
595
596    /** If rectangles a and b intersect, return true and set this rectangle to
597     *  that intersection, otherwise return false and do not change this
598     *  rectangle. If either rectangle is empty, do nothing and return false.
599     */
600    bool intersect(const SkRect& a, const SkRect& b);
601
602    /**
603     *  Return true if rectangles a and b are not empty and intersect.
604     */
605    static bool Intersects(const SkRect& a, const SkRect& b) {
606        return  !a.isEmpty() && !b.isEmpty() &&
607                a.fLeft < b.fRight && b.fLeft < a.fRight &&
608                a.fTop < b.fBottom && b.fTop < a.fBottom;
609    }
610
611    /**
612     *  Update this rectangle to enclose itself and the specified rectangle.
613     *  If this rectangle is empty, just set it to the specified rectangle.
614     *  If the specified rectangle is empty, do nothing.
615     */
616    void join(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom);
617
618    /** Update this rectangle to enclose itself and the specified rectangle.
619        If this rectangle is empty, just set it to the specified rectangle. If the specified
620        rectangle is empty, do nothing.
621    */
622    void join(const SkRect& r) {
623        this->join(r.fLeft, r.fTop, r.fRight, r.fBottom);
624    }
625    // alias for join()
626    void growToInclude(const SkRect& r) { this->join(r); }
627
628    /**
629     *  Grow the rect to include the specified (x,y). After this call, the
630     *  following will be true: fLeft <= x <= fRight && fTop <= y <= fBottom.
631     *
632     *  This is close, but not quite the same contract as contains(), since
633     *  contains() treats the left and top different from the right and bottom.
634     *  contains(x,y) -> fLeft <= x < fRight && fTop <= y < fBottom. Also note
635     *  that contains(x,y) always returns false if the rect is empty.
636     */
637    void growToInclude(SkScalar x, SkScalar y) {
638        fLeft  = SkMinScalar(x, fLeft);
639        fRight = SkMaxScalar(x, fRight);
640        fTop    = SkMinScalar(y, fTop);
641        fBottom = SkMaxScalar(y, fBottom);
642    }
643
644    /**
645     *  Returns true if (p.fX,p.fY) is inside the rectangle, and the rectangle
646     *  is not empty.
647     *
648     *  Contains treats the left and top differently from the right and bottom.
649     *  The left and top coordinates of the rectangle are themselves considered
650     *  to be inside, while the right and bottom are not. Thus for the rectangle
651     *  {0, 0, 5, 10}, (0,0) is contained, but (0,10), (5,0) and (5,10) are not.
652     */
653    bool contains(const SkPoint& p) const {
654        return !this->isEmpty() &&
655               fLeft <= p.fX && p.fX < fRight && fTop <= p.fY && p.fY < fBottom;
656    }
657
658    /**
659     *  Returns true if (x,y) is inside the rectangle, and the rectangle
660     *  is not empty.
661     *
662     *  Contains treats the left and top differently from the right and bottom.
663     *  The left and top coordinates of the rectangle are themselves considered
664     *  to be inside, while the right and bottom are not. Thus for the rectangle
665     *  {0, 0, 5, 10}, (0,0) is contained, but (0,10), (5,0) and (5,10) are not.
666     */
667    bool contains(SkScalar x, SkScalar y) const {
668        return  !this->isEmpty() &&
669                fLeft <= x && x < fRight && fTop <= y && y < fBottom;
670    }
671
672    /**
673     *  Return true if this rectangle contains r, and if both rectangles are
674     *  not empty.
675     */
676    bool contains(const SkRect& r) const {
677        return  !r.isEmpty() && !this->isEmpty() &&
678                fLeft <= r.fLeft && fTop <= r.fTop &&
679                fRight >= r.fRight && fBottom >= r.fBottom;
680    }
681
682    /**
683     *  Set the dst rectangle by rounding this rectangle's coordinates to their
684     *  nearest integer values using SkScalarRound.
685     */
686    void round(SkIRect* dst) const {
687        SkASSERT(dst);
688        dst->set(SkScalarRoundToInt(fLeft), SkScalarRoundToInt(fTop),
689                 SkScalarRoundToInt(fRight), SkScalarRoundToInt(fBottom));
690    }
691
692    /**
693     *  Set the dst rectangle by rounding "out" this rectangle, choosing the
694     *  SkScalarFloor of top and left, and the SkScalarCeil of right and bottom.
695     */
696    void roundOut(SkIRect* dst) const {
697        SkASSERT(dst);
698        dst->set(SkScalarFloorToInt(fLeft), SkScalarFloorToInt(fTop),
699                 SkScalarCeilToInt(fRight), SkScalarCeilToInt(fBottom));
700    }
701
702    /**
703     *  Expand this rectangle by rounding its coordinates "out", choosing the
704     *  floor of top and left, and the ceil of right and bottom. If this rect
705     *  is already on integer coordinates, then it will be unchanged.
706     */
707    void roundOut() {
708        this->set(SkScalarFloorToScalar(fLeft),
709                  SkScalarFloorToScalar(fTop),
710                  SkScalarCeilToScalar(fRight),
711                  SkScalarCeilToScalar(fBottom));
712    }
713
714    /**
715     *  Set the dst rectangle by rounding "in" this rectangle, choosing the
716     *  ceil of top and left, and the floor of right and bottom. This does *not*
717     *  call sort(), so it is possible that the resulting rect is inverted...
718     *  e.g. left >= right or top >= bottom. Call isEmpty() to detect that.
719     */
720    void roundIn(SkIRect* dst) const {
721        SkASSERT(dst);
722        dst->set(SkScalarCeilToInt(fLeft), SkScalarCeilToInt(fTop),
723                 SkScalarFloorToInt(fRight), SkScalarFloorToInt(fBottom));
724    }
725
726
727    /**
728     *  Swap top/bottom or left/right if there are flipped (i.e. if width()
729     *  or height() would have returned a negative value.) This should be called
730     *  if the edges are computed separately, and may have crossed over each
731     *  other. When this returns, left <= right && top <= bottom
732     */
733    void sort();
734};
735
736#endif
737
738